bridge-agent 0.10.5 → 0.10.6
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/dist/index.js +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -406,7 +406,7 @@ ${ni("bridge_get_my_task","bridge_complete_task","bridge_fail_task","bridge_get_
|
|
|
406
406
|
`,"utf-8"),console.log("[daemon] persona.prompt.written",{agentId:r,tmpPath:n}),["--append-system-prompt-file",n]}catch(n){return console.warn("[daemon] persona.prompt.write.failed",{agentId:r,error:String(n)}),[]}return t==="qwen"?["--append-system-prompt",e.trim()]:[]}function lt(t){return`"${t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function qc(t){try{let e=process.env.BRIDGE_MCP_URL,r=e?{mcpServers:{bridge:{type:"http",url:`${e}/mcp/${t.workspaceId}/${t.projectId||"workspace"}`,headers:{Authorization:`Bearer ${t.token}`,"x-panel-id":t.agentId??"","x-panel-persona-id":t.personaId??""}}}}:{mcpServers:{bridge:{command:Ie(),args:[],env:{BRIDGE_SERVER_URL:t.serverUrl,BRIDGE_TOKEN:t.token,BRIDGE_WORKSPACE_ID:t.workspaceId,BRIDGE_PROJECT_ID:t.projectId||"workspace",BRIDGE_PANEL_ID:t.agentId??"",BRIDGE_PERSONA_ID:t.personaId??"",HTTP_MODE:"false"}}}},n=O.default.join(R.default.tmpdir(),`bridge-mcp-kimi-${t.agentId??(t.projectId||"workspace")}.json`);return N.default.writeFileSync(n,JSON.stringify(r,null,2)+`
|
|
407
407
|
`,"utf-8"),console.log("[daemon] kimi.mcp.config.written",{tmpPath:n,transport:e?"http":"stdio"}),["--mcp-config-file",n]}catch(e){return console.warn("[daemon] kimi.mcp.config.build.failed",{error:String(e)}),[]}}function Vc(t){try{let e=Ie(),r=`{BRIDGE_SERVER_URL=${lt(t.serverUrl)},BRIDGE_TOKEN=${lt(t.token)},BRIDGE_WORKSPACE_ID=${lt(t.workspaceId)},BRIDGE_PROJECT_ID=${lt(t.projectId||"workspace")},HTTP_MODE="false"}`;return["-c",'mcp_servers.bridge.transport="stdio"',"-c",`mcp_servers.bridge.command=${lt(e)}`,"-c","mcp_servers.bridge.args=[]","-c",`mcp_servers.bridge.env=${r}`]}catch(e){return console.warn("[daemon] codex.mcp.config.build.failed",{error:String(e)}),[]}}function Kc(t){try{return N.default.statSync(t).isDirectory()}catch{return!1}}function en(t,e){try{return e(t)}catch{return!1}}function Jc(t,e,r,n,s=Kc){let i=n?.[t];if(i&&en(i,s))return{path:i,source:"local_override"};if(r){if(en(r,s))return{path:r,source:"daemon_override"};console.warn("[daemon] spawn.cwd.daemon_override_missing",{projectId:t,daemonLocalPath:r,hint:`Run: jerico link-project ${t} <local-path>`})}if(e&&en(e,s))return{path:e,source:"server_project"};let a=!t||t.trim()===""?"Missing projectId in spawn message \u2014 server-side bug, file issue at https://github.com/alperduzgun/jerico/issues":`Set projectPaths["${t}"] in ~/.jerico/settings.json`;return console.warn("[daemon] spawn.cwd.fallback_home",{projectId:t,serverCwd:e,localOverride:i,daemonLocalPath:r??void 0,hint:a}),{path:R.default.homedir(),source:"fallback_home"}}function Yc(){let t=O.default.join(R.default.homedir(),".forge",".forge.toml");if(N.default.existsSync(t))try{let e=N.default.readFileSync(t,"utf-8");if(e.includes("auto_update = true")){let r=e.replace(/^auto_update\s*=\s*true$/m,"auto_update = false");N.default.writeFileSync(t,r),console.log("[daemon] forge.auto_update.disabled",{reason:"prevents-spawn-crash"})}}catch(e){console.warn("[daemon] forge.auto_update.patch.failed",{error:String(e)})}}function zc(t){Yc();try{if(!t.cwd)return console.warn("[daemon] forge.mcp.setup.skipped",{reason:"missing_cwd",projectId:t.projectId||"workspace"}),!1;let e=Ie(),r=JSON.stringify({mcpServers:{bridge:{command:e,args:[],env:{BRIDGE_SERVER_URL:t.serverUrl,BRIDGE_TOKEN:t.token,BRIDGE_WORKSPACE_ID:t.workspaceId,BRIDGE_PROJECT_ID:t.projectId||"workspace",BRIDGE_PANEL_ID:t.agentId??"",BRIDGE_PERSONA_ID:t.personaId??"",HTTP_MODE:"false"}}}}),n={cwd:t.cwd,encoding:"utf-8",timeout:5e3,stdio:"pipe"};(0,Ge.spawnSync)("forge",["mcp","remove","--scope","local","bridge"],n);let s=(0,Ge.spawnSync)("forge",["mcp","import",r,"--scope","local"],n);return s.status===0?(console.log("[daemon] forge.mcp.setup.ok",{cwd:t.cwd,projectId:t.projectId||"workspace"}),!0):(console.warn("[daemon] forge.mcp.setup.failed",{cwd:t.cwd,projectId:t.projectId,status:s.status,stderr:(s.stderr??"").toString().slice(0,300)}),!1)}catch(e){return console.warn("[daemon] forge.mcp.setup.error",{error:String(e),projectId:t.projectId}),!1}}function Xc(t){try{let e=O.default.join(R.default.homedir(),".config","opencode","opencode.json"),r={};try{r=JSON.parse(N.default.readFileSync(e,"utf-8"))}catch{}delete r.mcpServers;let n=process.env.BRIDGE_MCP_URL,s=t.projectId||"workspace",i={...r.mcp??{}};return n?i.bridge={type:"remote",url:`${n}/mcp/${t.workspaceId}/${s}`,enabled:!0,headers:{Authorization:`Bearer ${t.token}`,"x-panel-id":t.agentId??"","x-panel-persona-id":t.personaId??""}}:i.bridge={type:"local",command:[Ie()],environment:{BRIDGE_SERVER_URL:t.serverUrl,BRIDGE_TOKEN:t.token,BRIDGE_WORKSPACE_ID:t.workspaceId,BRIDGE_PROJECT_ID:s,BRIDGE_PANEL_ID:t.agentId??"",BRIDGE_PERSONA_ID:t.personaId??"",HTTP_MODE:"false"},enabled:!0},r.mcp=i,N.default.mkdirSync(O.default.dirname(e),{recursive:!0}),N.default.writeFileSync(e,JSON.stringify(r,null,2)+`
|
|
408
408
|
`,"utf-8"),console.log("[daemon] opencode.mcp.config.written",{configPath:e,transport:n?"http":"stdio"}),!0}catch(e){return console.warn("[daemon] opencode.mcp.config.build.failed",{error:String(e)}),!1}}function Qc(t){try{if(!t.cwd)return console.warn("[daemon] qwen.mcp.setup.skipped",{reason:"missing_cwd",projectId:t.projectId||"workspace"}),!1;let e=Ie(),r={cwd:t.cwd,encoding:"utf-8",timeout:5e3,stdio:"pipe"},n=O.default.resolve(t.cwd)===O.default.resolve(R.default.homedir()),s=n?"user":"project";n&&console.warn("[daemon] qwen.mcp.home_dir_fallback",{cwd:t.cwd,projectId:t.projectId||"workspace",scope:"user"}),(0,Ge.spawnSync)("qwen",["mcp","remove","--scope",s,"bridge"],r);let i=(0,Ge.spawnSync)("qwen",["mcp","add","--scope",s,"-t","stdio","-e",`BRIDGE_SERVER_URL=${t.serverUrl}`,"-e",`BRIDGE_TOKEN=${t.token}`,"-e",`BRIDGE_WORKSPACE_ID=${t.workspaceId}`,"-e",`BRIDGE_PROJECT_ID=${t.projectId||"workspace"}`,"-e",`BRIDGE_PANEL_ID=${t.agentId??""}`,"-e",`BRIDGE_PERSONA_ID=${t.personaId??""}`,"-e","HTTP_MODE=false","bridge",e],r);return i.status===0?(console.log("[daemon] qwen.mcp.setup.ok",{cwd:t.cwd,projectId:t.projectId||"workspace"}),!0):(console.warn("[daemon] qwen.mcp.setup.failed",{cwd:t.cwd,projectId:t.projectId,status:i.status,stderr:(i.stderr??"").toString().slice(0,300)}),!1)}catch(e){return console.warn("[daemon] qwen.mcp.setup.error",{error:String(e),projectId:t.projectId}),!1}}function Zc(t){try{if(!t.cwd)return console.warn("[daemon] gemini.mcp.setup.skipped",{reason:"missing_cwd",projectId:t.projectId||"workspace"}),!1;let e=O.default.join(t.cwd,".gemini"),r=O.default.join(e,"settings.json"),n={};try{n=JSON.parse(N.default.readFileSync(r,"utf-8"))}catch{}let s=Ie(),i=t.projectId||"workspace",o=process.env.BRIDGE_MCP_URL,a={...n.mcpServers??{}};return o?a.bridge={type:"http",url:`${o}/mcp/${t.workspaceId}/${i}`,headers:{Authorization:`Bearer ${t.token}`,"x-panel-id":t.agentId??"","x-panel-persona-id":t.personaId??""},trust:!0,description:"Bridge MCP server"}:a.bridge={command:s,args:[],env:{BRIDGE_SERVER_URL:t.serverUrl,BRIDGE_TOKEN:t.token,BRIDGE_WORKSPACE_ID:t.workspaceId,BRIDGE_PROJECT_ID:i,BRIDGE_PANEL_ID:t.agentId??"",BRIDGE_PERSONA_ID:t.personaId??"",HTTP_MODE:"false"},trust:!0,description:"Bridge MCP server"},n.mcpServers=a,N.default.mkdirSync(e,{recursive:!0}),N.default.writeFileSync(r,JSON.stringify(n,null,2)+`
|
|
409
|
-
`,"utf-8"),console.log("[daemon] gemini.mcp.config.written",{configPath:r,transport:o?"http":"stdio"}),!0}catch(e){return console.warn("[daemon] gemini.mcp.config.build.failed",{error:String(e)}),!1}}var pt=[],tn=!1,Ai=!1;function Ti(){return tn}function Ri(t){if(Ai)throw new Error("[daemon] startDaemonConnection called twice \u2014 only one connection manager allowed");if(Ai=!0,process.env.BRIDGE_TEST_SCRIPTED_REVIEW!=="1")try{let g=O.default.join(R.default.homedir(),".jerico","settings.json");N.default.existsSync(g)&&JSON.parse(N.default.readFileSync(g,"utf-8")).testScriptedReview===!0&&(process.env.BRIDGE_TEST_SCRIPTED_REVIEW="1",console.log("[daemon] scripted-review-mode enabled from ~/.jerico/settings.json"))}catch{}process.env.BRIDGE_TEST_SCRIPTED_REVIEW==="1"&&console.log("[daemon] scripted-review-mode ENABLED");let e=ne(),r=(0,ht.createHash)("sha256").update(e.token).digest("hex"),n=new Mt(r),s=null,i=null,o=null,a=0,c=0,l=0n,d=0,u=0;function h(){i&&(clearTimeout(i),i=null),o&&(clearInterval(o),o=null);let g=Date.now(),b=process.hrtime.bigint();s=new k(e.server,{headers:{Authorization:`Bearer ${e.token}`}});let y=s,w=(0,ht.randomUUID)();Zr=w;let D=R.default.networkInterfaces(),P=Object.entries(D).flatMap(([m,x])=>(x||[]).filter(G=>!G.internal).map(G=>({iface:m,address:G.address,family:G.family}))),U=JSON.stringify(P);console.log(JSON.stringify({ts:Date.now(),level:"info",event:"net.interfaces",interfaces:P,connectionId:w})),Vt&&Vt!==U&&console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"net.interfaces.changed",previous:Vt,current:U,connectionId:w})),Vt=U;let Ve=y.send.bind(y);y.send=function(m){if(y.readyState!==k.OPEN){let x="unknown";try{x=JSON.parse(m).type}catch{}console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.send.dropped",messageType:x,readyState:y.readyState,connectionId:w}));return}return Ve(m)},console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.connecting",server:e.server,connectionId:w}));let S=null,E=0,v=null,I=!1;y.on("open",()=>{tn=!0,console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.connected",server:e.server,connectionId:w})),o=setInterval(()=>{y.readyState===k.OPEN&&(y.ping(),E=Date.now(),v&&clearTimeout(v),v=setTimeout(()=>{console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.heartbeat.timeout",connectionId:w})),y.terminate()},Pi))},Ci),t.setCurrentWs(y);let m=!Oi();y.send(JSON.stringify({type:"ready",version:"1.1",npmVersion:"0.10.5",name:e.name,spawnHelperBroken:m,liveAgentIds:t.getLiveAgentIds(),machineFingerprint:rn(),connectionId:w,claudeTier:Wt()})),n.updateWs(y),Promise.all([mr(e.agentPaths),Wr()]).then(([x,G])=>{pt=G?[...x,G]:x,y.readyState===k.OPEN&&y.send(JSON.stringify({type:"agents",list:pt}))}),S=Ii(x=>{y.readyState===k.OPEN&&y.send(JSON.stringify({type:"system_metrics",daemonId:r,...x}))})}),y.on("message",m=>{let x;try{x=JSON.parse(m.toString())}catch{console.warn("[daemon] Invalid JSON from server, ignoring");return}el(x,y,t,e,n)}),y.on("pong",()=>{v&&(clearTimeout(v),v=null);let m=Date.now()-E;console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.heartbeat.pong",rttMs:m,connectionId:w})),I||(I=!0,c=0,l=0n,d=0,u=0)}),y.on("close",(m,x)=>{tn=!1,o&&(clearInterval(o),o=null),v&&(clearTimeout(v),v=null),S?.(),S=null,n.stopAll(),m===1008?(a++,a>=2&&(console.error("[daemon] ws.auth_failed \u2014 token invalid or expired (2 consecutive rejections), stopping. Re-run: bridge-agent auth"),p(),setTimeout(()=>process.exit(1),2e3)),console.warn("[daemon] ws.auth_rejected \u2014 transient 1008, will retry once",{attempt:a})):a=0;let G=Number((process.hrtime.bigint()-b)/1000000n);if(console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.closed",code:m,reason:x?.toString()||void 0,uptimeMs:G,connectionId:w})),i)return;if(!I&&G<Ci+Pi+5e3&&m!==1008&&(d++,console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.reconnect.zombie",zombieStreak:d,uptimeMs:G,connectionId:w}))),d>=3){u++,console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.reconnect.zombie.escalate",zombieStreak:d,escalationCount:u,connectionId:w})),u>=3&&(console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.reconnect.zombie.fatal",escalationCount:u,zombieStreak:d,connectionId:w})),p(),setTimeout(()=>process.exit(1),2e3)),d=0,y?.removeAllListeners?.(),o&&(clearInterval(o),o=null),v&&(clearTimeout(v),v=null),i&&(clearTimeout(i),i=null),i=setTimeout(h,1e4);return}c===0&&(l=process.hrtime.bigint()),c++;let zt=Number((process.hrtime.bigint()-l)/1000000n);c>=10&&zt<6e4&&(console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.reconnect.storm",reconnectCount:c,connectionId:w})),p(),setTimeout(()=>process.exit(1),2e3));let Zi=Math.min(3e4,1e3*Math.pow(2,Math.min(c,5))),pn=Math.round(Zi+Math.random()*500);console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.reconnect.scheduled",delayMs:pn,reconnectCount:c,connectionId:w})),i=setTimeout(h,pn)}),y.on("error",m=>{console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.error",message:m.message,code:m.code,connectionId:w}))})}function p(){o&&(clearInterval(o),o=null),t.stopLivenessCheck(),Dc();for(let g of Ee.values())g();n.stopAll(),t.killAll(),s?.close()}function f(g){console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.signal",signal:g,connectionId:Zr})),p(),setTimeout(()=>process.exit(0),100)}process.on("SIGINT",()=>f("SIGINT")),process.on("SIGTERM",()=>f("SIGTERM")),process.on("SIGHUP",()=>f("SIGHUP")),process.on("uncaughtException",g=>{console.log(JSON.stringify({ts:Date.now(),level:"error",event:"daemon.uncaught",error:String(g),stack:g.stack,connectionId:Zr}));try{p()}catch{}setTimeout(()=>process.exit(1),2e3)}),h()}function el(t,e,r,n,s){switch(t.type){case"spawn":{if(console.log("[daemon] pty.spawn.start",{agentId:t.agentId,agentKey:t.agentKey,sessionId:t.sessionId,projectId:t.projectId,workspaceId:t.workspaceId,role:t.role}),t.agentKey==="sim_ios"){s.start(t.agentId);return}let i=pt.find(S=>S.key===t.agentKey);if(!i){e.readyState===k.OPEN&&e.send(JSON.stringify({type:"error",code:"AGENT_NOT_FOUND",message:`Agent '${t.agentKey}' is not installed on this machine`}));return}let o=fe.find(S=>S.key===t.agentKey),a=[];if(t.sessionId&&o?.resumeArgs)a=o.resumeArgs(t.sessionId),console.log("[daemon] pty.spawn.resume",{agentId:t.agentId,sessionId:t.sessionId}),t.agentKey==="claude"&&(Ee.get(t.agentId)?.(),Ee.set(t.agentId,Jr(t.agentId,t.sessionId,(S,E,v)=>{let I=r.getCurrentWs();I?.readyState===k.OPEN&&I.send(JSON.stringify({type:"panel_token_usage",agentId:S,usedPct:E,usedTokens:v,...We}))})));else if(o?.assignSessionId){let S=crypto.randomUUID(),E=t.agentKey==="kimi"?"--session":t.agentKey==="forge"?"--conversation-id":"--session-id";a=[...o.spawnArgs??[],E,S],e.readyState===k.OPEN&&(e.send(JSON.stringify({type:"session_started",agentId:t.agentId,sessionId:S})),console.log("[daemon] session.assigned",{agentId:t.agentId,sessionId:S})),t.agentKey==="claude"&&(Ee.get(t.agentId)?.(),Ee.set(t.agentId,Jr(t.agentId,S,(v,I,m)=>{let x=r.getCurrentWs();x?.readyState===k.OPEN&&x.send(JSON.stringify({type:"panel_token_usage",agentId:v,usedPct:I,usedTokens:m,...We}))})))}else a=[...o?.spawnArgs??[]],e.readyState===k.OPEN&&e.send(JSON.stringify({type:"session_started",agentId:t.agentId,sessionId:crypto.randomUUID()}));let c,l=!1,d,u;if(t.workspaceId){let S=$c(n.server),E=Jc(t.projectId??"",t.cwd,t.daemonLocalPath,n.projectPaths),v=E.path;if(u=E.source,u==="fallback_home"&&t.sessionId){let m=t.daemonLocalPath?"daemon_override_missing":"not_found";console.warn("[daemon] resume.cwd_fallback_blocked",{agentId:t.agentId,sessionId:t.sessionId,requestedCwd:t.cwd,projectId:t.projectId,reason:m}),e.readyState===k.OPEN&&e.send(JSON.stringify({type:"error",code:"CWD_MISSING_ON_DAEMON",message:`Cannot resume session \u2014 project path not found on this machine. Run: bridge-agent link-project ${t.projectId??"?"} <local-path>`,agentId:t.agentId,sessionId:t.sessionId}));return}let I=Vr(v);if(c={serverUrl:S,token:n.token,workspaceId:Zs(t.workspaceId),projectId:t.projectId?ei(t.projectId):void 0,agentId:t.agentId?Qs(t.agentId):void 0,personaId:t.personaId,cwd:v,projectEnv:I.env},t.agentKey==="claude"){let m=Uc(c);l=m.length>0,d=process.env.BRIDGE_MCP_URL?"http":"stdio",a=[...a,...m]}else if(t.agentKey==="codex"){let m=Vc(c);l=m.length>0,d="stdio",a=[...a,...m]}else if(t.agentKey==="qwen")l=Qc(c),d=l?"stdio":void 0;else if(t.agentKey==="kimi"){let m=qc(c);l=m.length>0,d=process.env.BRIDGE_MCP_URL?"http":"stdio",a=[...a,...m]}else t.agentKey==="forge"?(l=zc(c),d=l?"stdio":void 0):t.agentKey==="opencode"?(l=Xc(c),d=l?process.env.BRIDGE_MCP_URL?"http":"stdio":void 0):t.agentKey==="gemini"?(l=Zc(c),d=l?process.env.BRIDGE_MCP_URL?"http":"stdio":void 0):(l=!1,console.log("[daemon] mcp.config.skipped",{agentId:t.agentId,agentKey:t.agentKey,reason:"unsupported_agent_path"}));if($r("phase2a.verified_at")&&(E.source==="daemon_override"||E.source==="server_project")){let m=`${S}/api/workspaces/${t.workspaceId}/projects/${t.projectId}/machine-paths/${t.daemonId}/verify`;fetch(m,{method:"PATCH",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:"{}"}).catch(x=>{console.warn("[daemon] verify.patch_failed",{projectId:t.projectId,error:String(x)})})}if($r("phase2a.auto_register")&&(E.source==="daemon_override"||E.source==="server_project"))try{let m=(0,Ge.spawnSync)("git",["remote","get-url","origin"],{cwd:v,timeout:5e3,encoding:"utf-8"});if(m.status===0&&m.stdout&&m.stdout.trim()){let x=m.stdout.trim();t.projectId&&(n.projectPaths||(n.projectPaths={}),n.projectPaths[t.projectId]=v,J({projectPaths:n.projectPaths}));let G=`${S}/api/workspaces/${t.workspaceId}/projects/${t.projectId}/machine-paths`;fetch(G,{method:"POST",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:JSON.stringify({daemonId:t.daemonId,localPath:v,repoUrl:x})}).catch(zt=>{console.warn("[daemon] auto_register.post_failed",{projectId:t.projectId,error:String(zt)})}),console.log("[daemon] auto_register.ok",{projectId:t.projectId,localPath:v,repoUrl:x})}}catch(m){console.log("[daemon] auto_register.skipped",{projectId:t.projectId,reason:String(m)})}}let h=Gc(t.role,t.systemPrompt,t.agentId,t.workspaceId,t.projectId,t.groupId),p=Fc(t.agentKey,h,t.agentId);p.length>0&&(a=[...a,...p]);let f=Hc(t.agentKey,t.systemPrompt,t.agentId);f.length>0&&(a=[...a,...f]);let g=Math.max(1,Math.min(500,t.cols)),b=Math.max(1,Math.min(500,t.rows)),y=Date.now(),w="",D=0,P=!1,U=!1;if(r.spawn(t.agentId,t.agentKey,i.binaryPath,a,g,b,S=>{if(D+=S.length,t.agentKey==="gemini")try{let v=Buffer.from(S,"base64").toString("utf-8");if(v.includes("shell mode enabled"))ve.get(t.agentId)||(ve.set(t.agentId,!0),console.log("[daemon] gemini.shell_mode.entered",{agentId:t.agentId.slice(-8)}));else if(v.includes("Type your message")&&(ve.get(t.agentId)&&(ve.set(t.agentId,!1),console.log("[daemon] gemini.shell_mode.exited",{agentId:t.agentId.slice(-8)})),!Ue.get(t.agentId))){Ue.set(t.agentId,!0);let I=ke.get(t.agentId)??[];ke.delete(t.agentId),console.log("[daemon] gemini.ready",{agentId:t.agentId.slice(-8),flushing:I.length}),I.length>0&&setTimeout(()=>{for(let m of I)r.write(t.agentId,m,"orchestrator");setTimeout(()=>{r.write(t.agentId,Buffer.from("\r").toString("base64"),"orchestrator")},1e3)},500)}}catch{}try{let v=Buffer.from(S,"base64").toString("utf-8");if(t.agentKey==="kimi"&&t.role&&!U&&Date.now()-y<3e4&&(/yolo agent/.test(v)||/●/.test(v)||/○/.test(v))){U=!0;let I=h;if(I){let m=Nc(I),x=Buffer.from(m).toString("base64");r.write(t.agentId,x,"orchestrator"),console.log("[daemon] kimi.role.injected",{agentId:t.agentId,role:t.role})}}}catch{}if(!w)try{let v=Buffer.from(S,"base64").toString("utf-8"),I=Bc(v).replace(/\x00/g,"").trim();if(I&&(w=Mc(I)),t.agentKey==="codex"&&!P&&Date.now()-y<2e4&&/included in your plan for free|let[’']s build together/i.test(I)&&/yes|no|\[y\/n\]|\(y\/n\)|y\/n/i.test(I)){P=!0;let m=Buffer.from("y").toString("base64");r.write(t.agentId,m,"orchestrator"),console.log("[daemon] codex.onboarding.auto_ack",{agentId:t.agentId})}}catch{}let E=r.getCurrentWs();E?.readyState===k.OPEN&&E.send(JSON.stringify({type:"output",agentId:t.agentId,data:S})),Ac(t.agentId,()=>r.getCurrentWs())},(S,E)=>{let v=Date.now()-y,I=v<=jc;console.log("[daemon] pty.spawn.result",{agentId:t.agentId,agentKey:t.agentKey,daemonId:t.daemonId,exitCode:S,signal:E,uptimeMs:v,earlyExit:I,outputBytes:D,firstOutputSnippet:w||void 0});let m=r.getCurrentWs();I&&m?.readyState===k.OPEN&&m.send(JSON.stringify({type:"error",code:"SPAWN_FAILED",message:`Early exit: agent=${t.agentKey} code=${S??"null"} signal=${E??"null"} snippet="${w||"no output"}"`})),m?.readyState===k.OPEN&&m.send(JSON.stringify({type:"exit",agentId:t.agentId,exitCode:S,signal:E})),Tc(t.agentId),ve.delete(t.agentId),Ue.delete(t.agentId),ke.delete(t.agentId),Promise.all([(0,dt.unlink)(O.default.join(R.default.tmpdir(),`bridge-persona-${t.agentId}.md`)),(0,dt.unlink)(O.default.join(R.default.tmpdir(),`bridge-role-${t.agentId}.md`)),(0,dt.unlink)(O.default.join(R.default.tmpdir(),`bridge-mcp-${t.agentId}.json`)),(0,dt.unlink)(O.default.join(R.default.tmpdir(),`bridge-mcp-kimi-${t.agentId}.json`))].map(x=>x.catch(()=>{}))).catch(()=>{})},c)){if(t.agentKey==="gemini"&&setTimeout(()=>{if(!Ue.get(t.agentId)){Ue.set(t.agentId,!0);let S=ke.get(t.agentId)??[];ke.delete(t.agentId),S.length>0&&(console.warn("[daemon] gemini.ready.timeout_fallback",{agentId:t.agentId.slice(-8),flushing:S.length}),setTimeout(()=>{for(let E of S)r.write(t.agentId,E,"orchestrator");setTimeout(()=>{r.write(t.agentId,Buffer.from("\r").toString("base64"),"orchestrator")},1e3)},500))}},3e4),u==="fallback_home"&&e.readyState===k.OPEN){let S=t.daemonLocalPath?"daemon_override_missing":"not_found";console.warn("[daemon] cwd_fallback",{agentId:t.agentId,requestedCwd:t.cwd,actualCwd:R.default.homedir(),reason:S,projectId:t.projectId,daemonId:t.daemonId}),e.send(JSON.stringify({type:"cwd_fallback",agentId:t.agentId,requestedCwd:t.cwd,actualCwd:R.default.homedir(),source:"fallback_home",reason:S,projectId:t.projectId,daemonId:t.daemonId}))}e.readyState===k.OPEN&&e.send(JSON.stringify({type:"mcp_status",agentId:t.agentId,mcpConfigured:l,transport:l?d:void 0,projectId:c?.projectId,effectiveCwd:c?.cwd,cwdSource:u}))}else{let E=r.getLastError(t.agentId)?.includes("posix_spawnp failed")&&Rc(t.agentKey);e.readyState===k.OPEN&&(E?e.send(JSON.stringify({type:"error",code:"SPAWN_HELPER_BROKEN",message:"node-pty spawn-helper is not executable. Upgrade bridge-agent to v0.2.10+."})):e.send(JSON.stringify({type:"error",code:"SPAWN_FAILED",message:`Failed to spawn panel ${t.agentId}`})))}e.readyState===k.OPEN&&e.send(JSON.stringify({type:"agent_spawned",agentId:t.agentId,agentKey:t.agentKey,daemonId:t.daemonId,role:t.role,personaId:t.personaId}));break}case"input":{if(r.getAgentKey(t.agentId)==="gemini"&&t.source==="orchestrator"){if(!Ue.get(t.agentId)){let o=ke.get(t.agentId)??[];o.push(t.data),ke.set(t.agentId,o),console.log("[daemon] gemini.input.buffered",{agentId:t.agentId.slice(-8),queued:o.length});break}if(ve.get(t.agentId)){r.write(t.agentId,Buffer.from("\x1B").toString("base64"),"user"),ve.set(t.agentId,!1),console.log("[daemon] gemini.shell_mode.esc_before_inject",{agentId:t.agentId.slice(-8)}),setTimeout(()=>{r.write(t.agentId,t.data,t.source)},100);break}}r.write(t.agentId,t.data,t.source);break}case"kill":console.log("[daemon] kill.received",{agentId:t.agentId,force:t.force??!1}),Ee.get(t.agentId)?.(),Ee.delete(t.agentId),s.stop(t.agentId),r.kill(t.agentId,t.force);break;case"resize":r.resize(t.agentId,t.cols,t.rows);break;case"sim_tap":case"sim_swipe":case"sim_key":case"sim_button":case"sim_get_source":case"sim_subscribe":case"sim_unsubscribe":case"sim_healthcheck":case"sim_install_run":case"sim_install_cancel":s.handle(t);break;case"detect_agents":Promise.all([mr(n.agentPaths),Wr()]).then(([i,o])=>{pt=o?[...i,o]:i,e.readyState===k.OPEN&&e.send(JSON.stringify({type:"agents",list:pt}))});break;case"dir_list":{let i=R.default.homedir(),o=(t.path||"~").replace(/^~/,i),a=O.default.resolve(o);if(a!==i&&!a.startsWith(i+O.default.sep)){e.readyState===k.OPEN&&e.send(JSON.stringify({type:"error",code:"INVALID_MSG",message:"Path outside home directory"}));return}try{let c=N.default.readdirSync(a,{withFileTypes:!0}).filter(l=>l.isDirectory()&&!l.name.startsWith(".")).map(l=>({name:l.name,path:O.default.join(a,l.name)})).sort((l,d)=>l.name.localeCompare(d.name));e.readyState===k.OPEN&&e.send(JSON.stringify({type:"dir_list_result",requestId:t.requestId,path:a,entries:c}))}catch(c){e.readyState===k.OPEN&&e.send(JSON.stringify({type:"dir_list_result",requestId:t.requestId,path:a,entries:[],error:c instanceof Error?c.message:"Cannot read directory"}))}break}case"persona_apply":{let i=r.getAgentKey(t.agentId);if(!i){console.warn("[daemon] persona_apply.no_panel",{agentId:t.agentId});break}let o;t.systemPrompt?o=`[BRIDGE-ORCH] Persona updated: ${t.personaId}
|
|
409
|
+
`,"utf-8"),console.log("[daemon] gemini.mcp.config.written",{configPath:r,transport:o?"http":"stdio"}),!0}catch(e){return console.warn("[daemon] gemini.mcp.config.build.failed",{error:String(e)}),!1}}var pt=[],tn=!1,Ai=!1;function Ti(){return tn}function Ri(t){if(Ai)throw new Error("[daemon] startDaemonConnection called twice \u2014 only one connection manager allowed");if(Ai=!0,process.env.BRIDGE_TEST_SCRIPTED_REVIEW!=="1")try{let g=O.default.join(R.default.homedir(),".jerico","settings.json");N.default.existsSync(g)&&JSON.parse(N.default.readFileSync(g,"utf-8")).testScriptedReview===!0&&(process.env.BRIDGE_TEST_SCRIPTED_REVIEW="1",console.log("[daemon] scripted-review-mode enabled from ~/.jerico/settings.json"))}catch{}process.env.BRIDGE_TEST_SCRIPTED_REVIEW==="1"&&console.log("[daemon] scripted-review-mode ENABLED");let e=ne(),r=(0,ht.createHash)("sha256").update(e.token).digest("hex"),n=new Mt(r),s=null,i=null,o=null,a=0,c=0,l=0n,d=0,u=0;function h(){i&&(clearTimeout(i),i=null),o&&(clearInterval(o),o=null);let g=Date.now(),b=process.hrtime.bigint();s=new k(e.server,{headers:{Authorization:`Bearer ${e.token}`}});let y=s,w=(0,ht.randomUUID)();Zr=w;let D=R.default.networkInterfaces(),P=Object.entries(D).flatMap(([m,x])=>(x||[]).filter(G=>!G.internal).map(G=>({iface:m,address:G.address,family:G.family}))),U=JSON.stringify(P);console.log(JSON.stringify({ts:Date.now(),level:"info",event:"net.interfaces",interfaces:P,connectionId:w})),Vt&&Vt!==U&&console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"net.interfaces.changed",previous:Vt,current:U,connectionId:w})),Vt=U;let Ve=y.send.bind(y);y.send=function(m){if(y.readyState!==k.OPEN){let x="unknown";try{x=JSON.parse(m).type}catch{}console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.send.dropped",messageType:x,readyState:y.readyState,connectionId:w}));return}return Ve(m)},console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.connecting",server:e.server,connectionId:w}));let S=null,E=0,v=null,I=!1;y.on("open",()=>{tn=!0,console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.connected",server:e.server,connectionId:w})),o=setInterval(()=>{y.readyState===k.OPEN&&(y.ping(),E=Date.now(),v&&clearTimeout(v),v=setTimeout(()=>{console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.heartbeat.timeout",connectionId:w})),y.terminate()},Pi))},Ci),t.setCurrentWs(y);let m=!Oi();y.send(JSON.stringify({type:"ready",version:"1.1",npmVersion:"0.10.6",name:e.name,spawnHelperBroken:m,liveAgentIds:t.getLiveAgentIds(),machineFingerprint:rn(),connectionId:w,claudeTier:Wt()})),n.updateWs(y),Promise.all([mr(e.agentPaths),Wr()]).then(([x,G])=>{pt=G?[...x,G]:x,y.readyState===k.OPEN&&y.send(JSON.stringify({type:"agents",list:pt}))}),S=Ii(x=>{y.readyState===k.OPEN&&y.send(JSON.stringify({type:"system_metrics",daemonId:r,...x}))})}),y.on("message",m=>{let x;try{x=JSON.parse(m.toString())}catch{console.warn("[daemon] Invalid JSON from server, ignoring");return}el(x,y,t,e,n)}),y.on("pong",()=>{v&&(clearTimeout(v),v=null);let m=Date.now()-E;console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.heartbeat.pong",rttMs:m,connectionId:w})),I||(I=!0,c=0,l=0n,d=0,u=0)}),y.on("close",(m,x)=>{tn=!1,o&&(clearInterval(o),o=null),v&&(clearTimeout(v),v=null),S?.(),S=null,n.stopAll(),m===1008?(a++,a>=2&&(console.error("[daemon] ws.auth_failed \u2014 token invalid or expired (2 consecutive rejections), stopping. Re-run: bridge-agent auth"),p(),setTimeout(()=>process.exit(1),2e3)),console.warn("[daemon] ws.auth_rejected \u2014 transient 1008, will retry once",{attempt:a})):a=0;let G=Number((process.hrtime.bigint()-b)/1000000n);if(console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.closed",code:m,reason:x?.toString()||void 0,uptimeMs:G,connectionId:w})),i)return;if(!I&&G<Ci+Pi+5e3&&m!==1008&&(d++,console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.reconnect.zombie",zombieStreak:d,uptimeMs:G,connectionId:w}))),d>=3){u++,console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.reconnect.zombie.escalate",zombieStreak:d,escalationCount:u,connectionId:w})),u>=3&&(console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.reconnect.zombie.fatal",escalationCount:u,zombieStreak:d,connectionId:w})),p(),setTimeout(()=>process.exit(1),2e3)),d=0,y?.removeAllListeners?.(),o&&(clearInterval(o),o=null),v&&(clearTimeout(v),v=null),i&&(clearTimeout(i),i=null),i=setTimeout(h,1e4);return}c===0&&(l=process.hrtime.bigint()),c++;let zt=Number((process.hrtime.bigint()-l)/1000000n);c>=10&&zt<6e4&&(console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.reconnect.storm",reconnectCount:c,connectionId:w})),p(),setTimeout(()=>process.exit(1),2e3));let Zi=Math.min(3e4,1e3*Math.pow(2,Math.min(c,5))),pn=Math.round(Zi+Math.random()*500);console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.reconnect.scheduled",delayMs:pn,reconnectCount:c,connectionId:w})),i=setTimeout(h,pn)}),y.on("error",m=>{console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.error",message:m.message,code:m.code,connectionId:w}))})}function p(){o&&(clearInterval(o),o=null),t.stopLivenessCheck(),Dc();for(let g of Ee.values())g();n.stopAll(),t.killAll(),s?.close()}function f(g){console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.signal",signal:g,connectionId:Zr})),p(),setTimeout(()=>process.exit(0),100)}process.on("SIGINT",()=>f("SIGINT")),process.on("SIGTERM",()=>f("SIGTERM")),process.on("SIGHUP",()=>f("SIGHUP")),process.on("uncaughtException",g=>{console.log(JSON.stringify({ts:Date.now(),level:"error",event:"daemon.uncaught",error:String(g),stack:g.stack,connectionId:Zr}));try{p()}catch{}setTimeout(()=>process.exit(1),2e3)}),h()}function el(t,e,r,n,s){switch(t.type){case"spawn":{if(console.log("[daemon] pty.spawn.start",{agentId:t.agentId,agentKey:t.agentKey,sessionId:t.sessionId,projectId:t.projectId,workspaceId:t.workspaceId,role:t.role}),t.agentKey==="sim_ios"){s.start(t.agentId);return}let i=pt.find(S=>S.key===t.agentKey);if(!i){e.readyState===k.OPEN&&e.send(JSON.stringify({type:"error",code:"AGENT_NOT_FOUND",message:`Agent '${t.agentKey}' is not installed on this machine`}));return}let o=fe.find(S=>S.key===t.agentKey),a=[];if(t.sessionId&&o?.resumeArgs)a=o.resumeArgs(t.sessionId),console.log("[daemon] pty.spawn.resume",{agentId:t.agentId,sessionId:t.sessionId}),t.agentKey==="claude"&&(Ee.get(t.agentId)?.(),Ee.set(t.agentId,Jr(t.agentId,t.sessionId,(S,E,v)=>{let I=r.getCurrentWs();I?.readyState===k.OPEN&&I.send(JSON.stringify({type:"panel_token_usage",agentId:S,usedPct:E,usedTokens:v,...We}))})));else if(o?.assignSessionId){let S=crypto.randomUUID(),E=t.agentKey==="kimi"?"--session":t.agentKey==="forge"?"--conversation-id":"--session-id";a=[...o.spawnArgs??[],E,S],e.readyState===k.OPEN&&(e.send(JSON.stringify({type:"session_started",agentId:t.agentId,sessionId:S})),console.log("[daemon] session.assigned",{agentId:t.agentId,sessionId:S})),t.agentKey==="claude"&&(Ee.get(t.agentId)?.(),Ee.set(t.agentId,Jr(t.agentId,S,(v,I,m)=>{let x=r.getCurrentWs();x?.readyState===k.OPEN&&x.send(JSON.stringify({type:"panel_token_usage",agentId:v,usedPct:I,usedTokens:m,...We}))})))}else a=[...o?.spawnArgs??[]],e.readyState===k.OPEN&&e.send(JSON.stringify({type:"session_started",agentId:t.agentId,sessionId:crypto.randomUUID()}));let c,l=!1,d,u;if(t.workspaceId){let S=$c(n.server),E=Jc(t.projectId??"",t.cwd,t.daemonLocalPath,n.projectPaths),v=E.path;if(u=E.source,u==="fallback_home"&&t.sessionId){let m=t.daemonLocalPath?"daemon_override_missing":"not_found";console.warn("[daemon] resume.cwd_fallback_blocked",{agentId:t.agentId,sessionId:t.sessionId,requestedCwd:t.cwd,projectId:t.projectId,reason:m}),e.readyState===k.OPEN&&e.send(JSON.stringify({type:"error",code:"CWD_MISSING_ON_DAEMON",message:`Cannot resume session \u2014 project path not found on this machine. Run: bridge-agent link-project ${t.projectId??"?"} <local-path>`,agentId:t.agentId,sessionId:t.sessionId}));return}let I=Vr(v);if(c={serverUrl:S,token:n.token,workspaceId:Zs(t.workspaceId),projectId:t.projectId?ei(t.projectId):void 0,agentId:t.agentId?Qs(t.agentId):void 0,personaId:t.personaId,cwd:v,projectEnv:I.env},t.agentKey==="claude"){let m=Uc(c);l=m.length>0,d=process.env.BRIDGE_MCP_URL?"http":"stdio",a=[...a,...m]}else if(t.agentKey==="codex"){let m=Vc(c);l=m.length>0,d="stdio",a=[...a,...m]}else if(t.agentKey==="qwen")l=Qc(c),d=l?"stdio":void 0;else if(t.agentKey==="kimi"){let m=qc(c);l=m.length>0,d=process.env.BRIDGE_MCP_URL?"http":"stdio",a=[...a,...m]}else t.agentKey==="forge"?(l=zc(c),d=l?"stdio":void 0):t.agentKey==="opencode"?(l=Xc(c),d=l?process.env.BRIDGE_MCP_URL?"http":"stdio":void 0):t.agentKey==="gemini"?(l=Zc(c),d=l?process.env.BRIDGE_MCP_URL?"http":"stdio":void 0):(l=!1,console.log("[daemon] mcp.config.skipped",{agentId:t.agentId,agentKey:t.agentKey,reason:"unsupported_agent_path"}));if($r("phase2a.verified_at")&&(E.source==="daemon_override"||E.source==="server_project")){let m=`${S}/api/workspaces/${t.workspaceId}/projects/${t.projectId}/machine-paths/${t.daemonId}/verify`;fetch(m,{method:"PATCH",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:"{}"}).catch(x=>{console.warn("[daemon] verify.patch_failed",{projectId:t.projectId,error:String(x)})})}if($r("phase2a.auto_register")&&(E.source==="daemon_override"||E.source==="server_project"))try{let m=(0,Ge.spawnSync)("git",["remote","get-url","origin"],{cwd:v,timeout:5e3,encoding:"utf-8"});if(m.status===0&&m.stdout&&m.stdout.trim()){let x=m.stdout.trim();t.projectId&&(n.projectPaths||(n.projectPaths={}),n.projectPaths[t.projectId]=v,J({projectPaths:n.projectPaths}));let G=`${S}/api/workspaces/${t.workspaceId}/projects/${t.projectId}/machine-paths`;fetch(G,{method:"POST",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:JSON.stringify({daemonId:t.daemonId,localPath:v,repoUrl:x})}).catch(zt=>{console.warn("[daemon] auto_register.post_failed",{projectId:t.projectId,error:String(zt)})}),console.log("[daemon] auto_register.ok",{projectId:t.projectId,localPath:v,repoUrl:x})}}catch(m){console.log("[daemon] auto_register.skipped",{projectId:t.projectId,reason:String(m)})}}let h=Gc(t.role,t.systemPrompt,t.agentId,t.workspaceId,t.projectId,t.groupId),p=Fc(t.agentKey,h,t.agentId);p.length>0&&(a=[...a,...p]);let f=Hc(t.agentKey,t.systemPrompt,t.agentId);f.length>0&&(a=[...a,...f]);let g=Math.max(1,Math.min(500,t.cols)),b=Math.max(1,Math.min(500,t.rows)),y=Date.now(),w="",D=0,P=!1,U=!1;if(r.spawn(t.agentId,t.agentKey,i.binaryPath,a,g,b,S=>{if(D+=S.length,t.agentKey==="gemini")try{let v=Buffer.from(S,"base64").toString("utf-8");if(v.includes("shell mode enabled"))ve.get(t.agentId)||(ve.set(t.agentId,!0),console.log("[daemon] gemini.shell_mode.entered",{agentId:t.agentId.slice(-8)}));else if(v.includes("Type your message")&&(ve.get(t.agentId)&&(ve.set(t.agentId,!1),console.log("[daemon] gemini.shell_mode.exited",{agentId:t.agentId.slice(-8)})),!Ue.get(t.agentId))){Ue.set(t.agentId,!0);let I=ke.get(t.agentId)??[];ke.delete(t.agentId),console.log("[daemon] gemini.ready",{agentId:t.agentId.slice(-8),flushing:I.length}),I.length>0&&setTimeout(()=>{for(let m of I)r.write(t.agentId,m,"orchestrator");setTimeout(()=>{r.write(t.agentId,Buffer.from("\r").toString("base64"),"orchestrator")},1e3)},500)}}catch{}try{let v=Buffer.from(S,"base64").toString("utf-8");if(t.agentKey==="kimi"&&t.role&&!U&&Date.now()-y<3e4&&(/yolo agent/.test(v)||/●/.test(v)||/○/.test(v))){U=!0;let I=h;if(I){let m=Nc(I),x=Buffer.from(m).toString("base64");r.write(t.agentId,x,"orchestrator"),console.log("[daemon] kimi.role.injected",{agentId:t.agentId,role:t.role})}}}catch{}if(!w)try{let v=Buffer.from(S,"base64").toString("utf-8"),I=Bc(v).replace(/\x00/g,"").trim();if(I&&(w=Mc(I)),t.agentKey==="codex"&&!P&&Date.now()-y<2e4&&/included in your plan for free|let[’']s build together/i.test(I)&&/yes|no|\[y\/n\]|\(y\/n\)|y\/n/i.test(I)){P=!0;let m=Buffer.from("y").toString("base64");r.write(t.agentId,m,"orchestrator"),console.log("[daemon] codex.onboarding.auto_ack",{agentId:t.agentId})}}catch{}let E=r.getCurrentWs();E?.readyState===k.OPEN&&E.send(JSON.stringify({type:"output",agentId:t.agentId,data:S})),Ac(t.agentId,()=>r.getCurrentWs())},(S,E)=>{let v=Date.now()-y,I=v<=jc;console.log("[daemon] pty.spawn.result",{agentId:t.agentId,agentKey:t.agentKey,daemonId:t.daemonId,exitCode:S,signal:E,uptimeMs:v,earlyExit:I,outputBytes:D,firstOutputSnippet:w||void 0});let m=r.getCurrentWs();I&&m?.readyState===k.OPEN&&m.send(JSON.stringify({type:"error",code:"SPAWN_FAILED",message:`Early exit: agent=${t.agentKey} code=${S??"null"} signal=${E??"null"} snippet="${w||"no output"}"`})),m?.readyState===k.OPEN&&m.send(JSON.stringify({type:"exit",agentId:t.agentId,exitCode:S,signal:E})),Tc(t.agentId),ve.delete(t.agentId),Ue.delete(t.agentId),ke.delete(t.agentId),Promise.all([(0,dt.unlink)(O.default.join(R.default.tmpdir(),`bridge-persona-${t.agentId}.md`)),(0,dt.unlink)(O.default.join(R.default.tmpdir(),`bridge-role-${t.agentId}.md`)),(0,dt.unlink)(O.default.join(R.default.tmpdir(),`bridge-mcp-${t.agentId}.json`)),(0,dt.unlink)(O.default.join(R.default.tmpdir(),`bridge-mcp-kimi-${t.agentId}.json`))].map(x=>x.catch(()=>{}))).catch(()=>{})},c)){if(t.agentKey==="gemini"&&setTimeout(()=>{if(!Ue.get(t.agentId)){Ue.set(t.agentId,!0);let S=ke.get(t.agentId)??[];ke.delete(t.agentId),S.length>0&&(console.warn("[daemon] gemini.ready.timeout_fallback",{agentId:t.agentId.slice(-8),flushing:S.length}),setTimeout(()=>{for(let E of S)r.write(t.agentId,E,"orchestrator");setTimeout(()=>{r.write(t.agentId,Buffer.from("\r").toString("base64"),"orchestrator")},1e3)},500))}},3e4),u==="fallback_home"&&e.readyState===k.OPEN){let S=t.daemonLocalPath?"daemon_override_missing":"not_found";console.warn("[daemon] cwd_fallback",{agentId:t.agentId,requestedCwd:t.cwd,actualCwd:R.default.homedir(),reason:S,projectId:t.projectId,daemonId:t.daemonId}),e.send(JSON.stringify({type:"cwd_fallback",agentId:t.agentId,requestedCwd:t.cwd,actualCwd:R.default.homedir(),source:"fallback_home",reason:S,projectId:t.projectId,daemonId:t.daemonId}))}e.readyState===k.OPEN&&e.send(JSON.stringify({type:"mcp_status",agentId:t.agentId,mcpConfigured:l,transport:l?d:void 0,projectId:c?.projectId,effectiveCwd:c?.cwd,cwdSource:u}))}else{let E=r.getLastError(t.agentId)?.includes("posix_spawnp failed")&&Rc(t.agentKey);e.readyState===k.OPEN&&(E?e.send(JSON.stringify({type:"error",code:"SPAWN_HELPER_BROKEN",message:"node-pty spawn-helper is not executable. Upgrade bridge-agent to v0.2.10+."})):e.send(JSON.stringify({type:"error",code:"SPAWN_FAILED",message:`Failed to spawn panel ${t.agentId}`})))}e.readyState===k.OPEN&&e.send(JSON.stringify({type:"agent_spawned",agentId:t.agentId,agentKey:t.agentKey,daemonId:t.daemonId,role:t.role,personaId:t.personaId}));break}case"input":{if(r.getAgentKey(t.agentId)==="gemini"&&t.source==="orchestrator"){if(!Ue.get(t.agentId)){let o=ke.get(t.agentId)??[];o.push(t.data),ke.set(t.agentId,o),console.log("[daemon] gemini.input.buffered",{agentId:t.agentId.slice(-8),queued:o.length});break}if(ve.get(t.agentId)){r.write(t.agentId,Buffer.from("\x1B").toString("base64"),"user"),ve.set(t.agentId,!1),console.log("[daemon] gemini.shell_mode.esc_before_inject",{agentId:t.agentId.slice(-8)}),setTimeout(()=>{r.write(t.agentId,t.data,t.source)},100);break}}r.write(t.agentId,t.data,t.source);break}case"kill":console.log("[daemon] kill.received",{agentId:t.agentId,force:t.force??!1}),Ee.get(t.agentId)?.(),Ee.delete(t.agentId),s.stop(t.agentId),r.kill(t.agentId,t.force);break;case"resize":r.resize(t.agentId,t.cols,t.rows);break;case"sim_tap":case"sim_swipe":case"sim_key":case"sim_button":case"sim_get_source":case"sim_subscribe":case"sim_unsubscribe":case"sim_healthcheck":case"sim_install_run":case"sim_install_cancel":s.handle(t);break;case"detect_agents":Promise.all([mr(n.agentPaths),Wr()]).then(([i,o])=>{pt=o?[...i,o]:i,e.readyState===k.OPEN&&e.send(JSON.stringify({type:"agents",list:pt}))});break;case"dir_list":{let i=R.default.homedir(),o=(t.path||"~").replace(/^~/,i),a=O.default.resolve(o);if(a!==i&&!a.startsWith(i+O.default.sep)){e.readyState===k.OPEN&&e.send(JSON.stringify({type:"error",code:"INVALID_MSG",message:"Path outside home directory"}));return}try{let c=N.default.readdirSync(a,{withFileTypes:!0}).filter(l=>l.isDirectory()&&!l.name.startsWith(".")).map(l=>({name:l.name,path:O.default.join(a,l.name)})).sort((l,d)=>l.name.localeCompare(d.name));e.readyState===k.OPEN&&e.send(JSON.stringify({type:"dir_list_result",requestId:t.requestId,path:a,entries:c}))}catch(c){e.readyState===k.OPEN&&e.send(JSON.stringify({type:"dir_list_result",requestId:t.requestId,path:a,entries:[],error:c instanceof Error?c.message:"Cannot read directory"}))}break}case"persona_apply":{let i=r.getAgentKey(t.agentId);if(!i){console.warn("[daemon] persona_apply.no_panel",{agentId:t.agentId});break}let o;t.systemPrompt?o=`[BRIDGE-ORCH] Persona updated: ${t.personaId}
|
|
410
410
|
${t.systemPrompt}
|
|
411
411
|
`:o=`[BRIDGE-ORCH] Persona assigned: ${t.personaId}
|
|
412
412
|
Call bridge_get_persona({ id: "${t.personaId}" }) immediately for your authoritative operating instructions.
|
|
@@ -448,6 +448,6 @@ exec "$(command -v node)" "${t}" start
|
|
|
448
448
|
${c} </dict>
|
|
449
449
|
</dict>
|
|
450
450
|
</plist>
|
|
451
|
-
`;try{return(0,j.writeFileSync)(r,h,"utf-8"),!0}catch(p){return console.warn("[bridge] launchd.plist.write.failed",{error:String(p)}),!1}}function rl(){let t=le(),e=W.default.join(Kt,t);try{return(0,xe.execSync)(`launchctl kickstart -kp gui/$(id -u)/${t} 2>/dev/null; launchctl unload "${e}" 2>/dev/null; launchctl load "${e}"`,{stdio:"pipe"}),{ok:!0,permissionDenied:!1}}catch(r){let n=String(r);return{ok:!1,permissionDenied:n.includes("Permission denied")||n.includes("not allowed")||n.includes("bootstrap")}}}function nl(t){let{out:e,err:r}=$t();try{let n=(0,xe.spawn)(t,["start"],{detached:!0,stdio:"ignore",env:{...process.env,PATH:Li(),BRIDGE_DAEMON:"1"}});n.unref(),setTimeout(()=>{n.pid&&process.kill(n.pid,0)?(console.log("[bridge] daemon.pid",{pid:n.pid}),console.log("[bridge] background.ok",{log:e})):console.error("[bridge] background.failed \u2014 check: tail -f",{log:r})},2e3)}catch(n){console.error("[bridge] background.spawn.failed",{error:String(n)})}}function sl(){let t=st(),e=Date.now()+6e3,r=()=>{if(Date.now()>e){console.error("[bridge] health.verify.timeout \u2014 daemon may have crashed immediately");return}try{let s=require("node:http").get(`http://127.0.0.1:${t}/health`,i=>{i.statusCode===200?console.log("[bridge] health.verify.ok"):setTimeout(r,500)});s.on("error",()=>{setTimeout(r,500)}),s.setTimeout(1e3,()=>{s.destroy(),setTimeout(r,500)})}catch{setTimeout(r,500)}};setTimeout(r,1e3)}function il(){ji();let t=new wt;nn=t,Ri(t),t.startLivenessCheck(6e4);let e=st(),r=(0,Ni.createServer)((n,s)=>{let i=Ti(),o=JSON.stringify({status:"ok",connected:i,uptime:process.uptime(),version:"0.10.
|
|
451
|
+
`;try{return(0,j.writeFileSync)(r,h,"utf-8"),!0}catch(p){return console.warn("[bridge] launchd.plist.write.failed",{error:String(p)}),!1}}function rl(){let t=le(),e=W.default.join(Kt,t);try{return(0,xe.execSync)(`launchctl kickstart -kp gui/$(id -u)/${t} 2>/dev/null; launchctl unload "${e}" 2>/dev/null; launchctl load "${e}"`,{stdio:"pipe"}),{ok:!0,permissionDenied:!1}}catch(r){let n=String(r);return{ok:!1,permissionDenied:n.includes("Permission denied")||n.includes("not allowed")||n.includes("bootstrap")}}}function nl(t){let{out:e,err:r}=$t();try{let n=(0,xe.spawn)(t,["start"],{detached:!0,stdio:"ignore",env:{...process.env,PATH:Li(),BRIDGE_DAEMON:"1"}});n.unref(),setTimeout(()=>{n.pid&&process.kill(n.pid,0)?(console.log("[bridge] daemon.pid",{pid:n.pid}),console.log("[bridge] background.ok",{log:e})):console.error("[bridge] background.failed \u2014 check: tail -f",{log:r})},2e3)}catch(n){console.error("[bridge] background.spawn.failed",{error:String(n)})}}function sl(){let t=st(),e=Date.now()+6e3,r=()=>{if(Date.now()>e){console.error("[bridge] health.verify.timeout \u2014 daemon may have crashed immediately");return}try{let s=require("node:http").get(`http://127.0.0.1:${t}/health`,i=>{i.statusCode===200?console.log("[bridge] health.verify.ok"):setTimeout(r,500)});s.on("error",()=>{setTimeout(r,500)}),s.setTimeout(1e3,()=>{s.destroy(),setTimeout(r,500)})}catch{setTimeout(r,500)}};setTimeout(r,1e3)}function il(){ji();let t=new wt;nn=t,Ri(t),t.startLivenessCheck(6e4);let e=st(),r=(0,Ni.createServer)((n,s)=>{let i=Ti(),o=JSON.stringify({status:"ok",connected:i,uptime:process.uptime(),version:"0.10.6",activePanels:nn?.getLiveAgentIds().length??0});s.writeHead(i?200:503,{"Content-Type":"application/json"}),s.end(o)});r.listen(e,"127.0.0.1",()=>{console.log(`[bridge] health. listening on 127.0.0.1:${e}`)}),r.on("error",n=>{console.error("[bridge] health.error",{error:n.message})})}function Bi(){let t=process.env.BRIDGE_DAEMON==="1"||process.argv.includes("--daemon");if(!t&&!process.env.BRIDGE_PROFILE){let l=process.argv[1]??"";(l.includes("packages/daemon/dist")||l.includes("packages/daemon/src"))&&(console.warn("[bridge] WARNING: running monorepo daemon without --profile \u2014 will use prod config (~/.jerico/settings.json)."),console.warn("[bridge] If this is unintentional, stop and rerun with: node packages/daemon/dist/index.js --profile dev start"))}if(console.log("[bridge] Starting bridge-agent daemon..."),t){il();return}let e=tl();if(!e.ok){let l=e.err,d=Me();l.code==="EEXIST"?console.warn("[bridge] start.aborted.already.running"):l.code==="EACCES"||l.code==="EPERM"?console.warn(`[bridge] start.aborted.permission_denied \u2014 cannot write ${d} (${l.code}). Directory may be owned by root from \`sudo npm install\`. Try: sudo chown -R "$(whoami):staff" ~/.bridge`):l.code==="ENOENT"?console.warn(`[bridge] start.aborted.lock_dir_missing \u2014 ${d}`):console.warn(`[bridge] start.aborted.lock_error \u2014 ${l.code}: ${l.message}`),process.exit(1)}let r=ft(),n=Jt(r),{ok:s,permissionDenied:i}=n?rl():{ok:!1,permissionDenied:!1},o=W.default.join(Kt,le()),{out:a,err:c}=$t();if(s){console.log("[bridge] launchd.ok \u2014 managed, auto-restart enabled"),console.log("[bridge] logs: tail -f",{out:a,err:c}),sl(),process.exit(0);return}i&&(console.warn("[bridge] launchd.permission.denied"),console.warn("[bridge] \u2192 Auto-start on login requires:"),console.warn(`[bridge] sudo launchctl bootstrap gui/$(id -u) "${o}"`),console.warn(`[bridge] Falling back to background process...
|
|
452
452
|
`)),nl(r),process.exit(0)}var Mi=_(require("https")),$i=_(require("http"));Se();de();var ol="https://lcars.jerico.appnova.io";function al(t){return(t??"").trim()}async function Ui(t,e=!1,r){let n=!(t&&t.trim()),s=n?ol:t.trim();console.log("[bridge] Starting auth flow..."),console.log(`[bridge] Server: ${s}${n?" (default)":""}`),console.log("[bridge] Open this URL to generate a daemon token:"),console.log(` ${s}/connect`);let i=al(r);i&&console.log("[bridge] Using token from --token"),e&&(i?console.log("[bridge] --no-browser ignored because --token is provided."):(console.log("[bridge] --no-browser: exiting after printing URL."),process.exit(0)));let o=i;o||(console.log(),console.log("[bridge] After authenticating, paste your token here:"),o=await cl()),o||(console.error("[bridge] No token provided. Exiting."),process.exit(1)),await ll(s,o)||(console.error("[bridge] Token validation failed. Please try again."),process.exit(1));let l=s.replace(/^https?:\/\//,d=>d.startsWith("https")?"wss://":"ws://").replace(/\/?$/,"/ws/daemon");J({server:l,token:o,name:process.env.HOSTNAME??"My Machine"}),console.log(`[bridge] Auth successful! Config saved to ${re()}`),console.log("[bridge] Run: bridge-agent start"),process.exit(0)}async function cl(){return new Promise(t=>{process.stdout.write("Token: ");let e="";process.stdin.setEncoding("utf-8"),process.stdin.on("data",r=>{e+=r,e.includes(`
|
|
453
|
-
`)&&(process.stdin.pause(),t(e.trim()))}),process.stdin.resume()})}async function ll(t,e){return new Promise(r=>{let n=new URL("/api/tokens/validate",t),s=n.protocol==="https:",i=s?Mi.default:$i.default,o={hostname:n.hostname,port:n.port||(s?443:80),path:n.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}},a=i.request(o,c=>{r(c.statusCode===200)});a.on("error",()=>r(!1)),a.end()})}var Wi=_(require("https")),Gi=_(require("http")),sn=_(require("fs")),on=_(require("path")),Fi=require("node:crypto");Se();function dl(t){return t.replace(/^wss?:/,e=>e==="wss:"?"https:":"http:").replace(/\/ws(\/.*)?$/,"")}async function Hi(t,e,r){let n=ne(),s=(0,Fi.createHash)("sha256").update(n.token).digest("hex"),i=dl(n.server),o=on.default.resolve(r);on.default.isAbsolute(o)||(console.error("[bridge] link-project: path must be absolute"),process.exit(1)),sn.default.existsSync(o)||(console.error("[bridge] link-project: path does not exist:",o),process.exit(1)),sn.default.statSync(o).isDirectory()||(console.error("[bridge] link-project: path must be a directory:",o),process.exit(1));let c=new URL(`/api/workspaces/${t}/projects/${e}/machine-paths`,i),l=c.protocol==="https:",d=l?Wi.default:Gi.default;n.projectPaths={...n.projectPaths??{},[e]:o},J({projectPaths:n.projectPaths}),console.log("[cli] link-project.local_json_written",{projectId:e,path:o});let u=JSON.stringify({daemonId:s,localPath:o,machineFingerprint:rn()}),h=await new Promise((p,f)=>{let g=d.request({hostname:c.hostname,port:c.port||(l?443:80),path:c.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n.token}`,"Content-Length":Buffer.byteLength(u)}},b=>{let y="";b.on("data",w=>{y+=w}),b.on("end",()=>{if(b.statusCode===200)p(200);else{try{let w=JSON.parse(y);console.error("[bridge] link-project failed:",w.error??`HTTP ${b.statusCode}`)}catch{console.error("[bridge] link-project failed:",`HTTP ${b.statusCode}`)}p(b.statusCode??0)}})});g.on("error",b=>{f(b)}),g.write(u),g.end()});h===200?(console.log("[cli] link-project.server_success",{projectId:e}),console.log("[cli] link-project.success (dual-write)"),console.log(` workspace: ${t}`),console.log(` project: ${e}`),console.log(` daemon: ${s.slice(0,16)}\u2026`),console.log(` path: ${o}`),console.log("[cli] Next spawn for this project will use the linked path."),process.exit(0)):(console.warn("[cli] link-project.server_fail",{projectId:e,statusCode:h}),console.log("[cli] Local override still active \u2014 path will work on this machine"),process.exit(0))}Se();function ul(t){return t.replace(/^wss?:/,e=>e==="wss:"?"https:":"http:").replace(/\/ws(\/.*)?$/,"")}async function qi(){let t=ne(),e=ul(t.server),r=await fetch(`${e}/api/admin/cleanup-orphans`,{method:"POST",headers:{Authorization:`Bearer ${t.token}`,"Content-Type":"application/json"},body:"{}"});r.ok||(console.error(`[cli] cleanup-orphans: HTTP ${r.status}`),process.exit(1));let{deleted:n}=await r.json();console.log(`[cli] cleanup-orphans: deleted ${n} orphaned path ${n===1?"entry":"entries"}`),process.exit(0)}var an=require("node:child_process"),gt=require("node:fs"),cn=_(require("path"));de();var Vi=require("node:os"),pl=cn.default.join((0,Vi.homedir)(),"Library","LaunchAgents");function Ki(){let t=le(),e=t.replace(".plist",""),r=cn.default.join(pl,t);try{(0,an.execSync)(`launchctl bootout gui/$(id -u)/${e}`,{stdio:"pipe"}),console.log("[bridge] launchd.stopped \u2014 daemon unloaded")}catch{try{(0,gt.existsSync)(r)?((0,an.execSync)(`launchctl unload "${r}"`,{stdio:"pipe"}),console.log("[bridge] launchd.unloaded \u2014 daemon stopped")):console.warn("[bridge] launchd.stop.failed \u2014 plist not found, daemon may not be running via launchd")}catch{console.warn("[bridge] launchd.stop.failed \u2014 daemon may not be running via launchd"),console.warn(`[bridge] Manual: launchctl bootout gui/$(id -u)/${e}`)}}let n=Me();if((0,gt.existsSync)(n))try{(0,gt.unlinkSync)(n),console.log("[bridge] lock.cleaned")}catch{}}var He=require("node:child_process"),B=require("node:fs"),un=require("node:os"),Xi=_(require("node:http")),mt=_(require("path"));de();Se();var Ji=require("node:child_process");function hl(t,e){let r=t.split("."),n=e.split(".");for(let s=0;s<3;s++){let i=parseInt(r[s]??"0",10),o=parseInt(n[s]??"0",10);if(isNaN(i)||isNaN(o))break;if(i!==o)return i-o}return t.localeCompare(e)}function ln(t,e){return hl(t,e)>0}function dn(t="latest"){let r=["latest","beta","next","canary"].includes(t)?t:"latest";try{let s=(0,Ji.execSync)(`npm view bridge-agent@${r} version`,{timeout:5e3,stdio:"pipe"}).toString().trim();return/^\d+\.\d+\.\d+/.test(s)?s:null}catch{return null}}function Yi(t="latest",e){let r=dn(t);return r?ln(e,r)?{updateAvailable:!1,currentVersion:e,latestVersion:r,reason:"ahead_of_channel"}:e===r?{updateAvailable:!1,currentVersion:e,latestVersion:r,reason:"up_to_date"}:{updateAvailable:!0,latestVersion:r,currentVersion:e}:{updateAvailable:!1,currentVersion:e,reason:"registry_unreachable"}}var Yt=mt.default.join((0,un.homedir)(),".bridge"),qe=mt.default.join(Yt,"update.lock"),fl=mt.default.join(Yt,"update-state.json"),Ru=mt.default.join((0,un.homedir)(),"Library","LaunchAgents");function gl(){if((0,B.existsSync)(qe))try{let{pid:t}=JSON.parse((0,B.readFileSync)(qe,"utf8"));if(t&&process.kill(t,0))return;(0,B.unlinkSync)(qe)}catch{try{(0,B.unlinkSync)(qe)}catch{}}}function ml(){try{(0,B.mkdirSync)(Yt,{recursive:!0})}catch{}gl();try{let t=(0,B.openSync)(qe,"wx");return(0,B.writeSync)(t,JSON.stringify({pid:process.pid,startedAt:Date.now()})),(0,B.closeSync)(t),{ok:!0}}catch(t){return{ok:!1,err:t}}}function pe(){try{(0,B.unlinkSync)(qe)}catch{}}function _l(t){try{(0,B.mkdirSync)(Yt,{recursive:!0})}catch{}(0,B.writeFileSync)(fl,JSON.stringify(t,null,2),{mode:384})}function zi(t,e=3e4){let r=st(),n=Date.now()+e;return new Promise(s=>{let i=()=>{if(Date.now()>n){s(!1);return}try{let o=Xi.default.get(`http://127.0.0.1:${r}/health`,a=>{let c="";a.on("data",l=>{c+=l}),a.on("end",()=>{try{if(JSON.parse(c).version===t){s(!0);return}}catch{}setTimeout(i,500)})});o.on("error",()=>{setTimeout(i,500)}),o.setTimeout(1e3,()=>{o.destroy(),setTimeout(i,500)})}catch{setTimeout(i,500)}};setTimeout(i,1e3)})}async function Qi(t){let e="0.10.5",r=ne(),n=t.channel??r.updateChannel??"latest",s=ft();if((s.includes("packages/daemon/dist")||s.includes("packages/daemon/src"))&&(console.error("[bridge] update.refused: running from monorepo \u2014 cannot self-update a dev checkout."),console.error("[bridge] To test update logic, install the published package globally:"),console.error("[bridge] npm i -g bridge-agent"),process.exit(1)),t.check){let p=Yi(n,e);p.updateAvailable&&(console.log(`[bridge] update.available: ${e} \u2192 ${p.latestVersion} (channel: ${n})`),process.exit(10));let f=p.reason??"unknown";console.log(`[bridge] update.unavailable: ${e} (channel: ${n}, reason: ${f})`),process.exit(0)}let i=dn(n);i||(console.error("[bridge] update.failed: cannot reach npm registry"),process.exit(1)),e===i&&(console.log(`[bridge] update.up_to_date: ${e} (channel: ${n})`),t.saveChannel&&(J({updateChannel:n}),console.log(`[bridge] update.channel.saved: ${n}`)),process.exit(0)),ln(e,i)&&(console.log(`[bridge] update.ahead: ${e} > ${i} (channel: ${n}).`),console.log("[bridge] You are on a build ahead of the public channel. Update not available."),process.exit(0)),console.log(`[bridge] update.available: ${e} \u2192 ${i} (channel: ${n})`);let o=Di()?.getLiveAgentIds().length??0;o>0&&!t.force&&(console.error(`[bridge] update.blocked: ${o} active panel(s) \u2014 cannot update without --force`),console.error("[bridge] Use --force to bypass this safety check, or stop panels first."),console.error("[bridge] bridge-agent stop # stop the daemon"),process.exit(1)),o>0&&t.force&&console.log(`[bridge] update.force: ${o} active panel(s) will be terminated during update.`),t.saveChannel&&(J({updateChannel:n}),console.log(`[bridge] update.channel.saved: ${n}`));let a=ml();if(!a.ok){let p=a.err;p.code==="EEXIST"?console.error("[bridge] update.aborted: another update is already in progress (update.lock exists)"):console.error(`[bridge] update.lock.failed: ${p.code} \u2014 ${p.message}`),process.exit(1)}console.log(`[bridge] update.installing: bridge-agent@${n}...`);let c=!1;try{(0,He.execSync)(`npm install -g bridge-agent@${n}`,{stdio:"inherit",timeout:12e4}),c=!0}catch(p){console.error(`[bridge] update.install.failed: ${String(p)}`),c=!1}if(!c){console.error(`[bridge] update.install.failed: rolling back to bridge-agent@${e}...`);try{(0,He.execSync)(`npm install -g bridge-agent@${e}`,{stdio:"inherit",timeout:12e4}),console.log("[bridge] update.install.rollback.ok \u2014 restored previous version")}catch(p){pe(),console.error(`[bridge] update.install.rollback.FAILED: ${String(p)}`),console.error("[bridge] \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.error("[bridge] \u2551 CRITICAL: npm install failed AND rollback failed. \u2551"),console.error("[bridge] \u2551 Binary may be broken. Manual recovery needed. \u2551"),console.error(`[bridge] \u2551 Try: npm install -g bridge-agent@${e} \u2551`),console.error("[bridge] \u2551 Then: bridge-agent start \u2551"),console.error("[bridge] \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),process.exit(1)}pe(),console.error("[bridge] update.aborted: npm install failed, daemon is on previous version."),process.exit(1)}let l=ft();Jt(l)||(pe(),console.error("[bridge] update.failed: could not write launchd plist"),console.error("[bridge] npm install succeeded but launchd setup failed. Run: bridge-agent start"),process.exit(1));let d=le();try{(0,He.execSync)(`launchctl kickstart -kp gui/$(id -u)/${d}`,{stdio:"pipe"}),console.log("[bridge] update.kickstart.ok \u2014 daemon restarting with new version")}catch{pe(),console.error("[bridge] update.failed: launchctl kickstart failed"),console.error(`[bridge] Manual restart: launchctl kickstart -kp gui/$(id -u)/${d}`),process.exit(1)}console.log(`[bridge] update.verifying: polling health for version ${i}...`),await zi(i,3e4)&&(_l({previousVersion:e,channel:n,installedAt:new Date().toISOString()}),pe(),console.log(`[bridge] update.complete: ${e} \u2192 ${i}`),process.exit(0)),console.error(`[bridge] update.health.timeout: daemon did not report version ${i} within 30s`),console.error(`[bridge] update.rolling_back: reinstalling bridge-agent@${e}...`);try{(0,He.execSync)(`npm install -g bridge-agent@${e}`,{stdio:"inherit",timeout:12e4}),console.log("[bridge] update.rollback.install.ok")}catch(p){pe(),console.error(`[bridge] update.rollback.install.FAILED: ${String(p)}`),console.error("[bridge] \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.error("[bridge] \u2551 CRITICAL: update failed AND rollback failed. \u2551"),console.error("[bridge] \u2551 Daemon may be broken. Manual recovery needed. \u2551"),console.error(`[bridge] \u2551 Try: npm install -g bridge-agent@${e} \u2551`),console.error("[bridge] \u2551 Then: bridge-agent start \u2551"),console.error("[bridge] \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),process.exit(1)}try{let p=ft();Jt(p),(0,He.execSync)(`launchctl kickstart -kp gui/$(id -u)/${d}`,{stdio:"pipe"}),console.log("[bridge] update.rollback.kickstart.ok")}catch{pe(),console.error("[bridge] update.rollback.kickstart.failed \u2014 daemon may need manual restart"),console.error(`[bridge] Run: launchctl kickstart -kp gui/$(id -u)/${d}`),process.exit(1)}console.log(`[bridge] update.rollback.verifying: polling for version ${e}...`);let h=await zi(e,3e4);pe(),h&&(console.log(`[bridge] update.rollback.complete: restored to ${e}`),console.log(`[bridge] Update to ${i} failed \u2014 daemon is running on previous version.`),process.exit(1)),console.error("[bridge] \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.error("[bridge] \u2551 CRITICAL: update failed AND rollback health-check failed.\u2551"),console.error("[bridge] \u2551 Daemon may still be running \u2014 DO NOT KILL IT. \u2551"),console.error("[bridge] \u2551 Manual check: bridge-agent status \u2551"),console.error("[bridge] \u2551 Check logs: tail -f ~/bridge-daemon.log \u2551"),console.error("[bridge] \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),process.exit(1)}var se=new On;se.name("bridge-agent").description("Bridge local agent \u2014 connects your AI tools to Jerico").version("0.10.5").option("--profile <name>","Config profile name (e.g. dev). Isolates config, lock, and fingerprint from the default prod profile.").hook("preAction",t=>{let e=t.opts().profile;e&&(process.env.BRIDGE_PROFILE=e)});se.command("start").description("Start the bridge-agent daemon").option("--health-port <port>","Health check HTTP port (default: 3101 prod, 3102 for --profile <name>). Overrides the per-profile default.").action(t=>{t.healthPort&&(process.env.HEALTH_PORT=t.healthPort),Bi()});se.command("auth").description("Authenticate with Bridge server").option("-s, --server <url>","Server URL (default: https://lcars.jerico.appnova.io)").option("-t, --token <token>","Use token non-interactively").option("--no-browser","Print auth URL without opening browser or interactive prompt").action(t=>{Ui(t.server,!t.browser,t.token)});se.command("link-project <workspace-id> <project-id> <local-path>").description("Link a local directory to a project for this machine (Issue #152)").action((t,e,r)=>{Hi(t,e,r)});se.command("cleanup-orphans").description("Remove orphaned daemon_project_paths rows for this user").action(()=>{qi()});se.command("status").description("Show connection status").action(async()=>{try{let{loadConfig:t}=await Promise.resolve().then(()=>(Se(),mi)),e=t();console.log("[bridge] Config found"),console.log(" Server:",e.server),console.log(" Name:",e.name)}catch{console.log("[bridge] Not authenticated. Run: bridge-agent auth")}});se.command("stop").description("Stop the bridge-agent daemon").action(()=>{Ki()});se.command("update").description("Update bridge-agent to the latest version (or a specific channel)").option("--check","Check for update availability (exit 0 if up-to-date or ahead, 10 if update available)").option("--channel <name>","npm dist-tag channel (latest, beta, next, canary)").option("--save-channel","Persist the channel to config (default: only used for this run)").option("--force","Bypass active-panel safety block (allows update with live panels)").option("--yes","Non-interactive mode (skip TTY prompts; still refuses if panels are active without --force)").action(t=>{Qi(t)});se.parse();
|
|
453
|
+
`)&&(process.stdin.pause(),t(e.trim()))}),process.stdin.resume()})}async function ll(t,e){return new Promise(r=>{let n=new URL("/api/tokens/validate",t),s=n.protocol==="https:",i=s?Mi.default:$i.default,o={hostname:n.hostname,port:n.port||(s?443:80),path:n.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}},a=i.request(o,c=>{r(c.statusCode===200)});a.on("error",()=>r(!1)),a.end()})}var Wi=_(require("https")),Gi=_(require("http")),sn=_(require("fs")),on=_(require("path")),Fi=require("node:crypto");Se();function dl(t){return t.replace(/^wss?:/,e=>e==="wss:"?"https:":"http:").replace(/\/ws(\/.*)?$/,"")}async function Hi(t,e,r){let n=ne(),s=(0,Fi.createHash)("sha256").update(n.token).digest("hex"),i=dl(n.server),o=on.default.resolve(r);on.default.isAbsolute(o)||(console.error("[bridge] link-project: path must be absolute"),process.exit(1)),sn.default.existsSync(o)||(console.error("[bridge] link-project: path does not exist:",o),process.exit(1)),sn.default.statSync(o).isDirectory()||(console.error("[bridge] link-project: path must be a directory:",o),process.exit(1));let c=new URL(`/api/workspaces/${t}/projects/${e}/machine-paths`,i),l=c.protocol==="https:",d=l?Wi.default:Gi.default;n.projectPaths={...n.projectPaths??{},[e]:o},J({projectPaths:n.projectPaths}),console.log("[cli] link-project.local_json_written",{projectId:e,path:o});let u=JSON.stringify({daemonId:s,localPath:o,machineFingerprint:rn()}),h=await new Promise((p,f)=>{let g=d.request({hostname:c.hostname,port:c.port||(l?443:80),path:c.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n.token}`,"Content-Length":Buffer.byteLength(u)}},b=>{let y="";b.on("data",w=>{y+=w}),b.on("end",()=>{if(b.statusCode===200)p(200);else{try{let w=JSON.parse(y);console.error("[bridge] link-project failed:",w.error??`HTTP ${b.statusCode}`)}catch{console.error("[bridge] link-project failed:",`HTTP ${b.statusCode}`)}p(b.statusCode??0)}})});g.on("error",b=>{f(b)}),g.write(u),g.end()});h===200?(console.log("[cli] link-project.server_success",{projectId:e}),console.log("[cli] link-project.success (dual-write)"),console.log(` workspace: ${t}`),console.log(` project: ${e}`),console.log(` daemon: ${s.slice(0,16)}\u2026`),console.log(` path: ${o}`),console.log("[cli] Next spawn for this project will use the linked path."),process.exit(0)):(console.warn("[cli] link-project.server_fail",{projectId:e,statusCode:h}),console.log("[cli] Local override still active \u2014 path will work on this machine"),process.exit(0))}Se();function ul(t){return t.replace(/^wss?:/,e=>e==="wss:"?"https:":"http:").replace(/\/ws(\/.*)?$/,"")}async function qi(){let t=ne(),e=ul(t.server),r=await fetch(`${e}/api/admin/cleanup-orphans`,{method:"POST",headers:{Authorization:`Bearer ${t.token}`,"Content-Type":"application/json"},body:"{}"});r.ok||(console.error(`[cli] cleanup-orphans: HTTP ${r.status}`),process.exit(1));let{deleted:n}=await r.json();console.log(`[cli] cleanup-orphans: deleted ${n} orphaned path ${n===1?"entry":"entries"}`),process.exit(0)}var an=require("node:child_process"),gt=require("node:fs"),cn=_(require("path"));de();var Vi=require("node:os"),pl=cn.default.join((0,Vi.homedir)(),"Library","LaunchAgents");function Ki(){let t=le(),e=t.replace(".plist",""),r=cn.default.join(pl,t);try{(0,an.execSync)(`launchctl bootout gui/$(id -u)/${e}`,{stdio:"pipe"}),console.log("[bridge] launchd.stopped \u2014 daemon unloaded")}catch{try{(0,gt.existsSync)(r)?((0,an.execSync)(`launchctl unload "${r}"`,{stdio:"pipe"}),console.log("[bridge] launchd.unloaded \u2014 daemon stopped")):console.warn("[bridge] launchd.stop.failed \u2014 plist not found, daemon may not be running via launchd")}catch{console.warn("[bridge] launchd.stop.failed \u2014 daemon may not be running via launchd"),console.warn(`[bridge] Manual: launchctl bootout gui/$(id -u)/${e}`)}}let n=Me();if((0,gt.existsSync)(n))try{(0,gt.unlinkSync)(n),console.log("[bridge] lock.cleaned")}catch{}}var He=require("node:child_process"),B=require("node:fs"),un=require("node:os"),Xi=_(require("node:http")),mt=_(require("path"));de();Se();var Ji=require("node:child_process");function hl(t,e){let r=t.split("."),n=e.split(".");for(let s=0;s<3;s++){let i=parseInt(r[s]??"0",10),o=parseInt(n[s]??"0",10);if(isNaN(i)||isNaN(o))break;if(i!==o)return i-o}return t.localeCompare(e)}function ln(t,e){return hl(t,e)>0}function dn(t="latest"){let r=["latest","beta","next","canary"].includes(t)?t:"latest";try{let s=(0,Ji.execSync)(`npm view bridge-agent@${r} version`,{timeout:5e3,stdio:"pipe"}).toString().trim();return/^\d+\.\d+\.\d+/.test(s)?s:null}catch{return null}}function Yi(t="latest",e){let r=dn(t);return r?ln(e,r)?{updateAvailable:!1,currentVersion:e,latestVersion:r,reason:"ahead_of_channel"}:e===r?{updateAvailable:!1,currentVersion:e,latestVersion:r,reason:"up_to_date"}:{updateAvailable:!0,latestVersion:r,currentVersion:e}:{updateAvailable:!1,currentVersion:e,reason:"registry_unreachable"}}var Yt=mt.default.join((0,un.homedir)(),".bridge"),qe=mt.default.join(Yt,"update.lock"),fl=mt.default.join(Yt,"update-state.json"),Ru=mt.default.join((0,un.homedir)(),"Library","LaunchAgents");function gl(){if((0,B.existsSync)(qe))try{let{pid:t}=JSON.parse((0,B.readFileSync)(qe,"utf8"));if(t&&process.kill(t,0))return;(0,B.unlinkSync)(qe)}catch{try{(0,B.unlinkSync)(qe)}catch{}}}function ml(){try{(0,B.mkdirSync)(Yt,{recursive:!0})}catch{}gl();try{let t=(0,B.openSync)(qe,"wx");return(0,B.writeSync)(t,JSON.stringify({pid:process.pid,startedAt:Date.now()})),(0,B.closeSync)(t),{ok:!0}}catch(t){return{ok:!1,err:t}}}function pe(){try{(0,B.unlinkSync)(qe)}catch{}}function _l(t){try{(0,B.mkdirSync)(Yt,{recursive:!0})}catch{}(0,B.writeFileSync)(fl,JSON.stringify(t,null,2),{mode:384})}function zi(t,e=3e4){let r=st(),n=Date.now()+e;return new Promise(s=>{let i=()=>{if(Date.now()>n){s(!1);return}try{let o=Xi.default.get(`http://127.0.0.1:${r}/health`,a=>{let c="";a.on("data",l=>{c+=l}),a.on("end",()=>{try{if(JSON.parse(c).version===t){s(!0);return}}catch{}setTimeout(i,500)})});o.on("error",()=>{setTimeout(i,500)}),o.setTimeout(1e3,()=>{o.destroy(),setTimeout(i,500)})}catch{setTimeout(i,500)}};setTimeout(i,1e3)})}async function Qi(t){let e="0.10.6",r=ne(),n=t.channel??r.updateChannel??"latest",s=ft();if((s.includes("packages/daemon/dist")||s.includes("packages/daemon/src"))&&(console.error("[bridge] update.refused: running from monorepo \u2014 cannot self-update a dev checkout."),console.error("[bridge] To test update logic, install the published package globally:"),console.error("[bridge] npm i -g bridge-agent"),process.exit(1)),t.check){let p=Yi(n,e);p.updateAvailable&&(console.log(`[bridge] update.available: ${e} \u2192 ${p.latestVersion} (channel: ${n})`),process.exit(10));let f=p.reason??"unknown";console.log(`[bridge] update.unavailable: ${e} (channel: ${n}, reason: ${f})`),process.exit(0)}let i=dn(n);i||(console.error("[bridge] update.failed: cannot reach npm registry"),process.exit(1)),e===i&&(console.log(`[bridge] update.up_to_date: ${e} (channel: ${n})`),t.saveChannel&&(J({updateChannel:n}),console.log(`[bridge] update.channel.saved: ${n}`)),process.exit(0)),ln(e,i)&&(console.log(`[bridge] update.ahead: ${e} > ${i} (channel: ${n}).`),console.log("[bridge] You are on a build ahead of the public channel. Update not available."),process.exit(0)),console.log(`[bridge] update.available: ${e} \u2192 ${i} (channel: ${n})`);let o=Di()?.getLiveAgentIds().length??0;o>0&&!t.force&&(console.error(`[bridge] update.blocked: ${o} active panel(s) \u2014 cannot update without --force`),console.error("[bridge] Use --force to bypass this safety check, or stop panels first."),console.error("[bridge] bridge-agent stop # stop the daemon"),process.exit(1)),o>0&&t.force&&console.log(`[bridge] update.force: ${o} active panel(s) will be terminated during update.`),t.saveChannel&&(J({updateChannel:n}),console.log(`[bridge] update.channel.saved: ${n}`));let a=ml();if(!a.ok){let p=a.err;p.code==="EEXIST"?console.error("[bridge] update.aborted: another update is already in progress (update.lock exists)"):console.error(`[bridge] update.lock.failed: ${p.code} \u2014 ${p.message}`),process.exit(1)}console.log(`[bridge] update.installing: bridge-agent@${n}...`);let c=!1;try{(0,He.execSync)(`npm install -g bridge-agent@${n}`,{stdio:"inherit",timeout:12e4}),c=!0}catch(p){console.error(`[bridge] update.install.failed: ${String(p)}`),c=!1}if(!c){console.error(`[bridge] update.install.failed: rolling back to bridge-agent@${e}...`);try{(0,He.execSync)(`npm install -g bridge-agent@${e}`,{stdio:"inherit",timeout:12e4}),console.log("[bridge] update.install.rollback.ok \u2014 restored previous version")}catch(p){pe(),console.error(`[bridge] update.install.rollback.FAILED: ${String(p)}`),console.error("[bridge] \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.error("[bridge] \u2551 CRITICAL: npm install failed AND rollback failed. \u2551"),console.error("[bridge] \u2551 Binary may be broken. Manual recovery needed. \u2551"),console.error(`[bridge] \u2551 Try: npm install -g bridge-agent@${e} \u2551`),console.error("[bridge] \u2551 Then: bridge-agent start \u2551"),console.error("[bridge] \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),process.exit(1)}pe(),console.error("[bridge] update.aborted: npm install failed, daemon is on previous version."),process.exit(1)}let l=ft();Jt(l)||(pe(),console.error("[bridge] update.failed: could not write launchd plist"),console.error("[bridge] npm install succeeded but launchd setup failed. Run: bridge-agent start"),process.exit(1));let d=le();try{(0,He.execSync)(`launchctl kickstart -kp gui/$(id -u)/${d}`,{stdio:"pipe"}),console.log("[bridge] update.kickstart.ok \u2014 daemon restarting with new version")}catch{pe(),console.error("[bridge] update.failed: launchctl kickstart failed"),console.error(`[bridge] Manual restart: launchctl kickstart -kp gui/$(id -u)/${d}`),process.exit(1)}console.log(`[bridge] update.verifying: polling health for version ${i}...`),await zi(i,3e4)&&(_l({previousVersion:e,channel:n,installedAt:new Date().toISOString()}),pe(),console.log(`[bridge] update.complete: ${e} \u2192 ${i}`),process.exit(0)),console.error(`[bridge] update.health.timeout: daemon did not report version ${i} within 30s`),console.error(`[bridge] update.rolling_back: reinstalling bridge-agent@${e}...`);try{(0,He.execSync)(`npm install -g bridge-agent@${e}`,{stdio:"inherit",timeout:12e4}),console.log("[bridge] update.rollback.install.ok")}catch(p){pe(),console.error(`[bridge] update.rollback.install.FAILED: ${String(p)}`),console.error("[bridge] \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.error("[bridge] \u2551 CRITICAL: update failed AND rollback failed. \u2551"),console.error("[bridge] \u2551 Daemon may be broken. Manual recovery needed. \u2551"),console.error(`[bridge] \u2551 Try: npm install -g bridge-agent@${e} \u2551`),console.error("[bridge] \u2551 Then: bridge-agent start \u2551"),console.error("[bridge] \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),process.exit(1)}try{let p=ft();Jt(p),(0,He.execSync)(`launchctl kickstart -kp gui/$(id -u)/${d}`,{stdio:"pipe"}),console.log("[bridge] update.rollback.kickstart.ok")}catch{pe(),console.error("[bridge] update.rollback.kickstart.failed \u2014 daemon may need manual restart"),console.error(`[bridge] Run: launchctl kickstart -kp gui/$(id -u)/${d}`),process.exit(1)}console.log(`[bridge] update.rollback.verifying: polling for version ${e}...`);let h=await zi(e,3e4);pe(),h&&(console.log(`[bridge] update.rollback.complete: restored to ${e}`),console.log(`[bridge] Update to ${i} failed \u2014 daemon is running on previous version.`),process.exit(1)),console.error("[bridge] \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),console.error("[bridge] \u2551 CRITICAL: update failed AND rollback health-check failed.\u2551"),console.error("[bridge] \u2551 Daemon may still be running \u2014 DO NOT KILL IT. \u2551"),console.error("[bridge] \u2551 Manual check: bridge-agent status \u2551"),console.error("[bridge] \u2551 Check logs: tail -f ~/bridge-daemon.log \u2551"),console.error("[bridge] \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),process.exit(1)}var se=new On;se.name("bridge-agent").description("Bridge local agent \u2014 connects your AI tools to Jerico").version("0.10.6").option("--profile <name>","Config profile name (e.g. dev). Isolates config, lock, and fingerprint from the default prod profile.").hook("preAction",t=>{let e=t.opts().profile;e&&(process.env.BRIDGE_PROFILE=e)});se.command("start").description("Start the bridge-agent daemon").option("--health-port <port>","Health check HTTP port (default: 3101 prod, 3102 for --profile <name>). Overrides the per-profile default.").action(t=>{t.healthPort&&(process.env.HEALTH_PORT=t.healthPort),Bi()});se.command("auth").description("Authenticate with Bridge server").option("-s, --server <url>","Server URL (default: https://lcars.jerico.appnova.io)").option("-t, --token <token>","Use token non-interactively").option("--no-browser","Print auth URL without opening browser or interactive prompt").action(t=>{Ui(t.server,!t.browser,t.token)});se.command("link-project <workspace-id> <project-id> <local-path>").description("Link a local directory to a project for this machine (Issue #152)").action((t,e,r)=>{Hi(t,e,r)});se.command("cleanup-orphans").description("Remove orphaned daemon_project_paths rows for this user").action(()=>{qi()});se.command("status").description("Show connection status").action(async()=>{try{let{loadConfig:t}=await Promise.resolve().then(()=>(Se(),mi)),e=t();console.log("[bridge] Config found"),console.log(" Server:",e.server),console.log(" Name:",e.name)}catch{console.log("[bridge] Not authenticated. Run: bridge-agent auth")}});se.command("stop").description("Stop the bridge-agent daemon").action(()=>{Ki()});se.command("update").description("Update bridge-agent to the latest version (or a specific channel)").option("--check","Check for update availability (exit 0 if up-to-date or ahead, 10 if update available)").option("--channel <name>","npm dist-tag channel (latest, beta, next, canary)").option("--save-channel","Persist the channel to config (default: only used for this run)").option("--force","Bypass active-panel safety block (allows update with live panels)").option("--yes","Non-interactive mode (skip TTY prompts; still refuses if panels are active without --force)").action(t=>{Qi(t)});se.parse();
|