chainlesschain 0.162.156 → 0.162.158

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 (195) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-DjBXlypQ.js → AIOps-BwpTJTN_.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-Cv9er9bp.js → ActionButton-BtQOoo3l.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-CLKDjSNs.js → Analytics-Duf_rXZa.js} +3 -3
  7. package/src/assets/web-panel/assets/AppLayout-XQK3wjvB.js +9 -0
  8. package/src/assets/web-panel/assets/Artifacts-CTVt96zW.css +1 -0
  9. package/src/assets/web-panel/assets/Artifacts-DQvJoQ6E.js +1 -0
  10. package/src/assets/web-panel/assets/{Audit-CXafD178.js → Audit-DNjOGQLh.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-CP5c-GSd.js → BackgroundAgents-FH9RAfB5.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-BbYLQfyt.js → Backup-ZIbrR4-U.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-Bqe0MwZL.js → BaseInput-DSt3NaND.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-jNA_yUPH.js → Chat-CY-wvbjv.js} +6 -6
  15. package/src/assets/web-panel/assets/Chat-KSGPtU0L.css +1 -0
  16. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BOFLF01s.js → ChatBubbleRenderer-BAV9V-t-.js} +1 -1
  17. package/src/assets/web-panel/assets/{Checkbox-Dlzz-zD1.js → Checkbox-8JVadE_B.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-BAsDQjGf.js → Codegen-CN83nPYI.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-Ju0HrAuS.js → Col-xPSvqdN8.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-DynJd43Z.js → Community-D78cnIjG.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-CabbZVww.js → Compact-CSw6Csbp.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-DW4BmAoh.js → Compliance-E_HhjcYR.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-Bk1S_7X-.js → Cowork-DybeQjmm.js} +3 -3
  24. package/src/assets/web-panel/assets/{Cron-By4sh_NM.js → Cron-DS0BJeLY.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-DdZdbS1C.js → Crosschain-BOwVgkbs.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-CkL-sQyS.js → DID-DRUr9YuX.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-g_mOpumg.js → Dashboard-Cht-yUKW.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-DtHyE7Ao.js → Dropdown-BLr_EJ9X.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-Kpvov5Wr.js → EmailListRenderer-Drexuh5W.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-C4kZoePR.js → FamilyGuardDashboard-D9Q2Kq63.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-BAwWoK2N.js → Federation-C-Z1xI-T.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-DeI0i5f8.js → FormItemContext-DLHPMkQF.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-CkcKRtos.js → GenericCardRenderer-DxxEdn2r.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-kX6jjI9y.js → Git-syATcaBt.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-BXJCBm6x.js → Governance-CYe_r8Zf.js} +1 -1
  36. package/src/assets/web-panel/assets/Inference-GWxErB7k.js +1 -0
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-3Dnuf1Wh.js → KnowledgeGraph-qQvVCZoi.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-lVAZCtUB.js → Logs-BenAU2W8.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-7agE3Or1.js +1 -0
  40. package/src/assets/web-panel/assets/MarkdownRenderer-DbzhFwvz.css +1 -0
  41. package/src/assets/web-panel/assets/Marketplace-D4Jn5fpD.js +1 -0
  42. package/src/assets/web-panel/assets/{McpTools-CqjzefRU.js → McpTools-DtAwoqiQ.js} +4 -4
  43. package/src/assets/web-panel/assets/{Memory-BFiPAxk6.js → Memory-BI_O50I8.js} +2 -2
  44. package/src/assets/web-panel/assets/{MobileBridge-D0O43VwF.js → MobileBridge-CQWE2lqx.js} +1 -1
  45. package/src/assets/web-panel/assets/{MobileProjects-B3now48t.js → MobileProjects-CVtTqgtg.js} +1 -1
  46. package/src/assets/web-panel/assets/{Mtc-DybhtaCS.js → Mtc-Dnr16qsn.js} +2 -2
  47. package/src/assets/web-panel/assets/{MtcAudit-D7MmY4F0.js → MtcAudit-CQ5Xe4-a.js} +5 -5
  48. package/src/assets/web-panel/assets/{Multisig-wZvGJnB8.js → Multisig-Bjr8O-wy.js} +3 -3
  49. package/src/assets/web-panel/assets/{NLProgramming-BNPpgfvn.js → NLProgramming-CEe-KirU.js} +1 -1
  50. package/src/assets/web-panel/assets/{Notes-B6FS3KBj.js → Notes-spKJIKF9.js} +4 -4
  51. package/src/assets/web-panel/assets/{NotificationSettings-CK0yla9U.js → NotificationSettings-DRp83LFG.js} +1 -1
  52. package/src/assets/web-panel/assets/OrderTableRenderer-h1A0XB2a.js +1 -0
  53. package/src/assets/web-panel/assets/{Organization-geqgwN1T.js → Organization-BlgB0IYg.js} +4 -4
  54. package/src/assets/web-panel/assets/{Overflow-BWJYZFbC.js → Overflow-a_35HqZI.js} +1 -1
  55. package/src/assets/web-panel/assets/{P2P-DnU1505F.js → P2P-CSNHCNPC.js} +2 -2
  56. package/src/assets/web-panel/assets/{PdhVaultBrowser-BGY74KnC.js → PdhVaultBrowser-C8M1JH-1.js} +5 -5
  57. package/src/assets/web-panel/assets/{Permissions-CgArrWtQ.js → Permissions-DmjJi9Ms.js} +4 -4
  58. package/src/assets/web-panel/assets/{PersonalDataHub-C2vYE61a.js → PersonalDataHub-DfuwRyf4.js} +2 -2
  59. package/src/assets/web-panel/assets/{Pipeline-CBYLI4yW.js → Pipeline-B2-S4ekE.js} +1 -1
  60. package/src/assets/web-panel/assets/{Privacy-B-PdW9aN.js → Privacy-B1dOiBLC.js} +1 -1
  61. package/src/assets/web-panel/assets/{ProjectInit-CuWQegbV.js → ProjectInit-_pNmc-DX.js} +2 -2
  62. package/src/assets/web-panel/assets/{ProjectSettings-4d32m_cS.js → ProjectSettings-DmwG2Ii1.js} +2 -2
  63. package/src/assets/web-panel/assets/{Projects-VLA7ttwd.js → Projects-COATmHxF.js} +1 -1
  64. package/src/assets/web-panel/assets/{Providers-B_Izb_oa.js → Providers-C6HSjg1d.js} +1 -1
  65. package/src/assets/web-panel/assets/{QrScannerModal-C6B_ndXV.js → QrScannerModal-CrDmS7l1.js} +1 -1
  66. package/src/assets/web-panel/assets/{QuickAsk-C6tavL-y.js → QuickAsk-CfKvWt-x.js} +1 -1
  67. package/src/assets/web-panel/assets/{Recommend-CF-LaZ6x.js → Recommend-DMa6Kuzv.js} +1 -1
  68. package/src/assets/web-panel/assets/RemoteSession-DrktUo5x.js +4 -0
  69. package/src/assets/web-panel/assets/Reputation-BTPQ1vjL.js +1 -0
  70. package/src/assets/web-panel/assets/{Row-DO0fd48A.js → Row-B6Q7QkMG.js} +1 -1
  71. package/src/assets/web-panel/assets/{RssFeed-BV5LDzFR.js → RssFeed-B1IJhAmX.js} +3 -3
  72. package/src/assets/web-panel/assets/Search-xbea1kGD.js +1 -0
  73. package/src/assets/web-panel/assets/{Security-DwSrWRCw.js → Security-7rs0cO3F.js} +4 -4
  74. package/src/assets/web-panel/assets/{Services-BEf1QyM4.js → Services-0fjixK0S.js} +2 -2
  75. package/src/assets/web-panel/assets/{Skeleton-LZXTpovy.js → Skeleton-B_rVq9Cu.js} +1 -1
  76. package/src/assets/web-panel/assets/{Skills-SKgc0Zug.js → Skills-C5uM90b9.js} +1 -1
  77. package/src/assets/web-panel/assets/{Sla-C_QVOtkN.js → Sla-U4pYCIZH.js} +1 -1
  78. package/src/assets/web-panel/assets/{SpeechSettings-v5TW2V-X.js → SpeechSettings-Cdz4yTWx.js} +1 -1
  79. package/src/assets/web-panel/assets/{SyncSettings-CQPjHdqU.js → SyncSettings-Me3aetHv.js} +2 -2
  80. package/src/assets/web-panel/assets/{Tasks-DCd-uYcI.js → Tasks-Cf6aNkL_.js} +1 -1
  81. package/src/assets/web-panel/assets/{Templates-62VDIjtj.js → Templates-CYatk4tU.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tenant-BnFQ0pNy.js → Tenant-DIMKLw7o.js} +1 -1
  83. package/src/assets/web-panel/assets/{Terminal-D3v0MGSj.js → Terminal-C_cp-uSJ.js} +2 -2
  84. package/src/assets/web-panel/assets/{TimelineRenderer-BI1Ka-cu.js → TimelineRenderer-cUPVNADp.js} +1 -1
  85. package/src/assets/web-panel/assets/{Tokens-BwX1jXYP.js → Tokens-CiaEIXVf.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trigger-CSA8TqNx.js → Trigger-DB1WU5lQ.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trust-Bn3IjCx7.js → Trust-Cfht9Ijy.js} +1 -1
  88. package/src/assets/web-panel/assets/{UkeySign-pUbOAqNi.js → UkeySign-K3P4Vt9S.js} +1 -1
  89. package/src/assets/web-panel/assets/{VideoEditing-Db2RercF.js → VideoEditing-DWjhjXRh.js} +1 -1
  90. package/src/assets/web-panel/assets/{Wallet-CpR1BVAl.js → Wallet-D9-Q1Kan.js} +4 -4
  91. package/src/assets/web-panel/assets/{WebAuthn-Yxtkn7Zp.js → WebAuthn-BDszy-oV.js} +5 -5
  92. package/src/assets/web-panel/assets/{WorkflowEditor-CYLe9a2E.js → WorkflowEditor-DIhij4rA.js} +1 -1
  93. package/src/assets/web-panel/assets/{chat-gsOGdak0.js → chat-D7VCiKbh.js} +1 -1
  94. package/src/assets/web-panel/assets/{colors-D9fN299a.js → colors-BvOd9pVn.js} +1 -1
  95. package/src/assets/web-panel/assets/{compact-item-vkd7s-ay.js → compact-item-DoqXBiAO.js} +1 -1
  96. package/src/assets/web-panel/assets/{createContext-C7YkbMyy.js → createContext-CrKRzUtp.js} +1 -1
  97. package/src/assets/web-panel/assets/devWarning-nDB--2xr.js +1 -0
  98. package/src/assets/web-panel/assets/{hasIn-ig7reRSU.js → hasIn-BWAev4WC.js} +1 -1
  99. package/src/assets/web-panel/assets/{icons-DEmcnxBf.js → icons-DG5UD-6K.js} +4 -4
  100. package/src/assets/web-panel/assets/{index-W52sHRdr.js → index-1poMpMU0.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DZAxCnjS.js → index-8g5TJCZ3.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-9TxdMYju.js → index-B0vGEbJT.js} +1 -1
  103. package/src/assets/web-panel/assets/index-B1_pRTtB.js +1 -0
  104. package/src/assets/web-panel/assets/{index-DhdXbsXX.js → index-B30NvR21.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B7QRpKif.js → index-BCyP071m.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Bt-9ZhIu.js → index-BHOcVYrx.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BYe9HRSt.js → index-BN9m4Ux2.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BkP17Z95.js → index-BWWsaimP.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CDWTycrg.js → index-BXyl8O23.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CspGymmg.js → index-BZGk8AbZ.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DFfxF7Vt.js → index-Bf9YlbDn.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DQ8U7kzC.js → index-Bj7EgmOp.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-D2yhtk6a.js → index-BkgnGX7v.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-FzGr6CVk.js → index-BoYrS_L2.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BMw48d19.js → index-Bq_ctRpz.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CAkz1f1r.js → index-C5kRmj3P.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-SDrcQXO1.js → index-CDGLdn12.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-gj8kxcAi.js → index-CEPHMSih.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-PkH39qsp.js → index-CEXfKSiI.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BHHN_KTS.js → index-CSb-tnIo.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-gpurplyq.js → index-CmJ6xKBO.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BfpVcXKa.js → index-CoD31Ndm.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CGzGe5tv.js → index-Cx7M7PSF.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BhftELHI.js → index-D23L1V76.js} +3 -3
  125. package/src/assets/web-panel/assets/{index-DPguq3X7.js → index-DV-Rfmfx.js} +4 -4
  126. package/src/assets/web-panel/assets/{index-BpGlLbRv.js → index-DlGu7As6.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-C8HZMygt.js → index-DvDOpsJB.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DuwbKHoS.js → index-HwHdTusY.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C7AY39sg.js → index-ISvPZ05r.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-nX8YE6cj.js → index-JzUmJMvn.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DvCJXmrx.js → index-KR1-Em9C.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Co2NYyew.js → index-PDxGjKRu.js} +1 -1
  133. package/src/assets/web-panel/assets/index-TMM9FuW-.js +1 -0
  134. package/src/assets/web-panel/assets/{index-D6s_kbjt.js → index-YGDy7nNq.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-Dy_TKZ9h.js → index-gmxqu5Kk.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DFM1oNe1.js → index-oY45XrkG.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-bVbgYBhv.js → index-ww1QtLnX.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-BvDEukXe.js → index-zH-tuuGZ.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-BrgfVRg9.js → initDefaultProps-XW-OR3mL.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-D_3xmwac.js → motion-CeuEHh20.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-DDDJdlxw.js → move-Dva79Keg.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-BK2uEWwn.js → mtc-parser-C0B6bD2j.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-BPHKbDcf.js → omit-AkZvO-a2.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-LNnTscuz.js → pickAttrs-B4r55qGc.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-CvmTZll5.js → placementArrow-BLH-z7YE.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-eBj7qi2J.js → responsiveObserve-ksEGZ2Wf.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-D68hHkrM.js → slide-Cth4OD1Z.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-daTlaeo0.js → statusUtils-9S83ezxw.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-DtyKMtHB.js → styleChecker-7yQmQGZ4.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-ekFwFs9h.js → useFlexGapSupport-DpGnMmPc.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-jRaSEoF4.js → useFs-C4zDZIXH.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-DD5nGzjA.js → usePersonalDataHub-CoLICdUZ.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-KcgLUiom.js → vnode-CKyH-35X.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-Cyk2PQ-s.js → zoom-DRDGit17.js} +1 -1
  155. package/src/assets/web-panel/index.html +2 -2
  156. package/src/command-manifest.json +8 -1
  157. package/src/commands/agent.js +49 -5
  158. package/src/commands/artifacts.js +161 -0
  159. package/src/commands/browse.js +204 -2
  160. package/src/data/changelog.json +13 -2
  161. package/src/gateways/ws/artifact-protocol.js +219 -0
  162. package/src/gateways/ws/message-dispatcher.js +6 -0
  163. package/src/gateways/ws/ws-server.js +32 -0
  164. package/src/index.js +6 -0
  165. package/src/lib/accessibility.js +55 -0
  166. package/src/lib/artifact-store.js +236 -0
  167. package/src/lib/chrome-connector.js +349 -0
  168. package/src/lib/hook-runner.cjs +47 -7
  169. package/src/lib/ide-context.js +84 -0
  170. package/src/lib/permission-rules.cjs +26 -3
  171. package/src/lib/plugin-runtime/scopes.js +12 -0
  172. package/src/lib/remote-control.js +35 -0
  173. package/src/lib/safe-mode.js +40 -0
  174. package/src/lib/shell-selector.cjs +203 -0
  175. package/src/lib/skill-loader.js +19 -0
  176. package/src/lib/slash-dispatch.js +34 -0
  177. package/src/lib/web-ui-server.js +120 -7
  178. package/src/repl/agent-repl.js +330 -116
  179. package/src/repl/remote-approval.js +111 -0
  180. package/src/runtime/agent-core.js +129 -8
  181. package/src/runtime/coding-agent-contract-shared.cjs +105 -0
  182. package/src/runtime/coding-agent-policy.cjs +31 -0
  183. package/src/runtime/headless-stream.js +51 -1
  184. package/src/runtime/policies/agent-policy.js +4 -0
  185. package/src/assets/web-panel/assets/AppLayout-CfyZNzmJ.js +0 -9
  186. package/src/assets/web-panel/assets/Chat-DDh58PCf.css +0 -1
  187. package/src/assets/web-panel/assets/Inference-ujD2JSKo.js +0 -1
  188. package/src/assets/web-panel/assets/Marketplace-qnzNPm-A.js +0 -1
  189. package/src/assets/web-panel/assets/OrderTableRenderer-CXfPHIpy.js +0 -1
  190. package/src/assets/web-panel/assets/RemoteSession-DBqTTQ9_.js +0 -4
  191. package/src/assets/web-panel/assets/Reputation-B01FALUi.js +0 -1
  192. package/src/assets/web-panel/assets/Search-CTti4_MP.js +0 -1
  193. package/src/assets/web-panel/assets/devWarning-DEcR2h6k.js +0 -1
  194. package/src/assets/web-panel/assets/index-BEibanjg.js +0 -1
  195. package/src/assets/web-panel/assets/index-z_25tU3p.js +0 -1
