chainlesschain 0.162.157 → 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 (212) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-CfMP2Oud.js → AIOps-ByIiF5bT.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-Zu0N8BQL.js → ActionButton-NlgSFZq5.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-DZTwj5T_.js → Analytics-D17cOUcb.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CVFJh47v.js → AppLayout-B4mEZcbl.js} +5 -5
  8. package/src/assets/web-panel/assets/Artifacts-CASsmyQw.js +1 -0
  9. package/src/assets/web-panel/assets/Artifacts-CTVt96zW.css +1 -0
  10. package/src/assets/web-panel/assets/{Audit-BMfiLj7T.js → Audit-DYAia2e2.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-BslPCdGF.js → BackgroundAgents-C1lvYUSu.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-CQ_fMC1r.js → Backup-B6agK6bA.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-CsFsARiC.js → BaseInput-DM43R2vy.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-CwfBobco.js → Chat-Dtdp3eXp.js} +6 -6
  15. package/src/assets/web-panel/assets/Chat-KSGPtU0L.css +1 -0
  16. package/src/assets/web-panel/assets/{ChatBubbleRenderer-K6Nf3xeN.js → ChatBubbleRenderer-BL5c_OQ1.js} +1 -1
  17. package/src/assets/web-panel/assets/{Checkbox-DkSyjjPp.js → Checkbox-D2xf7uZt.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-B7Fx3zZ6.js → Codegen-D3j45jJL.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-Dzfqn8Ep.js → Col-voPJ9fUZ.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-DhHPdzMM.js → Community-DEsyTESF.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-Ct18_8y7.js → Compact-OHV_QXLD.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-CY64IqBi.js → Compliance-eDTJWC-J.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-BYSmWlUl.js → Cowork-BBvy-6d1.js} +2 -2
  24. package/src/assets/web-panel/assets/{Cron-_4xtP3Ug.js → Cron-Dw2eoJxu.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-B4qY-Ycr.js → Crosschain-DQHms_Bh.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-CkCzWkx1.js → DID-Cyu7Id1c.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-C1scT7Ke.js → Dashboard-sIDzkG92.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-DBnQ2EWd.js → Dropdown-DUW3T2ey.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-C9JhOTq0.js → EmailListRenderer-CECELXW8.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CWXv5RUv.js → FamilyGuardDashboard-BIZR37ov.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-fYdcbz9W.js → Federation-BEZIQX84.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-CJqOT3Yj.js → FormItemContext-BcdUMznL.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-DGCsHc5K.js → GenericCardRenderer-DsN_fr5H.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-EH2K-H0Q.js → Git-63LhjBx2.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-DJn1X2pR.js → Governance-CYtQtIcH.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-Dch1E8qd.js → Inference-BwR6UUox.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-QIur8j8-.js → KnowledgeGraph-D9lVNTUA.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-DUgHldPg.js → Logs-C4q5h7Ut.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-DbzhFwvz.css +1 -0
  40. package/src/assets/web-panel/assets/MarkdownRenderer-DexLlXfN.js +1 -0
  41. package/src/assets/web-panel/assets/{Marketplace-DafrSfvd.js → Marketplace-Plksliuw.js} +1 -1
  42. package/src/assets/web-panel/assets/{McpTools-D2xRbfJx.js → McpTools-DZUFfeuG.js} +3 -3
  43. package/src/assets/web-panel/assets/{Memory-C6RbVHAo.js → Memory-NoDYt29V.js} +2 -2
  44. package/src/assets/web-panel/assets/{MobileBridge-BPtVBKqn.js → MobileBridge-CEXGTkdh.js} +1 -1
  45. package/src/assets/web-panel/assets/{MobileProjects-Cuw832cr.js → MobileProjects-DnbJkbZo.js} +1 -1
  46. package/src/assets/web-panel/assets/{Mtc-D6O9fWFa.js → Mtc-DTAa0cwy.js} +5 -5
  47. package/src/assets/web-panel/assets/{MtcAudit-CWZcXIH1.js → MtcAudit-CVV7LnNS.js} +4 -4
  48. package/src/assets/web-panel/assets/{Multisig-DhIBxTFd.js → Multisig-BqqGrjt_.js} +3 -3
  49. package/src/assets/web-panel/assets/{NLProgramming-wkBFS33e.js → NLProgramming-C4WP8DRp.js} +1 -1
  50. package/src/assets/web-panel/assets/{Notes-B09FxncA.js → Notes-Zo4DJUVI.js} +3 -3
  51. package/src/assets/web-panel/assets/{NotificationSettings-oQwtH6-9.js → NotificationSettings-DBcjRaz2.js} +1 -1
  52. package/src/assets/web-panel/assets/OrderTableRenderer-BCQel9bD.js +1 -0
  53. package/src/assets/web-panel/assets/{Organization-CsF-NIjz.js → Organization-BT9WPBOX.js} +4 -4
  54. package/src/assets/web-panel/assets/{Overflow-bLxv9Dqi.js → Overflow-D6b4bZ3q.js} +1 -1
  55. package/src/assets/web-panel/assets/{P2P-DVwQtm4q.js → P2P-Cw3OsYx-.js} +2 -2
  56. package/src/assets/web-panel/assets/{PdhVaultBrowser-Bgic3QKm.js → PdhVaultBrowser-C0nyiK2b.js} +4 -4
  57. package/src/assets/web-panel/assets/{Permissions-as80-9ep.js → Permissions-zVBZEB_C.js} +3 -3
  58. package/src/assets/web-panel/assets/{PersonalDataHub-BGmUw36a.js → PersonalDataHub-BOspsFew.js} +2 -2
  59. package/src/assets/web-panel/assets/{Pipeline-BM96zBxG.js → Pipeline-CQWfZ4XH.js} +1 -1
  60. package/src/assets/web-panel/assets/{Privacy-BBOzBSWe.js → Privacy-C2oGJ_WL.js} +1 -1
  61. package/src/assets/web-panel/assets/{ProjectInit-GHX41V28.js → ProjectInit-BZMR4qY1.js} +2 -2
  62. package/src/assets/web-panel/assets/{ProjectSettings-DraqzxKD.js → ProjectSettings-DAujoP63.js} +2 -2
  63. package/src/assets/web-panel/assets/{Projects-BzzdUml4.js → Projects-DvH_P2Uq.js} +1 -1
  64. package/src/assets/web-panel/assets/{Providers-CSeYNAtW.js → Providers-D_RGHM-v.js} +1 -1
  65. package/src/assets/web-panel/assets/{QrScannerModal-DlzBCdXh.js → QrScannerModal-Mf6KfL2J.js} +1 -1
  66. package/src/assets/web-panel/assets/{QuickAsk-p8iB7od_.js → QuickAsk-5D8URoI_.js} +1 -1
  67. package/src/assets/web-panel/assets/{Recommend-DjOVXacd.js → Recommend-Df4kC8Gy.js} +1 -1
  68. package/src/assets/web-panel/assets/RemoteSession-DGi3f3vO.js +4 -0
  69. package/src/assets/web-panel/assets/{Reputation-CjT3M0Di.js → Reputation-jmkGFNWb.js} +1 -1
  70. package/src/assets/web-panel/assets/{Row-tw8m6T0c.js → Row-DP6Pcu3m.js} +1 -1
  71. package/src/assets/web-panel/assets/{RssFeed-B47KBx_f.js → RssFeed-D60hSuPO.js} +3 -3
  72. package/src/assets/web-panel/assets/{Search-D2sx1PBe.js → Search-0mf1BQUK.js} +1 -1
  73. package/src/assets/web-panel/assets/{Security-JmtL8g7D.js → Security-CfZtLFYV.js} +3 -3
  74. package/src/assets/web-panel/assets/{Services-BxrNqjin.js → Services-D9zpZLWz.js} +2 -2
  75. package/src/assets/web-panel/assets/{Skeleton-udk8L18t.js → Skeleton-D1_44eMD.js} +1 -1
  76. package/src/assets/web-panel/assets/{Skills-DooLT9of.js → Skills-cVFa8zkz.js} +1 -1
  77. package/src/assets/web-panel/assets/{Sla-ITVZE1xI.js → Sla-Cinpzc3L.js} +1 -1
  78. package/src/assets/web-panel/assets/{SpeechSettings-DCkfqY1n.js → SpeechSettings-bqdiJE_P.js} +1 -1
  79. package/src/assets/web-panel/assets/{SyncSettings-CkNlgFjM.js → SyncSettings-Dgl_SLgj.js} +2 -2
  80. package/src/assets/web-panel/assets/{Tasks-BMAoyCM_.js → Tasks-DawWAEhy.js} +1 -1
  81. package/src/assets/web-panel/assets/{Templates-BnrFTlrz.js → Templates-Ca0nY651.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tenant-BjNsy3-i.js → Tenant-CgaGEhLm.js} +1 -1
  83. package/src/assets/web-panel/assets/{Terminal-C0gxLL7V.js → Terminal-D-9EnpRx.js} +2 -2
  84. package/src/assets/web-panel/assets/{TimelineRenderer-CUtj_KHA.js → TimelineRenderer-CSOxDHZ6.js} +1 -1
  85. package/src/assets/web-panel/assets/{Tokens-DOg61zlq.js → Tokens-BpwLZpL3.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trigger-D4ldCewj.js → Trigger-DgowwBK5.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trust-3lk_Zd8j.js → Trust-BZutapjE.js} +1 -1
  88. package/src/assets/web-panel/assets/{UkeySign-kWhFR6Li.js → UkeySign-QZPt8_Sp.js} +1 -1
  89. package/src/assets/web-panel/assets/{VideoEditing-D3GOFVWg.js → VideoEditing-DlQx5UDJ.js} +1 -1
  90. package/src/assets/web-panel/assets/{Wallet-DzrZfBuh.js → Wallet-ZfdTgtWA.js} +4 -4
  91. package/src/assets/web-panel/assets/{WebAuthn-CyVJVp_g.js → WebAuthn-CAp0y_Cr.js} +5 -5
  92. package/src/assets/web-panel/assets/{WorkflowEditor-i_b0wi9b.js → WorkflowEditor-BVITZEmr.js} +1 -1
  93. package/src/assets/web-panel/assets/{chat-DwPCK8I7.js → chat-CC2tPaNg.js} +1 -1
  94. package/src/assets/web-panel/assets/{colors-D0vaVqZU.js → colors-31brc9CA.js} +1 -1
  95. package/src/assets/web-panel/assets/{compact-item-Don7nGW2.js → compact-item-DLMkC9C-.js} +1 -1
  96. package/src/assets/web-panel/assets/{createContext-D84R5qy2.js → createContext-BMtveI6F.js} +1 -1
  97. package/src/assets/web-panel/assets/devWarning-CB8pPOtd.js +1 -0
  98. package/src/assets/web-panel/assets/{hasIn-BeUqVVKU.js → hasIn-DbD6WHW2.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-m9bn0F1p.js → index-3oBsXZmF.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CfYRv-zA.js → index-ALvoNTRF.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-4MkfPLGv.js → index-AaIKG60c.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-LMo9bBLJ.js → index-BFRLmCR3.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-wesQQ2cH.js → index-BKAB6-6V.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CzT56x-_.js → index-BOM-VFlv.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-L73NrmlW.js → index-BPpS-lGb.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-WRw1pM5E.js → index-Bbc2JeQG.js} +1 -1
  107. package/src/assets/web-panel/assets/index-BhXiaiev.js +1 -0
  108. package/src/assets/web-panel/assets/{index-Br3SOdER.js → index-BiRQUoyE.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-D8r7WKk-.js → index-BnFLzejT.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CAdCTTBC.js → index-BoO4WEJB.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BlfTf0ka.js → index-C-cGlCDW.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-B57al0Z5.js → index-C1PfeI88.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-D4b5XqIy.js → index-C21pdBqs.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CnnxzIx0.js → index-C7LHNw_N.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BNpJf-sf.js → index-CEXa-4zd.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DT40zd7K.js → index-CEwjBA9q.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CL71rIwo.js → index-CFXKbOek.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BZ1N07Sp.js → index-CJhREOlG.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-C0_sKVi7.js → index-COHHQ9cU.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DBzBLX-K.js → index-CUmLMFsy.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-De85D9Pc.js → index-CWgfipcC.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-x7VYlV41.js → index-C_eUKGYP.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-hjgrIX5I.js → index-CcVszn2b.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DMT8n9vB.js → index-Cod97Urs.js} +3 -3
  125. package/src/assets/web-panel/assets/{index-DFFzwrNs.js → index-Cwbqh0KZ.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-YKLCotoo.js → index-D67kIagl.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-IGGttsCv.js → index-D7cV0tu0.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DQor_7NF.js → index-DJvxFyIz.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D84BnuFg.js → index-DZl-UXB6.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CrnVEEQO.js → index-Dm0byjm1.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BER98o4P.js → index-DndNnYc0.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DA0-EJKx.js → index-WQUO2vvK.js} +1 -1
  133. package/src/assets/web-panel/assets/index-WpaYaE3D.js +1 -0
  134. package/src/assets/web-panel/assets/{index-CExWtm98.js → index-bdaJwTXJ.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-MKZrJrP_.js → index-ep6JchNG.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-7QUwcGTg.js → index-jG6h22Qg.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-BohrJpBf.js → index-ntVQqSML.js} +1 -1
  138. package/src/assets/web-panel/assets/{initDefaultProps-DGeU4vPS.js → initDefaultProps-D5UoBRhN.js} +1 -1
  139. package/src/assets/web-panel/assets/{motion-Dgqj9ab3.js → motion-DltOw0CR.js} +1 -1
  140. package/src/assets/web-panel/assets/{move-BFyEU6Lr.js → move-_oPkk5zj.js} +1 -1
  141. package/src/assets/web-panel/assets/{mtc-parser-CueCXXPC.js → mtc-parser-EES8ROCS.js} +1 -1
  142. package/src/assets/web-panel/assets/{omit-D2pU5OyE.js → omit-B-_39x_M.js} +1 -1
  143. package/src/assets/web-panel/assets/{pickAttrs-CKTf6zD6.js → pickAttrs-l6D0yJHz.js} +1 -1
  144. package/src/assets/web-panel/assets/{placementArrow-DieJaGCN.js → placementArrow-DIeUK31L.js} +1 -1
  145. package/src/assets/web-panel/assets/{responsiveObserve-Bxr-rmU6.js → responsiveObserve-dG4EzUQo.js} +1 -1
  146. package/src/assets/web-panel/assets/{slide-CDEDk3Se.js → slide-DWFzYGdH.js} +1 -1
  147. package/src/assets/web-panel/assets/{statusUtils-icf2eCTx.js → statusUtils-CECdTA5H.js} +1 -1
  148. package/src/assets/web-panel/assets/{styleChecker-qKvgmBhE.js → styleChecker-D6kP-mMK.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFlexGapSupport-1_UhiyJZ.js → useFlexGapSupport-BWfna_rd.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFs-CFGLXDWh.js → useFs-Bb-j6rzo.js} +1 -1
  151. package/src/assets/web-panel/assets/{usePersonalDataHub-UafOXvQ6.js → usePersonalDataHub-D5OIsYM4.js} +1 -1
  152. package/src/assets/web-panel/assets/{vnode-BfPqSx79.js → vnode-DNpwzFTM.js} +1 -1
  153. package/src/assets/web-panel/assets/{zoom-CXsVcRB6.js → zoom-vNLpFQBW.js} +1 -1
  154. package/src/assets/web-panel/index.html +1 -1
  155. package/src/command-manifest.json +17 -3
  156. package/src/commands/agent.js +11 -1
  157. package/src/commands/background-session.js +143 -3
  158. package/src/commands/browse.js +86 -0
  159. package/src/commands/cloud.js +232 -0
  160. package/src/commands/doctor.js +61 -6
  161. package/src/commands/mcp.js +61 -0
  162. package/src/commands/plugin.js +63 -1
  163. package/src/commands/routine.js +367 -0
  164. package/src/commands/session.js +326 -0
  165. package/src/data/changelog.json +12 -2
  166. package/src/harness/jsonl-session-store.js +82 -2
  167. package/src/harness/session-index.js +295 -0
  168. package/src/harness/session-mirror.js +142 -0
  169. package/src/harness/transcript-integrity.js +182 -0
  170. package/src/index.js +8 -0
  171. package/src/lib/background-agent-supervisor.js +126 -2
  172. package/src/lib/channels/channel-manager.js +126 -0
  173. package/src/lib/channels/telegram-channel.js +112 -0
  174. package/src/lib/channels/webhook-channel.js +140 -0
  175. package/src/lib/chrome-connector.js +425 -4
  176. package/src/lib/cloud/bundle.js +110 -0
  177. package/src/lib/cloud/cloud-client.js +152 -0
  178. package/src/lib/computer-use/authorization.js +173 -0
  179. package/src/lib/computer-use/computer-use-server.js +276 -0
  180. package/src/lib/computer-use/control-backend.js +150 -0
  181. package/src/lib/doctor-checkup.js +652 -0
  182. package/src/lib/jsonl-session-store.js +4 -0
  183. package/src/lib/lsp/lsp-server-registry.js +48 -21
  184. package/src/lib/plugin-runtime/governance.js +174 -0
  185. package/src/lib/pr-link-ledger.js +221 -0
  186. package/src/lib/remote-control.js +35 -0
  187. package/src/lib/routine-store.js +352 -0
  188. package/src/lib/session-store-guard.js +40 -0
  189. package/src/lib/session-usage.js +318 -2
  190. package/src/lib/sub-agent-context.js +23 -0
  191. package/src/lib/web-ui-server.js +120 -7
  192. package/src/repl/agent-repl.js +592 -61
  193. package/src/repl/bg-dashboard.js +355 -0
  194. package/src/repl/fast-mode.js +103 -0
  195. package/src/repl/fullscreen-tui.js +197 -0
  196. package/src/repl/remote-approval.js +111 -0
  197. package/src/repl/slash-command-registry.js +11 -3
  198. package/src/repl/voice-dictation.js +132 -0
  199. package/src/runtime/agent-core.js +278 -1
  200. package/src/runtime/coding-agent-contract-shared.cjs +141 -0
  201. package/src/runtime/coding-agent-policy.cjs +33 -0
  202. package/src/runtime/headless-runner.js +71 -7
  203. package/src/runtime/headless-stream.js +14 -8
  204. package/src/runtime/policies/agent-policy.js +6 -0
  205. package/src/assets/web-panel/assets/Artifacts-BbN5V7au.js +0 -1
  206. package/src/assets/web-panel/assets/Artifacts-CRkepl4t.css +0 -1
  207. package/src/assets/web-panel/assets/Chat-DDh58PCf.css +0 -1
  208. package/src/assets/web-panel/assets/OrderTableRenderer-iFKeNf6Y.js +0 -1
  209. package/src/assets/web-panel/assets/RemoteSession-CIGk7gk-.js +0 -4
  210. package/src/assets/web-panel/assets/devWarning-BBwWehQ7.js +0 -1
  211. package/src/assets/web-panel/assets/index-DJ8etkBT.js +0 -1
  212. package/src/assets/web-panel/assets/index-OeaK-zXZ.js +0 -1
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import chalk from "chalk";
3
3
  import { logger } from "../lib/logger.js";
4
+ import { readPrLinkLedger } from "../lib/pr-link-ledger.js";
4
5
 
5
6
  function formatAge(ms) {
6
7
  const n = Math.max(0, Math.round(Number(ms || 0) / 1000));
@@ -67,6 +68,11 @@ export function formatBackgroundAgentDetails(
67
68
  ` log: ${session.logFile || "-"}`,
68
69
  ];
69
70
  if (session.phase) lines.push(` phase: ${session.phase}`);
71
+ if (session.pr?.number) {
72
+ lines.push(
73
+ ` pr: #${session.pr.number}${session.pr.state ? ` ${session.pr.state}` : ""}${session.pr.url ? ` ${session.pr.url}` : ""}`,
74
+ );
75
+ }
70
76
  if (Number.isFinite(Number(session.turnCount))) {
71
77
  lines.push(` turns: ${session.turnCount}`);
72
78
  }
@@ -146,7 +152,7 @@ async function followBackgroundAgent(id, options = {}) {
146
152
  * when the transport is unavailable so the caller can fall back to the
147
153
  * log-only follow.
148
154
  */
149
- async function interactiveAttach(id, state, options = {}) {
155
+ export async function interactiveAttach(id, state, options = {}) {
150
156
  const { connectBackgroundSession } =
151
157
  await import("../lib/background-session-transport.js");
152
158
  const { readBackgroundAgentLog, logPath } = await loadSupervisor();
@@ -279,6 +285,134 @@ async function interactiveAttach(id, state, options = {}) {
279
285
  return true;
280
286
  }
281
287
 
288
+ /**
289
+ * `cc daemon view` (no id) — the interactive agent dashboard. Wires the real
290
+ * supervisor/transport into the injectable controller (repl/bg-dashboard.js).
291
+ * Non-TTY (or --json) degrades to the status listing.
292
+ */
293
+ async function runDashboardView(options = {}) {
294
+ const supervisor = await loadSupervisor();
295
+ const {
296
+ listBackgroundAgents,
297
+ readBackgroundAgentLog,
298
+ stopBackgroundAgent,
299
+ renameBackgroundAgent,
300
+ setBackgroundAgentPinned,
301
+ resumeBackgroundAgent,
302
+ readBackgroundAgentState,
303
+ effectiveBackgroundAgentState,
304
+ } = supervisor;
305
+
306
+ const listAll = () => {
307
+ const sessions = listBackgroundAgents({ all: true });
308
+ // PR/session linking: decorate rows whose conversation touched a PR
309
+ // (`#123 open`). One ledger read per refresh; best-effort.
310
+ try {
311
+ const ledger = readPrLinkLedger();
312
+ for (const s of sessions) {
313
+ const links = s.sessionId ? ledger[s.sessionId] : null;
314
+ if (Array.isArray(links) && links.length > 0 && !s.pr) {
315
+ s.pr = [...links].sort(
316
+ (a, b) => (b.updatedAt || 0) - (a.updatedAt || 0),
317
+ )[0];
318
+ }
319
+ }
320
+ } catch {
321
+ /* PR decoration is cosmetic */
322
+ }
323
+ return sessions;
324
+ };
325
+
326
+ if (options.json || !process.stdout.isTTY || !process.stdin.isTTY) {
327
+ const sessions = listAll();
328
+ if (options.json) {
329
+ console.log(JSON.stringify({ sessions }, null, 2));
330
+ } else {
331
+ printBackgroundAgents(sessions);
332
+ logger.log(
333
+ chalk.gray("(interactive dashboard needs a TTY — showing a snapshot)"),
334
+ );
335
+ }
336
+ return;
337
+ }
338
+
339
+ const { runBgDashboard } = await import("../repl/bg-dashboard.js");
340
+ const { fileURLToPath } = await import("node:url");
341
+ const { spawn } = await import("node:child_process");
342
+ const BIN_PATH = fileURLToPath(
343
+ new URL("../../bin/chainlesschain.js", import.meta.url),
344
+ );
345
+
346
+ await runBgDashboard({
347
+ listAgents: listAll,
348
+ readLog: (id, lines) => {
349
+ try {
350
+ return readBackgroundAgentLog(id, { lines });
351
+ } catch {
352
+ return "";
353
+ }
354
+ },
355
+ stopAgent: (id) => stopBackgroundAgent(id),
356
+ renameAgent: (id, title) => renameBackgroundAgent(id, title),
357
+ pinAgent: (id, pinned) => setBackgroundAgentPinned(id, pinned),
358
+ replyAgent: async (session, text) => {
359
+ // Running with a live transport → queue a follow-up turn; otherwise
360
+ // continue the finished conversation as a new background session.
361
+ if (
362
+ session.status === "running" &&
363
+ session.transport?.pipe &&
364
+ session.transport?.token
365
+ ) {
366
+ const { connectBackgroundSession } =
367
+ await import("../lib/background-session-transport.js");
368
+ const conn = await connectBackgroundSession({
369
+ pipePath: session.transport.pipe,
370
+ token: session.transport.token,
371
+ onEvent: () => {},
372
+ onClose: () => {},
373
+ });
374
+ try {
375
+ conn.send({ type: "prompt", text });
376
+ // give the frame a beat to flush before closing
377
+ await new Promise((r) => setTimeout(r, 150));
378
+ } finally {
379
+ try {
380
+ conn.close();
381
+ } catch {
382
+ /* worker already closed it */
383
+ }
384
+ }
385
+ return;
386
+ }
387
+ resumeBackgroundAgent(session.id, text);
388
+ },
389
+ attachAgent: async (session) => {
390
+ const fresh = effectiveBackgroundAgentState(
391
+ readBackgroundAgentState(session.id),
392
+ );
393
+ if (!fresh) return;
394
+ if (
395
+ fresh.status === "running" &&
396
+ fresh.transport?.pipe &&
397
+ fresh.transport?.token
398
+ ) {
399
+ const attached = await interactiveAttach(session.id, fresh, {});
400
+ if (attached) return;
401
+ }
402
+ await followBackgroundAgent(session.id, { lines: 40 });
403
+ },
404
+ dispatchAgent: async (text) => {
405
+ const child = spawn(
406
+ process.execPath,
407
+ [BIN_PATH, "agent", "--bg", "-p", text],
408
+ { detached: true, stdio: "ignore", windowsHide: true },
409
+ );
410
+ child.unref();
411
+ return null; // id is minted by the launcher; the next refresh shows it
412
+ },
413
+ });
414
+ }
415
+
282
416
  export function registerBackgroundSessionCommands(program) {
283
417
  program
284
418
  .command("logs <id>")
@@ -378,12 +512,18 @@ export function registerBackgroundSessionCommands(program) {
378
512
  });
379
513
 
380
514
  daemon
381
- .command("view <id>")
382
- .description("Show a detailed background agent view")
515
+ .command("view [id]")
516
+ .description(
517
+ "Detailed view of one background agent, or the interactive agent dashboard when no id is given",
518
+ )
383
519
  .option("-n, --lines <n>", "Recent log lines to include", "40")
384
520
  .option("--json", "Output as JSON")
385
521
  .action(async (id, options) => {
386
522
  try {
523
+ if (!id) {
524
+ await runDashboardView(options);
525
+ return;
526
+ }
387
527
  const {
388
528
  readBackgroundAgentState,
389
529
  effectiveBackgroundAgentState,
@@ -391,6 +391,92 @@ export function registerBrowseChromeCommand(browse) {
391
391
  logger.success(`Screenshot: ${state.screenshotPath}`);
392
392
  }
393
393
  });
394
+
395
+ chrome
396
+ .command("act")
397
+ .description(
398
+ "Perform EXPLICIT actions (click/type/press/navigate/waitForSelector/screenshot/assertText) in the connected Chrome — unlike 'state', this DRIVES your logged-in browser",
399
+ )
400
+ .option("-p, --port <port>", "CDP port", "9222")
401
+ .option("-t, --tab <n>", "Tab index", "0")
402
+ .requiredOption(
403
+ "--actions <json|@file>",
404
+ 'JSON array of steps, e.g. \'[{"type":"click","selector":"#go"}]\', or @steps.json',
405
+ )
406
+ .option(
407
+ "--continue-on-error",
408
+ "Keep executing the remaining steps after a failed one (default: fail fast)",
409
+ )
410
+ .option("--json", "Output as JSON")
411
+ .action(async (options) => {
412
+ const { discoverCdp, performActions } =
413
+ await import("../lib/chrome-connector.js");
414
+ const port = numericOption(options.port, {
415
+ name: "--port",
416
+ integer: true,
417
+ min: 1,
418
+ fallback: 9222,
419
+ });
420
+ let actions;
421
+ try {
422
+ const raw = options.actions.startsWith("@")
423
+ ? (await import("fs")).readFileSync(options.actions.slice(1), "utf-8")
424
+ : options.actions;
425
+ actions = JSON.parse(raw);
426
+ } catch (err) {
427
+ logger.error(
428
+ `--actions must be a JSON array (or @file.json): ${err.message}`,
429
+ );
430
+ process.exit(1);
431
+ }
432
+ // Refuse outright when nothing is listening — an action command must
433
+ // never silently no-op or launch a browser on its own.
434
+ const probe = await discoverCdp({ port });
435
+ if (!probe.ok) {
436
+ const msg = `No debuggable Chrome on port ${port} — refusing to act. Start one first: cc browse chrome launch`;
437
+ if (options.json) {
438
+ console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
439
+ } else {
440
+ logger.error(msg);
441
+ }
442
+ process.exitCode = 1;
443
+ return;
444
+ }
445
+ const res = await performActions(actions, {
446
+ port,
447
+ tab: numericOption(options.tab, {
448
+ name: "--tab",
449
+ integer: true,
450
+ min: 0,
451
+ fallback: 0,
452
+ }),
453
+ continueOnError: options.continueOnError === true,
454
+ });
455
+ if (options.json) {
456
+ console.log(JSON.stringify(res, null, 2));
457
+ if (!res.ok) process.exitCode = 1;
458
+ return;
459
+ }
460
+ if (res.error) {
461
+ logger.error(res.error);
462
+ process.exitCode = 1;
463
+ return;
464
+ }
465
+ if (res.profileWarning) logger.warn(res.profileWarning);
466
+ for (const step of res.steps) {
467
+ const mark = step.ok ? chalk.green("ok") : chalk.red("FAIL");
468
+ logger.log(
469
+ ` [${mark}] ${step.action} ${chalk.gray(`(${step.durationMs}ms)`)} ${step.detail}`,
470
+ );
471
+ }
472
+ logger.log(
473
+ ` ${res.executed}/${actions.length} step(s) executed → ${chalk.cyan(res.url)}${res.title ? ` (${res.title})` : ""}`,
474
+ );
475
+ if (res.auditError) {
476
+ logger.warn(`audit log write failed: ${res.auditError}`);
477
+ }
478
+ if (!res.ok) process.exitCode = 1;
479
+ });
394
480
  }
395
481
 
396
482
  import {
@@ -0,0 +1,232 @@
1
+ /**
2
+ * `cc cloud` — self-hosted cloud handoff (gap-2026-07-11 P1#7).
3
+ *
4
+ * cc cloud run "<task>" bundle branch → submit to the private runner → record job
5
+ * cc cloud status [id] poll job(s) (last job when id omitted)
6
+ * cc cloud attach <id> wait for completion, reflow patch/plan/pr/artifacts locally
7
+ * cc cloud list local job ledger
8
+ *
9
+ * Runner endpoint + token come from config (cloud.baseUrl / cloud.token) or
10
+ * env (CC_CLOUD_URL / CC_CLOUD_TOKEN). See src/lib/cloud/cloud-client.js for
11
+ * the runner protocol.
12
+ */
13
+
14
+ import { join } from "node:path";
15
+ import { existsSync, mkdirSync } from "node:fs";
16
+ import chalk from "chalk";
17
+ import { logger } from "../lib/logger.js";
18
+
19
+ async function resolveRunner() {
20
+ let cfg = {};
21
+ try {
22
+ cfg = (await import("../lib/config-manager.js")).loadConfig()?.cloud || {};
23
+ } catch {
24
+ cfg = {};
25
+ }
26
+ const baseUrl = process.env.CC_CLOUD_URL || cfg.baseUrl || "";
27
+ const token = process.env.CC_CLOUD_TOKEN || cfg.token || null;
28
+ return { baseUrl, token };
29
+ }
30
+
31
+ function statusColor(status) {
32
+ if (status === "done") return chalk.green;
33
+ if (status === "failed" || status === "timeout") return chalk.red;
34
+ if (status === "running") return chalk.cyan;
35
+ return chalk.gray;
36
+ }
37
+
38
+ export function registerCloudCommand(program) {
39
+ const cloud = program
40
+ .command("cloud")
41
+ .description(
42
+ "Self-hosted cloud handoff — offload a task to a private runner (bundle → run → reflow)",
43
+ );
44
+
45
+ cloud
46
+ .command("run <task...>")
47
+ .description(
48
+ "Bundle the current branch and submit a task to the private runner",
49
+ )
50
+ .option("--json", "Output as JSON")
51
+ .option("--attach", "Wait for completion and reflow the result")
52
+ .action(async (taskWords, options) => {
53
+ try {
54
+ const task = taskWords.join(" ");
55
+ const { baseUrl, token } = await resolveRunner();
56
+ const { CloudClient, saveJob } =
57
+ await import("../lib/cloud/cloud-client.js");
58
+ const { bundleBranch } = await import("../lib/cloud/bundle.js");
59
+ const client = new CloudClient({ baseUrl, token });
60
+
61
+ logger.log(chalk.gray("Bundling current branch…"));
62
+ const snap = bundleBranch(process.cwd());
63
+ logger.log(
64
+ chalk.gray(
65
+ ` ${snap.branch} @ ${snap.baseSha.slice(0, 8)} (${(snap.bytes / 1024).toFixed(0)} KB)`,
66
+ ),
67
+ );
68
+
69
+ const submitted = await client.submit({
70
+ task,
71
+ bundle: snap.bundle,
72
+ branch: snap.branch,
73
+ baseSha: snap.baseSha,
74
+ });
75
+ const job = saveJob({
76
+ jobId: submitted.jobId,
77
+ task,
78
+ branch: snap.branch,
79
+ baseSha: snap.baseSha,
80
+ baseUrl,
81
+ status: "queued",
82
+ submittedAt: Date.now(),
83
+ cwd: process.cwd(),
84
+ });
85
+ if (options.json && !options.attach) {
86
+ return console.log(JSON.stringify(job, null, 2));
87
+ }
88
+ logger.success(`Submitted cloud job ${job.jobId} → ${baseUrl}`);
89
+ logger.log(chalk.gray(` cc cloud attach ${job.jobId}`));
90
+ if (options.attach) await attachJob(job.jobId, options);
91
+ } catch (err) {
92
+ logger.error(err.message);
93
+ process.exitCode = 1;
94
+ }
95
+ });
96
+
97
+ cloud
98
+ .command("status [id]")
99
+ .description("Poll a cloud job's status (most recent when id omitted)")
100
+ .option("--json", "Output as JSON")
101
+ .action(async (id, options) => {
102
+ try {
103
+ const { CloudClient, readJob, listJobs, saveJob } =
104
+ await import("../lib/cloud/cloud-client.js");
105
+ const job = id ? readJob(id) : listJobs()[0];
106
+ if (!job)
107
+ throw new Error(id ? `job not found: ${id}` : "no cloud jobs");
108
+ const client = new CloudClient({
109
+ baseUrl: job.baseUrl,
110
+ token: (await resolveRunner()).token,
111
+ });
112
+ const status = await client.status(job.jobId);
113
+ saveJob({ ...job, status: status.status, lastSummary: status.summary });
114
+ if (options.json) return console.log(JSON.stringify(status, null, 2));
115
+ logger.log(
116
+ `${statusColor(status.status)(status.status)} ${job.jobId} ${chalk.gray(job.task)}`,
117
+ );
118
+ if (status.summary) logger.log(chalk.gray(` ${status.summary}`));
119
+ } catch (err) {
120
+ logger.error(err.message);
121
+ process.exitCode = 1;
122
+ }
123
+ });
124
+
125
+ cloud
126
+ .command("attach <id>")
127
+ .description("Wait for a cloud job to finish and reflow its result locally")
128
+ .option("--json", "Output as JSON")
129
+ .option("--no-apply", "Fetch the result but do not apply the patch")
130
+ .action(async (id, options) => {
131
+ try {
132
+ await attachJob(id, options);
133
+ } catch (err) {
134
+ logger.error(err.message);
135
+ process.exitCode = 1;
136
+ }
137
+ });
138
+
139
+ cloud
140
+ .command("list", { isDefault: true })
141
+ .description("List local cloud jobs")
142
+ .option("--json", "Output as JSON")
143
+ .action(async (options) => {
144
+ try {
145
+ const { listJobs } = await import("../lib/cloud/cloud-client.js");
146
+ const jobs = listJobs();
147
+ if (options.json) return console.log(JSON.stringify(jobs, null, 2));
148
+ if (jobs.length === 0) {
149
+ logger.log(
150
+ chalk.gray("No cloud jobs. Submit one with `cc cloud run`."),
151
+ );
152
+ return;
153
+ }
154
+ for (const j of jobs) {
155
+ logger.log(
156
+ `${statusColor(j.status)((j.status || "?").padEnd(8))} ${j.jobId} ${chalk.gray(j.branch)} ${j.task}`,
157
+ );
158
+ }
159
+ } catch (err) {
160
+ logger.error(err.message);
161
+ process.exitCode = 1;
162
+ }
163
+ });
164
+ }
165
+
166
+ async function attachJob(id, options = {}) {
167
+ const { CloudClient, readJob, saveJob, pollUntilDone } =
168
+ await import("../lib/cloud/cloud-client.js");
169
+ const { applyResultPatch, persistResultArtifacts } =
170
+ await import("../lib/cloud/bundle.js");
171
+ const { token } = await resolveRunner();
172
+
173
+ const job = readJob(id);
174
+ if (!job) throw new Error(`job not found: ${id}`);
175
+ const client = new CloudClient({ baseUrl: job.baseUrl, token });
176
+
177
+ logger.log(chalk.gray(`Waiting for ${id}…`));
178
+ const final = await pollUntilDone(client, id, {
179
+ onTick: (s) =>
180
+ logger.log(
181
+ chalk.gray(` ${s.status}${s.summary ? `: ${s.summary}` : ""}`),
182
+ ),
183
+ });
184
+ saveJob({ ...job, status: final.status, lastSummary: final.summary });
185
+
186
+ if (final.status !== "done") {
187
+ logger.error(`Job ${id} ended ${final.status}: ${final.summary || ""}`);
188
+ process.exitCode = 1;
189
+ return;
190
+ }
191
+
192
+ const result = await client.result(id);
193
+
194
+ // Persist plan/artifacts under the job's local dir.
195
+ const { cloudJobsDir } = await import("../lib/cloud/cloud-client.js");
196
+ const destDir = join(cloudJobsDir(), `${id}-result`);
197
+ if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
198
+ const written = persistResultArtifacts(result, destDir);
199
+
200
+ let applied = null;
201
+ if (result.patch && options.apply !== false) {
202
+ applied = applyResultPatch(result.patch, job.cwd || process.cwd());
203
+ }
204
+
205
+ if (options.json) {
206
+ return console.log(
207
+ JSON.stringify(
208
+ { jobId: id, status: final.status, applied, written, pr: result.pr },
209
+ null,
210
+ 2,
211
+ ),
212
+ );
213
+ }
214
+ logger.success(`Job ${id} done`);
215
+ if (result.pr)
216
+ logger.log(chalk.magenta(` PR: ${result.pr.url || result.pr}`));
217
+ if (applied) {
218
+ logger.log(
219
+ applied.applied
220
+ ? chalk.green(` patch: ${applied.reason}`)
221
+ : chalk.yellow(` patch: ${applied.reason} (saved under ${destDir})`),
222
+ );
223
+ if (!applied.applied) {
224
+ // Save the unapplied patch so the user can resolve it by hand.
225
+ persistResultArtifacts(
226
+ { artifacts: [{ name: "result.patch", content: result.patch }] },
227
+ destDir,
228
+ );
229
+ }
230
+ }
231
+ for (const w of written) logger.log(chalk.gray(` wrote ${w}`));
232
+ }
@@ -1,18 +1,40 @@
1
1
  import chalk from "chalk";
2
2
  import logger from "../lib/logger.js";
3
3
  import { collectDoctorReport } from "../runtime/diagnostics.js";
4
+ import {
5
+ collectCheckupSections,
6
+ runCheckupFixes,
7
+ unsafeFixCommands,
8
+ } from "../lib/doctor-checkup.js";
9
+
10
+ const LEVEL_ICON = {
11
+ ok: () => chalk.green("✔"),
12
+ warn: () => chalk.yellow("⚠"),
13
+ err: () => chalk.red("✖"),
14
+ info: () => chalk.gray("·"),
15
+ };
4
16
 
5
17
  export function registerDoctorCommand(program) {
6
18
  program
7
19
  .command("doctor")
8
- .description("Diagnose your ChainlessChain environment")
20
+ .alias("checkup")
21
+ .description("Diagnose your ChainlessChain environment (alias: checkup)")
9
22
  .option("--json", "Output as machine-readable JSON")
23
+ .option("--fix", "Apply safe fixes (stale job files, git worktree prune)")
10
24
  .action(async (options) => {
11
25
  const report = await collectDoctorReport();
26
+ const sections = await collectCheckupSections({ cwd: process.cwd() });
27
+ const fixResults = options.fix ? await runCheckupFixes(sections) : null;
28
+
29
+ const checkupErrs = sections
30
+ .flatMap((s) => s.checks)
31
+ .filter((c) => c.level === "err").length;
12
32
 
13
33
  if (options.json) {
14
- console.log(JSON.stringify(report, null, 2));
15
- if (report.summary.criticalFailed > 0) {
34
+ console.log(
35
+ JSON.stringify({ ...report, checkup: sections, fixResults }, null, 2),
36
+ );
37
+ if (report.summary.criticalFailed > 0 || checkupErrs > 0) {
16
38
  process.exitCode = 1;
17
39
  }
18
40
  return;
@@ -41,6 +63,17 @@ export function registerDoctorCommand(program) {
41
63
  logger.log(` ${icon} ${check.name}${detail}`);
42
64
  }
43
65
 
66
+ // Layered checkup sections (config chain / provider / MCP / IDE /
67
+ // plugins / subagents / transcripts / background agents / worktrees).
68
+ for (const section of sections) {
69
+ logger.log(chalk.bold(`\n ${section.title}\n`));
70
+ for (const c of section.checks) {
71
+ const icon = (LEVEL_ICON[c.level] || LEVEL_ICON.info)();
72
+ const detail = c.detail ? chalk.gray(` — ${c.detail}`) : "";
73
+ logger.log(` ${icon} ${c.name}${detail}`);
74
+ }
75
+ }
76
+
44
77
  logger.log(chalk.bold("\n Port Status\n"));
45
78
  for (const p of report.ports) {
46
79
  const icon = p.open ? chalk.green("●") : chalk.gray("○");
@@ -54,13 +87,35 @@ export function registerDoctorCommand(program) {
54
87
  logger.log(` ${icon} Free space: ${report.disk.freeGB.toFixed(1)} GB`);
55
88
  }
56
89
 
90
+ // Applied fixes (--fix) and copyable commands for the rest.
91
+ if (fixResults && fixResults.length > 0) {
92
+ logger.log(chalk.bold("\n Fixes applied\n"));
93
+ for (const f of fixResults) {
94
+ const icon = f.applied ? chalk.green("✔") : chalk.red("✖");
95
+ logger.log(` ${icon} ${f.id}: ${f.detail}`);
96
+ }
97
+ } else if (options.fix) {
98
+ logger.log(chalk.gray("\n No safe fixes needed.\n"));
99
+ }
100
+ const manual = unsafeFixCommands(sections);
101
+ if (manual.length > 0) {
102
+ logger.log(
103
+ chalk.bold("\n Suggested commands (need your judgement)\n"),
104
+ );
105
+ for (const m of manual) {
106
+ logger.log(` ${chalk.gray("#")} ${m.description}`);
107
+ logger.log(` ${chalk.cyan(m.command)}`);
108
+ }
109
+ }
110
+
57
111
  logger.newline();
58
- if (report.summary.failed === 0) {
112
+ const totalIssues = report.summary.criticalFailed + checkupErrs;
113
+ if (report.summary.failed === 0 && checkupErrs === 0) {
59
114
  logger.log(chalk.bold.green(" All checks passed!\n"));
60
- } else if (report.summary.criticalFailed > 0) {
115
+ } else if (totalIssues > 0) {
61
116
  logger.log(
62
117
  chalk.bold.red(
63
- ` ${report.summary.criticalFailed} issue(s) found. See details above.\n`,
118
+ ` ${totalIssues} issue(s) found. See details above.\n`,
64
119
  ),
65
120
  );
66
121
  process.exitCode = 1;
@@ -342,6 +342,67 @@ export function registerMcpCommand(program) {
342
342
  }
343
343
  });
344
344
 
345
+ // mcp computer-use — expose GUI control verbs as an MCP server (opt-in)
346
+ mcp
347
+ .command("computer-use")
348
+ .description(
349
+ "Expose GUI control (screenshot/window-list/click/type/scroll/clipboard/app-launch) as a Streamable-HTTP MCP server. OFF by default; input verbs need confirm:true; high-risk apps (terminals/IDEs/settings/password managers) always confirm",
350
+ )
351
+ .option("--port <n>", "Port to listen on (default: random free port)", "0")
352
+ .option(
353
+ "--capabilities <list>",
354
+ "Comma-separated subset (default: all): screenshot,window_list,app_launch,click,type,scroll,clipboard_read,clipboard_write",
355
+ )
356
+ .option(
357
+ "--allow-apps <list>",
358
+ "Comma-separated app allowlist for input/launch verbs (default: any app)",
359
+ )
360
+ .option(
361
+ "--confirm-all",
362
+ "Require confirm:true for every verb, not just input verbs",
363
+ )
364
+ .option("--token <token>", "Fixed Bearer token (default: random)")
365
+ .option("--no-auth", "Disable Bearer auth (server binds 127.0.0.1 only)")
366
+ .action(async (options) => {
367
+ try {
368
+ const { startComputerUseServer } =
369
+ await import("../lib/computer-use/computer-use-server.js");
370
+ const handle = await startComputerUseServer({
371
+ port: Number(options.port) || 0,
372
+ token: options.auth === false ? false : options.token || null,
373
+ config: {
374
+ capabilities: options.capabilities
375
+ ? options.capabilities.split(",").map((s) => s.trim())
376
+ : undefined,
377
+ appAllowlist: options.allowApps
378
+ ? options.allowApps.split(",").map((s) => s.trim())
379
+ : undefined,
380
+ confirmAll: options.confirmAll === true,
381
+ },
382
+ });
383
+ logger.log(
384
+ chalk.bold("Computer-use MCP server ready (Streamable-HTTP)"),
385
+ );
386
+ logger.log(` URL: ${chalk.cyan(handle.url)}`);
387
+ logger.log(` Capabilities: ${handle.capabilities.join(", ")}`);
388
+ if (handle.token) {
389
+ logger.log(` Auth: Bearer ${handle.token}`);
390
+ } else {
391
+ logger.log(chalk.yellow(" Auth: disabled (--no-auth)"));
392
+ }
393
+ logger.log(
394
+ chalk.yellow(
395
+ " ⚠ GUI control can act on anything on screen. Input verbs need confirm:true; high-risk apps always confirm.",
396
+ ),
397
+ );
398
+ logger.log(chalk.gray("\nCtrl+C to stop."));
399
+ await new Promise(() => {});
400
+ } catch (err) {
401
+ logger.error(chalk.red(`mcp computer-use failed: ${err.message}`));
402
+ process.exitCode = 1;
403
+ }
404
+ });
405
+
345
406
  // mcp servers — list configured servers
346
407
  mcp
347
408
  .command("servers")