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,30 +1,113 @@
1
1
  /**
2
- * Pure helpers for the REPL `/btw` aside (Claude-Code parity, one-shot variant).
2
+ * Pure helpers for ephemeral REPL side questions.
3
3
  *
4
- * `/btw <note>` queues a side note that rides ONLY the next message: it is sent
5
- * to the model for that one turn (so it can steer the answer) and then removed,
6
- * so it is never persisted to the session history and never carried into later
7
- * turns — i.e. context without bloat. vscode/readline-free → unit-testable; the
8
- * REPL owns the queue + the inject/restore around the agentLoop call.
4
+ * `/btw <question>` immediately asks a tool-free, single-response question
5
+ * against a snapshot of the current conversation. The snapshot and answer are
6
+ * never added to the parent conversation. `/btw --fork <question>` persists the
7
+ * side thread into an independent child session when the caller has a durable
8
+ * session store.
9
9
  *
10
- * /btw I'm on Windows, use PowerShell → queued, applied to the next turn only
11
- * /btw → usage error (nothing queued)
10
+ * The former "inject a note into the next turn" behavior remains available as
11
+ * `/note-next <note>` so `/btw` can keep the same contract as Claude Code.
12
12
  */
13
13
 
14
14
  /** Parse a `/btw …` line. Returns { text } | { error } | null (not a /btw). */
15
15
  export function parseBtwCommand(trimmed) {
16
16
  const t = String(trimmed == null ? "" : trimmed).trim();
17
17
  if (t !== "/btw" && !t.startsWith("/btw ")) return null;
18
- const text = t.slice("/btw".length).trim();
18
+ let text = t.slice("/btw".length).trim();
19
+ let fork = false;
20
+ if (text === "--fork" || text.startsWith("--fork ")) {
21
+ fork = true;
22
+ text = text.slice("--fork".length).trim();
23
+ }
24
+ if (!text) {
25
+ return {
26
+ error:
27
+ "usage: /btw [--fork] <question> — ask an immediate tool-free side question without changing parent history",
28
+ };
29
+ }
30
+ return fork ? { text, fork: true } : { text };
31
+ }
32
+
33
+ /** Parse the legacy next-turn guidance command. */
34
+ export function parseNoteNextCommand(trimmed) {
35
+ const t = String(trimmed == null ? "" : trimmed).trim();
36
+ if (t !== "/note-next" && !t.startsWith("/note-next ")) return null;
37
+ const text = t.slice("/note-next".length).trim();
19
38
  if (!text) {
20
39
  return {
21
40
  error:
22
- "usage: /btw <note> — a one-off aside for your next message (sent to the model, not saved to history)",
41
+ "usage: /note-next <note> — apply ephemeral guidance to the next main turn",
23
42
  };
24
43
  }
25
44
  return { text };
26
45
  }
27
46
 
