@seanhogg/builderforce-agents 2026.10.12 → 2026.10.13

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 (186) hide show
  1. package/dist/{agent-DvDtjczG.js → agent-CeWx2EpQ.js} +1 -1
  2. package/dist/{agent-DiLX8OzY.js → agent-DrcnpqOF.js} +1 -1
  3. package/dist/{agents-BawpdEjP.js → agents-CRJM6qhK.js} +1 -1
  4. package/dist/{agents-COWLUJqm.js → agents-hATFRfwk.js} +1 -1
  5. package/dist/{audio-preflight-CYQiI74L.js → audio-preflight-B9CfGDD2.js} +1 -1
  6. package/dist/{audio-preflight-BN1u9Tpc.js → audio-preflight-DHHeocUj.js} +1 -1
  7. package/dist/{auth-choice-D9VN-WjA.js → auth-choice-CWbPLRN0.js} +1 -1
  8. package/dist/{auth-choice-3cdcHeim.js → auth-choice-CzhKgWJy.js} +1 -1
  9. package/dist/{auth-choice.apply-Cd0RR0Z-.js → auth-choice.apply-C0RTYtRN.js} +1 -1
  10. package/dist/{auth-choice.apply-CMDgoDNN.js → auth-choice.apply-ChrTTHkK.js} +1 -1
  11. package/dist/{auth-choice.apply-BAeGyEKW.js → auth-choice.apply-D4LYzI8l.js} +1 -1
  12. package/dist/{auth-choice.apply-CSXvPCea.js → auth-choice.apply-Dy4rVG6K.js} +1 -1
  13. package/dist/{auth-choice.apply.transformers-DkX2-OZa.js → auth-choice.apply.transformers-9v6HFzNs.js} +1 -1
  14. package/dist/{auth-choice.apply.transformers-CEVxl3ul.js → auth-choice.apply.transformers-Be8599JD.js} +1 -1
  15. package/dist/{auth-choice.apply.transformers-B2Nr9M7m.js → auth-choice.apply.transformers-CgfGlqy1.js} +1 -1
  16. package/dist/{auth-choice.apply.transformers-Dpy9gODo.js → auth-choice.apply.transformers-D9a8-sLS.js} +1 -1
  17. package/dist/{banner-C93QSUTe.js → banner-8F7-gU1V.js} +1 -1
  18. package/dist/build-info.json +3 -3
  19. package/dist/{builderforce-Dl4bZ63C.js → builderforce-CCfM1c79.js} +1 -1
  20. package/dist/{builderforce-C_tuO46t.js → builderforce-CImLd8Zo.js} +1 -1
  21. package/dist/bundled/boot-md/handler.js +1 -1
  22. package/dist/bundled/session-memory/handler.js +1 -1
  23. package/dist/{channel-options-CiYpNR-1.js → channel-options-CRng-5hZ.js} +1 -1
  24. package/dist/{channel-options-Cziy0WDc.js → channel-options-D5kOIN7b.js} +1 -1
  25. package/dist/{channel-web-Ae15MleJ.js → channel-web-B5HSpL4k.js} +1 -1
  26. package/dist/{channels-cli-CZM033Me.js → channels-cli-COl9TDHT.js} +1 -1
  27. package/dist/{channels-cli-yi1vxpvO.js → channels-cli-bR8QwOv3.js} +1 -1
  28. package/dist/chrome-ChzFLAeJ.js +4 -0
  29. package/dist/chrome-CrqJ4Ijz.js +4 -0
  30. package/dist/{cli-Bwv_-VuS.js → cli-BqJMHFNK.js} +1 -1
  31. package/dist/{cli-D8fndSEi.js → cli-DBn0qbHS.js} +1 -1
  32. package/dist/{command-registry-Cjom5ab0.js → command-registry-BqhtXJa7.js} +1 -1
  33. package/dist/{command-registry-8uEx2JjY.js → command-registry-DVH79C3B.js} +1 -1
  34. package/dist/{completion-cli-PTFpWp8Q.js → completion-cli-BFR0u1Uh.js} +1 -1
  35. package/dist/{completion-cli-LUuqgvVQ.js → completion-cli-BuUAEqQw.js} +1 -1
  36. package/dist/{completion-cli-DRsz70D2.js → completion-cli-CwaIh4zw.js} +1 -1
  37. package/dist/{completion-cli-BsXDz7T2.js → completion-cli-Da3-oE7r.js} +1 -1
  38. package/dist/{config-cli-BIx0enD5.js → config-cli-Bhrj7H1i.js} +1 -1
  39. package/dist/{config-cli-BFhOXrua.js → config-cli-DOHKZ1lO.js} +1 -1
  40. package/dist/{configure-D96xLIb6.js → configure-B-Yta1X3.js} +1 -1
  41. package/dist/{configure-S7YE6hn1.js → configure-BHVk4Ax9.js} +1 -1
  42. package/dist/{configure-dDKfCq_g.js → configure-D9YZEK_D.js} +1 -1
  43. package/dist/{configure-C7xdw9Kq.js → configure-DPE2hDzY.js} +1 -1
  44. package/dist/{deps-CGiO_NDu.js → deps-CrAVOWsA.js} +1 -1
  45. package/dist/{doctor-completion-ChhIrLd3.js → doctor-completion-CkjrUmbI.js} +1 -1
  46. package/dist/{doctor-completion-BUZwWoWB.js → doctor-completion-Dh9ah5lH.js} +1 -1
  47. package/dist/{embedded-DJYMy81Q.js → embedded-BrqzM5oT.js} +12 -12
  48. package/dist/{embedded-DjDnQMNx.js → embedded-wYxo-ADm.js} +12 -12
  49. package/dist/entry.js +1 -1
  50. package/dist/extensionAPI.js +1 -1
  51. package/dist/{gateway-cli-CN114d5j.js → gateway-cli-C2nh9UyY.js} +2 -2
  52. package/dist/{gateway-cli-Dzl70YBF.js → gateway-cli-CGkTLhet.js} +2 -2
  53. package/dist/{health-Cf1YoTRN.js → health-CEz2-7et.js} +1 -1
  54. package/dist/{health-AlkF1nUa.js → health-CFVx21sO.js} +1 -1
  55. package/dist/{health-ySVOGGNu.js → health-aKuq4xwa.js} +1 -1
  56. package/dist/{hooks-cli-6jeFEGg3.js → hooks-cli-DPSrycwI.js} +1 -1
  57. package/dist/{hooks-cli-DVPMCXUq.js → hooks-cli-uPHs7qnC.js} +1 -1
  58. package/dist/index.js +2 -2
  59. package/dist/llm-slug-generator.js +1 -1
  60. package/dist/{models-CGUxphfN.js → models--TwKHn8b.js} +1 -1
  61. package/dist/{models-CIMM_Z3u.js → models-BXJebxTU.js} +1 -1
  62. package/dist/{models-cli-Cijh2uON.js → models-cli-O1zCgeoA.js} +1 -1
  63. package/dist/{models-cli-Oys3e_I3.js → models-cli-iKu1IVeH.js} +1 -1
  64. package/dist/{onboard-DAEXNhNd.js → onboard--0I8pdee.js} +1 -1
  65. package/dist/{onboard-b2fWbf0Q.js → onboard-C40OvMZO.js} +1 -1
  66. package/dist/{onboard-channels-elaccQRE.js → onboard-channels-BbpyejX4.js} +1 -1
  67. package/dist/{onboard-channels-Bsd11scA.js → onboard-channels-CoJnsCfd.js} +1 -1
  68. package/dist/{onboard-channels-C_Q7OUow.js → onboard-channels-ZI4QC9WU.js} +1 -1
  69. package/dist/{onboard-channels-Tl1X4Pl_.js → onboard-channels-uvIeLPXK.js} +1 -1
  70. package/dist/{onboard-interactive-DyGNiYRI.js → onboard-interactive-B3Z0XLT6.js} +1 -1
  71. package/dist/{onboard-interactive-C0qmgHsH.js → onboard-interactive-CJdxqQ1b.js} +1 -1
  72. package/dist/{onboard-interactive-86s992_v.js → onboard-interactive-COnCCTTW.js} +1 -1
  73. package/dist/{onboard-interactive-CvMSTjPK.js → onboard-interactive-jss8R9r9.js} +1 -1
  74. package/dist/{onboarding-DzvbhsaR.js → onboarding-B1BmYWrs.js} +2 -2
  75. package/dist/{onboarding-B0tbaqZ7.js → onboarding-CdRbvLgp.js} +2 -2
  76. package/dist/{onboarding.finalize-D-Pi9Blv.js → onboarding.finalize-B0AjF6qZ.js} +1 -1
  77. package/dist/{onboarding.finalize-CERLBlRF.js → onboarding.finalize-WsL-ijTc.js} +1 -1
  78. package/dist/{outbound-send-deps-CzhBrVa7.js → outbound-send-deps-DuML6h7r.js} +1 -1
  79. package/dist/{plugin-registry-DtrHn5NR.js → plugin-registry-BjWNyeVY.js} +1 -1
  80. package/dist/{plugin-registry-Avx51RIY.js → plugin-registry-Cf_sv-ny.js} +1 -1
  81. package/dist/{plugin-registry-CFkQDTOt.js → plugin-registry-DdFb5usc.js} +1 -1
  82. package/dist/{plugin-registry-BEmyRfmb.js → plugin-registry-DrEpL5ac.js} +1 -1
  83. package/dist/plugin-sdk/{accounts-BwreSNAR.js → accounts-Cy3WCbWg.js} +1 -1
  84. package/dist/plugin-sdk/{active-listener-DpQ7aGYd.js → active-listener-DVWVNlT9.js} +1 -1
  85. package/dist/plugin-sdk/agent-runtime/src/agents/tool-retry.d.ts +40 -32
  86. package/dist/plugin-sdk/agent-runtime/src/builderforce/model/agent-types.d.ts +6 -0
  87. package/dist/plugin-sdk/{agent-scope-BQByW0cD.js → agent-scope-DgKN27hJ.js} +1 -1
  88. package/dist/plugin-sdk/{api-key-rotation-yqTCeKjV.js → api-key-rotation-D37jV9ZW.js} +1 -1
  89. package/dist/plugin-sdk/{audio-preflight-B6uTvVfA.js → audio-preflight-D4xyO8Zq.js} +1 -1
  90. package/dist/plugin-sdk/{auth-json-Dw6ij9Pa.js → auth-json-nASe57Uw.js} +1 -1
  91. package/dist/plugin-sdk/{bindings-CDEzl4kl.js → bindings-CH-YLOLC.js} +1 -1
  92. package/dist/plugin-sdk/{channel-web-DKbpA9xC.js → channel-web-huZSNTX3.js} +1 -1
  93. package/dist/plugin-sdk/{chrome-DriEqJRH.js → chrome-CRUzg3kA.js} +1 -1
  94. package/dist/plugin-sdk/{chunk-cW0POl22.js → chunk-C94IAOuf.js} +1 -1
  95. package/dist/plugin-sdk/{command-format-CAX9XFjI.js → command-format-B3XMq_73.js} +1 -1
  96. package/dist/plugin-sdk/{common-BxEWhN2X.js → common-n0l_XN-S.js} +1 -1
  97. package/dist/plugin-sdk/{config-3vPn_hmp.js → config--Ci8Y91R.js} +2 -2
  98. package/dist/plugin-sdk/{fetch-DH0Y8iyO.js → fetch-B-GxSYRO.js} +1 -1
  99. package/dist/plugin-sdk/index.js +1 -1
  100. package/dist/plugin-sdk/{login-Dhdx0bVL.js → login-DZliYZg8.js} +1 -1
  101. package/dist/plugin-sdk/{login-qr-DAjOuijP.js → login-qr-DKcGvAjv.js} +1 -1
  102. package/dist/plugin-sdk/{manager-i8psl2Er.js → manager-DioOqJm_.js} +1 -1
  103. package/dist/plugin-sdk/{markdown-tables-Epim9b-0.js → markdown-tables-BUfhHgfs.js} +1 -1
  104. package/dist/plugin-sdk/{message-channel-sBPQc_-T.js → message-channel-CuZ2xOAM.js} +1 -1
  105. package/dist/plugin-sdk/{model-catalog-COVRezOQ.js → model-catalog-DIQ5a-o4.js} +1 -1
  106. package/dist/plugin-sdk/{model-selection-Crz-xYNU.js → model-selection-_H_U9jWH.js} +1 -1
  107. package/dist/plugin-sdk/{outbound-CPutSvae.js → outbound-Djibdmi7.js} +1 -1
  108. package/dist/plugin-sdk/{plugins-CaUOZBVb.js → plugins-BdkC9v5E.js} +1 -1
  109. package/dist/plugin-sdk/{pw-ai-jI9AWvKe.js → pw-ai-Bbi8Us-p.js} +1 -1
  110. package/dist/plugin-sdk/{qmd-manager-BRe5fGZw.js → qmd-manager-Dxn0jCpE.js} +1 -1
  111. package/dist/plugin-sdk/{registry-DJq2Cvo9.js → registry-CZHRcH-q.js} +1 -1
  112. package/dist/plugin-sdk/{render-BUCRXPIk.js → render-CuA_WRX5.js} +1 -1
  113. package/dist/plugin-sdk/{replies-CYjI7bye.js → replies-Cf69aZLA.js} +1 -1
  114. package/dist/plugin-sdk/{reply-B5o-SSYy.js → reply-BOVC-7UD.js} +13 -13
  115. package/dist/plugin-sdk/{reply-prefix-CCymsmsP.js → reply-prefix-w7kAvH11.js} +1 -1
  116. package/dist/plugin-sdk/{resolve-route-DN1J7Wyc.js → resolve-route-0sbvl4ZN.js} +1 -1
  117. package/dist/plugin-sdk/{runner-C2pDJlRw.js → runner-DKoKK09-.js} +4 -4
  118. package/dist/plugin-sdk/{session-BnleckVX.js → session-DGLuyt10.js} +1 -1
  119. package/dist/plugin-sdk/{sqlite-BlMLqMl8.js → sqlite-JjFgDV-H.js} +1 -1
  120. package/dist/plugin-sdk/{subsystem-COTa5Ly_.js → subsystem-D0Ril4rt.js} +1 -1
  121. package/dist/plugin-sdk/{tool-images-DSpchb4x.js → tool-images-WRTP95FT.js} +1 -1
  122. package/dist/plugin-sdk/{tool-loop-detection-16p7mJ8N.js → tool-loop-detection-g8gPTCgJ.js} +1 -1
  123. package/dist/plugin-sdk/web-Cdu8TkUy.js +1 -0
  124. package/dist/plugin-sdk/{whatsapp-actions-C2B3iw8n.js → whatsapp-actions-CsSzy7G0.js} +1 -1
  125. package/dist/{plugins-DAlgx58e.js → plugins-Dr1wmnAf.js} +1 -1
  126. package/dist/{plugins-De7aK3yK.js → plugins-JhEblShx.js} +1 -1
  127. package/dist/{plugins-cli-CwdUVWjG.js → plugins-cli-DW4hoeeV.js} +1 -1
  128. package/dist/{plugins-cli-CfVCrrhx.js → plugins-cli-GewV3E8e.js} +1 -1
  129. package/dist/{program-CFL6mW3l.js → program-bggmBKuL.js} +2 -2
  130. package/dist/{program-context-DP4Xq9zC.js → program-context-BCTE8zEF.js} +1 -1
  131. package/dist/{prompt-select-styled-NxrGT7OR.js → prompt-select-styled-BtjhlTEH.js} +1 -1
  132. package/dist/{prompt-select-styled-Csz9HlSx.js → prompt-select-styled-CaNl41mG.js} +1 -1
  133. package/dist/{provider-auth-helpers-BMBw21Tn.js → provider-auth-helpers-CWUfg9zf.js} +1 -1
  134. package/dist/{provider-auth-helpers-VWPvSXPH.js → provider-auth-helpers-y1X8xKVE.js} +1 -1
  135. package/dist/{provider-dispatcher-CSOHd9zJ.js → provider-dispatcher-CRsPmKhJ.js} +1 -1
  136. package/dist/{provider-dispatcher-Bg9orQPy.js → provider-dispatcher-D9GbE_Ce.js} +1 -1
  137. package/dist/{push-apns-rMu8MKXi.js → push-apns-Cb1sQEEa.js} +1 -1
  138. package/dist/{push-apns-ep5WkyGz.js → push-apns-Cr-6aD3y.js} +1 -1
  139. package/dist/{pw-ai-UXo3gDGy.js → pw-ai-CG-kY5NP.js} +1 -1
  140. package/dist/{pw-ai-CIN6tj0G.js → pw-ai-DcZPg2vm.js} +1 -1
  141. package/dist/{register.agent-BynXVz7v.js → register.agent-B33EZBoL.js} +1 -1
  142. package/dist/{register.agent-RNVNKBP3.js → register.agent-DfYqZls1.js} +1 -1
  143. package/dist/{register.configure-BdqREs1-.js → register.configure-CREcJhKA.js} +1 -1
  144. package/dist/{register.configure-DDrvpBnA.js → register.configure-D8an7wc5.js} +1 -1
  145. package/dist/{register.maintenance-DT6t7mD_.js → register.maintenance-D84M5XLR.js} +1 -1
  146. package/dist/{register.maintenance-BSKHOCTV.js → register.maintenance-Dnp_Ii2x.js} +1 -1
  147. package/dist/{register.message-7KIfSUxS.js → register.message-B6E0uAEu.js} +1 -1
  148. package/dist/{register.message-DDhEvcaX.js → register.message-WOWC4tyf.js} +1 -1
  149. package/dist/{register.onboard-CKhooa7L.js → register.onboard-AgVEhehS.js} +1 -1
  150. package/dist/{register.onboard-CswvuzLx.js → register.onboard-Cwozk0Tx.js} +1 -1
  151. package/dist/{register.setup-1BmR-qlh.js → register.setup-BKyCvo9_.js} +1 -1
  152. package/dist/{register.setup-CivwfXf_.js → register.setup-C9IeGiAd.js} +1 -1
  153. package/dist/{register.status-health-sessions-CLdHZiJm.js → register.status-health-sessions-CYZctjpx.js} +1 -1
  154. package/dist/{register.status-health-sessions-BXpljfv3.js → register.status-health-sessions-CcL6srRC.js} +1 -1
  155. package/dist/{register.subclis-D_fHb-Aj.js → register.subclis-AFsfDByV.js} +1 -1
  156. package/dist/{register.subclis-CTTxdHaJ.js → register.subclis-C0DxtuRO.js} +1 -1
  157. package/dist/{reply-D9wUWhMx.js → reply-BuUSdq2L.js} +9 -9
  158. package/dist/{run-main-DNyQhVQT.js → run-main-CgJMiKPV.js} +1 -1
  159. package/dist/{runner-BNnckkaT.js → runner-C8oNv-9y.js} +3 -3
  160. package/dist/{runner-EHybuAt7.js → runner-nDoIXX7n.js} +3 -3
  161. package/dist/{server-node-events-BGrnw4ZT.js → server-node-events-BMsKmU5S.js} +1 -1
  162. package/dist/{server-node-events-D4WVcVHy.js → server-node-events-fS8TluXq.js} +1 -1
  163. package/dist/{session-dirs-eNN7E3kA.js → session-dirs-Bkfs-7vN.js} +1 -1
  164. package/dist/{session-dirs-C-pVBwSV.js → session-dirs-rYDCA_mQ.js} +1 -1
  165. package/dist/{status-Demw1HZ7.js → status-Ad1eFPKR.js} +1 -1
  166. package/dist/{status-CBieo24v.js → status-BMzVz5KY.js} +1 -1
  167. package/dist/{status-rkFgCaBM.js → status-CXRyaGws.js} +1 -1
  168. package/dist/{status-wTMmjZ7M.js → status-DpEUFAMk.js} +1 -1
  169. package/dist/{status-BhJw9Htq.js → status-oaiZkYBt.js} +1 -1
  170. package/dist/{subagent-registry-Bje3RAgk.js → subagent-registry-gVTWLPpL.js} +1 -1
  171. package/dist/{subagent-registry-B0kpBIxD.js → subagent-registry-hM0OCDzv.js} +1 -1
  172. package/dist/{subagent-registry-Cj5yC7B4.js → subagent-registry-m_x-JRkR.js} +9 -9
  173. package/dist/{tui-BCtecmPL.js → tui-HTtOgZ_X.js} +2 -2
  174. package/dist/{tui-BqHLI73U.js → tui-LemSel3H.js} +2 -2
  175. package/dist/{tui-cli-2R0xjpqW.js → tui-cli-BpzicV5H.js} +1 -1
  176. package/dist/{tui-cli-Dvd8BwzD.js → tui-cli-CruoIP1K.js} +1 -1
  177. package/dist/{update-cli-DUObGvw1.js → update-cli-Wa-nZ_Lq.js} +1 -1
  178. package/dist/{update-cli-Bt7Vfi7c.js → update-cli-zv67YxK1.js} +1 -1
  179. package/dist/{web--KblE8ax.js → web-BrsbhB1i.js} +1 -1
  180. package/dist/{web-C-yTnRvS.js → web-BzkO4Pbe.js} +1 -1
  181. package/dist/{web-0VRcRcFj.js → web-D_QYY7Gt.js} +1 -1
  182. package/dist/{web-BcUIWAAJ.js → web-jPbmSTQm.js} +1 -1
  183. package/package.json +1 -1
  184. package/dist/chrome-CmCESKt9.js +0 -4
  185. package/dist/chrome-D6qk0wxW.js +0 -4
  186. package/dist/plugin-sdk/web-CzJYJZZs.js +0 -1
