chainlesschain 0.162.49 → 0.162.60
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/bin/chainlesschain.js +1 -1
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-DmdtNmWd.js → AIOps-a2cSbSEu.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DkuYVafg.js → ActionButton-DwvSB5Pp.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Ba_h8Tub.js → Analytics-BqaRaBDD.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-yb8Zm9MX.js → AppLayout-Beck7v8t.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-BGjex2fm.js → Audit-UtJhPdXJ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-IFQ2hOF2.js → Backup-HVZhcdll.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-W8AkPkrV.js → BaseInput-DRY_ZGmj.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BgI7t-iW.js → Chat-D7Vuwfe2.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BS2q_hPX.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DuWsZP4g.js → Checkbox-B406i7N1.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DyoTNmYg.js → Codegen-BvTCqHi3.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DttmlDRk.js → Col-DRiyxTQP.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D9nnIdKn.js → Community-DWmhxHQa.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-C8KVQaHb.js → Compact-DO1HBZEz.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-R2owqgjj.js → Compliance-D4j-VHwS.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DwGMMjRn.js → Cowork-BGBkWtat.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BSTcN_lK.js → Cron-Xa9PtMUQ.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CTNuIbFD.js → Crosschain-wVWs4lqN.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CgApGsFP.js → DID-DTkqiRuT.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-D_OJ3UN5.js → Dashboard-d9STUbrr.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-B84Jwra_.js → Dropdown-CrdxS-C8.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Bv-YO-6y.js → EmailListRenderer-D78XHUEp.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-drgZ408Y.js → FamilyGuardDashboard-iAeSETIP.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CtzFkdW2.js → Federation-CTV1Sxqs.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BFAvNhl9.js → FormItemContext-BtwNuQKK.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DnuEyz_l.js → GenericCardRenderer-CdEgHjkl.js} +1 -1
- package/src/assets/web-panel/assets/{Git-jlHajmRJ.js → Git-BTo-PJr_.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DmJC7PGL.js → Governance-DquOG94r.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-B-u7xD2n.js → Inference-DDtcBxRB.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BaYCA2Cd.js → KnowledgeGraph-KUOmNj5C.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DTNYQWfp.js → Logs-HKm7kRs7.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CUu1xYvo.js → Marketplace-IxrOcbFB.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BmoeTyrC.js → McpTools-D6a1LM3S.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-DxTU3QU7.js → Memory-lFkD2ZuM.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CpcOlKAD.js → MobileBridge-xwuQTps5.js} +2 -2
- package/src/assets/web-panel/assets/MobileProjects-BYr1D3WO.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-LfxwOm0x.js → Mtc-BXpJGrjm.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-D6A9Gjkh.js → MtcAudit-CWttaim1.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Ch_jofPV.js → Multisig-jKgTuVLS.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Bkvogg0I.js → NLProgramming-xl4RDzQj.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C5t5Xihm.js → Notes-DPBOvscE.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CTpDUNCb.js → NotificationSettings-8TkIkRo3.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Dwa-XtoE.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Dr37BaXa.js → Organization-CJ0xVwZM.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-ZGjsdP7N.js → Overflow-V7VuUslt.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-bWJU5Vxd.js → P2P-BxuccEGq.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-DaP2Q5kU.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-BOSnFZaC.js → Permissions-CPJFF0zU.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-X4SgjP6P.js → PersonalDataHub-Cmn2uiuw.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DoJhB9bj.js → Pipeline-0zX89_iz.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-OM9lDj-R.js → Privacy-DROUg3XE.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BXQEOmLn.js → ProjectInit-c5KESOK4.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DBXo3K5u.js → ProjectSettings-BfiCcnb_.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-CJ4DBJlS.js → Projects-BtZH5-Eh.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Tk9SawmO.js → Providers-C9Rr_dOk.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DRI1-nTC.js → QuickAsk-Du4p90W6.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DtrIVTu9.js → Recommend-B-DQenTl.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DkH8ImwZ.js → Reputation-DvwlAVRZ.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DpA9dlvi.js → Row-rTnbvkP-.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DV3OhxWd.js → RssFeed-DwvsqWbB.js} +3 -3
- package/src/assets/web-panel/assets/{Search-QxdntiQx.js → Search-U_Xj5SvF.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CGuEnrD2.js → Security-CdjsVDQ8.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BvwSSD8b.js → Services-DUd3mFXk.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-sx_8L3-5.js → Skeleton-CA2gCJmY.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-dWOwxRsu.js → Skills-BIw7Rb-m.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-zxXnfKrT.js → Sla-vySPesC0.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CmFlcNjr.js → SpeechSettings-EniuTjBJ.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BeXeqURL.js → SyncSettings-DkrqbzYS.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-oyPnWRbw.js +1 -0
- package/src/assets/web-panel/assets/{Templates-DlgR3XFH.js → Templates-C2Kvn60U.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-0P8HgQaM.js → Tenant-x6jVMx4D.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-C2nZbPBs.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-hbO7agZs.js → TimelineRenderer-BF6HAETd.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CsmhgTBO.js → Tokens-B-KcVAin.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DnaF_2PP.js → Trigger-B-Caiptm.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-C1oafGj1.js → Trust-_8sq7pJp.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-eLL4DOmC.js → UkeySign-CLveUEgo.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CX45sVq7.js → VideoEditing-iVc9jxt9.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-aWPqpHdQ.js → Wallet-D1n5pidD.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DMYV1MAo.js → WebAuthn-CA8kubXb.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-D9uRIJvH.js → WorkflowEditor-BXWwd_fB.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BmWYfCxG.js → chat-DUNkQr1A.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DqvTCkBe.js → colors-Dz5ozTcp.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Bh0L0ejI.js → compact-item-CZ5-JSLh.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-r2qgp1mn.js → createContext-CFxlcPug.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BMRVR8Xp.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BcffXa-S.js → hasIn-CqWIkHJm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DutDlDUF.js → index-3elHm6lI.js} +1 -1
- package/src/assets/web-panel/assets/{index-XwbSqOB2.js → index-8l5LLWxH.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2-02rrp.js → index-BBq1ySIt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY8RXaZR.js → index-BI2EU3hC.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6pAm1iJ.js → index-BJt6sNTF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dcjol7ot.js → index-BLLSLAC3.js} +1 -1
- package/src/assets/web-panel/assets/{index-U86pxDyR.js → index-BLNgGXeg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DPFT7J7I.js → index-BO-yo7Jv.js} +1 -1
- package/src/assets/web-panel/assets/index-BT2s_zxU.js +1 -0
- package/src/assets/web-panel/assets/{index-DRXcGa5y.js → index-BiAcVeea.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7z0qK1W.js → index-C2SoMbLc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DW1y18GR.js → index-C5XUilwu.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCBqTRWH.js → index-C5zhjact.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMn_luHQ.js → index-CBeASfAD.js} +1 -1
- package/src/assets/web-panel/assets/{index-COrfHebA.js → index-CD7UjlnE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxajFkK2.js → index-CDq8IVvv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJt0iuep.js → index-CE-gpaY9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtyXyl3t.js → index-CL6wt2JN.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cbj6C3pA.js → index-CLu3Oyef.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKnEtlZD.js → index-C_WWTpLE.js} +1 -1
- package/src/assets/web-panel/assets/{index-De36_UgR.js → index-CbcHBDYj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAlxkpnv.js → index-CguUaiiY.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ct8qhPZe.js → index-Ci1-8q-g.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbMox24t.js → index-CvMZxZOn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLN-neIf.js → index-D6Nkerss.js} +1 -1
- package/src/assets/web-panel/assets/{index-h4O0AcBt.js → index-DEzYXMgc.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXXxkeij.js → index-DF0hXW5L.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3mmDuOv.js → index-DGAjS_D9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDR3GmaO.js → index-DO6mf95c.js} +1 -1
- package/src/assets/web-panel/assets/index-DOTL6NDc.js +1 -0
- package/src/assets/web-panel/assets/{index-BeV-KoQl.js → index-DUyhvh0L.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bma_yHcC.js → index-DW18L-o6.js} +1 -1
- package/src/assets/web-panel/assets/{index-585fuGAN.js → index-Dc-5Ulgt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCyB-RK5.js → index-DvUlrMy-.js} +3 -3
- package/src/assets/web-panel/assets/{index-DWlDSE0F.js → index-FsYDYVUk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXae4ZyX.js → index-GVbsyUQm.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9nh3ANl.js → index-noQc_RpT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQlAPNSU.js → index-rR060KAF.js} +1 -1
- package/src/assets/web-panel/assets/{index-S4E77Aer.js → index-xaZX6ZDL.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C1d8I-BX.js → initDefaultProps-PIetywTX.js} +1 -1
- package/src/assets/web-panel/assets/{motion-Dq7fiy4Y.js → motion-gQJEK3wO.js} +1 -1
- package/src/assets/web-panel/assets/{move-Bqb2dySM.js → move-ML1nRxts.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BUYqb4My.js → omit-wUWsw3YL.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DeytiKlZ.js → pickAttrs-A0Wlomih.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-xrXZWCqG.js → placementArrow-C5RKYdxT.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CcL2K-YY.js → responsiveObserve-DIxNVSJl.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DmCWaic7.js → slide-B-tNesVu.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CqNrFif7.js → statusUtils-CftzO200.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-C436m5Xy.js → styleChecker-CMgvWu90.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CVhutCN8.js → useFlexGapSupport-sxqoDNhZ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DUd49Bui.js → useFs-CowEXz4v.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-fuS9raic.js → usePersonalDataHub-6ISRG7V-.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C3kmDmk-.js → vnode-C2mnXfmw.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-hX-F1dT-.js → zoom-DMsur0jx.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +66 -28
- package/src/harness/mcp-client.js +48 -2
- package/src/lib/llm-pricing.js +9 -0
- package/src/lib/permission-rules.cjs +11 -1
- package/src/lib/personal-data-hub-wiring.js +24 -0
- package/src/lib/repl-multiline.js +64 -0
- package/src/lib/repl-rewind.js +65 -2
- package/src/lib/repl-vim.js +445 -0
- package/src/lib/safe-mode.js +17 -3
- package/src/lib/skill-loader.js +45 -1
- package/src/lib/slash-commands.js +13 -3
- package/src/lib/status-line.cjs +33 -3
- package/src/repl/agent-repl.js +253 -27
- package/src/repl/session-cost.js +98 -1
- package/src/runtime/agent-core.js +23 -8
- package/src/runtime/fallback-model.js +125 -30
- package/src/runtime/headless-runner.js +2 -0
- package/src/runtime/headless-stream.js +2 -0
- package/src/runtime/mcp-config.js +14 -3
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CfpKEQUF.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-Bjh_z16l.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-ST2lr-Bi.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-BRVoW-ye.js +0 -7
- package/src/assets/web-panel/assets/Tasks-iImd8xSO.js +0 -1
- package/src/assets/web-panel/assets/Terminal-B5VDEEHD.js +0 -3
- package/src/assets/web-panel/assets/devWarning-CusWDjWW.js +0 -1
- package/src/assets/web-panel/assets/index-BhYltBvN.js +0 -1
- package/src/assets/web-panel/assets/index-CZiIHw4e.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{K as o}from"./index-
|
|
1
|
+
import{K as o}from"./index-DvUlrMy-.js";import{i as f}from"./motion-gQJEK3wO.js";const c=new o("antZoomIn",{"0%":{transform:"scale(0.2)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),y=new o("antZoomOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.2)",opacity:0}}),a=new o("antZoomBigIn",{"0%":{transform:"scale(0.8)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),s=new o("antZoomBigOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.8)",opacity:0}}),g=new o("antZoomUpIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 0%"}}),O=new o("antZoomUpOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 0%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0}}),l=new o("antZoomLeftIn",{"0%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"0% 50%"}}),u=new o("antZoomLeftOut",{"0%":{transform:"scale(1)",transformOrigin:"0% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0}}),p=new o("antZoomRightIn",{"0%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"100% 50%"}}),z=new o("antZoomRightOut",{"0%":{transform:"scale(1)",transformOrigin:"100% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0}}),K=new o("antZoomDownIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 100%"}}),w=new o("antZoomDownOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 100%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0}}),I={zoom:{inKeyframes:c,outKeyframes:y},"zoom-big":{inKeyframes:a,outKeyframes:s},"zoom-big-fast":{inKeyframes:a,outKeyframes:s},"zoom-left":{inKeyframes:l,outKeyframes:u},"zoom-right":{inKeyframes:p,outKeyframes:z},"zoom-up":{inKeyframes:g,outKeyframes:O},"zoom-down":{inKeyframes:K,outKeyframes:w}},h=(n,r)=>{const{antCls:m}=n,t=`${m}-${r}`,{inKeyframes:i,outKeyframes:e}=I[r];return[f(t,i,e,r==="zoom-big-fast"?n.motionDurationFast:n.motionDurationMid),{[`
|
|
2
2
|
${t}-enter,
|
|
3
3
|
${t}-appear
|
|
4
4
|
`]:{transform:"scale(0)",opacity:0,animationTimingFunction:n.motionEaseOutCirc,"&-prepare":{transform:"none"}},[`${t}-leave`]:{animationTimingFunction:n.motionEaseInOutCirc}}]};export{h as i,c as z};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// Injected by web-ui-server.js at serve time
|
|
9
9
|
window.__CC_CONFIG__ = __CC_CONFIG_PLACEHOLDER__;
|
|
10
10
|
</script>
|
|
11
|
-
<script type="module" crossorigin src="./assets/index-
|
|
11
|
+
<script type="module" crossorigin src="./assets/index-DvUlrMy-.js"></script>
|
|
12
12
|
<link rel="modulepreload" crossorigin href="./assets/vendor-BvqAck49.js">
|
|
13
13
|
<link rel="modulepreload" crossorigin href="./assets/icons-DP3uiYxy.js">
|
|
14
14
|
<link rel="stylesheet" crossorigin href="./assets/index-Cq93VfoF.css">
|
package/src/commands/agent.js
CHANGED
|
@@ -10,7 +10,10 @@ import path from "node:path";
|
|
|
10
10
|
import fs from "node:fs";
|
|
11
11
|
import { createAgentRuntimeFactory } from "../runtime/runtime-factory.js";
|
|
12
12
|
import { resolvePromptText } from "../runtime/system-prompt.js";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
makeFallbackChatFn,
|
|
15
|
+
normalizeFallbackModels,
|
|
16
|
+
} from "../runtime/fallback-model.js";
|
|
14
17
|
import { resolveImages, resolveVisionLlm } from "../lib/image-input.js";
|
|
15
18
|
import { loadConfig } from "../lib/config-manager.js";
|
|
16
19
|
|
|
@@ -56,6 +59,25 @@ export function resolveThinkingBudget(raw) {
|
|
|
56
59
|
return Math.floor(n);
|
|
57
60
|
}
|
|
58
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the ordered fallback-model chain for a run. The `--fallback-model`
|
|
64
|
+
* flag (repeatable / comma-separated → array) takes precedence; otherwise the
|
|
65
|
+
* configured `llm.fallbackModels` (array or comma string) or legacy
|
|
66
|
+
* `llm.fallbackModel` (single) seeds the chain so unattended runs need no flag.
|
|
67
|
+
* Pure; exported for tests. Normalization (trim / dedupe / cap-at-3) is applied.
|
|
68
|
+
*
|
|
69
|
+
* @param {string[]|string|undefined} flagValue raw --fallback-model value
|
|
70
|
+
* @param {object} [llm] config.llm block
|
|
71
|
+
* @returns {string[]}
|
|
72
|
+
*/
|
|
73
|
+
export function resolveFallbackModels(flagValue, llm = {}) {
|
|
74
|
+
const fromFlag = normalizeFallbackModels(flagValue);
|
|
75
|
+
if (fromFlag.length) return fromFlag;
|
|
76
|
+
const configured =
|
|
77
|
+
llm && llm.fallbackModels != null ? llm.fallbackModels : llm?.fallbackModel;
|
|
78
|
+
return normalizeFallbackModels(configured);
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
/**
|
|
60
82
|
* Read all of stdin as a UTF-8 string. Resolves "" immediately when stdin is a
|
|
61
83
|
* TTY (nothing piped) so we never block an interactive invocation.
|
|
@@ -153,6 +175,10 @@ export function registerAgentCommand(program) {
|
|
|
153
175
|
.option("--recall-limit <n>", "Top-K memories to inject into system prompt")
|
|
154
176
|
.option("--recall-query <q>", "Query string for startup memory recall")
|
|
155
177
|
.option("--no-recall-memory", "Disable startup memory recall")
|
|
178
|
+
.option(
|
|
179
|
+
"--vim",
|
|
180
|
+
"Start the interactive REPL in vim-mode line editing (toggle later with /vim; or CC_VIM=1)",
|
|
181
|
+
)
|
|
156
182
|
.option("--no-stream", "Disable streamed response rendering")
|
|
157
183
|
.option(
|
|
158
184
|
"--no-park-on-exit",
|
|
@@ -212,7 +238,8 @@ export function registerAgentCommand(program) {
|
|
|
212
238
|
)
|
|
213
239
|
.option(
|
|
214
240
|
"--fallback-model <model>",
|
|
215
|
-
"
|
|
241
|
+
"Backup model(s) to try in order when the primary fails (transient error or model-not-found). Repeatable or comma-separated; up to 3. Defaults to config llm.fallbackModels. claude-code parity.",
|
|
242
|
+
(val, prev) => (prev || []).concat([val]),
|
|
216
243
|
)
|
|
217
244
|
.option(
|
|
218
245
|
"--include-partial-messages",
|
|
@@ -252,14 +279,18 @@ export function registerAgentCommand(program) {
|
|
|
252
279
|
"Merge an extra .claude/settings.json-shaped file for this run: permission rules (allow/ask/deny) + native config overrides (model, env)",
|
|
253
280
|
)
|
|
254
281
|
.action(async (task, options, command) => {
|
|
255
|
-
// --safe-mode
|
|
256
|
-
// kill-switch BEFORE anything
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
282
|
+
// --safe-mode flag OR CC_SAFE_MODE / CLAUDE_CODE_SAFE_MODE env (Claude-Code
|
|
283
|
+
// 2.1.169 parity): flip every customization kill-switch BEFORE anything
|
|
284
|
+
// loads. Permission rules stay active.
|
|
285
|
+
{
|
|
286
|
+
const { applySafeMode, safeModeRequested } =
|
|
287
|
+
await import("../lib/safe-mode.js");
|
|
288
|
+
if (safeModeRequested(options)) {
|
|
289
|
+
const applied = applySafeMode();
|
|
290
|
+
process.stderr.write(
|
|
291
|
+
`safe mode: customizations disabled (${applied.join(", ")}) — permission rules stay active.\n`,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
263
294
|
}
|
|
264
295
|
// --worktree (Claude-Code 2.1.171 parity): run THIS session in a fresh
|
|
265
296
|
// git worktree — edits land on an isolated branch, the main working
|
|
@@ -268,9 +299,8 @@ export function registerAgentCommand(program) {
|
|
|
268
299
|
let _worktree = null;
|
|
269
300
|
if (options.worktree) {
|
|
270
301
|
try {
|
|
271
|
-
const { setupAgentWorktree } =
|
|
272
|
-
"../lib/agent-worktree.js"
|
|
273
|
-
);
|
|
302
|
+
const { setupAgentWorktree } =
|
|
303
|
+
await import("../lib/agent-worktree.js");
|
|
274
304
|
_worktree = setupAgentWorktree({ cwd: process.cwd() });
|
|
275
305
|
process.chdir(_worktree.path);
|
|
276
306
|
process.stderr.write(
|
|
@@ -284,9 +314,8 @@ export function registerAgentCommand(program) {
|
|
|
284
314
|
const _finishWorktree = async () => {
|
|
285
315
|
if (!_worktree) return;
|
|
286
316
|
try {
|
|
287
|
-
const { finishAgentWorktree } =
|
|
288
|
-
"../lib/agent-worktree.js"
|
|
289
|
-
);
|
|
317
|
+
const { finishAgentWorktree } =
|
|
318
|
+
await import("../lib/agent-worktree.js");
|
|
290
319
|
process.chdir(_worktree.repoRoot); // release the dir before removal
|
|
291
320
|
const fin = finishAgentWorktree(_worktree);
|
|
292
321
|
process.stderr.write(
|
|
@@ -301,9 +330,8 @@ export function registerAgentCommand(program) {
|
|
|
301
330
|
// Claude-Code parity: auto-checkpoint defaults ON inside a git repo
|
|
302
331
|
// (shadow-commit engine, zero working-tree touch); explicit
|
|
303
332
|
// --checkpoint / --no-checkpoint always wins.
|
|
304
|
-
const { resolveAutoCheckpoint } =
|
|
305
|
-
"../lib/auto-checkpoint-default.js"
|
|
306
|
-
);
|
|
333
|
+
const { resolveAutoCheckpoint } =
|
|
334
|
+
await import("../lib/auto-checkpoint-default.js");
|
|
307
335
|
const autoCheckpoint = resolveAutoCheckpoint({
|
|
308
336
|
flagValue: options.checkpoint,
|
|
309
337
|
flagSource: command?.getOptionValueSource?.("checkpoint"),
|
|
@@ -485,16 +513,23 @@ export function registerAgentCommand(program) {
|
|
|
485
513
|
// --think/--ultrathink and on adaptive models). undefined 鈫?engine default.
|
|
486
514
|
const thinkingBudget = resolveThinkingBudget(options.thinkingBudget);
|
|
487
515
|
|
|
488
|
-
// --fallback-model:
|
|
489
|
-
// the primary errors out (overload / rate-limit / network)
|
|
490
|
-
// the
|
|
491
|
-
//
|
|
492
|
-
|
|
516
|
+
// --fallback-model: an ordered chain of backup models tried in turn when
|
|
517
|
+
// the primary errors out (transient overload / rate-limit / network) or
|
|
518
|
+
// the primary model id is not found. The flag (repeatable / comma-list)
|
|
519
|
+
// wins; otherwise config llm.fallbackModels (or llm.fallbackModel) seeds
|
|
520
|
+
// the chain so unattended runs need no flag. Passed into the headless
|
|
521
|
+
// runners via options.chatFn (the agent loop's seam), so no runner
|
|
522
|
+
// changes are needed. Notice goes to stderr to keep stdout clean.
|
|
523
|
+
const fallbackModels = resolveFallbackModels(
|
|
524
|
+
options.fallbackModel,
|
|
525
|
+
loadConfig().llm || {},
|
|
526
|
+
);
|
|
527
|
+
const fallbackChatFn = fallbackModels.length
|
|
493
528
|
? makeFallbackChatFn({
|
|
494
|
-
|
|
529
|
+
fallbackModels,
|
|
495
530
|
onFallback: ({ from, to, error }) =>
|
|
496
531
|
process.stderr.write(
|
|
497
|
-
`Note: model "${from}" failed (${error}); retrying with
|
|
532
|
+
`Note: model "${from}" failed (${error}); retrying with fallback model "${to}".\n`,
|
|
498
533
|
),
|
|
499
534
|
})
|
|
500
535
|
: undefined;
|
|
@@ -719,6 +754,8 @@ export function registerAgentCommand(program) {
|
|
|
719
754
|
bundlePath: options.bundle || null,
|
|
720
755
|
additionalDirectories,
|
|
721
756
|
autoCheckpoint,
|
|
757
|
+
// --vim: start the REPL in vim-mode editing (also CC_VIM=1 or /vim).
|
|
758
|
+
vimMode: options.vim === true,
|
|
722
759
|
// --system-prompt / --append-system-prompt (literal or @file) also
|
|
723
760
|
// apply to interactive sessions, composed in startAgentRepl.
|
|
724
761
|
systemPrompt: resolvePromptText(options.systemPrompt, {
|
|
@@ -727,8 +764,9 @@ export function registerAgentCommand(program) {
|
|
|
727
764
|
appendSystemPrompt: resolvePromptText(options.appendSystemPrompt, {
|
|
728
765
|
cwd: process.cwd(),
|
|
729
766
|
}),
|
|
730
|
-
// --fallback-model also applies interactively (wrapper built in the
|
|
731
|
-
|
|
767
|
+
// --fallback-model also applies interactively (wrapper built in the
|
|
768
|
+
// REPL). Pass the fully resolved chain (flag + config default).
|
|
769
|
+
fallbackModels: fallbackModels.length ? fallbackModels : null,
|
|
732
770
|
// --mcp-config + registered (cc mcp add) servers also apply to the
|
|
733
771
|
// interactive session (the REPL resolves both via the mcp-config engine).
|
|
734
772
|
mcpConfig: options.mcpConfig || null,
|
|
@@ -91,12 +91,52 @@ export function isLikelyConnectionError(err) {
|
|
|
91
91
|
* MCP Client — manages connections to MCP servers.
|
|
92
92
|
*/
|
|
93
93
|
export class MCPClient extends EventEmitter {
|
|
94
|
-
|
|
94
|
+
/**
|
|
95
|
+
* @param {object} [options]
|
|
96
|
+
* @param {string|null} [options.sessionId] agent session id advertised to
|
|
97
|
+
* spawned stdio MCP servers (CC_SESSION_ID / CLAUDE_CODE_SESSION_ID env).
|
|
98
|
+
*/
|
|
99
|
+
constructor(options = {}) {
|
|
95
100
|
super();
|
|
96
101
|
this.servers = new Map(); // name → { process, state, tools, resources, config }
|
|
97
102
|
this._nextId = 1;
|
|
98
103
|
this._reconnectors = new Map(); // name → async () => config|null
|
|
99
104
|
this._reconnecting = new Map(); // name → in-flight reconnect promise
|
|
105
|
+
this._sessionId =
|
|
106
|
+
options && options.sessionId != null ? String(options.sessionId) : null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Set (or clear) the agent session id advertised to stdio MCP servers. Only
|
|
111
|
+
* servers connected *after* this call see the new value; already-spawned
|
|
112
|
+
* processes keep the env they were launched with.
|
|
113
|
+
* @param {string|null|undefined} id
|
|
114
|
+
*/
|
|
115
|
+
setSessionId(id) {
|
|
116
|
+
this._sessionId = id != null && id !== "" ? String(id) : null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Environment a spawned stdio MCP server inherits to identify the agent it
|
|
121
|
+
* runs under (Claude-Code 2.1.154 / 2.1.163 parity). `CLAUDECODE` (parity)
|
|
122
|
+
* and `CHAINLESSCHAIN` (native) mark "launched by the agent"; the session id —
|
|
123
|
+
* from the configured value or an ambient `CC_SESSION_ID` — lets a server
|
|
124
|
+
* correlate its work to the run. `CLAUDE_CODE_SESSION_ID` mirrors
|
|
125
|
+
* `CC_SESSION_ID` so servers written for Claude Code work unchanged.
|
|
126
|
+
* @returns {Record<string,string>}
|
|
127
|
+
*/
|
|
128
|
+
_agentIdentityEnv() {
|
|
129
|
+
const env = { CLAUDECODE: "1", CHAINLESSCHAIN: "1" };
|
|
130
|
+
const sid =
|
|
131
|
+
this._sessionId ||
|
|
132
|
+
process.env.CC_SESSION_ID ||
|
|
133
|
+
process.env.CLAUDE_CODE_SESSION_ID ||
|
|
134
|
+
null;
|
|
135
|
+
if (sid) {
|
|
136
|
+
env.CC_SESSION_ID = String(sid);
|
|
137
|
+
env.CLAUDE_CODE_SESSION_ID = String(sid);
|
|
138
|
+
}
|
|
139
|
+
return env;
|
|
100
140
|
}
|
|
101
141
|
|
|
102
142
|
/**
|
|
@@ -159,7 +199,13 @@ export class MCPClient extends EventEmitter {
|
|
|
159
199
|
}
|
|
160
200
|
const proc = _deps.spawn(config.command, config.args || [], {
|
|
161
201
|
stdio: ["pipe", "pipe", "pipe"],
|
|
162
|
-
|
|
202
|
+
// process.env < agent identity (CLAUDECODE / session id) < the
|
|
203
|
+
// server's own config.env, so an explicit per-server override wins.
|
|
204
|
+
env: {
|
|
205
|
+
...process.env,
|
|
206
|
+
...this._agentIdentityEnv(),
|
|
207
|
+
...(config.env || {}),
|
|
208
|
+
},
|
|
163
209
|
});
|
|
164
210
|
|
|
165
211
|
entry.process = proc;
|
package/src/lib/llm-pricing.js
CHANGED
|
@@ -35,6 +35,15 @@ export const PRICE_TABLE = Object.freeze({
|
|
|
35
35
|
{ match: "haiku", in: 1, out: 5 },
|
|
36
36
|
],
|
|
37
37
|
openai: [
|
|
38
|
+
// GPT-5 family (2026). Matching is longest-pattern-first, so dated/variant
|
|
39
|
+
// ids (gpt-5.5, gpt-5.5-pro, gpt-5.5-instant, …) resolve to the most
|
|
40
|
+
// specific rate; bare "gpt-5" is the catch-all base rate.
|
|
41
|
+
{ match: "gpt-5.5-pro", in: 30, out: 180 },
|
|
42
|
+
{ match: "gpt-5.5", in: 5, out: 30 },
|
|
43
|
+
{ match: "gpt-5.4", in: 2.5, out: 15 },
|
|
44
|
+
{ match: "gpt-5-mini", in: 0.25, out: 2 },
|
|
45
|
+
{ match: "gpt-5-nano", in: 0.05, out: 0.4 },
|
|
46
|
+
{ match: "gpt-5", in: 1.25, out: 10 },
|
|
38
47
|
{ match: "gpt-4o-mini", in: 0.15, out: 0.6 },
|
|
39
48
|
{ match: "gpt-4o", in: 2.5, out: 10 },
|
|
40
49
|
{ match: "gpt-4-turbo", in: 10, out: 30 },
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* Edit(//etc/**) → edit_file on an absolute path under /etc
|
|
15
15
|
* WebFetch(domain:example.com) → web_fetch of https://example.com/…
|
|
16
16
|
* Bash → every run_shell call
|
|
17
|
+
* * → every tool call (Claude-Code deny-all idiom)
|
|
18
|
+
* Bash(*) → every run_shell call (lone-`*` pattern = match-all)
|
|
17
19
|
*
|
|
18
20
|
* Pure + self-contained (no glob dependency — `globToRegExp` is built in, the
|
|
19
21
|
* repo avoids pulling minimatch/picomatch). Decision precedence is
|
|
@@ -75,6 +77,8 @@ const URL_TOOLS = new Set(["web_fetch"]);
|
|
|
75
77
|
function toolMatches(ruleTool, actualTool) {
|
|
76
78
|
const r = String(ruleTool || "").toLowerCase();
|
|
77
79
|
const a = String(actualTool || "");
|
|
80
|
+
// Claude-Code `*` deny-all: a bare-`*` tool token matches every tool.
|
|
81
|
+
if (r === "*") return true;
|
|
78
82
|
if (Object.prototype.hasOwnProperty.call(TOOL_GROUPS, r)) {
|
|
79
83
|
return TOOL_GROUPS[r].includes(a);
|
|
80
84
|
}
|
|
@@ -88,7 +92,8 @@ function toolMatches(ruleTool, actualTool) {
|
|
|
88
92
|
function parseRule(rule) {
|
|
89
93
|
const raw = String(rule || "").trim();
|
|
90
94
|
if (!raw) return null;
|
|
91
|
-
|
|
95
|
+
// Tool token is an umbrella/CLI name OR a bare `*` (Claude-Code deny-all).
|
|
96
|
+
const m = raw.match(/^(\*|[A-Za-z_][\w-]*)\s*(?:\(([\s\S]*)\))?$/);
|
|
92
97
|
if (!m) return null;
|
|
93
98
|
const tool = m[1];
|
|
94
99
|
const pattern = m[2] === undefined ? null : m[2].trim();
|
|
@@ -198,6 +203,11 @@ function matchUrl(pattern, url) {
|
|
|
198
203
|
*/
|
|
199
204
|
function matchPattern(pattern, actualTool, args, cwd) {
|
|
200
205
|
if (pattern === null) return true;
|
|
206
|
+
// A lone `*` / `**` pattern matches any target regardless of slashes — covers
|
|
207
|
+
// `Bash(*)`, `Read(**)`, `WebFetch(*)`, etc. Done before the glob path so a
|
|
208
|
+
// command/url/path containing `/` can't slip past a deny-all (globToRegExp's
|
|
209
|
+
// `*` → `[^/]*` otherwise excludes slashes).
|
|
210
|
+
if (pattern === "*" || pattern === "**") return true;
|
|
201
211
|
const target = extractTarget(actualTool, args, cwd);
|
|
202
212
|
if (target.kind === "command") {
|
|
203
213
|
return target.value ? matchCommand(pattern, target.value) : false;
|
|
@@ -54,6 +54,9 @@ const {
|
|
|
54
54
|
LocalFilesAdapter,
|
|
55
55
|
BilibiliAdapter,
|
|
56
56
|
WeiboAdapter,
|
|
57
|
+
ZhihuAdapter,
|
|
58
|
+
BossZhipinAdapter,
|
|
59
|
+
CsdnAdapter,
|
|
57
60
|
DouyinAdapter,
|
|
58
61
|
XiaohongshuAdapter,
|
|
59
62
|
ToutiaoAdapter,
|
|
@@ -68,7 +71,13 @@ const {
|
|
|
68
71
|
QQPcAdapter,
|
|
69
72
|
AppleHealthAdapter,
|
|
70
73
|
NeteaseMusicAdapter,
|
|
74
|
+
KugouMusicAdapter,
|
|
75
|
+
IqiyiVideoAdapter,
|
|
76
|
+
TencentVideoAdapter,
|
|
71
77
|
WeReadAdapter,
|
|
78
|
+
WpsDocAdapter,
|
|
79
|
+
TencentDocsAdapter,
|
|
80
|
+
BaiduNetdiskAdapter,
|
|
72
81
|
DingTalkPcAdapter,
|
|
73
82
|
FeishuPcAdapter,
|
|
74
83
|
BaiduMapAdapter,
|
|
@@ -76,9 +85,12 @@ const {
|
|
|
76
85
|
JdAdapter,
|
|
77
86
|
MeituanAdapter,
|
|
78
87
|
PinduoduoAdapter,
|
|
88
|
+
DianpingAdapter,
|
|
79
89
|
Train12306Adapter,
|
|
80
90
|
TaobaoAdapter,
|
|
81
91
|
CtripAdapter,
|
|
92
|
+
TongchengAdapter,
|
|
93
|
+
DidiAdapter,
|
|
82
94
|
AmapAdapter,
|
|
83
95
|
TelegramAdapter,
|
|
84
96
|
WhatsAppAdapter,
|
|
@@ -514,6 +526,9 @@ async function initHub() {
|
|
|
514
526
|
// accurate.
|
|
515
527
|
for (const Cls of [
|
|
516
528
|
WeiboAdapter,
|
|
529
|
+
ZhihuAdapter,
|
|
530
|
+
BossZhipinAdapter,
|
|
531
|
+
CsdnAdapter,
|
|
517
532
|
DouyinAdapter,
|
|
518
533
|
XiaohongshuAdapter,
|
|
519
534
|
ToutiaoAdapter,
|
|
@@ -528,7 +543,13 @@ async function initHub() {
|
|
|
528
543
|
QQPcAdapter,
|
|
529
544
|
AppleHealthAdapter,
|
|
530
545
|
NeteaseMusicAdapter,
|
|
546
|
+
KugouMusicAdapter,
|
|
547
|
+
IqiyiVideoAdapter,
|
|
548
|
+
TencentVideoAdapter,
|
|
531
549
|
WeReadAdapter,
|
|
550
|
+
WpsDocAdapter,
|
|
551
|
+
TencentDocsAdapter,
|
|
552
|
+
BaiduNetdiskAdapter,
|
|
532
553
|
DingTalkPcAdapter,
|
|
533
554
|
FeishuPcAdapter,
|
|
534
555
|
BaiduMapAdapter,
|
|
@@ -536,9 +557,12 @@ async function initHub() {
|
|
|
536
557
|
JdAdapter,
|
|
537
558
|
MeituanAdapter,
|
|
538
559
|
PinduoduoAdapter,
|
|
560
|
+
DianpingAdapter,
|
|
539
561
|
Train12306Adapter,
|
|
540
562
|
TaobaoAdapter,
|
|
541
563
|
CtripAdapter,
|
|
564
|
+
TongchengAdapter,
|
|
565
|
+
DidiAdapter,
|
|
542
566
|
AmapAdapter,
|
|
543
567
|
TelegramAdapter,
|
|
544
568
|
WhatsAppAdapter,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multiline REPL input via backslash continuation (Claude-Code multiline parity).
|
|
3
|
+
*
|
|
4
|
+
* Node's readline submits on every Enter, so a single prompt is one line. This
|
|
5
|
+
* pure helper lets the REPL accumulate a multi-line prompt: a physical line that
|
|
6
|
+
* ends with a continuation backslash keeps the prompt open and the next line is
|
|
7
|
+
* appended (joined with "\n"), so code blocks / multi-paragraph prompts can be
|
|
8
|
+
* entered without a turn firing per line.
|
|
9
|
+
*
|
|
10
|
+
* The rule is shell-like but Windows-path-safe: a trailing backslash continues
|
|
11
|
+
* the line ONLY when it is a lone `\` or the backslash run is preceded by
|
|
12
|
+
* whitespace, and the run length is odd (so `\\` stays a literal backslash).
|
|
13
|
+
* That keeps a stray path like `dir C:\` from being swallowed as a continuation.
|
|
14
|
+
*
|
|
15
|
+
* analyzeContinuation("write a function \\") → { continued:true, text:"write a function" }
|
|
16
|
+
* analyzeContinuation("dir C:\\") → { continued:false, text:"dir C:\\" }
|
|
17
|
+
* analyzeContinuation("plain line") → { continued:false, text:"plain line" }
|
|
18
|
+
*
|
|
19
|
+
* The REPL keeps an array of `text` pieces and `joinContinuation()` stitches the
|
|
20
|
+
* final submission.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** Count the run of backslashes at the very end of a string. */
|
|
24
|
+
function trailingBackslashes(s) {
|
|
25
|
+
let n = 0;
|
|
26
|
+
for (let i = s.length - 1; i >= 0 && s[i] === "\\"; i--) n++;
|
|
27
|
+
return n;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Decide whether a physical input line continues onto the next one.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} line the raw line as readline delivered it
|
|
34
|
+
* @returns {{ continued:boolean, text:string }}
|
|
35
|
+
* continued → drop the trailing backslash (+ the space before it) and wait for
|
|
36
|
+
* more; not continued → the line stands as typed (text === line).
|
|
37
|
+
*/
|
|
38
|
+
export function analyzeContinuation(line) {
|
|
39
|
+
const s = typeof line === "string" ? line : "";
|
|
40
|
+
const n = trailingBackslashes(s);
|
|
41
|
+
if (n === 0 || n % 2 === 0) return { continued: false, text: s };
|
|
42
|
+
// Odd trailing backslashes: gate on what precedes the run so Windows paths
|
|
43
|
+
// (no preceding whitespace) are not treated as continuations.
|
|
44
|
+
const before = s[s.length - n - 1]; // undefined when the run is the whole line
|
|
45
|
+
const gated = before === undefined || /\s/.test(before);
|
|
46
|
+
if (!gated) return { continued: false, text: s };
|
|
47
|
+
// Strip exactly one trailing backslash, then trim the now-trailing whitespace
|
|
48
|
+
// so the join reads cleanly.
|
|
49
|
+
const text = s.slice(0, s.length - 1).replace(/\s+$/, "");
|
|
50
|
+
return { continued: true, text };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Stitch accumulated continuation pieces plus the final line into one prompt.
|
|
55
|
+
*
|
|
56
|
+
* @param {string[]} pieces prior `text` values from continued lines
|
|
57
|
+
* @param {string} finalLine the line that ended the continuation (raw)
|
|
58
|
+
* @returns {string}
|
|
59
|
+
*/
|
|
60
|
+
export function joinContinuation(pieces, finalLine) {
|
|
61
|
+
const parts = Array.isArray(pieces) ? pieces.slice() : [];
|
|
62
|
+
parts.push(typeof finalLine === "string" ? finalLine : "");
|
|
63
|
+
return parts.join("\n");
|
|
64
|
+
}
|
package/src/lib/repl-rewind.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* REPL conversation rewind — Claude-Code double-Esc parity
|
|
3
|
-
*
|
|
2
|
+
* REPL conversation rewind — Claude-Code double-Esc parity. Conversation state
|
|
3
|
+
* AND, when auto-checkpointing is on (git work tree), the file tree are rewound
|
|
4
|
+
* together — matching Claude Code's rewind, which restores code + conversation
|
|
5
|
+
* in one step instead of leaving files on a separate `cc checkpoint restore`.
|
|
4
6
|
*
|
|
5
7
|
* Pure helpers over the REPL's live `messages` array so the picker logic is
|
|
6
8
|
* unit-testable without readline:
|
|
@@ -8,9 +10,19 @@
|
|
|
8
10
|
* - rewindToTurn(): truncate the conversation BACK TO BEFORE turn #n and
|
|
9
11
|
* return the original text so the caller can prefill the input line
|
|
10
12
|
* (edit-and-resend, like Claude Code's rewind).
|
|
13
|
+
* - pickCheckpointForTurn(): map a rewound turn to the file checkpoint that
|
|
14
|
+
* captured the work tree just before that turn first mutated it.
|
|
15
|
+
* - pruneMarksAfter(): drop checkpoint marks for the turns that were dropped.
|
|
11
16
|
*
|
|
12
17
|
* Trigger surfaces (wired in agent-repl): `/rewind` lists, `/rewind <n>`
|
|
13
18
|
* rewinds, and a double-Esc while idle prints the same list as a shortcut.
|
|
19
|
+
*
|
|
20
|
+
* Checkpoint marks: the REPL records `{ atMessageCount, id, tool }` for every
|
|
21
|
+
* `checkpoint` event the agent loop emits — `atMessageCount` is `messages.length`
|
|
22
|
+
* at the instant the snapshot was taken (always just AFTER the turn's user
|
|
23
|
+
* message was appended, so it is strictly greater than that turn's message
|
|
24
|
+
* index, and not-greater than any later turn's). That ordering is what lets a
|
|
25
|
+
* turn be matched to its pre-mutation snapshot purely from the count.
|
|
14
26
|
*/
|
|
15
27
|
|
|
16
28
|
export const DEFAULT_LIST_LIMIT = 10;
|
|
@@ -64,10 +76,61 @@ export function rewindToTurn(messages, n) {
|
|
|
64
76
|
messages.splice(turn.index);
|
|
65
77
|
return {
|
|
66
78
|
removed,
|
|
79
|
+
index: turn.index,
|
|
67
80
|
text: typeof turn.content === "string" ? turn.content : null,
|
|
68
81
|
};
|
|
69
82
|
}
|
|
70
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Map a rewound turn to the checkpoint that captured the work tree right BEFORE
|
|
86
|
+
* that turn first changed a file.
|
|
87
|
+
*
|
|
88
|
+
* A turn's auto-checkpoints are all taken with `atMessageCount` strictly greater
|
|
89
|
+
* than the turn's message index (the user message is appended first), while the
|
|
90
|
+
* previous turn's checkpoints have `atMessageCount <= turnIndex`. So the snapshot
|
|
91
|
+
* representing "state before turn N" is the one with the SMALLEST atMessageCount
|
|
92
|
+
* still greater than turnIndex.
|
|
93
|
+
*
|
|
94
|
+
* @param {Array<{atMessageCount:number,id:string,tool?:string}>} marks
|
|
95
|
+
* @param {number} turnIndex message index returned by rewindToTurn
|
|
96
|
+
* @returns {{atMessageCount:number,id:string,tool?:string}|null}
|
|
97
|
+
*/
|
|
98
|
+
export function pickCheckpointForTurn(marks, turnIndex) {
|
|
99
|
+
if (!Array.isArray(marks) || marks.length === 0) return null;
|
|
100
|
+
const idx = Number(turnIndex);
|
|
101
|
+
if (!Number.isFinite(idx)) return null;
|
|
102
|
+
let best = null;
|
|
103
|
+
for (const m of marks) {
|
|
104
|
+
if (!m || typeof m.id !== "string") continue;
|
|
105
|
+
const c = Number(m.atMessageCount);
|
|
106
|
+
if (!Number.isFinite(c) || c <= idx) continue;
|
|
107
|
+
if (best === null || c < Number(best.atMessageCount)) best = m;
|
|
108
|
+
}
|
|
109
|
+
return best;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Drop checkpoint marks belonging to turns that were just rewound away (those
|
|
114
|
+
* with `atMessageCount` greater than the surviving message count). Mutates the
|
|
115
|
+
* array in place so the REPL's `const` marks array keeps its identity.
|
|
116
|
+
*
|
|
117
|
+
* @returns {number} how many marks were removed
|
|
118
|
+
*/
|
|
119
|
+
export function pruneMarksAfter(marks, turnIndex) {
|
|
120
|
+
if (!Array.isArray(marks)) return 0;
|
|
121
|
+
const idx = Number(turnIndex);
|
|
122
|
+
if (!Number.isFinite(idx)) return 0;
|
|
123
|
+
let removed = 0;
|
|
124
|
+
for (let i = marks.length - 1; i >= 0; i--) {
|
|
125
|
+
const c = Number(marks[i]?.atMessageCount);
|
|
126
|
+
if (!Number.isFinite(c) || c > idx) {
|
|
127
|
+
marks.splice(i, 1);
|
|
128
|
+
removed += 1;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return removed;
|
|
132
|
+
}
|
|
133
|
+
|
|
71
134
|
/**
|
|
72
135
|
* Offline extractive recap for a resumed conversation ("where were we") —
|
|
73
136
|
* no LLM call: turn counts + last ask + last reply previews.
|