chainlesschain 0.162.188 → 0.162.193

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 (337) hide show
  1. package/README.md +61 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
  12. package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
  18. package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
  19. package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
  26. package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
  44. package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
  48. package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
  49. package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
  52. package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
  53. package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
  54. package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
  57. package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
  58. package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
  60. package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
  69. package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
  70. package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
  73. package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
  75. package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
  93. package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
  94. package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
  127. package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
  133. package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
  134. package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
  135. package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1107 -175
  159. package/src/command-surface-policy.js +197 -0
  160. package/src/commands/agent.js +98 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-managed.js +1059 -0
  164. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  165. package/src/commands/checkpoint.js +950 -22
  166. package/src/commands/compact.js +101 -25
  167. package/src/commands/config.js +506 -20
  168. package/src/commands/doctor.js +4 -1
  169. package/src/commands/hub.js +1 -1
  170. package/src/commands/mcp.js +688 -24
  171. package/src/commands/pack.js +16 -2
  172. package/src/commands/plugin.js +20 -12
  173. package/src/commands/session-mcp-recovery.js +218 -0
  174. package/src/commands/session.js +470 -110
  175. package/src/commands/setup.js +36 -10
  176. package/src/commands/skill.js +181 -110
  177. package/src/commands/status.js +21 -5
  178. package/src/commands/team-distributed.js +3324 -0
  179. package/src/commands/team.js +1130 -74
  180. package/src/commands/update.js +68 -6
  181. package/src/constants.js +11 -0
  182. package/src/data/changelog.json +26 -0
  183. package/src/gateways/ws/action-protocol.js +10 -0
  184. package/src/gateways/ws/session-protocol.js +555 -27
  185. package/src/gateways/ws/ws-agent-handler.js +541 -14
  186. package/src/gateways/ws/ws-session-gateway.js +129 -22
  187. package/src/gateways/ws/ws-session-state.js +431 -0
  188. package/src/harness/background-task-manager.js +233 -36
  189. package/src/harness/jsonl-session-store.js +2551 -167
  190. package/src/harness/mcp-client.js +802 -61
  191. package/src/harness/prompt-compressor.js +227 -27
  192. package/src/harness/session-index.js +89 -38
  193. package/src/harness/session-list-index.js +254 -0
  194. package/src/harness/structured-handoff.js +410 -0
  195. package/src/lazy-dispatch.js +747 -84
  196. package/src/lib/__tests__/logger.test.js +50 -2
  197. package/src/lib/advisor-runtime.js +1047 -0
  198. package/src/lib/agent-core.js +2 -0
  199. package/src/lib/agent-sandbox.js +120 -26
  200. package/src/lib/agent-session-export.js +20 -0
  201. package/src/lib/agent-team/task-lease.js +271 -3
  202. package/src/lib/agent-team/team-adjudication.js +1501 -0
  203. package/src/lib/agent-team/team-budget.js +4 -1
  204. package/src/lib/agent-team/team-control-store.js +582 -0
  205. package/src/lib/agent-team/team-distributed-queue.js +5246 -0
  206. package/src/lib/agent-team/team-process-checkpoint.js +211 -0
  207. package/src/lib/agent-team/team-runner.js +543 -24
  208. package/src/lib/agent-team/team-worktree.js +1403 -95
  209. package/src/lib/artifact-store.js +131 -8
  210. package/src/lib/background-agent-supervisor.js +185 -13
  211. package/src/lib/background-interaction-journal.js +37 -9
  212. package/src/lib/background-launch-profile.js +1058 -0
  213. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  214. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  215. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  216. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  217. package/src/lib/checkpoint-restore-recovery.js +884 -0
  218. package/src/lib/checkpoint-restore-retention.js +126 -0
  219. package/src/lib/checkpoint-restore-saga.js +5079 -0
  220. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  221. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  222. package/src/lib/checkpoint-store.js +1688 -97
  223. package/src/lib/checkpoint-timeline-authority.js +522 -0
  224. package/src/lib/checkpoint-timeline.js +642 -0
  225. package/src/lib/config-keys.js +18 -119
  226. package/src/lib/config-manager.js +446 -27
  227. package/src/lib/config-redaction.js +57 -0
  228. package/src/lib/config-schema.js +853 -0
  229. package/src/lib/cowork-mcp-tools.js +5 -0
  230. package/src/lib/cowork-task-runner.js +458 -63
  231. package/src/lib/delivery-coordinator.js +1234 -0
  232. package/src/lib/delivery-evidence.js +450 -0
  233. package/src/lib/doctor-checkup.js +199 -14
  234. package/src/lib/executable-path.js +34 -0
  235. package/src/lib/fatal-handler.js +16 -0
  236. package/src/lib/file-checkpoint.js +4909 -186
  237. package/src/lib/file-lines.js +125 -0
  238. package/src/lib/headless-config-command.js +16 -5
  239. package/src/lib/hook-runner.cjs +139 -38
  240. package/src/lib/hooks-v2-workspace-context.js +10 -0
  241. package/src/lib/impacted-gate-selector.js +424 -0
  242. package/src/lib/interaction-adapter.js +62 -0
  243. package/src/lib/jsonl-session-store.js +1 -35
  244. package/src/lib/logger.js +66 -14
  245. package/src/lib/managed-checkpoint-render.js +60 -0
  246. package/src/lib/managed-tool-checkpoint.js +194 -0
  247. package/src/lib/mcp-call-ledger-store.js +1069 -0
  248. package/src/lib/mcp-call-ledger.js +747 -0
  249. package/src/lib/mcp-client.js +5 -0
  250. package/src/lib/mcp-conflict-scheduler.js +468 -0
  251. package/src/lib/mcp-effect-contract.js +102 -0
  252. package/src/lib/mcp-headers-helper-trust.js +145 -0
  253. package/src/lib/mcp-headers-helper.js +616 -0
  254. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  255. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  256. package/src/lib/mcp-recovery-adjudication.js +443 -0
  257. package/src/lib/output-context.js +86 -0
  258. package/src/lib/packer/file-identity.js +170 -0
  259. package/src/lib/packer/index.js +3 -0
  260. package/src/lib/packer/native-update-state.js +277 -0
  261. package/src/lib/packer/pack-update-applier.js +1983 -136
  262. package/src/lib/packer/pack-update-checker.js +34 -0
  263. package/src/lib/packer/pack-update-downloader.js +875 -86
  264. package/src/lib/packer/pack-update-signature.js +86 -0
  265. package/src/lib/packer/pkg-config-generator.js +6 -0
  266. package/src/lib/paths.js +65 -10
  267. package/src/lib/plan-mode.js +831 -14
  268. package/src/lib/plan-persistence.js +540 -0
  269. package/src/lib/plugin-runtime/hooks.js +227 -69
  270. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  271. package/src/lib/pr-automation-policy.js +146 -8
  272. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  273. package/src/lib/process-execution-broker/index.js +491 -13
  274. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
  275. package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
  276. package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
  277. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  278. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  279. package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
  280. package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
  281. package/src/lib/project-instructions.js +165 -29
  282. package/src/lib/project-mcp-trust.js +67 -0
  283. package/src/lib/public-ide-capability-manifest.js +272 -0
  284. package/src/lib/public-ide-capability-validation.js +351 -0
  285. package/src/lib/secret-store.js +267 -43
  286. package/src/lib/secure-file-identity.js +433 -0
  287. package/src/lib/secure-fs.js +1089 -0
  288. package/src/lib/security-audit.js +58 -0
  289. package/src/lib/service-manager.js +34 -13
  290. package/src/lib/session-budget-runtime.js +1452 -0
  291. package/src/lib/session-host-snapshot.js +388 -0
  292. package/src/lib/session-message-provenance.js +429 -0
  293. package/src/lib/session-projection.js +804 -0
  294. package/src/lib/session-resource-budget.js +1495 -0
  295. package/src/lib/settings-hooks.cjs +138 -22
  296. package/src/lib/settings-loader.cjs +25 -2
  297. package/src/lib/side-effect-ledger-store.js +45 -23
  298. package/src/lib/skill-execution-identity.js +217 -0
  299. package/src/lib/skill-loader.js +299 -18
  300. package/src/lib/sub-agent-context.js +236 -28
  301. package/src/lib/sub-agent-registry.js +5 -0
  302. package/src/lib/subagent-contract.js +94 -0
  303. package/src/lib/todo-manager.js +185 -18
  304. package/src/lib/todo-persistence.js +417 -0
  305. package/src/lib/turn-binding-store.js +41 -23
  306. package/src/lib/turn-binding.js +160 -2
  307. package/src/lib/with-file-lock.js +165 -24
  308. package/src/lib/ws-chat-handler.js +21 -0
  309. package/src/program-base.js +18 -0
  310. package/src/repl/advisor-command.js +103 -0
  311. package/src/repl/agent-repl.js +2175 -146
  312. package/src/repl/btw-command.js +93 -10
  313. package/src/repl/clipboard-image.js +119 -0
  314. package/src/repl/config-summary.js +64 -108
  315. package/src/repl/prompt-editor.js +233 -0
  316. package/src/repl/prompt-interactions.js +344 -0
  317. package/src/repl/prompt-stash.js +354 -0
  318. package/src/repl/prompt-suggestions.js +312 -0
  319. package/src/repl/repl-keybindings.js +227 -0
  320. package/src/repl/session-recap.js +217 -0
  321. package/src/repl/slash-command-registry.js +22 -0
  322. package/src/repl/terminal-layout.js +88 -0
  323. package/src/runtime/agent-core.js +1630 -447
  324. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  325. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  326. package/src/runtime/diagnostics.js +32 -13
  327. package/src/runtime/headless-runner.js +310 -118
  328. package/src/runtime/headless-stream.js +356 -95
  329. package/src/runtime/mcp-config.js +148 -14
  330. package/src/runtime/policies/agent-policy.js +14 -0
  331. package/src/runtime/status-diagnostics-lite.js +137 -0
  332. package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
  333. package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
  334. package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
  335. package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
  336. package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
  337. package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
