chainlesschain 0.162.142 → 0.162.147

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 (192) hide show
  1. package/bin/chainlesschain.js +5 -3
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/assets/{AIOps-Dc6fWgoa.js → AIOps-DywJ7xTv.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-DzMx25vJ.js → ActionButton-BTlqcY-q.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-eDC3KNht.js → Analytics-FdG1Mvwy.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-uA1TOtNp.js → AppLayout-CVsnbvN1.js} +3 -3
  7. package/src/assets/web-panel/assets/{Audit-Bq3QX9Cj.js → Audit-ITdpJ7vR.js} +1 -1
  8. package/src/assets/web-panel/assets/{Backup-B1V3Jfyv.js → Backup-BfXqnXo1.js} +1 -1
  9. package/src/assets/web-panel/assets/{BaseInput-DMFwddIF.js → BaseInput-C09ip3_E.js} +1 -1
  10. package/src/assets/web-panel/assets/{Chat-CKWQDH5j.js → Chat-qdkhB42l.js} +6 -6
  11. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CStSBCnk.js → ChatBubbleRenderer-D2KfETZD.js} +1 -1
  12. package/src/assets/web-panel/assets/{Checkbox-DepIzI7G.js → Checkbox-j6WZCuff.js} +1 -1
  13. package/src/assets/web-panel/assets/{Codegen-ClanWll2.js → Codegen-CGZ-K3uK.js} +1 -1
  14. package/src/assets/web-panel/assets/{Col-CFBzsL4W.js → Col-CIlPOAu6.js} +1 -1
  15. package/src/assets/web-panel/assets/{Community-CaAyZ_Pt.js → Community-sY-i-hic.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compact-3dCHRSVe.js → Compact-DcoEfyL8.js} +1 -1
  17. package/src/assets/web-panel/assets/Compliance-T8EtTecW.js +1 -0
  18. package/src/assets/web-panel/assets/{Cowork-DkJmdQaU.js → Cowork-DLY_fkLv.js} +3 -3
  19. package/src/assets/web-panel/assets/{Cron-DKfNf6J2.js → Cron-D049pZBC.js} +2 -2
  20. package/src/assets/web-panel/assets/{Crosschain-COu1aQIO.js → Crosschain-DCXdE8M9.js} +1 -1
  21. package/src/assets/web-panel/assets/{DID-CkAgFLkI.js → DID-JCvPZtjW.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dashboard-CfaKWZCU.js → Dashboard-Cg2xu3iE.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dropdown-Cjw97sdb.js → Dropdown-DjJLjbLh.js} +1 -1
  24. package/src/assets/web-panel/assets/{EmailListRenderer-DROLQgOn.js → EmailListRenderer-DugNcSLR.js} +1 -1
  25. package/src/assets/web-panel/assets/{FamilyGuardDashboard-o_cYzlLq.js → FamilyGuardDashboard-J6Nb-E30.js} +1 -1
  26. package/src/assets/web-panel/assets/{Federation-Boex3ljt.js → Federation-CQ3Ttpbl.js} +1 -1
  27. package/src/assets/web-panel/assets/{FormItemContext-BQQ05T_3.js → FormItemContext-Cz0NKag4.js} +1 -1
  28. package/src/assets/web-panel/assets/{GenericCardRenderer-CdfL8PBd.js → GenericCardRenderer-NYcMP6iz.js} +1 -1
  29. package/src/assets/web-panel/assets/{Git-CfZ07qJy.js → Git-B4hYN18N.js} +2 -2
  30. package/src/assets/web-panel/assets/{Governance-B21ISudq.js → Governance-DOQPCcC0.js} +1 -1
  31. package/src/assets/web-panel/assets/{Inference-CGIK4Im1.js → Inference-HtLF746W.js} +1 -1
  32. package/src/assets/web-panel/assets/{KnowledgeGraph-CI1kmfdT.js → KnowledgeGraph-BXrk8rMm.js} +1 -1
  33. package/src/assets/web-panel/assets/{Logs-Dpc1-__h.js → Logs-DS0JnD3-.js} +2 -2
  34. package/src/assets/web-panel/assets/{Marketplace-BpMtMWyK.js → Marketplace-Cqnjihrz.js} +1 -1
  35. package/src/assets/web-panel/assets/{McpTools-B94WvOOS.js → McpTools-Cx3Psk-U.js} +5 -5
  36. package/src/assets/web-panel/assets/{Memory-DODsAxZf.js → Memory-BjyysPtj.js} +2 -2
  37. package/src/assets/web-panel/assets/{MobileBridge-C3Bjshem.js → MobileBridge-CYaITZ7w.js} +1 -1
  38. package/src/assets/web-panel/assets/{MobileProjects-Bi8IHDv_.js → MobileProjects-Xwf-fdOQ.js} +1 -1
  39. package/src/assets/web-panel/assets/{Mtc-CH5BSuWG.js → Mtc-Djkql5m5.js} +2 -2
  40. package/src/assets/web-panel/assets/{MtcAudit-DN3MzNtL.js → MtcAudit-D2BAZlu0.js} +2 -2
  41. package/src/assets/web-panel/assets/{Multisig-CO6GWQOh.js → Multisig-ByqP1ZzH.js} +3 -3
  42. package/src/assets/web-panel/assets/{NLProgramming-DhIr3V_u.js → NLProgramming-C_kn0nE2.js} +1 -1
  43. package/src/assets/web-panel/assets/{Notes-CNgrvZCJ.js → Notes-7l7eXHPq.js} +3 -3
  44. package/src/assets/web-panel/assets/{NotificationSettings-Crr4LPjQ.js → NotificationSettings-BrCDoitw.js} +1 -1
  45. package/src/assets/web-panel/assets/{OrderTableRenderer-C8q-kK2z.js → OrderTableRenderer-CmtqIdwr.js} +1 -1
  46. package/src/assets/web-panel/assets/{Organization-hWhCmeUn.js → Organization-DdoNAxsM.js} +4 -4
  47. package/src/assets/web-panel/assets/{Overflow-t_EBxns-.js → Overflow-Bw7R6dE3.js} +1 -1
  48. package/src/assets/web-panel/assets/{P2P-B8fqfwis.js → P2P-DJNtBugA.js} +2 -2
  49. package/src/assets/web-panel/assets/{PdhVaultBrowser-d-wlJw3R.js → PdhVaultBrowser-Dwhd5_ue.js} +3 -3
  50. package/src/assets/web-panel/assets/{Permissions-Ch13YpBo.js → Permissions-BYoSfhPR.js} +4 -4
  51. package/src/assets/web-panel/assets/{PersonalDataHub-DW7LlLbS.js → PersonalDataHub-aYCYJbnH.js} +2 -2
  52. package/src/assets/web-panel/assets/{Pipeline-BHh3HqOQ.js → Pipeline-DJp6CprF.js} +1 -1
  53. package/src/assets/web-panel/assets/{Privacy-DAhlJDSC.js → Privacy-Cq9HZweR.js} +1 -1
  54. package/src/assets/web-panel/assets/{ProjectInit-BRtddAM_.js → ProjectInit-CmF0HsSt.js} +2 -2
  55. package/src/assets/web-panel/assets/{ProjectSettings-CzR1EC7b.js → ProjectSettings-P8V5Aea2.js} +2 -2
  56. package/src/assets/web-panel/assets/{Projects-DSavX602.js → Projects-DPd5-lNS.js} +1 -1
  57. package/src/assets/web-panel/assets/{Providers-D55_kGZs.js → Providers-D589v0q2.js} +1 -1
  58. package/src/assets/web-panel/assets/{QuickAsk-BR5qDIaT.js → QuickAsk-lvRV2osB.js} +1 -1
  59. package/src/assets/web-panel/assets/{Recommend-CTFAM97K.js → Recommend-sb84MTpY.js} +1 -1
  60. package/src/assets/web-panel/assets/{Reputation-Z7pvEha9.js → Reputation-d9Y3vy-W.js} +1 -1
  61. package/src/assets/web-panel/assets/{Row-MqKcIsjP.js → Row-DMdhLUTp.js} +1 -1
  62. package/src/assets/web-panel/assets/{RssFeed-DdLDjRpk.js → RssFeed-OL-SMDkz.js} +3 -3
  63. package/src/assets/web-panel/assets/{Search-CeOzh2hz.js → Search-BjStLKq1.js} +1 -1
  64. package/src/assets/web-panel/assets/{Security-gHrXaf4o.js → Security-MeI411qr.js} +3 -3
  65. package/src/assets/web-panel/assets/{Services-B8Y7pmY1.js → Services-UajosuhT.js} +2 -2
  66. package/src/assets/web-panel/assets/{Skeleton-CRS0WNut.js → Skeleton-CGpG-QJ1.js} +1 -1
  67. package/src/assets/web-panel/assets/{Skills--a5_Pdxx.js → Skills-C6P2RPY-.js} +1 -1
  68. package/src/assets/web-panel/assets/{Sla-EcTyL6EM.js → Sla-B_fPprgw.js} +1 -1
  69. package/src/assets/web-panel/assets/{SpeechSettings-QpfvOiJr.js → SpeechSettings-CqxLjSlQ.js} +1 -1
  70. package/src/assets/web-panel/assets/{SyncSettings-DaLBBzlE.js → SyncSettings-DixSfFOQ.js} +2 -2
  71. package/src/assets/web-panel/assets/{Tasks-Ca6xvO-I.js → Tasks-PavzPBxc.js} +1 -1
  72. package/src/assets/web-panel/assets/{Templates-CWguiCoE.js → Templates-BYdGRnfX.js} +1 -1
  73. package/src/assets/web-panel/assets/{Tenant-BGLLZulu.js → Tenant-BQLgnarD.js} +1 -1
  74. package/src/assets/web-panel/assets/Terminal-BzOHpq-B.js +3 -0
  75. package/src/assets/web-panel/assets/{TimelineRenderer-CLjvjbmr.js → TimelineRenderer-Bv7uZRM7.js} +1 -1
  76. package/src/assets/web-panel/assets/{Tokens-De5mmw_a.js → Tokens-DxhgszRJ.js} +1 -1
  77. package/src/assets/web-panel/assets/{Trigger-Chbq6U0N.js → Trigger-nQYHayuc.js} +1 -1
  78. package/src/assets/web-panel/assets/{Trust-CYxUO2lv.js → Trust-CvqZDuZ4.js} +1 -1
  79. package/src/assets/web-panel/assets/{UkeySign-iyoZXXF6.js → UkeySign-DaR8GV2I.js} +1 -1
  80. package/src/assets/web-panel/assets/{VideoEditing-CHg3ifJs.js → VideoEditing-C6Mpsokw.js} +1 -1
  81. package/src/assets/web-panel/assets/{Wallet-DfjqObsO.js → Wallet-B57VRrWc.js} +4 -4
  82. package/src/assets/web-panel/assets/{WebAuthn-0FI6xfud.js → WebAuthn-BbtEEtpq.js} +4 -4
  83. package/src/assets/web-panel/assets/{WorkflowEditor-CJgGcctS.js → WorkflowEditor-C5LwvKmH.js} +1 -1
  84. package/src/assets/web-panel/assets/{chat-fH-E4vhY.js → chat-MzuPR5jh.js} +1 -1
  85. package/src/assets/web-panel/assets/{colors-CuxsOD6d.js → colors-HyW8mi_y.js} +1 -1
  86. package/src/assets/web-panel/assets/{compact-item-AfVcFrFU.js → compact-item-DvUSzWAp.js} +1 -1
  87. package/src/assets/web-panel/assets/{createContext-DTsD7sPO.js → createContext-4MppZl7X.js} +1 -1
  88. package/src/assets/web-panel/assets/devWarning-6YJJMjSH.js +1 -0
  89. package/src/assets/web-panel/assets/{hasIn-DJR763M6.js → hasIn-D9q3CJ-u.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-DhM9FZUH.js → index--Bm6OqmU.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-OZwLoscJ.js → index-B5E4DhVc.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-CF8OSTin.js → index-B994UQfE.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-9cryBBzh.js → index-BF2JsbiX.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-BMVULNUC.js → index-BFGfC5RS.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Dj1_lz3M.js → index-BGQtFso0.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DBPAH7rp.js → index-BcunsBIx.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-mLAfJXAf.js → index-Bl-E4W4q.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Cfppli6E.js → index-BmCo2Xdp.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-_hP8-Y2F.js → index-Btz8pU68.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DvlzcX3Q.js → index-C0DiL97c.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CBBStCbO.js → index-C9I5MuJ0.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-SuJ2_OzM.js → index-CLAZs1Vd.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-B8DLT-F4.js → index-Caqtu6Et.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Cm4cHE5_.js → index-CgIfXOD9.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DbQX0Zbf.js → index-Ci6adKh8.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BEGMojUg.js → index-CifKUNtV.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CdV7a6-K.js → index-Cs-RKRUM.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Dswd93W4.js → index-CucRo4Vz.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-D2KdGSMa.js → index-CvAqCAo9.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BqflTl_b.js → index-D2jrnaq3.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Cl7chKuM.js → index-D7TDMMfu.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CAbZ3dW9.js → index-DDZ6fP5Z.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BD4-kWQY.js → index-DFqvWeGc.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DejUsZOw.js → index-DNYqw0MO.js} +1 -1
  115. package/src/assets/web-panel/assets/index-D_oeGLr6.js +1 -0
  116. package/src/assets/web-panel/assets/{index-DH-dA4pG.js → index-DcMkjb92.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CMcYdHhK.js → index-DmZ6-suL.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-85iIi3qF.js → index-Dv7ffI2g.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DJIFQ-Ay.js → index-Dvg5xYuP.js} +1 -1
  120. package/src/assets/web-panel/assets/index-Qa57YG19.js +1 -0
  121. package/src/assets/web-panel/assets/{index-DxD03TL7.js → index-SDblbKj6.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CmUxSTNy.js → index-UUMCA2Sq.js} +3 -3
  123. package/src/assets/web-panel/assets/{index-BJl6Ob-o.js → index-Zvtru2oE.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DPHYW3IK.js → index-eOQO6KnV.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-B-rcowKd.js → index-m0b6Fj9q.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BTtL2Qkb.js → index-ryFLxB1p.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-fj3ZXgiy.js → index-xvUVuFnA.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BbpuFc8C.js → index-zLwYpvX0.js} +1 -1
  129. package/src/assets/web-panel/assets/{initDefaultProps-BGoLJP6T.js → initDefaultProps-CC--PMsC.js} +1 -1
  130. package/src/assets/web-panel/assets/{motion-23xdoVi0.js → motion-DdrBjRF1.js} +1 -1
  131. package/src/assets/web-panel/assets/{move-C3Bnnft-.js → move-D712Gwl2.js} +1 -1
  132. package/src/assets/web-panel/assets/{mtc-parser-Dv0C3a90.js → mtc-parser-39y-keKO.js} +1 -1
  133. package/src/assets/web-panel/assets/{omit-C3r9qzDO.js → omit-6Y51gDB9.js} +1 -1
  134. package/src/assets/web-panel/assets/{pickAttrs-B4bJOcNp.js → pickAttrs-Cy6EHbq9.js} +1 -1
  135. package/src/assets/web-panel/assets/{placementArrow-Dxf48wcO.js → placementArrow-BYxdAm0p.js} +1 -1
  136. package/src/assets/web-panel/assets/{responsiveObserve-Rq9U2hbz.js → responsiveObserve-C9R6q_cr.js} +1 -1
  137. package/src/assets/web-panel/assets/{slide-BeWiqbdF.js → slide-CXUJlilB.js} +1 -1
  138. package/src/assets/web-panel/assets/{statusUtils-yX9N1cEc.js → statusUtils-DOtrOeql.js} +1 -1
  139. package/src/assets/web-panel/assets/{styleChecker-5Ko9NorO.js → styleChecker-D5r39o92.js} +1 -1
  140. package/src/assets/web-panel/assets/{useFlexGapSupport-WKpkTLok.js → useFlexGapSupport-DfAD5U4Z.js} +1 -1
  141. package/src/assets/web-panel/assets/{useFs-BV4X0JOG.js → useFs-BkrT-Zbc.js} +1 -1
  142. package/src/assets/web-panel/assets/{usePersonalDataHub-g41wq_2p.js → usePersonalDataHub-BwnnnZjU.js} +1 -1
  143. package/src/assets/web-panel/assets/{vnode-BAurbOH8.js → vnode-SU-N4pum.js} +1 -1
  144. package/src/assets/web-panel/assets/{zoom-Cl5XniRg.js → zoom-DHScfpTP.js} +1 -1
  145. package/src/assets/web-panel/index.html +1 -1
  146. package/src/auth/npm-auth.js +65 -0
  147. package/src/command-manifest.json +1126 -0
  148. package/src/commands/agent.js +92 -0
  149. package/src/commands/agents.js +68 -0
  150. package/src/commands/note.js +2 -1
  151. package/src/commands/permissions.js +66 -10
  152. package/src/commands/plugin.js +50 -3
  153. package/src/commands/search.js +2 -1
  154. package/src/harness/worktree-isolator.js +14 -7
  155. package/src/index.js +4 -12
  156. package/src/lazy-dispatch.js +107 -0
  157. package/src/lib/agent-sandbox.js +72 -0
  158. package/src/lib/background-agent-supervisor.js +197 -0
  159. package/src/lib/code-review.js +72 -0
  160. package/src/lib/ensure-utf8.js +25 -7
  161. package/src/lib/knowledge-exporter.js +3 -2
  162. package/src/lib/permission-engine.js +1 -1
  163. package/src/lib/plugin-security.js +128 -0
  164. package/src/lib/pr-create.js +108 -0
  165. package/src/lib/publish-workspace.js +107 -0
  166. package/src/lib/resume-session.js +111 -0
  167. package/src/lib/session-manager.js +2 -1
  168. package/src/lib/settings-hooks.cjs +68 -25
  169. package/src/lib/settings-loader.cjs +115 -2
  170. package/src/lib/task-list.js +53 -0
  171. package/src/program-base.js +24 -0
  172. package/src/repl/agent-repl.js +108 -3
  173. package/src/repl/agents-status.js +8 -2
  174. package/src/repl/btw-command.js +56 -0
  175. package/src/repl/chat-repl.js +52 -1
  176. package/src/repl/hooks-status.js +1 -2
  177. package/src/repl/slash-command-registry.js +197 -0
  178. package/src/repl/think-command.js +31 -0
  179. package/src/runtime/agent-core.js +137 -1
  180. package/src/runtime/coding-agent-contract-shared.cjs +37 -0
  181. package/src/runtime/coding-agent-policy.cjs +14 -0
  182. package/src/runtime/file-ref-expander.js +100 -14
  183. package/src/runtime/headless-runner.js +26 -6
  184. package/src/runtime/headless-stream.js +25 -6
  185. package/src/runtime/mcp-config.js +46 -2
  186. package/src/runtime/policies/agent-policy.js +1 -0
  187. package/src/workers/background-agent-worker.js +60 -0
  188. package/src/assets/web-panel/assets/Compliance-BKYHHTdq.js +0 -1
  189. package/src/assets/web-panel/assets/Terminal-Bryzb1Rm.js +0 -3
  190. package/src/assets/web-panel/assets/devWarning-DffbPlEe.js +0 -1
  191. package/src/assets/web-panel/assets/index-BAHgOh3h.js +0 -1
  192. package/src/assets/web-panel/assets/index-zfkDb9FC.js +0 -1
