chainlesschain 0.162.125 → 0.162.127
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/assets/{AIOps-DcqNhZhA.js → AIOps-CsHJh6tT.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BigtmPoq.js → ActionButton-ClDr78Wl.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-1J_X_HF4.js → Analytics-CQQBX5mv.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DlcDG_a_.js → AppLayout-DIofBNeG.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-Do-y8_3w.js → Audit-d8pxGJLK.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-S2Df-50Y.js → Backup-ChZb31ek.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D5kgWJfk.js → BaseInput-CQsSXb5v.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-aUcp3kN1.js → Chat-C_mjILx8.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-B545kWla.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DTg1U7Xs.js → Checkbox-CWFmVuo8.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-YO9ZZ4Ky.js → Codegen-DwicePOQ.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BHonE9fU.js → Col-B36SnRdL.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DA2AlEFh.js → Community-C_sZ2HhK.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DULxLRNg.js → Compact-B2jzDcUl.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BZqfuuZL.js → Compliance-BD58_IHe.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CJe3vyMS.js → Cowork-VIBdGc4D.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CeV8AtRu.js → Cron-CDTVWUmV.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CAg66zS5.js → Crosschain-D5DkGNKU.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Dtup5JZm.js → DID-B23ae8PQ.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DAR_8PNy.js → Dashboard-DTG5MsSx.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-K5bTaCYN.js → Dropdown-D35RRnMZ.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C890uErx.js → EmailListRenderer-DRvY2nPk.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-B-Tj_8yM.js → FamilyGuardDashboard-BT_eESkk.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C6WZ98ni.js → Federation-CxX9F7IL.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-D-LTfGWd.js → FormItemContext-C1xDz6D8.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-C80DK4W7.js → GenericCardRenderer-CjBOAXcO.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Cjvvv3zW.js → Git-I9I9NkPO.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C0BND77H.js → Governance-BiigWxQW.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BL9kTtSu.js → Inference-C0KrSCgh.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CnVTBmJf.js → KnowledgeGraph-B1Nd54ow.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CbCbg7K6.js → Logs-CeOtvYIo.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CG5On-fH.js → Marketplace-CRhgvAVQ.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-AYYDZZK7.js → McpTools-BIJNah-H.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-tMWbMDQq.js → Memory-D6gsbo4e.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BAOsf4wB.js → MobileBridge-DDkIKA6U.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BT-2komQ.js → MobileProjects-BBkI02Lf.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BFwfC63n.js → Mtc-BziHK7HS.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-DYG3CWdH.js → MtcAudit-CWXjbkeF.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-KJwd0yWT.js → Multisig-9jNF_VWa.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BmL5dNWm.js → NLProgramming-BUdF7I2G.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DmkaVaMc.js → Notes-D5ls1r1T.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-tmVQszDZ.js → NotificationSettings-B2WX_TMX.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BtrR7anf.js → OrderTableRenderer-COSzdTcE.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-pppktQyW.js → Organization-tzWIgnbM.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-D3lBoQDA.js → Overflow-Ca1gp_3S.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BgE2qGlZ.js → P2P-XnfDfRK9.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-D26Bz5gS.js → PdhVaultBrowser-23Susb25.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BR8no2Xe.js → Permissions-CnkhYPqt.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DabbyQEF.js → PersonalDataHub-CZ1UasJc.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-n4sNpEz8.js → Pipeline-DC1oC84K.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CGNp4n8M.js → Privacy-CdqayaCE.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CAVA5VsX.js → ProjectInit-DS7NbGQL.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-GCgkfM7A.js → ProjectSettings-fdzwup3n.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BYK17p52.js → Projects-FvodeZob.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DpUT5W-d.js → Providers-IxYyzeSI.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-ZJxTb7vi.js → QuickAsk-BAtFET-B.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CIzFRDk1.js → Recommend-DCNRV9Vr.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-lQ_WDNZn.js → Reputation-lg2JmIai.js} +1 -1
- package/src/assets/web-panel/assets/{Row-1MEtrgtF.js → Row-BAhyDuri.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-SSgcPPl4.js → RssFeed-BA_3issD.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CcTMOGNY.js → Search-CJheUJDl.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BA1KMaDx.js → Security-D2VczQDD.js} +3 -3
- package/src/assets/web-panel/assets/{Services-_aj7czZn.js → Services-7ZFAzqVR.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BWgg_0Zr.js → Skeleton-CsBoTasD.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C2ZIziYM.js → Skills-DT_j_gj0.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CYxp4axY.js → Sla-C9D5geJx.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C7Csp1jV.js → SpeechSettings-CWCNVW42.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-svGeswiw.js → SyncSettings-TYCbf2kk.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-ClISj6oK.js → Tasks-CbRoXu1G.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CmO-Fp7r.js → Templates-CxBjIrkJ.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-a3Ac3lxz.js → Tenant-NKVyFsPM.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DyJIRh81.js → Terminal-D5aAL5_H.js} +2 -2
- package/src/assets/web-panel/assets/TimelineRenderer-CD1JE0Rb.js +1 -0
- package/src/assets/web-panel/assets/{Tokens-DJW0KqV4.js → Tokens-CdepBSYe.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-0HeTi4r6.js → Trigger-Br3n_PEh.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-aFym34eo.js → Trust-CSac0pMf.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CYhszHJv.js → UkeySign-BiWo43zc.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BbJxPF9X.js → VideoEditing-Dj50GuoF.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DDthEwiu.js → Wallet-CQK_g4_U.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DQ6McYPg.js → WebAuthn-D8mBl1NC.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-CnF8zRsi.js → WorkflowEditor-CHeS_vab.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Dzkx2gTP.js → chat-CbeOf_lH.js} +1 -1
- package/src/assets/web-panel/assets/{colors-35T51Oo5.js → colors-CTFiyfed.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-TtzNrlu1.js → compact-item-CZsh8FXE.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Y1LkWrYb.js → createContext-UPhnXsap.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BFRqfgsk.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BOYw1BgS.js → hasIn-CCqQtSY-.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2od7Bgx.js → index-1d4pat4L.js} +1 -1
- package/src/assets/web-panel/assets/{index-NM9Oke2k.js → index-86dmMEZY.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dof7lWA_.js → index-B-OcSTNA.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7dCBw_M.js → index-B1tylGKq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqhwG1ox.js → index-BAcem_Qs.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZ16GlOs.js → index-BKADY9Iw.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPGNc2tF.js → index-Be0uH7m1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAizH273.js → index-Bga0UuWA.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFhlelzN.js → index-Blgzobgm.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6tG4B25.js → index-BwPULPuj.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjeUZxE5.js → index-CIQVlE9u.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLqC2sRT.js → index-CMi91z74.js} +1 -1
- package/src/assets/web-panel/assets/{index-hyqEKkBT.js → index-CNteMctn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cs82BHAj.js → index-CQHQiYAO.js} +1 -1
- package/src/assets/web-panel/assets/{index-zF77jnI2.js → index-CVKFSFkX.js} +1 -1
- package/src/assets/web-panel/assets/{index-G4ClSmJc.js → index-CctoAd9I.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhMSOd_2.js → index-CdiuRSqw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWgNn9As.js → index-Cy83zglX.js} +3 -3
- package/src/assets/web-panel/assets/{index-Bw1iOGhM.js → index-DBJjqjxL.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4BgCBa3.js → index-DFbyobqi.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKRlWHUp.js → index-DcJxrM1F.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7aKAZzS.js → index-DgXn2sWa.js} +1 -1
- package/src/assets/web-panel/assets/{index-D47robkX.js → index-Dkn1r09O.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVrUs6rf.js → index-DmScDPXc.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bs69SI96.js → index-DpTaXoo4.js} +1 -1
- package/src/assets/web-panel/assets/index-DqADH38Q.js +1 -0
- package/src/assets/web-panel/assets/{index-BxWUEFKy.js → index-DvaDSd9k.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtlJWaSP.js → index-LIFKNtNq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGPEaeB1.js → index-LyzbfmcN.js} +1 -1
- package/src/assets/web-panel/assets/index-Pbx8iJt_.js +1 -0
- package/src/assets/web-panel/assets/{index-KgXrlfNF.js → index-WGmri9tu.js} +1 -1
- package/src/assets/web-panel/assets/{index-XIuZV9by.js → index-Yd1x-xhs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dhfw-BXs.js → index-_OOipSkX.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dx0hIfC-.js → index-dwBroN51.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7Wt5feN.js → index-e6tj_vqt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdyFg4FI.js → index-lOxvi-gf.js} +1 -1
- package/src/assets/web-panel/assets/{index-8jffdb6b.js → index-qTrskpW-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmkG479D.js → index-uH-glcG6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSpFe6j5.js → index-z5pyzCXj.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DD5y5msp.js → initDefaultProps-K95PVa57.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BuoutMia.js → motion-DwTSyvvW.js} +1 -1
- package/src/assets/web-panel/assets/{move-DkpjqOXg.js → move-BuRSogkN.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BmGJD-v-.js → mtc-parser-twEnPl1V.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DftUE0Sz.js → omit-CdPhebkX.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DDRb9FIu.js → pickAttrs-CGcIpdPi.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DPgtxOOD.js → placementArrow-DixkX9VV.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BQFRzFeZ.js → responsiveObserve-C74t3rB5.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DQ4lmUSz.js → slide-TcNt6K6l.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C1TR4ZiQ.js → statusUtils-mpTN9mrS.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B-Suj978.js → styleChecker-Bwg8zmIj.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Q7bDZ3EI.js → useFlexGapSupport-Cz4mN4sW.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DHjRLyQH.js → useFs-DF9zRfbI.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-lQOvCvCr.js → usePersonalDataHub-BcQ4O2UK.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Ie0g4-p3.js → vnode-juM2dgAV.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CHP0YEoH.js → zoom-c4aJj-vC.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +41 -2
- package/src/commands/compliance.js +3 -1
- package/src/commands/review.js +47 -17
- package/src/commands/session.js +11 -2
- package/src/gateways/ws/message-dispatcher.js +145 -165
- package/src/gateways/ws/ws-session-gateway.js +39 -5
- package/src/harness/jsonl-session-store.js +39 -12
- package/src/harness/worktree-isolator.js +5 -0
- package/src/lib/agent-core.js +1 -0
- package/src/lib/audit-logger.js +3 -1
- package/src/lib/chat-core.js +5 -2
- package/src/lib/chat-intent-service.js +68 -21
- package/src/lib/config-manager.js +25 -1
- package/src/lib/credential-guard.js +43 -1
- package/src/lib/git-integration.js +5 -0
- package/src/lib/interaction-adapter.js +32 -11
- package/src/lib/jsonl-session-store.js +1 -0
- package/src/lib/llm-config-defaults.js +37 -0
- package/src/lib/mcp-oauth.js +76 -10
- package/src/lib/permission-engine.js +4 -1
- package/src/lib/personal-data-hub-wiring.js +14 -0
- package/src/lib/pipeline-orchestrator.js +20 -2
- package/src/lib/project-detector.js +44 -3
- package/src/lib/project-instructions.js +13 -0
- package/src/lib/repl-denials.js +137 -0
- package/src/lib/safe-json.js +22 -0
- package/src/lib/sandbox-v2.js +7 -6
- package/src/lib/search-command.js +65 -0
- package/src/lib/settings-hooks.cjs +133 -0
- package/src/lib/settings-loader.cjs +16 -7
- package/src/lib/social-graph.js +3 -1
- package/src/lib/stream-retry.js +27 -0
- package/src/lib/turn-context.js +15 -5
- package/src/repl/agent-repl.js +81 -8
- package/src/runtime/__tests__/message-roles.test.js +36 -3
- package/src/runtime/agent-core.js +175 -50
- package/src/runtime/coding-agent-contract-shared.cjs +9 -2
- package/src/runtime/coding-agent-shell-policy.cjs +23 -2
- package/src/runtime/file-ref-expander.js +51 -7
- package/src/runtime/headless-runner.js +83 -2
- package/src/runtime/headless-stream.js +69 -3
- package/src/runtime/mcp-config.js +42 -1
- package/src/runtime/message-roles.js +14 -1
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Pg7dIsiE.js +0 -1
- package/src/assets/web-panel/assets/TimelineRenderer-acXS5N5h.js +0 -1
- package/src/assets/web-panel/assets/devWarning-D_lwLZ6O.js +0 -1
- package/src/assets/web-panel/assets/index-CEwuCM44.js +0 -1
- package/src/assets/web-panel/assets/index-DzzgU4IU.js +0 -1
|
@@ -288,7 +288,7 @@ const DECISION_SEVERITY = Object.freeze({
|
|
|
288
288
|
});
|
|
289
289
|
|
|
290
290
|
/** Classify ONE command segment (no separators). */
|
|
291
|
-
function evaluateSegmentPolicy(segment, overrideRuleIds) {
|
|
291
|
+
function evaluateSegmentPolicy(segment, overrideRuleIds, classifyAllShell) {
|
|
292
292
|
const normalized = normalizeShellCommand(segment);
|
|
293
293
|
const tokens = tokenizeShellCommand(normalized);
|
|
294
294
|
const firstToken = (tokens[0] || "").toLowerCase();
|
|
@@ -326,6 +326,20 @@ function evaluateSegmentPolicy(segment, overrideRuleIds) {
|
|
|
326
326
|
rule.test(context),
|
|
327
327
|
);
|
|
328
328
|
if (allowlistedRule) {
|
|
329
|
+
// `classifyAllShell` (Claude-Code 2.1.193 `autoMode.classifyAllShell`):
|
|
330
|
+
// don't fast-path the built-in verification allowlist to ALLOW (risk LOW,
|
|
331
|
+
// auto-approved). Downgrade to WARN so EVERY shell command is classified
|
|
332
|
+
// and routed through the ApprovalGate confirm — the allowlist still
|
|
333
|
+
// documents intent, but the agent can't silently run even `npm test`.
|
|
334
|
+
if (classifyAllShell) {
|
|
335
|
+
return {
|
|
336
|
+
allowed: true,
|
|
337
|
+
decision: SHELL_POLICY_DECISIONS.WARN,
|
|
338
|
+
reason: `${allowlistedRule.reason} (classifyAllShell: confirm required)`,
|
|
339
|
+
ruleId: allowlistedRule.id,
|
|
340
|
+
normalizedCommand: normalized,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
329
343
|
return {
|
|
330
344
|
allowed: true,
|
|
331
345
|
decision: SHELL_POLICY_DECISIONS.ALLOW,
|
|
@@ -350,6 +364,9 @@ function evaluateShellCommandPolicy(command, options = {}) {
|
|
|
350
364
|
const overrideRuleIds = Array.isArray(options.overrideRuleIds)
|
|
351
365
|
? new Set(options.overrideRuleIds)
|
|
352
366
|
: new Set();
|
|
367
|
+
// When set, allowlisted commands are classified (WARN) instead of fast-pathed
|
|
368
|
+
// (ALLOW) — see evaluateSegmentPolicy.
|
|
369
|
+
const classifyAllShell = options.classifyAllShell === true;
|
|
353
370
|
|
|
354
371
|
// Inspect EVERY segment of a compound command, not just the first — a
|
|
355
372
|
// dangerous segment after `&&` / `;` / `|` must still be caught. The most
|
|
@@ -368,7 +385,11 @@ function evaluateShellCommandPolicy(command, options = {}) {
|
|
|
368
385
|
|
|
369
386
|
let worst = null;
|
|
370
387
|
for (const segment of segments) {
|
|
371
|
-
const result = evaluateSegmentPolicy(
|
|
388
|
+
const result = evaluateSegmentPolicy(
|
|
389
|
+
segment,
|
|
390
|
+
overrideRuleIds,
|
|
391
|
+
classifyAllShell,
|
|
392
|
+
);
|
|
372
393
|
const sev = DECISION_SEVERITY[result.decision] ?? 1;
|
|
373
394
|
const worstSev = worst ? (DECISION_SEVERITY[worst.decision] ?? 1) : -1;
|
|
374
395
|
if (sev > worstSev) worst = result;
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
|
|
25
25
|
import fsDefault from "fs";
|
|
26
26
|
import pathDefault from "path";
|
|
27
|
+
import {
|
|
28
|
+
credentialFileReasonResolved,
|
|
29
|
+
credentialGuardDisabled,
|
|
30
|
+
} from "../lib/credential-guard.js";
|
|
27
31
|
|
|
28
32
|
export const DEFAULT_MAX_BYTES = 100 * 1024; // 100 KB per referenced file
|
|
29
33
|
export const DEFAULT_MAX_DIR_ENTRIES = 200;
|
|
@@ -181,6 +185,27 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
|
|
|
181
185
|
};
|
|
182
186
|
}
|
|
183
187
|
if (stat.isFile()) {
|
|
188
|
+
// Refuse to inline a credential / secret file. `@file` expansion pulls
|
|
189
|
+
// file contents straight into the (possibly cloud) LLM prompt, so it is a
|
|
190
|
+
// second channel for file→LLM exfiltration that must honour the same guard
|
|
191
|
+
// as read_file / run_shell / the project-memory @import path. Checked on
|
|
192
|
+
// the RESOLVED path (the read follows symlinks, so a notes.txt → id_rsa
|
|
193
|
+
// link would otherwise leak the key) and BEFORE any read, so the secret
|
|
194
|
+
// bytes are never loaded. CC_CREDENTIAL_GUARD=0 opts out.
|
|
195
|
+
if (!credentialGuardDisabled()) {
|
|
196
|
+
const credReason = credentialFileReasonResolved(abs, {
|
|
197
|
+
cwd,
|
|
198
|
+
deps: { realpathSync: fs.realpathSync, resolve: path.resolve },
|
|
199
|
+
});
|
|
200
|
+
if (credReason) {
|
|
201
|
+
return {
|
|
202
|
+
kind: "blocked",
|
|
203
|
+
raw: cand,
|
|
204
|
+
rel: fsPath,
|
|
205
|
+
reason: credReason,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
184
209
|
// PDFs (pdf-parse needs the bytes) and line ranges (must reach the end
|
|
185
210
|
// line) need the whole file; a plain inline only ever shows the first
|
|
186
211
|
// maxBytes, so cap the read there instead of slurping the entire file.
|
|
@@ -222,7 +247,12 @@ function resolveRef(raw, { cwd, fs, path, maxBytes, maxDirEntries }) {
|
|
|
222
247
|
}
|
|
223
248
|
if (range) {
|
|
224
249
|
// Slice the requested lines (clamped to the file), then byte-cap them.
|
|
225
|
-
const sl = sliceLines(
|
|
250
|
+
const sl = sliceLines(
|
|
251
|
+
buf.toString("utf-8"),
|
|
252
|
+
range.start,
|
|
253
|
+
range.end,
|
|
254
|
+
maxBytes,
|
|
255
|
+
);
|
|
226
256
|
return {
|
|
227
257
|
kind: "file",
|
|
228
258
|
raw: cand,
|
|
@@ -296,7 +326,9 @@ function renderBlock(refs) {
|
|
|
296
326
|
} else if (ref.kind === "pdf") {
|
|
297
327
|
if (typeof ref.content === "string") {
|
|
298
328
|
const pageAttr =
|
|
299
|
-
ref.pageStart != null
|
|
329
|
+
ref.pageStart != null
|
|
330
|
+
? ` pages="${ref.pageStart}-${ref.pageEnd}"`
|
|
331
|
+
: "";
|
|
300
332
|
const attrs =
|
|
301
333
|
`path="${escapeAttr(ref.rel)}" bytes="${ref.bytes}" type="pdf"` +
|
|
302
334
|
pageAttr +
|
|
@@ -306,7 +338,9 @@ function renderBlock(refs) {
|
|
|
306
338
|
parts.push(`<file ${attrs}>`);
|
|
307
339
|
parts.push(ref.content);
|
|
308
340
|
if (ref.truncated) {
|
|
309
|
-
parts.push(
|
|
341
|
+
parts.push(
|
|
342
|
+
`\n… [truncated — PDF text exceeds ${DEFAULT_MAX_BYTES} bytes]`,
|
|
343
|
+
);
|
|
310
344
|
}
|
|
311
345
|
parts.push("</file>");
|
|
312
346
|
} else {
|
|
@@ -369,6 +403,13 @@ function _resolveAllRefs(text, opts) {
|
|
|
369
403
|
warnings.push(`@${ref.raw} — ${ref.message} (left as-is)`);
|
|
370
404
|
continue;
|
|
371
405
|
}
|
|
406
|
+
if (ref.kind === "blocked") {
|
|
407
|
+
// Credential/secret file — never read or injected; only a visible warning.
|
|
408
|
+
warnings.push(
|
|
409
|
+
`@${ref.raw} — refused: ${ref.reason}; not injected into the prompt`,
|
|
410
|
+
);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
372
413
|
refs.push(ref);
|
|
373
414
|
}
|
|
374
415
|
return { refs, warnings, maxBytes };
|
|
@@ -440,7 +481,10 @@ export async function expandFileRefsAsync(prompt, opts = {}) {
|
|
|
440
481
|
* when those are null), byte-capped at maxBytes. Throws code `PDF_LIB_MISSING`
|
|
441
482
|
* when the optional dependency is not installed.
|
|
442
483
|
*/
|
|
443
|
-
async function _extractPdfPages(
|
|
484
|
+
async function _extractPdfPages(
|
|
485
|
+
buffer,
|
|
486
|
+
{ firstPage, lastPage, maxBytes } = {},
|
|
487
|
+
) {
|
|
444
488
|
let pdfParse;
|
|
445
489
|
try {
|
|
446
490
|
// pdf-parse's index.js runs debug code under ESM (no module.parent), so
|
|
@@ -459,9 +503,9 @@ async function _extractPdfPages(buffer, { firstPage, lastPage, maxBytes } = {})
|
|
|
459
503
|
if (firstPage && n < firstPage) return "";
|
|
460
504
|
if (lastPage && n > lastPage) return "";
|
|
461
505
|
}
|
|
462
|
-
return pageData
|
|
463
|
-
|
|
464
|
-
|
|
506
|
+
return pageData
|
|
507
|
+
.getTextContent()
|
|
508
|
+
.then((tc) => (tc.items || []).map((it) => it.str).join(" "));
|
|
465
509
|
},
|
|
466
510
|
});
|
|
467
511
|
let out = String(data?.text || "").trim();
|
|
@@ -50,6 +50,11 @@ import { mergeConsecutiveMessages } from "./message-roles.js";
|
|
|
50
50
|
import { isHeadlessConfigCommand } from "../lib/headless-config-command.js";
|
|
51
51
|
import { withQuietStdout } from "./quiet-stdout.js";
|
|
52
52
|
import { CostBudget } from "../lib/cost-budget.js";
|
|
53
|
+
import {
|
|
54
|
+
classifyDenial,
|
|
55
|
+
recordDenial,
|
|
56
|
+
formatDenials,
|
|
57
|
+
} from "../lib/repl-denials.js";
|
|
53
58
|
|
|
54
59
|
/** Tools that cannot mutate the filesystem or run commands. */
|
|
55
60
|
export const READ_ONLY_TOOLS = Object.freeze([
|
|
@@ -294,17 +299,46 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
294
299
|
let settingsHooks = options.settingsHooks || null;
|
|
295
300
|
if (!settingsHooks) {
|
|
296
301
|
try {
|
|
297
|
-
const { loadHooks } =
|
|
302
|
+
const { loadHooks, projectHookTrustNotice } =
|
|
303
|
+
await import("../lib/settings-hooks.cjs");
|
|
298
304
|
const loaded = loadHooks({ cwd, settingsFile: options.settingsFile });
|
|
299
305
|
settingsHooks =
|
|
300
306
|
loaded.hooks && Object.keys(loaded.hooks).length > 0
|
|
301
307
|
? loaded.hooks
|
|
302
308
|
: null;
|
|
309
|
+
// First-run trust notice for an untrusted/cloned repo's shell-running
|
|
310
|
+
// hooks (Claude-Code 2.1.195 parity). Best-effort, stderr-only.
|
|
311
|
+
try {
|
|
312
|
+
const notice = projectHookTrustNotice({
|
|
313
|
+
cwd,
|
|
314
|
+
settingsFile: options.settingsFile,
|
|
315
|
+
});
|
|
316
|
+
if (notice) process.stderr.write(notice + "\n");
|
|
317
|
+
} catch {
|
|
318
|
+
/* trust notice is best-effort */
|
|
319
|
+
}
|
|
303
320
|
} catch {
|
|
304
321
|
settingsHooks = null; // fail-open
|
|
305
322
|
}
|
|
306
323
|
}
|
|
307
324
|
|
|
325
|
+
// autoMode.classifyAllShell (Claude-Code 2.1.193): route the built-in
|
|
326
|
+
// verification allowlist through the shell-policy classifier instead of
|
|
327
|
+
// fast-pathing it. Explicit option wins; otherwise read settings.json.
|
|
328
|
+
let classifyAllShell = options.classifyAllShell || false;
|
|
329
|
+
if (!classifyAllShell) {
|
|
330
|
+
try {
|
|
331
|
+
const { readBooleanSetting } = await import("../lib/settings-loader.cjs");
|
|
332
|
+
classifyAllShell =
|
|
333
|
+
readBooleanSetting("autoMode.classifyAllShell", {
|
|
334
|
+
cwd,
|
|
335
|
+
settingsFile: options.settingsFile,
|
|
336
|
+
}) === true;
|
|
337
|
+
} catch {
|
|
338
|
+
classifyAllShell = false; // fail-open
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
308
342
|
const runLoop = deps.agentLoop || coreAgentLoop;
|
|
309
343
|
const doBootstrap = deps.bootstrap || bootstrap;
|
|
310
344
|
const getApprovalGate =
|
|
@@ -776,6 +810,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
776
810
|
approvalGate,
|
|
777
811
|
permissionRules,
|
|
778
812
|
settingsHooks,
|
|
813
|
+
classifyAllShell,
|
|
779
814
|
enabledToolNames,
|
|
780
815
|
disabledTools,
|
|
781
816
|
iterationBudget: budget,
|
|
@@ -847,6 +882,10 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
847
882
|
|
|
848
883
|
const startedAt = deps.now ? deps.now() : Date.now();
|
|
849
884
|
const toolCalls = [];
|
|
885
|
+
// Policy denials (blocked tool calls) collected for an end-of-run summary,
|
|
886
|
+
// so a non-interactive run surfaces what got blocked the way the REPL's
|
|
887
|
+
// `/permissions denials` does (Claude-Code 2.1.193 denial reasons).
|
|
888
|
+
const denials = [];
|
|
850
889
|
const usage = {
|
|
851
890
|
input_tokens: 0,
|
|
852
891
|
output_tokens: 0,
|
|
@@ -924,6 +963,26 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
924
963
|
if (toolCalls.length > 0) {
|
|
925
964
|
toolCalls[toolCalls.length - 1].is_error = Boolean(err);
|
|
926
965
|
}
|
|
966
|
+
// Track policy denials (not plain tool failures) for the end-of-run
|
|
967
|
+
// summary. The preceding tool-executing pushed the args.
|
|
968
|
+
if (err) {
|
|
969
|
+
const last = toolCalls[toolCalls.length - 1];
|
|
970
|
+
const denial = classifyDenial({
|
|
971
|
+
tool: event.tool,
|
|
972
|
+
result: event.result,
|
|
973
|
+
error: event.error,
|
|
974
|
+
argsSummary:
|
|
975
|
+
last && last.tool === event.tool
|
|
976
|
+
? formatToolArgs(event.tool, last.args)
|
|
977
|
+
: "",
|
|
978
|
+
});
|
|
979
|
+
if (denial) {
|
|
980
|
+
recordDenial(denials, {
|
|
981
|
+
...denial,
|
|
982
|
+
at: deps.now ? deps.now() : Date.now(),
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
}
|
|
927
986
|
break;
|
|
928
987
|
}
|
|
929
988
|
case "token-usage": {
|
|
@@ -1013,6 +1072,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1013
1072
|
usage,
|
|
1014
1073
|
numTurns: budget.consumed,
|
|
1015
1074
|
durationMs: (deps.now ? deps.now() : Date.now()) - startedAt,
|
|
1075
|
+
denials,
|
|
1016
1076
|
}),
|
|
1017
1077
|
) + "\n",
|
|
1018
1078
|
);
|
|
@@ -1132,6 +1192,21 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1132
1192
|
}
|
|
1133
1193
|
}
|
|
1134
1194
|
|
|
1195
|
+
// End-of-run policy-denial summary so a non-interactive run surfaces what was
|
|
1196
|
+
// blocked (mirrors the REPL's `/permissions denials`). Text → stderr lines;
|
|
1197
|
+
// stream → a `denials_summary` event before the final result.
|
|
1198
|
+
if (denials.length) {
|
|
1199
|
+
if (isText) {
|
|
1200
|
+
writeErr(
|
|
1201
|
+
`\n ${denials.length} tool call(s) were denied by policy this run:\n` +
|
|
1202
|
+
formatDenials(denials, { now: deps.now ? deps.now() : Date.now() }) +
|
|
1203
|
+
"\n",
|
|
1204
|
+
);
|
|
1205
|
+
} else if (isStream) {
|
|
1206
|
+
emitStream({ type: "denials_summary", count: denials.length, denials });
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1135
1210
|
if (isStream) {
|
|
1136
1211
|
emitStream({
|
|
1137
1212
|
type: "result",
|
|
@@ -1155,6 +1230,7 @@ export async function runAgentHeadless(options = {}, deps = {}) {
|
|
|
1155
1230
|
usage,
|
|
1156
1231
|
numTurns: budget.consumed,
|
|
1157
1232
|
durationMs,
|
|
1233
|
+
denials,
|
|
1158
1234
|
}),
|
|
1159
1235
|
) + "\n",
|
|
1160
1236
|
);
|
|
@@ -1175,8 +1251,9 @@ function buildResultEnvelope({
|
|
|
1175
1251
|
usage,
|
|
1176
1252
|
numTurns,
|
|
1177
1253
|
durationMs,
|
|
1254
|
+
denials,
|
|
1178
1255
|
}) {
|
|
1179
|
-
|
|
1256
|
+
const env = {
|
|
1180
1257
|
type: "result",
|
|
1181
1258
|
subtype,
|
|
1182
1259
|
is_error: isError,
|
|
@@ -1187,4 +1264,8 @@ function buildResultEnvelope({
|
|
|
1187
1264
|
tool_calls: toolCalls,
|
|
1188
1265
|
usage,
|
|
1189
1266
|
};
|
|
1267
|
+
// Only present when something was blocked — keeps the no-denial envelope
|
|
1268
|
+
// byte-identical to before (Claude-Code 2.1.193 denial reasons, json mode).
|
|
1269
|
+
if (Array.isArray(denials) && denials.length) env.denials = denials;
|
|
1270
|
+
return env;
|
|
1190
1271
|
}
|
|
@@ -318,9 +318,26 @@ export function sanitizeLlmHint(raw) {
|
|
|
318
318
|
/**
|
|
319
319
|
* Yield NDJSON lines from a byte/string stream (stdin). Splits on "\n" and
|
|
320
320
|
* flushes any trailing partial line when the stream ends.
|
|
321
|
+
*
|
|
322
|
+
* A single line with no terminating "\n" must never accumulate without bound:
|
|
323
|
+
* a stuck / garbage producer (or a runaway multi-MB inline payload) that never
|
|
324
|
+
* emits a newline would otherwise grow `buf` unbounded and OOM this long-lived
|
|
325
|
+
* stream process. When a line exceeds the cap, a short head is yielded (so the
|
|
326
|
+
* caller surfaces it as an invalid-JSON error rather than dropping it silently)
|
|
327
|
+
* and the rest of that monster line is discarded until its newline — the stream
|
|
328
|
+
* resyncs cleanly to the next well-formed line. Cap precedence:
|
|
329
|
+
* `opts.maxLineLength` > `CC_MAX_INPUT_LINE_BYTES` env > 16 MB default.
|
|
321
330
|
*/
|
|
322
|
-
export async function* readJsonLines(input) {
|
|
331
|
+
export async function* readJsonLines(input, opts = {}) {
|
|
332
|
+
const envCap = Number(process.env.CC_MAX_INPUT_LINE_BYTES);
|
|
333
|
+
const maxLineLength =
|
|
334
|
+
Number.isFinite(opts.maxLineLength) && opts.maxLineLength > 0
|
|
335
|
+
? opts.maxLineLength
|
|
336
|
+
: Number.isFinite(envCap) && envCap > 0
|
|
337
|
+
? envCap
|
|
338
|
+
: 16 * 1024 * 1024;
|
|
323
339
|
let buf = "";
|
|
340
|
+
let overflow = false; // discarding the tail of an over-long line until its \n
|
|
324
341
|
// Reuse ONE streaming decoder across chunks so a multi-byte UTF-8 character
|
|
325
342
|
// (e.g. a 3-byte Chinese char) split across two Buffer chunks is reassembled
|
|
326
343
|
// rather than corrupted. process.stdin yields Buffers with no setEncoding, so
|
|
@@ -332,14 +349,34 @@ export async function* readJsonLines(input) {
|
|
|
332
349
|
typeof chunk === "string"
|
|
333
350
|
? chunk
|
|
334
351
|
: decoder.decode(chunk, { stream: true });
|
|
352
|
+
// Still skipping past an over-long line: drop everything up to (and
|
|
353
|
+
// including) the next newline, then resume normal line parsing. While no
|
|
354
|
+
// newline has arrived, keep `buf` empty so we don't re-grow it.
|
|
355
|
+
if (overflow) {
|
|
356
|
+
const nl = buf.indexOf("\n");
|
|
357
|
+
if (nl < 0) {
|
|
358
|
+
buf = "";
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
buf = buf.slice(nl + 1);
|
|
362
|
+
overflow = false;
|
|
363
|
+
}
|
|
335
364
|
let idx;
|
|
336
365
|
while ((idx = buf.indexOf("\n")) >= 0) {
|
|
337
366
|
yield buf.slice(0, idx);
|
|
338
367
|
buf = buf.slice(idx + 1);
|
|
339
368
|
}
|
|
369
|
+
// No newline in the remaining buffer and it has blown past the cap — this is
|
|
370
|
+
// a pathological unterminated line. Yield a short head (an invalid-JSON
|
|
371
|
+
// error for the caller) and discard the rest until the next newline.
|
|
372
|
+
if (buf.length > maxLineLength) {
|
|
373
|
+
yield buf.slice(0, 200);
|
|
374
|
+
buf = "";
|
|
375
|
+
overflow = true;
|
|
376
|
+
}
|
|
340
377
|
}
|
|
341
378
|
buf += decoder.decode(); // flush any bytes held from a final partial char
|
|
342
|
-
if (buf.trim()) yield buf;
|
|
379
|
+
if (!overflow && buf.trim()) yield buf;
|
|
343
380
|
}
|
|
344
381
|
|
|
345
382
|
/**
|
|
@@ -497,17 +534,45 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
497
534
|
let settingsHooks = options.settingsHooks || null;
|
|
498
535
|
if (!settingsHooks) {
|
|
499
536
|
try {
|
|
500
|
-
const { loadHooks } =
|
|
537
|
+
const { loadHooks, projectHookTrustNotice } =
|
|
538
|
+
await import("../lib/settings-hooks.cjs");
|
|
501
539
|
const loaded = loadHooks({ cwd, settingsFile: options.settingsFile });
|
|
502
540
|
settingsHooks =
|
|
503
541
|
loaded.hooks && Object.keys(loaded.hooks).length > 0
|
|
504
542
|
? loaded.hooks
|
|
505
543
|
: null;
|
|
544
|
+
// First-run trust notice for an untrusted/cloned repo's shell-running
|
|
545
|
+
// hooks (Claude-Code 2.1.195 parity). stderr keeps the NDJSON stdout clean.
|
|
546
|
+
try {
|
|
547
|
+
const notice = projectHookTrustNotice({
|
|
548
|
+
cwd,
|
|
549
|
+
settingsFile: options.settingsFile,
|
|
550
|
+
});
|
|
551
|
+
if (notice) process.stderr.write(notice + "\n");
|
|
552
|
+
} catch {
|
|
553
|
+
/* trust notice is best-effort */
|
|
554
|
+
}
|
|
506
555
|
} catch {
|
|
507
556
|
settingsHooks = null; // fail-open
|
|
508
557
|
}
|
|
509
558
|
}
|
|
510
559
|
|
|
560
|
+
// autoMode.classifyAllShell (Claude-Code 2.1.193): classify the built-in
|
|
561
|
+
// verification allowlist through the shell-policy instead of fast-pathing it.
|
|
562
|
+
let classifyAllShell = options.classifyAllShell || false;
|
|
563
|
+
if (!classifyAllShell) {
|
|
564
|
+
try {
|
|
565
|
+
const { readBooleanSetting } = await import("../lib/settings-loader.cjs");
|
|
566
|
+
classifyAllShell =
|
|
567
|
+
readBooleanSetting("autoMode.classifyAllShell", {
|
|
568
|
+
cwd,
|
|
569
|
+
settingsFile: options.settingsFile,
|
|
570
|
+
}) === true;
|
|
571
|
+
} catch {
|
|
572
|
+
classifyAllShell = false; // fail-open
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
511
576
|
const input = deps.input || process.stdin;
|
|
512
577
|
const runLoop = deps.agentLoop || coreAgentLoop;
|
|
513
578
|
const doBootstrap = deps.bootstrap || bootstrap;
|
|
@@ -914,6 +979,7 @@ export async function runAgentHeadlessStream(options = {}, deps = {}) {
|
|
|
914
979
|
approvalGate,
|
|
915
980
|
permissionRules,
|
|
916
981
|
settingsHooks,
|
|
982
|
+
classifyAllShell,
|
|
917
983
|
enabledToolNames,
|
|
918
984
|
disabledTools,
|
|
919
985
|
// --interactive-approvals: settings/hook `ask` (and, with an IDE bridge,
|
|
@@ -65,6 +65,22 @@ export function mcpToolName(server, tool) {
|
|
|
65
65
|
return `mcp__${server}__${tool}`;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Case-insensitive "does this header map already carry `name`?". HTTP header
|
|
70
|
+
* names are case-insensitive, so a caller-supplied `AUTHORIZATION` must count
|
|
71
|
+
* the same as `Authorization` — otherwise the OAuth-injection guard below would
|
|
72
|
+
* not see it and would add a SECOND, conflicting auth header, leaking our
|
|
73
|
+
* stored token where the user explicitly pinned their own credential.
|
|
74
|
+
*/
|
|
75
|
+
export function hasHeaderInsensitive(headers, name) {
|
|
76
|
+
if (!headers || typeof headers !== "object") return false;
|
|
77
|
+
const want = String(name).toLowerCase();
|
|
78
|
+
for (const k of Object.keys(headers)) {
|
|
79
|
+
if (k.toLowerCase() === want) return true;
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
68
84
|
/**
|
|
69
85
|
* When an MCP connect fails with an authentication error (HTTP 401/403, or an
|
|
70
86
|
* explicit Unauthorized/Forbidden) on a URL-based server, return an actionable
|
|
@@ -143,7 +159,7 @@ export async function setupMcpFromConfig(servers, deps = {}) {
|
|
|
143
159
|
// unless the config already supplies an Authorization header. Best-effort:
|
|
144
160
|
// no token / a refresh failure just connects unauthenticated.
|
|
145
161
|
let connectCfg = cfg;
|
|
146
|
-
if (cfg.url && !cfg.headers
|
|
162
|
+
if (cfg.url && !hasHeaderInsensitive(cfg.headers, "Authorization")) {
|
|
147
163
|
try {
|
|
148
164
|
const { ensureValidToken } = await import("../lib/mcp-oauth.js");
|
|
149
165
|
const token = await ensureValidToken(cfg.url);
|
|
@@ -152,6 +168,31 @@ export async function setupMcpFromConfig(servers, deps = {}) {
|
|
|
152
168
|
...cfg,
|
|
153
169
|
headers: { ...cfg.headers, Authorization: `Bearer ${token}` },
|
|
154
170
|
};
|
|
171
|
+
// Auto-recover from a mid-session 401/403 (server-side token rotation
|
|
172
|
+
// / revocation while the locally-stored copy still looks unexpired):
|
|
173
|
+
// register a reconnector that force-refreshes the bearer, so the
|
|
174
|
+
// mcp-client's callTool retry path reconnects and re-runs the call
|
|
175
|
+
// once with a fresh token (Claude-Code 2.1.193: "MCP auth re-runs and
|
|
176
|
+
// reconnects automatically on 401/403"). Best-effort, and skipped for
|
|
177
|
+
// a server whose config carries its own Authorization header (handled
|
|
178
|
+
// by the guard above) — an explicit IDE-bridge reconnector registered
|
|
179
|
+
// after setup still wins on any name clash.
|
|
180
|
+
if (typeof mcpClient.setReconnector === "function") {
|
|
181
|
+
const baseCfg = cfg;
|
|
182
|
+
mcpClient.setReconnector(name, async () => {
|
|
183
|
+
const { ensureValidToken: reauth } =
|
|
184
|
+
await import("../lib/mcp-oauth.js");
|
|
185
|
+
const fresh = await reauth(baseCfg.url, { forceRefresh: true });
|
|
186
|
+
if (!fresh) return null;
|
|
187
|
+
return {
|
|
188
|
+
...baseCfg,
|
|
189
|
+
headers: {
|
|
190
|
+
...baseCfg.headers,
|
|
191
|
+
Authorization: `Bearer ${fresh}`,
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
}
|
|
155
196
|
}
|
|
156
197
|
} catch {
|
|
157
198
|
// OAuth wiring is best-effort
|
|
@@ -64,6 +64,17 @@ function joinContent(a, b) {
|
|
|
64
64
|
*/
|
|
65
65
|
const MERGEABLE_ROLES = new Set(["user", "assistant"]);
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Does this message carry tool calls? An assistant turn with `tool_calls` is a
|
|
69
|
+
* STRUCTURED turn whose calls must stay paired with their `tool` results —
|
|
70
|
+
* folding it loses one side's tool_calls (orphaning results / unanswered calls)
|
|
71
|
+
* and the strict-API 400s. Such turns are never merged (left to alternate; the
|
|
72
|
+
* tool-pair fix lives in sanitizeToolPairs, not here).
|
|
73
|
+
*/
|
|
74
|
+
function hasToolCalls(msg) {
|
|
75
|
+
return Array.isArray(msg && msg.tool_calls) && msg.tool_calls.length > 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
67
78
|
/**
|
|
68
79
|
* Merge consecutive same-role messages so the conversation alternates roles for
|
|
69
80
|
* the provider. Only `user`/`assistant` turns fold; `tool` and `system` turns
|
|
@@ -85,7 +96,9 @@ export function mergeConsecutiveMessages(messages) {
|
|
|
85
96
|
msg &&
|
|
86
97
|
typeof msg.role === "string" &&
|
|
87
98
|
MERGEABLE_ROLES.has(msg.role) &&
|
|
88
|
-
prev.role === msg.role
|
|
99
|
+
prev.role === msg.role &&
|
|
100
|
+
!hasToolCalls(prev) && // never fold a structured tool-call turn — merging
|
|
101
|
+
!hasToolCalls(msg) // drops one side's tool_calls and breaks pairing
|
|
89
102
|
) {
|
|
90
103
|
out[out.length - 1] = {
|
|
91
104
|
...prev,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as v,P as u,J as y,U as a,R as n,S,K as C,Q as x,V as w,_ as B,b as s}from"./vendor-BvqAck49.js";import{_ as k}from"./index-BWgNn9As.js";import"./icons-DP3uiYxy.js";const T={__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(),f=String(e.getMonth()+1).padStart(2,"0"),g=String(e.getDate()).padStart(2,"0"),b=String(e.getHours()).padStart(2,"0"),h=String(e.getMinutes()).padStart(2,"0");return`${p}-${f}-${g} ${b}:${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"},R={class:"meta"},M={class:"actor"},O={class:"time"},V={class:"body"};function q(c,d,t,r,i,l){const o=v("a-tag");return u(),y("div",{class:B(["chat-row",{mine:r.isMine}])},[a("div",N,[a("div",R,[a("span",M,n(r.actorLabel),1),a("span",O,n(r.formattedTime),1)]),a("div",V,n(r.messageText),1),t.event.source.adapter?(u(),S(o,{key:0,class:"src",color:r.adapterColor},{default:C(()=>[x(n(t.event.source.adapter),1)]),_:1},8,["color"])):w("v-if",!0)])],2)}const A=k(T,[["render",q],["__scopeId","data-v-49238629"],["__file","/tmp/cc-web-panel-aRyQTO/repo/packages/web-panel/src/components/pdh/renderers/ChatBubbleRenderer.vue"]]);export{A as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as S,P as n,J as i,U as l,S as h,R as o,c,K as d,Q as u,V as g,b as a}from"./vendor-BvqAck49.js";import{_ as b}from"./index-BWgNn9As.js";import{aD as O,aH as D}from"./icons-DP3uiYxy.js";const C={__name:"TimelineRenderer",props:{event:{type:Object,required:!0}},setup(v,{expose:_}){_();const r=v,e=a(()=>r.event.content||{}),p=a(()=>{const t=r.event.source.adapter||"";return t.startsWith("travel-12306")||t.startsWith("travel-ctrip")}),m=a(()=>e.value.from&&e.value.to?`${e.value.from} → ${e.value.to}`:e.value.origin&&e.value.destination?`${e.value.origin} → ${e.value.destination}`:null),s=a(()=>r.event.place||e.value.placeName||e.value.poi),N=a(()=>e.value.trainNo),T=a(()=>e.value.flightNo),y=a(()=>e.value.title||e.value.text||e.value.description||"—"),k=a(()=>{const t=[];return e.value.departureTime&&t.push(`出发 ${e.value.departureTime}`),e.value.arrivalTime&&t.push(`到达 ${e.value.arrivalTime}`),e.value.duration&&t.push(`${e.value.duration}`),e.value.distance&&t.push(`${e.value.distance}`),t.length?t.join(" · "):null}),x=a(()=>{if(!r.event.occurredAt)return"";const t=new Date(r.event.occurredAt);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`}),f={props:r,c:e,isTravel:p,route:m,placeName:s,trainNo:N,flightNo:T,fallbackText:y,extraDetail:k,formattedTime:x,computed:a,get CarOutlined(){return D},get EnvironmentOutlined(){return O}};return Object.defineProperty(f,"__isScriptSetup",{enumerable:!1,value:!0}),f}},R={class:"timeline-event"},V={class:"dot"},w={class:"card"},B={class:"head"},E={class:"time"},j={class:"primary"},A={key:0},H={key:1},I={key:2},M={key:0,class:"trip-no"},P={key:1,class:"extra"};function Q(v,_,r,e,p,m){const s=S("a-tag");return n(),i("div",R,[l("div",V,[e.isTravel?(n(),h(e.CarOutlined,{key:0})):(n(),h(e.EnvironmentOutlined,{key:1}))]),l("div",w,[l("div",B,[l("span",E,o(e.formattedTime),1),c(s,{color:"cyan"},{default:d(()=>[u(o(r.event.source.adapter),1)]),_:1}),c(s,null,{default:d(()=>[u(o(r.event.subtype),1)]),_:1})]),l("div",j,[e.route?(n(),i("span",A,o(e.route),1)):e.placeName?(n(),i("span",H,"📍 "+o(e.placeName),1)):(n(),i("span",I,o(e.fallbackText),1))]),e.trainNo||e.flightNo?(n(),i("div",M,[c(s,{color:"blue"},{default:d(()=>[u(o(e.trainNo||e.flightNo),1)]),_:1})])):g("v-if",!0),e.extraDetail?(n(),i("div",P,o(e.extraDetail),1)):g("v-if",!0)])])}const J=b(C,[["render",Q],["__scopeId","data-v-18400280"],["__file","/tmp/cc-web-panel-aRyQTO/repo/packages/web-panel/src/components/pdh/renderers/TimelineRenderer.vue"]]);export{J as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{R as r}from"./index-BWgNn9As.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{C as o}from"./Col-BHonE9fU.js";import{a0 as t}from"./index-BWgNn9As.js";import"./vendor-BvqAck49.js";import"./index-BSpFe6j5.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as o}from"./Row-1MEtrgtF.js";import{a0 as t}from"./index-BWgNn9As.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-BQFRzFeZ.js";import"./useFlexGapSupport-Q7bDZ3EI.js";import"./styleChecker-B-Suj978.js";import"./index-BSpFe6j5.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};
|