@@ -1,4 +1,4 @@
1
- import{n as DEFAULT_AGENT_ID}from"./session-key-5J69DULS.js";import{j as resolveUserPath,k as resolveConfigDir,x as escapeRegExp}from"./registry-DJq2Cvo9.js";import{o as resolveOAuthPath,s as resolveStateDir}from"./paths-Cb8zTlyG.js";import{t as createSubsystemLogger}from"./subsystem-COTa5Ly_.js";import{A as logDebug,a as resolveAgentModelPrimary,n as resolveAgentConfig}from"./agent-scope-BQByW0cD.js";import{r as isTruthyEnvValue,t as formatCliCommand}from"./command-format-CAX9XFjI.js";import{n as saveJsonFile,t as loadJsonFile}from"./json-file-DUi7S24G.js";import{E as isModelRole,g as evaluatePolicyGate,v as toolCallPaths}from"./src-5XE2oMwl.js";import path,{join,resolve}from"node:path";import fs,{appendFileSync,existsSync,mkdirSync,readFileSync,writeFileSync}from"node:fs";import{randomUUID}from"node:crypto";import fs$1 from"node:fs/promises";import{execFileSync}from"node:child_process";import{BedrockClient,ListFoundationModelsCommand}from"@aws-sdk/client-bedrock";function isPidAlive(pid){if(!Number.isFinite(pid)||pid<=0)return!1;try{return process.kill(pid,0),!0}catch{return!1}}function resolveProcessScopedMap(key){let proc=process,existing=proc[key];if(existing)return existing;let created=new Map;return proc[key]=created,created}const HELD_LOCKS=resolveProcessScopedMap(Symbol.for(`builderforce.fileLockHeldLocks`));function computeDelayMs(retries,attempt){let base=Math.min(retries.maxTimeout,Math.max(retries.minTimeout,retries.minTimeout*retries.factor**attempt)),jitter=retries.randomize?1+Math.random():1;return Math.min(retries.maxTimeout,Math.round(base*jitter))}async function readLockPayload(lockPath){try{let raw=await fs$1.readFile(lockPath,`utf8`),parsed=JSON.parse(raw);return typeof parsed.pid!=`number`||typeof parsed.createdAt!=`string`?null:{pid:parsed.pid,createdAt:parsed.createdAt}}catch{return null}}async function resolveNormalizedFilePath(filePath){let resolved=path.resolve(filePath),dir=path.dirname(resolved);await fs$1.mkdir(dir,{recursive:!0});try{let realDir=await fs$1.realpath(dir);return path.join(realDir,path.basename(resolved))}catch{return resolved}}async function isStaleLock(lockPath,staleMs){let payload=await readLockPayload(lockPath);if(payload?.pid&&!isPidAlive(payload.pid))return!0;if(payload?.createdAt){let createdAt=Date.parse(payload.createdAt);if(!Number.isFinite(createdAt)||Date.now()-createdAt>staleMs)return!0}try{let stat=await fs$1.stat(lockPath);return Date.now()-stat.mtimeMs>staleMs}catch{return!0}}async function releaseHeldLock(normalizedFile){let current=HELD_LOCKS.get(normalizedFile);current&&(--current.count,!(current.count>0)&&(HELD_LOCKS.delete(normalizedFile),await current.handle.close().catch(()=>void 0),await fs$1.rm(current.lockPath,{force:!0}).catch(()=>void 0)))}async function acquireFileLock(filePath,options){let normalizedFile=await resolveNormalizedFilePath(filePath),lockPath=`${normalizedFile}.lock`,held=HELD_LOCKS.get(normalizedFile);if(held)return held.count+=1,{lockPath,release:()=>releaseHeldLock(normalizedFile)};let attempts=Math.max(1,options.retries.retries+1);for(let attempt=0;attempt<attempts;attempt+=1)try{let handle=await fs$1.open(lockPath,`wx`);return await handle.writeFile(JSON.stringify({pid:process.pid,createdAt:new Date().toISOString()},null,2),`utf8`),HELD_LOCKS.set(normalizedFile,{count:1,handle,lockPath}),{lockPath,release:()=>releaseHeldLock(normalizedFile)}}catch(err){if(err.code!==`EEXIST`)throw err;if(await isStaleLock(lockPath,options.stale)){await fs$1.rm(lockPath,{force:!0}).catch(()=>void 0);continue}if(attempt>=attempts-1)break;await new Promise(resolve=>setTimeout(resolve,computeDelayMs(options.retries,attempt)))}throw Error(`file lock timeout for ${normalizedFile}`)}async function withFileLock(filePath,options,fn){let lock=await acquireFileLock(filePath,options);try{return await fn()}finally{await lock.release()}}const DEFAULT_TIMEOUT_MS=15e3;let lastAppliedKeys=[],cachedShellPath;function resolveTimeoutMs(timeoutMs){return typeof timeoutMs!=`number`||!Number.isFinite(timeoutMs)?DEFAULT_TIMEOUT_MS:Math.max(0,timeoutMs)}function resolveShell(env){let shell=env.SHELL?.trim();return shell&&shell.length>0?shell:`/bin/sh`}function execLoginShellEnvZero(params){return params.exec(params.shell,[`-l`,`-c`,`env -0`],{encoding:`buffer`,timeout:params.timeoutMs,maxBuffer:2097152,env:params.env,stdio:[`ignore`,`pipe`,`pipe`]})}function parseShellEnv(stdout){let shellEnv=new Map,parts=stdout.toString(`utf8`).split(`\0`);for(let part of parts){if(!part)continue;let eq=part.indexOf(`=`);if(eq<=0)continue;let key=part.slice(0,eq),value=part.slice(eq+1);key&&shellEnv.set(key,value)}return shellEnv}function loadShellEnvFallback(opts){let logger=opts.logger??console,exec=opts.exec??execFileSync;if(!opts.enabled)return lastAppliedKeys=[],{ok:!0,applied:[],skippedReason:`disabled`};if(opts.expectedKeys.some(key=>!!opts.env[key]?.trim()))return lastAppliedKeys=[],{ok:!0,applied:[],skippedReason:`already-has-keys`};let timeoutMs=resolveTimeoutMs(opts.timeoutMs),shell=resolveShell(opts.env),stdout;try{stdout=execLoginShellEnvZero({shell,env:opts.env,exec,timeoutMs})}catch(err){let msg=err instanceof Error?err.message:String(err);return logger.warn(`[builderforce] shell env fallback failed: ${msg}`),lastAppliedKeys=[],{ok:!1,error:msg,applied:[]}}let shellEnv=parseShellEnv(stdout),applied=[];for(let key of opts.expectedKeys){if(opts.env[key]?.trim())continue;let value=shellEnv.get(key);value?.trim()&&(opts.env[key]=value,applied.push(key))}return lastAppliedKeys=applied,{ok:!0,applied}}function shouldEnableShellEnvFallback(env){return isTruthyEnvValue(env.BUILDERFORCE_AGENTS_LOAD_SHELL_ENV)}function shouldDeferShellEnvFallback(env){return isTruthyEnvValue(env.BUILDERFORCE_AGENTS_DEFER_SHELL_ENV_FALLBACK)}function resolveShellEnvFallbackTimeoutMs(env){let raw=env.BUILDERFORCE_AGENTS_SHELL_ENV_TIMEOUT_MS?.trim();if(!raw)return DEFAULT_TIMEOUT_MS;let parsed=Number.parseInt(raw,10);return Number.isFinite(parsed)?Math.max(0,parsed):DEFAULT_TIMEOUT_MS}function getShellPathFromLoginShell(opts){if(cachedShellPath!==void 0)return cachedShellPath;if(process.platform===`win32`)return cachedShellPath=null,cachedShellPath;let exec=opts.exec??execFileSync,timeoutMs=resolveTimeoutMs(opts.timeoutMs),shell=resolveShell(opts.env),stdout;try{stdout=execLoginShellEnvZero({shell,env:opts.env,exec,timeoutMs})}catch{return cachedShellPath=null,cachedShellPath}let shellPath=parseShellEnv(stdout).get(`PATH`)?.trim();return cachedShellPath=shellPath&&shellPath.length>0?shellPath:null,cachedShellPath}function getShellEnvAppliedKeys(){return[...lastAppliedKeys]}const TOKENS_PER_MILLION=1e6;function perMillionToPerToken(usdPerMillion){return usdPerMillion/TOKENS_PER_MILLION}function perTokenToPerMillion(usdPerToken){return usdPerToken*TOKENS_PER_MILLION}Object.freeze({input:0,output:0});const UNKNOWN_TIER_RANK=4,STRONGEST_FIRST={ULTRA:0,PREMIUM:1,STANDARD:2,FREE:3};function tierRank(tier){return tier&&tier in STRONGEST_FIRST?STRONGEST_FIRST[tier]:4}function tierForPrice(price){if(price.input===0&&price.output===0)return`FREE`;let outputPerMillion=perTokenToPerMillion(price.output);return outputPerMillion<8?`STANDARD`:outputPerMillion<20?`PREMIUM`:`ULTRA`}function resolveModelTier(known){return known.catalogTier?known.catalogTier:known.price?tierForPrice(known.price):void 0}const LLM_PROVIDER_INFO=[{id:`anthropic`,label:`Anthropic (Claude)`,credential:`api_key`,keyPlaceholder:`sk-ant-…`,subscription:`paste`},{id:`openai`,label:`OpenAI`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:`paste`},{id:`google`,label:`Google (Gemini)`,credential:`api_key`,keyPlaceholder:`AIza…`,subscription:null},{id:`meta`,label:`Meta AI (MUSE)`,credential:`api_key`,keyPlaceholder:`meta-…`,subscription:null},{id:`kimi`,label:`Kimi`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:`device`},{id:`moonshot`,label:`Moonshot AI`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:null},{id:`qwen`,label:`Qwen`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:null},{id:`minimax`,label:`MiniMax`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:null},{id:`xai`,label:`xAI (Grok)`,credential:`api_key`,keyPlaceholder:`xai-…`,subscription:`paste`},{id:`ollama`,label:`Ollama Cloud`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:null},{id:`ollama-local`,label:`Ollama`,credential:`local_runtime`,keyPlaceholder:``,subscription:null,localRuntime:{defaultBaseUrl:`http://127.0.0.1:11434`,exampleModel:`llama3.1:8b`}},{id:`freetoken`,label:`FreeToken`,credential:`local_runtime`,keyPlaceholder:``,subscription:null,localRuntime:{defaultBaseUrl:`http://127.0.0.1:1919`}}];LLM_PROVIDER_INFO.map(p=>p.id),new Map(LLM_PROVIDER_INFO.map(p=>[p.id,p]));const ANTHROPIC_FAMILIES=[`opus`,`sonnet`,`haiku`,`fable`],ANTHROPIC_RELEASES={opus:[`5.5`,`5`,`4.8`,`4.7`,`4.6`,`4.5`,`4.1`,`4.0`],sonnet:[`5.5`,`5`,`4.6`,`4.5`,`4.0`],haiku:[`5.5`,`4.5`],fable:[`5.1`,`5`]};function parseVersion(version){let[major,minor]=version.split(`.`);return[Number(major),Number(minor??0)]}function compareVersions(a,b){return a[0]-b[0]||a[1]-b[1]}function anthropicModelId(family,version){return`claude-${family}-${version.replace(`.`,`-`)}`}function currentAnthropicModelId(family){return anthropicModelId(family,ANTHROPIC_RELEASES[family][0])}function resolveAnthropicShortAlias(raw){let match=/^(opus|sonnet|haiku|fable)-(\d+)\.(\d+)$/.exec(raw.trim().toLowerCase());return match?`claude-${match[1]}-${match[2]}-${match[3]}`:void 0}const CLAUDE_ID=/^claude-(opus|sonnet|haiku|fable)-(\d+)(?:([-.])(\d{1,2})(?=-|$))?(-.*)?$/;function parseAnthropicModelId(id){let match=CLAUDE_ID.exec(id.trim().toLowerCase());if(match)return{family:match[1],version:[Number(match[2]),Number(match[4]??0)],separator:match[3]===`.`?`.`:`-`,suffix:match[5]??``}}function olderAnthropicTemplateIds(id){let parsed=parseAnthropicModelId(id);if(!parsed)return[];let older=ANTHROPIC_RELEASES[parsed.family].filter(v=>compareVersions(parseVersion(v),parsed.version)<0),spell=v=>`claude-${parsed.family}-${v.replace(`.`,parsed.separator)}`,withSuffix=parsed.suffix?older.map(v=>`${spell(v)}${parsed.suffix}`):[];return[...new Set([...withSuffix,...older.map(spell)])]}const LEGACY_FAMILY_ALIASES={"haiku-3.5":`haiku`,"claude-3-5-haiku":`haiku`};function anthropicFamilyAliases(){let out={...LEGACY_FAMILY_ALIASES};for(let family of ANTHROPIC_FAMILIES){out[family]=family;for(let version of ANTHROPIC_RELEASES[family])out[`${family}-${version}`]=family,out[anthropicModelId(family,version)]=family}return out}const DEFAULT_PROVIDER=`builderforcellm`,DEFAULT_MODEL=`auto`,DEFAULT_CONTEXT_TOKENS=2e5;function normalizeBaseUrl(url){return url.replace(/\/+$/,``)}const QWEN_CLI_PROFILE_ID=`qwen-portal:qwen-cli`,AUTH_STORE_LOCK_OPTIONS={retries:{retries:10,factor:2,minTimeout:100,maxTimeout:1e4,randomize:!0},stale:3e4},EXTERNAL_CLI_SYNC_TTL_MS=900*1e3,log$1=createSubsystemLogger(`agents/auth-profiles`);function resolveAuthProfileDisplayLabel(params){let{cfg,store,profileId}=params,profile=store.profiles[profileId],email=cfg?.auth?.profiles?.[profileId]?.email?.trim()||(profile&&`email`in profile?profile.email?.trim():void 0);return email?`${profileId} (${email})`:profileId}function normalizeSecretInput(value){return typeof value==`string`?value.replace(/[\r\n\u2028\u2029]+/g,``).trim():``}function normalizeOptionalSecretInput(value){return normalizeSecretInput(value)||void 0}createSubsystemLogger(`agents/auth-profiles`);async function cachedByKey(store,cacheKey,ttlMs,loader){let now=Date.now();if(ttlMs>0&&store.current&&store.current.cacheKey===cacheKey&&now-store.current.readAt<ttlMs)return store.current.value;let value=await loader();return ttlMs>0&&(store.current={value,readAt:now,cacheKey}),value}const qwenCliCache={current:null},minimaxCliCache={current:null};function resolveQwenCliCredentialsPath(homeDir){let baseDir=homeDir??resolveUserPath(`~`);return path.join(baseDir,`.qwen/oauth_creds.json`)}function resolveMiniMaxCliCredentialsPath(homeDir){let baseDir=homeDir??resolveUserPath(`~`);return path.join(baseDir,`.minimax/oauth_creds.json`)}async function readQwenCliCredentials(options){return readPortalCliOauthCredentials(resolveQwenCliCredentialsPath(options?.homeDir),`qwen-portal`)}async function readPortalCliOauthCredentials(credPath,provider){let raw=await loadJsonFile(credPath);if(!raw||typeof raw!=`object`)return null;let data=raw,accessToken=data.access_token,refreshToken=data.refresh_token,expiresAt=data.expiry_date;return typeof accessToken!=`string`||!accessToken||typeof refreshToken!=`string`||!refreshToken||typeof expiresAt!=`number`||!Number.isFinite(expiresAt)?null:{type:`oauth`,provider,access:accessToken,refresh:refreshToken,expires:expiresAt}}async function readMiniMaxCliCredentials(options){return readPortalCliOauthCredentials(resolveMiniMaxCliCredentialsPath(options?.homeDir),`minimax-portal`)}async function readQwenCliCredentialsCached(options){return cachedByKey(qwenCliCache,resolveQwenCliCredentialsPath(options?.homeDir),options?.ttlMs??0,()=>readQwenCliCredentials({homeDir:options?.homeDir}))}async function readMiniMaxCliCredentialsCached(options){return cachedByKey(minimaxCliCache,resolveMiniMaxCliCredentialsPath(options?.homeDir),options?.ttlMs??0,()=>readMiniMaxCliCredentials({homeDir:options?.homeDir}))}function shallowEqualOAuthCredentials(a,b){return!a||a.type!==`oauth`?!1:a.provider===b.provider&&a.access===b.access&&a.refresh===b.refresh&&a.expires===b.expires&&a.email===b.email&&a.enterpriseUrl===b.enterpriseUrl&&a.projectId===b.projectId&&a.accountId===b.accountId}function isExternalProfileFresh(cred,now){return!cred||cred.type!==`oauth`&&cred.type!==`token`||cred.provider!==`qwen-portal`&&cred.provider!==`minimax-portal`?!1:typeof cred.expires==`number`?cred.expires>now+6e5:!0}async function syncExternalCliCredentialsForProvider(store,profileId,provider,readCredentials,now){let existing=store.profiles[profileId],creds=!existing||existing.provider!==provider||!isExternalProfileFresh(existing,now)?await readCredentials():null;if(!creds)return!1;let existingOAuth=existing?.type===`oauth`?existing:void 0;return(!existingOAuth||existingOAuth.provider!==provider||existingOAuth.expires<=now||creds.expires>existingOAuth.expires)&&!shallowEqualOAuthCredentials(existingOAuth,creds)?(store.profiles[profileId]=creds,log$1.info(`synced ${provider} credentials from external cli`,{profileId,expires:new Date(creds.expires).toISOString()}),!0):!1}async function syncExternalCliCredentials(store){let mutated=!1,now=Date.now(),existingQwen=store.profiles[QWEN_CLI_PROFILE_ID],qwenCreds=!existingQwen||existingQwen.provider!==`qwen-portal`||!isExternalProfileFresh(existingQwen,now)?await readQwenCliCredentialsCached({ttlMs:EXTERNAL_CLI_SYNC_TTL_MS}):null;if(qwenCreds){let existing=store.profiles[QWEN_CLI_PROFILE_ID],existingOAuth=existing?.type===`oauth`?existing:void 0;(!existingOAuth||existingOAuth.provider!==`qwen-portal`||existingOAuth.expires<=now||qwenCreds.expires>existingOAuth.expires)&&!shallowEqualOAuthCredentials(existingOAuth,qwenCreds)&&(store.profiles[QWEN_CLI_PROFILE_ID]=qwenCreds,mutated=!0,log$1.info(`synced qwen credentials from qwen cli`,{profileId:QWEN_CLI_PROFILE_ID,expires:new Date(qwenCreds.expires).toISOString()}))}return await syncExternalCliCredentialsForProvider(store,`minimax-portal:minimax-cli`,`minimax-portal`,()=>readMiniMaxCliCredentialsCached({ttlMs:EXTERNAL_CLI_SYNC_TTL_MS}),now)&&(mutated=!0),mutated}function resolveBuilderForceAgentsAgentDir(){return resolveUserPath(process.env.BUILDERFORCE_AGENTS_AGENT_DIR?.trim()||process.env.PI_CODING_AGENT_DIR?.trim()||path.join(resolveStateDir(),`agents`,DEFAULT_AGENT_ID,`agent`))}function resolveAuthStorePath(agentDir){let resolved=resolveUserPath(agentDir??resolveBuilderForceAgentsAgentDir());return path.join(resolved,`auth-profiles.json`)}function resolveLegacyAuthStorePath(agentDir){let resolved=resolveUserPath(agentDir??resolveBuilderForceAgentsAgentDir());return path.join(resolved,`auth.json`)}function resolveAuthStorePathForDisplay(agentDir){let pathname=resolveAuthStorePath(agentDir);return pathname.startsWith(`~`)?pathname:resolveUserPath(pathname)}async function ensureAuthStoreFile(pathname){fs.existsSync(pathname)||await saveJsonFile(pathname,{version:1,profiles:{}})}async function updateAuthProfileStoreWithLock(params){let authPath=resolveAuthStorePath(params.agentDir);await ensureAuthStoreFile(authPath);try{return await withFileLock(authPath,AUTH_STORE_LOCK_OPTIONS,async()=>{let store=await ensureAuthProfileStore(params.agentDir);return params.updater(store)&&await saveAuthProfileStore(store,params.agentDir),store})}catch{return null}}function coerceLegacyStore(raw){if(!raw||typeof raw!=`object`)return null;let record=raw;if(`profiles`in record)return null;let entries={};for(let[key,value]of Object.entries(record)){if(!value||typeof value!=`object`)continue;let typed=value;typed.type!==`api_key`&&typed.type!==`oauth`&&typed.type!==`token`||(entries[key]={...typed,provider:String(typed.provider??key)})}return Object.keys(entries).length>0?entries:null}function coerceAuthStore(raw){if(!raw||typeof raw!=`object`)return null;let record=raw;if(!record.profiles||typeof record.profiles!=`object`)return null;let profiles=record.profiles,normalized={};for(let[key,value]of Object.entries(profiles)){if(!value||typeof value!=`object`)continue;let typed=value;typed.type!==`api_key`&&typed.type!==`oauth`&&typed.type!==`token`||typed.provider&&(normalized[key]=typed)}let order=record.order&&typeof record.order==`object`?Object.entries(record.order).reduce((acc,[provider,value])=>{if(!Array.isArray(value))return acc;let list=value.map(entry=>typeof entry==`string`?entry.trim():``).filter(Boolean);return list.length===0||(acc[provider]=list),acc},{}):void 0;return{version:Number(record.version??1),profiles:normalized,order,lastGood:record.lastGood&&typeof record.lastGood==`object`?record.lastGood:void 0,usageStats:record.usageStats&&typeof record.usageStats==`object`?record.usageStats:void 0}}function mergeRecord(base,override){if(!(!base&&!override))return base?override?{...base,...override}:{...base}:{...override}}function mergeAuthProfileStores(base,override){return Object.keys(override.profiles).length===0&&!override.order&&!override.lastGood&&!override.usageStats?base:{version:Math.max(base.version,override.version??base.version),profiles:{...base.profiles,...override.profiles},order:mergeRecord(base.order,override.order),lastGood:mergeRecord(base.lastGood,override.lastGood),usageStats:mergeRecord(base.usageStats,override.usageStats)}}async function mergeOAuthFileIntoStore(store){let oauthRaw=await loadJsonFile(resolveOAuthPath());if(!oauthRaw||typeof oauthRaw!=`object`)return!1;let oauthEntries=oauthRaw,mutated=!1;for(let[provider,creds]of Object.entries(oauthEntries)){if(!creds||typeof creds!=`object`)continue;let profileId=`${provider}:default`;store.profiles[profileId]||(store.profiles[profileId]={type:`oauth`,provider,...creds},mutated=!0)}return mutated}function applyLegacyStore(store,legacy){for(let[provider,cred]of Object.entries(legacy)){let profileId=`${provider}:default`;if(cred.type===`api_key`){store.profiles[profileId]={type:`api_key`,provider:String(cred.provider??provider),key:cred.key,...cred.email?{email:cred.email}:{}};continue}if(cred.type===`token`){store.profiles[profileId]={type:`token`,provider:String(cred.provider??provider),token:cred.token,...typeof cred.expires==`number`?{expires:cred.expires}:{},...cred.email?{email:cred.email}:{}};continue}store.profiles[profileId]={type:`oauth`,provider:String(cred.provider??provider),access:cred.access,refresh:cred.refresh,expires:cred.expires,...cred.enterpriseUrl?{enterpriseUrl:cred.enterpriseUrl}:{},...cred.projectId?{projectId:cred.projectId}:{},...cred.accountId?{accountId:cred.accountId}:{},...cred.email?{email:cred.email}:{}}}}async function loadAuthProfileStoreForAgent(agentDir,_options){let authPath=resolveAuthStorePath(agentDir),asStore=coerceAuthStore(await loadJsonFile(authPath));if(asStore)return await syncExternalCliCredentials(asStore)&&await saveJsonFile(authPath,asStore),asStore;if(agentDir){let mainStore=coerceAuthStore(await loadJsonFile(resolveAuthStorePath()));if(mainStore&&Object.keys(mainStore.profiles).length>0)return await saveJsonFile(authPath,mainStore),log$1.info(`inherited auth-profiles from main agent`,{agentDir}),mainStore}let legacy=coerceLegacyStore(await loadJsonFile(resolveLegacyAuthStorePath(agentDir))),store={version:1,profiles:{}};legacy&&applyLegacyStore(store,legacy);let mergedOAuth=await mergeOAuthFileIntoStore(store),syncedCli=await syncExternalCliCredentials(store),shouldWrite=legacy!==null||mergedOAuth||syncedCli;if(shouldWrite&&await saveJsonFile(authPath,store),shouldWrite&&legacy!==null){let legacyPath=resolveLegacyAuthStorePath(agentDir);try{fs.unlinkSync(legacyPath)}catch(err){err?.code!==`ENOENT`&&log$1.warn(`failed to delete legacy auth.json after migration`,{err,legacyPath})}}return store}async function ensureAuthProfileStore(agentDir,options){let store=await loadAuthProfileStoreForAgent(agentDir,options),authPath=resolveAuthStorePath(agentDir),mainAuthPath=resolveAuthStorePath();return!agentDir||authPath===mainAuthPath?store:mergeAuthProfileStores(await loadAuthProfileStoreForAgent(void 0,options),store)}async function saveAuthProfileStore(store,agentDir){await saveJsonFile(resolveAuthStorePath(agentDir),{version:1,profiles:store.profiles,order:store.order??void 0,lastGood:store.lastGood??void 0,usageStats:store.usageStats??void 0})}function dedupeProfileIds(profileIds){return[...new Set(profileIds)]}function listProfilesForProvider(store,provider){let providerKey=normalizeProviderId(provider);return Object.entries(store.profiles).filter(([,cred])=>normalizeProviderId(cred.provider)===providerKey).map(([id])=>id)}async function markAuthProfileGood(params){let{store,provider,profileId,agentDir}=params,updated=await updateAuthProfileStoreWithLock({agentDir,updater:freshStore=>{let profile=freshStore.profiles[profileId];return!profile||profile.provider!==provider?!1:(freshStore.lastGood={...freshStore.lastGood,[provider]:profileId},!0)}});if(updated){store.lastGood=updated.lastGood;return}let profile=store.profiles[profileId];!profile||profile.provider!==provider||(store.lastGood={...store.lastGood,[provider]:profileId},await saveAuthProfileStore(store,agentDir))}function getProfileSuffix(profileId){let idx=profileId.indexOf(`:`);return idx<0?``:profileId.slice(idx+1)}function isEmailLike(value){let trimmed=value.trim();return trimmed?trimmed.includes(`@`)&&trimmed.includes(`.`):!1}function suggestOAuthProfileIdForLegacyDefault(params){let providerKey=normalizeProviderId(params.provider);if(getProfileSuffix(params.legacyProfileId)!==`default`)return null;let legacyCfg=params.cfg?.auth?.profiles?.[params.legacyProfileId];if(legacyCfg&&normalizeProviderId(legacyCfg.provider)===providerKey&&legacyCfg.mode!==`oauth`)return null;let oauthProfiles=listProfilesForProvider(params.store,providerKey).filter(id=>params.store.profiles[id]?.type===`oauth`);if(oauthProfiles.length===0)return null;let configuredEmail=legacyCfg?.email?.trim();if(configuredEmail){let byEmail=oauthProfiles.find(id=>{let cred=params.store.profiles[id];return!cred||cred.type!==`oauth`?!1:cred.email?.trim()===configuredEmail||id===`${providerKey}:${configuredEmail}`});if(byEmail)return byEmail}let lastGood=params.store.lastGood?.[providerKey]??params.store.lastGood?.[params.provider];if(lastGood&&oauthProfiles.includes(lastGood))return lastGood;let nonLegacy=oauthProfiles.filter(id=>id!==params.legacyProfileId);if(nonLegacy.length===1)return nonLegacy[0]??null;let emailLike=nonLegacy.filter(id=>isEmailLike(getProfileSuffix(id)));return emailLike.length===1?emailLike[0]??null:null}function formatAuthDoctorHint(params){let providerKey=normalizeProviderId(params.provider);if(providerKey!==`anthropic`)return``;let legacyProfileId=params.profileId??`anthropic:default`,suggested=suggestOAuthProfileIdForLegacyDefault({cfg:params.cfg,store:params.store,provider:providerKey,legacyProfileId});if(!suggested||suggested===legacyProfileId)return``;let storeOauthProfiles=listProfilesForProvider(params.store,providerKey).filter(id=>params.store.profiles[id]?.type===`oauth`).join(`, `),cfgMode=params.cfg?.auth?.profiles?.[legacyProfileId]?.mode,cfgProvider=params.cfg?.auth?.profiles?.[legacyProfileId]?.provider;return[`Doctor hint (for GitHub issue):`,`- provider: ${providerKey}`,`- config: ${legacyProfileId}${cfgProvider||cfgMode?` (provider=${cfgProvider??`?`}, mode=${cfgMode??`?`})`:``}`,`- auth store oauth profiles: ${storeOauthProfiles||`(none)`}`,`- suggested profile: ${suggested}`,`Fix: run "${formatCliCommand(`builderforce doctor --yes`)}"`].join(`
1
+ import{n as DEFAULT_AGENT_ID}from"./session-key-5J69DULS.js";import{j as resolveUserPath,k as resolveConfigDir,x as escapeRegExp}from"./registry-CZHRcH-q.js";import{o as resolveOAuthPath,s as resolveStateDir}from"./paths-Cb8zTlyG.js";import{t as createSubsystemLogger}from"./subsystem-D0Ril4rt.js";import{A as logDebug,a as resolveAgentModelPrimary,n as resolveAgentConfig}from"./agent-scope-DgKN27hJ.js";import{r as isTruthyEnvValue,t as formatCliCommand}from"./command-format-B3XMq_73.js";import{n as saveJsonFile,t as loadJsonFile}from"./json-file-DUi7S24G.js";import{E as isModelRole,g as evaluatePolicyGate,v as toolCallPaths}from"./src-5XE2oMwl.js";import path,{join,resolve}from"node:path";import fs,{appendFileSync,existsSync,mkdirSync,readFileSync,writeFileSync}from"node:fs";import{randomUUID}from"node:crypto";import fs$1 from"node:fs/promises";import{execFileSync}from"node:child_process";import{BedrockClient,ListFoundationModelsCommand}from"@aws-sdk/client-bedrock";function isPidAlive(pid){if(!Number.isFinite(pid)||pid<=0)return!1;try{return process.kill(pid,0),!0}catch{return!1}}function resolveProcessScopedMap(key){let proc=process,existing=proc[key];if(existing)return existing;let created=new Map;return proc[key]=created,created}const HELD_LOCKS=resolveProcessScopedMap(Symbol.for(`builderforce.fileLockHeldLocks`));function computeDelayMs(retries,attempt){let base=Math.min(retries.maxTimeout,Math.max(retries.minTimeout,retries.minTimeout*retries.factor**attempt)),jitter=retries.randomize?1+Math.random():1;return Math.min(retries.maxTimeout,Math.round(base*jitter))}async function readLockPayload(lockPath){try{let raw=await fs$1.readFile(lockPath,`utf8`),parsed=JSON.parse(raw);return typeof parsed.pid!=`number`||typeof parsed.createdAt!=`string`?null:{pid:parsed.pid,createdAt:parsed.createdAt}}catch{return null}}async function resolveNormalizedFilePath(filePath){let resolved=path.resolve(filePath),dir=path.dirname(resolved);await fs$1.mkdir(dir,{recursive:!0});try{let realDir=await fs$1.realpath(dir);return path.join(realDir,path.basename(resolved))}catch{return resolved}}async function isStaleLock(lockPath,staleMs){let payload=await readLockPayload(lockPath);if(payload?.pid&&!isPidAlive(payload.pid))return!0;if(payload?.createdAt){let createdAt=Date.parse(payload.createdAt);if(!Number.isFinite(createdAt)||Date.now()-createdAt>staleMs)return!0}try{let stat=await fs$1.stat(lockPath);return Date.now()-stat.mtimeMs>staleMs}catch{return!0}}async function releaseHeldLock(normalizedFile){let current=HELD_LOCKS.get(normalizedFile);current&&(--current.count,!(current.count>0)&&(HELD_LOCKS.delete(normalizedFile),await current.handle.close().catch(()=>void 0),await fs$1.rm(current.lockPath,{force:!0}).catch(()=>void 0)))}async function acquireFileLock(filePath,options){let normalizedFile=await resolveNormalizedFilePath(filePath),lockPath=`${normalizedFile}.lock`,held=HELD_LOCKS.get(normalizedFile);if(held)return held.count+=1,{lockPath,release:()=>releaseHeldLock(normalizedFile)};let attempts=Math.max(1,options.retries.retries+1);for(let attempt=0;attempt<attempts;attempt+=1)try{let handle=await fs$1.open(lockPath,`wx`);return await handle.writeFile(JSON.stringify({pid:process.pid,createdAt:new Date().toISOString()},null,2),`utf8`),HELD_LOCKS.set(normalizedFile,{count:1,handle,lockPath}),{lockPath,release:()=>releaseHeldLock(normalizedFile)}}catch(err){if(err.code!==`EEXIST`)throw err;if(await isStaleLock(lockPath,options.stale)){await fs$1.rm(lockPath,{force:!0}).catch(()=>void 0);continue}if(attempt>=attempts-1)break;await new Promise(resolve=>setTimeout(resolve,computeDelayMs(options.retries,attempt)))}throw Error(`file lock timeout for ${normalizedFile}`)}async function withFileLock(filePath,options,fn){let lock=await acquireFileLock(filePath,options);try{return await fn()}finally{await lock.release()}}const DEFAULT_TIMEOUT_MS=15e3;let lastAppliedKeys=[],cachedShellPath;function resolveTimeoutMs(timeoutMs){return typeof timeoutMs!=`number`||!Number.isFinite(timeoutMs)?DEFAULT_TIMEOUT_MS:Math.max(0,timeoutMs)}function resolveShell(env){let shell=env.SHELL?.trim();return shell&&shell.length>0?shell:`/bin/sh`}function execLoginShellEnvZero(params){return params.exec(params.shell,[`-l`,`-c`,`env -0`],{encoding:`buffer`,timeout:params.timeoutMs,maxBuffer:2097152,env:params.env,stdio:[`ignore`,`pipe`,`pipe`]})}function parseShellEnv(stdout){let shellEnv=new Map,parts=stdout.toString(`utf8`).split(`\0`);for(let part of parts){if(!part)continue;let eq=part.indexOf(`=`);if(eq<=0)continue;let key=part.slice(0,eq),value=part.slice(eq+1);key&&shellEnv.set(key,value)}return shellEnv}function loadShellEnvFallback(opts){let logger=opts.logger??console,exec=opts.exec??execFileSync;if(!opts.enabled)return lastAppliedKeys=[],{ok:!0,applied:[],skippedReason:`disabled`};if(opts.expectedKeys.some(key=>!!opts.env[key]?.trim()))return lastAppliedKeys=[],{ok:!0,applied:[],skippedReason:`already-has-keys`};let timeoutMs=resolveTimeoutMs(opts.timeoutMs),shell=resolveShell(opts.env),stdout;try{stdout=execLoginShellEnvZero({shell,env:opts.env,exec,timeoutMs})}catch(err){let msg=err instanceof Error?err.message:String(err);return logger.warn(`[builderforce] shell env fallback failed: ${msg}`),lastAppliedKeys=[],{ok:!1,error:msg,applied:[]}}let shellEnv=parseShellEnv(stdout),applied=[];for(let key of opts.expectedKeys){if(opts.env[key]?.trim())continue;let value=shellEnv.get(key);value?.trim()&&(opts.env[key]=value,applied.push(key))}return lastAppliedKeys=applied,{ok:!0,applied}}function shouldEnableShellEnvFallback(env){return isTruthyEnvValue(env.BUILDERFORCE_AGENTS_LOAD_SHELL_ENV)}function shouldDeferShellEnvFallback(env){return isTruthyEnvValue(env.BUILDERFORCE_AGENTS_DEFER_SHELL_ENV_FALLBACK)}function resolveShellEnvFallbackTimeoutMs(env){let raw=env.BUILDERFORCE_AGENTS_SHELL_ENV_TIMEOUT_MS?.trim();if(!raw)return DEFAULT_TIMEOUT_MS;let parsed=Number.parseInt(raw,10);return Number.isFinite(parsed)?Math.max(0,parsed):DEFAULT_TIMEOUT_MS}function getShellPathFromLoginShell(opts){if(cachedShellPath!==void 0)return cachedShellPath;if(process.platform===`win32`)return cachedShellPath=null,cachedShellPath;let exec=opts.exec??execFileSync,timeoutMs=resolveTimeoutMs(opts.timeoutMs),shell=resolveShell(opts.env),stdout;try{stdout=execLoginShellEnvZero({shell,env:opts.env,exec,timeoutMs})}catch{return cachedShellPath=null,cachedShellPath}let shellPath=parseShellEnv(stdout).get(`PATH`)?.trim();return cachedShellPath=shellPath&&shellPath.length>0?shellPath:null,cachedShellPath}function getShellEnvAppliedKeys(){return[...lastAppliedKeys]}const TOKENS_PER_MILLION=1e6;function perMillionToPerToken(usdPerMillion){return usdPerMillion/TOKENS_PER_MILLION}function perTokenToPerMillion(usdPerToken){return usdPerToken*TOKENS_PER_MILLION}Object.freeze({input:0,output:0});const UNKNOWN_TIER_RANK=4,STRONGEST_FIRST={ULTRA:0,PREMIUM:1,STANDARD:2,FREE:3};function tierRank(tier){return tier&&tier in STRONGEST_FIRST?STRONGEST_FIRST[tier]:4}function tierForPrice(price){if(price.input===0&&price.output===0)return`FREE`;let outputPerMillion=perTokenToPerMillion(price.output);return outputPerMillion<8?`STANDARD`:outputPerMillion<20?`PREMIUM`:`ULTRA`}function resolveModelTier(known){return known.catalogTier?known.catalogTier:known.price?tierForPrice(known.price):void 0}const LLM_PROVIDER_INFO=[{id:`anthropic`,label:`Anthropic (Claude)`,credential:`api_key`,keyPlaceholder:`sk-ant-…`,subscription:`paste`},{id:`openai`,label:`OpenAI`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:`paste`},{id:`google`,label:`Google (Gemini)`,credential:`api_key`,keyPlaceholder:`AIza…`,subscription:null},{id:`meta`,label:`Meta AI (MUSE)`,credential:`api_key`,keyPlaceholder:`meta-…`,subscription:null},{id:`kimi`,label:`Kimi`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:`device`},{id:`moonshot`,label:`Moonshot AI`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:null},{id:`qwen`,label:`Qwen`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:null},{id:`minimax`,label:`MiniMax`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:null},{id:`xai`,label:`xAI (Grok)`,credential:`api_key`,keyPlaceholder:`xai-…`,subscription:`paste`},{id:`ollama`,label:`Ollama Cloud`,credential:`api_key`,keyPlaceholder:`sk-…`,subscription:null},{id:`ollama-local`,label:`Ollama`,credential:`local_runtime`,keyPlaceholder:``,subscription:null,localRuntime:{defaultBaseUrl:`http://127.0.0.1:11434`,exampleModel:`llama3.1:8b`}},{id:`freetoken`,label:`FreeToken`,credential:`local_runtime`,keyPlaceholder:``,subscription:null,localRuntime:{defaultBaseUrl:`http://127.0.0.1:1919`}}];LLM_PROVIDER_INFO.map(p=>p.id),new Map(LLM_PROVIDER_INFO.map(p=>[p.id,p]));const ANTHROPIC_FAMILIES=[`opus`,`sonnet`,`haiku`,`fable`],ANTHROPIC_RELEASES={opus:[`5.5`,`5`,`4.8`,`4.7`,`4.6`,`4.5`,`4.1`,`4.0`],sonnet:[`5.5`,`5`,`4.6`,`4.5`,`4.0`],haiku:[`5.5`,`4.5`],fable:[`5.1`,`5`]};function parseVersion(version){let[major,minor]=version.split(`.`);return[Number(major),Number(minor??0)]}function compareVersions(a,b){return a[0]-b[0]||a[1]-b[1]}function anthropicModelId(family,version){return`claude-${family}-${version.replace(`.`,`-`)}`}function currentAnthropicModelId(family){return anthropicModelId(family,ANTHROPIC_RELEASES[family][0])}function resolveAnthropicShortAlias(raw){let match=/^(opus|sonnet|haiku|fable)-(\d+)\.(\d+)$/.exec(raw.trim().toLowerCase());return match?`claude-${match[1]}-${match[2]}-${match[3]}`:void 0}const CLAUDE_ID=/^claude-(opus|sonnet|haiku|fable)-(\d+)(?:([-.])(\d{1,2})(?=-|$))?(-.*)?$/;function parseAnthropicModelId(id){let match=CLAUDE_ID.exec(id.trim().toLowerCase());if(match)return{family:match[1],version:[Number(match[2]),Number(match[4]??0)],separator:match[3]===`.`?`.`:`-`,suffix:match[5]??``}}function olderAnthropicTemplateIds(id){let parsed=parseAnthropicModelId(id);if(!parsed)return[];let older=ANTHROPIC_RELEASES[parsed.family].filter(v=>compareVersions(parseVersion(v),parsed.version)<0),spell=v=>`claude-${parsed.family}-${v.replace(`.`,parsed.separator)}`,withSuffix=parsed.suffix?older.map(v=>`${spell(v)}${parsed.suffix}`):[];return[...new Set([...withSuffix,...older.map(spell)])]}const LEGACY_FAMILY_ALIASES={"haiku-3.5":`haiku`,"claude-3-5-haiku":`haiku`};function anthropicFamilyAliases(){let out={...LEGACY_FAMILY_ALIASES};for(let family of ANTHROPIC_FAMILIES){out[family]=family;for(let version of ANTHROPIC_RELEASES[family])out[`${family}-${version}`]=family,out[anthropicModelId(family,version)]=family}return out}const DEFAULT_PROVIDER=`builderforcellm`,DEFAULT_MODEL=`auto`,DEFAULT_CONTEXT_TOKENS=2e5;function normalizeBaseUrl(url){return url.replace(/\/+$/,``)}const QWEN_CLI_PROFILE_ID=`qwen-portal:qwen-cli`,AUTH_STORE_LOCK_OPTIONS={retries:{retries:10,factor:2,minTimeout:100,maxTimeout:1e4,randomize:!0},stale:3e4},EXTERNAL_CLI_SYNC_TTL_MS=900*1e3,log$1=createSubsystemLogger(`agents/auth-profiles`);function resolveAuthProfileDisplayLabel(params){let{cfg,store,profileId}=params,profile=store.profiles[profileId],email=cfg?.auth?.profiles?.[profileId]?.email?.trim()||(profile&&`email`in profile?profile.email?.trim():void 0);return email?`${profileId} (${email})`:profileId}function normalizeSecretInput(value){return typeof value==`string`?value.replace(/[\r\n\u2028\u2029]+/g,``).trim():``}function normalizeOptionalSecretInput(value){return normalizeSecretInput(value)||void 0}createSubsystemLogger(`agents/auth-profiles`);async function cachedByKey(store,cacheKey,ttlMs,loader){let now=Date.now();if(ttlMs>0&&store.current&&store.current.cacheKey===cacheKey&&now-store.current.readAt<ttlMs)return store.current.value;let value=await loader();return ttlMs>0&&(store.current={value,readAt:now,cacheKey}),value}const qwenCliCache={current:null},minimaxCliCache={current:null};function resolveQwenCliCredentialsPath(homeDir){let baseDir=homeDir??resolveUserPath(`~`);return path.join(baseDir,`.qwen/oauth_creds.json`)}function resolveMiniMaxCliCredentialsPath(homeDir){let baseDir=homeDir??resolveUserPath(`~`);return path.join(baseDir,`.minimax/oauth_creds.json`)}async function readQwenCliCredentials(options){return readPortalCliOauthCredentials(resolveQwenCliCredentialsPath(options?.homeDir),`qwen-portal`)}async function readPortalCliOauthCredentials(credPath,provider){let raw=await loadJsonFile(credPath);if(!raw||typeof raw!=`object`)return null;let data=raw,accessToken=data.access_token,refreshToken=data.refresh_token,expiresAt=data.expiry_date;return typeof accessToken!=`string`||!accessToken||typeof refreshToken!=`string`||!refreshToken||typeof expiresAt!=`number`||!Number.isFinite(expiresAt)?null:{type:`oauth`,provider,access:accessToken,refresh:refreshToken,expires:expiresAt}}async function readMiniMaxCliCredentials(options){return readPortalCliOauthCredentials(resolveMiniMaxCliCredentialsPath(options?.homeDir),`minimax-portal`)}async function readQwenCliCredentialsCached(options){return cachedByKey(qwenCliCache,resolveQwenCliCredentialsPath(options?.homeDir),options?.ttlMs??0,()=>readQwenCliCredentials({homeDir:options?.homeDir}))}async function readMiniMaxCliCredentialsCached(options){return cachedByKey(minimaxCliCache,resolveMiniMaxCliCredentialsPath(options?.homeDir),options?.ttlMs??0,()=>readMiniMaxCliCredentials({homeDir:options?.homeDir}))}function shallowEqualOAuthCredentials(a,b){return!a||a.type!==`oauth`?!1:a.provider===b.provider&&a.access===b.access&&a.refresh===b.refresh&&a.expires===b.expires&&a.email===b.email&&a.enterpriseUrl===b.enterpriseUrl&&a.projectId===b.projectId&&a.accountId===b.accountId}function isExternalProfileFresh(cred,now){return!cred||cred.type!==`oauth`&&cred.type!==`token`||cred.provider!==`qwen-portal`&&cred.provider!==`minimax-portal`?!1:typeof cred.expires==`number`?cred.expires>now+6e5:!0}async function syncExternalCliCredentialsForProvider(store,profileId,provider,readCredentials,now){let existing=store.profiles[profileId],creds=!existing||existing.provider!==provider||!isExternalProfileFresh(existing,now)?await readCredentials():null;if(!creds)return!1;let existingOAuth=existing?.type===`oauth`?existing:void 0;return(!existingOAuth||existingOAuth.provider!==provider||existingOAuth.expires<=now||creds.expires>existingOAuth.expires)&&!shallowEqualOAuthCredentials(existingOAuth,creds)?(store.profiles[profileId]=creds,log$1.info(`synced ${provider} credentials from external cli`,{profileId,expires:new Date(creds.expires).toISOString()}),!0):!1}async function syncExternalCliCredentials(store){let mutated=!1,now=Date.now(),existingQwen=store.profiles[QWEN_CLI_PROFILE_ID],qwenCreds=!existingQwen||existingQwen.provider!==`qwen-portal`||!isExternalProfileFresh(existingQwen,now)?await readQwenCliCredentialsCached({ttlMs:EXTERNAL_CLI_SYNC_TTL_MS}):null;if(qwenCreds){let existing=store.profiles[QWEN_CLI_PROFILE_ID],existingOAuth=existing?.type===`oauth`?existing:void 0;(!existingOAuth||existingOAuth.provider!==`qwen-portal`||existingOAuth.expires<=now||qwenCreds.expires>existingOAuth.expires)&&!shallowEqualOAuthCredentials(existingOAuth,qwenCreds)&&(store.profiles[QWEN_CLI_PROFILE_ID]=qwenCreds,mutated=!0,log$1.info(`synced qwen credentials from qwen cli`,{profileId:QWEN_CLI_PROFILE_ID,expires:new Date(qwenCreds.expires).toISOString()}))}return await syncExternalCliCredentialsForProvider(store,`minimax-portal:minimax-cli`,`minimax-portal`,()=>readMiniMaxCliCredentialsCached({ttlMs:EXTERNAL_CLI_SYNC_TTL_MS}),now)&&(mutated=!0),mutated}function resolveBuilderForceAgentsAgentDir(){return resolveUserPath(process.env.BUILDERFORCE_AGENTS_AGENT_DIR?.trim()||process.env.PI_CODING_AGENT_DIR?.trim()||path.join(resolveStateDir(),`agents`,DEFAULT_AGENT_ID,`agent`))}function resolveAuthStorePath(agentDir){let resolved=resolveUserPath(agentDir??resolveBuilderForceAgentsAgentDir());return path.join(resolved,`auth-profiles.json`)}function resolveLegacyAuthStorePath(agentDir){let resolved=resolveUserPath(agentDir??resolveBuilderForceAgentsAgentDir());return path.join(resolved,`auth.json`)}function resolveAuthStorePathForDisplay(agentDir){let pathname=resolveAuthStorePath(agentDir);return pathname.startsWith(`~`)?pathname:resolveUserPath(pathname)}async function ensureAuthStoreFile(pathname){fs.existsSync(pathname)||await saveJsonFile(pathname,{version:1,profiles:{}})}async function updateAuthProfileStoreWithLock(params){let authPath=resolveAuthStorePath(params.agentDir);await ensureAuthStoreFile(authPath);try{return await withFileLock(authPath,AUTH_STORE_LOCK_OPTIONS,async()=>{let store=await ensureAuthProfileStore(params.agentDir);return params.updater(store)&&await saveAuthProfileStore(store,params.agentDir),store})}catch{return null}}function coerceLegacyStore(raw){if(!raw||typeof raw!=`object`)return null;let record=raw;if(`profiles`in record)return null;let entries={};for(let[key,value]of Object.entries(record)){if(!value||typeof value!=`object`)continue;let typed=value;typed.type!==`api_key`&&typed.type!==`oauth`&&typed.type!==`token`||(entries[key]={...typed,provider:String(typed.provider??key)})}return Object.keys(entries).length>0?entries:null}function coerceAuthStore(raw){if(!raw||typeof raw!=`object`)return null;let record=raw;if(!record.profiles||typeof record.profiles!=`object`)return null;let profiles=record.profiles,normalized={};for(let[key,value]of Object.entries(profiles)){if(!value||typeof value!=`object`)continue;let typed=value;typed.type!==`api_key`&&typed.type!==`oauth`&&typed.type!==`token`||typed.provider&&(normalized[key]=typed)}let order=record.order&&typeof record.order==`object`?Object.entries(record.order).reduce((acc,[provider,value])=>{if(!Array.isArray(value))return acc;let list=value.map(entry=>typeof entry==`string`?entry.trim():``).filter(Boolean);return list.length===0||(acc[provider]=list),acc},{}):void 0;return{version:Number(record.version??1),profiles:normalized,order,lastGood:record.lastGood&&typeof record.lastGood==`object`?record.lastGood:void 0,usageStats:record.usageStats&&typeof record.usageStats==`object`?record.usageStats:void 0}}function mergeRecord(base,override){if(!(!base&&!override))return base?override?{...base,...override}:{...base}:{...override}}function mergeAuthProfileStores(base,override){return Object.keys(override.profiles).length===0&&!override.order&&!override.lastGood&&!override.usageStats?base:{version:Math.max(base.version,override.version??base.version),profiles:{...base.profiles,...override.profiles},order:mergeRecord(base.order,override.order),lastGood:mergeRecord(base.lastGood,override.lastGood),usageStats:mergeRecord(base.usageStats,override.usageStats)}}async function mergeOAuthFileIntoStore(store){let oauthRaw=await loadJsonFile(resolveOAuthPath());if(!oauthRaw||typeof oauthRaw!=`object`)return!1;let oauthEntries=oauthRaw,mutated=!1;for(let[provider,creds]of Object.entries(oauthEntries)){if(!creds||typeof creds!=`object`)continue;let profileId=`${provider}:default`;store.profiles[profileId]||(store.profiles[profileId]={type:`oauth`,provider,...creds},mutated=!0)}return mutated}function applyLegacyStore(store,legacy){for(let[provider,cred]of Object.entries(legacy)){let profileId=`${provider}:default`;if(cred.type===`api_key`){store.profiles[profileId]={type:`api_key`,provider:String(cred.provider??provider),key:cred.key,...cred.email?{email:cred.email}:{}};continue}if(cred.type===`token`){store.profiles[profileId]={type:`token`,provider:String(cred.provider??provider),token:cred.token,...typeof cred.expires==`number`?{expires:cred.expires}:{},...cred.email?{email:cred.email}:{}};continue}store.profiles[profileId]={type:`oauth`,provider:String(cred.provider??provider),access:cred.access,refresh:cred.refresh,expires:cred.expires,...cred.enterpriseUrl?{enterpriseUrl:cred.enterpriseUrl}:{},...cred.projectId?{projectId:cred.projectId}:{},...cred.accountId?{accountId:cred.accountId}:{},...cred.email?{email:cred.email}:{}}}}async function loadAuthProfileStoreForAgent(agentDir,_options){let authPath=resolveAuthStorePath(agentDir),asStore=coerceAuthStore(await loadJsonFile(authPath));if(asStore)return await syncExternalCliCredentials(asStore)&&await saveJsonFile(authPath,asStore),asStore;if(agentDir){let mainStore=coerceAuthStore(await loadJsonFile(resolveAuthStorePath()));if(mainStore&&Object.keys(mainStore.profiles).length>0)return await saveJsonFile(authPath,mainStore),log$1.info(`inherited auth-profiles from main agent`,{agentDir}),mainStore}let legacy=coerceLegacyStore(await loadJsonFile(resolveLegacyAuthStorePath(agentDir))),store={version:1,profiles:{}};legacy&&applyLegacyStore(store,legacy);let mergedOAuth=await mergeOAuthFileIntoStore(store),syncedCli=await syncExternalCliCredentials(store),shouldWrite=legacy!==null||mergedOAuth||syncedCli;if(shouldWrite&&await saveJsonFile(authPath,store),shouldWrite&&legacy!==null){let legacyPath=resolveLegacyAuthStorePath(agentDir);try{fs.unlinkSync(legacyPath)}catch(err){err?.code!==`ENOENT`&&log$1.warn(`failed to delete legacy auth.json after migration`,{err,legacyPath})}}return store}async function ensureAuthProfileStore(agentDir,options){let store=await loadAuthProfileStoreForAgent(agentDir,options),authPath=resolveAuthStorePath(agentDir),mainAuthPath=resolveAuthStorePath();return!agentDir||authPath===mainAuthPath?store:mergeAuthProfileStores(await loadAuthProfileStoreForAgent(void 0,options),store)}async function saveAuthProfileStore(store,agentDir){await saveJsonFile(resolveAuthStorePath(agentDir),{version:1,profiles:store.profiles,order:store.order??void 0,lastGood:store.lastGood??void 0,usageStats:store.usageStats??void 0})}function dedupeProfileIds(profileIds){return[...new Set(profileIds)]}function listProfilesForProvider(store,provider){let providerKey=normalizeProviderId(provider);return Object.entries(store.profiles).filter(([,cred])=>normalizeProviderId(cred.provider)===providerKey).map(([id])=>id)}async function markAuthProfileGood(params){let{store,provider,profileId,agentDir}=params,updated=await updateAuthProfileStoreWithLock({agentDir,updater:freshStore=>{let profile=freshStore.profiles[profileId];return!profile||profile.provider!==provider?!1:(freshStore.lastGood={...freshStore.lastGood,[provider]:profileId},!0)}});if(updated){store.lastGood=updated.lastGood;return}let profile=store.profiles[profileId];!profile||profile.provider!==provider||(store.lastGood={...store.lastGood,[provider]:profileId},await saveAuthProfileStore(store,agentDir))}function getProfileSuffix(profileId){let idx=profileId.indexOf(`:`);return idx<0?``:profileId.slice(idx+1)}function isEmailLike(value){let trimmed=value.trim();return trimmed?trimmed.includes(`@`)&&trimmed.includes(`.`):!1}function suggestOAuthProfileIdForLegacyDefault(params){let providerKey=normalizeProviderId(params.provider);if(getProfileSuffix(params.legacyProfileId)!==`default`)return null;let legacyCfg=params.cfg?.auth?.profiles?.[params.legacyProfileId];if(legacyCfg&&normalizeProviderId(legacyCfg.provider)===providerKey&&legacyCfg.mode!==`oauth`)return null;let oauthProfiles=listProfilesForProvider(params.store,providerKey).filter(id=>params.store.profiles[id]?.type===`oauth`);if(oauthProfiles.length===0)return null;let configuredEmail=legacyCfg?.email?.trim();if(configuredEmail){let byEmail=oauthProfiles.find(id=>{let cred=params.store.profiles[id];return!cred||cred.type!==`oauth`?!1:cred.email?.trim()===configuredEmail||id===`${providerKey}:${configuredEmail}`});if(byEmail)return byEmail}let lastGood=params.store.lastGood?.[providerKey]??params.store.lastGood?.[params.provider];if(lastGood&&oauthProfiles.includes(lastGood))return lastGood;let nonLegacy=oauthProfiles.filter(id=>id!==params.legacyProfileId);if(nonLegacy.length===1)return nonLegacy[0]??null;let emailLike=nonLegacy.filter(id=>isEmailLike(getProfileSuffix(id)));return emailLike.length===1?emailLike[0]??null:null}function formatAuthDoctorHint(params){let providerKey=normalizeProviderId(params.provider);if(providerKey!==`anthropic`)return``;let legacyProfileId=params.profileId??`anthropic:default`,suggested=suggestOAuthProfileIdForLegacyDefault({cfg:params.cfg,store:params.store,provider:providerKey,legacyProfileId});if(!suggested||suggested===legacyProfileId)return``;let storeOauthProfiles=listProfilesForProvider(params.store,providerKey).filter(id=>params.store.profiles[id]?.type===`oauth`).join(`, `),cfgMode=params.cfg?.auth?.profiles?.[legacyProfileId]?.mode,cfgProvider=params.cfg?.auth?.profiles?.[legacyProfileId]?.provider;return[`Doctor hint (for GitHub issue):`,`- provider: ${providerKey}`,`- config: ${legacyProfileId}${cfgProvider||cfgMode?` (provider=${cfgProvider??`?`}, mode=${cfgMode??`?`})`:``}`,`- auth store oauth profiles: ${storeOauthProfiles||`(none)`}`,`- suggested profile: ${suggested}`,`Fix: run "${formatCliCommand(`builderforce doctor --yes`)}"`].join(`
2
2
  `)}typeof process<`u`&&(process.versions?.node||process.versions?.bun)&&(import(`node:crypto`).then(m=>{m.randomBytes}),import(`node:http`).then(m=>{}));function decodeJwt(token){try{let parts=token.split(`.`);return parts.length===3?JSON.parse(atob(parts[1]??``)):null}catch{return null}}async function refreshAccessToken(refreshToken){try{let response=await fetch(`https://auth.openai.com/oauth/token`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({grant_type:`refresh_token`,refresh_token:refreshToken,client_id:`app_EMoamEEZ73f0CkXaXp7hrann`})});if(!response.ok)return{type:`failed`};let json=await response.json();return!json.access_token||!json.refresh_token||typeof json.expires_in!=`number`?{type:`failed`}:{type:`success`,access:json.access_token,refresh:json.refresh_token,expires:Date.now()+json.expires_in*1e3}}catch{return{type:`failed`}}}function getAccountId(accessToken){let accountId=decodeJwt(accessToken)?.[`https://api.openai.com/auth`]?.chatgpt_account_id;return typeof accountId==`string`&&accountId.length>0?accountId:null}async function refreshOpenAICodexToken(refreshToken){let result=await refreshAccessToken(refreshToken);if(result.type!==`success`)throw Error(`Failed to refresh OpenAI Codex token`);let accountId=getAccountId(result.access);if(!accountId)throw Error(`Failed to extract accountId from token`);return{access:result.access,refresh:result.refresh,expires:result.expires,accountId}}const decode=s=>atob(s),ANTHROPIC_CLIENT_ID=decode(`OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl`);async function refreshAnthropicToken(refreshToken){let response=await fetch(`https://console.anthropic.com/v1/oauth/token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({grant_type:`refresh_token`,client_id:ANTHROPIC_CLIENT_ID,refresh_token:refreshToken})});if(!response.ok)throw Error(`Anthropic token refresh failed: ${await response.text()}`);let data=await response.json();return{refresh:data.refresh_token,access:data.access_token,expires:Date.now()+data.expires_in*1e3-300*1e3}}const COPILOT_HEADERS={"User-Agent":`GitHubCopilotChat/0.35.0`,"Editor-Version":`vscode/1.107.0`,"Editor-Plugin-Version":`copilot-chat/0.35.0`,"Copilot-Integration-Id":`vscode-chat`};async function refreshGitHubCopilotToken(refreshToken,enterpriseDomain){let copilotTokenUrl=`https://api.${enterpriseDomain||`github.com`}/copilot_internal/v2/token`,response=await fetch(copilotTokenUrl,{headers:{Accept:`application/json`,Authorization:`Bearer ${refreshToken}`,...COPILOT_HEADERS}});if(!response.ok)throw Error(`Copilot token refresh failed: ${await response.text()}`);let raw=await response.json();if(typeof raw.token!=`string`||typeof raw.expires_at!=`number`)throw Error(`Invalid Copilot token response fields`);return{refresh:refreshToken,access:raw.token,expires:raw.expires_at*1e3-300*1e3,enterpriseUrl:enterpriseDomain}}async function refreshGoogleToken(refreshToken,projectId,clientId,clientSecret){let response=await fetch(`https://oauth2.googleapis.com/token`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({client_id:clientId,client_secret:clientSecret,refresh_token:refreshToken,grant_type:`refresh_token`})});if(!response.ok)throw Error(`Google token refresh failed: ${await response.text()}`);let data=await response.json();return{refresh:data.refresh_token||refreshToken,access:data.access_token,expires:Date.now()+data.expires_in*1e3-300*1e3,projectId}}const ANTIGRAVITY_CLIENT_ID=decode(`MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ==`),ANTIGRAVITY_CLIENT_SECRET=decode(`R09DU1BYLUs1OEZXUjQ4NkxkTEoxbUxCOHNYQzR6NnFEQWY=`),GEMINI_CLIENT_ID=decode(`NjgxMjU1ODA5Mzk1LW9vOGZ0Mm9wcmRybnA5ZTNhcWY2YXYzaG1kaWIxMzVqLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29t`),GEMINI_CLIENT_SECRET=decode(`R09DU1BYLTR1SGdNUG0tMW83U2stZ2VWNkN1NWNsWEZzeGw=`),refreshAntigravityToken=(refreshToken,projectId)=>refreshGoogleToken(refreshToken,projectId,ANTIGRAVITY_CLIENT_ID,ANTIGRAVITY_CLIENT_SECRET),refreshGoogleCloudToken=(refreshToken,projectId)=>refreshGoogleToken(refreshToken,projectId,GEMINI_CLIENT_ID,GEMINI_CLIENT_SECRET),googleGetApiKey=c=>JSON.stringify({token:c.access,projectId:c.projectId}),providers=[{id:`anthropic`,name:`Anthropic (Claude Pro/Max)`,refreshToken:c=>refreshAnthropicToken(c.refresh),getApiKey:c=>c.access},{id:`github-copilot`,name:`GitHub Copilot`,refreshToken:c=>refreshGitHubCopilotToken(c.refresh,c.enterpriseUrl),getApiKey:c=>c.access},{id:`google-gemini-cli`,name:`Google Cloud Code Assist (Gemini CLI)`,refreshToken:c=>{let projectId=c.projectId;if(!projectId)throw Error(`Google Cloud credentials missing projectId`);return refreshGoogleCloudToken(c.refresh,projectId)},getApiKey:googleGetApiKey},{id:`google-antigravity`,name:`Antigravity (Gemini 3, Claude, GPT-OSS)`,refreshToken:c=>{let projectId=c.projectId;if(!projectId)throw Error(`Antigravity credentials missing projectId`);return refreshAntigravityToken(c.refresh,projectId)},getApiKey:googleGetApiKey},{id:`openai-codex`,name:`ChatGPT Plus/Pro (Codex Subscription)`,refreshToken:c=>refreshOpenAICodexToken(c.refresh),getApiKey:c=>c.access}],registry=new Map(providers.map(p=>[p.id,p]));function getOAuthProvider(id){return registry.get(id)}function getOAuthProviders(){return Array.from(registry.values())}async function getOAuthApiKey(providerId,credentials){let provider=getOAuthProvider(providerId);if(!provider)throw Error(`Unknown OAuth provider: ${providerId}`);let creds=credentials[providerId];if(!creds)return null;if(Date.now()>=creds.expires)try{creds=await provider.refreshToken(creds)}catch{throw Error(`Failed to refresh OAuth token for ${providerId}`)}return{newCredentials:creds,apiKey:provider.getApiKey(creds)}}async function refreshQwenPortalCredentials(credentials){if(!credentials.refresh?.trim())throw Error(`Qwen OAuth refresh token missing; re-authenticate.`);let response=await fetch(`https://chat.qwen.ai/api/v1/oauth2/token`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`,Accept:`application/json`},body:new URLSearchParams({grant_type:`refresh_token`,refresh_token:credentials.refresh,client_id:`f0304373b74a44d2b584a3fb70ca9e56`})});if(!response.ok){let text=await response.text();throw response.status===400?Error(`Qwen OAuth refresh token expired or invalid. Re-authenticate with \`${formatCliCommand(`builderforce models auth login --provider qwen-portal`)}\`.`):Error(`Qwen OAuth refresh failed: ${text||response.statusText}`)}let payload=await response.json();if(!payload.access_token||!payload.expires_in)throw Error(`Qwen OAuth refresh response missing access token.`);return{...credentials,access:payload.access_token,refresh:payload.refresh_token||credentials.refresh,expires:Date.now()+payload.expires_in*1e3}}const CHUTES_OAUTH_ISSUER=`https://api.chutes.ai`;`${CHUTES_OAUTH_ISSUER}`;const CHUTES_TOKEN_ENDPOINT=`${CHUTES_OAUTH_ISSUER}/idp/token`;`${CHUTES_OAUTH_ISSUER}`;function coerceExpiresAt(expiresInSeconds,now){let value=now+Math.max(0,Math.floor(expiresInSeconds))*1e3-3e5;return Math.max(value,now+3e4)}async function refreshChutesTokens(params){let fetchFn=params.fetchFn??fetch,now=params.now??Date.now(),refreshToken=params.credential.refresh?.trim();if(!refreshToken)throw Error(`Chutes OAuth credential is missing refresh token`);let clientId=params.credential.clientId?.trim()??process.env.CHUTES_CLIENT_ID?.trim();if(!clientId)throw Error(`Missing CHUTES_CLIENT_ID for Chutes OAuth refresh (set env var or re-auth).`);let clientSecret=process.env.CHUTES_CLIENT_SECRET?.trim()||void 0,body=new URLSearchParams({grant_type:`refresh_token`,client_id:clientId,refresh_token:refreshToken});clientSecret&&body.set(`client_secret`,clientSecret);let response=await fetchFn(CHUTES_TOKEN_ENDPOINT,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body});if(!response.ok){let text=await response.text();throw Error(`Chutes token refresh failed: ${text}`)}let data=await response.json(),access=data.access_token?.trim(),newRefresh=data.refresh_token?.trim(),expiresIn=data.expires_in??0;if(!access)throw Error(`Chutes token refresh returned no access_token`);return{...params.credential,access,refresh:newRefresh||refreshToken,expires:coerceExpiresAt(expiresIn,now),clientId}}const OAUTH_PROVIDER_IDS=new Set(getOAuthProviders().map(provider=>provider.id)),isOAuthProvider=provider=>OAUTH_PROVIDER_IDS.has(provider),resolveOAuthProvider=provider=>isOAuthProvider(provider)?provider:null;function isProfileConfigCompatible(params){let profileConfig=params.cfg?.auth?.profiles?.[params.profileId];return!(profileConfig&&profileConfig.provider!==params.provider||profileConfig&&profileConfig.mode!==params.mode&&!(params.allowOAuthTokenCompatibility&&profileConfig.mode===`oauth`&&params.mode===`token`))}function buildOAuthApiKey(provider,credentials){return provider===`google-gemini-cli`||provider===`google-antigravity`?JSON.stringify({token:credentials.access,projectId:credentials.projectId}):credentials.access}function buildApiKeyProfileResult(params){return{apiKey:params.apiKey,provider:params.provider,email:params.email}}function buildOAuthProfileResult(params){return buildApiKeyProfileResult({apiKey:buildOAuthApiKey(params.provider,params.credentials),provider:params.provider,email:params.email})}function isExpiredCredential(expires){return typeof expires==`number`&&Number.isFinite(expires)&&expires>0&&Date.now()>=expires}async function refreshOAuthTokenWithLock(params){let authPath=resolveAuthStorePath(params.agentDir);return await ensureAuthStoreFile(authPath),await withFileLock(authPath,AUTH_STORE_LOCK_OPTIONS,async()=>{let store=await ensureAuthProfileStore(params.agentDir),cred=store.profiles[params.profileId];if(!cred||cred.type!==`oauth`)return null;if(Date.now()<cred.expires)return{apiKey:buildOAuthApiKey(cred.provider,cred),newCredentials:cred};let oauthCreds={[cred.provider]:cred},result=String(cred.provider)===`chutes`?await(async()=>{let newCredentials=await refreshChutesTokens({credential:cred});return{apiKey:newCredentials.access,newCredentials}})():String(cred.provider)===`qwen-portal`?await(async()=>{let newCredentials=await refreshQwenPortalCredentials(cred);return{apiKey:newCredentials.access,newCredentials}})():await(async()=>{let oauthProvider=resolveOAuthProvider(cred.provider);return oauthProvider?await getOAuthApiKey(oauthProvider,oauthCreds):null})();return result?(store.profiles[params.profileId]={...cred,...result.newCredentials,type:`oauth`},await saveAuthProfileStore(store,params.agentDir),result):null})}async function tryResolveOAuthProfile(params){let{cfg,store,profileId}=params,cred=store.profiles[profileId];if(!cred||cred.type!==`oauth`||!isProfileConfigCompatible({cfg,profileId,provider:cred.provider,mode:cred.type}))return null;if(Date.now()<cred.expires)return buildOAuthProfileResult({provider:cred.provider,credentials:cred,email:cred.email});let refreshed=await refreshOAuthTokenWithLock({profileId,agentDir:params.agentDir});return refreshed?buildApiKeyProfileResult({apiKey:refreshed.apiKey,provider:cred.provider,email:cred.email}):null}async function resolveApiKeyForProfile(params){let{cfg,store,profileId}=params,cred=store.profiles[profileId];if(!cred||!isProfileConfigCompatible({cfg,profileId,provider:cred.provider,mode:cred.type,allowOAuthTokenCompatibility:!0}))return null;if(cred.type===`api_key`){let key=cred.key?.trim();return key?buildApiKeyProfileResult({apiKey:key,provider:cred.provider,email:cred.email}):null}if(cred.type===`token`){let token=cred.token?.trim();return!token||isExpiredCredential(cred.expires)?null:buildApiKeyProfileResult({apiKey:token,provider:cred.provider,email:cred.email})}if(Date.now()<cred.expires)return buildOAuthProfileResult({provider:cred.provider,credentials:cred,email:cred.email});try{let result=await refreshOAuthTokenWithLock({profileId,agentDir:params.agentDir});return result?buildApiKeyProfileResult({apiKey:result.apiKey,provider:cred.provider,email:cred.email}):null}catch(error){let refreshedStore=await ensureAuthProfileStore(params.agentDir),refreshed=refreshedStore.profiles[profileId];if(refreshed?.type===`oauth`&&Date.now()<refreshed.expires)return buildOAuthProfileResult({provider:refreshed.provider,credentials:refreshed,email:refreshed.email??cred.email});let fallbackProfileId=suggestOAuthProfileIdForLegacyDefault({cfg,store:refreshedStore,provider:cred.provider,legacyProfileId:profileId});if(fallbackProfileId&&fallbackProfileId!==profileId)try{let fallbackResolved=await tryResolveOAuthProfile({cfg,store:refreshedStore,profileId:fallbackProfileId,agentDir:params.agentDir});if(fallbackResolved)return fallbackResolved}catch{}if(params.agentDir)try{let mainCred=(await ensureAuthProfileStore(void 0)).profiles[profileId];if(mainCred?.type===`oauth`&&Date.now()<mainCred.expires)return refreshedStore.profiles[profileId]={...mainCred},await saveAuthProfileStore(refreshedStore,params.agentDir),log$1.info(`inherited fresh OAuth credentials from main agent`,{profileId,agentDir:params.agentDir,expires:new Date(mainCred.expires).toISOString()}),buildOAuthProfileResult({provider:mainCred.provider,credentials:mainCred,email:mainCred.email})}catch{}let message=error instanceof Error?error.message:String(error),hint=formatAuthDoctorHint({cfg,store:refreshedStore,provider:cred.provider,profileId});throw Error(`OAuth token refresh failed for ${cred.provider}: ${message}. Please try again or re-authenticate.`+(hint?`\n\n${hint}`:``),{cause:error})}}function resolveProfileUnusableUntil(stats){let values=[stats.cooldownUntil,stats.disabledUntil].filter(value=>typeof value==`number`).filter(value=>Number.isFinite(value)&&value>0);return values.length===0?null:Math.max(...values)}function isProfileInCooldown(store,profileId){let stats=store.usageStats?.[profileId];if(!stats)return!1;let unusableUntil=resolveProfileUnusableUntil(stats);return unusableUntil?Date.now()<unusableUntil:!1}function getSoonestCooldownExpiry(store,profileIds){let soonest=null;for(let id of profileIds){let stats=store.usageStats?.[id];if(!stats)continue;let until=resolveProfileUnusableUntil(stats);typeof until!=`number`||!Number.isFinite(until)||until<=0||(soonest===null||until<soonest)&&(soonest=until)}return soonest}function clearExpiredCooldowns(store,now){let usageStats=store.usageStats;if(!usageStats)return!1;let ts=now??Date.now(),mutated=!1;for(let[profileId,stats]of Object.entries(usageStats)){if(!stats)continue;let profileMutated=!1,cooldownExpired=typeof stats.cooldownUntil==`number`&&Number.isFinite(stats.cooldownUntil)&&stats.cooldownUntil>0&&ts>=stats.cooldownUntil,disabledExpired=typeof stats.disabledUntil==`number`&&Number.isFinite(stats.disabledUntil)&&stats.disabledUntil>0&&ts>=stats.disabledUntil;cooldownExpired&&(stats.cooldownUntil=void 0,profileMutated=!0),disabledExpired&&(stats.disabledUntil=void 0,stats.disabledReason=void 0,profileMutated=!0),profileMutated&&!resolveProfileUnusableUntil(stats)&&(stats.errorCount=0,stats.failureCounts=void 0),profileMutated&&(usageStats[profileId]=stats,mutated=!0)}return mutated}async function markAuthProfileUsed(params){let{store,profileId,agentDir}=params,updated=await updateAuthProfileStoreWithLock({agentDir,updater:freshStore=>freshStore.profiles[profileId]?(freshStore.usageStats=freshStore.usageStats??{},freshStore.usageStats[profileId]={...freshStore.usageStats[profileId],lastUsed:Date.now(),errorCount:0,cooldownUntil:void 0,disabledUntil:void 0,disabledReason:void 0,failureCounts:void 0},!0):!1});if(updated){store.usageStats=updated.usageStats;return}store.profiles[profileId]&&(store.usageStats=store.usageStats??{},store.usageStats[profileId]={...store.usageStats[profileId],lastUsed:Date.now(),errorCount:0,cooldownUntil:void 0,disabledUntil:void 0,disabledReason:void 0,failureCounts:void 0},await saveAuthProfileStore(store,agentDir))}function calculateAuthProfileCooldownMs(errorCount){let normalized=Math.max(1,errorCount);return Math.min(3600*1e3,60*1e3*5**Math.min(normalized-1,3))}function resolveAuthCooldownConfig(params){let defaults={billingBackoffHours:5,billingMaxHours:24,failureWindowHours:24},resolveHours=(value,fallback)=>typeof value==`number`&&Number.isFinite(value)&&value>0?value:fallback,cooldowns=params.cfg?.auth?.cooldowns,billingBackoffHours=resolveHours((()=>{let map=cooldowns?.billingBackoffHoursByProvider;if(map){for(let[key,value]of Object.entries(map))if(normalizeProviderId(key)===params.providerId)return value}})()??cooldowns?.billingBackoffHours,defaults.billingBackoffHours),billingMaxHours=resolveHours(cooldowns?.billingMaxHours,defaults.billingMaxHours),failureWindowHours=resolveHours(cooldowns?.failureWindowHours,defaults.failureWindowHours);return{billingBackoffMs:billingBackoffHours*60*60*1e3,billingMaxMs:billingMaxHours*60*60*1e3,failureWindowMs:failureWindowHours*60*60*1e3}}function calculateAuthProfileBillingDisableMsWithConfig(params){let normalized=Math.max(1,params.errorCount),baseMs=Math.max(6e4,params.baseMs),maxMs=Math.max(baseMs,params.maxMs),raw=baseMs*2**Math.min(normalized-1,10);return Math.min(maxMs,raw)}function computeNextProfileUsageStats(params){let windowMs=params.cfgResolved.failureWindowMs,windowExpired=typeof params.existing.lastFailureAt==`number`&&params.existing.lastFailureAt>0&&params.now-params.existing.lastFailureAt>windowMs,nextErrorCount=(windowExpired?0:params.existing.errorCount??0)+1,failureCounts=windowExpired?{}:{...params.existing.failureCounts};failureCounts[params.reason]=(failureCounts[params.reason]??0)+1;let updatedStats={...params.existing,errorCount:nextErrorCount,failureCounts,lastFailureAt:params.now};if(params.reason===`billing`){let backoffMs=calculateAuthProfileBillingDisableMsWithConfig({errorCount:failureCounts.billing??1,baseMs:params.cfgResolved.billingBackoffMs,maxMs:params.cfgResolved.billingMaxMs});updatedStats.disabledUntil=params.now+backoffMs,updatedStats.disabledReason=`billing`}else{let backoffMs=calculateAuthProfileCooldownMs(nextErrorCount);updatedStats.cooldownUntil=params.now+backoffMs}return updatedStats}async function markAuthProfileFailure(params){let{store,profileId,reason,agentDir,cfg}=params,updated=await updateAuthProfileStoreWithLock({agentDir,updater:freshStore=>{let profile=freshStore.profiles[profileId];if(!profile)return!1;freshStore.usageStats=freshStore.usageStats??{};let existing=freshStore.usageStats[profileId]??{},now=Date.now(),cfgResolved=resolveAuthCooldownConfig({cfg,providerId:normalizeProviderId(profile.provider)});return freshStore.usageStats[profileId]=computeNextProfileUsageStats({existing,now,reason,cfgResolved}),!0}});if(updated){store.usageStats=updated.usageStats;return}if(!store.profiles[profileId])return;store.usageStats=store.usageStats??{};let existing=store.usageStats[profileId]??{},now=Date.now(),cfgResolved=resolveAuthCooldownConfig({cfg,providerId:normalizeProviderId(store.profiles[profileId]?.provider??``)});store.usageStats[profileId]=computeNextProfileUsageStats({existing,now,reason,cfgResolved}),await saveAuthProfileStore(store,agentDir)}function resolveAuthProfileOrder(params){let{cfg,store,provider,preferredProfile}=params,providerKey=normalizeProviderId(provider),now=Date.now();clearExpiredCooldowns(store,now);let storedOrder=findNormalizedProviderValue(store.order,providerKey),configuredOrder=findNormalizedProviderValue(cfg?.auth?.order,providerKey),explicitOrder=storedOrder??configuredOrder,explicitProfiles=cfg?.auth?.profiles?Object.entries(cfg.auth.profiles).filter(([,profile])=>normalizeProviderId(profile.provider)===providerKey).map(([profileId])=>profileId):[],baseOrder=explicitOrder??(explicitProfiles.length>0?explicitProfiles:listProfilesForProvider(store,providerKey));if(baseOrder.length===0)return[];let deduped=dedupeProfileIds(baseOrder.filter(profileId=>{let cred=store.profiles[profileId];if(!cred||normalizeProviderId(cred.provider)!==providerKey)return!1;let profileConfig=cfg?.auth?.profiles?.[profileId];return profileConfig&&(normalizeProviderId(profileConfig.provider)!==providerKey||profileConfig.mode!==cred.type&&!(profileConfig.mode===`oauth`&&cred.type===`token`))?!1:cred.type===`api_key`?!!cred.key?.trim():cred.type===`token`?!(!cred.token?.trim()||typeof cred.expires==`number`&&Number.isFinite(cred.expires)&&cred.expires>0&&now>=cred.expires):cred.type===`oauth`?!!(cred.access?.trim()||cred.refresh?.trim()):!1}));if(explicitOrder&&explicitOrder.length>0){let available=[],inCooldown=[];for(let profileId of deduped){let cooldownUntil=resolveProfileUnusableUntil(store.usageStats?.[profileId]??{})??0;typeof cooldownUntil==`number`&&Number.isFinite(cooldownUntil)&&cooldownUntil>0&&now<cooldownUntil?inCooldown.push({profileId,cooldownUntil}):available.push(profileId)}let cooldownSorted=inCooldown.toSorted((a,b)=>a.cooldownUntil-b.cooldownUntil).map(entry=>entry.profileId),ordered=[...available,...cooldownSorted];return preferredProfile&&ordered.includes(preferredProfile)?[preferredProfile,...ordered.filter(e=>e!==preferredProfile)]:ordered}let sorted=orderProfilesByMode(deduped,store);return preferredProfile&&sorted.includes(preferredProfile)?[preferredProfile,...sorted.filter(e=>e!==preferredProfile)]:sorted}function orderProfilesByMode(order,store){let now=Date.now(),available=[],inCooldown=[];for(let profileId of order)isProfileInCooldown(store,profileId)?inCooldown.push(profileId):available.push(profileId);let sorted=available.map(profileId=>{let type=store.profiles[profileId]?.type;return{profileId,typeScore:type===`oauth`?0:type===`token`?1:type===`api_key`?2:3,lastUsed:store.usageStats?.[profileId]?.lastUsed??0}}).toSorted((a,b)=>a.typeScore===b.typeScore?a.lastUsed-b.lastUsed:a.typeScore-b.typeScore).map(entry=>entry.profileId),cooldownSorted=inCooldown.map(profileId=>({profileId,cooldownUntil:resolveProfileUnusableUntil(store.usageStats?.[profileId]??{})??now})).toSorted((a,b)=>a.cooldownUntil-b.cooldownUntil).map(entry=>entry.profileId);return[...sorted,...cooldownSorted]}const DEFAULT_CONTEXT_WINDOW$1=32e3,DEFAULT_MAX_TOKENS$1=4096,DEFAULT_COST={input:0,output:0,cacheRead:0,cacheWrite:0},discoveryCache=new Map;let hasLoggedBedrockError=!1;function normalizeProviderFilter(filter){if(!filter||filter.length===0)return[];let normalized=new Set(filter.map(entry=>entry.trim().toLowerCase()).filter(entry=>entry.length>0));return Array.from(normalized).toSorted()}function buildCacheKey(params){return JSON.stringify(params)}function includesTextModalities(modalities){return(modalities??[]).some(entry=>entry.toLowerCase()===`text`)}function isActive(summary){let status=summary.modelLifecycle?.status;return typeof status==`string`?status.toUpperCase()===`ACTIVE`:!1}function mapInputModalities(summary){let inputs=summary.inputModalities??[],mapped=new Set;for(let modality of inputs){let lower=modality.toLowerCase();lower===`text`&&mapped.add(`text`),lower===`image`&&mapped.add(`image`)}return mapped.size===0&&mapped.add(`text`),Array.from(mapped)}function inferReasoningSupport(summary){let haystack=`${summary.modelId??``} ${summary.modelName??``}`.toLowerCase();return haystack.includes(`reasoning`)||haystack.includes(`thinking`)}function resolveDefaultContextWindow(config){let value=Math.floor(config?.defaultContextWindow??DEFAULT_CONTEXT_WINDOW$1);return value>0?value:DEFAULT_CONTEXT_WINDOW$1}function resolveDefaultMaxTokens(config){let value=Math.floor(config?.defaultMaxTokens??DEFAULT_MAX_TOKENS$1);return value>0?value:DEFAULT_MAX_TOKENS$1}function matchesProviderFilter(summary,filter){if(filter.length===0)return!0;let normalized=(summary.providerName??(typeof summary.modelId==`string`?summary.modelId.split(`.`)[0]:void 0))?.trim().toLowerCase();return normalized?filter.includes(normalized):!1}function shouldIncludeSummary(summary,filter){return!(!summary.modelId?.trim()||!matchesProviderFilter(summary,filter)||summary.responseStreamingSupported!==!0||!includesTextModalities(summary.outputModalities)||!isActive(summary))}function toModelDefinition(summary,defaults){let id=summary.modelId?.trim()??``;return{id,name:summary.modelName?.trim()||id,reasoning:inferReasoningSupport(summary),input:mapInputModalities(summary),cost:DEFAULT_COST,contextWindow:defaults.contextWindow,maxTokens:defaults.maxTokens}}async function discoverBedrockModels(params){let refreshIntervalSeconds=Math.max(0,Math.floor(params.config?.refreshInterval??3600)),providerFilter=normalizeProviderFilter(params.config?.providerFilter),defaultContextWindow=resolveDefaultContextWindow(params.config),defaultMaxTokens=resolveDefaultMaxTokens(params.config),cacheKey=buildCacheKey({region:params.region,providerFilter,refreshIntervalSeconds,defaultContextWindow,defaultMaxTokens}),now=params.now?.()??Date.now();if(refreshIntervalSeconds>0){let cached=discoveryCache.get(cacheKey);if(cached?.value&&cached.expiresAt>now)return cached.value;if(cached?.inFlight)return cached.inFlight}let client=(params.clientFactory??(region=>new BedrockClient({region})))(params.region),discoveryPromise=(async()=>{let response=await client.send(new ListFoundationModelsCommand({})),discovered=[];for(let summary of response.modelSummaries??[])shouldIncludeSummary(summary,providerFilter)&&discovered.push(toModelDefinition(summary,{contextWindow:defaultContextWindow,maxTokens:defaultMaxTokens}));return discovered.toSorted((a,b)=>a.name.localeCompare(b.name))})();refreshIntervalSeconds>0&&discoveryCache.set(cacheKey,{expiresAt:now+refreshIntervalSeconds*1e3,inFlight:discoveryPromise});try{let value=await discoveryPromise;return refreshIntervalSeconds>0&&discoveryCache.set(cacheKey,{expiresAt:now+refreshIntervalSeconds*1e3,value}),value}catch(error){return refreshIntervalSeconds>0&&discoveryCache.delete(cacheKey),hasLoggedBedrockError||(hasLoggedBedrockError=!0,console.warn(`[bedrock-discovery] Failed to list models: ${String(error)}`)),[]}}const CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID=`claude-sonnet-4-5`;`${CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID}`;const CLOUDFLARE_AI_GATEWAY_DEFAULT_COST={input:3,output:15,cacheRead:.3,cacheWrite:3.75};function buildCloudflareAiGatewayModelDefinition(params){return{id:params?.id?.trim()||CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_ID,name:params?.name??`Claude Sonnet 4.5`,reasoning:params?.reasoning??!0,input:params?.input??[`text`,`image`],cost:CLOUDFLARE_AI_GATEWAY_DEFAULT_COST,contextWindow:2e5,maxTokens:64e3}}function resolveCloudflareAiGatewayBaseUrl(params){let accountId=params.accountId.trim(),gatewayId=params.gatewayId.trim();return!accountId||!gatewayId?``:`https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/anthropic`}const HUGGINGFACE_BASE_URL=`https://router.huggingface.co/v1`,HUGGINGFACE_DEFAULT_COST={input:0,output:0,cacheRead:0,cacheWrite:0},HUGGINGFACE_MODEL_CATALOG=[{id:`deepseek-ai/DeepSeek-R1`,name:`DeepSeek R1`,reasoning:!0,input:[`text`],contextWindow:131072,maxTokens:8192,cost:{input:3,output:7,cacheRead:3,cacheWrite:3}},{id:`deepseek-ai/DeepSeek-V3.1`,name:`DeepSeek V3.1`,reasoning:!1,input:[`text`],contextWindow:131072,maxTokens:8192,cost:{input:.6,output:1.25,cacheRead:.6,cacheWrite:.6}},{id:`meta-llama/Llama-3.3-70B-Instruct-Turbo`,name:`Llama 3.3 70B Instruct Turbo`,reasoning:!1,input:[`text`],contextWindow:131072,maxTokens:8192,cost:{input:.88,output:.88,cacheRead:.88,cacheWrite:.88}},{id:`openai/gpt-oss-120b`,name:`GPT-OSS 120B`,reasoning:!1,input:[`text`],contextWindow:131072,maxTokens:8192,cost:{input:0,output:0,cacheRead:0,cacheWrite:0}}];function buildHuggingfaceModelDefinition(model){return{id:model.id,name:model.name,reasoning:model.reasoning,input:model.input,cost:model.cost,contextWindow:model.contextWindow,maxTokens:model.maxTokens}}function inferredMetaFromModelId(id){let base=id.split(`/`).pop()??id,reasoning=/r1|reasoning|thinking|reason/i.test(id)||/-\d+[tb]?-thinking/i.test(base);return{name:base.replace(/-/g,` `).replace(/\b(\w)/g,c=>c.toUpperCase()),reasoning}}function displayNameFromApiEntry(entry,inferredName){let fromApi=typeof entry.name==`string`&&entry.name.trim()||typeof entry.title==`string`&&entry.title.trim()||typeof entry.display_name==`string`&&entry.display_name.trim();if(fromApi)return fromApi;if(typeof entry.owned_by==`string`&&entry.owned_by.trim()){let base=entry.id.split(`/`).pop()??entry.id;return`${entry.owned_by.trim()}/${base}`}return inferredName}async function discoverHuggingfaceModels(apiKey){if(process.env.VITEST===`true`)return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);let trimmedKey=apiKey?.trim();if(!trimmedKey)return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);try{let response=await fetch(`${HUGGINGFACE_BASE_URL}/models`,{signal:AbortSignal.timeout(1e4),headers:{Authorization:`Bearer ${trimmedKey}`,"Content-Type":`application/json`}});if(!response.ok)return console.warn(`[huggingface-models] GET /v1/models failed: HTTP ${response.status}, using static catalog`),HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);let data=(await response.json())?.data;if(!Array.isArray(data)||data.length===0)return console.warn(`[huggingface-models] No models in response, using static catalog`),HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);let catalogById=new Map(HUGGINGFACE_MODEL_CATALOG.map(m=>[m.id,m])),seen=new Set,models=[];for(let entry of data){let id=typeof entry?.id==`string`?entry.id.trim():``;if(!id||seen.has(id))continue;seen.add(id);let catalogEntry=catalogById.get(id);if(catalogEntry)models.push(buildHuggingfaceModelDefinition(catalogEntry));else{let inferred=inferredMetaFromModelId(id),name=displayNameFromApiEntry(entry,inferred.name),modalities=entry.architecture?.input_modalities,input=Array.isArray(modalities)&&modalities.includes(`image`)?[`text`,`image`]:[`text`],contextLength=(Array.isArray(entry.providers)?entry.providers:[]).find(p=>typeof p?.context_length==`number`&&p.context_length>0)?.context_length??131072;models.push({id,name,reasoning:inferred.reasoning,input,cost:HUGGINGFACE_DEFAULT_COST,contextWindow:contextLength,maxTokens:8192})}}return models.length>0?models:HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition)}catch(error){return console.warn(`[huggingface-models] Discovery failed: ${String(error)}, using static catalog`),HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition)}}function readSharedEnvVar(key,env=process.env){let dir=resolveConfigDir(env),filepath=path.join(dir,`.env`);if(!fs.existsSync(filepath))return;let raw=fs.readFileSync(filepath,`utf8`),matcher=RegExp(`^(?:export\\s+)?${escapeRegExp(key.trim())}=(.*)$`,`m`),match=raw.match(matcher);return match&&match[1]?.trim()||void 0}const AWS_BEARER_ENV=`AWS_BEARER_TOKEN_BEDROCK`,AWS_ACCESS_KEY_ENV=`AWS_ACCESS_KEY_ID`,AWS_SECRET_KEY_ENV=`AWS_SECRET_ACCESS_KEY`,AWS_PROFILE_ENV=`AWS_PROFILE`;function resolveProviderConfig(cfg,provider){let providers=cfg?.models?.providers??{},direct=providers[provider];if(direct)return direct;let normalized=normalizeProviderId(provider);return normalized===provider?Object.entries(providers).find(([key])=>normalizeProviderId(key)===normalized)?.[1]:providers[normalized]??Object.entries(providers).find(([key])=>normalizeProviderId(key)===normalized)?.[1]}function getCustomProviderApiKey(cfg,provider){return normalizeOptionalSecretInput(resolveProviderConfig(cfg,provider)?.apiKey)}function resolveProviderAuthOverride(cfg,provider){let auth=resolveProviderConfig(cfg,provider)?.auth;if(auth===`api-key`||auth===`aws-sdk`||auth===`oauth`||auth===`token`)return auth}function resolveEnvSourceLabel(params){return`${params.envVars.some(envVar=>params.applied.has(envVar))?`shell env: `:`env: `}${params.label}`}function resolveAwsSdkEnvVarName(env=process.env){if(env[AWS_BEARER_ENV]?.trim())return AWS_BEARER_ENV;if(env[AWS_ACCESS_KEY_ENV]?.trim()&&env[AWS_SECRET_KEY_ENV]?.trim())return AWS_ACCESS_KEY_ENV;if(env[AWS_PROFILE_ENV]?.trim())return AWS_PROFILE_ENV}function resolveAwsSdkAuthInfo(){let applied=new Set(getShellEnvAppliedKeys());return process.env[AWS_BEARER_ENV]?.trim()?{mode:`aws-sdk`,source:resolveEnvSourceLabel({applied,envVars:[AWS_BEARER_ENV],label:AWS_BEARER_ENV})}:process.env[AWS_ACCESS_KEY_ENV]?.trim()&&process.env[AWS_SECRET_KEY_ENV]?.trim()?{mode:`aws-sdk`,source:resolveEnvSourceLabel({applied,envVars:[AWS_ACCESS_KEY_ENV,AWS_SECRET_KEY_ENV],label:`${AWS_ACCESS_KEY_ENV} + ${AWS_SECRET_KEY_ENV}`})}:process.env[AWS_PROFILE_ENV]?.trim()?{mode:`aws-sdk`,source:resolveEnvSourceLabel({applied,envVars:[AWS_PROFILE_ENV],label:AWS_PROFILE_ENV})}:{mode:`aws-sdk`,source:`aws-sdk default chain`}}async function resolveApiKeyForProvider(params){let{provider,cfg,profileId,preferredProfile}=params,store=params.store??await ensureAuthProfileStore(params.agentDir);if(profileId){let resolved=await resolveApiKeyForProfile({cfg,store,profileId,agentDir:params.agentDir});if(!resolved)throw Error(`No credentials found for profile "${profileId}".`);let mode=store.profiles[profileId]?.type;return{apiKey:resolved.apiKey,profileId,source:`profile:${profileId}`,mode:mode===`oauth`?`oauth`:mode===`token`?`token`:`api-key`}}let authOverride=resolveProviderAuthOverride(cfg,provider);if(authOverride===`aws-sdk`)return resolveAwsSdkAuthInfo();let order=resolveAuthProfileOrder({cfg,store,provider,preferredProfile});for(let candidate of order)try{let resolved=await resolveApiKeyForProfile({cfg,store,profileId:candidate,agentDir:params.agentDir});if(resolved){let mode=store.profiles[candidate]?.type;return{apiKey:resolved.apiKey,profileId:candidate,source:`profile:${candidate}`,mode:mode===`oauth`?`oauth`:mode===`token`?`token`:`api-key`}}}catch{}let envResolved=resolveEnvApiKey(provider);if(envResolved)return{apiKey:envResolved.apiKey,source:envResolved.source,mode:envResolved.source.includes(`OAUTH_TOKEN`)?`oauth`:`api-key`};let customKey=getCustomProviderApiKey(cfg,provider);if(customKey)return{apiKey:customKey,source:`models.json`,mode:`api-key`};let normalized=normalizeProviderId(provider);if(normalized===`builderforcellm`){let sharedKey=normalizeOptionalSecretInput(readSharedEnvVar(`BUILDERFORCE_API_KEY`));if(sharedKey)return{apiKey:sharedKey,source:`shared env: BUILDERFORCE_API_KEY`,mode:`api-key`};throw Error(`No Builderforce registration found for provider "builderforcellm". Run ${formatCliCommand(`builderforce onboard`)} (or /setup in TUI) to register your agentNode, then retry.`)}if(authOverride===void 0&&normalized===`amazon-bedrock`)return resolveAwsSdkAuthInfo();if(provider===`openai`&&listProfilesForProvider(store,`openai-codex`).length>0)throw Error(`No API key found for provider "openai". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.3-codex (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.1-codex.`);let authStorePath=resolveAuthStorePathForDisplay(params.agentDir),resolvedAgentDir=path.dirname(authStorePath);throw Error([`No API key found for provider "${provider}".`,`Auth store: ${authStorePath} (agentDir: ${resolvedAgentDir}).`,`Configure auth for this agent (${formatCliCommand(`builderforce agents add <id>`)}) or copy auth-profiles.json from the main agentDir.`].join(` `))}function resolveEnvApiKey(provider){let normalized=normalizeProviderId(provider),applied=new Set(getShellEnvAppliedKeys()),pick=envVar=>{let value=normalizeOptionalSecretInput(process.env[envVar]);return value?{apiKey:value,source:applied.has(envVar)?`shell env: ${envVar}`:`env: ${envVar}`}:null};if(normalized===`github-copilot`)return pick(`COPILOT_GITHUB_TOKEN`)??pick(`GH_TOKEN`)??pick(`GITHUB_TOKEN`);if(normalized===`anthropic`)return pick(`ANTHROPIC_OAUTH_TOKEN`)??pick(`ANTHROPIC_API_KEY`);if(normalized===`chutes`)return pick(`CHUTES_OAUTH_TOKEN`)??pick(`CHUTES_API_KEY`);if(normalized===`zai`)return pick(`ZAI_API_KEY`)??pick(`Z_AI_API_KEY`);if(normalized===`google-vertex`)return null;if(normalized===`opencode`)return pick(`OPENCODE_API_KEY`)??pick(`OPENCODE_ZEN_API_KEY`);if(normalized===`qwen-portal`)return pick(`QWEN_OAUTH_TOKEN`)??pick(`QWEN_PORTAL_API_KEY`);if(normalized===`minimax-portal`)return pick(`MINIMAX_OAUTH_TOKEN`)??pick(`MINIMAX_API_KEY`);if(normalized===`kimi-coding`)return pick(`KIMI_API_KEY`)??pick(`KIMICODE_API_KEY`);if(normalized===`huggingface`)return pick(`HUGGINGFACE_HUB_TOKEN`)??pick(`HF_TOKEN`);let envVar={openai:`OPENAI_API_KEY`,google:`GEMINI_API_KEY`,voyage:`VOYAGE_API_KEY`,groq:`GROQ_API_KEY`,deepgram:`DEEPGRAM_API_KEY`,cerebras:`CEREBRAS_API_KEY`,xai:`XAI_API_KEY`,openrouter:`OPENROUTER_API_KEY`,litellm:`LITELLM_API_KEY`,"vercel-ai-gateway":`AI_GATEWAY_API_KEY`,"cloudflare-ai-gateway":`CLOUDFLARE_AI_GATEWAY_API_KEY`,moonshot:`MOONSHOT_API_KEY`,minimax:`MINIMAX_API_KEY`,nvidia:`NVIDIA_API_KEY`,xiaomi:`XIAOMI_API_KEY`,synthetic:`SYNTHETIC_API_KEY`,venice:`VENICE_API_KEY`,mistral:`MISTRAL_API_KEY`,opencode:`OPENCODE_API_KEY`,builderforcellm:`BUILDERFORCE_API_KEY`,together:`TOGETHER_API_KEY`,qianfan:`QIANFAN_API_KEY`,ollama:`OLLAMA_API_KEY`,vllm:`VLLM_API_KEY`}[normalized];return envVar?pick(envVar):null}async function resolveModelAuthMode(provider,cfg,store){let resolved=provider?.trim();if(!resolved)return;let authOverride=resolveProviderAuthOverride(cfg,resolved);if(authOverride===`aws-sdk`)return`aws-sdk`;let authStore=store??await ensureAuthProfileStore(),profiles=listProfilesForProvider(authStore,resolved);if(profiles.length>0){let modes=new Set(profiles.map(id=>authStore.profiles[id]?.type).filter(mode=>!!mode));if([`oauth`,`token`,`api_key`].filter(k=>modes.has(k)).length>=2)return`mixed`;if(modes.has(`oauth`))return`oauth`;if(modes.has(`token`))return`token`;if(modes.has(`api_key`))return`api-key`}if(authOverride===void 0&&normalizeProviderId(resolved)===`amazon-bedrock`)return`aws-sdk`;let envKey=resolveEnvApiKey(resolved);return envKey?.apiKey?envKey.source.includes(`OAUTH_TOKEN`)?`oauth`:`api-key`:getCustomProviderApiKey(cfg,resolved)||normalizeProviderId(resolved)===`builderforcellm`&&normalizeOptionalSecretInput(readSharedEnvVar(`BUILDERFORCE_API_KEY`))?`api-key`:`unknown`}async function getApiKeyForModel(params){return resolveApiKeyForProvider({provider:params.model.provider,cfg:params.cfg,profileId:params.profileId,preferredProfile:params.preferredProfile,store:params.store,agentDir:params.agentDir})}function requireApiKey(auth,provider){let key=normalizeSecretInput(auth.apiKey);if(key)return key;throw Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`)}const DEFAULT_MODEL_IDS=[`gpt-4o`,`gpt-4.1`,`gpt-4.1-mini`,`gpt-4.1-nano`,`o1`,`o1-mini`,`o3-mini`];function getDefaultCopilotModelIds(){return[...DEFAULT_MODEL_IDS]}function buildCopilotModelDefinition(modelId){let id=modelId.trim();if(!id)throw Error(`Model id required`);return{id,name:id,api:`openai-responses`,reasoning:!1,input:[`text`,`image`],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:128e3,maxTokens:8192}}const CURRENT_SESSION_VERSION=3;function createCompactionSummaryMessage(summary,tokensBefore,timestamp){return{role:`compactionSummary`,summary,tokensBefore,timestamp:new Date(timestamp).getTime()}}function createBranchSummaryMessage(summary,fromId,timestamp){return{role:`branchSummary`,summary,fromId,timestamp:new Date(timestamp).getTime()}}function createCustomMessage(customType,content,display,details,timestamp){return{role:`custom`,customType,content,display,details,timestamp:new Date(timestamp).getTime()}}function generateId(byId){for(let i=0;i<100;i++){let id=randomUUID().slice(0,8);if(!byId.has(id))return id}return randomUUID()}function loadEntriesFromFile(filePath){if(!existsSync(filePath))return[];let content=readFileSync(filePath,`utf8`),entries=[];for(let line of content.trim().split(`
3
3
  `)){if(!line.trim())continue;let entry=parseFileEntry(line);entry&&entries.push(entry)}if(entries.length===0)return entries;let header=entries[0];return header.type!==`session`||typeof header.id!=`string`?[]:entries}function migrateV1ToV2(entries){let ids=new Map,prevId=null;for(let entry of entries){if(entry.type===`session`){entry.version=2;continue}if(entry.id=generateId(ids),ids.set(entry.id,entry),entry.parentId=prevId,prevId=entry.id,entry.type===`compaction`){let comp=entry;if(typeof comp.firstKeptEntryIndex==`number`){let target=entries[comp.firstKeptEntryIndex];target&&target.type!==`session`&&(comp.firstKeptEntryId=target.id),comp.firstKeptEntryIndex=void 0}}}}function migrateV2ToV3(entries){for(let entry of entries){if(entry.type===`session`){entry.version=3;continue}if(entry.type===`message`){let msg=entry.message;msg&&msg.role===`hookMessage`&&(msg.role=`custom`)}}}function migrateToCurrentVersion(entries){let version=entries.find(e=>e.type===`session`)?.version??1;return version>=3?!1:(version<2&&migrateV1ToV2(entries),version<3&&migrateV2ToV3(entries),!0)}function buildSessionContext(entries,leafId,byId){if(!byId){byId=new Map;for(let entry of entries)byId.set(entry.id,entry)}if(leafId===null)return{messages:[],thinkingLevel:`off`,model:null};let leaf=leafId?byId.get(leafId):void 0;if(leaf||=entries[entries.length-1],!leaf)return{messages:[],thinkingLevel:`off`,model:null};let path=[],current=leaf;for(;current;)path.unshift(current),current=current.parentId?byId.get(current.parentId):void 0;let thinkingLevel=`off`,model=null,compaction=null;for(let entry of path)entry.type===`thinking_level_change`?thinkingLevel=entry.thinkingLevel:entry.type===`model_change`?model={provider:entry.provider,modelId:entry.modelId}:entry.type===`message`&&entry.message.role===`assistant`?model={provider:entry.message.provider,modelId:entry.message.model}:entry.type===`compaction`&&(compaction=entry);let messages=[],appendMessage=entry=>{entry.type===`message`?messages.push(entry.message):entry.type===`custom_message`?messages.push(createCustomMessage(entry.customType,entry.content,entry.display,entry.details,entry.timestamp)):entry.type===`branch_summary`&&entry.summary&&messages.push(createBranchSummaryMessage(entry.summary,entry.fromId,entry.timestamp))};if(compaction){messages.push(createCompactionSummaryMessage(compaction.summary,compaction.tokensBefore,compaction.timestamp));let compactionIdx=path.findIndex(e=>e.type===`compaction`&&e.id===compaction.id),foundFirstKept=!1;for(let i=0;i<compactionIdx;i++){let entry=path[i];entry.id===compaction.firstKeptEntryId&&(foundFirstKept=!0),foundFirstKept&&appendMessage(entry)}for(let i=compactionIdx+1;i<path.length;i++)appendMessage(path[i])}else for(let entry of path)appendMessage(entry);return{messages,thinkingLevel,model}}var SessionManager=class SessionManager{constructor(cwd,sessionDir,sessionFile,persist){this.sessionId=randomUUID(),this.flushed=!1,this.fileEntries=[],this.byId=new Map,this.labelsById=new Map,this.leafId=null,this.cwd=cwd,this.sessionDir=sessionDir,this.persist=persist,persist&&sessionDir&&!existsSync(sessionDir)&&mkdirSync(sessionDir,{recursive:!0}),sessionFile?this.setSessionFile(sessionFile):this.newSession()}static create(cwd,sessionDir){return new SessionManager(cwd,sessionDir??defaultSessionDir(cwd),void 0,!0)}static open(path,sessionDir){let dir=sessionDir??resolve(path,`..`);return new SessionManager(process.cwd(),dir,path,!0)}static inMemory(cwd){return new SessionManager(cwd??process.cwd(),``,void 0,!1)}setSessionFile(sessionFile){if(this.sessionFile=resolve(sessionFile),existsSync(this.sessionFile)){if(this.fileEntries=loadEntriesFromFile(this.sessionFile),this.fileEntries.length===0){let explicit=this.sessionFile;this.newSession(),this.sessionFile=explicit,this._rewriteFile(),this.flushed=!0;return}this.sessionId=this.fileEntries.find(e=>e.type===`session`)?.id??randomUUID(),migrateToCurrentVersion(this.fileEntries)&&this._rewriteFile(),this._buildIndex(),this.flushed=!0}else{let explicit=this.sessionFile;this.newSession(),this.sessionFile=explicit}}newSession(options){this.sessionId=randomUUID();let timestamp=new Date().toISOString();if(this.fileEntries=[{type:`session`,version:3,id:this.sessionId,timestamp,cwd:this.cwd,parentSession:options?.parentSession}],this.byId.clear(),this.labelsById.clear(),this.leafId=null,this.flushed=!1,this.persist){let fileTs=timestamp.replace(/[:.]/g,`-`);this.sessionFile=join(this.getSessionDir(),`${fileTs}_${this.sessionId}.jsonl`)}return this.sessionFile}_buildIndex(){this.byId.clear(),this.labelsById.clear(),this.leafId=null;for(let entry of this.fileEntries)entry.type!==`session`&&(this.byId.set(entry.id,entry),this.leafId=entry.id,entry.type===`label`&&(entry.label?this.labelsById.set(entry.targetId,entry.label):this.labelsById.delete(entry.targetId)))}_rewriteFile(){!this.persist||!this.sessionFile||writeFileSync(this.sessionFile,`${this.fileEntries.map(e=>JSON.stringify(e)).join(`
4
4
  `)}\n`)}isPersisted(){return this.persist}getCwd(){return this.cwd}getSessionDir(){return this.sessionDir}getSessionId(){return this.sessionId}getSessionFile(){return this.sessionFile}_persist(entry){if(!(!this.persist||!this.sessionFile)){if(!this.fileEntries.some(e=>e.type===`message`&&e.message.role===`assistant`)){this.flushed=!1;return}if(this.flushed)appendFileSync(this.sessionFile,`${JSON.stringify(entry)}\n`);else{for(let e of this.fileEntries)appendFileSync(this.sessionFile,`${JSON.stringify(e)}\n`);this.flushed=!0}}}_appendEntry(entry){this.fileEntries.push(entry),this.byId.set(entry.id,entry),this.leafId=entry.id,this._persist(entry)}_base(){return{id:generateId(this.byId),parentId:this.leafId,timestamp:new Date().toISOString()}}appendMessage(message){let entry={type:`message`,...this._base(),message};return this._appendEntry(entry),entry.id}appendThinkingLevelChange(thinkingLevel){let entry={type:`thinking_level_change`,...this._base(),thinkingLevel};return this._appendEntry(entry),entry.id}appendModelChange(provider,modelId){let entry={type:`model_change`,...this._base(),provider,modelId};return this._appendEntry(entry),entry.id}appendCompaction(summary,firstKeptEntryId,tokensBefore,details,fromHook){let entry={type:`compaction`,...this._base(),summary,firstKeptEntryId,tokensBefore,details,fromHook};return this._appendEntry(entry),entry.id}appendCustomEntry(customType,data){let entry={type:`custom`,...this._base(),customType,data};return this._appendEntry(entry),entry.id}appendSessionInfo(name){let entry={type:`session_info`,...this._base(),name};return this._appendEntry(entry),entry.id}getSessionName(){for(let i=this.fileEntries.length-1;i>=0;i--){let e=this.fileEntries[i];if(e.type===`session_info`)return e.name}}appendCustomMessageEntry(customType,content,display,details){let entry={type:`custom_message`,...this._base(),customType,content,display,details};return this._appendEntry(entry),entry.id}appendLabelChange(targetId,label){let entry={type:`label`,...this._base(),targetId,label};return label?this.labelsById.set(targetId,label):this.labelsById.delete(targetId),this._appendEntry(entry),entry.id}getLeafId(){return this.leafId}getLeafEntry(){return this.leafId?this.byId.get(this.leafId):void 0}getEntry(id){return this.byId.get(id)}getChildren(parentId){return this.getEntries().filter(e=>e.parentId===parentId)}getLabel(id){return this.labelsById.get(id)}getBranch(fromId){let path=[],current=fromId??this.leafId?this.byId.get(fromId??this.leafId):void 0;for(;current;)path.unshift(current),current=current.parentId?this.byId.get(current.parentId):void 0;return path}buildSessionContext(){return buildSessionContext(this.getEntries(),this.leafId,this.byId)}getHeader(){return this.fileEntries.find(e=>e.type===`session`)??null}getEntries(){return this.fileEntries.filter(e=>e.type!==`session`)}getTree(){let nodes=new Map,roots=[];for(let entry of this.getEntries())nodes.set(entry.id,{entry,children:[],label:this.labelsById.get(entry.id)});for(let node of nodes.values()){let parentId=node.entry.parentId,parent=parentId?nodes.get(parentId):void 0;parent?parent.children.push(node):roots.push(node)}return roots}branch(branchFromId){this.byId.has(branchFromId)&&(this.leafId=branchFromId)}resetLeaf(){this.leafId=null}persistLeaf(){let header=this.fileEntries.find(e=>e.type===`session`),branch=this.getBranch();this.fileEntries=header?[header,...branch]:[...branch],this._buildIndex(),this._rewriteFile(),this.flushed=!0}createBranchedSession(leafId){let previousSessionFile=this.sessionFile,path=this.getBranch(leafId);if(path.length===0)throw Error(`Entry ${leafId} not found`);let pathWithoutLabels=path.filter(e=>e.type!==`label`);if(!this.persist)return;let newSessionId=randomUUID(),timestamp=new Date().toISOString(),fileTimestamp=timestamp.replace(/[:.]/g,`-`),newSessionFile=join(this.getSessionDir(),`${fileTimestamp}_${newSessionId}.jsonl`),header={type:`session`,version:3,id:newSessionId,timestamp,cwd:this.cwd,parentSession:previousSessionFile};appendFileSync(newSessionFile,`${JSON.stringify(header)}\n`);for(let entry of pathWithoutLabels)appendFileSync(newSessionFile,`${JSON.stringify(entry)}\n`);let pathEntryIds=new Set(pathWithoutLabels.map(e=>e.id));for(let[targetId,label]of this.labelsById)if(pathEntryIds.has(targetId)){let labelEntry={type:`label`,id:generateId(this.byId),parentId:pathWithoutLabels[pathWithoutLabels.length-1]?.id??null,timestamp:new Date().toISOString(),targetId,label};appendFileSync(newSessionFile,`${JSON.stringify(labelEntry)}\n`)}return this.setSessionFile(newSessionFile),newSessionFile}};function defaultSessionDir(cwd){let encoded=cwd.replace(/[^a-zA-Z0-9]+/g,`-`).replace(/^-+|-+$/g,``);return join(process.env.HOME??process.env.USERPROFILE??cwd,`.pi`,`agent`,`sessions`,encoded)}function parseFileEntry(line){try{return JSON.parse(line)}catch{return null}}var SettingsManager=class SettingsManager{constructor(settings){this.settings=settings}static create(_cwd,_agentDir){return new SettingsManager({})}applyOverrides(overrides){this.settings={...this.settings,...overrides,compaction:{...this.settings.compaction,...overrides.compaction}}}getCompactionReserveTokens(){return this.settings.compaction?.reserveTokens??16384}getCompactionKeepRecentTokens(){return this.settings.compaction?.keepRecentTokens??2e4}getCompactionSettings(){return{reserveTokens:this.getCompactionReserveTokens(),keepRecentTokens:this.getCompactionKeepRecentTokens()}}},EventStream=class{constructor(isComplete,extractResult){this.isComplete=isComplete,this.extractResult=extractResult,this.queue=[],this.waiting=[],this.done=!1,this.finalResultPromise=new Promise(resolve=>{this.resolveFinalResult=resolve})}push(event){if(this.done)return;this.isComplete(event)&&(this.done=!0,this.resolveFinalResult(this.extractResult(event)));let waiter=this.waiting.shift();waiter?waiter({value:event,done:!1}):this.queue.push(event)}end(result){for(this.done=!0,result!==void 0&&this.resolveFinalResult(result);this.waiting.length>0;)this.waiting.shift()?.({value:void 0,done:!0})}async*[Symbol.asyncIterator](){for(;;)if(this.queue.length>0)yield this.queue.shift();else if(this.done)return;else{let result=await new Promise(resolve=>this.waiting.push(resolve));if(result.done)return;yield result.value}}result(){return this.finalResultPromise}},AssistantMessageEventStream=class extends EventStream{constructor(){super(event=>event.type===`done`||event.type===`error`,event=>{if(event.type===`done`)return event.message;if(event.type===`error`)return event.error;throw Error(`Unexpected event type for final result`)})}};function createAssistantMessageEventStream(){return new AssistantMessageEventStream}function sseDataPayload(line){let trimmed=line.trim();if(trimmed.startsWith(`data:`))return trimmed.slice(5).trim()}async function*readSseDataPayloads(body){if(!body)return;let reader=body.getReader(),decoder=new TextDecoder,buffer=``;try{for(;;){let{done,value}=await reader.read();if(done)break;buffer+=decoder.decode(value,{stream:!0});let lines=buffer.split(`
@@ -1 +1 @@
1
- import{t as __exportAll}from"./rolldown-runtime-BlRA8w72.js";import{L as toWhatsappJid,Z as getChildLogger,x as escapeRegExp}from"./registry-DJq2Cvo9.js";import{n as loadConfig}from"./config-3vPn_hmp.js";import{t as createSubsystemLogger}from"./subsystem-COTa5Ly_.js";import{i as convertMarkdownTables,n as requireActiveWebListener,o as normalizePollInput}from"./active-listener-DpQ7aGYd.js";import{o as loadWebMedia}from"./render-BUCRXPIk.js";import{n as resolveMarkdownTableMode}from"./markdown-tables-Epim9b-0.js";import{randomUUID}from"node:crypto";const FENCE_PLACEHOLDER=`\0FENCE`,INLINE_CODE_PLACEHOLDER=`\0CODE`;function markdownToWhatsApp(text){if(!text)return text;let fences=[],result=text.replace(/```[\s\S]*?```/g,match=>(fences.push(match),`${FENCE_PLACEHOLDER}${fences.length-1}`)),inlineCodes=[];return result=result.replace(/`[^`\n]+`/g,match=>(inlineCodes.push(match),`${INLINE_CODE_PLACEHOLDER}${inlineCodes.length-1}`)),result=result.replace(/\*\*(.+?)\*\*/g,`*$1*`),result=result.replace(/__(.+?)__/g,`*$1*`),result=result.replace(/~~(.+?)~~/g,`~$1~`),result=result.replace(RegExp(`${escapeRegExp(INLINE_CODE_PLACEHOLDER)}(\\d+)`,`g`),(_,idx)=>inlineCodes[Number(idx)]??``),result=result.replace(RegExp(`${escapeRegExp(FENCE_PLACEHOLDER)}(\\d+)`,`g`),(_,idx)=>fences[Number(idx)]??``),result}var outbound_exports=__exportAll({sendMessageWhatsApp:()=>sendMessageWhatsApp,sendPollWhatsApp:()=>sendPollWhatsApp,sendReactionWhatsApp:()=>sendReactionWhatsApp});const outboundLog=createSubsystemLogger(`gateway/channels/whatsapp`).child(`outbound`);async function sendMessageWhatsApp(to,body,options){let text=body,correlationId=randomUUID(),startedAt=Date.now(),{listener:active,accountId:resolvedAccountId}=requireActiveWebListener(options.accountId),tableMode=resolveMarkdownTableMode({cfg:loadConfig(),channel:`whatsapp`,accountId:resolvedAccountId??options.accountId});text=convertMarkdownTables(text??``,tableMode),text=markdownToWhatsApp(text);let logger=getChildLogger({module:`web-outbound`,correlationId,to});try{let jid=toWhatsappJid(to),mediaBuffer,mediaType,documentFileName;if(options.mediaUrl){let media=await loadWebMedia(options.mediaUrl,{localRoots:options.mediaLocalRoots}),caption=text||void 0;mediaBuffer=media.buffer,mediaType=media.contentType,media.kind===`audio`?mediaType=media.contentType===`audio/ogg`?`audio/ogg; codecs=opus`:media.contentType??`application/octet-stream`:media.kind===`video`||media.kind===`image`?text=caption??``:(text=caption??``,documentFileName=media.fileName)}outboundLog.info(`Sending message -> ${jid}${options.mediaUrl?` (media)`:``}`),logger.info({jid,hasMedia:!!options.mediaUrl},`sending message`),await active.sendComposingTo(to);let accountId=options.accountId?.trim()?resolvedAccountId:void 0,sendOptions=options.gifPlayback||accountId||documentFileName?{...options.gifPlayback?{gifPlayback:!0}:{},...documentFileName?{fileName:documentFileName}:{},accountId}:void 0,messageId=(sendOptions?await active.sendMessage(to,text,mediaBuffer,mediaType,sendOptions):await active.sendMessage(to,text,mediaBuffer,mediaType))?.messageId??`unknown`,durationMs=Date.now()-startedAt;return outboundLog.info(`Sent message ${messageId} -> ${jid}${options.mediaUrl?` (media)`:``} (${durationMs}ms)`),logger.info({jid,messageId},`sent message`),{messageId,toJid:jid}}catch(err){throw logger.error({err:String(err),to,hasMedia:!!options.mediaUrl},`failed to send via web session`),err}}async function sendReactionWhatsApp(chatJid,messageId,emoji,options){let correlationId=randomUUID(),{listener:active}=requireActiveWebListener(options.accountId),logger=getChildLogger({module:`web-outbound`,correlationId,chatJid,messageId});try{let jid=toWhatsappJid(chatJid);outboundLog.info(`Sending reaction "${emoji}" -> message ${messageId}`),logger.info({chatJid:jid,messageId,emoji},`sending reaction`),await active.sendReaction(chatJid,messageId,emoji,options.fromMe??!1,options.participant),outboundLog.info(`Sent reaction "${emoji}" -> message ${messageId}`),logger.info({chatJid:jid,messageId,emoji},`sent reaction`)}catch(err){throw logger.error({err:String(err),chatJid,messageId,emoji},`failed to send reaction via web session`),err}}async function sendPollWhatsApp(to,poll,options){let correlationId=randomUUID(),startedAt=Date.now(),{listener:active}=requireActiveWebListener(options.accountId),logger=getChildLogger({module:`web-outbound`,correlationId,to});try{let jid=toWhatsappJid(to),normalized=normalizePollInput(poll,{maxOptions:12});outboundLog.info(`Sending poll -> ${jid}: "${normalized.question}"`),logger.info({jid,question:normalized.question,optionCount:normalized.options.length,maxSelections:normalized.maxSelections},`sending poll`);let messageId=(await active.sendPoll(to,normalized))?.messageId??`unknown`,durationMs=Date.now()-startedAt;return outboundLog.info(`Sent poll ${messageId} -> ${jid} (${durationMs}ms)`),logger.info({jid,messageId},`sent poll`),{messageId,toJid:jid}}catch(err){throw logger.error({err:String(err),to,question:poll.question},`failed to send poll via web session`),err}}export{markdownToWhatsApp as i,sendMessageWhatsApp as n,sendReactionWhatsApp as r,outbound_exports as t};
1
+ import{t as __exportAll}from"./rolldown-runtime-BlRA8w72.js";import{L as toWhatsappJid,Z as getChildLogger,x as escapeRegExp}from"./registry-CZHRcH-q.js";import{n as loadConfig}from"./config--Ci8Y91R.js";import{t as createSubsystemLogger}from"./subsystem-D0Ril4rt.js";import{i as convertMarkdownTables,n as requireActiveWebListener,o as normalizePollInput}from"./active-listener-DVWVNlT9.js";import{o as loadWebMedia}from"./render-CuA_WRX5.js";import{n as resolveMarkdownTableMode}from"./markdown-tables-BUfhHgfs.js";import{randomUUID}from"node:crypto";const FENCE_PLACEHOLDER=`\0FENCE`,INLINE_CODE_PLACEHOLDER=`\0CODE`;function markdownToWhatsApp(text){if(!text)return text;let fences=[],result=text.replace(/```[\s\S]*?```/g,match=>(fences.push(match),`${FENCE_PLACEHOLDER}${fences.length-1}`)),inlineCodes=[];return result=result.replace(/`[^`\n]+`/g,match=>(inlineCodes.push(match),`${INLINE_CODE_PLACEHOLDER}${inlineCodes.length-1}`)),result=result.replace(/\*\*(.+?)\*\*/g,`*$1*`),result=result.replace(/__(.+?)__/g,`*$1*`),result=result.replace(/~~(.+?)~~/g,`~$1~`),result=result.replace(RegExp(`${escapeRegExp(INLINE_CODE_PLACEHOLDER)}(\\d+)`,`g`),(_,idx)=>inlineCodes[Number(idx)]??``),result=result.replace(RegExp(`${escapeRegExp(FENCE_PLACEHOLDER)}(\\d+)`,`g`),(_,idx)=>fences[Number(idx)]??``),result}var outbound_exports=__exportAll({sendMessageWhatsApp:()=>sendMessageWhatsApp,sendPollWhatsApp:()=>sendPollWhatsApp,sendReactionWhatsApp:()=>sendReactionWhatsApp});const outboundLog=createSubsystemLogger(`gateway/channels/whatsapp`).child(`outbound`);async function sendMessageWhatsApp(to,body,options){let text=body,correlationId=randomUUID(),startedAt=Date.now(),{listener:active,accountId:resolvedAccountId}=requireActiveWebListener(options.accountId),tableMode=resolveMarkdownTableMode({cfg:loadConfig(),channel:`whatsapp`,accountId:resolvedAccountId??options.accountId});text=convertMarkdownTables(text??``,tableMode),text=markdownToWhatsApp(text);let logger=getChildLogger({module:`web-outbound`,correlationId,to});try{let jid=toWhatsappJid(to),mediaBuffer,mediaType,documentFileName;if(options.mediaUrl){let media=await loadWebMedia(options.mediaUrl,{localRoots:options.mediaLocalRoots}),caption=text||void 0;mediaBuffer=media.buffer,mediaType=media.contentType,media.kind===`audio`?mediaType=media.contentType===`audio/ogg`?`audio/ogg; codecs=opus`:media.contentType??`application/octet-stream`:media.kind===`video`||media.kind===`image`?text=caption??``:(text=caption??``,documentFileName=media.fileName)}outboundLog.info(`Sending message -> ${jid}${options.mediaUrl?` (media)`:``}`),logger.info({jid,hasMedia:!!options.mediaUrl},`sending message`),await active.sendComposingTo(to);let accountId=options.accountId?.trim()?resolvedAccountId:void 0,sendOptions=options.gifPlayback||accountId||documentFileName?{...options.gifPlayback?{gifPlayback:!0}:{},...documentFileName?{fileName:documentFileName}:{},accountId}:void 0,messageId=(sendOptions?await active.sendMessage(to,text,mediaBuffer,mediaType,sendOptions):await active.sendMessage(to,text,mediaBuffer,mediaType))?.messageId??`unknown`,durationMs=Date.now()-startedAt;return outboundLog.info(`Sent message ${messageId} -> ${jid}${options.mediaUrl?` (media)`:``} (${durationMs}ms)`),logger.info({jid,messageId},`sent message`),{messageId,toJid:jid}}catch(err){throw logger.error({err:String(err),to,hasMedia:!!options.mediaUrl},`failed to send via web session`),err}}async function sendReactionWhatsApp(chatJid,messageId,emoji,options){let correlationId=randomUUID(),{listener:active}=requireActiveWebListener(options.accountId),logger=getChildLogger({module:`web-outbound`,correlationId,chatJid,messageId});try{let jid=toWhatsappJid(chatJid);outboundLog.info(`Sending reaction "${emoji}" -> message ${messageId}`),logger.info({chatJid:jid,messageId,emoji},`sending reaction`),await active.sendReaction(chatJid,messageId,emoji,options.fromMe??!1,options.participant),outboundLog.info(`Sent reaction "${emoji}" -> message ${messageId}`),logger.info({chatJid:jid,messageId,emoji},`sent reaction`)}catch(err){throw logger.error({err:String(err),chatJid,messageId,emoji},`failed to send reaction via web session`),err}}async function sendPollWhatsApp(to,poll,options){let correlationId=randomUUID(),startedAt=Date.now(),{listener:active}=requireActiveWebListener(options.accountId),logger=getChildLogger({module:`web-outbound`,correlationId,to});try{let jid=toWhatsappJid(to),normalized=normalizePollInput(poll,{maxOptions:12});outboundLog.info(`Sending poll -> ${jid}: "${normalized.question}"`),logger.info({jid,question:normalized.question,optionCount:normalized.options.length,maxSelections:normalized.maxSelections},`sending poll`);let messageId=(await active.sendPoll(to,normalized))?.messageId??`unknown`,durationMs=Date.now()-startedAt;return outboundLog.info(`Sent poll ${messageId} -> ${jid} (${durationMs}ms)`),logger.info({jid,messageId},`sent poll`),{messageId,toJid:jid}}catch(err){throw logger.error({err:String(err),to,question:poll.question},`failed to send poll via web session`),err}}export{markdownToWhatsApp as i,sendMessageWhatsApp as n,sendReactionWhatsApp as r,outbound_exports as t};
@@ -1 +1 @@
1
- import{c as normalizeAccountId,t as DEFAULT_ACCOUNT_ID}from"./session-key-5J69DULS.js";import{_ as createAccountListHelpers,r as resolveWhatsAppAccount}from"./accounts-BwreSNAR.js";import{D as normalizeE164,c as requireActivePluginRegistry,i as normalizeAnyChannelId,n as CHAT_CHANNEL_ORDER}from"./registry-DJq2Cvo9.js";import{r as isTruthyEnvValue}from"./command-format-CAX9XFjI.js";import{t as normalizeChatType}from"./chat-type-Dv7EB0qD.js";import{n as listBoundAccountIds,r as resolveDefaultAgentBoundAccountId}from"./bindings-CDEzl4kl.js";import fs from"node:fs";function createAccountActionGate(params){return(key,defaultValue=!0)=>{let accountValue=params.accountActions?.[key];if(accountValue!==void 0)return accountValue;let baseValue=params.baseActions?.[key];return baseValue===void 0?defaultValue:baseValue}}function normalizeDiscordToken(raw){if(!raw)return;let trimmed=raw.trim();if(trimmed)return trimmed.replace(/^Bot\s+/i,``)}function resolveDiscordToken(cfg,opts={}){let accountId=normalizeAccountId(opts.accountId),discordCfg=cfg?.channels?.discord,accountToken=normalizeDiscordToken((accountId===DEFAULT_ACCOUNT_ID?discordCfg?.accounts?.[DEFAULT_ACCOUNT_ID]:discordCfg?.accounts?.[accountId])?.token??void 0);if(accountToken)return{token:accountToken,source:`config`};let allowEnv=accountId===DEFAULT_ACCOUNT_ID,configToken=allowEnv?normalizeDiscordToken(discordCfg?.token??void 0):void 0;if(configToken)return{token:configToken,source:`config`};let envToken=allowEnv?normalizeDiscordToken(opts.envToken??process.env.DISCORD_BOT_TOKEN):void 0;return envToken?{token:envToken,source:`env`}:{token:``,source:`none`}}const{listAccountIds:listAccountIds$1,resolveDefaultAccountId:resolveDefaultAccountId$1}=createAccountListHelpers(`discord`),listDiscordAccountIds=listAccountIds$1,resolveDefaultDiscordAccountId=resolveDefaultAccountId$1;function resolveAccountConfig$2(cfg,accountId){let accounts=cfg.channels?.discord?.accounts;if(!(!accounts||typeof accounts!=`object`))return accounts[accountId]}function mergeDiscordAccountConfig(cfg,accountId){let{accounts:_ignored,...base}=cfg.channels?.discord??{},account=resolveAccountConfig$2(cfg,accountId)??{};return{...base,...account}}function createDiscordActionGate(params){let accountId=normalizeAccountId(params.accountId);return createAccountActionGate({baseActions:params.cfg.channels?.discord?.actions,accountActions:resolveAccountConfig$2(params.cfg,accountId)?.actions})}function resolveDiscordAccount(params){let accountId=normalizeAccountId(params.accountId),baseEnabled=params.cfg.channels?.discord?.enabled!==!1,merged=mergeDiscordAccountConfig(params.cfg,accountId),accountEnabled=merged.enabled!==!1,enabled=baseEnabled&&accountEnabled,tokenResolution=resolveDiscordToken(params.cfg,{accountId});return{accountId,enabled,name:merged.name?.trim()||void 0,token:tokenResolution.token,tokenSource:tokenResolution.source,config:merged}}function listEnabledDiscordAccounts(cfg){return listDiscordAccountIds(cfg).map(accountId=>resolveDiscordAccount({cfg,accountId})).filter(account=>account.enabled)}function normalizeSlackToken(raw){return raw?.trim()||void 0}function resolveSlackBotToken(raw){return normalizeSlackToken(raw)}function resolveSlackAppToken(raw){return normalizeSlackToken(raw)}const{listAccountIds,resolveDefaultAccountId}=createAccountListHelpers(`slack`),listSlackAccountIds=listAccountIds,resolveDefaultSlackAccountId=resolveDefaultAccountId;function resolveAccountConfig$1(cfg,accountId){let accounts=cfg.channels?.slack?.accounts;if(!(!accounts||typeof accounts!=`object`))return accounts[accountId]}function mergeSlackAccountConfig(cfg,accountId){let{accounts:_ignored,...base}=cfg.channels?.slack??{},account=resolveAccountConfig$1(cfg,accountId)??{};return{...base,...account}}function resolveSlackAccount(params){let accountId=normalizeAccountId(params.accountId),baseEnabled=params.cfg.channels?.slack?.enabled!==!1,merged=mergeSlackAccountConfig(params.cfg,accountId),accountEnabled=merged.enabled!==!1,enabled=baseEnabled&&accountEnabled,allowEnv=accountId===DEFAULT_ACCOUNT_ID,envBot=allowEnv?resolveSlackBotToken(process.env.SLACK_BOT_TOKEN):void 0,envApp=allowEnv?resolveSlackAppToken(process.env.SLACK_APP_TOKEN):void 0,configBot=resolveSlackBotToken(merged.botToken),configApp=resolveSlackAppToken(merged.appToken),botToken=configBot??envBot,appToken=configApp??envApp,botTokenSource=configBot?`config`:envBot?`env`:`none`,appTokenSource=configApp?`config`:envApp?`env`:`none`;return{accountId,enabled,name:merged.name?.trim()||void 0,botToken,appToken,botTokenSource,appTokenSource,config:merged,groupPolicy:merged.groupPolicy,textChunkLimit:merged.textChunkLimit,mediaMaxMb:merged.mediaMaxMb,reactionNotifications:merged.reactionNotifications,reactionAllowlist:merged.reactionAllowlist,replyToMode:merged.replyToMode,replyToModeByChatType:merged.replyToModeByChatType,actions:merged.actions,slashCommand:merged.slashCommand,dm:merged.dm,channels:merged.channels}}function listEnabledSlackAccounts(cfg){return listSlackAccountIds(cfg).map(accountId=>resolveSlackAccount({cfg,accountId})).filter(account=>account.enabled)}function resolveSlackReplyToMode(account,chatType){let normalized=normalizeChatType(chatType??void 0);return normalized&&account.replyToModeByChatType?.[normalized]!==void 0?account.replyToModeByChatType[normalized]??`off`:normalized===`direct`&&account.dm?.replyToMode!==void 0?account.dm.replyToMode:account.replyToMode??`off`}function resolveTelegramToken(cfg,opts={}){let accountId=normalizeAccountId(opts.accountId),telegramCfg=cfg?.channels?.telegram,accountCfg=(id=>{let accounts=telegramCfg?.accounts;if(!accounts||typeof accounts!=`object`||Array.isArray(accounts))return;let direct=accounts[id];if(direct)return direct;let matchKey=Object.keys(accounts).find(key=>normalizeAccountId(key)===id);return matchKey?accounts[matchKey]:void 0})(accountId===DEFAULT_ACCOUNT_ID?DEFAULT_ACCOUNT_ID:accountId),accountTokenFile=accountCfg?.tokenFile?.trim();if(accountTokenFile){if(!fs.existsSync(accountTokenFile))return opts.logMissingFile?.(`channels.telegram.accounts.${accountId}.tokenFile not found: ${accountTokenFile}`),{token:``,source:`none`};try{let token=fs.readFileSync(accountTokenFile,`utf-8`).trim();if(token)return{token,source:`tokenFile`}}catch(err){return opts.logMissingFile?.(`channels.telegram.accounts.${accountId}.tokenFile read failed: ${String(err)}`),{token:``,source:`none`}}return{token:``,source:`none`}}let accountToken=accountCfg?.botToken?.trim();if(accountToken)return{token:accountToken,source:`config`};let allowEnv=accountId===DEFAULT_ACCOUNT_ID,tokenFile=telegramCfg?.tokenFile?.trim();if(tokenFile&&allowEnv){if(!fs.existsSync(tokenFile))return opts.logMissingFile?.(`channels.telegram.tokenFile not found: ${tokenFile}`),{token:``,source:`none`};try{let token=fs.readFileSync(tokenFile,`utf-8`).trim();if(token)return{token,source:`tokenFile`}}catch(err){return opts.logMissingFile?.(`channels.telegram.tokenFile read failed: ${String(err)}`),{token:``,source:`none`}}}let configToken=telegramCfg?.botToken?.trim();if(configToken&&allowEnv)return{token:configToken,source:`config`};let envToken=allowEnv?(opts.envToken??process.env.TELEGRAM_BOT_TOKEN)?.trim():``;return envToken?{token:envToken,source:`env`}:{token:``,source:`none`}}const debugAccounts=(...args)=>{isTruthyEnvValue(process.env.BUILDERFORCE_AGENTS_DEBUG_TELEGRAM_ACCOUNTS)&&console.warn(`[telegram:accounts]`,...args)};function listConfiguredAccountIds(cfg){let accounts=cfg.channels?.telegram?.accounts;if(!accounts||typeof accounts!=`object`)return[];let ids=new Set;for(let key of Object.keys(accounts))key&&ids.add(normalizeAccountId(key));return[...ids]}function listTelegramAccountIds(cfg){let ids=Array.from(new Set([...listConfiguredAccountIds(cfg),...listBoundAccountIds(cfg,`telegram`)]));return debugAccounts(`listTelegramAccountIds`,ids),ids.length===0?[DEFAULT_ACCOUNT_ID]:ids.toSorted((a,b)=>a.localeCompare(b))}function resolveDefaultTelegramAccountId(cfg){let boundDefault=resolveDefaultAgentBoundAccountId(cfg,`telegram`);if(boundDefault)return boundDefault;let ids=listTelegramAccountIds(cfg);return ids.includes(DEFAULT_ACCOUNT_ID)?DEFAULT_ACCOUNT_ID:ids[0]??DEFAULT_ACCOUNT_ID}function resolveAccountConfig(cfg,accountId){let accounts=cfg.channels?.telegram?.accounts;if(!accounts||typeof accounts!=`object`)return;let direct=accounts[accountId];if(direct)return direct;let normalized=normalizeAccountId(accountId),matchKey=Object.keys(accounts).find(key=>normalizeAccountId(key)===normalized);return matchKey?accounts[matchKey]:void 0}function mergeTelegramAccountConfig(cfg,accountId){let{accounts:_ignored,...base}=cfg.channels?.telegram??{},account=resolveAccountConfig(cfg,accountId)??{};return{...base,...account}}function createTelegramActionGate(params){let accountId=normalizeAccountId(params.accountId);return createAccountActionGate({baseActions:params.cfg.channels?.telegram?.actions,accountActions:resolveAccountConfig(params.cfg,accountId)?.actions})}function resolveTelegramAccount(params){let hasExplicitAccountId=!!params.accountId?.trim(),baseEnabled=params.cfg.channels?.telegram?.enabled!==!1,resolve=accountId=>{let merged=mergeTelegramAccountConfig(params.cfg,accountId),accountEnabled=merged.enabled!==!1,enabled=baseEnabled&&accountEnabled,tokenResolution=resolveTelegramToken(params.cfg,{accountId});return debugAccounts(`resolve`,{accountId,enabled,tokenSource:tokenResolution.source}),{accountId,enabled,name:merged.name?.trim()||void 0,token:tokenResolution.token,tokenSource:tokenResolution.source,config:merged}},primary=resolve(normalizeAccountId(params.accountId));if(hasExplicitAccountId||primary.tokenSource!==`none`)return primary;let fallbackId=resolveDefaultTelegramAccountId(params.cfg);if(fallbackId===primary.accountId)return primary;let fallback=resolve(fallbackId);return fallback.tokenSource===`none`?primary:fallback}function listEnabledTelegramAccounts(cfg){return listTelegramAccountIds(cfg).map(accountId=>resolveTelegramAccount({cfg,accountId})).filter(account=>account.enabled)}const WHATSAPP_USER_JID_RE=/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i,WHATSAPP_LID_RE=/^(\d+)@lid$/i;function stripWhatsAppTargetPrefixes(value){let candidate=value.trim();for(;;){let before=candidate;if(candidate=candidate.replace(/^whatsapp:/i,``).trim(),candidate===before)return candidate}}function isWhatsAppGroupJid(value){let candidate=stripWhatsAppTargetPrefixes(value);if(!candidate.toLowerCase().endsWith(`@g.us`))return!1;let localPart=candidate.slice(0,candidate.length-5);return!localPart||localPart.includes(`@`)?!1:/^[0-9]+(-[0-9]+)*$/.test(localPart)}function isWhatsAppUserTarget(value){let candidate=stripWhatsAppTargetPrefixes(value);return WHATSAPP_USER_JID_RE.test(candidate)||WHATSAPP_LID_RE.test(candidate)}function extractUserJidPhone(jid){let userMatch=jid.match(WHATSAPP_USER_JID_RE);if(userMatch)return userMatch[1];let lidMatch=jid.match(WHATSAPP_LID_RE);return lidMatch?lidMatch[1]:null}function normalizeWhatsAppTarget(value){let candidate=stripWhatsAppTargetPrefixes(value);if(!candidate)return null;if(isWhatsAppGroupJid(candidate))return`${candidate.slice(0,candidate.length-5)}@g.us`;if(isWhatsAppUserTarget(candidate)){let phone=extractUserJidPhone(candidate);if(!phone)return null;let normalized=normalizeE164(phone);return normalized.length>1?normalized:null}if(candidate.includes(`@`))return null;let normalized=normalizeE164(candidate);return normalized.length>1?normalized:null}function normalizeTargetId(kind,id){return`${kind}:${id}`.toLowerCase()}function buildMessagingTarget(kind,id,raw){return{kind,id,raw,normalized:normalizeTargetId(kind,id)}}function ensureTargetId(params){if(!params.pattern.test(params.candidate))throw Error(params.errorMessage);return params.candidate}function parseTargetMention(params){let match=params.raw.match(params.mentionPattern);if(match?.[1])return buildMessagingTarget(params.kind,match[1],params.raw)}function parseTargetPrefix(params){if(!params.raw.startsWith(params.prefix))return;let id=params.raw.slice(params.prefix.length).trim();return id?buildMessagingTarget(params.kind,id,params.raw):void 0}function parseTargetPrefixes(params){for(let entry of params.prefixes){let parsed=parseTargetPrefix({raw:params.raw,prefix:entry.prefix,kind:entry.kind});if(parsed)return parsed}}function requireTargetKind(params){let kindLabel=params.kind;if(!params.target)throw Error(`${params.platform} ${kindLabel} id is required.`);if(params.target.kind!==params.kind)throw Error(`${params.platform} ${kindLabel} id is required (use ${kindLabel}:<id>).`);return params.target.id}function parseSlackTarget(raw,options={}){let trimmed=raw.trim();return trimmed?parseTargetMention({raw:trimmed,mentionPattern:/^<@([A-Z0-9]+)>$/i,kind:`user`})||parseTargetPrefixes({raw:trimmed,prefixes:[{prefix:`user:`,kind:`user`},{prefix:`channel:`,kind:`channel`},{prefix:`slack:`,kind:`user`}]})||(trimmed.startsWith(`@`)?buildMessagingTarget(`user`,ensureTargetId({candidate:trimmed.slice(1).trim(),pattern:/^[A-Z0-9]+$/i,errorMessage:`Slack DMs require a user id (use user:<id> or <@id>)`}),trimmed):trimmed.startsWith(`#`)?buildMessagingTarget(`channel`,ensureTargetId({candidate:trimmed.slice(1).trim(),pattern:/^[A-Z0-9]+$/i,errorMessage:`Slack channels require a channel id (use channel:<id>)`}),trimmed):options.defaultKind?buildMessagingTarget(options.defaultKind,trimmed,trimmed):buildMessagingTarget(`channel`,trimmed,trimmed)):void 0}function resolveSlackChannelId(raw){return requireTargetKind({platform:`Slack`,target:parseSlackTarget(raw,{defaultKind:`channel`}),kind:`channel`})}function normalizeSlackMessagingTarget(raw){return parseSlackTarget(raw,{defaultKind:`channel`})?.normalized}function looksLikeSlackTargetId(raw){let trimmed=raw.trim();return trimmed?/^<@([A-Z0-9]+)>$/i.test(trimmed)||/^(user|channel):/i.test(trimmed)||/^slack:/i.test(trimmed)||/^[@#]/.test(trimmed)?!0:/^[CUWGD][A-Z0-9]{8,}$/i.test(trimmed):!1}function addAllowFromAndDmsIds(ids,allowFrom,dms){for(let entry of allowFrom??[]){let raw=String(entry).trim();!raw||raw===`*`||ids.add(raw)}for(let id of Object.keys(dms??{})){let trimmed=id.trim();trimmed&&ids.add(trimmed)}}function resolveDirectoryQuery(query){return query?.trim().toLowerCase()||``}function resolveDirectoryLimit(limit){return typeof limit==`number`&&limit>0?limit:void 0}function applyDirectoryQueryAndLimit(ids,params){let q=resolveDirectoryQuery(params.query),limit=resolveDirectoryLimit(params.limit),filtered=ids.filter(id=>q?id.toLowerCase().includes(q):!0);return typeof limit==`number`?filtered.slice(0,limit):filtered}function toDirectoryEntries(kind,ids){return ids.map(id=>({kind,id}))}async function listSlackDirectoryPeersFromConfig(params){let account=resolveSlackAccount({cfg:params.cfg,accountId:params.accountId}),ids=new Set;addAllowFromAndDmsIds(ids,account.config.allowFrom??account.dm?.allowFrom,account.config.dms);for(let channel of Object.values(account.config.channels??{}))for(let user of channel.users??[]){let raw=String(user).trim();raw&&ids.add(raw)}return toDirectoryEntries(`user`,applyDirectoryQueryAndLimit(Array.from(ids).map(raw=>raw.trim()).filter(Boolean).map(raw=>{let normalizedUserId=(raw.match(/^<@([A-Z0-9]+)>$/i)?.[1]??raw).replace(/^(slack|user):/i,``).trim();if(!normalizedUserId)return null;let target=`user:${normalizedUserId}`;return normalizeSlackMessagingTarget(target)??target.toLowerCase()}).filter(id=>!!id).filter(id=>id.startsWith(`user:`)),params))}async function listSlackDirectoryGroupsFromConfig(params){let account=resolveSlackAccount({cfg:params.cfg,accountId:params.accountId});return toDirectoryEntries(`group`,applyDirectoryQueryAndLimit(Object.keys(account.config.channels??{}).map(raw=>raw.trim()).filter(Boolean).map(raw=>normalizeSlackMessagingTarget(raw)??raw.toLowerCase()).filter(id=>id.startsWith(`channel:`)),params))}async function listDiscordDirectoryPeersFromConfig(params){let account=resolveDiscordAccount({cfg:params.cfg,accountId:params.accountId}),ids=new Set;addAllowFromAndDmsIds(ids,account.config.allowFrom??account.config.dm?.allowFrom,account.config.dms);for(let guild of Object.values(account.config.guilds??{})){for(let entry of guild.users??[]){let raw=String(entry).trim();raw&&ids.add(raw)}for(let channel of Object.values(guild.channels??{}))for(let user of channel.users??[]){let raw=String(user).trim();raw&&ids.add(raw)}}return toDirectoryEntries(`user`,applyDirectoryQueryAndLimit(Array.from(ids).map(raw=>raw.trim()).filter(Boolean).map(raw=>{let cleaned=(raw.match(/^<@!?(\d+)>$/)?.[1]??raw).replace(/^(discord|user):/i,``).trim();return/^\d+$/.test(cleaned)?`user:${cleaned}`:null}).filter(id=>!!id),params))}async function listDiscordDirectoryGroupsFromConfig(params){let account=resolveDiscordAccount({cfg:params.cfg,accountId:params.accountId}),ids=new Set;for(let guild of Object.values(account.config.guilds??{}))for(let channelId of Object.keys(guild.channels??{})){let trimmed=channelId.trim();trimmed&&ids.add(trimmed)}return toDirectoryEntries(`group`,applyDirectoryQueryAndLimit(Array.from(ids).map(raw=>raw.trim()).filter(Boolean).map(raw=>{let cleaned=(raw.match(/^<#(\d+)>$/)?.[1]??raw).replace(/^(discord|channel|group):/i,``).trim();return/^\d+$/.test(cleaned)?`channel:${cleaned}`:null}).filter(id=>!!id),params))}async function listTelegramDirectoryPeersFromConfig(params){let account=resolveTelegramAccount({cfg:params.cfg,accountId:params.accountId}),raw=[...(account.config.allowFrom??[]).map(entry=>String(entry)),...Object.keys(account.config.dms??{})];return toDirectoryEntries(`user`,applyDirectoryQueryAndLimit(Array.from(new Set(raw.map(entry=>entry.trim()).filter(Boolean).map(entry=>entry.replace(/^(telegram|tg):/i,``)))).map(entry=>{let trimmed=entry.trim();return trimmed?/^-?\d+$/.test(trimmed)||trimmed.startsWith(`@`)?trimmed:`@${trimmed}`:null}).filter(id=>!!id),params))}async function listTelegramDirectoryGroupsFromConfig(params){let account=resolveTelegramAccount({cfg:params.cfg,accountId:params.accountId});return toDirectoryEntries(`group`,applyDirectoryQueryAndLimit(Object.keys(account.config.groups??{}).map(id=>id.trim()).filter(id=>!!id&&id!==`*`),params))}async function listWhatsAppDirectoryPeersFromConfig(params){return toDirectoryEntries(`user`,applyDirectoryQueryAndLimit((resolveWhatsAppAccount({cfg:params.cfg,accountId:params.accountId}).allowFrom??[]).map(entry=>String(entry).trim()).filter(entry=>!!entry&&entry!==`*`).map(entry=>normalizeWhatsAppTarget(entry)??``).filter(Boolean).filter(id=>!isWhatsAppGroupJid(id)),params))}async function listWhatsAppDirectoryGroupsFromConfig(params){let account=resolveWhatsAppAccount({cfg:params.cfg,accountId:params.accountId});return toDirectoryEntries(`group`,applyDirectoryQueryAndLimit(Object.keys(account.groups??{}).map(id=>id.trim()).filter(id=>!!id&&id!==`*`),params))}function listPluginChannels(){return requireActivePluginRegistry().channels.map(entry=>entry.plugin)}function dedupeChannels(channels){let seen=new Set,resolved=[];for(let plugin of channels){let id=String(plugin.id).trim();!id||seen.has(id)||(seen.add(id),resolved.push(plugin))}return resolved}function listChannelPlugins(){return dedupeChannels(listPluginChannels()).toSorted((a,b)=>{let indexA=CHAT_CHANNEL_ORDER.indexOf(a.id),indexB=CHAT_CHANNEL_ORDER.indexOf(b.id),orderA=a.meta.order??(indexA===-1?999:indexA),orderB=b.meta.order??(indexB===-1?999:indexB);return orderA===orderB?a.id.localeCompare(b.id):orderA-orderB})}function getChannelPlugin(id){let resolvedId=String(id).trim();if(resolvedId)return listChannelPlugins().find(plugin=>plugin.id===resolvedId)}function normalizeChannelId(raw){return normalizeAnyChannelId(raw)}export{listSlackAccountIds as A,resolveDiscordAccount as B,createTelegramActionGate as C,resolveTelegramAccount as D,resolveDefaultTelegramAccountId as E,resolveSlackBotToken as F,createDiscordActionGate as I,listDiscordAccountIds as L,resolveSlackAccount as M,resolveSlackReplyToMode as N,resolveTelegramToken as O,resolveSlackAppToken as P,listEnabledDiscordAccounts as R,normalizeWhatsAppTarget as S,listTelegramAccountIds as T,normalizeDiscordToken as V,ensureTargetId as _,listDiscordDirectoryPeersFromConfig as a,requireTargetKind as b,listTelegramDirectoryGroupsFromConfig as c,listWhatsAppDirectoryPeersFromConfig as d,looksLikeSlackTargetId as f,buildMessagingTarget as g,resolveSlackChannelId as h,listDiscordDirectoryGroupsFromConfig as i,resolveDefaultSlackAccountId as j,listEnabledSlackAccounts as k,listTelegramDirectoryPeersFromConfig as l,parseSlackTarget as m,listChannelPlugins as n,listSlackDirectoryGroupsFromConfig as o,normalizeSlackMessagingTarget as p,normalizeChannelId as r,listSlackDirectoryPeersFromConfig as s,getChannelPlugin as t,listWhatsAppDirectoryGroupsFromConfig as u,parseTargetMention as v,listEnabledTelegramAccounts as w,isWhatsAppGroupJid as x,parseTargetPrefixes as y,resolveDefaultDiscordAccountId as z};
1
+ import{c as normalizeAccountId,t as DEFAULT_ACCOUNT_ID}from"./session-key-5J69DULS.js";import{_ as createAccountListHelpers,r as resolveWhatsAppAccount}from"./accounts-Cy3WCbWg.js";import{D as normalizeE164,c as requireActivePluginRegistry,i as normalizeAnyChannelId,n as CHAT_CHANNEL_ORDER}from"./registry-CZHRcH-q.js";import{r as isTruthyEnvValue}from"./command-format-B3XMq_73.js";import{t as normalizeChatType}from"./chat-type-Dv7EB0qD.js";import{n as listBoundAccountIds,r as resolveDefaultAgentBoundAccountId}from"./bindings-CH-YLOLC.js";import fs from"node:fs";function createAccountActionGate(params){return(key,defaultValue=!0)=>{let accountValue=params.accountActions?.[key];if(accountValue!==void 0)return accountValue;let baseValue=params.baseActions?.[key];return baseValue===void 0?defaultValue:baseValue}}function normalizeDiscordToken(raw){if(!raw)return;let trimmed=raw.trim();if(trimmed)return trimmed.replace(/^Bot\s+/i,``)}function resolveDiscordToken(cfg,opts={}){let accountId=normalizeAccountId(opts.accountId),discordCfg=cfg?.channels?.discord,accountToken=normalizeDiscordToken((accountId===DEFAULT_ACCOUNT_ID?discordCfg?.accounts?.[DEFAULT_ACCOUNT_ID]:discordCfg?.accounts?.[accountId])?.token??void 0);if(accountToken)return{token:accountToken,source:`config`};let allowEnv=accountId===DEFAULT_ACCOUNT_ID,configToken=allowEnv?normalizeDiscordToken(discordCfg?.token??void 0):void 0;if(configToken)return{token:configToken,source:`config`};let envToken=allowEnv?normalizeDiscordToken(opts.envToken??process.env.DISCORD_BOT_TOKEN):void 0;return envToken?{token:envToken,source:`env`}:{token:``,source:`none`}}const{listAccountIds:listAccountIds$1,resolveDefaultAccountId:resolveDefaultAccountId$1}=createAccountListHelpers(`discord`),listDiscordAccountIds=listAccountIds$1,resolveDefaultDiscordAccountId=resolveDefaultAccountId$1;function resolveAccountConfig$2(cfg,accountId){let accounts=cfg.channels?.discord?.accounts;if(!(!accounts||typeof accounts!=`object`))return accounts[accountId]}function mergeDiscordAccountConfig(cfg,accountId){let{accounts:_ignored,...base}=cfg.channels?.discord??{},account=resolveAccountConfig$2(cfg,accountId)??{};return{...base,...account}}function createDiscordActionGate(params){let accountId=normalizeAccountId(params.accountId);return createAccountActionGate({baseActions:params.cfg.channels?.discord?.actions,accountActions:resolveAccountConfig$2(params.cfg,accountId)?.actions})}function resolveDiscordAccount(params){let accountId=normalizeAccountId(params.accountId),baseEnabled=params.cfg.channels?.discord?.enabled!==!1,merged=mergeDiscordAccountConfig(params.cfg,accountId),accountEnabled=merged.enabled!==!1,enabled=baseEnabled&&accountEnabled,tokenResolution=resolveDiscordToken(params.cfg,{accountId});return{accountId,enabled,name:merged.name?.trim()||void 0,token:tokenResolution.token,tokenSource:tokenResolution.source,config:merged}}function listEnabledDiscordAccounts(cfg){return listDiscordAccountIds(cfg).map(accountId=>resolveDiscordAccount({cfg,accountId})).filter(account=>account.enabled)}function normalizeSlackToken(raw){return raw?.trim()||void 0}function resolveSlackBotToken(raw){return normalizeSlackToken(raw)}function resolveSlackAppToken(raw){return normalizeSlackToken(raw)}const{listAccountIds,resolveDefaultAccountId}=createAccountListHelpers(`slack`),listSlackAccountIds=listAccountIds,resolveDefaultSlackAccountId=resolveDefaultAccountId;function resolveAccountConfig$1(cfg,accountId){let accounts=cfg.channels?.slack?.accounts;if(!(!accounts||typeof accounts!=`object`))return accounts[accountId]}function mergeSlackAccountConfig(cfg,accountId){let{accounts:_ignored,...base}=cfg.channels?.slack??{},account=resolveAccountConfig$1(cfg,accountId)??{};return{...base,...account}}function resolveSlackAccount(params){let accountId=normalizeAccountId(params.accountId),baseEnabled=params.cfg.channels?.slack?.enabled!==!1,merged=mergeSlackAccountConfig(params.cfg,accountId),accountEnabled=merged.enabled!==!1,enabled=baseEnabled&&accountEnabled,allowEnv=accountId===DEFAULT_ACCOUNT_ID,envBot=allowEnv?resolveSlackBotToken(process.env.SLACK_BOT_TOKEN):void 0,envApp=allowEnv?resolveSlackAppToken(process.env.SLACK_APP_TOKEN):void 0,configBot=resolveSlackBotToken(merged.botToken),configApp=resolveSlackAppToken(merged.appToken),botToken=configBot??envBot,appToken=configApp??envApp,botTokenSource=configBot?`config`:envBot?`env`:`none`,appTokenSource=configApp?`config`:envApp?`env`:`none`;return{accountId,enabled,name:merged.name?.trim()||void 0,botToken,appToken,botTokenSource,appTokenSource,config:merged,groupPolicy:merged.groupPolicy,textChunkLimit:merged.textChunkLimit,mediaMaxMb:merged.mediaMaxMb,reactionNotifications:merged.reactionNotifications,reactionAllowlist:merged.reactionAllowlist,replyToMode:merged.replyToMode,replyToModeByChatType:merged.replyToModeByChatType,actions:merged.actions,slashCommand:merged.slashCommand,dm:merged.dm,channels:merged.channels}}function listEnabledSlackAccounts(cfg){return listSlackAccountIds(cfg).map(accountId=>resolveSlackAccount({cfg,accountId})).filter(account=>account.enabled)}function resolveSlackReplyToMode(account,chatType){let normalized=normalizeChatType(chatType??void 0);return normalized&&account.replyToModeByChatType?.[normalized]!==void 0?account.replyToModeByChatType[normalized]??`off`:normalized===`direct`&&account.dm?.replyToMode!==void 0?account.dm.replyToMode:account.replyToMode??`off`}function resolveTelegramToken(cfg,opts={}){let accountId=normalizeAccountId(opts.accountId),telegramCfg=cfg?.channels?.telegram,accountCfg=(id=>{let accounts=telegramCfg?.accounts;if(!accounts||typeof accounts!=`object`||Array.isArray(accounts))return;let direct=accounts[id];if(direct)return direct;let matchKey=Object.keys(accounts).find(key=>normalizeAccountId(key)===id);return matchKey?accounts[matchKey]:void 0})(accountId===DEFAULT_ACCOUNT_ID?DEFAULT_ACCOUNT_ID:accountId),accountTokenFile=accountCfg?.tokenFile?.trim();if(accountTokenFile){if(!fs.existsSync(accountTokenFile))return opts.logMissingFile?.(`channels.telegram.accounts.${accountId}.tokenFile not found: ${accountTokenFile}`),{token:``,source:`none`};try{let token=fs.readFileSync(accountTokenFile,`utf-8`).trim();if(token)return{token,source:`tokenFile`}}catch(err){return opts.logMissingFile?.(`channels.telegram.accounts.${accountId}.tokenFile read failed: ${String(err)}`),{token:``,source:`none`}}return{token:``,source:`none`}}let accountToken=accountCfg?.botToken?.trim();if(accountToken)return{token:accountToken,source:`config`};let allowEnv=accountId===DEFAULT_ACCOUNT_ID,tokenFile=telegramCfg?.tokenFile?.trim();if(tokenFile&&allowEnv){if(!fs.existsSync(tokenFile))return opts.logMissingFile?.(`channels.telegram.tokenFile not found: ${tokenFile}`),{token:``,source:`none`};try{let token=fs.readFileSync(tokenFile,`utf-8`).trim();if(token)return{token,source:`tokenFile`}}catch(err){return opts.logMissingFile?.(`channels.telegram.tokenFile read failed: ${String(err)}`),{token:``,source:`none`}}}let configToken=telegramCfg?.botToken?.trim();if(configToken&&allowEnv)return{token:configToken,source:`config`};let envToken=allowEnv?(opts.envToken??process.env.TELEGRAM_BOT_TOKEN)?.trim():``;return envToken?{token:envToken,source:`env`}:{token:``,source:`none`}}const debugAccounts=(...args)=>{isTruthyEnvValue(process.env.BUILDERFORCE_AGENTS_DEBUG_TELEGRAM_ACCOUNTS)&&console.warn(`[telegram:accounts]`,...args)};function listConfiguredAccountIds(cfg){let accounts=cfg.channels?.telegram?.accounts;if(!accounts||typeof accounts!=`object`)return[];let ids=new Set;for(let key of Object.keys(accounts))key&&ids.add(normalizeAccountId(key));return[...ids]}function listTelegramAccountIds(cfg){let ids=Array.from(new Set([...listConfiguredAccountIds(cfg),...listBoundAccountIds(cfg,`telegram`)]));return debugAccounts(`listTelegramAccountIds`,ids),ids.length===0?[DEFAULT_ACCOUNT_ID]:ids.toSorted((a,b)=>a.localeCompare(b))}function resolveDefaultTelegramAccountId(cfg){let boundDefault=resolveDefaultAgentBoundAccountId(cfg,`telegram`);if(boundDefault)return boundDefault;let ids=listTelegramAccountIds(cfg);return ids.includes(DEFAULT_ACCOUNT_ID)?DEFAULT_ACCOUNT_ID:ids[0]??DEFAULT_ACCOUNT_ID}function resolveAccountConfig(cfg,accountId){let accounts=cfg.channels?.telegram?.accounts;if(!accounts||typeof accounts!=`object`)return;let direct=accounts[accountId];if(direct)return direct;let normalized=normalizeAccountId(accountId),matchKey=Object.keys(accounts).find(key=>normalizeAccountId(key)===normalized);return matchKey?accounts[matchKey]:void 0}function mergeTelegramAccountConfig(cfg,accountId){let{accounts:_ignored,...base}=cfg.channels?.telegram??{},account=resolveAccountConfig(cfg,accountId)??{};return{...base,...account}}function createTelegramActionGate(params){let accountId=normalizeAccountId(params.accountId);return createAccountActionGate({baseActions:params.cfg.channels?.telegram?.actions,accountActions:resolveAccountConfig(params.cfg,accountId)?.actions})}function resolveTelegramAccount(params){let hasExplicitAccountId=!!params.accountId?.trim(),baseEnabled=params.cfg.channels?.telegram?.enabled!==!1,resolve=accountId=>{let merged=mergeTelegramAccountConfig(params.cfg,accountId),accountEnabled=merged.enabled!==!1,enabled=baseEnabled&&accountEnabled,tokenResolution=resolveTelegramToken(params.cfg,{accountId});return debugAccounts(`resolve`,{accountId,enabled,tokenSource:tokenResolution.source}),{accountId,enabled,name:merged.name?.trim()||void 0,token:tokenResolution.token,tokenSource:tokenResolution.source,config:merged}},primary=resolve(normalizeAccountId(params.accountId));if(hasExplicitAccountId||primary.tokenSource!==`none`)return primary;let fallbackId=resolveDefaultTelegramAccountId(params.cfg);if(fallbackId===primary.accountId)return primary;let fallback=resolve(fallbackId);return fallback.tokenSource===`none`?primary:fallback}function listEnabledTelegramAccounts(cfg){return listTelegramAccountIds(cfg).map(accountId=>resolveTelegramAccount({cfg,accountId})).filter(account=>account.enabled)}const WHATSAPP_USER_JID_RE=/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i,WHATSAPP_LID_RE=/^(\d+)@lid$/i;function stripWhatsAppTargetPrefixes(value){let candidate=value.trim();for(;;){let before=candidate;if(candidate=candidate.replace(/^whatsapp:/i,``).trim(),candidate===before)return candidate}}function isWhatsAppGroupJid(value){let candidate=stripWhatsAppTargetPrefixes(value);if(!candidate.toLowerCase().endsWith(`@g.us`))return!1;let localPart=candidate.slice(0,candidate.length-5);return!localPart||localPart.includes(`@`)?!1:/^[0-9]+(-[0-9]+)*$/.test(localPart)}function isWhatsAppUserTarget(value){let candidate=stripWhatsAppTargetPrefixes(value);return WHATSAPP_USER_JID_RE.test(candidate)||WHATSAPP_LID_RE.test(candidate)}function extractUserJidPhone(jid){let userMatch=jid.match(WHATSAPP_USER_JID_RE);if(userMatch)return userMatch[1];let lidMatch=jid.match(WHATSAPP_LID_RE);return lidMatch?lidMatch[1]:null}function normalizeWhatsAppTarget(value){let candidate=stripWhatsAppTargetPrefixes(value);if(!candidate)return null;if(isWhatsAppGroupJid(candidate))return`${candidate.slice(0,candidate.length-5)}@g.us`;if(isWhatsAppUserTarget(candidate)){let phone=extractUserJidPhone(candidate);if(!phone)return null;let normalized=normalizeE164(phone);return normalized.length>1?normalized:null}if(candidate.includes(`@`))return null;let normalized=normalizeE164(candidate);return normalized.length>1?normalized:null}function normalizeTargetId(kind,id){return`${kind}:${id}`.toLowerCase()}function buildMessagingTarget(kind,id,raw){return{kind,id,raw,normalized:normalizeTargetId(kind,id)}}function ensureTargetId(params){if(!params.pattern.test(params.candidate))throw Error(params.errorMessage);return params.candidate}function parseTargetMention(params){let match=params.raw.match(params.mentionPattern);if(match?.[1])return buildMessagingTarget(params.kind,match[1],params.raw)}function parseTargetPrefix(params){if(!params.raw.startsWith(params.prefix))return;let id=params.raw.slice(params.prefix.length).trim();return id?buildMessagingTarget(params.kind,id,params.raw):void 0}function parseTargetPrefixes(params){for(let entry of params.prefixes){let parsed=parseTargetPrefix({raw:params.raw,prefix:entry.prefix,kind:entry.kind});if(parsed)return parsed}}function requireTargetKind(params){let kindLabel=params.kind;if(!params.target)throw Error(`${params.platform} ${kindLabel} id is required.`);if(params.target.kind!==params.kind)throw Error(`${params.platform} ${kindLabel} id is required (use ${kindLabel}:<id>).`);return params.target.id}function parseSlackTarget(raw,options={}){let trimmed=raw.trim();return trimmed?parseTargetMention({raw:trimmed,mentionPattern:/^<@([A-Z0-9]+)>$/i,kind:`user`})||parseTargetPrefixes({raw:trimmed,prefixes:[{prefix:`user:`,kind:`user`},{prefix:`channel:`,kind:`channel`},{prefix:`slack:`,kind:`user`}]})||(trimmed.startsWith(`@`)?buildMessagingTarget(`user`,ensureTargetId({candidate:trimmed.slice(1).trim(),pattern:/^[A-Z0-9]+$/i,errorMessage:`Slack DMs require a user id (use user:<id> or <@id>)`}),trimmed):trimmed.startsWith(`#`)?buildMessagingTarget(`channel`,ensureTargetId({candidate:trimmed.slice(1).trim(),pattern:/^[A-Z0-9]+$/i,errorMessage:`Slack channels require a channel id (use channel:<id>)`}),trimmed):options.defaultKind?buildMessagingTarget(options.defaultKind,trimmed,trimmed):buildMessagingTarget(`channel`,trimmed,trimmed)):void 0}function resolveSlackChannelId(raw){return requireTargetKind({platform:`Slack`,target:parseSlackTarget(raw,{defaultKind:`channel`}),kind:`channel`})}function normalizeSlackMessagingTarget(raw){return parseSlackTarget(raw,{defaultKind:`channel`})?.normalized}function looksLikeSlackTargetId(raw){let trimmed=raw.trim();return trimmed?/^<@([A-Z0-9]+)>$/i.test(trimmed)||/^(user|channel):/i.test(trimmed)||/^slack:/i.test(trimmed)||/^[@#]/.test(trimmed)?!0:/^[CUWGD][A-Z0-9]{8,}$/i.test(trimmed):!1}function addAllowFromAndDmsIds(ids,allowFrom,dms){for(let entry of allowFrom??[]){let raw=String(entry).trim();!raw||raw===`*`||ids.add(raw)}for(let id of Object.keys(dms??{})){let trimmed=id.trim();trimmed&&ids.add(trimmed)}}function resolveDirectoryQuery(query){return query?.trim().toLowerCase()||``}function resolveDirectoryLimit(limit){return typeof limit==`number`&&limit>0?limit:void 0}function applyDirectoryQueryAndLimit(ids,params){let q=resolveDirectoryQuery(params.query),limit=resolveDirectoryLimit(params.limit),filtered=ids.filter(id=>q?id.toLowerCase().includes(q):!0);return typeof limit==`number`?filtered.slice(0,limit):filtered}function toDirectoryEntries(kind,ids){return ids.map(id=>({kind,id}))}async function listSlackDirectoryPeersFromConfig(params){let account=resolveSlackAccount({cfg:params.cfg,accountId:params.accountId}),ids=new Set;addAllowFromAndDmsIds(ids,account.config.allowFrom??account.dm?.allowFrom,account.config.dms);for(let channel of Object.values(account.config.channels??{}))for(let user of channel.users??[]){let raw=String(user).trim();raw&&ids.add(raw)}return toDirectoryEntries(`user`,applyDirectoryQueryAndLimit(Array.from(ids).map(raw=>raw.trim()).filter(Boolean).map(raw=>{let normalizedUserId=(raw.match(/^<@([A-Z0-9]+)>$/i)?.[1]??raw).replace(/^(slack|user):/i,``).trim();if(!normalizedUserId)return null;let target=`user:${normalizedUserId}`;return normalizeSlackMessagingTarget(target)??target.toLowerCase()}).filter(id=>!!id).filter(id=>id.startsWith(`user:`)),params))}async function listSlackDirectoryGroupsFromConfig(params){let account=resolveSlackAccount({cfg:params.cfg,accountId:params.accountId});return toDirectoryEntries(`group`,applyDirectoryQueryAndLimit(Object.keys(account.config.channels??{}).map(raw=>raw.trim()).filter(Boolean).map(raw=>normalizeSlackMessagingTarget(raw)??raw.toLowerCase()).filter(id=>id.startsWith(`channel:`)),params))}async function listDiscordDirectoryPeersFromConfig(params){let account=resolveDiscordAccount({cfg:params.cfg,accountId:params.accountId}),ids=new Set;addAllowFromAndDmsIds(ids,account.config.allowFrom??account.config.dm?.allowFrom,account.config.dms);for(let guild of Object.values(account.config.guilds??{})){for(let entry of guild.users??[]){let raw=String(entry).trim();raw&&ids.add(raw)}for(let channel of Object.values(guild.channels??{}))for(let user of channel.users??[]){let raw=String(user).trim();raw&&ids.add(raw)}}return toDirectoryEntries(`user`,applyDirectoryQueryAndLimit(Array.from(ids).map(raw=>raw.trim()).filter(Boolean).map(raw=>{let cleaned=(raw.match(/^<@!?(\d+)>$/)?.[1]??raw).replace(/^(discord|user):/i,``).trim();return/^\d+$/.test(cleaned)?`user:${cleaned}`:null}).filter(id=>!!id),params))}async function listDiscordDirectoryGroupsFromConfig(params){let account=resolveDiscordAccount({cfg:params.cfg,accountId:params.accountId}),ids=new Set;for(let guild of Object.values(account.config.guilds??{}))for(let channelId of Object.keys(guild.channels??{})){let trimmed=channelId.trim();trimmed&&ids.add(trimmed)}return toDirectoryEntries(`group`,applyDirectoryQueryAndLimit(Array.from(ids).map(raw=>raw.trim()).filter(Boolean).map(raw=>{let cleaned=(raw.match(/^<#(\d+)>$/)?.[1]??raw).replace(/^(discord|channel|group):/i,``).trim();return/^\d+$/.test(cleaned)?`channel:${cleaned}`:null}).filter(id=>!!id),params))}async function listTelegramDirectoryPeersFromConfig(params){let account=resolveTelegramAccount({cfg:params.cfg,accountId:params.accountId}),raw=[...(account.config.allowFrom??[]).map(entry=>String(entry)),...Object.keys(account.config.dms??{})];return toDirectoryEntries(`user`,applyDirectoryQueryAndLimit(Array.from(new Set(raw.map(entry=>entry.trim()).filter(Boolean).map(entry=>entry.replace(/^(telegram|tg):/i,``)))).map(entry=>{let trimmed=entry.trim();return trimmed?/^-?\d+$/.test(trimmed)||trimmed.startsWith(`@`)?trimmed:`@${trimmed}`:null}).filter(id=>!!id),params))}async function listTelegramDirectoryGroupsFromConfig(params){let account=resolveTelegramAccount({cfg:params.cfg,accountId:params.accountId});return toDirectoryEntries(`group`,applyDirectoryQueryAndLimit(Object.keys(account.config.groups??{}).map(id=>id.trim()).filter(id=>!!id&&id!==`*`),params))}async function listWhatsAppDirectoryPeersFromConfig(params){return toDirectoryEntries(`user`,applyDirectoryQueryAndLimit((resolveWhatsAppAccount({cfg:params.cfg,accountId:params.accountId}).allowFrom??[]).map(entry=>String(entry).trim()).filter(entry=>!!entry&&entry!==`*`).map(entry=>normalizeWhatsAppTarget(entry)??``).filter(Boolean).filter(id=>!isWhatsAppGroupJid(id)),params))}async function listWhatsAppDirectoryGroupsFromConfig(params){let account=resolveWhatsAppAccount({cfg:params.cfg,accountId:params.accountId});return toDirectoryEntries(`group`,applyDirectoryQueryAndLimit(Object.keys(account.groups??{}).map(id=>id.trim()).filter(id=>!!id&&id!==`*`),params))}function listPluginChannels(){return requireActivePluginRegistry().channels.map(entry=>entry.plugin)}function dedupeChannels(channels){let seen=new Set,resolved=[];for(let plugin of channels){let id=String(plugin.id).trim();!id||seen.has(id)||(seen.add(id),resolved.push(plugin))}return resolved}function listChannelPlugins(){return dedupeChannels(listPluginChannels()).toSorted((a,b)=>{let indexA=CHAT_CHANNEL_ORDER.indexOf(a.id),indexB=CHAT_CHANNEL_ORDER.indexOf(b.id),orderA=a.meta.order??(indexA===-1?999:indexA),orderB=b.meta.order??(indexB===-1?999:indexB);return orderA===orderB?a.id.localeCompare(b.id):orderA-orderB})}function getChannelPlugin(id){let resolvedId=String(id).trim();if(resolvedId)return listChannelPlugins().find(plugin=>plugin.id===resolvedId)}function normalizeChannelId(raw){return normalizeAnyChannelId(raw)}export{listSlackAccountIds as A,resolveDiscordAccount as B,createTelegramActionGate as C,resolveTelegramAccount as D,resolveDefaultTelegramAccountId as E,resolveSlackBotToken as F,createDiscordActionGate as I,listDiscordAccountIds as L,resolveSlackAccount as M,resolveSlackReplyToMode as N,resolveTelegramToken as O,resolveSlackAppToken as P,listEnabledDiscordAccounts as R,normalizeWhatsAppTarget as S,listTelegramAccountIds as T,normalizeDiscordToken as V,ensureTargetId as _,listDiscordDirectoryPeersFromConfig as a,requireTargetKind as b,listTelegramDirectoryGroupsFromConfig as c,listWhatsAppDirectoryPeersFromConfig as d,looksLikeSlackTargetId as f,buildMessagingTarget as g,resolveSlackChannelId as h,listDiscordDirectoryGroupsFromConfig as i,resolveDefaultSlackAccountId as j,listEnabledSlackAccounts as k,listTelegramDirectoryPeersFromConfig as l,parseSlackTarget as m,listChannelPlugins as n,listSlackDirectoryGroupsFromConfig as o,normalizeSlackMessagingTarget as p,normalizeChannelId as r,listSlackDirectoryPeersFromConfig as s,getChannelPlugin as t,listWhatsAppDirectoryGroupsFromConfig as u,parseTargetMention as v,listEnabledTelegramAccounts as w,isWhatsAppGroupJid as x,parseTargetPrefixes as y,resolveDefaultDiscordAccountId as z};
@@ -1,4 +1,4 @@
1
- import"./session-key-5J69DULS.js";import"./registry-DJq2Cvo9.js";import"./paths-Cb8zTlyG.js";import{mt as normalizeBaseUrl}from"./model-selection-Crz-xYNU.js";import"./config-3vPn_hmp.js";import"./subsystem-COTa5Ly_.js";import"./agent-scope-BQByW0cD.js";import"./redact-Bv8wnIZm.js";import{n as formatErrorMessage}from"./errors-L3rugjUL.js";import{_ as withCdpSocket,d as normalizeCdpWsUrl,g as getHeadersWithAuth,j as resolvePreferredBuilderForceAgentsTmpDir,m as fetchJson,p as appendCdpPath,t as getChromeWebSocketUrl,u as formatAriaSnapshot}from"./chrome-DriEqJRH.js";import{t as formatCliCommand}from"./command-format-CAX9XFjI.js";import"./src-5XE2oMwl.js";import path from"node:path";import crypto from"node:crypto";import fs from"node:fs/promises";import{chromium,devices}from"playwright-core";const pageStates=new WeakMap,contextStates=new WeakMap,observedContexts=new WeakSet,observedPages=new WeakSet,roleRefsByTarget=new Map;let cached=null,connecting=null;function normalizeCdpUrl(raw){return raw.replace(/\/$/,``)}function findNetworkRequestById(state,id){for(let i=state.requests.length-1;i>=0;--i){let candidate=state.requests[i];if(candidate&&candidate.id===id)return candidate}}function roleRefsKey(cdpUrl,targetId){return`${normalizeCdpUrl(cdpUrl)}::${targetId}`}function rememberRoleRefsForTarget(opts){let targetId=opts.targetId.trim();if(targetId)for(roleRefsByTarget.set(roleRefsKey(opts.cdpUrl,targetId),{refs:opts.refs,...opts.frameSelector?{frameSelector:opts.frameSelector}:{},...opts.mode?{mode:opts.mode}:{}});roleRefsByTarget.size>50;){let first=roleRefsByTarget.keys().next();if(first.done)break;roleRefsByTarget.delete(first.value)}}function storeRoleRefsForTarget(opts){let state=ensurePageState(opts.page);state.roleRefs=opts.refs,state.roleRefsFrameSelector=opts.frameSelector,state.roleRefsMode=opts.mode,opts.targetId?.trim()&&rememberRoleRefsForTarget({cdpUrl:opts.cdpUrl,targetId:opts.targetId,refs:opts.refs,frameSelector:opts.frameSelector,mode:opts.mode})}function restoreRoleRefsForTarget(opts){let targetId=opts.targetId?.trim()||``;if(!targetId)return;let cached=roleRefsByTarget.get(roleRefsKey(opts.cdpUrl,targetId));if(!cached)return;let state=ensurePageState(opts.page);state.roleRefs||(state.roleRefs=cached.refs,state.roleRefsFrameSelector=cached.frameSelector,state.roleRefsMode=cached.mode)}function ensurePageState(page){let existing=pageStates.get(page);if(existing)return existing;let state={console:[],errors:[],requests:[],requestIds:new WeakMap,nextRequestId:0,armIdUpload:0,armIdDialog:0,armIdDownload:0};return pageStates.set(page,state),observedPages.has(page)||(observedPages.add(page),page.on(`console`,msg=>{let entry={type:msg.type(),text:msg.text(),timestamp:new Date().toISOString(),location:msg.location()};state.console.push(entry),state.console.length>500&&state.console.shift()}),page.on(`pageerror`,err=>{state.errors.push({message:err?.message?String(err.message):String(err),name:err?.name?String(err.name):void 0,stack:err?.stack?String(err.stack):void 0,timestamp:new Date().toISOString()}),state.errors.length>200&&state.errors.shift()}),page.on(`request`,req=>{state.nextRequestId+=1;let id=`r${state.nextRequestId}`;state.requestIds.set(req,id),state.requests.push({id,timestamp:new Date().toISOString(),method:req.method(),url:req.url(),resourceType:req.resourceType()}),state.requests.length>500&&state.requests.shift()}),page.on(`response`,resp=>{let req=resp.request(),id=state.requestIds.get(req);if(!id)return;let rec=findNetworkRequestById(state,id);rec&&(rec.status=resp.status(),rec.ok=resp.ok())}),page.on(`requestfailed`,req=>{let id=state.requestIds.get(req);if(!id)return;let rec=findNetworkRequestById(state,id);rec&&(rec.failureText=req.failure()?.errorText,rec.ok=!1)}),page.on(`close`,()=>{pageStates.delete(page),observedPages.delete(page)})),state}function observeContext(context){if(!observedContexts.has(context)){observedContexts.add(context),ensureContextState(context);for(let page of context.pages())ensurePageState(page);context.on(`page`,page=>ensurePageState(page))}}function ensureContextState(context){let existing=contextStates.get(context);if(existing)return existing;let state={traceActive:!1};return contextStates.set(context,state),state}function observeBrowser(browser){for(let context of browser.contexts())observeContext(context)}async function connectBrowser(cdpUrl){let normalized=normalizeCdpUrl(cdpUrl);return cached?.cdpUrl===normalized?cached:(connecting||=(async()=>{let lastErr;for(let attempt=0;attempt<3;attempt+=1)try{let timeout=5e3+attempt*2e3,endpoint=await getChromeWebSocketUrl(normalized,timeout).catch(()=>null)??normalized,headers=getHeadersWithAuth(endpoint),browser=await chromium.connectOverCDP(endpoint,{timeout,headers}),onDisconnected=()=>{cached?.browser===browser&&(cached=null)},connected={browser,cdpUrl:normalized,onDisconnected};return cached=connected,browser.on(`disconnected`,onDisconnected),observeBrowser(browser),connected}catch(err){lastErr=err;let delay=250+attempt*250;await new Promise(r=>setTimeout(r,delay))}if(lastErr instanceof Error)throw lastErr;let message=lastErr?formatErrorMessage(lastErr):`CDP connect failed`;throw Error(message)})().finally(()=>{connecting=null}),await connecting)}async function getAllPages(browser){return browser.contexts().flatMap(c=>c.pages())}async function pageTargetId(page){let session=await page.context().newCDPSession(page);try{let info=await session.send(`Target.getTargetInfo`);return String(info?.targetInfo?.targetId??``).trim()||null}finally{await session.detach().catch(()=>{})}}async function findPageByTargetId(browser,targetId,cdpUrl){let pages=await getAllPages(browser),resolvedViaCdp=!1;for(let page of pages){let tid=null;try{tid=await pageTargetId(page),resolvedViaCdp=!0}catch{tid=null}if(tid&&tid===targetId)return page}if(!resolvedViaCdp&&pages.length===1)return pages[0];if(cdpUrl)try{let listUrl=`${normalizeBaseUrl(cdpUrl).replace(/^ws:/,`http:`).replace(/\/cdp$/,``)}/json/list`,response=await fetch(listUrl,{headers:getHeadersWithAuth(listUrl)});if(response.ok){let targets=await response.json(),target=targets.find(t=>t.id===targetId);if(target){let urlMatch=pages.filter(p=>p.url()===target.url);if(urlMatch.length===1)return urlMatch[0];if(urlMatch.length>1){let sameUrlTargets=targets.filter(t=>t.url===target.url);if(sameUrlTargets.length===urlMatch.length){let idx=sameUrlTargets.findIndex(t=>t.id===targetId);if(idx>=0&&idx<urlMatch.length)return urlMatch[idx]}}}}}catch{}return null}async function getPageForTargetId(opts){let{browser}=await connectBrowser(opts.cdpUrl),pages=await getAllPages(browser);if(!pages.length)throw Error(`No pages available in the connected browser.`);let first=pages[0];if(!opts.targetId)return first;let found=await findPageByTargetId(browser,opts.targetId,opts.cdpUrl);if(!found){if(pages.length===1)return first;throw Error(`tab not found`)}return found}function refLocator(page,ref){let normalized=ref.startsWith(`@`)?ref.slice(1):ref.startsWith(`ref=`)?ref.slice(4):ref;if(/^e\d+$/.test(normalized)){let state=pageStates.get(page);if(state?.roleRefsMode===`aria`)return(state.roleRefsFrameSelector?page.frameLocator(state.roleRefsFrameSelector):page).locator(`aria-ref=${normalized}`);let info=state?.roleRefs?.[normalized];if(!info)throw Error(`Unknown ref "${normalized}". Run a new snapshot and use a ref from that snapshot.`);let locAny=state?.roleRefsFrameSelector?page.frameLocator(state.roleRefsFrameSelector):page,locator=info.name?locAny.getByRole(info.role,{name:info.name,exact:!0}):locAny.getByRole(info.role);return info.nth===void 0?locator:locator.nth(info.nth)}return page.locator(`aria-ref=${normalized}`)}async function closePlaywrightBrowserConnection(){let cur=cached;cached=null,connecting=null,cur&&(cur.onDisconnected&&typeof cur.browser.off==`function`&&cur.browser.off(`disconnected`,cur.onDisconnected),await cur.browser.close().catch(()=>{}))}function normalizeCdpHttpBaseForJsonEndpoints(cdpUrl){try{let url=new URL(cdpUrl);return url.protocol===`ws:`?url.protocol=`http:`:url.protocol===`wss:`&&(url.protocol=`https:`),url.pathname=url.pathname.replace(/\/devtools\/browser\/.*$/,``),url.pathname=url.pathname.replace(/\/cdp$/,``),url.toString().replace(/\/$/,``)}catch{return cdpUrl.replace(/^ws:/,`http:`).replace(/^wss:/,`https:`).replace(/\/devtools\/browser\/.*$/,``).replace(/\/cdp$/,``).replace(/\/$/,``)}}function cdpSocketNeedsAttach(wsUrl){try{let pathname=new URL(wsUrl).pathname;return pathname===`/cdp`||pathname.endsWith(`/cdp`)||pathname.includes(`/devtools/browser/`)}catch{return!1}}async function tryTerminateExecutionViaCdp(opts){let cdpHttpBase=normalizeCdpHttpBaseForJsonEndpoints(opts.cdpUrl),pages=await fetchJson(appendCdpPath(cdpHttpBase,`/json/list`),2e3).catch(()=>null);if(!pages||pages.length===0)return;let target=pages.find(p=>String(p.id??``).trim()===opts.targetId),wsUrlRaw=String(target?.webSocketDebuggerUrl??``).trim();if(!wsUrlRaw)return;let wsUrl=normalizeCdpWsUrl(wsUrlRaw,cdpHttpBase),needsAttach=cdpSocketNeedsAttach(wsUrl),runWithTimeout=async(work,ms)=>{let timer,timeoutPromise=new Promise((_,reject)=>{timer=setTimeout(()=>reject(Error(`CDP command timed out`)),ms)});try{return await Promise.race([work,timeoutPromise])}finally{timer&&clearTimeout(timer)}};await withCdpSocket(wsUrl,async send=>{let sessionId;try{if(needsAttach){let attached=await runWithTimeout(send(`Target.attachToTarget`,{targetId:opts.targetId,flatten:!0}),1500);typeof attached?.sessionId==`string`&&attached.sessionId.trim()&&(sessionId=attached.sessionId)}await runWithTimeout(send(`Runtime.terminateExecution`,void 0,sessionId),1500),sessionId&&send(`Target.detachFromTarget`,{sessionId}).catch(()=>{})}catch{}},{handshakeTimeoutMs:2e3}).catch(()=>{})}async function forceDisconnectPlaywrightForTarget(opts){let normalized=normalizeCdpUrl(opts.cdpUrl);if(cached?.cdpUrl!==normalized)return;let cur=cached;if(cached=null,connecting=null,cur){cur.onDisconnected&&typeof cur.browser.off==`function`&&cur.browser.off(`disconnected`,cur.onDisconnected);let targetId=opts.targetId?.trim()||``;targetId&&await tryTerminateExecutionViaCdp({cdpUrl:normalized,targetId}).catch(()=>{}),cur.browser.close().catch(()=>{})}}async function listPagesViaPlaywright(opts){let{browser}=await connectBrowser(opts.cdpUrl),pages=await getAllPages(browser),results=[];for(let page of pages){let tid=await pageTargetId(page).catch(()=>null);tid&&results.push({targetId:tid,title:await page.title().catch(()=>``),url:page.url(),type:`page`})}return results}async function createPageViaPlaywright(opts){let{browser}=await connectBrowser(opts.cdpUrl),context=browser.contexts()[0]??await browser.newContext();ensureContextState(context);let page=await context.newPage();ensurePageState(page);let targetUrl=opts.url.trim()||`about:blank`;targetUrl!==`about:blank`&&await page.goto(targetUrl,{timeout:3e4}).catch(()=>{});let tid=await pageTargetId(page).catch(()=>null);if(!tid)throw Error(`Failed to get targetId for new page`);return{targetId:tid,title:await page.title().catch(()=>``),url:page.url(),type:`page`}}async function closePageByTargetIdViaPlaywright(opts){let{browser}=await connectBrowser(opts.cdpUrl),page=await findPageByTargetId(browser,opts.targetId,opts.cdpUrl);if(!page)throw Error(`tab not found`);await page.close()}async function focusPageByTargetIdViaPlaywright(opts){let{browser}=await connectBrowser(opts.cdpUrl),page=await findPageByTargetId(browser,opts.targetId,opts.cdpUrl);if(!page)throw Error(`tab not found`);try{await page.bringToFront()}catch(err){let session=await page.context().newCDPSession(page);try{await session.send(`Page.bringToFront`);return}catch{throw err}finally{await session.detach().catch(()=>{})}}}async function getPageErrorsViaPlaywright(opts){let state=ensurePageState(await getPageForTargetId(opts)),errors=[...state.errors];return opts.clear&&(state.errors=[]),{errors}}async function getNetworkRequestsViaPlaywright(opts){let state=ensurePageState(await getPageForTargetId(opts)),raw=[...state.requests],filter=typeof opts.filter==`string`?opts.filter.trim():``,requests=filter?raw.filter(r=>r.url.includes(filter)):raw;return opts.clear&&(state.requests=[],state.requestIds=new WeakMap),{requests}}function consolePriority(level){switch(level){case`error`:return 3;case`warning`:return 2;case`info`:case`log`:return 1;case`debug`:return 0;default:return 1}}async function getConsoleMessagesViaPlaywright(opts){let state=ensurePageState(await getPageForTargetId(opts));if(!opts.level)return[...state.console];let min=consolePriority(opts.level);return state.console.filter(msg=>consolePriority(msg.type)>=min)}const INTERACTIVE_ROLES=new Set([`button`,`link`,`textbox`,`checkbox`,`radio`,`combobox`,`listbox`,`menuitem`,`menuitemcheckbox`,`menuitemradio`,`option`,`searchbox`,`slider`,`spinbutton`,`switch`,`tab`,`treeitem`]),CONTENT_ROLES=new Set([`heading`,`cell`,`gridcell`,`columnheader`,`rowheader`,`listitem`,`article`,`region`,`main`,`navigation`]),STRUCTURAL_ROLES=new Set([`generic`,`group`,`list`,`table`,`row`,`rowgroup`,`grid`,`treegrid`,`menu`,`menubar`,`toolbar`,`tablist`,`tree`,`directory`,`document`,`application`,`presentation`,`none`]);function getRoleSnapshotStats(snapshot,refs){let interactive=Object.values(refs).filter(r=>INTERACTIVE_ROLES.has(r.role)).length;return{lines:snapshot.split(`
1
+ import"./session-key-5J69DULS.js";import"./registry-CZHRcH-q.js";import"./paths-Cb8zTlyG.js";import{mt as normalizeBaseUrl}from"./model-selection-_H_U9jWH.js";import"./config--Ci8Y91R.js";import"./subsystem-D0Ril4rt.js";import"./agent-scope-DgKN27hJ.js";import"./redact-Bv8wnIZm.js";import{n as formatErrorMessage}from"./errors-L3rugjUL.js";import{_ as withCdpSocket,d as normalizeCdpWsUrl,g as getHeadersWithAuth,j as resolvePreferredBuilderForceAgentsTmpDir,m as fetchJson,p as appendCdpPath,t as getChromeWebSocketUrl,u as formatAriaSnapshot}from"./chrome-CRUzg3kA.js";import{t as formatCliCommand}from"./command-format-B3XMq_73.js";import"./src-5XE2oMwl.js";import path from"node:path";import crypto from"node:crypto";import fs from"node:fs/promises";import{chromium,devices}from"playwright-core";const pageStates=new WeakMap,contextStates=new WeakMap,observedContexts=new WeakSet,observedPages=new WeakSet,roleRefsByTarget=new Map;let cached=null,connecting=null;function normalizeCdpUrl(raw){return raw.replace(/\/$/,``)}function findNetworkRequestById(state,id){for(let i=state.requests.length-1;i>=0;--i){let candidate=state.requests[i];if(candidate&&candidate.id===id)return candidate}}function roleRefsKey(cdpUrl,targetId){return`${normalizeCdpUrl(cdpUrl)}::${targetId}`}function rememberRoleRefsForTarget(opts){let targetId=opts.targetId.trim();if(targetId)for(roleRefsByTarget.set(roleRefsKey(opts.cdpUrl,targetId),{refs:opts.refs,...opts.frameSelector?{frameSelector:opts.frameSelector}:{},...opts.mode?{mode:opts.mode}:{}});roleRefsByTarget.size>50;){let first=roleRefsByTarget.keys().next();if(first.done)break;roleRefsByTarget.delete(first.value)}}function storeRoleRefsForTarget(opts){let state=ensurePageState(opts.page);state.roleRefs=opts.refs,state.roleRefsFrameSelector=opts.frameSelector,state.roleRefsMode=opts.mode,opts.targetId?.trim()&&rememberRoleRefsForTarget({cdpUrl:opts.cdpUrl,targetId:opts.targetId,refs:opts.refs,frameSelector:opts.frameSelector,mode:opts.mode})}function restoreRoleRefsForTarget(opts){let targetId=opts.targetId?.trim()||``;if(!targetId)return;let cached=roleRefsByTarget.get(roleRefsKey(opts.cdpUrl,targetId));if(!cached)return;let state=ensurePageState(opts.page);state.roleRefs||(state.roleRefs=cached.refs,state.roleRefsFrameSelector=cached.frameSelector,state.roleRefsMode=cached.mode)}function ensurePageState(page){let existing=pageStates.get(page);if(existing)return existing;let state={console:[],errors:[],requests:[],requestIds:new WeakMap,nextRequestId:0,armIdUpload:0,armIdDialog:0,armIdDownload:0};return pageStates.set(page,state),observedPages.has(page)||(observedPages.add(page),page.on(`console`,msg=>{let entry={type:msg.type(),text:msg.text(),timestamp:new Date().toISOString(),location:msg.location()};state.console.push(entry),state.console.length>500&&state.console.shift()}),page.on(`pageerror`,err=>{state.errors.push({message:err?.message?String(err.message):String(err),name:err?.name?String(err.name):void 0,stack:err?.stack?String(err.stack):void 0,timestamp:new Date().toISOString()}),state.errors.length>200&&state.errors.shift()}),page.on(`request`,req=>{state.nextRequestId+=1;let id=`r${state.nextRequestId}`;state.requestIds.set(req,id),state.requests.push({id,timestamp:new Date().toISOString(),method:req.method(),url:req.url(),resourceType:req.resourceType()}),state.requests.length>500&&state.requests.shift()}),page.on(`response`,resp=>{let req=resp.request(),id=state.requestIds.get(req);if(!id)return;let rec=findNetworkRequestById(state,id);rec&&(rec.status=resp.status(),rec.ok=resp.ok())}),page.on(`requestfailed`,req=>{let id=state.requestIds.get(req);if(!id)return;let rec=findNetworkRequestById(state,id);rec&&(rec.failureText=req.failure()?.errorText,rec.ok=!1)}),page.on(`close`,()=>{pageStates.delete(page),observedPages.delete(page)})),state}function observeContext(context){if(!observedContexts.has(context)){observedContexts.add(context),ensureContextState(context);for(let page of context.pages())ensurePageState(page);context.on(`page`,page=>ensurePageState(page))}}function ensureContextState(context){let existing=contextStates.get(context);if(existing)return existing;let state={traceActive:!1};return contextStates.set(context,state),state}function observeBrowser(browser){for(let context of browser.contexts())observeContext(context)}async function connectBrowser(cdpUrl){let normalized=normalizeCdpUrl(cdpUrl);return cached?.cdpUrl===normalized?cached:(connecting||=(async()=>{let lastErr;for(let attempt=0;attempt<3;attempt+=1)try{let timeout=5e3+attempt*2e3,endpoint=await getChromeWebSocketUrl(normalized,timeout).catch(()=>null)??normalized,headers=getHeadersWithAuth(endpoint),browser=await chromium.connectOverCDP(endpoint,{timeout,headers}),onDisconnected=()=>{cached?.browser===browser&&(cached=null)},connected={browser,cdpUrl:normalized,onDisconnected};return cached=connected,browser.on(`disconnected`,onDisconnected),observeBrowser(browser),connected}catch(err){lastErr=err;let delay=250+attempt*250;await new Promise(r=>setTimeout(r,delay))}if(lastErr instanceof Error)throw lastErr;let message=lastErr?formatErrorMessage(lastErr):`CDP connect failed`;throw Error(message)})().finally(()=>{connecting=null}),await connecting)}async function getAllPages(browser){return browser.contexts().flatMap(c=>c.pages())}async function pageTargetId(page){let session=await page.context().newCDPSession(page);try{let info=await session.send(`Target.getTargetInfo`);return String(info?.targetInfo?.targetId??``).trim()||null}finally{await session.detach().catch(()=>{})}}async function findPageByTargetId(browser,targetId,cdpUrl){let pages=await getAllPages(browser),resolvedViaCdp=!1;for(let page of pages){let tid=null;try{tid=await pageTargetId(page),resolvedViaCdp=!0}catch{tid=null}if(tid&&tid===targetId)return page}if(!resolvedViaCdp&&pages.length===1)return pages[0];if(cdpUrl)try{let listUrl=`${normalizeBaseUrl(cdpUrl).replace(/^ws:/,`http:`).replace(/\/cdp$/,``)}/json/list`,response=await fetch(listUrl,{headers:getHeadersWithAuth(listUrl)});if(response.ok){let targets=await response.json(),target=targets.find(t=>t.id===targetId);if(target){let urlMatch=pages.filter(p=>p.url()===target.url);if(urlMatch.length===1)return urlMatch[0];if(urlMatch.length>1){let sameUrlTargets=targets.filter(t=>t.url===target.url);if(sameUrlTargets.length===urlMatch.length){let idx=sameUrlTargets.findIndex(t=>t.id===targetId);if(idx>=0&&idx<urlMatch.length)return urlMatch[idx]}}}}}catch{}return null}async function getPageForTargetId(opts){let{browser}=await connectBrowser(opts.cdpUrl),pages=await getAllPages(browser);if(!pages.length)throw Error(`No pages available in the connected browser.`);let first=pages[0];if(!opts.targetId)return first;let found=await findPageByTargetId(browser,opts.targetId,opts.cdpUrl);if(!found){if(pages.length===1)return first;throw Error(`tab not found`)}return found}function refLocator(page,ref){let normalized=ref.startsWith(`@`)?ref.slice(1):ref.startsWith(`ref=`)?ref.slice(4):ref;if(/^e\d+$/.test(normalized)){let state=pageStates.get(page);if(state?.roleRefsMode===`aria`)return(state.roleRefsFrameSelector?page.frameLocator(state.roleRefsFrameSelector):page).locator(`aria-ref=${normalized}`);let info=state?.roleRefs?.[normalized];if(!info)throw Error(`Unknown ref "${normalized}". Run a new snapshot and use a ref from that snapshot.`);let locAny=state?.roleRefsFrameSelector?page.frameLocator(state.roleRefsFrameSelector):page,locator=info.name?locAny.getByRole(info.role,{name:info.name,exact:!0}):locAny.getByRole(info.role);return info.nth===void 0?locator:locator.nth(info.nth)}return page.locator(`aria-ref=${normalized}`)}async function closePlaywrightBrowserConnection(){let cur=cached;cached=null,connecting=null,cur&&(cur.onDisconnected&&typeof cur.browser.off==`function`&&cur.browser.off(`disconnected`,cur.onDisconnected),await cur.browser.close().catch(()=>{}))}function normalizeCdpHttpBaseForJsonEndpoints(cdpUrl){try{let url=new URL(cdpUrl);return url.protocol===`ws:`?url.protocol=`http:`:url.protocol===`wss:`&&(url.protocol=`https:`),url.pathname=url.pathname.replace(/\/devtools\/browser\/.*$/,``),url.pathname=url.pathname.replace(/\/cdp$/,``),url.toString().replace(/\/$/,``)}catch{return cdpUrl.replace(/^ws:/,`http:`).replace(/^wss:/,`https:`).replace(/\/devtools\/browser\/.*$/,``).replace(/\/cdp$/,``).replace(/\/$/,``)}}function cdpSocketNeedsAttach(wsUrl){try{let pathname=new URL(wsUrl).pathname;return pathname===`/cdp`||pathname.endsWith(`/cdp`)||pathname.includes(`/devtools/browser/`)}catch{return!1}}async function tryTerminateExecutionViaCdp(opts){let cdpHttpBase=normalizeCdpHttpBaseForJsonEndpoints(opts.cdpUrl),pages=await fetchJson(appendCdpPath(cdpHttpBase,`/json/list`),2e3).catch(()=>null);if(!pages||pages.length===0)return;let target=pages.find(p=>String(p.id??``).trim()===opts.targetId),wsUrlRaw=String(target?.webSocketDebuggerUrl??``).trim();if(!wsUrlRaw)return;let wsUrl=normalizeCdpWsUrl(wsUrlRaw,cdpHttpBase),needsAttach=cdpSocketNeedsAttach(wsUrl),runWithTimeout=async(work,ms)=>{let timer,timeoutPromise=new Promise((_,reject)=>{timer=setTimeout(()=>reject(Error(`CDP command timed out`)),ms)});try{return await Promise.race([work,timeoutPromise])}finally{timer&&clearTimeout(timer)}};await withCdpSocket(wsUrl,async send=>{let sessionId;try{if(needsAttach){let attached=await runWithTimeout(send(`Target.attachToTarget`,{targetId:opts.targetId,flatten:!0}),1500);typeof attached?.sessionId==`string`&&attached.sessionId.trim()&&(sessionId=attached.sessionId)}await runWithTimeout(send(`Runtime.terminateExecution`,void 0,sessionId),1500),sessionId&&send(`Target.detachFromTarget`,{sessionId}).catch(()=>{})}catch{}},{handshakeTimeoutMs:2e3}).catch(()=>{})}async function forceDisconnectPlaywrightForTarget(opts){let normalized=normalizeCdpUrl(opts.cdpUrl);if(cached?.cdpUrl!==normalized)return;let cur=cached;if(cached=null,connecting=null,cur){cur.onDisconnected&&typeof cur.browser.off==`function`&&cur.browser.off(`disconnected`,cur.onDisconnected);let targetId=opts.targetId?.trim()||``;targetId&&await tryTerminateExecutionViaCdp({cdpUrl:normalized,targetId}).catch(()=>{}),cur.browser.close().catch(()=>{})}}async function listPagesViaPlaywright(opts){let{browser}=await connectBrowser(opts.cdpUrl),pages=await getAllPages(browser),results=[];for(let page of pages){let tid=await pageTargetId(page).catch(()=>null);tid&&results.push({targetId:tid,title:await page.title().catch(()=>``),url:page.url(),type:`page`})}return results}async function createPageViaPlaywright(opts){let{browser}=await connectBrowser(opts.cdpUrl),context=browser.contexts()[0]??await browser.newContext();ensureContextState(context);let page=await context.newPage();ensurePageState(page);let targetUrl=opts.url.trim()||`about:blank`;targetUrl!==`about:blank`&&await page.goto(targetUrl,{timeout:3e4}).catch(()=>{});let tid=await pageTargetId(page).catch(()=>null);if(!tid)throw Error(`Failed to get targetId for new page`);return{targetId:tid,title:await page.title().catch(()=>``),url:page.url(),type:`page`}}async function closePageByTargetIdViaPlaywright(opts){let{browser}=await connectBrowser(opts.cdpUrl),page=await findPageByTargetId(browser,opts.targetId,opts.cdpUrl);if(!page)throw Error(`tab not found`);await page.close()}async function focusPageByTargetIdViaPlaywright(opts){let{browser}=await connectBrowser(opts.cdpUrl),page=await findPageByTargetId(browser,opts.targetId,opts.cdpUrl);if(!page)throw Error(`tab not found`);try{await page.bringToFront()}catch(err){let session=await page.context().newCDPSession(page);try{await session.send(`Page.bringToFront`);return}catch{throw err}finally{await session.detach().catch(()=>{})}}}async function getPageErrorsViaPlaywright(opts){let state=ensurePageState(await getPageForTargetId(opts)),errors=[...state.errors];return opts.clear&&(state.errors=[]),{errors}}async function getNetworkRequestsViaPlaywright(opts){let state=ensurePageState(await getPageForTargetId(opts)),raw=[...state.requests],filter=typeof opts.filter==`string`?opts.filter.trim():``,requests=filter?raw.filter(r=>r.url.includes(filter)):raw;return opts.clear&&(state.requests=[],state.requestIds=new WeakMap),{requests}}function consolePriority(level){switch(level){case`error`:return 3;case`warning`:return 2;case`info`:case`log`:return 1;case`debug`:return 0;default:return 1}}async function getConsoleMessagesViaPlaywright(opts){let state=ensurePageState(await getPageForTargetId(opts));if(!opts.level)return[...state.console];let min=consolePriority(opts.level);return state.console.filter(msg=>consolePriority(msg.type)>=min)}const INTERACTIVE_ROLES=new Set([`button`,`link`,`textbox`,`checkbox`,`radio`,`combobox`,`listbox`,`menuitem`,`menuitemcheckbox`,`menuitemradio`,`option`,`searchbox`,`slider`,`spinbutton`,`switch`,`tab`,`treeitem`]),CONTENT_ROLES=new Set([`heading`,`cell`,`gridcell`,`columnheader`,`rowheader`,`listitem`,`article`,`region`,`main`,`navigation`]),STRUCTURAL_ROLES=new Set([`generic`,`group`,`list`,`table`,`row`,`rowgroup`,`grid`,`treegrid`,`menu`,`menubar`,`toolbar`,`tablist`,`tree`,`directory`,`document`,`application`,`presentation`,`none`]);function getRoleSnapshotStats(snapshot,refs){let interactive=Object.values(refs).filter(r=>INTERACTIVE_ROLES.has(r.role)).length;return{lines:snapshot.split(`
2
2
  `).length,chars:snapshot.length,refs:Object.keys(refs).length,interactive}}function getIndentLevel(line){let match=line.match(/^(\s*)/);return match?Math.floor(match[1].length/2):0}function matchInteractiveSnapshotLine(line,options){let depth=getIndentLevel(line);if(options.maxDepth!==void 0&&depth>options.maxDepth)return null;let match=line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);if(!match)return null;let[,,roleRaw,name,suffix]=match;return roleRaw.startsWith(`/`)?null:{roleRaw,role:roleRaw.toLowerCase(),...name?{name}:{},suffix}}function createRoleNameTracker(){let counts=new Map,refsByKey=new Map;return{counts,refsByKey,getKey(role,name){return`${role}:${name??``}`},getNextIndex(role,name){let key=this.getKey(role,name),current=counts.get(key)??0;return counts.set(key,current+1),current},trackRef(role,name,ref){let key=this.getKey(role,name),list=refsByKey.get(key)??[];list.push(ref),refsByKey.set(key,list)},getDuplicateKeys(){let out=new Set;for(let[key,refs]of refsByKey)refs.length>1&&out.add(key);return out}}}function removeNthFromNonDuplicates(refs,tracker){let duplicates=tracker.getDuplicateKeys();for(let[ref,data]of Object.entries(refs)){let key=tracker.getKey(data.role,data.name);duplicates.has(key)||delete refs[ref]?.nth}}function compactTree(tree){let lines=tree.split(`
3
3
  `),result=[];for(let i=0;i<lines.length;i+=1){let line=lines[i];if(line.includes(`[ref=`)){result.push(line);continue}if(line.includes(`:`)&&!line.trimEnd().endsWith(`:`)){result.push(line);continue}let currentIndent=getIndentLevel(line),hasRelevantChildren=!1;for(let j=i+1;j<lines.length&&!(getIndentLevel(lines[j])<=currentIndent);j+=1)if(lines[j]?.includes(`[ref=`)){hasRelevantChildren=!0;break}hasRelevantChildren&&result.push(line)}return result.join(`
4
4
  `)}function processLine(line,refs,options,tracker,nextRef){let depth=getIndentLevel(line);if(options.maxDepth!==void 0&&depth>options.maxDepth)return null;let match=line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);if(!match)return options.interactive?null:line;let[,prefix,roleRaw,name,suffix]=match;if(roleRaw.startsWith(`/`))return options.interactive?null:line;let role=roleRaw.toLowerCase(),isInteractive=INTERACTIVE_ROLES.has(role),isContent=CONTENT_ROLES.has(role),isStructural=STRUCTURAL_ROLES.has(role);if(options.interactive&&!isInteractive||options.compact&&isStructural&&!name)return null;if(!(isInteractive||isContent&&name))return line;let ref=nextRef(),nth=tracker.getNextIndex(role,name);tracker.trackRef(role,name,ref),refs[ref]={role,name,nth};let enhanced=`${prefix}${roleRaw}`;return name&&(enhanced+=` "${name}"`),enhanced+=` [ref=${ref}]`,nth>0&&(enhanced+=` [nth=${nth}]`),suffix&&(enhanced+=suffix),enhanced}function parseRoleRef(raw){let trimmed=raw.trim();if(!trimmed)return null;let normalized=trimmed.startsWith(`@`)?trimmed.slice(1):trimmed.startsWith(`ref=`)?trimmed.slice(4):trimmed;return/^e\d+$/.test(normalized)?normalized:null}function buildRoleSnapshotFromAriaSnapshot(ariaSnapshot,options={}){let lines=ariaSnapshot.split(`
@@ -1,4 +1,4 @@
1
- import{v as parseAgentSessionKey}from"./session-key-5J69DULS.js";import"./registry-DJq2Cvo9.js";import{s as resolveStateDir}from"./paths-Cb8zTlyG.js";import{t as createSubsystemLogger}from"./subsystem-COTa5Ly_.js";import{s as resolveAgentWorkspaceDir}from"./agent-scope-BQByW0cD.js";import"./redact-Bv8wnIZm.js";import"./paths-DtbnCdO7.js";import{n as buildSessionEntry,r as listSessionFilesForAgent,t as requireNodeSqlite}from"./sqlite-BlMLqMl8.js";import path from"node:path";import os from"node:os";import fs from"node:fs/promises";import{spawn}from"node:child_process";import readline from"node:readline";function isQmdScopeAllowed(scope,sessionKey){if(!scope)return!0;let parsed=parseQmdSessionScope(sessionKey),channel=parsed.channel,chatType=parsed.chatType,normalizedKey=parsed.normalizedKey??``,rawKey=sessionKey?.trim().toLowerCase()??``;for(let rule of scope.rules??[]){if(!rule)continue;let match=rule.match??{};if(match.channel&&match.channel!==channel||match.chatType&&match.chatType!==chatType)continue;let normalizedPrefix=match.keyPrefix?.trim().toLowerCase()||void 0,rawPrefix=match.rawKeyPrefix?.trim().toLowerCase()||void 0;if(!(rawPrefix&&!rawKey.startsWith(rawPrefix))){if(normalizedPrefix){if(normalizedPrefix.startsWith(`agent:`)){if(!rawKey.startsWith(normalizedPrefix))continue}else if(!normalizedKey.startsWith(normalizedPrefix))continue}return rule.action===`allow`}}return(scope.default??`allow`)===`allow`}function deriveQmdScopeChannel(key){return parseQmdSessionScope(key).channel}function deriveQmdScopeChatType(key){return parseQmdSessionScope(key).chatType}function parseQmdSessionScope(key){let normalized=normalizeQmdSessionKey(key);if(!normalized)return{};let parts=normalized.split(`:`).filter(Boolean),chatType;return parts.length>=2&&(parts[1]===`group`||parts[1]===`channel`||parts[1]===`direct`||parts[1]===`dm`)?(parts.includes(`group`)?chatType=`group`:parts.includes(`channel`)&&(chatType=`channel`),{normalizedKey:normalized,channel:parts[0]?.toLowerCase(),chatType:chatType??`direct`}):normalized.includes(`:group:`)?{normalizedKey:normalized,chatType:`group`}:normalized.includes(`:channel:`)?{normalizedKey:normalized,chatType:`channel`}:{normalizedKey:normalized,chatType:`direct`}}function normalizeQmdSessionKey(key){if(!key)return;let trimmed=key.trim();if(!trimmed)return;let normalized=(parseAgentSessionKey(trimmed)?.rest??trimmed).toLowerCase();if(!normalized.startsWith(`subagent:`))return normalized}const log$1=createSubsystemLogger(`memory`);function parseQmdQueryJson(stdout,stderr){let trimmedStdout=stdout.trim(),trimmedStderr=stderr.trim(),stdoutIsMarker=trimmedStdout.length>0&&isQmdNoResultsOutput(trimmedStdout),stderrIsMarker=trimmedStderr.length>0&&isQmdNoResultsOutput(trimmedStderr);if(stdoutIsMarker||!trimmedStdout&&stderrIsMarker)return[];if(!trimmedStdout){let message=`stdout empty${trimmedStderr?` (stderr: ${summarizeQmdStderr(trimmedStderr)})`:``}`;throw log$1.warn(`qmd query returned invalid JSON: ${message}`),Error(`qmd query returned invalid JSON: ${message}`)}try{let parsed=parseQmdQueryResultArray(trimmedStdout);if(parsed!==null)return parsed;let noisyPayload=extractFirstJsonArray(trimmedStdout);if(!noisyPayload)throw Error(`qmd query JSON response was not an array`);let fallback=parseQmdQueryResultArray(noisyPayload);if(fallback!==null)return fallback;throw Error(`qmd query JSON response was not an array`)}catch(err){let message=err instanceof Error?err.message:String(err);throw log$1.warn(`qmd query returned invalid JSON: ${message}`),Error(`qmd query returned invalid JSON: ${message}`,{cause:err})}}function isQmdNoResultsOutput(raw){return raw.split(/\r?\n/).map(line=>line.trim().toLowerCase().replace(/\s+/g,` `)).filter(line=>line.length>0).some(line=>isQmdNoResultsLine(line))}function isQmdNoResultsLine(line){return line===`no results found`||line===`no results found.`?!0:/^(?:\[[^\]]+\]\s*)?(?:(?:warn(?:ing)?|info|error|qmd)\s*:\s*)+no results found\.?$/.test(line)}function summarizeQmdStderr(raw){return raw.length<=120?raw:`${raw.slice(0,117)}...`}function parseQmdQueryResultArray(raw){try{let parsed=JSON.parse(raw);return Array.isArray(parsed)?parsed:null}catch{return null}}function extractFirstJsonArray(raw){let start=raw.indexOf(`[`);if(start<0)return null;let depth=0,inString=!1,escaped=!1;for(let i=start;i<raw.length;i+=1){let char=raw[i];if(char===void 0)break;if(inString){if(escaped){escaped=!1;continue}char===`\\`?escaped=!0:char===`"`&&(inString=!1);continue}if(char===`"`){inString=!0;continue}if(char===`[`)depth+=1;else if(char===`]`&&(--depth,depth===0))return raw.slice(start,i+1)}return null}const log=createSubsystemLogger(`memory`),SNIPPET_HEADER_RE=/@@\s*-([0-9]+),([0-9]+)/,NUL_MARKER_RE=/(?:\^@|\\0|\\x00|\\u0000|null\s*byte|nul\s*byte)/i;var QmdMemoryManager=class QmdMemoryManager{static async create(params){let resolved=params.resolved.qmd;if(!resolved)return null;let manager=new QmdMemoryManager({cfg:params.cfg,agentId:params.agentId,resolved});return await manager.initialize(params.mode??`full`),manager}constructor(params){this.collectionRoots=new Map,this.sources=new Set,this.docPathCache=new Map,this.exportedSessionState=new Map,this.maxQmdOutputChars=2e5,this.updateTimer=null,this.pendingUpdate=null,this.queuedForcedUpdate=null,this.queuedForcedRuns=0,this.closed=!1,this.db=null,this.lastUpdateAt=null,this.lastEmbedAt=null,this.attemptedNullByteCollectionRepair=!1,this.cfg=params.cfg,this.agentId=params.agentId,this.qmd=params.resolved,this.workspaceDir=resolveAgentWorkspaceDir(params.cfg,params.agentId),this.stateDir=resolveStateDir(process.env,os.homedir),this.agentStateDir=path.join(this.stateDir,`agents`,this.agentId),this.qmdDir=path.join(this.agentStateDir,`qmd`),this.xdgConfigHome=path.join(this.qmdDir,`xdg-config`),this.xdgCacheHome=path.join(this.qmdDir,`xdg-cache`),this.indexPath=path.join(this.xdgCacheHome,`qmd`,`index.sqlite`),this.env={...process.env,XDG_CONFIG_HOME:this.xdgConfigHome,XDG_CACHE_HOME:this.xdgCacheHome,NO_COLOR:`1`},this.sessionExporter=this.qmd.sessions.enabled?{dir:this.qmd.sessions.exportDir??path.join(this.qmdDir,`sessions`),retentionMs:this.qmd.sessions.retentionDays?this.qmd.sessions.retentionDays*24*60*60*1e3:void 0,collectionName:this.pickSessionCollectionName()}:null,this.sessionExporter&&(this.qmd.collections=[...this.qmd.collections,{name:this.sessionExporter.collectionName,path:this.sessionExporter.dir,pattern:`**/*.md`,kind:`sessions`}])}async initialize(mode){if(this.bootstrapCollections(),mode!==`status`){if(await fs.mkdir(this.xdgConfigHome,{recursive:!0}),await fs.mkdir(this.xdgCacheHome,{recursive:!0}),await fs.mkdir(path.dirname(this.indexPath),{recursive:!0}),this.sessionExporter&&await fs.mkdir(this.sessionExporter.dir,{recursive:!0}),await this.symlinkSharedModels(),await this.ensureCollections(),this.qmd.update.onBoot){let bootRun=this.runUpdate(`boot`,!0);this.qmd.update.waitForBootSync?await bootRun.catch(err=>{log.warn(`qmd boot update failed: ${String(err)}`)}):bootRun.catch(err=>{log.warn(`qmd boot update failed: ${String(err)}`)})}this.qmd.update.intervalMs>0&&(this.updateTimer=setInterval(()=>{this.runUpdate(`interval`).catch(err=>{log.warn(`qmd update failed (${String(err)})`)})},this.qmd.update.intervalMs))}}bootstrapCollections(){this.collectionRoots.clear(),this.sources.clear();for(let collection of this.qmd.collections){let kind=collection.kind===`sessions`?`sessions`:`memory`;this.collectionRoots.set(collection.name,{path:collection.path,kind}),this.sources.add(kind)}}async ensureCollections(){let existing=new Map;try{let result=await this.runQmd([`collection`,`list`,`--json`],{timeoutMs:this.qmd.update.commandTimeoutMs}),parsed=JSON.parse(result.stdout);if(Array.isArray(parsed)){for(let entry of parsed)if(typeof entry==`string`)existing.set(entry,{});else if(entry&&typeof entry==`object`){let name=entry.name;if(typeof name==`string`){let listedPath=entry.path,listedPattern=entry.pattern,listedMask=entry.mask;existing.set(name,{path:typeof listedPath==`string`?listedPath:void 0,pattern:typeof listedPattern==`string`?listedPattern:typeof listedMask==`string`?listedMask:void 0})}}}}catch{}for(let collection of this.qmd.collections){let listed=existing.get(collection.name);if(!(listed&&!this.shouldRebindCollection(collection,listed))){if(listed)try{await this.removeCollection(collection.name)}catch(err){let message=err instanceof Error?err.message:String(err);this.isCollectionMissingError(message)||log.warn(`qmd collection remove failed for ${collection.name}: ${message}`)}try{await this.ensureCollectionPath(collection),await this.addCollection(collection.path,collection.name,collection.pattern)}catch(err){let message=err instanceof Error?err.message:String(err);if(this.isCollectionAlreadyExistsError(message))continue;log.warn(`qmd collection add failed for ${collection.name}: ${message}`)}}}}async ensureCollectionPath(collection){this.isDirectoryGlobPattern(collection.pattern)&&await fs.mkdir(collection.path,{recursive:!0})}isDirectoryGlobPattern(pattern){return pattern.includes(`*`)||pattern.includes(`?`)||pattern.includes(`[`)}isCollectionAlreadyExistsError(message){let lower=message.toLowerCase();return lower.includes(`already exists`)||lower.includes(`exists`)}isCollectionMissingError(message){let lower=message.toLowerCase();return lower.includes(`not found`)||lower.includes(`does not exist`)||lower.includes(`missing`)}async addCollection(pathArg,name,pattern){await this.runQmd([`collection`,`add`,pathArg,`--name`,name,`--mask`,pattern],{timeoutMs:this.qmd.update.commandTimeoutMs})}async removeCollection(name){await this.runQmd([`collection`,`remove`,name],{timeoutMs:this.qmd.update.commandTimeoutMs})}shouldRebindCollection(collection,listed){return listed.path?!this.pathsMatch(listed.path,collection.path)||typeof listed.pattern==`string`&&listed.pattern!==collection.pattern:collection.kind===`sessions`}pathsMatch(left,right){let normalize=value=>{let resolved=path.isAbsolute(value)?path.resolve(value):path.resolve(this.workspaceDir,value),normalized=path.normalize(resolved);return process.platform===`win32`?normalized.toLowerCase():normalized};return normalize(left)===normalize(right)}shouldRepairNullByteCollectionError(err){let message=err instanceof Error?err.message:String(err),lower=message.toLowerCase();return(lower.includes(`enotdir`)||lower.includes(`not a directory`))&&NUL_MARKER_RE.test(message)}async tryRepairNullByteCollections(err,reason){if(this.attemptedNullByteCollectionRepair||!this.shouldRepairNullByteCollectionError(err))return!1;this.attemptedNullByteCollectionRepair=!0,log.warn(`qmd update failed with suspected null-byte collection metadata (${reason}); rebuilding managed collections and retrying once`);for(let collection of this.qmd.collections){try{await this.removeCollection(collection.name)}catch(removeErr){let removeMessage=removeErr instanceof Error?removeErr.message:String(removeErr);this.isCollectionMissingError(removeMessage)||log.warn(`qmd collection remove failed for ${collection.name}: ${removeMessage}`)}try{await this.addCollection(collection.path,collection.name,collection.pattern)}catch(addErr){let addMessage=addErr instanceof Error?addErr.message:String(addErr);this.isCollectionAlreadyExistsError(addMessage)||log.warn(`qmd collection add failed for ${collection.name}: ${addMessage}`)}}return!0}async search(query,opts){if(!this.isScopeAllowed(opts?.sessionKey))return this.logScopeDenied(opts?.sessionKey),[];let trimmed=query.trim();if(!trimmed)return[];await this.waitForPendingUpdateBeforeSearch();let limit=Math.min(this.qmd.limits.maxResults,opts?.maxResults??this.qmd.limits.maxResults),collectionNames=this.listManagedCollectionNames();if(collectionNames.length===0)return log.warn(`qmd query skipped: no managed collections configured`),[];let qmdSearchCommand=this.qmd.searchMode,parsed;try{if(qmdSearchCommand===`query`&&collectionNames.length>1)parsed=await this.runQueryAcrossCollections(trimmed,limit,collectionNames);else{let args=this.buildSearchArgs(qmdSearchCommand,trimmed,limit);args.push(...this.buildCollectionFilterArgs(collectionNames));let result=await this.runQmd(args,{timeoutMs:this.qmd.limits.timeoutMs});parsed=parseQmdQueryJson(result.stdout,result.stderr)}}catch(err){if(qmdSearchCommand!==`query`&&this.isUnsupportedQmdOptionError(err)){log.warn(`qmd ${qmdSearchCommand} does not support configured flags; retrying search with qmd query`);try{if(collectionNames.length>1)parsed=await this.runQueryAcrossCollections(trimmed,limit,collectionNames);else{let fallbackArgs=this.buildSearchArgs(`query`,trimmed,limit);fallbackArgs.push(...this.buildCollectionFilterArgs(collectionNames));let fallback=await this.runQmd(fallbackArgs,{timeoutMs:this.qmd.limits.timeoutMs});parsed=parseQmdQueryJson(fallback.stdout,fallback.stderr)}}catch(fallbackErr){throw log.warn(`qmd query fallback failed: ${String(fallbackErr)}`),fallbackErr instanceof Error?fallbackErr:Error(String(fallbackErr))}}else throw log.warn(`qmd ${qmdSearchCommand} failed: ${String(err)}`),err instanceof Error?err:Error(String(err))}let results=[];for(let entry of parsed){let doc=await this.resolveDocLocation(entry.docid);if(!doc)continue;let snippet=entry.snippet?.slice(0,this.qmd.limits.maxSnippetChars)??``,lines=this.extractSnippetLines(snippet),score=typeof entry.score==`number`?entry.score:0;score<(opts?.minScore??0)||results.push({path:doc.rel,startLine:lines.startLine,endLine:lines.endLine,score,snippet,source:doc.source})}return this.clampResultsByInjectedChars(results.slice(0,limit))}async sync(params){params?.progress&&params.progress({completed:0,total:1,label:`Updating QMD index…`}),await this.runUpdate(params?.reason??`manual`,params?.force),params?.progress&&params.progress({completed:1,total:1,label:`QMD index updated`})}async readFile(params){let relPath=params.relPath?.trim();if(!relPath)throw Error(`path required`);let absPath=this.resolveReadPath(relPath);if(!absPath.endsWith(`.md`))throw Error(`path required`);let stat=await fs.lstat(absPath);if(stat.isSymbolicLink()||!stat.isFile())throw Error(`path required`);if(params.from!==void 0||params.lines!==void 0)return{text:await this.readPartialText(absPath,params.from,params.lines),path:relPath};let content=await fs.readFile(absPath,`utf-8`);if(!params.from&&!params.lines)return{text:content,path:relPath};let lines=content.split(`
1
+ import{v as parseAgentSessionKey}from"./session-key-5J69DULS.js";import"./registry-CZHRcH-q.js";import{s as resolveStateDir}from"./paths-Cb8zTlyG.js";import{t as createSubsystemLogger}from"./subsystem-D0Ril4rt.js";import{s as resolveAgentWorkspaceDir}from"./agent-scope-DgKN27hJ.js";import"./redact-Bv8wnIZm.js";import"./paths-DtbnCdO7.js";import{n as buildSessionEntry,r as listSessionFilesForAgent,t as requireNodeSqlite}from"./sqlite-JjFgDV-H.js";import path from"node:path";import os from"node:os";import fs from"node:fs/promises";import{spawn}from"node:child_process";import readline from"node:readline";function isQmdScopeAllowed(scope,sessionKey){if(!scope)return!0;let parsed=parseQmdSessionScope(sessionKey),channel=parsed.channel,chatType=parsed.chatType,normalizedKey=parsed.normalizedKey??``,rawKey=sessionKey?.trim().toLowerCase()??``;for(let rule of scope.rules??[]){if(!rule)continue;let match=rule.match??{};if(match.channel&&match.channel!==channel||match.chatType&&match.chatType!==chatType)continue;let normalizedPrefix=match.keyPrefix?.trim().toLowerCase()||void 0,rawPrefix=match.rawKeyPrefix?.trim().toLowerCase()||void 0;if(!(rawPrefix&&!rawKey.startsWith(rawPrefix))){if(normalizedPrefix){if(normalizedPrefix.startsWith(`agent:`)){if(!rawKey.startsWith(normalizedPrefix))continue}else if(!normalizedKey.startsWith(normalizedPrefix))continue}return rule.action===`allow`}}return(scope.default??`allow`)===`allow`}function deriveQmdScopeChannel(key){return parseQmdSessionScope(key).channel}function deriveQmdScopeChatType(key){return parseQmdSessionScope(key).chatType}function parseQmdSessionScope(key){let normalized=normalizeQmdSessionKey(key);if(!normalized)return{};let parts=normalized.split(`:`).filter(Boolean),chatType;return parts.length>=2&&(parts[1]===`group`||parts[1]===`channel`||parts[1]===`direct`||parts[1]===`dm`)?(parts.includes(`group`)?chatType=`group`:parts.includes(`channel`)&&(chatType=`channel`),{normalizedKey:normalized,channel:parts[0]?.toLowerCase(),chatType:chatType??`direct`}):normalized.includes(`:group:`)?{normalizedKey:normalized,chatType:`group`}:normalized.includes(`:channel:`)?{normalizedKey:normalized,chatType:`channel`}:{normalizedKey:normalized,chatType:`direct`}}function normalizeQmdSessionKey(key){if(!key)return;let trimmed=key.trim();if(!trimmed)return;let normalized=(parseAgentSessionKey(trimmed)?.rest??trimmed).toLowerCase();if(!normalized.startsWith(`subagent:`))return normalized}const log$1=createSubsystemLogger(`memory`);function parseQmdQueryJson(stdout,stderr){let trimmedStdout=stdout.trim(),trimmedStderr=stderr.trim(),stdoutIsMarker=trimmedStdout.length>0&&isQmdNoResultsOutput(trimmedStdout),stderrIsMarker=trimmedStderr.length>0&&isQmdNoResultsOutput(trimmedStderr);if(stdoutIsMarker||!trimmedStdout&&stderrIsMarker)return[];if(!trimmedStdout){let message=`stdout empty${trimmedStderr?` (stderr: ${summarizeQmdStderr(trimmedStderr)})`:``}`;throw log$1.warn(`qmd query returned invalid JSON: ${message}`),Error(`qmd query returned invalid JSON: ${message}`)}try{let parsed=parseQmdQueryResultArray(trimmedStdout);if(parsed!==null)return parsed;let noisyPayload=extractFirstJsonArray(trimmedStdout);if(!noisyPayload)throw Error(`qmd query JSON response was not an array`);let fallback=parseQmdQueryResultArray(noisyPayload);if(fallback!==null)return fallback;throw Error(`qmd query JSON response was not an array`)}catch(err){let message=err instanceof Error?err.message:String(err);throw log$1.warn(`qmd query returned invalid JSON: ${message}`),Error(`qmd query returned invalid JSON: ${message}`,{cause:err})}}function isQmdNoResultsOutput(raw){return raw.split(/\r?\n/).map(line=>line.trim().toLowerCase().replace(/\s+/g,` `)).filter(line=>line.length>0).some(line=>isQmdNoResultsLine(line))}function isQmdNoResultsLine(line){return line===`no results found`||line===`no results found.`?!0:/^(?:\[[^\]]+\]\s*)?(?:(?:warn(?:ing)?|info|error|qmd)\s*:\s*)+no results found\.?$/.test(line)}function summarizeQmdStderr(raw){return raw.length<=120?raw:`${raw.slice(0,117)}...`}function parseQmdQueryResultArray(raw){try{let parsed=JSON.parse(raw);return Array.isArray(parsed)?parsed:null}catch{return null}}function extractFirstJsonArray(raw){let start=raw.indexOf(`[`);if(start<0)return null;let depth=0,inString=!1,escaped=!1;for(let i=start;i<raw.length;i+=1){let char=raw[i];if(char===void 0)break;if(inString){if(escaped){escaped=!1;continue}char===`\\`?escaped=!0:char===`"`&&(inString=!1);continue}if(char===`"`){inString=!0;continue}if(char===`[`)depth+=1;else if(char===`]`&&(--depth,depth===0))return raw.slice(start,i+1)}return null}const log=createSubsystemLogger(`memory`),SNIPPET_HEADER_RE=/@@\s*-([0-9]+),([0-9]+)/,NUL_MARKER_RE=/(?:\^@|\\0|\\x00|\\u0000|null\s*byte|nul\s*byte)/i;var QmdMemoryManager=class QmdMemoryManager{static async create(params){let resolved=params.resolved.qmd;if(!resolved)return null;let manager=new QmdMemoryManager({cfg:params.cfg,agentId:params.agentId,resolved});return await manager.initialize(params.mode??`full`),manager}constructor(params){this.collectionRoots=new Map,this.sources=new Set,this.docPathCache=new Map,this.exportedSessionState=new Map,this.maxQmdOutputChars=2e5,this.updateTimer=null,this.pendingUpdate=null,this.queuedForcedUpdate=null,this.queuedForcedRuns=0,this.closed=!1,this.db=null,this.lastUpdateAt=null,this.lastEmbedAt=null,this.attemptedNullByteCollectionRepair=!1,this.cfg=params.cfg,this.agentId=params.agentId,this.qmd=params.resolved,this.workspaceDir=resolveAgentWorkspaceDir(params.cfg,params.agentId),this.stateDir=resolveStateDir(process.env,os.homedir),this.agentStateDir=path.join(this.stateDir,`agents`,this.agentId),this.qmdDir=path.join(this.agentStateDir,`qmd`),this.xdgConfigHome=path.join(this.qmdDir,`xdg-config`),this.xdgCacheHome=path.join(this.qmdDir,`xdg-cache`),this.indexPath=path.join(this.xdgCacheHome,`qmd`,`index.sqlite`),this.env={...process.env,XDG_CONFIG_HOME:this.xdgConfigHome,XDG_CACHE_HOME:this.xdgCacheHome,NO_COLOR:`1`},this.sessionExporter=this.qmd.sessions.enabled?{dir:this.qmd.sessions.exportDir??path.join(this.qmdDir,`sessions`),retentionMs:this.qmd.sessions.retentionDays?this.qmd.sessions.retentionDays*24*60*60*1e3:void 0,collectionName:this.pickSessionCollectionName()}:null,this.sessionExporter&&(this.qmd.collections=[...this.qmd.collections,{name:this.sessionExporter.collectionName,path:this.sessionExporter.dir,pattern:`**/*.md`,kind:`sessions`}])}async initialize(mode){if(this.bootstrapCollections(),mode!==`status`){if(await fs.mkdir(this.xdgConfigHome,{recursive:!0}),await fs.mkdir(this.xdgCacheHome,{recursive:!0}),await fs.mkdir(path.dirname(this.indexPath),{recursive:!0}),this.sessionExporter&&await fs.mkdir(this.sessionExporter.dir,{recursive:!0}),await this.symlinkSharedModels(),await this.ensureCollections(),this.qmd.update.onBoot){let bootRun=this.runUpdate(`boot`,!0);this.qmd.update.waitForBootSync?await bootRun.catch(err=>{log.warn(`qmd boot update failed: ${String(err)}`)}):bootRun.catch(err=>{log.warn(`qmd boot update failed: ${String(err)}`)})}this.qmd.update.intervalMs>0&&(this.updateTimer=setInterval(()=>{this.runUpdate(`interval`).catch(err=>{log.warn(`qmd update failed (${String(err)})`)})},this.qmd.update.intervalMs))}}bootstrapCollections(){this.collectionRoots.clear(),this.sources.clear();for(let collection of this.qmd.collections){let kind=collection.kind===`sessions`?`sessions`:`memory`;this.collectionRoots.set(collection.name,{path:collection.path,kind}),this.sources.add(kind)}}async ensureCollections(){let existing=new Map;try{let result=await this.runQmd([`collection`,`list`,`--json`],{timeoutMs:this.qmd.update.commandTimeoutMs}),parsed=JSON.parse(result.stdout);if(Array.isArray(parsed)){for(let entry of parsed)if(typeof entry==`string`)existing.set(entry,{});else if(entry&&typeof entry==`object`){let name=entry.name;if(typeof name==`string`){let listedPath=entry.path,listedPattern=entry.pattern,listedMask=entry.mask;existing.set(name,{path:typeof listedPath==`string`?listedPath:void 0,pattern:typeof listedPattern==`string`?listedPattern:typeof listedMask==`string`?listedMask:void 0})}}}}catch{}for(let collection of this.qmd.collections){let listed=existing.get(collection.name);if(!(listed&&!this.shouldRebindCollection(collection,listed))){if(listed)try{await this.removeCollection(collection.name)}catch(err){let message=err instanceof Error?err.message:String(err);this.isCollectionMissingError(message)||log.warn(`qmd collection remove failed for ${collection.name}: ${message}`)}try{await this.ensureCollectionPath(collection),await this.addCollection(collection.path,collection.name,collection.pattern)}catch(err){let message=err instanceof Error?err.message:String(err);if(this.isCollectionAlreadyExistsError(message))continue;log.warn(`qmd collection add failed for ${collection.name}: ${message}`)}}}}async ensureCollectionPath(collection){this.isDirectoryGlobPattern(collection.pattern)&&await fs.mkdir(collection.path,{recursive:!0})}isDirectoryGlobPattern(pattern){return pattern.includes(`*`)||pattern.includes(`?`)||pattern.includes(`[`)}isCollectionAlreadyExistsError(message){let lower=message.toLowerCase();return lower.includes(`already exists`)||lower.includes(`exists`)}isCollectionMissingError(message){let lower=message.toLowerCase();return lower.includes(`not found`)||lower.includes(`does not exist`)||lower.includes(`missing`)}async addCollection(pathArg,name,pattern){await this.runQmd([`collection`,`add`,pathArg,`--name`,name,`--mask`,pattern],{timeoutMs:this.qmd.update.commandTimeoutMs})}async removeCollection(name){await this.runQmd([`collection`,`remove`,name],{timeoutMs:this.qmd.update.commandTimeoutMs})}shouldRebindCollection(collection,listed){return listed.path?!this.pathsMatch(listed.path,collection.path)||typeof listed.pattern==`string`&&listed.pattern!==collection.pattern:collection.kind===`sessions`}pathsMatch(left,right){let normalize=value=>{let resolved=path.isAbsolute(value)?path.resolve(value):path.resolve(this.workspaceDir,value),normalized=path.normalize(resolved);return process.platform===`win32`?normalized.toLowerCase():normalized};return normalize(left)===normalize(right)}shouldRepairNullByteCollectionError(err){let message=err instanceof Error?err.message:String(err),lower=message.toLowerCase();return(lower.includes(`enotdir`)||lower.includes(`not a directory`))&&NUL_MARKER_RE.test(message)}async tryRepairNullByteCollections(err,reason){if(this.attemptedNullByteCollectionRepair||!this.shouldRepairNullByteCollectionError(err))return!1;this.attemptedNullByteCollectionRepair=!0,log.warn(`qmd update failed with suspected null-byte collection metadata (${reason}); rebuilding managed collections and retrying once`);for(let collection of this.qmd.collections){try{await this.removeCollection(collection.name)}catch(removeErr){let removeMessage=removeErr instanceof Error?removeErr.message:String(removeErr);this.isCollectionMissingError(removeMessage)||log.warn(`qmd collection remove failed for ${collection.name}: ${removeMessage}`)}try{await this.addCollection(collection.path,collection.name,collection.pattern)}catch(addErr){let addMessage=addErr instanceof Error?addErr.message:String(addErr);this.isCollectionAlreadyExistsError(addMessage)||log.warn(`qmd collection add failed for ${collection.name}: ${addMessage}`)}}return!0}async search(query,opts){if(!this.isScopeAllowed(opts?.sessionKey))return this.logScopeDenied(opts?.sessionKey),[];let trimmed=query.trim();if(!trimmed)return[];await this.waitForPendingUpdateBeforeSearch();let limit=Math.min(this.qmd.limits.maxResults,opts?.maxResults??this.qmd.limits.maxResults),collectionNames=this.listManagedCollectionNames();if(collectionNames.length===0)return log.warn(`qmd query skipped: no managed collections configured`),[];let qmdSearchCommand=this.qmd.searchMode,parsed;try{if(qmdSearchCommand===`query`&&collectionNames.length>1)parsed=await this.runQueryAcrossCollections(trimmed,limit,collectionNames);else{let args=this.buildSearchArgs(qmdSearchCommand,trimmed,limit);args.push(...this.buildCollectionFilterArgs(collectionNames));let result=await this.runQmd(args,{timeoutMs:this.qmd.limits.timeoutMs});parsed=parseQmdQueryJson(result.stdout,result.stderr)}}catch(err){if(qmdSearchCommand!==`query`&&this.isUnsupportedQmdOptionError(err)){log.warn(`qmd ${qmdSearchCommand} does not support configured flags; retrying search with qmd query`);try{if(collectionNames.length>1)parsed=await this.runQueryAcrossCollections(trimmed,limit,collectionNames);else{let fallbackArgs=this.buildSearchArgs(`query`,trimmed,limit);fallbackArgs.push(...this.buildCollectionFilterArgs(collectionNames));let fallback=await this.runQmd(fallbackArgs,{timeoutMs:this.qmd.limits.timeoutMs});parsed=parseQmdQueryJson(fallback.stdout,fallback.stderr)}}catch(fallbackErr){throw log.warn(`qmd query fallback failed: ${String(fallbackErr)}`),fallbackErr instanceof Error?fallbackErr:Error(String(fallbackErr))}}else throw log.warn(`qmd ${qmdSearchCommand} failed: ${String(err)}`),err instanceof Error?err:Error(String(err))}let results=[];for(let entry of parsed){let doc=await this.resolveDocLocation(entry.docid);if(!doc)continue;let snippet=entry.snippet?.slice(0,this.qmd.limits.maxSnippetChars)??``,lines=this.extractSnippetLines(snippet),score=typeof entry.score==`number`?entry.score:0;score<(opts?.minScore??0)||results.push({path:doc.rel,startLine:lines.startLine,endLine:lines.endLine,score,snippet,source:doc.source})}return this.clampResultsByInjectedChars(results.slice(0,limit))}async sync(params){params?.progress&&params.progress({completed:0,total:1,label:`Updating QMD index…`}),await this.runUpdate(params?.reason??`manual`,params?.force),params?.progress&&params.progress({completed:1,total:1,label:`QMD index updated`})}async readFile(params){let relPath=params.relPath?.trim();if(!relPath)throw Error(`path required`);let absPath=this.resolveReadPath(relPath);if(!absPath.endsWith(`.md`))throw Error(`path required`);let stat=await fs.lstat(absPath);if(stat.isSymbolicLink()||!stat.isFile())throw Error(`path required`);if(params.from!==void 0||params.lines!==void 0)return{text:await this.readPartialText(absPath,params.from,params.lines),path:relPath};let content=await fs.readFile(absPath,`utf-8`);if(!params.from&&!params.lines)return{text:content,path:relPath};let lines=content.split(`
2
2
  `),start=Math.max(1,params.from??1),count=Math.max(1,params.lines??lines.length);return{text:lines.slice(start-1,start-1+count).join(`
3
3
  `),path:relPath}}status(){let counts=this.readCounts();return{backend:`qmd`,provider:`qmd`,model:`qmd`,requestedProvider:`qmd`,files:counts.totalDocuments,chunks:counts.totalDocuments,dirty:!1,workspaceDir:this.workspaceDir,dbPath:this.indexPath,sources:Array.from(this.sources),sourceCounts:counts.sourceCounts,vector:{enabled:!0,available:!0},batch:{enabled:!1,failures:0,limit:0,wait:!1,concurrency:0,pollIntervalMs:0,timeoutMs:0},custom:{qmd:{collections:this.qmd.collections.length,lastUpdateAt:this.lastUpdateAt}}}}async probeEmbeddingAvailability(){return{ok:!0}}async probeVectorAvailability(){return!0}async close(){this.closed||(this.closed=!0,this.updateTimer&&=(clearInterval(this.updateTimer),null),this.queuedForcedRuns=0,await this.pendingUpdate?.catch(()=>void 0),await this.queuedForcedUpdate?.catch(()=>void 0),this.db&&=(this.db.close(),null))}async runUpdate(reason,force,opts){if(!this.closed){if(this.pendingUpdate)return force?this.enqueueForcedUpdate(reason):this.pendingUpdate;if(this.queuedForcedUpdate&&!opts?.fromForcedQueue)return force?this.enqueueForcedUpdate(reason):this.queuedForcedUpdate;this.shouldSkipUpdate(force)||(this.pendingUpdate=(async()=>{this.sessionExporter&&await this.exportSessions();try{await this.runQmd([`update`],{timeoutMs:this.qmd.update.updateTimeoutMs})}catch(err){if(!await this.tryRepairNullByteCollections(err,reason))throw err;await this.runQmd([`update`],{timeoutMs:this.qmd.update.updateTimeoutMs})}let embedIntervalMs=this.qmd.update.embedIntervalMs;if(force||this.lastEmbedAt===null||embedIntervalMs>0&&Date.now()-this.lastEmbedAt>embedIntervalMs)try{await this.runQmd([`embed`],{timeoutMs:this.qmd.update.embedTimeoutMs}),this.lastEmbedAt=Date.now()}catch(err){log.warn(`qmd embed failed (${reason}): ${String(err)}`)}this.lastUpdateAt=Date.now(),this.docPathCache.clear()})().finally(()=>{this.pendingUpdate=null}),await this.pendingUpdate)}}enqueueForcedUpdate(reason){return this.queuedForcedRuns+=1,this.queuedForcedUpdate||=this.drainForcedUpdates(reason).finally(()=>{this.queuedForcedUpdate=null}),this.queuedForcedUpdate}async drainForcedUpdates(reason){for(await this.pendingUpdate?.catch(()=>void 0);!this.closed&&this.queuedForcedRuns>0;)--this.queuedForcedRuns,await this.runUpdate(`${reason}:queued`,!0,{fromForcedQueue:!0})}async symlinkSharedModels(){let defaultCacheHome=process.env.XDG_CACHE_HOME||(process.platform===`win32`?process.env.LOCALAPPDATA:void 0)||path.join(os.homedir(),`.cache`),defaultModelsDir=path.join(defaultCacheHome,`qmd`,`models`),targetModelsDir=path.join(this.xdgCacheHome,`qmd`,`models`);try{if(!(await fs.stat(defaultModelsDir).catch(err=>{if(err.code===`ENOENT`)return null;throw err}))?.isDirectory())return;try{await fs.lstat(targetModelsDir);return}catch{}try{await fs.symlink(defaultModelsDir,targetModelsDir,`dir`)}catch(symlinkErr){let code=symlinkErr.code;if(process.platform===`win32`&&(code===`EPERM`||code===`ENOTSUP`))await fs.symlink(defaultModelsDir,targetModelsDir,`junction`);else throw symlinkErr}log.debug(`symlinked qmd models: ${defaultModelsDir} → ${targetModelsDir}`)}catch(err){log.warn(`failed to symlink qmd models directory: ${String(err)}`)}}async runQmd(args,opts){return await new Promise((resolve,reject)=>{let child=spawn(this.qmd.command,args,{env:this.env,cwd:this.workspaceDir}),stdout=``,stderr=``,stdoutTruncated=!1,stderrTruncated=!1,timer=opts?.timeoutMs?setTimeout(()=>{child.kill(`SIGKILL`),reject(Error(`qmd ${args.join(` `)} timed out after ${opts.timeoutMs}ms`))},opts.timeoutMs):null;child.stdout.on(`data`,data=>{let next=appendOutputWithCap(stdout,data.toString(`utf8`),this.maxQmdOutputChars);stdout=next.text,stdoutTruncated||=next.truncated}),child.stderr.on(`data`,data=>{let next=appendOutputWithCap(stderr,data.toString(`utf8`),this.maxQmdOutputChars);stderr=next.text,stderrTruncated||=next.truncated}),child.on(`error`,err=>{timer&&clearTimeout(timer),reject(err)}),child.on(`close`,code=>{if(timer&&clearTimeout(timer),stdoutTruncated||stderrTruncated){reject(Error(`qmd ${args.join(` `)} produced too much output (limit ${this.maxQmdOutputChars} chars)`));return}code===0?resolve({stdout,stderr}):reject(Error(`qmd ${args.join(` `)} failed (code ${code}): ${stderr||stdout}`))})})}async readPartialText(absPath,from,lines){let start=Math.max(1,from??1),count=Math.max(1,lines??1/0),handle=await fs.open(absPath),stream=handle.createReadStream({encoding:`utf-8`}),rl=readline.createInterface({input:stream,crlfDelay:1/0}),selected=[],index=0;try{for await(let line of rl)if(index+=1,!(index<start)){if(selected.length>=count)break;selected.push(line)}}finally{rl.close(),await handle.close()}return selected.slice(0,count).join(`
4
4
  `)}ensureDb(){if(this.db)return this.db;let{DatabaseSync}=requireNodeSqlite();return this.db=new DatabaseSync(this.indexPath,{readOnly:!0}),this.db.exec(`PRAGMA busy_timeout = 1`),this.db}async exportSessions(){if(!this.sessionExporter)return;let exportDir=this.sessionExporter.dir;await fs.mkdir(exportDir,{recursive:!0});let files=await listSessionFilesForAgent(this.agentId),keep=new Set,tracked=new Set,cutoff=this.sessionExporter.retentionMs?Date.now()-this.sessionExporter.retentionMs:null;for(let sessionFile of files){let entry=await buildSessionEntry(sessionFile);if(!entry||cutoff&&entry.mtimeMs<cutoff)continue;let target=path.join(exportDir,`${path.basename(sessionFile,`.jsonl`)}.md`);tracked.add(sessionFile);let state=this.exportedSessionState.get(sessionFile);(!state||state.hash!==entry.hash||state.mtimeMs!==entry.mtimeMs)&&await fs.writeFile(target,this.renderSessionMarkdown(entry),`utf-8`),this.exportedSessionState.set(sessionFile,{hash:entry.hash,mtimeMs:entry.mtimeMs,target}),keep.add(target)}let exported=await fs.readdir(exportDir).catch(()=>[]);for(let name of exported){if(!name.endsWith(`.md`))continue;let full=path.join(exportDir,name);keep.has(full)||await fs.rm(full,{force:!0})}for(let[sessionFile,state]of this.exportedSessionState)(!tracked.has(sessionFile)||!state.target.startsWith(exportDir+path.sep))&&this.exportedSessionState.delete(sessionFile)}renderSessionMarkdown(entry){return`${`# Session ${path.basename(entry.absPath,path.extname(entry.absPath))}`}\n\n${entry.content?.trim().length?entry.content.trim():`(empty)`}\n`}pickSessionCollectionName(){let existing=new Set(this.qmd.collections.map(collection=>collection.name)),base=`sessions-${this.sanitizeCollectionNameSegment(this.agentId)}`;if(!existing.has(base))return base;let counter=2,candidate=`${base}-${counter}`;for(;existing.has(candidate);)counter+=1,candidate=`${base}-${counter}`;return candidate}sanitizeCollectionNameSegment(input){return input.toLowerCase().replace(/[^a-z0-9-]+/g,`-`).replace(/^-+|-+$/g,``)||`agent`}async resolveDocLocation(docid){if(!docid)return null;let normalized=docid.startsWith(`#`)?docid.slice(1):docid;if(!normalized)return null;let cached=this.docPathCache.get(normalized);if(cached)return cached;let db=this.ensureDb(),row;try{row=db.prepare(`SELECT collection, path FROM documents WHERE hash = ? AND active = 1 LIMIT 1`).get(normalized),row||=db.prepare(`SELECT collection, path FROM documents WHERE hash LIKE ? AND active = 1 LIMIT 1`).get(`${normalized}%`)}catch(err){throw this.isSqliteBusyError(err)?(log.debug(`qmd index is busy while resolving doc path: ${String(err)}`),this.createQmdBusyError(err)):err}if(!row)return null;let location=this.toDocLocation(row.collection,row.path);return location?(this.docPathCache.set(normalized,location),location):null}extractSnippetLines(snippet){let match=SNIPPET_HEADER_RE.exec(snippet);if(match){let start=Number(match[1]),count=Number(match[2]);if(Number.isFinite(start)&&Number.isFinite(count))return{startLine:start,endLine:start+count-1}}return{startLine:1,endLine:snippet.split(`