chainlesschain 0.162.158 → 0.162.159
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-BwpTJTN_.js → AIOps-ByIiF5bT.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BtQOoo3l.js → ActionButton-NlgSFZq5.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Duf_rXZa.js → Analytics-D17cOUcb.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-XQK3wjvB.js → AppLayout-B4mEZcbl.js} +4 -4
- package/src/assets/web-panel/assets/Artifacts-CASsmyQw.js +1 -0
- package/src/assets/web-panel/assets/{Audit-DNjOGQLh.js → Audit-DYAia2e2.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-FH9RAfB5.js → BackgroundAgents-C1lvYUSu.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-ZIbrR4-U.js → Backup-B6agK6bA.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DSt3NaND.js → BaseInput-DM43R2vy.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CY-wvbjv.js → Chat-Dtdp3eXp.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BAV9V-t-.js → ChatBubbleRenderer-BL5c_OQ1.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-8JVadE_B.js → Checkbox-D2xf7uZt.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CN83nPYI.js → Codegen-D3j45jJL.js} +1 -1
- package/src/assets/web-panel/assets/{Col-xPSvqdN8.js → Col-voPJ9fUZ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D78cnIjG.js → Community-DEsyTESF.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CSw6Csbp.js → Compact-OHV_QXLD.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-E_HhjcYR.js → Compliance-eDTJWC-J.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DybeQjmm.js → Cowork-BBvy-6d1.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DS0BJeLY.js → Cron-Dw2eoJxu.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BOwVgkbs.js → Crosschain-DQHms_Bh.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DRUr9YuX.js → DID-Cyu7Id1c.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cht-yUKW.js → Dashboard-sIDzkG92.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BLr_EJ9X.js → Dropdown-DUW3T2ey.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Drexuh5W.js → EmailListRenderer-CECELXW8.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D9Q2Kq63.js → FamilyGuardDashboard-BIZR37ov.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C-Z1xI-T.js → Federation-BEZIQX84.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DLHPMkQF.js → FormItemContext-BcdUMznL.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DxxEdn2r.js → GenericCardRenderer-DsN_fr5H.js} +1 -1
- package/src/assets/web-panel/assets/{Git-syATcaBt.js → Git-63LhjBx2.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CYe_r8Zf.js → Governance-CYtQtIcH.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-GWxErB7k.js → Inference-BwR6UUox.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-qQvVCZoi.js → KnowledgeGraph-D9lVNTUA.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BenAU2W8.js → Logs-C4q5h7Ut.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-7agE3Or1.js → MarkdownRenderer-DexLlXfN.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-D4Jn5fpD.js → Marketplace-Plksliuw.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DtAwoqiQ.js → McpTools-DZUFfeuG.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-BI_O50I8.js → Memory-NoDYt29V.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CQWE2lqx.js → MobileBridge-CEXGTkdh.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CVtTqgtg.js → MobileProjects-DnbJkbZo.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Dnr16qsn.js → Mtc-DTAa0cwy.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-CQ5Xe4-a.js → MtcAudit-CVV7LnNS.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Bjr8O-wy.js → Multisig-BqqGrjt_.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CEe-KirU.js → NLProgramming-C4WP8DRp.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-spKJIKF9.js → Notes-Zo4DJUVI.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-DRp83LFG.js → NotificationSettings-DBcjRaz2.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BCQel9bD.js +1 -0
- package/src/assets/web-panel/assets/{Organization-BlgB0IYg.js → Organization-BT9WPBOX.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-a_35HqZI.js → Overflow-D6b4bZ3q.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CSNHCNPC.js → P2P-Cw3OsYx-.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-C8M1JH-1.js → PdhVaultBrowser-C0nyiK2b.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DmjJi9Ms.js → Permissions-zVBZEB_C.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-DfuwRyf4.js → PersonalDataHub-BOspsFew.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-B2-S4ekE.js → Pipeline-CQWfZ4XH.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B1dOiBLC.js → Privacy-C2oGJ_WL.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-_pNmc-DX.js → ProjectInit-BZMR4qY1.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DmwG2Ii1.js → ProjectSettings-DAujoP63.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-COATmHxF.js → Projects-DvH_P2Uq.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-C6HSjg1d.js → Providers-D_RGHM-v.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CrDmS7l1.js → QrScannerModal-Mf6KfL2J.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CfKvWt-x.js → QuickAsk-5D8URoI_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DMa6Kuzv.js → Recommend-Df4kC8Gy.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DrktUo5x.js → RemoteSession-DGi3f3vO.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BTPQ1vjL.js → Reputation-jmkGFNWb.js} +1 -1
- package/src/assets/web-panel/assets/{Row-B6Q7QkMG.js → Row-DP6Pcu3m.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B1IJhAmX.js → RssFeed-D60hSuPO.js} +3 -3
- package/src/assets/web-panel/assets/{Search-xbea1kGD.js → Search-0mf1BQUK.js} +1 -1
- package/src/assets/web-panel/assets/{Security-7rs0cO3F.js → Security-CfZtLFYV.js} +4 -4
- package/src/assets/web-panel/assets/{Services-0fjixK0S.js → Services-D9zpZLWz.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-B_rVq9Cu.js → Skeleton-D1_44eMD.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C5uM90b9.js → Skills-cVFa8zkz.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-U4pYCIZH.js → Sla-Cinpzc3L.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cdz4yTWx.js → SpeechSettings-bqdiJE_P.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Me3aetHv.js → SyncSettings-Dgl_SLgj.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Cf6aNkL_.js → Tasks-DawWAEhy.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CYatk4tU.js → Templates-Ca0nY651.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DIMKLw7o.js → Tenant-CgaGEhLm.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-C_cp-uSJ.js → Terminal-D-9EnpRx.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-cUPVNADp.js → TimelineRenderer-CSOxDHZ6.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CiaEIXVf.js → Tokens-BpwLZpL3.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DB1WU5lQ.js → Trigger-DgowwBK5.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Cfht9Ijy.js → Trust-BZutapjE.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-K3P4Vt9S.js → UkeySign-QZPt8_Sp.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DWjhjXRh.js → VideoEditing-DlQx5UDJ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D9-Q1Kan.js → Wallet-ZfdTgtWA.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BDszy-oV.js → WebAuthn-CAp0y_Cr.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-DIhij4rA.js → WorkflowEditor-BVITZEmr.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D7VCiKbh.js → chat-CC2tPaNg.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BvOd9pVn.js → colors-31brc9CA.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DoqXBiAO.js → compact-item-DLMkC9C-.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CrKRzUtp.js → createContext-BMtveI6F.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CB8pPOtd.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BWAev4WC.js → hasIn-DbD6WHW2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B30NvR21.js → index-3oBsXZmF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx7M7PSF.js → index-ALvoNTRF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHOcVYrx.js → index-AaIKG60c.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXyl8O23.js → index-BFRLmCR3.js} +1 -1
- package/src/assets/web-panel/assets/{index-YGDy7nNq.js → index-BKAB6-6V.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoYrS_L2.js → index-BOM-VFlv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bq_ctRpz.js → index-BPpS-lGb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDGLdn12.js → index-Bbc2JeQG.js} +1 -1
- package/src/assets/web-panel/assets/index-BhXiaiev.js +1 -0
- package/src/assets/web-panel/assets/{index-ISvPZ05r.js → index-BiRQUoyE.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0vGEbJT.js → index-BnFLzejT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bj7EgmOp.js → index-BoO4WEJB.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZGk8AbZ.js → index-C-cGlCDW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkgnGX7v.js → index-C1PfeI88.js} +1 -1
- package/src/assets/web-panel/assets/{index-HwHdTusY.js → index-C21pdBqs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bf9YlbDn.js → index-C7LHNw_N.js} +1 -1
- package/src/assets/web-panel/assets/{index-oY45XrkG.js → index-CEXa-4zd.js} +1 -1
- package/src/assets/web-panel/assets/{index-KR1-Em9C.js → index-CEwjBA9q.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5kRmj3P.js → index-CFXKbOek.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN9m4Ux2.js → index-CJhREOlG.js} +1 -1
- package/src/assets/web-panel/assets/{index-PDxGjKRu.js → index-COHHQ9cU.js} +1 -1
- package/src/assets/web-panel/assets/{index-D23L1V76.js → index-CUmLMFsy.js} +1 -1
- package/src/assets/web-panel/assets/{index-zH-tuuGZ.js → index-CWgfipcC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmJ6xKBO.js → index-C_eUKGYP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEPHMSih.js → index-CcVszn2b.js} +1 -1
- package/src/assets/web-panel/assets/{index-DV-Rfmfx.js → index-Cod97Urs.js} +3 -3
- package/src/assets/web-panel/assets/{index-BWWsaimP.js → index-Cwbqh0KZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-8g5TJCZ3.js → index-D67kIagl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEXfKSiI.js → index-D7cV0tu0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CoD31Ndm.js → index-DJvxFyIz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSb-tnIo.js → index-DZl-UXB6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvDOpsJB.js → index-Dm0byjm1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlGu7As6.js → index-DndNnYc0.js} +1 -1
- package/src/assets/web-panel/assets/{index-gmxqu5Kk.js → index-WQUO2vvK.js} +1 -1
- package/src/assets/web-panel/assets/index-WpaYaE3D.js +1 -0
- package/src/assets/web-panel/assets/{index-ww1QtLnX.js → index-bdaJwTXJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-JzUmJMvn.js → index-ep6JchNG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCyP071m.js → index-jG6h22Qg.js} +1 -1
- package/src/assets/web-panel/assets/{index-1poMpMU0.js → index-ntVQqSML.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-XW-OR3mL.js → initDefaultProps-D5UoBRhN.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CeuEHh20.js → motion-DltOw0CR.js} +1 -1
- package/src/assets/web-panel/assets/{move-Dva79Keg.js → move-_oPkk5zj.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C0B6bD2j.js → mtc-parser-EES8ROCS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-AkZvO-a2.js → omit-B-_39x_M.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-B4r55qGc.js → pickAttrs-l6D0yJHz.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BLH-z7YE.js → placementArrow-DIeUK31L.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-ksEGZ2Wf.js → responsiveObserve-dG4EzUQo.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Cth4OD1Z.js → slide-DWFzYGdH.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-9S83ezxw.js → statusUtils-CECdTA5H.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-7yQmQGZ4.js → styleChecker-D6kP-mMK.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DpGnMmPc.js → useFlexGapSupport-BWfna_rd.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-C4zDZIXH.js → useFs-Bb-j6rzo.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CoLICdUZ.js → usePersonalDataHub-D5OIsYM4.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CKyH-35X.js → vnode-DNpwzFTM.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DRDGit17.js → zoom-vNLpFQBW.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-manifest.json +17 -3
- package/src/commands/agent.js +7 -0
- package/src/commands/background-session.js +143 -3
- package/src/commands/browse.js +86 -0
- package/src/commands/cloud.js +232 -0
- package/src/commands/doctor.js +61 -6
- package/src/commands/mcp.js +61 -0
- package/src/commands/plugin.js +63 -1
- package/src/commands/routine.js +367 -0
- package/src/commands/session.js +326 -0
- package/src/data/changelog.json +7 -2
- package/src/harness/jsonl-session-store.js +82 -2
- package/src/harness/session-index.js +295 -0
- package/src/harness/session-mirror.js +142 -0
- package/src/harness/transcript-integrity.js +182 -0
- package/src/index.js +8 -0
- package/src/lib/background-agent-supervisor.js +126 -2
- package/src/lib/channels/channel-manager.js +126 -0
- package/src/lib/channels/telegram-channel.js +112 -0
- package/src/lib/channels/webhook-channel.js +140 -0
- package/src/lib/chrome-connector.js +386 -0
- package/src/lib/cloud/bundle.js +110 -0
- package/src/lib/cloud/cloud-client.js +152 -0
- package/src/lib/computer-use/authorization.js +173 -0
- package/src/lib/computer-use/computer-use-server.js +276 -0
- package/src/lib/computer-use/control-backend.js +150 -0
- package/src/lib/doctor-checkup.js +652 -0
- package/src/lib/jsonl-session-store.js +4 -0
- package/src/lib/lsp/lsp-server-registry.js +48 -21
- package/src/lib/plugin-runtime/governance.js +174 -0
- package/src/lib/pr-link-ledger.js +221 -0
- package/src/lib/routine-store.js +352 -0
- package/src/lib/session-store-guard.js +40 -0
- package/src/lib/session-usage.js +318 -2
- package/src/lib/sub-agent-context.js +23 -0
- package/src/repl/agent-repl.js +361 -3
- package/src/repl/bg-dashboard.js +355 -0
- package/src/repl/fast-mode.js +103 -0
- package/src/repl/fullscreen-tui.js +197 -0
- package/src/repl/slash-command-registry.js +11 -3
- package/src/repl/voice-dictation.js +132 -0
- package/src/runtime/agent-core.js +242 -1
- package/src/runtime/coding-agent-contract-shared.cjs +88 -0
- package/src/runtime/coding-agent-policy.cjs +17 -0
- package/src/runtime/headless-runner.js +71 -7
- package/src/runtime/headless-stream.js +14 -8
- package/src/runtime/policies/agent-policy.js +3 -0
- package/src/assets/web-panel/assets/Artifacts-DQvJoQ6E.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-h1A0XB2a.js +0 -1
- package/src/assets/web-panel/assets/devWarning-nDB--2xr.js +0 -1
- package/src/assets/web-panel/assets/index-B1_pRTtB.js +0 -1
- package/src/assets/web-panel/assets/index-TMM9FuW-.js +0 -1
package/src/repl/agent-repl.js
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
appendAssistantMessage,
|
|
48
48
|
appendCompactEvent,
|
|
49
49
|
appendTokenUsage,
|
|
50
|
+
appendToolCallCompact,
|
|
50
51
|
rebuildMessages,
|
|
51
52
|
sessionExists,
|
|
52
53
|
} from "../harness/jsonl-session-store.js";
|
|
@@ -316,6 +317,25 @@ export async function agentLoop(messages, options) {
|
|
|
316
317
|
),
|
|
317
318
|
);
|
|
318
319
|
} else if (event.type === "tool-result") {
|
|
320
|
+
// 用量归因: persist a compact tool_call record (name + error flag +
|
|
321
|
+
// skill hint — never args, which can carry whole file bodies) so
|
|
322
|
+
// `cc session usage --by tool|mcp` and `cc insights` can aggregate
|
|
323
|
+
// tool use for REPL sessions. Best-effort; opt out with
|
|
324
|
+
// options.persistToolCalls === false.
|
|
325
|
+
if (options.sessionId && options.persistToolCalls !== false) {
|
|
326
|
+
try {
|
|
327
|
+
appendToolCallCompact(options.sessionId, {
|
|
328
|
+
tool: event.tool,
|
|
329
|
+
isError: Boolean(event.error || event.result?.error),
|
|
330
|
+
skill:
|
|
331
|
+
event.tool === "run_skill" && _lastExec?.tool === "run_skill"
|
|
332
|
+
? _lastExec.args?.skill_name
|
|
333
|
+
: undefined,
|
|
334
|
+
});
|
|
335
|
+
} catch (_e) {
|
|
336
|
+
// persistence is best-effort — never break the turn
|
|
337
|
+
}
|
|
338
|
+
}
|
|
319
339
|
if (event.error || event.result?.error) {
|
|
320
340
|
process.stdout.write(
|
|
321
341
|
chalk.red(` Error: ${event.error || event.result?.error}\n`),
|
|
@@ -1298,6 +1318,21 @@ export async function startAgentRepl(options = {}) {
|
|
|
1298
1318
|
if (options.sessionId && sessionId) {
|
|
1299
1319
|
try {
|
|
1300
1320
|
if (useJsonl) {
|
|
1321
|
+
// Interactive tamper warning: a broken hash chain means the transcript
|
|
1322
|
+
// was edited outside the store — resume proceeds (the user is present)
|
|
1323
|
+
// but the restored context is flagged untrusted.
|
|
1324
|
+
try {
|
|
1325
|
+
const { verifySession } =
|
|
1326
|
+
await import("../harness/jsonl-session-store.js");
|
|
1327
|
+
const trust = verifySession(sessionId);
|
|
1328
|
+
if (trust.status === "tampered") {
|
|
1329
|
+
logger.warn(
|
|
1330
|
+
`⚠ Transcript integrity check FAILED (${trust.reason}) — restored context is untrusted. Run 'cc session verify ${sessionId}'.`,
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
} catch (_err) {
|
|
1334
|
+
// verification is best-effort in the interactive path
|
|
1335
|
+
}
|
|
1301
1336
|
const rebuilt = rebuildMessages(sessionId);
|
|
1302
1337
|
if (rebuilt.length > 0) {
|
|
1303
1338
|
messages.push(...rebuilt.filter((m) => m.role !== "system"));
|
|
@@ -1413,6 +1448,84 @@ export async function startAgentRepl(options = {}) {
|
|
|
1413
1448
|
// stored cli.theme is untouched — /theme still shows and can change it).
|
|
1414
1449
|
if (_screenReaderMode) _theme = "mono";
|
|
1415
1450
|
applyThemeChalk(_theme, chalk, _chalkBaselineLevel);
|
|
1451
|
+
|
|
1452
|
+
// Fullscreen / no-flicker TUI mode (Claude-Code `/tui` parity). Resolve from
|
|
1453
|
+
// CC_NO_FLICKER (forces fullscreen) or persisted `cli.tuiMode`; switchable at
|
|
1454
|
+
// runtime via `/tui fullscreen|default`. Screen-reader mode forces default —
|
|
1455
|
+
// an alternate screen buffer breaks readers. The heavy renderer lives in
|
|
1456
|
+
// fullscreen-tui.js; here we just track the mode and toggle the alt buffer.
|
|
1457
|
+
const {
|
|
1458
|
+
resolveTuiMode: _resolveTuiMode,
|
|
1459
|
+
renderTuiStatus: _renderTuiStatus,
|
|
1460
|
+
ALT_SCREEN_ENTER: _ALT_ENTER,
|
|
1461
|
+
ALT_SCREEN_LEAVE: _ALT_LEAVE,
|
|
1462
|
+
} = await import("./fullscreen-tui.js");
|
|
1463
|
+
let _tuiMode = "default";
|
|
1464
|
+
try {
|
|
1465
|
+
const { getConfigValue } = await import("../lib/config-manager.js");
|
|
1466
|
+
_tuiMode = _resolveTuiMode({
|
|
1467
|
+
env: process.env.CC_NO_FLICKER,
|
|
1468
|
+
setting: getConfigValue("cli.tuiMode"),
|
|
1469
|
+
});
|
|
1470
|
+
} catch (_e) {
|
|
1471
|
+
_tuiMode = _resolveTuiMode({ env: process.env.CC_NO_FLICKER });
|
|
1472
|
+
}
|
|
1473
|
+
if (_screenReaderMode) _tuiMode = "default";
|
|
1474
|
+
const _setTuiMode = (next) => {
|
|
1475
|
+
if (next === _tuiMode) return;
|
|
1476
|
+
// Enter/leave the alternate screen buffer so the user's scrollback is
|
|
1477
|
+
// preserved either way. Only touch a real TTY.
|
|
1478
|
+
if (process.stdout.isTTY) {
|
|
1479
|
+
process.stdout.write(next === "fullscreen" ? _ALT_ENTER : _ALT_LEAVE);
|
|
1480
|
+
}
|
|
1481
|
+
_tuiMode = next;
|
|
1482
|
+
};
|
|
1483
|
+
if (_tuiMode === "fullscreen" && process.stdout.isTTY) {
|
|
1484
|
+
process.stdout.write(_ALT_ENTER);
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
// Fast mode (Claude-Code `/fast` parity, generalized to a latency profile).
|
|
1488
|
+
// When on, the next turn minimizes reasoning and — unless the user pinned a
|
|
1489
|
+
// model this session — swaps to the provider's low-latency model. Resolved
|
|
1490
|
+
// from config `cli.fastMode`; toggled at runtime via `/fast`. `_modelPinned`
|
|
1491
|
+
// tracks an explicit `/model x` so fast mode never overrides a chosen model.
|
|
1492
|
+
const {
|
|
1493
|
+
parseFastCommand: _parseFastCommand,
|
|
1494
|
+
resolveFastPlan: _resolveFastPlan,
|
|
1495
|
+
renderFastStatus: _renderFastStatus,
|
|
1496
|
+
} = await import("./fast-mode.js");
|
|
1497
|
+
let _fastMode = false;
|
|
1498
|
+
let _modelPinned = false;
|
|
1499
|
+
try {
|
|
1500
|
+
const { getConfigValue } = await import("../lib/config-manager.js");
|
|
1501
|
+
_fastMode = getConfigValue("cli.fastMode") === true;
|
|
1502
|
+
} catch (_e) {
|
|
1503
|
+
/* config optional */
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// Voice dictation (Claude-Code `/voice` parity). Local-first STT priority;
|
|
1507
|
+
// degrades cleanly on headless/SSH. Real capture is a host binding — probed
|
|
1508
|
+
// from config `voice.backends` (map of backend id → true) — so with no
|
|
1509
|
+
// backend bundled, `/voice hold` reports how to enable one rather than
|
|
1510
|
+
// pretending to listen. `voice.allowCloud` gates cloud transcription.
|
|
1511
|
+
const {
|
|
1512
|
+
parseVoiceCommand: _parseVoiceCommand,
|
|
1513
|
+
resolveSttBackend: _resolveSttBackend,
|
|
1514
|
+
detectVoiceEnvironment: _detectVoiceEnvironment,
|
|
1515
|
+
renderVoiceStatus: _renderVoiceStatus,
|
|
1516
|
+
} = await import("./voice-dictation.js");
|
|
1517
|
+
let _voiceMode = "off";
|
|
1518
|
+
let _voiceConfig = { backends: {}, allowCloud: false };
|
|
1519
|
+
try {
|
|
1520
|
+
const { getConfigValue } = await import("../lib/config-manager.js");
|
|
1521
|
+
const v = getConfigValue("voice") || {};
|
|
1522
|
+
_voiceConfig = {
|
|
1523
|
+
backends: v.backends || {},
|
|
1524
|
+
allowCloud: v.allowCloud === true,
|
|
1525
|
+
};
|
|
1526
|
+
} catch (_e) {
|
|
1527
|
+
/* config optional */
|
|
1528
|
+
}
|
|
1416
1529
|
const themedPrompt = (text) => {
|
|
1417
1530
|
const a = promptAccent(_theme);
|
|
1418
1531
|
if (a === "blue") return chalk.blue(text);
|
|
@@ -1457,6 +1570,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1457
1570
|
"/cd",
|
|
1458
1571
|
"/clear",
|
|
1459
1572
|
"/compact",
|
|
1573
|
+
"/checkup",
|
|
1460
1574
|
"/config",
|
|
1461
1575
|
"/context",
|
|
1462
1576
|
"/copy",
|
|
@@ -1466,6 +1580,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1466
1580
|
"/effort",
|
|
1467
1581
|
"/exit",
|
|
1468
1582
|
"/export",
|
|
1583
|
+
"/fast",
|
|
1469
1584
|
"/help",
|
|
1470
1585
|
"/hooks",
|
|
1471
1586
|
"/ide",
|
|
@@ -1501,8 +1616,10 @@ export async function startAgentRepl(options = {}) {
|
|
|
1501
1616
|
"/theme",
|
|
1502
1617
|
"/think",
|
|
1503
1618
|
"/todos",
|
|
1619
|
+
"/tui",
|
|
1504
1620
|
"/ultrathink",
|
|
1505
1621
|
"/vim",
|
|
1622
|
+
"/voice",
|
|
1506
1623
|
],
|
|
1507
1624
|
// User/project custom commands (.claude/commands/*.md) join TAB completion
|
|
1508
1625
|
// alongside the built-ins above. Sync + best-effort; the completer
|
|
@@ -1545,6 +1662,37 @@ export async function startAgentRepl(options = {}) {
|
|
|
1545
1662
|
// "close" cleanup instead of a bare exit.
|
|
1546
1663
|
_replRl = rl;
|
|
1547
1664
|
|
|
1665
|
+
// Inbound channels (--channels, gap-2026-07-11 P0#5): external events enter
|
|
1666
|
+
// this session as user turns. rl.emit("line") reuses the REPL's own input
|
|
1667
|
+
// path, so an event landing mid-turn queues behind it (pending-lines), and
|
|
1668
|
+
// the [channel:...] prefix keeps provenance visible while guaranteeing the
|
|
1669
|
+
// injected line can never read as a slash command or shell escape.
|
|
1670
|
+
let _channels = null;
|
|
1671
|
+
if (options.channels) {
|
|
1672
|
+
try {
|
|
1673
|
+
const { startChannels, formatChannelEvent } =
|
|
1674
|
+
await import("../lib/channels/channel-manager.js");
|
|
1675
|
+
let channelsConfig = {};
|
|
1676
|
+
try {
|
|
1677
|
+
channelsConfig =
|
|
1678
|
+
(await import("../lib/config-manager.js")).loadConfig()?.channels ||
|
|
1679
|
+
{};
|
|
1680
|
+
} catch (_err) {
|
|
1681
|
+
// config read is best-effort; channels validate their own inputs
|
|
1682
|
+
}
|
|
1683
|
+
_channels = await startChannels(options.channels, {
|
|
1684
|
+
config: channelsConfig,
|
|
1685
|
+
onEvent: (event) => rl.emit("line", formatChannelEvent(event)),
|
|
1686
|
+
log: (msg) => logger.info(msg),
|
|
1687
|
+
});
|
|
1688
|
+
for (const c of _channels.channels) {
|
|
1689
|
+
logger.info(`channel ready: ${c.describe}`);
|
|
1690
|
+
}
|
|
1691
|
+
} catch (err) {
|
|
1692
|
+
logger.warn(`channels: ${err.message}`);
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1548
1696
|
// Vim-mode plumbing: capture readline's OWN keypress listeners now so we can
|
|
1549
1697
|
// suspend them while in NORMAL mode (the engine drives editing then) and
|
|
1550
1698
|
// reattach them for INSERT mode (readline's rich editing/history/completion).
|
|
@@ -1985,6 +2133,15 @@ export async function startAgentRepl(options = {}) {
|
|
|
1985
2133
|
logger.log(
|
|
1986
2134
|
` ${chalk.cyan("/theme")} Color theme (/theme <auto|dark|light|mono>; mono = no color)`,
|
|
1987
2135
|
);
|
|
2136
|
+
logger.log(
|
|
2137
|
+
` ${chalk.cyan("/tui")} Fullscreen no-flicker view (/tui <fullscreen|default>; CC_NO_FLICKER=1)`,
|
|
2138
|
+
);
|
|
2139
|
+
logger.log(
|
|
2140
|
+
` ${chalk.cyan("/fast")} Latency profile — faster+cheaper, less reasoning (/fast on|off|status)`,
|
|
2141
|
+
);
|
|
2142
|
+
logger.log(
|
|
2143
|
+
` ${chalk.cyan("/voice")} Speech dictation — local-first STT (/voice hold|tap|off)`,
|
|
2144
|
+
);
|
|
1988
2145
|
logger.log(
|
|
1989
2146
|
` ${chalk.cyan("/output-style")} Response persona (/output-style <name|list>; explanatory/learning built-in)`,
|
|
1990
2147
|
);
|
|
@@ -1992,7 +2149,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
1992
2149
|
` ${chalk.cyan("/config")} Show config; ${chalk.cyan("/config <key>")} read, ${chalk.cyan("/config <key>=<val>")} set, ${chalk.cyan("/config --help")} keys`,
|
|
1993
2150
|
);
|
|
1994
2151
|
logger.log(
|
|
1995
|
-
` ${chalk.cyan("/doctor")} Session health check (provider/key/IDE/MCP/hooks)`,
|
|
2152
|
+
` ${chalk.cyan("/doctor")} Session health check (provider/key/IDE/MCP/hooks; alias /checkup)`,
|
|
1996
2153
|
);
|
|
1997
2154
|
logger.log(
|
|
1998
2155
|
` ${chalk.cyan("/status")} Environment snapshot (version/model/session/cwd/roots/IDE·MCP·hooks)`,
|
|
@@ -2402,6 +2559,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
2402
2559
|
if (arg) {
|
|
2403
2560
|
model = arg;
|
|
2404
2561
|
_curModel = model; // keep the status-line readout in sync
|
|
2562
|
+
_modelPinned = true; // explicit choice — fast mode must not override it
|
|
2405
2563
|
logger.info(`Model: ${chalk.cyan(model)}`);
|
|
2406
2564
|
// Claude-Code 2.1.183 parity: warn when the newly-selected model is a
|
|
2407
2565
|
// provider-retired/deprecated snapshot. Headless paths already warn via
|
|
@@ -2580,6 +2738,149 @@ export async function startAgentRepl(options = {}) {
|
|
|
2580
2738
|
return;
|
|
2581
2739
|
}
|
|
2582
2740
|
|
|
2741
|
+
// `/tui` — fullscreen no-flicker view (Claude-Code parity). `fullscreen`
|
|
2742
|
+
// enters the alternate screen buffer; `default` returns to streaming
|
|
2743
|
+
// scrollback. No arg prints the current mode. Persisted to `cli.tuiMode`.
|
|
2744
|
+
if (trimmed === "/tui" || trimmed.startsWith("/tui ")) {
|
|
2745
|
+
const arg = trimmed.slice("/tui".length).trim().toLowerCase();
|
|
2746
|
+
if (!arg) {
|
|
2747
|
+
logger.log(chalk.gray(_renderTuiStatus(_tuiMode)));
|
|
2748
|
+
prompt();
|
|
2749
|
+
return;
|
|
2750
|
+
}
|
|
2751
|
+
const next = _resolveTuiMode({ arg });
|
|
2752
|
+
if (arg !== "fullscreen" && arg !== "default") {
|
|
2753
|
+
logger.error(
|
|
2754
|
+
chalk.red(`Unknown TUI mode "${arg}". Use: fullscreen | default`),
|
|
2755
|
+
);
|
|
2756
|
+
prompt();
|
|
2757
|
+
return;
|
|
2758
|
+
}
|
|
2759
|
+
if (_screenReaderMode && next === "fullscreen") {
|
|
2760
|
+
logger.info(
|
|
2761
|
+
chalk.gray(
|
|
2762
|
+
"Screen-reader mode is on — staying in default (scrollback) view.",
|
|
2763
|
+
),
|
|
2764
|
+
);
|
|
2765
|
+
prompt();
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
_setTuiMode(next);
|
|
2769
|
+
try {
|
|
2770
|
+
const { setConfigValue } = await import("../lib/config-manager.js");
|
|
2771
|
+
setConfigValue("cli.tuiMode", _tuiMode);
|
|
2772
|
+
} catch (_e) {
|
|
2773
|
+
/* persistence is best-effort */
|
|
2774
|
+
}
|
|
2775
|
+
logger.log(chalk.gray(_renderTuiStatus(_tuiMode)));
|
|
2776
|
+
prompt();
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
// `/fast` — latency profile (Claude-Code parity). on/off/status/toggle.
|
|
2781
|
+
// When on, the next turn minimizes reasoning and swaps to the provider's
|
|
2782
|
+
// low-latency model (unless a model is pinned). Persisted to cli.fastMode.
|
|
2783
|
+
{
|
|
2784
|
+
const fast = _parseFastCommand(trimmed);
|
|
2785
|
+
if (fast) {
|
|
2786
|
+
if (fast.error) {
|
|
2787
|
+
logger.error(chalk.red(fast.error));
|
|
2788
|
+
prompt();
|
|
2789
|
+
return;
|
|
2790
|
+
}
|
|
2791
|
+
if (fast.action === "status") {
|
|
2792
|
+
logger.log(
|
|
2793
|
+
chalk.gray(
|
|
2794
|
+
_renderFastStatus({ enabled: _fastMode, provider, model }),
|
|
2795
|
+
),
|
|
2796
|
+
);
|
|
2797
|
+
prompt();
|
|
2798
|
+
return;
|
|
2799
|
+
}
|
|
2800
|
+
_fastMode =
|
|
2801
|
+
fast.action === "on"
|
|
2802
|
+
? true
|
|
2803
|
+
: fast.action === "off"
|
|
2804
|
+
? false
|
|
2805
|
+
: !_fastMode;
|
|
2806
|
+
try {
|
|
2807
|
+
const { setConfigValue } = await import("../lib/config-manager.js");
|
|
2808
|
+
setConfigValue("cli.fastMode", _fastMode);
|
|
2809
|
+
} catch (_e) {
|
|
2810
|
+
/* persistence is best-effort */
|
|
2811
|
+
}
|
|
2812
|
+
logger.log(
|
|
2813
|
+
chalk.gray(
|
|
2814
|
+
_renderFastStatus({ enabled: _fastMode, provider, model }),
|
|
2815
|
+
),
|
|
2816
|
+
);
|
|
2817
|
+
prompt();
|
|
2818
|
+
return;
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
// `/voice` — speech dictation (Claude-Code parity). hold=push-to-talk,
|
|
2823
|
+
// tap=toggle, off, status. Local-first STT; degrades on headless/SSH or
|
|
2824
|
+
// when no capture backend is configured (voice.backends / voice.allowCloud).
|
|
2825
|
+
{
|
|
2826
|
+
const voice = _parseVoiceCommand(trimmed);
|
|
2827
|
+
if (voice) {
|
|
2828
|
+
if (voice.error) {
|
|
2829
|
+
logger.error(chalk.red(voice.error));
|
|
2830
|
+
prompt();
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2833
|
+
const voiceEnv = _detectVoiceEnvironment({
|
|
2834
|
+
env: process.env,
|
|
2835
|
+
isTTY: Boolean(process.stdin.isTTY),
|
|
2836
|
+
});
|
|
2837
|
+
if (voice.action === "status") {
|
|
2838
|
+
const be = _resolveSttBackend(_voiceConfig).backend;
|
|
2839
|
+
logger.log(
|
|
2840
|
+
chalk.gray(
|
|
2841
|
+
_renderVoiceStatus({
|
|
2842
|
+
mode: _voiceMode,
|
|
2843
|
+
backend: be,
|
|
2844
|
+
env: voiceEnv,
|
|
2845
|
+
}),
|
|
2846
|
+
),
|
|
2847
|
+
);
|
|
2848
|
+
prompt();
|
|
2849
|
+
return;
|
|
2850
|
+
}
|
|
2851
|
+
if (voice.action === "off") {
|
|
2852
|
+
_voiceMode = "off";
|
|
2853
|
+
logger.log(chalk.gray("Voice: off."));
|
|
2854
|
+
prompt();
|
|
2855
|
+
return;
|
|
2856
|
+
}
|
|
2857
|
+
// hold | tap — need a usable environment AND a resolvable backend.
|
|
2858
|
+
if (!voiceEnv.supported) {
|
|
2859
|
+
logger.info(chalk.yellow(`Voice unavailable — ${voiceEnv.reason}.`));
|
|
2860
|
+
prompt();
|
|
2861
|
+
return;
|
|
2862
|
+
}
|
|
2863
|
+
const { backend, reason } = _resolveSttBackend(_voiceConfig);
|
|
2864
|
+
if (!backend) {
|
|
2865
|
+
logger.info(chalk.yellow(`Voice: ${reason}`));
|
|
2866
|
+
prompt();
|
|
2867
|
+
return;
|
|
2868
|
+
}
|
|
2869
|
+
_voiceMode = voice.action;
|
|
2870
|
+
logger.log(
|
|
2871
|
+
chalk.gray(
|
|
2872
|
+
_renderVoiceStatus({
|
|
2873
|
+
mode: _voiceMode,
|
|
2874
|
+
backend,
|
|
2875
|
+
env: voiceEnv,
|
|
2876
|
+
}) + ` (${reason})`,
|
|
2877
|
+
),
|
|
2878
|
+
);
|
|
2879
|
+
prompt();
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2583
2884
|
if (trimmed === "/vim" || trimmed.startsWith("/vim ")) {
|
|
2584
2885
|
const arg = trimmed.slice("/vim".length).trim().toLowerCase();
|
|
2585
2886
|
const turnOn = arg === "on" || (arg === "" && !_vimEnabled);
|
|
@@ -2982,6 +3283,18 @@ export async function startAgentRepl(options = {}) {
|
|
|
2982
3283
|
const resumeId = sessionArg.slice(7).trim();
|
|
2983
3284
|
try {
|
|
2984
3285
|
if (useJsonl && sessionExists(resumeId)) {
|
|
3286
|
+
try {
|
|
3287
|
+
const { verifySession } =
|
|
3288
|
+
await import("../harness/jsonl-session-store.js");
|
|
3289
|
+
const trust = verifySession(resumeId);
|
|
3290
|
+
if (trust.status === "tampered") {
|
|
3291
|
+
logger.warn(
|
|
3292
|
+
`⚠ Transcript integrity check FAILED (${trust.reason}) — restored context is untrusted. Run 'cc session verify ${resumeId}'.`,
|
|
3293
|
+
);
|
|
3294
|
+
}
|
|
3295
|
+
} catch (_err) {
|
|
3296
|
+
// verification is best-effort in the interactive path
|
|
3297
|
+
}
|
|
2985
3298
|
const rebuilt = rebuildMessages(resumeId);
|
|
2986
3299
|
messages.length = 1; // keep system prompt
|
|
2987
3300
|
messages.push(...rebuilt.filter((m) => m.role !== "system"));
|
|
@@ -3924,7 +4237,13 @@ export async function startAgentRepl(options = {}) {
|
|
|
3924
4237
|
|
|
3925
4238
|
// `/doctor` — consolidated session-health readout (Claude-Code parity):
|
|
3926
4239
|
// provider/key/IDE/MCP/permissions/hooks in one pass-or-warn view.
|
|
3927
|
-
|
|
4240
|
+
// `/checkup` is the Claude-Code 2.1.205 alias for the same readout.
|
|
4241
|
+
if (
|
|
4242
|
+
trimmed === "/doctor" ||
|
|
4243
|
+
trimmed.startsWith("/doctor ") ||
|
|
4244
|
+
trimmed === "/checkup" ||
|
|
4245
|
+
trimmed.startsWith("/checkup ")
|
|
4246
|
+
) {
|
|
3928
4247
|
let config = {};
|
|
3929
4248
|
try {
|
|
3930
4249
|
config = (await import("../lib/config-manager.js")).loadConfig() || {};
|
|
@@ -4633,6 +4952,22 @@ export async function startAgentRepl(options = {}) {
|
|
|
4633
4952
|
}
|
|
4634
4953
|
}
|
|
4635
4954
|
|
|
4955
|
+
// Fast mode (P2#12): minimize reasoning + swap to the provider's
|
|
4956
|
+
// low-latency model for this turn (never over a pinned model). Applied
|
|
4957
|
+
// after auto-selection so it has the last word on latency.
|
|
4958
|
+
let turnThinking = thinking;
|
|
4959
|
+
if (_fastMode) {
|
|
4960
|
+
const fastPlan = _resolveFastPlan({
|
|
4961
|
+
enabled: true,
|
|
4962
|
+
provider,
|
|
4963
|
+
model: activeModel,
|
|
4964
|
+
modelPinned: _modelPinned,
|
|
4965
|
+
});
|
|
4966
|
+
turnThinking = fastPlan.thinking;
|
|
4967
|
+
if (fastPlan.swapped) activeModel = fastPlan.model;
|
|
4968
|
+
logger.info(chalk.gray(`[fast] ${fastPlan.note}`));
|
|
4969
|
+
}
|
|
4970
|
+
|
|
4636
4971
|
try {
|
|
4637
4972
|
process.stdout.write("\n");
|
|
4638
4973
|
const iterationBudget = new IterationBudget({ owner: sessionId });
|
|
@@ -4751,7 +5086,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
4751
5086
|
// turn only (provider/baseUrl/apiKey unchanged, model → vision model).
|
|
4752
5087
|
provider: _visionLlm ? _visionLlm.provider : provider,
|
|
4753
5088
|
model: _visionLlm ? _visionLlm.model : activeModel,
|
|
4754
|
-
thinking,
|
|
5089
|
+
thinking: turnThinking,
|
|
4755
5090
|
thinkingBudget,
|
|
4756
5091
|
baseUrl: _visionLlm ? _visionLlm.baseUrl : baseUrl,
|
|
4757
5092
|
apiKey: _visionLlm ? _visionLlm.apiKey : apiKey,
|
|
@@ -4804,6 +5139,10 @@ export async function startAgentRepl(options = {}) {
|
|
|
4804
5139
|
provider: ue.provider,
|
|
4805
5140
|
model: ue.model,
|
|
4806
5141
|
usage: ue.usage,
|
|
5142
|
+
// 用量归因: sub-agent / isolated-skill usage carries its
|
|
5143
|
+
// attribution frame into the transcript; main-loop events stay
|
|
5144
|
+
// exactly as before (absence ⇒ origin "main").
|
|
5145
|
+
...(ue.attribution ? { attribution: ue.attribution } : {}),
|
|
4807
5146
|
});
|
|
4808
5147
|
} catch (_e) {
|
|
4809
5148
|
/* best-effort */
|
|
@@ -5039,6 +5378,25 @@ export async function startAgentRepl(options = {}) {
|
|
|
5039
5378
|
});
|
|
5040
5379
|
|
|
5041
5380
|
rl.on("close", async () => {
|
|
5381
|
+
// Leave the alternate screen buffer first so the terminal is restored to
|
|
5382
|
+
// the user's scrollback no matter how the REPL exits.
|
|
5383
|
+
if (_tuiMode === "fullscreen" && process.stdout.isTTY) {
|
|
5384
|
+
try {
|
|
5385
|
+
process.stdout.write(_ALT_LEAVE);
|
|
5386
|
+
} catch (_err) {
|
|
5387
|
+
// best-effort restore
|
|
5388
|
+
}
|
|
5389
|
+
}
|
|
5390
|
+
// Stop inbound channel listeners before anything else — no new external
|
|
5391
|
+
// events may enter a session that is shutting down.
|
|
5392
|
+
if (_channels) {
|
|
5393
|
+
try {
|
|
5394
|
+
_channels.stop();
|
|
5395
|
+
} catch (_err) {
|
|
5396
|
+
// best-effort
|
|
5397
|
+
}
|
|
5398
|
+
_channels = null;
|
|
5399
|
+
}
|
|
5042
5400
|
// settings.json SessionEnd hooks (observe-only) when the REPL exits.
|
|
5043
5401
|
if (_settingsHooks) {
|
|
5044
5402
|
try {
|