chainlesschain 0.162.160 → 0.162.161

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 (179) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-CkRHjW8e.js → AIOps-DMn528q-.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BP3MeNi2.js → ActionButton-D9ZcDCJL.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-CjbjQsOr.js → Analytics-A_K-8PX0.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-i0adH1M8.js → AppLayout-D4pFW3X6.js} +3 -3
  6. package/src/assets/web-panel/assets/{Artifacts-CCCG2GOU.js → Artifacts-Dz46COAd.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-DrsgvwHC.js → Audit-cbMjbyg0.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DkXNkbZM.js → BackgroundAgents-Dtf88GAj.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DarTWCex.js → Backup-C5KRxn52.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-DaDzhcto.js → BaseInput-Dd2UK3BN.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-C4EzGw6V.js → Chat-lptKTFdG.js} +6 -6
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-C2KLtwHz.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-gddNgaQi.js → Checkbox-_yspG6rG.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-BKldFWf9.js → Codegen-BGq_GAha.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-ChR-brDs.js → Col-CePor71g.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-DlHtZX86.js → Community-CLOWhIT7.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BAhfcBpC.js → Compact-CivJt2vT.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-gIrKkm6m.js → Compliance-Btmo1GGE.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-BYnzLBO3.js → Cowork-Ct35OlG4.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-ByUDIljI.js → Cron-CTc2GmhB.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-DOdNbHFp.js → Crosschain-ZtiBETk1.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-BJHaNWD2.js → DID-BNqMQQXw.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-Drm_tClz.js → Dashboard-BmzZd-9V.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-CA1WLzGN.js → Dropdown-CMVgvP2M.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-Di1SKjNO.js → EmailListRenderer-CcqQFAfT.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-44Ve7ZFe.js → FamilyGuardDashboard-CTqB1_4V.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-CubPwv_N.js → Federation-CiKOOzlb.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CsUFe5bU.js → FormItemContext-Wk-OT0gr.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-D7xRjPjZ.js → GenericCardRenderer-DbEQT6ue.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-D-Qx9dhO.js → Git-0ZvCPSD9.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-_YMYaU4n.js → Governance-CmVuKkPb.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-J7Yzh-K_.js → Inference-CTWE3Jwg.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-D37iI_Mo.js → KnowledgeGraph-CBEIF00L.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-oMTSYfGY.js → Logs-DLhxDwVG.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-DxywvhTU.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-DKUqYDaF.js → Marketplace-BgsCBrnc.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-BEv3Gx61.js → McpTools-ClBUGDS2.js} +3 -3
  38. package/src/assets/web-panel/assets/{Memory-CtA8XD2y.js → Memory-CnG_ZnYw.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-ug7c1mMj.js → MobileBridge-BUOAbR1Z.js} +1 -1
  40. package/src/assets/web-panel/assets/MobileProjects-Dnt_9-WB.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-WJaMs4i2.js → Mtc-CLjt4kCD.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-DXnK_-ru.js → MtcAudit-f24U9Aes.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-C4Ev7726.js → Multisig-GrmGQbSq.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-BMFb9_zk.js → NLProgramming-DADaWn-n.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-Bl93nvBX.js → Notes-xtf5RX6C.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-BN2W5cl6.js → NotificationSettings-Cd27Rgtx.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-Dxc9oN4o.js → OrderTableRenderer-fXRxlDjl.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-CAs48637.js → Organization-joCFlNB0.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Bhq27Zoc.js → Overflow-B1HoURq0.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-D61-2542.js → P2P-DiwsKbT7.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-C1j4iUxz.js → PdhVaultBrowser-Xe-BsW6S.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-rJ2-fScM.js → Permissions-C23qi8kl.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-DFIlTok6.js → PersonalDataHub-BS1syX2f.js} +2 -2
  54. package/src/assets/web-panel/assets/{Pipeline-BjIgEWoZ.js → Pipeline-DRYwwDyh.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-BQoH5wcX.js → Privacy-BQKaDHPH.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-CYR_-_Ub.js → ProjectInit-BC6F9xiG.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-nkatCq-9.js → ProjectSettings-ClFPc1Nd.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-SS9uZKCl.js → Projects-Dn-f5aYe.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-BnKM9fsF.js → Providers-CLWuOUNt.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-Cfe82dbz.js → QrScannerModal-DiqULTxb.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-r1RbPufV.js → QuickAsk-9A03P-E_.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-CjCbM2WE.js → Recommend-CJZAnbq_.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-BuMGPH6V.js → RemoteSession-C9A1R77h.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-Bmj3NY1F.js → Reputation-BIZc6Rky.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-BIsNcE_1.js → Row-DfIPNtuG.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-BObmojD2.js → RssFeed-C5znFcQ1.js} +2 -2
  67. package/src/assets/web-panel/assets/{Search-BRmbkQNS.js → Search-DSs2z3OX.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-_rF3DRpY.js → Security-CV6LcrLY.js} +3 -3
  69. package/src/assets/web-panel/assets/{Services-D0If9ZV4.js → Services-cmhoX0Xj.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-o7zIksUg.js → Skeleton-tCsg2po7.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-oUR7zi9u.js → Skills-BK1KUDiy.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-fqKyGi03.js → Sla-yRgyeA82.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-B1wZ_gxx.js → SpeechSettings-c1mo1mlp.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-B3qJWYXq.js → SyncSettings-koIAfuT3.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-BH5_dUfr.js → Tasks-DkkreAaB.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-CCIVpjRP.js → Templates-fy5Ctf9M.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-2GZtTGnB.js → Tenant-Bw70Jf6S.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-BlMkfs_u.js → Terminal-BKh6Rx-4.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-U6hi5OMc.js → TimelineRenderer-Dg54WP0c.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-C-_BerGJ.js → Tokens-BvvD5SxJ.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-DaKzBgN3.js → Trigger-B7Ug9x4e.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-CLvcsco3.js → Trust-BjvuMORY.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-BFn_Y1zZ.js → UkeySign-CZqhkx8p.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-B0V18dLT.js → VideoEditing-ClR50lhX.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-BbmP7Imu.js → Wallet-DlfppYjx.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-Dewj_0kt.js → WebAuthn-BirgVr8B.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-DOxz3Lwa.js → WorkflowEditor-B8DP_bax.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-B1OIpZnh.js → chat-DA8AUZzL.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-CSGNVdri.js → colors-C38pLGp1.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-8S0vcg0u.js → compact-item-81rtr98o.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-vZyc27TN.js → createContext-D34ixq8t.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CHDIEOeN.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-DWw3-UhA.js → hasIn-D4bzqTrZ.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-dxocDVD_.js → index-9qoVpPt6.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-xx5M5Rbj.js → index-B0QArPQt.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DtHWHJnj.js → index-B8mkLM4x.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DLgkAhEE.js → index-BIP62a6r.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-tr1x96W9.js → index-BP-zkXK8.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CfEvacz7.js → index-BS3M5H9V.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-D1i_8oop.js → index-BXd2_LmH.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BDHyovnK.js → index-BlxEphl7.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CLPr2vC_.js → index-BqIhLAbA.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BQssf0EQ.js → index-BtGxuQrO.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BuB5P0TR.js → index-BvD7b2IK.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DeCS12Mh.js → index-BvL_3J_n.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BeBv896m.js → index-COe_cOLJ.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Dc40pX3F.js → index-CP5alL4t.js} +1 -1
  108. package/src/assets/web-panel/assets/index-CY1NURWZ.js +1 -0
  109. package/src/assets/web-panel/assets/{index-B4pP2ycr.js → index-CbhE3j5j.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DKwl1AkQ.js → index-Cd3KuNK5.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BZnauCqN.js → index-CoVgZw_b.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BwKrTVV0.js → index-CuS-UPoj.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Q6oyLnKC.js → index-D0Ih7Hwn.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CB2MOS_8.js → index-D3zCCZRS.js} +3 -3
  115. package/src/assets/web-panel/assets/{index-BdyokEau.js → index-D6GfvEQG.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DPgY5GLy.js → index-DBFSo1NF.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CFQWZvak.js → index-DFHa1HIg.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BjC-TrOb.js → index-DFyWKOBD.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Dg0Izipr.js → index-DMgnRwrK.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BKEmQQvR.js → index-DUQLXLQM.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DLAvUtOH.js → index-D_2VYPr1.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-D8qXVfoV.js → index-DakfFZ-k.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DcfLXAW7.js → index-Ddk0e_Pi.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BoIPHP4R.js → index-DkHqMnn3.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CJgKP2cm.js → index-Dmo3dFHb.js} +1 -1
  126. package/src/assets/web-panel/assets/index-DokUYqpq.js +1 -0
  127. package/src/assets/web-panel/assets/{index-C6r27A-o.js → index-DvfCEJG-.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CbZqw7pg.js → index-E1OJRXs4.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BkWd6YL7.js → index-F76w1NiL.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-t-q3rkVm.js → index-ZRJRItm0.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CwXBblm-.js → index-fI5sXMLg.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CI3slBKI.js → index-tKiC8T-4.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-Di5YFId0.js → initDefaultProps-ByyvflIR.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BVSN0aeL.js → motion-B3FQm2By.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-DHNiaP2l.js → move-BSfns6Ef.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-xJPf3gQD.js → mtc-parser-CTG1Ieri.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-C7qzUdkN.js → omit-DObM_2j6.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-pSpjg3Le.js → pickAttrs-DOfelQ1t.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-cs_jL_UC.js → placementArrow-CHZILds_.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-DkS_Zs4r.js → responsiveObserve-REbucKSx.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-B5O1Kpxo.js → slide-C6EZzD7o.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-BX02GnZp.js → statusUtils-BxkWS-g3.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-EmBYRftd.js → styleChecker-Chklyoq6.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-ZGzN1cU8.js → useFlexGapSupport-CRVwKrrI.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-CfP7M1m7.js → useFs-DV24ik_J.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CbIPHgNh.js → usePersonalDataHub-C7vIo4Pg.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-7xh0If_O.js → vnode-By-v5GlF.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DmitvTR2.js → zoom-B1w9Am3r.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/commands/agenda.js +15 -1
  151. package/src/commands/agent.js +7 -0
  152. package/src/commands/background-session.js +16 -2
  153. package/src/data/changelog.json +7 -2
  154. package/src/gateways/ws/background-agent-protocol.js +88 -14
  155. package/src/lib/agent-authority.js +251 -0
  156. package/src/lib/background-agent-phase.js +100 -0
  157. package/src/lib/background-agent-supervisor.js +288 -8
  158. package/src/lib/backpressure-policy.js +105 -0
  159. package/src/lib/capability-negotiation.js +212 -0
  160. package/src/lib/credential-guard.js +11 -0
  161. package/src/lib/credential-proxy.js +182 -0
  162. package/src/lib/event-seq-replay.js +167 -0
  163. package/src/lib/goal-condition-engine.js +369 -0
  164. package/src/lib/headless-manifest.js +13 -0
  165. package/src/lib/ide-context.js +53 -14
  166. package/src/lib/project-instructions.js +98 -1
  167. package/src/lib/remote-path-mapping.js +229 -0
  168. package/src/lib/schedule-planner.js +136 -0
  169. package/src/repl/bg-dashboard.js +13 -12
  170. package/src/runtime/agent-core.js +11 -4
  171. package/src/runtime/headless-stream.js +195 -11
  172. package/src/runtime/system-prompt.js +3 -0
  173. package/src/workers/background-agent-worker.js +37 -2
  174. package/src/assets/web-panel/assets/ChatBubbleRenderer-lkavIWMS.js +0 -1
  175. package/src/assets/web-panel/assets/MarkdownRenderer-BqaPmC0W.js +0 -1
  176. package/src/assets/web-panel/assets/MobileProjects-BpX5g9It.js +0 -1
  177. package/src/assets/web-panel/assets/devWarning-DYEZcY55.js +0 -1
  178. package/src/assets/web-panel/assets/index-DmVFfcNR.js +0 -1
  179. package/src/assets/web-panel/assets/index-x7YyhMUa.js +0 -1
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Remote URI ↔ filesystem path mapping for the IDE bridge.
3
+ *
4
+ * A local IDE (VS Code / JetBrains) can report a file in a representation that
5
+ * does not exist on the host `cc` runs on, so inlining it into the prompt makes
6
+ * the agent's read_file/edit_file target a path the CLI host can't see:
7
+ * - a URI: file:///c:/code/my%20proj/文件.ts
8
+ * vscode-remote://wsl+Ubuntu/home/u/x
9
+ * vscode-remote://ssh-remote+host/home/u/x
10
+ * vscode-remote://dev-container+<hex>/workspaces/x
11
+ * - a WSL UNC path from a Windows host: \\wsl.localhost\Ubuntu\home\u\x
12
+ * (older Windows builds: \\wsl$\Ubuntu\home\u\x)
13
+ * - a Windows drive path while cc runs INSIDE WSL: C:\code\x == /mnt/c/code/x
14
+ *
15
+ * normalizeIdePathForCli() folds these foreign forms into the CLI's native fs
16
+ * path; anything already native (or unrecognized) passes through byte-for-byte.
17
+ * cliPathToIdeUri() is the reverse, for surfaces that must hand a URI back to
18
+ * the editor.
19
+ *
20
+ * Pure: string transforms only (no fs / process). Percent-decoding preserves
21
+ * spaces and non-ASCII (中文) exactly, so round-trips are lossless.
22
+ */
23
+
24
+ /** decodeURIComponent that never throws on a malformed % sequence. */
25
+ function decodeSafe(s) {
26
+ if (typeof s !== "string") return s;
27
+ try {
28
+ return decodeURIComponent(s);
29
+ } catch {
30
+ return s; // leave a malformed sequence as-is rather than lose the value
31
+ }
32
+ }
33
+
34
+ /** Has a `scheme://` prefix (a URI, not a bare path). */
35
+ export function looksLikeUri(value) {
36
+ return typeof value === "string" && /^[a-z][a-z0-9.+-]*:\/\//i.test(value);
37
+ }
38
+
39
+ /** `C:\…` or `C:/…` — a Windows drive-absolute path. */
40
+ export function looksLikeWindowsPath(value) {
41
+ return typeof value === "string" && /^[a-zA-Z]:[\\/]/.test(value);
42
+ }
43
+
44
+ /** `\\host\…` or `//host/…` — a UNC path. */
45
+ function looksLikeUnc(value) {
46
+ return typeof value === "string" && /^(\\\\|\/\/)[^\\/]/.test(value);
47
+ }
48
+
49
+ const WSL_UNC_RE =
50
+ /^(?:\\\\|\/\/)(?:wsl\.localhost|wsl\$)[\\/]([^\\/]+)[\\/]?(.*)$/i;
51
+
52
+ /**
53
+ * `\\wsl.localhost\Ubuntu\home\u\x` (or `\\wsl$\…`, forward-slash variants) →
54
+ * `{ distro:"Ubuntu", posix:"/home/u/x" }`, or null when not a WSL UNC path.
55
+ */
56
+ export function wslUncToPosix(value) {
57
+ if (typeof value !== "string") return null;
58
+ const m = value.match(WSL_UNC_RE);
59
+ if (!m) return null;
60
+ const distro = m[1];
61
+ const rest = (m[2] || "").replace(/\\/g, "/");
62
+ return { distro, posix: "/" + rest.replace(/^\/+/, "") };
63
+ }
64
+
65
+ /** `/home/u/x` + distro → `\\wsl.localhost\Ubuntu\home\u\x` (host overridable). */
66
+ export function posixToWslUnc(posix, distro, { host = "wsl.localhost" } = {}) {
67
+ if (typeof posix !== "string" || !distro) return null;
68
+ const win = posix.replace(/^\/+/, "").replace(/\//g, "\\");
69
+ return `\\\\${host}\\${distro}\\${win}`;
70
+ }
71
+
72
+ /** `C:\code\x` → `/mnt/c/code/x`, or null when not a drive path. */
73
+ export function winDriveToWslMount(value) {
74
+ if (!looksLikeWindowsPath(value)) return null;
75
+ const drive = value[0].toLowerCase();
76
+ const rest = value.slice(2).replace(/\\/g, "/").replace(/^\/+/, "");
77
+ return `/mnt/${drive}${rest ? "/" + rest : ""}`;
78
+ }
79
+
80
+ const WSL_MOUNT_RE = /^\/mnt\/([a-zA-Z])(?:\/(.*))?$/;
81
+
82
+ /** `/mnt/c/code/x` → `C:\code\x`, or null when not a /mnt/<drive> path. */
83
+ export function wslMountToWinDrive(value) {
84
+ if (typeof value !== "string") return null;
85
+ const m = value.match(WSL_MOUNT_RE);
86
+ if (!m) return null;
87
+ const drive = m[1].toUpperCase();
88
+ const rest = (m[2] || "").replace(/\//g, "\\");
89
+ return `${drive}:\\${rest}`;
90
+ }
91
+
92
+ /**
93
+ * Parse an IDE URI into its parts. Returns null for a non-URI or an unknown
94
+ * scheme (so the caller leaves it untouched).
95
+ * { scheme, remoteKind, remoteParam, fsPath }
96
+ * `fsPath` is the decoded on-host path: a Windows drive path for a `file://`
97
+ * drive URI, else POSIX. `remoteKind`/`remoteParam` are set for vscode-remote.
98
+ */
99
+ export function parseRemoteUri(uri) {
100
+ if (!looksLikeUri(uri)) return null;
101
+ const m = uri.match(/^([a-z][a-z0-9.+-]*):\/\/([^/]*)((?:\/[^?#]*)?)/i);
102
+ if (!m) return null;
103
+ const scheme = m[1].toLowerCase();
104
+ const authority = m[2] || "";
105
+ const rawPath = m[3] || "";
106
+
107
+ if (scheme === "file") {
108
+ if (authority) {
109
+ // file://server/share/… → UNC \\server\share\…
110
+ const unc = "\\\\" + authority + rawPath.replace(/\//g, "\\");
111
+ return {
112
+ scheme,
113
+ remoteKind: null,
114
+ remoteParam: null,
115
+ fsPath: decodeSafe(unc),
116
+ };
117
+ }
118
+ const decoded = decodeSafe(rawPath);
119
+ // /c:/code/x → c:\code\x (Windows drive URI); else a POSIX path.
120
+ if (/^\/[a-zA-Z]:/.test(decoded)) {
121
+ return {
122
+ scheme,
123
+ remoteKind: null,
124
+ remoteParam: null,
125
+ fsPath: decoded.slice(1).replace(/\//g, "\\"),
126
+ };
127
+ }
128
+ return {
129
+ scheme,
130
+ remoteKind: null,
131
+ remoteParam: null,
132
+ fsPath: decoded || "/",
133
+ };
134
+ }
135
+
136
+ if (scheme === "vscode-remote" || scheme === "vscode-vfs") {
137
+ // authority = "<kind>+<param>", where `+` may be percent-encoded (%2B).
138
+ const auth = decodeSafe(authority);
139
+ const plus = auth.indexOf("+");
140
+ const remoteKind = plus >= 0 ? auth.slice(0, plus) : auth;
141
+ const remoteParam = plus >= 0 ? auth.slice(plus + 1) : null;
142
+ return {
143
+ scheme,
144
+ remoteKind: remoteKind || null,
145
+ remoteParam: remoteParam || null,
146
+ fsPath: decodeSafe(rawPath) || "/",
147
+ };
148
+ }
149
+
150
+ return null; // unknown scheme — don't guess
151
+ }
152
+
153
+ /**
154
+ * Detect the running CLI's WSL context from env (best-effort). Returns
155
+ * `{ isWsl, distro }`. Injected in tests; ide-context passes process.env.
156
+ */
157
+ export function detectWsl(env = {}) {
158
+ const distro = env.WSL_DISTRO_NAME || null;
159
+ const isWsl = Boolean(distro || env.WSL_INTEROP);
160
+ return { isWsl, distro };
161
+ }
162
+
163
+ /**
164
+ * Fold an IDE-reported file value into the path `cc` can actually open on THIS
165
+ * host. Only recognized foreign forms are rewritten; a native or unrecognized
166
+ * value is returned unchanged (byte-for-byte).
167
+ *
168
+ * @param {string} value URI or path as the IDE reported it
169
+ * @param {object} [opts]
170
+ * @param {string} [opts.platform=process.platform] the CLI host platform
171
+ * @param {{isWsl?:boolean, distro?:string}} [opts.wsl] WSL context (see detectWsl)
172
+ * @returns {string}
173
+ */
174
+ export function normalizeIdePathForCli(value, opts = {}) {
175
+ if (typeof value !== "string" || value.length === 0) return value;
176
+ const platform = opts.platform || process.platform;
177
+ const wsl = opts.wsl || {};
178
+ const onWindows = platform === "win32";
179
+
180
+ // 1) Resolve a URI down to its on-host fsPath first.
181
+ let base = value;
182
+ let remoteKind = null;
183
+ let remoteParam = null;
184
+ if (looksLikeUri(value)) {
185
+ const parsed = parseRemoteUri(value);
186
+ if (!parsed) return value; // unknown scheme → leave untouched
187
+ base = parsed.fsPath;
188
+ remoteKind = parsed.remoteKind;
189
+ remoteParam = parsed.remoteParam;
190
+ }
191
+
192
+ if (onWindows) {
193
+ // Native form is a Windows path. A POSIX path from a wsl-remote URI is
194
+ // reachable from Windows as a \\wsl.localhost\<distro>\… UNC.
195
+ if (remoteKind === "wsl" && remoteParam && base.startsWith("/")) {
196
+ return posixToWslUnc(base, remoteParam) || base;
197
+ }
198
+ return base;
199
+ }
200
+
201
+ // Native form is POSIX (Linux remote-host or inside WSL).
202
+ const wslUnc = wslUncToPosix(base);
203
+ if (wslUnc) return wslUnc.posix;
204
+ if (looksLikeWindowsPath(base) && wsl.isWsl) {
205
+ return winDriveToWslMount(base) || base;
206
+ }
207
+ return base;
208
+ }
209
+
210
+ /**
211
+ * Reverse: a CLI-native fs path → a URI the editor can open. `remoteAuthority`
212
+ * (e.g. "wsl+Ubuntu", "ssh-remote+host") produces a vscode-remote URI; without
213
+ * it, a `file://` URI. Percent-encodes spaces / non-ASCII per component.
214
+ */
215
+ export function cliPathToIdeUri(fsPath, { remoteAuthority } = {}) {
216
+ if (typeof fsPath !== "string" || fsPath.length === 0) return fsPath;
217
+ const isWinDrive = looksLikeWindowsPath(fsPath);
218
+ const posixish = fsPath.replace(/\\/g, "/");
219
+ const encoded = posixish
220
+ .split("/")
221
+ .map((seg) => (/^[a-zA-Z]:$/.test(seg) ? seg : encodeURIComponent(seg)))
222
+ .join("/");
223
+ if (remoteAuthority) {
224
+ const path = encoded.startsWith("/") ? encoded : "/" + encoded;
225
+ return `vscode-remote://${remoteAuthority}${path}`;
226
+ }
227
+ const path = isWinDrive ? "/" + encoded : encoded;
228
+ return `file://${path.startsWith("/") ? "" : "/"}${path}`;
229
+ }
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Pure scheduling planner for the agent Scheduler / Monitor (P1 §"统一持久
3
+ * Scheduler、Monitor 和 Channel").
4
+ *
5
+ * The persisted store ([[agent-schedule-store.js]]) already guarantees the
6
+ * catch-up invariant — a cron down for N periods fires ONCE, not N times,
7
+ * because `advanceCron` jumps to `nextCronTime(now)` rather than stepping
8
+ * through every miss. This module adds the pieces a unified daemon event
9
+ * runtime still needs, all as PURE, clock-injected functions (no timers, no
10
+ * RNG, deterministic across restarts):
11
+ *
12
+ * - **deterministic jitter** — spread tasks that share a cron minute (e.g.
13
+ * every `0 * * * *`) by a STABLE per-task offset, so a shared tick is not a
14
+ * thundering herd. The offset is a hash of the task id, so it never moves
15
+ * across a restart (an RNG offset would, defeating the point).
16
+ * - **adaptive next-wakeup** — the earliest future fire time, so a daemon
17
+ * sleeps until then instead of polling.
18
+ * - **expiry** — a task past `expiresAt` retires without a final fire.
19
+ *
20
+ * A daemon uses `partitionSchedule` (retire expired, fire due) then
21
+ * `msUntilNextWakeup` (sleep precisely). `jitterMs = 0` (the default) makes the
22
+ * due set byte-identical to the store's existing `due()`.
23
+ */
24
+
25
+ // FNV-1a → a stable 32-bit hash. Deterministic and dependency-free, so the same
26
+ // task always draws the same jitter offset (across processes and restarts).
27
+ function hash32(str) {
28
+ let h = 0x811c9dc5;
29
+ const s = String(str ?? "");
30
+ for (let i = 0; i < s.length; i += 1) {
31
+ h ^= s.charCodeAt(i);
32
+ h = Math.imul(h, 0x01000193);
33
+ }
34
+ return h >>> 0;
35
+ }
36
+
37
+ /**
38
+ * A stable jitter offset in `[0, jitterMs)` derived from the task id. Same id +
39
+ * same jitterMs → same offset, every time. `jitterMs <= 0` → no jitter (0).
40
+ */
41
+ export function jitterOffsetMs(id, jitterMs) {
42
+ const j = Math.floor(Number(jitterMs) || 0);
43
+ if (j <= 0) return 0;
44
+ return hash32(id) % j;
45
+ }
46
+
47
+ /** The entry's base fire time: `dueAt` for a wakeup, `nextAt` otherwise. */
48
+ export function baseFireAt(entry) {
49
+ if (!entry) return null;
50
+ const raw = entry.kind === "wakeup" ? entry.dueAt : entry.nextAt;
51
+ const n = Number(raw);
52
+ return Number.isFinite(n) ? n : null;
53
+ }
54
+
55
+ /** Base fire time with the entry's deterministic jitter applied. */
56
+ export function effectiveFireAt(entry, jitterMs = 0) {
57
+ const base = baseFireAt(entry);
58
+ if (base == null) return null;
59
+ return base + jitterOffsetMs(entry?.id, jitterMs);
60
+ }
61
+
62
+ /** Is an entry still pending/active (not in a terminal state)? */
63
+ export function isSchedulable(entry) {
64
+ if (!entry) return false;
65
+ if (entry.kind === "wakeup") return entry.status === "pending";
66
+ return entry.status === "active";
67
+ }
68
+
69
+ /**
70
+ * Expiry: a task with an `expiresAt` at or before `now` is retired regardless
71
+ * of its schedule. A missing / non-positive `expiresAt` never expires.
72
+ */
73
+ export function isEntryExpired(entry, now) {
74
+ const exp = Number(entry?.expiresAt);
75
+ return Number.isFinite(exp) && exp > 0 && exp <= Number(now);
76
+ }
77
+
78
+ /**
79
+ * Partition schedulable entries at `now` into what a daemon should do:
80
+ * - `expired` — retire (status → expired). Checked BEFORE due so an expired
81
+ * task never gets a final fire.
82
+ * - `due` — fire now (jittered fire time has arrived).
83
+ * - `waiting` — still pending.
84
+ * Terminal entries are skipped entirely.
85
+ */
86
+ export function partitionSchedule(entries, { now, jitterMs = 0 } = {}) {
87
+ const t = Number(now);
88
+ const expired = [];
89
+ const due = [];
90
+ const waiting = [];
91
+ for (const entry of entries || []) {
92
+ if (!isSchedulable(entry)) continue;
93
+ if (isEntryExpired(entry, t)) {
94
+ expired.push(entry);
95
+ continue;
96
+ }
97
+ const fireAt = effectiveFireAt(entry, jitterMs);
98
+ if (fireAt != null && fireAt <= t) due.push(entry);
99
+ else waiting.push(entry);
100
+ }
101
+ return { expired, due, waiting };
102
+ }
103
+
104
+ /**
105
+ * The earliest future jittered fire time among schedulable, non-expired
106
+ * entries — what a daemon sleeps until (adaptive wakeup). An already-due entry
107
+ * contributes `now` (fire immediately). Returns null when nothing is scheduled.
108
+ */
109
+ export function nextWakeupAt(entries, { now, jitterMs = 0 } = {}) {
110
+ const t = Number(now);
111
+ let min = null;
112
+ for (const entry of entries || []) {
113
+ if (!isSchedulable(entry) || isEntryExpired(entry, t)) continue;
114
+ const fireAt = effectiveFireAt(entry, jitterMs);
115
+ if (fireAt == null) continue;
116
+ const at = fireAt <= t ? t : fireAt;
117
+ if (min == null || at < min) min = at;
118
+ }
119
+ return min;
120
+ }
121
+
122
+ /**
123
+ * Milliseconds until the next wakeup, clamped to `[0, maxMs]` (a cap keeps a
124
+ * far-future task from parking the daemon forever — it re-checks by `maxMs`).
125
+ * null when nothing is scheduled.
126
+ */
127
+ export function msUntilNextWakeup(
128
+ entries,
129
+ { now, jitterMs = 0, maxMs = null } = {},
130
+ ) {
131
+ const at = nextWakeupAt(entries, { now, jitterMs });
132
+ if (at == null) return null;
133
+ let ms = Math.max(0, at - Number(now));
134
+ if (maxMs != null && Number.isFinite(maxMs)) ms = Math.min(ms, Number(maxMs));
135
+ return ms;
136
+ }
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * Background-agent dashboard — the interactive agent view behind
3
3
  * `cc daemon view` (no id). Claude-Code `claude agents` parity: one live panel
4
- * over every background session with grouping (Needs input / Working /
4
+ * over every background session with grouping (Needs input / Working / Idle /
5
5
  * Completed / Failed / Stopped), peek + reply, attach hand-off, stop, rename,
6
- * pin, filter, and new-task dispatch.
6
+ * pin, filter, and new-task dispatch. Phase→group classification is the shared
7
+ * `background-agent-phase.js` contract, so `idle` (parked, nothing blocking)
8
+ * is kept distinct from a genuine `needs-input` (a human decision blocks it).
7
9
  *
8
10
  * Design:
9
11
  * - Pure model/render layer (`groupKey`, `buildDashboardModel`,
@@ -17,10 +19,12 @@
17
19
  */
18
20
 
19
21
  import chalk from "chalk";
22
+ import { phaseGroupKey } from "../lib/background-agent-phase.js";
20
23
 
21
24
  export const GROUP_ORDER = [
22
25
  "needs-input",
23
26
  "working",
27
+ "idle",
24
28
  "completed",
25
29
  "failed",
26
30
  "stopped",
@@ -29,24 +33,21 @@ export const GROUP_ORDER = [
29
33
  export const GROUP_TITLES = {
30
34
  "needs-input": "Needs input",
31
35
  working: "Working",
36
+ idle: "Idle",
32
37
  completed: "Completed",
33
38
  failed: "Failed",
34
39
  stopped: "Stopped",
35
40
  };
36
41
 
37
42
  /**
38
- * Group a session: running+idle phase = waiting for a follow-up (the closest
39
- * analog of "needs input" — the worker finished a turn and a client can
40
- * reply); running+turn = working; lost workers count as failed.
43
+ * Group a session into a dashboard bucket. Delegates to the shared
44
+ * `background-agent-phase.js` contract so the worker/supervisor and this panel
45
+ * agree on phase semantics: running + pending approval / blocking phase →
46
+ * "needs-input"; running + idle (parked, nothing blocking) → "idle"; running +
47
+ * working/turn/starting → "working"; lost/unknown → "failed".
41
48
  */
42
49
  export function groupKey(session) {
43
- const status = session?.status;
44
- if (status === "running") {
45
- return session.phase === "idle" ? "needs-input" : "working";
46
- }
47
- if (status === "completed") return "completed";
48
- if (status === "stopped") return "stopped";
49
- return "failed"; // failed | lost | unknown
50
+ return phaseGroupKey(session);
50
51
  }
51
52
 
52
53
  function formatAge(ms) {
@@ -25,6 +25,7 @@ import sharedSettingsHooks from "../lib/settings-hooks.cjs";
25
25
  import sharedHookRunner from "../lib/hook-runner.cjs";
26
26
  import sharedHookEvents from "../lib/settings-hook-events.cjs";
27
27
  import { mergeProviderOptions } from "../lib/provider-options.js";
28
+ import { applyCredentialProxy } from "../lib/credential-proxy.js";
28
29
  import { getPlanModeManager } from "../lib/plan-mode.js";
29
30
  import { CLISkillLoader } from "../lib/skill-loader.js";
30
31
  import { executeHooks, HookEvents } from "../lib/hook-manager.js";
@@ -2540,7 +2541,10 @@ async function executeToolInner(
2540
2541
  // Same agent-identity env as the foreground path: CLAUDECODE marks
2541
2542
  // "running under the agent"; the session id correlates work to the
2542
2543
  // run (CC_SESSION_ID + CLAUDE_CODE_SESSION_ID for Claude-Code parity).
2543
- env: {
2544
+ // Credential proxy (opt-in, CC_CREDENTIAL_PROXY): keeps the agent's
2545
+ // real long-lived secrets out of the spawned command's env — a
2546
+ // no-op (same object) when disabled. See credential-proxy.js.
2547
+ env: applyCredentialProxy({
2544
2548
  ...process.env,
2545
2549
  CLAUDECODE: "1",
2546
2550
  ...(sessionId
@@ -2549,7 +2553,7 @@ async function executeToolInner(
2549
2553
  CLAUDE_CODE_SESSION_ID: String(sessionId),
2550
2554
  }
2551
2555
  : {}),
2552
- },
2556
+ }).env,
2553
2557
  // POSIX: own process group so check_shell{kill}/teardown can signal
2554
2558
  // the whole tree (shell + its grandchild command). No-op on Windows
2555
2559
  // where the tree is killed via taskkill /T instead.
@@ -2715,7 +2719,10 @@ async function executeToolInner(
2715
2719
  // parity): CLAUDECODE=1 marks "running under the agent"; CC_SESSION_ID
2716
2720
  // + its CLAUDE_CODE_SESSION_ID mirror let scripts/hooks correlate work
2717
2721
  // to the agent session (the mirror is what CC-targeting tools expect).
2718
- env: {
2722
+ // Credential proxy (opt-in, CC_CREDENTIAL_PROXY): keeps the agent's
2723
+ // real long-lived secrets out of the shell's env — a no-op (same
2724
+ // object) when disabled. See credential-proxy.js.
2725
+ env: applyCredentialProxy({
2719
2726
  ...process.env,
2720
2727
  CLAUDECODE: "1",
2721
2728
  ...(sessionId
@@ -2724,7 +2731,7 @@ async function executeToolInner(
2724
2731
  CLAUDE_CODE_SESSION_ID: String(sessionId),
2725
2732
  }
2726
2733
  : {}),
2727
- },
2734
+ }).env,
2728
2735
  };
2729
2736
  let output;
2730
2737
  if (shellInv.useDefaultShell) {