chainlesschain 0.162.124 → 0.162.126
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/.build-hash +1 -1
- package/src/assets/web-panel/assets/AIOps-BrTOcqIJ.js +1 -0
- package/src/assets/web-panel/assets/{ActionButton-COjZZKWG.js → ActionButton-na9cocmf.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-4ZDZE7lc.js → Analytics-BtDygkpt.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CYH5k2Rp.js → AppLayout-D_t5CS18.js} +5 -5
- package/src/assets/web-panel/assets/Audit-BYMZccCy.js +1 -0
- package/src/assets/web-panel/assets/{Backup-CiX61Qc2.js → Backup-D2qDfAdL.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CDxIQokd.js → BaseInput-kj456Ju9.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CaKgdRab.js → Chat-BY0A0ZLE.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-D1VvrOPQ.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-CjiWfu4s.js → Checkbox-DiBhtXsh.js} +1 -1
- package/src/assets/web-panel/assets/Codegen-B1ER0L0j.js +1 -0
- package/src/assets/web-panel/assets/{Col-ZKWREyNs.js → Col-CjLmza7D.js} +1 -1
- package/src/assets/web-panel/assets/Community-BNId05U7.js +1 -0
- package/src/assets/web-panel/assets/{Compact-DqknM98n.js → Compact-BuuMj7K1.js} +1 -1
- package/src/assets/web-panel/assets/Compliance-DUuDycaJ.js +1 -0
- package/src/assets/web-panel/assets/{Cowork-Dp29kHsC.js → Cowork-BKHiF6uL.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-zmEJAetz.js → Cron-C7p-lHnC.js} +2 -2
- package/src/assets/web-panel/assets/Crosschain-BvSOx8a6.js +1 -0
- package/src/assets/web-panel/assets/{DID-D_UFNzJ5.js → DID-D1k9jgHv.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-B9mCCnqY.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-CH7l3KCs.js → Dropdown-ge9UHSXF.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Bud2M3XX.js → EmailListRenderer-TZO7ppXi.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bd2_8uME.js → FamilyGuardDashboard-DkhLJmzx.js} +1 -1
- package/src/assets/web-panel/assets/Federation-JLuA_8zp.js +1 -0
- package/src/assets/web-panel/assets/{FormItemContext-CpSH464Y.js → FormItemContext-C4w-rzNg.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CANo8O-y.js → GenericCardRenderer-Btns4sV9.js} +1 -1
- package/src/assets/web-panel/assets/{Git-hvuZVoD3.js → Git-BheXMjzC.js} +2 -2
- package/src/assets/web-panel/assets/Governance-D9rLlatH.js +1 -0
- package/src/assets/web-panel/assets/Inference-DiklIMcd.js +1 -0
- package/src/assets/web-panel/assets/KnowledgeGraph-C70EWL03.js +1 -0
- package/src/assets/web-panel/assets/{Logs-DDkTnedu.js → Logs-Zt_MLI10.js} +2 -2
- package/src/assets/web-panel/assets/Marketplace-suQxES99.js +1 -0
- package/src/assets/web-panel/assets/{McpTools-Qx78XyOT.js → McpTools-CclpCDpY.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CXYDO1oT.js → Memory-B2lHOUwF.js} +2 -2
- package/src/assets/web-panel/assets/MobileBridge-BMXKoDAD.js +1 -0
- package/src/assets/web-panel/assets/{MobileProjects-DEDbWNIk.js → MobileProjects-a6mWVdBV.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Dwa_vlR8.js → Mtc-BFpM4Fkj.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DAVkxhJv.js → MtcAudit-DDQkxkbS.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-C3upmgPN.js → Multisig-Crkd_zKQ.js} +3 -3
- package/src/assets/web-panel/assets/NLProgramming-Dpk5An7B.js +1 -0
- package/src/assets/web-panel/assets/{Notes-B1Oy3FbC.js → Notes-BrFnOMNz.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-Bs4-Fc6b.js → NotificationSettings-CM0iApFM.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CEy1pIeq.js → OrderTableRenderer-XXjeqkdz.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-D4cJ1UNo.js → Organization-CHFW_38T.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-fdzvlF7x.js → Overflow-C-vl3EjV.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Y13PwXBA.js → P2P-BT7Slavq.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Ck1zCLe6.js → PdhVaultBrowser-DRUaULap.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CvEXP6LC.js → Permissions-DkhOAvMz.js} +2 -2
- package/src/assets/web-panel/assets/{PersonalDataHub-JeP7IWMW.js → PersonalDataHub-Dl7dSOvV.js} +3 -3
- package/src/assets/web-panel/assets/Pipeline-B3nVI4p6.js +1 -0
- package/src/assets/web-panel/assets/Privacy-Dv1SXx1Q.js +1 -0
- package/src/assets/web-panel/assets/{ProjectInit-DeWd9UcS.js → ProjectInit-DrAhVi5p.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DUpVuU9F.js → ProjectSettings-h-ggCYN_.js} +2 -2
- package/src/assets/web-panel/assets/Projects-CM91hYdr.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DECW00ek.js → Providers-rfkZel3N.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Dl-pK9Io.js → QuickAsk-XepZB7h_.js} +1 -1
- package/src/assets/web-panel/assets/Recommend-DzQWsh1a.js +1 -0
- package/src/assets/web-panel/assets/Reputation-CDeaal0j.js +1 -0
- package/src/assets/web-panel/assets/Row-BN4aKhFH.js +1 -0
- package/src/assets/web-panel/assets/{RssFeed-iyQT5q9l.js → RssFeed-INP6VYAA.js} +3 -3
- package/src/assets/web-panel/assets/Search-ChPbwatu.js +1 -0
- package/src/assets/web-panel/assets/{Security-c4Jxf5Ih.js → Security-C97ZCY8N.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CRuisolj.js → Services-Cbtl2Ajs.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CCnzJkb-.js → Skeleton-B13sFxBQ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CZURCwZg.js → Skills-vI9zSIKX.js} +1 -1
- package/src/assets/web-panel/assets/Sla-Cr3oBH39.js +1 -0
- package/src/assets/web-panel/assets/SpeechSettings-BwemqPPV.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-CJWVtd87.js → SyncSettings-CLA78P-Z.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-61lrQ_lS.js → Tasks-DBjQ_DOM.js} +1 -1
- package/src/assets/web-panel/assets/Templates-BkSLDkBs.js +1 -0
- package/src/assets/web-panel/assets/Tenant-Dn0nSlib.js +1 -0
- package/src/assets/web-panel/assets/{Terminal-CP15hcNS.js → Terminal-C8f4boru.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Sl5uXrkN.js → TimelineRenderer-DW_rMtJR.js} +1 -1
- package/src/assets/web-panel/assets/Tokens-BdffrKYV.js +1 -0
- package/src/assets/web-panel/assets/{Trigger-BLCQEOF2.js → Trigger-CX4CUg-Q.js} +1 -1
- package/src/assets/web-panel/assets/Trust-Cq9Bl7Od.js +1 -0
- package/src/assets/web-panel/assets/{UkeySign-Dwp0zXQ6.js → UkeySign-BQy18_VY.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CIHA55Sx.js → VideoEditing-h5hzK7Vw.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Hjajvnto.js → Wallet-BLotT3gw.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-DqSURUvI.js → WebAuthn-8cCANYLE.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-B5bHRwUG.js → WorkflowEditor-Db6NwtAv.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DsheLKkG.js → chat-BPk1LbpL.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CST2UkgL.js → colors-BnNal71p.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-yqEoy1L7.js → compact-item-W2VC0tcy.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Jwp78HFY.js → createContext-DceVsgnZ.js} +1 -1
- package/src/assets/web-panel/assets/devWarning--rwFDBhx.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CVS5mFEP.js → hasIn-BEq6EDcp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLTUVd0V.js → index-5gIBUFBn.js} +2 -2
- package/src/assets/web-panel/assets/index-APCHxOkM.js +3 -0
- package/src/assets/web-panel/assets/index-B2dMhwZi.js +1 -0
- package/src/assets/web-panel/assets/{index-C0FZScMe.js → index-B8cPjrEH.js} +4 -4
- package/src/assets/web-panel/assets/{index-CjfN2CpJ.js → index-BDC5HsxZ.js} +1 -1
- package/src/assets/web-panel/assets/index-BPFuPGKi.js +1 -0
- package/src/assets/web-panel/assets/{index-SjxCCf5h.js → index-BUkDcIwJ.js} +2 -2
- package/src/assets/web-panel/assets/{index-Cjig5i3a.js → index-BWcCyH6-.js} +28 -26
- package/src/assets/web-panel/assets/{index-AnW25bEq.js → index-BgZikQoh.js} +1 -1
- package/src/assets/web-panel/assets/index-Bwjus13Y.js +1 -0
- package/src/assets/web-panel/assets/index-BzSzRWsw.js +55 -0
- package/src/assets/web-panel/assets/index-C1K9CsGr.js +1 -0
- package/src/assets/web-panel/assets/{index-DDAigsel.js → index-CBZVISK6.js} +2 -2
- package/src/assets/web-panel/assets/index-CEJN-R2L.js +1 -0
- package/src/assets/web-panel/assets/index-CG5dGC9E.js +1 -0
- package/src/assets/web-panel/assets/{index-DxaU_lza.js → index-CMGLpstm.js} +1 -1
- package/src/assets/web-panel/assets/index-CWrGCndd.js +1 -0
- package/src/assets/web-panel/assets/index-CbcvfpCV.js +1 -0
- package/src/assets/web-panel/assets/{index-De600Jjm.js → index-Ceqv4lI2.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cy0dNzkp.js → index-CsT6frT8.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDAPnZUs.js → index-D8PQKsDT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Crk4KWLW.js → index-DGncdA-j.js} +1 -1
- package/src/assets/web-panel/assets/{index-R-VGFpi6.js → index-DHanQHO0.js} +3 -3
- package/src/assets/web-panel/assets/index-DaUBk28E.js +12 -0
- package/src/assets/web-panel/assets/{index-BzetOasL.js → index-Di2J4b4V.js} +1 -1
- package/src/assets/web-panel/assets/index-DtuLvWZN.js +21 -0
- package/src/assets/web-panel/assets/{index-Dgyn8-wN.js → index-DvS1J8xc.js} +2 -2
- package/src/assets/web-panel/assets/{index-CtyEOGuj.js → index-DxePJdwP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzsKK0tQ.js → index-Et4XvL49.js} +2 -2
- package/src/assets/web-panel/assets/{index-BuI27WSx.js → index-GlFxgcj4.js} +2 -2
- package/src/assets/web-panel/assets/index-HV119Oui.js +1 -0
- package/src/assets/web-panel/assets/index-InGW87pj.js +13 -0
- package/src/assets/web-panel/assets/{index-Dxljh9Fu.js → index-P1-s8JR7.js} +2 -2
- package/src/assets/web-panel/assets/{index-CSBPc-sI.js → index-SdABCNoi.js} +2 -2
- package/src/assets/web-panel/assets/{index-BCHAUdel.js → index-WTAZbN-c.js} +1 -1
- package/src/assets/web-panel/assets/index-_2I-KzOj.js +1 -0
- package/src/assets/web-panel/assets/index-m1sVaWVU.js +1 -0
- package/src/assets/web-panel/assets/index-s37wwyeN.js +1 -0
- package/src/assets/web-panel/assets/{index-CRBbVS43.js → index-tyWABqp9.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-ClAjrsQ-.js → initDefaultProps-DzrCDb3j.js} +1 -1
- package/src/assets/web-panel/assets/motion-BQERVnE3.js +11 -0
- package/src/assets/web-panel/assets/{move-DMelzIW-.js → move-I9ACA5XJ.js} +1 -1
- package/src/assets/web-panel/assets/mtc-parser-Dd2Pw-tr.js +1 -0
- package/src/assets/web-panel/assets/{omit-oxecfU3b.js → omit-DwzYRzWV.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DJ5F5M6x.js → pickAttrs-BSGULyIL.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DdbKsant.js → placementArrow-tSYYjAts.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BUuM5cmS.js → responsiveObserve-Dy2lqikT.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DSV0ccvR.js → slide-RaB4Uq0c.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B-6oLAXf.js → statusUtils-CBpC_wZg.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DdCAHtsZ.js → styleChecker-BEKwPWt5.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-ZORkcoZd.js → useFlexGapSupport-C4CnYJH1.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BFp46LoP.js → useFs-n24jutw5.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-H7rxgbdW.js → usePersonalDataHub-DMgS8F6G.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-eIq4Tk0J.js → vnode-BSp2KYcj.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CTNrv8-H.js → zoom-7UfQtTPh.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +51 -2
- package/src/commands/compliance.js +3 -1
- package/src/commands/ide.js +60 -5
- package/src/commands/incentive.js +22 -22
- package/src/commands/mtc.js +5 -1
- package/src/commands/review.js +47 -17
- package/src/commands/session.js +11 -2
- package/src/gateways/ws/message-dispatcher.js +149 -166
- package/src/gateways/ws/ws-session-gateway.js +95 -9
- package/src/harness/background-task-manager.js +5 -1
- package/src/harness/jsonl-session-store.js +90 -12
- package/src/harness/mcp-client.js +62 -21
- package/src/harness/prompt-compressor.js +24 -5
- package/src/harness/worktree-isolator.js +10 -1
- package/src/lib/agent-core.js +2 -0
- package/src/lib/audit-logger.js +3 -1
- package/src/lib/autonomous-agent.js +29 -0
- package/src/lib/chat-core.js +5 -2
- package/src/lib/chat-intent-service.js +82 -23
- package/src/lib/checkpoint-store.js +31 -4
- package/src/lib/claude-code-bridge.js +48 -3
- package/src/lib/config-manager.js +25 -1
- package/src/lib/cost-budget.js +13 -2
- package/src/lib/credential-guard.js +81 -1
- package/src/lib/git-integration.js +16 -2
- package/src/lib/goal-store.js +11 -0
- package/src/lib/hook-manager.js +4 -0
- package/src/lib/interaction-adapter.js +32 -11
- package/src/lib/jetbrains-bridge.js +147 -0
- package/src/lib/jsonl-session-store.js +2 -0
- package/src/lib/llm-config-defaults.js +37 -0
- package/src/lib/llm-pricing.js +11 -4
- package/src/lib/llm-providers.js +11 -1
- package/src/lib/mcp-oauth.js +88 -10
- package/src/lib/mcp-serve.js +29 -0
- package/src/lib/orchestrator.js +38 -2
- package/src/lib/permission-engine.js +4 -1
- package/src/lib/pipeline-orchestrator.js +20 -2
- package/src/lib/project-instructions.js +13 -0
- package/src/lib/repl-bang-memorize.js +9 -1
- package/src/lib/repl-denials.js +137 -0
- package/src/lib/runnable-provider.js +7 -1
- 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/session-insights.js +13 -6
- package/src/lib/session-usage.js +21 -3
- 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/status-line.cjs +4 -1
- package/src/lib/stream-retry.js +27 -0
- package/src/lib/sub-agent-context.js +9 -0
- package/src/lib/turn-context.js +15 -5
- package/src/repl/agent-repl.js +110 -8
- package/src/runtime/__tests__/message-roles.test.js +36 -3
- package/src/runtime/agent-core.js +179 -52
- 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 +96 -2
- package/src/runtime/headless-stream.js +78 -3
- package/src/runtime/mcp-config.js +114 -4
- package/src/runtime/message-roles.js +14 -1
- package/src/runtime/pipe-safety.js +51 -0
- package/src/runtime/policies/agent-policy.js +3 -0
- package/src/assets/web-panel/assets/AIOps-BsDJlD_l.js +0 -1
- package/src/assets/web-panel/assets/Audit-BKlFbLdl.js +0 -1
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DgvpwU5o.js +0 -1
- package/src/assets/web-panel/assets/Codegen-tKWGzajw.js +0 -1
- package/src/assets/web-panel/assets/Community-CmLuPBUU.js +0 -1
- package/src/assets/web-panel/assets/Compliance-PZw0aBLI.js +0 -1
- package/src/assets/web-panel/assets/Crosschain-Sb-uM7Ty.js +0 -1
- package/src/assets/web-panel/assets/Dashboard-Btag698v.js +0 -3
- package/src/assets/web-panel/assets/Federation-1jhstF5P.js +0 -1
- package/src/assets/web-panel/assets/Governance-BQrWksKt.js +0 -1
- package/src/assets/web-panel/assets/Inference-jEBTp12v.js +0 -1
- package/src/assets/web-panel/assets/KnowledgeGraph-tDiV2taf.js +0 -1
- package/src/assets/web-panel/assets/Marketplace-9Yi32avt.js +0 -1
- package/src/assets/web-panel/assets/MobileBridge-MfUfkHA0.js +0 -1
- package/src/assets/web-panel/assets/NLProgramming-DO3CZ0_z.js +0 -1
- package/src/assets/web-panel/assets/Pipeline-BZ7wRzG1.js +0 -1
- package/src/assets/web-panel/assets/Privacy-BJ6qj9Hv.js +0 -1
- package/src/assets/web-panel/assets/Projects-y1WbI337.js +0 -1
- package/src/assets/web-panel/assets/Recommend-Bju04wTd.js +0 -1
- package/src/assets/web-panel/assets/Reputation-BUPa3nEk.js +0 -1
- package/src/assets/web-panel/assets/Row-WYqqaq_5.js +0 -1
- package/src/assets/web-panel/assets/Search-CrfwJF0R.js +0 -1
- package/src/assets/web-panel/assets/Sla-CrMzaEi2.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-jTDOM5eY.js +0 -1
- package/src/assets/web-panel/assets/Templates-Cg-iF2g1.js +0 -1
- package/src/assets/web-panel/assets/Tenant-DrDv1FFc.js +0 -1
- package/src/assets/web-panel/assets/Tokens-yRIZTVsR.js +0 -1
- package/src/assets/web-panel/assets/Trust-D5xq8z6s.js +0 -1
- package/src/assets/web-panel/assets/community-parser-Cuyslaku.js +0 -3
- package/src/assets/web-panel/assets/devWarning-C8to6gQk.js +0 -1
- package/src/assets/web-panel/assets/index-BeblNJDH.js +0 -1
- package/src/assets/web-panel/assets/index-C130LLPq.js +0 -1
- package/src/assets/web-panel/assets/index-C8rq85gu.js +0 -1
- package/src/assets/web-panel/assets/index-CIE2n8k_.js +0 -1
- package/src/assets/web-panel/assets/index-CTd3lDxp.js +0 -13
- package/src/assets/web-panel/assets/index-CUWj5L2s.js +0 -1
- package/src/assets/web-panel/assets/index-ChRL6rgA.js +0 -3
- package/src/assets/web-panel/assets/index-CrlRa054.js +0 -1
- package/src/assets/web-panel/assets/index-Cu6Ql64n.js +0 -1
- package/src/assets/web-panel/assets/index-Cx_t5rWw.js +0 -12
- package/src/assets/web-panel/assets/index-DZfnYE6e.js +0 -1
- package/src/assets/web-panel/assets/index-D_1b7uh6.js +0 -55
- package/src/assets/web-panel/assets/index-D_e9gwfn.js +0 -1
- package/src/assets/web-panel/assets/index-DbxAlpPC.js +0 -21
- package/src/assets/web-panel/assets/index-DiK4vSZa.js +0 -1
- package/src/assets/web-panel/assets/index-DpYn5v2k.js +0 -1
- package/src/assets/web-panel/assets/index-diWkx2Wq.js +0 -1
- package/src/assets/web-panel/assets/motion-BalXv_60.js +0 -11
- package/src/assets/web-panel/assets/mtc-parser-CEQffxds.js +0 -1
package/src/lib/sandbox-v2.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import crypto from "crypto";
|
|
7
|
+
import { safeJsonParse } from "./safe-json.js";
|
|
7
8
|
import { createRequire } from "module";
|
|
8
9
|
|
|
9
10
|
const _require = createRequire(import.meta.url);
|
|
@@ -429,9 +430,9 @@ export function getSandbox(db, sandboxId) {
|
|
|
429
430
|
id: row.id,
|
|
430
431
|
agentId: row.agent_id,
|
|
431
432
|
status: row.status,
|
|
432
|
-
permissions:
|
|
433
|
-
quota:
|
|
434
|
-
resourceUsage:
|
|
433
|
+
permissions: safeJsonParse(row.permissions, {}),
|
|
434
|
+
quota: safeJsonParse(row.quota, {}),
|
|
435
|
+
resourceUsage: safeJsonParse(row.resource_usage, {}),
|
|
435
436
|
createdAt: row.created_at,
|
|
436
437
|
};
|
|
437
438
|
}
|
|
@@ -609,9 +610,9 @@ export function restoreFromDb(db) {
|
|
|
609
610
|
id: row.id,
|
|
610
611
|
agentId: row.agent_id,
|
|
611
612
|
status: row.status || "active",
|
|
612
|
-
permissions:
|
|
613
|
-
quota:
|
|
614
|
-
resourceUsage:
|
|
613
|
+
permissions: safeJsonParse(row.permissions, {}),
|
|
614
|
+
quota: safeJsonParse(row.quota, {}),
|
|
615
|
+
resourceUsage: safeJsonParse(row.resource_usage, {}),
|
|
615
616
|
createdAt: row.created_at || new Date(now).toISOString(),
|
|
616
617
|
policy,
|
|
617
618
|
createdAtMs: row.created_at_ms || now,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* search-command — build the shell command for the agent `search_files` tool
|
|
3
|
+
* with the model/user-supplied pattern SAFELY embedded.
|
|
4
|
+
*
|
|
5
|
+
* The pattern flows into execSync (a real shell), so a raw interpolation
|
|
6
|
+
* (`grep -i "${pattern}"`) is a command-injection vector: a pattern like
|
|
7
|
+
* `x" ; curl evil ; "` runs arbitrary commands — and `search_files` is
|
|
8
|
+
* read-only + NOT confirm-gated, so it would bypass the `run_shell`
|
|
9
|
+
* ApprovalGate + credential guards entirely (reachable via prompt-injection).
|
|
10
|
+
* Raw interpolation is also semantically wrong: the shell would expand `$HOME`,
|
|
11
|
+
* backticks, globs, etc. in the pattern instead of searching for them literally.
|
|
12
|
+
*
|
|
13
|
+
* Fix: quote the pattern so every shell metacharacter is inert. The emitted
|
|
14
|
+
* commands (and therefore the output format `_ingestSearchOutput` parses) are
|
|
15
|
+
* otherwise unchanged.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** POSIX single-quote: wrap in '…' and escape any embedded ' as '\''. Single
|
|
19
|
+
* quotes neutralize EVERY shell metacharacter, so nothing inside is expanded
|
|
20
|
+
* or can break out. */
|
|
21
|
+
export function shquotePosix(s) {
|
|
22
|
+
return `'${String(s).replace(/'/g, "'\\''")}'`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Build `{ cmd }` for a search, or `{ error }` when the pattern can't be made
|
|
27
|
+
* safe on the target platform.
|
|
28
|
+
*
|
|
29
|
+
* @param {object} a
|
|
30
|
+
* @param {string} a.pattern the raw search pattern
|
|
31
|
+
* @param {boolean} a.isContent content search (grep/findstr) vs filename
|
|
32
|
+
* @param {string} [a.platform=process.platform]
|
|
33
|
+
* @returns {{cmd:string}|{error:string}}
|
|
34
|
+
*/
|
|
35
|
+
export function buildSearchCommand({
|
|
36
|
+
pattern,
|
|
37
|
+
isContent,
|
|
38
|
+
platform = process.platform,
|
|
39
|
+
}) {
|
|
40
|
+
const pat = String(pattern ?? "");
|
|
41
|
+
|
|
42
|
+
if (platform === "win32") {
|
|
43
|
+
// cmd.exe has no reliable way to escape an embedded double-quote, and the
|
|
44
|
+
// pattern is double-quoted below — so reject a literal `"` (rare in a search
|
|
45
|
+
// pattern; run_shell handles complex cases). Every OTHER metacharacter
|
|
46
|
+
// (& | < > ^ ( )) is literal INSIDE cmd double quotes, so quoting the
|
|
47
|
+
// pattern closes the injection while leaving the redirect (2>NUL) outside.
|
|
48
|
+
if (pat.includes('"')) {
|
|
49
|
+
return {
|
|
50
|
+
error: 'search pattern may not contain a double-quote (") on Windows',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
cmd: isContent
|
|
55
|
+
? `findstr /s /i /n "${pat}" *`
|
|
56
|
+
: `dir /s /b "*${pat}*" 2>NUL`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
cmd: isContent
|
|
62
|
+
? `grep -r -l -i ${shquotePosix(pat)} . --include="*" 2>/dev/null | head -20`
|
|
63
|
+
: `find . -name ${shquotePosix(`*${pat}*`)} -type f 2>/dev/null | head -20`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -31,7 +31,7 @@ function isToolError(event) {
|
|
|
31
31
|
const r = event?.data?.result;
|
|
32
32
|
return Boolean(
|
|
33
33
|
event?.data?.error ||
|
|
34
|
-
|
|
34
|
+
(r && typeof r === "object" && (r.error || r.is_error || r.isError)),
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -46,11 +46,18 @@ export function analyzeSession(events, sessionId) {
|
|
|
46
46
|
const evs = Array.isArray(events) ? events : [];
|
|
47
47
|
const start = evs.find((e) => e && e.type === "session_start");
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
// Single-pass min/max (NOT Math.min(...stamps)): spreading a per-event array
|
|
50
|
+
// throws RangeError "Maximum call stack size exceeded" past ~130k elements, so
|
|
51
|
+
// a long session would crash `cc insights`. A reduce-style scan is O(n) and
|
|
52
|
+
// size-independent.
|
|
53
|
+
let startedAt = null;
|
|
54
|
+
let endedAt = null;
|
|
55
|
+
for (const e of evs) {
|
|
56
|
+
const t = Number(e?.timestamp);
|
|
57
|
+
if (!Number.isFinite(t) || t <= 0) continue;
|
|
58
|
+
if (startedAt == null || t < startedAt) startedAt = t;
|
|
59
|
+
if (endedAt == null || t > endedAt) endedAt = t;
|
|
60
|
+
}
|
|
54
61
|
const durationMs =
|
|
55
62
|
startedAt != null && endedAt != null ? endedAt - startedAt : 0;
|
|
56
63
|
|
package/src/lib/session-usage.js
CHANGED
|
@@ -13,6 +13,12 @@ import {
|
|
|
13
13
|
listJsonlSessions,
|
|
14
14
|
} from "../harness/jsonl-session-store.js";
|
|
15
15
|
|
|
16
|
+
// Injectable disk seams (tests override). readEvents skips malformed JSON lines
|
|
17
|
+
// but does NOT guard readFileSync, so an unreadable session file (EACCES /
|
|
18
|
+
// EISDIR / a Windows lock / an ENOENT race after existsSync) throws — which
|
|
19
|
+
// allSessionsUsage tolerates per-session below.
|
|
20
|
+
export const _deps = { readEvents, listJsonlSessions };
|
|
21
|
+
|
|
16
22
|
const USAGE_EVENT_TYPES = new Set([
|
|
17
23
|
"token_usage",
|
|
18
24
|
"assistant_message",
|
|
@@ -138,7 +144,7 @@ export function aggregateUsage(events) {
|
|
|
138
144
|
* Roll up usage for a single JSONL session.
|
|
139
145
|
*/
|
|
140
146
|
export function sessionUsage(sessionId) {
|
|
141
|
-
const events = readEvents(sessionId);
|
|
147
|
+
const events = _deps.readEvents(sessionId);
|
|
142
148
|
const agg = aggregateUsage(events);
|
|
143
149
|
return { sessionId, ...agg };
|
|
144
150
|
}
|
|
@@ -147,8 +153,19 @@ export function sessionUsage(sessionId) {
|
|
|
147
153
|
* Roll up usage across every JSONL session on disk.
|
|
148
154
|
*/
|
|
149
155
|
export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
150
|
-
const sessions = listJsonlSessions({ limit });
|
|
151
|
-
|
|
156
|
+
const sessions = _deps.listJsonlSessions({ limit });
|
|
157
|
+
// One unreadable / corrupt session file (sessionUsage → readEvents →
|
|
158
|
+
// readFileSync can throw on EACCES/EISDIR/lock) must NOT abort the whole
|
|
159
|
+
// roll-up. Skip the failed session and report how many were skipped.
|
|
160
|
+
const perSession = [];
|
|
161
|
+
let skipped = 0;
|
|
162
|
+
for (const s of sessions || []) {
|
|
163
|
+
try {
|
|
164
|
+
perSession.push(sessionUsage(s.id));
|
|
165
|
+
} catch {
|
|
166
|
+
skipped++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
152
169
|
|
|
153
170
|
const total = {
|
|
154
171
|
inputTokens: 0,
|
|
@@ -191,6 +208,7 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
191
208
|
|
|
192
209
|
return {
|
|
193
210
|
sessions: perSession,
|
|
211
|
+
skipped,
|
|
194
212
|
total,
|
|
195
213
|
byModel: Array.from(byKey.values()).sort(
|
|
196
214
|
(a, b) => b.totalTokens - a.totalTokens,
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
const path = require("node:path");
|
|
28
28
|
const os = require("node:os");
|
|
29
29
|
const fsDefault = require("node:fs");
|
|
30
|
+
const crypto = require("node:crypto");
|
|
30
31
|
const { SUGGEST_UMBRELLA } = require("./permission-rules.cjs");
|
|
31
32
|
const { projectRootBase } = require("./project-root.cjs");
|
|
32
33
|
|
|
@@ -179,8 +180,140 @@ function collectHooks(hooksBlock, event, toolName) {
|
|
|
179
180
|
return out;
|
|
180
181
|
}
|
|
181
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Every command-hook in a parsed settings object, tagged with the event +
|
|
185
|
+
* matcher it fires under (so a fingerprint reflects WHEN it runs, not just the
|
|
186
|
+
* command string). Mirrors loadHooks' command-hook filter.
|
|
187
|
+
*/
|
|
188
|
+
function extractCommandHooks(data) {
|
|
189
|
+
const out = [];
|
|
190
|
+
const block =
|
|
191
|
+
data && data.hooks && typeof data.hooks === "object" ? data.hooks : null;
|
|
192
|
+
if (!block) return out;
|
|
193
|
+
for (const [event, groups] of Object.entries(block)) {
|
|
194
|
+
if (!Array.isArray(groups)) continue;
|
|
195
|
+
for (const g of groups) {
|
|
196
|
+
if (!g || typeof g !== "object" || !Array.isArray(g.hooks)) continue;
|
|
197
|
+
for (const h of g.hooks) {
|
|
198
|
+
if (h && h.type === "command" && h.command) {
|
|
199
|
+
out.push({
|
|
200
|
+
event,
|
|
201
|
+
matcher: g.matcher ?? null,
|
|
202
|
+
command: String(h.command),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return out;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** `~/.chainlesschain/hook-trust.json` — remembered first-run acknowledgments. */
|
|
212
|
+
function hookTrustStorePath() {
|
|
213
|
+
return path.join(_deps.homedir(), ".chainlesschain", "hook-trust.json");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function readHookTrustStore() {
|
|
217
|
+
try {
|
|
218
|
+
const f = hookTrustStorePath();
|
|
219
|
+
if (!_deps.fs.existsSync(f)) return {};
|
|
220
|
+
const parsed = JSON.parse(_deps.fs.readFileSync(f, "utf-8"));
|
|
221
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
222
|
+
} catch {
|
|
223
|
+
return {}; // unreadable store → treat as nothing acknowledged
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function writeHookTrustStore(store) {
|
|
228
|
+
try {
|
|
229
|
+
const f = hookTrustStorePath();
|
|
230
|
+
_deps.fs.mkdirSync(path.dirname(f), { recursive: true });
|
|
231
|
+
_deps.fs.writeFileSync(f, JSON.stringify(store, null, 2), "utf-8");
|
|
232
|
+
return true;
|
|
233
|
+
} catch {
|
|
234
|
+
return false; // best-effort — a failed write just re-shows the notice
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* First-run trust notice for project-sourced settings.json hooks (which run
|
|
240
|
+
* shell). The user's own `~/.claude/settings.json` and an explicit `--settings`
|
|
241
|
+
* file are trusted; only the project's `.claude/settings{,.local}.json` (project
|
|
242
|
+
* root + cwd) carry the cloned-repo auto-execution risk that Claude-Code 2.1.195
|
|
243
|
+
* gated ("untrusted project config must require explicit consent").
|
|
244
|
+
*
|
|
245
|
+
* Returns a one-line notice (and records an acknowledgment hash) the FIRST time
|
|
246
|
+
* a project's shell-running hooks are seen — and again only if those hooks
|
|
247
|
+
* change. Returns null when there are no project hooks, the hooks are unchanged
|
|
248
|
+
* since last acknowledged, or the notice is disabled (`CC_HOOK_TRUST_NOTICE=0`,
|
|
249
|
+
* or hooks themselves are off via `CC_SETTINGS_HOOKS=0`). Best-effort: a failed
|
|
250
|
+
* store write still returns the notice (shown again next run) rather than
|
|
251
|
+
* throwing — it must never abort agent startup.
|
|
252
|
+
*
|
|
253
|
+
* @returns {string|null}
|
|
254
|
+
*/
|
|
255
|
+
function projectHookTrustNotice({ cwd = process.cwd(), settingsFile } = {}) {
|
|
256
|
+
if (process.env.CC_HOOK_TRUST_NOTICE === "0") return null;
|
|
257
|
+
if (process.env.CC_SETTINGS_HOOKS === "0") return null; // hooks won't run anyway
|
|
258
|
+
const home = path.join(_deps.homedir(), ".claude", "settings.json");
|
|
259
|
+
const explicit = settingsFile ? path.resolve(cwd, settingsFile) : null;
|
|
260
|
+
const trusted = new Set([home, explicit].filter(Boolean));
|
|
261
|
+
const seen = new Set();
|
|
262
|
+
const projectFiles = settingsFiles(cwd, settingsFile).filter((f) => {
|
|
263
|
+
if (trusted.has(f) || seen.has(f)) return false;
|
|
264
|
+
seen.add(f);
|
|
265
|
+
return true;
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const entries = [];
|
|
269
|
+
const contributing = [];
|
|
270
|
+
for (const f of projectFiles) {
|
|
271
|
+
let data;
|
|
272
|
+
try {
|
|
273
|
+
if (!_deps.fs.existsSync(f)) continue;
|
|
274
|
+
data = JSON.parse(_deps.fs.readFileSync(f, "utf-8"));
|
|
275
|
+
} catch {
|
|
276
|
+
continue; // malformed JSON is surfaced by loadHooks' own warn path
|
|
277
|
+
}
|
|
278
|
+
const cmds = extractCommandHooks(data);
|
|
279
|
+
if (cmds.length) {
|
|
280
|
+
entries.push(...cmds);
|
|
281
|
+
contributing.push(f);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (entries.length === 0) return null;
|
|
285
|
+
|
|
286
|
+
const fingerprint = entries
|
|
287
|
+
.map((e) => `${e.event}${e.matcher ?? ""}${e.command}`)
|
|
288
|
+
.sort();
|
|
289
|
+
const hash = crypto
|
|
290
|
+
.createHash("sha256")
|
|
291
|
+
.update(JSON.stringify(fingerprint))
|
|
292
|
+
.digest("hex");
|
|
293
|
+
const key = projectRootBase(cwd, { fs: _deps.fs, path }) || cwd;
|
|
294
|
+
|
|
295
|
+
const store = readHookTrustStore();
|
|
296
|
+
if (store[key] && store[key].hash === hash) return null; // already acknowledged
|
|
297
|
+
store[key] = {
|
|
298
|
+
hash,
|
|
299
|
+
files: contributing,
|
|
300
|
+
count: entries.length,
|
|
301
|
+
at: new Date().toISOString(),
|
|
302
|
+
};
|
|
303
|
+
writeHookTrustStore(store); // best-effort acknowledgment
|
|
304
|
+
|
|
305
|
+
const fileList = contributing.map((f) => ` ${f}`).join("\n");
|
|
306
|
+
return (
|
|
307
|
+
`⚠ This project's .claude/settings.json defines ${entries.length} ` +
|
|
308
|
+
`shell-running hook(s) that auto-run on agent activity:\n${fileList}\n` +
|
|
309
|
+
` Review them before trusting this repo. Shown once per change; ` +
|
|
310
|
+
`disable all hooks with CC_SETTINGS_HOOKS=0.`
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
182
314
|
module.exports = {
|
|
183
315
|
loadHooks,
|
|
316
|
+
projectHookTrustNotice,
|
|
184
317
|
collectHooks,
|
|
185
318
|
compileMatcher,
|
|
186
319
|
umbrellaFor,
|
|
@@ -240,12 +240,16 @@ function loadSettingsConfig(opts = {}) {
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
/**
|
|
243
|
-
* Read a
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* a
|
|
243
|
+
* Read a boolean setting across the layered `.claude/settings.json` files
|
|
244
|
+
* (last/closest layer wins — same precedence as the permission rules). The key
|
|
245
|
+
* may be a dotted path for nested settings (e.g. `autoMode.classifyAllShell`);
|
|
246
|
+
* a plain key walks a one-element path, so existing callers are unaffected.
|
|
247
|
+
* Non-boolean values (and partial paths through a non-object) are ignored.
|
|
248
|
+
* Returns `undefined` when no layer sets it, so a caller can distinguish
|
|
249
|
+
* "unset" from an explicit `false`.
|
|
247
250
|
*
|
|
248
|
-
* @param {string} key
|
|
251
|
+
* @param {string} key settings key or dotted path (e.g. "respondToBashCommands"
|
|
252
|
+
* or "autoMode.classifyAllShell")
|
|
249
253
|
* @param {object} [opts]
|
|
250
254
|
* @param {string} [opts.cwd=process.cwd()]
|
|
251
255
|
* @param {string} [opts.settingsFile]
|
|
@@ -254,11 +258,16 @@ function loadSettingsConfig(opts = {}) {
|
|
|
254
258
|
*/
|
|
255
259
|
function readBooleanSetting(key, opts = {}) {
|
|
256
260
|
const cwd = opts.cwd || process.cwd();
|
|
261
|
+
const parts = String(key).split(".");
|
|
257
262
|
let value;
|
|
258
263
|
for (const file of settingsPaths(cwd, opts.settingsFile)) {
|
|
259
264
|
const data = readSettingsFile(file, { onWarn: opts.onWarn });
|
|
260
|
-
|
|
261
|
-
|
|
265
|
+
let node = data;
|
|
266
|
+
for (const p of parts) {
|
|
267
|
+
node = node && typeof node === "object" ? node[p] : undefined;
|
|
268
|
+
}
|
|
269
|
+
if (typeof node === "boolean") {
|
|
270
|
+
value = node; // last (closest) layer wins
|
|
262
271
|
}
|
|
263
272
|
}
|
|
264
273
|
return value;
|
package/src/lib/social-graph.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { EventEmitter } from "events";
|
|
25
|
+
import { safeJsonParse } from "./safe-json.js";
|
|
25
26
|
|
|
26
27
|
/* ── Edge types ────────────────────────────────────────────── */
|
|
27
28
|
|
|
@@ -325,7 +326,8 @@ export function loadFromDb(db) {
|
|
|
325
326
|
)
|
|
326
327
|
.all();
|
|
327
328
|
for (const row of rows) {
|
|
328
|
-
|
|
329
|
+
// A single corrupt metadata cell must not crash the whole graph load.
|
|
330
|
+
const metadata = safeJsonParse(row.metadata, null);
|
|
329
331
|
// Hydrate without re-emitting events (bulk load).
|
|
330
332
|
_hydrateEdge({
|
|
331
333
|
sourceDid: row.source_did,
|
package/src/lib/status-line.cjs
CHANGED
|
@@ -48,7 +48,10 @@ function loadStatusLineConfig({ cwd = process.cwd(), settingsFile } = {}) {
|
|
|
48
48
|
cfg = {
|
|
49
49
|
type: sl.type || "command",
|
|
50
50
|
command: sl.command,
|
|
51
|
-
|
|
51
|
+
// Clamp to [0,80]: a non-finite/huge padding (e.g. "1e999" → Infinity,
|
|
52
|
+
// or 999999999) would make " ".repeat(padding) at render time throw
|
|
53
|
+
// RangeError on every REPL prompt, bricking the status line.
|
|
54
|
+
padding: Math.max(0, Math.min(80, Math.floor(Number(sl.padding)) || 0)),
|
|
52
55
|
};
|
|
53
56
|
} else if (sl === false || sl === null) {
|
|
54
57
|
cfg = null; // an explicit disable in a higher layer wins
|
package/src/lib/stream-retry.js
CHANGED
|
@@ -18,6 +18,33 @@ import { isAbortError } from "./abort-utils.js";
|
|
|
18
18
|
export const STREAM_RETRY_MAX = 2;
|
|
19
19
|
export const STREAM_RETRY_BASE_MS = 400;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Hard ceiling on the *configurable* retry budget (Claude-Code 2.1.186:
|
|
23
|
+
* "CLAUDE_CODE_MAX_RETRIES capped at 15") — keeps a stray huge value from
|
|
24
|
+
* turning a dead endpoint into a multi-minute exponential-backoff hang.
|
|
25
|
+
*/
|
|
26
|
+
export const STREAM_RETRY_MAX_CAP = 15;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the streaming-retry budget. Users can raise (or lower) the default
|
|
30
|
+
* via `CC_MAX_RETRIES` (native) or `CLAUDE_CODE_MAX_RETRIES` (Claude-Code
|
|
31
|
+
* parity); the value is clamped to `[0, STREAM_RETRY_MAX_CAP]`. Unset / blank /
|
|
32
|
+
* non-numeric falls back to the default `STREAM_RETRY_MAX`; a negative value
|
|
33
|
+
* clamps to 0 (retries disabled). `CC_MAX_RETRIES` wins when both are set.
|
|
34
|
+
*
|
|
35
|
+
* @param {Record<string,string|undefined>} [env=process.env]
|
|
36
|
+
* @returns {number}
|
|
37
|
+
*/
|
|
38
|
+
export function resolveStreamRetryMax(env = process.env) {
|
|
39
|
+
const raw = env.CC_MAX_RETRIES ?? env.CLAUDE_CODE_MAX_RETRIES;
|
|
40
|
+
if (raw == null || String(raw).trim() === "") return STREAM_RETRY_MAX;
|
|
41
|
+
const n = Number.parseInt(String(raw).trim(), 10);
|
|
42
|
+
if (!Number.isFinite(n)) return STREAM_RETRY_MAX;
|
|
43
|
+
if (n < 0) return 0;
|
|
44
|
+
if (n > STREAM_RETRY_MAX_CAP) return STREAM_RETRY_MAX_CAP;
|
|
45
|
+
return n;
|
|
46
|
+
}
|
|
47
|
+
|
|
21
48
|
/**
|
|
22
49
|
* Is this error from a streaming chat request a transient API CONNECTION drop
|
|
23
50
|
* that is safe to retry? True only for genuine network failures (reset /
|
|
@@ -365,6 +365,15 @@ export class SubAgentContext {
|
|
|
365
365
|
return this.result;
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
+
// If the loop already force-completed (abort signal or token budget),
|
|
369
|
+
// preserve that result. The normal completion below would otherwise
|
|
370
|
+
// overwrite the cancellation / budget marker with a plain summary of
|
|
371
|
+
// whatever was streamed so far — the parent agent would then mistake a
|
|
372
|
+
// truncated/cancelled run for a clean one.
|
|
373
|
+
if (this.status !== "active") {
|
|
374
|
+
return this.result;
|
|
375
|
+
}
|
|
376
|
+
|
|
368
377
|
// Summarize the result
|
|
369
378
|
const summary = this.summarize(lastContent);
|
|
370
379
|
|
package/src/lib/turn-context.js
CHANGED
|
@@ -30,6 +30,9 @@ function _git(cmd, cwd) {
|
|
|
30
30
|
encoding: "utf-8",
|
|
31
31
|
stdio: ["ignore", "pipe", "ignore"],
|
|
32
32
|
timeout: 1500,
|
|
33
|
+
// `status --porcelain` on a dirty repo with many files can exceed the
|
|
34
|
+
// 1 MB execSync default → ENOBUFS → null → "(clean)" misreport below.
|
|
35
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
33
36
|
})
|
|
34
37
|
.trim();
|
|
35
38
|
} catch (_e) {
|
|
@@ -61,11 +64,18 @@ export function buildTurnContext({
|
|
|
61
64
|
if (branch) {
|
|
62
65
|
const head = _git("rev-parse --short HEAD", cwd);
|
|
63
66
|
const status = _git("status --porcelain", cwd);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
67
|
+
// Distinguish "command failed" (null — timeout / huge output) from "" (truly
|
|
68
|
+
// clean): the old `status && …` reported a repo as "(clean)" whenever status
|
|
69
|
+
// couldn't be determined, which is a wrong signal to the model.
|
|
70
|
+
let stateLabel;
|
|
71
|
+
if (status === null) {
|
|
72
|
+
stateLabel = " (status unknown)";
|
|
73
|
+
} else if (status.length > 0) {
|
|
74
|
+
stateLabel = ` (${status.split("\n").filter(Boolean).length} uncommitted)`;
|
|
75
|
+
} else {
|
|
76
|
+
stateLabel = " (clean)";
|
|
77
|
+
}
|
|
78
|
+
lines.push(`- git: ${branch}@${head || "?"}${stateLabel}`);
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
if (sessionId) {
|