47
+ function textContent(content) {
48
+ if (typeof content === "string") return content;
49
+ if (!Array.isArray(content)) return content == null ? "" : String(content);
50
+ return content
51
+ .map((part) => {
52
+ if (typeof part === "string") return part;
53
+ if (part?.type === "text") return String(part.text || "");
54
+ if (part?.type === "image_url" || part?.image_url) return "[image]";
55
+ return "";
56
+ })
57
+ .filter(Boolean)
58
+ .join("\n");
59
+ }
60
+
61
+ /**
62
+ * Build a provider-neutral, tool-free snapshot for a side question. Tool
63
+ * results are retained as quoted user context, but tool-call protocol fields
64
+ * are deliberately removed so the side call cannot continue a tool exchange.
65
+ */
66
+ export function buildBtwMessages(messages, question) {
67
+ const out = [];
68
+ for (const message of Array.isArray(messages) ? messages : []) {
69
+ if (!message || typeof message !== "object") continue;
70
+ const content = textContent(message.content);
71
+ if (!content) continue;
72
+ if (message.role === "system") out.push({ role: "system", content });
73
+ else if (message.role === "assistant")
74
+ out.push({ role: "assistant", content });
75
+ else if (message.role === "tool")
76
+ out.push({ role: "user", content: `[Tool result]\n${content}` });
77
+ else if (message.role === "user") out.push({ role: "user", content });
78
+ }
79
+ out.push({
80
+ role: "system",
81
+ content:
82
+ "Answer the final side question from the supplied conversation context. " +
83
+ "This is an ephemeral, single-response exchange. Do not call or request tools, " +
84
+ "do not change the main task, and answer concisely.",
85
+ });
86
+ out.push({ role: "user", content: String(question || "").trim() });
87
+ return out;
88
+ }
89
+
90
+ /** Run a single tool-free side question through an injected chat function. */
91
+ export async function runBtwQuestion({
92
+ messages,
93
+ question,
94
+ chatFn,
95
+ model,
96
+ maxTokens = 1024,
97
+ } = {}) {
98
+ if (typeof chatFn !== "function") {
99
+ throw new TypeError("/btw requires a chat function");
100
+ }
101
+ const text = String(question || "").trim();
102
+ if (!text) throw new TypeError("/btw requires a question");
103
+ const snapshot = buildBtwMessages(messages, text);
104
+ const answer = await chatFn(snapshot, { model, maxTokens });
105
+ return {
106
+ answer: String(answer == null ? "" : answer),
107
+ snapshot,
108
+ };
109
+ }
110
+
28
111
  /**
29
112
  * Render queued asides into a single tagged block, or null when there is
30
113
  * nothing to add. The note tells the model this is ephemeral user guidance.
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Clipboard-image capability boundary for terminal REPL hosts.
3
+ *
4
+ * Plain Node readline receives pasted text only; it has no portable clipboard
5
+ * image event. We therefore enable image chips solely when an embedding host
6
+ * supplies an explicit, testable `readImage()` binding. Standard terminals get
7
+ * a truthful path-attachment fallback instead of a fake "paste succeeded".
8
+ */
9
+
10
+ export const CLIPBOARD_IMAGE_MEDIA_TYPES = Object.freeze([
11
+ "image/png",
12
+ "image/jpeg",
13
+ "image/gif",
14
+ "image/webp",
15
+ ]);
16
+ export const MAX_CLIPBOARD_IMAGE_BYTES = 20 * 1024 * 1024;
17
+
18
+ export function detectClipboardImageCapability(binding) {
19
+ if (
20
+ binding?.supportsImagePaste === true &&
21
+ typeof binding.readImage === "function"
22
+ ) {
23
+ return {
24
+ supported: true,
25
+ mode: "host-binding",
26
+ reason: "The terminal host exposes clipboard image bytes.",
27
+ };
28
+ }
29
+ return {
30
+ supported: false,
31
+ mode: "path-fallback",
32
+ reason:
33
+ "This terminal exposes pasted text only, not clipboard image bytes. Save the image and paste its png/jpg/gif/webp path to attach it.",
34
+ };
35
+ }
36
+
37
+ function decodeImageData(value) {
38
+ if (Buffer.isBuffer(value)) return value;
39
+ if (value instanceof Uint8Array) return Buffer.from(value);
40
+ if (typeof value !== "string") return null;
41
+ const base64 = value.replace(/^data:[^;,]+;base64,/i, "").trim();
42
+ if (!base64 || !/^[A-Za-z0-9+/]*={0,2}$/.test(base64)) return null;
43
+ try {
44
+ return Buffer.from(base64, "base64");
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Read one image from a trusted host binding and return an OpenAI-shaped image
52
+ * content part (the CLI's provider-neutral internal multimodal shape).
53
+ */
54
+ export async function readClipboardImageChip(binding, options = {}) {
55
+ const capability = detectClipboardImageCapability(binding);
56
+ if (!capability.supported) return { ok: false, ...capability };
57
+ let image;
58
+ try {
59
+ image = await binding.readImage();
60
+ } catch (error) {
61
+ return {
62
+ ok: false,
63
+ supported: true,
64
+ mode: "host-binding",
65
+ reason: `Clipboard image read failed: ${error.message}`,
66
+ };
67
+ }
68
+ if (!image) {
69
+ return {
70
+ ok: false,
71
+ supported: true,
72
+ mode: "host-binding",
73
+ reason: "The clipboard does not currently contain an image.",
74
+ };
75
+ }
76
+ const mediaType = String(image.mediaType || image.type || "").toLowerCase();
77
+ if (!CLIPBOARD_IMAGE_MEDIA_TYPES.includes(mediaType)) {
78
+ return {
79
+ ok: false,
80
+ supported: true,
81
+ mode: "host-binding",
82
+ reason: `Unsupported clipboard image type: ${mediaType || "unknown"}.`,
83
+ };
84
+ }
85
+ const data = decodeImageData(image.data);
86
+ if (!data?.length) {
87
+ return {
88
+ ok: false,
89
+ supported: true,
90
+ mode: "host-binding",
91
+ reason: "The clipboard image payload is empty or invalid.",
92
+ };
93
+ }
94
+ const maxBytes = Math.max(
95
+ 1,
96
+ Number(options.maxBytes) || MAX_CLIPBOARD_IMAGE_BYTES,
97
+ );
98
+ if (data.length > maxBytes) {
99
+ return {
100
+ ok: false,
101
+ supported: true,
102
+ mode: "host-binding",
103
+ reason: `Clipboard image exceeds ${maxBytes} bytes.`,
104
+ };
105
+ }
106
+ return {
107
+ ok: true,
108
+ supported: true,
109
+ mode: "host-binding",
110
+ bytes: data.length,
111
+ mediaType,
112
+ chip: {
113
+ type: "image_url",
114
+ image_url: {
115
+ url: `data:${mediaType};base64,${data.toString("base64")}`,
116
+ },
117
+ },
118
+ };
119
+ }
@@ -1,141 +1,93 @@
1
- /**
2
- * `/config` REPL command (Claude-Code parity) — show the effective
3
- * configuration in a readable, SECRET-SAFE form: the LLM provider/model/baseURL
4
- * actually in effect, whether an API key is set (never the key itself), the
5
- * web-search backend, and the config-file path. Also surfaces the session's
6
- * active provider/model, which can differ from the file (a --provider flag or
7
- * .claude/settings.json overrides it).
8
- *
9
- * Pure: takes the loaded config + context, returns plain text. The REPL does
10
- * the I/O. NEVER prints a secret — only "set (…1234)" / "not set".
11
- */
1
+ /** Secret-safe rendering and parsing for the interactive `/config` command. */
2
+ import {
3
+ isSecretConfigKey,
4
+ redactConfigValue,
5
+ } from "../lib/config-redaction.js";
12
6
 
13
- /** Mask a secret: presence + last 4 chars only, or "not set". */
14
- export function maskSecret(v) {
15
- if (v == null || v === "") return "not set";
16
- const s = String(v);
17
- return s.length <= 4 ? "set (hidden)" : `set (…${s.slice(-4)})`;
18
- }
7
+ export { isSecretConfigKey } from "../lib/config-redaction.js";
19
8
 
20
- /**
21
- * A config key whose value must never be echoed in plaintext in the
22
- * (shoulder-surfable) interactive REPL — apiKey / secret / token / password.
23
- * Matched on the last dotted segment (e.g. `llm.apiKey`, `webSearch.apiKey`).
24
- */
25
- const SECRET_KEY_RE = /(api[_-]?key|secret|token|password|passwd)$/i;
26
- export function isSecretConfigKey(key) {
27
- if (!key) return false;
28
- const last = String(key).split(".").pop();
29
- return SECRET_KEY_RE.test(last);
9
+ /** Report only presence; never retain a suffix from a credential. */
10
+ export function maskSecret(value) {
11
+ return value == null || value === "" ? "not set" : "set (hidden)";
30
12
  }
31
13
 
32
- /**
33
- * Parse the argument string after `/config` into an action.
34
- * Mirrors Claude Code's `/config key=value` syntax, and also accepts the
35
- * `/config key value` form. Returns one of:
36
- * { action: "show" } // `/config`
37
- * { action: "get", key } // `/config llm.model`
38
- * { action: "set", key, value } // `/config llm.model=opus` | `/config llm.model opus`
39
- * { action: "error", message }
40
- * `value` is the raw string; the caller coerces (true/false/null/number) via
41
- * config-manager's setConfigValue.
42
- *
43
- * @param {string} argStr everything after the literal `/config`
44
- */
45
14
  export function parseConfigCommand(argStr) {
46
- const s = (argStr || "").trim();
47
- if (s === "") return { action: "show" };
48
-
49
- // `/config --help` | `-h` | `help` | `?` (Claude-Code 2.1.183 parity) — list
50
- // the common config keys. Checked before `=` / `key value` so `help` isn't
51
- // mistaken for a key read.
52
- if (/^(--help|-h|help|\?)$/i.test(s)) return { action: "help" };
53
-
54
- const eq = s.indexOf("=");
55
- if (eq !== -1) {
56
- const key = s.slice(0, eq).trim();
57
- const value = s.slice(eq + 1).trim();
15
+ const input = (argStr || "").trim();
16
+ if (input === "") return { action: "show" };
17
+ if (/^(--help|-h|help|\?)$/i.test(input)) return { action: "help" };
18
+
19
+ const equals = input.indexOf("=");
20
+ if (equals !== -1) {
21
+ const key = input.slice(0, equals).trim();
22
+ const value = input.slice(equals + 1).trim();
58
23
  if (!key) return { action: "error", message: "missing key before '='" };
59
24
  return { action: "set", key, value };
60
25
  }
61
26
 
62
- // `key value` — split on the first run of whitespace.
63
- const m = s.match(/^(\S+)\s+([\s\S]+)$/);
64
- if (m) return { action: "set", key: m[1], value: m[2].trim() };
65
-
66
- // Bare token → read that key.
67
- return { action: "get", key: s };
27
+ const spaced = input.match(/^(\S+)\s+([\s\S]+)$/);
28
+ if (spaced) {
29
+ return { action: "set", key: spaced[1], value: spaced[2].trim() };
30
+ }
31
+ return { action: "get", key: input };
68
32
  }
69
33
 
70
- /**
71
- * The common config keys, surfaced by `/config --help`. cc's `/config` accepts
72
- * any dotted key (free-form), so this is a curated quick-reference of the keys
73
- * the CLI actually reads — not an exhaustive schema.
74
- */
75
34
  export const COMMON_CONFIG_KEYS = Object.freeze([
76
- [
77
- "llm.provider",
78
- "LLM provider (ollama | volcengine | anthropic | openai | …)",
79
- ],
35
+ ["llm.provider", "LLM provider id"],
80
36
  ["llm.model", "default text model id"],
81
- ["llm.visionModel", "model used for image turns (falls back to a default)"],
37
+ ["llm.visionModel", "model used for image turns"],
82
38
  ["llm.baseUrl", "provider API base URL"],
83
- ["llm.apiKey", "provider API key (stored masked; env *_API_KEY overrides)"],
84
- [
85
- "webSearch.provider",
86
- "web_search backend (auto | tavily | brave | duckduckgo | …)",
87
- ],
88
- ["webSearch.apiKey", "web-search API key"],
39
+ ["llm.apiKey", "provider API key (use cc config set-secret)"],
40
+ ["webSearch.provider", "web-search backend"],
41
+ ["webSearch.apiKey", "web-search API key (use cc config set-secret)"],
89
42
  ["cli.theme", "REPL color theme (auto | dark | light | mono)"],
90
43
  ]);
91
44
 
92
- /** Render `/config --help`: usage + the common config keys. */
93
45
  export function renderConfigHelp() {
94
46
  const lines = [
95
- "/config — show or edit configuration:",
47
+ "/config — show or edit non-secret configuration:",
96
48
  " /config show effective config (secret-safe)",
97
- " /config <key> read a value (e.g. /config llm.model)",
98
- " /config <key>=<value> set a value (e.g. /config llm.model=opus)",
99
- " /config <key> <value> set a value (space form)",
49
+ " /config <key> read a value",
50
+ " /config <key>=<value> set a non-secret value",
51
+ " /config <key> <value> set a non-secret value",
100
52
  " /config --help this list",
101
53
  "",
102
54
  "Common keys:",
103
55
  ];
104
- const width = Math.max(...COMMON_CONFIG_KEYS.map(([k]) => k.length));
105
- for (const [key, desc] of COMMON_CONFIG_KEYS) {
106
- lines.push(` ${key.padEnd(width)} ${desc}`);
56
+ const width = Math.max(...COMMON_CONFIG_KEYS.map(([key]) => key.length));
57
+ for (const [key, description] of COMMON_CONFIG_KEYS) {
58
+ lines.push(` ${key.padEnd(width)} ${description}`);
107
59
  }
108
60
  lines.push("");
109
- lines.push(" (any dotted key is accepted; keys are stored in config.json)");
61
+ lines.push(
62
+ " Unknown keys are rejected; use `cc config set --allow-unknown` only for extension development.",
63
+ );
64
+ lines.push(
65
+ " Secrets cannot be set here; use the hidden `cc config set-secret <key>` input.",
66
+ );
110
67
  return lines.join("\n");
111
68
  }
112
69
 
113
- /** Render a single config value for `/config <key>`, masking secrets. */
114
70
  export function renderConfigGet(key, value) {
115
71
  if (value === undefined) return `${key} = (unset)`;
116
72
  if (isSecretConfigKey(key)) return `${key} = ${maskSecret(value)}`;
73
+ const safe = redactConfigValue(key, value);
117
74
  const shown =
118
- value !== null && typeof value === "object"
119
- ? JSON.stringify(value)
120
- : String(value);
75
+ safe !== null && typeof safe === "object"
76
+ ? JSON.stringify(safe)
77
+ : String(safe);
121
78
  return `${key} = ${shown}`;
122
79
  }
123
80
 
124
- /** Render the confirmation line after `/config <key>=<value>`. */
125
81
  export function renderConfigSet(key, storedValue) {
126
82
  if (isSecretConfigKey(key)) return `set ${key} = ${maskSecret(storedValue)}`;
83
+ const safe = redactConfigValue(key, storedValue);
127
84
  const shown =
128
- storedValue !== null && typeof storedValue === "object"
129
- ? JSON.stringify(storedValue)
130
- : String(storedValue);
85
+ safe !== null && typeof safe === "object"
86
+ ? JSON.stringify(safe)
87
+ : String(safe);
131
88
  return `set ${key} = ${shown}`;
132
89
  }
133
90
 
134
- /**
135
- * @param {object|null} config loaded config.json
136
- * @param {object} [opts] { path, activeProvider, activeModel }
137
- * @returns {string}
138
- */
139
91
  export function renderConfigSummary(config, opts = {}) {
140
92
  const cfg = config || {};
141
93
  const llm = cfg.llm || {};
@@ -143,31 +95,35 @@ export function renderConfigSummary(config, opts = {}) {
143
95
  if (opts.path) lines.push(` config file: ${opts.path}`);
144
96
 
145
97
  lines.push(" llm:");
146
- lines.push(` provider: ${llm.provider || "(unset → defaults to ollama)"}`);
98
+ lines.push(` provider: ${llm.provider || "(unset; defaults to ollama)"}`);
147
99
  lines.push(` model: ${llm.model || "(unset)"}`);
148
100
  if (llm.visionModel) lines.push(` vision: ${llm.visionModel}`);
149
- if (llm.baseUrl) lines.push(` baseUrl: ${llm.baseUrl}`);
101
+ if (llm.baseUrl)
102
+ lines.push(
103
+ ` baseUrl: ${redactConfigValue("llm.baseUrl", llm.baseUrl)}`,
104
+ );
150
105
  lines.push(` apiKey: ${maskSecret(llm.apiKey)}`);
151
106
 
152
- const ws = cfg.webSearch || {};
153
- if (ws.provider || ws.apiKey) {
107
+ const webSearch = cfg.webSearch || {};
108
+ if (webSearch.provider || webSearch.apiKey) {
154
109
  lines.push(" webSearch:");
155
- lines.push(` provider: ${ws.provider || "(unset → auto)"}`);
156
- lines.push(` apiKey: ${maskSecret(ws.apiKey)}`);
110
+ lines.push(` provider: ${webSearch.provider || "(unset; auto)"}`);
111
+ lines.push(` apiKey: ${maskSecret(webSearch.apiKey)}`);
157
112
  }
158
113
 
159
114
  if (opts.activeProvider || opts.activeModel) {
160
- const ap = opts.activeProvider || "?";
161
- const am = opts.activeModel || "?";
162
- const differs = !!llm.provider && (ap !== llm.provider || am !== llm.model);
115
+ const provider = opts.activeProvider || "?";
116
+ const model = opts.activeModel || "?";
117
+ const differs =
118
+ Boolean(llm.provider) &&
119
+ (provider !== llm.provider || model !== llm.model);
163
120
  lines.push(
164
- ` active this session: ${ap} · ${am}` +
165
- (differs ? " (overrides config)" : ""),
121
+ ` active this session: ${provider} · ${model}${differs ? " (overrides config)" : ""}`,
166
122
  );
167
123
  }
168
124
 
169
125
  lines.push(
170
- " note: keys are hidden; env vars (e.g. *_API_KEY) can override config at runtime.",
126
+ " note: secret values are hidden; environment variables can override config at runtime.",
171
127
  );
172
128
  return lines.join("\n");
173
129
  }