@@ -16,6 +16,7 @@ import {
16
16
  } from "../runtime/fallback-model.js";
17
17
  import { resolveImages, resolveVisionLlm } from "../lib/image-input.js";
18
18
  import { loadConfig } from "../lib/config-manager.js";
19
+ import { normalizeAgentSandbox } from "../lib/agent-sandbox.js";
19
20
 
20
21
  /**
21
22
  * Resolve + validate `--add-dir` values into absolute, existing, de-duped
@@ -171,6 +172,15 @@ export function registerAgentCommand(program) {
171
172
  "--worktree",
172
173
  "Run this session in a fresh git worktree (isolated branch; auto-removed when the session changes nothing)",
173
174
  )
175
+ .option(
176
+ "--sandbox [image]",
177
+ "Run shell commands in an ephemeral Docker sandbox (network disabled by default)",
178
+ )
179
+ .option("--sandbox-network", "Allow network access inside --sandbox")
180
+ .option(
181
+ "--bg, --background",
182
+ "Start as a detached background agent and return its id immediately",
183
+ )
174
184
  .option("--agent-id <id>", "Agent id for scoped memory recall")
175
185
  .option("--recall-limit <n>", "Top-K memories to inject into system prompt")
176
186
  .option("--recall-query <q>", "Query string for startup memory recall")
@@ -308,7 +318,29 @@ export function registerAgentCommand(program) {
308
318
  "--replay-user-messages",
309
319
  "Stream-input mode: echo each accepted stdin user message back as a `user` event (transcript/correlation)",
310
320
  )
321
+ .option(
322
+ "--allow-dangerous-bypass",
323
+ "Bypass all permission prompts in headless mode (DANGEROUS: auto-approves all tool calls)",
324
+ false,
325
+ )
326
+ .option("-y, --yolo", "Alias for --allow-dangerous-bypass", false)
327
+ .option(
328
+ "--dangerously-skip-permissions",
329
+ "Alias for --allow-dangerous-bypass",
330
+ false,
331
+ )
311
332
  .action(async (task, options, command) => {
333
+ const bypassPermissions = !!(
334
+ options.allowDangerousBypass ||
335
+ options.yolo ||
336
+ options.dangerouslySkipPermissions
337
+ );
338
+ if (bypassPermissions) {
339
+ process.env.CC_BYPASS_PERMISSIONS = "1";
340
+ process.stderr.write(
341
+ "⚠️ DANGER MODE: All permissions bypassed, no prompts will be shown.\n",
342
+ );
343
+ }
312
344
  // --safe-mode flag OR CC_SAFE_MODE / CLAUDE_CODE_SAFE_MODE env (Claude-Code
313
345
  // 2.1.169 parity): flip every customization kill-switch BEFORE anything
314
346
  // loads. Permission rules stay active.
@@ -735,7 +767,62 @@ export function registerAgentCommand(program) {
735
767
  if (piped) prompt = piped;
736
768
  }
737
769
 
770
+ if (options.bg && !prompt) {
771
+ process.stderr.write(
772
+ "--bg requires a task via positional text, -p, or piped stdin.\n",
773
+ );
774
+ process.exitCode = 1;
775
+ return;
776
+ }
777
+
738
778
  if (prompt) {
779
+ if (options.bg) {
780
+ if (options.worktree) {
781
+ process.stderr.write(
782
+ "--bg and --worktree cannot be combined yet; create the worktree first and launch the background agent from it.\n",
783
+ );
784
+ process.exitCode = 1;
785
+ return;
786
+ }
787
+ const { launchBackgroundAgent } =
788
+ await import("../lib/background-agent-supervisor.js");
789
+ const childArgv = process.argv
790
+ .slice(2)
791
+ .filter((arg) => arg !== "--bg" && arg !== "--background");
792
+ const hasSessionArg = childArgv.some(
793
+ (arg) =>
794
+ arg === "--session" ||
795
+ arg === "--resume" ||
796
+ arg === "--continue" ||
797
+ arg === "-c",
798
+ );
799
+ const sessionId =
800
+ options.session ||
801
+ `session-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
802
+ if (!hasSessionArg) childArgv.push("--session", sessionId);
803
+ const promptWasPiped =
804
+ positional.length === 0 &&
805
+ !(typeof options.print === "string" && options.print.trim());
806
+ if (promptWasPiped) childArgv.push(prompt);
807
+ const state = launchBackgroundAgent({
808
+ argv: childArgv,
809
+ cwd: process.cwd(),
810
+ sessionId,
811
+ title: prompt.slice(0, 100),
812
+ });
813
+ if (options.outputFormat === "json") {
814
+ console.log(JSON.stringify(state));
815
+ } else {
816
+ console.log(`Background agent started: ${state.id}`);
817
+ console.log(` logs: cc agents logs ${state.id}`);
818
+ console.log(` stop: cc agents stop ${state.id}`);
819
+ }
820
+ return;
821
+ }
822
+ const agentSandbox = normalizeAgentSandbox(options.sandbox, {
823
+ cwd: process.cwd(),
824
+ network: options.sandboxNetwork === true,
825
+ });
739
826
  // Resume requested onto a session with no headless (JSONL) transcript?
740
827
  // Warn instead of silently starting empty 鈥?headless resume rebuilds
741
828
  // from the JSONL store only (DB-only sessions are not replayable here).
@@ -775,6 +862,7 @@ export function registerAgentCommand(program) {
775
862
  allowedTools: parseToolList(options.allowedTools),
776
863
  disallowedTools: parseToolList(options.disallowedTools),
777
864
  additionalDirectories,
865
+ sandbox: agentSandbox,
778
866
  autoCheckpoint,
779
867
  maxTurns,
780
868
  // commander maps --no-file-refs 鈫?options.fileRefs === false
@@ -884,6 +972,10 @@ export function registerAgentCommand(program) {
884
972
  parkOnExit: options.parkOnExit, // false when --no-park-on-exit
885
973
  bundlePath: options.bundle || null,
886
974
  additionalDirectories,
975
+ sandbox: normalizeAgentSandbox(options.sandbox, {
976
+ cwd: process.cwd(),
977
+ network: options.sandboxNetwork === true,
978
+ }),
887
979
  autoCheckpoint,
888
980
  // --vim: start the REPL in vim-mode editing (also CC_VIM=1 or /vim).
889
981
  vimMode: options.vim === true,
@@ -22,6 +22,74 @@ export function registerAgentsCommand(program) {
22
22
  .command("agents")
23
23
  .description("User-defined subagents (.claude/agents/*.md)");
24
24
 
25
+ cmd
26
+ .command("background")
27
+ .alias("bg")
28
+ .description("List background agent sessions")
29
+ .option("--all", "Include completed, failed, stopped and lost sessions")
30
+ .option("--json", "Output as JSON")
31
+ .action(async (options) => {
32
+ const { listBackgroundAgents } =
33
+ await import("../lib/background-agent-supervisor.js");
34
+ const sessions = listBackgroundAgents({ all: options.all === true });
35
+ if (options.json) {
36
+ console.log(JSON.stringify(sessions, null, 2));
37
+ return;
38
+ }
39
+ if (sessions.length === 0) {
40
+ logger.log(chalk.gray("No background agents."));
41
+ return;
42
+ }
43
+ for (const session of sessions) {
44
+ const elapsed = session.endedAt
45
+ ? session.endedAt - session.startedAt
46
+ : Date.now() - session.startedAt;
47
+ logger.log(
48
+ `${chalk.cyan(session.id)} ${session.status.padEnd(9)} ${Math.max(0, Math.round(elapsed / 1000))}s ${session.title || ""}`,
49
+ );
50
+ logger.log(chalk.gray(` pid ${session.pid} ${session.cwd}`));
51
+ }
52
+ });
53
+
54
+ cmd
55
+ .command("logs <id>")
56
+ .description("Print recent output from a background agent")
57
+ .option("-n, --lines <n>", "Number of lines", "100")
58
+ .action(async (id, options) => {
59
+ try {
60
+ const { readBackgroundAgentState, readBackgroundAgentLog } =
61
+ await import("../lib/background-agent-supervisor.js");
62
+ if (!readBackgroundAgentState(id)) {
63
+ throw new Error(`Background agent not found: ${id}`);
64
+ }
65
+ process.stdout.write(
66
+ readBackgroundAgentLog(id, { lines: Number(options.lines) }),
67
+ );
68
+ } catch (error) {
69
+ logger.error(chalk.red(error.message));
70
+ process.exitCode = 1;
71
+ }
72
+ });
73
+
74
+ cmd
75
+ .command("stop <id>")
76
+ .description("Stop a running background agent")
77
+ .option("--json", "Output as JSON")
78
+ .action(async (id, options) => {
79
+ try {
80
+ const { stopBackgroundAgent } =
81
+ await import("../lib/background-agent-supervisor.js");
82
+ const state = stopBackgroundAgent(id);
83
+ if (options.json) console.log(JSON.stringify(state, null, 2));
84
+ else if (state.stopped)
85
+ logger.log(chalk.green(`Stopped background agent ${id}`));
86
+ else logger.log(chalk.gray(`${id} is already ${state.status}`));
87
+ } catch (error) {
88
+ logger.error(chalk.red(error.message));
89
+ process.exitCode = 1;
90
+ }
91
+ });
92
+
25
93
  // ── list ──────────────────────────────────────────────────────────────
26
94
  cmd
27
95
  .command("list")
@@ -8,6 +8,7 @@ import { numericOption } from "../lib/cli-numeric.js";
8
8
  import { logger } from "../lib/logger.js";
9
9
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
10
10
  import { likePrefix } from "../lib/sql-like.js";
11
+ import { safeJsonParse } from "../lib/safe-json.js";
11
12
  import {
12
13
  ensureVersionsTable,
13
14
  saveVersion,
@@ -204,7 +205,7 @@ export function registerNoteCommand(program) {
204
205
  } else {
205
206
  logger.log(chalk.bold(`Notes (${notes.length}):\n`));
206
207
  for (const n of notes) {
207
- const tags = JSON.parse(n.tags || "[]");
208
+ const tags = safeJsonParse(n.tags, []);
208
209
  const tagStr =
209
210
  tags.length > 0 ? chalk.gray(` [${tags.join(", ")}]`) : "";
210
211
  logger.log(
@@ -53,26 +53,33 @@ export function registerPermissionsCommand(program) {
53
53
  cmd
54
54
  .command("list")
55
55
  .alias("ls")
56
- .description("Show the merged permission ruleset and where each rule came from")
56
+ .description(
57
+ "Show the merged permission ruleset and where each rule came from",
58
+ )
57
59
  .option("--json", "Output as JSON")
58
60
  .option("--settings <file>", "Also merge an explicit settings file")
59
61
  .action(async (options) => {
60
62
  try {
61
63
  const { loadSettings } = await import("../lib/settings-loader.cjs");
62
- const { rules, sources, files } = loadSettings({
64
+ const { rules, sources, files, managed, managedFile } = loadSettings({
63
65
  cwd: process.cwd(),
64
66
  settingsFile: options.settings,
65
67
  });
66
68
  if (options.json) {
67
- console.log(JSON.stringify({ rules, sources, files }, null, 2));
69
+ console.log(
70
+ JSON.stringify(
71
+ { rules, sources, files, managed, managedFile },
72
+ null,
73
+ 2,
74
+ ),
75
+ );
68
76
  return;
69
77
  }
70
- const total =
71
- rules.allow.length + rules.ask.length + rules.deny.length;
78
+ const total = rules.allow.length + rules.ask.length + rules.deny.length;
72
79
  if (total === 0) {
73
80
  logger.log(
74
81
  chalk.gray(
75
- "No permission rules. Add one: cc permissions add deny \"Bash(rm:*)\"\n" +
82
+ 'No permission rules. Add one: cc permissions add deny "Bash(rm:*)"\n' +
76
83
  "(or create .claude/settings.json with a permissions block)",
77
84
  ),
78
85
  );
@@ -89,6 +96,40 @@ export function registerPermissionsCommand(program) {
89
96
  if (files.length) {
90
97
  logger.log(chalk.dim(`\nsources: ${files.join(", ")}`));
91
98
  }
99
+ if (managedFile) {
100
+ logger.log(chalk.yellow(`managed policy: ${managedFile}`));
101
+ if (managed?.allowManagedPermissionRulesOnly) {
102
+ logger.log(
103
+ chalk.yellow(" user/project permission rules disabled"),
104
+ );
105
+ }
106
+ if (
107
+ managed?.disableBypassPermissionsMode === true ||
108
+ managed?.disableBypassPermissionsMode === "disable"
109
+ ) {
110
+ logger.log(chalk.yellow(" bypassPermissions disabled"));
111
+ }
112
+ if (managed?.allowManagedHooksOnly) {
113
+ logger.log(chalk.yellow(" only managed hooks may run"));
114
+ }
115
+ if (managed?.allowManagedMcpServersOnly) {
116
+ logger.log(
117
+ chalk.yellow(" only managed-allowed MCP servers may connect"),
118
+ );
119
+ }
120
+ if (managed?.requireSignedPlugins) {
121
+ logger.log(chalk.yellow(" signed plugin manifests required"));
122
+ }
123
+ if (
124
+ Array.isArray(managed?.allowedPlugins) ||
125
+ Array.isArray(managed?.deniedPlugins) ||
126
+ Array.isArray(managed?.blockedMarketplaces)
127
+ ) {
128
+ logger.log(
129
+ chalk.yellow(" managed plugin supply-chain policy active"),
130
+ );
131
+ }
132
+ }
92
133
  } catch (err) {
93
134
  logger.error(chalk.red(`permissions list failed: ${err.message}`));
94
135
  process.exitCode = 1;
@@ -131,7 +172,13 @@ export function registerPermissionsCommand(program) {
131
172
  if (options.json) {
132
173
  console.log(
133
174
  JSON.stringify(
134
- { tool: concrete, args: toolArgs, decision, rule: result.rule, source },
175
+ {
176
+ tool: concrete,
177
+ args: toolArgs,
178
+ decision,
179
+ rule: result.rule,
180
+ source,
181
+ },
135
182
  null,
136
183
  2,
137
184
  ),
@@ -164,14 +211,19 @@ export function registerPermissionsCommand(program) {
164
211
  cmd
165
212
  .command("add <decision> <rule>")
166
213
  .description("Append a rule (allow|ask|deny) to a settings file")
167
- .option("--local", "Write to .claude/settings.local.json (personal, gitignored)")
214
+ .option(
215
+ "--local",
216
+ "Write to .claude/settings.local.json (personal, gitignored)",
217
+ )
168
218
  .option("--user", "Write to ~/.claude/settings.json (all projects)")
169
219
  .action(async (decision, rule, options) => {
170
220
  try {
171
221
  const kind = String(decision || "").toLowerCase();
172
222
  if (!["allow", "ask", "deny"].includes(kind)) {
173
223
  logger.error(
174
- chalk.red(`decision must be allow | ask | deny (got "${decision}")`),
224
+ chalk.red(
225
+ `decision must be allow | ask | deny (got "${decision}")`,
226
+ ),
175
227
  );
176
228
  process.exitCode = 1;
177
229
  return;
@@ -188,7 +240,11 @@ export function registerPermissionsCommand(program) {
188
240
  return;
189
241
  }
190
242
 
191
- const scope = options.user ? "user" : options.local ? "local" : "project";
243
+ const scope = options.user
244
+ ? "user"
245
+ : options.local
246
+ ? "local"
247
+ : "project";
192
248
  const { addRule } = await import("../lib/settings-loader.cjs");
193
249
  const { file, added } = addRule({
194
250
  cwd: process.cwd(),
@@ -5,6 +5,11 @@
5
5
 
6
6
  import chalk from "chalk";
7
7
  import { logger } from "../lib/logger.js";
8
+ import {
9
+ enforcePluginPolicy,
10
+ loadPluginManagedPolicy,
11
+ verifyPluginManifest,
12
+ } from "../lib/plugin-security.js";
8
13
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
9
14
  import {
10
15
  installPlugin,
@@ -90,9 +95,32 @@ export function registerPluginCommand(program) {
90
95
  .option("--description <desc>", "Plugin description")
91
96
  .option("--author <author>", "Plugin author")
92
97
  .option("--manifest <path>", "Plugin manifest file with skill declarations")
98
+ .option("--source <source>", "Plugin source or marketplace identifier")
99
+ .option("--sha256 <hex>", "Expected SHA-256 of the manifest")
100
+ .option("--signature <path>", "Detached Ed25519 signature of the manifest")
101
+ .option("--public-key <path>", "PEM public key used to verify --signature")
93
102
  .option("--json", "Output as JSON")
94
103
  .action(async (name, options) => {
95
104
  try {
105
+ const managed = loadPluginManagedPolicy();
106
+ enforcePluginPolicy(
107
+ { name, source: options.source, action: "install" },
108
+ managed,
109
+ );
110
+ let verifiedManifest = null;
111
+ let parsedManifest = null;
112
+ if (options.manifest || managed?.requireSignedPlugins) {
113
+ verifiedManifest = verifyPluginManifest({
114
+ manifestFile: options.manifest,
115
+ expectedSha256: options.sha256,
116
+ signatureFile: options.signature,
117
+ publicKeyFile: options.publicKey,
118
+ requireSignature: managed?.requireSignedPlugins === true,
119
+ trustedKeySha256: managed?.trustedPluginKeySha256,
120
+ requireTrustedKey: managed?.requireSignedPlugins === true,
121
+ });
122
+ parsedManifest = JSON.parse(verifiedManifest.bytes.toString("utf8"));
123
+ }
96
124
  const ctx = await bootstrap({ verbose: program.opts().verbose });
97
125
  if (!ctx.db) {
98
126
  logger.error("Database not available");
@@ -111,8 +139,9 @@ export function registerPluginCommand(program) {
111
139
  if (options.manifest) {
112
140
  try {
113
141
  const fs = await import("fs");
114
- const manifestContent = fs.readFileSync(options.manifest, "utf-8");
115
- const manifest = JSON.parse(manifestContent);
142
+ const manifest =
143
+ parsedManifest ||
144
+ JSON.parse(fs.readFileSync(options.manifest, "utf-8"));
116
145
  if (manifest.skills && manifest.skills.length > 0) {
117
146
  const path = await import("path");
118
147
  const pluginPath = path.dirname(path.resolve(options.manifest));
@@ -131,7 +160,17 @@ export function registerPluginCommand(program) {
131
160
  if (options.json) {
132
161
  console.log(
133
162
  JSON.stringify(
134
- { ...result, skills: skillResult.installed },
163
+ {
164
+ ...result,
165
+ skills: skillResult.installed,
166
+ integrity: verifiedManifest
167
+ ? {
168
+ sha256: verifiedManifest.sha256,
169
+ signatureVerified: verifiedManifest.signatureVerified,
170
+ publicKeySha256: verifiedManifest.publicKeySha256,
171
+ }
172
+ : null,
173
+ },
135
174
  null,
136
175
  2,
137
176
  ),
@@ -205,6 +244,10 @@ export function registerPluginCommand(program) {
205
244
  .argument("<name>", "Plugin name")
206
245
  .action(async (name) => {
207
246
  try {
247
+ enforcePluginPolicy(
248
+ { name, action: "enable" },
249
+ loadPluginManagedPolicy(),
250
+ );
208
251
  const ctx = await bootstrap({ verbose: program.opts().verbose });
209
252
  if (!ctx.db) {
210
253
  logger.error("Database not available");
@@ -262,6 +305,10 @@ export function registerPluginCommand(program) {
262
305
  .argument("<version>", "New version")
263
306
  .action(async (name, version) => {
264
307
  try {
308
+ enforcePluginPolicy(
309
+ { name, action: "update" },
310
+ loadPluginManagedPolicy(),
311
+ );
265
312
  const ctx = await bootstrap({ verbose: program.opts().verbose });
266
313
  if (!ctx.db) {
267
314
  logger.error("Database not available");
@@ -8,6 +8,7 @@ import ora from "ora";
8
8
  import { logger } from "../lib/logger.js";
9
9
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
10
10
  import { BM25Search } from "../lib/bm25-search.js";
11
+ import { safeJsonParse } from "../lib/safe-json.js";
11
12
 
12
13
  /**
13
14
  * Ensure the notes table exists (same as note.js)
@@ -213,7 +214,7 @@ export function registerSearchCommand(program) {
213
214
  ),
214
215
  );
215
216
  for (const r of results) {
216
- const tags = JSON.parse(r.doc.tags || "[]");
217
+ const tags = safeJsonParse(r.doc.tags, []);
217
218
  const tagStr =
218
219
  tags.length > 0 ? chalk.gray(` [${tags.join(", ")}]`) : "";
219
220
  const snippet = (r.doc.content || "")
@@ -857,23 +857,30 @@ function _resolveBaseBranchForMerge(repoDir, baseBranch) {
857
857
  }
858
858
 
859
859
  function _applyAutomationResolution(repoDir, candidateId, filePath) {
860
+ // filePath here is a conflicted filename straight from `git diff --name-only`
861
+ // — i.e. it reflects whatever names exist in the (possibly untrusted) branch
862
+ // being merged. The sibling public functions assertSafeGitPath their filePath,
863
+ // but this internal helper interpolated it raw into a shell command string, so
864
+ // a file named `x"; rm -rf ~; ".txt` was a command-injection vector. Use the
865
+ // array-form gitExecArgs (spawnSync, no shell) so the path is a literal arg —
866
+ // injection-proof and correct for filenames with spaces/special chars too.
860
867
  switch (candidateId) {
861
868
  case "accept-current":
862
- gitExec(`checkout --theirs -- "${filePath}"`, repoDir);
863
- gitExec(`add "${filePath}"`, repoDir);
869
+ gitExecArgs(["checkout", "--theirs", "--", filePath], repoDir);
870
+ gitExecArgs(["add", "--", filePath], repoDir);
864
871
  return;
865
872
  case "accept-incoming":
866
873
  case "restore-incoming":
867
- gitExec(`checkout --ours -- "${filePath}"`, repoDir);
868
- gitExec(`add "${filePath}"`, repoDir);
874
+ gitExecArgs(["checkout", "--ours", "--", filePath], repoDir);
875
+ gitExecArgs(["add", "--", filePath], repoDir);
869
876
  return;
870
877
  case "restore-current":
871
- gitExec(`checkout --theirs -- "${filePath}"`, repoDir);
872
- gitExec(`add "${filePath}"`, repoDir);
878
+ gitExecArgs(["checkout", "--theirs", "--", filePath], repoDir);
879
+ gitExecArgs(["add", "--", filePath], repoDir);
873
880
  return;
874
881
  case "confirm-delete":
875
882
  case "accept-delete":
876
- gitExec(`rm -- "${filePath}"`, repoDir);
883
+ gitExecArgs(["rm", "--", filePath], repoDir);
877
884
  return;
878
885
  default:
879
886
  throw new Error(`Unsupported automation resolution: ${candidateId}`);
package/src/index.js CHANGED
@@ -1,5 +1,4 @@
1
- import { Command } from "commander";
2
- import { VERSION } from "./constants.js";
1
+ import { createBaseProgram } from "./program-base.js";
3
2
  import { maybeNotifyUpdate } from "./lib/update-notice.js";
4
3
  import { registerSetupCommand } from "./commands/setup.js";
5
4
  import { registerStartCommand } from "./commands/start.js";
@@ -391,16 +390,9 @@ import { registerPipoV2Commands } from "./commands/pipeline.js";
391
390
  * opts.allowedCommands takes precedence over the env var.
392
391
  */
