chainlesschain 0.162.107 → 0.162.109
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-B7Hz-sMT.js → AIOps-DOMx_gkg.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-tIqg_ue9.js → ActionButton-C3V6-KN7.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-B6DbVy_b.js → Analytics-DhcH00zB.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Cm_hOXV8.js → AppLayout-DxaARGVc.js} +4 -4
- package/src/assets/web-panel/assets/{Audit-Crc94mKO.js → Audit-B5v_yPs_.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DIZVZXve.js → Backup-y0trXy2c.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BZWHuJyu.js → BaseInput-BKmOrsWP.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BOCsYs8k.js → Chat-YxvzoXfA.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BK6OX-J4.js → ChatBubbleRenderer-BT502wFg.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-_bsZN_Td.js → Checkbox-CWlobcH7.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Cu-YIxg5.js → Codegen-DyDnpB9x.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BMM77pN6.js → Col-vSk5m8e6.js} +1 -1
- package/src/assets/web-panel/assets/{Community-B4uw3_sc.js → Community-ms1KDyit.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-RxrnL4Ql.js → Compact-CgOlMunA.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CKEfGRFH.js → Compliance-BtmnlvkF.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-jS0AVJjh.js → Cowork-oEgcjamv.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-DNyVTsuS.js → Cron-C45dOmbZ.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DRaSmfQP.js → Crosschain-COCW4N4S.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B5UTlNum.js → DID-D6L3jdjB.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-OVoPMtcA.js → Dashboard-CZO_nWR9.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-5OA2sbK9.js → Dropdown-BHogrwxg.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DUJPUE_n.js → EmailListRenderer-DVU5KA6Y.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BKFSlqTB.js → FamilyGuardDashboard-BpJuZRlS.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BAhgrKK6.js → Federation-C8XUIu9h.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CZ8wh8ZQ.js → FormItemContext-Dkv__07L.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Cnsg9gY4.js → GenericCardRenderer-PI4Hv6J7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-EY6xhhH-.js → Git-DwoiOK7x.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CKGWi2hF.js → Governance-CZMrVnKF.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Bibz4dcl.js → Inference-DGMCR5fY.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-B1GhH4Rh.js → KnowledgeGraph-CHnyTP7N.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Ce6yjdqa.js → Logs-aHwf1vTL.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-0dFzmO9J.js → Marketplace-DrrJWlYy.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-crttKADW.js → McpTools-FsvEQItl.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BjtmouRu.js → Memory-BaLEbZZU.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Djm8NKL7.js → MobileBridge-Cbpe-UlH.js} +2 -2
- package/src/assets/web-panel/assets/MobileProjects-WpHJ6m0I.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-UvDcNKPe.js → Mtc-B2-MRjt7.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-CCUvaVsw.js → MtcAudit-BPKg4478.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-CltVDZII.js → Multisig-DL-OMvg9.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-nVqmxQ1N.js → NLProgramming-BFbo7QJF.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-gyIOnFru.js → Notes-DxlawFPj.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-C7VByx8y.js → NotificationSettings-mXTgzIC1.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DopvBK5x.js → OrderTableRenderer-BUcf5CYv.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-VxnADtjw.js → Organization-FeID8_Wf.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Du67ZgzE.js → Overflow-DTFS4Vaz.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CXK6FzZK.js → P2P-BkylEhA8.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-D8bxEEcj.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-B23k4uT8.js → Permissions-BSQ09sRI.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CjiMy8De.js → PersonalDataHub-Ba5iRuIi.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-Z1KmgqP5.js → Pipeline-DmL3Gpxg.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CmxIvTR1.js → Privacy-DAvd_DSh.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bts__Qz3.js → ProjectInit-AxBuFwBR.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Bd_lhQgg.js → ProjectSettings-BZ40fAt5.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DR-bmuRQ.js → Projects-BHNbHuBF.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-kaD-Hp-Y.js → Providers-CDkzXPon.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-qy3iXhzr.js → QuickAsk-CzKbOUkP.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DONp9kRc.js → Recommend-D82aHoFt.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DDyL2Aeq.js → Reputation-zpuCi7ft.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D8YcGPf4.js → Row-BDq7p96-.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DXUODZiL.js → RssFeed-pAo6EJPy.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DEdHYWFg.js → Search-BXv5RRMM.js} +1 -1
- package/src/assets/web-panel/assets/{Security-H-o6s5e0.js → Security-Gn-HnKp5.js} +3 -3
- package/src/assets/web-panel/assets/{Services-UuIWNe9h.js → Services-BlfMJ4ZL.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DYtxZPtS.js → Skeleton-Q8cKUNTJ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DDifBlN4.js → Skills-BjOLODy1.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-D1ZAkzmU.js → Sla-TbklgbfG.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CKjGGj0q.js → SpeechSettings-DzKKyV6J.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BGg86vP1.js → SyncSettings-Bq-76qhL.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-VxIkYJmg.js → Tasks-DWBUnqic.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DFRL3OpQ.js → Templates-CS77urAR.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CmYigIMz.js → Tenant-B1hx8tjz.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-CNX2SAIP.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-B75R5MPw.js → TimelineRenderer-CS_iGXXB.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BQjcUYi2.js → Tokens-CPfe_Ndx.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-B87osPjr.js → Trigger-DARLZ6w5.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BMNsPMGf.js → Trust-R_mlmd7H.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Dh8aq9A5.js → UkeySign-CysEd--z.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BrW9UYwd.js → VideoEditing-eQ46o05K.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-rVZaz6JO.js → Wallet-C5788NxS.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BaQ7s6Rr.js → WebAuthn-CK_CPM4k.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-DFo5Ff-W.js → WorkflowEditor-DhvdLkE6.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BhGtd3vF.js → chat-CcKQhy1e.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C_Hs-0Q_.js → colors-B4d3_MCE.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Cxku8C7o.js → compact-item-DC-Xf92z.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-v6jUmogl.js → createContext-KBHDmwRY.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Da3Hdd0q.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BKhLdwbQ.js → hasIn-DEuYFeVL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfD0hdcw.js → index-2Csz0FGD.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2rsPZun.js → index-8BCBAwoA.js} +3 -3
- package/src/assets/web-panel/assets/{index-Bgtv4PNS.js → index-B4RknAfS.js} +1 -1
- package/src/assets/web-panel/assets/{index-CARZxqzf.js → index-B5cOdkHy.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2IZIcKV.js → index-BB9f50Gt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMiUs7VJ.js → index-BCbc993k.js} +1 -1
- package/src/assets/web-panel/assets/{index-GoxGMHvm.js → index-BJbBr6_l.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDW_6hBP.js → index-BK8vM7es.js} +1 -1
- package/src/assets/web-panel/assets/index-BMeXnsEn.js +1 -0
- package/src/assets/web-panel/assets/{index-B3pkWuB9.js → index-BZjC0VTy.js} +1 -1
- package/src/assets/web-panel/assets/index-BdqPeWvV.js +1 -0
- package/src/assets/web-panel/assets/{index-CBL2DZwT.js → index-Bm39r2a4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpO44b89.js → index-BwD3FKsC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BolB2BAg.js → index-BxlEfskb.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfjaeiC1.js → index-C4Ose5wC.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaDs425R.js → index-CCnk_-ug.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMCT14Fw.js → index-CTgs-ddr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVAVApRf.js → index-CdabmsmR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwKGHmaT.js → index-ChJ_B7b9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BElj4Od7.js → index-Cl0As6V5.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2PkAyeB.js → index-CxtHBFqA.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ha3xv10h.js → index-Cyb-NAiR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Mloutg2P.js → index-DE0-JQay.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmhCbfio.js → index-DQMDCc8g.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkFQKhAE.js → index-DQXNz0yD.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgpKinbP.js → index-DSXxbnHU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZDVxpam.js → index-DTudiivg.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfTpPsv6.js → index-DZN3yAE2.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnYbnWuX.js → index-DhGYNT5Y.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dfnrfw8C.js → index-DkoDAyug.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYz9sJYb.js → index-EnBI6ILp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLJ91vZT.js → index-JXP0mbdx.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8-PVIyz.js → index-N4xZOl6m.js} +1 -1
- package/src/assets/web-panel/assets/{index-ITysWrpU.js → index-Tcf8b4Dr.js} +1 -1
- package/src/assets/web-panel/assets/{index-gjdcCPuc.js → index-VkeJvcgx.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_vs8HEm.js → index-ZbZ9FKyc.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7aePQoD.js → index-gOIec6-U.js} +1 -1
- package/src/assets/web-panel/assets/{index-51MhKb2G.js → index-p5OuYAoC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Hmuq7HiU.js → index-tW1RyKbL.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-3JYk3XrB.js → initDefaultProps-BSjGxzmn.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DnWevrJa.js → motion-B5_Cszlm.js} +1 -1
- package/src/assets/web-panel/assets/{move-9bW2GZpH.js → move-Zi4ZApRv.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D8ydPKdj.js → omit-BNHsjZx4.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-l5iG1eRA.js → pickAttrs-GzJRqTuY.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Bp1b6Ucy.js → placementArrow-CXfzbh2d.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-ChTuOCcn.js → responsiveObserve-lhENMtmd.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Ck7EHmbe.js → slide-BaUzfEHc.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Beih7s__.js → statusUtils-ZYc611Fn.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Dddg8IJR.js → styleChecker-CaymUbb1.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DU6cxKQF.js → useFlexGapSupport-9EAy_UPY.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BISbGmgC.js → useFs-CUqinWaA.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CuO7bBz3.js → usePersonalDataHub-eOXrcae-.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Cq3NWQzC.js → vnode-gBQTchDv.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BTh_EbRh.js → zoom-CCC5-LNi.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-query-events.test.js +134 -0
- package/src/commands/agent.js +6 -0
- package/src/commands/hub.js +39 -10
- package/src/commands/mcp.js +42 -10
- package/src/commands/pdh.js +191 -1
- package/src/constants.js +2 -2
- package/src/gateways/ws/video-protocol.js +7 -0
- package/src/harness/feature-flags.js +19 -6
- package/src/harness/prompt-compressor.js +1 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/config-manager.js +42 -1
- package/src/lib/git-integration.js +1 -2
- package/src/lib/learning/learning-hooks.js +6 -0
- package/src/lib/llm-providers.js +2 -0
- package/src/lib/mcp-auth-target.js +53 -0
- package/src/lib/repl-completer.js +48 -9
- package/src/lib/shell-approval.js +7 -12
- package/src/lib/skill-loader.js +6 -2
- package/src/lib/suggest-name.js +91 -0
- package/src/lib/task-model-selector.js +5 -5
- package/src/repl/agent-repl.js +21 -1
- package/src/repl/slash-macro.js +7 -1
- package/src/runtime/agent-core.js +62 -3
- package/src/runtime/coding-agent-contract-shared.cjs +11 -1
- package/src/runtime/headless-runner.js +57 -4
- package/src/runtime/headless-stream.js +50 -2
- package/src/session/index.js +6 -2
- package/src/assets/web-panel/assets/MobileProjects-CuWSdENU.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-BH6PhZwi.js +0 -7
- package/src/assets/web-panel/assets/Terminal-DjjQrZtn.js +0 -3
- package/src/assets/web-panel/assets/devWarning-BnANFH7b.js +0 -1
- package/src/assets/web-panel/assets/index-CEJN-vG4.js +0 -1
- package/src/assets/web-panel/assets/index-CeJCYDPn.js +0 -1
package/src/commands/hub.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* All output supports --json for scripting. Default is human-readable.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
18
19
|
import chalk from "chalk";
|
|
19
20
|
import ora from "ora";
|
|
20
21
|
import { logger } from "../lib/logger.js";
|
|
@@ -528,7 +529,7 @@ async function cmdQueryEvents(options) {
|
|
|
528
529
|
// skips the 77-adapter registry build (and is crash-resilient to a
|
|
529
530
|
// partial pdh install). getHubMinimal() returns the full hub if one was
|
|
530
531
|
// already built this process, so the vault instance is identical.
|
|
531
|
-
const hub = await getHubMinimal();
|
|
532
|
+
const hub = await (options._getHub || getHubMinimal)();
|
|
532
533
|
const q = {};
|
|
533
534
|
if (options.subtype) q.subtype = options.subtype;
|
|
534
535
|
if (options.since) q.since = Number(options.since);
|
|
@@ -543,10 +544,18 @@ async function cmdQueryEvents(options) {
|
|
|
543
544
|
}
|
|
544
545
|
logger.log(`${events.length} events:`);
|
|
545
546
|
for (const ev of events) {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
547
|
+
// Vault events carry `occurredAt` (epoch ms) + `content`, NOT `at` /
|
|
548
|
+
// `summary` — reading the wrong fields previously threw "Invalid time
|
|
549
|
+
// value" on the first row and killed the whole listing. Guard the
|
|
550
|
+
// timestamp so one malformed row can't crash the output.
|
|
551
|
+
const ts = Number(ev.occurredAt);
|
|
552
|
+
const at = Number.isFinite(ts) ? new Date(ts).toISOString() : "(no date)";
|
|
553
|
+
const summary =
|
|
554
|
+
(ev.content &&
|
|
555
|
+
(ev.content.text || ev.content.title || ev.content.subject)) ||
|
|
556
|
+
ev.summary ||
|
|
557
|
+
ev.id;
|
|
558
|
+
logger.log(` ${chalk.gray(at)} ${chalk.cyan(ev.subtype)} ${summary}`);
|
|
550
559
|
}
|
|
551
560
|
process.exit(0);
|
|
552
561
|
} catch (err) {
|
|
@@ -601,7 +610,9 @@ async function cmdExportEvents(options) {
|
|
|
601
610
|
const hub = await (options._getHub || getHubMinimal)();
|
|
602
611
|
const all = exportAllEvents(hub.vault);
|
|
603
612
|
if (options.output) {
|
|
604
|
-
require("fs")
|
|
613
|
+
// ESM module — must NOT use require("fs") (ReferenceError: require is
|
|
614
|
+
// not defined). Use the static node:fs import.
|
|
615
|
+
writeFileSync(options.output, JSON.stringify(all), "utf-8");
|
|
605
616
|
if (options.json) {
|
|
606
617
|
jsonAndExit({ ok: true, count: all.length, output: options.output });
|
|
607
618
|
return;
|
|
@@ -623,7 +634,8 @@ async function cmdImportEvents(options) {
|
|
|
623
634
|
"import-events: --input <file> is required (a JSON array of events)",
|
|
624
635
|
);
|
|
625
636
|
}
|
|
626
|
-
|
|
637
|
+
// ESM module — use the static node:fs import, not require("fs").
|
|
638
|
+
const raw = readFileSync(options.input, "utf-8");
|
|
627
639
|
const events = JSON.parse(raw);
|
|
628
640
|
if (!Array.isArray(events)) {
|
|
629
641
|
throw new Error("import-events: expected a JSON array of events");
|
|
@@ -789,7 +801,7 @@ async function cmdEventDetail(eventId, options) {
|
|
|
789
801
|
}
|
|
790
802
|
try {
|
|
791
803
|
// Read-only single-event lookup — vault-only, use the minimal hub.
|
|
792
|
-
const hub = await getHubMinimal();
|
|
804
|
+
const hub = await (options._getHub || getHubMinimal)();
|
|
793
805
|
const event = hub.vault.getEvent(eventId);
|
|
794
806
|
if (!event) {
|
|
795
807
|
const result = { found: false, eventId };
|
|
@@ -802,9 +814,24 @@ async function cmdEventDetail(eventId, options) {
|
|
|
802
814
|
} else {
|
|
803
815
|
logger.log(chalk.bold(`event ${event.id}`));
|
|
804
816
|
logger.log(` subtype: ${event.subtype}`);
|
|
805
|
-
|
|
806
|
-
|
|
817
|
+
// occurredAt (epoch ms) is the canonical timestamp; guard a bad value.
|
|
818
|
+
const ts = Number(event.occurredAt);
|
|
819
|
+
if (Number.isFinite(ts)) {
|
|
820
|
+
logger.log(` occurred: ${new Date(ts).toISOString()}`);
|
|
821
|
+
}
|
|
822
|
+
// `source` is an object ({ adapter, ... }) — print the adapter, not the
|
|
823
|
+
// object (which renders as "[object Object]").
|
|
824
|
+
const adapter =
|
|
825
|
+
event.source && typeof event.source === "object"
|
|
826
|
+
? event.source.adapter
|
|
827
|
+
: event.source;
|
|
828
|
+
if (adapter) logger.log(` source: ${adapter}`);
|
|
807
829
|
if (event.actor) logger.log(` actor: ${event.actor}`);
|
|
830
|
+
const summary =
|
|
831
|
+
event.content &&
|
|
832
|
+
(event.content.text || event.content.title || event.content.subject);
|
|
833
|
+
if (summary) logger.log(` content: ${summary}`);
|
|
834
|
+
if (event.title) logger.log(` title: ${event.title}`);
|
|
808
835
|
if (event.amount != null) {
|
|
809
836
|
logger.log(` amount: ${event.amount} ${event.currency || ""}`);
|
|
810
837
|
}
|
|
@@ -3263,6 +3290,8 @@ export const _internal = {
|
|
|
3263
3290
|
cmdRetrieveContext,
|
|
3264
3291
|
cmdStats,
|
|
3265
3292
|
cmdHealth,
|
|
3293
|
+
cmdQueryEvents,
|
|
3294
|
+
cmdEventDetail,
|
|
3266
3295
|
parsePositiveInt,
|
|
3267
3296
|
cmdAIChatList,
|
|
3268
3297
|
cmdAIChatLogin,
|
package/src/commands/mcp.js
CHANGED
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
SUPPORTED_TRANSPORTS,
|
|
24
24
|
} from "../lib/mcp-scaffold.js";
|
|
25
25
|
import { parseJsonOption } from "../lib/parse-json-option.js";
|
|
26
|
+
import { resolveMcpAuthTarget, isUrlLike } from "../lib/mcp-auth-target.js";
|
|
27
|
+
import { notFoundWithSuggestion } from "../lib/suggest-name.js";
|
|
26
28
|
import {
|
|
27
29
|
CATALOG as REGISTRY_CATALOG,
|
|
28
30
|
CATEGORIES as REGISTRY_CATEGORIES,
|
|
@@ -39,6 +41,27 @@ function getClient() {
|
|
|
39
41
|
return mcpClient;
|
|
40
42
|
}
|
|
41
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a `mcp login|logout <target>` argument (a URL or a configured server
|
|
46
|
+
* NAME — Claude-Code 2.1.186 parity) to a concrete server URL. The DB is only
|
|
47
|
+
* bootstrapped when a name lookup is actually needed, so a raw-URL login stays
|
|
48
|
+
* dependency-free.
|
|
49
|
+
*/
|
|
50
|
+
async function resolveAuthTargetUrl(program, target) {
|
|
51
|
+
if (isUrlLike(target)) return resolveMcpAuthTarget(target).url;
|
|
52
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
53
|
+
const lookup = (name) => {
|
|
54
|
+
try {
|
|
55
|
+
return ctx.db
|
|
56
|
+
? new MCPServerConfig(ctx.db.getDatabase()).get(name)
|
|
57
|
+
: null;
|
|
58
|
+
} catch {
|
|
59
|
+
return null; // a lookup failure surfaces as "unknown server" below
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
return resolveMcpAuthTarget(target, lookup).url;
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
/**
|
|
43
66
|
* Connect MCP server(s) for a one-shot query (resources / prompts). Connects
|
|
44
67
|
* the named server, or every registered server when `serverName` is omitted.
|
|
@@ -56,8 +79,9 @@ async function connectForQuery(program, serverName) {
|
|
|
56
79
|
if (serverName) {
|
|
57
80
|
const row = config.get(serverName);
|
|
58
81
|
if (!row) {
|
|
82
|
+
const names = config.list().map((s) => s.name);
|
|
59
83
|
logger.error(
|
|
60
|
-
|
|
84
|
+
`${notFoundWithSuggestion(serverName, names, { noun: "Server" })}. Use 'mcp add' first.`,
|
|
61
85
|
);
|
|
62
86
|
await shutdown();
|
|
63
87
|
process.exit(1);
|
|
@@ -111,9 +135,9 @@ export function registerMcpCommand(program) {
|
|
|
111
135
|
|
|
112
136
|
// mcp login — OAuth 2.0 (Auth Code + PKCE) for a remote MCP server.
|
|
113
137
|
mcp
|
|
114
|
-
.command("login <
|
|
138
|
+
.command("login <target>")
|
|
115
139
|
.description(
|
|
116
|
-
"Authorize a remote MCP server via OAuth (opens a browser); stores the token",
|
|
140
|
+
"Authorize a remote MCP server via OAuth (opens a browser); stores the token. <target> is a URL or a configured server name.",
|
|
117
141
|
)
|
|
118
142
|
.option("--scope <scope>", "OAuth scope(s) to request")
|
|
119
143
|
.option(
|
|
@@ -127,8 +151,9 @@ export function registerMcpCommand(program) {
|
|
|
127
151
|
53682,
|
|
128
152
|
)
|
|
129
153
|
.option("--no-open", "Print the authorize URL instead of opening a browser")
|
|
130
|
-
.action(async (
|
|
154
|
+
.action(async (target, options) => {
|
|
131
155
|
try {
|
|
156
|
+
const url = await resolveAuthTargetUrl(program, target);
|
|
132
157
|
const oauth = await import("../lib/mcp-oauth.js");
|
|
133
158
|
if (options.open === false) {
|
|
134
159
|
oauth._deps.openBrowser = () => false; // commander maps --no-open → open:false
|
|
@@ -159,10 +184,13 @@ export function registerMcpCommand(program) {
|
|
|
159
184
|
|
|
160
185
|
// mcp logout — forget a stored OAuth token.
|
|
161
186
|
mcp
|
|
162
|
-
.command("logout <
|
|
163
|
-
.description(
|
|
164
|
-
|
|
187
|
+
.command("logout <target>")
|
|
188
|
+
.description(
|
|
189
|
+
"Delete the stored OAuth token for a remote MCP server (<target> is a URL or a configured server name)",
|
|
190
|
+
)
|
|
191
|
+
.action(async (target) => {
|
|
165
192
|
try {
|
|
193
|
+
const url = await resolveAuthTargetUrl(program, target);
|
|
166
194
|
const { deleteStoredToken, serverKey } =
|
|
167
195
|
await import("../lib/mcp-oauth.js");
|
|
168
196
|
const ok = deleteStoredToken(url);
|
|
@@ -199,7 +227,7 @@ export function registerMcpCommand(program) {
|
|
|
199
227
|
}
|
|
200
228
|
if (rows.length === 0) {
|
|
201
229
|
logger.log(
|
|
202
|
-
chalk.gray("No MCP OAuth tokens. Run: cc mcp login <url>"),
|
|
230
|
+
chalk.gray("No MCP OAuth tokens. Run: cc mcp login <name|url>"),
|
|
203
231
|
);
|
|
204
232
|
return;
|
|
205
233
|
}
|
|
@@ -497,12 +525,13 @@ export function registerMcpCommand(program) {
|
|
|
497
525
|
|
|
498
526
|
const db = ctx.db.getDatabase();
|
|
499
527
|
const config = new MCPServerConfig(db);
|
|
528
|
+
const names = config.list().map((s) => s.name);
|
|
500
529
|
const removed = config.remove(name);
|
|
501
530
|
|
|
502
531
|
if (removed) {
|
|
503
532
|
logger.success(`MCP server "${name}" removed`);
|
|
504
533
|
} else {
|
|
505
|
-
logger.error(
|
|
534
|
+
logger.error(notFoundWithSuggestion(name, names, { noun: "Server" }));
|
|
506
535
|
}
|
|
507
536
|
|
|
508
537
|
await shutdown();
|
|
@@ -533,7 +562,10 @@ export function registerMcpCommand(program) {
|
|
|
533
562
|
const serverConfig = config.get(name);
|
|
534
563
|
|
|
535
564
|
if (!serverConfig) {
|
|
536
|
-
|
|
565
|
+
const names = config.list().map((s) => s.name);
|
|
566
|
+
logger.error(
|
|
567
|
+
`${notFoundWithSuggestion(name, names, { noun: "Server" })}. Use 'mcp add' first.`,
|
|
568
|
+
);
|
|
537
569
|
process.exit(1);
|
|
538
570
|
}
|
|
539
571
|
|
package/src/commands/pdh.js
CHANGED
|
@@ -23,11 +23,125 @@ import {
|
|
|
23
23
|
pdhLockDir,
|
|
24
24
|
diagnosePdh,
|
|
25
25
|
} from "../lib/pdh-bridge.js";
|
|
26
|
+
import { setupMcpFromConfig } from "../runtime/mcp-config.js";
|
|
27
|
+
import {
|
|
28
|
+
readFeedback,
|
|
29
|
+
summarizeFeedback,
|
|
30
|
+
} from "../lib/pdh-feedback-ledger.js";
|
|
26
31
|
|
|
27
32
|
function emit(obj) {
|
|
28
33
|
console.log(JSON.stringify(obj, null, 2));
|
|
29
34
|
}
|
|
30
35
|
|
|
36
|
+
/** Concatenate the text blocks of an MCP tool result, else null. */
|
|
37
|
+
function mcpResultText(r) {
|
|
38
|
+
if (!r) return null;
|
|
39
|
+
if (Array.isArray(r.content)) {
|
|
40
|
+
const t = r.content
|
|
41
|
+
.filter((b) => b && b.type === "text" && typeof b.text === "string")
|
|
42
|
+
.map((b) => b.text)
|
|
43
|
+
.join("");
|
|
44
|
+
if (t) return t;
|
|
45
|
+
}
|
|
46
|
+
if (typeof r.result === "string") return r.result;
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function safeDisconnectAll(out) {
|
|
51
|
+
try {
|
|
52
|
+
await out?.mcpClient?.disconnectAll?.();
|
|
53
|
+
} catch {
|
|
54
|
+
/* best-effort cleanup */
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Live connectivity probe for the discovered PDH bridge — the cc-side
|
|
60
|
+
* diagnostic the list/status/doctor inspectors lack: list/status/doctor only
|
|
61
|
+
* read lockfiles, this actually **connects** and verifies the server responds
|
|
62
|
+
* (discover → connect → `pdh_ping` round-trip → report). Best-effort; always
|
|
63
|
+
* disconnects. The result NEVER carries the bearer token. Injectable for tests.
|
|
64
|
+
*
|
|
65
|
+
* @returns {Promise<object>} { ok, stage, reason?, device?, port?, transport?,
|
|
66
|
+
* tools?, latencyMs?, pingAttempted?, pingOk?, pingText?, pingError? }
|
|
67
|
+
*/
|
|
68
|
+
export async function probePdhBridge(opts = {}, deps = {}) {
|
|
69
|
+
const env = opts.env || process.env;
|
|
70
|
+
const discover = deps.discoverPdhServer || discoverPdhServer;
|
|
71
|
+
const connect = deps.setupMcpFromConfig || setupMcpFromConfig;
|
|
72
|
+
const now = deps.now || (() => Date.now());
|
|
73
|
+
|
|
74
|
+
const lock = discover({ env });
|
|
75
|
+
if (!lock) {
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
stage: "discover",
|
|
79
|
+
reason: "no live PDH server discovered (run `cc pdh doctor`)",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const base = {
|
|
83
|
+
device: lock.device,
|
|
84
|
+
port: lock.port,
|
|
85
|
+
transport: lock.transport,
|
|
86
|
+
};
|
|
87
|
+
const cfg = pdhServerToMcpConfig(lock);
|
|
88
|
+
const start = now();
|
|
89
|
+
let out;
|
|
90
|
+
try {
|
|
91
|
+
out = await connect({ pdh: cfg }, { writeErr: () => {} });
|
|
92
|
+
} catch (err) {
|
|
93
|
+
return { ok: false, stage: "connect", reason: err.message, ...base };
|
|
94
|
+
}
|
|
95
|
+
const conn = (out.connected || []).find((c) => c.server === "pdh");
|
|
96
|
+
if (!conn) {
|
|
97
|
+
await safeDisconnectAll(out);
|
|
98
|
+
return {
|
|
99
|
+
ok: false,
|
|
100
|
+
stage: "connect",
|
|
101
|
+
reason: "server did not connect (no tools)",
|
|
102
|
+
...base,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// The bare tool names the bridge exposes (mcp__pdh__collect_files →
|
|
106
|
+
// collect_files), so the probe shows WHICH collectors a device advertises —
|
|
107
|
+
// confirming the bridge version/capabilities, not just a count.
|
|
108
|
+
const toolNames = (out.extraToolDefinitions || [])
|
|
109
|
+
.map((t) => t && t.function && t.function.name)
|
|
110
|
+
.filter((n) => typeof n === "string")
|
|
111
|
+
.map((n) =>
|
|
112
|
+
n.startsWith("mcp__pdh__") ? n.slice("mcp__pdh__".length) : n,
|
|
113
|
+
);
|
|
114
|
+
// Round-trip via pdh_ping when the bridge exposes it; otherwise the
|
|
115
|
+
// tools/list that connect already performed is itself proof of liveness.
|
|
116
|
+
const hasPing = toolNames.includes("pdh_ping");
|
|
117
|
+
let pingOk = null;
|
|
118
|
+
let pingText = null;
|
|
119
|
+
let pingError = null;
|
|
120
|
+
if (hasPing) {
|
|
121
|
+
try {
|
|
122
|
+
const r = await out.mcpClient.callTool("pdh", "pdh_ping", {});
|
|
123
|
+
pingOk = !r?.isError;
|
|
124
|
+
pingText = mcpResultText(r);
|
|
125
|
+
} catch (err) {
|
|
126
|
+
pingOk = false;
|
|
127
|
+
pingError = err.message;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
await safeDisconnectAll(out);
|
|
131
|
+
return {
|
|
132
|
+
ok: pingOk !== false, // connected; an attempted ping must not have failed
|
|
133
|
+
stage: "ping",
|
|
134
|
+
...base,
|
|
135
|
+
tools: conn.tools,
|
|
136
|
+
toolNames,
|
|
137
|
+
latencyMs: now() - start,
|
|
138
|
+
pingAttempted: hasPing,
|
|
139
|
+
pingOk,
|
|
140
|
+
pingText,
|
|
141
|
+
pingError,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
31
145
|
/** Strip the raw bearer token + internal _file path from a lock for output. */
|
|
32
146
|
function redactLock(lock) {
|
|
33
147
|
if (!lock) return null;
|
|
@@ -35,7 +149,8 @@ function redactLock(lock) {
|
|
|
35
149
|
return { ...rest, hasToken: !!token };
|
|
36
150
|
}
|
|
37
151
|
|
|
38
|
-
export function registerPdhCommand(program) {
|
|
152
|
+
export function registerPdhCommand(program, deps = {}) {
|
|
153
|
+
const probe = deps.probePdhBridge || probePdhBridge;
|
|
39
154
|
const pdh = program
|
|
40
155
|
.command("pdh")
|
|
41
156
|
.description(
|
|
@@ -158,5 +273,80 @@ export function registerPdhCommand(program) {
|
|
|
158
273
|
console.log(` reason : ${diag.reason}`);
|
|
159
274
|
});
|
|
160
275
|
|
|
276
|
+
pdh
|
|
277
|
+
.command("ping")
|
|
278
|
+
.description(
|
|
279
|
+
"Connect to the discovered PDH server and verify it responds (pdh_ping round-trip)",
|
|
280
|
+
)
|
|
281
|
+
.option("--json", "Machine-readable output")
|
|
282
|
+
.action(async (options) => {
|
|
283
|
+
const res = await probe({ env: process.env });
|
|
284
|
+
if (options.json) {
|
|
285
|
+
emit(res);
|
|
286
|
+
} else if (res.stage === "discover") {
|
|
287
|
+
console.log(
|
|
288
|
+
chalk.yellow("No PDH server discovered.") +
|
|
289
|
+
chalk.gray(" Run `cc pdh doctor` for why."),
|
|
290
|
+
);
|
|
291
|
+
} else if (!res.ok) {
|
|
292
|
+
console.log(
|
|
293
|
+
chalk.red(
|
|
294
|
+
`PDH ${res.device}:${res.port} — ${res.stage} failed: ` +
|
|
295
|
+
`${res.reason || res.pingError || "unknown"}`,
|
|
296
|
+
),
|
|
297
|
+
);
|
|
298
|
+
} else {
|
|
299
|
+
const tag = res.pingAttempted
|
|
300
|
+
? res.pingOk
|
|
301
|
+
? chalk.green("pong")
|
|
302
|
+
: chalk.red("ping failed")
|
|
303
|
+
: chalk.gray("connected (no pdh_ping tool)");
|
|
304
|
+
console.log(
|
|
305
|
+
`PDH ${chalk.cyan(res.device)}:${res.port} ${chalk.green("OK")} — ` +
|
|
306
|
+
`${tag}, ${res.tools} tools, ${res.latencyMs}ms`,
|
|
307
|
+
);
|
|
308
|
+
if (res.toolNames && res.toolNames.length) {
|
|
309
|
+
console.log(chalk.gray(" tools: " + res.toolNames.join(", ")));
|
|
310
|
+
}
|
|
311
|
+
if (res.pingText) console.log(chalk.gray(" " + res.pingText));
|
|
312
|
+
}
|
|
313
|
+
if (!res.ok) process.exitCode = 1;
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
pdh
|
|
317
|
+
.command("feedback")
|
|
318
|
+
.description(
|
|
319
|
+
"Show what cc has learned from your cross-session corrections (§3.5.13 flywheel)",
|
|
320
|
+
)
|
|
321
|
+
.option("--json", "Machine-readable output")
|
|
322
|
+
.action((options) => {
|
|
323
|
+
const read = deps.readFeedback || readFeedback;
|
|
324
|
+
const summarize = deps.summarizeFeedback || summarizeFeedback;
|
|
325
|
+
const summary = summarize(read());
|
|
326
|
+
if (options.json) {
|
|
327
|
+
emit(summary);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
// Honest empty state (§3.5.18: surface "尚无" truthfully, never hide).
|
|
331
|
+
if (!summary.total) {
|
|
332
|
+
console.log(
|
|
333
|
+
chalk.gray("尚无跨会话反馈记录 (no cross-session feedback yet)."),
|
|
334
|
+
);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
console.log(chalk.bold(`PDH 自学习反馈 (${summary.total} 条)`));
|
|
338
|
+
console.log(
|
|
339
|
+
` ${chalk.green("👍 " + summary.positive)} ` +
|
|
340
|
+
`${chalk.red("👎 " + summary.negative)} ` +
|
|
341
|
+
`净倾向 ${summary.sentiment >= 0 ? "+" : ""}${summary.sentiment}`,
|
|
342
|
+
);
|
|
343
|
+
if (summary.corrections.length) {
|
|
344
|
+
console.log(chalk.bold(" 已记住的纠正 (最新优先):"));
|
|
345
|
+
for (const c of summary.corrections) {
|
|
346
|
+
console.log(chalk.gray(` • ${c}`));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
161
351
|
return pdh;
|
|
162
352
|
}
|
package/src/constants.js
CHANGED
|
@@ -30,7 +30,7 @@ export const LLM_PROVIDERS = {
|
|
|
30
30
|
volcengine: {
|
|
31
31
|
name: "Volcengine (火山引擎/豆包)",
|
|
32
32
|
defaultBaseUrl: "https://ark.cn-beijing.volces.com/api/v3",
|
|
33
|
-
defaultModel: "doubao-seed-1-
|
|
33
|
+
defaultModel: "doubao-seed-2-1-pro-260628",
|
|
34
34
|
requiresApiKey: true,
|
|
35
35
|
},
|
|
36
36
|
openai: {
|
|
@@ -144,7 +144,7 @@ export const DEFAULT_CONFIG = {
|
|
|
144
144
|
provider: "volcengine",
|
|
145
145
|
apiKey: null,
|
|
146
146
|
baseUrl: "https://ark.cn-beijing.volces.com/api/v3",
|
|
147
|
-
model: "doubao-seed-1-
|
|
147
|
+
model: "doubao-seed-2-1-pro-260628",
|
|
148
148
|
// When true, `cc ask` (provider=ollama only) overrides baseUrl to point at
|
|
149
149
|
// the Android LocalLlmServer (127.0.0.1:18484). User opt-in toggle:
|
|
150
150
|
// cc config set llm.preferAndroidLocal true
|
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
* Route keys use dot-case: video.assets.list, video.deconstruct, etc.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import { createRequire } from "node:module";
|
|
12
|
+
// ESM module — `require` is not a global here. createRequire gives a working
|
|
13
|
+
// require() for the lazy loads below (VideoPipeline + node core modules, kept
|
|
14
|
+
// lazy so importing this protocol module doesn't pull the video stack on
|
|
15
|
+
// every `cc` startup). Node >=22.12 (our engines floor) supports require(esm).
|
|
16
|
+
const require = createRequire(import.meta.url);
|
|
17
|
+
|
|
11
18
|
function ok(data = {}) {
|
|
12
19
|
return { ok: true, ...data };
|
|
13
20
|
}
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
* - object { enabled, variant, description }
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
loadConfig,
|
|
13
|
+
getConfigValue,
|
|
14
|
+
saveConfig,
|
|
15
|
+
} from "../lib/config-manager.js";
|
|
16
|
+
import { withFileLock } from "../lib/with-file-lock.js";
|
|
17
|
+
import { getConfigPath } from "../lib/paths.js";
|
|
12
18
|
import { createHash } from "node:crypto";
|
|
13
19
|
import { hostname } from "node:os";
|
|
14
20
|
|
|
@@ -51,7 +57,8 @@ export function feature(name) {
|
|
|
51
57
|
if (value && typeof value === "object") return Boolean(value.enabled);
|
|
52
58
|
const defaultValue = _getDefault(name);
|
|
53
59
|
if (typeof defaultValue === "boolean") return defaultValue;
|
|
54
|
-
if (typeof defaultValue === "number")
|
|
60
|
+
if (typeof defaultValue === "number")
|
|
61
|
+
return _percentageCheck(name, defaultValue);
|
|
55
62
|
if (defaultValue && typeof defaultValue === "object") {
|
|
56
63
|
return Boolean(defaultValue.enabled);
|
|
57
64
|
}
|
|
@@ -106,10 +113,16 @@ export function listFeatures() {
|
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
export function setFeature(name, value) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
// Serialize the read-modify-write across processes so two concurrent
|
|
117
|
+
// `cc config features enable/disable` invocations don't clobber each other
|
|
118
|
+
// (and to space out writes so the atomic rename doesn't collide). Mirrors
|
|
119
|
+
// setConfigValue; the lock is best-effort and never hangs the CLI.
|
|
120
|
+
withFileLock(getConfigPath(), () => {
|
|
121
|
+
const config = loadConfig();
|
|
122
|
+
if (!config.features) config.features = {};
|
|
123
|
+
config.features[name] = value;
|
|
124
|
+
saveConfig(config);
|
|
125
|
+
});
|
|
113
126
|
}
|
|
114
127
|
|
|
115
128
|
export function getFlagInfo(name) {
|
package/src/lib/agent-core.js
CHANGED
|
@@ -37,7 +37,7 @@ export function saveConfig(config) {
|
|
|
37
37
|
const tmp = `${configPath}.${process.pid}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
38
38
|
try {
|
|
39
39
|
writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
40
|
-
|
|
40
|
+
renameWithRetry(tmp, configPath);
|
|
41
41
|
} catch (err) {
|
|
42
42
|
try {
|
|
43
43
|
if (existsSync(tmp)) unlinkSync(tmp);
|
|
@@ -48,6 +48,47 @@ export function saveConfig(config) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// On Windows, `rename` over a target that another process currently has open
|
|
52
|
+
// (e.g. a concurrent `loadConfig` reader) fails with EPERM/EACCES/EBUSY instead
|
|
53
|
+
// of POSIX's silent atomic replace. Under bursts of concurrent `cc config`/`cc
|
|
54
|
+
// config features` invocations this surfaced as a flaky exit-1. Retry the rename
|
|
55
|
+
// a few times with a short synchronous backoff so the transient lock clears;
|
|
56
|
+
// the temp file is already fully written, so this stays crash-safe.
|
|
57
|
+
export function renameWithRetry(tmp, target, opts = {}) {
|
|
58
|
+
const {
|
|
59
|
+
attempts = 8,
|
|
60
|
+
baseDelayMs = 15,
|
|
61
|
+
_rename = renameSync,
|
|
62
|
+
_sleep = sleepSync,
|
|
63
|
+
} = opts;
|
|
64
|
+
for (let i = 0; ; i++) {
|
|
65
|
+
try {
|
|
66
|
+
_rename(tmp, target);
|
|
67
|
+
return;
|
|
68
|
+
} catch (err) {
|
|
69
|
+
const transient =
|
|
70
|
+
err &&
|
|
71
|
+
(err.code === "EPERM" ||
|
|
72
|
+
err.code === "EACCES" ||
|
|
73
|
+
err.code === "EBUSY" ||
|
|
74
|
+
err.code === "EEXIST");
|
|
75
|
+
if (!transient || i >= attempts - 1) throw err;
|
|
76
|
+
_sleep(baseDelayMs * (i + 1));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function sleepSync(ms) {
|
|
82
|
+
try {
|
|
83
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
84
|
+
} catch {
|
|
85
|
+
const end = Date.now() + ms; // SharedArrayBuffer unavailable — bounded spin
|
|
86
|
+
while (Date.now() < end) {
|
|
87
|
+
/* spin */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
51
92
|
export function getConfigValue(key) {
|
|
52
93
|
const config = loadConfig();
|
|
53
94
|
return getNestedValue(config, key);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { execSync } from "child_process";
|
|
6
|
-
import { existsSync } from "fs";
|
|
6
|
+
import { existsSync, writeFileSync, chmodSync } from "fs";
|
|
7
7
|
import { join } from "path";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -236,7 +236,6 @@ export function installHooks(dir) {
|
|
|
236
236
|
echo "ChainlessChain: pre-commit hook running"
|
|
237
237
|
`;
|
|
238
238
|
|
|
239
|
-
const { writeFileSync, chmodSync } = require("fs");
|
|
240
239
|
writeFileSync(hookPath, hookContent, "utf-8");
|
|
241
240
|
try {
|
|
242
241
|
chmodSync(hookPath, 0o755);
|
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
* - Stateless — the trajectory ID is tracked on learningCtx
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import { createRequire } from "node:module";
|
|
20
|
+
// ESM module — `require` is not a global here. createRequire gives a working
|
|
21
|
+
// require() for the lazy TrajectoryStore load below (kept lazy to avoid a
|
|
22
|
+
// circular import). Node >=22.12 (our engines floor) supports require(esm).
|
|
23
|
+
const require = createRequire(import.meta.url);
|
|
24
|
+
|
|
19
25
|
/**
|
|
20
26
|
* @typedef {object} LearningContext
|
|
21
27
|
* @property {import("./trajectory-store.js").TrajectoryStore} trajectoryStore
|
package/src/lib/llm-providers.js
CHANGED
|
@@ -84,6 +84,8 @@ export const BUILT_IN_PROVIDERS = {
|
|
|
84
84
|
baseUrl: "https://ark.cn-beijing.volces.com/api/v3",
|
|
85
85
|
apiKeyEnv: "VOLCENGINE_API_KEY",
|
|
86
86
|
models: [
|
|
87
|
+
"doubao-seed-2-1-pro-260628",
|
|
88
|
+
"doubao-seed-2-0-lite-260215",
|
|
87
89
|
"doubao-seed-1-6-251015",
|
|
88
90
|
"doubao-seed-1-6-flash-250828",
|
|
89
91
|
"doubao-seed-1-6-lite-251015",
|