chainlesschain 0.165.5 → 0.165.8

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 (256) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/assets/{AIOps-CEeYTeDB.js → AIOps-B3gWmXjo.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BeRUQ3V2.js → ActionButton-G9pdT-0e.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DrV718XF.js → Analytics-Ca30J7m2.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-Cd2Frt7Q.js → AppLayout-BtVTm8PU.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-CUJMlORU.js → Artifacts-BhViNa6u.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CXJcfT6p.js → Audit-DhKq-FnY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DOv6Z7H9.js → BackgroundAgents-BL0SVbnE.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BwdDyBI0.js → Backup-BWkblnFi.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BmLn4kYH.js → BaseInput-ClaRNrF8.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-COg8pAW2.js → Chat-sZE2Z77o.js} +4 -4
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-BAfKOnRe.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-BCP4uoU8.js → Checkbox-Cvhay5WM.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-pRt6Y9JI.js → Codegen-BpejL-4N.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-DLaprKhS.js → Col-g2Ki6g_1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-DyATsz5f.js → Community-D2xKbNo9.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BXAaupZK.js → Compact-DbL1Pds3.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-DpcJBELr.js → Compliance-DGtZCV4c.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-DG4EFWyd.js → Cowork-4kQpoNsI.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-F6Oy5n2P.js → Cron-BxTYXXAN.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BOdgtalX.js → Crosschain-k0J0LT2N.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-DT1dSkjH.js → DID-BaqhoPgN.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-NBUIqWzC.js → Dashboard-T4RVPIM1.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-CSpHeMYB.js → Dropdown-DszOToWq.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-CEG0xISr.js → EmailListRenderer-C9KJU7HF.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BTZ0BZna.js → FamilyGuardDashboard-Cmr0JnsA.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BuuCTn2V.js → Federation-BI-_2xZX.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-KAVceevk.js → FormItemContext-DsnDEPsl.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-DnHpcQvW.js → GenericCardRenderer-BLncAKKK.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-C_B_0HwB.js → Git-BPQhGXDn.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DPSZuzuu.js → Governance-CyElbUQW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BV-06V7q.js → Inference-CcSntBQD.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-wpDuupn6.js → KnowledgeGraph-p6e7HZ2r.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-Bseca1_I.js → Logs-CNEtr-wz.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-Bj9xI0YH.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-d3kM4DDL.js → Marketplace-Dd2notAJ.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DQ_xZ23i.js → McpTools-BBsN2CSW.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-CRIeYO4L.js → Memory-Dg2uTvwx.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-BsllIa9l.js → MobileBridge-r1YMRiJV.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-BUuQy30X.js → MobileProjects-C-89kSm4.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-BOFDIzrC.js → Mtc-CrPZcVgf.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-BQg-vyvG.js → MtcAudit-sxi7hqJb.js} +5 -5
  43. package/src/assets/web-panel/assets/{Multisig-Bo1jrPdN.js → Multisig-CAgOMfF1.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-Bmod8alw.js → NLProgramming-DafaPts3.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CGGFL8w-.js → Notes-CJM-xUW_.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-BsZvCJxC.js → NotificationSettings-L0ZjfAh_.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-C1-Quo_h.js → OrderTableRenderer-BB1CvCK0.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-BjOeDYOi.js → Organization-DeLtgAD8.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-DwVV3l5A.js → Overflow-CKC2b10z.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-Cu3DQT9W.js → P2P-eyf2rzY1.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-Cg0gR7dH.js → PdhVaultBrowser-5upNIOW8.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-CsAXxRN5.js → Permissions-B8p3W6JK.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-C-nNmnYp.js → PersonalDataHub-BnRMxTq3.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-BOnW7nNc.js → Pipeline-DjCNI1li.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-ClLSyGKt.js → Privacy-u6gXLbWT.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-DuLvjjq7.js → ProjectInit-BZAw4tkM.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-DQYYbDD9.js → ProjectSettings-B1Tr72q7.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-Drw8MBGK.js → Projects-DO7HFuBQ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-ckqHQe6K.js → Providers-BjCztyhj.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DW5BXk-G.js → QrScannerModal-ZWyCUbR1.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-DDLnhNTp.js → QuickAsk-DhDjeW4G.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-PJQ2C91U.js → Recommend-R_CN2MuU.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-s6wmda34.js → RemoteSession-uxFcujeu.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-DC2sb-I3.js → Reputation-DX8D7rks.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-hPGk1eGj.js → Row-BYahQILD.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-RIvfZql0.js → RssFeed-CUSQ2tm-.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DFg1G1eR.js → Search-CnN_S8Cs.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-D6H5p8Dp.js → Security-DcZlh-O4.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-nxYiFV_w.js → Services-ZhBOjzIX.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-BmgFNAdB.js → Skeleton-D5Qnq_lI.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-CsaaD2av.js → Skills-BC9cZ3Be.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-yM5y9yvK.js → Sla-DauJ3E8_.js} +1 -1
  73. package/src/assets/web-panel/assets/SpeechSettings-DbNeZ_fh.js +1 -0
  74. package/src/assets/web-panel/assets/{SyncSettings-CFVhEyyr.js → SyncSettings-DUvJbSct.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-DdO02Inn.js → Tasks-BXa-5noQ.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-Eo2d8Llu.js → Templates-JxaiUt_3.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-ChESOXgy.js → Tenant-BW4ERQN8.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-BJ7oDxTI.js → Terminal-DltUbdtv.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-hWX0fUvz.js → TimelineRenderer-CMoZz0Tc.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-DVBZQnd-.js → Tokens-D_VEV60K.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-D89cQfVq.js → Trigger-CCXTCs0R.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BIVSb4-V.js → Trust-lkGRIPcG.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-B58gWopl.js → UkeySign-BfGeQ9HX.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DhHI7bmG.js → VideoEditing-BEC7pYvc.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-C4FheWS_.js → Wallet-BZdG24o0.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DnPRq-Bx.js → WebAuthn-yoEddedp.js} +3 -3
  87. package/src/assets/web-panel/assets/{WorkflowEditor-BerRPjpJ.js → WorkflowEditor-BXZEprOW.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-BzZ52iKr.js → chat-gg0bzZal.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-BI_E4BAn.js → colors-DjRVRuin.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-d50mr3yk.js → compact-item-su-dieAc.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-C6FsQ1IH.js → createContext-Ci3S8oKF.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CxbFX9uH.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-DLZEMgLP.js → hasIn-D8F10heH.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-D-aBumtY.js → index-11wtYQiF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CjuKZBqJ.js → index-1IgxgALJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-9H_M2jju.js → index-1agckWSq.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DE0V6cp-.js → index-5JqhujnR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Y2-q7QLm.js → index-6Tniqk1s.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DoFtCVZ7.js → index-8Z-8BIlN.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-KNGgO4Wm.js → index-BCI5v0yB.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DY4j5zkF.js → index-BDJntYmJ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BZjjdQ62.js → index-BGzixOGZ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BTpIOTfR.js → index-BMMOVoLD.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BB9SqVSt.js → index-BTFpdBtt.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-AHr7ryWf.js → index-Ba_HyPnE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Pvf30m8Q.js → index-BbF1IHof.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CRN5TRTQ.js → index-BgT9su_e.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CUaEHfQ0.js → index-BzPB6kGZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CdKt9fOd.js → index-C6ygzplr.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Dec0Kf_Z.js → index-CC3ZDjzY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-IPkwSAW_.js → index-CEmXRhAE.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CJGOlduY.js +1 -0
  113. package/src/assets/web-panel/assets/{index-C3k8kevG.js → index-CMPqd5Cv.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-A5CDWP7y.js → index-COWd8uGx.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CO8DAF7U.js → index-CPIYSp4H.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CVzuawCX.js → index-CR0h6seT.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Co7s9LsB.js → index-CUmDhC4j.js} +1 -1
  118. package/src/assets/web-panel/assets/index-CkBCN5yH.js +1 -0
  119. package/src/assets/web-panel/assets/{index-CLoTQr0W.js → index-CusgZPtc.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-B81mo1Et.js → index-DBAETXft.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BcSUl9fA.js → index-DIJ2qFOC.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Q5Tn735s.js → index-Dbq4NMET.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-GXE0D8Nx.js → index-DkMEF5VT.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-TWG-_D1M.js → index-DkfQR3hM.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BAE3hwev.js → index-DnLucOn9.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CgkoH3_g.js → index-DugB_aKa.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BRGx3w6T.js → index-DyLUarhZ.js} +3 -3
  128. package/src/assets/web-panel/assets/{index-BeM4hfht.js → index-T6_6ygJZ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DsscwxPE.js → index-Tu8eWqh-.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Bmr_vxXD.js → index-W7XUgdVL.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BoNZlzhQ.js → index-dHZinfko.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DqkbHHg8.js → index-jyNgp5FI.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-D-4Hzgej.js → initDefaultProps-Cv4p8e4w.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-D4Wl4xU7.js → motion-B8EwmMOw.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Cd5eQvL0.js → move-B8R9F8TK.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-B4ilslCW.js → mtc-parser-DoFYz5Bp.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-Ckarx-tf.js → omit-CHWYLBjI.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-QJ0bpCmc.js → pickAttrs-CXuPDO77.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-CKHm-tq8.js → placementArrow-BaAtUUon.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-CV6a_w_Y.js → responsiveObserve-DCc4zcDD.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-mHpeQFgk.js → slide-B_lx89oZ.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-DIaQNQWA.js → statusUtils-DE8DPmR0.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-PJpzavV8.js → styleChecker-1ktXOsL_.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-BH7zTw8S.js → useFlexGapSupport-xH89-wjh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-BDNG3JDd.js → useFs-DscvfW5p.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CY2VWdUg.js → usePersonalDataHub-RdMKQta7.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-D0kw9jhz.js → vnode-Z3wTni2T.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-B5g7TN7r.js → zoom-B0iChCsm.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +3 -3
  151. package/src/commands/agent.js +105 -62
  152. package/src/commands/background-session.js +100 -10
  153. package/src/commands/git.js +39 -0
  154. package/src/commands/mcp.js +5 -0
  155. package/src/commands/plugin.js +160 -29
  156. package/src/commands/remote-control.js +295 -110
  157. package/src/commands/session-group.js +131 -0
  158. package/src/commands/session-location.js +48 -0
  159. package/src/commands/session-message.js +171 -0
  160. package/src/commands/session.js +22 -0
  161. package/src/commands/sync-providers.js +4 -1
  162. package/src/commands/update.js +1 -0
  163. package/src/data/changelog.json +41 -2
  164. package/src/gateways/ws/ws-agent-handler.js +20 -12
  165. package/src/harness/jsonl-session-store.js +279 -37
  166. package/src/harness/mcp-client.js +832 -91
  167. package/src/harness/session-index.js +15 -4
  168. package/src/lib/agent-worktree.js +8 -1
  169. package/src/lib/auto-mode-safety-classifier.js +3 -17
  170. package/src/lib/background-agent-keeper-protocol.js +26 -6
  171. package/src/lib/background-agent-supervisor.js +17 -1
  172. package/src/lib/background-session-transport.js +153 -27
  173. package/src/lib/browser-evidence.js +1405 -0
  174. package/src/lib/chrome-connector.js +465 -79
  175. package/src/lib/claude-project-auto-memory.js +481 -0
  176. package/src/lib/claude-project-storage-layout.js +104 -0
  177. package/src/lib/cloud/cloud-client.js +40 -0
  178. package/src/lib/execution-location-local-supervisor.mjs +226 -0
  179. package/src/lib/execution-location-runner-lifecycle.js +991 -0
  180. package/src/lib/execution-location-target-preflight.js +333 -0
  181. package/src/lib/execution-location-target.js +783 -13
  182. package/src/lib/file-lines.js +6 -1
  183. package/src/lib/gateway-client-resilience.js +571 -0
  184. package/src/lib/gitlab-mr-worktree.js +176 -0
  185. package/src/lib/hooks-v2-producers.js +119 -15
  186. package/src/lib/hooks-v2-workspace-context.js +44 -1
  187. package/src/lib/host-resource-budget.js +295 -0
  188. package/src/lib/ide-context.js +15 -2
  189. package/src/lib/llm-config-defaults.js +43 -0
  190. package/src/lib/mcp-client.js +2 -0
  191. package/src/lib/mcp-headers-helper.js +47 -5
  192. package/src/lib/mcp-lifecycle-authority.js +887 -0
  193. package/src/lib/mcp-oauth.js +156 -26
  194. package/src/lib/mcp-tls.js +330 -0
  195. package/src/lib/output-styles.js +12 -0
  196. package/src/lib/paths.js +260 -32
  197. package/src/lib/permission-request.js +48 -0
  198. package/src/lib/plugin-runtime/bin.js +3 -1
  199. package/src/lib/plugin-runtime/hooks.js +3 -1
  200. package/src/lib/plugin-runtime/install.js +730 -71
  201. package/src/lib/plugin-runtime/lsp.js +4 -4
  202. package/src/lib/plugin-runtime/marketplace-archive-source.js +366 -0
  203. package/src/lib/plugin-runtime/marketplace-catalog.js +63 -6
  204. package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
  205. package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
  206. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1 -0
  207. package/src/lib/plugin-runtime/marketplace-source-adapter.js +188 -0
  208. package/src/lib/plugin-runtime/marketplace-source-cache.js +11 -1
  209. package/src/lib/plugin-runtime/mcp.js +3 -1
  210. package/src/lib/plugin-runtime/monitors.js +3 -1
  211. package/src/lib/plugin-runtime/remote-source.js +583 -58
  212. package/src/lib/plugin-runtime/settings.js +3 -1
  213. package/src/lib/plugin-runtime/trust.js +274 -13
  214. package/src/lib/plugin-security.js +393 -41
  215. package/src/lib/plugin-source-identity.js +850 -0
  216. package/src/lib/process-execution-broker/credential-agent.js +210 -41
  217. package/src/lib/process-execution-broker/index.js +15 -1
  218. package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
  219. package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
  220. package/src/lib/project-mcp-trust.js +165 -10
  221. package/src/lib/remote-approval-bridge.js +136 -46
  222. package/src/lib/remote-control.js +217 -31
  223. package/src/lib/resume-session.js +9 -6
  224. package/src/lib/session-core-singletons.js +26 -11
  225. package/src/lib/session-host-lease.js +52 -16
  226. package/src/lib/session-lifecycle-scope.js +153 -0
  227. package/src/lib/session-message-fabric.js +1252 -0
  228. package/src/lib/session-projection.js +286 -3
  229. package/src/lib/session-runtime-retention.js +155 -0
  230. package/src/lib/session-store-guard.js +3 -1
  231. package/src/lib/session-workbench-store.js +466 -0
  232. package/src/lib/settings-loader.cjs +29 -0
  233. package/src/lib/spellcheck.js +211 -0
  234. package/src/lib/sub-agent-context.js +9 -9
  235. package/src/lib/sync-cli-db.js +485 -129
  236. package/src/lib/sync-credentials.js +31 -20
  237. package/src/lib/web-fetch.js +112 -40
  238. package/src/lib/web-search.js +127 -61
  239. package/src/lib/workspace-trust.js +793 -0
  240. package/src/repl/agent-repl.js +175 -19
  241. package/src/repl/permission-prompt.js +29 -8
  242. package/src/repl/repl-keybindings.js +55 -0
  243. package/src/runtime/agent-core.js +362 -20
  244. package/src/runtime/bootstrap.js +37 -13
  245. package/src/runtime/coding-agent-contract-shared.cjs +11 -4
  246. package/src/runtime/headless-runner.js +281 -102
  247. package/src/runtime/headless-stream.js +199 -30
  248. package/src/runtime/mcp-config.js +298 -6
  249. package/src/runtime/policies/agent-policy.js +10 -0
  250. package/src/runtime/status-diagnostics-lite.js +9 -1
  251. package/src/assets/web-panel/assets/ChatBubbleRenderer-4gGkdGgA.js +0 -1
  252. package/src/assets/web-panel/assets/MarkdownRenderer-B4RLp2zs.js +0 -1
  253. package/src/assets/web-panel/assets/SpeechSettings-DPy1XMYh.js +0 -1
  254. package/src/assets/web-panel/assets/devWarning-CagEcIex.js +0 -1
  255. package/src/assets/web-panel/assets/index-pzT9PpOU.js +0 -1
  256. package/src/assets/web-panel/assets/index-z1kFadaX.js +0 -1
@@ -30,6 +30,11 @@ import {
30
30
  transformBackgroundLaunchArgv,
31
31
  } from "../lib/background-command-argv.js";
32
32
  import { resolveSessionBudgetRootOptions } from "../lib/session-budget-production-root.js";
33
+ import {
34
+ captureClaudeStorageLaunchEnvironment,
35
+ restoreClaudeStorageLaunchEnvironment,
36
+ validateClaudeStorageLaunchEnvironment,
37
+ } from "../lib/claude-project-auto-memory.js";
33
38
 
34
39
  /**
35
40
  * Resolve + validate `--add-dir` values into absolute, existing, de-duped
@@ -445,7 +450,7 @@ export function registerAgentCommand(program) {
445
450
  )
446
451
  .option(
447
452
  "--output-style <name>",
448
- "Apply a named output-style persona (.claude/output-styles/<name>.md or a built-in: explanatory | learning)",
453
+ "Apply a named output-style persona (.claude/output-styles/<name>.md or a built-in: concise | explanatory | learning)",
449
454
  )
450
455
  .option(
451
456
  "--input-format <fmt>",
@@ -465,6 +470,10 @@ export function registerAgentCommand(program) {
465
470
  "--include-partial-messages",
466
471
  "Emit live assistant-text deltas as stream_event lines (requires --output-format stream-json)",
467
472
  )
473
+ .option(
474
+ "--include-hook-events",
475
+ "Emit redacted hook and subagent lifecycle events (requires --output-format stream-json)",
476
+ )
468
477
  .option(
469
478
  "--goal [id]",
470
479
  "Bind a cc goal into the run (id, or omit the value to auto-resolve the active goal)",
@@ -530,7 +539,11 @@ export function registerAgentCommand(program) {
530
539
  )
531
540
  .option(
532
541
  "--remote-control",
533
- "Route confirm-tier approvals to paired mobile/web devices — prints a pairing URI/QR. Headless waits for the remote allow/deny (fail-closed on timeout); interactive races the terminal prompt (first answer wins; also /remote-control)",
542
+ "Route confirm-tier approvals to paired mobile/web devices — requires a relay or explicit LAN opt-in; headless waits fail-closed, interactive races the terminal prompt (also /remote-control)",
543
+ )
544
+ .option(
545
+ "--remote-control-allow-lan",
546
+ "Permit --remote-control to expose its authenticated WS endpoint on a trusted LAN",
534
547
  )
535
548
  .option(
536
549
  "--channels <list>",
@@ -616,6 +629,20 @@ export function registerAgentCommand(program) {
616
629
  false,
617
630
  )
618
631
  .action(async (task, options, command) => {
632
+ // These variables select canonical config/session storage. Capture and
633
+ // validate them before any project settings file can merge an arbitrary
634
+ // `env` map; settings remain useful for child tools but never acquire
635
+ // launcher authority over transcript or automatic-memory placement.
636
+ const claudeStorageLaunchEnv = captureClaudeStorageLaunchEnvironment();
637
+ try {
638
+ validateClaudeStorageLaunchEnvironment(claudeStorageLaunchEnv, {
639
+ cwd: process.cwd(),
640
+ });
641
+ } catch (error) {
642
+ process.stderr.write(`Error: ${error.message}\n`);
643
+ process.exitCode = 1;
644
+ return;
645
+ }
619
646
  // Scope is immutable session authority. Resolve every scope/fork
620
647
  // conflict before worktree creation, session forking, bootstrap, or any
621
648
  // other externally visible setup performed by this action.
@@ -632,18 +659,16 @@ export function registerAgentCommand(program) {
632
659
  // --capabilities: print the machine-readable manifest and exit — no
633
660
  // config, no bootstrap, no network (gap-analysis 2026-07-11 快速收益 #6).
634
661
  if (options.capabilities) {
635
- const { buildAgentCapabilities } = await import(
636
- "../lib/headless-manifest.js"
637
- );
662
+ const { buildAgentCapabilities } =
663
+ await import("../lib/headless-manifest.js");
638
664
  console.log(JSON.stringify(buildAgentCapabilities(), null, 2));
639
665
  return;
640
666
  }
641
667
  let toolAdmission = null;
642
668
  if (process.env.CC_TOOL_ADMISSION) {
643
669
  try {
644
- const { parseToolAdmissionConfig } = await import(
645
- "../lib/agent-tool-admission.js"
646
- );
670
+ const { parseToolAdmissionConfig } =
671
+ await import("../lib/agent-tool-admission.js");
647
672
  toolAdmission = parseToolAdmissionConfig(
648
673
  process.env.CC_TOOL_ADMISSION,
649
674
  );
@@ -720,9 +745,8 @@ export function registerAgentCommand(program) {
720
745
  // screen readers (mono theme + no repainting status line). Applied
721
746
  // before anything renders.
722
747
  {
723
- const { screenReaderRequested, applyScreenReaderMode } = await import(
724
- "../lib/accessibility.js"
725
- );
748
+ const { screenReaderRequested, applyScreenReaderMode } =
749
+ await import("../lib/accessibility.js");
726
750
  if (screenReaderRequested(options)) {
727
751
  applyScreenReaderMode();
728
752
  }
@@ -755,9 +779,8 @@ export function registerAgentCommand(program) {
755
779
  };
756
780
  if (options.worktree !== undefined || backgroundRequested) {
757
781
  try {
758
- const { resolveBackgroundWorktreePolicy } = await import(
759
- "../lib/background-worktree-policy.js"
760
- );
782
+ const { resolveBackgroundWorktreePolicy } =
783
+ await import("../lib/background-worktree-policy.js");
761
784
  worktreeDecision = resolveBackgroundWorktreePolicy({
762
785
  background: backgroundRequested,
763
786
  worktree: options.worktree,
@@ -809,9 +832,8 @@ export function registerAgentCommand(program) {
809
832
  };
810
833
  if (worktreeDecision.enabled) {
811
834
  try {
812
- const { setupAgentWorktree, finishAgentWorktree } = await import(
813
- "../lib/agent-worktree.js"
814
- );
835
+ const { setupAgentWorktree, finishAgentWorktree } =
836
+ await import("../lib/agent-worktree.js");
815
837
  _finishAgentWorktreeFn = finishAgentWorktree;
816
838
  const detectedRepoRoot = worktreeDecision.repoRoot || invocationCwd;
817
839
  const worktreeCwd =
@@ -839,9 +861,8 @@ export function registerAgentCommand(program) {
839
861
  const { loadHooks } = await import("../lib/settings-hooks.cjs");
840
862
  _worktreeSettingsHooks =
841
863
  loadHooks({ cwd: _worktree.repoRoot }).hooks || null;
842
- const { runWorktreeCreateHooks, dispatchAsyncHooks } = await import(
843
- "../lib/settings-hook-events.js"
844
- );
864
+ const { runWorktreeCreateHooks, dispatchAsyncHooks } =
865
+ await import("../lib/settings-hook-events.js");
845
866
  runWorktreeCreateHooks(_worktreeSettingsHooks, {
846
867
  worktreePath: _worktree.path,
847
868
  branch: _worktree.branch,
@@ -849,9 +870,8 @@ export function registerAgentCommand(program) {
849
870
  cwd: _worktree.path,
850
871
  });
851
872
  if (!_worktreeAsyncSupervisor) {
852
- const { AsyncHookSupervisor } = await import(
853
- "../lib/async-hook-supervisor.js"
854
- );
873
+ const { AsyncHookSupervisor } =
874
+ await import("../lib/async-hook-supervisor.js");
855
875
  _worktreeAsyncSupervisor = new AsyncHookSupervisor({
856
876
  persistStats: true,
857
877
  });
@@ -936,9 +956,8 @@ export function registerAgentCommand(program) {
936
956
  // Claude-Code parity: auto-checkpoint defaults ON inside a git repo
937
957
  // (shadow-commit engine, zero working-tree touch); explicit
938
958
  // --checkpoint / --no-checkpoint always wins.
939
- const { resolveAutoCheckpoint } = await import(
940
- "../lib/auto-checkpoint-default.js"
941
- );
959
+ const { resolveAutoCheckpoint } =
960
+ await import("../lib/auto-checkpoint-default.js");
942
961
  const autoCheckpoint = resolveAutoCheckpoint({
943
962
  flagValue: options.checkpoint,
944
963
  flagSource: command?.getOptionValueSource?.("checkpoint"),
@@ -965,15 +984,13 @@ export function registerAgentCommand(program) {
965
984
  if (headlessIntent) {
966
985
  // Headless replays the JSONL store only, so resolve "most recent"
967
986
  // from there 鈥?a DB-only id would resume into an empty transcript.
968
- const { getLastSessionId } = await import(
969
- "../harness/jsonl-session-store.js"
970
- );
987
+ const { getLastSessionId } =
988
+ await import("../harness/jsonl-session-store.js");
971
989
  options.session = getLastSessionId();
972
990
  } else {
973
991
  // Interactive: picker across both stores (agent REPL rebuilds either).
974
- const { pickRecentSession } = await import(
975
- "../lib/session-picker.js"
976
- );
992
+ const { pickRecentSession } =
993
+ await import("../lib/session-picker.js");
977
994
  const picked = await pickRecentSession(ctx, {
978
995
  message: "Resume which agent session?",
979
996
  });
@@ -996,9 +1013,8 @@ export function registerAgentCommand(program) {
996
1013
  // a no-op (silent) for a fresh run.
997
1014
  if (options.forkSession && options.session) {
998
1015
  const store = await import("../harness/jsonl-session-store.js");
999
- const { applyForkSession } = await import(
1000
- "../runtime/headless-runner.js"
1001
- );
1016
+ const { applyForkSession } =
1017
+ await import("../runtime/headless-runner.js");
1002
1018
  const fork = applyForkSession(
1003
1019
  {
1004
1020
  forkSession: true,
@@ -1020,16 +1036,16 @@ export function registerAgentCommand(program) {
1020
1036
  }
1021
1037
  }
1022
1038
 
1023
- // --include-partial-messages only makes sense for NDJSON output: the
1024
- // stream-input mode is always NDJSON, otherwise require stream-json
1025
- // explicitly (fail fast rather than silently dropping the deltas).
1039
+ // Event projections only make sense for NDJSON output: the stream-input
1040
+ // mode is always NDJSON, otherwise require stream-json explicitly (fail
1041
+ // fast rather than silently dropping an opt-in machine contract).
1026
1042
  if (
1027
- options.includePartialMessages &&
1043
+ (options.includePartialMessages || options.includeHookEvents) &&
1028
1044
  options.inputFormat !== "stream-json" &&
1029
1045
  options.outputFormat !== "stream-json"
1030
1046
  ) {
1031
1047
  process.stderr.write(
1032
- "--include-partial-messages requires --output-format stream-json.\n",
1048
+ "--include-partial-messages and --include-hook-events require --output-format stream-json.\n",
1033
1049
  );
1034
1050
  await _finishWorktree();
1035
1051
  process.exit(1);
@@ -1054,6 +1070,12 @@ export function registerAgentCommand(program) {
1054
1070
  // block below may default options.model 鈥?so vision input can tell an
1055
1071
  // explicit model from a settings default.
1056
1072
  const explicitCliModel = options.model;
1073
+ // Launcher environment is captured before a settings file can merge its
1074
+ // own `env` map. In particular, a checked-in project settings file must
1075
+ // not manufacture ANTHROPIC_MODEL / CLAUDE_CODE_* launcher authority.
1076
+ const startupAnthropicModel = process.env.ANTHROPIC_MODEL;
1077
+ const startupAnthropicDefaultModel = process.env.ANTHROPIC_DEFAULT_MODEL;
1078
+ let settingsModel = null;
1057
1079
 
1058
1080
  // --settings native config overrides: a .claude/settings.json-shaped file
1059
1081
  // (and the discovered .claude settings) may set `model` + `env` for this
@@ -1064,9 +1086,8 @@ export function registerAgentCommand(program) {
1064
1086
  let settingsSandbox = null;
1065
1087
  let managedSettingsSandbox = null;
1066
1088
  try {
1067
- const { loadSettingsConfig } = await import(
1068
- "../lib/settings-loader.cjs"
1069
- );
1089
+ const { loadSettingsConfig } =
1090
+ await import("../lib/settings-loader.cjs");
1070
1091
  const sc = loadSettingsConfig({
1071
1092
  cwd: process.cwd(),
1072
1093
  unattendedActionPolicy: options.unattended
@@ -1084,7 +1105,10 @@ export function registerAgentCommand(program) {
1084
1105
  for (const [k, v] of Object.entries(sc.env || {})) {
1085
1106
  process.env[k] = v;
1086
1107
  }
1087
- if (!options.model && sc.model) options.model = sc.model;
1108
+ if (!options.model && sc.model) {
1109
+ options.model = sc.model;
1110
+ settingsModel = sc.model;
1111
+ }
1088
1112
  settingsSandbox = sc.sandbox || null;
1089
1113
  managedSettingsSandbox = sc.managedSandbox || null;
1090
1114
  } catch (error) {
@@ -1095,6 +1119,8 @@ export function registerAgentCommand(program) {
1095
1119
  }
1096
1120
  // User/project settings overrides remain best-effort. Organization
1097
1121
  // managed settings are handled above and may never fail open.
1122
+ } finally {
1123
+ restoreClaudeStorageLaunchEnvironment(claudeStorageLaunchEnv);
1098
1124
  }
1099
1125
 
1100
1126
  let resolvedAgentSandbox;
@@ -1190,7 +1216,7 @@ export function registerAgentCommand(program) {
1190
1216
  // flags there, and BEFORE every dispatch (headless/stream/REPL) since
1191
1217
  // they all read options.provider/model/baseUrl/apiKey.
1192
1218
  {
1193
- const { applyConfigLlmDefaults, reconcileConfigLlmProvider } =
1219
+ const { applyAgentModelDefaults, reconcileConfigLlmProvider } =
1194
1220
  await import("../lib/llm-config-defaults.js");
1195
1221
 
1196
1222
  // Self-repair a MISLABELED config (provider disagrees with the provider
@@ -1218,8 +1244,16 @@ export function registerAgentCommand(program) {
1218
1244
  }
1219
1245
  }
1220
1246
 
1221
- applyConfigLlmDefaults(options, repairedLlm, {
1222
- explicitModel: explicitCliModel, // settings-file model must not ride
1247
+ applyAgentModelDefaults(options, repairedLlm, {
1248
+ explicitModel: explicitCliModel,
1249
+ anthropicModel: startupAnthropicModel,
1250
+ anthropicDefaultModel: startupAnthropicDefaultModel,
1251
+ settingsModel,
1252
+ // ANTHROPIC_DEFAULT_MODEL is deliberately a new-session fallback;
1253
+ // a resume/continue keeps its recorded model unless a higher source
1254
+ // explicitly replaces it.
1255
+ isNewSession:
1256
+ !options.session && !options.continue && !options.resume,
1223
1257
  });
1224
1258
 
1225
1259
  // Also reconcile the RESOLVED options: the editor panel may have already
@@ -1243,9 +1277,8 @@ export function registerAgentCommand(program) {
1243
1277
  // never pollutes spawned-bin test stderr.
1244
1278
  if (!process.env.VITEST && !process.env.VITEST_WORKER_ID) {
1245
1279
  try {
1246
- const { maybeWarnDeprecatedModel } = await import(
1247
- "../lib/model-deprecation.js"
1248
- );
1280
+ const { maybeWarnDeprecatedModel } =
1281
+ await import("../lib/model-deprecation.js");
1249
1282
  maybeWarnDeprecatedModel({ model: options.model });
1250
1283
  } catch {
1251
1284
  /* fail-open: a deprecation notice must never affect the run */
@@ -1331,9 +1364,8 @@ export function registerAgentCommand(program) {
1331
1364
  // stdin; output is always NDJSON. Routed before single-prompt handling
1332
1365
  // so stdin is consumed as events, not as one prompt.
1333
1366
  if (options.inputFormat === "stream-json") {
1334
- const { runAgentHeadlessStream } = await import(
1335
- "../runtime/headless-stream.js"
1336
- );
1367
+ const { runAgentHeadlessStream } =
1368
+ await import("../runtime/headless-stream.js");
1337
1369
  const { parseToolList } = await import("../runtime/headless-runner.js");
1338
1370
  const cwd = process.cwd();
1339
1371
  let outcome;
@@ -1374,6 +1406,7 @@ export function registerAgentCommand(program) {
1374
1406
  // (flag absent) leaves the default-on path byte-identical.
1375
1407
  projectMemory: options.projectMemory,
1376
1408
  includePartialMessages: options.includePartialMessages === true,
1409
+ includeHookEvents: options.includeHookEvents === true,
1377
1410
  goal: options.goal,
1378
1411
  mcpConfig: options.mcpConfig || null,
1379
1412
  useRegisteredMcp: options.mcp !== false,
@@ -1383,6 +1416,7 @@ export function registerAgentCommand(program) {
1383
1416
  cwd,
1384
1417
  permissionPromptTool: options.permissionPromptTool || null,
1385
1418
  remoteControl: options.remoteControl === true,
1419
+ remoteControlAllowLan: options.remoteControlAllowLan === true,
1386
1420
  interactiveApprovals: options.interactiveApprovals === true,
1387
1421
  settingsFile: options.settings || null,
1388
1422
  outputStyle: options.outputStyle || null,
@@ -1401,6 +1435,7 @@ export function registerAgentCommand(program) {
1401
1435
  // into the system prompt, and a per-turn `structured_result` event is
1402
1436
  // appended after each turn (parity with single-prompt --json-schema).
1403
1437
  jsonSchema: options.jsonSchema || null,
1438
+ claudeStorageLaunchEnv,
1404
1439
  });
1405
1440
  } catch (err) {
1406
1441
  process.stderr.write(
@@ -1564,9 +1599,8 @@ export function registerAgentCommand(program) {
1564
1599
  const resumeRequested =
1565
1600
  Boolean(options.continue) || options.resume !== undefined;
1566
1601
  if (resumeRequested && options.session) {
1567
- const { sessionHasPersistedEvidence } = await import(
1568
- "../harness/jsonl-session-store.js"
1569
- );
1602
+ const { sessionHasPersistedEvidence } =
1603
+ await import("../harness/jsonl-session-store.js");
1570
1604
  if (!sessionHasPersistedEvidence(options.session)) {
1571
1605
  process.stderr.write(
1572
1606
  `Note: no headless transcript for session "${options.session}" 鈥?` +
@@ -1574,16 +1608,14 @@ export function registerAgentCommand(program) {
1574
1608
  );
1575
1609
  }
1576
1610
  }
1577
- const { runAgentHeadless, parseToolList } = await import(
1578
- "../runtime/headless-runner.js"
1579
- );
1611
+ const { runAgentHeadless, parseToolList } =
1612
+ await import("../runtime/headless-runner.js");
1580
1613
  // --goal-condition: validate the spec up front so a bad prefix fails
1581
1614
  // fast (before any model call) with a clear message.
1582
1615
  if (options.goalCondition) {
1583
1616
  try {
1584
- const { parseGoalCondition } = await import(
1585
- "../lib/goal-condition-engine.js"
1586
- );
1617
+ const { parseGoalCondition } =
1618
+ await import("../lib/goal-condition-engine.js");
1587
1619
  parseGoalCondition(options.goalCondition);
1588
1620
  } catch (e) {
1589
1621
  process.stderr.write(`--goal-condition: ${e.message}\n`);
@@ -1651,6 +1683,8 @@ export function registerAgentCommand(program) {
1651
1683
  projectMemory: options.projectMemory,
1652
1684
  // --include-partial-messages: live token deltas as stream_event lines
1653
1685
  includePartialMessages: options.includePartialMessages === true,
1686
+ // --include-hook-events: redacted lifecycle/progress NDJSON lines
1687
+ includeHookEvents: options.includeHookEvents === true,
1654
1688
  // --goal [id]: bind a cc goal into the run (Phase 1)
1655
1689
  goal: options.goal,
1656
1690
  // --goal-assess: run-end LLM progress assessment (Phase 2)
@@ -1685,6 +1719,7 @@ export function registerAgentCommand(program) {
1685
1719
  permissionPromptTool: options.permissionPromptTool || null,
1686
1720
  // --remote-control: approvals from paired mobile/web devices
1687
1721
  remoteControl: options.remoteControl === true,
1722
+ remoteControlAllowLan: options.remoteControlAllowLan === true,
1688
1723
  // --strict-mcp-config: only --mcp-config servers (ignore registered + IDE)
1689
1724
  strictMcpConfig: options.strictMcpConfig === true,
1690
1725
  // --settings: extra .claude/settings.json permission rules
@@ -1701,6 +1736,7 @@ export function registerAgentCommand(program) {
1701
1736
  : undefined,
1702
1737
  // --fallback-model: retry once on a backup model on transient errors
1703
1738
  chatFn: fallbackChatFn,
1739
+ claudeStorageLaunchEnv,
1704
1740
  };
1705
1741
 
1706
1742
  // --json-schema: structured output. Accepts a file path OR inline JSON.
@@ -1836,6 +1872,11 @@ export function registerAgentCommand(program) {
1836
1872
  // === false suppresses the auto-loaded rules.md + cc.md/CLAUDE.md block
1837
1873
  // in the REPL's composed system prompt. Absent (undefined) = default-on.
1838
1874
  projectMemory: options.projectMemory,
1875
+ // Output styles and the one-shot settings layer are also consumed by
1876
+ // the interactive REPL. Keep them on the runtime-policy allowlist so
1877
+ // `--output-style concise` and `--settings` are not silently dropped.
1878
+ outputStyle: options.outputStyle || null,
1879
+ settingsFile: options.settings || null,
1839
1880
  // --fallback-model also applies interactively (wrapper built in the
1840
1881
  // REPL). Pass the fully resolved chain (flag + config default).
1841
1882
  fallbackModels: fallbackModels.length ? fallbackModels : null,
@@ -1854,12 +1895,14 @@ export function registerAgentCommand(program) {
1854
1895
  // --remote-control: start the paired-device approval bridge for the
1855
1896
  // interactive session too (terminal prompt races the device).
1856
1897
  remoteControl: options.remoteControl === true,
1898
+ remoteControlAllowLan: options.remoteControlAllowLan === true,
1857
1899
  // --channels: inbound channel listeners (webhook/telegram) whose
1858
1900
  // events become user turns in this session.
1859
1901
  channels: options.channels || null,
1860
1902
  observabilityScope: hasObservabilityScope
1861
1903
  ? observabilityScope
1862
1904
  : undefined,
1905
+ claudeStorageLaunchEnv,
1863
1906
  });
1864
1907
  await runtime.startAgentSession();
1865
1908
  // Interactive session ended (REPL closed) — settle the worktree.
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync } from "node:fs";
1
+ import { closeSync, openSync, readSync, statSync } from "node:fs";
2
2
  import chalk from "chalk";
3
3
  import { logger } from "../lib/logger.js";
4
4
  import { readPrLinkLedger } from "../lib/pr-link-ledger.js";
@@ -350,22 +350,112 @@ export async function retryBackgroundNeedsInputNotification(
350
350
  export const LOG_TRUNCATION_NOTICE =
351
351
  "--- log truncated/rotated, resuming from tail ---";
352
352
  const TRUNCATION_RESUME_TAIL_BYTES = 4096;
353
+ export const MAX_BACKGROUND_LOG_DELTA_BYTES = 1024 * 1024;
354
+
355
+ function backgroundLogSize(file) {
356
+ try {
357
+ return statSync(file).size;
358
+ } catch {
359
+ return null;
360
+ }
361
+ }
362
+
363
+ function completeUtf8PrefixLength(buffer) {
364
+ if (buffer.length === 0) return 0;
365
+ let leadIndex = buffer.length - 1;
366
+ let continuationBytes = 0;
367
+ while (
368
+ leadIndex >= 0 &&
369
+ (buffer[leadIndex] & 0xc0) === 0x80 &&
370
+ continuationBytes < 3
371
+ ) {
372
+ continuationBytes += 1;
373
+ leadIndex -= 1;
374
+ }
375
+ if (leadIndex < 0) return buffer.length;
376
+ const lead = buffer[leadIndex];
377
+ const expectedBytes =
378
+ (lead & 0x80) === 0
379
+ ? 1
380
+ : (lead & 0xe0) === 0xc0
381
+ ? 2
382
+ : (lead & 0xf0) === 0xe0
383
+ ? 3
384
+ : (lead & 0xf8) === 0xf0
385
+ ? 4
386
+ : 1;
387
+ return buffer.length - leadIndex < expectedBytes ? leadIndex : buffer.length;
388
+ }
389
+
390
+ function readBackgroundLogRange(
391
+ file,
392
+ start,
393
+ length,
394
+ preserveTrailingUtf8 = false,
395
+ ) {
396
+ if (length <= 0) return { text: "", bytesRead: 0 };
397
+ let fd;
398
+ try {
399
+ fd = openSync(file, "r");
400
+ const buffer = Buffer.allocUnsafe(length);
401
+ let bytesRead = 0;
402
+ while (bytesRead < length) {
403
+ const count = readSync(
404
+ fd,
405
+ buffer,
406
+ bytesRead,
407
+ length - bytesRead,
408
+ start + bytesRead,
409
+ );
410
+ if (count === 0) break;
411
+ bytesRead += count;
412
+ }
413
+ const completeBytes = preserveTrailingUtf8
414
+ ? completeUtf8PrefixLength(buffer.subarray(0, bytesRead))
415
+ : bytesRead;
416
+ return {
417
+ text: buffer.subarray(0, completeBytes).toString("utf8"),
418
+ bytesRead: completeBytes,
419
+ };
420
+ } catch {
421
+ return { text: "", bytesRead: 0 };
422
+ } finally {
423
+ if (fd !== undefined) closeSync(fd);
424
+ }
425
+ }
353
426
 
354
427
  export function readLogFromOffset(file, offset) {
355
- if (!existsSync(file)) return { text: "", offset };
356
- const text = readFileSync(file, "utf8");
357
- if (offset > text.length) {
428
+ const normalizedOffset = Number.isSafeInteger(offset)
429
+ ? Math.max(0, offset)
430
+ : 0;
431
+ const size = backgroundLogSize(file);
432
+ if (size === null) return { text: "", offset: normalizedOffset };
433
+ if (normalizedOffset > size) {
358
434
  // Gap 3: the log shrank under us (rotation/truncation). Resetting the
359
435
  // offset to 0 used to REPLAY the entire new file into the follow stream;
360
436
  // resume from the current tail instead, with an explicit marker.
361
- const from = Math.max(0, text.length - TRUNCATION_RESUME_TAIL_BYTES);
437
+ const from = Math.max(0, size - TRUNCATION_RESUME_TAIL_BYTES);
438
+ const tail = readBackgroundLogRange(file, from, size - from);
362
439
  return {
363
- text: `\n${LOG_TRUNCATION_NOTICE}\n${text.slice(from)}`,
364
- offset: text.length,
440
+ text: `\n${LOG_TRUNCATION_NOTICE}\n${tail.text}`,
441
+ offset: from + tail.bytesRead,
365
442
  truncated: true,
366
443
  };
367
444
  }
368
- return { text: text.slice(offset), offset: text.length };
445
+ const length = Math.min(
446
+ size - normalizedOffset,
447
+ MAX_BACKGROUND_LOG_DELTA_BYTES,
448
+ );
449
+ const delta = readBackgroundLogRange(
450
+ file,
451
+ normalizedOffset,
452
+ length,
453
+ normalizedOffset + length < size,
454
+ );
455
+ return {
456
+ text: delta.text,
457
+ offset: normalizedOffset + delta.bytesRead,
458
+ };
369
459
  }
370
460
 
371
461
  /** Content-free JSONL authority exposed at the real background attach seam. */
@@ -390,7 +480,7 @@ async function followBackgroundAgent(id, options = {}) {
390
480
  const initial = readBackgroundAgentLog(id, { lines });
391
481
  if (initial)
392
482
  process.stdout.write(initial.endsWith("\n") ? initial : `${initial}\n`);
393
- let offset = existsSync(logFile) ? readFileSync(logFile, "utf8").length : 0;
483
+ let offset = backgroundLogSize(logFile) ?? 0;
394
484
 
395
485
  if (options.follow === false || state.status !== "running") {
396
486
  return state;
@@ -597,7 +687,7 @@ export async function interactiveAttach(id, state, options = {}) {
597
687
  if (initial)
598
688
  process.stdout.write(initial.endsWith("\n") ? initial : `${initial}\n`);
599
689
  const logFile = logPath(id);
600
- let offset = existsSync(logFile) ? readFileSync(logFile, "utf8").length : 0;
690
+ let offset = backgroundLogSize(logFile) ?? 0;
601
691
  logger.log(
602
692
  chalk.gray(
603
693
  `Attached to ${id} (interactive). Type a prompt to continue the session; /stop · /status · Ctrl-C detaches.`,
@@ -15,12 +15,51 @@ import {
15
15
  gitInit,
16
16
  isGitRepo,
17
17
  } from "../lib/git-integration.js";
18
+ import {
19
+ parseGitLabMergeRequestReference,
20
+ renderGitLabMergeRequestFooter,
21
+ } from "../lib/gitlab-mr-worktree.js";
18
22
 
19
23
  export function registerGitCommand(program) {
20
24
  const git = program
21
25
  .command("git")
22
26
  .description("Git integration for knowledge base versioning");
23
27
 
28
+ git
29
+ .command("gitlab-mr <reference>")
30
+ .description("Render a local GitLab MR/worktree footer (no network I/O)")
31
+ .option("--worktree <path>", "Worktree path to include in the footer")
32
+ .option("--host <host>", "Default GitLab host for project!iid shorthand")
33
+ .option("--json", "Output the normalized local display model as JSON")
34
+ .action((reference, options) => {
35
+ try {
36
+ const mr = parseGitLabMergeRequestReference(reference, {
37
+ defaultHost: options.host,
38
+ });
39
+ if (options.json) {
40
+ console.log(
41
+ JSON.stringify(
42
+ {
43
+ ...mr,
44
+ ...(options.worktree ? { worktreePath: options.worktree } : {}),
45
+ },
46
+ null,
47
+ 2,
48
+ ),
49
+ );
50
+ return;
51
+ }
52
+ logger.log(
53
+ renderGitLabMergeRequestFooter(mr, {
54
+ worktreePath: options.worktree,
55
+ }),
56
+ );
57
+ } catch (error) {
58
+ logger.error(`GitLab MR footer failed: ${error.message}`);
59
+ process.exitCode = 1;
60
+ }
61
+ });
62
+
24
63
  // git status
25
64
  git
26
65
  .command("status")
@@ -632,6 +632,10 @@ export function registerMcpCommand(program) {
632
632
  "--client-id <id>",
633
633
  "Use a pre-registered client_id instead of dynamic registration",
634
634
  )
635
+ .option(
636
+ "--redirect-uri <url>",
637
+ "Exact pre-registered http://127.0.0.1:<port>/<path> callback URI",
638
+ )
635
639
  .option(
636
640
  "--port <n>",
637
641
  "Localhost callback port",
@@ -662,6 +666,7 @@ export function registerMcpCommand(program) {
662
666
  const rec = await oauth.authorizeInteractive(url, {
663
667
  scope: options.scope,
664
668
  clientId: options.clientId,
669
+ redirectUri: options.redirectUri,
665
670
  port: options.port,
666
671
  writeOut: (s) => process.stdout.write(s),
667
672
  });