chainlesschain 0.162.34 → 0.162.36

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 (185) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-BYfi9NYS.js → AIOps-vAVAFNJ4.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BiS_tAN7.js → ActionButton-BnRHFCKM.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-jiWl_p-B.js → Analytics-BOjwqWqG.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-m4sIzDot.js → AppLayout-Dc0D1Txn.js} +5 -5
  6. package/src/assets/web-panel/assets/{Audit-CPla3Erm.js → Audit-dd_2efaZ.js} +1 -1
  7. package/src/assets/web-panel/assets/{Backup-BGeQzTaB.js → Backup-HF1jgm8G.js} +1 -1
  8. package/src/assets/web-panel/assets/{BaseInput-DTf7Z1iU.js → BaseInput-CCtzmoKe.js} +1 -1
  9. package/src/assets/web-panel/assets/{Chat-DPTlQlD-.js → Chat-BNfH1c3p.js} +6 -6
  10. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BgRXce4e.js → ChatBubbleRenderer-DCWFqmI4.js} +1 -1
  11. package/src/assets/web-panel/assets/{Checkbox-DY-XuQMu.js → Checkbox-BOr-NscK.js} +1 -1
  12. package/src/assets/web-panel/assets/{Codegen-B6oxPiZI.js → Codegen-DE058N7-.js} +1 -1
  13. package/src/assets/web-panel/assets/{Col-Dqxb4wSE.js → Col-SOREo1XE.js} +1 -1
  14. package/src/assets/web-panel/assets/{Community-DCIX514p.js → Community-sOvNZo9f.js} +1 -1
  15. package/src/assets/web-panel/assets/{Compact-BGtCzDoJ.js → Compact-DnBe558D.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compliance-zcOYd55o.js → Compliance-o-r6CUbg.js} +1 -1
  17. package/src/assets/web-panel/assets/{Cowork-DVTtdIdM.js → Cowork-D6_k9mHP.js} +4 -4
  18. package/src/assets/web-panel/assets/{Cron-CPUaR69k.js → Cron-CEV3Xkrm.js} +2 -2
  19. package/src/assets/web-panel/assets/{Crosschain-DnjUS6QH.js → Crosschain-eJ1lQWKU.js} +1 -1
  20. package/src/assets/web-panel/assets/{DID-Dnz8VDmx.js → DID-B-WqM9Hp.js} +2 -2
  21. package/src/assets/web-panel/assets/{Dashboard-CtWf27j7.js → Dashboard-ZnKPcsHN.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dropdown-B4GC1ZV4.js → Dropdown-B8uLWDIP.js} +1 -1
  23. package/src/assets/web-panel/assets/{EmailListRenderer-wjij3kzr.js → EmailListRenderer-Jmj2Y7aH.js} +1 -1
  24. package/src/assets/web-panel/assets/{FamilyGuardDashboard-rS-2W4u5.js → FamilyGuardDashboard-Cb2xetG-.js} +1 -1
  25. package/src/assets/web-panel/assets/{Federation-90p5Tnoz.js → Federation-C_07GXoq.js} +1 -1
  26. package/src/assets/web-panel/assets/{FormItemContext-Cnrw7gzq.js → FormItemContext-D3kbYrMU.js} +1 -1
  27. package/src/assets/web-panel/assets/{GenericCardRenderer-C85NsWa3.js → GenericCardRenderer-9xgqvGPg.js} +1 -1
  28. package/src/assets/web-panel/assets/{Git-BFAVM9F8.js → Git-BlwWlMMB.js} +2 -2
  29. package/src/assets/web-panel/assets/{Governance-DBoRonpq.js → Governance-DxN3wQZ_.js} +1 -1
  30. package/src/assets/web-panel/assets/{Inference-DHRyD66j.js → Inference-ls7pSw_D.js} +1 -1
  31. package/src/assets/web-panel/assets/{KnowledgeGraph-CTvUKecD.js → KnowledgeGraph-_n9hYuPI.js} +1 -1
  32. package/src/assets/web-panel/assets/{Logs-CB0dv_Ts.js → Logs-CvEVY5TK.js} +2 -2
  33. package/src/assets/web-panel/assets/{Marketplace-CN7Hm5Uw.js → Marketplace-C3qvQJT7.js} +1 -1
  34. package/src/assets/web-panel/assets/{McpTools-q5H25_8L.js → McpTools-DiwKpnKx.js} +5 -5
  35. package/src/assets/web-panel/assets/{Memory-BCV3pZ1d.js → Memory-CIBPi_da.js} +2 -2
  36. package/src/assets/web-panel/assets/{MobileBridge-C04Mngt4.js → MobileBridge-D-v0Se8y.js} +2 -2
  37. package/src/assets/web-panel/assets/MobileProjects-cP1apTQD.js +1 -0
  38. package/src/assets/web-panel/assets/{Mtc-ByAMz2DN.js → Mtc-BMFWrI65.js} +4 -4
  39. package/src/assets/web-panel/assets/{MtcAudit-B7V7byJq.js → MtcAudit-2s8LaHtR.js} +2 -2
  40. package/src/assets/web-panel/assets/{Multisig-DtKmcVQV.js → Multisig-dL_nvj7d.js} +3 -3
  41. package/src/assets/web-panel/assets/{NLProgramming-CaMbT5SC.js → NLProgramming-BbrJp06R.js} +1 -1
  42. package/src/assets/web-panel/assets/{Notes-DRjbSTCU.js → Notes-jR9irwy3.js} +4 -4
  43. package/src/assets/web-panel/assets/{NotificationSettings-B9YbJID5.js → NotificationSettings-Dk-STCIX.js} +1 -1
  44. package/src/assets/web-panel/assets/{OrderTableRenderer-BcI_-vGS.js → OrderTableRenderer-CqqfY6zq.js} +1 -1
  45. package/src/assets/web-panel/assets/{Organization-oTask4BE.js → Organization-BCK5jylo.js} +4 -4
  46. package/src/assets/web-panel/assets/{Overflow-Bab06ey7.js → Overflow-BRAY7Smt.js} +1 -1
  47. package/src/assets/web-panel/assets/{P2P--wlBeU0N.js → P2P-BltVRGjb.js} +2 -2
  48. package/src/assets/web-panel/assets/{PdhVaultBrowser-D4t77Pwc.js → PdhVaultBrowser-CV8UbXHe.js} +3 -3
  49. package/src/assets/web-panel/assets/{Permissions-B3sf6CJ3.js → Permissions-_tNl47Qh.js} +4 -4
  50. package/src/assets/web-panel/assets/{PersonalDataHub-BXOojk63.js → PersonalDataHub-Cgc4HjpX.js} +4 -4
  51. package/src/assets/web-panel/assets/{Pipeline-DReqtBFN.js → Pipeline-Bn_QU4mu.js} +1 -1
  52. package/src/assets/web-panel/assets/{Privacy-cT1GwKLx.js → Privacy-jzJowp5P.js} +1 -1
  53. package/src/assets/web-panel/assets/{ProjectInit-BhTAzVhH.js → ProjectInit-B_1pJ8qd.js} +2 -2
  54. package/src/assets/web-panel/assets/{ProjectSettings-CK-D8Fyj.js → ProjectSettings-CPVZpXzs.js} +2 -2
  55. package/src/assets/web-panel/assets/{Projects-CbHiwen6.js → Projects-CQsHOWnT.js} +1 -1
  56. package/src/assets/web-panel/assets/{Providers-B-ftiXa8.js → Providers-CzzMiLC0.js} +1 -1
  57. package/src/assets/web-panel/assets/{QuickAsk-CT5XPwTF.js → QuickAsk-MxBKIn9o.js} +1 -1
  58. package/src/assets/web-panel/assets/{Recommend-CohhlBZ_.js → Recommend-D8lN6Lis.js} +1 -1
  59. package/src/assets/web-panel/assets/{Reputation-CrgbixFz.js → Reputation-CfYK-IrV.js} +1 -1
  60. package/src/assets/web-panel/assets/{Row-ClExmBn3.js → Row-Bg7NZDP9.js} +1 -1
  61. package/src/assets/web-panel/assets/{RssFeed-VV0qizCJ.js → RssFeed-BOVNJhj0.js} +3 -3
  62. package/src/assets/web-panel/assets/{Search-CqJapSiL.js → Search-B38qzmhY.js} +1 -1
  63. package/src/assets/web-panel/assets/{Security-DY66Zie6.js → Security-CjqleZpe.js} +4 -4
  64. package/src/assets/web-panel/assets/{Services-RQwxat7-.js → Services-Bu9JSJap.js} +2 -2
  65. package/src/assets/web-panel/assets/{Skeleton-0v37UTU_.js → Skeleton-B2RvRkaX.js} +1 -1
  66. package/src/assets/web-panel/assets/{Skills-B4Vm4DxN.js → Skills-_h42mxMN.js} +1 -1
  67. package/src/assets/web-panel/assets/{Sla-CggphTlo.js → Sla-BssLs56D.js} +1 -1
  68. package/src/assets/web-panel/assets/{SpeechSettings-BAOU08C7.js → SpeechSettings-DCxFYHsd.js} +1 -1
  69. package/src/assets/web-panel/assets/{SyncSettings-DmtC4J1w.js → SyncSettings-D2xQuNLE.js} +2 -2
  70. package/src/assets/web-panel/assets/Tasks-DhpOGOlo.js +1 -0
  71. package/src/assets/web-panel/assets/{Templates-C1QK0YoU.js → Templates-CYG-R-aS.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tenant-CieOfmqp.js → Tenant-BQRYLsvP.js} +1 -1
  73. package/src/assets/web-panel/assets/{Terminal-DWdhrxRq.js → Terminal-imKU7N5j.js} +2 -2
  74. package/src/assets/web-panel/assets/{TimelineRenderer-CjFVUUDU.js → TimelineRenderer-BIZzBftk.js} +1 -1
  75. package/src/assets/web-panel/assets/{Tokens-Bwbk3id9.js → Tokens-uMLH5p_a.js} +1 -1
  76. package/src/assets/web-panel/assets/{Trigger-uJle_yj4.js → Trigger-BzS6XPqx.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trust-BcOuxAA5.js → Trust-R4zhHufZ.js} +1 -1
  78. package/src/assets/web-panel/assets/{UkeySign-DUu7Ufg6.js → UkeySign-DATQCoGe.js} +1 -1
  79. package/src/assets/web-panel/assets/{VideoEditing-Ck8JtQ2n.js → VideoEditing-ClUmKOtS.js} +1 -1
  80. package/src/assets/web-panel/assets/{Wallet-B3jw43on.js → Wallet-DzJTbQzD.js} +4 -4
  81. package/src/assets/web-panel/assets/{WebAuthn-Baf9K0y7.js → WebAuthn-CrXrLmzQ.js} +5 -5
  82. package/src/assets/web-panel/assets/{WorkflowEditor-CTEDl_83.js → WorkflowEditor-CpvZ0Tma.js} +1 -1
  83. package/src/assets/web-panel/assets/{chat-CKV51quV.js → chat-a6wpYmVL.js} +1 -1
  84. package/src/assets/web-panel/assets/{colors-BO_RP_yz.js → colors-CXJADb1t.js} +1 -1
  85. package/src/assets/web-panel/assets/{compact-item-BZsxw_ZG.js → compact-item-CL2pohS_.js} +1 -1
  86. package/src/assets/web-panel/assets/{createContext-CAbvtzVL.js → createContext-xFi_1G5_.js} +1 -1
  87. package/src/assets/web-panel/assets/devWarning-BtmELbtB.js +1 -0
  88. package/src/assets/web-panel/assets/{hasIn-QmHT8zDz.js → hasIn-Bchh1rAi.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-fnDgExTu.js → index-B3Tpv7-d.js} +1 -1
  90. package/src/assets/web-panel/assets/index-B4l4vLTB.js +1 -0
  91. package/src/assets/web-panel/assets/{index-BEJa1FiF.js → index-B4zNisy9.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-jd2r-T4p.js → index-B6NehWty.js} +1 -1
  93. package/src/assets/web-panel/assets/index-B7Ek5iiY.js +1 -0
  94. package/src/assets/web-panel/assets/{index-BPZHeug4.js → index-B7knYOpm.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-GPY0LjCu.js → index-B7wT5VRi.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DKnngF_f.js → index-BF4xx1_b.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BRNYA0BV.js → index-BH9t10pe.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DKquNxL2.js → index-BPH5ESqs.js} +3 -3
  99. package/src/assets/web-panel/assets/{index-CEh2Ry_A.js → index-BmsIKzyu.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-Dob6B6qS.js → index-BoaRB-4a.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Ha2_56mf.js → index-BrbJBnT-.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Dln_vjSY.js → index-C2eMYASq.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CqiKnXtL.js → index-C4yBRKT4.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-B3fwyCjJ.js → index-CGq4HQno.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B2aiE8jk.js → index-CMybtJY6.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-B5zhcul9.js → index-CR3kFPuC.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-8BMLlHCv.js → index-CTRd7vkq.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C6i3reUS.js → index-CdU8BwRW.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BNvTNZ1V.js → index-Cua_P8St.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DjrDGJP2.js → index-CuehgDOp.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BCsZiq4i.js → index-D-TT9Swq.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-qPafbZmr.js → index-DEYcLAl7.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DeC7lehI.js → index-DQ_hw_5P.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BnPBG3Tr.js → index-DTEu7TSF.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-D8CHQnPl.js → index-DVo1GJoj.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-9IqJODII.js → index-DjdOL159.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DBCYOypV.js → index-DsbMVBj1.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BL7gQAuB.js → index-DxahxRP7.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DC1CFfQU.js → index-EPERz4Pu.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CVoYeZ5Q.js → index-IkvkNxbc.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CsBx0u5G.js → index-KCib1PTw.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-5hlO2-JQ.js → index-M8SZI11a.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CSaI8R_7.js → index-TxbHusq2.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C6AA-xB2.js → index-dsLc7t6W.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DRK0oAV5.js → index-jMcv1u5o.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-B9Z83FTS.js → index-majCS3s2.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-C3K1eHDd.js → index-u8K1y_lh.js} +1 -1
  128. package/src/assets/web-panel/assets/{initDefaultProps-Bc2GWeWe.js → initDefaultProps-DYn3Gc09.js} +1 -1
  129. package/src/assets/web-panel/assets/{motion-BI-Rxw6o.js → motion-ZS3eolb9.js} +1 -1
  130. package/src/assets/web-panel/assets/{move-DRPdwDQB.js → move-CEw4uqr3.js} +1 -1
  131. package/src/assets/web-panel/assets/{omit-B4XTl3jW.js → omit-DlHFZnPp.js} +1 -1
  132. package/src/assets/web-panel/assets/{pickAttrs-Do5d86Wr.js → pickAttrs-eZQvV5fA.js} +1 -1
  133. package/src/assets/web-panel/assets/{placementArrow-B8VGZ0ZF.js → placementArrow-B31jQwa-.js} +1 -1
  134. package/src/assets/web-panel/assets/{responsiveObserve-Cf0kI_vN.js → responsiveObserve-DAsNmVto.js} +1 -1
  135. package/src/assets/web-panel/assets/{slide-Cb0psjSL.js → slide-gPQPrYZC.js} +1 -1
  136. package/src/assets/web-panel/assets/{statusUtils-Bjuo5Oal.js → statusUtils-DwWKX5co.js} +1 -1
  137. package/src/assets/web-panel/assets/{styleChecker-BLMhoHJ5.js → styleChecker-B3VOtXuH.js} +1 -1
  138. package/src/assets/web-panel/assets/{useFlexGapSupport-BdCwAfNU.js → useFlexGapSupport-6ADctM2r.js} +1 -1
  139. package/src/assets/web-panel/assets/{useFs-9Jhaz5gG.js → useFs-6Zx1SSKs.js} +1 -1
  140. package/src/assets/web-panel/assets/{usePersonalDataHub-xYFyXKwD.js → usePersonalDataHub-BzReowln.js} +1 -1
  141. package/src/assets/web-panel/assets/{vnode-CVhepE6Z.js → vnode-C8IpEQbD.js} +1 -1
  142. package/src/assets/web-panel/assets/{zoom-IbbtJ4Zr.js → zoom-ruc9vHr0.js} +1 -1
  143. package/src/assets/web-panel/index.html +1 -1
  144. package/src/commands/agent.js +161 -6
  145. package/src/commands/agents.js +199 -0
  146. package/src/commands/command.js +7 -2
  147. package/src/commands/hook.js +136 -28
  148. package/src/commands/ide.js +168 -0
  149. package/src/commands/mcp.js +92 -0
  150. package/src/commands/output-style.js +127 -0
  151. package/src/commands/permissions.js +211 -0
  152. package/src/commands/statusline.js +93 -0
  153. package/src/index.js +8 -0
  154. package/src/lib/agent-core.js +7 -0
  155. package/src/lib/agents.js +147 -0
  156. package/src/lib/hook-manager.js +1 -0
  157. package/src/lib/hook-runner.cjs +183 -0
  158. package/src/lib/ide-bridge.js +310 -0
  159. package/src/lib/image-input.js +156 -0
  160. package/src/lib/mcp-oauth.js +415 -0
  161. package/src/lib/output-styles.js +179 -0
  162. package/src/lib/permission-rules.cjs +325 -0
  163. package/src/lib/provider-options.js +11 -7
  164. package/src/lib/settings-hook-events.cjs +102 -0
  165. package/src/lib/settings-hooks.cjs +163 -0
  166. package/src/lib/settings-loader.cjs +244 -0
  167. package/src/lib/slash-commands.js +21 -13
  168. package/src/lib/status-line.cjs +204 -0
  169. package/src/lib/sub-agent-profiles.js +3 -0
  170. package/src/lib/web-search.js +487 -0
  171. package/src/repl/agent-repl.js +445 -35
  172. package/src/repl/slash-macro.js +45 -0
  173. package/src/runtime/agent-core.js +799 -21
  174. package/src/runtime/coding-agent-contract-shared.cjs +94 -4
  175. package/src/runtime/coding-agent-policy.cjs +24 -0
  176. package/src/runtime/headless-runner.js +162 -6
  177. package/src/runtime/headless-stream.js +133 -7
  178. package/src/runtime/mcp-config.js +161 -15
  179. package/src/runtime/policies/agent-policy.js +1 -0
  180. package/src/runtime/system-prompt.js +6 -1
  181. package/src/assets/web-panel/assets/MobileProjects-CUxONYre.js +0 -1
  182. package/src/assets/web-panel/assets/Tasks-CExqxzL6.js +0 -1
  183. package/src/assets/web-panel/assets/devWarning-DQYatsRR.js +0 -1
  184. package/src/assets/web-panel/assets/index-Bv_y1Ud7.js +0 -1
  185. package/src/assets/web-panel/assets/index-CZZnSJEX.js +0 -1
