bridge-agent 0.10.1 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +3 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ Expecting one of '${n.join("', '")}'`);let s=`${e}Help`;return this.on(s,i=>{let
27
27
  `)+`\r
28
28
  \r
29
29
  `+r)}function ue(t,e,r,n,s,i){if(t.listenerCount("wsClientError")){let o=new Error(s);Error.captureStackTrace(o,ue),t.emit("wsClientError",o,r,e)}else Ye(r,n,s,i)}});function Qe(){return process.env.BRIDGE_PROFILE||void 0}function Z(){let t=Qe();return t?he.default.join(Xs,"profiles",t,"settings.json"):he.default.join(Xs,"settings.json")}function Re(){let t=Qe(),e=t?`${t}.daemon.lock`:"daemon.lock";return he.default.join((0,Xe.homedir)(),".bridge",e)}function Ne(){let t=Qe();return t?`com.jerico.bridge-agent.${t}.plist`:"com.jerico.bridge-agent.plist"}function Rt(){let t=Qe(),e=t?`-${t}`:"";return{out:he.default.join((0,Xe.homedir)(),`bridge-daemon${e}.log`),err:he.default.join((0,Xe.homedir)(),`bridge-daemon${e}.err.log`)}}function Qs(){let t=Qe();return t?`:profile:${t}`:""}var Xe,he,Xs,fe=zr(()=>{"use strict";Xe=require("node:os"),he=_(require("path")),Xs=he.default.join((0,Xe.homedir)(),".jerico")});var ei={};ji(ei,{getConfigPath:()=>Z,loadConfig:()=>ge,loadProjectSettings:()=>jr,mergeSettings:()=>re,saveConfig:()=>qa});function Ze(t,e){let r=t[e];if(!(!r||typeof r!="object"||Array.isArray(r)))return Object.fromEntries(Object.entries(r).filter(([,n])=>typeof n=="string"))}function ge(){let t=Z(),e=B.default.existsSync(t)?t:Ha;if(!B.default.existsSync(e)){let f=process.env.BRIDGE_PROFILE?`bridge-agent --profile ${process.env.BRIDGE_PROFILE} auth`:"bridge-agent auth";console.error(`[bridge] Config not found. Run: ${f}`),process.exit(1)}let r=B.default.readFileSync(e,"utf-8"),n;try{n=JSON.parse(r)}catch{console.error("[bridge] Invalid config file at",e),process.exit(1)}(!n||typeof n!="object")&&(console.error("[bridge] Config must be a JSON object. Run: bridge-agent auth"),process.exit(1));let s=n,i=typeof s.server=="string"?s.server:"",o=typeof s.token=="string"?s.token:"",a=typeof s.name=="string"?s.name:"bridge-agent",c=[/23-88-110-113\.sslip\.io/i,/23\.88\.110\.113:443\/ws\/daemon$/,/23\.88\.110\.113:3100\/ws\/daemon$/],l="wss://lcars.jerico.appnova.io/ws/daemon";if(i&&c.some(f=>f.test(i))){console.warn(`[daemon] config.url_migration: migrating stale URL ${i} \u2192 ${l}`),i=l,s.server=i;try{B.default.writeFileSync(e,JSON.stringify(s,null,2),{mode:384}),B.default.chmodSync(e,384)}catch(f){console.warn("[daemon] config.url_migration: failed to save migrated config",String(f))}}(!i||!o)&&(console.error("[bridge] Config missing server or token. Run: bridge-agent auth"),process.exit(1));let d={server:i,token:o,name:a},u=Ze(s,"agentPaths"),h=Ze(s,"projectPaths");return u&&(d.agentPaths=u),h&&(d.projectPaths=h),typeof s.claudeTier=="string"&&(d.claudeTier=s.claudeTier),d}function qa(t){let e=Z(),r=et.default.dirname(e);B.default.existsSync(r)||B.default.mkdirSync(r,{recursive:!0}),B.default.writeFileSync(e,JSON.stringify(t,null,2),{mode:384})}function re(t){let e=Z(),r=et.default.dirname(e);B.default.existsSync(r)||B.default.mkdirSync(r,{recursive:!0});let n={};if(B.default.existsSync(e))try{n=JSON.parse(B.default.readFileSync(e,"utf-8"))}catch{n={}}B.default.writeFileSync(e,JSON.stringify({...n,...t},null,2),{mode:384})}function jr(t){let e=et.default.join(t??process.cwd(),".jerico","settings.json");if(!B.default.existsSync(e))return{};try{let r=B.default.readFileSync(e,"utf-8"),n=JSON.parse(r);if(!n||typeof n!="object"||Array.isArray(n))return{};let s=n,i={};typeof s.preferredAgent=="string"&&(i.preferredAgent=s.preferredAgent);let o=Ze(s,"hooks"),a=Ze(s,"env"),c=Ze(s,"agentPaths");return o&&(i.hooks=o),a&&(i.env=a),c&&(i.agentPaths=c),i}catch{return console.warn("[bridge] Failed to parse .jerico/settings.json, ignoring"),{}}}var B,et,Zs,Ha,De=zr(()=>{"use strict";B=_(require("fs")),et=_(require("path")),Zs=_(require("os"));fe();Ha=et.default.join(Zs.default.homedir(),".bridge","config.json")});var dn=_(ln(),1),{program:el,createCommand:tl,createArgument:rl,createOption:nl,CommanderError:sl,InvalidArgumentError:il,InvalidOptionArgumentError:ol,Command:un,Argument:al,Option:cl,Help:ll}=dn.default;var gi=require("node:http"),we=require("node:child_process"),D=require("node:fs"),$e=require("node:os"),$=_(require("path"));var Tn=_(require("node-pty"));var ir=_(On()),ve=_(require("fs")),Ge=_(require("path")),Pn=_(require("net")),An=require("child_process"),sr=t=>t+`
30
- `,ie=t=>t.replace(/[\r\n]+$/,"")+"\r",oe=[{key:"sh",displayName:"Shell",binary:"sh",checkAuth:async()=>!0,formatInput:sr},{key:"claude",displayName:"Claude Code",binary:"claude",checkAuth:async()=>We(".claude")||V("ANTHROPIC_API_KEY"),assignSessionId:!0,spawnArgs:["--dangerously-skip-permissions"],resumeArgs:t=>["--dangerously-skip-permissions","--resume",t],supportsMcpConfig:!0,formatInput:ie,versionDirGlobs:[".local/share/claude/versions/*"]},{key:"codex",displayName:"Codex CLI",binary:"codex",checkAuth:async()=>V("OPENAI_API_KEY"),spawnArgs:["--full-auto"],supportsMcpConfig:!0,formatInput:ie},{key:"qwen",displayName:"Qwen CLI",binary:"qwen",checkAuth:async()=>We(".qwen"),assignSessionId:!0,spawnArgs:["--yolo"],resumeArgs:t=>["--resume",t,"--yolo"],supportsMcpConfig:!0,formatInput:ie,versionDirGlobs:[".local/share/qwen/versions/*"]},{key:"gemini",displayName:"Gemini",binary:"gemini",checkAuth:async()=>V("GEMINI_API_KEY"),spawnArgs:["--approval-mode","yolo"],assignSessionId:!0,resumeArgs:t=>["--approval-mode","yolo","--session-id",t],supportsMcpConfig:!0,formatInput:ie},{key:"ollama",displayName:"Ollama",binary:"ollama",checkAuth:async()=>ho(11434),formatInput:sr},{key:"aider",displayName:"Aider",binary:"aider",checkAuth:async()=>V("OPENAI_API_KEY")||V("ANTHROPIC_API_KEY"),supportsMcpConfig:!0,formatInput:sr},{key:"kimi",displayName:"Kimi Code",binary:"kimi",checkAuth:async()=>We(".kimi")||V("KIMI_API_KEY"),assignSessionId:!0,spawnArgs:["--yolo"],resumeArgs:t=>["-r",t,"--yolo"],supportsMcpConfig:!0,formatInput:ie,versionDirGlobs:[".local/share/uv/tools/kimi-cli/bin",".local/share/kimi/versions/*"]},{key:"forge",displayName:"Forge",binary:"forge",checkAuth:async()=>We(".forge/.credentials.json")||V("FORGE_API_KEY"),assignSessionId:!0,resumeArgs:t=>["--conversation-id",t],supportsMcpConfig:!0,formatInput:ie},{key:"opencode",displayName:"OpenCode",binary:"opencode",checkAuth:async()=>We(".config/opencode")||V("OPENCODE_API_KEY")||V("ANTHROPIC_API_KEY")||V("OPENAI_API_KEY"),supportsMcpConfig:!0,formatInput:ie,versionDirGlobs:[".opencode/bin"],env:{OPENCODE_CONFIG_CONTENT:'{"permission":"allow"}'}}];var Cn=process.env.HOME??"/Users/unknown";function pt(t){try{let e=(0,An.spawnSync)(t,["--version"],{timeout:5e3});return e.status!==0?void 0:(e.stdout??e.stderr??Buffer.from("")).toString("utf8").split(`
30
+ `,ie=t=>t.replace(/[\r\n]+$/,"")+"\r",oe=[{key:"sh",displayName:"Shell",binary:"sh",checkAuth:async()=>!0,formatInput:sr},{key:"claude",displayName:"Claude Code",binary:"claude",checkAuth:async()=>We(".claude")||V("ANTHROPIC_API_KEY"),assignSessionId:!0,spawnArgs:["--dangerously-skip-permissions"],resumeArgs:t=>["--dangerously-skip-permissions","--resume",t],supportsMcpConfig:!0,formatInput:ie,versionDirGlobs:[".local/share/claude/versions/*"]},{key:"codex",displayName:"Codex CLI",binary:"codex",checkAuth:async()=>V("OPENAI_API_KEY"),spawnArgs:["--full-auto"],supportsMcpConfig:!0,formatInput:ie},{key:"qwen",displayName:"Qwen CLI",binary:"qwen",checkAuth:async()=>We(".qwen"),assignSessionId:!0,spawnArgs:["--yolo"],resumeArgs:t=>["--resume",t,"--yolo"],supportsMcpConfig:!0,formatInput:ie,versionDirGlobs:[".local/share/qwen/versions/*"]},{key:"gemini",displayName:"Gemini",binary:"gemini",checkAuth:async()=>V("GEMINI_API_KEY"),spawnArgs:["--approval-mode","yolo"],assignSessionId:!0,resumeArgs:t=>["--approval-mode","yolo","--resume",t],supportsMcpConfig:!0,formatInput:ie},{key:"ollama",displayName:"Ollama",binary:"ollama",checkAuth:async()=>ho(11434),formatInput:sr},{key:"aider",displayName:"Aider",binary:"aider",checkAuth:async()=>V("OPENAI_API_KEY")||V("ANTHROPIC_API_KEY"),supportsMcpConfig:!0,formatInput:sr},{key:"kimi",displayName:"Kimi Code",binary:"kimi",checkAuth:async()=>We(".kimi")||V("KIMI_API_KEY"),assignSessionId:!0,spawnArgs:["--yolo"],resumeArgs:t=>["-r",t,"--yolo"],supportsMcpConfig:!0,formatInput:ie,versionDirGlobs:[".local/share/uv/tools/kimi-cli/bin",".local/share/kimi/versions/*"]},{key:"forge",displayName:"Forge",binary:"forge",checkAuth:async()=>We(".forge/.credentials.json")||V("FORGE_API_KEY"),assignSessionId:!0,resumeArgs:t=>["--conversation-id",t],supportsMcpConfig:!0,formatInput:ie},{key:"opencode",displayName:"OpenCode",binary:"opencode",checkAuth:async()=>We(".config/opencode")||V("OPENCODE_API_KEY")||V("ANTHROPIC_API_KEY")||V("OPENAI_API_KEY"),supportsMcpConfig:!0,formatInput:ie,versionDirGlobs:[".opencode/bin"],env:{OPENCODE_CONFIG_CONTENT:'{"permission":"allow"}'}}];var Cn=process.env.HOME??"/Users/unknown";function pt(t){try{let e=(0,An.spawnSync)(t,["--version"],{timeout:5e3});return e.status!==0?void 0:(e.stdout??e.stderr??Buffer.from("")).toString("utf8").split(`
31
31
  `)[0].trim()||void 0}catch{return}}function uo(t){if(!t.versionDirGlobs?.length)return[];let e=[],r=t.versionDirGlobs;for(let n of r){let s=Ge.default.join(Cn,n.replace(/\/\*$/,""));if(n.endsWith("/*")){let i=[];try{i=ve.default.readdirSync(s)}catch{}i.sort((o,a)=>a.localeCompare(o));for(let o of i){let a=Ge.default.join(s,o,t.binary);if(ve.default.existsSync(a)){let c=pt(a);e.push({path:a,version:c})}}}else{let i=Ge.default.join(Cn,n);if(ve.default.existsSync(i)){let o=pt(i);e.push({path:i,version:o})}}}return e}async function po(t,e={}){if(e[t.key]){let n=e[t.key],s=pt(n);if(s)return{path:n,version:s}}try{let n=await(0,ir.default)(t.binary);if(n&&ve.default.existsSync(n)){let s=pt(n);if(s!==void 0)return{path:n,version:s}}}catch{}let r=uo(t);for(let n of r)if(n.version!==void 0)return n;try{let n=await(0,ir.default)(t.binary);if(n)return{path:n}}catch{}throw new Error(`No working binary found for agent '${t.key}'`)}async function or(t={}){let e=[];for(let r of oe)try{let{path:n,version:s}=await po(r,t),o=await r.checkAuth()?"ok":"missing";e.push({key:r.key,displayName:r.displayName,binaryPath:n,authStatus:o,version:s})}catch{}return console.log("[daemon] agent.detect.done",{found:e.map(r=>r.key),missing:oe.map(r=>r.key).filter(r=>!e.find(n=>n.key===r))}),e}function We(t){return ve.default.existsSync(Ge.default.join(process.env.HOME??"",t))}function V(t){return!!process.env[t]}async function ho(t){return new Promise(e=>{let r=Pn.default.createConnection(t,"127.0.0.1");r.setTimeout(200),r.on("connect",()=>{r.destroy(),e(!0)}),r.on("error",()=>e(!1)),r.on("timeout",()=>{r.destroy(),e(!1)})})}var ht=class{handles=new Map;nextInstanceId=1;lastErrors=new Map;livenessTimer=null;currentWs=null;setCurrentWs(e){this.currentWs=e}getCurrentWs(){return this.currentWs}startLivenessCheck(e=6e4){this.livenessTimer||(this.livenessTimer=setInterval(()=>{for(let[r,n]of this.handles.entries()){if(n.killed)continue;let s=!1;try{s=process.kill(n.pid,0)}catch{s=!1}s||(console.warn("[daemon] pty.liveness.dead",{agentId:r,pid:n.pid}),this.handles.delete(r),n.onExit(137,"SIGKILL"))}},e),console.log("[daemon] pty.liveness.started",{intervalMs:e}))}stopLivenessCheck(){this.livenessTimer&&(clearInterval(this.livenessTimer),this.livenessTimer=null,console.log("[daemon] pty.liveness.stopped"))}spawn(e,r,n,s,i,o,a,c,l){let d=this.handles.get(e);d&&(console.warn("[daemon] pty.spawn.replace_existing",{agentId:e,oldPid:d.pid,newAgentKey:r}),this.kill(e,!0));let u=Math.max(1,Math.min(500,i)),h=Math.max(1,Math.min(500,o)),f={...process.env,TERM:"xterm-256color",COLORTERM:"truecolor"};l&&(f.BRIDGE_SERVER_URL=l.serverUrl,f.BRIDGE_TOKEN=l.token,f.BRIDGE_WORKSPACE_ID=l.workspaceId,f.BRIDGE_PROJECT_ID=l.projectId||"",l.projectEnv&&Object.assign(f,l.projectEnv));let g=oe.find(C=>C.key===r);g?.env&&Object.assign(f,g.env);let p=process.env.BRIDGE_MCP_URL;p&&(f.BRIDGE_MCP_URL=p);let m;try{m=Tn.spawn(n,s,{name:"xterm-256color",cols:u,rows:h,cwd:l?.cwd,env:f})}catch(C){let T=C instanceof Error?C.message:String(C);return this.lastErrors.set(e,T),console.error("[daemon] pty.spawn.failed",{agentId:e,agentKey:r,error:T}),!1}let I=this.nextInstanceId++,k={agentId:e,agentKey:r,process:m,pid:m.pid,killed:!1,instanceId:I,onExit:c};return m.onData(C=>{let T=this.handles.get(e);!T||T.instanceId!==I||k.killed||a(Buffer.from(C).toString("base64"))}),m.onExit(({exitCode:C,signal:T})=>{let M=this.handles.get(e);!M||M.instanceId!==I||k.killed||k.killed||(this.handles.delete(e),console.log("[daemon] pty.exit",{agentId:e,exitCode:C,signal:T}),c(C??null,T?String(T):null))}),this.lastErrors.delete(e),this.handles.set(e,k),console.log("[daemon] pty.spawn.success",{agentId:e,agentKey:r,args:s,cwd:l?.cwd}),!0}write(e,r,n){let s=this.handles.get(e);if(!s){console.warn("[daemon] pty.write.no_handle",{agentId:e.slice(-8),source:n,dataLength:r.length});return}let i=Buffer.from(r,"base64").toString(),o=oe.find(c=>c.key===s.agentKey),a=n==="orchestrator"&&o?.formatInput?o.formatInput(i):i;s.process.write(a)}kill(e,r=!1){let n=this.handles.get(e);if(!n)return;n.killed=!0,this.handles.delete(e);let s=n.pid;if(r){try{process.kill(-s,"SIGTERM")}catch{n.process.kill()}setTimeout(()=>{try{process.kill(-s,"SIGKILL")}catch{}},2e3)}else try{process.kill(-s,"SIGTERM")}catch{n.process.kill()}console.log("[daemon] pty.kill",{agentId:e,force:r})}resize(e,r,n){let s=this.handles.get(e);if(!s)return;let i=Math.max(1,Math.min(500,r)),o=Math.max(1,Math.min(500,n));s.process.resize(i,o)}getLastError(e){return this.lastErrors.get(e)}killAll(){for(let e of this.handles.values())try{process.kill(-e.pid,"SIGTERM")}catch{e.process.kill()}this.handles.clear()}getLiveAgentIds(){return[...this.handles.keys()]}getAgentKey(e){return this.handles.get(e)?.agentKey}};var Na=_(xs(),1),Da=_(vt(),1),ja=_(Ie(),1),La=_(_r(),1),Ba=_(wr(),1),Ma=_(xr(),1),js=_(xt(),1),$a=_(Ds(),1);var S=js.default;var N=_(require("fs")),st=require("node:fs/promises"),x=_(require("path")),R=_(require("os")),Me=require("node:child_process"),at=require("node:crypto");var Cr=["claude","codex","qwen","kimi","forge","opencode","gemini"];var Ct=["developer","reviewer","planner","executor","shell","runner","orchestrator"],jl=Ct.filter(t=>t!=="orchestrator"),Ll=[...Ct,"system"];var Ls=t=>t;var Bs=t=>t,Ms=t=>t,$s=3e3;function Pr(t){return(process.env.JERICO_FEATURES??"").split(",").map(r=>r.trim()).filter(Boolean).includes(t)}var Us={developer:`# Bridge Worker \u2014 Developer Role
32
32
 
33
33
  You are a **Developer** worker in a multi-agent orchestration system called Bridge.
@@ -406,7 +406,7 @@ ${Ws("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 nt(t){return`"${t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function vc(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:be(),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=x.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 Ec(t){try{let e=be(),r=`{BRIDGE_SERVER_URL=${nt(t.serverUrl)},BRIDGE_TOKEN=${nt(t.token)},BRIDGE_WORKSPACE_ID=${nt(t.workspaceId)},BRIDGE_PROJECT_ID=${nt(t.projectId||"workspace")},HTTP_MODE="false"}`;return["-c",'mcp_servers.bridge.transport="stdio"',"-c",`mcp_servers.bridge.command=${nt(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 Fr(t,e){try{return e(t)}catch{return!1}}function Ic(t,e,r,n,s=kc){let i=n?.[t];if(i&&Fr(i,s))return{path:i,source:"local_override"};if(r){if(Fr(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&&Fr(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 xc(){let t=x.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 Oc(t){xc();try{if(!t.cwd)return console.warn("[daemon] forge.mcp.setup.skipped",{reason:"missing_cwd",projectId:t.projectId||"workspace"}),!1;let e=be(),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,Me.spawnSync)("forge",["mcp","remove","--scope","local","bridge"],n);let s=(0,Me.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 Cc(t){try{let e=x.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:[be()],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(x.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 Pc(t){try{if(!t.cwd)return console.warn("[daemon] qwen.mcp.setup.skipped",{reason:"missing_cwd",projectId:t.projectId||"workspace"}),!1;let e=be(),r={cwd:t.cwd,encoding:"utf-8",timeout:5e3,stdio:"pipe"},n=x.default.resolve(t.cwd)===x.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,Me.spawnSync)("qwen",["mcp","remove","--scope",s,"bridge"],r);let i=(0,Me.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 Ac(t){try{if(!t.cwd)return console.warn("[daemon] gemini.mcp.setup.skipped",{reason:"missing_cwd",projectId:t.projectId||"workspace"}),!1;let e=x.default.join(t.cwd,".gemini"),r=x.default.join(e,"settings.json"),n={};try{n=JSON.parse(N.default.readFileSync(r,"utf-8"))}catch{}let s=be(),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 ot=[],Hr=!1,pi=!1;function hi(){return Hr}function fi(t){if(pi)throw new Error("[daemon] startDaemonConnection called twice \u2014 only one connection manager allowed");if(pi=!0,process.env.BRIDGE_TEST_SCRIPTED_REVIEW!=="1")try{let f=x.default.join(R.default.homedir(),".jerico","settings.json");N.default.existsSync(f)&&JSON.parse(N.default.readFileSync(f,"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=ge(),r=(0,at.createHash)("sha256").update(e.token).digest("hex"),n=new Tt(r),s=null,i=null,o=null,a=0,c=0,l=0n;function d(){i&&(clearTimeout(i),i=null);let f=Date.now(),g=process.hrtime.bigint();s=new S(e.server,{headers:{Authorization:`Bearer ${e.token}`}});let p=s,m=(0,at.randomUUID)();Gr=m;let I=R.default.networkInterfaces(),k=Object.entries(I).flatMap(([b,w])=>(w||[]).filter(v=>!v.internal).map(v=>({iface:b,address:v.address,family:v.family}))),C=JSON.stringify(k);console.log(JSON.stringify({ts:Date.now(),level:"info",event:"net.interfaces",interfaces:k,connectionId:m})),$t&&$t!==C&&console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"net.interfaces.changed",previous:$t,current:C,connectionId:m})),$t=C;let T=p.send.bind(p);p.send=function(b){if(p.readyState!==S.OPEN){let w="unknown";try{w=JSON.parse(b).type}catch{}console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.send.dropped",messageType:w,readyState:p.readyState,connectionId:m}));return}return T(b)},console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.connecting",server:e.server,connectionId:m}));let M=null,Se=0,y=null;p.on("open",()=>{Hr=!0,c=0,l=0n,console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.connected",server:e.server,connectionId:m})),o=setInterval(()=>{p.readyState===S.OPEN&&(p.ping(),Se=Date.now(),y&&clearTimeout(y),y=setTimeout(()=>{console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.heartbeat.timeout",connectionId:m})),p.terminate()},uc))},dc),t.setCurrentWs(p);let b=!ui();p.send(JSON.stringify({type:"ready",version:"1.1",npmVersion:"0.10.1",name:e.name,spawnHelperBroken:b,liveAgentIds:t.getLiveAgentIds(),machineFingerprint:qr(),connectionId:m,claudeTier:Dt()})),n.updateWs(p),Promise.all([or(e.agentPaths),Tr()]).then(([w,v])=>{ot=v?[...w,v]:w,p.readyState===S.OPEN&&p.send(JSON.stringify({type:"agents",list:ot}))}),M=li(w=>{p.readyState===S.OPEN&&p.send(JSON.stringify({type:"system_metrics",daemonId:r,...w}))})}),p.on("message",b=>{let w;try{w=JSON.parse(b.toString())}catch{console.warn("[daemon] Invalid JSON from server, ignoring");return}Tc(w,p,t,e,n)}),p.on("pong",()=>{y&&(clearTimeout(y),y=null);let b=Date.now()-Se;console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.heartbeat.pong",rttMs:b,connectionId:m}))}),p.on("close",(b,w)=>{Hr=!1,o&&(clearInterval(o),o=null),y&&(clearTimeout(y),y=null),M?.(),M=null,n.stopAll(),b===1008?(a++,a>=2&&(console.error("[daemon] ws.auth_failed \u2014 token invalid or expired (2 consecutive rejections), stopping. Re-run: bridge-agent auth"),process.exit(1)),console.warn("[daemon] ws.auth_rejected \u2014 transient 1008, will retry once",{attempt:a})):a=0;let v=Number((process.hrtime.bigint()-g)/1000000n);if(console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.closed",code:b,reason:w?.toString()||void 0,uptimeMs:v,connectionId:m})),i)return;c===0&&(l=process.hrtime.bigint()),c++;let E=Number((process.hrtime.bigint()-l)/1000000n);c>=10&&E<6e4&&(console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.reconnect.storm",reconnectCount:c,connectionId:m})),process.exit(1));let U=Math.min(3e4,1e3*Math.pow(2,Math.min(c,5))),lt=Math.round(U+Math.random()*500);console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.reconnect.scheduled",delayMs:lt,reconnectCount:c,connectionId:m})),i=setTimeout(d,lt)}),p.on("error",b=>{console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.error",message:b.message,code:b.code,connectionId:m}))})}function u(){o&&(clearInterval(o),o=null),t.stopLivenessCheck(),lc();for(let f of ye.values())f();n.stopAll(),t.killAll(),s?.close()}function h(f){console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.signal",signal:f,connectionId:Gr})),u(),setTimeout(()=>process.exit(0),100)}process.on("SIGINT",()=>h("SIGINT")),process.on("SIGTERM",()=>h("SIGTERM")),process.on("SIGHUP",()=>h("SIGHUP")),process.on("uncaughtException",f=>{console.log(JSON.stringify({ts:Date.now(),level:"error",event:"daemon.uncaught",error:String(f),stack:f.stack,connectionId:Gr})),t.killAll(),process.exit(1)}),d()}function Tc(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=ot.find(y=>y.key===t.agentKey);if(!i){e.readyState===S.OPEN&&e.send(JSON.stringify({type:"error",code:"AGENT_NOT_FOUND",message:`Agent '${t.agentKey}' is not installed on this machine`}));return}let o=oe.find(y=>y.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"&&(ye.get(t.agentId)?.(),ye.set(t.agentId,Br(t.agentId,t.sessionId,(y,b,w)=>{let v=r.getCurrentWs();v?.readyState===S.OPEN&&v.send(JSON.stringify({type:"panel_token_usage",agentId:y,usedPct:b,usedTokens:w,...Be}))})));else if(o?.assignSessionId){let y=crypto.randomUUID(),b=t.agentKey==="kimi"?"--session":t.agentKey==="forge"?"--conversation-id":"--session-id";a=[...o.spawnArgs??[],b,y],e.readyState===S.OPEN&&(e.send(JSON.stringify({type:"session_started",agentId:t.agentId,sessionId:y})),console.log("[daemon] session.assigned",{agentId:t.agentId,sessionId:y})),t.agentKey==="claude"&&(ye.get(t.agentId)?.(),ye.set(t.agentId,Br(t.agentId,y,(w,v,E)=>{let U=r.getCurrentWs();U?.readyState===S.OPEN&&U.send(JSON.stringify({type:"panel_token_usage",agentId:w,usedPct:v,usedTokens:E,...Be}))})))}else a=[...o?.spawnArgs??[]],e.readyState===S.OPEN&&e.send(JSON.stringify({type:"session_started",agentId:t.agentId,sessionId:crypto.randomUUID()}));let c,l=!1,d,u;if(t.workspaceId){let y=mc(n.server),b=Ic(t.projectId??"",t.cwd,t.daemonLocalPath,n.projectPaths),w=b.path;u=b.source;let v=jr(w);if(c={serverUrl:y,token:n.token,workspaceId:Bs(t.workspaceId),projectId:t.projectId?Ms(t.projectId):void 0,agentId:t.agentId?Ls(t.agentId):void 0,personaId:t.personaId,cwd:w,projectEnv:v.env},t.agentKey==="claude"){let E=_c(c);l=E.length>0,d=process.env.BRIDGE_MCP_URL?"http":"stdio",a=[...a,...E]}else if(t.agentKey==="codex"){let E=Ec(c);l=E.length>0,d="stdio",a=[...a,...E]}else if(t.agentKey==="qwen")l=Pc(c),d=l?"stdio":void 0;else if(t.agentKey==="kimi"){let E=vc(c);l=E.length>0,d=process.env.BRIDGE_MCP_URL?"http":"stdio",a=[...a,...E]}else t.agentKey==="forge"?(l=Oc(c),d=l?"stdio":void 0):t.agentKey==="opencode"?(l=Cc(c),d=l?process.env.BRIDGE_MCP_URL?"http":"stdio":void 0):t.agentKey==="gemini"?(l=Ac(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(Pr("phase2a.verified_at")&&(b.source==="daemon_override"||b.source==="server_project")){let E=`${y}/api/workspaces/${t.workspaceId}/projects/${t.projectId}/machine-paths/${t.daemonId}/verify`;fetch(E,{method:"PATCH",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:"{}"}).catch(U=>{console.warn("[daemon] verify.patch_failed",{projectId:t.projectId,error:String(U)})})}if(Pr("phase2a.auto_register")&&(b.source==="daemon_override"||b.source==="server_project"))try{let E=(0,Me.spawnSync)("git",["remote","get-url","origin"],{cwd:w,timeout:5e3,encoding:"utf-8"});if(E.status===0&&E.stdout&&E.stdout.trim()){let U=E.stdout.trim();t.projectId&&(n.projectPaths||(n.projectPaths={}),n.projectPaths[t.projectId]=w,re({projectPaths:n.projectPaths}));let lt=`${y}/api/workspaces/${t.workspaceId}/projects/${t.projectId}/machine-paths`;fetch(lt,{method:"POST",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:JSON.stringify({daemonId:t.daemonId,localPath:w,repoUrl:U})}).catch(Pi=>{console.warn("[daemon] auto_register.post_failed",{projectId:t.projectId,error:String(Pi)})}),console.log("[daemon] auto_register.ok",{projectId:t.projectId,localPath:w,repoUrl:U})}}catch(E){console.log("[daemon] auto_register.skipped",{projectId:t.projectId,reason:String(E)})}}let h=bc(t.role,t.systemPrompt,t.agentId,t.workspaceId,t.projectId,t.groupId),f=wc(t.agentKey,h,t.agentId);f.length>0&&(a=[...a,...f]);let g=Sc(t.agentKey,t.systemPrompt,t.agentId);g.length>0&&(a=[...a,...g]);let p=Math.max(1,Math.min(500,t.cols)),m=Math.max(1,Math.min(500,t.rows)),I=Date.now(),k="",C=0,T=!1,M=!1;if(r.spawn(t.agentId,t.agentKey,i.binaryPath,a,p,m,y=>{if(C+=y.length,t.agentKey==="gemini")try{let w=Buffer.from(y,"base64").toString("utf-8");if(w.includes("shell mode enabled"))me.get(t.agentId)||(me.set(t.agentId,!0),console.log("[daemon] gemini.shell_mode.entered",{agentId:t.agentId.slice(-8)}));else if(w.includes("Type your message")&&(me.get(t.agentId)&&(me.set(t.agentId,!1),console.log("[daemon] gemini.shell_mode.exited",{agentId:t.agentId.slice(-8)})),!Le.get(t.agentId))){Le.set(t.agentId,!0);let v=_e.get(t.agentId)??[];_e.delete(t.agentId),console.log("[daemon] gemini.ready",{agentId:t.agentId.slice(-8),flushing:v.length}),v.length>0&&setTimeout(()=>{for(let E of v)r.write(t.agentId,E,"orchestrator");setTimeout(()=>{r.write(t.agentId,Buffer.from("\r").toString("base64"),"orchestrator")},1e3)},500)}}catch{}try{let w=Buffer.from(y,"base64").toString("utf-8");if(t.agentKey==="kimi"&&t.role&&!M&&Date.now()-I<3e4&&(/yolo agent/.test(w)||/●/.test(w)||/○/.test(w))){M=!0;let v=h;if(v){let E=cc(v),U=Buffer.from(E).toString("base64");r.write(t.agentId,U,"orchestrator"),console.log("[daemon] kimi.role.injected",{agentId:t.agentId,role:t.role})}}}catch{}if(!k)try{let w=Buffer.from(y,"base64").toString("utf-8"),v=fc(w).replace(/\x00/g,"").trim();if(v&&(k=gc(v)),t.agentKey==="codex"&&!T&&Date.now()-I<2e4&&/included in your plan for free|let[’']s build together/i.test(v)&&/yes|no|\[y\/n\]|\(y\/n\)|y\/n/i.test(v)){T=!0;let E=Buffer.from("y").toString("base64");r.write(t.agentId,E,"orchestrator"),console.log("[daemon] codex.onboarding.auto_ack",{agentId:t.agentId})}}catch{}let b=r.getCurrentWs();b?.readyState===S.OPEN&&b.send(JSON.stringify({type:"output",agentId:t.agentId,data:y})),ic(t.agentId,()=>r.getCurrentWs())},(y,b)=>{let w=Date.now()-I,v=w<=pc;console.log("[daemon] pty.spawn.result",{agentId:t.agentId,agentKey:t.agentKey,daemonId:t.daemonId,exitCode:y,signal:b,uptimeMs:w,earlyExit:v,outputBytes:C,firstOutputSnippet:k||void 0});let E=r.getCurrentWs();v&&E?.readyState===S.OPEN&&E.send(JSON.stringify({type:"error",code:"SPAWN_FAILED",message:`Early exit: agent=${t.agentKey} code=${y??"null"} signal=${b??"null"} snippet="${k||"no output"}"`})),E?.readyState===S.OPEN&&E.send(JSON.stringify({type:"exit",agentId:t.agentId,exitCode:y,signal:b})),oc(t.agentId),me.delete(t.agentId),Le.delete(t.agentId),_e.delete(t.agentId),Promise.all([(0,st.unlink)(x.default.join(R.default.tmpdir(),`bridge-persona-${t.agentId}.md`)),(0,st.unlink)(x.default.join(R.default.tmpdir(),`bridge-role-${t.agentId}.md`)),(0,st.unlink)(x.default.join(R.default.tmpdir(),`bridge-mcp-${t.agentId}.json`)),(0,st.unlink)(x.default.join(R.default.tmpdir(),`bridge-mcp-kimi-${t.agentId}.json`))].map(U=>U.catch(()=>{}))).catch(()=>{})},c)){if(t.agentKey==="gemini"&&setTimeout(()=>{if(!Le.get(t.agentId)){Le.set(t.agentId,!0);let y=_e.get(t.agentId)??[];_e.delete(t.agentId),y.length>0&&(console.warn("[daemon] gemini.ready.timeout_fallback",{agentId:t.agentId.slice(-8),flushing:y.length}),setTimeout(()=>{for(let b of y)r.write(t.agentId,b,"orchestrator");setTimeout(()=>{r.write(t.agentId,Buffer.from("\r").toString("base64"),"orchestrator")},1e3)},500))}},3e4),u==="fallback_home"&&e.readyState===S.OPEN){let y=t.daemonLocalPath?"daemon_override_missing":"not_found";console.warn("[daemon] cwd_fallback",{agentId:t.agentId,requestedCwd:t.cwd,actualCwd:R.default.homedir(),reason:y,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:y,projectId:t.projectId,daemonId:t.daemonId}))}e.readyState===S.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 b=r.getLastError(t.agentId)?.includes("posix_spawnp failed")&&ac(t.agentKey);e.readyState===S.OPEN&&(b?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===S.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(!Le.get(t.agentId)){let o=_e.get(t.agentId)??[];o.push(t.data),_e.set(t.agentId,o),console.log("[daemon] gemini.input.buffered",{agentId:t.agentId.slice(-8),queued:o.length});break}if(me.get(t.agentId)){r.write(t.agentId,Buffer.from("\x1B").toString("base64"),"user"),me.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}),ye.get(t.agentId)?.(),ye.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([or(n.agentPaths),Tr()]).then(([i,o])=>{ot=o?[...i,o]:i,e.readyState===S.OPEN&&e.send(JSON.stringify({type:"agents",list:ot}))});break;case"dir_list":{let i=R.default.homedir(),o=(t.path||"~").replace(/^~/,i),a=x.default.resolve(o);if(a!==i&&!a.startsWith(i+x.default.sep)){e.readyState===S.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:x.default.join(a,l.name)})).sort((l,d)=>l.name.localeCompare(d.name));e.readyState===S.OPEN&&e.send(JSON.stringify({type:"dir_list_result",requestId:t.requestId,path:a,entries:c}))}catch(c){e.readyState===S.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 ot=[],Hr=!1,pi=!1;function hi(){return Hr}function fi(t){if(pi)throw new Error("[daemon] startDaemonConnection called twice \u2014 only one connection manager allowed");if(pi=!0,process.env.BRIDGE_TEST_SCRIPTED_REVIEW!=="1")try{let f=x.default.join(R.default.homedir(),".jerico","settings.json");N.default.existsSync(f)&&JSON.parse(N.default.readFileSync(f,"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=ge(),r=(0,at.createHash)("sha256").update(e.token).digest("hex"),n=new Tt(r),s=null,i=null,o=null,a=0,c=0,l=0n;function d(){i&&(clearTimeout(i),i=null);let f=Date.now(),g=process.hrtime.bigint();s=new S(e.server,{headers:{Authorization:`Bearer ${e.token}`}});let p=s,m=(0,at.randomUUID)();Gr=m;let I=R.default.networkInterfaces(),k=Object.entries(I).flatMap(([b,w])=>(w||[]).filter(E=>!E.internal).map(E=>({iface:b,address:E.address,family:E.family}))),C=JSON.stringify(k);console.log(JSON.stringify({ts:Date.now(),level:"info",event:"net.interfaces",interfaces:k,connectionId:m})),$t&&$t!==C&&console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"net.interfaces.changed",previous:$t,current:C,connectionId:m})),$t=C;let T=p.send.bind(p);p.send=function(b){if(p.readyState!==S.OPEN){let w="unknown";try{w=JSON.parse(b).type}catch{}console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.send.dropped",messageType:w,readyState:p.readyState,connectionId:m}));return}return T(b)},console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.connecting",server:e.server,connectionId:m}));let M=null,Se=0,y=null;p.on("open",()=>{Hr=!0,c=0,l=0n,console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.connected",server:e.server,connectionId:m})),o=setInterval(()=>{p.readyState===S.OPEN&&(p.ping(),Se=Date.now(),y&&clearTimeout(y),y=setTimeout(()=>{console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.heartbeat.timeout",connectionId:m})),p.terminate()},uc))},dc),t.setCurrentWs(p);let b=!ui();p.send(JSON.stringify({type:"ready",version:"1.1",npmVersion:"0.10.2",name:e.name,spawnHelperBroken:b,liveAgentIds:t.getLiveAgentIds(),machineFingerprint:qr(),connectionId:m,claudeTier:Dt()})),n.updateWs(p),Promise.all([or(e.agentPaths),Tr()]).then(([w,E])=>{ot=E?[...w,E]:w,p.readyState===S.OPEN&&p.send(JSON.stringify({type:"agents",list:ot}))}),M=li(w=>{p.readyState===S.OPEN&&p.send(JSON.stringify({type:"system_metrics",daemonId:r,...w}))})}),p.on("message",b=>{let w;try{w=JSON.parse(b.toString())}catch{console.warn("[daemon] Invalid JSON from server, ignoring");return}Tc(w,p,t,e,n)}),p.on("pong",()=>{y&&(clearTimeout(y),y=null);let b=Date.now()-Se;console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.heartbeat.pong",rttMs:b,connectionId:m}))}),p.on("close",(b,w)=>{Hr=!1,o&&(clearInterval(o),o=null),y&&(clearTimeout(y),y=null),M?.(),M=null,n.stopAll(),b===1008?(a++,a>=2&&(console.error("[daemon] ws.auth_failed \u2014 token invalid or expired (2 consecutive rejections), stopping. Re-run: bridge-agent auth"),process.exit(1)),console.warn("[daemon] ws.auth_rejected \u2014 transient 1008, will retry once",{attempt:a})):a=0;let E=Number((process.hrtime.bigint()-g)/1000000n);if(console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.closed",code:b,reason:w?.toString()||void 0,uptimeMs:E,connectionId:m})),i)return;c===0&&(l=process.hrtime.bigint()),c++;let v=Number((process.hrtime.bigint()-l)/1000000n);c>=10&&v<6e4&&(console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.reconnect.storm",reconnectCount:c,connectionId:m})),process.exit(1));let U=Math.min(3e4,1e3*Math.pow(2,Math.min(c,5))),lt=Math.round(U+Math.random()*500);console.log(JSON.stringify({ts:Date.now(),level:"info",event:"ws.reconnect.scheduled",delayMs:lt,reconnectCount:c,connectionId:m})),i=setTimeout(d,lt)}),p.on("error",b=>{console.log(JSON.stringify({ts:Date.now(),level:"error",event:"ws.error",message:b.message,code:b.code,connectionId:m}))})}function u(){o&&(clearInterval(o),o=null),t.stopLivenessCheck(),lc();for(let f of ye.values())f();n.stopAll(),t.killAll(),s?.close()}function h(f){console.log(JSON.stringify({ts:Date.now(),level:"warn",event:"ws.signal",signal:f,connectionId:Gr})),u(),setTimeout(()=>process.exit(0),100)}process.on("SIGINT",()=>h("SIGINT")),process.on("SIGTERM",()=>h("SIGTERM")),process.on("SIGHUP",()=>h("SIGHUP")),process.on("uncaughtException",f=>{console.log(JSON.stringify({ts:Date.now(),level:"error",event:"daemon.uncaught",error:String(f),stack:f.stack,connectionId:Gr})),t.killAll(),process.exit(1)}),d()}function Tc(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=ot.find(y=>y.key===t.agentKey);if(!i){e.readyState===S.OPEN&&e.send(JSON.stringify({type:"error",code:"AGENT_NOT_FOUND",message:`Agent '${t.agentKey}' is not installed on this machine`}));return}let o=oe.find(y=>y.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"&&(ye.get(t.agentId)?.(),ye.set(t.agentId,Br(t.agentId,t.sessionId,(y,b,w)=>{let E=r.getCurrentWs();E?.readyState===S.OPEN&&E.send(JSON.stringify({type:"panel_token_usage",agentId:y,usedPct:b,usedTokens:w,...Be}))})));else if(o?.assignSessionId){let y=crypto.randomUUID(),b=t.agentKey==="kimi"?"--session":t.agentKey==="forge"?"--conversation-id":"--session-id";a=[...o.spawnArgs??[],b,y],e.readyState===S.OPEN&&(e.send(JSON.stringify({type:"session_started",agentId:t.agentId,sessionId:y})),console.log("[daemon] session.assigned",{agentId:t.agentId,sessionId:y})),t.agentKey==="claude"&&(ye.get(t.agentId)?.(),ye.set(t.agentId,Br(t.agentId,y,(w,E,v)=>{let U=r.getCurrentWs();U?.readyState===S.OPEN&&U.send(JSON.stringify({type:"panel_token_usage",agentId:w,usedPct:E,usedTokens:v,...Be}))})))}else a=[...o?.spawnArgs??[]],e.readyState===S.OPEN&&e.send(JSON.stringify({type:"session_started",agentId:t.agentId,sessionId:crypto.randomUUID()}));let c,l=!1,d,u;if(t.workspaceId){let y=mc(n.server),b=Ic(t.projectId??"",t.cwd,t.daemonLocalPath,n.projectPaths),w=b.path;if(u=b.source,u==="fallback_home"&&t.sessionId){let v=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:v}),e.readyState===S.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 E=jr(w);if(c={serverUrl:y,token:n.token,workspaceId:Bs(t.workspaceId),projectId:t.projectId?Ms(t.projectId):void 0,agentId:t.agentId?Ls(t.agentId):void 0,personaId:t.personaId,cwd:w,projectEnv:E.env},t.agentKey==="claude"){let v=_c(c);l=v.length>0,d=process.env.BRIDGE_MCP_URL?"http":"stdio",a=[...a,...v]}else if(t.agentKey==="codex"){let v=Ec(c);l=v.length>0,d="stdio",a=[...a,...v]}else if(t.agentKey==="qwen")l=Pc(c),d=l?"stdio":void 0;else if(t.agentKey==="kimi"){let v=vc(c);l=v.length>0,d=process.env.BRIDGE_MCP_URL?"http":"stdio",a=[...a,...v]}else t.agentKey==="forge"?(l=Oc(c),d=l?"stdio":void 0):t.agentKey==="opencode"?(l=Cc(c),d=l?process.env.BRIDGE_MCP_URL?"http":"stdio":void 0):t.agentKey==="gemini"?(l=Ac(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(Pr("phase2a.verified_at")&&(b.source==="daemon_override"||b.source==="server_project")){let v=`${y}/api/workspaces/${t.workspaceId}/projects/${t.projectId}/machine-paths/${t.daemonId}/verify`;fetch(v,{method:"PATCH",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:"{}"}).catch(U=>{console.warn("[daemon] verify.patch_failed",{projectId:t.projectId,error:String(U)})})}if(Pr("phase2a.auto_register")&&(b.source==="daemon_override"||b.source==="server_project"))try{let v=(0,Me.spawnSync)("git",["remote","get-url","origin"],{cwd:w,timeout:5e3,encoding:"utf-8"});if(v.status===0&&v.stdout&&v.stdout.trim()){let U=v.stdout.trim();t.projectId&&(n.projectPaths||(n.projectPaths={}),n.projectPaths[t.projectId]=w,re({projectPaths:n.projectPaths}));let lt=`${y}/api/workspaces/${t.workspaceId}/projects/${t.projectId}/machine-paths`;fetch(lt,{method:"POST",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:JSON.stringify({daemonId:t.daemonId,localPath:w,repoUrl:U})}).catch(Pi=>{console.warn("[daemon] auto_register.post_failed",{projectId:t.projectId,error:String(Pi)})}),console.log("[daemon] auto_register.ok",{projectId:t.projectId,localPath:w,repoUrl:U})}}catch(v){console.log("[daemon] auto_register.skipped",{projectId:t.projectId,reason:String(v)})}}let h=bc(t.role,t.systemPrompt,t.agentId,t.workspaceId,t.projectId,t.groupId),f=wc(t.agentKey,h,t.agentId);f.length>0&&(a=[...a,...f]);let g=Sc(t.agentKey,t.systemPrompt,t.agentId);g.length>0&&(a=[...a,...g]);let p=Math.max(1,Math.min(500,t.cols)),m=Math.max(1,Math.min(500,t.rows)),I=Date.now(),k="",C=0,T=!1,M=!1;if(r.spawn(t.agentId,t.agentKey,i.binaryPath,a,p,m,y=>{if(C+=y.length,t.agentKey==="gemini")try{let w=Buffer.from(y,"base64").toString("utf-8");if(w.includes("shell mode enabled"))me.get(t.agentId)||(me.set(t.agentId,!0),console.log("[daemon] gemini.shell_mode.entered",{agentId:t.agentId.slice(-8)}));else if(w.includes("Type your message")&&(me.get(t.agentId)&&(me.set(t.agentId,!1),console.log("[daemon] gemini.shell_mode.exited",{agentId:t.agentId.slice(-8)})),!Le.get(t.agentId))){Le.set(t.agentId,!0);let E=_e.get(t.agentId)??[];_e.delete(t.agentId),console.log("[daemon] gemini.ready",{agentId:t.agentId.slice(-8),flushing:E.length}),E.length>0&&setTimeout(()=>{for(let v of E)r.write(t.agentId,v,"orchestrator");setTimeout(()=>{r.write(t.agentId,Buffer.from("\r").toString("base64"),"orchestrator")},1e3)},500)}}catch{}try{let w=Buffer.from(y,"base64").toString("utf-8");if(t.agentKey==="kimi"&&t.role&&!M&&Date.now()-I<3e4&&(/yolo agent/.test(w)||/●/.test(w)||/○/.test(w))){M=!0;let E=h;if(E){let v=cc(E),U=Buffer.from(v).toString("base64");r.write(t.agentId,U,"orchestrator"),console.log("[daemon] kimi.role.injected",{agentId:t.agentId,role:t.role})}}}catch{}if(!k)try{let w=Buffer.from(y,"base64").toString("utf-8"),E=fc(w).replace(/\x00/g,"").trim();if(E&&(k=gc(E)),t.agentKey==="codex"&&!T&&Date.now()-I<2e4&&/included in your plan for free|let[’']s build together/i.test(E)&&/yes|no|\[y\/n\]|\(y\/n\)|y\/n/i.test(E)){T=!0;let v=Buffer.from("y").toString("base64");r.write(t.agentId,v,"orchestrator"),console.log("[daemon] codex.onboarding.auto_ack",{agentId:t.agentId})}}catch{}let b=r.getCurrentWs();b?.readyState===S.OPEN&&b.send(JSON.stringify({type:"output",agentId:t.agentId,data:y})),ic(t.agentId,()=>r.getCurrentWs())},(y,b)=>{let w=Date.now()-I,E=w<=pc;console.log("[daemon] pty.spawn.result",{agentId:t.agentId,agentKey:t.agentKey,daemonId:t.daemonId,exitCode:y,signal:b,uptimeMs:w,earlyExit:E,outputBytes:C,firstOutputSnippet:k||void 0});let v=r.getCurrentWs();E&&v?.readyState===S.OPEN&&v.send(JSON.stringify({type:"error",code:"SPAWN_FAILED",message:`Early exit: agent=${t.agentKey} code=${y??"null"} signal=${b??"null"} snippet="${k||"no output"}"`})),v?.readyState===S.OPEN&&v.send(JSON.stringify({type:"exit",agentId:t.agentId,exitCode:y,signal:b})),oc(t.agentId),me.delete(t.agentId),Le.delete(t.agentId),_e.delete(t.agentId),Promise.all([(0,st.unlink)(x.default.join(R.default.tmpdir(),`bridge-persona-${t.agentId}.md`)),(0,st.unlink)(x.default.join(R.default.tmpdir(),`bridge-role-${t.agentId}.md`)),(0,st.unlink)(x.default.join(R.default.tmpdir(),`bridge-mcp-${t.agentId}.json`)),(0,st.unlink)(x.default.join(R.default.tmpdir(),`bridge-mcp-kimi-${t.agentId}.json`))].map(U=>U.catch(()=>{}))).catch(()=>{})},c)){if(t.agentKey==="gemini"&&setTimeout(()=>{if(!Le.get(t.agentId)){Le.set(t.agentId,!0);let y=_e.get(t.agentId)??[];_e.delete(t.agentId),y.length>0&&(console.warn("[daemon] gemini.ready.timeout_fallback",{agentId:t.agentId.slice(-8),flushing:y.length}),setTimeout(()=>{for(let b of y)r.write(t.agentId,b,"orchestrator");setTimeout(()=>{r.write(t.agentId,Buffer.from("\r").toString("base64"),"orchestrator")},1e3)},500))}},3e4),u==="fallback_home"&&e.readyState===S.OPEN){let y=t.daemonLocalPath?"daemon_override_missing":"not_found";console.warn("[daemon] cwd_fallback",{agentId:t.agentId,requestedCwd:t.cwd,actualCwd:R.default.homedir(),reason:y,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:y,projectId:t.projectId,daemonId:t.daemonId}))}e.readyState===S.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 b=r.getLastError(t.agentId)?.includes("posix_spawnp failed")&&ac(t.agentKey);e.readyState===S.OPEN&&(b?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===S.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(!Le.get(t.agentId)){let o=_e.get(t.agentId)??[];o.push(t.data),_e.set(t.agentId,o),console.log("[daemon] gemini.input.buffered",{agentId:t.agentId.slice(-8),queued:o.length});break}if(me.get(t.agentId)){r.write(t.agentId,Buffer.from("\x1B").toString("base64"),"user"),me.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}),ye.get(t.agentId)?.(),ye.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([or(n.agentPaths),Tr()]).then(([i,o])=>{ot=o?[...i,o]:i,e.readyState===S.OPEN&&e.send(JSON.stringify({type:"agents",list:ot}))});break;case"dir_list":{let i=R.default.homedir(),o=(t.path||"~").replace(/^~/,i),a=x.default.resolve(o);if(a!==i&&!a.startsWith(i+x.default.sep)){e.readyState===S.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:x.default.join(a,l.name)})).sort((l,d)=>l.name.localeCompare(d.name));e.readyState===S.OPEN&&e.send(JSON.stringify({type:"dir_list_result",requestId:t.requestId,path:a,entries:c}))}catch(c){e.readyState===S.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.
@@ -450,4 +450,4 @@ ${c} </dict>
450
450
  </plist>
451
451
  `;try{return(0,D.writeFileSync)(r,h,"utf-8"),!0}catch(f){return console.warn("[bridge] launchd.plist.write.failed",{error:String(f)}),!1}}function jc(){let t=Ne(),e=$.default.join(Ut,t);try{return(0,we.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 Lc(t){let{out:e,err:r}=Rt();try{let n=(0,we.spawn)(t,["start"],{detached:!0,stdio:"ignore",env:{...process.env,PATH:_i(),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 Bc(){let t=parseInt(process.env.HEALTH_PORT??"3101",10),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 Mc(){mi();let t=new ht;fi(t),t.startLivenessCheck(6e4);let e=parseInt(process.env.HEALTH_PORT??"3101",10),r=(0,gi.createServer)((n,s)=>{let i=hi(),o=JSON.stringify({status:"ok",connected:i,uptime:process.uptime()});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 yi(){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){Mc();return}let e=Nc();if(!e.ok){let l=e.err,d=Re();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=Rc(),n=Dc(r),{ok:s,permissionDenied:i}=n?jc():{ok:!1,permissionDenied:!1},o=$.default.join(Ut,Ne()),{out:a,err:c}=Rt();if(s){console.log("[bridge] launchd.ok \u2014 managed, auto-restart enabled"),console.log("[bridge] logs: tail -f",{out:a,err:c}),Bc(),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
  `)),Lc(r),process.exit(0)}var bi=_(require("https")),wi=_(require("http"));De();fe();var $c="https://lcars.jerico.appnova.io";function Uc(t){return(t??"").trim()}async function Si(t,e=!1,r){let n=!(t&&t.trim()),s=n?$c: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=Uc(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 Wc()),o||(console.error("[bridge] No token provided. Exiting."),process.exit(1)),await Gc(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");re({server:l,token:o,name:process.env.HOSTNAME??"My Machine"}),console.log(`[bridge] Auth successful! Config saved to ${Z()}`),console.log("[bridge] Run: bridge-agent start"),process.exit(0)}async function Wc(){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 Gc(t,e){return new Promise(r=>{let n=new URL("/api/tokens/validate",t),s=n.protocol==="https:",i=s?bi.default:wi.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 vi=_(require("https")),Ei=_(require("http")),Vr=_(require("fs")),Kr=_(require("path")),ki=require("node:crypto");De();function Fc(t){return t.replace(/^wss?:/,e=>e==="wss:"?"https:":"http:").replace(/\/ws(\/.*)?$/,"")}async function Ii(t,e,r){let n=ge(),s=(0,ki.createHash)("sha256").update(n.token).digest("hex"),i=Fc(n.server),o=Kr.default.resolve(r);Kr.default.isAbsolute(o)||(console.error("[bridge] link-project: path must be absolute"),process.exit(1)),Vr.default.existsSync(o)||(console.error("[bridge] link-project: path does not exist:",o),process.exit(1)),Vr.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?vi.default:Ei.default;n.projectPaths={...n.projectPaths??{},[e]:o},re({projectPaths:n.projectPaths}),console.log("[cli] link-project.local_json_written",{projectId:e,path:o});let u=JSON.stringify({daemonId:s,localPath:o,machineFingerprint:qr()}),h=await new Promise((f,g)=>{let p=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)}},m=>{let I="";m.on("data",k=>{I+=k}),m.on("end",()=>{if(m.statusCode===200)f(200);else{try{let k=JSON.parse(I);console.error("[bridge] link-project failed:",k.error??`HTTP ${m.statusCode}`)}catch{console.error("[bridge] link-project failed:",`HTTP ${m.statusCode}`)}f(m.statusCode??0)}})});p.on("error",m=>{g(m)}),p.write(u),p.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))}De();function Hc(t){return t.replace(/^wss?:/,e=>e==="wss:"?"https:":"http:").replace(/\/ws(\/.*)?$/,"")}async function xi(){let t=ge(),e=Hc(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 Jr=require("node:child_process"),ct=require("node:fs"),Yr=_(require("path"));fe();var Oi=require("node:os"),qc=Yr.default.join((0,Oi.homedir)(),"Library","LaunchAgents");function Ci(){let t=Ne(),e=t.replace(".plist",""),r=Yr.default.join(qc,t);try{(0,Jr.execSync)(`launchctl bootout gui/$(id -u)/${e}`,{stdio:"pipe"}),console.log("[bridge] launchd.stopped \u2014 daemon unloaded")}catch{try{(0,ct.existsSync)(r)?((0,Jr.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=Re();if((0,ct.existsSync)(n))try{(0,ct.unlinkSync)(n),console.log("[bridge] lock.cleaned")}catch{}}var se=new un;se.name("bridge-agent").description("Bridge local agent \u2014 connects your AI tools to Jerico").version("0.10.1").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, or 3101+offset per profile)").action(t=>{t.healthPort&&(process.env.HEALTH_PORT=t.healthPort),yi()});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=>{Si(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)=>{Ii(t,e,r)});se.command("cleanup-orphans").description("Remove orphaned daemon_project_paths rows for this user").action(()=>{xi()});se.command("status").description("Show connection status").action(async()=>{try{let{loadConfig:t}=await Promise.resolve().then(()=>(De(),ei)),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(()=>{Ci()});se.parse();
453
+ `)&&(process.stdin.pause(),t(e.trim()))}),process.stdin.resume()})}async function Gc(t,e){return new Promise(r=>{let n=new URL("/api/tokens/validate",t),s=n.protocol==="https:",i=s?bi.default:wi.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 vi=_(require("https")),Ei=_(require("http")),Vr=_(require("fs")),Kr=_(require("path")),ki=require("node:crypto");De();function Fc(t){return t.replace(/^wss?:/,e=>e==="wss:"?"https:":"http:").replace(/\/ws(\/.*)?$/,"")}async function Ii(t,e,r){let n=ge(),s=(0,ki.createHash)("sha256").update(n.token).digest("hex"),i=Fc(n.server),o=Kr.default.resolve(r);Kr.default.isAbsolute(o)||(console.error("[bridge] link-project: path must be absolute"),process.exit(1)),Vr.default.existsSync(o)||(console.error("[bridge] link-project: path does not exist:",o),process.exit(1)),Vr.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?vi.default:Ei.default;n.projectPaths={...n.projectPaths??{},[e]:o},re({projectPaths:n.projectPaths}),console.log("[cli] link-project.local_json_written",{projectId:e,path:o});let u=JSON.stringify({daemonId:s,localPath:o,machineFingerprint:qr()}),h=await new Promise((f,g)=>{let p=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)}},m=>{let I="";m.on("data",k=>{I+=k}),m.on("end",()=>{if(m.statusCode===200)f(200);else{try{let k=JSON.parse(I);console.error("[bridge] link-project failed:",k.error??`HTTP ${m.statusCode}`)}catch{console.error("[bridge] link-project failed:",`HTTP ${m.statusCode}`)}f(m.statusCode??0)}})});p.on("error",m=>{g(m)}),p.write(u),p.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))}De();function Hc(t){return t.replace(/^wss?:/,e=>e==="wss:"?"https:":"http:").replace(/\/ws(\/.*)?$/,"")}async function xi(){let t=ge(),e=Hc(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 Jr=require("node:child_process"),ct=require("node:fs"),Yr=_(require("path"));fe();var Oi=require("node:os"),qc=Yr.default.join((0,Oi.homedir)(),"Library","LaunchAgents");function Ci(){let t=Ne(),e=t.replace(".plist",""),r=Yr.default.join(qc,t);try{(0,Jr.execSync)(`launchctl bootout gui/$(id -u)/${e}`,{stdio:"pipe"}),console.log("[bridge] launchd.stopped \u2014 daemon unloaded")}catch{try{(0,ct.existsSync)(r)?((0,Jr.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=Re();if((0,ct.existsSync)(n))try{(0,ct.unlinkSync)(n),console.log("[bridge] lock.cleaned")}catch{}}var se=new un;se.name("bridge-agent").description("Bridge local agent \u2014 connects your AI tools to Jerico").version("0.10.2").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, or 3101+offset per profile)").action(t=>{t.healthPort&&(process.env.HEALTH_PORT=t.healthPort),yi()});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=>{Si(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)=>{Ii(t,e,r)});se.command("cleanup-orphans").description("Remove orphaned daemon_project_paths rows for this user").action(()=>{xi()});se.command("status").description("Show connection status").action(async()=>{try{let{loadConfig:t}=await Promise.resolve().then(()=>(De(),ei)),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(()=>{Ci()});se.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bridge-agent",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "Bridge local agent — connects your AI tools to Jerico",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",