junhost 0.2.1 → 0.2.4

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 (141) hide show
  1. package/bin/jun.js +55 -1
  2. package/dist/browser-mcp-server.js +1 -1
  3. package/dist/index.js +58 -59
  4. package/dist/mcp-server.js +11 -11
  5. package/package.json +1 -1
  6. package/ui-dist/assets/BrowserPage-SOejdSXd.js +1 -0
  7. package/ui-dist/assets/DashboardPage-DBSjArx4.js +1 -0
  8. package/ui-dist/assets/FilesPage-Co7w4yPV.js +64 -0
  9. package/ui-dist/assets/FormContext-CdQ9sDWR.js +1 -0
  10. package/ui-dist/assets/LogsPage-BPcYN5yl.js +1 -0
  11. package/ui-dist/assets/McpPage-DMSfd_bz.js +1 -0
  12. package/ui-dist/assets/MemoriesPage-BrZWQnNs.js +1 -0
  13. package/ui-dist/assets/{RunsPage-CK9pwAgz.js → RunsPage-DGPOmwHg.js} +50 -50
  14. package/ui-dist/assets/SchedulesPage-CGRBnO2D.js +1 -0
  15. package/ui-dist/assets/SettingsPage-C_hWawaj.js +1 -0
  16. package/ui-dist/assets/SkillsPage-CpF3t2F6.js +1 -0
  17. package/ui-dist/assets/api-DTaM-PBA.js +1 -0
  18. package/ui-dist/assets/architecture-7EHR7CIX-Dcu_L_tZ.js +1 -0
  19. package/ui-dist/assets/{architectureDiagram-3BPJPVTR-BP2MZYle.js → architectureDiagram-3BPJPVTR-CYwo6wbL.js} +1 -1
  20. package/ui-dist/assets/badge-Czi0QcSt.js +1 -0
  21. package/ui-dist/assets/{blockDiagram-GPEHLZMM-Af1ue8xv.js → blockDiagram-GPEHLZMM-ESzvgY_d.js} +1 -1
  22. package/ui-dist/assets/button-C5SbvNQM.js +1 -0
  23. package/ui-dist/assets/{c4Diagram-AAUBKEIU-AY7PqfkW.js → c4Diagram-AAUBKEIU-BFIF6RjX.js} +1 -1
  24. package/ui-dist/assets/channel-BCV_BwnR.js +1 -0
  25. package/ui-dist/assets/checkbox-CvgOimO2.js +1 -0
  26. package/ui-dist/assets/{chunk-2J33WTMH-h9HiYY_u.js → chunk-2J33WTMH-DHrqzPNv.js} +1 -1
  27. package/ui-dist/assets/{chunk-3OPIFGDE-BhRd3oVg.js → chunk-3OPIFGDE-D-OBfFax.js} +1 -1
  28. package/ui-dist/assets/{chunk-5ZQYHXKU-3UMjEqrw.js → chunk-5ZQYHXKU-D5zzqgKr.js} +1 -1
  29. package/ui-dist/assets/{chunk-727SXJPM-BcWt_3lo.js → chunk-727SXJPM-C3PXI115.js} +1 -1
  30. package/ui-dist/assets/{chunk-AQP2D5EJ-Cpch5yeN.js → chunk-AQP2D5EJ-Bpj50bQh.js} +1 -1
  31. package/ui-dist/assets/{chunk-BO2N2NFS-tci6_YFK.js → chunk-BO2N2NFS-CgXJ5x75.js} +4 -4
  32. package/ui-dist/assets/{chunk-CSCIHK7Q-B7WJrDNL.js → chunk-CSCIHK7Q-BtmPGR8Z.js} +3 -3
  33. package/ui-dist/assets/{chunk-KSCS5N6A-C_P0C3_7.js → chunk-KSCS5N6A-CopX8M46.js} +1 -1
  34. package/ui-dist/assets/{chunk-L5ZTLDWV-CgJ4GCaj.js → chunk-L5ZTLDWV-BviTnq5M.js} +1 -1
  35. package/ui-dist/assets/{chunk-LZXEDZCA-C2PsTcer.js → chunk-LZXEDZCA-BAENHcPD.js} +2 -2
  36. package/ui-dist/assets/{chunk-ND2GUHAM-CSipvS6t.js → chunk-ND2GUHAM-DZ9eeo3O.js} +1 -1
  37. package/ui-dist/assets/{chunk-NZK2D7GU-BmtPBmfa.js → chunk-NZK2D7GU-B-IcekpZ.js} +1 -1
  38. package/ui-dist/assets/{chunk-O5CBEL6O-DHg6U4bD.js → chunk-O5CBEL6O-uzui4fRc.js} +1 -1
  39. package/ui-dist/assets/{chunk-WU5MYG2G-Jao3JHnT.js → chunk-WU5MYG2G-CYvvOcUE.js} +1 -1
  40. package/ui-dist/assets/{circle-x-BSTd_gmE.js → circle-x-CAsSuVme.js} +1 -1
  41. package/ui-dist/assets/classDiagram-4FO5ZUOK-Dq-Bv-C-.js +1 -0
  42. package/ui-dist/assets/classDiagram-v2-Q7XG4LA2-Dq-Bv-C-.js +1 -0
  43. package/ui-dist/assets/collapsible-DBUxLbzP.js +1 -0
  44. package/ui-dist/assets/{dagre-BM42HDAG-CmyaiNOn.js → dagre-BM42HDAG-BnZediLS.js} +1 -1
  45. package/ui-dist/assets/{diagram-2AECGRRQ-C8X3Dn_F.js → diagram-2AECGRRQ-R3SA74dj.js} +1 -1
  46. package/ui-dist/assets/{diagram-5GNKFQAL-D7FdDkBI.js → diagram-5GNKFQAL-BIFqDshR.js} +1 -1
  47. package/ui-dist/assets/{diagram-KO2AKTUF-DTvmbX9D.js → diagram-KO2AKTUF-BewO5gZn.js} +1 -1
  48. package/ui-dist/assets/{diagram-LMA3HP47-C4ytoinJ.js → diagram-LMA3HP47-VCDqO0nt.js} +1 -1
  49. package/ui-dist/assets/{diagram-OG6HWLK6-Ck8n45l9.js → diagram-OG6HWLK6-CqtMJ04I.js} +1 -1
  50. package/ui-dist/assets/dialog-DNn7-a_m.js +1 -0
  51. package/ui-dist/assets/{erDiagram-TEJ5UH35-DEdyi5kb.js → erDiagram-TEJ5UH35-DieBE3Rx.js} +1 -1
  52. package/ui-dist/assets/eventmodeling-FCH6USID-BSOzHW1O.js +1 -0
  53. package/ui-dist/assets/{external-link-DiZ5uX5z.js → external-link-DCXGJhiP.js} +1 -1
  54. package/ui-dist/assets/{flowDiagram-I6XJVG4X-DJh6JTpP.js → flowDiagram-I6XJVG4X-_gTMsbYe.js} +1 -1
  55. package/ui-dist/assets/{ganttDiagram-6RSMTGT7-40CbH6vs.js → ganttDiagram-6RSMTGT7-Ojxb0li0.js} +1 -1
  56. package/ui-dist/assets/{gitGraph-WXDBUCRP-Bb8N_3_Z.js → gitGraph-WXDBUCRP-CAGTBNn6.js} +1 -1
  57. package/ui-dist/assets/{gitGraphDiagram-PVQCEYII-CYO8lsXs.js → gitGraphDiagram-PVQCEYII-BCMq34-W.js} +1 -1
  58. package/ui-dist/assets/{highlighted-body-OFNGDK62-C9QojPJP.js → highlighted-body-OFNGDK62-CtSa94q8.js} +1 -1
  59. package/ui-dist/assets/{index-CZzHSXB1.css → index-CWOY_p-K.css} +1 -1
  60. package/ui-dist/assets/index-yyhnv7Ap.js +12 -0
  61. package/ui-dist/assets/{info-J43DQDTF-CuL2NM7A.js → info-J43DQDTF-gykbtpzn.js} +1 -1
  62. package/ui-dist/assets/{infoDiagram-5YYISTIA-BPLgO20D.js → infoDiagram-5YYISTIA-CAFjVe3v.js} +1 -1
  63. package/ui-dist/assets/input-CzAFDIdf.js +1 -0
  64. package/ui-dist/assets/{ishikawaDiagram-YF4QCWOH-CvaXogtI.js → ishikawaDiagram-YF4QCWOH-D3BdPtw9.js} +1 -1
  65. package/ui-dist/assets/{journeyDiagram-JHISSGLW-C1J-v-pE.js → journeyDiagram-JHISSGLW-BzT9Xthe.js} +1 -1
  66. package/ui-dist/assets/{kanban-definition-UN3LZRKU-CRmhIHz7.js → kanban-definition-UN3LZRKU-CQj8Taa5.js} +1 -1
  67. package/ui-dist/assets/katex-BX33ra8Y.js +1 -0
  68. package/ui-dist/assets/{key-round-D965pLEl.js → key-round-i_iJarVP.js} +1 -1
  69. package/ui-dist/assets/label-Bu19spuB.js +1 -0
  70. package/ui-dist/assets/{line-BdBKXCG0.js → line-BofMfFGW.js} +1 -1
  71. package/ui-dist/assets/mermaid-GHXKKRXX-CJkN8RLl.js +1 -0
  72. package/ui-dist/assets/{mermaid-parser.core-BS-vIFlR.js → mermaid-parser.core-B-NMEyis.js} +2 -2
  73. package/ui-dist/assets/{mindmap-definition-RKZ34NQL-1LEnd-Xo.js → mindmap-definition-RKZ34NQL-Co7nZa8L.js} +1 -1
  74. package/ui-dist/assets/{packet-YPE3B663-BYcxKrId.js → packet-YPE3B663-CUHl-3-z.js} +1 -1
  75. package/ui-dist/assets/{pause-h76ixDr5.js → pause-DhMeMeEd.js} +1 -1
  76. package/ui-dist/assets/{pie-LRSECV5Y-DYSxmFzY.js → pie-LRSECV5Y-66vPnpWw.js} +1 -1
  77. package/ui-dist/assets/{pieDiagram-4H26LBE5-EqE8umht.js → pieDiagram-4H26LBE5-anqqKj6T.js} +1 -1
  78. package/ui-dist/assets/play-D3mjFMmX.js +1 -0
  79. package/ui-dist/assets/{quadrantDiagram-W4KKPZXB-CEBlRqkN.js → quadrantDiagram-W4KKPZXB-CH1Wkvzf.js} +1 -1
  80. package/ui-dist/assets/{radar-GUYGQ44K-DloreDUf.js → radar-GUYGQ44K-C-aSbLx7.js} +1 -1
  81. package/ui-dist/assets/{requirementDiagram-4Y6WPE33-BtG32uo4.js → requirementDiagram-4Y6WPE33-BXgFmUPx.js} +1 -1
  82. package/ui-dist/assets/{rotate-cw-B1ZRM7VI.js → rotate-cw-BUTALXBe.js} +1 -1
  83. package/ui-dist/assets/{sankeyDiagram-5OEKKPKP-LFkiQmlj.js → sankeyDiagram-5OEKKPKP-BZJiw-wH.js} +1 -1
  84. package/ui-dist/assets/search-CKqhWG6h.js +1 -0
  85. package/ui-dist/assets/select-s2HSAntK.js +1 -0
  86. package/ui-dist/assets/{sequenceDiagram-3UESZ5HK-BFABrHKQ.js → sequenceDiagram-3UESZ5HK-C6ZDPDNO.js} +1 -1
  87. package/ui-dist/assets/square-COjZqkOL.js +1 -0
  88. package/ui-dist/assets/{stateDiagram-AJRCARHV-UZadGigl.js → stateDiagram-AJRCARHV-BNz2d_tV.js} +1 -1
  89. package/ui-dist/assets/stateDiagram-v2-BHNVJYJU-C7n6nn-m.js +1 -0
  90. package/ui-dist/assets/tabs-grE19_AL.js +1 -0
  91. package/ui-dist/assets/textarea-CwL3B5t5.js +1 -0
  92. package/ui-dist/assets/{timeline-definition-PNZ67QCA-B0GbqI20.js → timeline-definition-PNZ67QCA-Ctli85zn.js} +1 -1
  93. package/ui-dist/assets/{trash-2-D4CnL8wv.js → trash-2-D5W0vize.js} +1 -1
  94. package/ui-dist/assets/{treeView-BLDUP644-COM1up3U.js → treeView-BLDUP644-DsKAQvGU.js} +1 -1
  95. package/ui-dist/assets/{treemap-LRROVOQU-CWvutEBH.js → treemap-LRROVOQU-DabIXs6O.js} +1 -1
  96. package/ui-dist/assets/useBaseUiId-DL38u1cQ.js +1 -0
  97. package/ui-dist/assets/useButton-kcIJA9wR.js +1 -0
  98. package/ui-dist/assets/useCompositeListItem-I_fNdF1_.js +1 -0
  99. package/ui-dist/assets/useRegisterFieldControl-DOObtV36.js +1 -0
  100. package/ui-dist/assets/{vennDiagram-CIIHVFJN-BU2bLP3c.js → vennDiagram-CIIHVFJN-DYyyOGXD.js} +1 -1
  101. package/ui-dist/assets/{wardley-L42UT6IY-DiQe6mxF.js → wardley-L42UT6IY-4pZOEfsT.js} +1 -1
  102. package/ui-dist/assets/{wardleyDiagram-YWT4CUSO-D4BuSn5f.js → wardleyDiagram-YWT4CUSO-Ba6H_8tB.js} +1 -1
  103. package/ui-dist/assets/{xychartDiagram-2RQKCTM6-CcKf_YnL.js → xychartDiagram-2RQKCTM6-DQSqwpal.js} +1 -1
  104. package/ui-dist/index.html +4 -4
  105. package/ui-dist/assets/BrowserPage-vw54Zy8i.js +0 -1
  106. package/ui-dist/assets/DashboardPage-Fae7MOCk.js +0 -1
  107. package/ui-dist/assets/FilesPage-DGMWNSyG.js +0 -64
  108. package/ui-dist/assets/FormContext-6Ydu-jal.js +0 -1
  109. package/ui-dist/assets/LogsPage-ChoGgfAX.js +0 -1
  110. package/ui-dist/assets/McpPage-CZ_0PAsI.js +0 -1
  111. package/ui-dist/assets/MemoriesPage-j2hFZJtC.js +0 -1
  112. package/ui-dist/assets/SchedulesPage-BdOov1_M.js +0 -1
  113. package/ui-dist/assets/SettingsPage-BawGPDde.js +0 -1
  114. package/ui-dist/assets/SkillsPage-BoDc74ND.js +0 -1
  115. package/ui-dist/assets/architecture-7EHR7CIX-4fzAtq46.js +0 -1
  116. package/ui-dist/assets/badge-DjyNiZCE.js +0 -1
  117. package/ui-dist/assets/button-Cg-0y2B2.js +0 -1
  118. package/ui-dist/assets/channel-COgxKgTn.js +0 -1
  119. package/ui-dist/assets/checkbox-B77q6yf0.js +0 -1
  120. package/ui-dist/assets/classDiagram-4FO5ZUOK-CxJD7YbT.js +0 -1
  121. package/ui-dist/assets/classDiagram-v2-Q7XG4LA2-CxJD7YbT.js +0 -1
  122. package/ui-dist/assets/collapsible-CP1QD5GK.js +0 -1
  123. package/ui-dist/assets/dialog-CPRWiMQj.js +0 -1
  124. package/ui-dist/assets/eventmodeling-FCH6USID-CZSE8Xfh.js +0 -1
  125. package/ui-dist/assets/index-CqEDC1ie.js +0 -12
  126. package/ui-dist/assets/input-B0qeLI2E.js +0 -1
  127. package/ui-dist/assets/katex--eycYE9W.js +0 -1
  128. package/ui-dist/assets/label-CxX4-RmK.js +0 -1
  129. package/ui-dist/assets/mermaid-GHXKKRXX-CvI11iBs.js +0 -1
  130. package/ui-dist/assets/play-B4R5rXMZ.js +0 -1
  131. package/ui-dist/assets/search-09Pme-NO.js +0 -1
  132. package/ui-dist/assets/select-CF2SUxSi.js +0 -1
  133. package/ui-dist/assets/square-_9cV5Fet.js +0 -1
  134. package/ui-dist/assets/stateDiagram-v2-BHNVJYJU-BeslXd68.js +0 -1
  135. package/ui-dist/assets/tabs-CpVOS0Mr.js +0 -1
  136. package/ui-dist/assets/textarea-5JHEEgU-.js +0 -1
  137. package/ui-dist/assets/useBaseUiId-dSIElxm7.js +0 -1
  138. package/ui-dist/assets/useButton-DKtiRcm8.js +0 -1
  139. package/ui-dist/assets/useCompositeListItem-CJiAiQsj.js +0 -1
  140. package/ui-dist/assets/useRegisterFieldControl-CbOBCC3j.js +0 -1
  141. package/ui-dist/assets/utils-BX1Diber.js +0 -1
package/dist/index.js CHANGED
@@ -1,14 +1,13 @@
1
1
  // @bun
2
- var N2=Object.create;var{getPrototypeOf:H2,defineProperty:D0,getOwnPropertyNames:Y2}=Object;var W2=Object.prototype.hasOwnProperty;function $2(N){return this[N]}var G2,U2,M$=(N,H,Y)=>{var W=N!=null&&typeof N==="object";if(W){var $=H?G2??=new WeakMap:U2??=new WeakMap,G=$.get(N);if(G)return G}Y=N!=null?N2(H2(N)):{};let U=H||!N||!N.__esModule?D0(Y,"default",{value:N,enumerable:!0}):Y;for(let O of Y2(N))if(!W2.call(U,O))D0(U,O,{get:$2.bind(N,O),enumerable:!0});if(W)$.set(N,U);return U};var J$=(N,H)=>()=>(H||N((H={exports:{}}).exports,H),H.exports);var O2=(N)=>N;function Q2(N,H){this[N]=O2.bind(null,H)}var B$=(N,H)=>{for(var Y in H)D0(N,Y,{get:H[Y],enumerable:!0,configurable:!0,set:Q2.bind(H,Y)})};import{existsSync as tY,watch as X$}from"fs";import{stat as rY}from"fs/promises";import b from"path";import{promises as a}from"fs";import i from"path";import{existsSync as $1,renameSync as X2}from"fs";import G1 from"os";import R from"path";function q(N){return process.env[`JUN_${N}`]??process.env[`AGENTHOST_${N}`]}function Z2(){let N=q("HOME");if(N)return N;let H=R.join(G1.homedir(),".jun"),Y=R.join(G1.homedir(),".agenthost");if(!$1(H)&&$1(Y))try{X2(Y,H),console.log("[paths] migrated data dir ~/.agenthost -> ~/.jun")}catch(W){return console.warn("[paths] could not migrate ~/.agenthost -> ~/.jun (files in use?) \u2014 using legacy dir:",W),Y}return H}var I=Z2(),K="default",C0=q("HOST")??"127.0.0.1",uN=Number(q("PORT")??8787);function QN(){return R.join(I,"projects")}function NN(N=K){return R.join(QN(),N)}function o(){return R.join(I,"runs")}function B(N=K){return R.join(NN(N),"workspace")}function RN(){return R.join(I,"schedules")}function j(N=K){return R.join(NN(N),"codex-home")}function U1(N=K){return R.join(NN(N),"widgets")}function SN(N=K){return R.join(NN(N),"browser")}function iN(N){let H=R.resolve(QN()),Y=R.relative(H,R.resolve(N));if(!Y||Y.startsWith("..")||R.isAbsolute(Y))return null;return Y.split(R.sep)[0]||null}function u(N){return N.split(R.sep).join("/")}function R0(N){return i.join(NN(N),"project.json")}var z2=["files","reports","downloads","screenshots","artifacts",".agents/skills"],F2=["profile","downloads","screenshots","recordings"],V2={projectId:K,defaultModel:"gpt-5.4",defaultSandbox:"workspaceWrite",defaultApprovalPolicy:"onRequest",host:"127.0.0.1",port:8787,browserProvider:"agent-browser"},K2={version:1,pages:[{id:"home",title:"Home",widgets:[]}]},L2='# Jun workspace\n\nYou are running inside JunHost \u2014 a self-hosted dashboard that supervises you.\nThis directory is your workspace; write outputs here.\n\n## Browsing the web \u2014 use the `jun-browser` MCP tools\n\nA shared, visible browser session is already running \u2014 the same one the user\nwatches in the dashboard. Drive and inspect it through the **`jun-browser` MCP\nserver\'s tools**, NOT the `agent-browser` shell command:\n\n- `browser_status` \u2014 what URL/title is open RIGHT NOW + who has control. Use\n this to answer "what page is open" / "what am I logged in as" \u2014 it reflects\n exactly what the user sees.\n- `browser_navigate {url}` \u2014 go to a URL\n- `browser_snapshot {interactive}` \u2014 accessibility tree with @ref handles (decide what to click)\n- `browser_click {target}` \u2014 click an @ref or CSS selector\n- `browser_fill {target, text}` \u2014 fill an input\n- `browser_read {selector?}` \u2014 read page text\n- `browser_eval {expression}` \u2014 run JS in the page (read precise state)\n- `browser_screenshot` \u2014 capture to the workspace, returns a path to read\n\nWHY NOT the `agent-browser` CLI: your shell runs in a sandbox that can\'t reach\nthe shared session\'s socket and has no network, so `agent-browser \u2026` there\nfails ("Socket directory not writable" / "Daemon process exited") or silently\nopens a SEPARATE blank page \u2014 you\'d see `about:blank` while the user sees a real\nsite. The MCP tools run in the daemon (unsandboxed) and always act on the shared\npage. So to check a logged-in state, just call `browser_status` (or\n`browser_navigate` to the site, which keeps the user\'s cookies and loads signed\nin) \u2014 never shell out to `agent-browser`.\n\nPrefer snapshot \u2192 @ref actions over guessing selectors. Save extracted notes and\nscreenshots under `reports/` and `screenshots/`.\n\n## Output locations\n- `reports/` \u2014 summaries and findings\n- `screenshots/` \u2014 captured images\n- `downloads/` \u2014 downloaded files\n',M2=`# Codex configuration for this Jun project.
2
+ var lH=Object.create;var{getPrototypeOf:pH,defineProperty:J0,getOwnPropertyNames:uH}=Object;var iH=Object.prototype.hasOwnProperty;function dH(N){return this[N]}var oH,nH,UO=(N,U,H)=>{var Y=N!=null&&typeof N==="object";if(Y){var O=U?oH??=new WeakMap:nH??=new WeakMap,W=O.get(N);if(W)return W}H=N!=null?lH(pH(N)):{};let $=U||!N||!N.__esModule?J0(H,"default",{value:N,enumerable:!0}):H;for(let G of uH(N))if(!iH.call($,G))J0($,G,{get:dH.bind(N,G),enumerable:!0});if(Y)O.set(N,$);return $};var HO=(N,U)=>()=>(U||N((U={exports:{}}).exports,U),U.exports);var aH=(N)=>N;function sH(N,U){this[N]=aH.bind(null,U)}var YO=(N,U)=>{for(var H in U)J0(N,H,{get:U[H],enumerable:!0,configurable:!0,set:sH.bind(U,H)})};import{existsSync as hH,watch as n2}from"fs";import{stat as mH}from"fs/promises";import w from"path";import{promises as o}from"fs";import d from"path";import{existsSync as s0,renameSync as tH}from"fs";import t0 from"os";import h from"path";function x(N){return process.env[`JUN_${N}`]??process.env[`AGENTHOST_${N}`]}function rH(){let N=x("HOME");if(N)return N;let U=h.join(t0.homedir(),".jun"),H=h.join(t0.homedir(),".agenthost");if(!s0(U)&&s0(H))try{tH(H,U),console.log("[paths] migrated data dir ~/.agenthost -> ~/.jun")}catch(Y){return console.warn("[paths] could not migrate ~/.agenthost -> ~/.jun (files in use?) \u2014 using legacy dir:",Y),H}return U}var f=rH(),A0=x("HOST")??"127.0.0.1",mN=Number(x("PORT")??8787);function $N(){return h.join(f,"projects","default")}function i(){return h.join(f,"runs")}function M(){return h.join($N(),"workspace")}function EN(){return h.join(f,"schedules")}function k(){return h.join($N(),"codex-home")}function r0(){return h.join($N(),"widgets")}function TN(){return h.join($N(),"browser")}function c(N){return N.split(h.sep).join("/")}var eH=["files","reports","downloads","screenshots","artifacts",".agents/skills"],NY=["profile","downloads","screenshots","recordings"],UY={defaultModel:"gpt-5.4",defaultSandbox:"workspaceWrite",defaultApprovalPolicy:"onRequest",host:"127.0.0.1",port:8787,browserProvider:"agent-browser"},HY={version:1,pages:[{id:"home",title:"Home",widgets:[]}]},YY='# Jun workspace\n\nYou are running inside JunHost \u2014 a self-hosted dashboard that supervises you.\nThis directory is your workspace; write outputs here.\n\n## Browsing the web \u2014 use the `jun-browser` MCP tools\n\nA shared, visible browser session is already running \u2014 the same one the user\nwatches in the dashboard. Drive and inspect it through the **`jun-browser` MCP\nserver\'s tools**, NOT the `agent-browser` shell command:\n\n- `browser_status` \u2014 what URL/title is open RIGHT NOW + who has control. Use\n this to answer "what page is open" / "what am I logged in as" \u2014 it reflects\n exactly what the user sees.\n- `browser_navigate {url}` \u2014 go to a URL\n- `browser_snapshot {interactive}` \u2014 accessibility tree with @ref handles (decide what to click)\n- `browser_click {target}` \u2014 click an @ref or CSS selector\n- `browser_fill {target, text}` \u2014 fill an input\n- `browser_read {selector?}` \u2014 read page text\n- `browser_eval {expression}` \u2014 run JS in the page (read precise state)\n- `browser_screenshot` \u2014 capture to the workspace, returns a path to read\n\nWHY NOT the `agent-browser` CLI: your shell runs in a sandbox that can\'t reach\nthe shared session\'s socket and has no network, so `agent-browser \u2026` there\nfails ("Socket directory not writable" / "Daemon process exited") or silently\nopens a SEPARATE blank page \u2014 you\'d see `about:blank` while the user sees a real\nsite. The MCP tools run in the daemon (unsandboxed) and always act on the shared\npage. So to check a logged-in state, just call `browser_status` (or\n`browser_navigate` to the site, which keeps the user\'s cookies and loads signed\nin) \u2014 never shell out to `agent-browser`.\n\nPrefer snapshot \u2192 @ref actions over guessing selectors. Save extracted notes and\nscreenshots under `reports/` and `screenshots/`.\n\n## Output locations\n- `reports/` \u2014 summaries and findings\n- `screenshots/` \u2014 captured images\n- `downloads/` \u2014 downloaded files\n',OY=`# Codex configuration for this Jun project.
3
3
  # MCP servers are configured here, e.g.:
4
4
  #
5
5
  # [mcp_servers.context7]
6
6
  # command = "npx"
7
7
  # args = ["-y", "@upstash/context7-mcp"]