@@ -1,18 +1,43 @@
1
1
  import chalk from "chalk";
2
+ import { existsSync } from "node:fs";
2
3
  import {
3
4
  loadConfig,
4
5
  getConfigValue,
5
6
  setConfigValue,
6
7
  resetConfig,
7
8
  saveConfig,
9
+ loadUserConfig,
10
+ setSecretConfigValue,
11
+ backupConfigForMigration,
12
+ withConfigLock,
8
13
  } from "../lib/config-manager.js";
9
- import { getConfigPath } from "../lib/paths.js";
14
+ import { getConfigPath, getHomeDir } from "../lib/paths.js";
10
15
  import logger from "../lib/logger.js";
11
16
  import { listFeatures, setFeature, getFlagInfo } from "../lib/feature-flags.js";
12
17
  import { executionBroker } from "../lib/process-execution-broker/index.js";
18
+ import {
19
+ CONFIG_SCHEMA_VERSION,
20
+ getConfigDescriptor,
21
+ getConfigDescriptors,
22
+ getConfigJsonSchema,
23
+ isSecretConfigKey,
24
+ migrateConfigDocument,
25
+ validateConfigDocument,
26
+ } from "../lib/config-schema.js";
27
+ import {
28
+ CONFIG_REDACTED,
29
+ redactConfigObject,
30
+ redactConfigValue,
31
+ } from "../lib/config-redaction.js";
32
+ import {
33
+ ensurePrivateDirectory,
34
+ inspectPrivatePaths,
35
+ repairPrivatePaths,
36
+ } from "../lib/secure-fs.js";
13
37
 
