junhost 0.1.1 → 0.2.0
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.
- package/README.md +43 -1
- package/dist/browser-mcp-server.js +42 -0
- package/dist/index.js +52 -52
- package/dist/mcp-server.js +1 -1
- package/package.json +2 -2
- package/ui-dist/assets/{BrowserPage-CLwJOnA1.js → BrowserPage-Bw1kBIM_.js} +1 -1
- package/ui-dist/assets/{DashboardPage-DNlY12tH.js → DashboardPage-BvNlgB4B.js} +1 -1
- package/ui-dist/assets/{FilesPage-CfFJjtlo.js → FilesPage-C1IqnxpR.js} +1 -1
- package/ui-dist/assets/{McpPage-Ckmbp2T3.js → McpPage-BgXcKazm.js} +1 -1
- package/ui-dist/assets/{MemoriesPage-BgBe2rb6.js → MemoriesPage-DYOob4W0.js} +1 -1
- package/ui-dist/assets/{RunsPage-9w7iFG8N.js → RunsPage-BpBj82Ux.js} +4 -4
- package/ui-dist/assets/{SchedulesPage-B5FVZB0F.js → SchedulesPage-mIWaXymg.js} +1 -1
- package/ui-dist/assets/{SettingsPage-lNZmrgQF.js → SettingsPage-C5vG-RLn.js} +1 -1
- package/ui-dist/assets/{SkillsPage-BXcSp6ls.js → SkillsPage-DuFQfdSR.js} +1 -1
- package/ui-dist/assets/architecture-7EHR7CIX-BMNBOS2i.js +1 -0
- package/ui-dist/assets/{architectureDiagram-3BPJPVTR-CZU-I50b.js → architectureDiagram-3BPJPVTR-CQ1UyWn-.js} +1 -1
- package/ui-dist/assets/{blockDiagram-GPEHLZMM-CyBud8P5.js → blockDiagram-GPEHLZMM-DO2WH3yT.js} +1 -1
- package/ui-dist/assets/{c4Diagram-AAUBKEIU--J4ICgL4.js → c4Diagram-AAUBKEIU-CDcDkAFN.js} +1 -1
- package/ui-dist/assets/channel-BMSobhoT.js +1 -0
- package/ui-dist/assets/{checkbox-Dl42vHZu.js → checkbox-BO9cBKlP.js} +1 -1
- package/ui-dist/assets/{chunk-2J33WTMH-BDb1cFmy.js → chunk-2J33WTMH-CxE9IMxF.js} +1 -1
- package/ui-dist/assets/{chunk-3OPIFGDE-BlluxIcQ.js → chunk-3OPIFGDE-CWe0ghtO.js} +1 -1
- package/ui-dist/assets/{chunk-5ZQYHXKU-CKTcuPiD.js → chunk-5ZQYHXKU-D9lXR7-a.js} +1 -1
- package/ui-dist/assets/{chunk-727SXJPM-MZn2xvWx.js → chunk-727SXJPM-1INZms_u.js} +1 -1
- package/ui-dist/assets/{chunk-AQP2D5EJ-BJaTZvWO.js → chunk-AQP2D5EJ-Bo5P94jR.js} +1 -1
- package/ui-dist/assets/{chunk-BO2N2NFS-BnH2G-m5.js → chunk-BO2N2NFS-Bb9QKS7r.js} +4 -4
- package/ui-dist/assets/{chunk-CSCIHK7Q-CXkHF5UK.js → chunk-CSCIHK7Q-BXW0kTPy.js} +3 -3
- package/ui-dist/assets/{chunk-KSCS5N6A-BahjoFv5.js → chunk-KSCS5N6A-su0hRnFY.js} +1 -1
- package/ui-dist/assets/{chunk-L5ZTLDWV-Bx4WHt-z.js → chunk-L5ZTLDWV-CLjULdtO.js} +1 -1
- package/ui-dist/assets/{chunk-LZXEDZCA-CkFznL5l.js → chunk-LZXEDZCA-DSupe1kd.js} +2 -2
- package/ui-dist/assets/{chunk-ND2GUHAM-B8gmrqM9.js → chunk-ND2GUHAM-DVaKW6-I.js} +1 -1
- package/ui-dist/assets/{chunk-NZK2D7GU-C18DTyig.js → chunk-NZK2D7GU-DP_luiUT.js} +1 -1
- package/ui-dist/assets/{chunk-O5CBEL6O-DhXgjXO_.js → chunk-O5CBEL6O-DJ6oobwT.js} +1 -1
- package/ui-dist/assets/{chunk-WU5MYG2G-DakMffny.js → chunk-WU5MYG2G-BJCNi6Df.js} +1 -1
- package/ui-dist/assets/classDiagram-4FO5ZUOK-C8buBHXm.js +1 -0
- package/ui-dist/assets/classDiagram-v2-Q7XG4LA2-C8buBHXm.js +1 -0
- package/ui-dist/assets/{collapsible-BdLJt-lG.js → collapsible-0tqcZUWD.js} +1 -1
- package/ui-dist/assets/{dagre-BM42HDAG-CRPnH9-w.js → dagre-BM42HDAG-CRyL8hRI.js} +1 -1
- package/ui-dist/assets/{diagram-2AECGRRQ-BHmnvDJu.js → diagram-2AECGRRQ-DyjpW-BD.js} +1 -1
- package/ui-dist/assets/{diagram-5GNKFQAL-CnuSOf5i.js → diagram-5GNKFQAL-CBTUCxgf.js} +1 -1
- package/ui-dist/assets/{diagram-KO2AKTUF-DkD3Oyzq.js → diagram-KO2AKTUF-C7inOR0g.js} +1 -1
- package/ui-dist/assets/{diagram-LMA3HP47-qngr_ayi.js → diagram-LMA3HP47-CfCMRg_H.js} +1 -1
- package/ui-dist/assets/{diagram-OG6HWLK6-BUXAAFlB.js → diagram-OG6HWLK6-DLl3GKVl.js} +1 -1
- package/ui-dist/assets/{dialog-Bl8-9u35.js → dialog-gLEpdaG1.js} +1 -1
- package/ui-dist/assets/{erDiagram-TEJ5UH35-B7fmkd3a.js → erDiagram-TEJ5UH35-D3SsdlGo.js} +1 -1
- package/ui-dist/assets/eventmodeling-FCH6USID-Dl7jZkr1.js +1 -0
- package/ui-dist/assets/{flowDiagram-I6XJVG4X-D3K28Pdy.js → flowDiagram-I6XJVG4X-BIZoa3Ff.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-6RSMTGT7-CXzmskXJ.js → ganttDiagram-6RSMTGT7-DoIzzrgl.js} +1 -1
- package/ui-dist/assets/{gitGraph-WXDBUCRP-CROsiysY.js → gitGraph-WXDBUCRP-tT7WczwY.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-PVQCEYII-BBhICl9b.js → gitGraphDiagram-PVQCEYII-CwoMoyS1.js} +1 -1
- package/ui-dist/assets/{highlighted-body-OFNGDK62-woHDdMrg.js → highlighted-body-OFNGDK62-X8dg_vaO.js} +1 -1
- package/ui-dist/assets/{index-DmmH6oax.css → index-C_NJsn6Z.css} +1 -1
- package/ui-dist/assets/{index-j386AZTn.js → index-DXYsuK0q.js} +2 -2
- package/ui-dist/assets/{info-J43DQDTF-DHht6dOt.js → info-J43DQDTF-Da0djCPL.js} +1 -1
- package/ui-dist/assets/{infoDiagram-5YYISTIA-Df4LhnuE.js → infoDiagram-5YYISTIA-D-OHDMDH.js} +1 -1
- package/ui-dist/assets/{input-D4O22yGt.js → input-BPTmfk5i.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-YF4QCWOH-B8KMc0In.js → ishikawaDiagram-YF4QCWOH-Bzg0E0Z1.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-JHISSGLW-Bpr7eOEv.js → journeyDiagram-JHISSGLW-rmeE-f4I.js} +1 -1
- package/ui-dist/assets/{kanban-definition-UN3LZRKU-R8MXwX2D.js → kanban-definition-UN3LZRKU-DSy_xosI.js} +1 -1
- package/ui-dist/assets/katex-BNbsei-7.js +1 -0
- package/ui-dist/assets/{line-EyXPCaOi.js → line-6Sq5fd7W.js} +1 -1
- package/ui-dist/assets/mermaid-GHXKKRXX-eP_ygZe4.js +1 -0
- package/ui-dist/assets/{mermaid-parser.core-Bd2TX3li.js → mermaid-parser.core-C6nlL4jI.js} +2 -2
- package/ui-dist/assets/{mindmap-definition-RKZ34NQL-CCrZYYSm.js → mindmap-definition-RKZ34NQL-CSJ0pwqG.js} +1 -1
- package/ui-dist/assets/{packet-YPE3B663-BsRm1dxS.js → packet-YPE3B663-CJYSZVBB.js} +1 -1
- package/ui-dist/assets/{pie-LRSECV5Y-2jRO4jrF.js → pie-LRSECV5Y-B7FDQxHq.js} +1 -1
- package/ui-dist/assets/{pieDiagram-4H26LBE5-O21uLYd7.js → pieDiagram-4H26LBE5-BYco3Xpn.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-W4KKPZXB-PFuRo2tu.js → quadrantDiagram-W4KKPZXB-BSzj1BbK.js} +1 -1
- package/ui-dist/assets/{radar-GUYGQ44K-DrLd9hhi.js → radar-GUYGQ44K-CIqNKREz.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-4Y6WPE33-CsP61d0X.js → requirementDiagram-4Y6WPE33-DTMmHobs.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-5OEKKPKP-OXRKlXwh.js → sankeyDiagram-5OEKKPKP-v48Pd1Sj.js} +1 -1
- package/ui-dist/assets/{select-CYgMxtlk.js → select-jBmyVjXL.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-3UESZ5HK-CGKNazDP.js → sequenceDiagram-3UESZ5HK-Cutc-QJ-.js} +1 -1
- package/ui-dist/assets/{stateDiagram-AJRCARHV-BBiaMVYA.js → stateDiagram-AJRCARHV-C9wjw5vE.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-BHNVJYJU-0qv-iPvr.js +1 -0
- package/ui-dist/assets/{tabs-DS9zR4V0.js → tabs-BUCI-mwA.js} +1 -1
- package/ui-dist/assets/{timeline-definition-PNZ67QCA-DCONMP8y.js → timeline-definition-PNZ67QCA-Be0sJR3F.js} +1 -1
- package/ui-dist/assets/{treeView-BLDUP644-DLNyeiHu.js → treeView-BLDUP644-BuO1c41a.js} +1 -1
- package/ui-dist/assets/{treemap-LRROVOQU-Cdld0366.js → treemap-LRROVOQU-DnqRpBrL.js} +1 -1
- package/ui-dist/assets/{useCompositeListItem-BQ4RLkNZ.js → useCompositeListItem-BMeUcGkY.js} +1 -1
- package/ui-dist/assets/{vennDiagram-CIIHVFJN-C21GUpuw.js → vennDiagram-CIIHVFJN-BU-tyhcP.js} +1 -1
- package/ui-dist/assets/{wardley-L42UT6IY-PuTi7B-8.js → wardley-L42UT6IY-C4lBe1D1.js} +1 -1
- package/ui-dist/assets/{wardleyDiagram-YWT4CUSO-BwV-yZO0.js → wardleyDiagram-YWT4CUSO-Ba4GgkxA.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-2RQKCTM6-D-bOqUpK.js → xychartDiagram-2RQKCTM6-BZYGoMGR.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/architecture-7EHR7CIX-D8QwdCM4.js +0 -1
- package/ui-dist/assets/channel-CXOCC3Ms.js +0 -1
- package/ui-dist/assets/classDiagram-4FO5ZUOK-DMdoabn-.js +0 -1
- package/ui-dist/assets/classDiagram-v2-Q7XG4LA2-DMdoabn-.js +0 -1
- package/ui-dist/assets/eventmodeling-FCH6USID-DUPVuqbK.js +0 -1
- package/ui-dist/assets/katex-U6Climy7.js +0 -1
- package/ui-dist/assets/mermaid-GHXKKRXX-CDSYqrX3.js +0 -1
- package/ui-dist/assets/stateDiagram-v2-BHNVJYJU-C_bLdSQ9.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var iW=Object.create;var{getPrototypeOf:pW,defineProperty:BH,getOwnPropertyNames:nW}=Object;var oW=Object.prototype.hasOwnProperty;function aW(N){return this[N]}var dW,sW,H2=(N,H,W)=>{var O=N!=null&&typeof N==="object";if(O){var Y=H?dW??=new WeakMap:sW??=new WeakMap,G=Y.get(N);if(G)return G}W=N!=null?iW(pW(N)):{};let $=H||!N||!N.__esModule?BH(W,"default",{value:N,enumerable:!0}):W;for(let U of nW(N))if(!oW.call($,U))BH($,U,{get:aW.bind(N,U),enumerable:!0});if(O)Y.set(N,$);return $};var W2=(N,H)=>()=>(H||N((H={exports:{}}).exports,H),H.exports);var tW=(N)=>N;function rW(N,H){this[N]=tW.bind(null,H)}var O2=(N,H)=>{for(var W in H)BH(N,W,{get:H[W],enumerable:!0,configurable:!0,set:rW.bind(H,W)})};import{existsSync as cW,watch as aY}from"fs";import{stat as lW}from"fs/promises";import b from"path";import{promises as d}from"fs";import u from"path";import{existsSync as N0,renameSync as eW}from"fs";import H0 from"os";import S from"path";function q(N){return process.env[`JUN_${N}`]??process.env[`AGENTHOST_${N}`]}function NO(){let N=q("HOME");if(N)return N;let H=S.join(H0.homedir(),".jun"),W=S.join(H0.homedir(),".agenthost");if(!N0(H)&&N0(W))try{eW(W,H),console.log("[paths] migrated data dir ~/.agenthost -> ~/.jun")}catch(O){return console.warn("[paths] could not migrate ~/.agenthost -> ~/.jun (files in use?) \u2014 using legacy dir:",O),W}return H}var I=NO(),V="default",DH=q("HOST")??"127.0.0.1",uN=Number(q("PORT")??8787);function QN(){return S.join(I,"projects")}function NN(N=V){return S.join(QN(),N)}function a(){return S.join(I,"runs")}function J(N=V){return S.join(NN(N),"workspace")}function CN(){return S.join(I,"schedules")}function j(N=V){return S.join(NN(N),"codex-home")}function W0(N=V){return S.join(NN(N),"widgets")}function SN(N=V){return S.join(NN(N),"browser")}function iN(N){let H=S.resolve(QN()),W=S.relative(H,S.resolve(N));if(!W||W.startsWith("..")||S.isAbsolute(W))return null;return W.split(S.sep)[0]||null}function l(N){return N.split(S.sep).join("/")}function CH(N){return u.join(NN(N),"project.json")}var HO=["files","reports","downloads","screenshots","artifacts",".agents/skills"],WO=["profile","downloads","screenshots","recordings"],OO={projectId:V,defaultModel:"gpt-5.4",defaultSandbox:"workspaceWrite",defaultApprovalPolicy:"onRequest",host:"127.0.0.1",port:8787,browserProvider:"agent-browser"},YO={version:1,pages:[{id:"home",title:"Home",widgets:[]}]},GO='# 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',$O=`# 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
|
|
9
|
-
`),await
|
|
10
|
-
`),await
|
|
11
|
-
`),await
|
|
8
|
+
`;async function RN(N,H){try{await d.access(N)}catch{await d.mkdir(u.dirname(N),{recursive:!0}),await d.writeFile(N,H,"utf8")}}async function SH(N,H){let W=J(N);for(let O of HO)await d.mkdir(u.join(W,O),{recursive:!0});for(let O of WO)await d.mkdir(u.join(SN(N),O),{recursive:!0});await d.mkdir(W0(N),{recursive:!0}),await d.mkdir(u.join(j(N),"logs"),{recursive:!0}),await RN(CH(N),JSON.stringify({id:N,name:H??N,createdAt:new Date().toISOString()},null,2)+`
|
|
9
|
+
`),await RN(u.join(NN(N),"dashboard.json"),JSON.stringify(YO,null,2)+`
|
|
10
|
+
`),await RN(u.join(j(N),"config.toml"),$O),await RN(u.join(W,"AGENTS.md"),GO)}async function O0(){await d.mkdir(a(),{recursive:!0}),await RN(u.join(I,"config.json"),JSON.stringify(OO,null,2)+`
|
|
11
|
+
`),await SH(V,"Default")}import{promises as LN}from"fs";import WY from"path";/*!
|
|
12
12
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
13
13
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
14
14
|
*
|
|
@@ -34,11 +34,11 @@ var bO=Object.create;var{getPrototypeOf:qO,defineProperty:KH,getOwnPropertyNames
|
|
|
34
34
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
35
35
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
36
36
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
37
|
-
*/function
|
|
38
|
-
`,$===H)Y+=" ".repeat(G+
|
|
39
|
-
`}return Y}class
|
|
37
|
+
*/function UO(N,H){let W=N.slice(0,H).split(/\r\n|\n|\r/g);return[W.length,W.pop().length+1]}function QO(N,H,W){let O=N.split(/\r\n|\n|\r/g),Y="",G=(Math.log10(H+1)|0)+1;for(let $=H-1;$<=H+1;$++){let U=O[$-1];if(!U)continue;if(Y+=$.toString().padEnd(G," "),Y+=": ",Y+=U,Y+=`
|
|
38
|
+
`,$===H)Y+=" ".repeat(G+W+2),Y+=`^
|
|
39
|
+
`}return Y}class M extends Error{line;column;codeblock;constructor(N,H){let[W,O]=UO(H.toml,H.ptr),Y=QO(H.toml,W,O);super(`Invalid TOML document: ${N}
|
|
40
40
|
|
|
41
|
-
${Y}`,H);this.line=
|
|
41
|
+
${Y}`,H);this.line=W,this.column=O,this.codeblock=Y}}/*!
|
|
42
42
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
43
43
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
44
44
|
*
|
|
@@ -64,14 +64,14 @@ ${Y}`,H);this.line=O,this.column=W,this.codeblock=Y}}/*!
|
|
|
64
64
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
65
65
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
66
66
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
67
|
-
*/function
|
|
68
|
-
`,H);if(N[
|
|
69
|
-
`)return
|
|
70
|
-
`)return
|
|
67
|
+
*/function XO(N,H){let W=0;while(N[H-++W]==="\\");return--W&&W%2}function pN(N,H=0,W=N.length){let O=N.indexOf(`
|
|
68
|
+
`,H);if(N[O-1]==="\r")O--;return O<=W?O:-1}function XN(N,H){for(let W=H;W<N.length;W++){let O=N[W];if(O===`
|
|
69
|
+
`)return W;if(O==="\r"&&N[W+1]===`
|
|
70
|
+
`)return W+1;if(O<" "&&O!=="\t"||O==="\x7F")throw new M("control characters are not allowed in comments",{toml:N,ptr:H})}return N.length}function w(N,H,W,O){let Y;while(!0){while((Y=N[H])===" "||Y==="\t"||!W&&(Y===`
|
|
71
71
|
`||Y==="\r"&&N[H+1]===`
|
|
72
|
-
`))H++;if(
|
|
72
|
+
`))H++;if(O||Y!=="#")break;H=XN(N,H)}return H}function Y0(N,H,W,O,Y=!1){if(!O)return H=pN(N,H),H<0?N.length:H;for(let G=H;G<N.length;G++){let $=N[G];if($==="#")G=pN(N,G);else if($===W)return G+1;else if($===O||Y&&($===`
|
|
73
73
|
`||$==="\r"&&N[G+1]===`
|
|
74
|
-
`))return G}throw new
|
|
74
|
+
`))return G}throw new M("cannot find end of structure",{toml:N,ptr:H})}function nN(N,H){let W=N[H],O=W===N[H+1]&&N[H+1]===N[H+2]?N.slice(H,H+3):W;H+=O.length-1;do H=N.indexOf(O,++H);while(H>-1&&W!=="'"&&XO(N,H));if(H>-1){if(H+=O.length,O.length>1){if(N[H]===W)H++;if(N[H]===W)H++}}return H}/*!
|
|
75
75
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
76
76
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
77
77
|
*
|
|
@@ -97,7 +97,7 @@ ${Y}`,H);this.line=O,this.column=W,this.codeblock=Y}}/*!
|
|
|
97
97
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
98
98
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
99
99
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
100
|
-
*/var
|
|
100
|
+
*/var ZO=/^(\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;#W=!1;#N=null;constructor(N){let H=!0,W=!0,O="Z";if(typeof N==="string"){let Y=N.match(ZO);if(Y){if(!Y[1])H=!1,N=`0000-01-01T${N}`;if(W=!!Y[2],W&&N[10]===" "&&(N=N.replace(" ","T")),Y[2]&&+Y[2]>23)N="";else if(O=Y[3]||null,N=N.toUpperCase(),!O&&W)N+="Z"}else N=""}super(N);if(!isNaN(this.getTime()))this.#H=H,this.#W=W,this.#N=O}isDateTime(){return this.#H&&this.#W}isLocal(){return!this.#H||!this.#W||!this.#N}isDate(){return this.#H&&!this.#W}isTime(){return this.#W&&!this.#H}isValid(){return this.#H||this.#W}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 W=new s(N);return W.#N=H,W}static wrapAsLocalDateTime(N){let H=new s(N);return H.#N=null,H}static wrapAsLocalDate(N){let H=new s(N);return H.#W=!1,H.#N=null,H}static wrapAsLocalTime(N){let H=new s(N);return H.#H=!1,H.#N=null,H}}/*!
|
|
101
101
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
102
102
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
103
103
|
*
|
|
@@ -123,13 +123,13 @@ ${Y}`,H);this.line=O,this.column=W,this.codeblock=Y}}/*!
|
|
|
123
123
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
124
124
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
125
125
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
126
|
-
*/var
|
|
127
|
-
`,f:"\f",r:"\r",e:"\x1B",'"':'"',"\\":"\\"};function
|
|
128
|
-
`)H++}let G=0,$,U="",Q=H;while(H<
|
|
126
|
+
*/var zO=/^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/,FO=/^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/,LO=/^[+-]?0[0-9_]/,VO=/^[0-9a-f]{2,8}$/i,G0={b:"\b",t:"\t",n:`
|
|
127
|
+
`,f:"\f",r:"\r",e:"\x1B",'"':'"',"\\":"\\"};function oN(N,H=0,W=N.length){let O=N[H]==="'",Y=N[H++]===N[H]&&N[H]===N[H+1];if(Y){if(W-=2,N[H+=2]==="\r")H++;if(N[H]===`
|
|
128
|
+
`)H++}let G=0,$,U="",Q=H;while(H<W-1){let X=N[H++];if(X===`
|
|
129
129
|
`||X==="\r"&&N[H]===`
|
|
130
|
-
`){if(!Y)throw new
|
|
131
|
-
`||X===" "||X==="\t"||X==="\r")){if(H=
|
|
132
|
-
`&&N[H]!=="\r")throw new
|
|
130
|
+
`){if(!Y)throw new M("newlines are not allowed in strings",{toml:N,ptr:H-1})}else if(X<" "&&X!=="\t"||X==="\x7F")throw new M("control characters are not allowed in strings",{toml:N,ptr:H-1});if($){if($=!1,X==="x"||X==="u"||X==="U"){let F=N.slice(H,H+=X==="x"?2:X==="u"?4:8);if(!VO.test(F))throw new M("invalid unicode escape",{toml:N,ptr:G});try{U+=String.fromCodePoint(parseInt(F,16))}catch{throw new M("invalid unicode escape",{toml:N,ptr:G})}}else if(Y&&(X===`
|
|
131
|
+
`||X===" "||X==="\t"||X==="\r")){if(H=w(N,H-1,!0),N[H]!==`
|
|
132
|
+
`&&N[H]!=="\r")throw new M("invalid escape: only line-ending whitespace may be escaped",{toml:N,ptr:G});H=w(N,H)}else if(X in G0)U+=G0[X];else throw new M("unrecognized escape sequence",{toml:N,ptr:G});Q=H}else if(!O&&X==="\\")G=H-1,$=!0,U+=N.slice(Q,G)}return U+N.slice(Q,W-1)}function $0(N,H,W,O){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 O?0n:0;let Y=zO.test(N);if(Y||FO.test(N)){if(LO.test(N))throw new M("leading zeroes are not allowed",{toml:H,ptr:W});N=N.replace(/_/g,"");let $=+N;if(isNaN($))throw new M("invalid number",{toml:H,ptr:W});if(Y){if((Y=!Number.isSafeInteger($))&&!O)throw new M("integer value cannot be represented losslessly",{toml:H,ptr:W});if(Y||O===!0)$=BigInt(N)}return $}let G=new s(N);if(!G.isValid())throw new M("invalid value",{toml:H,ptr:W});return G}/*!
|
|
133
133
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
134
134
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
135
135
|
*
|
|
@@ -155,8 +155,8 @@ ${Y}`,H);this.line=O,this.column=W,this.codeblock=Y}}/*!
|
|
|
155
155
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
156
156
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
157
157
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
158
|
-
*/function
|
|
159
|
-
`&&N[$]!=="\r")throw new
|
|
158
|
+
*/function MO(N,H,W){let O=N.slice(H,W),Y=O.indexOf("#");if(Y>-1)XN(N,Y),O=O.slice(0,Y);return[O.trimEnd(),Y]}function TN(N,H,W,O,Y){if(O===0)throw new M("document contains excessively nested structures. aborting.",{toml:N,ptr:H});let G=N[H];if(G==="["||G==="{"){let[Q,X]=G==="["?Q0(N,H,O,Y):U0(N,H,O,Y);if(W){if(X=w(N,X),N[X]===",")X++;else if(N[X]!==W)throw new M("expected comma or end of structure",{toml:N,ptr:X})}return[Q,X]}let $;if(G==='"'||G==="'"){$=nN(N,H);let Q=oN(N,H,$);if(W){if($=w(N,$),N[$]&&N[$]!==","&&N[$]!==W&&N[$]!==`
|
|
159
|
+
`&&N[$]!=="\r")throw new M("unexpected character encountered",{toml:N,ptr:$});$+=+(N[$]===",")}return[Q,$]}$=Y0(N,H,",",W);let U=MO(N,H,$-+(N[$-1]===","));if(!U[0])throw new M("incomplete key-value declaration: no value specified",{toml:N,ptr:H});if(W&&U[1]>-1)$=w(N,H+U[1]),$+=+(N[$]===",");return[$0(U[0],N,H,Y),$]}/*!
|
|
160
160
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
161
161
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
162
162
|
*
|
|
@@ -182,9 +182,9 @@ ${Y}`,H);this.line=O,this.column=W,this.codeblock=Y}}/*!
|
|
|
182
182
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
183
183
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
184
184
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
185
|
-
*/var
|
|
186
|
-
`&&$!=="\r"){let U,Q=Y,X=!1,[F,K]=aN(N,H-1);for(let
|
|
187
|
-
`&&G!=="\r"){let $=
|
|
185
|
+
*/var KO=/^[a-zA-Z0-9-_]+[ \t]*$/;function aN(N,H,W="="){let O=H-1,Y=[],G=N.indexOf(W,H);if(G<0)throw new M("incomplete key-value: cannot find end of key",{toml:N,ptr:H});do{let $=N[H=++O];if($!==" "&&$!=="\t")if($==='"'||$==="'"){if($===N[H+1]&&$===N[H+2])throw new M("multiline strings are not allowed in keys",{toml:N,ptr:H});let U=nN(N,H);if(U<0)throw new M("unfinished string encountered",{toml:N,ptr:H});O=N.indexOf(".",U);let Q=N.slice(U,O<0||O>G?G:O),X=pN(Q);if(X>-1)throw new M("newlines are not allowed in keys",{toml:N,ptr:H+O+X});if(Q.trimStart())throw new M("found extra tokens after the string part",{toml:N,ptr:U});if(G<U){if(G=N.indexOf(W,U),G<0)throw new M("incomplete key-value: cannot find end of key",{toml:N,ptr:H})}Y.push(oN(N,H,U))}else{O=N.indexOf(".",H);let U=N.slice(H,O<0||O>G?G:O);if(!KO.test(U))throw new M("only letter, numbers, dashes and underscores are allowed in keys",{toml:N,ptr:H});Y.push(U.trimEnd())}}while(O+1&&O<G);return[Y,w(N,G+1,!0,!0)]}function U0(N,H,W,O){let Y={},G=new Set,$;H++;while(($=N[H++])!=="}"&&$)if($===",")throw new M("expected value, found comma",{toml:N,ptr:H-1});else if($==="#")H=XN(N,H);else if($!==" "&&$!=="\t"&&$!==`
|
|
186
|
+
`&&$!=="\r"){let U,Q=Y,X=!1,[F,K]=aN(N,H-1);for(let UN=0;UN<F.length;UN++){if(UN)Q=X?Q[U]:Q[U]={};if(U=F[UN],(X=Object.hasOwn(Q,U))&&(typeof Q[U]!=="object"||G.has(Q[U])))throw new M("trying to redefine an already defined value",{toml:N,ptr:H});if(!X&&U==="__proto__")Object.defineProperty(Q,U,{enumerable:!0,configurable:!0,writable:!0})}if(X)throw new M("trying to redefine an already defined value",{toml:N,ptr:H});let[T,x]=TN(N,K,"}",W-1,O);G.add(T),Q[U]=T,H=x}if(!$)throw new M("unfinished table encountered",{toml:N,ptr:H});return[Y,H]}function Q0(N,H,W,O){let Y=[],G;H++;while((G=N[H++])!=="]"&&G)if(G===",")throw new M("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 $=TN(N,H-1,"]",W-1,O);Y.push($[0]),H=$[1]}if(!G)throw new M("unfinished array encountered",{toml:N,ptr:H});return[Y,H]}/*!
|
|
188
188
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
189
189
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
190
190
|
*
|
|
@@ -210,8 +210,8 @@ ${Y}`,H);this.line=O,this.column=W,this.codeblock=Y}}/*!
|
|
|
210
210
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
211
211
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
212
212
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
213
|
-
*/function
|
|
214
|
-
`&&N[U]!=="\r")throw new
|
|
213
|
+
*/function X0(N,H,W,O){let Y=H,G=W,$,U=!1,Q;for(let X=0;X<N.length;X++){if(X){if(Y=U?Y[$]:Y[$]={},G=(Q=G[$]).c,O===0&&(Q.t===1||Q.t===2))return null;if(Q.t===2){let F=Y.length-1;Y=Y[F],G=G[F].c}}if($=N[X],(U=Object.hasOwn(Y,$))&&G[$]?.t===0&&G[$]?.d)return null;if(!U){if($==="__proto__")Object.defineProperty(Y,$,{enumerable:!0,configurable:!0,writable:!0}),Object.defineProperty(G,$,{enumerable:!0,configurable:!0,writable:!0});G[$]={t:X<N.length-1&&O===2?3:O,d:!1,i:0,c:{}}}}if(Q=G[$],Q.t!==O&&!(O===1&&Q.t===3))return null;if(O===2){if(!Q.d)Q.d=!0,Y[$]=[];Y[$].push(Y={}),Q.c[Q.i++]=Q={t:1,d:!1,i:0,c:{}}}if(Q.d)return null;if(Q.d=!0,O===1)Y=U?Y[$]:Y[$]={};else if(O===0&&U)return null;return[$,Y,Q.c]}function c(N,{maxDepth:H=1000,integersAsBigInt:W}={}){let O={},Y={},G=O,$=Y;for(let U=w(N,0);U<N.length;){if(N[U]==="["){let Q=N[++U]==="[",X=aN(N,U+=+Q,"]");if(Q){if(N[X[1]-1]!=="]")throw new M("expected end of table declaration",{toml:N,ptr:X[1]-1});X[1]++}let F=X0(X[0],O,Y,Q?2:1);if(!F)throw new M("trying to redefine an already defined table or value",{toml:N,ptr:U});$=F[2],G=F[1],U=X[1]}else{let Q=aN(N,U),X=X0(Q[0],G,$,0);if(!X)throw new M("trying to redefine an already defined table or value",{toml:N,ptr:U});let F=TN(N,Q[1],void 0,H,W);X[1][X[0]]=F[0],U=F[1]}if(U=w(N,U,!0),N[U]&&N[U]!==`
|
|
214
|
+
`&&N[U]!=="\r")throw new M("each key-value declaration must be followed by an end-of-line",{toml:N,ptr:U});U=w(N,U)}return O}/*!
|
|
215
215
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
216
216
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
217
217
|
*
|
|
@@ -237,16 +237,16 @@ ${Y}`,H);this.line=O,this.column=W,this.codeblock=Y}}/*!
|
|
|
237
237
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
238
238
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
239
239
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
240
|
-
*/var
|
|
240
|
+
*/var Z0=/^[a-z0-9-_]+$/i;function EN(N){let H=typeof N;if(H==="object"){if(Array.isArray(N))return"array";if(N instanceof Date)return"date"}return H}function AO(N){for(let H=0;H<N.length;H++)if(EN(N[H])!=="object")return!1;return N.length!=0}function RH(N){return JSON.stringify(N).replace(/\x7f/g,"\\u007f")}function TH(N,H,W,O){if(W===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(O&&Number.isInteger(N))return N.toFixed(1);return N.toString()}if(H==="bigint"||H==="boolean")return N.toString();if(H==="string")return RH(N);if(H==="date"){if(isNaN(N.getTime()))throw TypeError("cannot serialize invalid date");return N.toISOString()}if(H==="object")return JO(N,W,O);if(H==="array")return BO(N,W,O)}function JO(N,H,W){let O=Object.keys(N);if(O.length===0)return"{}";let Y="{ ";for(let G=0;G<O.length;G++){let $=O[G];if(G)Y+=", ";Y+=Z0.test($)?$:RH($),Y+=" = ",Y+=TH(N[$],EN(N[$]),H-1,W)}return Y+" }"}function BO(N,H,W){if(N.length===0)return"[]";let O="[ ";for(let Y=0;Y<N.length;Y++){if(Y)O+=", ";if(N[Y]===null||N[Y]===void 0)throw TypeError("arrays cannot contain null or undefined values");O+=TH(N[Y],EN(N[Y]),H-1,W)}return O+" ]"}function DO(N,H,W,O){if(W===0)throw Error("Could not stringify the object: maximum object depth exceeded");let Y="";for(let G=0;G<N.length;G++)Y+=`${Y&&`
|
|
241
241
|
`}[[${H}]]
|
|
242
|
-
`,Y+=
|
|
243
|
-
`)+
|
|
244
|
-
`)+
|
|
242
|
+
`,Y+=EH(0,N[G],H,W,O);return Y}function EH(N,H,W,O,Y){if(O===0)throw Error("Could not stringify the object: maximum object depth exceeded");let G="",$="",U=Object.keys(H);for(let Q=0;Q<U.length;Q++){let X=U[Q];if(H[X]!==null&&H[X]!==void 0){let F=EN(H[X]);if(F==="symbol"||F==="function")throw TypeError(`cannot serialize values of type '${F}'`);let K=Z0.test(X)?X:RH(X);if(F==="array"&&AO(H[X]))$+=($&&`
|
|
243
|
+
`)+DO(H[X],W?`${W}.${K}`:K,O-1,Y);else if(F==="object"){let T=W?`${W}.${K}`:K;$+=($&&`
|
|
244
|
+
`)+EH(T,H[X],T,O-1,Y)}else G+=K,G+=" = ",G+=TH(H[X],F,O,Y),G+=`
|
|
245
245
|
`}}if(N&&(G||!$))G=G?`[${N}]
|
|
246
246
|
${G}`:`[${N}]`;return G&&$?`${G}
|
|
247
|
-
${$}`:G||$}function
|
|
248
|
-
`)return
|
|
249
|
-
`;return
|
|
247
|
+
${$}`:G||$}function t(N,{maxDepth:H=1000,numbersAsFloat:W=!1}={}){if(EN(N)!=="object")throw TypeError("stringify can only be called with an object");let O=EH(0,N,"",H,W);if(O[O.length-1]!==`
|
|
248
|
+
`)return O+`
|
|
249
|
+
`;return O}/*!
|
|
250
250
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
251
251
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
252
252
|
*
|
|
@@ -272,13 +272,13 @@ ${$}`:G||$}function d(N,{maxDepth:H=1000,numbersAsFloat:O=!1}={}){if(TN(N)!=="ob
|
|
|
272
272
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
273
273
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
274
274
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
275
|
-
*/function
|
|
276
|
-
`,"utf8")}async function
|
|
277
|
-
`,"utf8")}var
|
|
278
|
-
`);if(
|
|
279
|
-
`,"utf8"),rN=H,H}var
|
|
280
|
-
`))!==-1){let G=H.slice(0,Y).replace(/\r$/,"");if(H=H.slice(Y+1),G.trim().length>0)N(G)}},flush(){let
|
|
281
|
-
`),
|
|
275
|
+
*/function Z(N,H=200){return new Response(JSON.stringify(N),{status:H,headers:{"content-type":"application/json"}})}function z(N,H,W){return Z({error:H,detail:W},N)}async function L(N){try{return await N.json()}catch{throw new B("Invalid JSON body")}}function A(N,H){if(typeof N!=="string"||N.length===0)throw new B(`Missing or invalid field: ${H}`);return N}class B extends Error{constructor(N){super(N);this.name="BadRequestError"}}import{promises as g}from"fs";import v from"path";import _H from"path";function HN(N,H){let W=_H.resolve(N),O=_H.resolve(W,H||".");if(O!==W&&!O.startsWith(W+_H.sep))throw new dN(H);return O}class dN extends Error{constructor(N){super(`Path escapes workspace: ${N}`);this.name="PathEscapeError"}}var CO=2097152,SO=new Set([".png",".jpg",".jpeg",".gif",".webp",".svg",".bmp",".ico",".avif"]),RO=new Set([".zip",".tar",".gz",".7z",".exe",".dll",".so",".dylib",".pdf",".woff",".woff2",".ttf",".mp3",".mp4",".mov",".webm",".sqlite",".db",".bin"]);function TO(N){let H=v.extname(N).toLowerCase();if(H===".md"||H===".markdown")return"markdown";if(H===".json"||H===".jsonl")return"json";if(SO.has(H))return"image";if(RO.has(H))return"binary";return"text"}function r(N,H){return HN(J(H),N)}function wH(N,H){let W=v.relative(J(H),N);return W===""?".":l(W)}async function z0(N,H){let W=await g.stat(N),O={name:v.basename(N)||".",path:wH(N,H),type:W.isDirectory()?"dir":"file",modifiedAt:W.mtime.toISOString()};if(O.type==="file")return O.size=W.size,O;let Y=await g.readdir(N,{withFileTypes:!0}),G=await Promise.all(Y.map(($)=>z0(v.join(N,$.name),H)));return G.sort(($,U)=>$.type!==U.type?$.type==="dir"?-1:1:$.name.localeCompare(U.name)),O.children=G,O}async function F0(N=".",H=V){return z0(r(N,H),H)}async function L0(N,H=V){let W=r(N,H),O=await g.stat(W);if(O.isDirectory())throw Error(`Not a file: ${N}`);let Y=TO(W),G={path:wH(W,H),kind:Y,size:O.size,modifiedAt:O.mtime.toISOString()};if(Y==="image"||Y==="binary")return G;if(O.size>CO)throw Error(`File too large to open (${O.size} bytes): ${N}`);return G.content=await g.readFile(W,"utf8"),G}async function V0(N,H,W=V){let O=r(N,W);await g.mkdir(v.dirname(O),{recursive:!0}),await g.writeFile(O,H,"utf8")}async function M0(N,H=V){await g.mkdir(r(N,H),{recursive:!0})}async function K0(N,H=V){let W=r(N,H);if(W===v.resolve(J(H)))throw Error("Cannot delete the workspace root");await g.rm(W,{recursive:!0,force:!0})}async function A0(N,H,W=V){let O=r(N,W),Y=r(H,W);if(O===v.resolve(J(W)))throw Error("Cannot rename the workspace root");await g.mkdir(v.dirname(Y),{recursive:!0}),await g.rename(O,Y)}async function J0(N,H,W,O=V){let Y=v.basename(H);if(!Y||Y==="."||Y==="..")throw Error(`Invalid file name: ${H}`);let G=HN(J(O),v.join(N||".",Y));return await g.mkdir(v.dirname(G),{recursive:!0}),await Bun.write(G,W),wH(G,O)}function sN(N,H=V){return r(N,H)}import{randomBytes as EO}from"crypto";function tN(N){return`${N}_${EO(6).toString("hex")}`}var PH=null;function D0(N){PH=N}function i(N,H){PH?.publish(N,JSON.stringify(H))}function C0(N,H){PH?.publish(N,H)}import{promises as _N}from"fs";import _O from"os";import fH from"path";var e=new Map,S0=!1;function xH(N){return fH.join(a(),N,"meta.json")}var R0=fH.join(_O.homedir(),".agenthost");function T0(N){let H=JSON.parse(N);if(H.cwd?.startsWith(R0))H.cwd=I+H.cwd.slice(R0.length);return H}async function E0(N){await _N.mkdir(fH.join(a(),N.id),{recursive:!0}),await _N.writeFile(xH(N.id),JSON.stringify(N,null,2)+`
|
|
276
|
+
`,"utf8")}async function wO(){if(S0)return;S0=!0;let N;try{N=await _N.readdir(a())}catch{return}for(let H of N){if(e.has(H))continue;try{let W=await _N.readFile(xH(H),"utf8"),O=T0(W);e.set(O.id,O)}catch{}}}async function _0(N){let H={id:tN("run"),projectId:N.projectId??V,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 E0(H),H}async function WN(N,H){let W=await D(N);if(!W)return null;let O={...W,...H};return e.set(N,O),await E0(O),O}async function D(N){if(e.has(N))return e.get(N);try{let H=await _N.readFile(xH(N),"utf8"),W=T0(H);return e.set(N,W),W}catch{return null}}async function w0(N){await wO();let H=[...e.values()];return(N?H.filter((O)=>O.projectId===N):H).sort((O,Y)=>Y.startedAt.localeCompare(O.startedAt))}function h(N){return N==="queued"||N==="starting"||N==="running"||N==="waiting_approval"}import{promises as P0}from"fs";import PO from"path";function f0(N){return PO.join(a(),N,"events.jsonl")}async function x0(N){await P0.appendFile(f0(N.runId),JSON.stringify(N)+`
|
|
277
|
+
`,"utf8")}var fO=/"type":\s*"run\.(started|resumed|steered)"/,xO=400;async function k0(N,H={}){let W;try{W=await P0.readFile(f0(N),"utf8")}catch{return{events:[],offset:0,total:0}}let O=W.split(`
|
|
278
|
+
`);if(O.length>0&&O[O.length-1]==="")O.pop();let Y=O.length,G=Math.max(0,Math.min(H.before??Y,Y)),$=H.limit===void 0?0:Math.max(0,G-H.limit);if($>0){for(let Q=$;Q>=Math.max(0,$-xO);Q--)if(fO.test(O[Q])){$=Q;break}}let U=[];for(let Q=$;Q<G;Q++){let X=O[Q].trim();if(!X)continue;try{U.push(JSON.parse(X))}catch{}}return{events:U,offset:$,total:Y}}import{promises as z1}from"fs";import nO from"os";import F1 from"path";var b0={name:"junhost",version:"0.2.0",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=b0.version;import IO from"os";import P from"path";import{existsSync as fN,readdirSync as jO}from"fs";import{mkdir as c0}from"fs/promises";import{randomUUID as vO}from"crypto";import{readFileSync as yO}from"fs";import{promises as bO}from"fs";import qO from"path";var q0=["browserProxy","browserNoProxy"];function I0(){return qO.join(I,"config.json")}var rN=null;function eN(){if(rN)return rN;let N={};try{N=JSON.parse(yO(I0(),"utf8"))}catch{}let H={};for(let W of q0){let O=N[W];if(typeof O==="string"&&O.length>0)H[W]=O}return rN=H,H}async function j0(N){let H={...eN()};for(let W of q0){if(!(W in N))continue;let O=N[W];if(typeof O==="string"&&O.trim().length>0)H[W]=O.trim();else delete H[W]}return await bO.writeFile(I0(),JSON.stringify(H,null,2)+`
|
|
279
|
+
`,"utf8"),rN=H,H}var gO="jun",v0=200,l0=process.platform==="win32"?"agent-browser.exe":"agent-browser";function u0(){let N=import.meta.dir;for(let H=0;H<8;H++){let W=P.join(N,"node_modules",".bin");if(fN(P.join(W,l0)))return W;let O=P.dirname(N);if(O===N)break;N=O}return null}function hO(N){let H=u0();if(H)return[P.join(H,l0),...N];return process.platform==="win32"?["cmd","/c","agent-browser",...N]:["agent-browser",...N]}var g0=Object.keys(process.env).find((N)=>N.toUpperCase()==="PATH")??"PATH",OH="agent",HH=null,NH=[];function i0(){let N=q("CLOAK_PATH");if(N&&fN(N))return N;let H=P.join(IO.homedir(),".cloakbrowser"),W;try{W=jO(H).filter((Y)=>Y.startsWith("chromium-"))}catch{return null}W.sort().reverse();let O=process.platform==="win32"?"chrome.exe":"chrome";for(let Y of W){let G=P.join(H,Y,O);if(fN(G))return G}return null}function mO(){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((W)=>W&&fN(W))??null}function bH(){let N={AGENT_BROWSER_SESSION:gO,AGENT_BROWSER_PROFILE:P.join(SN(),"profile"),AGENT_BROWSER_DOWNLOAD_PATH:P.join(J(),"downloads"),AGENT_BROWSER_SCREENSHOT_DIR:P.join(J(),"screenshots"),AGENT_BROWSER_ARGS:"--disable-blink-features=AutomationControlled"},H=YH().value;if(H)N.AGENT_BROWSER_PROXY=H;let W=GH().value;if(W)N.AGENT_BROWSER_PROXY_BYPASS=W;let O=u0();if(O)N[g0]=`${O}${P.delimiter}${process.env[g0]??""}`;let Y=i0();if(Y)return N.AGENT_BROWSER_EXECUTABLE_PATH=Y,N;let G=mO(),$=process.platform!=="linux"||Boolean(process.env.DISPLAY),U=q("BROWSER_HEADED")!=="false"&&$;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&&U)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 cO(){return{...process.env,...bH()}}function lO(){let N=YH().value;if(!N)return[];let H=["--proxy",N],W=GH().value;if(W)H.push("--proxy-bypass",W);return H}function YH(){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 GH(){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 yH=!1;function p0(N){if(yH)return;if(q("NO_CLOAK_DOWNLOAD")==="true")return;if(i0())return;yH=!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((W)=>{if(yH=!1,W===0)console.log("[browser] cloakbrowser Stealth Chromium ready.");else console.warn(`[browser] cloakbrowser download exited with code ${W}.`)})}async function h0(N,H,W){if(!N)return"";let O=N.getReader(),Y=new TextDecoder,G="",$=Date.now()+W;try{while(Date.now()<$){let U=Math.min(H,$-Date.now()),Q=await Promise.race([O.read(),new Promise((X)=>setTimeout(()=>X("timeout"),U))]);if(Q==="timeout"||Q.done)break;G+=Y.decode(Q.value,{stream:!0})}}finally{O.releaseLock()}return G}async function R(N,H={}){let W=[...lO(),...N],O=H.json?[...W,"--json"]:W,Y=Bun.spawn(hO(O),{env:cO(),stdout:"pipe",stderr:"pipe"}),G=setTimeout(()=>Y.kill(),H.timeoutMs??120000),$=await Y.exited;clearTimeout(G);let[U,Q]=await Promise.all([h0(Y.stdout,80,1500),h0(Y.stderr,60,300)]),X,F;if(H.json)try{let K=JSON.parse(U);if(X=K.data??K,K.success===!1)F=typeof K.error==="string"?K.error:"command failed"}catch{}return{ok:$===0&&!F,stdout:U,stderr:Q,data:X,error:F}}function p(N,H){if(NH.unshift({id:vO(),ts:new Date().toISOString(),kind:N,detail:H}),NH.length>v0)NH.length=v0}function n0(){return NH}function o0(){return OH}function a0(N){OH=N,p("control",N)}function d0(){return HH}var s0=(N)=>typeof N==="object"&&N!==null?N:{};function WH(N){if(typeof N==="string")return N;let H=s0(N);for(let W of["url","title","value","text","result"])if(typeof H[W]==="string")return H[W];return null}var uO=2500,PN=null,wN=null;function n(){PN=null}async function xN(){if(PN&&Date.now()-PN.at<uO)return{...PN.status,controller:OH};if(wN)return wN;return wN=iO().then((N)=>{return PN={at:Date.now(),status:N},N}).finally(()=>{wN=null}),wN}async function iO(){let N=await R(["stream","status"],{json:!0,timeoutMs:30000}),H=s0(N.data),W=N.ok&&H.connected===!0,O=W&&H.enabled===!0;HH=O&&typeof H.port==="number"?H.port:null;let Y=null,G=null;if(W){let[$,U]=await Promise.all([R(["get","url"],{json:!0,timeoutMs:30000}),R(["get","title"],{json:!0,timeoutMs:30000})]);Y=$.ok?WH($.data):null,G=U.ok?WH(U.data):null}return{running:W,streaming:O,streamPort:HH,url:Y,title:G,controller:OH}}var m0={width:1280,height:720};async function qH(){await R(["set","viewport",String(m0.width),String(m0.height)],{timeoutMs:30000})}async function t0(){await Promise.all(["screenshots","downloads","reports"].map((N)=>c0(P.join(J(),N),{recursive:!0})))}async function r0(N){await t0(),await c0(P.join(SN(),"profile"),{recursive:!0});let H=await R(["open",N??"about:blank"],{timeoutMs:180000});if(!H.ok)throw Error(`agent-browser open failed: ${H.stderr||H.stdout}`);return await qH(),await R(["stream","enable"],{json:!0,timeoutMs:30000}),p("start",N??"about:blank"),n(),xN()}async function e0(){await R(["close"],{timeoutMs:30000}),HH=null,n(),p("stop")}async function N1(N){let H=await R(["open",N],{timeoutMs:120000});if(!H.ok)throw Error(`Navigation failed: ${H.stderr||H.stdout}`);await qH(),n(),p("navigate",N)}async function H1(N){let H=await R([N],{timeoutMs:60000});if(!H.ok)throw Error(`${N} failed: ${H.stderr||H.stdout}`);await qH(),n(),p(N)}async function W1(N){let H=await R(["press",N],{timeoutMs:30000});if(!H.ok)throw Error(`Key press failed: ${H.stderr||H.stdout}`);n()}async function O1(){await t0();let N=`browser-${new Date().toISOString().replace(/[:.]/g,"-")}.png`,H=P.join(J(),"screenshots",N),W=await R(["screenshot",H],{timeoutMs:60000});if(!W.ok)throw Error(`Screenshot failed: ${W.stderr||W.stdout}`);return p("screenshot",`screenshots/${N}`),`screenshots/${N}`}async function Y1(N=!0){let H=await R(["snapshot",...N?["-i"]:[]],{timeoutMs:60000});if(!H.ok)throw Error(`Snapshot failed: ${H.stderr||H.stdout}`);return H.stdout.trim()}async function G1(N){let H=await R(["click",N],{timeoutMs:30000});if(!H.ok)throw Error(`Click failed: ${H.stderr||H.stdout}`);n(),p("click",N)}async function $1(N,H){let W=await R(["fill",N,H],{timeoutMs:30000});if(!W.ok)throw Error(`Fill failed: ${W.stderr||W.stdout}`);p("fill",N)}async function U1(N){let W=await R(N?["get","text",N]:["get","text","body"],{json:!0,timeoutMs:30000});if(!W.ok)throw Error(`Read failed: ${W.stderr||W.stdout}`);return WH(W.data)??W.stdout.trim()}async function Q1(N){let H=await R(["eval",N],{json:!0,timeoutMs:30000});if(!H.ok)throw Error(`Eval failed: ${H.stderr||H.stdout}`);return WH(H.data)??H.stdout.trim()}async function X1(N,H={}){if(!Array.isArray(N)||N.length===0||!N.every((O)=>typeof O==="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 W=await R(N,{json:H.json,timeoutMs:H.timeoutMs??120000});return n(),p("exec",N.join(" ").slice(0,80)),{ok:W.ok,stdout:W.stdout,stderr:W.stderr,error:W.error}}class IH{send;handlers;nextId=1;pending=new Map;constructor(N,H){this.send=N;this.handlers=H}request(N,H){let W=this.nextId++,O=new Promise((Y,G)=>{this.pending.set(W,{method:N,resolve:Y,reject:G})});return this.send(JSON.stringify({jsonrpc:"2.0",id:W,method:N,params:H})),O}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,W){this.send(JSON.stringify({jsonrpc:"2.0",id:N,error:{code:H,message:W}}))}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 W=this.pending.get(Number(H.id));if(!W)return;if(this.pending.delete(Number(H.id)),H.error)W.reject(Error(`${W.method} failed: ${H.error.message} (${H.error.code})`));else W.resolve(H.result)}failAll(N){for(let H of this.pending.values())H.reject(Error(`${H.method} failed: ${N}`));this.pending.clear()}}function Z1(N){let H="",W=new TextDecoder;return{push(O){H+=W.decode(O,{stream:!0});let Y;while((Y=H.indexOf(`
|
|
280
|
+
`))!==-1){let G=H.slice(0,Y).replace(/\r$/,"");if(H=H.slice(Y+1),G.trim().length>0)N(G)}},flush(){let O=H.trim();if(H="",O.length>0)N(O)}}}class jH{handlers;proc=null;rpc=null;initialized=!1;constructor(N){this.handlers=N}get running(){return this.proc!==null}async start(){if(this.proc)return;await oO();let N=Bun.which("codex");if(!N)throw Error("codex binary not found in PATH. Install Codex CLI first.");let H=/\.(cmd|bat)$/i.test(N)?["cmd","/c",N,"app-server"]:[N,"app-server"],W=Bun.spawn(H,{cwd:J(),env:{...process.env,CODEX_HOME:j(),...bH()},stdin:"pipe",stdout:"pipe",stderr:"pipe",onExit:(Y,G)=>{console.log(`[codex] app-server exited (code ${G})`),this.rpc?.failAll(`codex app-server exited (code ${G})`),this.proc=null,this.rpc=null,this.initialized=!1,this.handlers.onExit(G)}});this.proc=W,this.rpc=new IH((Y)=>{W.stdin.write(Y+`
|
|
281
|
+
`),W.stdin.flush()},{onNotification:(Y,G)=>this.handlers.onNotification(Y,G),onServerRequest:(Y,G,$)=>this.handlers.onServerRequest(Y,G,$)});let O=this.rpc;(async()=>{let Y=Z1((G)=>O.handleLine(G));for await(let G of W.stdout)Y.push(G);Y.flush()})(),(async()=>{let Y=new TextDecoder;for await(let G of W.stderr){let $=Y.decode(G).trimEnd();if($)console.error("[codex:stderr]",$)}})()}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,W){this.requireRpc().respondError(N,H,W)}requireRpc(){if(!this.rpc)throw Error("codex app-server is not running");return this.rpc}}async function oO(){let N=F1.join(j(),"auth.json");try{await z1.access(N);return}catch{}let H=F1.join(nO.homedir(),".codex","auth.json");try{await z1.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 kN=null,$H=null;function UH(){return kN}function L1(){return $H}function V1(N){if(kN=N,N)$H=null}function QH(){kN=null,$H=null}function M1(N){let H=N??{};if($H={success:H.success===!0,error:H.error??null,at:new Date().toISOString()},!H.loginId||kN?.loginId===H.loginId)kN=null}var aO={"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"},dO={"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 K1(N){return aO[N]??`codex.${N.split("/").join(".")}`}function A1(N){return dO[N]??null}function J1(N){return N==="item/commandExecution/requestApproval"||N==="item/fileChange/requestApproval"||N==="item/permissions/requestApproval"}function yN(N){if(typeof N!=="object"||N===null)return null;let H=N;if(typeof H.threadId==="string")return H.threadId;let W=H.thread;if(typeof W==="object"&&W!==null){let O=W.id;if(typeof O==="string")return O}return null}var B1={readOnly:"read-only",workspaceWrite:"workspace-write",dangerFullAccess:"danger-full-access"},D1={readOnly:{type:"readOnly"},workspaceWrite:{type:"workspaceWrite"},dangerFullAccess:{type:"dangerFullAccess"}},vH={never:"never",onRequest:"on-request",onFailure:"on-failure",untrusted:"untrusted"},XH=`# Who you are
|
|
282
282
|
|
|
283
283
|
You are Jun. That's your name, use it if anyone asks. You live inside JunHost,
|
|
284
284
|
your own self-hosted dashboard that runs you as a long-running local/VPS assistant, and
|
|
@@ -319,20 +319,20 @@ model powers you; you're just Jun.
|
|
|
319
319
|
- Report outcomes honestly. If something failed, say so plainly with the actual
|
|
320
320
|
error; don't dress up a partial result as done.
|
|
321
321
|
- Per-workspace guidance lives in each workspace's AGENTS.md and takes
|
|
322
|
-
precedence over this general guidance when they differ.`,ON=new Map,
|
|
322
|
+
precedence over this general guidance when they differ.`,ON=new Map,YN=new Map,bN=new Map,C1=new Set,qN=new Map,zN=new Map,gH="__default__";function sO(N){let H=N.error?.message;return typeof H==="string"&&H.includes("unsupported_parameter")&&H.includes("reasoning.summary")}async function S1(N,H,W){if(C1.has(H))W.summary="none";qN.set(N,W),await k().request("turn/start",W)}var jN=new Map,IN=null;function k(){if(!IN)IN=new jH({onNotification:tO,onServerRequest:rO,onExit:eO});return IN}async function E(N,H,W,O){let Y={id:tN("evt"),runId:N,ts:new Date().toISOString(),source:H,type:W,payload:O};return await x0(Y),i(`run:${N}`,Y),i("runs",{type:"run.event",runId:N,eventType:W}),Y}async function y(N,H){let W={status:H};if(H==="completed"||H==="failed"||H==="stopped")W.completedAt=new Date().toISOString();let O=await WN(N,W);if(O)i("runs",{type:"run.updated",run:O})}function tO(N,H){if(N==="account/login/completed"){M1(H);return}let W=yN(H),O=W?jN.get(W):void 0;if(O){if(N==="item/completed"){let G=H.item;if(G?.type==="agentMessage"&&typeof G.text==="string")O.text=G.text}else if(N==="turn/completed"||N==="error")O.done(O.text);return}let Y=W?ON.get(W):void 0;if(!Y)return;(async()=>{if(await E(Y,"codex",K1(N),H),N==="turn/started"){let G=H.turn?.id;if(typeof G==="string")bN.set(Y,G)}else if(N==="turn/completed"){let G=H.turn?.id;if(typeof G==="string"&&zN.get(Y)===G){zN.delete(Y);return}zN.delete(Y),bN.delete(Y),qN.delete(Y);let $=await D(Y);if($&&h($.status))await y(Y,"completed");if(YN.delete(Y),$&&!$.title)HY(Y)}else if(N==="error"){let G=H.turnId;bN.delete(Y);let $=await D(Y),U=qN.get(Y);if($&&U&&U.summary&&U.summary!=="none"&&sO(H)){C1.add($.model??gH);let Q={...U,summary:"none"};console.warn(`[runs] ${$.model??"default model"} rejects reasoning.summary \u2014 retrying with summaries disabled`);try{if(typeof G==="string")zN.set(Y,G);qN.set(Y,Q),await k().request("turn/start",Q);return}catch(X){zN.delete(Y),console.warn(`[runs] summary-less retry failed for ${Y}:`,X)}}if($&&h($.status))await y(Y,"failed")}else if(N==="thread/name/updated"){let G=H.threadName;if(typeof G==="string"&&G.trim()){let $=await WN(Y,{title:G.trim()});if($)i("runs",{type:"run.updated",run:$})}}})()}function rO(N,H,W){let O=A1(H),Y=yN(W),G=Y?ON.get(Y):void 0;if(!O||!G){if(console.warn(`[runs] auto-declining unroutable server request ${H} (id ${N})`),J1(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 U=await D(G);if(U?.approvalPolicy==="never"||U?.approvalsReviewer==="auto_review"){k().respond(N,{action:"accept"}),await E(G,"daemon","approval.resolved",{requestId:N,decision:"accept",auto:!0});return}}let $=YN.get(G)??[];$.push({requestId:N,method:H}),YN.set(G,$),await y(G,"waiting_approval"),await E(G,"codex",O,{requestId:N,method:H,params:W})})()}function eO(N){for(let W of jN.values())W.done(W.text);jN.clear();let H=[...ON.values()];ON.clear(),YN.clear(),bN.clear(),qN.clear(),zN.clear();for(let W of H)(async()=>{let O=await D(W);if(!O||!h(O.status))return;await E(W,"daemon","run.failed",{reason:`codex app-server exited (code ${N})`}),await y(W,"failed")})()}function hH(N,H,W,O){let Y=(W??[]).filter((Q)=>Q.mediaType?.startsWith("image/")),G=(W??[]).filter((Q)=>!Q.mediaType?.startsWith("image/")),$=H;if(G.length>0)$+=`
|
|
323
323
|
|
|
324
324
|
Attached workspace files:
|
|
325
325
|
`+G.map((Q)=>`- ${Q.path}`).join(`
|
|
326
|
-
`);let U=[{type:"text",text:$}];if(
|
|
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
|
|
326
|
+
`);let U=[{type:"text",text:$}];if(O)U.push({type:"skill",name:O.name,path:O.path});for(let Q of Y)U.push({type:"localImage",path:sN(Q.path,N)});return U}function NY(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 HY(N){let H=await D(N);if(!H||H.title||!H.codexThreadId)return;try{let W=k(),O=await W.request("thread/start",{cwd:H.cwd,ephemeral:!0,sandbox:"read-only",approvalPolicy:"never",serviceName:"jun"}),Y=yN(O);if(!Y)return;let G=await new Promise((Q)=>{let X=(K)=>{clearTimeout(F),jN.delete(Y),Q(K)},F=setTimeout(()=>X(null),30000);jN.set(Y,{text:null,done:X}),W.request("turn/start",{threadId:Y,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
328
|
|
|
329
|
-
`+H.prompt.slice(0,2000)}],effort:"low"}).catch(()=>X(null))}),$=uW(G);if(!$)return;await O.request("thread/name/set",{threadId:H.codexThreadId,name:$});let U=await NN(N,{title:$});if(U)i("runs",{type:"run.updated",run:U})}catch(O){console.warn(`[runs] title generation failed for ${N}:`,O)}}async function C(N,H){let O=h();return await O.start(),await O.initializeOnce(),O.request(N,H)}async function LN(N){let H=N.projectId??"default",O=N.cwd??J(H),W=await S0({prompt:N.prompt,cwd:O,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 i("runs",{type:"run.updated",run:W}),await T(W.id,"daemon","run.started",{prompt:N.prompt,cwd:O,projectId:H,attachments:N.attachments??[]}),(async()=>{try{let Y=h();await Y.start(),await Y.initializeOnce();let G=await Y.request("thread/start",{cwd:O,model:N.model??null,sandbox:Z1[N.sandbox??"workspaceWrite"],approvalPolicy:jH[N.approvalPolicy??"onRequest"],...N.approvalsReviewer==="auto_review"?{approvalsReviewer:"auto_review"}:{},...$H?{developerInstructions:$H}:{},serviceName:"jun"}),$=kN(G)??(typeof G.threadId==="string"?G.threadId:null);if(!$)throw Error(`thread/start returned no thread id: ${JSON.stringify(G)}`);ON.set($,W.id),await NN(W.id,{codexThreadId:$}),await x(W.id,"running"),await z1(W.id,N.model??gH,{threadId:$,input:vH(H,N.prompt,N.attachments,N.skill),summary:"detailed",effort:N.effort??"medium",sandboxPolicy:L1[N.sandbox??"workspaceWrite"]})}catch(Y){let G=Y instanceof Error?Y.message:String(Y);await T(W.id,"daemon","run.failed",{reason:G}),await x(W.id,"failed")}})(),W}async function hH(N,H){let O=h();if(await O.start(),await O.initializeOnce(),ON.has(H))return{server:O,resumed:!1};let W=await D(N);return await O.request("thread/resume",{threadId:H,...W?.approvalPolicy?{approvalPolicy:jH[W.approvalPolicy]}:{},...W?.approvalsReviewer==="auto_review"?{approvalsReviewer:"auto_review"}:{},...W?.model?{model:W.model}:{},...W?.sandbox?{sandbox:Z1[W.sandbox]}:{},...$H?{developerInstructions:$H}:{}}),ON.set(H,N),{server:O,resumed:!0}}async function UH(N,H,O,W){let Y=await D(N);if(!Y)throw Error(`Run not found: ${N}`);if(g(Y.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let G=Y.codexThreadId;if(!G)throw Error("Run has no Codex thread to resume");let $={};if(W?.sandbox&&W.sandbox!==Y.sandbox)$.sandbox=W.sandbox;if(W?.approvalPolicy&&W.approvalPolicy!==Y.approvalPolicy)$.approvalPolicy=W.approvalPolicy;if(W?.approvalsReviewer&&W.approvalsReviewer!==Y.approvalsReviewer)$.approvalsReviewer=W.approvalsReviewer;if(W?.model&&W.model!==Y.model)$.model=W.model;if(W?.effort&&W.effort!==Y.effort)$.effort=W.effort;if(Object.keys($).length>0){let U=await NN(N,$);if(U)i("runs",{type:"run.updated",run:U})}return await T(N,"daemon","run.resumed",{prompt:H,attachments:O??[],...Object.keys($).length>0?{modeChanges:$}:{}}),await x(N,"running"),(async()=>{try{await hH(N,G);let U=$.sandbox??Y.sandbox??"workspaceWrite",Q=$.approvalPolicy??Y.approvalPolicy??"onRequest",X=$.approvalsReviewer??Y.approvalsReviewer,F=$.model??Y.model,K=(await D(N))?.serviceTier;await z1(N,F??gH,{threadId:G,input:vH(Y.projectId,H,O),summary:"detailed",effort:$.effort??Y.effort??"medium",sandboxPolicy:L1[U],approvalPolicy:jH[Q],...X==="auto_review"?{approvalsReviewer:X}:{},...F?{model:F}:{},...K?{serviceTier:K}:{}})}catch(U){let Q=U instanceof Error?U.message:String(U);await T(N,"daemon","run.failed",{reason:Q}),await x(N,"failed")}})(),await D(N)}async function V1(N,H,O){let W=await D(N);if(!W)throw Error(`Run not found: ${N}`);if(!g(W.status))throw Error("Run is not active \u2014 send a follow-up message instead");let Y=W.codexThreadId,G=yN.get(N);if(!Y||!G)throw Error("No active turn to steer");await T(N,"daemon","run.steered",{prompt:H,attachments:O??[]}),await h().request("turn/steer",{threadId:Y,expectedTurnId:G,input:vH(W.projectId,H,O)})}async function M1(N,H){let O=await D(N);if(!O)throw Error(`Run not found: ${N}`);if(H){let G=((await C("model/list",{})).data??[]).find(($)=>O.model?$.model===O.model:$.isDefault);if(!G?.serviceTiers?.some(($)=>$.id==="priority"))throw Error(`Model ${G?.model??O.model??"unknown"} does not support fast mode`)}let W=await NN(N,{serviceTier:H?"priority":"standard"});if(W)i("runs",{type:"run.updated",run:W});return await T(N,"daemon","run.fast",{enabled:H}),W}async function K1(N){let H=await D(N);if(!H)throw Error(`Run not found: ${N}`);if(g(H.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let O=H.codexThreadId;if(!O)throw Error("Run has no Codex thread");let{server:W}=await hH(N,O);await T(N,"daemon","run.compact.started",{}),await W.request("thread/compact/start",{threadId:O})}async function A1(N,H){let O=await D(N);if(!O)throw Error(`Run not found: ${N}`);if(g(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");let{server:Y}=await hH(N,W),G=H?.trim();await T(N,"daemon","run.review.started",{instructions:G??null}),await x(N,"running");try{await Y.request("review/start",{threadId:W,target:G?{type:"custom",instructions:G}:{type:"uncommittedChanges"},delivery:"inline"})}catch($){let U=$ instanceof Error?$.message:String($);throw await T(N,"daemon","run.failed",{reason:U}),await x(N,"failed"),$}return await D(N)}async function J1(N){let H=await D(N);if(!H||!g(H.status))return!1;if(H.codexThreadId&&qN?.running)try{await qN.request("turn/interrupt",{threadId:H.codexThreadId})}catch(O){console.warn(`[runs] turn/interrupt failed for ${N}:`,O)}return WN.delete(N),await T(N,"daemon","run.stopped",{}),await x(N,"stopped"),!0}async function B1(N,H,O){let W=WN.get(N)??[],Y=W.findIndex(($)=>String($.requestId)===String(H));if(Y===-1)return!1;let[G]=W.splice(Y,1);if(W.length===0)WN.delete(N);if(G.method==="mcpServer/elicitation/request"){let $=O==="decline"||O==="cancel"?O:"accept";h().respond(G.requestId,{action:$})}else h().respond(G.requestId,{decision:O});if(await T(N,"daemon","approval.resolved",{requestId:G.requestId,decision:O}),W.length===0)await x(N,"running");return!0}function zN(){return pW.join(q(),"config.toml")}async function p(){try{return await FN.readFile(zN(),"utf8")}catch{return""}}async function C1(N){try{c(N)}catch(H){throw new B(`Invalid TOML: ${H instanceof Error?H.message:String(H)}`)}await FN.writeFile(zN(),N,"utf8")}function nW(N){if(!N.trim())return{};let O=c(N).mcp_servers;if(typeof O!=="object"||O===null)return{};return O}async function aW(){let N=new Map;try{let H=await C("mcpServerStatus/list",{detail:"full"});for(let O of H.data??[]){let W=Object.entries(O.tools??{}).map(([Y,G])=>({name:Y,description:G?.description}));N.set(O.name,{startupState:O.serverInfo?"ready":"starting",authStatus:O.authStatus??null,tools:W})}}catch(H){console.warn("[mcp] mcpServerStatus/list failed:",H)}return N}async function S1(){let N=await p(),H=nW(N),O=await aW();return{servers:Object.entries(H).map(([Y,G])=>{let $=O.get(Y);return{name:Y,command:G.command,args:G.args,envKeys:G.env?Object.keys(G.env):void 0,url:G.url,enabled:G.enabled!==!1,startupState:$?.startupState??null,authStatus:$?.authStatus??null,tools:$?.tools??[],error:$?.error}})}}var oW=/^[A-Za-z0-9_-]+$/;async function R1(N){if(!oW.test(N.name))throw new B(`Invalid server name "${N.name}" \u2014 letters, digits, _ and - only`);if(!N.command&&!N.url)throw new B("Server needs either a command or a url");let H=await p(),O=H.trim()?c(H):{},W=O.mcp_servers??{},Y={};if(N.command)Y.command=N.command;if(N.args&&N.args.length>0)Y.args=N.args;if(N.env&&Object.keys(N.env).length>0)Y.env=N.env;if(N.url)Y.url=N.url;if(N.enabled===!1)Y.enabled=!1;W[N.name]=Y,O.mcp_servers=W,await FN.writeFile(zN(),d(O),"utf8")}async function T1(N){let H=await p();if(!H.trim())return!1;let O=c(H),W=O.mcp_servers;if(!W||!(N in W))return!1;return delete W[N],await FN.writeFile(zN(),d(O),"utf8"),!0}async function E1(N,H){let O=await p(),W=c(O||""),Y=W.mcp_servers??{};if(!Y[N])throw new B(`Server not found: ${N}`);Y[N].enabled=H,W.mcp_servers=Y,await FN.writeFile(zN(),d(W),"utf8")}async function _1(){await C("config/mcpServer/reload",{})}async function w1(N,H){let O=await p(),W=O.trim()?c(O):{},Y=W.mcp_servers??{},G={command:process.execPath,args:[N],env:{JUN_PORT:String(H)}},$=Y.jun;if($&&!Y.agenthost&&$.command===G.command&&JSON.stringify($.args)===JSON.stringify(G.args)&&$.env?.JUN_PORT===String(H))return;delete Y.agenthost,Y.jun=G,W.mcp_servers=Y,await FN.writeFile(zN(),d(W),"utf8")}var sW=Date.now();function P1(){return L({ok:!0})}function f1(){let N={ok:!0,name:"jun",version:tN,projectId:z,dataRoot:b,workspaceRoot:J(),uptimeSeconds:Math.round((Date.now()-sW)/1000)};return L(N)}import tW from"path";var QH={ok:!0};async function x1(N,H){let O=H.pathname.slice(11),W=H.searchParams.get("path")??".",Y=H.searchParams.get("project")??z;switch(`${N.method} ${O}`){case"GET tree":return L(await Q0(W,Y));case"GET read":return L(await X0(W,Y));case"GET download":{let G=dN(W,Y),$=Bun.file(G);if(!await $.exists())return Z(404,`File not found: ${W}`);return new Response($,{headers:{"content-disposition":`attachment; filename="${encodeURIComponent(tW.basename(G))}"`}})}case"POST write":{let G=await M(N);return await Z0(A(G.path,"path"),typeof G.content==="string"?G.content:"",Y),L(QH)}case"POST mkdir":{let G=await M(N);return await L0(A(G.path,"path"),Y),L(QH)}case"POST delete":{let G=await M(N);return await F0(A(G.path,"path"),Y),L(QH)}case"POST rename":{let G=await M(N);return await z0(A(G.from,"from"),A(G.to,"to"),Y),L(QH)}case"POST upload":{let G;try{G=await N.formData()}catch{throw new B("Expected multipart/form-data body")}let $=String(G.get("path")??"."),U=G.getAll("file").filter((X)=>X instanceof File);if(U.length===0)throw new B("No files in upload (field name: file)");let Q=[];for(let X of U)Q.push(await V0($,X.name,X,Y));return L({ok:!0,saved:Q})}default:return Z(404,`Unknown files endpoint: ${N.method} /api/files/${O}`)}}import{promises as k1}from"fs";function rW(N){return N.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,48)}async function y1(N){try{let H=await k1.readFile(JH(N),"utf8"),O=JSON.parse(H);return{id:O.id??N,name:O.name??N,createdAt:O.createdAt??new Date(0).toISOString(),workspaceRoot:J(N)}}catch{return null}}async function b1(){let N;try{N=await k1.readdir(UN(),{withFileTypes:!0})}catch{return[]}let H=[];for(let O of N){if(!O.isDirectory())continue;let W=await y1(O.name);if(W)H.push(W)}return H.sort((O,W)=>{if(O.id===z)return-1;if(W.id===z)return 1;return W.createdAt.localeCompare(O.createdAt)}),H}async function jN(N){return y1(N)}async function q1(N){let H=N.trim();if(!H)throw Error("Project name is required");let O=rW(H);if(!O)throw Error("Project name must contain letters or numbers");if(await jN(O))throw Error(`A project named "${O}" already exists`);await BH(O,H);let W=await jN(O);if(!W)throw Error(`Failed to create project "${O}"`);return W}async function VN(N){return await jN(N)!==null}async function I1(N,H){let W=H.pathname.split("/").filter(Boolean)[2];if(!W){if(N.method==="GET"){let Y={projects:await b1()};return L(Y)}if(N.method==="POST"){let Y=await M(N);A(Y.name,"name");try{let $={project:await q1(Y.name)};return L($,201)}catch(G){let $=G instanceof Error?G.message:String(G),U=$.includes("already exists")?409:400;return Z(U,$)}}return Z(405,"Method not allowed")}if(N.method==="GET"){let Y=await jN(W);return Y?L({project:Y}):Z(404,`Project not found: ${W}`)}return Z(405,"Method not allowed")}var eW=new Set(["accept","acceptForSession","decline","cancel"]);async function j1(N,H,O){let W=H.pathname.split("/").filter(Boolean),Y=W[2],G=W[3];if(!Y){if(N.method==="GET"){let $=H.searchParams.get("project")??void 0,U={runs:await R0($)};return L(U)}if(N.method==="POST"){let $=await M(N);A($.prompt,"prompt");let Q={run:await LN($)};return L(Q,201)}return Z(405,"Method not allowed")}if(G==="events"){if(!await D(Y))return Z(404,`Run not found: ${Y}`);return O.upgrade(N,{data:{channel:`run:${Y}`}})?void 0:Z(400,"WebSocket upgrade required")}if(!G&&N.method==="GET"){let $=await D(Y);if(!$)return Z(404,`Run not found: ${Y}`);let U=Number(H.searchParams.get("tail")??NaN),Q=Number(H.searchParams.get("before")??NaN),X=await w0(Y,{limit:Number.isFinite(U)&&U>0?U:void 0,before:Number.isFinite(Q)&&Q>=0?Q:void 0}),F={run:$,events:X.events,eventsOffset:X.offset,totalEvents:X.total};return L(F)}if(N.method!=="POST")return Z(405,"Method not allowed");switch(G){case"stop":return await J1(Y)?L({ok:!0}):Z(409,"Run is not active");case"resume":{let $=await M(N);A($.prompt,"prompt");try{let U=await UH(Y,$.prompt,Array.isArray($.attachments)?$.attachments:void 0,{sandbox:$.sandbox,approvalPolicy:$.approvalPolicy,approvalsReviewer:$.approvalsReviewer,model:$.model,effort:$.effort});return L({run:U})}catch(U){let Q=U instanceof Error?U.message:String(U),X=Q.includes("not found")?404:Q.includes("still active")?409:400;return Z(X,Q)}}case"steer":{let $=await M(N);A($.prompt,"prompt");try{return await V1(Y,$.prompt,Array.isArray($.attachments)?$.attachments:void 0),L({ok:!0})}catch(U){let Q=U instanceof Error?U.message:String(U),X=Q.includes("not found")?404:Q.includes("not active")||Q.includes("No active turn")?409:400;return Z(X,Q)}}case"fast":{let $=await M(N);if(typeof $.enabled!=="boolean")return Z(400,"Missing or invalid field: enabled");try{let U=await M1(Y,$.enabled);return L({run:U})}catch(U){let Q=U instanceof Error?U.message:String(U),X=Q.includes("not found")?404:Q.includes("does not support")?400:500;return Z(X,Q)}}case"compact":try{return await K1(Y),L({ok:!0})}catch($){let U=$ instanceof Error?$.message:String($),Q=U.includes("not found")?404:U.includes("still active")?409:400;return Z(Q,U)}case"review":{let $=await M(N);try{let U=await A1(Y,$.instructions);return L({run:U})}catch(U){let Q=U instanceof Error?U.message:String(U),X=Q.includes("not found")?404:Q.includes("still active")?409:400;return Z(X,Q)}}case"approve":{let $=await M(N);if(!eW.has(String($.decision)))return Z(400,`Invalid decision: ${String($.decision)}`);if($.requestId===void 0||$.requestId===null)return Z(400,"Missing field: requestId");return await B1(Y,$.requestId,$.decision)?L({ok:!0}):Z(404,"No matching pending approval")}default:return Z(404,`Unknown runs endpoint: ${H.pathname}`)}}var YN="browser-stream",m=null,g1=null,MN=0,KN=null,cH=null;function NY(N){if(m&&g1===N&&m.readyState<=WebSocket.OPEN)return;m?.close(),g1=N;let H=new WebSocket(`ws://127.0.0.1:${N}`);m=H,H.onmessage=(O)=>{let W=String(O.data);if(W.includes('"type":"frame"'))cH=W;A0(YN,W)},H.onclose=()=>{if(m===H)m=null,cH=null,v1()},H.onerror=()=>{}}function v1(){if(KN||MN===0)return;KN=setTimeout(()=>{KN=null,gN(!0)},2000)}async function gN(N=!1){if(MN===0)return;let H=N?null:n0();if(H===null){if(N)HN();H=(await fN()).streamPort}if(H!==null)NY(H);else v1()}function h1(){MN+=1,gN()}function m1(){return cH}function c1(){if(MN=Math.max(0,MN-1),MN===0){if(m?.close(),m=null,KN)clearTimeout(KN),KN=null}}var HY=new Set(["input_mouse","input_keyboard","input_touch"]);function l1(N){if(i0()!=="user")return;if(!m||m.readyState!==WebSocket.OPEN)return;let H=typeof N==="string"?N:N.toString("utf8");try{let O=JSON.parse(H);if(typeof O.type==="string"&&HY.has(O.type))m.send(H)}catch{}}var OY=new Set(["user","agent","paused"]);async function u1(N,H,O){let Y=H.pathname.split("/").filter(Boolean)[2];if(Y==="stream")return O.upgrade(N,{data:{channel:YN}})?void 0:Z(400,"WebSocket upgrade required");if(N.method==="GET")switch(Y){case"status":{let G=await fN();if(G.streaming)gN();return L({status:G})}case"actions":{let G={actions:u0()};return L(G)}default:return Z(404,`Unknown browser endpoint: ${H.pathname}`)}if(N.method!=="POST")return Z(405,"Method not allowed");switch(Y){case"start":{let G=await M(N).catch(()=>({})),$=await d0(typeof G.url==="string"&&G.url.length>0?G.url:void 0);return gN(),L({status:$})}case"stop":return await s0(),L({ok:!0});case"navigate":{let G=await M(N);return A(G.url,"url"),await t0(G.url),L({ok:!0})}case"key":{let G=await M(N);return A(G.key,"key"),await e0(G.key),L({ok:!0})}case"back":case"forward":case"reload":return await r0(Y),L({ok:!0});case"screenshot":{let $={path:await N1()};return L($)}case"control":{let G=await M(N);if(!OY.has(String(G.controller)))return Z(400,`Invalid controller: ${String(G.controller)}`);return p0(G.controller),L({ok:!0})}default:return Z(404,`Unknown browser endpoint: ${H.pathname}`)}}import{promises as P}from"fs";import E from"path";var n1=".agents/skills";function AN(N){return E.join(J(N),n1)}var WY=/^[a-z0-9][a-z0-9-]*$/,YY=new Set(["registry","install"]);function JN(N,H){if(!WY.test(N))throw new B(`Invalid skill id "${N}" \u2014 use lowercase letters, digits and dashes`);return E.join(AN(H),N)}function i1(N){return N.replace(/\x1b\[[0-9;?]*[A-Za-z]/g,"")}async function a1(N,H,O=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"}),Y=setTimeout(()=>W.kill(),O);try{let[G,$,U]=await Promise.all([new Response(W.stdout).text(),new Response(W.stderr).text(),W.exited]);return{stdout:i1(G),stderr:i1($),code:U}}finally{clearTimeout(Y)}}function GY(N){let H=[],O=null;for(let W of N.split(/\r?\n/)){let Y=W.trim(),G=/^(\S+@\S+)\s+([\d.]+[KMB]?)\s+installs\b/.exec(Y);if(G){let U=G[1],Q=U.indexOf("@");O={source:U,repo:U.slice(0,Q),name:U.slice(Q+1),installs:G[2]},H.push(O);continue}let $=/^[\u2514\u2570]\s*(https?:\/\/\S+)/.exec(Y);if($&&O)O.url=$[1],O=null}return H}function $Y(N){let H=[],O=/^---\r?\n([\s\S]*?)\r?\n---/.exec(N.replace(/^\uFEFF/,""));if(!O)return{errors:["Missing YAML frontmatter (--- name/description ---)"]};let W={};for(let Y of O[1].split(/\r?\n/)){let G=/^([A-Za-z_][\w-]*):\s*(.*)$/.exec(Y);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 UY=15000,uH=new Map,lH=new Map;function vN(N){uH.delete(N)}async function QY(N){let H=uH.get(N);if(H&&Date.now()-H.at<UY)return H.view;let O=lH.get(N);if(O)return O;let W=XY(N).then((Y)=>{return uH.set(N,{at:Date.now(),view:Y}),Y}).finally(()=>{lH.delete(N)});return lH.set(N,W),W}async function XY(N){let H=new Map,O=[];try{let W=await C("skills/list",{cwds:[J(N)],forceReload:!0});for(let Y of W.data??[]){for(let G of Y.errors??[])O.push(G);for(let G of Y.skills??[]){let $=E.basename(E.dirname(G.path));H.set($,G)}}}catch(W){console.warn("[skills] skills/list failed:",W)}return{byDir:H,errors:O}}async function XH(N=z){await P.mkdir(AN(N),{recursive:!0});let O=(await P.readdir(AN(N),{withFileTypes:!0})).filter((U)=>U.isDirectory()).map((U)=>U.name),{byDir:W,errors:Y}=await QY(N),G=[];for(let U of O){let Q=E.join(AN(N),U,"SKILL.md"),X=null;try{X=await P.readFile(Q,"utf8")}catch{G.push({id:U,name:U,description:"",enabled:!1,errors:["Missing SKILL.md"]});continue}let F=$Y(X),K=W.get(U),R=Y.filter((f)=>l(f.path).includes(`/${U}/`)||E.basename(E.dirname(f.path))===U).map((f)=>f.message);G.push({id:U,name:K?.name??F.name??U,description:K?.description??F.description??"",enabled:K?.enabled??!0,errors:[...new Set([...F.errors,...R])]})}let $=Y.filter((U)=>!O.some((Q)=>l(U.path).includes(`/${Q}/`)));return{skills:G,errors:$}}async function hN(N,H=z){let O=JN(N,H),W;try{W=await P.readFile(E.join(O,"SKILL.md"),"utf8")}catch{return null}let{skills:Y}=await XH(H),G=Y.find((Q)=>Q.id===N)??{id:N,name:N,description:"",enabled:!0,errors:[]},$=[],U=async(Q)=>{let X=await P.readdir(E.join(O,Q),{withFileTypes:!0});for(let F of X){let K=Q?`${Q}/${F.name}`:F.name;if(F.isDirectory())await U(K);else if(K!=="SKILL.md")$.push(`${n1}/${N}/${K}`)}};return await U(""),{info:G,content:W,files:$}}async function o1(N,H=z){let O=N.name.trim().toLowerCase().replace(/\s+/g,"-");if(YY.has(O))throw new B(`"${O}" is a reserved name \u2014 pick another`);let W=JN(O,H);try{throw await P.access(E.join(W,"SKILL.md")),new B(`Skill "${O}" already exists`)}catch(G){if(G instanceof B)throw G}let Y=`---
|
|
330
|
-
name: ${
|
|
329
|
+
`+H.prompt.slice(0,2000)}],effort:"low"}).catch(()=>X(null))}),$=NY(G);if(!$)return;await W.request("thread/name/set",{threadId:H.codexThreadId,name:$});let U=await WN(N,{title:$});if(U)i("runs",{type:"run.updated",run:U})}catch(W){console.warn(`[runs] title generation failed for ${N}:`,W)}}async function C(N,H){let W=k();return await W.start(),await W.initializeOnce(),W.request(N,H)}async function FN(N){let H=N.projectId??"default",W=N.cwd??J(H),O=await _0({prompt:N.prompt,cwd:W,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 i("runs",{type:"run.updated",run:O}),await E(O.id,"daemon","run.started",{prompt:N.prompt,cwd:W,projectId:H,attachments:N.attachments??[]}),(async()=>{try{let Y=k();await Y.start(),await Y.initializeOnce();let G=await Y.request("thread/start",{cwd:W,model:N.model??null,sandbox:B1[N.sandbox??"workspaceWrite"],approvalPolicy:vH[N.approvalPolicy??"onRequest"],...N.approvalsReviewer==="auto_review"?{approvalsReviewer:"auto_review"}:{},...XH?{developerInstructions:XH}:{},serviceName:"jun"}),$=yN(G)??(typeof G.threadId==="string"?G.threadId:null);if(!$)throw Error(`thread/start returned no thread id: ${JSON.stringify(G)}`);ON.set($,O.id),await WN(O.id,{codexThreadId:$}),await y(O.id,"running"),await S1(O.id,N.model??gH,{threadId:$,input:hH(H,N.prompt,N.attachments,N.skill),summary:"detailed",effort:N.effort??"medium",sandboxPolicy:D1[N.sandbox??"workspaceWrite"]})}catch(Y){let G=Y instanceof Error?Y.message:String(Y);await E(O.id,"daemon","run.failed",{reason:G}),await y(O.id,"failed")}})(),O}async function mH(N,H){let W=k();if(await W.start(),await W.initializeOnce(),ON.has(H))return{server:W,resumed:!1};let O=await D(N);return await W.request("thread/resume",{threadId:H,...O?.approvalPolicy?{approvalPolicy:vH[O.approvalPolicy]}:{},...O?.approvalsReviewer==="auto_review"?{approvalsReviewer:"auto_review"}:{},...O?.model?{model:O.model}:{},...O?.sandbox?{sandbox:B1[O.sandbox]}:{},...XH?{developerInstructions:XH}:{}}),ON.set(H,N),{server:W,resumed:!0}}async function ZH(N,H,W,O){let Y=await D(N);if(!Y)throw Error(`Run not found: ${N}`);if(h(Y.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let G=Y.codexThreadId;if(!G)throw Error("Run has no Codex thread to resume");let $={};if(O?.sandbox&&O.sandbox!==Y.sandbox)$.sandbox=O.sandbox;if(O?.approvalPolicy&&O.approvalPolicy!==Y.approvalPolicy)$.approvalPolicy=O.approvalPolicy;if(O?.approvalsReviewer&&O.approvalsReviewer!==Y.approvalsReviewer)$.approvalsReviewer=O.approvalsReviewer;if(O?.model&&O.model!==Y.model)$.model=O.model;if(O?.effort&&O.effort!==Y.effort)$.effort=O.effort;if(Object.keys($).length>0){let U=await WN(N,$);if(U)i("runs",{type:"run.updated",run:U})}return await E(N,"daemon","run.resumed",{prompt:H,attachments:W??[],...Object.keys($).length>0?{modeChanges:$}:{}}),await y(N,"running"),(async()=>{try{await mH(N,G);let U=$.sandbox??Y.sandbox??"workspaceWrite",Q=$.approvalPolicy??Y.approvalPolicy??"onRequest",X=$.approvalsReviewer??Y.approvalsReviewer,F=$.model??Y.model,K=(await D(N))?.serviceTier;await S1(N,F??gH,{threadId:G,input:hH(Y.projectId,H,W),summary:"detailed",effort:$.effort??Y.effort??"medium",sandboxPolicy:D1[U],approvalPolicy:vH[Q],...X==="auto_review"?{approvalsReviewer:X}:{},...F?{model:F}:{},...K?{serviceTier:K}:{}})}catch(U){let Q=U instanceof Error?U.message:String(U);await E(N,"daemon","run.failed",{reason:Q}),await y(N,"failed")}})(),await D(N)}async function R1(N,H,W){let O=await D(N);if(!O)throw Error(`Run not found: ${N}`);if(!h(O.status))throw Error("Run is not active \u2014 send a follow-up message instead");let Y=O.codexThreadId,G=bN.get(N);if(!Y||!G)throw Error("No active turn to steer");await E(N,"daemon","run.steered",{prompt:H,attachments:W??[]}),await k().request("turn/steer",{threadId:Y,expectedTurnId:G,input:hH(O.projectId,H,W)})}async function T1(N,H){let W=await D(N);if(!W)throw Error(`Run not found: ${N}`);if(H){let G=((await C("model/list",{})).data??[]).find(($)=>W.model?$.model===W.model:$.isDefault);if(!G?.serviceTiers?.some(($)=>$.id==="priority"))throw Error(`Model ${G?.model??W.model??"unknown"} does not support fast mode`)}let O=await WN(N,{serviceTier:H?"priority":"standard"});if(O)i("runs",{type:"run.updated",run:O});return await E(N,"daemon","run.fast",{enabled:H}),O}async function E1(N){let H=await D(N);if(!H)throw Error(`Run not found: ${N}`);if(h(H.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let W=H.codexThreadId;if(!W)throw Error("Run has no Codex thread");let{server:O}=await mH(N,W);await E(N,"daemon","run.compact.started",{}),await O.request("thread/compact/start",{threadId:W})}async function _1(N,H){let W=await D(N);if(!W)throw Error(`Run not found: ${N}`);if(h(W.status))throw Error("Run is still active \u2014 wait for the current turn to finish");let O=W.codexThreadId;if(!O)throw Error("Run has no Codex thread");let{server:Y}=await mH(N,O),G=H?.trim();await E(N,"daemon","run.review.started",{instructions:G??null}),await y(N,"running");try{await Y.request("review/start",{threadId:O,target:G?{type:"custom",instructions:G}:{type:"uncommittedChanges"},delivery:"inline"})}catch($){let U=$ instanceof Error?$.message:String($);throw await E(N,"daemon","run.failed",{reason:U}),await y(N,"failed"),$}return await D(N)}async function w1(N){let H=await D(N);if(!H||!h(H.status))return!1;if(H.codexThreadId&&IN?.running)try{await IN.request("turn/interrupt",{threadId:H.codexThreadId})}catch(W){console.warn(`[runs] turn/interrupt failed for ${N}:`,W)}return YN.delete(N),await E(N,"daemon","run.stopped",{}),await y(N,"stopped"),!0}async function P1(N,H,W){let O=YN.get(N)??[],Y=O.findIndex(($)=>String($.requestId)===String(H));if(Y===-1)return!1;let[G]=O.splice(Y,1);if(O.length===0)YN.delete(N);if(G.method==="mcpServer/elicitation/request"){let $=W==="decline"||W==="cancel"?W:"accept";k().respond(G.requestId,{action:$})}else k().respond(G.requestId,{decision:W});if(await E(N,"daemon","approval.resolved",{requestId:G.requestId,decision:W}),O.length===0)await y(N,"running");return!0}function VN(){return WY.join(j(),"config.toml")}async function o(){try{return await LN.readFile(VN(),"utf8")}catch{return""}}async function x1(N){try{c(N)}catch(H){throw new B(`Invalid TOML: ${H instanceof Error?H.message:String(H)}`)}await LN.writeFile(VN(),N,"utf8")}function OY(N){if(!N.trim())return{};let W=c(N).mcp_servers;if(typeof W!=="object"||W===null)return{};return W}async function YY(){let N=new Map;try{let H=await C("mcpServerStatus/list",{detail:"full"});for(let W of H.data??[]){let O=Object.entries(W.tools??{}).map(([Y,G])=>({name:Y,description:G?.description}));N.set(W.name,{startupState:W.serverInfo?"ready":"starting",authStatus:W.authStatus??null,tools:O})}}catch(H){console.warn("[mcp] mcpServerStatus/list failed:",H)}return N}async function k1(){let N=await o(),H=OY(N),W=await YY();return{servers:Object.entries(H).map(([Y,G])=>{let $=W.get(Y);return{name:Y,command:G.command,args:G.args,envKeys:G.env?Object.keys(G.env):void 0,url:G.url,enabled:G.enabled!==!1,startupState:$?.startupState??null,authStatus:$?.authStatus??null,tools:$?.tools??[],error:$?.error}})}}var GY=/^[A-Za-z0-9_-]+$/;async function y1(N){if(!GY.test(N.name))throw new B(`Invalid server name "${N.name}" \u2014 letters, digits, _ and - only`);if(!N.command&&!N.url)throw new B("Server needs either a command or a url");let H=await o(),W=H.trim()?c(H):{},O=W.mcp_servers??{},Y={};if(N.command)Y.command=N.command;if(N.args&&N.args.length>0)Y.args=N.args;if(N.env&&Object.keys(N.env).length>0)Y.env=N.env;if(N.url)Y.url=N.url;if(N.enabled===!1)Y.enabled=!1;O[N.name]=Y,W.mcp_servers=O,await LN.writeFile(VN(),t(W),"utf8")}async function b1(N){let H=await o();if(!H.trim())return!1;let W=c(H),O=W.mcp_servers;if(!O||!(N in O))return!1;return delete O[N],await LN.writeFile(VN(),t(W),"utf8"),!0}async function q1(N,H){let W=await o(),O=c(W||""),Y=O.mcp_servers??{};if(!Y[N])throw new B(`Server not found: ${N}`);Y[N].enabled=H,O.mcp_servers=Y,await LN.writeFile(VN(),t(O),"utf8")}async function I1(){await C("config/mcpServer/reload",{})}async function j1(N,H,W,O){let Y=await o(),G=Y.trim()?c(Y):{},$=G.mcp_servers??{},U={command:process.execPath,args:[H],env:{JUN_PORT:String(W)}},Q=$[N],X=Boolean(O&&$[O]);if(Q&&!X&&Q.command===U.command&&JSON.stringify(Q.args)===JSON.stringify(U.args)&&Q.env?.JUN_PORT===String(W))return;if(O)delete $[O];$[N]=U,G.mcp_servers=$,await LN.writeFile(VN(),t(G),"utf8")}var UY="https://registry.npmjs.org/junhost/latest",QY=86400000,XY=3600000,cH=null,v1=0,lH=!1,uH=null;async function ZY(){try{let N=await fetch(UY,{signal:AbortSignal.timeout(5000)});if(!N.ok)throw Error(`registry ${N.status}`);let H=await N.json();cH=typeof H.version==="string"?H.version:null,lH=cH!==null}catch{lH=!1}finally{v1=Date.now(),uH=null}}function zY(){let N=lH?QY:XY;if(!uH&&Date.now()-v1>N)uH=ZY();return cH}function FY(N,H){let W=N.split(".").map((Y)=>parseInt(Y,10)||0),O=H.split(".").map((Y)=>parseInt(Y,10)||0);for(let Y=0;Y<Math.max(W.length,O.length);Y++){let G=W[Y]??0,$=O[Y]??0;if(G!==$)return G>$}return!1}function g1(){let N=zY();return{latestVersion:N,updateAvailable:N!==null&&FY(N,ZN)}}var LY=Date.now();function h1(){return Z({ok:!0})}function m1(){let N={ok:!0,name:"jun",version:ZN,...g1(),projectId:V,dataRoot:I,workspaceRoot:J(),uptimeSeconds:Math.round((Date.now()-LY)/1000)};return Z(N)}import VY from"path";var zH={ok:!0};async function c1(N,H){let W=H.pathname.slice(11),O=H.searchParams.get("path")??".",Y=H.searchParams.get("project")??V;switch(`${N.method} ${W}`){case"GET tree":return Z(await F0(O,Y));case"GET read":return Z(await L0(O,Y));case"GET download":{let G=sN(O,Y),$=Bun.file(G);if(!await $.exists())return z(404,`File not found: ${O}`);return new Response($,{headers:{"content-disposition":`attachment; filename="${encodeURIComponent(VY.basename(G))}"`}})}case"POST write":{let G=await L(N);return await V0(A(G.path,"path"),typeof G.content==="string"?G.content:"",Y),Z(zH)}case"POST mkdir":{let G=await L(N);return await M0(A(G.path,"path"),Y),Z(zH)}case"POST delete":{let G=await L(N);return await K0(A(G.path,"path"),Y),Z(zH)}case"POST rename":{let G=await L(N);return await A0(A(G.from,"from"),A(G.to,"to"),Y),Z(zH)}case"POST upload":{let G;try{G=await N.formData()}catch{throw new B("Expected multipart/form-data body")}let $=String(G.get("path")??"."),U=G.getAll("file").filter((X)=>X instanceof File);if(U.length===0)throw new B("No files in upload (field name: file)");let Q=[];for(let X of U)Q.push(await J0($,X.name,X,Y));return Z({ok:!0,saved:Q})}default:return z(404,`Unknown files endpoint: ${N.method} /api/files/${W}`)}}import{promises as l1}from"fs";function MY(N){return N.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,48)}async function u1(N){try{let H=await l1.readFile(CH(N),"utf8"),W=JSON.parse(H);return{id:W.id??N,name:W.name??N,createdAt:W.createdAt??new Date(0).toISOString(),workspaceRoot:J(N)}}catch{return null}}async function i1(){let N;try{N=await l1.readdir(QN(),{withFileTypes:!0})}catch{return[]}let H=[];for(let W of N){if(!W.isDirectory())continue;let O=await u1(W.name);if(O)H.push(O)}return H.sort((W,O)=>{if(W.id===V)return-1;if(O.id===V)return 1;return O.createdAt.localeCompare(W.createdAt)}),H}async function vN(N){return u1(N)}async function p1(N){let H=N.trim();if(!H)throw Error("Project name is required");let W=MY(H);if(!W)throw Error("Project name must contain letters or numbers");if(await vN(W))throw Error(`A project named "${W}" already exists`);await SH(W,H);let O=await vN(W);if(!O)throw Error(`Failed to create project "${W}"`);return O}async function MN(N){return await vN(N)!==null}async function n1(N,H){let O=H.pathname.split("/").filter(Boolean)[2];if(!O){if(N.method==="GET"){let Y={projects:await i1()};return Z(Y)}if(N.method==="POST"){let Y=await L(N);A(Y.name,"name");try{let $={project:await p1(Y.name)};return Z($,201)}catch(G){let $=G instanceof Error?G.message:String(G),U=$.includes("already exists")?409:400;return z(U,$)}}return z(405,"Method not allowed")}if(N.method==="GET"){let Y=await vN(O);return Y?Z({project:Y}):z(404,`Project not found: ${O}`)}return z(405,"Method not allowed")}var KY=new Set(["accept","acceptForSession","decline","cancel"]);async function o1(N,H,W){let O=H.pathname.split("/").filter(Boolean),Y=O[2],G=O[3];if(!Y){if(N.method==="GET"){let $=H.searchParams.get("project")??void 0,U={runs:await w0($)};return Z(U)}if(N.method==="POST"){let $=await L(N);A($.prompt,"prompt");let Q={run:await FN($)};return Z(Q,201)}return z(405,"Method not allowed")}if(G==="events"){if(!await D(Y))return z(404,`Run not found: ${Y}`);return W.upgrade(N,{data:{channel:`run:${Y}`}})?void 0:z(400,"WebSocket upgrade required")}if(!G&&N.method==="GET"){let $=await D(Y);if(!$)return z(404,`Run not found: ${Y}`);let U=Number(H.searchParams.get("tail")??NaN),Q=Number(H.searchParams.get("before")??NaN),X=await k0(Y,{limit:Number.isFinite(U)&&U>0?U:void 0,before:Number.isFinite(Q)&&Q>=0?Q:void 0}),F={run:$,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 w1(Y)?Z({ok:!0}):z(409,"Run is not active");case"resume":{let $=await L(N);A($.prompt,"prompt");try{let U=await ZH(Y,$.prompt,Array.isArray($.attachments)?$.attachments:void 0,{sandbox:$.sandbox,approvalPolicy:$.approvalPolicy,approvalsReviewer:$.approvalsReviewer,model:$.model,effort:$.effort});return Z({run:U})}catch(U){let Q=U instanceof Error?U.message:String(U),X=Q.includes("not found")?404:Q.includes("still active")?409:400;return z(X,Q)}}case"steer":{let $=await L(N);A($.prompt,"prompt");try{return await R1(Y,$.prompt,Array.isArray($.attachments)?$.attachments:void 0),Z({ok:!0})}catch(U){let Q=U instanceof Error?U.message:String(U),X=Q.includes("not found")?404:Q.includes("not active")||Q.includes("No active turn")?409:400;return z(X,Q)}}case"fast":{let $=await L(N);if(typeof $.enabled!=="boolean")return z(400,"Missing or invalid field: enabled");try{let U=await T1(Y,$.enabled);return Z({run:U})}catch(U){let Q=U instanceof Error?U.message:String(U),X=Q.includes("not found")?404:Q.includes("does not support")?400:500;return z(X,Q)}}case"compact":try{return await E1(Y),Z({ok:!0})}catch($){let U=$ instanceof Error?$.message:String($),Q=U.includes("not found")?404:U.includes("still active")?409:400;return z(Q,U)}case"review":{let $=await L(N);try{let U=await _1(Y,$.instructions);return Z({run:U})}catch(U){let Q=U instanceof Error?U.message:String(U),X=Q.includes("not found")?404:Q.includes("still active")?409:400;return z(X,Q)}}case"approve":{let $=await L(N);if(!KY.has(String($.decision)))return z(400,`Invalid decision: ${String($.decision)}`);if($.requestId===void 0||$.requestId===null)return z(400,"Missing field: requestId");return await P1(Y,$.requestId,$.decision)?Z({ok:!0}):z(404,"No matching pending approval")}default:return z(404,`Unknown runs endpoint: ${H.pathname}`)}}var GN="browser-stream",m=null,a1=null,KN=0,AN=null,pH=null;function AY(N){if(m&&a1===N&&m.readyState<=WebSocket.OPEN)return;m?.close(),a1=N;let H=new WebSocket(`ws://127.0.0.1:${N}`);m=H,H.onmessage=(W)=>{let O=String(W.data);if(O.includes('"type":"frame"'))pH=O;C0(GN,O)},H.onclose=()=>{if(m===H)m=null,pH=null,d1()},H.onerror=()=>{}}function d1(){if(AN||KN===0)return;AN=setTimeout(()=>{AN=null,gN(!0)},2000)}async function gN(N=!1){if(KN===0)return;let H=N?null:d0();if(H===null){if(N)n();H=(await xN()).streamPort}if(H!==null)AY(H);else d1()}function s1(){KN+=1,gN()}function t1(){return pH}function r1(){if(KN=Math.max(0,KN-1),KN===0){if(m?.close(),m=null,AN)clearTimeout(AN),AN=null}}var JY=new Set(["input_mouse","input_keyboard","input_touch"]);function e1(N){if(o0()!=="user")return;if(!m||m.readyState!==WebSocket.OPEN)return;let H=typeof N==="string"?N:N.toString("utf8");try{let W=JSON.parse(H);if(typeof W.type==="string"&&JY.has(W.type))m.send(H)}catch{}}var BY=new Set(["user","agent","paused"]);async function NW(N,H,W){let Y=H.pathname.split("/").filter(Boolean)[2];if(Y==="stream")return W.upgrade(N,{data:{channel:GN}})?void 0:z(400,"WebSocket upgrade required");if(N.method==="GET")switch(Y){case"status":{let G=await xN();if(G.streaming)gN();return Z({status:G})}case"actions":{let G={actions:n0()};return Z(G)}default:return z(404,`Unknown browser endpoint: ${H.pathname}`)}if(N.method!=="POST")return z(405,"Method not allowed");switch(Y){case"start":{let G=await L(N).catch(()=>({})),$=await r0(typeof G.url==="string"&&G.url.length>0?G.url:void 0);return gN(),Z({status:$})}case"stop":return await e0(),Z({ok:!0});case"navigate":{let G=await L(N);return A(G.url,"url"),await N1(G.url),Z({ok:!0})}case"key":{let G=await L(N);return A(G.key,"key"),await W1(G.key),Z({ok:!0})}case"back":case"forward":case"reload":return await H1(Y),Z({ok:!0});case"screenshot":{let $={path:await O1()};return Z($)}case"snapshot":{let G=await L(N).catch(()=>({})),$=await Y1(G.interactive??!0);return Z({snapshot:$})}case"click":{let G=await L(N);return A(G.target,"target"),await G1(G.target),Z({ok:!0})}case"fill":{let G=await L(N);return A(G.target,"target"),A(G.text,"text"),await $1(G.target,G.text),Z({ok:!0})}case"read":{let G=await L(N).catch(()=>({})),$=await U1(G.selector);return Z({text:$})}case"eval":{let G=await L(N);A(G.expression,"expression");let $=await Q1(G.expression);return Z({result:$})}case"exec":{let G=await L(N);if(!Array.isArray(G.args)||G.args.length===0)return z(400,"args must be a non-empty array of strings");let $=await X1(G.args,{json:G.json});return Z($)}case"control":{let G=await L(N);if(!BY.has(String(G.controller)))return z(400,`Invalid controller: ${String(G.controller)}`);return a0(G.controller),Z({ok:!0})}default:return z(404,`Unknown browser endpoint: ${H.pathname}`)}}import{promises as f}from"fs";import _ from"path";var OW=".agents/skills";function JN(N){return _.join(J(N),OW)}var DY=/^[a-z0-9][a-z0-9-]*$/,CY=new Set(["registry","install"]);function BN(N,H){if(!DY.test(N))throw new B(`Invalid skill id "${N}" \u2014 use lowercase letters, digits and dashes`);return _.join(JN(H),N)}function HW(N){return N.replace(/\x1b\[[0-9;?]*[A-Za-z]/g,"")}async function YW(N,H,W=120000){let O=Bun.spawn([process.execPath,"x","skills",...N],{cwd:H,env:{...process.env,DISABLE_TELEMETRY:"1",DO_NOT_TRACK:"1"},stdout:"pipe",stderr:"pipe"}),Y=setTimeout(()=>O.kill(),W);try{let[G,$,U]=await Promise.all([new Response(O.stdout).text(),new Response(O.stderr).text(),O.exited]);return{stdout:HW(G),stderr:HW($),code:U}}finally{clearTimeout(Y)}}function SY(N){let H=[],W=null;for(let O of N.split(/\r?\n/)){let Y=O.trim(),G=/^(\S+@\S+)\s+([\d.]+[KMB]?)\s+installs\b/.exec(Y);if(G){let U=G[1],Q=U.indexOf("@");W={source:U,repo:U.slice(0,Q),name:U.slice(Q+1),installs:G[2]},H.push(W);continue}let $=/^[\u2514\u2570]\s*(https?:\/\/\S+)/.exec(Y);if($&&W)W.url=$[1],W=null}return H}function RY(N){let H=[],W=/^---\r?\n([\s\S]*?)\r?\n---/.exec(N.replace(/^\uFEFF/,""));if(!W)return{errors:["Missing YAML frontmatter (--- name/description ---)"]};let O={};for(let Y of W[1].split(/\r?\n/)){let G=/^([A-Za-z_][\w-]*):\s*(.*)$/.exec(Y);if(G)O[G[1].toLowerCase()]=G[2].trim().replace(/^["']|["']$/g,"")}if(!O.name)H.push("Frontmatter is missing required field: name");if(!O.description)H.push("Frontmatter is missing required field: description");return{name:O.name,description:O.description,errors:H}}var TY=15000,oH=new Map,nH=new Map;function hN(N){oH.delete(N)}async function EY(N){let H=oH.get(N);if(H&&Date.now()-H.at<TY)return H.view;let W=nH.get(N);if(W)return W;let O=_Y(N).then((Y)=>{return oH.set(N,{at:Date.now(),view:Y}),Y}).finally(()=>{nH.delete(N)});return nH.set(N,O),O}async function _Y(N){let H=new Map,W=[];try{let O=await C("skills/list",{cwds:[J(N)],forceReload:!0});for(let Y of O.data??[]){for(let G of Y.errors??[])W.push(G);for(let G of Y.skills??[]){let $=_.basename(_.dirname(G.path));H.set($,G)}}}catch(O){console.warn("[skills] skills/list failed:",O)}return{byDir:H,errors:W}}async function FH(N=V){await f.mkdir(JN(N),{recursive:!0});let W=(await f.readdir(JN(N),{withFileTypes:!0})).filter((U)=>U.isDirectory()).map((U)=>U.name),{byDir:O,errors:Y}=await EY(N),G=[];for(let U of W){let Q=_.join(JN(N),U,"SKILL.md"),X=null;try{X=await f.readFile(Q,"utf8")}catch{G.push({id:U,name:U,description:"",enabled:!1,errors:["Missing SKILL.md"]});continue}let F=RY(X),K=O.get(U),T=Y.filter((x)=>l(x.path).includes(`/${U}/`)||_.basename(_.dirname(x.path))===U).map((x)=>x.message);G.push({id:U,name:K?.name??F.name??U,description:K?.description??F.description??"",enabled:K?.enabled??!0,errors:[...new Set([...F.errors,...T])]})}let $=Y.filter((U)=>!W.some((Q)=>l(U.path).includes(`/${Q}/`)));return{skills:G,errors:$}}async function mN(N,H=V){let W=BN(N,H),O;try{O=await f.readFile(_.join(W,"SKILL.md"),"utf8")}catch{return null}let{skills:Y}=await FH(H),G=Y.find((Q)=>Q.id===N)??{id:N,name:N,description:"",enabled:!0,errors:[]},$=[],U=async(Q)=>{let X=await f.readdir(_.join(W,Q),{withFileTypes:!0});for(let F of X){let K=Q?`${Q}/${F.name}`:F.name;if(F.isDirectory())await U(K);else if(K!=="SKILL.md")$.push(`${OW}/${N}/${K}`)}};return await U(""),{info:G,content:O,files:$}}async function GW(N,H=V){let W=N.name.trim().toLowerCase().replace(/\s+/g,"-");if(CY.has(W))throw new B(`"${W}" is a reserved name \u2014 pick another`);let O=BN(W,H);try{throw await f.access(_.join(O,"SKILL.md")),new B(`Skill "${W}" already exists`)}catch(G){if(G instanceof B)throw G}let Y=`---
|
|
330
|
+
name: ${W}
|
|
331
331
|
description: ${N.description.trim()}
|
|
332
332
|
---
|
|
333
333
|
|
|
334
334
|
${N.instructions?.trim()??"Describe when and how to use this skill."}
|
|
335
|
-
`;return await
|
|
336
|
-
`).trim();throw new B(`No skill installed from "${
|
|
337
|
-
${F}`:""}`)}let{skills:X}=await
|
|
338
|
-
`).trim()}}async function NO(N,H,O=z){let W=await hN(N,O);if(!W)throw new B(`Skill not found: ${N}`);let Y={prompt:H?.trim()||`Use the "${W.info.name}" skill to demonstrate what it does. Follow its instructions and report the result.`,projectId:O,skill:{name:W.info.name,path:E.join(JN(N,O),"SKILL.md")}};return LN(Y)}async function LY(N){let H=N.searchParams.get("project");if(H)return H;let O=N.searchParams.get("cwd");if(O){let W=uN(O);if(W&&await VN(W))return W}return z}async function HO(N,H){let O=H.pathname.split("/").filter(Boolean),W=O[2],Y=O[3],G=await LY(H);if(W==="registry"){if(Y==="search"&&N.method==="GET"){let $=H.searchParams.get("q")??"",U=await r1($);return L({results:U})}if(Y==="install"&&N.method==="POST"){let $=await M(N);A($.source,"source");let U=await e1($.source,G);return L(U,201)}return Z(404,`Unknown skills endpoint: ${H.pathname}`)}if(!W){if(N.method==="GET")return L(await XH(G));if(N.method==="POST"){let $=await M(N);A($.name,"name"),A($.description,"description");let U=await o1($,G);return L({skill:U},201)}return Z(405,"Method not allowed")}if(!Y)switch(N.method){case"GET":{let $=await hN(W,G);return $?L({skill:$}):Z(404,`Skill not found: ${W}`)}case"PUT":{let $=await M(N);A($.content,"content");let U=await d1(W,$.content,G);return L({skill:U})}case"DELETE":return await s1(W,G)?L({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(Y){case"enable":{let $=await M(N);if(typeof $.enabled!=="boolean")return Z(400,"Missing or invalid field: enabled");return await t1(W,$.enabled,G),L({ok:!0})}case"test":{let $=await M(N).catch(()=>({})),U=await NO(W,$.prompt,G);return L({run:U},201)}default:return Z(404,`Unknown skills endpoint: ${H.pathname}`)}}async function OO(N,H){let O=H.pathname.split("/").filter(Boolean),W=O[2];if(!W){if(N.method==="GET")return L(await S1());return Z(405,"Method not allowed")}if(W==="config"){if(N.method==="GET"){let Y={toml:await p()};return L(Y)}if(N.method==="PUT"){let Y=await M(N);return A(Y.toml,"toml"),await C1(Y.toml),L({ok:!0})}return Z(405,"Method not allowed")}if(W==="reload"&&N.method==="POST")return await _1(),L({ok:!0});if(W==="servers"){let Y=O[3];if(!Y){if(N.method==="POST"){let $=await M(N);return A($.name,"name"),await R1($),L({ok:!0},201)}return Z(405,"Method not allowed")}let G=O[4];if(G==="enable"&&N.method==="POST"){let $=await M(N);if(typeof $.enabled!=="boolean")return Z(400,"Missing or invalid field: enabled");return await E1(Y,$.enabled),L({ok:!0})}if(!G&&N.method==="DELETE")return await T1(Y)?L({ok:!0}):Z(404,`Server not found: ${Y}`);return Z(405,"Method not allowed")}return Z(404,`Unknown MCP endpoint: ${H.pathname}`)}import{promises as GN}from"fs";import mN from"path";function FY(){return mN.join(q(),"config.toml")}function LH(){return mN.join(q(),"memories")}async function WO(){let N=await p();return N.trim()?c(N):{}}function ZH(N){return typeof N==="object"&&N!==null?N:{}}function zY(N){let H=ZH(N.memories),O={};if(typeof H.generate_memories==="boolean")O.generateMemories=H.generate_memories;if(typeof H.use_memories==="boolean")O.useMemories=H.use_memories;if(typeof H.disable_on_external_context==="boolean")O.disableOnExternalContext=H.disable_on_external_context;if(typeof H.min_rate_limit_remaining_percent==="number")O.minRateLimitRemainingPercent=H.min_rate_limit_remaining_percent;return O}async function VY(){let N=LH(),H=[];async function O(W){let Y;try{Y=await GN.readdir(W,{withFileTypes:!0})}catch{return}for(let G of Y){let $=mN.join(W,G.name);if(G.isDirectory()){if(G.name===".git")continue;await O($)}else if(G.isFile()){let U=await GN.stat($);H.push({path:l(mN.relative(N,$)),name:G.name,size:U.size,modifiedAt:U.mtime.toISOString()})}}}return await O(N),H.sort((W,Y)=>Y.modifiedAt.localeCompare(W.modifiedAt)),H}async function MY(){try{let H=((await C("experimentalFeature/list",{})).data??[]).find((O)=>O.name==="memories");return H?H.enabled:null}catch(N){return console.warn("[memories] experimentalFeature/list failed:",N),null}}async function YO(){let N=await WO();return{enabled:ZH(N.features).memories===!0,liveEnabled:await MY(),settings:zY(N),files:await VY()}}async function GO(N){let H=await WO();if(typeof N.enabled==="boolean"){let O=ZH(H.features);O.memories=N.enabled,H.features=O}if(N.settings){let O=ZH(H.memories),W=N.settings;if(typeof W.generateMemories==="boolean")O.generate_memories=W.generateMemories;if(typeof W.useMemories==="boolean")O.use_memories=W.useMemories;if(typeof W.disableOnExternalContext==="boolean")O.disable_on_external_context=W.disableOnExternalContext;if(typeof W.minRateLimitRemainingPercent==="number")O.min_rate_limit_remaining_percent=W.minRateLimitRemainingPercent;H.memories=O}if(await GN.writeFile(FY(),d(H),"utf8"),typeof N.enabled==="boolean")try{await C("experimentalFeature/enablement/set",{enablement:{memories:N.enabled}})}catch(O){console.warn("[memories] live enablement/set failed (applies on restart):",O)}}async function $O(N){let H=e(LH(),N);return GN.readFile(H,"utf8")}async function UO(N,H){let O=e(LH(),N);await GN.mkdir(mN.dirname(O),{recursive:!0}),await GN.writeFile(O,H,"utf8")}async function QO(N){let H=e(LH(),N);await GN.rm(H)}async function XO(N,H){let W=H.pathname.split("/").filter(Boolean)[2];if(!W){if(N.method==="GET")return L(await YO());return Z(405,"Method not allowed")}if(W==="config"){if(N.method==="PUT"){let Y=await M(N);if(typeof Y.enabled!=="boolean"&&!Y.settings)return Z(400,"Nothing to update: pass enabled and/or settings");return await GO(Y),L({ok:!0})}return Z(405,"Method not allowed")}if(W==="file"){if(N.method==="GET"){let Y=A(H.searchParams.get("path"),"path"),G={path:Y,content:await $O(Y)};return L(G)}if(N.method==="PUT"){let Y=await M(N);if(A(Y.path,"path"),typeof Y.content!=="string")return Z(400,"Missing or invalid field: content");return await UO(Y.path,Y.content),L({ok:!0})}if(N.method==="DELETE"){let Y=A(H.searchParams.get("path"),"path");return await QO(Y),L({ok:!0})}return Z(405,"Method not allowed")}return Z(404,`Unknown memories endpoint: ${H.pathname}`)}var AY=300000,FH=null;async function ZO(N){if(N.method!=="GET")return Z(405,"Method not allowed");if(FH&&Date.now()-FH.at<AY)return L({models:FH.models});let O=((await C("model/list",{})).data??[]).filter((Y)=>!Y.hidden).map((Y)=>({id:Y.id,model:Y.model,displayName:Y.displayName,description:Y.description,isDefault:Y.isDefault,defaultReasoningEffort:Y.defaultReasoningEffort,supportedReasoningEfforts:Y.supportedReasoningEfforts??[]}));return FH={at:Date.now(),models:O},L({models:O})}async function zH(){let N=await C("account/read",{});return{account:N.account??null,requiresOpenaiAuth:N.requiresOpenaiAuth,pendingLogin:YH(),lastLoginResult:Y1()}}async function LO(N,H){if(H.pathname==="/api/account"){if(N.method!=="GET")return Z(405,"Method not allowed");return L(await zH())}if(H.pathname==="/api/account/login"&&N.method==="POST"){let O=await M(N),W;if(O.type==="chatgpt"||O.type==="chatgptDeviceCode")W={type:O.type};else if(O.type==="apiKey")W={type:"apiKey",apiKey:A(O.apiKey,"apiKey")};else throw new B("type must be one of: chatgpt, chatgptDeviceCode, apiKey");let Y=YH();if(Y)await C("account/login/cancel",{loginId:Y.loginId}).catch(()=>{});GH();let G=await C("account/login/start",W);if((G.type==="chatgpt"||G.type==="chatgptDeviceCode")&&G.loginId){let $={loginId:G.loginId,type:G.type,authUrl:G.authUrl,userCode:G.userCode,verificationUrl:G.verificationUrl,startedAt:new Date().toISOString()};G1($)}return L(await zH())}if(H.pathname==="/api/account/login/cancel"&&N.method==="POST"){let O=YH();if(O)await C("account/login/cancel",{loginId:O.loginId}).catch(()=>{});return GH(),L(await zH())}if(H.pathname==="/api/account/logout"&&N.method==="POST")return await C("account/logout",{}),GH(),L(await zH());return Z(404,`Not found: ${H.pathname}`)}function JY(N){if(!N)return null;return N.replace(/^([a-z0-9+.-]+:\/\/[^:@/]+):[^@/]+@/i,"$1:\u2022\u2022\u2022\u2022@")}function FO(){let N=kH(),H=yH();return{browserProxy:{proxyUrl:JY(N.value),source:N.source,noProxy:H.value,noProxySource:H.source}}}async function zO(N,H){if(H.pathname==="/api/settings"&&N.method==="GET")return L(FO());if(H.pathname==="/api/settings/browser-proxy"&&N.method==="PUT"){let O=await M(N);if(O.proxyUrl!==void 0&&O.proxyUrl!==null&&O.proxyUrl.trim())try{if(!new URL(O.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 y0({...O.proxyUrl!==void 0?{browserProxy:O.proxyUrl}:{},...O.noProxy!==void 0?{browserNoProxy:O.noProxy}:{}}),L(FO())}if(N.method!=="GET"&&N.method!=="PUT")return Z(405,"Method not allowed");return Z(404,`Unknown settings endpoint: ${H.pathname}`)}import{promises as BN}from"fs";import DO from"path";import{randomUUID as EY}from"crypto";function cN(N,H,O,W){let Y=new Set,G=N.trim()!=="*";for(let $ of N.split(",")){let U=$.trim();if(!U)throw Error(`Invalid ${W} field: empty term`);let Q=U,X=1,F=U.indexOf("/");if(F!==-1){if(Q=U.slice(0,F),X=Number(U.slice(F+1)),!Number.isInteger(X)||X<=0)throw Error(`Invalid step in ${W}: ${U}`)}let K,R;if(Q==="*")K=H,R=O;else if(Q.includes("-")){let[f,$N]=Q.split("-");K=Number(f),R=Number($N)}else K=Number(Q),R=K;if(!Number.isInteger(K)||!Number.isInteger(R))throw Error(`Invalid ${W} value: ${U}`);if(K<H||R>O||K>R)throw Error(`${W} out of range (${H}-${O}): ${U}`);for(let f=K;f<=R;f+=X)Y.add(f)}return{set:Y,restricted:G}}function KO(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 O=cN(H[0],0,59,"minute"),W=cN(H[1],0,23,"hour"),Y=cN(H[2],1,31,"day-of-month"),G=cN(H[3],1,12,"month"),$=cN(H[4],0,7,"day-of-week"),U=new Set;for(let Q of $.set)U.add(Q===7?0:Q);return{minute:O.set,hour:W.set,dom:Y.set,month:G.set,dow:U,domRestricted:Y.restricted,dowRestricted:$.restricted}}function AO(N){try{return KO(N),null}catch(H){return H instanceof Error?H.message:"Invalid cron expression"}}function BY(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 JO(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 O={};for(let W of BY(H).formatToParts(N))if(W.type!=="literal")O[W.type]=Number(W.value);return{year:O.year,month:O.month,day:O.day,hour:O.hour,minute:O.minute,second:O.second}}function DY(N,H){return new Date(Date.UTC(N,H,0)).getUTCDate()}function CY(N){return new Date(Date.UTC(N.year,N.month-1,N.day)).getUTCDay()}function VO(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<=DY(N.year,N.month))return;if(N.day=1,N.month++,N.month<=12)return;N.month=1,N.year++}function SY(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 O=N.dom.has(H.day),W=N.dow.has(CY(H));if(N.domRestricted&&N.dowRestricted)return O||W;if(N.domRestricted)return O;if(N.dowRestricted)return W;return!0}function MO(N,H){let O=JO(N,H);return Date.UTC(O.year,O.month-1,O.day,O.hour,O.minute,O.second)-N.getTime()}function RY(N,H){if(!H)return new Date(N.year,N.month-1,N.day,N.hour,N.minute,0,0);let O=Date.UTC(N.year,N.month-1,N.day,N.hour,N.minute,0),W=MO(new Date(O),H),Y=O-W,G=MO(new Date(Y),H);if(G!==W)Y=O-G;return new Date(Y)}var TY=4216320;function BO(N,H,O){let W=KO(N),Y=JO(H,O),G={year:Y.year,month:Y.month,day:Y.day,hour:Y.hour,minute:Y.minute};VO(G);for(let $=0;$<TY;$++){if(SY(W,G))return RY(G,O);VO(G)}return null}var _Y={sandbox:"workspaceWrite",approvalPolicy:"onRequest",approvalsReviewer:"auto_review",effort:"medium"};function wY(N){return N.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}function pH(N){return DO.join(DN(),`${N}.json`)}async function CO(){await BN.mkdir(DN(),{recursive:!0})}async function nH(N){await CO(),await BN.writeFile(pH(N.id),JSON.stringify(N,null,2),"utf8")}function aH(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 O=BO(N.cron,H,N.tz);return O?O.toISOString():null}function SO(N,H){if(H==="cron"){if(!N.cron)throw Error("cron expression is required for a cron schedule");let O=AO(N.cron);if(O)throw Error(`Invalid cron expression: ${O}`)}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 oH(N){await CO();let H;try{H=await BN.readdir(DN())}catch{return[]}let O=[];for(let W of H){if(!W.endsWith(".json"))continue;try{let Y=await BN.readFile(DO.join(DN(),W),"utf8"),G=JSON.parse(Y);if(N&&G.projectId!==N)continue;O.push(G)}catch{}}return O.sort((W,Y)=>Y.createdAt.localeCompare(W.createdAt)),O}async function VH(N){try{let H=await BN.readFile(pH(N),"utf8");return JSON.parse(H)}catch{return null}}async function RO(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 O=N.projectId??"default";if(!await VN(O))throw Error(`Unknown project: ${O}`);let W=N.kind??"cron";SO(N,W);let Y=`${wY(H)||"schedule"}-${EY().slice(0,8)}`,G=new Date,$={id:Y,name:H,projectId:O,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:{..._Y,...N.mode??{}},resume:N.resume??!1,threadRunId:null,enabled:N.enabled??!0,createdAt:G.toISOString(),lastRunAt:null,lastRunId:null,lastError:null,nextRunAt:null};return $.nextRunAt=aH($,G),await nH($),$}async function TO(N,H){let O=await VH(N);if(!O)return null;let W=H.kind??O.kind,Y={...O,name:H.name?.trim()||O.name,prompt:H.prompt??O.prompt,kind:W,cron:W==="cron"?H.cron??O.cron:void 0,runAt:W==="once"?H.runAt?new Date(H.runAt).toISOString():O.runAt:void 0,tz:H.tz!==void 0?H.tz||void 0:O.tz,mode:H.mode?{...O.mode,...H.mode}:O.mode,resume:H.resume??O.resume,enabled:H.enabled??O.enabled};if(SO(Y,W),W==="once"&&H.runAt&&Y.runAt!==O.runAt)Y.lastRunAt=null;return Y.nextRunAt=aH(Y,new Date),await nH(Y),Y}async function EO(N){try{return await BN.unlink(pH(N)),!0}catch{return!1}}function PY(N){return{sandbox:N.sandbox,approvalPolicy:N.approvalPolicy,approvalsReviewer:N.approvalsReviewer,model:N.model,effort:N.effort}}async function dH(N,H){let O=N.lastRunId??null,W=null,Y=N.threadRunId??null;try{let $=N.mode;if(N.resume&&Y&&await D(Y)){let U=await D(Y);if(U&&g(U.status))throw Error("previous run still active \u2014 skipped this fire");O=(await UH(Y,N.prompt,[],PY($))).id}else{let U=await LN({prompt:N.prompt,projectId:N.projectId,sandbox:$.sandbox,approvalPolicy:$.approvalPolicy,approvalsReviewer:$.approvalsReviewer,model:$.model,effort:$.effort,source:"schedule",scheduleId:N.id,scheduleName:N.name});if(O=U.id,N.resume)Y=U.id}}catch($){W=$ instanceof Error?$.message:String($)}let G={...N,lastRunAt:H.toISOString(),lastRunId:O,lastError:W,threadRunId:Y};return G.nextRunAt=aH(G,H),await nH(G),G}var iH=!1;async function _O(N=new Date){if(iH)return;iH=!0;try{let H=await oH();for(let O of H){if(!O.enabled||!O.nextRunAt)continue;let W=new Date(O.nextRunAt);if(Number.isNaN(W.getTime())||W.getTime()>N.getTime())continue;try{await dH(O,N)}catch(Y){console.error(`[schedules] fire failed for ${O.id}:`,Y)}}}catch(H){console.error("[schedules] tick failed:",H)}finally{iH=!1}}async function wO(N){let H=N.searchParams.get("project");if(H)return H;let O=N.searchParams.get("cwd");if(O){let W=uN(O);if(W&&await VN(W))return W;return z}return}async function PO(N,H){let O=H.pathname.split("/").filter(Boolean),W=O[2],Y=O[3];if(!W){if(N.method==="GET"){let G=await wO(H),$={schedules:await oH(G)};return L($)}if(N.method==="POST"){let G=await M(N);if(!G.projectId){let $=await wO(H);if($)G.projectId=$}try{let U={schedule:await RO(G)};return L(U,201)}catch($){return Z(400,$ instanceof Error?$.message:String($))}}return Z(405,"Method not allowed")}if(Y==="run"&&N.method==="POST"){let G=await VH(W);if(!G)return Z(404,`Schedule not found: ${W}`);let U={schedule:await dH(G,new Date)};return L(U)}if(Y)return Z(404,`Not found: ${H.pathname}`);if(N.method==="GET"){let G=await VH(W);return G?L({schedule:G}):Z(404,`Schedule not found: ${W}`)}if(N.method==="PUT"){let G=await M(N);try{let $=await TO(W,G);return $?L({schedule:$}):Z(404,`Schedule not found: ${W}`)}catch($){return Z(400,$ instanceof Error?$.message:String($))}}if(N.method==="DELETE")return await EO(W)?L({ok:!0}):Z(404,`Schedule not found: ${W}`);return Z(405,"Method not allowed")}async function fO(N,H){let O=new URL(N.url);try{if(O.pathname==="/api/health")return P1();if(O.pathname==="/api/status")return f1();if(O.pathname==="/api/files/watch")return H.upgrade(N,{data:{channel:"files"}})?void 0:Z(400,"WebSocket upgrade required");if(O.pathname.startsWith("/api/files/"))return await x1(N,O);if(O.pathname==="/api/projects"||O.pathname.startsWith("/api/projects/"))return await I1(N,O);if(O.pathname==="/api/runs"||O.pathname.startsWith("/api/runs/"))return await j1(N,O,H);if(O.pathname.startsWith("/api/browser/"))return await u1(N,O,H);if(O.pathname==="/api/skills"||O.pathname.startsWith("/api/skills/"))return await HO(N,O);if(O.pathname==="/api/mcp"||O.pathname.startsWith("/api/mcp/"))return await OO(N,O);if(O.pathname==="/api/memories"||O.pathname.startsWith("/api/memories/"))return await XO(N,O);if(O.pathname==="/api/models")return await ZO(N);if(O.pathname==="/api/account"||O.pathname.startsWith("/api/account/"))return await LO(N,O);if(O.pathname==="/api/settings"||O.pathname.startsWith("/api/settings/"))return await zO(N,O);if(O.pathname==="/api/schedules"||O.pathname.startsWith("/api/schedules/"))return await PO(N,O);return Z(404,`Not found: ${O.pathname}`)}catch(W){if(W instanceof oN)return Z(400,W.message);if(W instanceof B)return Z(400,W.message);if(xY(W))return Z(404,`Not found: ${O.searchParams.get("path")??O.pathname}`);return console.error(`[api] ${N.method} ${O.pathname} failed:`,W),Z(500,W instanceof Error?W.message:"Internal error")}}function xY(N){return typeof N==="object"&&N!==null&&"code"in N&&N.code==="ENOENT"}await eH();var MH=[k.resolve(import.meta.dir,"../ui-dist"),k.resolve(import.meta.dir,"../../ui/dist")].find((N)=>xO(k.join(N,"index.html")))??k.resolve(import.meta.dir,"../../ui/dist");try{let N=["mcp-server.ts","mcp-server.js"].map((H)=>k.join(import.meta.dir,H)).find((H)=>xO(H));if(N)await w1(N,lN);else console.warn("[daemon] mcp-server script not found next to daemon entry")}catch(N){console.warn("[daemon] could not register Jun MCP server:",N)}l0(k.join(import.meta.dir,".."));var yO=Bun.serve({hostname:AH,port:lN,async fetch(N,H){let O=new URL(N.url);if(O.pathname.startsWith("/api/"))return fO(N,H);let W=await bY(O.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===YN){h1();let H=m1();if(H)N.send(H)}},message(N,H){if(N.data.channel===YN)l1(H)},close(N){if(N.unsubscribe(N.data.channel),N.data.channel===YN)c1()}}});K0(yO);try{kY(UN(),{recursive:!0},(N,H)=>{let O={type:"fs.changed",path:H?l(String(H)):null,ts:new Date().toISOString()};yO.publish("files",JSON.stringify(O))})}catch(N){console.warn("[daemon] workspace watcher unavailable:",N)}var yY=30000;setInterval(()=>{_O()},yY);console.log(`Jun daemon running at http://${AH}:${lN}`);console.log(`Workspace: ${k.resolve(J())}`);async function bY(N){let H=k.join(MH,"index.html");if(!await qY(H))return null;let O=k.normalize(decodeURIComponent(N)).replace(/^[/\\]+/,""),W=k.resolve(MH,O||"index.html"),Y=`${MH}${k.sep}`;if(W!==MH&&!W.startsWith(Y))return new Response("Not found",{status:404});if(await IY(W))return new Response(Bun.file(W),{headers:{"content-type":jY(W)}});return new Response(Bun.file(H),{headers:{"content-type":"text/html; charset=utf-8"}})}async function qY(N){try{return await kO(N),!0}catch{return!1}}async function IY(N){try{return(await kO(N)).isFile()}catch{return!1}}function jY(N){switch(k.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"}}
|
|
335
|
+
`;return await f.mkdir(O,{recursive:!0}),await f.writeFile(_.join(O,"SKILL.md"),Y,"utf8"),hN(H),await mN(W,H)}async function $W(N,H,W=V){let O=BN(N,W);try{await f.access(O)}catch{throw new B(`Skill not found: ${N}`)}return await f.writeFile(_.join(O,"SKILL.md"),H,"utf8"),hN(W),await mN(N,W)}async function UW(N,H=V){let W=BN(N,H);try{return await f.rm(W,{recursive:!0,force:!1}),hN(H),!0}catch{return!1}}async function QW(N,H,W=V){let O=_.join(BN(N,W),"SKILL.md");await C("skills/config/write",{path:O,enabled:H,name:null}),hN(W)}async function XW(N){let H=N.trim();if(!H)return[];let{stdout:W}=await YW(["find",H],J(V),30000);return SY(W)}async function WW(N){await f.mkdir(JN(N),{recursive:!0});let H=await f.readdir(JN(N),{withFileTypes:!0});return new Set(H.filter((W)=>W.isDirectory()).map((W)=>W.name))}async function ZW(N,H=V){let W=N.trim();if(!W)throw new B("Missing skill source");if(/[\s;&|`$(){}<>]/.test(W))throw new B("Invalid source \u2014 expected owner/repo[@skill] or a URL");let O=J(H),Y=await WW(H),{stdout:G,stderr:$}=await YW(["add",W,"-a","codex","--copy","-y"],O);hN(H);let Q=[...await WW(H)].filter((F)=>!Y.has(F));if(Q.length===0){let F=[G,$].filter(Boolean).join(`
|
|
336
|
+
`).trim();throw new B(`No skill installed from "${W}".${F?`
|
|
337
|
+
${F}`:""}`)}let{skills:X}=await FH(H);return{installed:Q,skills:X,log:[G,$].filter(Boolean).join(`
|
|
338
|
+
`).trim()}}async function zW(N,H,W=V){let O=await mN(N,W);if(!O)throw new B(`Skill not found: ${N}`);let Y={prompt:H?.trim()||`Use the "${O.info.name}" skill to demonstrate what it does. Follow its instructions and report the result.`,projectId:W,skill:{name:O.info.name,path:_.join(BN(N,W),"SKILL.md")}};return FN(Y)}async function PY(N){let H=N.searchParams.get("project");if(H)return H;let W=N.searchParams.get("cwd");if(W){let O=iN(W);if(O&&await MN(O))return O}return V}async function FW(N,H){let W=H.pathname.split("/").filter(Boolean),O=W[2],Y=W[3],G=await PY(H);if(O==="registry"){if(Y==="search"&&N.method==="GET"){let $=H.searchParams.get("q")??"",U=await XW($);return Z({results:U})}if(Y==="install"&&N.method==="POST"){let $=await L(N);A($.source,"source");let U=await ZW($.source,G);return Z(U,201)}return z(404,`Unknown skills endpoint: ${H.pathname}`)}if(!O){if(N.method==="GET")return Z(await FH(G));if(N.method==="POST"){let $=await L(N);A($.name,"name"),A($.description,"description");let U=await GW($,G);return Z({skill:U},201)}return z(405,"Method not allowed")}if(!Y)switch(N.method){case"GET":{let $=await mN(O,G);return $?Z({skill:$}):z(404,`Skill not found: ${O}`)}case"PUT":{let $=await L(N);A($.content,"content");let U=await $W(O,$.content,G);return Z({skill:U})}case"DELETE":return await UW(O,G)?Z({ok:!0}):z(404,`Skill not found: ${O}`);default:return z(405,"Method not allowed")}if(N.method!=="POST")return z(405,"Method not allowed");switch(Y){case"enable":{let $=await L(N);if(typeof $.enabled!=="boolean")return z(400,"Missing or invalid field: enabled");return await QW(O,$.enabled,G),Z({ok:!0})}case"test":{let $=await L(N).catch(()=>({})),U=await zW(O,$.prompt,G);return Z({run:U},201)}default:return z(404,`Unknown skills endpoint: ${H.pathname}`)}}async function LW(N,H){let W=H.pathname.split("/").filter(Boolean),O=W[2];if(!O){if(N.method==="GET")return Z(await k1());return z(405,"Method not allowed")}if(O==="config"){if(N.method==="GET"){let Y={toml:await o()};return Z(Y)}if(N.method==="PUT"){let Y=await L(N);return A(Y.toml,"toml"),await x1(Y.toml),Z({ok:!0})}return z(405,"Method not allowed")}if(O==="reload"&&N.method==="POST")return await I1(),Z({ok:!0});if(O==="servers"){let Y=W[3];if(!Y){if(N.method==="POST"){let $=await L(N);return A($.name,"name"),await y1($),Z({ok:!0},201)}return z(405,"Method not allowed")}let G=W[4];if(G==="enable"&&N.method==="POST"){let $=await L(N);if(typeof $.enabled!=="boolean")return z(400,"Missing or invalid field: enabled");return await q1(Y,$.enabled),Z({ok:!0})}if(!G&&N.method==="DELETE")return await b1(Y)?Z({ok:!0}):z(404,`Server not found: ${Y}`);return z(405,"Method not allowed")}return z(404,`Unknown MCP endpoint: ${H.pathname}`)}import{promises as $N}from"fs";import cN from"path";function fY(){return cN.join(j(),"config.toml")}function VH(){return cN.join(j(),"memories")}async function VW(){let N=await o();return N.trim()?c(N):{}}function LH(N){return typeof N==="object"&&N!==null?N:{}}function xY(N){let H=LH(N.memories),W={};if(typeof H.generate_memories==="boolean")W.generateMemories=H.generate_memories;if(typeof H.use_memories==="boolean")W.useMemories=H.use_memories;if(typeof H.disable_on_external_context==="boolean")W.disableOnExternalContext=H.disable_on_external_context;if(typeof H.min_rate_limit_remaining_percent==="number")W.minRateLimitRemainingPercent=H.min_rate_limit_remaining_percent;return W}async function kY(){let N=VH(),H=[];async function W(O){let Y;try{Y=await $N.readdir(O,{withFileTypes:!0})}catch{return}for(let G of Y){let $=cN.join(O,G.name);if(G.isDirectory()){if(G.name===".git")continue;await W($)}else if(G.isFile()){let U=await $N.stat($);H.push({path:l(cN.relative(N,$)),name:G.name,size:U.size,modifiedAt:U.mtime.toISOString()})}}}return await W(N),H.sort((O,Y)=>Y.modifiedAt.localeCompare(O.modifiedAt)),H}async function yY(){try{let H=((await C("experimentalFeature/list",{})).data??[]).find((W)=>W.name==="memories");return H?H.enabled:null}catch(N){return console.warn("[memories] experimentalFeature/list failed:",N),null}}async function MW(){let N=await VW();return{enabled:LH(N.features).memories===!0,liveEnabled:await yY(),settings:xY(N),files:await kY()}}async function KW(N){let H=await VW();if(typeof N.enabled==="boolean"){let W=LH(H.features);W.memories=N.enabled,H.features=W}if(N.settings){let W=LH(H.memories),O=N.settings;if(typeof O.generateMemories==="boolean")W.generate_memories=O.generateMemories;if(typeof O.useMemories==="boolean")W.use_memories=O.useMemories;if(typeof O.disableOnExternalContext==="boolean")W.disable_on_external_context=O.disableOnExternalContext;if(typeof O.minRateLimitRemainingPercent==="number")W.min_rate_limit_remaining_percent=O.minRateLimitRemainingPercent;H.memories=W}if(await $N.writeFile(fY(),t(H),"utf8"),typeof N.enabled==="boolean")try{await C("experimentalFeature/enablement/set",{enablement:{memories:N.enabled}})}catch(W){console.warn("[memories] live enablement/set failed (applies on restart):",W)}}async function AW(N){let H=HN(VH(),N);return $N.readFile(H,"utf8")}async function JW(N,H){let W=HN(VH(),N);await $N.mkdir(cN.dirname(W),{recursive:!0}),await $N.writeFile(W,H,"utf8")}async function BW(N){let H=HN(VH(),N);await $N.rm(H)}async function DW(N,H){let O=H.pathname.split("/").filter(Boolean)[2];if(!O){if(N.method==="GET")return Z(await MW());return z(405,"Method not allowed")}if(O==="config"){if(N.method==="PUT"){let Y=await L(N);if(typeof Y.enabled!=="boolean"&&!Y.settings)return z(400,"Nothing to update: pass enabled and/or settings");return await KW(Y),Z({ok:!0})}return z(405,"Method not allowed")}if(O==="file"){if(N.method==="GET"){let Y=A(H.searchParams.get("path"),"path"),G={path:Y,content:await AW(Y)};return Z(G)}if(N.method==="PUT"){let Y=await L(N);if(A(Y.path,"path"),typeof Y.content!=="string")return z(400,"Missing or invalid field: content");return await JW(Y.path,Y.content),Z({ok:!0})}if(N.method==="DELETE"){let Y=A(H.searchParams.get("path"),"path");return await BW(Y),Z({ok:!0})}return z(405,"Method not allowed")}return z(404,`Unknown memories endpoint: ${H.pathname}`)}var qY=300000,MH=null;async function CW(N){if(N.method!=="GET")return z(405,"Method not allowed");if(MH&&Date.now()-MH.at<qY)return Z({models:MH.models});let W=((await C("model/list",{})).data??[]).filter((Y)=>!Y.hidden).map((Y)=>({id:Y.id,model:Y.model,displayName:Y.displayName,description:Y.description,isDefault:Y.isDefault,defaultReasoningEffort:Y.defaultReasoningEffort,supportedReasoningEfforts:Y.supportedReasoningEfforts??[]}));return MH={at:Date.now(),models:W},Z({models:W})}async function KH(){let N=await C("account/read",{});return{account:N.account??null,requiresOpenaiAuth:N.requiresOpenaiAuth,pendingLogin:UH(),lastLoginResult:L1()}}async function SW(N,H){if(H.pathname==="/api/account"){if(N.method!=="GET")return z(405,"Method not allowed");return Z(await KH())}if(H.pathname==="/api/account/login"&&N.method==="POST"){let W=await L(N),O;if(W.type==="chatgpt"||W.type==="chatgptDeviceCode")O={type:W.type};else if(W.type==="apiKey")O={type:"apiKey",apiKey:A(W.apiKey,"apiKey")};else throw new B("type must be one of: chatgpt, chatgptDeviceCode, apiKey");let Y=UH();if(Y)await C("account/login/cancel",{loginId:Y.loginId}).catch(()=>{});QH();let G=await C("account/login/start",O);if((G.type==="chatgpt"||G.type==="chatgptDeviceCode")&&G.loginId){let $={loginId:G.loginId,type:G.type,authUrl:G.authUrl,userCode:G.userCode,verificationUrl:G.verificationUrl,startedAt:new Date().toISOString()};V1($)}return Z(await KH())}if(H.pathname==="/api/account/login/cancel"&&N.method==="POST"){let W=UH();if(W)await C("account/login/cancel",{loginId:W.loginId}).catch(()=>{});return QH(),Z(await KH())}if(H.pathname==="/api/account/logout"&&N.method==="POST")return await C("account/logout",{}),QH(),Z(await KH());return z(404,`Not found: ${H.pathname}`)}function IY(N){if(!N)return null;return N.replace(/^([a-z0-9+.-]+:\/\/[^:@/]+):[^@/]+@/i,"$1:\u2022\u2022\u2022\u2022@")}function RW(){let N=YH(),H=GH();return{browserProxy:{proxyUrl:IY(N.value),source:N.source,noProxy:H.value,noProxySource:H.source}}}async function TW(N,H){if(H.pathname==="/api/settings"&&N.method==="GET")return Z(RW());if(H.pathname==="/api/settings/browser-proxy"&&N.method==="PUT"){let W=await L(N);if(W.proxyUrl!==void 0&&W.proxyUrl!==null&&W.proxyUrl.trim())try{if(!new URL(W.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 j0({...W.proxyUrl!==void 0?{browserProxy:W.proxyUrl}:{},...W.noProxy!==void 0?{browserNoProxy:W.noProxy}:{}}),Z(RW())}if(N.method!=="GET"&&N.method!=="PUT")return z(405,"Method not allowed");return z(404,`Unknown settings endpoint: ${H.pathname}`)}import{promises as DN}from"fs";import kW from"path";import{randomUUID as lY}from"crypto";function lN(N,H,W,O){let Y=new Set,G=N.trim()!=="*";for(let $ of N.split(",")){let U=$.trim();if(!U)throw Error(`Invalid ${O} field: empty term`);let Q=U,X=1,F=U.indexOf("/");if(F!==-1){if(Q=U.slice(0,F),X=Number(U.slice(F+1)),!Number.isInteger(X)||X<=0)throw Error(`Invalid step in ${O}: ${U}`)}let K,T;if(Q==="*")K=H,T=W;else if(Q.includes("-")){let[x,UN]=Q.split("-");K=Number(x),T=Number(UN)}else K=Number(Q),T=K;if(!Number.isInteger(K)||!Number.isInteger(T))throw Error(`Invalid ${O} value: ${U}`);if(K<H||T>W||K>T)throw Error(`${O} out of range (${H}-${W}): ${U}`);for(let x=K;x<=T;x+=X)Y.add(x)}return{set:Y,restricted:G}}function wW(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 W=lN(H[0],0,59,"minute"),O=lN(H[1],0,23,"hour"),Y=lN(H[2],1,31,"day-of-month"),G=lN(H[3],1,12,"month"),$=lN(H[4],0,7,"day-of-week"),U=new Set;for(let Q of $.set)U.add(Q===7?0:Q);return{minute:W.set,hour:O.set,dom:Y.set,month:G.set,dow:U,domRestricted:Y.restricted,dowRestricted:$.restricted}}function PW(N){try{return wW(N),null}catch(H){return H instanceof Error?H.message:"Invalid cron expression"}}function jY(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 fW(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 W={};for(let O of jY(H).formatToParts(N))if(O.type!=="literal")W[O.type]=Number(O.value);return{year:W.year,month:W.month,day:W.day,hour:W.hour,minute:W.minute,second:W.second}}function vY(N,H){return new Date(Date.UTC(N,H,0)).getUTCDate()}function gY(N){return new Date(Date.UTC(N.year,N.month-1,N.day)).getUTCDay()}function EW(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<=vY(N.year,N.month))return;if(N.day=1,N.month++,N.month<=12)return;N.month=1,N.year++}function hY(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 W=N.dom.has(H.day),O=N.dow.has(gY(H));if(N.domRestricted&&N.dowRestricted)return W||O;if(N.domRestricted)return W;if(N.dowRestricted)return O;return!0}function _W(N,H){let W=fW(N,H);return Date.UTC(W.year,W.month-1,W.day,W.hour,W.minute,W.second)-N.getTime()}function mY(N,H){if(!H)return new Date(N.year,N.month-1,N.day,N.hour,N.minute,0,0);let W=Date.UTC(N.year,N.month-1,N.day,N.hour,N.minute,0),O=_W(new Date(W),H),Y=W-O,G=_W(new Date(Y),H);if(G!==O)Y=W-G;return new Date(Y)}var cY=4216320;function xW(N,H,W){let O=wW(N),Y=fW(H,W),G={year:Y.year,month:Y.month,day:Y.day,hour:Y.hour,minute:Y.minute};EW(G);for(let $=0;$<cY;$++){if(hY(O,G))return mY(G,W);EW(G)}return null}var uY={sandbox:"workspaceWrite",approvalPolicy:"onRequest",approvalsReviewer:"auto_review",effort:"medium"};function iY(N){return N.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}function dH(N){return kW.join(CN(),`${N}.json`)}async function yW(){await DN.mkdir(CN(),{recursive:!0})}async function sH(N){await yW(),await DN.writeFile(dH(N.id),JSON.stringify(N,null,2),"utf8")}function tH(N,H){if(!N.enabled)return null;if(N.kind==="once"){if(!N.runAt)return null;let O=new Date(N.runAt);if(Number.isNaN(O.getTime()))return null;if(N.lastRunAt)return null;return O.toISOString()}if(!N.cron)return null;let W=xW(N.cron,H,N.tz);return W?W.toISOString():null}function bW(N,H){if(H==="cron"){if(!N.cron)throw Error("cron expression is required for a cron schedule");let W=PW(N.cron);if(W)throw Error(`Invalid cron expression: ${W}`)}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 rH(N){await yW();let H;try{H=await DN.readdir(CN())}catch{return[]}let W=[];for(let O of H){if(!O.endsWith(".json"))continue;try{let Y=await DN.readFile(kW.join(CN(),O),"utf8"),G=JSON.parse(Y);if(N&&G.projectId!==N)continue;W.push(G)}catch{}}return W.sort((O,Y)=>Y.createdAt.localeCompare(O.createdAt)),W}async function AH(N){try{let H=await DN.readFile(dH(N),"utf8");return JSON.parse(H)}catch{return null}}async function qW(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 W=N.projectId??"default";if(!await MN(W))throw Error(`Unknown project: ${W}`);let O=N.kind??"cron";bW(N,O);let Y=`${iY(H)||"schedule"}-${lY().slice(0,8)}`,G=new Date,$={id:Y,name:H,projectId:W,prompt:N.prompt,kind:O,cron:O==="cron"?N.cron:void 0,runAt:O==="once"?new Date(N.runAt).toISOString():void 0,tz:N.tz,mode:{...uY,...N.mode??{}},resume:N.resume??!1,threadRunId:null,enabled:N.enabled??!0,createdAt:G.toISOString(),lastRunAt:null,lastRunId:null,lastError:null,nextRunAt:null};return $.nextRunAt=tH($,G),await sH($),$}async function IW(N,H){let W=await AH(N);if(!W)return null;let O=H.kind??W.kind,Y={...W,name:H.name?.trim()||W.name,prompt:H.prompt??W.prompt,kind:O,cron:O==="cron"?H.cron??W.cron:void 0,runAt:O==="once"?H.runAt?new Date(H.runAt).toISOString():W.runAt:void 0,tz:H.tz!==void 0?H.tz||void 0:W.tz,mode:H.mode?{...W.mode,...H.mode}:W.mode,resume:H.resume??W.resume,enabled:H.enabled??W.enabled};if(bW(Y,O),O==="once"&&H.runAt&&Y.runAt!==W.runAt)Y.lastRunAt=null;return Y.nextRunAt=tH(Y,new Date),await sH(Y),Y}async function jW(N){try{return await DN.unlink(dH(N)),!0}catch{return!1}}function pY(N){return{sandbox:N.sandbox,approvalPolicy:N.approvalPolicy,approvalsReviewer:N.approvalsReviewer,model:N.model,effort:N.effort}}async function eH(N,H){let W=N.lastRunId??null,O=null,Y=N.threadRunId??null;try{let $=N.mode;if(N.resume&&Y&&await D(Y)){let U=await D(Y);if(U&&h(U.status))throw Error("previous run still active \u2014 skipped this fire");W=(await ZH(Y,N.prompt,[],pY($))).id}else{let U=await FN({prompt:N.prompt,projectId:N.projectId,sandbox:$.sandbox,approvalPolicy:$.approvalPolicy,approvalsReviewer:$.approvalsReviewer,model:$.model,effort:$.effort,source:"schedule",scheduleId:N.id,scheduleName:N.name});if(W=U.id,N.resume)Y=U.id}}catch($){O=$ instanceof Error?$.message:String($)}let G={...N,lastRunAt:H.toISOString(),lastRunId:W,lastError:O,threadRunId:Y};return G.nextRunAt=tH(G,H),await sH(G),G}var aH=!1;async function vW(N=new Date){if(aH)return;aH=!0;try{let H=await rH();for(let W of H){if(!W.enabled||!W.nextRunAt)continue;let O=new Date(W.nextRunAt);if(Number.isNaN(O.getTime())||O.getTime()>N.getTime())continue;try{await eH(W,N)}catch(Y){console.error(`[schedules] fire failed for ${W.id}:`,Y)}}}catch(H){console.error("[schedules] tick failed:",H)}finally{aH=!1}}async function gW(N){let H=N.searchParams.get("project");if(H)return H;let W=N.searchParams.get("cwd");if(W){let O=iN(W);if(O&&await MN(O))return O;return V}return}async function hW(N,H){let W=H.pathname.split("/").filter(Boolean),O=W[2],Y=W[3];if(!O){if(N.method==="GET"){let G=await gW(H),$={schedules:await rH(G)};return Z($)}if(N.method==="POST"){let G=await L(N);if(!G.projectId){let $=await gW(H);if($)G.projectId=$}try{let U={schedule:await qW(G)};return Z(U,201)}catch($){return z(400,$ instanceof Error?$.message:String($))}}return z(405,"Method not allowed")}if(Y==="run"&&N.method==="POST"){let G=await AH(O);if(!G)return z(404,`Schedule not found: ${O}`);let U={schedule:await eH(G,new Date)};return Z(U)}if(Y)return z(404,`Not found: ${H.pathname}`);if(N.method==="GET"){let G=await AH(O);return G?Z({schedule:G}):z(404,`Schedule not found: ${O}`)}if(N.method==="PUT"){let G=await L(N);try{let $=await IW(O,G);return $?Z({schedule:$}):z(404,`Schedule not found: ${O}`)}catch($){return z(400,$ instanceof Error?$.message:String($))}}if(N.method==="DELETE")return await jW(O)?Z({ok:!0}):z(404,`Schedule not found: ${O}`);return z(405,"Method not allowed")}async function mW(N,H){let W=new URL(N.url);try{if(W.pathname==="/api/health")return h1();if(W.pathname==="/api/status")return m1();if(W.pathname==="/api/files/watch")return H.upgrade(N,{data:{channel:"files"}})?void 0:z(400,"WebSocket upgrade required");if(W.pathname.startsWith("/api/files/"))return await c1(N,W);if(W.pathname==="/api/projects"||W.pathname.startsWith("/api/projects/"))return await n1(N,W);if(W.pathname==="/api/runs"||W.pathname.startsWith("/api/runs/"))return await o1(N,W,H);if(W.pathname.startsWith("/api/browser/"))return await NW(N,W,H);if(W.pathname==="/api/skills"||W.pathname.startsWith("/api/skills/"))return await FW(N,W);if(W.pathname==="/api/mcp"||W.pathname.startsWith("/api/mcp/"))return await LW(N,W);if(W.pathname==="/api/memories"||W.pathname.startsWith("/api/memories/"))return await DW(N,W);if(W.pathname==="/api/models")return await CW(N);if(W.pathname==="/api/account"||W.pathname.startsWith("/api/account/"))return await SW(N,W);if(W.pathname==="/api/settings"||W.pathname.startsWith("/api/settings/"))return await TW(N,W);if(W.pathname==="/api/schedules"||W.pathname.startsWith("/api/schedules/"))return await hW(N,W);return z(404,`Not found: ${W.pathname}`)}catch(O){if(O instanceof dN)return z(400,O.message);if(O instanceof B)return z(400,O.message);if(oY(O))return z(404,`Not found: ${W.searchParams.get("path")??W.pathname}`);return console.error(`[api] ${N.method} ${W.pathname} failed:`,O),z(500,O instanceof Error?O.message:"Internal error")}}function oY(N){return typeof N==="object"&&N!==null&&"code"in N&&N.code==="ENOENT"}await O0();var JH=[b.resolve(import.meta.dir,"../ui-dist"),b.resolve(import.meta.dir,"../../ui/dist")].find((N)=>cW(b.join(N,"index.html")))??b.resolve(import.meta.dir,"../../ui/dist"),dY=(N)=>[`${N}.ts`,`${N}.js`].map((H)=>b.join(import.meta.dir,H)).find((H)=>cW(H));for(let[N,H,W]of[["jun","mcp-server","agenthost"],["jun-browser","browser-mcp-server",void 0]])try{let O=dY(H);if(O)await j1(N,O,uN,W);else console.warn(`[daemon] ${N} MCP server script (${H}) not found next to daemon`)}catch(O){console.warn(`[daemon] could not register ${N} MCP server:`,O)}p0(b.join(import.meta.dir,".."));var uW=Bun.serve({hostname:DH,port:uN,async fetch(N,H){let W=new URL(N.url);if(W.pathname.startsWith("/api/"))return mW(N,H);let O=await tY(W.pathname);if(O)return O;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){s1();let H=t1();if(H)N.send(H)}},message(N,H){if(N.data.channel===GN)e1(H)},close(N){if(N.unsubscribe(N.data.channel),N.data.channel===GN)r1()}}});D0(uW);try{aY(QN(),{recursive:!0},(N,H)=>{let W={type:"fs.changed",path:H?l(String(H)):null,ts:new Date().toISOString()};uW.publish("files",JSON.stringify(W))})}catch(N){console.warn("[daemon] workspace watcher unavailable:",N)}var sY=30000;setInterval(()=>{vW()},sY);console.log(`Jun daemon running at http://${DH}:${uN}`);console.log(`Workspace: ${b.resolve(J())}`);async function tY(N){let H=b.join(JH,"index.html");if(!await rY(H))return null;let W=b.normalize(decodeURIComponent(N)).replace(/^[/\\]+/,""),O=b.resolve(JH,W||"index.html"),Y=`${JH}${b.sep}`;if(O!==JH&&!O.startsWith(Y))return new Response("Not found",{status:404});if(await eY(O))return new Response(Bun.file(O),{headers:{"content-type":N2(O)}});return new Response(Bun.file(H),{headers:{"content-type":"text/html; charset=utf-8"}})}async function rY(N){try{return await lW(N),!0}catch{return!1}}async function eY(N){try{return(await lW(N)).isFile()}catch{return!1}}function N2(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"}}
|