393
392
  export function createProgram(opts = {}) {
394
- const program = new Command();
395
-
396
- program
397
- .name("chainlesschain")
398
- .description(
399
- "CLI for ChainlessChain - install, configure, and manage your personal AI management system",
400
- )
401
- .version(VERSION, "-v, --version")
402
- .option("--verbose", "Enable verbose output")
403
- .option("--quiet", "Suppress non-essential output");
393
+ // Base (name/version/global options) is shared with the lazy fast path
394
+ // (src/lazy-dispatch.js) via program-base.js so they can never drift.
395
+ const program = createBaseProgram();
404
396
 
405
397
  // Passive update nudge (Claude-Code parity): one sync cache read + gray
406
398
  // stderr line when a newer npm version is known; stale cache refreshes in a
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Lazy CLI dispatch — the cold-start optimization.
3
+ *
4
+ * Importing src/index.js eagerly loads all ~154 command modules + their
5
+ * transitive dependency graph (~2.7s; see memory
6
+ * cli_cold_start_bottleneck_hub_repl). But a real `cc <cmd>` invocation only
7
+ * needs ONE command's module. This dispatcher resolves the target command from
8
+ * argv against the generated manifest (src/command-manifest.json) and imports
9
+ * just that module, then parses.
10
+ *
11
+ * SAFETY: anything uncertain — no command, --help, an unknown command, or a
12
+ * project-mode subcommand whitelist — falls back to the full eager program
13
+ * (src/index.js `createProgram`), i.e. exactly today's behavior. The fast path
14
+ * only activates when a single known command resolves cleanly. Worst case is
15
+ * therefore "as slow as today, still correct", never "wrong".
16
+ *
17
+ * The manifest is regenerated by scripts/gen-command-manifest.mjs and guarded
18
+ * against drift by lazy-dispatch.test.js.
19
+ */
20
+ import { readFileSync } from "fs";
21
+ import { createBaseProgram } from "./program-base.js";
22
+ import { maybeNotifyUpdate } from "./lib/update-notice.js";
23
+
24
+ const manifest = JSON.parse(
25
+ readFileSync(new URL("./command-manifest.json", import.meta.url), "utf8"),
26
+ );
27
+
28
+ // name + every alias -> manifest entry
29
+ const byName = new Map();
30
+ for (const entry of manifest.commands) {
31
+ byName.set(entry.name, entry);
32
+ for (const alias of entry.aliases || []) byName.set(alias, entry);
33
+ }
34
+
35
+ /**
36
+ * The command token is the first positional arg (the first token that is not a
37
+ * global option). The root program's only global options (--verbose, --quiet)
38
+ * and the -v/--version / -h/--help flags are all boolean and never consume a
39
+ * following value, so "first token not starting with '-'" is unambiguous.
40
+ */
41
+ export function resolveCommandToken(argv) {
42
+ const rest = argv.slice(2);
43
+ for (const arg of rest) {
44
+ if (arg === "--") break;
45
+ if (arg.startsWith("-")) continue;
46
+ return arg;
47
+ }
48
+ return null;
49
+ }
50
+
51
+ function hasVersionFlag(argv) {
52
+ return argv.slice(2).some((a) => a === "-v" || a === "--version");
53
+ }
54
+
55
+ function notify() {
56
+ // Mirror index.js: passive update nudge, suppressed under vitest.
57
+ if (!process.env.VITEST) {
58
+ try {
59
+ maybeNotifyUpdate();
60
+ } catch {
61
+ /* fail-open — never block the CLI on the nudge */
62
+ }
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Parse and run the CLI. Used by the bin entry in place of importing index.js
68
+ * directly (which would defeat lazy loading).
69
+ *
70
+ * @param {string[]} [argv] defaults to process.argv
71
+ * @returns {Promise<import('commander').Command>}
72
+ */
73
+ export async function runCli(argv = process.argv) {
74
+ // Project-mode packed exes restrict the visible command set; the filtering
75
+ // lives in the eager createProgram, so defer to it for correctness.
76
+ const whitelistActive = !!process.env.CC_PROJECT_ALLOWED_SUBCOMMANDS;
77
+ const token = resolveCommandToken(argv);
78
+
79
+ // Fast path 1: a known command resolves cleanly.
80
+ if (token && !whitelistActive && byName.has(token)) {
81
+ const entry = byName.get(token);
82
+ const program = createBaseProgram();
83
+ notify();
84
+ const mod = await import(new URL(entry.module, import.meta.url));
85
+ const register = mod[entry.register];
86
+ if (typeof register === "function") {
87
+ register(program);
88
+ return program.parseAsync(argv);
89
+ }
90
+ // Manifest pointed at a missing export (should be impossible given the
91
+ // drift test) — fall through to the eager path rather than crash.
92
+ }
93
+
94
+ // Fast path 2: bare version request, no command (base program short-circuits
95
+ // without loading any command module).
96
+ if (!token && !whitelistActive && hasVersionFlag(argv)) {
97
+ const program = createBaseProgram();
98
+ notify();
99
+ return program.parseAsync(argv);
100
+ }
101
+
102
+ // Fallback: --help, no args, unknown command, or project whitelist — load the
103
+ // full eager program (today's behavior; createProgram fires its own update
104
+ // nudge so we do not call notify() here to avoid a double nudge).
105
+ const { createProgram } = await import("./index.js");
106
+ return createProgram().parseAsync(argv);
107
+ }