14
38
  export const _deps = {
15
39
  spawnSync: (...args) => executionBroker.spawnSync(...args),
40
+ platform: () => process.platform,
16
41
  };
17
42
 
18
43
  /** Parse the conventional $EDITOR string without invoking a shell. */
@@ -79,6 +104,287 @@ export function openConfigEditor(editor, configPath, deps = _deps) {
79
104
  });
80
105
  }
81
106
 
107
+ export async function readSecretInput(options = {}) {
108
+ const stdin = options.stdin || process.stdin;
109
+ if (stdin.isTTY) {
110
+ const askPassword =
111
+ options.askPassword || (await import("../lib/prompts.js")).askPassword;
112
+ return String(await askPassword(options.message || "Secret value:"));
113
+ }
114
+ let value = "";
115
+ stdin.setEncoding?.("utf8");
116
+ for await (const chunk of stdin) value += chunk;
117
+ // Drop only line endings introduced by piping/Enter. Spaces may be part of
118
+ // the credential and must not be silently changed.
119
+ return value.replace(/[\r\n]+$/, "");
120
+ }
121
+
122
+ function getNested(obj, key) {
123
+ let current = obj;
124
+ for (const part of String(key).split(".")) {
125
+ if (current == null || typeof current !== "object") return undefined;
126
+ current = current[part];
127
+ }
128
+ return current;
129
+ }
130
+
131
+ function hasNested(obj, key) {
132
+ let current = obj;
133
+ for (const part of String(key).split(".")) {
134
+ if (
135
+ current == null ||
136
+ typeof current !== "object" ||
137
+ !Object.prototype.hasOwnProperty.call(current, part)
138
+ ) {
139
+ return false;
140
+ }
141
+ current = current[part];
142
+ }
143
+ return true;
144
+ }
145
+
146
+ function setNested(obj, key, value) {
147
+ const parts = String(key).split(".");
148
+ let current = obj;
149
+ for (let index = 0; index < parts.length - 1; index += 1) {
150
+ current = current[parts[index]] ||= {};
151
+ }
152
+ current[parts.at(-1)] = value;
153
+ }
154
+
155
+ function recordUserProvenance(value, prefix, provenance, source) {
156
+ if (prefix) {
157
+ provenance[prefix] = {
158
+ source,
159
+ layer: "user",
160
+ overridden: [],
161
+ locked: false,
162
+ };
163
+ }
164
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
165
+ for (const [name, child] of Object.entries(value)) {
166
+ recordUserProvenance(
167
+ child,
168
+ prefix ? `${prefix}.${name}` : name,
169
+ provenance,
170
+ source,
171
+ );
172
+ }
173
+ }
174
+
175
+ /** Inspect, and optionally repair, the owner-only config storage contract. */
176
+ export function checkConfigStoragePermissions(options = {}) {
177
+ const home = options.home || getHomeDir();
178
+ const configPath = options.configPath || getConfigPath();
179
+ const platform = options.platform || _deps.platform();
180
+ const secureOptions = { platform, ...(options.secureOptions || {}) };
181
+ const pathExists =
182
+ options.existsSync || secureOptions.deps?.fs?.existsSync || existsSync;
183
+
184
+ const definitions = [
185
+ { name: "home", target: home, kind: "directory" },
186
+ { name: "config", target: configPath, kind: "file" },
187
+ ];
188
+ const results = new Map();
189
+ const existing = [];
190
+ for (const definition of definitions) {
191
+ let exists = false;
192
+ try {
193
+ exists = pathExists(definition.target);
194
+ } catch (error) {
195
+ results.set(definition.name, {
196
+ ok: false,
197
+ exists: false,
198
+ platform,
199
+ error: error.message,
200
+ });
201
+ continue;
202
+ }
203
+ if (!exists && options.fix && definition.kind === "directory") {
204
+ try {
205
+ ensurePrivateDirectory(definition.target, {
206
+ ...secureOptions,
207
+ failIfUnavailable: true,
208
+ });
209
+ results.set(definition.name, { ok: true, exists: true, platform });
210
+ } catch (error) {
211
+ results.set(definition.name, {
212
+ ok: false,
213
+ exists: false,
214
+ platform,
215
+ error: error.message,
216
+ });
217
+ }
218
+ continue;
219
+ }
220
+ if (!exists) {
221
+ results.set(definition.name, { ok: false, exists: false, platform });
222
+ continue;
223
+ }
224
+ existing.push(definition);
225
+ }
226
+
227
+ if (existing.length > 0) {
228
+ const targets = existing.map((entry) => entry.target);
229
+ let inspected;
230
+ try {
231
+ inspected = options.fix
232
+ ? repairPrivatePaths(targets, secureOptions)
233
+ : inspectPrivatePaths(targets, secureOptions);
234
+ } catch (error) {
235
+ // A batch repair may partially succeed. Read back every target so the
236
+ // report reflects durable post-fix state rather than a generic failure.
237
+ inspected = inspectPrivatePaths(targets, secureOptions).map((entry) => ({
238
+ ...entry,
239
+ ...(entry.ok ? {} : { error: entry.error || error.message }),
240
+ }));
241
+ }
242
+ for (let index = 0; index < existing.length; index += 1) {
243
+ results.set(existing[index].name, inspected[index]);
244
+ }
245
+ }
246
+
247
+ return {
248
+ home: results.get("home"),
249
+ config: results.get("config"),
250
+ };
251
+ }
252
+
253
+ /** Secure config.json for an editor without parsing or rewriting it. */
254
+ export function prepareConfigForEdit(options = {}) {
255
+ const configPath = options.configPath || getConfigPath();
256
+ const pathExists = options.existsSync || existsSync;
257
+ if (pathExists(configPath)) {
258
+ const checkPermissions =
259
+ options.checkPermissions || checkConfigStoragePermissions;
260
+ const permissions = checkPermissions({
261
+ fix: true,
262
+ configPath,
263
+ ...(options.home ? { home: options.home } : {}),
264
+ });
265
+ if (!permissions.home.ok || !permissions.config.ok) {
266
+ throw new Error("Could not secure config.json before editing");
267
+ }
268
+ } else {
269
+ const load = options.loadConfig || loadConfig;
270
+ const save = options.saveConfig || saveConfig;
271
+ save(load());
272
+ }
273
+ return configPath;
274
+ }
275
+
276
+ const PROVIDER_KEY_ENV = Object.freeze({
277
+ anthropic: "ANTHROPIC_API_KEY",
278
+ openai: "OPENAI_API_KEY",
279
+ volcengine: "VOLCENGINE_API_KEY",
280
+ deepseek: "DEEPSEEK_API_KEY",
281
+ dashscope: "DASHSCOPE_API_KEY",
282
+ gemini: "GEMINI_API_KEY",
283
+ kimi: "MOONSHOT_API_KEY",
284
+ minimax: "MINIMAX_API_KEY",
285
+ mistral: "MISTRAL_API_KEY",
286
+ });
287
+
288
+ /** Resolve the config layers used by CLI agent startup, with provenance. */
289
+ export async function resolveEffectiveConfig(options = {}) {
290
+ const env = options.env || process.env;
291
+ const cwd = options.cwd || process.cwd();
292
+ const raw = loadUserConfig();
293
+ const config = loadConfig({ resolveSecrets: false });
294
+ const provenance = {};
295
+ let settingsLayer = {
296
+ files: [],
297
+ managedFile: null,
298
+ environmentVariables: [],
299
+ sandbox: null,
300
+ };
301
+ let settingsEnv = {};
302
+ let settingsEnvSources = {};
303
+ recordUserProvenance(raw, "", provenance, getConfigPath());
304
+ for (const entry of getConfigDescriptors()) {
305
+ if (!hasNested(raw, entry.key) && entry.default !== undefined) {
306
+ provenance[entry.key] = {
307
+ source: "built-in default",
308
+ layer: "default",
309
+ overridden: [],
310
+ locked: false,
311
+ };
312
+ }
313
+ }
314
+
315
+ try {
316
+ const imported = await import("../lib/settings-loader.cjs");
317
+ const settings = imported.default || imported;
318
+ const loaded = settings.loadSettingsConfig({ cwd, env });
319
+ settingsEnv = loaded.env || {};
320
+ settingsEnvSources = loaded.envSources || {};
321
+ settingsLayer = {
322
+ files: loaded.files || [],
323
+ managedFile: loaded.managedFile || null,
324
+ environmentVariables: Object.keys(settingsEnv).sort(),
325
+ sandbox: redactConfigObject(loaded.sandbox),
326
+ };
327
+ if (loaded.model) {
328
+ const previous = provenance["llm.model"]?.source;
329
+ setNested(config, "llm.model", loaded.model);
330
+ const modelSource =
331
+ loaded.modelSource || loaded.files.at(-1) || "settings";
332
+ provenance["llm.model"] = {
333
+ source: modelSource,
334
+ layer:
335
+ loaded.managedFile && modelSource === loaded.managedFile
336
+ ? "managed"
337
+ : "settings",
338
+ overridden: previous ? [previous] : [],
339
+ locked: Boolean(
340
+ loaded.managedFile && modelSource === loaded.managedFile,
341
+ ),
342
+ };
343
+ }
344
+ } catch (error) {
345
+ provenance.$settings = {
346
+ source: "settings",
347
+ layer: "error",
348
+ overridden: [],
349
+ locked: false,
350
+ error: error.message,
351
+ };
352
+ }
353
+
354
+ const provider = config?.llm?.provider;
355
+ const effectiveEnv = { ...env, ...settingsEnv };
356
+ const envName = effectiveEnv.CC_API_KEY
357
+ ? "CC_API_KEY"
358
+ : PROVIDER_KEY_ENV[String(provider || "").toLowerCase()];
359
+ if (envName && effectiveEnv[envName]) {
360
+ const previous = provenance["llm.apiKey"]?.source;
361
+ const settingsSource = settingsEnvSources[envName];
362
+ setNested(config, "llm.apiKey", CONFIG_REDACTED);
363
+ provenance["llm.apiKey"] = {
364
+ source: settingsSource
365
+ ? `${settingsSource}:env.${envName}`
366
+ : `environment:${envName}`,
367
+ layer:
368
+ settingsSource && settingsSource === settingsLayer.managedFile
369
+ ? "managed"
370
+ : settingsSource
371
+ ? "settings-environment"
372
+ : "environment",
373
+ overridden: previous ? [previous] : [],
374
+ locked: Boolean(
375
+ settingsSource && settingsSource === settingsLayer.managedFile,
376
+ ),
377
+ };
378
+ }
379
+
380
+ return {
381
+ schemaVersion: CONFIG_SCHEMA_VERSION,
382
+ config: redactConfigObject(config),
383
+ provenance,
384
+ settings: settingsLayer,
385
+ };
386
+ }
387
+
82
388
  export function registerConfigCommand(program) {
83
389
  const cmd = program
84
390
  .command("config")
@@ -87,8 +393,13 @@ export function registerConfigCommand(program) {
87
393
  cmd
88
394
  .command("list")
89
395
  .description("Show all configuration values")
90
- .action(() => {
91
- const config = loadConfig();
396
+ .option("--json", "Output redacted JSON")
397
+ .action((options) => {
398
+ const config = redactConfigObject(loadConfig({ resolveSecrets: false }));
399
+ if (options.json) {
400
+ console.log(JSON.stringify(config, null, 2));
401
+ return;
402
+ }
92
403
  logger.log(chalk.bold(`\n Config: ${getConfigPath()}\n`));
93
404
  printConfig(config, " ");
94
405
  logger.newline();
@@ -130,16 +441,21 @@ export function registerConfigCommand(program) {
130
441
  .command("get")
131
442
  .description("Get a configuration value")
132
443
  .argument("<key>", "Config key (dot-notation, e.g. llm.provider)")
133
- .action((key) => {
134
- const value = getConfigValue(key);
444
+ .option("--json", "Output a redacted JSON envelope")
445
+ .action((key, options) => {
446
+ const value = getConfigValue(key, { resolveSecrets: false });
135
447
  if (value === undefined) {
136
448
  logger.error(`Key not found: ${key}`);
137
- process.exit(1);
449
+ process.exitCode = 1;
450
+ return;
138
451
  }
139
- if (typeof value === "object") {
140
- logger.log(JSON.stringify(value, null, 2));
452
+ const redacted = redactConfigValue(key, value);
453
+ if (options.json) {
454
+ console.log(JSON.stringify({ key, value: redacted }, null, 2));
455
+ } else if (typeof redacted === "object") {
456
+ logger.log(JSON.stringify(redacted, null, 2));
141
457
  } else {
142
- logger.log(String(value));
458
+ logger.log(String(redacted));
143
459
  }
144
460
  });
145
461
 
@@ -148,9 +464,22 @@ export function registerConfigCommand(program) {
148
464
  .description("Set a configuration value")
149
465
  .argument("<key>", "Config key (dot-notation)")
150
466
  .argument("<value>", "Value to set")
151
- .action(async (key, value) => {
152
- setConfigValue(key, value);
153
- logger.success(`Set ${key} = ${value}`);
467
+ .option(
468
+ "--allow-unknown",
469
+ "Allow an unregistered key for extension development",
470
+ )
471
+ .action(async (key, value, options) => {
472
+ if (isSecretConfigKey(key)) {
473
+ logger.error(
474
+ `Refusing a secret in argv for ${key}. Pipe it to "cc config set-secret ${key}" or use its hidden TTY prompt.`,
475
+ );
476
+ process.exitCode = 1;
477
+ return;
478
+ }
479
+ setConfigValue(key, value, {
480
+ allowUnknown: options.allowUnknown === true,
481
+ });
482
+ logger.success(`Set ${key}`);
154
483
  // Claude-Code parity: if the user just pinned a retired/deprecated model
155
484
  // id (llm.model / llm.visionModel / llm.fallbackModel), warn now — at pin
156
485
  // time — rather than only when a later run fails. stderr-only, vitest-safe.
@@ -169,11 +498,173 @@ export function registerConfigCommand(program) {
169
498
  }
170
499
  });
171
500
 
501
+ cmd
502
+ .command("set-secret")
503
+ .description("Set a secret from a hidden TTY prompt or stdin (never argv)")
504
+ .argument("<key>", "Schema-declared secret key")
505
+ .option(
506
+ "--storage <mode>",
507
+ "Storage: auto (OS store then 0600 fallback), keychain, or file",
508
+ "auto",
509
+ )
510
+ .action(async (key, options) => {
511
+ if (!isSecretConfigKey(key)) {
512
+ logger.error(`${key} is not a registered secret key`);
513
+ process.exitCode = 1;
514
+ return;
515
+ }
516
+ const value = await readSecretInput({
517
+ message: `Secret value for ${key}:`,
518
+ });
519
+ if (!value) {
520
+ logger.error("Secret input was empty; configuration was not changed");
521
+ process.exitCode = 1;
522
+ return;
523
+ }
524
+ const result = setSecretConfigValue(key, value, {
525
+ storage: options.storage,
526
+ });
527
+ logger.success(
528
+ `Set ${key} (${result.storage === "keychain" ? result.backend : "owner-only config file"})`,
529
+ );
530
+ });
531
+
532
+ cmd
533
+ .command("schema")
534
+ .description("Print the versioned JSON Schema for config.json")
535
+ .option("--json", "Output JSON (default)")
536
+ .action(() => {
537
+ console.log(JSON.stringify(getConfigJsonSchema(), null, 2));
538
+ });
539
+
540
+ cmd
541
+ .command("validate")
542
+ .description("Validate config.json types, keys and filesystem permissions")
543
+ .option("--fix", "Apply safe migrations and owner-only permissions")
544
+ .option("--allow-unknown", "Permit extension-development keys")
545
+ .option("--json", "Output JSON")
546
+ .action((options) => {
547
+ const permissions = checkConfigStoragePermissions({
548
+ fix: options.fix === true,
549
+ });
550
+ const inspectAndMaybeMigrate = () => {
551
+ const raw = loadUserConfig({ failIfUnavailable: true });
552
+ const migrated = migrateConfigDocument(raw);
553
+ const validation = validateConfigDocument(
554
+ options.fix ? migrated.config : raw,
555
+ { allowUnknown: options.allowUnknown === true },
556
+ );
557
+ if (options.fix && migrated.migrations.length && validation.valid) {
558
+ backupConfigForMigration(
559
+ `.before-schema-v${CONFIG_SCHEMA_VERSION.split(".")[0]}`,
560
+ { applyWindowsAcl: true, failIfUnavailable: true },
561
+ );
562
+ saveConfig(migrated.config);
563
+ }
564
+ return { migrated, validation };
565
+ };
566
+ // Re-read, migrate, back up and save under one cross-process lock. A
567
+ // concurrent `config set` can therefore never be overwritten by a stale
568
+ // pre-migration snapshot.
569
+ const { migrated, validation } = options.fix
570
+ ? withConfigLock(inspectAndMaybeMigrate)
571
+ : inspectAndMaybeMigrate();
572
+ const ok =
573
+ validation.valid &&
574
+ permissions.home.ok &&
575
+ (!permissions.config.exists || permissions.config.ok);
576
+ const result = {
577
+ ok,
578
+ ...validation,
579
+ migrations: migrated.migrations,
580
+ permissions,
581
+ };
582
+ if (options.json) {
583
+ console.log(JSON.stringify(result, null, 2));
584
+ } else if (ok) {
585
+ logger.success(
586
+ `Configuration is valid (schema ${CONFIG_SCHEMA_VERSION})`,
587
+ );
588
+ } else {
589
+ for (const issue of validation.issues) logger.error(issue.message);
590
+ if (!permissions.home.ok) logger.error("Config home is not owner-only");
591
+ if (permissions.config.exists && !permissions.config.ok) {
592
+ logger.error("config.json is not owner-only");
593
+ }
594
+ }
595
+ if (!ok) process.exitCode = 1;
596
+ });
597
+
598
+ cmd
599
+ .command("effective")
600
+ .description("Show the redacted effective configuration and provenance")
601
+ .option("--json", "Output JSON")
602
+ .action(async (options) => {
603
+ const result = await resolveEffectiveConfig();
604
+ if (options.json) {
605
+ console.log(JSON.stringify(result, null, 2));
606
+ return;
607
+ }
608
+ logger.log(
609
+ chalk.bold(`\n Effective config (schema ${result.schemaVersion})\n`),
610
+ );
611
+ printConfig(result.config, " ");
612
+ logger.newline();
613
+ });
614
+
615
+ cmd
616
+ .command("explain")
617
+ .description("Explain a key's type, redacted value, source and policy lock")
618
+ .argument("<key>", "Known config key")
619
+ .option("--json", "Output JSON")
620
+ .action(async (key, options) => {
621
+ const entry = getConfigDescriptor(key);
622
+ if (!entry) {
623
+ logger.error(`Unknown configuration key: ${key}`);
624
+ process.exitCode = 1;
625
+ return;
626
+ }
627
+ const effective = await resolveEffectiveConfig();
628
+ const result = {
629
+ schemaVersion: CONFIG_SCHEMA_VERSION,
630
+ key,
631
+ type: entry.type,
632
+ secret: entry.secret === true || isSecretConfigKey(key),
633
+ scope: entry.scope,
634
+ managedLock: entry.managedLock,
635
+ deprecated: entry.deprecated === true,
636
+ migration: entry.migration || null,
637
+ value: redactConfigValue(key, getNested(effective.config, key)),
638
+ provenance: effective.provenance[key] || {
639
+ source: "unset",
640
+ layer: "unset",
641
+ overridden: [],
642
+ locked: false,
643
+ },
644
+ };
645
+ if (options.json) {
646
+ console.log(JSON.stringify(result, null, 2));
647
+ return;
648
+ }
649
+ logger.log(`${chalk.cyan(key)} = ${String(result.value ?? "(unset)")}`);
650
+ logger.log(
651
+ ` type: ${Array.isArray(result.type) ? result.type.join(" | ") : result.type}`,
652
+ );
653
+ logger.log(` source: ${result.provenance.source}`);
654
+ logger.log(
655
+ ` policy lock: ${result.provenance.locked ? "managed" : "not locked"}`,
656
+ );
657
+ if (result.migration)
658
+ logger.warn(` deprecated; migrate to ${result.migration}`);
659
+ });
660
+
172
661
  cmd
173
662
  .command("edit")
174
663
  .description("Open config file in default editor")
175
664
  .action(async () => {
176
- const configPath = getConfigPath();
665
+ // Existing malformed JSON must reach the editor byte-for-byte; this only
666
+ // repairs owner-only permissions. A missing file is created atomically.
667
+ const configPath = prepareConfigForEdit();
177
668
  const editor =
178
669
  process.env.EDITOR ||
179
670
  process.env.VISUAL ||
@@ -314,18 +805,13 @@ export function registerConfigCommand(program) {
314
805
  });
315
806
  }
316
807
 
317
- function printConfig(obj, indent = "") {
808
+ export function printConfig(obj, indent = "") {
318
809
  for (const [key, value] of Object.entries(obj)) {
319
810
  if (value && typeof value === "object" && !Array.isArray(value)) {
320
811
  logger.log(`${indent}${chalk.cyan(key)}:`);
321
812
  printConfig(value, indent + " ");
322
813
  } else {
323
- const displayValue =
324
- value === null
325
- ? chalk.gray("null")
326
- : key.toLowerCase().includes("key") && value
327
- ? chalk.yellow("****")
328
- : String(value);
814
+ const displayValue = value === null ? chalk.gray("null") : String(value);
329
815
  logger.log(`${indent}${chalk.cyan(key)}: ${displayValue}`);
330
816
  }
331
817
  }
@@ -107,7 +107,10 @@ export function registerDoctorCommand(program) {
107
107
  return;
108
108
  }
109
109
 
110
- const sections = await collectCheckupSections({ cwd: process.cwd() });
110
+ const sections = await collectCheckupSections({
111
+ cwd: process.cwd(),
112
+ verifyWindowsAcl: true,
113
+ });
111
114
  const fixResults = options.fix ? await runCheckupFixes(sections) : null;
112
115
 
113
116
  const checkupErrs = sections
@@ -3475,7 +3475,7 @@ export function registerHubCommand(program) {
3475
3475
  " Separate key/account for the hub? set an object instead:\n" +
3476
3476
  " cc config set hub.llm.provider volcengine\n" +
3477
3477
  " cc config set hub.llm.model doubao-seed-2-1-pro-260628\n" +
3478
- " cc config set hub.llm.apiKeyEnv MY_HUB_KEY (or hub.llm.apiKey <key>)\n" +
3478
+ " cc config set hub.llm.apiKeyEnv MY_HUB_KEY (or: cc config set-secret hub.llm.apiKey)\n" +
3479
3479
  " • Ephemeral: CC_HUB_LLM=config|<provider> cc hub ask … --accept-non-local\n" +
3480
3480
  " (a one-off override still needs an explicit egress flag).",
3481
3481
  )