@@ -43,3 +43,43 @@ export function safeModeRequested(opts = {}, env = process.env) {
43
43
  const raw = env.CC_SAFE_MODE || env.CLAUDE_CODE_SAFE_MODE;
44
44
  return raw != null && /^(1|true|yes|on)$/i.test(String(raw).trim());
45
45
  }
46
+
47
+ /**
48
+ * `cc agent --bare` — everything --safe-mode disables PLUS skills, plugins and
49
+ * MCP auto-connect: a minimal, fast agent surface for scripted invocations.
50
+ * The two extra env switches are consumed at the single chokepoints all
51
+ * loading funnels through (skill-loader `loadAll`, plugin-runtime
52
+ * `discoverPlugins`); MCP/IDE/PDH/JetBrains auto-connect are flipped off on
53
+ * the parsed options by the agent command itself (an explicit --mcp-config
54
+ * still loads — bare kills ambient auto-connects, not explicit input).
55
+ * Permission rules stay active, same as safe mode.
56
+ */
57
+ export const BARE_MODE_EXTRA_SWITCHES = Object.freeze({
58
+ CC_SKILLS: "0", // every skill layer (list_skills/run_skill surface empties)
59
+ CC_PLUGINS: "0", // plugin runtime (hooks/monitors/MCP/LSP/bin/env/skills/agents)
60
+ });
61
+
62
+ /**
63
+ * Apply bare mode to an env: all safe-mode switches + the bare extras.
64
+ * @returns {string[]} the switch names applied (for the startup notice)
65
+ */
66
+ export function applyBareMode(env = process.env) {
67
+ const applied = applySafeMode(env);
68
+ for (const [k, v] of Object.entries(BARE_MODE_EXTRA_SWITCHES)) {
69
+ env[k] = v;
70
+ }
71
+ return [...applied, ...Object.keys(BARE_MODE_EXTRA_SWITCHES)];
72
+ }
73
+
74
+ /**
75
+ * Whether bare mode is requested — the explicit `--bare` flag or the ambient
76
+ * `CC_BARE` env var (truthy values: 1 / true / yes / on).
77
+ * @param {{ bare?: boolean }} [opts]
78
+ * @param {object} [env=process.env]
79
+ * @returns {boolean}
80
+ */
81
+ export function bareModeRequested(opts = {}, env = process.env) {
82
+ if (opts && opts.bare === true) return true;
83
+ const raw = env.CC_BARE;
84
+ return raw != null && /^(1|true|yes|on)$/i.test(String(raw).trim());
85
+ }
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * shell-selector — Windows / PowerShell first-class shell selection
5
+ * (gap-analysis P1 #8).
6
+ *
7
+ * Decides WHICH shell a `run_shell` command (or a settings hook with a
8
+ * `shell` field) executes under:
9
+ *
10
+ * - per-call: run_shell `{ shell: "powershell" | "pwsh" | "cmd" | "default" }`
11
+ * - configured: settings `shell.windowsDefault` ("cmd" | "powershell" | "pwsh",
12
+ * layered .claude/settings.json, closest wins) or the
13
+ * CC_WINDOWS_SHELL env var (wins over settings)
14
+ * - default: unchanged platform default (cmd.exe via ComSpec on Windows,
15
+ * /bin/sh elsewhere) — the unconfigured path is byte-identical.
16
+ *
17
+ * PowerShell runs go through explicit argv (`powershell.exe -NoProfile
18
+ * [-ExecutionPolicy <p>] -Command <command>`), NOT `shell: "powershell.exe"`,
19
+ * so the enterprise ExecutionPolicy override (settings
20
+ * `shell.powershell.executionPolicy`) can be applied per-invocation without
21
+ * touching machine state. The policy value is validated against the fixed
22
+ * PowerShell enum — a settings typo can NOT smuggle extra argv.
23
+ *
24
+ * Scope notes:
25
+ * - `windowsDefault` only applies on win32 (hence the name). A per-call
26
+ * `pwsh` request is honored on any platform (PowerShell 7 is
27
+ * cross-platform); `powershell`/`cmd` requests outside Windows fall back
28
+ * to the platform default with a note.
29
+ * - `-ExecutionPolicy` is only attached on win32 (POSIX pwsh has no policy).
30
+ * - Hooks opt in per-hook via `{ "shell": "powershell" }` — the configured
31
+ * windowsDefault deliberately does NOT rewrite existing hooks.
32
+ */
33
+
34
+ const settingsLoader = require("./settings-loader.cjs");
35
+
36
+ const SHELL_KINDS = Object.freeze(["default", "cmd", "powershell", "pwsh"]);
37
+
38
+ /** The fixed PowerShell ExecutionPolicy enum (canonical casing). */
39
+ const EXECUTION_POLICIES = Object.freeze([
40
+ "Restricted",
41
+ "AllSigned",
42
+ "RemoteSigned",
43
+ "Unrestricted",
44
+ "Bypass",
45
+ "Undefined",
46
+ ]);
47
+
48
+ /** Normalize a shell kind; unknown/empty → null (fail to default). */
49
+ function normalizeShellKind(value) {
50
+ if (typeof value !== "string") return null;
51
+ const v = value.trim().toLowerCase();
52
+ if (v === "powershell.exe" || v === "windowspowershell") return "powershell";
53
+ if (v === "pwsh.exe") return "pwsh";
54
+ if (v === "cmd.exe") return "cmd";
55
+ return SHELL_KINDS.includes(v) ? v : null;
56
+ }
57
+
58
+ /** Normalize an ExecutionPolicy to canonical casing; unknown → null. */
59
+ function normalizeExecutionPolicy(value) {
60
+ if (typeof value !== "string") return null;
61
+ const v = value.trim().toLowerCase();
62
+ return EXECUTION_POLICIES.find((p) => p.toLowerCase() === v) || null;
63
+ }
64
+
65
+ /**
66
+ * Layered `shell` settings: `{ windowsDefault, powershell: { executionPolicy } }`.
67
+ * Closest layer wins per key; invalid values are ignored (fail-to-default).
68
+ * CC_WINDOWS_SHELL env overrides the settings-provided windowsDefault.
69
+ *
70
+ * @param {{ cwd?: string, env?: object, settingsFile?: string, onWarn?: Function }} [opts]
71
+ * @returns {{ windowsDefault: string|null, executionPolicy: string|null, files: string[] }}
72
+ */
73
+ // Per-process memo: run_shell resolves the config on EVERY call, and the
74
+ // layered settings walk is filesystem I/O. A short TTL keeps mid-session
75
+ // settings edits honored without re-reading per tool call.
76
+ const _configCache = new Map(); // key → { at, value }
77
+ const CONFIG_CACHE_TTL_MS = 3000;
78
+
79
+ function loadShellConfig(opts = {}) {
80
+ const cwd = opts.cwd || process.cwd();
81
+ const env = opts.env || process.env;
82
+ const cacheable = !opts.env && !opts.onWarn;
83
+ const cacheKey = cacheable ? `${cwd}|${opts.settingsFile || ""}` : null;
84
+ if (cacheKey) {
85
+ const hit = _configCache.get(cacheKey);
86
+ if (hit && Date.now() - hit.at < CONFIG_CACHE_TTL_MS) return hit.value;
87
+ }
88
+ let windowsDefault = null;
89
+ let executionPolicy = null;
90
+ const files = [];
91
+ try {
92
+ for (const file of settingsLoader.settingsPaths(cwd, opts.settingsFile)) {
93
+ const data = settingsLoader.readSettingsFile(file, {
94
+ onWarn: opts.onWarn,
95
+ });
96
+ const shell = data && typeof data === "object" ? data.shell : null;
97
+ if (!shell || typeof shell !== "object" || Array.isArray(shell)) continue;
98
+ const kind = normalizeShellKind(shell.windowsDefault);
99
+ if (kind) windowsDefault = kind;
100
+ const pol = normalizeExecutionPolicy(shell.powershell?.executionPolicy);
101
+ if (pol) executionPolicy = pol;
102
+ files.push(file);
103
+ }
104
+ } catch {
105
+ /* settings are best-effort — never fail shell resolution over them */
106
+ }
107
+ const envKind = normalizeShellKind(env.CC_WINDOWS_SHELL);
108
+ if (envKind) windowsDefault = envKind;
109
+ const value = { windowsDefault, executionPolicy, files };
110
+ if (cacheKey) _configCache.set(cacheKey, { at: Date.now(), value });
111
+ return value;
112
+ }
113
+
114
+ /** Test hook: drop the config memo. */
115
+ function _clearShellConfigCache() {
116
+ _configCache.clear();
117
+ }
118
+
119
+ /**
120
+ * Build the explicit argv for a PowerShell invocation of `command`.
121
+ * @param {string} command
122
+ * @param {"powershell"|"pwsh"} kind
123
+ * @param {{ executionPolicy?: string|null, platform?: string }} [opts]
124
+ * @returns {{ file: string, argv: string[] }}
125
+ */
126
+ function buildPowershellArgv(command, kind, opts = {}) {
127
+ const platform = opts.platform || process.platform;
128
+ const file = kind === "pwsh" ? "pwsh" : "powershell.exe";
129
+ const policy =
130
+ platform === "win32"
131
+ ? normalizeExecutionPolicy(opts.executionPolicy)
132
+ : null;
133
+ return {
134
+ file,
135
+ argv: [
136
+ "-NoProfile",
137
+ ...(policy ? ["-ExecutionPolicy", policy] : []),
138
+ "-Command",
139
+ String(command ?? ""),
140
+ ],
141
+ };
142
+ }
143
+
144
+ /**
145
+ * Resolve how to run one shell command.
146
+ *
147
+ * Precedence: per-call `requested` > configured windowsDefault (win32 only)
148
+ * > platform default. Returns either the default-shell marker (caller keeps
149
+ * its existing exec/spawn `shell: true` path — byte-identical) or an explicit
150
+ * `{ file, argv }` PowerShell invocation.
151
+ *
152
+ * @param {{ command: string, requested?: string, cwd?: string, env?: object,
153
+ * platform?: string, settingsFile?: string,
154
+ * config?: { windowsDefault?: string|null, executionPolicy?: string|null } }} opts
155
+ * @returns {{ kind: string, useDefaultShell: boolean, file?: string,
156
+ * argv?: string[], note?: string }}
157
+ */
158
+ function resolveShellInvocation(opts = {}) {
159
+ const platform = opts.platform || process.platform;
160
+ const config = opts.config || loadShellConfig(opts);
161
+ const requested = normalizeShellKind(opts.requested);
162
+ let kind =
163
+ requested ||
164
+ (platform === "win32" ? config.windowsDefault : null) ||
165
+ "default";
166
+ let note;
167
+
168
+ if (kind === "cmd") {
169
+ if (platform === "win32") {
170
+ // cmd IS the Windows default shell — take the untouched default path so
171
+ // an explicit `shell:"cmd"` opt-out of a PowerShell windowsDefault stays
172
+ // byte-identical to the historical behavior.
173
+ return { kind: "cmd", useDefaultShell: true };
174
+ }
175
+ note = "cmd is Windows-only; using the platform default shell";
176
+ return { kind: "default", useDefaultShell: true, note };
177
+ }
178
+ if (kind === "powershell" && platform !== "win32") {
179
+ // Windows PowerShell 5.1 doesn't exist off-Windows; pwsh might.
180
+ note =
181
+ "powershell (5.1) is Windows-only; using the platform default shell (request pwsh for PowerShell 7)";
182
+ return { kind: "default", useDefaultShell: true, note };
183
+ }
184
+ if (kind === "powershell" || kind === "pwsh") {
185
+ const { file, argv } = buildPowershellArgv(opts.command, kind, {
186
+ executionPolicy: config.executionPolicy,
187
+ platform,
188
+ });
189
+ return { kind, useDefaultShell: false, file, argv };
190
+ }
191
+ return { kind: "default", useDefaultShell: true };
192
+ }
193
+
194
+ module.exports = {
195
+ SHELL_KINDS,
196
+ EXECUTION_POLICIES,
197
+ normalizeShellKind,
198
+ normalizeExecutionPolicy,
199
+ loadShellConfig,
200
+ buildPowershellArgv,
201
+ resolveShellInvocation,
202
+ _clearShellConfigCache,
203
+ };
@@ -68,6 +68,19 @@ export function bundledSkillsDisabled(opts = {}) {
68
68
  }
69
69
  }