@@ -0,0 +1,168 @@
1
+ /**
2
+ * `cc ide` — inspect IDE bridge discovery (Phase 0).
3
+ *
4
+ * The agent auto-connects a running editor's MCP server when inside an IDE
5
+ * integrated terminal (or with `cc agent --ide`). These subcommands make that
6
+ * discovery visible and debuggable WITHOUT running an agent:
7
+ *
8
+ * cc ide list list live IDE lockfiles found
9
+ * cc ide status which server `cc agent` would connect to (+ its MCP config)
10
+ * cc ide doctor explain WHY discovery did / didn't pick a server
11
+ *
12
+ * Pure read-only over ~/.chainlesschain/ide/*.json — see
13
+ * docs/design/modules/98_IDE桥接对标方案.md.
14
+ */
15
+ import chalk from "chalk";
16
+ import {
17
+ readIdeLocks,
18
+ discoverIdeServer,
19
+ ideServerToMcpConfig,
20
+ isInIdeTerminal,
21
+ ideLockDir,
22
+ diagnoseIde,
23
+ } from "../lib/ide-bridge.js";
24
+
25
+ function emit(obj) {
26
+ console.log(JSON.stringify(obj, null, 2));
27
+ }
28
+
29
+ export function registerIdeCommand(program) {
30
+ const ide = program
31
+ .command("ide")
32
+ .description("Inspect IDE bridge discovery (editor MCP server auto-connect)");
33
+
34
+ ide
35
+ .command("list")
36
+ .description("List live IDE lockfiles (editor MCP servers advertised)")
37
+ .option("--json", "Machine-readable output")
38
+ .action((options) => {
39
+ const locks = readIdeLocks();
40
+ if (options.json) {
41
+ // Never surface the raw bearer token or internal _file path.
42
+ const safe = locks.map(({ token, _file, ...rest }) => ({
43
+ ...rest,
44
+ hasToken: !!token,
45
+ }));
46
+ emit({ lockDir: ideLockDir(), count: safe.length, locks: safe });
47
+ return;
48
+ }
49
+ if (!locks.length) {
50
+ console.log(
51
+ chalk.gray(`No live IDE lockfiles in ${ideLockDir()}`),
52
+ );
53
+ console.log(
54
+ chalk.gray(
55
+ "Start an IDE extension that advertises one, or run `cc ide doctor`.",
56
+ ),
57
+ );
58
+ return;
59
+ }
60
+ console.log(chalk.bold(`IDE servers (${locks.length}) in ${ideLockDir()}:`));
61
+ for (const l of locks) {
62
+ console.log(
63
+ ` ${chalk.cyan(l.ide)} port ${l.port} ${l.transport} ` +
64
+ `${l.token ? chalk.green("token") : chalk.yellow("no-token")}`,
65
+ );
66
+ console.log(chalk.gray(` url ${l.url}`));
67
+ if (l.workspaceFolders.length) {
68
+ console.log(chalk.gray(` ws ${l.workspaceFolders.join(", ")}`));
69
+ }
70
+ }
71
+ });
72
+
73
+ ide
74
+ .command("status")
75
+ .description("Show the IDE server `cc agent` would connect to right now")
76
+ .option("--ide", "Force selection even outside an IDE terminal")
77
+ .option("--json", "Machine-readable output")
78
+ .action((options) => {
79
+ const env = process.env;
80
+ const cwd = process.cwd();
81
+ const inIde = isInIdeTerminal(env);
82
+ const lock = discoverIdeServer({ cwd, env, force: options.ide === true });
83
+ const cfg = lock ? ideServerToMcpConfig(lock) : null;
84
+ // Redact the bearer token in the previewed config.
85
+ const safeCfg = cfg
86
+ ? {
87
+ ...cfg,
88
+ headers: cfg.headers?.Authorization
89
+ ? { ...cfg.headers, Authorization: "Bearer ***" }
90
+ : cfg.headers,
91
+ }
92
+ : null;
93
+ if (options.json) {
94
+ // Strip the raw token + internal _file from the chosen lock.
95
+ const safeChosen = lock
96
+ ? (({ token, _file, ...rest }) => ({ ...rest, hasToken: !!token }))(
97
+ lock,
98
+ )
99
+ : null;
100
+ emit({
101
+ inIdeTerminal: inIde,
102
+ chosen: safeChosen,
103
+ mcpConfig: safeCfg,
104
+ });
105
+ return;
106
+ }
107
+ console.log(
108
+ `In IDE terminal: ${inIde ? chalk.green("yes") : chalk.gray("no")}`,
109
+ );
110
+ if (!lock) {
111
+ console.log(
112
+ chalk.gray(
113
+ "No IDE server would be connected. Try `cc ide doctor` for why.",
114
+ ),
115
+ );
116
+ return;
117
+ }
118
+ console.log(
119
+ `Would connect: ${chalk.cyan(lock.ide)} on port ${lock.port} ` +
120
+ `(${lock.transport}) as MCP server ${chalk.bold("ide")}`,
121
+ );
122
+ console.log(chalk.gray("MCP config:"));
123
+ console.log(chalk.gray(" " + JSON.stringify(safeCfg)));
124
+ });
125
+
126
+ ide
127
+ .command("doctor")
128
+ .description("Explain why IDE discovery did / didn't pick a server")
129
+ .option("--ide", "Diagnose as if --ide (force) were passed")
130
+ .option("--json", "Machine-readable output")
131
+ .action((options) => {
132
+ const diag = diagnoseIde({
133
+ cwd: process.cwd(),
134
+ env: process.env,
135
+ force: options.ide === true,
136
+ });
137
+ if (options.json) {
138
+ emit(diag);
139
+ return;
140
+ }
141
+ console.log(chalk.bold("IDE bridge discovery"));
142
+ console.log(` lock dir : ${diag.lockDir}`);
143
+ console.log(
144
+ ` in IDE terminal: ${diag.inIdeTerminal ? chalk.green("yes") : chalk.gray("no")}`,
145
+ );
146
+ console.log(` live locks : ${diag.locks.length}`);
147
+ for (const l of diag.locks) {
148
+ const m =
149
+ l.matchScore >= 0
150
+ ? chalk.green(`workspace-match(${l.matchScore})`)
151
+ : chalk.yellow("no-workspace-match");
152
+ console.log(
153
+ ` - ${chalk.cyan(l.ide)} port ${l.port} ${l.transport} ` +
154
+ `${l.hasToken ? "token" : chalk.yellow("no-token")} ${m}`,
155
+ );
156
+ }
157
+ console.log(
158
+ ` result : ${
159
+ diag.chosen
160
+ ? chalk.green(`connect ${diag.chosen.ide}:${diag.chosen.port}`)
161
+ : chalk.yellow("nothing to connect")
162
+ }`,
163
+ );
164
+ console.log(` reason : ${diag.reason}`);
165
+ });
166
+
167
+ return ide;
168
+ }
@@ -65,6 +65,98 @@ export function registerMcpCommand(program) {
65
65
  .command("mcp")
66
66
  .description("MCP server management and tool execution");
67
67
 
68
+ // mcp login — OAuth 2.0 (Auth Code + PKCE) for a remote MCP server.
69
+ mcp
70
+ .command("login <url>")
71
+ .description("Authorize a remote MCP server via OAuth (opens a browser); stores the token")
72
+ .option("--scope <scope>", "OAuth scope(s) to request")
73
+ .option("--client-id <id>", "Use a pre-registered client_id instead of dynamic registration")
74
+ .option("--port <n>", "Localhost callback port", (v) => parseInt(v, 10), 53682)
75
+ .option("--no-open", "Print the authorize URL instead of opening a browser")
76
+ .action(async (url, options) => {
77
+ try {
78
+ const oauth = await import("../lib/mcp-oauth.js");
79
+ if (options.open === false) {
80
+ oauth._deps.openBrowser = () => false; // commander maps --no-open → open:false
81
+ }
82
+ logger.log(chalk.gray(`Authorizing ${url} …`));
83
+ const rec = await oauth.authorizeInteractive(url, {
84
+ scope: options.scope,
85
+ clientId: options.clientId,
86
+ port: options.port,
87
+ writeOut: (s) => process.stdout.write(s),
88
+ });
89
+ logger.log(
90
+ chalk.green(`✓ authorized ${rec.server}`) +
91
+ chalk.gray(
92
+ rec.expires_at
93
+ ? ` (expires ${new Date(rec.expires_at).toISOString()})`
94
+ : "",
95
+ ),
96
+ );
97
+ logger.log(
98
+ chalk.gray("The token is injected as a Bearer header on connect."),
99
+ );
100
+ } catch (err) {
101
+ logger.error(chalk.red(`mcp login failed: ${err.message}`));
102
+ process.exitCode = 1;
103
+ }
104
+ });
105
+
106
+ // mcp logout — forget a stored OAuth token.
107
+ mcp
108
+ .command("logout <url>")
109
+ .description("Delete the stored OAuth token for a remote MCP server")
110
+ .action(async (url) => {
111
+ try {
112
+ const { deleteStoredToken, serverKey } = await import("../lib/mcp-oauth.js");
113
+ const ok = deleteStoredToken(url);
114
+ logger.log(
115
+ ok
116
+ ? chalk.green(`✓ removed token for ${serverKey(url)}`)
117
+ : chalk.gray(`no stored token for ${serverKey(url)}`),
118
+ );
119
+ } catch (err) {
120
+ logger.error(chalk.red(`mcp logout failed: ${err.message}`));
121
+ process.exitCode = 1;
122
+ }
123
+ });
124
+
125
+ // mcp auth — list stored OAuth tokens.
126
+ mcp
127
+ .command("auth")
128
+ .description("List stored MCP OAuth tokens")
129
+ .option("--json", "Output as JSON")
130
+ .action(async (options) => {
131
+ try {
132
+ const { loadTokenStore, isTokenExpired } = await import("../lib/mcp-oauth.js");
133
+ const store = loadTokenStore();
134
+ const rows = Object.values(store).map((r) => ({
135
+ server: r.server,
136
+ expired: isTokenExpired(r),
137
+ expires_at: r.expires_at || null,
138
+ refresh: Boolean(r.refresh_token),
139
+ }));
140
+ if (options.json) {
141
+ console.log(JSON.stringify(rows, null, 2));
142
+ return;
143
+ }
144
+ if (rows.length === 0) {
145
+ logger.log(chalk.gray("No MCP OAuth tokens. Run: cc mcp login <url>"));
146
+ return;
147
+ }
148
+ for (const r of rows) {
149
+ const state = r.expired ? chalk.red("expired") : chalk.green("valid");
150
+ logger.log(
151
+ ` ${chalk.cyan(r.server)} [${state}]${r.refresh ? chalk.gray(" +refresh") : ""}`,
152
+ );
153
+ }
154
+ } catch (err) {
155
+ logger.error(chalk.red(`mcp auth failed: ${err.message}`));
156
+ process.exitCode = 1;
157
+ }
158
+ });
159
+
68
160
  // mcp servers — list configured servers
69
161
  mcp
70
162
  .command("servers")
@@ -0,0 +1,127 @@
1
+ /**
2
+ * cc output-style — list / show output-style personas (Claude-Code parity).
3
+ *
4
+ * cc output-style list [--json] list built-ins + .claude/output-styles/*.md
5
+ * cc output-style show <name> show a style's metadata + body
6
+ * cc output-style new <name> scaffold a new style file
7
+ *
8
+ * Apply one with `cc agent --output-style <name>` or the REPL `/output-style`,
9
+ * or set a default via `outputStyle` in .claude/settings.json.
10
+ */
11
+
12
+ import chalk from "chalk";
13
+ import { logger } from "../lib/logger.js";
14
+
15
+ export function registerOutputStyleCommand(program) {
16
+ const cmd = program
17
+ .command("output-style")
18
+ .alias("output-styles")
19
+ .description("List / show agent output-style personas");
20
+
21
+ cmd
22
+ .command("list", { isDefault: true })
23
+ .alias("ls")
24
+ .description("List built-in + .claude/output-styles/*.md personas")
25
+ .option("--json", "Output as JSON")
26
+ .action(async (options) => {
27
+ try {
28
+ const { discoverOutputStyles, settingsDefaultOutputStyle } =
29
+ await import("../lib/output-styles.js");
30
+ const all = discoverOutputStyles(process.cwd());
31
+ const dflt = settingsDefaultOutputStyle(process.cwd());
32
+ if (options.json) {
33
+ console.log(JSON.stringify({ default: dflt, styles: all }, null, 2));
34
+ return;
35
+ }
36
+ for (const s of all) {
37
+ const tag = s.builtin
38
+ ? chalk.gray("[builtin]")
39
+ : s.scope === "project"
40
+ ? chalk.cyan("[proj]")
41
+ : chalk.gray("[pers]");
42
+ const star = s.name === dflt ? chalk.green(" *") : "";
43
+ logger.log(
44
+ `${chalk.bold(s.name.padEnd(16))} ${tag}${star} ${chalk.gray(s.description || "")}`,
45
+ );
46
+ }
47
+ if (dflt) logger.log(chalk.dim(`\ndefault (settings.json): ${dflt}`));
48
+ } catch (err) {
49
+ logger.error(chalk.red(`output-style list failed: ${err.message}`));
50
+ process.exitCode = 1;
51
+ }
52
+ });
53
+
54
+ cmd
55
+ .command("show <name>")
56
+ .description("Show a style's metadata and body")
57
+ .option("--json", "Output as JSON")
58
+ .action(async (name, options) => {
59
+ try {
60
+ const { getOutputStyle } = await import("../lib/output-styles.js");
61
+ const s = getOutputStyle(name, process.cwd());
62
+ if (!s) {
63
+ logger.error(chalk.red(`no such output style: ${name}`));
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+ if (options.json) {
68
+ console.log(JSON.stringify(s, null, 2));
69
+ return;
70
+ }
71
+ logger.log(
72
+ chalk.bold(s.name) +
73
+ (s.builtin ? chalk.gray(" [builtin]") : chalk.gray(` [${s.scope}]`)),
74
+ );
75
+ if (s.description) logger.log(chalk.gray(` ${s.description}`));
76
+ if (s.file) logger.log(chalk.gray(` file: ${s.file}`));
77
+ logger.log(chalk.dim(" ───"));
78
+ logger.log(s.body || chalk.gray("(empty — no persona overlay)"));
79
+ } catch (err) {
80
+ logger.error(chalk.red(`output-style show failed: ${err.message}`));
81
+ process.exitCode = 1;
82
+ }
83
+ });
84
+
85
+ cmd
86
+ .command("new <name>")
87
+ .description("Scaffold a new style under .claude/output-styles/")
88
+ .option("--description <d>", "Frontmatter description")
89
+ .option("--personal", "Create under ~/.claude/output-styles instead of project")
90
+ .action(async (name, options) => {
91
+ try {
92
+ const fs = await import("node:fs");
93
+ const path = await import("node:path");
94
+ const { homedir } = await import("node:os");
95
+ const safe = String(name).replace(/[^\w.-]/g, "-");
96
+ const root = options.personal
97
+ ? path.join(homedir(), ".claude", "output-styles")
98
+ : path.join(process.cwd(), ".claude", "output-styles");
99
+ const file = path.join(root, `${safe}.md`);
100
+ if (fs.existsSync(file)) {
101
+ logger.error(chalk.red(`already exists: ${file}`));
102
+ process.exitCode = 1;
103
+ return;
104
+ }
105
+ fs.mkdirSync(path.dirname(file), { recursive: true });
106
+ const tpl = `---
107
+ name: ${safe}
108
+ description: ${options.description || name}
109
+ ---
110
+
111
+ ## Output style: ${safe}
112
+
113
+ Describe how the agent should behave in this style. This text is appended to
114
+ the system prompt (after the base coding instructions), so keep it focused on
115
+ *behaviour / tone*, not tool mechanics.
116
+ `;
117
+ fs.writeFileSync(file, tpl, "utf-8");
118
+ logger.log(chalk.green(`✓ created ${file}`));
119
+ logger.log(
120
+ chalk.gray(` use it: cc agent --output-style ${safe} -p "..."`),
121
+ );
122
+ } catch (err) {
123
+ logger.error(chalk.red(`output-style new failed: ${err.message}`));
124
+ process.exitCode = 1;
125
+ }
126
+ });
127
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * cc permissions — inspect, dry-run, and edit the `.claude/settings.json`
3
+ * permission ruleset (Claude-Code `permissions.{allow,ask,deny}` parity).
4
+ *
5
+ * cc permissions list [--json] merged ruleset + source file
6
+ * cc permissions test <tool> <args...> dry-run: which rule decides?
7
+ * cc permissions add <allow|ask|deny> <rule> append a rule to a settings file
8
+ * [--local | --user] (default target: project)
9
+ *
10
+ * The ruleset is loaded by settings-loader (user < project < local < env) and
11
+ * evaluated by permission-rules (deny > ask > allow). This command only reads
12
+ * and edits the files / runs the engine — it does not yet gate the agent tool
13
+ * loop (that wiring is a separate, riskier step).
14
+ */
15
+
16
+ import chalk from "chalk";
17
+ import { logger } from "../lib/logger.js";
18
+
19
+ const KIND_COLOR = {
20
+ allow: chalk.green,
21
+ ask: chalk.yellow,
22
+ deny: chalk.red,
23
+ };
24
+
25
+ /** Resolve an umbrella token (Bash) to a concrete tool name for dry-run. */
26
+ function resolveConcreteTool(token, groups) {
27
+ const t = String(token || "");
28
+ const lower = t.toLowerCase();
29
+ if (Object.prototype.hasOwnProperty.call(groups, lower)) {
30
+ return groups[lower][0];
31
+ }
32
+ return t;
33
+ }
34
+
35
+ /** Build the tool args object a dry-run target needs from positional args. */
36
+ function buildArgs(tool, positional, rulesMod) {
37
+ const joined = positional.join(" ").trim();
38
+ if (rulesMod.COMMAND_TOOLS.has(tool)) return { command: joined };
39
+ if (rulesMod.PATH_TOOLS.has(tool)) return { path: positional[0] || "" };
40
+ if (rulesMod.URL_TOOLS.has(tool)) return { url: positional[0] || "" };
41
+ return {};
42
+ }
43
+
44
+ export function registerPermissionsCommand(program) {
45
+ const cmd = program
46
+ .command("permissions")
47
+ .alias("perms")
48
+ .description(
49
+ "Inspect / dry-run / edit .claude/settings.json permission rules",
50
+ );
51
+
52
+ // ── list ──────────────────────────────────────────────────────────────
53
+ cmd
54
+ .command("list")
55
+ .alias("ls")
56
+ .description("Show the merged permission ruleset and where each rule came from")
57
+ .option("--json", "Output as JSON")
58
+ .option("--settings <file>", "Also merge an explicit settings file")
59
+ .action(async (options) => {
60
+ try {
61
+ const { loadSettings } = await import("../lib/settings-loader.cjs");
62
+ const { rules, sources, files } = loadSettings({
63
+ cwd: process.cwd(),
64
+ settingsFile: options.settings,
65
+ });
66
+ if (options.json) {
67
+ console.log(JSON.stringify({ rules, sources, files }, null, 2));
68
+ return;
69
+ }
70
+ const total =
71
+ rules.allow.length + rules.ask.length + rules.deny.length;
72
+ if (total === 0) {
73
+ logger.log(
74
+ chalk.gray(
75
+ "No permission rules. Add one: cc permissions add deny \"Bash(rm:*)\"\n" +
76
+ "(or create .claude/settings.json with a permissions block)",
77
+ ),
78
+ );
79
+ return;
80
+ }
81
+ for (const kind of ["deny", "ask", "allow"]) {
82
+ if (rules[kind].length === 0) continue;
83
+ logger.log(KIND_COLOR[kind].bold(`${kind} (${rules[kind].length})`));
84
+ for (const rule of rules[kind]) {
85
+ const src = sources[`${kind}:${rule}`] || "?";
86
+ logger.log(` ${rule.padEnd(34)} ${chalk.gray(src)}`);
87
+ }
88
+ }
89
+ if (files.length) {
90
+ logger.log(chalk.dim(`\nsources: ${files.join(", ")}`));
91
+ }
92
+ } catch (err) {
93
+ logger.error(chalk.red(`permissions list failed: ${err.message}`));
94
+ process.exitCode = 1;
95
+ }
96
+ });
97
+
98
+ // ── test (dry-run) ─────────────────────────────────────────────────────
99
+ cmd
100
+ .command("test <tool> [args...]")
101
+ .description(
102
+ 'Dry-run a tool call against the ruleset, e.g. permissions test run_shell "git push"',
103
+ )
104
+ .option("--json", "Output as JSON")
105
+ .option("--settings <file>", "Also merge an explicit settings file")
106
+ .action(async (tool, args, options) => {
107
+ try {
108
+ const { loadSettings, ruleSource } =
109
+ await import("../lib/settings-loader.cjs");
110
+ // .cjs default-export interop: module.exports surfaces as `.default`.
111
+ const rulesMod = await import("../lib/permission-rules.cjs");
112
+ const mod = rulesMod.default || rulesMod;
113
+
114
+ const { rules, sources } = loadSettings({
115
+ cwd: process.cwd(),
116
+ settingsFile: options.settings,
117
+ });
118
+ const concrete = resolveConcreteTool(tool, mod.TOOL_GROUPS);
119
+ const toolArgs = buildArgs(concrete, args || [], mod);
120
+ const result = mod.evaluatePermissionRules({
121
+ tool: concrete,
122
+ args: toolArgs,
123
+ cwd: process.cwd(),
124
+ rules,
125
+ });
126
+ const decision = result.decision || "fallthrough";
127
+ const source = result.rule
128
+ ? ruleSource(sources, result.decision, result.rule)
129
+ : null;
130
+
131
+ if (options.json) {
132
+ console.log(
133
+ JSON.stringify(
134
+ { tool: concrete, args: toolArgs, decision, rule: result.rule, source },
135
+ null,
136
+ 2,
137
+ ),
138
+ );
139
+ return;
140
+ }
141
+
142
+ const color = KIND_COLOR[result.decision] || chalk.gray;
143
+ logger.log(
144
+ `${chalk.bold(concrete)} ${chalk.gray(JSON.stringify(toolArgs))}`,
145
+ );
146
+ logger.log(` decision: ${color.bold(decision)}`);
147
+ if (result.rule) {
148
+ logger.log(` rule: ${result.rule}`);
149
+ if (source) logger.log(` source: ${chalk.gray(source)}`);
150
+ } else {
151
+ logger.log(
152
+ chalk.gray(
153
+ " no rule matched → falls back to risk-tier / --permission-mode logic",
154
+ ),
155
+ );
156
+ }
157
+ } catch (err) {
158
+ logger.error(chalk.red(`permissions test failed: ${err.message}`));
159
+ process.exitCode = 1;
160
+ }
161
+ });
162
+
163
+ // ── add ────────────────────────────────────────────────────────────────
164
+ cmd
165
+ .command("add <decision> <rule>")
166
+ .description("Append a rule (allow|ask|deny) to a settings file")
167
+ .option("--local", "Write to .claude/settings.local.json (personal, gitignored)")
168
+ .option("--user", "Write to ~/.claude/settings.json (all projects)")
169
+ .action(async (decision, rule, options) => {
170
+ try {
171
+ const kind = String(decision || "").toLowerCase();
172
+ if (!["allow", "ask", "deny"].includes(kind)) {
173
+ logger.error(
174
+ chalk.red(`decision must be allow | ask | deny (got "${decision}")`),
175
+ );
176
+ process.exitCode = 1;
177
+ return;
178
+ }
179
+ const rulesMod = await import("../lib/permission-rules.cjs");
180
+ const mod = rulesMod.default || rulesMod;
181
+ if (!mod.parseRule(rule)) {
182
+ logger.error(
183
+ chalk.red(
184
+ `not a valid rule: "${rule}" (expected Tool or Tool(pattern), e.g. Bash(rm:*))`,
185
+ ),
186
+ );
187
+ process.exitCode = 1;
188
+ return;
189
+ }
190
+
191
+ const scope = options.user ? "user" : options.local ? "local" : "project";
192
+ const { addRule } = await import("../lib/settings-loader.cjs");
193
+ const { file, added } = addRule({
194
+ cwd: process.cwd(),
195
+ kind,
196
+ rule,
197
+ scope,
198
+ });
199
+ if (!added) {
200
+ logger.log(chalk.gray(`already present in ${file}: ${kind} ${rule}`));
201
+ return;
202
+ }
203
+ logger.log(
204
+ `${KIND_COLOR[kind].bold("✓ " + kind)} ${rule} ${chalk.gray("→ " + file)}`,
205
+ );
206
+ } catch (err) {
207
+ logger.error(chalk.red(`permissions add failed: ${err.message}`));
208
+ process.exitCode = 1;
209
+ }
210
+ });
211
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * cc statusline — preview the configured `statusLine` (Claude-Code parity).
3
+ *
4
+ * cc statusline preview the rendered status line
5
+ * cc statusline show show the resolved config (+ source)
6
+ *
7
+ * Configure in .claude/settings.json:
8
+ * { "statusLine": { "type": "command", "command": "~/.claude/status.sh" } }
9
+ * The command receives a JSON context on stdin and its first stdout line is the
10
+ * status line (shown above the REPL prompt each turn).
11
+ */
12
+
13
+ import chalk from "chalk";
14
+ import { logger } from "../lib/logger.js";
15
+
16
+ export function registerStatuslineCommand(program) {
17
+ const cmd = program
18
+ .command("statusline")
19
+ .alias("status-line")
20
+ .description("Preview / show the .claude/settings.json statusLine");
21
+
22
+ cmd
23
+ .command("preview", { isDefault: true })
24
+ .description("Render the configured status line once")
25
+ .option("--model <m>", "Model to pass in the context", "opus")
26
+ .option("--json", "Output as JSON")
27
+ .action(async (options) => {
28
+ try {
29
+ const { loadStatusLineConfig, buildContext, renderStatusLine } =
30
+ await import("../lib/status-line.cjs");
31
+ const cfg = loadStatusLineConfig({ cwd: process.cwd() });
32
+ if (!cfg) {
33
+ logger.log(
34
+ chalk.gray(
35
+ 'No statusLine configured. Add to .claude/settings.json:\n' +
36
+ ' { "statusLine": { "type": "command", "command": "./status.sh" } }',
37
+ ),
38
+ );
39
+ return;
40
+ }
41
+ const line = renderStatusLine(
42
+ cfg,
43
+ buildContext({
44
+ sessionId: "preview",
45
+ model: options.model,
46
+ cwd: process.cwd(),
47
+ }),
48
+ { cwd: process.cwd() },
49
+ );
50
+ if (options.json) {
51
+ console.log(JSON.stringify({ config: cfg, line }, null, 2));
52
+ return;
53
+ }
54
+ if (line == null) {
55
+ logger.error(
56
+ chalk.red(
57
+ `statusLine command produced no output (or failed): ${cfg.command}`,
58
+ ),
59
+ );
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+ process.stdout.write(line + "\n");
64
+ } catch (err) {
65
+ logger.error(chalk.red(`statusline preview failed: ${err.message}`));
66
+ process.exitCode = 1;
67
+ }
68
+ });
69
+
70
+ cmd
71
+ .command("show")
72
+ .description("Show the resolved statusLine config")
73
+ .option("--json", "Output as JSON")
74
+ .action(async (options) => {
75
+ try {
76
+ const { loadStatusLineConfig } = await import("../lib/status-line.cjs");
77
+ const cfg = loadStatusLineConfig({ cwd: process.cwd() });
78
+ if (options.json) {
79
+ console.log(JSON.stringify(cfg, null, 2));
80
+ return;
81
+ }
82
+ if (!cfg) {
83
+ logger.log(chalk.gray("No statusLine configured."));
84
+ return;
85
+ }
86
+ logger.log(`command: ${chalk.cyan(cfg.command)}`);
87
+ logger.log(chalk.gray(`type: ${cfg.type} padding: ${cfg.padding}`));
88
+ } catch (err) {
89
+ logger.error(chalk.red(`statusline show failed: ${err.message}`));
90
+ process.exitCode = 1;
91
+ }
92
+ });
93
+ }