chainlesschain 0.162.115 → 0.162.117
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 +2 -2
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-Co3Wa2si.js → AIOps-D1_eyrEP.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CLu_iLWH.js → ActionButton-tnrMeU0Q.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BZM53XMx.js → Analytics-SmbOMqoN.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BvWMuVj5.js → AppLayout-B4m4Ic3a.js} +4 -4
- package/src/assets/web-panel/assets/{Audit-LnZR0-SB.js → Audit-DTC34Qp6.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-m1_KWvdD.js → Backup-CU_llIBF.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DCOyDzK5.js → BaseInput-vP66eF17.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BxctrF91.js → Chat-B8-4iHVJ.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CFD0Xh5e.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-CiI-q7XC.js → Checkbox-zV2Jzmv8.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Bs5RpmWs.js → Codegen-C7kfk-rY.js} +1 -1
- package/src/assets/web-panel/assets/{Col-By1dCa5E.js → Col-t_vUszuS.js} +1 -1
- package/src/assets/web-panel/assets/{Community-WuZZQrIQ.js → Community-pRCzzaCc.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Bgjv17zY.js → Compact-7IgSGjnW.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CANmPNTe.js → Compliance-BqDi7iuY.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-B5vtDpAA.js → Cowork-BL84ZaWT.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CD1EDrV4.js → Cron-yzv32Scr.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-C8VDvGgO.js → Crosschain-6DTzS8P5.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DpZV0N2H.js → DID-CKP63O4a.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-NhU8jHSF.js → Dashboard-CsV3eP9F.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-D-r8yZE9.js → Dropdown-CByjFKzJ.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DG89eV-l.js → EmailListRenderer-C6Hn7n75.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-G-b864Cs.js → FamilyGuardDashboard-e1c1vXTT.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-yBmOj1ob.js → Federation-D9oejCYY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cb7_kwNJ.js → FormItemContext-DZ4d_-AT.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DH-hOAyY.js → GenericCardRenderer-QoGFWBcP.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DsxDUo_n.js → Git-DVZHPXw8.js} +2 -2
- package/src/assets/web-panel/assets/Governance-NwdvDPTB.js +1 -0
- package/src/assets/web-panel/assets/{Inference-BBp_JKRI.js → Inference-BYz9MiEu.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Dh1Hy3KR.js → KnowledgeGraph-BUdGIZKt.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B4dKW6iL.js → Logs-CPGewhlD.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-BwG7IJMb.js → Marketplace-BgRk4ZMW.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Bkem_Aad.js → McpTools-DLY9Fd7m.js} +5 -5
- package/src/assets/web-panel/assets/{Memory--XBiW9hE.js → Memory-B2QishHE.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Cw3bfWS4.js → MobileBridge-DXMQwB_y.js} +2 -2
- package/src/assets/web-panel/assets/{MobileProjects-DxtImZQU.js → MobileProjects-4uY4YbFm.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BGF20OtO.js → Mtc-BVASCKUv.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-D7z4gsQ5.js → MtcAudit-ByLFJ4Zu.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-yXwos6j_.js → Multisig-DRAZYcC6.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CDHJQX6y.js → NLProgramming-EiptSKn1.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-D39k9gda.js → Notes-BHh5Akqh.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-DRPq8tRI.js → NotificationSettings-XWFl4_3j.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-D2hEsaLV.js → OrderTableRenderer-Bdc_O7wT.js} +1 -1
- package/src/assets/web-panel/assets/{Organization--o8Lvsg2.js → Organization--VWlMdKp.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-D2ohI9Qx.js → Overflow-DuYUvyh7.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-2c8cEXWp.js → P2P-BnHaPvFP.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-D7NaNkzj.js → PdhVaultBrowser-WfbjffWL.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-ypORwVpA.js → Permissions-BIFhAsZO.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CwGL8rYc.js → PersonalDataHub-Dt_m7YZ6.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-sOxtzc6E.js → Pipeline-BsNDbhs7.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DQn-uEJl.js → Privacy-C1SJp30I.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-8C5fy5dR.js → ProjectInit-DIOkwlK-.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CX_i2PB9.js → ProjectSettings-BZIL8hvl.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-CHTItBCE.js → Projects-LHqWtiu2.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-hTVigloe.js → Providers-DlC7SSJT.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BqHj37NO.js → QuickAsk-DeaVcEma.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-W6Fz6lz7.js → Recommend-BbQI1g_u.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-BgEa2pxb.js → Reputation-Cro6z2uR.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DyIFWI6T.js → Row-D7LuPQVP.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CEYCVpMw.js → RssFeed-BowXZJOX.js} +3 -3
- package/src/assets/web-panel/assets/{Search-zVLBmQ7o.js → Search-8oufqOmB.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CqsG8Ps9.js → Security-CRKFB58y.js} +3 -3
- package/src/assets/web-panel/assets/{Services-BfBS_Jgz.js → Services-DzRJ4Kus.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Soo_Vk86.js → Skeleton-DtZmLaQr.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-PuZUk7l4.js → Skills-CPQFZvJ3.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CyXFxluF.js → Sla-C599OilU.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Bix3Aslu.js → SpeechSettings-VdhwHyYN.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CIpNxBVI.js → SyncSettings-BvX8fTlf.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-S3P_gUGK.js → Tasks-B63Y5zWj.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-ApPjFp6V.js → Templates-DZtjohnP.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CA39QBQx.js → Tenant-C8WHv74j.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-D0IC-PsM.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-BH_bLWth.js → TimelineRenderer-C392mTJ7.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CnM7BBQo.js → Tokens-BnmIK-7p.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BaTkvjag.js → Trigger-CLYUm45n.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BL5_D9F2.js → Trust-DmKkB9n0.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-RL5tPg28.js → UkeySign-Btsb1cq9.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DpziQ6j6.js → VideoEditing-KbSQiQ31.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-C5TJX6y1.js → Wallet-C7T1JpB8.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BRmIn8F_.js → WebAuthn-B7fk675F.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Dcq3e-ik.js → WorkflowEditor-BFEqg2-F.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CIxM8WKc.js → chat-CCONImPU.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C4KulwfK.js → colors-BO_usQco.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BuSPdvu3.js → compact-item-DPYH8VmY.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DnkNir9Q.js → createContext-DuzinRx4.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BJYFLmEO.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Cf4nLc1Z.js → hasIn-CGE1laax.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeV7mBjK.js → index-B5edbioK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLj6Tgel.js → index-B6faWLbM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdA5Ua1b.js → index-BBdlh4S9.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3K7gFx4.js → index-BJrz4R1Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUZ5Kool.js → index-BMvB7bwt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CIMAqOlD.js → index-BOrH71r5.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0Mg9TNh.js → index-BQieJh3P.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeMVCFm4.js → index-BhhReyyv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bxrdsatm.js → index-BoiTovAz.js} +1 -1
- package/src/assets/web-panel/assets/{index-E9E5_8nm.js → index-BxSrpYMm.js} +1 -1
- package/src/assets/web-panel/assets/index-BznL1yIS.js +1 -0
- package/src/assets/web-panel/assets/{index-DXmlFKkG.js → index-C0J2olcT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrjJWis4.js → index-C4OJtXb2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGVc7PRP.js → index-C6ORJpUJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKxfssGi.js → index-C8E575em.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlHHHyRx.js → index-C9a-SDrB.js} +3 -3
- package/src/assets/web-panel/assets/{index-BSSHH2wV.js → index-CCFBPPL3.js} +1 -1
- package/src/assets/web-panel/assets/{index-BixeTMRH.js → index-CFMqyOfS.js} +1 -1
- package/src/assets/web-panel/assets/{index-yzjY8Axn.js → index-CHBCKhGQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-LeyWnzub.js → index-CLevxAAl.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyWheeVw.js → index-CiJrDiUF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CBAXN3jR.js → index-Cjl3wd7u.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClY2B2K3.js → index-CsWempjh.js} +1 -1
- package/src/assets/web-panel/assets/{index-Djm5GtZl.js → index-CyNkEBra.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhJdIewr.js → index-CzJpaaYk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiSVvB5h.js → index-D7PjxVkg.js} +1 -1
- package/src/assets/web-panel/assets/{index-EdjA-3Bc.js → index-DEsKGcgq.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6_QgZN5.js → index-DFeaJhkI.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cq1Fi_sP.js → index-DPLKoezy.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjRLVmY5.js → index-DcDzDXuF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWDu1oDR.js → index-DhWFRGxq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkuD99JZ.js → index-Djr_9TsG.js} +1 -1
- package/src/assets/web-panel/assets/{index-xUqyfQDD.js → index-Dr_bswHZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bz60EXNV.js → index-Njlbk8o6.js} +1 -1
- package/src/assets/web-panel/assets/index-SDk3qvNU.js +1 -0
- package/src/assets/web-panel/assets/{index-Ch5ijBA1.js → index-VjWPHPNA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZrWQUeU.js → index-WNRdmI1g.js} +1 -1
- package/src/assets/web-panel/assets/{index-N1ncDYAO.js → index-_6PfzLBb.js} +1 -1
- package/src/assets/web-panel/assets/{index-2EWeBL-U.js → index-k_kmmJE3.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps--8dT0H6B.js → initDefaultProps-V7_xvS9N.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D90Oz3kN.js → motion-DRGZ-HPK.js} +1 -1
- package/src/assets/web-panel/assets/{move-CXTvl7NU.js → move-CZrcQSMV.js} +1 -1
- package/src/assets/web-panel/assets/{omit-0trPxlmr.js → omit-pd-_NH99.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CgAAFR7h.js → pickAttrs-CTupbn-v.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CS-hpoJS.js → placementArrow-Bn7FYxHg.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-9S3fBAtz.js → responsiveObserve-WfzZR_7N.js} +1 -1
- package/src/assets/web-panel/assets/{slide-B-R8yXs_.js → slide-CYH80N3q.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DQiprWuZ.js → statusUtils-C4hqTJzV.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-02H_AFJW.js → styleChecker-BQyUObAw.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-9DGfLuf2.js → useFlexGapSupport-BGDH_gNt.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CrPyzwar.js → useFs-D_3Y1Yh6.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BeLgaZq9.js → usePersonalDataHub-vnU0oI0p.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Cln6ZUUD.js → vnode-DnTqtAMj.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BauTGPPs.js → zoom-ChHcZlUk.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/hub.js +163 -2
- package/src/harness/mcp-client.js +17 -0
- package/src/lib/checkpoint-store.js +42 -5
- package/src/lib/cost-budget.js +14 -1
- package/src/lib/cross-chain-mtc.js +17 -0
- package/src/lib/dlp-engine.js +3 -1
- package/src/lib/hook-runner.cjs +35 -6
- package/src/lib/loop.js +16 -9
- package/src/lib/permission-rules.cjs +6 -2
- package/src/lib/skill-loader.js +9 -0
- package/src/lib/web-fetch.js +33 -4
- package/src/repl/agent-repl.js +12 -0
- package/src/runtime/headless-runner.js +14 -0
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Cr-ifTsG.js +0 -1
- package/src/assets/web-panel/assets/Governance-9tswXx9m.js +0 -1
- package/src/assets/web-panel/assets/Terminal-CZCQVy4D.js +0 -3
- package/src/assets/web-panel/assets/devWarning-CMQKGI8R.js +0 -1
- package/src/assets/web-panel/assets/index-D1b1GHRk.js +0 -1
- package/src/assets/web-panel/assets/index-DGZzQZUz.js +0 -1
package/src/commands/hub.js
CHANGED
|
@@ -1114,9 +1114,13 @@ async function cmdCollectQq(options) {
|
|
|
1114
1114
|
`qqnt-dec-${process.pid}.db`,
|
|
1115
1115
|
);
|
|
1116
1116
|
fs.writeFileSync(tmp, result.decrypted);
|
|
1117
|
-
let
|
|
1117
|
+
let parsed;
|
|
1118
1118
|
try {
|
|
1119
|
-
|
|
1119
|
+
// selfUid = the matched account uid → reliable self attribution.
|
|
1120
|
+
parsed = qq.parseEvents(Database, tmp, {
|
|
1121
|
+
selfUid: result.uid,
|
|
1122
|
+
self: options.self || "self",
|
|
1123
|
+
});
|
|
1120
1124
|
} finally {
|
|
1121
1125
|
try {
|
|
1122
1126
|
fs.unlinkSync(tmp);
|
|
@@ -1124,7 +1128,24 @@ async function cmdCollectQq(options) {
|
|
|
1124
1128
|
/* best-effort wipe */
|
|
1125
1129
|
}
|
|
1126
1130
|
}
|
|
1131
|
+
const events = Array.isArray(parsed) ? parsed : parsed.events || [];
|
|
1132
|
+
const persons = Array.isArray(parsed) ? [] : parsed.persons || [];
|
|
1133
|
+
const topics = Array.isArray(parsed) ? [] : parsed.topics || [];
|
|
1127
1134
|
|
|
1135
|
+
for (const p of persons) {
|
|
1136
|
+
try {
|
|
1137
|
+
vault.putPerson(p);
|
|
1138
|
+
} catch {
|
|
1139
|
+
/* dup / optional */
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
for (const t of topics) {
|
|
1143
|
+
try {
|
|
1144
|
+
if (typeof vault.putTopic === "function") vault.putTopic(t);
|
|
1145
|
+
} catch {
|
|
1146
|
+
/* dup / optional */
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1128
1149
|
let ingested = 0;
|
|
1129
1150
|
for (const ev of events) {
|
|
1130
1151
|
try {
|
|
@@ -1139,6 +1160,8 @@ async function cmdCollectQq(options) {
|
|
|
1139
1160
|
matchedUid: result.uid,
|
|
1140
1161
|
kdf: result.kdf,
|
|
1141
1162
|
messages: events.length,
|
|
1163
|
+
persons: persons.length,
|
|
1164
|
+
topics: topics.length,
|
|
1142
1165
|
ingested,
|
|
1143
1166
|
};
|
|
1144
1167
|
if (spinner) spinner.succeed(`collect-qq: ${ingested} QQ messages → vault`);
|
|
@@ -1380,6 +1403,121 @@ async function cmdCollectWechat(options) {
|
|
|
1380
1403
|
}
|
|
1381
1404
|
}
|
|
1382
1405
|
|
|
1406
|
+
// ─── collect-qzone (QQ空间 说说/留言板/相册 via API → vault) ──────────────
|
|
1407
|
+
//
|
|
1408
|
+
// module 101 — Qzone has no local DB, so this is the cookie+g_tk API path. The
|
|
1409
|
+
// Android in-app WebView (or a desktop browser) captures the qzone-domain
|
|
1410
|
+
// p_skey cookie; this derives g_tk and pulls the owner's feeds. The cookie is
|
|
1411
|
+
// passed via --cookie or --cookie-file (kept out of argv/history when staged).
|
|
1412
|
+
async function cmdCollectQzone(options) {
|
|
1413
|
+
const spinner = options.json
|
|
1414
|
+
? null
|
|
1415
|
+
: ora("collect-qzone (API + ingest)...").start();
|
|
1416
|
+
try {
|
|
1417
|
+
const { createRequire } = await import("module");
|
|
1418
|
+
const require = createRequire(import.meta.url);
|
|
1419
|
+
const fs = require("fs");
|
|
1420
|
+
const qz = options._qzoneCore
|
|
1421
|
+
? options._qzoneCore
|
|
1422
|
+
: await importPdh(
|
|
1423
|
+
"@chainlesschain/personal-data-hub/forensics/qzone-collect",
|
|
1424
|
+
);
|
|
1425
|
+
let cookie = options.cookie;
|
|
1426
|
+
if (!cookie && options.cookieFile && fs.existsSync(options.cookieFile))
|
|
1427
|
+
cookie = fs.readFileSync(options.cookieFile, "utf8").trim();
|
|
1428
|
+
if (!cookie)
|
|
1429
|
+
throw new Error(
|
|
1430
|
+
'need --cookie "<qzone cookie>" or --cookie-file <path> (must contain uin + p_skey)',
|
|
1431
|
+
);
|
|
1432
|
+
const what = (options.what || "shuoshuo,msgb,album")
|
|
1433
|
+
.split(",")
|
|
1434
|
+
.map((s) => s.trim())
|
|
1435
|
+
.filter(Boolean);
|
|
1436
|
+
const max = Number.isFinite(+options.max) ? +options.max : 1000;
|
|
1437
|
+
|
|
1438
|
+
const result = await qz.collectQzone({
|
|
1439
|
+
uin: options.uin,
|
|
1440
|
+
cookie,
|
|
1441
|
+
what,
|
|
1442
|
+
max,
|
|
1443
|
+
fetchImpl: options._fetch,
|
|
1444
|
+
});
|
|
1445
|
+
if (!result.ok) {
|
|
1446
|
+
const report = { ok: false, reason: result.reason };
|
|
1447
|
+
if (options.json) {
|
|
1448
|
+
jsonAndExit(report);
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
if (spinner) spinner.fail(`collect-qzone: ${result.reason}`);
|
|
1452
|
+
process.exit(2);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
const hub = await (options._getHub || getHub)();
|
|
1456
|
+
const vault = hub.vault;
|
|
1457
|
+
try {
|
|
1458
|
+
vault.putPerson({
|
|
1459
|
+
type: "person",
|
|
1460
|
+
subtype: "contact",
|
|
1461
|
+
id: qz.SELF_ID,
|
|
1462
|
+
names: ["我(QQ空间)"],
|
|
1463
|
+
source: {
|
|
1464
|
+
adapter: "qzone",
|
|
1465
|
+
adapterVersion: "0.1.0",
|
|
1466
|
+
originalId: qz.SELF_ID,
|
|
1467
|
+
capturedAt: Date.now(),
|
|
1468
|
+
capturedBy: "api",
|
|
1469
|
+
},
|
|
1470
|
+
ingestedAt: Date.now(),
|
|
1471
|
+
});
|
|
1472
|
+
} catch {
|
|
1473
|
+
/* dup */
|
|
1474
|
+
}
|
|
1475
|
+
for (const p of result.persons) {
|
|
1476
|
+
try {
|
|
1477
|
+
vault.putPerson(p);
|
|
1478
|
+
} catch {
|
|
1479
|
+
/* dup */
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
let ingested = 0;
|
|
1483
|
+
for (const ev of result.events) {
|
|
1484
|
+
try {
|
|
1485
|
+
vault.putEvent(ev);
|
|
1486
|
+
ingested++;
|
|
1487
|
+
} catch {
|
|
1488
|
+
/* dup */
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
const report = {
|
|
1493
|
+
ok: true,
|
|
1494
|
+
uin: result.uin,
|
|
1495
|
+
counts: result.counts,
|
|
1496
|
+
events: result.events.length,
|
|
1497
|
+
persons: result.persons.length,
|
|
1498
|
+
ingested,
|
|
1499
|
+
};
|
|
1500
|
+
if (spinner)
|
|
1501
|
+
spinner.succeed(
|
|
1502
|
+
`collect-qzone: ${ingested} events → vault (${Object.entries(
|
|
1503
|
+
result.counts,
|
|
1504
|
+
)
|
|
1505
|
+
.map(([k, v]) => k + ":" + v)
|
|
1506
|
+
.join(" ")})`,
|
|
1507
|
+
);
|
|
1508
|
+
if (options.json) {
|
|
1509
|
+
jsonAndExit(report);
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
logger.log(chalk.green("✓ Qzone collect succeeded"));
|
|
1513
|
+
logger.log(` counts: ${JSON.stringify(result.counts)}`);
|
|
1514
|
+
logger.log(` ingested: ${ingested}`);
|
|
1515
|
+
process.exit(0);
|
|
1516
|
+
} catch (err) {
|
|
1517
|
+
fail(spinner, err, options.json);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1383
1521
|
// ─── Phase 10.3 — cc hub aichat <verb> wizard subcommand surface ─────
|
|
1384
1522
|
//
|
|
1385
1523
|
// Mirrors the WS topics (personal-data-hub.aichat-*) so scripts and the
|
|
@@ -3188,6 +3326,29 @@ export function registerHubCommand(program) {
|
|
|
3188
3326
|
.option("--json", "Output JSON")
|
|
3189
3327
|
.action(cmdCollectWechat);
|
|
3190
3328
|
|
|
3329
|
+
hub
|
|
3330
|
+
.command("collect-qzone")
|
|
3331
|
+
.description(
|
|
3332
|
+
"QQ空间 (Qzone): collect 说说/留言板/相册 via the Qzone CGI API. No local DB — needs the qzone-domain p_skey cookie (from the in-app WebView or a browser login to user.qzone.qq.com; base .qq.com skey is rejected). Derives g_tk from p_skey and ingests as post/message/media events.",
|
|
3333
|
+
)
|
|
3334
|
+
.option(
|
|
3335
|
+
"--cookie <cookie>",
|
|
3336
|
+
"Qzone cookie string (must contain uin + p_skey)",
|
|
3337
|
+
)
|
|
3338
|
+
.option(
|
|
3339
|
+
"--cookie-file <path>",
|
|
3340
|
+
"File holding the cookie (preferred — keeps it out of argv)",
|
|
3341
|
+
)
|
|
3342
|
+
.option("--uin <uin>", "Account uin (else parsed from cookie)")
|
|
3343
|
+
.option(
|
|
3344
|
+
"--what <list>",
|
|
3345
|
+
"Comma list: shuoshuo,msgb,album (default all)",
|
|
3346
|
+
"shuoshuo,msgb,album",
|
|
3347
|
+
)
|
|
3348
|
+
.option("--max <n>", "Max items per source", "1000")
|
|
3349
|
+
.option("--json", "Output JSON")
|
|
3350
|
+
.action(cmdCollectQzone);
|
|
3351
|
+
|
|
3191
3352
|
hub
|
|
3192
3353
|
.command("event-detail <eventId>")
|
|
3193
3354
|
.description(
|
|
@@ -347,6 +347,23 @@ export class MCPClient extends EventEmitter {
|
|
|
347
347
|
};
|
|
348
348
|
} catch (err) {
|
|
349
349
|
entry.state = ServerState.ERROR;
|
|
350
|
+
// A stdio child spawned above but failed to initialize (handshake
|
|
351
|
+
// timeout / broken pipe / non-MCP command) would otherwise leak: we
|
|
352
|
+
// delete the entry from `this.servers` below, so disconnect() can never
|
|
353
|
+
// reach it, and an alive-but-unresponsive process fires neither `close`
|
|
354
|
+
// nor `error` — it would run orphaned with its stdio listeners bound for
|
|
355
|
+
// the lifetime of the CLI. Tear it down on the way out (best-effort;
|
|
356
|
+
// never mask the original connect error).
|
|
357
|
+
if (entry.process) {
|
|
358
|
+
try {
|
|
359
|
+
entry.process.stdout?.removeAllListeners();
|
|
360
|
+
entry.process.stderr?.removeAllListeners();
|
|
361
|
+
entry.process.removeAllListeners();
|
|
362
|
+
entry.process.kill();
|
|
363
|
+
} catch {
|
|
364
|
+
// teardown is best-effort — the connect error is what matters
|
|
365
|
+
}
|
|
366
|
+
}
|
|
350
367
|
this.servers.delete(name);
|
|
351
368
|
throw err;
|
|
352
369
|
}
|
|
@@ -91,6 +91,36 @@ function tempIndexPath(dir) {
|
|
|
91
91
|
return path.join(dir, `cc-checkpoint-index-${process.pid}-${Date.now()}`);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
/**
|
|
95
|
+
* rmSync that never throws. Used for best-effort teardown (temp index files,
|
|
96
|
+
* created-since files) so a transient unlink failure — e.g. a Windows file
|
|
97
|
+
* lock (EBUSY/EPERM) on the temp index — can't mask the operation's real
|
|
98
|
+
* result. Without this, a `finally { rmSync(tmpIndex) }` could turn a
|
|
99
|
+
* *successful* checkpoint into a thrown error, or replace the original git
|
|
100
|
+
* error with the cleanup error.
|
|
101
|
+
*/
|
|
102
|
+
function rmQuiet(target) {
|
|
103
|
+
try {
|
|
104
|
+
rmSync(target, { force: true });
|
|
105
|
+
} catch {
|
|
106
|
+
/* best-effort cleanup — the operation's real result is what matters */
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* True if `abs` is the repo root or lives inside it (containment guard).
|
|
112
|
+
* Both sides go through path.resolve so the comparison is robust to separator
|
|
113
|
+
* style — `repoRoot()` comes from `git rev-parse --show-toplevel` with forward
|
|
114
|
+
* slashes, while path.resolve yields native (backslash) paths on Windows.
|
|
115
|
+
*/
|
|
116
|
+
export function withinRoot(root, abs) {
|
|
117
|
+
const r = path.resolve(root);
|
|
118
|
+
const a = path.resolve(abs);
|
|
119
|
+
if (a === r) return true;
|
|
120
|
+
const prefix = r.endsWith(path.sep) ? r : r + path.sep;
|
|
121
|
+
return a.startsWith(prefix);
|
|
122
|
+
}
|
|
123
|
+
|
|
94
124
|
/**
|
|
95
125
|
* Snapshot the current working tree to a git tree object WITHOUT creating a
|
|
96
126
|
* commit and WITHOUT touching the real index. Returns the tree sha.
|
|
@@ -107,7 +137,7 @@ function snapshotTree(root, dir) {
|
|
|
107
137
|
git(["add", "-A"], { cwd: root, env });
|
|
108
138
|
return git(["write-tree"], { cwd: root, env });
|
|
109
139
|
} finally {
|
|
110
|
-
|
|
140
|
+
rmQuiet(tmpIndex);
|
|
111
141
|
}
|
|
112
142
|
}
|
|
113
143
|
|
|
@@ -228,7 +258,7 @@ export function createCheckpoint(cwd = process.cwd(), opts = {}) {
|
|
|
228
258
|
|
|
229
259
|
return { id, ref, commit, tree, parent, label, session, createdAt, files };
|
|
230
260
|
} finally {
|
|
231
|
-
|
|
261
|
+
rmQuiet(tmpIndex);
|
|
232
262
|
}
|
|
233
263
|
}
|
|
234
264
|
|
|
@@ -380,12 +410,19 @@ export function rewindTo(cwd = process.cwd(), idOrRef, opts = {}) {
|
|
|
380
410
|
git(["read-tree", targetTree], { cwd: root, env });
|
|
381
411
|
git(["checkout-index", "-a", "-f"], { cwd: root, env });
|
|
382
412
|
} finally {
|
|
383
|
-
|
|
413
|
+
rmQuiet(tmpIndex);
|
|
384
414
|
}
|
|
385
415
|
|
|
386
|
-
// Remove files the target snapshot does not contain (created since).
|
|
416
|
+
// Remove files the target snapshot does not contain (created since). These
|
|
417
|
+
// paths come from git's tree diff (repo-relative, git rejects `..` in tree
|
|
418
|
+
// entries), but this is a force-delete over the user's working tree — guard
|
|
419
|
+
// each resolved path against the repo root before unlinking, as
|
|
420
|
+
// defense-in-depth, and keep it best-effort so one locked file can't abort
|
|
421
|
+
// the whole rewind.
|
|
387
422
|
for (const rel of added) {
|
|
388
|
-
|
|
423
|
+
const abs = path.resolve(root, rel);
|
|
424
|
+
if (!withinRoot(root, abs)) continue; // never delete outside the repo
|
|
425
|
+
rmQuiet(abs);
|
|
389
426
|
}
|
|
390
427
|
|
|
391
428
|
return {
|
package/src/lib/cost-budget.js
CHANGED
|
@@ -62,14 +62,27 @@ export class CostBudget {
|
|
|
62
62
|
* @returns {object} the estimateCost() result for this record
|
|
63
63
|
*/
|
|
64
64
|
add({ provider, model, usage } = {}) {
|
|
65
|
+
// Prompt-cache tokens are billed too — cache CREATION at ~125% of the input
|
|
66
|
+
// rate (Anthropic), cache READ at 10–50%. The usage events carry
|
|
67
|
+
// cache_read_input_tokens / cache_creation_input_tokens, and `cc cost`
|
|
68
|
+
// already prices them; the hard --max-budget-usd cap must count them as well
|
|
69
|
+
// or it undercounts real spend on a cached Anthropic run and stops too late.
|
|
70
|
+
const cacheReadTokens = usage?.cache_read_input_tokens || 0;
|
|
71
|
+
const cacheCreationTokens = usage?.cache_creation_input_tokens || 0;
|
|
65
72
|
const est = estimateCost({
|
|
66
73
|
provider,
|
|
67
74
|
model,
|
|
68
75
|
inputTokens: usage?.input_tokens || 0,
|
|
69
76
|
outputTokens: usage?.output_tokens || 0,
|
|
77
|
+
cacheReadTokens,
|
|
78
|
+
cacheCreationTokens,
|
|
70
79
|
table: this.table,
|
|
71
80
|
});
|
|
72
|
-
const tokens =
|
|
81
|
+
const tokens =
|
|
82
|
+
(usage?.input_tokens || 0) +
|
|
83
|
+
(usage?.output_tokens || 0) +
|
|
84
|
+
cacheReadTokens +
|
|
85
|
+
cacheCreationTokens;
|
|
73
86
|
if (est.free) {
|
|
74
87
|
this.sawFree = true;
|
|
75
88
|
} else if (est.matched) {
|
|
@@ -749,6 +749,16 @@ export function verifyMultisigProvenance(envelope, policy) {
|
|
|
749
749
|
if (prov.signers.length !== prov.partial_sigs.length) {
|
|
750
750
|
return { ok: false, code: "SIGNERS_SIGS_LENGTH_MISMATCH" };
|
|
751
751
|
}
|
|
752
|
+
// A group of N members cannot produce more than N distinct signers; a
|
|
753
|
+
// provenance that lists more is self-inconsistent (and, without a
|
|
754
|
+
// policy.members roster below, would otherwise pass).
|
|
755
|
+
if (prov.signers.length > prov.member_count_n) {
|
|
756
|
+
return {
|
|
757
|
+
ok: false,
|
|
758
|
+
code: "TOO_MANY_SIGNERS",
|
|
759
|
+
detail: `${prov.signers.length} > ${prov.member_count_n}`,
|
|
760
|
+
};
|
|
761
|
+
}
|
|
752
762
|
const requiredM =
|
|
753
763
|
policy && Number.isInteger(policy.m) ? policy.m : prov.threshold_m;
|
|
754
764
|
if (prov.partial_sigs.length < requiredM) {
|
|
@@ -764,6 +774,13 @@ export function verifyMultisigProvenance(envelope, policy) {
|
|
|
764
774
|
return { ok: false, code: "SIGNERS_NOT_SORTED" };
|
|
765
775
|
}
|
|
766
776
|
}
|
|
777
|
+
// Signers must be distinct: duplicates (e.g. ["a","a","a"]) would otherwise
|
|
778
|
+
// let a single member meet an M-of-N threshold by repeating themselves.
|
|
779
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
780
|
+
if (sorted[i] === sorted[i - 1]) {
|
|
781
|
+
return { ok: false, code: "DUPLICATE_SIGNER", detail: sorted[i] };
|
|
782
|
+
}
|
|
783
|
+
}
|
|
767
784
|
const allowed =
|
|
768
785
|
policy && Array.isArray(policy.members)
|
|
769
786
|
? new Set(policy.members.map((m) => m.did))
|
package/src/lib/dlp-engine.js
CHANGED
|
@@ -193,7 +193,9 @@ export function listIncidents(filter = {}) {
|
|
|
193
193
|
if (filter.severity) {
|
|
194
194
|
incidents = incidents.filter((i) => i.severity === filter.severity);
|
|
195
195
|
}
|
|
196
|
-
if (filter.resolved ===
|
|
196
|
+
if (filter.resolved === true) {
|
|
197
|
+
incidents = incidents.filter((i) => !!i.resolvedAt);
|
|
198
|
+
} else if (filter.resolved === false) {
|
|
197
199
|
incidents = incidents.filter((i) => !i.resolvedAt);
|
|
198
200
|
}
|
|
199
201
|
const limit = filter.limit || 50;
|
package/src/lib/hook-runner.cjs
CHANGED
|
@@ -31,16 +31,30 @@ const HOOK_DECISIONS = Object.freeze({
|
|
|
31
31
|
CONTINUE: "continue",
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
+
/** JSON.parse that returns undefined (not throws) on failure. */
|
|
35
|
+
function tryJson(text) {
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(text);
|
|
38
|
+
} catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
34
43
|
/** Parse a hook's stdout JSON into a normalized decision, or null if not JSON. */
|
|
35
44
|
function tryParseDecision(stdout) {
|
|
36
45
|
const text = String(stdout || "").trim();
|
|
37
46
|
if (!text || text[0] !== "{") return null;
|
|
38
|
-
let obj;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
let obj = tryJson(text);
|
|
48
|
+
if (obj === undefined) {
|
|
49
|
+
// A hook that emits its decision as a JSON line followed by diagnostics
|
|
50
|
+
// (`{"decision":"block"}\n…log lines…`) would fail a whole-text parse, so
|
|
51
|
+
// the documented JSON-to-block pattern would be silently dropped and the
|
|
52
|
+
// tool would proceed. Recover the decision from the first line. (Pure
|
|
53
|
+
// pretty-printed JSON still parses via the whole-text attempt above.)
|
|
54
|
+
const firstLine = text.split("\n", 1)[0].trim();
|
|
55
|
+
if (firstLine && firstLine[0] === "{") obj = tryJson(firstLine);
|
|
43
56
|
}
|
|
57
|
+
if (obj === undefined || obj === null || typeof obj !== "object") return null;
|
|
44
58
|
// PreToolUse-specific permission decision
|
|
45
59
|
const hso = obj.hookSpecificOutput;
|
|
46
60
|
if (hso && hso.permissionDecision) {
|
|
@@ -148,7 +162,22 @@ function runCommandHook(command, input = {}, opts = {}) {
|
|
|
148
162
|
if (exitCode === 0) {
|
|
149
163
|
const parsed = tryParseDecision(stdout);
|
|
150
164
|
if (parsed) return { ...parsed, exitCode, stdout, stderr };
|
|
151
|
-
|
|
165
|
+
// stdout that *looks* like a decision (`{`-leading) but parses as neither
|
|
166
|
+
// whole-text nor first-line JSON is most likely a corrupt/truncated
|
|
167
|
+
// decision — don't swallow it silently (a block hook could be neutered).
|
|
168
|
+
// The exit code (0) still governs the flow (continue), but flag it so the
|
|
169
|
+
// caller/logs can surface the misconfiguration.
|
|
170
|
+
const looksLikeDecision = stdout.trim()[0] === "{";
|
|
171
|
+
return {
|
|
172
|
+
decision: HOOK_DECISIONS.CONTINUE,
|
|
173
|
+
reason: looksLikeDecision
|
|
174
|
+
? "hook stdout looked like a decision but did not parse as JSON"
|
|
175
|
+
: null,
|
|
176
|
+
exitCode,
|
|
177
|
+
stdout,
|
|
178
|
+
stderr,
|
|
179
|
+
...(looksLikeDecision ? { malformedDecision: true } : {}),
|
|
180
|
+
};
|
|
152
181
|
}
|
|
153
182
|
// Other non-zero → non-blocking error.
|
|
154
183
|
return {
|
package/src/lib/loop.js
CHANGED
|
@@ -108,15 +108,22 @@ export function makeSleep(signal) {
|
|
|
108
108
|
// process alive between rounds. Under a TTY the active stdin would mask
|
|
109
109
|
// an unref'd timer, but headless (piped stdin / CI / cron) the loop would
|
|
110
110
|
// exit after the first round. SIGINT aborts the wait via the signal.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
()
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
let t;
|
|
112
|
+
const onAbort = () => {
|
|
113
|
+
clearTimeout(t);
|
|
114
|
+
resolve();
|
|
115
|
+
};
|
|
116
|
+
t = setTimeout(() => {
|
|
117
|
+
// Normal completion: drop the abort listener so it can't accumulate on
|
|
118
|
+
// a shared signal across rounds. A long `cc loop` reuses one
|
|
119
|
+
// AbortController for the whole run, and `{once:true}` only removes the
|
|
120
|
+
// listener if it FIRES — a sleep that completes normally never aborts,
|
|
121
|
+
// so without this each round would leak a dangling listener (N rounds →
|
|
122
|
+
// N retained closures + a MaxListenersExceededWarning past 10).
|
|
123
|
+
signal?.removeEventListener("abort", onAbort);
|
|
124
|
+
resolve();
|
|
125
|
+
}, ms);
|
|
126
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
120
127
|
});
|
|
121
128
|
}
|
|
122
129
|
|
|
@@ -206,10 +206,14 @@ function matchCommand(pattern, command) {
|
|
|
206
206
|
function matchUrl(pattern, url) {
|
|
207
207
|
const u = String(url || "");
|
|
208
208
|
if (pattern.startsWith("domain:")) {
|
|
209
|
-
|
|
209
|
+
// Domains are case-insensitive (and `new URL().host` already lowercases the
|
|
210
|
+
// host), so lowercase the pattern too — otherwise a rule with any uppercase
|
|
211
|
+
// (`domain:Example.com`) silently never matches, turning a deny rule into a
|
|
212
|
+
// bypass and an allow rule into a no-op.
|
|
213
|
+
const host = pattern.slice("domain:".length).trim().toLowerCase();
|
|
210
214
|
let actualHost = "";
|
|
211
215
|
try {
|
|
212
|
-
actualHost = new URL(u).host;
|
|
216
|
+
actualHost = new URL(u).host.toLowerCase();
|
|
213
217
|
} catch {
|
|
214
218
|
return false;
|
|
215
219
|
}
|
package/src/lib/skill-loader.js
CHANGED
|
@@ -120,6 +120,15 @@ export function parseSkillMd(content) {
|
|
|
120
120
|
.slice(2)
|
|
121
121
|
.trim()
|
|
122
122
|
.replace(/^['"]|['"]$/g, "");
|
|
123
|
+
// Lazily start a block array on the first item under an empty-value key
|
|
124
|
+
// (`tools:\n - Read\n - Write`). Without this, currentArray was never
|
|
125
|
+
// assigned anywhere, so block-style YAML lists were silently dropped —
|
|
126
|
+
// e.g. an `allowed-tools:` list would vanish and its restriction be lost.
|
|
127
|
+
// Only create when the key carried no inline value (data[key] still
|
|
128
|
+
// undefined) so a scalar isn't clobbered by a stray dash.
|
|
129
|
+
if (!currentArray && currentKey && data[currentKey] === undefined) {
|
|
130
|
+
currentArray = data[currentKey] = [];
|
|
131
|
+
}
|
|
123
132
|
if (currentArray) currentArray.push(value);
|
|
124
133
|
continue;
|
|
125
134
|
}
|
package/src/lib/web-fetch.js
CHANGED
|
@@ -12,21 +12,50 @@ import { URL } from "url";
|
|
|
12
12
|
const DEFAULT_MAX_BYTES = 2_000_000;
|
|
13
13
|
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
14
14
|
|
|
15
|
-
// RFC 1918 + loopback + link-local. Blocked by default unless
|
|
15
|
+
// RFC 1918 + loopback + link-local (IPv4 and IPv6). Blocked by default unless
|
|
16
|
+
// config.allowPrivateHosts. Decimal/integer IPv4 forms (http://2130706433,
|
|
17
|
+
// http://0) are normalized to dotted-decimal by `new URL()` before they reach
|
|
18
|
+
// here, so the IPv4 patterns catch them too.
|
|
16
19
|
const PRIVATE_HOST_PATTERNS = [
|
|
17
20
|
/^127\./,
|
|
18
21
|
/^10\./,
|
|
19
22
|
/^192\.168\./,
|
|
20
23
|
/^172\.(1[6-9]|2\d|3[01])\./,
|
|
21
|
-
/^169\.254\./,
|
|
24
|
+
/^169\.254\./, // link-local incl. cloud metadata 169.254.169.254
|
|
22
25
|
/^0\.0\.0\.0$/,
|
|
23
|
-
|
|
26
|
+
/^0$/, // bare 0 → 0.0.0.0
|
|
27
|
+
/^::1$/, // IPv6 loopback
|
|
28
|
+
/^::$/, // IPv6 unspecified (== 0.0.0.0)
|
|
29
|
+
/^f[cd][0-9a-f]{2}:/, // fc00::/7 unique-local (ULA)
|
|
30
|
+
/^fe[89ab][0-9a-f]:/, // fe80::/10 link-local
|
|
24
31
|
/^localhost$/i,
|
|
25
32
|
];
|
|
26
33
|
|
|
34
|
+
// Decode the IPv4 embedded in an IPv4-mapped IPv6 address back to dotted form,
|
|
35
|
+
// or null if `h` is not such an address. `new URL()` normalizes the embedded
|
|
36
|
+
// IPv4 to hex (::ffff:127.0.0.1 → ::ffff:7f00:1), so without decoding, a fetch
|
|
37
|
+
// to [::ffff:127.0.0.1] would bypass the IPv4 loopback/private rules.
|
|
38
|
+
function mappedIPv4(h) {
|
|
39
|
+
const m = /^::ffff:(.+)$/.exec(h);
|
|
40
|
+
if (!m) return null;
|
|
41
|
+
const tail = m[1];
|
|
42
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(tail)) return tail; // already dotted
|
|
43
|
+
const hx = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(tail);
|
|
44
|
+
if (!hx) return null;
|
|
45
|
+
const a = parseInt(hx[1], 16);
|
|
46
|
+
const b = parseInt(hx[2], 16);
|
|
47
|
+
return [(a >> 8) & 255, a & 255, (b >> 8) & 255, b & 255].join(".");
|
|
48
|
+
}
|
|
49
|
+
|
|
27
50
|
export function isPrivateHost(host) {
|
|
28
51
|
if (!host) return true;
|
|
29
|
-
|
|
52
|
+
let h = String(host).toLowerCase();
|
|
53
|
+
// `new URL().hostname` returns IPv6 hosts bracketed ("[::1]") — strip so the
|
|
54
|
+
// IPv6 patterns (and the previously-dead ::1 rule) actually match.
|
|
55
|
+
if (h.startsWith("[") && h.endsWith("]")) h = h.slice(1, -1);
|
|
56
|
+
const v4 = mappedIPv4(h);
|
|
57
|
+
if (v4) h = v4; // re-check the embedded IPv4 against the IPv4 rules
|
|
58
|
+
return PRIVATE_HOST_PATTERNS.some((re) => re.test(h));
|
|
30
59
|
}
|
|
31
60
|
|
|
32
61
|
export function checkAllowed(urlStr, config = {}) {
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -1562,6 +1562,18 @@ export async function startAgentRepl(options = {}) {
|
|
|
1562
1562
|
model = arg;
|
|
1563
1563
|
_curModel = model; // keep the status-line readout in sync
|
|
1564
1564
|
logger.info(`Model: ${chalk.cyan(model)}`);
|
|
1565
|
+
// Claude-Code 2.1.183 parity: warn when the newly-selected model is a
|
|
1566
|
+
// provider-retired/deprecated snapshot. Headless paths already warn via
|
|
1567
|
+
// maybeWarnDeprecatedModel; the interactive /model switch did not, so a
|
|
1568
|
+
// user could silently switch to a retired id and only learn of it when
|
|
1569
|
+
// the next turn fails with an opaque "model not found".
|
|
1570
|
+
try {
|
|
1571
|
+
const { maybeWarnDeprecatedModel } =
|
|
1572
|
+
await import("../lib/model-deprecation.js");
|
|
1573
|
+
maybeWarnDeprecatedModel({ model });
|
|
1574
|
+
} catch {
|
|
1575
|
+
// deprecation notice is best-effort
|
|
1576
|
+
}
|
|
1565
1577
|
} else {
|
|
1566
1578
|
logger.info(`Current model: ${chalk.cyan(model)}`);
|
|
1567
1579
|
}
|
|
@@ -768,6 +768,20 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
768
768
|
// chatFn passthrough lets tests drive the loop deterministically.
|
|
769
769
|
chatFn: deps.chatFn || options.chatFn || undefined,
|
|
770
770
|
signal: options.signal || undefined,
|
|
771
|
+
// Stream-stall hint (Claude-Code 2.1.185): when the connection is alive but
|
|
772
|
+
// the API has gone silent mid-response, a headless run would otherwise look
|
|
773
|
+
// frozen with no feedback. The REPL already surfaces this; mirror it here to
|
|
774
|
+
// stderr — out-of-band for every output format (text answer / json envelope
|
|
775
|
+
// / stream-json NDJSON all go to stdout) so machine consumers are unaffected
|
|
776
|
+
// while a human watching a long `cc agent -p` run learns we're still waiting
|
|
777
|
+
// and, when a hard inactivity timeout is set, when it will auto-retry. Plain
|
|
778
|
+
// text (no chalk) since headless stderr is frequently piped/non-TTY.
|
|
779
|
+
onStall: (ms, timeoutMs) => {
|
|
780
|
+
const silent = Math.round(ms / 1000);
|
|
781
|
+
const retryIn = timeoutMs > ms ? Math.round((timeoutMs - ms) / 1000) : 0;
|
|
782
|
+
const suffix = retryIn > 0 ? ` · will retry in ${retryIn}s` : "";
|
|
783
|
+
writeErr(` ⏳ waiting for API response (silent ${silent}s)${suffix}…\n`);
|
|
784
|
+
},
|
|
771
785
|
};
|
|
772
786
|
|
|
773
787
|
// Goal binding (cc goal, Phase 1). `--goal <id>` binds explicitly; `--goal`
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as v,P as u,J as S,U as n,R as a,S as y,K as C,Q as x,V as w,_ as k,b as s}from"./vendor-BvqAck49.js";import{_ as B}from"./index-DlHHHyRx.js";import"./icons-DP3uiYxy.js";const M={__name:"ChatBubbleRenderer",props:{event:{type:Object,required:!0}},setup(c,{expose:d}){d();const t=c,r=s(()=>{const e=t.event.content||{};return e.text||e.body||e.message||e.title||JSON.stringify(e).slice(0,200)}),i=s(()=>{const e=t.event.content||{};return e.from||e.sender||e.senderName||t.event.actor||"(unknown)"}),l=s(()=>{const e=(t.event.actor||"").toLowerCase();return e.includes("self")||e==="me"||e.endsWith("_self")}),o=s(()=>{const e=t.event.source.adapter||"";return e.startsWith("messaging-qq")?"magenta":e==="wechat"?"green":"blue"}),m=s(()=>{if(!t.event.occurredAt)return"";try{const e=new Date(t.event.occurredAt),p=e.getFullYear(),b=String(e.getMonth()+1).padStart(2,"0"),f=String(e.getDate()).padStart(2,"0"),g=String(e.getHours()).padStart(2,"0"),h=String(e.getMinutes()).padStart(2,"0");return`${p}-${b}-${f} ${g}:${h}`}catch{return""}}),_={props:t,messageText:r,actorLabel:i,isMine:l,adapterColor:o,formattedTime:m,computed:s};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}},N={class:"bubble"},T={class:"meta"},R={class:"actor"},V={class:"time"},q={class:"body"};function D(c,d,t,r,i,l){const o=v("a-tag");return u(),S("div",{class:k(["chat-row",{mine:r.isMine}])},[n("div",N,[n("div",T,[n("span",R,a(r.actorLabel),1),n("span",V,a(r.formattedTime),1)]),n("div",q,a(r.messageText),1),t.event.source.adapter?(u(),y(o,{key:0,class:"src",color:r.adapterColor},{default:C(()=>[x(a(t.event.source.adapter),1)]),_:1},8,["color"])):w("v-if",!0)])],2)}const O=B(M,[["render",D],["__scopeId","data-v-49238629"],["__file","/tmp/cc-web-panel-kIMJb5/repo/packages/web-panel/src/components/pdh/renderers/ChatBubbleRenderer.vue"]]);export{O as default};
|