8
- `;async function TN(N,H){try{await a.access(N)}catch{await a.mkdir(i.dirname(N),{recursive:!0}),await a.writeFile(N,H,"utf8")}}async function S0(N,H){let Y=B(N);for(let W of z2)await a.mkdir(i.join(Y,W),{recursive:!0});for(let W of F2)await a.mkdir(i.join(SN(N),W),{recursive:!0});await a.mkdir(U1(N),{recursive:!0}),await a.mkdir(i.join(j(N),"logs"),{recursive:!0}),await TN(R0(N),JSON.stringify({id:N,name:H??N,createdAt:new Date().toISOString()},null,2)+`
9
- `),await TN(i.join(NN(N),"dashboard.json"),JSON.stringify(K2,null,2)+`
10
- `),await TN(i.join(j(N),"config.toml"),M2),await TN(i.join(Y,"AGENTS.md"),L2)}async function O1(){await a.mkdir(o(),{recursive:!0}),await TN(i.join(I,"config.json"),JSON.stringify(V2,null,2)+`
11
- `),await S0(K,"Default")}import{promises as KN}from"fs";import FW from"path";/*!
8
+ `;async function cN(N,U){try{await o.access(N)}catch{await o.mkdir(d.dirname(N),{recursive:!0}),await o.writeFile(N,U,"utf8")}}async function e0(){await o.mkdir(i(),{recursive:!0}),await cN(d.join(f,"config.json"),JSON.stringify(UY,null,2)+`
9
+ `);let N=M();for(let U of eH)await o.mkdir(d.join(N,U),{recursive:!0});for(let U of NY)await o.mkdir(d.join(TN(),U),{recursive:!0});await o.mkdir(r0(),{recursive:!0}),await o.mkdir(d.join(k(),"logs"),{recursive:!0}),await cN(d.join($N(),"dashboard.json"),JSON.stringify(HY,null,2)+`
10
+ `),await cN(d.join(k(),"config.toml"),OY),await cN(d.join(N,"AGENTS.md"),YY)}import{promises as LN}from"fs";import N2 from"path";/*!
12
11
  * Copyright (c) Squirrel Chat et al., All rights reserved.
13
12
  * SPDX-License-Identifier: BSD-3-Clause
14
13
  *
@@ -34,11 +33,11 @@ var N2=Object.create;var{getPrototypeOf:H2,defineProperty:D0,getOwnPropertyNames
34
33
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35
34
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36
35
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37
- */function J2(N,H){let Y=N.slice(0,H).split(/\r\n|\n|\r/g);return[Y.length,Y.pop().length+1]}function B2(N,H,Y){let W=N.split(/\r\n|\n|\r/g),$="",G=(Math.log10(H+1)|0)+1;for(let U=H-1;U<=H+1;U++){let O=W[U-1];if(!O)continue;if($+=U.toString().padEnd(G," "),$+=": ",$+=O,$+=`
38
- `,U===H)$+=" ".repeat(G+Y+2),$+=`^
39
- `}return $}class L extends Error{line;column;codeblock;constructor(N,H){let[Y,W]=J2(H.toml,H.ptr),$=B2(H.toml,Y,W);super(`Invalid TOML document: ${N}
36
+ */function WY(N,U){let H=N.slice(0,U).split(/\r\n|\n|\r/g);return[H.length,H.pop().length+1]}function $Y(N,U,H){let Y=N.split(/\r\n|\n|\r/g),O="",W=(Math.log10(U+1)|0)+1;for(let $=U-1;$<=U+1;$++){let G=Y[$-1];if(!G)continue;if(O+=$.toString().padEnd(W," "),O+=": ",O+=G,O+=`
37
+ `,$===U)O+=" ".repeat(W+H+2),O+=`^
38
+ `}return O}class V extends Error{line;column;codeblock;constructor(N,U){let[H,Y]=WY(U.toml,U.ptr),O=$Y(U.toml,H,Y);super(`Invalid TOML document: ${N}
40
39
 
41
- ${$}`,H);this.line=Y,this.column=W,this.codeblock=$}}/*!
40
+ ${O}`,U);this.line=H,this.column=Y,this.codeblock=O}}/*!
42
41
  * Copyright (c) Squirrel Chat et al., All rights reserved.
43
42
  * SPDX-License-Identifier: BSD-3-Clause
44
43
  *
@@ -64,14 +63,14 @@ ${$}`,H);this.line=Y,this.column=W,this.codeblock=$}}/*!
64
63
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
65
64
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
66
65
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67
- */function A2(N,H){let Y=0;while(N[H-++Y]==="\\");return--Y&&Y%2}function pN(N,H=0,Y=N.length){let W=N.indexOf(`
68
- `,H);if(N[W-1]==="\r")W--;return W<=Y?W:-1}function XN(N,H){for(let Y=H;Y<N.length;Y++){let W=N[Y];if(W===`
69
- `)return Y;if(W==="\r"&&N[Y+1]===`
70
- `)return Y+1;if(W<" "&&W!=="\t"||W==="\x7F")throw new L("control characters are not allowed in comments",{toml:N,ptr:H})}return N.length}function _(N,H,Y,W){let $;while(!0){while(($=N[H])===" "||$==="\t"||!Y&&($===`
71
- `||$==="\r"&&N[H+1]===`
72
- `))H++;if(W||$!=="#")break;H=XN(N,H)}return H}function Q1(N,H,Y,W,$=!1){if(!W)return H=pN(N,H),H<0?N.length:H;for(let G=H;G<N.length;G++){let U=N[G];if(U==="#")G=pN(N,G);else if(U===Y)return G+1;else if(U===W||$&&(U===`
73
- `||U==="\r"&&N[G+1]===`
74
- `))return G}throw new L("cannot find end of structure",{toml:N,ptr:H})}function nN(N,H){let Y=N[H],W=Y===N[H+1]&&N[H+1]===N[H+2]?N.slice(H,H+3):Y;H+=W.length-1;do H=N.indexOf(W,++H);while(H>-1&&Y!=="'"&&A2(N,H));if(H>-1){if(H+=W.length,W.length>1){if(N[H]===Y)H++;if(N[H]===Y)H++}}return H}/*!
66
+ */function GY(N,U){let H=0;while(N[U-++H]==="\\");return--H&&H%2}function lN(N,U=0,H=N.length){let Y=N.indexOf(`
67
+ `,U);if(N[Y-1]==="\r")Y--;return Y<=H?Y:-1}function GN(N,U){for(let H=U;H<N.length;H++){let Y=N[H];if(Y===`
68
+ `)return H;if(Y==="\r"&&N[H+1]===`
69
+ `)return H+1;if(Y<" "&&Y!=="\t"||Y==="\x7F")throw new V("control characters are not allowed in comments",{toml:N,ptr:U})}return N.length}function S(N,U,H,Y){let O;while(!0){while((O=N[U])===" "||O==="\t"||!H&&(O===`
70
+ `||O==="\r"&&N[U+1]===`
71
+ `))U++;if(Y||O!=="#")break;U=GN(N,U)}return U}function N1(N,U,H,Y,O=!1){if(!Y)return U=lN(N,U),U<0?N.length:U;for(let W=U;W<N.length;W++){let $=N[W];if($==="#")W=lN(N,W);else if($===H)return W+1;else if($===Y||O&&($===`
72
+ `||$==="\r"&&N[W+1]===`
73
+ `))return W}throw new V("cannot find end of structure",{toml:N,ptr:U})}function pN(N,U){let H=N[U],Y=H===N[U+1]&&N[U+1]===N[U+2]?N.slice(U,U+3):H;U+=Y.length-1;do U=N.indexOf(Y,++U);while(U>-1&&H!=="'"&&GY(N,U));if(U>-1){if(U+=Y.length,Y.length>1){if(N[U]===H)U++;if(N[U]===H)U++}}return U}/*!
75
74
  * Copyright (c) Squirrel Chat et al., All rights reserved.
76
75
  * SPDX-License-Identifier: BSD-3-Clause
77
76
  *
@@ -97,7 +96,7 @@ ${$}`,H);this.line=Y,this.column=W,this.codeblock=$}}/*!
97
96
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
98
97
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
99
98
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
100
- */var D2=/^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;class s extends Date{#H=!1;#Y=!1;#N=null;constructor(N){let H=!0,Y=!0,W="Z";if(typeof N==="string"){let $=N.match(D2);if($){if(!$[1])H=!1,N=`0000-01-01T${N}`;if(Y=!!$[2],Y&&N[10]===" "&&(N=N.replace(" ","T")),$[2]&&+$[2]>23)N="";else if(W=$[3]||null,N=N.toUpperCase(),!W&&Y)N+="Z"}else N=""}super(N);if(!isNaN(this.getTime()))this.#H=H,this.#Y=Y,this.#N=W}isDateTime(){return this.#H&&this.#Y}isLocal(){return!this.#H||!this.#Y||!this.#N}isDate(){return this.#H&&!this.#Y}isTime(){return this.#Y&&!this.#H}isValid(){return this.#H||this.#Y}toISOString(){let N=super.toISOString();if(this.isDate())return N.slice(0,10);if(this.isTime())return N.slice(11,23);if(this.#N===null)return N.slice(0,-1);if(this.#N==="Z")return N;let H=+this.#N.slice(1,3)*60+ +this.#N.slice(4,6);return H=this.#N[0]==="-"?H:-H,new Date(this.getTime()-H*60000).toISOString().slice(0,-1)+this.#N}static wrapAsOffsetDateTime(N,H="Z"){let Y=new s(N);return Y.#N=H,Y}static wrapAsLocalDateTime(N){let H=new s(N);return H.#N=null,H}static wrapAsLocalDate(N){let H=new s(N);return H.#Y=!1,H.#N=null,H}static wrapAsLocalTime(N){let H=new s(N);return H.#H=!1,H.#N=null,H}}/*!
99
+ */var FY=/^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;class n extends Date{#U=!1;#H=!1;#N=null;constructor(N){let U=!0,H=!0,Y="Z";if(typeof N==="string"){let O=N.match(FY);if(O){if(!O[1])U=!1,N=`0000-01-01T${N}`;if(H=!!O[2],H&&N[10]===" "&&(N=N.replace(" ","T")),O[2]&&+O[2]>23)N="";else if(Y=O[3]||null,N=N.toUpperCase(),!Y&&H)N+="Z"}else N=""}super(N);if(!isNaN(this.getTime()))this.#U=U,this.#H=H,this.#N=Y}isDateTime(){return this.#U&&this.#H}isLocal(){return!this.#U||!this.#H||!this.#N}isDate(){return this.#U&&!this.#H}isTime(){return this.#H&&!this.#U}isValid(){return this.#U||this.#H}toISOString(){let N=super.toISOString();if(this.isDate())return N.slice(0,10);if(this.isTime())return N.slice(11,23);if(this.#N===null)return N.slice(0,-1);if(this.#N==="Z")return N;let U=+this.#N.slice(1,3)*60+ +this.#N.slice(4,6);return U=this.#N[0]==="-"?U:-U,new Date(this.getTime()-U*60000).toISOString().slice(0,-1)+this.#N}static wrapAsOffsetDateTime(N,U="Z"){let H=new n(N);return H.#N=U,H}static wrapAsLocalDateTime(N){let U=new n(N);return U.#N=null,U}static wrapAsLocalDate(N){let U=new n(N);return U.#H=!1,U.#N=null,U}static wrapAsLocalTime(N){let U=new n(N);return U.#U=!1,U.#N=null,U}}/*!
101
100
  * Copyright (c) Squirrel Chat et al., All rights reserved.
102
101
  * SPDX-License-Identifier: BSD-3-Clause
103
102
  *
@@ -123,13 +122,13 @@ ${$}`,H);this.line=Y,this.column=W,this.codeblock=$}}/*!
123
122
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
124
123
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
125
124
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
126
- */var C2=/^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/,R2=/^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/,S2=/^[+-]?0[0-9_]/,T2=/^[0-9a-f]{2,8}$/i,X1={b:"\b",t:"\t",n:`
127
- `,f:"\f",r:"\r",e:"\x1B",'"':'"',"\\":"\\"};function dN(N,H=0,Y=N.length){let W=N[H]==="'",$=N[H++]===N[H]&&N[H]===N[H+1];if($){if(Y-=2,N[H+=2]==="\r")H++;if(N[H]===`
128
- `)H++}let G=0,U,O="",Q=H;while(H<Y-1){let X=N[H++];if(X===`
129
- `||X==="\r"&&N[H]===`
130
- `){if(!$)throw new L("newlines are not allowed in strings",{toml:N,ptr:H-1})}else if(X<" "&&X!=="\t"||X==="\x7F")throw new L("control characters are not allowed in strings",{toml:N,ptr:H-1});if(U){if(U=!1,X==="x"||X==="u"||X==="U"){let F=N.slice(H,H+=X==="x"?2:X==="u"?4:8);if(!T2.test(F))throw new L("invalid unicode escape",{toml:N,ptr:G});try{O+=String.fromCodePoint(parseInt(F,16))}catch{throw new L("invalid unicode escape",{toml:N,ptr:G})}}else if($&&(X===`
131
- `||X===" "||X==="\t"||X==="\r")){if(H=_(N,H-1,!0),N[H]!==`
132
- `&&N[H]!=="\r")throw new L("invalid escape: only line-ending whitespace may be escaped",{toml:N,ptr:G});H=_(N,H)}else if(X in X1)O+=X1[X];else throw new L("unrecognized escape sequence",{toml:N,ptr:G});Q=H}else if(!W&&X==="\\")G=H-1,U=!0,O+=N.slice(Q,G)}return O+N.slice(Q,Y-1)}function Z1(N,H,Y,W){if(N==="true")return!0;if(N==="false")return!1;if(N==="-inf")return-1/0;if(N==="inf"||N==="+inf")return 1/0;if(N==="nan"||N==="+nan"||N==="-nan")return NaN;if(N==="-0")return W?0n:0;let $=C2.test(N);if($||R2.test(N)){if(S2.test(N))throw new L("leading zeroes are not allowed",{toml:H,ptr:Y});N=N.replace(/_/g,"");let U=+N;if(isNaN(U))throw new L("invalid number",{toml:H,ptr:Y});if($){if(($=!Number.isSafeInteger(U))&&!W)throw new L("integer value cannot be represented losslessly",{toml:H,ptr:Y});if($||W===!0)U=BigInt(N)}return U}let G=new s(N);if(!G.isValid())throw new L("invalid value",{toml:H,ptr:Y});return G}/*!
125
+ */var QY=/^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/,XY=/^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/,ZY=/^[+-]?0[0-9_]/,LY=/^[0-9a-f]{2,8}$/i,U1={b:"\b",t:"\t",n:`
126
+ `,f:"\f",r:"\r",e:"\x1B",'"':'"',"\\":"\\"};function uN(N,U=0,H=N.length){let Y=N[U]==="'",O=N[U++]===N[U]&&N[U]===N[U+1];if(O){if(H-=2,N[U+=2]==="\r")U++;if(N[U]===`
127
+ `)U++}let W=0,$,G="",F=U;while(U<H-1){let Q=N[U++];if(Q===`
128
+ `||Q==="\r"&&N[U]===`
129
+ `){if(!O)throw new V("newlines are not allowed in strings",{toml:N,ptr:U-1})}else if(Q<" "&&Q!=="\t"||Q==="\x7F")throw new V("control characters are not allowed in strings",{toml:N,ptr:U-1});if($){if($=!1,Q==="x"||Q==="u"||Q==="U"){let L=N.slice(U,U+=Q==="x"?2:Q==="u"?4:8);if(!LY.test(L))throw new V("invalid unicode escape",{toml:N,ptr:W});try{G+=String.fromCodePoint(parseInt(L,16))}catch{throw new V("invalid unicode escape",{toml:N,ptr:W})}}else if(O&&(Q===`
130
+ `||Q===" "||Q==="\t"||Q==="\r")){if(U=S(N,U-1,!0),N[U]!==`
131
+ `&&N[U]!=="\r")throw new V("invalid escape: only line-ending whitespace may be escaped",{toml:N,ptr:W});U=S(N,U)}else if(Q in U1)G+=U1[Q];else throw new V("unrecognized escape sequence",{toml:N,ptr:W});F=U}else if(!Y&&Q==="\\")W=U-1,$=!0,G+=N.slice(F,W)}return G+N.slice(F,H-1)}function H1(N,U,H,Y){if(N==="true")return!0;if(N==="false")return!1;if(N==="-inf")return-1/0;if(N==="inf"||N==="+inf")return 1/0;if(N==="nan"||N==="+nan"||N==="-nan")return NaN;if(N==="-0")return Y?0n:0;let O=QY.test(N);if(O||XY.test(N)){if(ZY.test(N))throw new V("leading zeroes are not allowed",{toml:U,ptr:H});N=N.replace(/_/g,"");let $=+N;if(isNaN($))throw new V("invalid number",{toml:U,ptr:H});if(O){if((O=!Number.isSafeInteger($))&&!Y)throw new V("integer value cannot be represented losslessly",{toml:U,ptr:H});if(O||Y===!0)$=BigInt(N)}return $}let W=new n(N);if(!W.isValid())throw new V("invalid value",{toml:U,ptr:H});return W}/*!
133
132
  * Copyright (c) Squirrel Chat et al., All rights reserved.
134
133
  * SPDX-License-Identifier: BSD-3-Clause
135
134
  *
@@ -155,8 +154,8 @@ ${$}`,H);this.line=Y,this.column=W,this.codeblock=$}}/*!
155
154
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
156
155
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
157
156
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
158
- */function E2(N,H,Y){let W=N.slice(H,Y),$=W.indexOf("#");if($>-1)XN(N,$),W=W.slice(0,$);return[W.trimEnd(),$]}function EN(N,H,Y,W,$){if(W===0)throw new L("document contains excessively nested structures. aborting.",{toml:N,ptr:H});let G=N[H];if(G==="["||G==="{"){let[Q,X]=G==="["?F1(N,H,W,$):z1(N,H,W,$);if(Y){if(X=_(N,X),N[X]===",")X++;else if(N[X]!==Y)throw new L("expected comma or end of structure",{toml:N,ptr:X})}return[Q,X]}let U;if(G==='"'||G==="'"){U=nN(N,H);let Q=dN(N,H,U);if(Y){if(U=_(N,U),N[U]&&N[U]!==","&&N[U]!==Y&&N[U]!==`
159
- `&&N[U]!=="\r")throw new L("unexpected character encountered",{toml:N,ptr:U});U+=+(N[U]===",")}return[Q,U]}U=Q1(N,H,",",Y);let O=E2(N,H,U-+(N[U-1]===","));if(!O[0])throw new L("incomplete key-value declaration: no value specified",{toml:N,ptr:H});if(Y&&O[1]>-1)U=_(N,H+O[1]),U+=+(N[U]===",");return[Z1(O[0],N,H,$),U]}/*!
157
+ */function zY(N,U,H){let Y=N.slice(U,H),O=Y.indexOf("#");if(O>-1)GN(N,O),Y=Y.slice(0,O);return[Y.trimEnd(),O]}function BN(N,U,H,Y,O){if(Y===0)throw new V("document contains excessively nested structures. aborting.",{toml:N,ptr:U});let W=N[U];if(W==="["||W==="{"){let[F,Q]=W==="["?O1(N,U,Y,O):Y1(N,U,Y,O);if(H){if(Q=S(N,Q),N[Q]===",")Q++;else if(N[Q]!==H)throw new V("expected comma or end of structure",{toml:N,ptr:Q})}return[F,Q]}let $;if(W==='"'||W==="'"){$=pN(N,U);let F=uN(N,U,$);if(H){if($=S(N,$),N[$]&&N[$]!==","&&N[$]!==H&&N[$]!==`
158
+ `&&N[$]!=="\r")throw new V("unexpected character encountered",{toml:N,ptr:$});$+=+(N[$]===",")}return[F,$]}$=N1(N,U,",",H);let G=zY(N,U,$-+(N[$-1]===","));if(!G[0])throw new V("incomplete key-value declaration: no value specified",{toml:N,ptr:U});if(H&&G[1]>-1)$=S(N,U+G[1]),$+=+(N[$]===",");return[H1(G[0],N,U,O),$]}/*!
160
159
  * Copyright (c) Squirrel Chat et al., All rights reserved.
161
160
  * SPDX-License-Identifier: BSD-3-Clause
162
161
  *
@@ -182,9 +181,9 @@ ${$}`,H);this.line=Y,this.column=W,this.codeblock=$}}/*!
182
181
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
183
182
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
184
183
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
185
- */var w2=/^[a-zA-Z0-9-_]+[ \t]*$/;function oN(N,H,Y="="){let W=H-1,$=[],G=N.indexOf(Y,H);if(G<0)throw new L("incomplete key-value: cannot find end of key",{toml:N,ptr:H});do{let U=N[H=++W];if(U!==" "&&U!=="\t")if(U==='"'||U==="'"){if(U===N[H+1]&&U===N[H+2])throw new L("multiline strings are not allowed in keys",{toml:N,ptr:H});let O=nN(N,H);if(O<0)throw new L("unfinished string encountered",{toml:N,ptr:H});W=N.indexOf(".",O);let Q=N.slice(O,W<0||W>G?G:W),X=pN(Q);if(X>-1)throw new L("newlines are not allowed in keys",{toml:N,ptr:H+W+X});if(Q.trimStart())throw new L("found extra tokens after the string part",{toml:N,ptr:O});if(G<O){if(G=N.indexOf(Y,O),G<0)throw new L("incomplete key-value: cannot find end of key",{toml:N,ptr:H})}$.push(dN(N,H,O))}else{W=N.indexOf(".",H);let O=N.slice(H,W<0||W>G?G:W);if(!w2.test(O))throw new L("only letter, numbers, dashes and underscores are allowed in keys",{toml:N,ptr:H});$.push(O.trimEnd())}}while(W+1&&W<G);return[$,_(N,G+1,!0,!0)]}function z1(N,H,Y,W){let $={},G=new Set,U;H++;while((U=N[H++])!=="}"&&U)if(U===",")throw new L("expected value, found comma",{toml:N,ptr:H-1});else if(U==="#")H=XN(N,H);else if(U!==" "&&U!=="\t"&&U!==`
186
- `&&U!=="\r"){let O,Q=$,X=!1,[F,M]=oN(N,H-1);for(let ON=0;ON<F.length;ON++){if(ON)Q=X?Q[O]:Q[O]={};if(O=F[ON],(X=Object.hasOwn(Q,O))&&(typeof Q[O]!=="object"||G.has(Q[O])))throw new L("trying to redefine an already defined value",{toml:N,ptr:H});if(!X&&O==="__proto__")Object.defineProperty(Q,O,{enumerable:!0,configurable:!0,writable:!0})}if(X)throw new L("trying to redefine an already defined value",{toml:N,ptr:H});let[T,f]=EN(N,M,"}",Y-1,W);G.add(T),Q[O]=T,H=f}if(!U)throw new L("unfinished table encountered",{toml:N,ptr:H});return[$,H]}function F1(N,H,Y,W){let $=[],G;H++;while((G=N[H++])!=="]"&&G)if(G===",")throw new L("expected value, found comma",{toml:N,ptr:H-1});else if(G==="#")H=XN(N,H);else if(G!==" "&&G!=="\t"&&G!==`
187
- `&&G!=="\r"){let U=EN(N,H-1,"]",Y-1,W);$.push(U[0]),H=U[1]}if(!G)throw new L("unfinished array encountered",{toml:N,ptr:H});return[$,H]}/*!
184
+ */var VY=/^[a-zA-Z0-9-_]+[ \t]*$/;function iN(N,U,H="="){let Y=U-1,O=[],W=N.indexOf(H,U);if(W<0)throw new V("incomplete key-value: cannot find end of key",{toml:N,ptr:U});do{let $=N[U=++Y];if($!==" "&&$!=="\t")if($==='"'||$==="'"){if($===N[U+1]&&$===N[U+2])throw new V("multiline strings are not allowed in keys",{toml:N,ptr:U});let G=pN(N,U);if(G<0)throw new V("unfinished string encountered",{toml:N,ptr:U});Y=N.indexOf(".",G);let F=N.slice(G,Y<0||Y>W?W:Y),Q=lN(F);if(Q>-1)throw new V("newlines are not allowed in keys",{toml:N,ptr:U+Y+Q});if(F.trimStart())throw new V("found extra tokens after the string part",{toml:N,ptr:G});if(W<G){if(W=N.indexOf(H,G),W<0)throw new V("incomplete key-value: cannot find end of key",{toml:N,ptr:U})}O.push(uN(N,U,G))}else{Y=N.indexOf(".",U);let G=N.slice(U,Y<0||Y>W?W:Y);if(!VY.test(G))throw new V("only letter, numbers, dashes and underscores are allowed in keys",{toml:N,ptr:U});O.push(G.trimEnd())}}while(Y+1&&Y<W);return[O,S(N,W+1,!0,!0)]}function Y1(N,U,H,Y){let O={},W=new Set,$;U++;while(($=N[U++])!=="}"&&$)if($===",")throw new V("expected value, found comma",{toml:N,ptr:U-1});else if($==="#")U=GN(N,U);else if($!==" "&&$!=="\t"&&$!==`
185
+ `&&$!=="\r"){let G,F=O,Q=!1,[L,K]=iN(N,U-1);for(let WN=0;WN<L.length;WN++){if(WN)F=Q?F[G]:F[G]={};if(G=L[WN],(Q=Object.hasOwn(F,G))&&(typeof F[G]!=="object"||W.has(F[G])))throw new V("trying to redefine an already defined value",{toml:N,ptr:U});if(!Q&&G==="__proto__")Object.defineProperty(F,G,{enumerable:!0,configurable:!0,writable:!0})}if(Q)throw new V("trying to redefine an already defined value",{toml:N,ptr:U});let[E,r]=BN(N,K,"}",H-1,Y);W.add(E),F[G]=E,U=r}if(!$)throw new V("unfinished table encountered",{toml:N,ptr:U});return[O,U]}function O1(N,U,H,Y){let O=[],W;U++;while((W=N[U++])!=="]"&&W)if(W===",")throw new V("expected value, found comma",{toml:N,ptr:U-1});else if(W==="#")U=GN(N,U);else if(W!==" "&&W!=="\t"&&W!==`
186
+ `&&W!=="\r"){let $=BN(N,U-1,"]",H-1,Y);O.push($[0]),U=$[1]}if(!W)throw new V("unfinished array encountered",{toml:N,ptr:U});return[O,U]}/*!
188
187
  * Copyright (c) Squirrel Chat et al., All rights reserved.
189
188
  * SPDX-License-Identifier: BSD-3-Clause
190
189
  *
@@ -210,8 +209,8 @@ ${$}`,H);this.line=Y,this.column=W,this.codeblock=$}}/*!
210
209
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
211
210
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
212
211
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
213
- */function V1(N,H,Y,W){let $=H,G=Y,U,O=!1,Q;for(let X=0;X<N.length;X++){if(X){if($=O?$[U]:$[U]={},G=(Q=G[U]).c,W===0&&(Q.t===1||Q.t===2))return null;if(Q.t===2){let F=$.length-1;$=$[F],G=G[F].c}}if(U=N[X],(O=Object.hasOwn($,U))&&G[U]?.t===0&&G[U]?.d)return null;if(!O){if(U==="__proto__")Object.defineProperty($,U,{enumerable:!0,configurable:!0,writable:!0}),Object.defineProperty(G,U,{enumerable:!0,configurable:!0,writable:!0});G[U]={t:X<N.length-1&&W===2?3:W,d:!1,i:0,c:{}}}}if(Q=G[U],Q.t!==W&&!(W===1&&Q.t===3))return null;if(W===2){if(!Q.d)Q.d=!0,$[U]=[];$[U].push($={}),Q.c[Q.i++]=Q={t:1,d:!1,i:0,c:{}}}if(Q.d)return null;if(Q.d=!0,W===1)$=O?$[U]:$[U]={};else if(W===0&&O)return null;return[U,$,Q.c]}function l(N,{maxDepth:H=1000,integersAsBigInt:Y}={}){let W={},$={},G=W,U=$;for(let O=_(N,0);O<N.length;){if(N[O]==="["){let Q=N[++O]==="[",X=oN(N,O+=+Q,"]");if(Q){if(N[X[1]-1]!=="]")throw new L("expected end of table declaration",{toml:N,ptr:X[1]-1});X[1]++}let F=V1(X[0],W,$,Q?2:1);if(!F)throw new L("trying to redefine an already defined table or value",{toml:N,ptr:O});U=F[2],G=F[1],O=X[1]}else{let Q=oN(N,O),X=V1(Q[0],G,U,0);if(!X)throw new L("trying to redefine an already defined table or value",{toml:N,ptr:O});let F=EN(N,Q[1],void 0,H,Y);X[1][X[0]]=F[0],O=F[1]}if(O=_(N,O,!0),N[O]&&N[O]!==`
214
- `&&N[O]!=="\r")throw new L("each key-value declaration must be followed by an end-of-line",{toml:N,ptr:O});O=_(N,O)}return W}/*!
212
+ */function W1(N,U,H,Y){let O=U,W=H,$,G=!1,F;for(let Q=0;Q<N.length;Q++){if(Q){if(O=G?O[$]:O[$]={},W=(F=W[$]).c,Y===0&&(F.t===1||F.t===2))return null;if(F.t===2){let L=O.length-1;O=O[L],W=W[L].c}}if($=N[Q],(G=Object.hasOwn(O,$))&&W[$]?.t===0&&W[$]?.d)return null;if(!G){if($==="__proto__")Object.defineProperty(O,$,{enumerable:!0,configurable:!0,writable:!0}),Object.defineProperty(W,$,{enumerable:!0,configurable:!0,writable:!0});W[$]={t:Q<N.length-1&&Y===2?3:Y,d:!1,i:0,c:{}}}}if(F=W[$],F.t!==Y&&!(Y===1&&F.t===3))return null;if(Y===2){if(!F.d)F.d=!0,O[$]=[];O[$].push(O={}),F.c[F.i++]=F={t:1,d:!1,i:0,c:{}}}if(F.d)return null;if(F.d=!0,Y===1)O=G?O[$]:O[$]={};else if(Y===0&&G)return null;return[$,O,F.c]}function m(N,{maxDepth:U=1000,integersAsBigInt:H}={}){let Y={},O={},W=Y,$=O;for(let G=S(N,0);G<N.length;){if(N[G]==="["){let F=N[++G]==="[",Q=iN(N,G+=+F,"]");if(F){if(N[Q[1]-1]!=="]")throw new V("expected end of table declaration",{toml:N,ptr:Q[1]-1});Q[1]++}let L=W1(Q[0],Y,O,F?2:1);if(!L)throw new V("trying to redefine an already defined table or value",{toml:N,ptr:G});$=L[2],W=L[1],G=Q[1]}else{let F=iN(N,G),Q=W1(F[0],W,$,0);if(!Q)throw new V("trying to redefine an already defined table or value",{toml:N,ptr:G});let L=BN(N,F[1],void 0,U,H);Q[1][Q[0]]=L[0],G=L[1]}if(G=S(N,G,!0),N[G]&&N[G]!==`
213
+ `&&N[G]!=="\r")throw new V("each key-value declaration must be followed by an end-of-line",{toml:N,ptr:G});G=S(N,G)}return Y}/*!
215
214
  * Copyright (c) Squirrel Chat et al., All rights reserved.
216
215
  * SPDX-License-Identifier: BSD-3-Clause
217
216
  *
@@ -237,16 +236,16 @@ ${$}`,H);this.line=Y,this.column=W,this.codeblock=$}}/*!
237
236
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
238
237
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
239
238
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
240
- */var K1=/^[a-z0-9-_]+$/i;function wN(N){let H=typeof N;if(H==="object"){if(Array.isArray(N))return"array";if(N instanceof Date)return"date"}return H}function _2(N){for(let H=0;H<N.length;H++)if(wN(N[H])!=="object")return!1;return N.length!=0}function T0(N){return JSON.stringify(N).replace(/\x7f/g,"\\u007f")}function E0(N,H,Y,W){if(Y===0)throw Error("Could not stringify the object: maximum object depth exceeded");if(H==="number"){if(isNaN(N))return"nan";if(N===1/0)return"inf";if(N===-1/0)return"-inf";if(W&&Number.isInteger(N))return N.toFixed(1);return N.toString()}if(H==="bigint"||H==="boolean")return N.toString();if(H==="string")return T0(N);if(H==="date"){if(isNaN(N.getTime()))throw TypeError("cannot serialize invalid date");return N.toISOString()}if(H==="object")return P2(N,Y,W);if(H==="array")return x2(N,Y,W)}function P2(N,H,Y){let W=Object.keys(N);if(W.length===0)return"{}";let $="{ ";for(let G=0;G<W.length;G++){let U=W[G];if(G)$+=", ";$+=K1.test(U)?U:T0(U),$+=" = ",$+=E0(N[U],wN(N[U]),H-1,Y)}return $+" }"}function x2(N,H,Y){if(N.length===0)return"[]";let W="[ ";for(let $=0;$<N.length;$++){if($)W+=", ";if(N[$]===null||N[$]===void 0)throw TypeError("arrays cannot contain null or undefined values");W+=E0(N[$],wN(N[$]),H-1,Y)}return W+" ]"}function f2(N,H,Y,W){if(Y===0)throw Error("Could not stringify the object: maximum object depth exceeded");let $="";for(let G=0;G<N.length;G++)$+=`${$&&`
241
- `}[[${H}]]
242
- `,$+=w0(0,N[G],H,Y,W);return $}function w0(N,H,Y,W,$){if(W===0)throw Error("Could not stringify the object: maximum object depth exceeded");let G="",U="",O=Object.keys(H);for(let Q=0;Q<O.length;Q++){let X=O[Q];if(H[X]!==null&&H[X]!==void 0){let F=wN(H[X]);if(F==="symbol"||F==="function")throw TypeError(`cannot serialize values of type '${F}'`);let M=K1.test(X)?X:T0(X);if(F==="array"&&_2(H[X]))U+=(U&&`
243
- `)+f2(H[X],Y?`${Y}.${M}`:M,W-1,$);else if(F==="object"){let T=Y?`${Y}.${M}`:M;U+=(U&&`
244
- `)+w0(T,H[X],T,W-1,$)}else G+=M,G+=" = ",G+=E0(H[X],F,W,$),G+=`
245
- `}}if(N&&(G||!U))G=G?`[${N}]
246
- ${G}`:`[${N}]`;return G&&U?`${G}
247
- ${U}`:G||U}function t(N,{maxDepth:H=1000,numbersAsFloat:Y=!1}={}){if(wN(N)!=="object")throw TypeError("stringify can only be called with an object");let W=w0(0,N,"",H,Y);if(W[W.length-1]!==`
248
- `)return W+`
249
- `;return W}/*!
239
+ */var $1=/^[a-z0-9-_]+$/i;function CN(N){let U=typeof N;if(U==="object"){if(Array.isArray(N))return"array";if(N instanceof Date)return"date"}return U}function DY(N){for(let U=0;U<N.length;U++)if(CN(N[U])!=="object")return!1;return N.length!=0}function E0(N){return JSON.stringify(N).replace(/\x7f/g,"\\u007f")}function T0(N,U,H,Y){if(H===0)throw Error("Could not stringify the object: maximum object depth exceeded");if(U==="number"){if(isNaN(N))return"nan";if(N===1/0)return"inf";if(N===-1/0)return"-inf";if(Y&&Number.isInteger(N))return N.toFixed(1);return N.toString()}if(U==="bigint"||U==="boolean")return N.toString();if(U==="string")return E0(N);if(U==="date"){if(isNaN(N.getTime()))throw TypeError("cannot serialize invalid date");return N.toISOString()}if(U==="object")return KY(N,H,Y);if(U==="array")return MY(N,H,Y)}function KY(N,U,H){let Y=Object.keys(N);if(Y.length===0)return"{}";let O="{ ";for(let W=0;W<Y.length;W++){let $=Y[W];if(W)O+=", ";O+=$1.test($)?$:E0($),O+=" = ",O+=T0(N[$],CN(N[$]),U-1,H)}return O+" }"}function MY(N,U,H){if(N.length===0)return"[]";let Y="[ ";for(let O=0;O<N.length;O++){if(O)Y+=", ";if(N[O]===null||N[O]===void 0)throw TypeError("arrays cannot contain null or undefined values");Y+=T0(N[O],CN(N[O]),U-1,H)}return Y+" ]"}function JY(N,U,H,Y){if(H===0)throw Error("Could not stringify the object: maximum object depth exceeded");let O="";for(let W=0;W<N.length;W++)O+=`${O&&`
240
+ `}[[${U}]]
241
+ `,O+=B0(0,N[W],U,H,Y);return O}function B0(N,U,H,Y,O){if(Y===0)throw Error("Could not stringify the object: maximum object depth exceeded");let W="",$="",G=Object.keys(U);for(let F=0;F<G.length;F++){let Q=G[F];if(U[Q]!==null&&U[Q]!==void 0){let L=CN(U[Q]);if(L==="symbol"||L==="function")throw TypeError(`cannot serialize values of type '${L}'`);let K=$1.test(Q)?Q:E0(Q);if(L==="array"&&DY(U[Q]))$+=($&&`
242
+ `)+JY(U[Q],H?`${H}.${K}`:K,Y-1,O);else if(L==="object"){let E=H?`${H}.${K}`:K;$+=($&&`
243
+ `)+B0(E,U[Q],E,Y-1,O)}else W+=K,W+=" = ",W+=T0(U[Q],L,Y,O),W+=`
244
+ `}}if(N&&(W||!$))W=W?`[${N}]
245
+ ${W}`:`[${N}]`;return W&&$?`${W}
246
+ ${$}`:W||$}function a(N,{maxDepth:U=1000,numbersAsFloat:H=!1}={}){if(CN(N)!=="object")throw TypeError("stringify can only be called with an object");let Y=B0(0,N,"",U,H);if(Y[Y.length-1]!==`
247
+ `)return Y+`
248
+ `;return Y}/*!
250
249
  * Copyright (c) Squirrel Chat et al., All rights reserved.
251
250
  * SPDX-License-Identifier: BSD-3-Clause
252
251
  *
@@ -272,13 +271,13 @@ ${U}`:G||U}function t(N,{maxDepth:H=1000,numbersAsFloat:Y=!1}={}){if(wN(N)!=="ob
272
271
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
273
272
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
274
273
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275
- */function Z(N,H=200){return new Response(JSON.stringify(N),{status:H,headers:{"content-type":"application/json"}})}function z(N,H,Y){return Z({error:H,detail:Y},N)}async function V(N){try{return await N.json()}catch{throw new A("Invalid JSON body")}}function J(N,H){if(typeof N!=="string"||N.length===0)throw new A(`Missing or invalid field: ${H}`);return N}class A extends Error{constructor(N){super(N);this.name="BadRequestError"}}import{promises as g}from"fs";import v from"path";import _0 from"path";function HN(N,H){let Y=_0.resolve(N),W=_0.resolve(Y,H||".");if(W!==Y&&!W.startsWith(Y+_0.sep))throw new aN(H);return W}class aN extends Error{constructor(N){super(`Path escapes workspace: ${N}`);this.name="PathEscapeError"}}var k2=2097152,y2=new Set([".png",".jpg",".jpeg",".gif",".webp",".svg",".bmp",".ico",".avif"]),b2=new Set([".zip",".tar",".gz",".7z",".exe",".dll",".so",".dylib",".pdf",".woff",".woff2",".ttf",".mp3",".mp4",".mov",".webm",".sqlite",".db",".bin"]);function q2(N){let H=v.extname(N).toLowerCase();if(H===".md"||H===".markdown")return"markdown";if(H===".json"||H===".jsonl")return"json";if(y2.has(H))return"image";if(b2.has(H))return"binary";return"text"}function r(N,H){return HN(B(H),N)}function P0(N,H){let Y=v.relative(B(H),N);return Y===""?".":u(Y)}async function L1(N,H){let Y=await g.stat(N),W={name:v.basename(N)||".",path:P0(N,H),type:Y.isDirectory()?"dir":"file",modifiedAt:Y.mtime.toISOString()};if(W.type==="file")return W.size=Y.size,W;let $=await g.readdir(N,{withFileTypes:!0}),G=await Promise.all($.map((U)=>L1(v.join(N,U.name),H)));return G.sort((U,O)=>U.type!==O.type?U.type==="dir"?-1:1:U.name.localeCompare(O.name)),W.children=G,W}async function M1(N=".",H=K){return L1(r(N,H),H)}async function J1(N,H=K){let Y=r(N,H),W=await g.stat(Y);if(W.isDirectory())throw Error(`Not a file: ${N}`);let $=q2(Y),G={path:P0(Y,H),kind:$,size:W.size,modifiedAt:W.mtime.toISOString()};if($==="image"||$==="binary")return G;if(W.size>k2)throw Error(`File too large to open (${W.size} bytes): ${N}`);return G.content=await g.readFile(Y,"utf8"),G}async function B1(N,H,Y=K){let W=r(N,Y);await g.mkdir(v.dirname(W),{recursive:!0}),await g.writeFile(W,H,"utf8")}async function A1(N,H=K){await g.mkdir(r(N,H),{recursive:!0})}async function D1(N,H=K){let Y=r(N,H);if(Y===v.resolve(B(H)))throw Error("Cannot delete the workspace root");await g.rm(Y,{recursive:!0,force:!0})}async function C1(N,H,Y=K){let W=r(N,Y),$=r(H,Y);if(W===v.resolve(B(Y)))throw Error("Cannot rename the workspace root");await g.mkdir(v.dirname($),{recursive:!0}),await g.rename(W,$)}async function R1(N,H,Y,W=K){let $=v.basename(H);if(!$||$==="."||$==="..")throw Error(`Invalid file name: ${H}`);let G=HN(B(W),v.join(N||".",$));return await g.mkdir(v.dirname(G),{recursive:!0}),await Bun.write(G,Y),P0(G,W)}function sN(N,H=K){return r(N,H)}import{randomBytes as I2}from"crypto";function tN(N){return`${N}_${I2(6).toString("hex")}`}var x0=null;function T1(N){x0=N}function h(N,H){x0?.publish(N,JSON.stringify(H))}function E1(N,H){x0?.publish(N,H)}import{promises as _N}from"fs";import j2 from"os";import f0 from"path";var e=new Map,w1=!1;function k0(N){return f0.join(o(),N,"meta.json")}var _1=f0.join(j2.homedir(),".agenthost");function P1(N){let H=JSON.parse(N);if(H.cwd?.startsWith(_1))H.cwd=I+H.cwd.slice(_1.length);return H}async function x1(N){await _N.mkdir(f0.join(o(),N.id),{recursive:!0}),await _N.writeFile(k0(N.id),JSON.stringify(N,null,2)+`
276
- `,"utf8")}async function v2(){if(w1)return;w1=!0;let N;try{N=await _N.readdir(o())}catch{return}for(let H of N){if(e.has(H))continue;try{let Y=await _N.readFile(k0(H),"utf8"),W=P1(Y);e.set(W.id,W)}catch{}}}async function f1(N){let H={id:tN("run"),projectId:N.projectId??K,prompt:N.prompt,status:"starting",startedAt:new Date().toISOString(),cwd:N.cwd,sandbox:N.sandbox,approvalPolicy:N.approvalPolicy,approvalsReviewer:N.approvalsReviewer,model:N.model,effort:N.effort,source:N.source,scheduleId:N.scheduleId,scheduleName:N.scheduleName};return e.set(H.id,H),await x1(H),H}async function YN(N,H){let Y=await D(N);if(!Y)return null;let W={...Y,...H};return e.set(N,W),await x1(W),W}async function D(N){if(e.has(N))return e.get(N);try{let H=await _N.readFile(k0(N),"utf8"),Y=P1(H);return e.set(N,Y),Y}catch{return null}}async function k1(N){await v2();let H=[...e.values()];return(N?H.filter((W)=>W.projectId===N):H).sort((W,$)=>$.startedAt.localeCompare(W.startedAt))}function m(N){return N==="queued"||N==="starting"||N==="running"||N==="waiting_approval"}import{promises as y1}from"fs";import g2 from"path";function b1(N){return g2.join(o(),N,"events.jsonl")}async function q1(N){await y1.appendFile(b1(N.runId),JSON.stringify(N)+`
277
- `,"utf8")}var h2=/"type":\s*"run\.(started|resumed|steered)"/,m2=400;async function I1(N,H={}){let Y;try{Y=await y1.readFile(b1(N),"utf8")}catch{return{events:[],offset:0,total:0}}let W=Y.split(`
278
- `);if(W.length>0&&W[W.length-1]==="")W.pop();let $=W.length,G=Math.max(0,Math.min(H.before??$,$)),U=H.limit===void 0?0:Math.max(0,G-H.limit);if(U>0){for(let Q=U;Q>=Math.max(0,U-m2);Q--)if(h2.test(W[Q])){U=Q;break}}let O=[];for(let Q=U;Q<G;Q++){let X=W[Q].trim();if(!X)continue;try{O.push(JSON.parse(X))}catch{}}return{events:O,offset:U,total:$}}import{promises as LH}from"fs";import YW from"os";import MH from"path";var v1={name:"junhost",version:"0.2.1",description:"Jun \u2014 a self-hosted dashboard that runs and supervises Codex as a 24/7 local/VPS agent: chat runs, workspace files, remote browser, skills, MCP, schedules.",type:"module",bin:{jun:"bin/jun.js"},files:["bin","dist","ui-dist","README.md"],engines:{bun:">=1.2.0"},keywords:["codex","agent","ai","dashboard","self-hosted","browser-automation","mcp"],license:"UNLICENSED",scripts:{dev:"bun --hot src/index.ts",start:"bun src/index.ts",build:"bun build src/index.ts src/mcp-server.ts src/browser-mcp-server.ts --target=bun --minify --outdir=dist",typecheck:"bunx tsc --noEmit"},dependencies:{"agent-browser":"^0.27.1",cloakbrowser:"^0.3.31"},devDependencies:{"@junhost/shared":"workspace:*","@modelcontextprotocol/sdk":"^1.29.0","@types/bun":"^1.2.0","smol-toml":"^1.6.1",typescript:"^5.6.3",zod:"3"}};var ZN=v1.version;import p2 from"os";import P from"path";import{existsSync as fN,readdirSync as n2}from"fs";import{mkdir as p1}from"fs/promises";import{randomUUID as d2}from"crypto";import{readFileSync as l2}from"fs";import{promises as u2}from"fs";import i2 from"path";var g1=["browserProxy","browserNoProxy"];function h1(){return i2.join(I,"config.json")}var rN=null;function eN(){if(rN)return rN;let N={};try{N=JSON.parse(l2(h1(),"utf8"))}catch{}let H={};for(let Y of g1){let W=N[Y];if(typeof W==="string"&&W.length>0)H[Y]=W}return rN=H,H}async function m1(N){let H={...eN()};for(let Y of g1){if(!(Y in N))continue;let W=N[Y];if(typeof W==="string"&&W.trim().length>0)H[Y]=W.trim();else delete H[Y]}return await u2.writeFile(h1(),JSON.stringify(H,null,2)+`
279
- `,"utf8"),rN=H,H}var o2="jun",c1=200,n1=process.platform==="win32"?"agent-browser.exe":"agent-browser";function d1(){let N=import.meta.dir;for(let H=0;H<8;H++){let Y=P.join(N,"node_modules",".bin");if(fN(P.join(Y,n1)))return Y;let W=P.dirname(N);if(W===N)break;N=W}return null}function a2(N){let H=d1();if(H)return[P.join(H,n1),...N];return process.platform==="win32"?["cmd","/c","agent-browser",...N]:["agent-browser",...N]}var l1=Object.keys(process.env).find((N)=>N.toUpperCase()==="PATH")??"PATH",W0="agent",H0=null,N0=[];function o1(){let N=q("CLOAK_PATH");if(N&&fN(N))return N;let H=P.join(p2.homedir(),".cloakbrowser"),Y;try{Y=n2(H).filter(($)=>$.startsWith("chromium-"))}catch{return null}Y.sort().reverse();let W=process.platform==="win32"?"chrome.exe":"chrome";for(let $ of Y){let G=P.join(H,$,W);if(fN(G))return G}return null}function s2(){let N=q("CHROME_PATH");if(N&&fN(N))return N;return(process.platform==="win32"?[`${process.env.ProgramFiles}\\Google\\Chrome\\Application\\chrome.exe`,`${process.env["ProgramFiles(x86)"]}\\Google\\Chrome\\Application\\chrome.exe`,`${process.env.LocalAppData}\\Google\\Chrome\\Application\\chrome.exe`]:process.platform==="darwin"?["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"]:["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/opt/google/chrome/chrome"]).find((Y)=>Y&&fN(Y))??null}function q0(){let N={AGENT_BROWSER_SESSION:o2,AGENT_BROWSER_PROFILE:P.join(SN(),"profile"),AGENT_BROWSER_DOWNLOAD_PATH:P.join(B(),"downloads"),AGENT_BROWSER_SCREENSHOT_DIR:P.join(B(),"screenshots"),AGENT_BROWSER_ARGS:"--disable-blink-features=AutomationControlled"},H=$0().value;if(H)N.AGENT_BROWSER_PROXY=H;let Y=G0().value;if(Y)N.AGENT_BROWSER_PROXY_BYPASS=Y;let W=d1();if(W)N[l1]=`${W}${P.delimiter}${process.env[l1]??""}`;let $=o1();if($)return N.AGENT_BROWSER_EXECUTABLE_PATH=$,N;let G=s2(),U=process.platform!=="linux"||Boolean(process.env.DISPLAY),O=q("BROWSER_HEADED")!=="false"&&U;if(process.platform==="linux"&&!process.env.DISPLAY&&q("BROWSER_HEADED")!=="false")console.warn("[browser] No cloakbrowser engine and no DISPLAY \u2014 running HEADLESS. Edge "+"WAFs (Reddit/Fastly) will block headless. Install cloakbrowser (works headless) or set up Xvfb + Google Chrome with DISPLAY for a VPS.");if(G&&O)N.AGENT_BROWSER_EXECUTABLE_PATH=G,N.AGENT_BROWSER_HEADED="true";else{if(G)N.AGENT_BROWSER_EXECUTABLE_PATH=G;N.AGENT_BROWSER_USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36"}return N}function t2(){return{...process.env,...q0()}}function r2(){let N=$0().value;if(!N)return[];let H=["--proxy",N],Y=G0().value;if(Y)H.push("--proxy-bypass",Y);return H}function $0(){let N=eN().browserProxy;if(N)return{value:N,source:"settings"};let H=q("BROWSER_PROXY")?.trim();if(H)return{value:H,source:"env"};return{value:null,source:"none"}}function G0(){let N=eN().browserNoProxy;if(N)return{value:N,source:"settings"};let H=q("BROWSER_NO_PROXY")?.trim();if(H)return{value:H,source:"env"};return{value:null,source:"none"}}var b0=!1;function a1(N){if(b0)return;if(q("NO_CLOAK_DOWNLOAD")==="true")return;if(o1())return;b0=!0,console.log("[browser] cloakbrowser Stealth Chromium not found \u2014 downloading in background\u2026"),Bun.spawn([process.execPath,"x","cloakbrowser","install"],{cwd:N,stdout:"inherit",stderr:"inherit"}).exited.then((Y)=>{if(b0=!1,Y===0)console.log("[browser] cloakbrowser Stealth Chromium ready.");else console.warn(`[browser] cloakbrowser download exited with code ${Y}.`)})}async function u1(N,H,Y){if(!N)return"";let W=N.getReader(),$=new TextDecoder,G="",U=Date.now()+Y;try{while(Date.now()<U){let O=Math.min(H,U-Date.now()),Q=await Promise.race([W.read(),new Promise((X)=>setTimeout(()=>X("timeout"),O))]);if(Q==="timeout"||Q.done)break;G+=$.decode(Q.value,{stream:!0})}}finally{W.releaseLock()}return G}async function S(N,H={}){let Y=[...r2(),...N],W=H.json?[...Y,"--json"]:Y,$=Bun.spawn(a2(W),{env:t2(),stdout:"pipe",stderr:"pipe"}),G=setTimeout(()=>$.kill(),H.timeoutMs??120000),U=await $.exited;clearTimeout(G);let[O,Q]=await Promise.all([u1($.stdout,80,1500),u1($.stderr,60,300)]),X,F;if(H.json)try{let M=JSON.parse(O);if(X=M.data??M,M.success===!1)F=typeof M.error==="string"?M.error:"command failed"}catch{}return{ok:U===0&&!F,stdout:O,stderr:Q,data:X,error:F}}function p(N,H){if(N0.unshift({id:d2(),ts:new Date().toISOString(),kind:N,detail:H}),N0.length>c1)N0.length=c1}function s1(){return N0}function t1(){return W0}function r1(N){W0=N,p("control",N)}function e1(){return H0}var NH=(N)=>typeof N==="object"&&N!==null?N:{};function Y0(N){if(typeof N==="string")return N;let H=NH(N);for(let Y of["url","title","value","text","result"])if(typeof H[Y]==="string")return H[Y];return null}var e2=2500,xN=null,PN=null;function n(){xN=null}async function kN(){if(xN&&Date.now()-xN.at<e2)return{...xN.status,controller:W0};if(PN)return PN;return PN=NW().then((N)=>{return xN={at:Date.now(),status:N},N}).finally(()=>{PN=null}),PN}async function NW(){let N=await S(["stream","status"],{json:!0,timeoutMs:30000}),H=NH(N.data),Y=N.ok&&H.connected===!0,W=Y&&H.enabled===!0;H0=W&&typeof H.port==="number"?H.port:null;let $=null,G=null;if(Y){let[U,O]=await Promise.all([S(["get","url"],{json:!0,timeoutMs:30000}),S(["get","title"],{json:!0,timeoutMs:30000})]);$=U.ok?Y0(U.data):null,G=O.ok?Y0(O.data):null}return{running:Y,streaming:W,streamPort:H0,url:$,title:G,controller:W0}}var i1={width:1280,height:720};async function I0(){await S(["set","viewport",String(i1.width),String(i1.height)],{timeoutMs:30000})}async function HH(){await Promise.all(["screenshots","downloads","reports"].map((N)=>p1(P.join(B(),N),{recursive:!0})))}async function YH(N){await HH(),await p1(P.join(SN(),"profile"),{recursive:!0});let H=await S(["open",N??"about:blank"],{timeoutMs:180000});if(!H.ok)throw Error(`agent-browser open failed: ${H.stderr||H.stdout}`);return await I0(),await S(["stream","enable"],{json:!0,timeoutMs:30000}),p("start",N??"about:blank"),n(),kN()}async function WH(){await S(["close"],{timeoutMs:30000}),H0=null,n(),p("stop")}async function $H(N){let H=await S(["open",N],{timeoutMs:120000});if(!H.ok)throw Error(`Navigation failed: ${H.stderr||H.stdout}`);await I0(),n(),p("navigate",N)}async function GH(N){let H=await S([N],{timeoutMs:60000});if(!H.ok)throw Error(`${N} failed: ${H.stderr||H.stdout}`);await I0(),n(),p(N)}async function UH(N){let H=await S(["press",N],{timeoutMs:30000});if(!H.ok)throw Error(`Key press failed: ${H.stderr||H.stdout}`);n()}async function OH(){await HH();let N=`browser-${new Date().toISOString().replace(/[:.]/g,"-")}.png`,H=P.join(B(),"screenshots",N),Y=await S(["screenshot",H],{timeoutMs:60000});if(!Y.ok)throw Error(`Screenshot failed: ${Y.stderr||Y.stdout}`);return p("screenshot",`screenshots/${N}`),`screenshots/${N}`}async function QH(N=!0){let H=await S(["snapshot",...N?["-i"]:[]],{timeoutMs:60000});if(!H.ok)throw Error(`Snapshot failed: ${H.stderr||H.stdout}`);return H.stdout.trim()}async function XH(N){let H=await S(["click",N],{timeoutMs:30000});if(!H.ok)throw Error(`Click failed: ${H.stderr||H.stdout}`);n(),p("click",N)}async function ZH(N,H){let Y=await S(["fill",N,H],{timeoutMs:30000});if(!Y.ok)throw Error(`Fill failed: ${Y.stderr||Y.stdout}`);p("fill",N)}async function zH(N){let Y=await S(N?["get","text",N]:["get","text","body"],{json:!0,timeoutMs:30000});if(!Y.ok)throw Error(`Read failed: ${Y.stderr||Y.stdout}`);return Y0(Y.data)??Y.stdout.trim()}async function FH(N){let H=await S(["eval",N],{json:!0,timeoutMs:30000});if(!H.ok)throw Error(`Eval failed: ${H.stderr||H.stdout}`);return Y0(H.data)??H.stdout.trim()}async function VH(N,H={}){if(!Array.isArray(N)||N.length===0||!N.every((W)=>typeof W==="string"))throw Error("args must be a non-empty array of strings");if(N[0]==="close"||N[0]==="--all")throw Error("`close` is not allowed \u2014 the daemon owns the shared session's lifecycle");let Y=await S(N,{json:H.json,timeoutMs:H.timeoutMs??120000});return n(),p("exec",N.join(" ").slice(0,80)),{ok:Y.ok,stdout:Y.stdout,stderr:Y.stderr,error:Y.error}}class j0{send;handlers;nextId=1;pending=new Map;constructor(N,H){this.send=N;this.handlers=H}request(N,H){let Y=this.nextId++,W=new Promise(($,G)=>{this.pending.set(Y,{method:N,resolve:$,reject:G})});return this.send(JSON.stringify({jsonrpc:"2.0",id:Y,method:N,params:H})),W}notify(N,H){this.send(JSON.stringify({jsonrpc:"2.0",method:N,params:H}))}respond(N,H){this.send(JSON.stringify({jsonrpc:"2.0",id:N,result:H}))}respondError(N,H,Y){this.send(JSON.stringify({jsonrpc:"2.0",id:N,error:{code:H,message:Y}}))}handleLine(N){let H;try{H=JSON.parse(N)}catch{console.warn("[codex] non-JSON line on stdout:",N.slice(0,200));return}if(H.method!==void 0){if(H.id!==void 0)this.handlers.onServerRequest(H.id,H.method,H.params);else this.handlers.onNotification(H.method,H.params);return}if(H.id===void 0)return;let Y=this.pending.get(Number(H.id));if(!Y)return;if(this.pending.delete(Number(H.id)),H.error)Y.reject(Error(`${Y.method} failed: ${H.error.message} (${H.error.code})`));else Y.resolve(H.result)}failAll(N){for(let H of this.pending.values())H.reject(Error(`${H.method} failed: ${N}`));this.pending.clear()}}function KH(N){let H="",Y=new TextDecoder;return{push(W){H+=Y.decode(W,{stream:!0});let $;while(($=H.indexOf(`
280
- `))!==-1){let G=H.slice(0,$).replace(/\r$/,"");if(H=H.slice($+1),G.trim().length>0)N(G)}},flush(){let W=H.trim();if(H="",W.length>0)N(W)}}}var v0=60000,g0=5,JH=30000;class h0{handlers;proc=null;rpc=null;initialized=!1;exitTimes=[];backoffUntil=0;lastExitCode=null;constructor(N){this.handlers=N}get running(){return this.proc!==null}get health(){let N=Math.max(0,this.backoffUntil-Date.now());return{running:this.proc!==null,lastExitCode:this.lastExitCode,crashLooping:N>0,backoffMs:N}}async start(){if(this.proc)return;let N=this.backoffUntil-Date.now();if(N>0)throw Error(`codex app-server is crash-looping (${g0}+ exits in ${v0/1000}s) \u2014 `+`backing off, retry in ${Math.ceil(N/1000)}s. Run \`jun doctor\` to diagnose.`);await WW();let H=Bun.which("codex");if(!H)throw Error("codex binary not found in PATH. Install Codex CLI first.");let Y=/\.(cmd|bat)$/i.test(H)?["cmd","/c",H,"app-server"]:[H,"app-server"],W=Bun.spawn(Y,{cwd:B(),env:{...process.env,CODEX_HOME:j(),...q0()},stdin:"pipe",stdout:"pipe",stderr:"pipe",onExit:(G,U)=>{this.lastExitCode=U,this.rpc?.failAll(`codex app-server exited (code ${U})`),this.proc=null,this.rpc=null,this.initialized=!1;let O=Date.now();if(this.exitTimes=this.exitTimes.filter((Q)=>O-Q<v0),this.exitTimes.push(O),this.exitTimes.length>=g0)this.backoffUntil=O+JH,this.exitTimes=[],console.error(`[codex] app-server crash-looping (${g0} exits in ${v0/1000}s) \u2014 backing off ${JH/1000}s`);else console.log(`[codex] app-server exited (code ${U}) \u2014 will restart on next run`);this.handlers.onExit(U)}});this.proc=W,this.rpc=new j0((G)=>{W.stdin.write(G+`
281
- `),W.stdin.flush()},{onNotification:(G,U)=>this.handlers.onNotification(G,U),onServerRequest:(G,U,O)=>this.handlers.onServerRequest(G,U,O)});let $=this.rpc;(async()=>{let G=KH((U)=>$.handleLine(U));for await(let U of W.stdout)G.push(U);G.flush()})(),(async()=>{let G=new TextDecoder;for await(let U of W.stderr){let O=G.decode(U).trimEnd();if(O)console.error("[codex:stderr]",O)}})()}async initializeOnce(){if(this.initialized)return;await this.requireRpc().request("initialize",{clientInfo:{name:"jun",title:"Jun",version:ZN},capabilities:{experimentalApi:!0}}),this.requireRpc().notify("initialized",{}),this.initialized=!0}request(N,H){return this.requireRpc().request(N,H)}respond(N,H){this.requireRpc().respond(N,H)}respondError(N,H,Y){this.requireRpc().respondError(N,H,Y)}requireRpc(){if(!this.rpc)throw Error("codex app-server is not running");return this.rpc}}async function WW(){let N=MH.join(j(),"auth.json");try{await LH.access(N);return}catch{}let H=MH.join(YW.homedir(),".codex","auth.json");try{await LH.copyFile(H,N),console.log("[codex] copied auth.json from ~/.codex into project codex-home")}catch{console.warn("[codex] no auth.json found in ~/.codex \u2014 runs may fail until `codex login` is run")}}var yN=null,U0=null;function O0(){return yN}function BH(){return U0}function AH(N){if(yN=N,N)U0=null}function Q0(){yN=null,U0=null}function DH(N){let H=N??{};if(U0={success:H.success===!0,error:H.error??null,at:new Date().toISOString()},!H.loginId||yN?.loginId===H.loginId)yN=null}var $W={"thread/started":"codex.thread.started","turn/started":"codex.turn.started","turn/completed":"codex.turn.completed","item/started":"codex.item.started","item/completed":"codex.item.completed","item/agentMessage/delta":"codex.message.delta","item/reasoning/textDelta":"codex.reasoning.delta","item/reasoning/summaryTextDelta":"codex.reasoning.summary.delta","item/commandExecution/outputDelta":"codex.command.output","item/fileChange/patchUpdated":"codex.file_change.patch",error:"codex.error"},GW={"item/commandExecution/requestApproval":"codex.approval.command","item/fileChange/requestApproval":"codex.approval.file_change","item/permissions/requestApproval":"codex.approval.permissions","item/tool/requestUserInput":"codex.approval.user_input","mcpServer/elicitation/request":"codex.approval.elicitation"};function CH(N){return $W[N]??`codex.${N.split("/").join(".")}`}function RH(N){return GW[N]??null}function SH(N){return N==="item/commandExecution/requestApproval"||N==="item/fileChange/requestApproval"||N==="item/permissions/requestApproval"}function bN(N){if(typeof N!=="object"||N===null)return null;let H=N;if(typeof H.threadId==="string")return H.threadId;let Y=H.thread;if(typeof Y==="object"&&Y!==null){let W=Y.id;if(typeof W==="string")return W}return null}var TH={readOnly:"read-only",workspaceWrite:"workspace-write",dangerFullAccess:"danger-full-access"},EH={readOnly:{type:"readOnly"},workspaceWrite:{type:"workspaceWrite"},dangerFullAccess:{type:"dangerFullAccess"}},m0={never:"never",onRequest:"on-request",onFailure:"on-failure",untrusted:"untrusted"},X0=`# Who you are
274
+ */function X(N,U=200){return new Response(JSON.stringify(N),{status:U,headers:{"content-type":"application/json"}})}function Z(N,U,H){return X({error:U,detail:H},N)}async function z(N){try{return await N.json()}catch{throw new J("Invalid JSON body")}}function D(N,U){if(typeof N!=="string"||N.length===0)throw new J(`Missing or invalid field: ${U}`);return N}class J extends Error{constructor(N){super(N);this.name="BadRequestError"}}import{promises as b}from"fs";import y from"path";import C0 from"path";function e(N,U){let H=C0.resolve(N),Y=C0.resolve(H,U||".");if(Y!==H&&!Y.startsWith(H+C0.sep))throw new dN(U);return Y}class dN extends Error{constructor(N){super(`Path escapes workspace: ${N}`);this.name="PathEscapeError"}}var AY=2097152,EY=new Set([".png",".jpg",".jpeg",".gif",".webp",".svg",".bmp",".ico",".avif"]),TY=new Set([".zip",".tar",".gz",".7z",".exe",".dll",".so",".dylib",".pdf",".woff",".woff2",".ttf",".mp3",".mp4",".mov",".webm",".sqlite",".db",".bin"]);function BY(N){let U=y.extname(N).toLowerCase();if(U===".md"||U===".markdown")return"markdown";if(U===".json"||U===".jsonl")return"json";if(EY.has(U))return"image";if(TY.has(U))return"binary";return"text"}function s(N){return e(M(),N)}function R0(N){let U=y.relative(M(),N);return U===""?".":c(U)}async function G1(N){let U=await b.stat(N),H={name:y.basename(N)||".",path:R0(N),type:U.isDirectory()?"dir":"file",modifiedAt:U.mtime.toISOString()};if(H.type==="file")return H.size=U.size,H;let Y=await b.readdir(N,{withFileTypes:!0}),O=await Promise.all(Y.map((W)=>G1(y.join(N,W.name))));return O.sort((W,$)=>W.type!==$.type?W.type==="dir"?-1:1:W.name.localeCompare($.name)),H.children=O,H}async function F1(N="."){return G1(s(N))}async function Q1(N){let U=s(N),H=await b.stat(U);if(H.isDirectory())throw Error(`Not a file: ${N}`);let Y=BY(U),O={path:R0(U),kind:Y,size:H.size,modifiedAt:H.mtime.toISOString()};if(Y==="image"||Y==="binary")return O;if(H.size>AY)throw Error(`File too large to open (${H.size} bytes): ${N}`);return O.content=await b.readFile(U,"utf8"),O}async function X1(N,U){let H=s(N);await b.mkdir(y.dirname(H),{recursive:!0}),await b.writeFile(H,U,"utf8")}async function Z1(N){await b.mkdir(s(N),{recursive:!0})}async function L1(N){let U=s(N);if(U===y.resolve(M()))throw Error("Cannot delete the workspace root");await b.rm(U,{recursive:!0,force:!0})}async function z1(N,U){let H=s(N),Y=s(U);if(H===y.resolve(M()))throw Error("Cannot rename the workspace root");await b.mkdir(y.dirname(Y),{recursive:!0}),await b.rename(H,Y)}async function V1(N,U,H){let Y=y.basename(U);if(!Y||Y==="."||Y==="..")throw Error(`Invalid file name: ${U}`);let O=e(M(),y.join(N||".",Y));return await b.mkdir(y.dirname(O),{recursive:!0}),await Bun.write(O,H),R0(O)}function oN(N){return s(N)}import{randomBytes as CY}from"crypto";function nN(N){return`${N}_${CY(6).toString("hex")}`}var S0=null;function K1(N){S0=N}function q(N,U){S0?.publish(N,JSON.stringify(U))}function M1(N,U){S0?.publish(N,U)}import{promises as RN}from"fs";import RY from"os";import _0 from"path";var t=new Map,J1=!1;function j0(N){return _0.join(i(),N,"meta.json")}var A1=_0.join(RY.homedir(),".agenthost");function E1(N){let U=JSON.parse(N);if(U.cwd?.startsWith(A1))U.cwd=f+U.cwd.slice(A1.length);return U}async function T1(N){await RN.mkdir(_0.join(i(),N.id),{recursive:!0}),await RN.writeFile(j0(N.id),JSON.stringify(N,null,2)+`
275
+ `,"utf8")}async function SY(){if(J1)return;J1=!0;let N;try{N=await RN.readdir(i())}catch{return}for(let U of N){if(t.has(U))continue;try{let H=await RN.readFile(j0(U),"utf8"),Y=E1(H);t.set(Y.id,Y)}catch{}}}async function B1(N){let U={id:nN("run"),prompt:N.prompt,status:"starting",startedAt:new Date().toISOString(),cwd:N.cwd,sandbox:N.sandbox,approvalPolicy:N.approvalPolicy,approvalsReviewer:N.approvalsReviewer,model:N.model,effort:N.effort,source:N.source,scheduleId:N.scheduleId,scheduleName:N.scheduleName};return t.set(U.id,U),await T1(U),U}async function NN(N,U){let H=await A(N);if(!H)return null;let Y={...H,...U};return t.set(N,Y),await T1(Y),Y}async function A(N){if(t.has(N))return t.get(N);try{let U=await RN.readFile(j0(N),"utf8"),H=E1(U);return t.set(N,H),H}catch{return null}}async function C1(){return await SY(),[...t.values()].sort((N,U)=>U.startedAt.localeCompare(N.startedAt))}function v(N){return N==="queued"||N==="starting"||N==="running"||N==="waiting_approval"}import{promises as R1}from"fs";import _Y from"path";function S1(N){return _Y.join(i(),N,"events.jsonl")}async function _1(N){await R1.appendFile(S1(N.runId),JSON.stringify(N)+`
276
+ `,"utf8")}var jY=/"type":\s*"run\.(started|resumed|steered)"/,IY=400;async function j1(N,U={}){let H;try{H=await R1.readFile(S1(N),"utf8")}catch{return{events:[],offset:0,total:0}}let Y=H.split(`
277
+ `);if(Y.length>0&&Y[Y.length-1]==="")Y.pop();let O=Y.length,W=Math.max(0,Math.min(U.before??O,O)),$=U.limit===void 0?0:Math.max(0,W-U.limit);if($>0){for(let F=$;F>=Math.max(0,$-IY);F--)if(jY.test(Y[F])){$=F;break}}let G=[];for(let F=$;F<W;F++){let Q=Y[F].trim();if(!Q)continue;try{G.push(JSON.parse(Q))}catch{}}return{events:G,offset:$,total:O}}import{promises as GU}from"fs";import uY from"os";import FU from"path";var P1={name:"junhost",version:"0.2.4",description:"Jun \u2014 a self-hosted dashboard that runs and supervises Codex as a 24/7 local/VPS agent: chat runs, workspace files, remote browser, skills, MCP, schedules.",type:"module",bin:{jun:"bin/jun.js"},files:["bin","dist","ui-dist","README.md"],engines:{bun:">=1.2.0"},keywords:["codex","agent","ai","dashboard","self-hosted","browser-automation","mcp"],license:"UNLICENSED",scripts:{dev:"bun --hot src/index.ts",start:"bun src/index.ts",build:"bun build src/index.ts src/mcp-server.ts src/browser-mcp-server.ts --target=bun --minify --outdir=dist",typecheck:"bunx tsc --noEmit"},dependencies:{"agent-browser":"^0.27.1",cloakbrowser:"^0.3.31"},devDependencies:{"@junhost/shared":"workspace:*","@modelcontextprotocol/sdk":"^1.29.0","@types/bun":"^1.2.0","smol-toml":"^1.6.1",typescript:"^5.6.3",zod:"3"}};var FN=P1.version;import kY from"os";import _ from"path";import{existsSync as jN,readdirSync as yY}from"fs";import{mkdir as v1}from"fs/promises";import{randomUUID as bY}from"crypto";import{readFileSync as wY}from"fs";import{promises as xY}from"fs";import fY from"path";var w1=["browserProxy","browserNoProxy"];function x1(){return fY.join(f,"config.json")}var aN=null;function sN(){if(aN)return aN;let N={};try{N=JSON.parse(wY(x1(),"utf8"))}catch{}let U={};for(let H of w1){let Y=N[H];if(typeof Y==="string"&&Y.length>0)U[H]=Y}return aN=U,U}async function f1(N){let U={...sN()};for(let H of w1){if(!(H in N))continue;let Y=N[H];if(typeof Y==="string"&&Y.trim().length>0)U[H]=Y.trim();else delete U[H]}return await xY.writeFile(x1(),JSON.stringify(U,null,2)+`
278
+ `,"utf8"),aN=U,U}var qY="jun",k1=200,g1=process.platform==="win32"?"agent-browser.exe":"agent-browser";function h1(){let N=import.meta.dir;for(let U=0;U<8;U++){let H=_.join(N,"node_modules",".bin");if(jN(_.join(H,g1)))return H;let Y=_.dirname(N);if(Y===N)break;N=Y}return null}function vY(N){let U=h1();if(U)return[_.join(U,g1),...N];return process.platform==="win32"?["cmd","/c","agent-browser",...N]:["agent-browser",...N]}var y1=Object.keys(process.env).find((N)=>N.toUpperCase()==="PATH")??"PATH",N0="agent",rN=null,tN=[];function m1(){let N=x("CLOAK_PATH");if(N&&jN(N))return N;let U=_.join(kY.homedir(),".cloakbrowser"),H;try{H=yY(U).filter((O)=>O.startsWith("chromium-"))}catch{return null}H.sort().reverse();let Y=process.platform==="win32"?"chrome.exe":"chrome";for(let O of H){let W=_.join(U,O,Y);if(jN(W))return W}return null}function gY(){let N=x("CHROME_PATH");if(N&&jN(N))return N;return(process.platform==="win32"?[`${process.env.ProgramFiles}\\Google\\Chrome\\Application\\chrome.exe`,`${process.env["ProgramFiles(x86)"]}\\Google\\Chrome\\Application\\chrome.exe`,`${process.env.LocalAppData}\\Google\\Chrome\\Application\\chrome.exe`]:process.platform==="darwin"?["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"]:["/usr/bin/google-chrome","/usr/bin/google-chrome-stable","/opt/google/chrome/chrome"]).find((H)=>H&&jN(H))??null}function w0(){let N={AGENT_BROWSER_SESSION:qY,AGENT_BROWSER_PROFILE:_.join(TN(),"profile"),AGENT_BROWSER_DOWNLOAD_PATH:_.join(M(),"downloads"),AGENT_BROWSER_SCREENSHOT_DIR:_.join(M(),"screenshots"),AGENT_BROWSER_ARGS:"--disable-blink-features=AutomationControlled"},U=U0().value;if(U)N.AGENT_BROWSER_PROXY=U;let H=H0().value;if(H)N.AGENT_BROWSER_PROXY_BYPASS=H;let Y=h1();if(Y)N[y1]=`${Y}${_.delimiter}${process.env[y1]??""}`;let O=m1();if(O)return N.AGENT_BROWSER_EXECUTABLE_PATH=O,N;let W=gY(),$=process.platform!=="linux"||Boolean(process.env.DISPLAY),G=x("BROWSER_HEADED")!=="false"&&$;if(process.platform==="linux"&&!process.env.DISPLAY&&x("BROWSER_HEADED")!=="false")console.warn("[browser] No cloakbrowser engine and no DISPLAY \u2014 running HEADLESS. Edge "+"WAFs (Reddit/Fastly) will block headless. Install cloakbrowser (works headless) or set up Xvfb + Google Chrome with DISPLAY for a VPS.");if(W&&G)N.AGENT_BROWSER_EXECUTABLE_PATH=W,N.AGENT_BROWSER_HEADED="true";else{if(W)N.AGENT_BROWSER_EXECUTABLE_PATH=W;N.AGENT_BROWSER_USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36"}return N}function hY(){return{...process.env,...w0()}}function mY(){let N=U0().value;if(!N)return[];let U=["--proxy",N],H=H0().value;if(H)U.push("--proxy-bypass",H);return U}function U0(){let N=sN().browserProxy;if(N)return{value:N,source:"settings"};let U=x("BROWSER_PROXY")?.trim();if(U)return{value:U,source:"env"};return{value:null,source:"none"}}function H0(){let N=sN().browserNoProxy;if(N)return{value:N,source:"settings"};let U=x("BROWSER_NO_PROXY")?.trim();if(U)return{value:U,source:"env"};return{value:null,source:"none"}}var P0=!1;function c1(N){if(P0)return;if(x("NO_CLOAK_DOWNLOAD")==="true")return;if(m1())return;P0=!0,console.log("[browser] cloakbrowser Stealth Chromium not found \u2014 downloading in background\u2026"),Bun.spawn([process.execPath,"x","cloakbrowser","install"],{cwd:N,stdout:"inherit",stderr:"inherit"}).exited.then((H)=>{if(P0=!1,H===0)console.log("[browser] cloakbrowser Stealth Chromium ready.");else console.warn(`[browser] cloakbrowser download exited with code ${H}.`)})}async function b1(N,U,H){if(!N)return"";let Y=N.getReader(),O=new TextDecoder,W="",$=Date.now()+H;try{while(Date.now()<$){let G=Math.min(U,$-Date.now()),F=await Promise.race([Y.read(),new Promise((Q)=>setTimeout(()=>Q("timeout"),G))]);if(F==="timeout"||F.done)break;W+=O.decode(F.value,{stream:!0})}}finally{Y.releaseLock()}return W}async function B(N,U={}){let H=[...mY(),...N],Y=U.json?[...H,"--json"]:H,O=Bun.spawn(vY(Y),{env:hY(),stdout:"pipe",stderr:"pipe"}),W=setTimeout(()=>O.kill(),U.timeoutMs??120000),$=await O.exited;clearTimeout(W);let[G,F]=await Promise.all([b1(O.stdout,80,1500),b1(O.stderr,60,300)]),Q,L;if(U.json)try{let K=JSON.parse(G);if(Q=K.data??K,K.success===!1)L=typeof K.error==="string"?K.error:"command failed"}catch{}return{ok:$===0&&!L,stdout:G,stderr:F,data:Q,error:L}}function l(N,U){if(tN.unshift({id:bY(),ts:new Date().toISOString(),kind:N,detail:U}),tN.length>k1)tN.length=k1}function l1(){return tN}function p1(){return N0}function u1(N){N0=N,l("control",N)}function i1(){return rN}var d1=(N)=>typeof N==="object"&&N!==null?N:{};function eN(N){if(typeof N==="string")return N;let U=d1(N);for(let H of["url","title","value","text","result"])if(typeof U[H]==="string")return U[H];return null}var cY=2500,_N=null,SN=null;function p(){_N=null}async function IN(){if(_N&&Date.now()-_N.at<cY)return{..._N.status,controller:N0};if(SN)return SN;return SN=lY().then((N)=>{return _N={at:Date.now(),status:N},N}).finally(()=>{SN=null}),SN}async function lY(){let N=await B(["stream","status"],{json:!0,timeoutMs:30000}),U=d1(N.data),H=N.ok&&U.connected===!0,Y=H&&U.enabled===!0;rN=Y&&typeof U.port==="number"?U.port:null;let O=null,W=null;if(H){let[$,G]=await Promise.all([B(["get","url"],{json:!0,timeoutMs:30000}),B(["get","title"],{json:!0,timeoutMs:30000})]);O=$.ok?eN($.data):null,W=G.ok?eN(G.data):null}return{running:H,streaming:Y,streamPort:rN,url:O,title:W,controller:N0}}var q1={width:1280,height:720};async function x0(){await B(["set","viewport",String(q1.width),String(q1.height)],{timeoutMs:30000})}async function o1(){await Promise.all(["screenshots","downloads","reports"].map((N)=>v1(_.join(M(),N),{recursive:!0})))}async function n1(N){await o1(),await v1(_.join(TN(),"profile"),{recursive:!0});let U=await B(["open",N??"about:blank"],{timeoutMs:180000});if(!U.ok)throw Error(`agent-browser open failed: ${U.stderr||U.stdout}`);return await x0(),await B(["stream","enable"],{json:!0,timeoutMs:30000}),l("start",N??"about:blank"),p(),IN()}async function a1(){await B(["close"],{timeoutMs:30000}),rN=null,p(),l("stop")}async function s1(N){let U=await B(["open",N],{timeoutMs:120000});if(!U.ok)throw Error(`Navigation failed: ${U.stderr||U.stdout}`);await x0(),p(),l("navigate",N)}async function t1(N){let U=await B([N],{timeoutMs:60000});if(!U.ok)throw Error(`${N} failed: ${U.stderr||U.stdout}`);await x0(),p(),l(N)}async function r1(N){let U=await B(["press",N],{timeoutMs:30000});if(!U.ok)throw Error(`Key press failed: ${U.stderr||U.stdout}`);p()}async function e1(){await o1();let N=`browser-${new Date().toISOString().replace(/[:.]/g,"-")}.png`,U=_.join(M(),"screenshots",N),H=await B(["screenshot",U],{timeoutMs:60000});if(!H.ok)throw Error(`Screenshot failed: ${H.stderr||H.stdout}`);return l("screenshot",`screenshots/${N}`),`screenshots/${N}`}async function NU(N=!0){let U=await B(["snapshot",...N?["-i"]:[]],{timeoutMs:60000});if(!U.ok)throw Error(`Snapshot failed: ${U.stderr||U.stdout}`);return U.stdout.trim()}async function UU(N){let U=await B(["click",N],{timeoutMs:30000});if(!U.ok)throw Error(`Click failed: ${U.stderr||U.stdout}`);p(),l("click",N)}async function HU(N,U){let H=await B(["fill",N,U],{timeoutMs:30000});if(!H.ok)throw Error(`Fill failed: ${H.stderr||H.stdout}`);l("fill",N)}async function YU(N){let H=await B(N?["get","text",N]:["get","text","body"],{json:!0,timeoutMs:30000});if(!H.ok)throw Error(`Read failed: ${H.stderr||H.stdout}`);return eN(H.data)??H.stdout.trim()}async function OU(N){let U=await B(["eval",N],{json:!0,timeoutMs:30000});if(!U.ok)throw Error(`Eval failed: ${U.stderr||U.stdout}`);return eN(U.data)??U.stdout.trim()}async function WU(N,U={}){if(!Array.isArray(N)||N.length===0||!N.every((Y)=>typeof Y==="string"))throw Error("args must be a non-empty array of strings");if(N[0]==="close"||N[0]==="--all")throw Error("`close` is not allowed \u2014 the daemon owns the shared session's lifecycle");let H=await B(N,{json:U.json,timeoutMs:U.timeoutMs??120000});return p(),l("exec",N.join(" ").slice(0,80)),{ok:H.ok,stdout:H.stdout,stderr:H.stderr,error:H.error}}class f0{send;handlers;nextId=1;pending=new Map;constructor(N,U){this.send=N;this.handlers=U}request(N,U){let H=this.nextId++,Y=new Promise((O,W)=>{this.pending.set(H,{method:N,resolve:O,reject:W})});return this.send(JSON.stringify({jsonrpc:"2.0",id:H,method:N,params:U})),Y}notify(N,U){this.send(JSON.stringify({jsonrpc:"2.0",method:N,params:U}))}respond(N,U){this.send(JSON.stringify({jsonrpc:"2.0",id:N,result:U}))}respondError(N,U,H){this.send(JSON.stringify({jsonrpc:"2.0",id:N,error:{code:U,message:H}}))}handleLine(N){let U;try{U=JSON.parse(N)}catch{console.warn("[codex] non-JSON line on stdout:",N.slice(0,200));return}if(U.method!==void 0){if(U.id!==void 0)this.handlers.onServerRequest(U.id,U.method,U.params);else this.handlers.onNotification(U.method,U.params);return}if(U.id===void 0)return;let H=this.pending.get(Number(U.id));if(!H)return;if(this.pending.delete(Number(U.id)),U.error)H.reject(Error(`${H.method} failed: ${U.error.message} (${U.error.code})`));else H.resolve(U.result)}failAll(N){for(let U of this.pending.values())U.reject(Error(`${U.method} failed: ${N}`));this.pending.clear()}}function $U(N){let U="",H=new TextDecoder;return{push(Y){U+=H.decode(Y,{stream:!0});let O;while((O=U.indexOf(`
279
+ `))!==-1){let W=U.slice(0,O).replace(/\r$/,"");if(U=U.slice(O+1),W.trim().length>0)N(W)}},flush(){let Y=U.trim();if(U="",Y.length>0)N(Y)}}}var k0=60000,y0=5,QU=30000;class b0{handlers;proc=null;rpc=null;initialized=!1;exitTimes=[];backoffUntil=0;lastExitCode=null;constructor(N){this.handlers=N}get running(){return this.proc!==null}get health(){let N=Math.max(0,this.backoffUntil-Date.now());return{running:this.proc!==null,lastExitCode:this.lastExitCode,crashLooping:N>0,backoffMs:N}}async start(){if(this.proc)return;let N=this.backoffUntil-Date.now();if(N>0)throw Error(`codex app-server is crash-looping (${y0}+ exits in ${k0/1000}s) \u2014 `+`backing off, retry in ${Math.ceil(N/1000)}s. Run \`jun doctor\` to diagnose.`);await iY();let U=Bun.which("codex");if(!U)throw Error("codex binary not found in PATH. Install Codex CLI first.");let H=/\.(cmd|bat)$/i.test(U)?["cmd","/c",U,"app-server"]:[U,"app-server"],Y=Bun.spawn(H,{cwd:M(),env:{...process.env,CODEX_HOME:k(),...w0()},stdin:"pipe",stdout:"pipe",stderr:"pipe",onExit:(W,$)=>{this.lastExitCode=$,this.rpc?.failAll(`codex app-server exited (code ${$})`),this.proc=null,this.rpc=null,this.initialized=!1;let G=Date.now();if(this.exitTimes=this.exitTimes.filter((F)=>G-F<k0),this.exitTimes.push(G),this.exitTimes.length>=y0)this.backoffUntil=G+QU,this.exitTimes=[],console.error(`[codex] app-server crash-looping (${y0} exits in ${k0/1000}s) \u2014 backing off ${QU/1000}s`);else console.log(`[codex] app-server exited (code ${$}) \u2014 will restart on next run`);this.handlers.onExit($)}});this.proc=Y,this.rpc=new f0((W)=>{Y.stdin.write(W+`
280
+ `),Y.stdin.flush()},{onNotification:(W,$)=>this.handlers.onNotification(W,$),onServerRequest:(W,$,G)=>this.handlers.onServerRequest(W,$,G)});let O=this.rpc;(async()=>{let W=$U(($)=>O.handleLine($));for await(let $ of Y.stdout)W.push($);W.flush()})(),(async()=>{let W=new TextDecoder;for await(let $ of Y.stderr){let G=W.decode($).trimEnd();if(G)console.error("[codex:stderr]",G)}})()}async initializeOnce(){if(this.initialized)return;await this.requireRpc().request("initialize",{clientInfo:{name:"jun",title:"Jun",version:FN},capabilities:{experimentalApi:!0}}),this.requireRpc().notify("initialized",{}),this.initialized=!0}request(N,U){return this.requireRpc().request(N,U)}respond(N,U){this.requireRpc().respond(N,U)}respondError(N,U,H){this.requireRpc().respondError(N,U,H)}requireRpc(){if(!this.rpc)throw Error("codex app-server is not running");return this.rpc}}async function iY(){let N=FU.join(k(),"auth.json");try{await GU.access(N);return}catch{}let U=FU.join(uY.homedir(),".codex","auth.json");try{await GU.copyFile(U,N),console.log("[codex] copied auth.json from ~/.codex into project codex-home")}catch{console.warn("[codex] no auth.json found in ~/.codex \u2014 runs may fail until `codex login` is run")}}var PN=null,Y0=null;function O0(){return PN}function XU(){return Y0}function ZU(N){if(PN=N,N)Y0=null}function W0(){PN=null,Y0=null}function LU(N){let U=N??{};if(Y0={success:U.success===!0,error:U.error??null,at:new Date().toISOString()},!U.loginId||PN?.loginId===U.loginId)PN=null}var dY={"thread/started":"codex.thread.started","turn/started":"codex.turn.started","turn/completed":"codex.turn.completed","item/started":"codex.item.started","item/completed":"codex.item.completed","item/agentMessage/delta":"codex.message.delta","item/reasoning/textDelta":"codex.reasoning.delta","item/reasoning/summaryTextDelta":"codex.reasoning.summary.delta","item/commandExecution/outputDelta":"codex.command.output","item/fileChange/patchUpdated":"codex.file_change.patch",error:"codex.error"},oY={"item/commandExecution/requestApproval":"codex.approval.command","item/fileChange/requestApproval":"codex.approval.file_change","item/permissions/requestApproval":"codex.approval.permissions","item/tool/requestUserInput":"codex.approval.user_input","mcpServer/elicitation/request":"codex.approval.elicitation"};function zU(N){return dY[N]??`codex.${N.split("/").join(".")}`}function VU(N){return oY[N]??null}function DU(N){return N==="item/commandExecution/requestApproval"||N==="item/fileChange/requestApproval"||N==="item/permissions/requestApproval"}function wN(N){if(typeof N!=="object"||N===null)return null;let U=N;if(typeof U.threadId==="string")return U.threadId;let H=U.thread;if(typeof H==="object"&&H!==null){let Y=H.id;if(typeof Y==="string")return Y}return null}var KU={readOnly:"read-only",workspaceWrite:"workspace-write",dangerFullAccess:"danger-full-access"},MU={readOnly:{type:"readOnly"},workspaceWrite:{type:"workspaceWrite"},dangerFullAccess:{type:"dangerFullAccess"}},q0={never:"never",onRequest:"on-request",onFailure:"on-failure",untrusted:"untrusted"},$0=`# Who you are
282
281
 
283
282
  You are Jun. That's your name, use it if anyone asks. You live inside JunHost,
284
283
  your own self-hosted dashboard that runs you as a long-running local/VPS assistant, and
@@ -319,20 +318,20 @@ model powers you; you're just Jun.
319
318
  - Report outcomes honestly. If something failed, say so plainly with the actual
320
319
  error; don't dress up a partial result as done.
321
320
  - Per-workspace guidance lives in each workspace's AGENTS.md and takes
322
- precedence over this general guidance when they differ.`,WN=new Map,$N=new Map,qN=new Map,wH=new Set,IN=new Map,zN=new Map,c0="__default__";function UW(N){let H=N.error?.message;return typeof H==="string"&&H.includes("unsupported_parameter")&&H.includes("reasoning.summary")}async function _H(N,H,Y){if(wH.has(H))Y.summary="none";IN.set(N,Y),await k().request("turn/start",Y)}var jN=new Map,FN=null;function k(){if(!FN)FN=new h0({onNotification:OW,onServerRequest:QW,onExit:XW});return FN}function PH(){return FN?.health??{running:!1,lastExitCode:null,crashLooping:!1,backoffMs:0}}async function E(N,H,Y,W){let $={id:tN("evt"),runId:N,ts:new Date().toISOString(),source:H,type:Y,payload:W};return await q1($),h(`run:${N}`,$),h("runs",{type:"run.event",runId:N,eventType:Y}),$}async function y(N,H){let Y={status:H};if(H==="completed"||H==="failed"||H==="stopped")Y.completedAt=new Date().toISOString();let W=await YN(N,Y);if(W)h("runs",{type:"run.updated",run:W})}function OW(N,H){if(N==="account/login/completed"){DH(H);return}let Y=bN(H),W=Y?jN.get(Y):void 0;if(W){if(N==="item/completed"){let G=H.item;if(G?.type==="agentMessage"&&typeof G.text==="string")W.text=G.text}else if(N==="turn/completed"||N==="error")W.done(W.text);return}let $=Y?WN.get(Y):void 0;if(!$)return;(async()=>{if(await E($,"codex",CH(N),H),N==="turn/started"){let G=H.turn?.id;if(typeof G==="string")qN.set($,G)}else if(N==="turn/completed"){let G=H.turn?.id;if(typeof G==="string"&&zN.get($)===G){zN.delete($);return}zN.delete($),qN.delete($),IN.delete($);let U=await D($);if(U&&m(U.status))await y($,"completed");if($N.delete($),U&&!U.title)zW($)}else if(N==="error"){let G=H.turnId;qN.delete($);let U=await D($),O=IN.get($);if(U&&O&&O.summary&&O.summary!=="none"&&UW(H)){wH.add(U.model??c0);let Q={...O,summary:"none"};console.warn(`[runs] ${U.model??"default model"} rejects reasoning.summary \u2014 retrying with summaries disabled`);try{if(typeof G==="string")zN.set($,G);IN.set($,Q),await k().request("turn/start",Q);return}catch(X){zN.delete($),console.warn(`[runs] summary-less retry failed for ${$}:`,X)}}if(U&&m(U.status))await y($,"failed")}else if(N==="thread/name/updated"){let G=H.threadName;if(typeof G==="string"&&G.trim()){let U=await YN($,{title:G.trim()});if(U)h("runs",{type:"run.updated",run:U})}}})()}function QW(N,H,Y){let W=RH(H),$=bN(Y),G=$?WN.get($):void 0;if(!W||!G){if(console.warn(`[runs] auto-declining unroutable server request ${H} (id ${N})`),SH(H))k().respond(N,{decision:"decline"});else k().respondError(N,-32601,"Jun cannot handle this request yet");return}(async()=>{if(H==="mcpServer/elicitation/request"){let O=await D(G);if(O?.approvalPolicy==="never"||O?.approvalsReviewer==="auto_review"){k().respond(N,{action:"accept"}),await E(G,"daemon","approval.resolved",{requestId:N,decision:"accept",auto:!0});return}}let U=$N.get(G)??[];U.push({requestId:N,method:H}),$N.set(G,U),await y(G,"waiting_approval"),await E(G,"codex",W,{requestId:N,method:H,params:Y})})()}function XW(N){for(let Y of jN.values())Y.done(Y.text);jN.clear();let H=[...WN.values()];WN.clear(),$N.clear(),qN.clear(),IN.clear(),zN.clear();for(let Y of H)(async()=>{let W=await D(Y);if(!W||!m(W.status))return;await E(Y,"daemon","run.failed",{reason:`codex app-server exited (code ${N})`}),await y(Y,"failed")})()}function l0(N,H,Y,W){let $=(Y??[]).filter((Q)=>Q.mediaType?.startsWith("image/")),G=(Y??[]).filter((Q)=>!Q.mediaType?.startsWith("image/")),U=H;if(G.length>0)U+=`
321
+ precedence over this general guidance when they differ.`,UN=new Map,HN=new Map,xN=new Map,JU=new Set,fN=new Map,QN=new Map,v0="__default__";function nY(N){let U=N.error?.message;return typeof U==="string"&&U.includes("unsupported_parameter")&&U.includes("reasoning.summary")}async function AU(N,U,H){if(JU.has(U))H.summary="none";fN.set(N,H),await I().request("turn/start",H)}var kN=new Map,XN=null;function I(){if(!XN)XN=new b0({onNotification:aY,onServerRequest:sY,onExit:tY});return XN}function EU(){return XN?.health??{running:!1,lastExitCode:null,crashLooping:!1,backoffMs:0}}async function C(N,U,H,Y){let O={id:nN("evt"),runId:N,ts:new Date().toISOString(),source:U,type:H,payload:Y};return await _1(O),q(`run:${N}`,O),q("runs",{type:"run.event",runId:N,eventType:H}),O}async function P(N,U){let H={status:U};if(U==="completed"||U==="failed"||U==="stopped")H.completedAt=new Date().toISOString();let Y=await NN(N,H);if(Y)q("runs",{type:"run.updated",run:Y})}function aY(N,U){if(N==="account/login/completed"){LU(U);return}let H=wN(U),Y=H?kN.get(H):void 0;if(Y){if(N==="item/completed"){let W=U.item;if(W?.type==="agentMessage"&&typeof W.text==="string")Y.text=W.text}else if(N==="turn/completed"||N==="error")Y.done(Y.text);return}let O=H?UN.get(H):void 0;if(!O)return;(async()=>{if(await C(O,"codex",zU(N),U),N==="turn/started"){let W=U.turn?.id;if(typeof W==="string")xN.set(O,W)}else if(N==="turn/completed"){let W=U.turn?.id;if(typeof W==="string"&&QN.get(O)===W){QN.delete(O);return}QN.delete(O),xN.delete(O),fN.delete(O);let $=await A(O);if($&&v($.status))await P(O,"completed");if(HN.delete(O),$&&!$.title)eY(O)}else if(N==="error"){let W=U.turnId;xN.delete(O);let $=await A(O),G=fN.get(O);if($&&G&&G.summary&&G.summary!=="none"&&nY(U)){JU.add($.model??v0);let F={...G,summary:"none"};console.warn(`[runs] ${$.model??"default model"} rejects reasoning.summary \u2014 retrying with summaries disabled`);try{if(typeof W==="string")QN.set(O,W);fN.set(O,F),await I().request("turn/start",F);return}catch(Q){QN.delete(O),console.warn(`[runs] summary-less retry failed for ${O}:`,Q)}}if($&&v($.status))await P(O,"failed")}else if(N==="thread/name/updated"){let W=U.threadName;if(typeof W==="string"&&W.trim()){let $=await NN(O,{title:W.trim()});if($)q("runs",{type:"run.updated",run:$})}}})()}function sY(N,U,H){let Y=VU(U),O=wN(H),W=O?UN.get(O):void 0;if(!Y||!W){if(console.warn(`[runs] auto-declining unroutable server request ${U} (id ${N})`),DU(U))I().respond(N,{decision:"decline"});else I().respondError(N,-32601,"Jun cannot handle this request yet");return}(async()=>{if(U==="mcpServer/elicitation/request"){let G=await A(W);if(G?.approvalPolicy==="never"||G?.approvalsReviewer==="auto_review"){I().respond(N,{action:"accept"}),await C(W,"daemon","approval.resolved",{requestId:N,decision:"accept",auto:!0});return}}let $=HN.get(W)??[];$.push({requestId:N,method:U}),HN.set(W,$),await P(W,"waiting_approval"),await C(W,"codex",Y,{requestId:N,method:U,params:H})})()}function tY(N){for(let H of kN.values())H.done(H.text);kN.clear();let U=[...UN.values()];UN.clear(),HN.clear(),xN.clear(),fN.clear(),QN.clear();for(let H of U)(async()=>{let Y=await A(H);if(!Y||!v(Y.status))return;await C(H,"daemon","run.failed",{reason:`codex app-server exited (code ${N})`}),await P(H,"failed")})()}function g0(N,U,H){let Y=(U??[]).filter((G)=>G.mediaType?.startsWith("image/")),O=(U??[]).filter((G)=>!G.mediaType?.startsWith("image/")),W=N;if(O.length>0)W+=`
323
322
 
324
323
  Attached workspace files:
325
- `+G.map((Q)=>`- ${Q.path}`).join(`
326
- `);let O=[{type:"text",text:U}];if(W)O.push({type:"skill",name:W.name,path:W.path});for(let Q of $)O.push({type:"localImage",path:sN(Q.path,N)});return O}function ZW(N){if(!N)return null;let H=N.split(`
327
- `)[0].replace(/^["'`#*\s]+|["'`*\s]+$/g,"").replace(/\s+/g," ").trim();if(!H)return null;return H.length>60?H.slice(0,57).trimEnd()+"\u2026":H}async function zW(N){let H=await D(N);if(!H||H.title||!H.codexThreadId)return;try{let Y=k(),W=await Y.request("thread/start",{cwd:H.cwd,ephemeral:!0,sandbox:"read-only",approvalPolicy:"never",serviceName:"jun"}),$=bN(W);if(!$)return;let G=await new Promise((Q)=>{let X=(M)=>{clearTimeout(F),jN.delete($),Q(M)},F=setTimeout(()=>X(null),30000);jN.set($,{text:null,done:X}),Y.request("turn/start",{threadId:$,input:[{type:"text",text:`Reply with ONLY a short title (3-6 words, no quotes, no punctuation at the end) summarizing this conversation opener:
324
+ `+O.map((G)=>`- ${G.path}`).join(`
325
+ `);let $=[{type:"text",text:W}];if(H)$.push({type:"skill",name:H.name,path:H.path});for(let G of Y)$.push({type:"localImage",path:oN(G.path)});return $}function rY(N){if(!N)return null;let U=N.split(`
326
+ `)[0].replace(/^["'`#*\s]+|["'`*\s]+$/g,"").replace(/\s+/g," ").trim();if(!U)return null;return U.length>60?U.slice(0,57).trimEnd()+"\u2026":U}async function eY(N){let U=await A(N);if(!U||U.title||!U.codexThreadId)return;try{let H=I(),Y=await H.request("thread/start",{cwd:U.cwd,ephemeral:!0,sandbox:"read-only",approvalPolicy:"never",serviceName:"jun"}),O=wN(Y);if(!O)return;let W=await new Promise((F)=>{let Q=(K)=>{clearTimeout(L),kN.delete(O),F(K)},L=setTimeout(()=>Q(null),30000);kN.set(O,{text:null,done:Q}),H.request("turn/start",{threadId:O,input:[{type:"text",text:`Reply with ONLY a short title (3-6 words, no quotes, no punctuation at the end) summarizing this conversation opener:
328
327
 
329
- `+H.prompt.slice(0,2000)}],effort:"low"}).catch(()=>X(null))}),U=ZW(G);if(!U)return;await Y.request("thread/name/set",{threadId:H.codexThreadId,name:U});let O=await YN(N,{title:U});if(O)h("runs",{type:"run.updated",run:O})}catch(Y){console.warn(`[runs] title generation failed for ${N}:`,Y)}}async function C(N,H){let Y=k();return await Y.start(),await Y.initializeOnce(),Y.request(N,H)}async function VN(N){let H=N.projectId??"default",Y=N.cwd??B(H),W=await f1({prompt:N.prompt,cwd:Y,projectId:H,sandbox:N.sandbox??"workspaceWrite",approvalPolicy:N.approvalPolicy??"onRequest",approvalsReviewer:N.approvalsReviewer??"user",model:N.model,effort:N.effort??"medium",source:N.source,scheduleId:N.scheduleId,scheduleName:N.scheduleName});return h("runs",{type:"run.updated",run:W}),await E(W.id,"daemon","run.started",{prompt:N.prompt,cwd:Y,projectId:H,attachments:N.attachments??[]}),(async()=>{try{let $=k();await $.start(),await $.initializeOnce();let G=await $.request("thread/start",{cwd:Y,model:N.model??null,sandbox:TH[N.sandbox??"workspaceWrite"],approvalPolicy:m0[N.approvalPolicy??"onRequest"],...N.approvalsReviewer==="auto_review"?{approvalsReviewer:"auto_review"}:{},...X0?{developerInstructions:X0}:{},serviceName:"jun"}),U=bN(G)??(typeof G.threadId==="string"?G.threadId:null);if(!U)throw Error(`thread/start returned no thread id: ${JSON.stringify(G)}`);WN.set(U,W.id),await YN(W.id,{codexThreadId:U}),await y(W.id,"running"),await _H(W.id,N.model??c0,{threadId:U,input:l0(H,N.prompt,N.attachments,N.skill),summary:"detailed",effort:N.effort??"medium",sandboxPolicy:EH[N.sandbox??"workspaceWrite"]})}catch($){let G=$ instanceof Error?$.message:String($);await E(W.id,"daemon","run.failed",{reason:G}),await y(W.id,"failed")}})(),W}async function u0(N,H){let Y=k();if(await Y.start(),await Y.initializeOnce(),WN.has(H))return{server:Y,resumed:!1};let W=await D(N);return await Y.request("thread/resume",{threadId:H,...W?.approvalPolicy?{approvalPolicy:m0[W.approvalPolicy]}:{},...W?.approvalsReviewer==="auto_review"?{approvalsReviewer:"auto_review"}:{},...W?.model?{model:W.model}:{},...W?.sandbox?{sandbox:TH[W.sandbox]}:{},...X0?{developerInstructions:X0}:{}}),WN.set(H,N),{server:Y,resumed:!0}}async function Z0(N,H,Y,W){let $=await D(N);if(!$)throw Error(`Run not found: ${N}`);if(m($.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let G=$.codexThreadId;if(!G)throw Error("Run has no Codex thread to resume");let U={};if(W?.sandbox&&W.sandbox!==$.sandbox)U.sandbox=W.sandbox;if(W?.approvalPolicy&&W.approvalPolicy!==$.approvalPolicy)U.approvalPolicy=W.approvalPolicy;if(W?.approvalsReviewer&&W.approvalsReviewer!==$.approvalsReviewer)U.approvalsReviewer=W.approvalsReviewer;if(W?.model&&W.model!==$.model)U.model=W.model;if(W?.effort&&W.effort!==$.effort)U.effort=W.effort;if(Object.keys(U).length>0){let O=await YN(N,U);if(O)h("runs",{type:"run.updated",run:O})}return await E(N,"daemon","run.resumed",{prompt:H,attachments:Y??[],...Object.keys(U).length>0?{modeChanges:U}:{}}),await y(N,"running"),(async()=>{try{await u0(N,G);let O=U.sandbox??$.sandbox??"workspaceWrite",Q=U.approvalPolicy??$.approvalPolicy??"onRequest",X=U.approvalsReviewer??$.approvalsReviewer,F=U.model??$.model,M=(await D(N))?.serviceTier;await _H(N,F??c0,{threadId:G,input:l0($.projectId,H,Y),summary:"detailed",effort:U.effort??$.effort??"medium",sandboxPolicy:EH[O],approvalPolicy:m0[Q],...X==="auto_review"?{approvalsReviewer:X}:{},...F?{model:F}:{},...M?{serviceTier:M}:{}})}catch(O){let Q=O instanceof Error?O.message:String(O);await E(N,"daemon","run.failed",{reason:Q}),await y(N,"failed")}})(),await D(N)}async function xH(N,H,Y){let W=await D(N);if(!W)throw Error(`Run not found: ${N}`);if(!m(W.status))throw Error("Run is not active \u2014 send a follow-up message instead");let $=W.codexThreadId,G=qN.get(N);if(!$||!G)throw Error("No active turn to steer");await E(N,"daemon","run.steered",{prompt:H,attachments:Y??[]}),await k().request("turn/steer",{threadId:$,expectedTurnId:G,input:l0(W.projectId,H,Y)})}async function fH(N,H){let Y=await D(N);if(!Y)throw Error(`Run not found: ${N}`);if(H){let G=((await C("model/list",{})).data??[]).find((U)=>Y.model?U.model===Y.model:U.isDefault);if(!G?.serviceTiers?.some((U)=>U.id==="priority"))throw Error(`Model ${G?.model??Y.model??"unknown"} does not support fast mode`)}let W=await YN(N,{serviceTier:H?"priority":"standard"});if(W)h("runs",{type:"run.updated",run:W});return await E(N,"daemon","run.fast",{enabled:H}),W}async function kH(N){let H=await D(N);if(!H)throw Error(`Run not found: ${N}`);if(m(H.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let Y=H.codexThreadId;if(!Y)throw Error("Run has no Codex thread");let{server:W}=await u0(N,Y);await E(N,"daemon","run.compact.started",{}),await W.request("thread/compact/start",{threadId:Y})}async function yH(N,H){let Y=await D(N);if(!Y)throw Error(`Run not found: ${N}`);if(m(Y.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let W=Y.codexThreadId;if(!W)throw Error("Run has no Codex thread");let{server:$}=await u0(N,W),G=H?.trim();await E(N,"daemon","run.review.started",{instructions:G??null}),await y(N,"running");try{await $.request("review/start",{threadId:W,target:G?{type:"custom",instructions:G}:{type:"uncommittedChanges"},delivery:"inline"})}catch(U){let O=U instanceof Error?U.message:String(U);throw await E(N,"daemon","run.failed",{reason:O}),await y(N,"failed"),U}return await D(N)}async function bH(N){let H=await D(N);if(!H||!m(H.status))return!1;if(H.codexThreadId&&FN?.running)try{await FN.request("turn/interrupt",{threadId:H.codexThreadId})}catch(Y){console.warn(`[runs] turn/interrupt failed for ${N}:`,Y)}return $N.delete(N),await E(N,"daemon","run.stopped",{}),await y(N,"stopped"),!0}async function qH(N,H,Y){let W=$N.get(N)??[],$=W.findIndex((U)=>String(U.requestId)===String(H));if($===-1)return!1;let[G]=W.splice($,1);if(W.length===0)$N.delete(N);if(G.method==="mcpServer/elicitation/request"){let U=Y==="decline"||Y==="cancel"?Y:"accept";k().respond(G.requestId,{action:U})}else k().respond(G.requestId,{decision:Y});if(await E(N,"daemon","approval.resolved",{requestId:G.requestId,decision:Y}),W.length===0)await y(N,"running");return!0}function LN(){return FW.join(j(),"config.toml")}async function d(){try{return await KN.readFile(LN(),"utf8")}catch{return""}}async function jH(N){try{l(N)}catch(H){throw new A(`Invalid TOML: ${H instanceof Error?H.message:String(H)}`)}await KN.writeFile(LN(),N,"utf8")}function VW(N){if(!N.trim())return{};let Y=l(N).mcp_servers;if(typeof Y!=="object"||Y===null)return{};return Y}async function KW(){let N=new Map;try{let H=await C("mcpServerStatus/list",{detail:"full"});for(let Y of H.data??[]){let W=Object.entries(Y.tools??{}).map(([$,G])=>({name:$,description:G?.description}));N.set(Y.name,{startupState:Y.serverInfo?"ready":"starting",authStatus:Y.authStatus??null,tools:W})}}catch(H){console.warn("[mcp] mcpServerStatus/list failed:",H)}return N}async function vH(){let N=await d(),H=VW(N),Y=await KW();return{servers:Object.entries(H).map(([$,G])=>{let U=Y.get($);return{name:$,command:G.command,args:G.args,envKeys:G.env?Object.keys(G.env):void 0,url:G.url,enabled:G.enabled!==!1,startupState:U?.startupState??null,authStatus:U?.authStatus??null,tools:U?.tools??[],error:U?.error}})}}var LW=/^[A-Za-z0-9_-]+$/;async function gH(N){if(!LW.test(N.name))throw new A(`Invalid server name "${N.name}" \u2014 letters, digits, _ and - only`);if(!N.command&&!N.url)throw new A("Server needs either a command or a url");let H=await d(),Y=H.trim()?l(H):{},W=Y.mcp_servers??{},$={};if(N.command)$.command=N.command;if(N.args&&N.args.length>0)$.args=N.args;if(N.env&&Object.keys(N.env).length>0)$.env=N.env;if(N.url)$.url=N.url;if(N.enabled===!1)$.enabled=!1;W[N.name]=$,Y.mcp_servers=W,await KN.writeFile(LN(),t(Y),"utf8")}async function hH(N){let H=await d();if(!H.trim())return!1;let Y=l(H),W=Y.mcp_servers;if(!W||!(N in W))return!1;return delete W[N],await KN.writeFile(LN(),t(Y),"utf8"),!0}async function mH(N,H){let Y=await d(),W=l(Y||""),$=W.mcp_servers??{};if(!$[N])throw new A(`Server not found: ${N}`);$[N].enabled=H,W.mcp_servers=$,await KN.writeFile(LN(),t(W),"utf8")}async function cH(){await C("config/mcpServer/reload",{})}async function lH(N,H,Y,W){let $=await d(),G=$.trim()?l($):{},U=G.mcp_servers??{},O={command:process.execPath,args:[H],env:{JUN_PORT:String(Y)}},Q=U[N],X=Boolean(W&&U[W]);if(Q&&!X&&Q.command===O.command&&JSON.stringify(Q.args)===JSON.stringify(O.args)&&Q.env?.JUN_PORT===String(Y))return;if(W)delete U[W];U[N]=O,G.mcp_servers=U,await KN.writeFile(LN(),t(G),"utf8")}var JW="https://registry.npmjs.org/junhost/latest",BW=86400000,AW=3600000,i0=null,uH=0,p0=!1,n0=null;async function DW(){try{let N=await fetch(JW,{signal:AbortSignal.timeout(5000)});if(!N.ok)throw Error(`registry ${N.status}`);let H=await N.json();i0=typeof H.version==="string"?H.version:null,p0=i0!==null}catch{p0=!1}finally{uH=Date.now(),n0=null}}function CW(){let N=p0?BW:AW;if(!n0&&Date.now()-uH>N)n0=DW();return i0}function RW(N,H){let Y=N.split(".").map(($)=>parseInt($,10)||0),W=H.split(".").map(($)=>parseInt($,10)||0);for(let $=0;$<Math.max(Y.length,W.length);$++){let G=Y[$]??0,U=W[$]??0;if(G!==U)return G>U}return!1}function iH(){let N=CW();return{latestVersion:N,updateAvailable:N!==null&&RW(N,ZN)}}var SW=Date.now();function pH(){return Z({ok:!0})}function nH(){let N={ok:!0,name:"jun",version:ZN,...iH(),projectId:K,dataRoot:I,workspaceRoot:B(),uptimeSeconds:Math.round((Date.now()-SW)/1000),engine:PH()};return Z(N)}import TW from"path";var z0={ok:!0};async function dH(N,H){let Y=H.pathname.slice(11),W=H.searchParams.get("path")??".",$=H.searchParams.get("project")??K;switch(`${N.method} ${Y}`){case"GET tree":return Z(await M1(W,$));case"GET read":return Z(await J1(W,$));case"GET download":{let G=sN(W,$),U=Bun.file(G);if(!await U.exists())return z(404,`File not found: ${W}`);return new Response(U,{headers:{"content-disposition":`attachment; filename="${encodeURIComponent(TW.basename(G))}"`}})}case"POST write":{let G=await V(N);return await B1(J(G.path,"path"),typeof G.content==="string"?G.content:"",$),Z(z0)}case"POST mkdir":{let G=await V(N);return await A1(J(G.path,"path"),$),Z(z0)}case"POST delete":{let G=await V(N);return await D1(J(G.path,"path"),$),Z(z0)}case"POST rename":{let G=await V(N);return await C1(J(G.from,"from"),J(G.to,"to"),$),Z(z0)}case"POST upload":{let G;try{G=await N.formData()}catch{throw new A("Expected multipart/form-data body")}let U=String(G.get("path")??"."),O=G.getAll("file").filter((X)=>X instanceof File);if(O.length===0)throw new A("No files in upload (field name: file)");let Q=[];for(let X of O)Q.push(await R1(U,X.name,X,$));return Z({ok:!0,saved:Q})}default:return z(404,`Unknown files endpoint: ${N.method} /api/files/${Y}`)}}import{promises as oH}from"fs";function EW(N){return N.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,48)}async function aH(N){try{let H=await oH.readFile(R0(N),"utf8"),Y=JSON.parse(H);return{id:Y.id??N,name:Y.name??N,createdAt:Y.createdAt??new Date(0).toISOString(),workspaceRoot:B(N)}}catch{return null}}async function sH(){let N;try{N=await oH.readdir(QN(),{withFileTypes:!0})}catch{return[]}let H=[];for(let Y of N){if(!Y.isDirectory())continue;let W=await aH(Y.name);if(W)H.push(W)}return H.sort((Y,W)=>{if(Y.id===K)return-1;if(W.id===K)return 1;return W.createdAt.localeCompare(Y.createdAt)}),H}async function vN(N){return aH(N)}async function tH(N){let H=N.trim();if(!H)throw Error("Project name is required");let Y=EW(H);if(!Y)throw Error("Project name must contain letters or numbers");if(await vN(Y))throw Error(`A project named "${Y}" already exists`);await S0(Y,H);let W=await vN(Y);if(!W)throw Error(`Failed to create project "${Y}"`);return W}async function MN(N){return await vN(N)!==null}async function rH(N,H){let W=H.pathname.split("/").filter(Boolean)[2];if(!W){if(N.method==="GET"){let $={projects:await sH()};return Z($)}if(N.method==="POST"){let $=await V(N);J($.name,"name");try{let U={project:await tH($.name)};return Z(U,201)}catch(G){let U=G instanceof Error?G.message:String(G),O=U.includes("already exists")?409:400;return z(O,U)}}return z(405,"Method not allowed")}if(N.method==="GET"){let $=await vN(W);return $?Z({project:$}):z(404,`Project not found: ${W}`)}return z(405,"Method not allowed")}var wW=new Set(["accept","acceptForSession","decline","cancel"]);async function eH(N,H,Y){let W=H.pathname.split("/").filter(Boolean),$=W[2],G=W[3];if(!$){if(N.method==="GET"){let U=H.searchParams.get("project")??void 0,O={runs:await k1(U)};return Z(O)}if(N.method==="POST"){let U=await V(N);J(U.prompt,"prompt");let Q={run:await VN(U)};return Z(Q,201)}return z(405,"Method not allowed")}if(G==="events"){if(!await D($))return z(404,`Run not found: ${$}`);return Y.upgrade(N,{data:{channel:`run:${$}`}})?void 0:z(400,"WebSocket upgrade required")}if(!G&&N.method==="GET"){let U=await D($);if(!U)return z(404,`Run not found: ${$}`);let O=Number(H.searchParams.get("tail")??NaN),Q=Number(H.searchParams.get("before")??NaN),X=await I1($,{limit:Number.isFinite(O)&&O>0?O:void 0,before:Number.isFinite(Q)&&Q>=0?Q:void 0}),F={run:U,events:X.events,eventsOffset:X.offset,totalEvents:X.total};return Z(F)}if(N.method!=="POST")return z(405,"Method not allowed");switch(G){case"stop":return await bH($)?Z({ok:!0}):z(409,"Run is not active");case"resume":{let U=await V(N);J(U.prompt,"prompt");try{let O=await Z0($,U.prompt,Array.isArray(U.attachments)?U.attachments:void 0,{sandbox:U.sandbox,approvalPolicy:U.approvalPolicy,approvalsReviewer:U.approvalsReviewer,model:U.model,effort:U.effort});return Z({run:O})}catch(O){let Q=O instanceof Error?O.message:String(O),X=Q.includes("not found")?404:Q.includes("still active")?409:400;return z(X,Q)}}case"steer":{let U=await V(N);J(U.prompt,"prompt");try{return await xH($,U.prompt,Array.isArray(U.attachments)?U.attachments:void 0),Z({ok:!0})}catch(O){let Q=O instanceof Error?O.message:String(O),X=Q.includes("not found")?404:Q.includes("not active")||Q.includes("No active turn")?409:400;return z(X,Q)}}case"fast":{let U=await V(N);if(typeof U.enabled!=="boolean")return z(400,"Missing or invalid field: enabled");try{let O=await fH($,U.enabled);return Z({run:O})}catch(O){let Q=O instanceof Error?O.message:String(O),X=Q.includes("not found")?404:Q.includes("does not support")?400:500;return z(X,Q)}}case"compact":try{return await kH($),Z({ok:!0})}catch(U){let O=U instanceof Error?U.message:String(U),Q=O.includes("not found")?404:O.includes("still active")?409:400;return z(Q,O)}case"review":{let U=await V(N);try{let O=await yH($,U.instructions);return Z({run:O})}catch(O){let Q=O instanceof Error?O.message:String(O),X=Q.includes("not found")?404:Q.includes("still active")?409:400;return z(X,Q)}}case"approve":{let U=await V(N);if(!wW.has(String(U.decision)))return z(400,`Invalid decision: ${String(U.decision)}`);if(U.requestId===void 0||U.requestId===null)return z(400,"Missing field: requestId");return await qH($,U.requestId,U.decision)?Z({ok:!0}):z(404,"No matching pending approval")}default:return z(404,`Unknown runs endpoint: ${H.pathname}`)}}var GN="browser-stream",c=null,NY=null,JN=0,BN=null,o0=null;function _W(N){if(c&&NY===N&&c.readyState<=WebSocket.OPEN)return;c?.close(),NY=N;let H=new WebSocket(`ws://127.0.0.1:${N}`);c=H,H.onmessage=(Y)=>{let W=String(Y.data);if(W.includes('"type":"frame"'))o0=W;E1(GN,W)},H.onclose=()=>{if(c===H)c=null,o0=null,HY()},H.onerror=()=>{}}function HY(){if(BN||JN===0)return;BN=setTimeout(()=>{BN=null,gN(!0)},2000)}async function gN(N=!1){if(JN===0)return;let H=N?null:e1();if(H===null){if(N)n();H=(await kN()).streamPort}if(H!==null)_W(H);else HY()}function YY(){JN+=1,gN()}function WY(){return o0}function $Y(){if(JN=Math.max(0,JN-1),JN===0){if(c?.close(),c=null,BN)clearTimeout(BN),BN=null}}var PW=new Set(["input_mouse","input_keyboard","input_touch"]);function GY(N){if(t1()!=="user")return;if(!c||c.readyState!==WebSocket.OPEN)return;let H=typeof N==="string"?N:N.toString("utf8");try{let Y=JSON.parse(H);if(typeof Y.type==="string"&&PW.has(Y.type))c.send(H)}catch{}}var xW=new Set(["user","agent","paused"]);async function UY(N,H,Y){let $=H.pathname.split("/").filter(Boolean)[2];if($==="stream")return Y.upgrade(N,{data:{channel:GN}})?void 0:z(400,"WebSocket upgrade required");if(N.method==="GET")switch($){case"status":{let G=await kN();if(G.streaming)gN();return Z({status:G})}case"actions":{let G={actions:s1()};return Z(G)}default:return z(404,`Unknown browser endpoint: ${H.pathname}`)}if(N.method!=="POST")return z(405,"Method not allowed");switch($){case"start":{let G=await V(N).catch(()=>({})),U=await YH(typeof G.url==="string"&&G.url.length>0?G.url:void 0);return gN(),Z({status:U})}case"stop":return await WH(),Z({ok:!0});case"navigate":{let G=await V(N);return J(G.url,"url"),await $H(G.url),Z({ok:!0})}case"key":{let G=await V(N);return J(G.key,"key"),await UH(G.key),Z({ok:!0})}case"back":case"forward":case"reload":return await GH($),Z({ok:!0});case"screenshot":{let U={path:await OH()};return Z(U)}case"snapshot":{let G=await V(N).catch(()=>({})),U=await QH(G.interactive??!0);return Z({snapshot:U})}case"click":{let G=await V(N);return J(G.target,"target"),await XH(G.target),Z({ok:!0})}case"fill":{let G=await V(N);return J(G.target,"target"),J(G.text,"text"),await ZH(G.target,G.text),Z({ok:!0})}case"read":{let G=await V(N).catch(()=>({})),U=await zH(G.selector);return Z({text:U})}case"eval":{let G=await V(N);J(G.expression,"expression");let U=await FH(G.expression);return Z({result:U})}case"exec":{let G=await V(N);if(!Array.isArray(G.args)||G.args.length===0)return z(400,"args must be a non-empty array of strings");let U=await VH(G.args,{json:G.json});return Z(U)}case"control":{let G=await V(N);if(!xW.has(String(G.controller)))return z(400,`Invalid controller: ${String(G.controller)}`);return r1(G.controller),Z({ok:!0})}default:return z(404,`Unknown browser endpoint: ${H.pathname}`)}}import{promises as x}from"fs";import w from"path";var XY=".agents/skills";function AN(N){return w.join(B(N),XY)}var fW=/^[a-z0-9][a-z0-9-]*$/,kW=new Set(["registry","install"]);function DN(N,H){if(!fW.test(N))throw new A(`Invalid skill id "${N}" \u2014 use lowercase letters, digits and dashes`);return w.join(AN(H),N)}function OY(N){return N.replace(/\x1b\[[0-9;?]*[A-Za-z]/g,"")}async function ZY(N,H,Y=120000){let W=Bun.spawn([process.execPath,"x","skills",...N],{cwd:H,env:{...process.env,DISABLE_TELEMETRY:"1",DO_NOT_TRACK:"1"},stdout:"pipe",stderr:"pipe"}),$=setTimeout(()=>W.kill(),Y);try{let[G,U,O]=await Promise.all([new Response(W.stdout).text(),new Response(W.stderr).text(),W.exited]);return{stdout:OY(G),stderr:OY(U),code:O}}finally{clearTimeout($)}}function yW(N){let H=[],Y=null;for(let W of N.split(/\r?\n/)){let $=W.trim(),G=/^(\S+@\S+)\s+([\d.]+[KMB]?)\s+installs\b/.exec($);if(G){let O=G[1],Q=O.indexOf("@");Y={source:O,repo:O.slice(0,Q),name:O.slice(Q+1),installs:G[2]},H.push(Y);continue}let U=/^[\u2514\u2570]\s*(https?:\/\/\S+)/.exec($);if(U&&Y)Y.url=U[1],Y=null}return H}function bW(N){let H=[],Y=/^---\r?\n([\s\S]*?)\r?\n---/.exec(N.replace(/^\uFEFF/,""));if(!Y)return{errors:["Missing YAML frontmatter (--- name/description ---)"]};let W={};for(let $ of Y[1].split(/\r?\n/)){let G=/^([A-Za-z_][\w-]*):\s*(.*)$/.exec($);if(G)W[G[1].toLowerCase()]=G[2].trim().replace(/^["']|["']$/g,"")}if(!W.name)H.push("Frontmatter is missing required field: name");if(!W.description)H.push("Frontmatter is missing required field: description");return{name:W.name,description:W.description,errors:H}}var qW=15000,s0=new Map,a0=new Map;function hN(N){s0.delete(N)}async function IW(N){let H=s0.get(N);if(H&&Date.now()-H.at<qW)return H.view;let Y=a0.get(N);if(Y)return Y;let W=jW(N).then(($)=>{return s0.set(N,{at:Date.now(),view:$}),$}).finally(()=>{a0.delete(N)});return a0.set(N,W),W}async function jW(N){let H=new Map,Y=[];try{let W=await C("skills/list",{cwds:[B(N)],forceReload:!0});for(let $ of W.data??[]){for(let G of $.errors??[])Y.push(G);for(let G of $.skills??[]){let U=w.basename(w.dirname(G.path));H.set(U,G)}}}catch(W){console.warn("[skills] skills/list failed:",W)}return{byDir:H,errors:Y}}async function F0(N=K){await x.mkdir(AN(N),{recursive:!0});let Y=(await x.readdir(AN(N),{withFileTypes:!0})).filter((O)=>O.isDirectory()).map((O)=>O.name),{byDir:W,errors:$}=await IW(N),G=[];for(let O of Y){let Q=w.join(AN(N),O,"SKILL.md"),X=null;try{X=await x.readFile(Q,"utf8")}catch{G.push({id:O,name:O,description:"",enabled:!1,errors:["Missing SKILL.md"]});continue}let F=bW(X),M=W.get(O),T=$.filter((f)=>u(f.path).includes(`/${O}/`)||w.basename(w.dirname(f.path))===O).map((f)=>f.message);G.push({id:O,name:M?.name??F.name??O,description:M?.description??F.description??"",enabled:M?.enabled??!0,errors:[...new Set([...F.errors,...T])]})}let U=$.filter((O)=>!Y.some((Q)=>u(O.path).includes(`/${Q}/`)));return{skills:G,errors:U}}async function mN(N,H=K){let Y=DN(N,H),W;try{W=await x.readFile(w.join(Y,"SKILL.md"),"utf8")}catch{return null}let{skills:$}=await F0(H),G=$.find((Q)=>Q.id===N)??{id:N,name:N,description:"",enabled:!0,errors:[]},U=[],O=async(Q)=>{let X=await x.readdir(w.join(Y,Q),{withFileTypes:!0});for(let F of X){let M=Q?`${Q}/${F.name}`:F.name;if(F.isDirectory())await O(M);else if(M!=="SKILL.md")U.push(`${XY}/${N}/${M}`)}};return await O(""),{info:G,content:W,files:U}}async function zY(N,H=K){let Y=N.name.trim().toLowerCase().replace(/\s+/g,"-");if(kW.has(Y))throw new A(`"${Y}" is a reserved name \u2014 pick another`);let W=DN(Y,H);try{throw await x.access(w.join(W,"SKILL.md")),new A(`Skill "${Y}" already exists`)}catch(G){if(G instanceof A)throw G}let $=`---
330
- name: ${Y}
328
+ `+U.prompt.slice(0,2000)}],effort:"low"}).catch(()=>Q(null))}),$=rY(W);if(!$)return;await H.request("thread/name/set",{threadId:U.codexThreadId,name:$});let G=await NN(N,{title:$});if(G)q("runs",{type:"run.updated",run:G})}catch(H){console.warn(`[runs] title generation failed for ${N}:`,H)}}async function T(N,U){let H=I();return await H.start(),await H.initializeOnce(),H.request(N,U)}async function ZN(N){let U=N.cwd??M(),H=await B1({prompt:N.prompt,cwd:U,sandbox:N.sandbox??"workspaceWrite",approvalPolicy:N.approvalPolicy??"onRequest",approvalsReviewer:N.approvalsReviewer??"user",model:N.model,effort:N.effort??"medium",source:N.source,scheduleId:N.scheduleId,scheduleName:N.scheduleName});return q("runs",{type:"run.updated",run:H}),await C(H.id,"daemon","run.started",{prompt:N.prompt,cwd:U,attachments:N.attachments??[]}),(async()=>{try{let Y=I();await Y.start(),await Y.initializeOnce();let O=await Y.request("thread/start",{cwd:U,model:N.model??null,sandbox:KU[N.sandbox??"workspaceWrite"],approvalPolicy:q0[N.approvalPolicy??"onRequest"],...N.approvalsReviewer==="auto_review"?{approvalsReviewer:"auto_review"}:{},...$0?{developerInstructions:$0}:{},serviceName:"jun"}),W=wN(O)??(typeof O.threadId==="string"?O.threadId:null);if(!W)throw Error(`thread/start returned no thread id: ${JSON.stringify(O)}`);UN.set(W,H.id),await NN(H.id,{codexThreadId:W}),await P(H.id,"running"),await AU(H.id,N.model??v0,{threadId:W,input:g0(N.prompt,N.attachments,N.skill),summary:"detailed",effort:N.effort??"medium",sandboxPolicy:MU[N.sandbox??"workspaceWrite"]})}catch(Y){let O=Y instanceof Error?Y.message:String(Y);await C(H.id,"daemon","run.failed",{reason:O}),await P(H.id,"failed")}})(),H}async function h0(N,U){let H=I();if(await H.start(),await H.initializeOnce(),UN.has(U))return{server:H,resumed:!1};let Y=await A(N);return await H.request("thread/resume",{threadId:U,...Y?.approvalPolicy?{approvalPolicy:q0[Y.approvalPolicy]}:{},...Y?.approvalsReviewer==="auto_review"?{approvalsReviewer:"auto_review"}:{},...Y?.model?{model:Y.model}:{},...Y?.sandbox?{sandbox:KU[Y.sandbox]}:{},...$0?{developerInstructions:$0}:{}}),UN.set(U,N),{server:H,resumed:!0}}async function G0(N,U,H,Y){let O=await A(N);if(!O)throw Error(`Run not found: ${N}`);if(v(O.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let W=O.codexThreadId;if(!W)throw Error("Run has no Codex thread to resume");let $={};if(Y?.sandbox&&Y.sandbox!==O.sandbox)$.sandbox=Y.sandbox;if(Y?.approvalPolicy&&Y.approvalPolicy!==O.approvalPolicy)$.approvalPolicy=Y.approvalPolicy;if(Y?.approvalsReviewer&&Y.approvalsReviewer!==O.approvalsReviewer)$.approvalsReviewer=Y.approvalsReviewer;if(Y?.model&&Y.model!==O.model)$.model=Y.model;if(Y?.effort&&Y.effort!==O.effort)$.effort=Y.effort;if(Object.keys($).length>0){let G=await NN(N,$);if(G)q("runs",{type:"run.updated",run:G})}return await C(N,"daemon","run.resumed",{prompt:U,attachments:H??[],...Object.keys($).length>0?{modeChanges:$}:{}}),await P(N,"running"),(async()=>{try{await h0(N,W);let G=$.sandbox??O.sandbox??"workspaceWrite",F=$.approvalPolicy??O.approvalPolicy??"onRequest",Q=$.approvalsReviewer??O.approvalsReviewer,L=$.model??O.model,K=(await A(N))?.serviceTier;await AU(N,L??v0,{threadId:W,input:g0(U,H),summary:"detailed",effort:$.effort??O.effort??"medium",sandboxPolicy:MU[G],approvalPolicy:q0[F],...Q==="auto_review"?{approvalsReviewer:Q}:{},...L?{model:L}:{},...K?{serviceTier:K}:{}})}catch(G){let F=G instanceof Error?G.message:String(G);await C(N,"daemon","run.failed",{reason:F}),await P(N,"failed")}})(),await A(N)}async function TU(N,U,H){let Y=await A(N);if(!Y)throw Error(`Run not found: ${N}`);if(!v(Y.status))throw Error("Run is not active \u2014 send a follow-up message instead");let O=Y.codexThreadId,W=xN.get(N);if(!O||!W)throw Error("No active turn to steer");await C(N,"daemon","run.steered",{prompt:U,attachments:H??[]}),await I().request("turn/steer",{threadId:O,expectedTurnId:W,input:g0(U,H)})}async function BU(N,U){let H=await A(N);if(!H)throw Error(`Run not found: ${N}`);if(U){let W=((await T("model/list",{})).data??[]).find(($)=>H.model?$.model===H.model:$.isDefault);if(!W?.serviceTiers?.some(($)=>$.id==="priority"))throw Error(`Model ${W?.model??H.model??"unknown"} does not support fast mode`)}let Y=await NN(N,{serviceTier:U?"priority":"standard"});if(Y)q("runs",{type:"run.updated",run:Y});return await C(N,"daemon","run.fast",{enabled:U}),Y}async function CU(N){let U=await A(N);if(!U)throw Error(`Run not found: ${N}`);if(v(U.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let H=U.codexThreadId;if(!H)throw Error("Run has no Codex thread");let{server:Y}=await h0(N,H);await C(N,"daemon","run.compact.started",{}),await Y.request("thread/compact/start",{threadId:H})}async function RU(N,U){let H=await A(N);if(!H)throw Error(`Run not found: ${N}`);if(v(H.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let Y=H.codexThreadId;if(!Y)throw Error("Run has no Codex thread");let{server:O}=await h0(N,Y),W=U?.trim();await C(N,"daemon","run.review.started",{instructions:W??null}),await P(N,"running");try{await O.request("review/start",{threadId:Y,target:W?{type:"custom",instructions:W}:{type:"uncommittedChanges"},delivery:"inline"})}catch($){let G=$ instanceof Error?$.message:String($);throw await C(N,"daemon","run.failed",{reason:G}),await P(N,"failed"),$}return await A(N)}async function SU(N){let U=await A(N);if(!U||!v(U.status))return!1;if(U.codexThreadId&&XN?.running)try{await XN.request("turn/interrupt",{threadId:U.codexThreadId})}catch(H){console.warn(`[runs] turn/interrupt failed for ${N}:`,H)}return HN.delete(N),await C(N,"daemon","run.stopped",{}),await P(N,"stopped"),!0}async function _U(N,U,H){let Y=HN.get(N)??[],O=Y.findIndex(($)=>String($.requestId)===String(U));if(O===-1)return!1;let[W]=Y.splice(O,1);if(Y.length===0)HN.delete(N);if(W.method==="mcpServer/elicitation/request"){let $=H==="decline"||H==="cancel"?H:"accept";I().respond(W.requestId,{action:$})}else I().respond(W.requestId,{decision:H});if(await C(N,"daemon","approval.resolved",{requestId:W.requestId,decision:H}),Y.length===0)await P(N,"running");return!0}function zN(){return N2.join(k(),"config.toml")}async function u(){try{return await LN.readFile(zN(),"utf8")}catch{return""}}async function IU(N){try{m(N)}catch(U){throw new J(`Invalid TOML: ${U instanceof Error?U.message:String(U)}`)}await LN.writeFile(zN(),N,"utf8")}function U2(N){if(!N.trim())return{};let H=m(N).mcp_servers;if(typeof H!=="object"||H===null)return{};return H}async function H2(){let N=new Map;try{let U=await T("mcpServerStatus/list",{detail:"full"});for(let H of U.data??[]){let Y=Object.entries(H.tools??{}).map(([O,W])=>({name:O,description:W?.description}));N.set(H.name,{startupState:H.serverInfo?"ready":"starting",authStatus:H.authStatus??null,tools:Y})}}catch(U){console.warn("[mcp] mcpServerStatus/list failed:",U)}return N}async function PU(){let N=await u(),U=U2(N),H=await H2();return{servers:Object.entries(U).map(([O,W])=>{let $=H.get(O);return{name:O,command:W.command,args:W.args,envKeys:W.env?Object.keys(W.env):void 0,url:W.url,enabled:W.enabled!==!1,startupState:$?.startupState??null,authStatus:$?.authStatus??null,tools:$?.tools??[],error:$?.error}})}}var Y2=/^[A-Za-z0-9_-]+$/;async function wU(N){if(!Y2.test(N.name))throw new J(`Invalid server name "${N.name}" \u2014 letters, digits, _ and - only`);if(!N.command&&!N.url)throw new J("Server needs either a command or a url");let U=await u(),H=U.trim()?m(U):{},Y=H.mcp_servers??{},O={};if(N.command)O.command=N.command;if(N.args&&N.args.length>0)O.args=N.args;if(N.env&&Object.keys(N.env).length>0)O.env=N.env;if(N.url)O.url=N.url;if(N.enabled===!1)O.enabled=!1;Y[N.name]=O,H.mcp_servers=Y,await LN.writeFile(zN(),a(H),"utf8")}async function xU(N){let U=await u();if(!U.trim())return!1;let H=m(U),Y=H.mcp_servers;if(!Y||!(N in Y))return!1;return delete Y[N],await LN.writeFile(zN(),a(H),"utf8"),!0}async function fU(N,U){let H=await u(),Y=m(H||""),O=Y.mcp_servers??{};if(!O[N])throw new J(`Server not found: ${N}`);O[N].enabled=U,Y.mcp_servers=O,await LN.writeFile(zN(),a(Y),"utf8")}async function kU(){await T("config/mcpServer/reload",{})}async function yU(N,U,H,Y){let O=await u(),W=O.trim()?m(O):{},$=W.mcp_servers??{},G={command:process.execPath,args:[U],env:{JUN_PORT:String(H)}},F=$[N],Q=Boolean(Y&&$[Y]);if(F&&!Q&&F.command===G.command&&JSON.stringify(F.args)===JSON.stringify(G.args)&&F.env?.JUN_PORT===String(H))return;if(Y)delete $[Y];$[N]=G,W.mcp_servers=$,await LN.writeFile(zN(),a(W),"utf8")}var W2="https://registry.npmjs.org/junhost/latest",$2=7200000,G2=1800000,m0=null,bU=0,c0=!1,VN=null;async function qU(){try{let N=await fetch(W2,{signal:AbortSignal.timeout(5000)});if(!N.ok)throw Error(`registry ${N.status}`);let U=await N.json();m0=typeof U.version==="string"?U.version:null,c0=m0!==null}catch{c0=!1}finally{bU=Date.now(),VN=null}}function F2(){let N=c0?$2:G2;if(!VN&&Date.now()-bU>N)VN=qU();return m0}async function vU(){if(!VN)VN=qU();await VN}function Q2(N,U){let H=N.split(".").map((O)=>parseInt(O,10)||0),Y=U.split(".").map((O)=>parseInt(O,10)||0);for(let O=0;O<Math.max(H.length,Y.length);O++){let W=H[O]??0,$=Y[O]??0;if(W!==$)return W>$}return!1}function gU(){let N=F2();return{latestVersion:N,updateAvailable:N!==null&&Q2(N,FN)}}var X2=Date.now();function hU(){return X({ok:!0})}async function mU(N){if(N?.searchParams.get("refresh")==="1")await vU();let U={ok:!0,name:"jun",version:FN,...gU(),dataRoot:f,workspaceRoot:M(),uptimeSeconds:Math.round((Date.now()-X2)/1000),engine:EU()};return X(U)}import Z2 from"path";var F0={ok:!0};async function cU(N,U){let H=U.pathname.slice(11),Y=U.searchParams.get("path")??".";switch(`${N.method} ${H}`){case"GET tree":return X(await F1(Y));case"GET read":return X(await Q1(Y));case"GET download":{let O=oN(Y),W=Bun.file(O);if(!await W.exists())return Z(404,`File not found: ${Y}`);return new Response(W,{headers:{"content-disposition":`attachment; filename="${encodeURIComponent(Z2.basename(O))}"`}})}case"POST write":{let O=await z(N);return await X1(D(O.path,"path"),typeof O.content==="string"?O.content:""),X(F0)}case"POST mkdir":{let O=await z(N);return await Z1(D(O.path,"path")),X(F0)}case"POST delete":{let O=await z(N);return await L1(D(O.path,"path")),X(F0)}case"POST rename":{let O=await z(N);return await z1(D(O.from,"from"),D(O.to,"to")),X(F0)}case"POST upload":{let O;try{O=await N.formData()}catch{throw new J("Expected multipart/form-data body")}let W=String(O.get("path")??"."),$=O.getAll("file").filter((F)=>F instanceof File);if($.length===0)throw new J("No files in upload (field name: file)");let G=[];for(let F of $)G.push(await V1(W,F.name,F));return X({ok:!0,saved:G})}default:return Z(404,`Unknown files endpoint: ${N.method} /api/files/${H}`)}}var L2=new Set(["accept","acceptForSession","decline","cancel"]);async function lU(N,U,H){let Y=U.pathname.split("/").filter(Boolean),O=Y[2],W=Y[3];if(!O){if(N.method==="GET"){let $={runs:await C1()};return X($)}if(N.method==="POST"){let $=await z(N);D($.prompt,"prompt");let F={run:await ZN($)};return X(F,201)}return Z(405,"Method not allowed")}if(W==="events"){if(!await A(O))return Z(404,`Run not found: ${O}`);return H.upgrade(N,{data:{channel:`run:${O}`}})?void 0:Z(400,"WebSocket upgrade required")}if(!W&&N.method==="GET"){let $=await A(O);if(!$)return Z(404,`Run not found: ${O}`);let G=Number(U.searchParams.get("tail")??NaN),F=Number(U.searchParams.get("before")??NaN),Q=await j1(O,{limit:Number.isFinite(G)&&G>0?G:void 0,before:Number.isFinite(F)&&F>=0?F:void 0}),L={run:$,events:Q.events,eventsOffset:Q.offset,totalEvents:Q.total};return X(L)}if(N.method!=="POST")return Z(405,"Method not allowed");switch(W){case"stop":return await SU(O)?X({ok:!0}):Z(409,"Run is not active");case"resume":{let $=await z(N);D($.prompt,"prompt");try{let G=await G0(O,$.prompt,Array.isArray($.attachments)?$.attachments:void 0,{sandbox:$.sandbox,approvalPolicy:$.approvalPolicy,approvalsReviewer:$.approvalsReviewer,model:$.model,effort:$.effort});return X({run:G})}catch(G){let F=G instanceof Error?G.message:String(G),Q=F.includes("not found")?404:F.includes("still active")?409:400;return Z(Q,F)}}case"steer":{let $=await z(N);D($.prompt,"prompt");try{return await TU(O,$.prompt,Array.isArray($.attachments)?$.attachments:void 0),X({ok:!0})}catch(G){let F=G instanceof Error?G.message:String(G),Q=F.includes("not found")?404:F.includes("not active")||F.includes("No active turn")?409:400;return Z(Q,F)}}case"fast":{let $=await z(N);if(typeof $.enabled!=="boolean")return Z(400,"Missing or invalid field: enabled");try{let G=await BU(O,$.enabled);return X({run:G})}catch(G){let F=G instanceof Error?G.message:String(G),Q=F.includes("not found")?404:F.includes("does not support")?400:500;return Z(Q,F)}}case"compact":try{return await CU(O),X({ok:!0})}catch($){let G=$ instanceof Error?$.message:String($),F=G.includes("not found")?404:G.includes("still active")?409:400;return Z(F,G)}case"review":{let $=await z(N);try{let G=await RU(O,$.instructions);return X({run:G})}catch(G){let F=G instanceof Error?G.message:String(G),Q=F.includes("not found")?404:F.includes("still active")?409:400;return Z(Q,F)}}case"approve":{let $=await z(N);if(!L2.has(String($.decision)))return Z(400,`Invalid decision: ${String($.decision)}`);if($.requestId===void 0||$.requestId===null)return Z(400,"Missing field: requestId");return await _U(O,$.requestId,$.decision)?X({ok:!0}):Z(404,"No matching pending approval")}default:return Z(404,`Unknown runs endpoint: ${U.pathname}`)}}var YN="browser-stream",g=null,pU=null,DN=0,KN=null,l0=null;function z2(N){if(g&&pU===N&&g.readyState<=WebSocket.OPEN)return;g?.close(),pU=N;let U=new WebSocket(`ws://127.0.0.1:${N}`);g=U,U.onmessage=(H)=>{let Y=String(H.data);if(Y.includes('"type":"frame"'))l0=Y;M1(YN,Y)},U.onclose=()=>{if(g===U)g=null,l0=null,uU()},U.onerror=()=>{}}function uU(){if(KN||DN===0)return;KN=setTimeout(()=>{KN=null,yN(!0)},2000)}async function yN(N=!1){if(DN===0)return;let U=N?null:i1();if(U===null){if(N)p();U=(await IN()).streamPort}if(U!==null)z2(U);else uU()}function iU(){DN+=1,yN()}function dU(){return l0}function oU(){if(DN=Math.max(0,DN-1),DN===0){if(g?.close(),g=null,KN)clearTimeout(KN),KN=null}}var V2=new Set(["input_mouse","input_keyboard","input_touch"]);function nU(N){if(p1()!=="user")return;if(!g||g.readyState!==WebSocket.OPEN)return;let U=typeof N==="string"?N:N.toString("utf8");try{let H=JSON.parse(U);if(typeof H.type==="string"&&V2.has(H.type))g.send(U)}catch{}}var D2=new Set(["user","agent","paused"]);async function aU(N,U,H){let O=U.pathname.split("/").filter(Boolean)[2];if(O==="stream")return H.upgrade(N,{data:{channel:YN}})?void 0:Z(400,"WebSocket upgrade required");if(N.method==="GET")switch(O){case"status":{let W=await IN();if(W.streaming)yN();return X({status:W})}case"actions":{let W={actions:l1()};return X(W)}default:return Z(404,`Unknown browser endpoint: ${U.pathname}`)}if(N.method!=="POST")return Z(405,"Method not allowed");switch(O){case"start":{let W=await z(N).catch(()=>({})),$=await n1(typeof W.url==="string"&&W.url.length>0?W.url:void 0);return yN(),X({status:$})}case"stop":return await a1(),X({ok:!0});case"navigate":{let W=await z(N);return D(W.url,"url"),await s1(W.url),X({ok:!0})}case"key":{let W=await z(N);return D(W.key,"key"),await r1(W.key),X({ok:!0})}case"back":case"forward":case"reload":return await t1(O),X({ok:!0});case"screenshot":{let $={path:await e1()};return X($)}case"snapshot":{let W=await z(N).catch(()=>({})),$=await NU(W.interactive??!0);return X({snapshot:$})}case"click":{let W=await z(N);return D(W.target,"target"),await UU(W.target),X({ok:!0})}case"fill":{let W=await z(N);return D(W.target,"target"),D(W.text,"text"),await HU(W.target,W.text),X({ok:!0})}case"read":{let W=await z(N).catch(()=>({})),$=await YU(W.selector);return X({text:$})}case"eval":{let W=await z(N);D(W.expression,"expression");let $=await OU(W.expression);return X({result:$})}case"exec":{let W=await z(N);if(!Array.isArray(W.args)||W.args.length===0)return Z(400,"args must be a non-empty array of strings");let $=await WU(W.args,{json:W.json});return X($)}case"control":{let W=await z(N);if(!D2.has(String(W.controller)))return Z(400,`Invalid controller: ${String(W.controller)}`);return u1(W.controller),X({ok:!0})}default:return Z(404,`Unknown browser endpoint: ${U.pathname}`)}}import{promises as j}from"fs";import R from"path";var rU=".agents/skills";function MN(){return R.join(M(),rU)}var K2=/^[a-z0-9][a-z0-9-]*$/,M2=new Set(["registry","install"]);function JN(N){if(!K2.test(N))throw new J(`Invalid skill id "${N}" \u2014 use lowercase letters, digits and dashes`);return R.join(MN(),N)}function sU(N){return N.replace(/\x1b\[[0-9;?]*[A-Za-z]/g,"")}async function eU(N,U,H=120000){let Y=Bun.spawn([process.execPath,"x","skills",...N],{cwd:U,env:{...process.env,DISABLE_TELEMETRY:"1",DO_NOT_TRACK:"1"},stdout:"pipe",stderr:"pipe"}),O=setTimeout(()=>Y.kill(),H);try{let[W,$,G]=await Promise.all([new Response(Y.stdout).text(),new Response(Y.stderr).text(),Y.exited]);return{stdout:sU(W),stderr:sU($),code:G}}finally{clearTimeout(O)}}function J2(N){let U=[],H=null;for(let Y of N.split(/\r?\n/)){let O=Y.trim(),W=/^(\S+@\S+)\s+([\d.]+[KMB]?)\s+installs\b/.exec(O);if(W){let G=W[1],F=G.indexOf("@");H={source:G,repo:G.slice(0,F),name:G.slice(F+1),installs:W[2]},U.push(H);continue}let $=/^[\u2514\u2570]\s*(https?:\/\/\S+)/.exec(O);if($&&H)H.url=$[1],H=null}return U}function A2(N){let U=[],H=/^---\r?\n([\s\S]*?)\r?\n---/.exec(N.replace(/^\uFEFF/,""));if(!H)return{errors:["Missing YAML frontmatter (--- name/description ---)"]};let Y={};for(let O of H[1].split(/\r?\n/)){let W=/^([A-Za-z_][\w-]*):\s*(.*)$/.exec(O);if(W)Y[W[1].toLowerCase()]=W[2].trim().replace(/^["']|["']$/g,"")}if(!Y.name)U.push("Frontmatter is missing required field: name");if(!Y.description)U.push("Frontmatter is missing required field: description");return{name:Y.name,description:Y.description,errors:U}}var E2=15000,bN=null,Q0=null;function qN(){bN=null}async function T2(){if(bN&&Date.now()-bN.at<E2)return bN.view;if(Q0)return Q0;let N=B2().then((U)=>{return bN={at:Date.now(),view:U},U}).finally(()=>{Q0=null});return Q0=N,N}async function B2(){let N=new Map,U=[];try{let H=await T("skills/list",{cwds:[M()],forceReload:!0});for(let Y of H.data??[]){for(let O of Y.errors??[])U.push(O);for(let O of Y.skills??[]){let W=R.basename(R.dirname(O.path));N.set(W,O)}}}catch(H){console.warn("[skills] skills/list failed:",H)}return{byDir:N,errors:U}}async function X0(){await j.mkdir(MN(),{recursive:!0});let U=(await j.readdir(MN(),{withFileTypes:!0})).filter(($)=>$.isDirectory()).map(($)=>$.name),{byDir:H,errors:Y}=await T2(),O=[];for(let $ of U){let G=R.join(MN(),$,"SKILL.md"),F=null;try{F=await j.readFile(G,"utf8")}catch{O.push({id:$,name:$,description:"",enabled:!1,errors:["Missing SKILL.md"]});continue}let Q=A2(F),L=H.get($),K=Y.filter((E)=>c(E.path).includes(`/${$}/`)||R.basename(R.dirname(E.path))===$).map((E)=>E.message);O.push({id:$,name:L?.name??Q.name??$,description:L?.description??Q.description??"",enabled:L?.enabled??!0,errors:[...new Set([...Q.errors,...K])]})}let W=Y.filter(($)=>!U.some((G)=>c($.path).includes(`/${G}/`)));return{skills:O,errors:W}}async function vN(N){let U=JN(N),H;try{H=await j.readFile(R.join(U,"SKILL.md"),"utf8")}catch{return null}let{skills:Y}=await X0(),O=Y.find((G)=>G.id===N)??{id:N,name:N,description:"",enabled:!0,errors:[]},W=[],$=async(G)=>{let F=await j.readdir(R.join(U,G),{withFileTypes:!0});for(let Q of F){let L=G?`${G}/${Q.name}`:Q.name;if(Q.isDirectory())await $(L);else if(L!=="SKILL.md")W.push(`${rU}/${N}/${L}`)}};return await $(""),{info:O,content:H,files:W}}async function NH(N){let U=N.name.trim().toLowerCase().replace(/\s+/g,"-");if(M2.has(U))throw new J(`"${U}" is a reserved name \u2014 pick another`);let H=JN(U);try{throw await j.access(R.join(H,"SKILL.md")),new J(`Skill "${U}" already exists`)}catch(O){if(O instanceof J)throw O}let Y=`---
329
+ name: ${U}
331
330
  description: ${N.description.trim()}
332
331
  ---
333
332
 
334
333
  ${N.instructions?.trim()??"Describe when and how to use this skill."}
335
- `;return await x.mkdir(W,{recursive:!0}),await x.writeFile(w.join(W,"SKILL.md"),$,"utf8"),hN(H),await mN(Y,H)}async function FY(N,H,Y=K){let W=DN(N,Y);try{await x.access(W)}catch{throw new A(`Skill not found: ${N}`)}return await x.writeFile(w.join(W,"SKILL.md"),H,"utf8"),hN(Y),await mN(N,Y)}async function VY(N,H=K){let Y=DN(N,H);try{return await x.rm(Y,{recursive:!0,force:!1}),hN(H),!0}catch{return!1}}async function KY(N,H,Y=K){let W=w.join(DN(N,Y),"SKILL.md");await C("skills/config/write",{path:W,enabled:H,name:null}),hN(Y)}async function LY(N){let H=N.trim();if(!H)return[];let{stdout:Y}=await ZY(["find",H],B(K),30000);return yW(Y)}async function QY(N){await x.mkdir(AN(N),{recursive:!0});let H=await x.readdir(AN(N),{withFileTypes:!0});return new Set(H.filter((Y)=>Y.isDirectory()).map((Y)=>Y.name))}async function MY(N,H=K){let Y=N.trim();if(!Y)throw new A("Missing skill source");if(/[\s;&|`$(){}<>]/.test(Y))throw new A("Invalid source \u2014 expected owner/repo[@skill] or a URL");let W=B(H),$=await QY(H),{stdout:G,stderr:U}=await ZY(["add",Y,"-a","codex","--copy","-y"],W);hN(H);let Q=[...await QY(H)].filter((F)=>!$.has(F));if(Q.length===0){let F=[G,U].filter(Boolean).join(`
336
- `).trim();throw new A(`No skill installed from "${Y}".${F?`
337
- ${F}`:""}`)}let{skills:X}=await F0(H);return{installed:Q,skills:X,log:[G,U].filter(Boolean).join(`
338
- `).trim()}}async function JY(N,H,Y=K){let W=await mN(N,Y);if(!W)throw new A(`Skill not found: ${N}`);let $={prompt:H?.trim()||`Use the "${W.info.name}" skill to demonstrate what it does. Follow its instructions and report the result.`,projectId:Y,skill:{name:W.info.name,path:w.join(DN(N,Y),"SKILL.md")}};return VN($)}async function gW(N){let H=N.searchParams.get("project");if(H)return H;let Y=N.searchParams.get("cwd");if(Y){let W=iN(Y);if(W&&await MN(W))return W}return K}async function BY(N,H){let Y=H.pathname.split("/").filter(Boolean),W=Y[2],$=Y[3],G=await gW(H);if(W==="registry"){if($==="search"&&N.method==="GET"){let U=H.searchParams.get("q")??"",O=await LY(U);return Z({results:O})}if($==="install"&&N.method==="POST"){let U=await V(N);J(U.source,"source");let O=await MY(U.source,G);return Z(O,201)}return z(404,`Unknown skills endpoint: ${H.pathname}`)}if(!W){if(N.method==="GET")return Z(await F0(G));if(N.method==="POST"){let U=await V(N);J(U.name,"name"),J(U.description,"description");let O=await zY(U,G);return Z({skill:O},201)}return z(405,"Method not allowed")}if(!$)switch(N.method){case"GET":{let U=await mN(W,G);return U?Z({skill:U}):z(404,`Skill not found: ${W}`)}case"PUT":{let U=await V(N);J(U.content,"content");let O=await FY(W,U.content,G);return Z({skill:O})}case"DELETE":return await VY(W,G)?Z({ok:!0}):z(404,`Skill not found: ${W}`);default:return z(405,"Method not allowed")}if(N.method!=="POST")return z(405,"Method not allowed");switch($){case"enable":{let U=await V(N);if(typeof U.enabled!=="boolean")return z(400,"Missing or invalid field: enabled");return await KY(W,U.enabled,G),Z({ok:!0})}case"test":{let U=await V(N).catch(()=>({})),O=await JY(W,U.prompt,G);return Z({run:O},201)}default:return z(404,`Unknown skills endpoint: ${H.pathname}`)}}async function AY(N,H){let Y=H.pathname.split("/").filter(Boolean),W=Y[2];if(!W){if(N.method==="GET")return Z(await vH());return z(405,"Method not allowed")}if(W==="config"){if(N.method==="GET"){let $={toml:await d()};return Z($)}if(N.method==="PUT"){let $=await V(N);return J($.toml,"toml"),await jH($.toml),Z({ok:!0})}return z(405,"Method not allowed")}if(W==="reload"&&N.method==="POST")return await cH(),Z({ok:!0});if(W==="servers"){let $=Y[3];if(!$){if(N.method==="POST"){let U=await V(N);return J(U.name,"name"),await gH(U),Z({ok:!0},201)}return z(405,"Method not allowed")}let G=Y[4];if(G==="enable"&&N.method==="POST"){let U=await V(N);if(typeof U.enabled!=="boolean")return z(400,"Missing or invalid field: enabled");return await mH($,U.enabled),Z({ok:!0})}if(!G&&N.method==="DELETE")return await hH($)?Z({ok:!0}):z(404,`Server not found: ${$}`);return z(405,"Method not allowed")}return z(404,`Unknown MCP endpoint: ${H.pathname}`)}import{promises as UN}from"fs";import cN from"path";function hW(){return cN.join(j(),"config.toml")}function K0(){return cN.join(j(),"memories")}async function DY(){let N=await d();return N.trim()?l(N):{}}function V0(N){return typeof N==="object"&&N!==null?N:{}}function mW(N){let H=V0(N.memories),Y={};if(typeof H.generate_memories==="boolean")Y.generateMemories=H.generate_memories;if(typeof H.use_memories==="boolean")Y.useMemories=H.use_memories;if(typeof H.disable_on_external_context==="boolean")Y.disableOnExternalContext=H.disable_on_external_context;if(typeof H.min_rate_limit_remaining_percent==="number")Y.minRateLimitRemainingPercent=H.min_rate_limit_remaining_percent;return Y}async function cW(){let N=K0(),H=[];async function Y(W){let $;try{$=await UN.readdir(W,{withFileTypes:!0})}catch{return}for(let G of $){let U=cN.join(W,G.name);if(G.isDirectory()){if(G.name===".git")continue;await Y(U)}else if(G.isFile()){let O=await UN.stat(U);H.push({path:u(cN.relative(N,U)),name:G.name,size:O.size,modifiedAt:O.mtime.toISOString()})}}}return await Y(N),H.sort((W,$)=>$.modifiedAt.localeCompare(W.modifiedAt)),H}async function lW(){try{let H=((await C("experimentalFeature/list",{})).data??[]).find((Y)=>Y.name==="memories");return H?H.enabled:null}catch(N){return console.warn("[memories] experimentalFeature/list failed:",N),null}}async function CY(){let N=await DY();return{enabled:V0(N.features).memories===!0,liveEnabled:await lW(),settings:mW(N),files:await cW()}}async function RY(N){let H=await DY();if(typeof N.enabled==="boolean"){let Y=V0(H.features);Y.memories=N.enabled,H.features=Y}if(N.settings){let Y=V0(H.memories),W=N.settings;if(typeof W.generateMemories==="boolean")Y.generate_memories=W.generateMemories;if(typeof W.useMemories==="boolean")Y.use_memories=W.useMemories;if(typeof W.disableOnExternalContext==="boolean")Y.disable_on_external_context=W.disableOnExternalContext;if(typeof W.minRateLimitRemainingPercent==="number")Y.min_rate_limit_remaining_percent=W.minRateLimitRemainingPercent;H.memories=Y}if(await UN.writeFile(hW(),t(H),"utf8"),typeof N.enabled==="boolean")try{await C("experimentalFeature/enablement/set",{enablement:{memories:N.enabled}})}catch(Y){console.warn("[memories] live enablement/set failed (applies on restart):",Y)}}async function SY(N){let H=HN(K0(),N);return UN.readFile(H,"utf8")}async function TY(N,H){let Y=HN(K0(),N);await UN.mkdir(cN.dirname(Y),{recursive:!0}),await UN.writeFile(Y,H,"utf8")}async function EY(N){let H=HN(K0(),N);await UN.rm(H)}async function wY(N,H){let W=H.pathname.split("/").filter(Boolean)[2];if(!W){if(N.method==="GET")return Z(await CY());return z(405,"Method not allowed")}if(W==="config"){if(N.method==="PUT"){let $=await V(N);if(typeof $.enabled!=="boolean"&&!$.settings)return z(400,"Nothing to update: pass enabled and/or settings");return await RY($),Z({ok:!0})}return z(405,"Method not allowed")}if(W==="file"){if(N.method==="GET"){let $=J(H.searchParams.get("path"),"path"),G={path:$,content:await SY($)};return Z(G)}if(N.method==="PUT"){let $=await V(N);if(J($.path,"path"),typeof $.content!=="string")return z(400,"Missing or invalid field: content");return await TY($.path,$.content),Z({ok:!0})}if(N.method==="DELETE"){let $=J(H.searchParams.get("path"),"path");return await EY($),Z({ok:!0})}return z(405,"Method not allowed")}return z(404,`Unknown memories endpoint: ${H.pathname}`)}var iW=300000,L0=null;async function _Y(N){if(N.method!=="GET")return z(405,"Method not allowed");if(L0&&Date.now()-L0.at<iW)return Z({models:L0.models});let Y=((await C("model/list",{})).data??[]).filter(($)=>!$.hidden).map(($)=>({id:$.id,model:$.model,displayName:$.displayName,description:$.description,isDefault:$.isDefault,defaultReasoningEffort:$.defaultReasoningEffort,supportedReasoningEfforts:$.supportedReasoningEfforts??[]}));return L0={at:Date.now(),models:Y},Z({models:Y})}async function M0(){let N=await C("account/read",{});return{account:N.account??null,requiresOpenaiAuth:N.requiresOpenaiAuth,pendingLogin:O0(),lastLoginResult:BH()}}async function PY(N,H){if(H.pathname==="/api/account"){if(N.method!=="GET")return z(405,"Method not allowed");return Z(await M0())}if(H.pathname==="/api/account/login"&&N.method==="POST"){let Y=await V(N),W;if(Y.type==="chatgpt"||Y.type==="chatgptDeviceCode")W={type:Y.type};else if(Y.type==="apiKey")W={type:"apiKey",apiKey:J(Y.apiKey,"apiKey")};else throw new A("type must be one of: chatgpt, chatgptDeviceCode, apiKey");let $=O0();if($)await C("account/login/cancel",{loginId:$.loginId}).catch(()=>{});Q0();let G=await C("account/login/start",W);if((G.type==="chatgpt"||G.type==="chatgptDeviceCode")&&G.loginId){let U={loginId:G.loginId,type:G.type,authUrl:G.authUrl,userCode:G.userCode,verificationUrl:G.verificationUrl,startedAt:new Date().toISOString()};AH(U)}return Z(await M0())}if(H.pathname==="/api/account/login/cancel"&&N.method==="POST"){let Y=O0();if(Y)await C("account/login/cancel",{loginId:Y.loginId}).catch(()=>{});return Q0(),Z(await M0())}if(H.pathname==="/api/account/logout"&&N.method==="POST")return await C("account/logout",{}),Q0(),Z(await M0());return z(404,`Not found: ${H.pathname}`)}function pW(N){if(!N)return null;return N.replace(/^([a-z0-9+.-]+:\/\/[^:@/]+):[^@/]+@/i,"$1:\u2022\u2022\u2022\u2022@")}function xY(){let N=$0(),H=G0();return{browserProxy:{proxyUrl:pW(N.value),source:N.source,noProxy:H.value,noProxySource:H.source}}}async function fY(N,H){if(H.pathname==="/api/settings"&&N.method==="GET")return Z(xY());if(H.pathname==="/api/settings/browser-proxy"&&N.method==="PUT"){let Y=await V(N);if(Y.proxyUrl!==void 0&&Y.proxyUrl!==null&&Y.proxyUrl.trim())try{if(!new URL(Y.proxyUrl.trim()).hostname)throw Error("missing host")}catch{return z(400,"Invalid proxy URL \u2014 expected e.g. http://user:pass@host:port")}return await m1({...Y.proxyUrl!==void 0?{browserProxy:Y.proxyUrl}:{},...Y.noProxy!==void 0?{browserNoProxy:Y.noProxy}:{}}),Z(xY())}if(N.method!=="GET"&&N.method!=="PUT")return z(405,"Method not allowed");return z(404,`Unknown settings endpoint: ${H.pathname}`)}import{promises as CN}from"fs";import vY from"path";import{randomUUID as rW}from"crypto";function lN(N,H,Y,W){let $=new Set,G=N.trim()!=="*";for(let U of N.split(",")){let O=U.trim();if(!O)throw Error(`Invalid ${W} field: empty term`);let Q=O,X=1,F=O.indexOf("/");if(F!==-1){if(Q=O.slice(0,F),X=Number(O.slice(F+1)),!Number.isInteger(X)||X<=0)throw Error(`Invalid step in ${W}: ${O}`)}let M,T;if(Q==="*")M=H,T=Y;else if(Q.includes("-")){let[f,ON]=Q.split("-");M=Number(f),T=Number(ON)}else M=Number(Q),T=M;if(!Number.isInteger(M)||!Number.isInteger(T))throw Error(`Invalid ${W} value: ${O}`);if(M<H||T>Y||M>T)throw Error(`${W} out of range (${H}-${Y}): ${O}`);for(let f=M;f<=T;f+=X)$.add(f)}return{set:$,restricted:G}}function bY(N){let H=N.trim().split(/\s+/);if(H.length!==5)throw Error(`Cron must have 5 fields (min hour dom month dow); got ${H.length}`);let Y=lN(H[0],0,59,"minute"),W=lN(H[1],0,23,"hour"),$=lN(H[2],1,31,"day-of-month"),G=lN(H[3],1,12,"month"),U=lN(H[4],0,7,"day-of-week"),O=new Set;for(let Q of U.set)O.add(Q===7?0:Q);return{minute:Y.set,hour:W.set,dom:$.set,month:G.set,dow:O,domRestricted:$.restricted,dowRestricted:U.restricted}}function qY(N){try{return bY(N),null}catch(H){return H instanceof Error?H.message:"Invalid cron expression"}}function nW(N){return new Intl.DateTimeFormat("en-US",{timeZone:N,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hourCycle:"h23"})}function IY(N,H){if(!H)return{year:N.getFullYear(),month:N.getMonth()+1,day:N.getDate(),hour:N.getHours(),minute:N.getMinutes(),second:N.getSeconds()};let Y={};for(let W of nW(H).formatToParts(N))if(W.type!=="literal")Y[W.type]=Number(W.value);return{year:Y.year,month:Y.month,day:Y.day,hour:Y.hour,minute:Y.minute,second:Y.second}}function dW(N,H){return new Date(Date.UTC(N,H,0)).getUTCDate()}function oW(N){return new Date(Date.UTC(N.year,N.month-1,N.day)).getUTCDay()}function kY(N){if(N.minute++,N.minute<60)return;if(N.minute=0,N.hour++,N.hour<24)return;if(N.hour=0,N.day++,N.day<=dW(N.year,N.month))return;if(N.day=1,N.month++,N.month<=12)return;N.month=1,N.year++}function aW(N,H){if(!N.minute.has(H.minute))return!1;if(!N.hour.has(H.hour))return!1;if(!N.month.has(H.month))return!1;let Y=N.dom.has(H.day),W=N.dow.has(oW(H));if(N.domRestricted&&N.dowRestricted)return Y||W;if(N.domRestricted)return Y;if(N.dowRestricted)return W;return!0}function yY(N,H){let Y=IY(N,H);return Date.UTC(Y.year,Y.month-1,Y.day,Y.hour,Y.minute,Y.second)-N.getTime()}function sW(N,H){if(!H)return new Date(N.year,N.month-1,N.day,N.hour,N.minute,0,0);let Y=Date.UTC(N.year,N.month-1,N.day,N.hour,N.minute,0),W=yY(new Date(Y),H),$=Y-W,G=yY(new Date($),H);if(G!==W)$=Y-G;return new Date($)}var tW=4216320;function jY(N,H,Y){let W=bY(N),$=IY(H,Y),G={year:$.year,month:$.month,day:$.day,hour:$.hour,minute:$.minute};kY(G);for(let U=0;U<tW;U++){if(aW(W,G))return sW(G,Y);kY(G)}return null}var eW={sandbox:"workspaceWrite",approvalPolicy:"onRequest",approvalsReviewer:"auto_review",effort:"medium"};function N$(N){return N.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}function r0(N){return vY.join(RN(),`${N}.json`)}async function gY(){await CN.mkdir(RN(),{recursive:!0})}async function e0(N){await gY(),await CN.writeFile(r0(N.id),JSON.stringify(N,null,2),"utf8")}function N1(N,H){if(!N.enabled)return null;if(N.kind==="once"){if(!N.runAt)return null;let W=new Date(N.runAt);if(Number.isNaN(W.getTime()))return null;if(N.lastRunAt)return null;return W.toISOString()}if(!N.cron)return null;let Y=jY(N.cron,H,N.tz);return Y?Y.toISOString():null}function hY(N,H){if(H==="cron"){if(!N.cron)throw Error("cron expression is required for a cron schedule");let Y=qY(N.cron);if(Y)throw Error(`Invalid cron expression: ${Y}`)}else{if(!N.runAt)throw Error("runAt is required for a one-off schedule");if(Number.isNaN(new Date(N.runAt).getTime()))throw Error("runAt is not a valid datetime")}if(N.tz)try{new Intl.DateTimeFormat("en-US",{timeZone:N.tz})}catch{throw Error(`Unknown timezone: ${N.tz}`)}}async function H1(N){await gY();let H;try{H=await CN.readdir(RN())}catch{return[]}let Y=[];for(let W of H){if(!W.endsWith(".json"))continue;try{let $=await CN.readFile(vY.join(RN(),W),"utf8"),G=JSON.parse($);if(N&&G.projectId!==N)continue;Y.push(G)}catch{}}return Y.sort((W,$)=>$.createdAt.localeCompare(W.createdAt)),Y}async function J0(N){try{let H=await CN.readFile(r0(N),"utf8");return JSON.parse(H)}catch{return null}}async function mY(N){let H=N.name?.trim();if(!H)throw Error("Schedule name is required");if(!N.prompt?.trim())throw Error("Schedule prompt is required");let Y=N.projectId??"default";if(!await MN(Y))throw Error(`Unknown project: ${Y}`);let W=N.kind??"cron";hY(N,W);let $=`${N$(H)||"schedule"}-${rW().slice(0,8)}`,G=new Date,U={id:$,name:H,projectId:Y,prompt:N.prompt,kind:W,cron:W==="cron"?N.cron:void 0,runAt:W==="once"?new Date(N.runAt).toISOString():void 0,tz:N.tz,mode:{...eW,...N.mode??{}},resume:N.resume??!1,threadRunId:null,enabled:N.enabled??!0,createdAt:G.toISOString(),lastRunAt:null,lastRunId:null,lastError:null,nextRunAt:null};return U.nextRunAt=N1(U,G),await e0(U),U}async function cY(N,H){let Y=await J0(N);if(!Y)return null;let W=H.kind??Y.kind,$={...Y,name:H.name?.trim()||Y.name,prompt:H.prompt??Y.prompt,kind:W,cron:W==="cron"?H.cron??Y.cron:void 0,runAt:W==="once"?H.runAt?new Date(H.runAt).toISOString():Y.runAt:void 0,tz:H.tz!==void 0?H.tz||void 0:Y.tz,mode:H.mode?{...Y.mode,...H.mode}:Y.mode,resume:H.resume??Y.resume,enabled:H.enabled??Y.enabled};if(hY($,W),W==="once"&&H.runAt&&$.runAt!==Y.runAt)$.lastRunAt=null;return $.nextRunAt=N1($,new Date),await e0($),$}async function lY(N){try{return await CN.unlink(r0(N)),!0}catch{return!1}}function H$(N){return{sandbox:N.sandbox,approvalPolicy:N.approvalPolicy,approvalsReviewer:N.approvalsReviewer,model:N.model,effort:N.effort}}async function Y1(N,H){let Y=N.lastRunId??null,W=null,$=N.threadRunId??null;try{let U=N.mode;if(N.resume&&$&&await D($)){let O=await D($);if(O&&m(O.status))throw Error("previous run still active \u2014 skipped this fire");Y=(await Z0($,N.prompt,[],H$(U))).id}else{let O=await VN({prompt:N.prompt,projectId:N.projectId,sandbox:U.sandbox,approvalPolicy:U.approvalPolicy,approvalsReviewer:U.approvalsReviewer,model:U.model,effort:U.effort,source:"schedule",scheduleId:N.id,scheduleName:N.name});if(Y=O.id,N.resume)$=O.id}}catch(U){W=U instanceof Error?U.message:String(U)}let G={...N,lastRunAt:H.toISOString(),lastRunId:Y,lastError:W,threadRunId:$};return G.nextRunAt=N1(G,H),await e0(G),G}var t0=!1;async function uY(N=new Date){if(t0)return;t0=!0;try{let H=await H1();for(let Y of H){if(!Y.enabled||!Y.nextRunAt)continue;let W=new Date(Y.nextRunAt);if(Number.isNaN(W.getTime())||W.getTime()>N.getTime())continue;try{await Y1(Y,N)}catch($){console.error(`[schedules] fire failed for ${Y.id}:`,$)}}}catch(H){console.error("[schedules] tick failed:",H)}finally{t0=!1}}async function iY(N){let H=N.searchParams.get("project");if(H)return H;let Y=N.searchParams.get("cwd");if(Y){let W=iN(Y);if(W&&await MN(W))return W;return K}return}async function pY(N,H){let Y=H.pathname.split("/").filter(Boolean),W=Y[2],$=Y[3];if(!W){if(N.method==="GET"){let G=await iY(H),U={schedules:await H1(G)};return Z(U)}if(N.method==="POST"){let G=await V(N);if(!G.projectId){let U=await iY(H);if(U)G.projectId=U}try{let O={schedule:await mY(G)};return Z(O,201)}catch(U){return z(400,U instanceof Error?U.message:String(U))}}return z(405,"Method not allowed")}if($==="run"&&N.method==="POST"){let G=await J0(W);if(!G)return z(404,`Schedule not found: ${W}`);let O={schedule:await Y1(G,new Date)};return Z(O)}if($)return z(404,`Not found: ${H.pathname}`);if(N.method==="GET"){let G=await J0(W);return G?Z({schedule:G}):z(404,`Schedule not found: ${W}`)}if(N.method==="PUT"){let G=await V(N);try{let U=await cY(W,G);return U?Z({schedule:U}):z(404,`Schedule not found: ${W}`)}catch(U){return z(400,U instanceof Error?U.message:String(U))}}if(N.method==="DELETE")return await lY(W)?Z({ok:!0}):z(404,`Schedule not found: ${W}`);return z(405,"Method not allowed")}var W$=2000,B0=[],$$=0,nY=!1,W1="logs";function G$(N){return N.map((H)=>{if(typeof H==="string")return H;if(H instanceof Error)return H.stack??H.message;try{return Bun.inspect(H,{colors:!1,depth:3})}catch{return String(H)}}).join(" ")}function U$(N,H){let Y={seq:++$$,ts:new Date().toISOString(),level:N,text:G$(H)};if(B0.push(Y),B0.length>W$)B0.shift();h(W1,Y)}function dY(){if(nY)return;nY=!0;let N=(H,Y)=>{let W=console[H].bind(console);console[H]=(...$)=>{try{U$(Y,$)}catch{}W(...$)}};N("log","info"),N("info","info"),N("warn","warn"),N("error","error")}function oY(N={}){let H={info:0,warn:1,error:2},Y=N.level?H[N.level]:0,W=N.query?.toLowerCase(),$=B0.filter((G)=>H[G.level]>=Y&&(!W||G.text.toLowerCase().includes(W)));if(N.limit&&$.length>N.limit)$=$.slice(-N.limit);return $}var O$=new Set(["info","warn","error"]);function aY(N,H,Y){if(H.pathname==="/api/logs/stream")return Y.upgrade(N,{data:{channel:W1}})?void 0:z(400,"WebSocket upgrade required");if(N.method!=="GET")return z(405,"Method not allowed");let W=Number(H.searchParams.get("limit")),$=H.searchParams.get("level"),G=$&&O$.has($)?$:void 0,U={logs:oY({limit:Number.isFinite(W)&&W>0?Math.min(W,2000):500,level:G,query:H.searchParams.get("q")??void 0})};return Z(U)}async function sY(N,H){let Y=new URL(N.url);try{if(Y.pathname==="/api/health")return pH();if(Y.pathname==="/api/status")return nH();if(Y.pathname==="/api/files/watch")return H.upgrade(N,{data:{channel:"files"}})?void 0:z(400,"WebSocket upgrade required");if(Y.pathname.startsWith("/api/files/"))return await dH(N,Y);if(Y.pathname==="/api/projects"||Y.pathname.startsWith("/api/projects/"))return await rH(N,Y);if(Y.pathname==="/api/runs"||Y.pathname.startsWith("/api/runs/"))return await eH(N,Y,H);if(Y.pathname.startsWith("/api/browser/"))return await UY(N,Y,H);if(Y.pathname==="/api/skills"||Y.pathname.startsWith("/api/skills/"))return await BY(N,Y);if(Y.pathname==="/api/mcp"||Y.pathname.startsWith("/api/mcp/"))return await AY(N,Y);if(Y.pathname==="/api/memories"||Y.pathname.startsWith("/api/memories/"))return await wY(N,Y);if(Y.pathname==="/api/models")return await _Y(N);if(Y.pathname==="/api/account"||Y.pathname.startsWith("/api/account/"))return await PY(N,Y);if(Y.pathname==="/api/settings"||Y.pathname.startsWith("/api/settings/"))return await fY(N,Y);if(Y.pathname==="/api/schedules"||Y.pathname.startsWith("/api/schedules/"))return await pY(N,Y);if(Y.pathname==="/api/logs"||Y.pathname.startsWith("/api/logs/"))return aY(N,Y,H);return z(404,`Not found: ${Y.pathname}`)}catch(W){if(W instanceof aN)return z(400,W.message);if(W instanceof A)return z(400,W.message);if(Q$(W))return z(404,`Not found: ${Y.searchParams.get("path")??Y.pathname}`);return console.error(`[api] ${N.method} ${Y.pathname} failed:`,W),z(500,W instanceof Error?W.message:"Internal error")}}function Q$(N){return typeof N==="object"&&N!==null&&"code"in N&&N.code==="ENOENT"}dY();await O1();var A0=[b.resolve(import.meta.dir,"../ui-dist"),b.resolve(import.meta.dir,"../../ui/dist")].find((N)=>tY(b.join(N,"index.html")))??b.resolve(import.meta.dir,"../../ui/dist"),Z$=(N)=>[`${N}.ts`,`${N}.js`].map((H)=>b.join(import.meta.dir,H)).find((H)=>tY(H));for(let[N,H,Y]of[["jun","mcp-server","agenthost"],["jun-browser","browser-mcp-server",void 0]])try{let W=Z$(H);if(W)await lH(N,W,uN,Y);else console.warn(`[daemon] ${N} MCP server script (${H}) not found next to daemon`)}catch(W){console.warn(`[daemon] could not register ${N} MCP server:`,W)}a1(b.join(import.meta.dir,".."));var eY=Bun.serve({hostname:C0,port:uN,async fetch(N,H){let Y=new URL(N.url);if(Y.pathname.startsWith("/api/"))return sY(N,H);let W=await F$(Y.pathname);if(W)return W;return new Response("Jun daemon is running. Build the UI to enable the dashboard.",{status:200})},websocket:{idleTimeout:960,open(N){if(N.subscribe(N.data.channel),N.data.channel===GN){YY();let H=WY();if(H)N.send(H)}},message(N,H){if(N.data.channel===GN)GY(H)},close(N){if(N.unsubscribe(N.data.channel),N.data.channel===GN)$Y()}}});T1(eY);try{X$(QN(),{recursive:!0},(N,H)=>{let Y={type:"fs.changed",path:H?u(String(H)):null,ts:new Date().toISOString()};eY.publish("files",JSON.stringify(Y))})}catch(N){console.warn("[daemon] workspace watcher unavailable:",N)}var z$=30000;setInterval(()=>{uY()},z$);console.log(`Jun daemon running at http://${C0}:${uN}`);console.log(`Workspace: ${b.resolve(B())}`);async function F$(N){let H=b.join(A0,"index.html");if(!await V$(H))return null;let Y=b.normalize(decodeURIComponent(N)).replace(/^[/\\]+/,""),W=b.resolve(A0,Y||"index.html"),$=`${A0}${b.sep}`;if(W!==A0&&!W.startsWith($))return new Response("Not found",{status:404});if(await K$(W))return new Response(Bun.file(W),{headers:{"content-type":L$(W)}});return new Response(Bun.file(H),{headers:{"content-type":"text/html; charset=utf-8"}})}async function V$(N){try{return await rY(N),!0}catch{return!1}}async function K$(N){try{return(await rY(N)).isFile()}catch{return!1}}function L$(N){switch(b.extname(N)){case".css":return"text/css; charset=utf-8";case".html":return"text/html; charset=utf-8";case".js":return"text/javascript; charset=utf-8";case".json":return"application/json; charset=utf-8";case".svg":return"image/svg+xml";case".webp":return"image/webp";case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".ico":return"image/x-icon";default:return"application/octet-stream"}}
334
+ `;return await j.mkdir(H,{recursive:!0}),await j.writeFile(R.join(H,"SKILL.md"),Y,"utf8"),qN(),await vN(U)}async function UH(N,U){let H=JN(N);try{await j.access(H)}catch{throw new J(`Skill not found: ${N}`)}return await j.writeFile(R.join(H,"SKILL.md"),U,"utf8"),qN(),await vN(N)}async function HH(N){let U=JN(N);try{return await j.rm(U,{recursive:!0,force:!1}),qN(),!0}catch{return!1}}async function YH(N,U){let H=R.join(JN(N),"SKILL.md");await T("skills/config/write",{path:H,enabled:U,name:null}),qN()}async function OH(N){let U=N.trim();if(!U)return[];let{stdout:H}=await eU(["find",U],M(),30000);return J2(H)}async function tU(){await j.mkdir(MN(),{recursive:!0});let N=await j.readdir(MN(),{withFileTypes:!0});return new Set(N.filter((U)=>U.isDirectory()).map((U)=>U.name))}async function WH(N){let U=N.trim();if(!U)throw new J("Missing skill source");if(/[\s;&|`$(){}<>]/.test(U))throw new J("Invalid source \u2014 expected owner/repo[@skill] or a URL");let H=M(),Y=await tU(),{stdout:O,stderr:W}=await eU(["add",U,"-a","codex","--copy","-y"],H);qN();let G=[...await tU()].filter((Q)=>!Y.has(Q));if(G.length===0){let Q=[O,W].filter(Boolean).join(`
335
+ `).trim();throw new J(`No skill installed from "${U}".${Q?`
336
+ ${Q}`:""}`)}let{skills:F}=await X0();return{installed:G,skills:F,log:[O,W].filter(Boolean).join(`
337
+ `).trim()}}async function $H(N,U){let H=await vN(N);if(!H)throw new J(`Skill not found: ${N}`);let Y={prompt:U?.trim()||`Use the "${H.info.name}" skill to demonstrate what it does. Follow its instructions and report the result.`,skill:{name:H.info.name,path:R.join(JN(N),"SKILL.md")}};return ZN(Y)}async function GH(N,U){let H=U.pathname.split("/").filter(Boolean),Y=H[2],O=H[3];if(Y==="registry"){if(O==="search"&&N.method==="GET"){let W=U.searchParams.get("q")??"",$=await OH(W);return X({results:$})}if(O==="install"&&N.method==="POST"){let W=await z(N);D(W.source,"source");let $=await WH(W.source);return X($,201)}return Z(404,`Unknown skills endpoint: ${U.pathname}`)}if(!Y){if(N.method==="GET")return X(await X0());if(N.method==="POST"){let W=await z(N);D(W.name,"name"),D(W.description,"description");let $=await NH(W);return X({skill:$},201)}return Z(405,"Method not allowed")}if(!O)switch(N.method){case"GET":{let W=await vN(Y);return W?X({skill:W}):Z(404,`Skill not found: ${Y}`)}case"PUT":{let W=await z(N);D(W.content,"content");let $=await UH(Y,W.content);return X({skill:$})}case"DELETE":return await HH(Y)?X({ok:!0}):Z(404,`Skill not found: ${Y}`);default:return Z(405,"Method not allowed")}if(N.method!=="POST")return Z(405,"Method not allowed");switch(O){case"enable":{let W=await z(N);if(typeof W.enabled!=="boolean")return Z(400,"Missing or invalid field: enabled");return await YH(Y,W.enabled),X({ok:!0})}case"test":{let W=await z(N).catch(()=>({})),$=await $H(Y,W.prompt);return X({run:$},201)}default:return Z(404,`Unknown skills endpoint: ${U.pathname}`)}}async function FH(N,U){let H=U.pathname.split("/").filter(Boolean),Y=H[2];if(!Y){if(N.method==="GET")return X(await PU());return Z(405,"Method not allowed")}if(Y==="config"){if(N.method==="GET"){let O={toml:await u()};return X(O)}if(N.method==="PUT"){let O=await z(N);return D(O.toml,"toml"),await IU(O.toml),X({ok:!0})}return Z(405,"Method not allowed")}if(Y==="reload"&&N.method==="POST")return await kU(),X({ok:!0});if(Y==="servers"){let O=H[3];if(!O){if(N.method==="POST"){let $=await z(N);return D($.name,"name"),await wU($),X({ok:!0},201)}return Z(405,"Method not allowed")}let W=H[4];if(W==="enable"&&N.method==="POST"){let $=await z(N);if(typeof $.enabled!=="boolean")return Z(400,"Missing or invalid field: enabled");return await fU(O,$.enabled),X({ok:!0})}if(!W&&N.method==="DELETE")return await xU(O)?X({ok:!0}):Z(404,`Server not found: ${O}`);return Z(405,"Method not allowed")}return Z(404,`Unknown MCP endpoint: ${U.pathname}`)}import{promises as ON}from"fs";import gN from"path";function R2(){return gN.join(k(),"config.toml")}function L0(){return gN.join(k(),"memories")}async function QH(){let N=await u();return N.trim()?m(N):{}}function Z0(N){return typeof N==="object"&&N!==null?N:{}}function S2(N){let U=Z0(N.memories),H={};if(typeof U.generate_memories==="boolean")H.generateMemories=U.generate_memories;if(typeof U.use_memories==="boolean")H.useMemories=U.use_memories;if(typeof U.disable_on_external_context==="boolean")H.disableOnExternalContext=U.disable_on_external_context;if(typeof U.min_rate_limit_remaining_percent==="number")H.minRateLimitRemainingPercent=U.min_rate_limit_remaining_percent;return H}async function _2(){let N=L0(),U=[];async function H(Y){let O;try{O=await ON.readdir(Y,{withFileTypes:!0})}catch{return}for(let W of O){let $=gN.join(Y,W.name);if(W.isDirectory()){if(W.name===".git")continue;await H($)}else if(W.isFile()){let G=await ON.stat($);U.push({path:c(gN.relative(N,$)),name:W.name,size:G.size,modifiedAt:G.mtime.toISOString()})}}}return await H(N),U.sort((Y,O)=>O.modifiedAt.localeCompare(Y.modifiedAt)),U}async function j2(){try{let U=((await T("experimentalFeature/list",{})).data??[]).find((H)=>H.name==="memories");return U?U.enabled:null}catch(N){return console.warn("[memories] experimentalFeature/list failed:",N),null}}async function XH(){let N=await QH();return{enabled:Z0(N.features).memories===!0,liveEnabled:await j2(),settings:S2(N),files:await _2()}}async function ZH(N){let U=await QH();if(typeof N.enabled==="boolean"){let H=Z0(U.features);H.memories=N.enabled,U.features=H}if(N.settings){let H=Z0(U.memories),Y=N.settings;if(typeof Y.generateMemories==="boolean")H.generate_memories=Y.generateMemories;if(typeof Y.useMemories==="boolean")H.use_memories=Y.useMemories;if(typeof Y.disableOnExternalContext==="boolean")H.disable_on_external_context=Y.disableOnExternalContext;if(typeof Y.minRateLimitRemainingPercent==="number")H.min_rate_limit_remaining_percent=Y.minRateLimitRemainingPercent;U.memories=H}if(await ON.writeFile(R2(),a(U),"utf8"),typeof N.enabled==="boolean")try{await T("experimentalFeature/enablement/set",{enablement:{memories:N.enabled}})}catch(H){console.warn("[memories] live enablement/set failed (applies on restart):",H)}}async function LH(N){let U=e(L0(),N);return ON.readFile(U,"utf8")}async function zH(N,U){let H=e(L0(),N);await ON.mkdir(gN.dirname(H),{recursive:!0}),await ON.writeFile(H,U,"utf8")}async function VH(N){let U=e(L0(),N);await ON.rm(U)}async function DH(N,U){let Y=U.pathname.split("/").filter(Boolean)[2];if(!Y){if(N.method==="GET")return X(await XH());return Z(405,"Method not allowed")}if(Y==="config"){if(N.method==="PUT"){let O=await z(N);if(typeof O.enabled!=="boolean"&&!O.settings)return Z(400,"Nothing to update: pass enabled and/or settings");return await ZH(O),X({ok:!0})}return Z(405,"Method not allowed")}if(Y==="file"){if(N.method==="GET"){let O=D(U.searchParams.get("path"),"path"),W={path:O,content:await LH(O)};return X(W)}if(N.method==="PUT"){let O=await z(N);if(D(O.path,"path"),typeof O.content!=="string")return Z(400,"Missing or invalid field: content");return await zH(O.path,O.content),X({ok:!0})}if(N.method==="DELETE"){let O=D(U.searchParams.get("path"),"path");return await VH(O),X({ok:!0})}return Z(405,"Method not allowed")}return Z(404,`Unknown memories endpoint: ${U.pathname}`)}var P2=300000,z0=null;async function KH(N){if(N.method!=="GET")return Z(405,"Method not allowed");if(z0&&Date.now()-z0.at<P2)return X({models:z0.models});let H=((await T("model/list",{})).data??[]).filter((O)=>!O.hidden).map((O)=>({id:O.id,model:O.model,displayName:O.displayName,description:O.description,isDefault:O.isDefault,defaultReasoningEffort:O.defaultReasoningEffort,supportedReasoningEfforts:O.supportedReasoningEfforts??[]}));return z0={at:Date.now(),models:H},X({models:H})}async function V0(){let N=await T("account/read",{});return{account:N.account??null,requiresOpenaiAuth:N.requiresOpenaiAuth,pendingLogin:O0(),lastLoginResult:XU()}}async function MH(N,U){if(U.pathname==="/api/account"){if(N.method!=="GET")return Z(405,"Method not allowed");return X(await V0())}if(U.pathname==="/api/account/login"&&N.method==="POST"){let H=await z(N),Y;if(H.type==="chatgpt"||H.type==="chatgptDeviceCode")Y={type:H.type};else if(H.type==="apiKey")Y={type:"apiKey",apiKey:D(H.apiKey,"apiKey")};else throw new J("type must be one of: chatgpt, chatgptDeviceCode, apiKey");let O=O0();if(O)await T("account/login/cancel",{loginId:O.loginId}).catch(()=>{});W0();let W=await T("account/login/start",Y);if((W.type==="chatgpt"||W.type==="chatgptDeviceCode")&&W.loginId){let $={loginId:W.loginId,type:W.type,authUrl:W.authUrl,userCode:W.userCode,verificationUrl:W.verificationUrl,startedAt:new Date().toISOString()};ZU($)}return X(await V0())}if(U.pathname==="/api/account/login/cancel"&&N.method==="POST"){let H=O0();if(H)await T("account/login/cancel",{loginId:H.loginId}).catch(()=>{});return W0(),X(await V0())}if(U.pathname==="/api/account/logout"&&N.method==="POST")return await T("account/logout",{}),W0(),X(await V0());return Z(404,`Not found: ${U.pathname}`)}function w2(N){if(!N)return null;return N.replace(/^([a-z0-9+.-]+:\/\/[^:@/]+):[^@/]+@/i,"$1:\u2022\u2022\u2022\u2022@")}function JH(){let N=U0(),U=H0();return{browserProxy:{proxyUrl:w2(N.value),source:N.source,noProxy:U.value,noProxySource:U.source}}}async function AH(N,U){if(U.pathname==="/api/settings"&&N.method==="GET")return X(JH());if(U.pathname==="/api/settings/browser-proxy"&&N.method==="PUT"){let H=await z(N);if(H.proxyUrl!==void 0&&H.proxyUrl!==null&&H.proxyUrl.trim())try{if(!new URL(H.proxyUrl.trim()).hostname)throw Error("missing host")}catch{return Z(400,"Invalid proxy URL \u2014 expected e.g. http://user:pass@host:port")}return await f1({...H.proxyUrl!==void 0?{browserProxy:H.proxyUrl}:{},...H.noProxy!==void 0?{browserNoProxy:H.noProxy}:{}}),X(JH())}if(N.method!=="GET"&&N.method!=="PUT")return Z(405,"Method not allowed");return Z(404,`Unknown settings endpoint: ${U.pathname}`)}import{promises as AN}from"fs";import _H from"path";import{randomUUID as v2}from"crypto";function hN(N,U,H,Y){let O=new Set,W=N.trim()!=="*";for(let $ of N.split(",")){let G=$.trim();if(!G)throw Error(`Invalid ${Y} field: empty term`);let F=G,Q=1,L=G.indexOf("/");if(L!==-1){if(F=G.slice(0,L),Q=Number(G.slice(L+1)),!Number.isInteger(Q)||Q<=0)throw Error(`Invalid step in ${Y}: ${G}`)}let K,E;if(F==="*")K=U,E=H;else if(F.includes("-")){let[r,WN]=F.split("-");K=Number(r),E=Number(WN)}else K=Number(F),E=K;if(!Number.isInteger(K)||!Number.isInteger(E))throw Error(`Invalid ${Y} value: ${G}`);if(K<U||E>H||K>E)throw Error(`${Y} out of range (${U}-${H}): ${G}`);for(let r=K;r<=E;r+=Q)O.add(r)}return{set:O,restricted:W}}function BH(N){let U=N.trim().split(/\s+/);if(U.length!==5)throw Error(`Cron must have 5 fields (min hour dom month dow); got ${U.length}`);let H=hN(U[0],0,59,"minute"),Y=hN(U[1],0,23,"hour"),O=hN(U[2],1,31,"day-of-month"),W=hN(U[3],1,12,"month"),$=hN(U[4],0,7,"day-of-week"),G=new Set;for(let F of $.set)G.add(F===7?0:F);return{minute:H.set,hour:Y.set,dom:O.set,month:W.set,dow:G,domRestricted:O.restricted,dowRestricted:$.restricted}}function CH(N){try{return BH(N),null}catch(U){return U instanceof Error?U.message:"Invalid cron expression"}}function x2(N){return new Intl.DateTimeFormat("en-US",{timeZone:N,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hourCycle:"h23"})}function RH(N,U){if(!U)return{year:N.getFullYear(),month:N.getMonth()+1,day:N.getDate(),hour:N.getHours(),minute:N.getMinutes(),second:N.getSeconds()};let H={};for(let Y of x2(U).formatToParts(N))if(Y.type!=="literal")H[Y.type]=Number(Y.value);return{year:H.year,month:H.month,day:H.day,hour:H.hour,minute:H.minute,second:H.second}}function f2(N,U){return new Date(Date.UTC(N,U,0)).getUTCDate()}function k2(N){return new Date(Date.UTC(N.year,N.month-1,N.day)).getUTCDay()}function EH(N){if(N.minute++,N.minute<60)return;if(N.minute=0,N.hour++,N.hour<24)return;if(N.hour=0,N.day++,N.day<=f2(N.year,N.month))return;if(N.day=1,N.month++,N.month<=12)return;N.month=1,N.year++}function y2(N,U){if(!N.minute.has(U.minute))return!1;if(!N.hour.has(U.hour))return!1;if(!N.month.has(U.month))return!1;let H=N.dom.has(U.day),Y=N.dow.has(k2(U));if(N.domRestricted&&N.dowRestricted)return H||Y;if(N.domRestricted)return H;if(N.dowRestricted)return Y;return!0}function TH(N,U){let H=RH(N,U);return Date.UTC(H.year,H.month-1,H.day,H.hour,H.minute,H.second)-N.getTime()}function b2(N,U){if(!U)return new Date(N.year,N.month-1,N.day,N.hour,N.minute,0,0);let H=Date.UTC(N.year,N.month-1,N.day,N.hour,N.minute,0),Y=TH(new Date(H),U),O=H-Y,W=TH(new Date(O),U);if(W!==Y)O=H-W;return new Date(O)}var q2=4216320;function SH(N,U,H){let Y=BH(N),O=RH(U,H),W={year:O.year,month:O.month,day:O.day,hour:O.hour,minute:O.minute};EH(W);for(let $=0;$<q2;$++){if(y2(Y,W))return b2(W,H);EH(W)}return null}var g2={sandbox:"workspaceWrite",approvalPolicy:"onRequest",approvalsReviewer:"auto_review",effort:"medium"};function h2(N){return N.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}function u0(N){return _H.join(EN(),`${N}.json`)}async function jH(){await AN.mkdir(EN(),{recursive:!0})}async function i0(N){await jH(),await AN.writeFile(u0(N.id),JSON.stringify(N,null,2),"utf8")}function d0(N,U){if(!N.enabled)return null;if(N.kind==="once"){if(!N.runAt)return null;let Y=new Date(N.runAt);if(Number.isNaN(Y.getTime()))return null;if(N.lastRunAt)return null;return Y.toISOString()}if(!N.cron)return null;let H=SH(N.cron,U,N.tz);return H?H.toISOString():null}function IH(N,U){if(U==="cron"){if(!N.cron)throw Error("cron expression is required for a cron schedule");let H=CH(N.cron);if(H)throw Error(`Invalid cron expression: ${H}`)}else{if(!N.runAt)throw Error("runAt is required for a one-off schedule");if(Number.isNaN(new Date(N.runAt).getTime()))throw Error("runAt is not a valid datetime")}if(N.tz)try{new Intl.DateTimeFormat("en-US",{timeZone:N.tz})}catch{throw Error(`Unknown timezone: ${N.tz}`)}}async function o0(){await jH();let N;try{N=await AN.readdir(EN())}catch{return[]}let U=[];for(let H of N){if(!H.endsWith(".json"))continue;try{let Y=await AN.readFile(_H.join(EN(),H),"utf8"),O=JSON.parse(Y);U.push(O)}catch{}}return U.sort((H,Y)=>Y.createdAt.localeCompare(H.createdAt)),U}async function D0(N){try{let U=await AN.readFile(u0(N),"utf8");return JSON.parse(U)}catch{return null}}async function PH(N){let U=N.name?.trim();if(!U)throw Error("Schedule name is required");if(!N.prompt?.trim())throw Error("Schedule prompt is required");let H=N.kind??"cron";IH(N,H);let Y=`${h2(U)||"schedule"}-${v2().slice(0,8)}`,O=new Date,W={id:Y,name:U,prompt:N.prompt,kind:H,cron:H==="cron"?N.cron:void 0,runAt:H==="once"?new Date(N.runAt).toISOString():void 0,tz:N.tz,mode:{...g2,...N.mode??{}},resume:N.resume??!1,threadRunId:null,enabled:N.enabled??!0,createdAt:O.toISOString(),lastRunAt:null,lastRunId:null,lastError:null,nextRunAt:null};return W.nextRunAt=d0(W,O),await i0(W),W}async function wH(N,U){let H=await D0(N);if(!H)return null;let Y=U.kind??H.kind,O={...H,name:U.name?.trim()||H.name,prompt:U.prompt??H.prompt,kind:Y,cron:Y==="cron"?U.cron??H.cron:void 0,runAt:Y==="once"?U.runAt?new Date(U.runAt).toISOString():H.runAt:void 0,tz:U.tz!==void 0?U.tz||void 0:H.tz,mode:U.mode?{...H.mode,...U.mode}:H.mode,resume:U.resume??H.resume,enabled:U.enabled??H.enabled};if(IH(O,Y),Y==="once"&&U.runAt&&O.runAt!==H.runAt)O.lastRunAt=null;return O.nextRunAt=d0(O,new Date),await i0(O),O}async function xH(N){try{return await AN.unlink(u0(N)),!0}catch{return!1}}function m2(N){return{sandbox:N.sandbox,approvalPolicy:N.approvalPolicy,approvalsReviewer:N.approvalsReviewer,model:N.model,effort:N.effort}}async function n0(N,U){let H=N.lastRunId??null,Y=null,O=N.threadRunId??null;try{let $=N.mode;if(N.resume&&O&&await A(O)){let G=await A(O);if(G&&v(G.status))throw Error("previous run still active \u2014 skipped this fire");H=(await G0(O,N.prompt,[],m2($))).id}else{let G=await ZN({prompt:N.prompt,sandbox:$.sandbox,approvalPolicy:$.approvalPolicy,approvalsReviewer:$.approvalsReviewer,model:$.model,effort:$.effort,source:"schedule",scheduleId:N.id,scheduleName:N.name});if(H=G.id,N.resume)O=G.id}}catch($){Y=$ instanceof Error?$.message:String($)}let W={...N,lastRunAt:U.toISOString(),lastRunId:H,lastError:Y,threadRunId:O};return W.nextRunAt=d0(W,U),await i0(W),W}var p0=!1;async function fH(N=new Date){if(p0)return;p0=!0;try{let U=await o0();for(let H of U){if(!H.enabled||!H.nextRunAt)continue;let Y=new Date(H.nextRunAt);if(Number.isNaN(Y.getTime())||Y.getTime()>N.getTime())continue;try{await n0(H,N)}catch(O){console.error(`[schedules] fire failed for ${H.id}:`,O)}}}catch(U){console.error("[schedules] tick failed:",U)}finally{p0=!1}}async function kH(N,U){let H=U.pathname.split("/").filter(Boolean),Y=H[2],O=H[3];if(!Y){if(N.method==="GET"){let W={schedules:await o0()};return X(W)}if(N.method==="POST"){let W=await z(N);try{let G={schedule:await PH(W)};return X(G,201)}catch($){return Z(400,$ instanceof Error?$.message:String($))}}return Z(405,"Method not allowed")}if(O==="run"&&N.method==="POST"){let W=await D0(Y);if(!W)return Z(404,`Schedule not found: ${Y}`);let G={schedule:await n0(W,new Date)};return X(G)}if(O)return Z(404,`Not found: ${U.pathname}`);if(N.method==="GET"){let W=await D0(Y);return W?X({schedule:W}):Z(404,`Schedule not found: ${Y}`)}if(N.method==="PUT"){let W=await z(N);try{let $=await wH(Y,W);return $?X({schedule:$}):Z(404,`Schedule not found: ${Y}`)}catch($){return Z(400,$ instanceof Error?$.message:String($))}}if(N.method==="DELETE")return await xH(Y)?X({ok:!0}):Z(404,`Schedule not found: ${Y}`);return Z(405,"Method not allowed")}var l2=2000,K0=[],p2=0,yH=!1,a0="logs";function u2(N){return N.map((U)=>{if(typeof U==="string")return U;if(U instanceof Error)return U.stack??U.message;try{return Bun.inspect(U,{colors:!1,depth:3})}catch{return String(U)}}).join(" ")}function i2(N,U){let H={seq:++p2,ts:new Date().toISOString(),level:N,text:u2(U)};if(K0.push(H),K0.length>l2)K0.shift();q(a0,H)}function bH(){if(yH)return;yH=!0;let N=(U,H)=>{let Y=console[U].bind(console);console[U]=(...O)=>{try{i2(H,O)}catch{}Y(...O)}};N("log","info"),N("info","info"),N("warn","warn"),N("error","error")}function qH(N={}){let U={info:0,warn:1,error:2},H=N.level?U[N.level]:0,Y=N.query?.toLowerCase(),O=K0.filter((W)=>U[W.level]>=H&&(!Y||W.text.toLowerCase().includes(Y)));if(N.limit&&O.length>N.limit)O=O.slice(-N.limit);return O}var d2=new Set(["info","warn","error"]);function vH(N,U,H){if(U.pathname==="/api/logs/stream")return H.upgrade(N,{data:{channel:a0}})?void 0:Z(400,"WebSocket upgrade required");if(N.method!=="GET")return Z(405,"Method not allowed");let Y=Number(U.searchParams.get("limit")),O=U.searchParams.get("level"),W=O&&d2.has(O)?O:void 0,$={logs:qH({limit:Number.isFinite(Y)&&Y>0?Math.min(Y,2000):500,level:W,query:U.searchParams.get("q")??void 0})};return X($)}async function gH(N,U){let H=new URL(N.url);try{if(H.pathname==="/api/health")return hU();if(H.pathname==="/api/status")return await mU(H);if(H.pathname==="/api/files/watch")return U.upgrade(N,{data:{channel:"files"}})?void 0:Z(400,"WebSocket upgrade required");if(H.pathname.startsWith("/api/files/"))return await cU(N,H);if(H.pathname==="/api/runs"||H.pathname.startsWith("/api/runs/"))return await lU(N,H,U);if(H.pathname.startsWith("/api/browser/"))return await aU(N,H,U);if(H.pathname==="/api/skills"||H.pathname.startsWith("/api/skills/"))return await GH(N,H);if(H.pathname==="/api/mcp"||H.pathname.startsWith("/api/mcp/"))return await FH(N,H);if(H.pathname==="/api/memories"||H.pathname.startsWith("/api/memories/"))return await DH(N,H);if(H.pathname==="/api/models")return await KH(N);if(H.pathname==="/api/account"||H.pathname.startsWith("/api/account/"))return await MH(N,H);if(H.pathname==="/api/settings"||H.pathname.startsWith("/api/settings/"))return await AH(N,H);if(H.pathname==="/api/schedules"||H.pathname.startsWith("/api/schedules/"))return await kH(N,H);if(H.pathname==="/api/logs"||H.pathname.startsWith("/api/logs/"))return vH(N,H,U);return Z(404,`Not found: ${H.pathname}`)}catch(Y){if(Y instanceof dN)return Z(400,Y.message);if(Y instanceof J)return Z(400,Y.message);if(o2(Y))return Z(404,`Not found: ${H.searchParams.get("path")??H.pathname}`);return console.error(`[api] ${N.method} ${H.pathname} failed:`,Y),Z(500,Y instanceof Error?Y.message:"Internal error")}}function o2(N){return typeof N==="object"&&N!==null&&"code"in N&&N.code==="ENOENT"}bH();await e0();var M0=[w.resolve(import.meta.dir,"../ui-dist"),w.resolve(import.meta.dir,"../../ui/dist")].find((N)=>hH(w.join(N,"index.html")))??w.resolve(import.meta.dir,"../../ui/dist"),a2=(N)=>[`${N}.ts`,`${N}.js`].map((U)=>w.join(import.meta.dir,U)).find((U)=>hH(U));for(let[N,U,H]of[["jun","mcp-server","agenthost"],["jun-browser","browser-mcp-server",void 0]])try{let Y=a2(U);if(Y)await yU(N,Y,mN,H);else console.warn(`[daemon] ${N} MCP server script (${U}) not found next to daemon`)}catch(Y){console.warn(`[daemon] could not register ${N} MCP server:`,Y)}c1(w.join(import.meta.dir,".."));var cH=Bun.serve({hostname:A0,port:mN,async fetch(N,U){let H=new URL(N.url);if(H.pathname.startsWith("/api/"))return gH(N,U);let Y=await t2(H.pathname);if(Y)return Y;return new Response("Jun daemon is running. Build the UI to enable the dashboard.",{status:200})},websocket:{idleTimeout:960,open(N){if(N.subscribe(N.data.channel),N.data.channel===YN){iU();let U=dU();if(U)N.send(U)}},message(N,U){if(N.data.channel===YN)nU(U)},close(N){if(N.unsubscribe(N.data.channel),N.data.channel===YN)oU()}}});K1(cH);try{n2(M(),{recursive:!0},(N,U)=>{let H={type:"fs.changed",path:U?c(String(U)):null,ts:new Date().toISOString()};cH.publish("files",JSON.stringify(H))})}catch(N){console.warn("[daemon] workspace watcher unavailable:",N)}var s2=30000;setInterval(()=>{fH()},s2);console.log(`Jun daemon running at http://${A0}:${mN}`);console.log(`Workspace: ${w.resolve(M())}`);async function t2(N){let U=w.join(M0,"index.html");if(!await r2(U))return null;let H=w.normalize(decodeURIComponent(N)).replace(/^[/\\]+/,""),Y=w.resolve(M0,H||"index.html"),O=`${M0}${w.sep}`;if(Y!==M0&&!Y.startsWith(O))return new Response("Not found",{status:404});if(await e2(Y))return new Response(Bun.file(Y),{headers:{"content-type":NO(Y)}});return new Response(Bun.file(U),{headers:{"content-type":"text/html; charset=utf-8"}})}async function r2(N){try{return await mH(N),!0}catch{return!1}}async function e2(N){try{return(await mH(N)).isFile()}catch{return!1}}function NO(N){switch(w.extname(N)){case".css":return"text/css; charset=utf-8";case".html":return"text/html; charset=utf-8";case".js":return"text/javascript; charset=utf-8";case".json":return"application/json; charset=utf-8";case".svg":return"image/svg+xml";case".webp":return"image/webp";case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".ico":return"image/x-icon";default:return"application/octet-stream"}}