70
70
 
71
+ /**
72
+ * Whether ALL skill layers are disabled — `cc agent --bare` sets CC_SKILLS=0
73
+ * (safe-mode "feature=0 disables" convention). Single gate: `loadAll` is the
74
+ * one place every layer funnels through, so this empties list_skills /
75
+ * run_skill / persona auto-activation in one check.
76
+ * @param {{ env?: object }} [opts]
77
+ * @returns {boolean}
78
+ */
79
+ export function allSkillsDisabled(opts = {}) {
80
+ const raw = (opts.env || process.env).CC_SKILLS;
81
+ return raw != null && /^(0|false|no|off)$/i.test(String(raw).trim());
82
+ }
83
+
71
84
  /** Layer names in priority order (lowest → highest) */
72
85
  export const LAYER_NAMES = [
73
86
  "bundled",
@@ -475,6 +488,12 @@ export class CLISkillLoader {
475
488
  * @returns {object[]} Resolved skill list
476
489
  */
477
490
  loadAll(options = {}) {
491
+ // `cc agent --bare` (CC_SKILLS=0): no skill layer loads at all — cache the
492
+ // empty result so getResolvedSkills stays cheap on every call.
493
+ if (allSkillsDisabled(options)) {
494
+ this._cache = [];
495
+ return this._cache;
496
+ }
478
497
  const layers = this.getLayerPaths();
479
498
  const skillMap = new Map();
480
499
  // Claude-Code `disableBundledSkills`: hide the built-in layer so only
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `cc agent --disable-slash-commands` — REPL slash-dispatch bypass predicate.
3
+ *
4
+ * When active, a "/"-leading line is NOT dispatched to the built-in slash
5
+ * handlers (nor custom .claude/commands macros nor MCP prompt expansion): it
6
+ * reaches the model verbatim, the same fall-through an unmatched slash line
7
+ * already takes. `/exit` and `/quit` stay live so the session remains
8
+ * closable from the keyboard.
9
+ *
10
+ * The REPL swaps the dispatched string for a sentinel no handler can match
11
+ * (leading NUL — nothing in the dispatch chain starts with a control char)
12
+ * and restores the user's real text for the model turn.
13
+ */
14
+
15
+ /** The dispatch sentinel — starts with NUL so no handler branch matches. */
16
+ export function slashBypassSentinel() {
17
+ return String.fromCharCode(0) + "slash-bypassed";
18
+ }
19
+
20
+ /**
21
+ * Should this line bypass slash dispatch?
22
+ * @param {string} line the trimmed input line
23
+ * @param {boolean} disabled whether --disable-slash-commands is active
24
+ * @returns {boolean}
25
+ */
26
+ export function slashDispatchBypassed(line, disabled) {
27
+ return (
28
+ disabled === true &&
29
+ typeof line === "string" &&
30
+ line.startsWith("/") &&
31
+ line !== "/exit" &&
32
+ line !== "/quit"
33
+ );
34
+ }
@@ -19,6 +19,7 @@
19
19
  import http from "http";
20
20
  import fs from "fs";
21
21
  import path from "path";
22
+ import crypto from "crypto";
22
23
  import { fileURLToPath } from "url";
23
24
  import { getInlineSource as getEnvelopeInlineSource } from "./web-ui-envelope.js";
24
25
  import { CLISkillLoader } from "./skill-loader.js";
@@ -1224,28 +1225,140 @@ function findWebPanelDist(staticDir) {
1224
1225
  return null;
1225
1226
  }
1226
1227
 
1228
+ /** Constant-time token check (same construction as ws-server's): hash both
1229
+ * sides to a fixed length so length differences don't leak, then compare in
1230
+ * constant time. `null`/absent configured token → no auth required. */
1231
+ function downloadTokenOk(configuredToken, req) {
1232
+ if (!configuredToken) return true;
1233
+ let supplied = "";
1234
+ const auth = String(req.headers?.authorization || "");
1235
+ if (auth.toLowerCase().startsWith("bearer ")) {
1236
+ supplied = auth.slice(7).trim();
1237
+ } else {
1238
+ try {
1239
+ supplied =
1240
+ new URL(req.url, "http://localhost").searchParams.get("token") || "";
1241
+ } catch {
1242
+ supplied = "";
1243
+ }
1244
+ }
1245
+ const a = crypto.createHash("sha256").update(String(supplied)).digest();
1246
+ const b = crypto
1247
+ .createHash("sha256")
1248
+ .update(String(configuredToken))
1249
+ .digest();
1250
+ return crypto.timingSafeEqual(a, b);
1251
+ }
1252
+
1253
+ /** RFC 5987 filename* value for a Content-Disposition header. */
1254
+ function encodeDispositionFilename(name) {
1255
+ const base = String(name || "artifact").replace(/[\r\n"]/g, "_");
1256
+ return `attachment; filename*=UTF-8''${encodeURIComponent(base)}`;
1257
+ }
1258
+
1227
1259
  /**
1228
1260
  * Handle `/api/*` routes. Returns `true` if the request was handled (caller
1229
1261
  * must stop further processing) and `false` for everything else (caller
1230
1262
  * continues with the static/SPA handler).
1231
1263
  *
1232
- * Currently exposes a single read-only endpoint:
1264
+ * Endpoints:
1233
1265
  *
1234
1266
  * GET /api/skills → 200 { schema: 1, skills: [{name, source, category,
1235
1267
  * description, version}] }
1268
+ * GET /api/artifacts/<id>/download → the artifact's stored copy as an
1269
+ * attachment (full file — the WS artifact-content preview
1270
+ * route is capped; this is the uncapped download path the
1271
+ * web-panel's 下载 button uses). When the server was
1272
+ * created with a wsToken, the same token must accompany
1273
+ * the request (`Authorization: Bearer` or `?token=`).
1236
1274
  *
1237
- * The smoke-runner's project-mode probe (packer/smoke-runner.js) hits this
1238
- * to verify bundled skills were materialized and registered. The shape is
1239
- * deliberately minimal — the Web UI's richer skill views use WS.
1275
+ * The smoke-runner's project-mode probe (packer/smoke-runner.js) hits
1276
+ * /api/skills to verify bundled skills were materialized and registered. The
1277
+ * shapes are deliberately minimal — the Web UI's richer views use WS.
1240
1278
  *
1241
1279
  * @param {import("http").IncomingMessage} req
1242
1280
  * @param {import("http").ServerResponse} res
1281
+ * @param {{ wsToken?: string|null }} [ctx] server context (auth for downloads)
1243
1282
  * @returns {boolean} true if handled, false if the caller should continue
1244
1283
  */
1245
- export function handleApiRequest(req, res) {
1284
+ export function handleApiRequest(req, res, ctx = {}) {
1246
1285
  const urlPath = req.url.split("?")[0];
1247
1286
  if (!urlPath.startsWith("/api/")) return false;
1248
1287
 
1288
+ const artifactMatch = urlPath.match(
1289
+ /^\/api\/artifacts\/([A-Za-z0-9_]+)\/download$/,
1290
+ );
1291
+ if (artifactMatch) {
1292
+ if (req.method !== "GET") {
1293
+ res.writeHead(405, { "Content-Type": "application/json" });
1294
+ res.end(JSON.stringify({ error: "Method Not Allowed" }));
1295
+ return true;
1296
+ }
1297
+ // The panel authenticates its WS with this token; the download endpoint
1298
+ // serves artifact FILE CONTENT, so it must not be weaker than the WS.
1299
+ if (!downloadTokenOk(ctx.wsToken || null, req)) {
1300
+ res.writeHead(401, { "Content-Type": "application/json" });
1301
+ res.end(JSON.stringify({ error: "Unauthorized" }));
1302
+ return true;
1303
+ }
1304
+ // Async body in a sync router: the route is claimed (return true) and the
1305
+ // response completes when the store import resolves.
1306
+ (async () => {
1307
+ try {
1308
+ const { ArtifactStore } = await import("./artifact-store.js");
1309
+ const store = new ArtifactStore();
1310
+ const entry = store.get(artifactMatch[1]);
1311
+ if (!entry) {
1312
+ res.writeHead(404, { "Content-Type": "application/json" });
1313
+ res.end(JSON.stringify({ error: "Not Found" }));
1314
+ return;
1315
+ }
1316
+ // Same tamper guard as the WS content route: the stored filename must
1317
+ // be a plain basename or the index row is refused.
1318
+ if (
1319
+ !entry.file ||
1320
+ entry.file !== path.basename(entry.file) ||
1321
+ entry.file.includes("..")
1322
+ ) {
1323
+ res.writeHead(400, { "Content-Type": "application/json" });
1324
+ res.end(JSON.stringify({ error: "Bad artifact index row" }));
1325
+ return;
1326
+ }
1327
+ const storedPath = store.storedPath(entry);
1328
+ let size;
1329
+ try {
1330
+ size = fs.statSync(storedPath).size;
1331
+ } catch {
1332
+ res.writeHead(404, { "Content-Type": "application/json" });
1333
+ res.end(JSON.stringify({ error: "Stored copy missing" }));
1334
+ return;
1335
+ }
1336
+ const downloadName =
1337
+ entry.title && path.extname(entry.title)
1338
+ ? entry.title
1339
+ : path.basename(entry.sourcePath || entry.file);
1340
+ res.writeHead(200, {
1341
+ "Content-Type": entry.mime || "application/octet-stream",
1342
+ "Content-Length": size,
1343
+ "Content-Disposition": encodeDispositionFilename(downloadName),
1344
+ "Cache-Control": "no-store",
1345
+ "X-Content-Type-Options": "nosniff",
1346
+ });
1347
+ const stream = fs.createReadStream(storedPath);
1348
+ stream.on("error", () => res.destroy());
1349
+ stream.pipe(res);
1350
+ } catch (err) {
1351
+ try {
1352
+ res.writeHead(500, { "Content-Type": "application/json" });
1353
+ res.end(JSON.stringify({ error: err.message }));
1354
+ } catch {
1355
+ /* headers already sent — connection is torn down by the stream */
1356
+ }
1357
+ }
1358
+ })();
1359
+ return true;
1360
+ }
1361
+
1249
1362
  if (urlPath === "/api/skills") {
1250
1363
  if (req.method !== "GET") {
1251
1364
  res.writeHead(405, { "Content-Type": "application/json" });
@@ -1328,7 +1441,7 @@ export function createWebUIServer(opts) {
1328
1441
  return http.createServer((req, res) => {
1329
1442
  // /api/* routes are handled before the static file logic so GET /api/skills
1330
1443
  // doesn't accidentally resolve to index.html via the SPA fallback.
1331
- if (handleApiRequest(req, res)) return;
1444
+ if (handleApiRequest(req, res, { wsToken: opts.wsToken || null })) return;
1332
1445
 
1333
1446
  if (req.method !== "GET") {
1334
1447
  res.writeHead(405, { "Content-Type": "text/plain" });
@@ -1415,7 +1528,7 @@ export function createWebUIServer(opts) {
1415
1528
  // ── Fallback: embedded classic single-page HTML ─────────────────────────
1416
1529
  const html = buildHtml(opts);
1417
1530
  return http.createServer((req, res) => {
1418
- if (handleApiRequest(req, res)) return;
1531
+ if (handleApiRequest(req, res, { wsToken: opts.wsToken || null })) return;
1419
1532
 
1420
1533
  const urlPath = req.url.split("?")[0];
1421
1534
  if (