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.
Files changed (201) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-BwpTJTN_.js → AIOps-ByIiF5bT.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BtQOoo3l.js → ActionButton-NlgSFZq5.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-Duf_rXZa.js → Analytics-D17cOUcb.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-XQK3wjvB.js → AppLayout-B4mEZcbl.js} +4 -4
  6. package/src/assets/web-panel/assets/Artifacts-CASsmyQw.js +1 -0
  7. package/src/assets/web-panel/assets/{Audit-DNjOGQLh.js → Audit-DYAia2e2.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-FH9RAfB5.js → BackgroundAgents-C1lvYUSu.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-ZIbrR4-U.js → Backup-B6agK6bA.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-DSt3NaND.js → BaseInput-DM43R2vy.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-CY-wvbjv.js → Chat-Dtdp3eXp.js} +5 -5
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BAV9V-t-.js → ChatBubbleRenderer-BL5c_OQ1.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-8JVadE_B.js → Checkbox-D2xf7uZt.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-CN83nPYI.js → Codegen-D3j45jJL.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-xPSvqdN8.js → Col-voPJ9fUZ.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-D78cnIjG.js → Community-DEsyTESF.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-CSw6Csbp.js → Compact-OHV_QXLD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-E_HhjcYR.js → Compliance-eDTJWC-J.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-DybeQjmm.js → Cowork-BBvy-6d1.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-DS0BJeLY.js → Cron-Dw2eoJxu.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BOwVgkbs.js → Crosschain-DQHms_Bh.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-DRUr9YuX.js → DID-Cyu7Id1c.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-Cht-yUKW.js → Dashboard-sIDzkG92.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-BLr_EJ9X.js → Dropdown-DUW3T2ey.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-Drexuh5W.js → EmailListRenderer-CECELXW8.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D9Q2Kq63.js → FamilyGuardDashboard-BIZR37ov.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-C-Z1xI-T.js → Federation-BEZIQX84.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-DLHPMkQF.js → FormItemContext-BcdUMznL.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-DxxEdn2r.js → GenericCardRenderer-DsN_fr5H.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-syATcaBt.js → Git-63LhjBx2.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-CYe_r8Zf.js → Governance-CYtQtIcH.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-GWxErB7k.js → Inference-BwR6UUox.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-qQvVCZoi.js → KnowledgeGraph-D9lVNTUA.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-BenAU2W8.js → Logs-C4q5h7Ut.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-7agE3Or1.js → MarkdownRenderer-DexLlXfN.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-D4Jn5fpD.js → Marketplace-Plksliuw.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DtAwoqiQ.js → McpTools-DZUFfeuG.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-BI_O50I8.js → Memory-NoDYt29V.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-CQWE2lqx.js → MobileBridge-CEXGTkdh.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-CVtTqgtg.js → MobileProjects-DnbJkbZo.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-Dnr16qsn.js → Mtc-DTAa0cwy.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-CQ5Xe4-a.js → MtcAudit-CVV7LnNS.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-Bjr8O-wy.js → Multisig-BqqGrjt_.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-CEe-KirU.js → NLProgramming-C4WP8DRp.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-spKJIKF9.js → Notes-Zo4DJUVI.js} +4 -4
  46. package/src/assets/web-panel/assets/{NotificationSettings-DRp83LFG.js → NotificationSettings-DBcjRaz2.js} +1 -1
  47. package/src/assets/web-panel/assets/OrderTableRenderer-BCQel9bD.js +1 -0
  48. package/src/assets/web-panel/assets/{Organization-BlgB0IYg.js → Organization-BT9WPBOX.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-a_35HqZI.js → Overflow-D6b4bZ3q.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CSNHCNPC.js → P2P-Cw3OsYx-.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-C8M1JH-1.js → PdhVaultBrowser-C0nyiK2b.js} +5 -5
  52. package/src/assets/web-panel/assets/{Permissions-DmjJi9Ms.js → Permissions-zVBZEB_C.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-DfuwRyf4.js → PersonalDataHub-BOspsFew.js} +2 -2
  54. package/src/assets/web-panel/assets/{Pipeline-B2-S4ekE.js → Pipeline-CQWfZ4XH.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B1dOiBLC.js → Privacy-C2oGJ_WL.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-_pNmc-DX.js → ProjectInit-BZMR4qY1.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-DmwG2Ii1.js → ProjectSettings-DAujoP63.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-COATmHxF.js → Projects-DvH_P2Uq.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-C6HSjg1d.js → Providers-D_RGHM-v.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-CrDmS7l1.js → QrScannerModal-Mf6KfL2J.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-CfKvWt-x.js → QuickAsk-5D8URoI_.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-DMa6Kuzv.js → Recommend-Df4kC8Gy.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-DrktUo5x.js → RemoteSession-DGi3f3vO.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-BTPQ1vjL.js → Reputation-jmkGFNWb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-B6Q7QkMG.js → Row-DP6Pcu3m.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-B1IJhAmX.js → RssFeed-D60hSuPO.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-xbea1kGD.js → Search-0mf1BQUK.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-7rs0cO3F.js → Security-CfZtLFYV.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-0fjixK0S.js → Services-D9zpZLWz.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-B_rVq9Cu.js → Skeleton-D1_44eMD.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-C5uM90b9.js → Skills-cVFa8zkz.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-U4pYCIZH.js → Sla-Cinpzc3L.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-Cdz4yTWx.js → SpeechSettings-bqdiJE_P.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-Me3aetHv.js → SyncSettings-Dgl_SLgj.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-Cf6aNkL_.js → Tasks-DawWAEhy.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-CYatk4tU.js → Templates-Ca0nY651.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-DIMKLw7o.js → Tenant-CgaGEhLm.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-C_cp-uSJ.js → Terminal-D-9EnpRx.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-cUPVNADp.js → TimelineRenderer-CSOxDHZ6.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-CiaEIXVf.js → Tokens-BpwLZpL3.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-DB1WU5lQ.js → Trigger-DgowwBK5.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-Cfht9Ijy.js → Trust-BZutapjE.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-K3P4Vt9S.js → UkeySign-QZPt8_Sp.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DWjhjXRh.js → VideoEditing-DlQx5UDJ.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-D9-Q1Kan.js → Wallet-ZfdTgtWA.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-BDszy-oV.js → WebAuthn-CAp0y_Cr.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-DIhij4rA.js → WorkflowEditor-BVITZEmr.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-D7VCiKbh.js → chat-CC2tPaNg.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-BvOd9pVn.js → colors-31brc9CA.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-DoqXBiAO.js → compact-item-DLMkC9C-.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-CrKRzUtp.js → createContext-BMtveI6F.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CB8pPOtd.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-BWAev4WC.js → hasIn-DbD6WHW2.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-B30NvR21.js → index-3oBsXZmF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Cx7M7PSF.js → index-ALvoNTRF.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BHOcVYrx.js → index-AaIKG60c.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BXyl8O23.js → index-BFRLmCR3.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-YGDy7nNq.js → index-BKAB6-6V.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BoYrS_L2.js → index-BOM-VFlv.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-Bq_ctRpz.js → index-BPpS-lGb.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CDGLdn12.js → index-Bbc2JeQG.js} +1 -1
  102. package/src/assets/web-panel/assets/index-BhXiaiev.js +1 -0
  103. package/src/assets/web-panel/assets/{index-ISvPZ05r.js → index-BiRQUoyE.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-B0vGEbJT.js → index-BnFLzejT.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Bj7EgmOp.js → index-BoO4WEJB.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BZGk8AbZ.js → index-C-cGlCDW.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BkgnGX7v.js → index-C1PfeI88.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-HwHdTusY.js → index-C21pdBqs.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bf9YlbDn.js → index-C7LHNw_N.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-oY45XrkG.js → index-CEXa-4zd.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-KR1-Em9C.js → index-CEwjBA9q.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C5kRmj3P.js → index-CFXKbOek.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BN9m4Ux2.js → index-CJhREOlG.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-PDxGjKRu.js → index-COHHQ9cU.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-D23L1V76.js → index-CUmLMFsy.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-zH-tuuGZ.js → index-CWgfipcC.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CmJ6xKBO.js → index-C_eUKGYP.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CEPHMSih.js → index-CcVszn2b.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DV-Rfmfx.js → index-Cod97Urs.js} +3 -3
  120. package/src/assets/web-panel/assets/{index-BWWsaimP.js → index-Cwbqh0KZ.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-8g5TJCZ3.js → index-D67kIagl.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CEXfKSiI.js → index-D7cV0tu0.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CoD31Ndm.js → index-DJvxFyIz.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CSb-tnIo.js → index-DZl-UXB6.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DvDOpsJB.js → index-Dm0byjm1.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DlGu7As6.js → index-DndNnYc0.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-gmxqu5Kk.js → index-WQUO2vvK.js} +1 -1
  128. package/src/assets/web-panel/assets/index-WpaYaE3D.js +1 -0
  129. package/src/assets/web-panel/assets/{index-ww1QtLnX.js → index-bdaJwTXJ.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-JzUmJMvn.js → index-ep6JchNG.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BCyP071m.js → index-jG6h22Qg.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-1poMpMU0.js → index-ntVQqSML.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-XW-OR3mL.js → initDefaultProps-D5UoBRhN.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-CeuEHh20.js → motion-DltOw0CR.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Dva79Keg.js → move-_oPkk5zj.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-C0B6bD2j.js → mtc-parser-EES8ROCS.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-AkZvO-a2.js → omit-B-_39x_M.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-B4r55qGc.js → pickAttrs-l6D0yJHz.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BLH-z7YE.js → placementArrow-DIeUK31L.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-ksEGZ2Wf.js → responsiveObserve-dG4EzUQo.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-Cth4OD1Z.js → slide-DWFzYGdH.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-9S83ezxw.js → statusUtils-CECdTA5H.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-7yQmQGZ4.js → styleChecker-D6kP-mMK.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DpGnMmPc.js → useFlexGapSupport-BWfna_rd.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-C4zDZIXH.js → useFs-Bb-j6rzo.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CoLICdUZ.js → usePersonalDataHub-D5OIsYM4.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-CKyH-35X.js → vnode-DNpwzFTM.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DRDGit17.js → zoom-vNLpFQBW.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-manifest.json +17 -3
  151. package/src/commands/agent.js +7 -0
  152. package/src/commands/background-session.js +143 -3
  153. package/src/commands/browse.js +86 -0
  154. package/src/commands/cloud.js +232 -0
  155. package/src/commands/doctor.js +61 -6
  156. package/src/commands/mcp.js +61 -0
  157. package/src/commands/plugin.js +63 -1
  158. package/src/commands/routine.js +367 -0
  159. package/src/commands/session.js +326 -0
  160. package/src/data/changelog.json +7 -2
  161. package/src/harness/jsonl-session-store.js +82 -2
  162. package/src/harness/session-index.js +295 -0
  163. package/src/harness/session-mirror.js +142 -0
  164. package/src/harness/transcript-integrity.js +182 -0
  165. package/src/index.js +8 -0
  166. package/src/lib/background-agent-supervisor.js +126 -2
  167. package/src/lib/channels/channel-manager.js +126 -0
  168. package/src/lib/channels/telegram-channel.js +112 -0
  169. package/src/lib/channels/webhook-channel.js +140 -0
  170. package/src/lib/chrome-connector.js +386 -0
  171. package/src/lib/cloud/bundle.js +110 -0
  172. package/src/lib/cloud/cloud-client.js +152 -0
  173. package/src/lib/computer-use/authorization.js +173 -0
  174. package/src/lib/computer-use/computer-use-server.js +276 -0
  175. package/src/lib/computer-use/control-backend.js +150 -0
  176. package/src/lib/doctor-checkup.js +652 -0
  177. package/src/lib/jsonl-session-store.js +4 -0
  178. package/src/lib/lsp/lsp-server-registry.js +48 -21
  179. package/src/lib/plugin-runtime/governance.js +174 -0
  180. package/src/lib/pr-link-ledger.js +221 -0
  181. package/src/lib/routine-store.js +352 -0
  182. package/src/lib/session-store-guard.js +40 -0
  183. package/src/lib/session-usage.js +318 -2
  184. package/src/lib/sub-agent-context.js +23 -0
  185. package/src/repl/agent-repl.js +361 -3
  186. package/src/repl/bg-dashboard.js +355 -0
  187. package/src/repl/fast-mode.js +103 -0
  188. package/src/repl/fullscreen-tui.js +197 -0
  189. package/src/repl/slash-command-registry.js +11 -3
  190. package/src/repl/voice-dictation.js +132 -0
  191. package/src/runtime/agent-core.js +242 -1
  192. package/src/runtime/coding-agent-contract-shared.cjs +88 -0
  193. package/src/runtime/coding-agent-policy.cjs +17 -0
  194. package/src/runtime/headless-runner.js +71 -7
  195. package/src/runtime/headless-stream.js +14 -8
  196. package/src/runtime/policies/agent-policy.js +3 -0
  197. package/src/assets/web-panel/assets/Artifacts-DQvJoQ6E.js +0 -1
  198. package/src/assets/web-panel/assets/OrderTableRenderer-h1A0XB2a.js +0 -1
  199. package/src/assets/web-panel/assets/devWarning-nDB--2xr.js +0 -1
  200. package/src/assets/web-panel/assets/index-B1_pRTtB.js +0 -1
  201. package/src/assets/web-panel/assets/index-TMM9FuW-.js +0 -1
@@ -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
- if (trimmed === "/doctor" || trimmed.startsWith("/doctor ")) {
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 {