glenn-code 1.0.37 → 1.0.39

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.
@@ -1356,7 +1356,7 @@ You have access to **Playwright MCP** tools to verify the UI works correctly aft
1356
1356
  Recent logs:
1357
1357
  ${D.join(`
1358
1358
  `)}`:"";h.backendError||(h.backendError=`Backend failed to start.${R}`)}return P&&!N.web&&(h.success=!1,h.frontendError||(h.frontendError="Frontend failed to start")),h},Rt=async()=>{if(!l||!I.existsSync(l))return{success:!0};try{return re(f,{cwd:l,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),{success:!0}}catch(S){let h=S;return{success:!1,errors:h.stdout||h.stderr||"Build failed"}}},Tt=async()=>{if(!g||!I.existsSync(ne.join(g,"package.json")))return{success:!0};try{return re(E,{cwd:g,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),{success:!0}}catch(S){let h=S;return{success:!1,errors:h.stdout||h.stderr||"Type check failed"}}},gn=async()=>{let[S,h]=await Promise.all([Rt(),Tt()]);return{backend:S,frontend:h}},It=async(S,h)=>{let v=S==="backend"?x:w;if(!I.existsSync(v))return[`Log file not found: ${v}`];try{return re(`tail -n ${h} ${v}`,{encoding:"utf-8"}).split(`
1359
- `).filter(Boolean)}catch(P){return[`Error reading logs: ${P instanceof Error?P.message:String(P)}`]}};return{startBackend:d,startFrontend:C,stopBackend:U,stopFrontend:$,restartServices:un,checkHealth:pe,waitForHealth:Pt,getProcesses:()=>({backend:m,frontend:j}),checkBackendBuild:Rt,checkFrontendTypes:Tt,runTypeChecks:gn,tailLogs:It,checkSwaggerEndpoints:async S=>{let h=ne.join(e,"swagger.json");if(!I.existsSync(h))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let v=JSON.parse(I.readFileSync(h,"utf-8")),P=Object.keys(v.paths||{}),N=[];for(let D of P)if(D.toLowerCase().includes(S.toLowerCase())){let R=Object.keys(v.paths[D]);for(let Z of R)N.push(`${Z.toUpperCase()} ${D}`)}return{foundEndpoints:N,totalEndpoints:P.length}}catch(v){return{foundEndpoints:[`Error parsing swagger.json: ${v instanceof Error?v.message:String(v)}`],totalEndpoints:0}}}}}function Mn(n){let e=n.toLowerCase();return e.includes("exception")||e.includes("fail:")||e.includes("[err]")||e.includes("[error]")}import{execSync as ie}from"child_process";function Me(n){let e=async()=>{try{return ie("git status --porcelain",{cwd:n,encoding:"utf-8"}).trim().length>0}catch{return!1}},t=async()=>{try{return ie("git branch --show-current",{cwd:n,encoding:"utf-8"}).trim()}catch{return"unknown"}};return{hasChanges:e,commitAndPush:async(s,r)=>{try{if(!await e())return{success:!0,noChanges:!0};let i=s.length>60?s.substring(0,60)+"...":s,c=`${r?"[agent] (partial)":"[agent]"} ${i}`;ie("git add -A",{cwd:n}),ie(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:n,encoding:"utf-8"});let l=ie("git rev-parse --short HEAD",{cwd:n,encoding:"utf-8"}).trim();try{ie("git push",{cwd:n,stdio:"pipe"})}catch(g){let u=g instanceof Error?g.message:String(g);if(u.includes("no upstream branch")){let p=await t();ie(`git push --set-upstream origin ${p}`,{cwd:n,stdio:"pipe"})}else return console.error("[Git] Push failed:",u),{success:!1,commitHash:l,commitSucceeded:!0,pushFailed:!0,error:u}}return{success:!0,commitHash:l}}catch(i){let a=i instanceof Error?i.message:String(i);return console.error("[Git] Error:",a),{success:!1,error:a}}},getCurrentBranch:t}}import*as oe from"@microsoft/signalr";import*as zt from"fs";import*as Jt from"os";import*as Qt from"path";import{exec as Fn}from"child_process";import{promisify as $n}from"util";var K=class{constructor(e,t){this.connection=e;this.receiverMethod=t}dispose=()=>{for(let e of this.receiverMethod)this.connection.off(e.methodName,e.method)}},qt=n=>{if(n==="IDeploymentWatcherHub")return et.Instance;if(n==="IDeploymentHub")return nt.Instance;if(n==="IKanbanHub")return st.Instance;if(n==="IAgentHub")return it.Instance;if(n==="ISlaveHub")return ct.Instance;if(n==="ISlaveWatcherHub")return pt.Instance;if(n==="ITestHub")return ut.Instance},Yt=n=>{if(n==="IDeploymentWatcherClient")return mt.Instance;if(n==="IDeploymentHubClient")return ht.Instance;if(n==="IKanbanBoardClient")return ft.Instance;if(n==="IAgentReceiver")return yt.Instance;if(n==="IBackofficeReceiver")return bt.Instance;if(n==="ISlaveHubClient")return St.Instance;if(n==="ISlaveWatcherClient")return wt.Instance;if(n==="ITestHubClient")return vt.Instance},et=class n{static Instance=new n;constructor(){}createHubProxy=e=>new tt(e)},tt=class{constructor(e){this.connection=e}watchMachine=async e=>await this.connection.invoke("WatchMachine",e);unwatchMachine=async e=>await this.connection.invoke("UnwatchMachine",e);startStreamingLogs=async e=>await this.connection.invoke("StartStreamingLogs",e);stopStreamingLogs=async e=>await this.connection.invoke("StopStreamingLogs",e)},nt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new ot(e)},ot=class{constructor(e){this.connection=e}registerMachine=async(e,t)=>await this.connection.invoke("RegisterMachine",e,t);getSecrets=async()=>await this.connection.invoke("GetSecrets");reportDeploymentStatus=async e=>await this.connection.invoke("ReportDeploymentStatus",e);reportHealth=async e=>await this.connection.invoke("ReportHealth",e);reportMachineStatus=async e=>await this.connection.invoke("ReportMachineStatus",e);sendDeploymentLog=async e=>await this.connection.invoke("SendDeploymentLog",e)},st=class n{static Instance=new n;constructor(){}createHubProxy=e=>new rt(e)},rt=class{constructor(e){this.connection=e}joinBoard=async e=>await this.connection.invoke("JoinBoard",e);leaveBoard=async e=>await this.connection.invoke("LeaveBoard",e)},it=class n{static Instance=new n;constructor(){}createHubProxy=e=>new at(e)},at=class{constructor(e){this.connection=e}registerAgent=async e=>await this.connection.invoke("RegisterAgent",e);getSecrets=async()=>await this.connection.invoke("GetSecrets");reportStatus=async(e,t)=>await this.connection.invoke("ReportStatus",e,t);reportSessionOutput=async(e,t,o)=>await this.connection.invoke("ReportSessionOutput",e,t,o);reportSessionCost=async(e,t,o)=>await this.connection.invoke("ReportSessionCost",e,t,o);reportInsight=async(e,t)=>await this.connection.invoke("ReportInsight",e,t);setClaudeSessionId=async(e,t)=>await this.connection.invoke("SetClaudeSessionId",e,t);sessionCompleted=async(e,t,o)=>await this.connection.invoke("SessionCompleted",e,t,o);initSessionCompleted=async(e,t,o,s)=>await this.connection.invoke("InitSessionCompleted",e,t,o,s);reportPreviewBuild=async(e,t,o)=>await this.connection.invoke("ReportPreviewBuild",e,t,o);saveSpecification=async(e,t,o,s)=>await this.connection.invoke("SaveSpecification",e,t,o,s);getSpecification=async(e,t)=>await this.connection.invoke("GetSpecification",e,t);listSpecifications=async e=>await this.connection.invoke("ListSpecifications",e);deleteSpecification=async(e,t)=>await this.connection.invoke("DeleteSpecification",e,t);watchContainer=async e=>await this.connection.invoke("WatchContainer",e);watchSession=async e=>await this.connection.invoke("WatchSession",e);watchProject=async e=>await this.connection.invoke("WatchProject",e);unwatchProject=async e=>await this.connection.invoke("UnwatchProject",e);watchSlaves=async()=>await this.connection.invoke("WatchSlaves");unwatchSlaves=async()=>await this.connection.invoke("UnwatchSlaves");sendPrompt=async(e,t,o,s)=>await this.connection.invoke("SendPrompt",e,t,o,s);stopSession=async e=>await this.connection.invoke("StopSession",e);switchSession=async(e,t)=>await this.connection.invoke("SwitchSession",e,t);createSession=async e=>await this.connection.invoke("CreateSession",e);refreshGitHubToken=async()=>await this.connection.invoke("RefreshGitHubToken");reportError=async(e,t)=>await this.connection.invoke("ReportError",e,t);startClaudeLogin=async e=>await this.connection.invoke("StartClaudeLogin",e);submitClaudeLoginCode=async(e,t)=>await this.connection.invoke("SubmitClaudeLoginCode",e,t)},ct=class n{static Instance=new n;constructor(){}createHubProxy=e=>new lt(e)},lt=class{constructor(e){this.connection=e}register=async(e,t)=>await this.connection.invoke("Register",e,t);getSecrets=async()=>await this.connection.invoke("GetSecrets");containerCreated=async e=>await this.connection.invoke("ContainerCreated",e);containerReady=async e=>await this.connection.invoke("ContainerReady",e);reportCapacity=async e=>await this.connection.invoke("ReportCapacity",e);reportError=async e=>await this.connection.invoke("ReportError",e);reportDockerContainers=async e=>await this.connection.invoke("ReportDockerContainers",e);reportContainerLog=async e=>await this.connection.invoke("ReportContainerLog",e);reportAgentRestarted=async(e,t,o)=>await this.connection.invoke("ReportAgentRestarted",e,t,o);reportContainerTerminated=async(e,t,o)=>await this.connection.invoke("ReportContainerTerminated",e,t,o);reportSlaveAgentLog=async e=>await this.connection.invoke("ReportSlaveAgentLog",e);reportClaudeLoginUrl=async e=>await this.connection.invoke("ReportClaudeLoginUrl",e);reportClaudeLoginResult=async e=>await this.connection.invoke("ReportClaudeLoginResult",e)},pt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new dt(e)},dt=class{constructor(e){this.connection=e}watchSlave=async e=>await this.connection.invoke("WatchSlave",e);unwatchSlave=async e=>await this.connection.invoke("UnwatchSlave",e);requestDockerContainers=async e=>await this.connection.invoke("RequestDockerContainers",e);startStreamingContainerLogs=async(e,t,o)=>await this.connection.invoke("StartStreamingContainerLogs",e,t,o);stopStreamingContainerLogs=async(e,t)=>await this.connection.invoke("StopStreamingContainerLogs",e,t);restartLabAgent=async(e,t)=>await this.connection.invoke("RestartLabAgent",e,t);terminateContainer=async(e,t)=>await this.connection.invoke("TerminateContainer",e,t);startStreamingSlaveAgentLogs=async(e,t)=>await this.connection.invoke("StartStreamingSlaveAgentLogs",e,t);stopStreamingSlaveAgentLogs=async e=>await this.connection.invoke("StopStreamingSlaveAgentLogs",e);startClaudeLogin=async(e,t)=>await this.connection.invoke("StartClaudeLogin",e,t);submitClaudeLoginCode=async(e,t,o)=>await this.connection.invoke("SubmitClaudeLoginCode",e,t,o)},ut=class n{static Instance=new n;constructor(){}createHubProxy=e=>new gt(e)},gt=class{constructor(e){this.connection=e}joinProject=async e=>await this.connection.invoke("JoinProject",e);leaveProject=async e=>await this.connection.invoke("LeaveProject",e)},mt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...a)=>t.deploymentStatusUpdated(...a),s=(...a)=>t.deploymentLogReceived(...a),r=(...a)=>t.machineStatusUpdated(...a);e.on("DeploymentStatusUpdated",o),e.on("DeploymentLogReceived",s),e.on("MachineStatusUpdated",r);let i=[{methodName:"DeploymentStatusUpdated",method:o},{methodName:"DeploymentLogReceived",method:s},{methodName:"MachineStatusUpdated",method:r}];return new K(e,i)}},ht=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...c)=>t.deploy(...c),s=(...c)=>t.stop(...c),r=(...c)=>t.startLogStreaming(...c),i=(...c)=>t.stopLogStreaming(...c);e.on("Deploy",o),e.on("Stop",s),e.on("StartLogStreaming",r),e.on("StopLogStreaming",i);let a=[{methodName:"Deploy",method:o},{methodName:"Stop",method:s},{methodName:"StartLogStreaming",method:r},{methodName:"StopLogStreaming",method:i}];return new K(e,a)}},ft=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...m)=>t.boardUpdated(...m),s=(...m)=>t.boardDeleted(...m),r=(...m)=>t.columnCreated(...m),i=(...m)=>t.columnUpdated(...m),a=(...m)=>t.columnDeleted(...m),c=(...m)=>t.cardCreated(...m),l=(...m)=>t.cardUpdated(...m),g=(...m)=>t.cardDeleted(...m),u=(...m)=>t.subtaskCreated(...m),p=(...m)=>t.subtaskUpdated(...m),f=(...m)=>t.subtaskDeleted(...m),k=(...m)=>t.noteCreated(...m),E=(...m)=>t.noteUpdated(...m),x=(...m)=>t.noteDeleted(...m);e.on("BoardUpdated",o),e.on("BoardDeleted",s),e.on("ColumnCreated",r),e.on("ColumnUpdated",i),e.on("ColumnDeleted",a),e.on("CardCreated",c),e.on("CardUpdated",l),e.on("CardDeleted",g),e.on("SubtaskCreated",u),e.on("SubtaskUpdated",p),e.on("SubtaskDeleted",f),e.on("NoteCreated",k),e.on("NoteUpdated",E),e.on("NoteDeleted",x);let w=[{methodName:"BoardUpdated",method:o},{methodName:"BoardDeleted",method:s},{methodName:"ColumnCreated",method:r},{methodName:"ColumnUpdated",method:i},{methodName:"ColumnDeleted",method:a},{methodName:"CardCreated",method:c},{methodName:"CardUpdated",method:l},{methodName:"CardDeleted",method:g},{methodName:"SubtaskCreated",method:u},{methodName:"SubtaskUpdated",method:p},{methodName:"SubtaskDeleted",method:f},{methodName:"NoteCreated",method:k},{methodName:"NoteUpdated",method:E},{methodName:"NoteDeleted",method:x}];return new K(e,w)}},yt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...u)=>t.initSession(...u),s=(...u)=>t.runPrompt(...u),r=(...u)=>t.setModel(...u),i=()=>t.stopAgent(),a=()=>t.ping(),c=(...u)=>t.switchSession(...u),l=(...u)=>t.projectPromptUpdated(...u);e.on("InitSession",o),e.on("RunPrompt",s),e.on("SetModel",r),e.on("StopAgent",i),e.on("Ping",a),e.on("SwitchSession",c),e.on("ProjectPromptUpdated",l);let g=[{methodName:"InitSession",method:o},{methodName:"RunPrompt",method:s},{methodName:"SetModel",method:r},{methodName:"StopAgent",method:i},{methodName:"Ping",method:a},{methodName:"SwitchSession",method:c},{methodName:"ProjectPromptUpdated",method:l}];return new K(e,g)}},bt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...y)=>t.sessionOutput(...y),s=(...y)=>t.sessionCost(...y),r=(...y)=>t.sessionCompleted(...y),i=(...y)=>t.containerStatus(...y),a=(...y)=>t.slaveCapacityUpdate(...y),c=(...y)=>t.previewBuildStatus(...y),l=(...y)=>t.previewReload(...y),g=(...y)=>t.questionsReceived(...y),u=(...y)=>t.specificationUpdated(...y),p=(...y)=>t.singleQuestionReceived(...y),f=(...y)=>t.questionSessionEnded(...y),k=(...y)=>t.creditsUpdated(...y),E=(...y)=>t.insufficientCredits(...y),x=(...y)=>t.projectSessionStatusChanged(...y),w=(...y)=>t.claudeLoginUrlReceived(...y),m=(...y)=>t.claudeLoginCompleted(...y);e.on("SessionOutput",o),e.on("SessionCost",s),e.on("SessionCompleted",r),e.on("ContainerStatus",i),e.on("SlaveCapacityUpdate",a),e.on("PreviewBuildStatus",c),e.on("PreviewReload",l),e.on("QuestionsReceived",g),e.on("SpecificationUpdated",u),e.on("SingleQuestionReceived",p),e.on("QuestionSessionEnded",f),e.on("CreditsUpdated",k),e.on("InsufficientCredits",E),e.on("ProjectSessionStatusChanged",x),e.on("ClaudeLoginUrlReceived",w),e.on("ClaudeLoginCompleted",m);let j=[{methodName:"SessionOutput",method:o},{methodName:"SessionCost",method:s},{methodName:"SessionCompleted",method:r},{methodName:"ContainerStatus",method:i},{methodName:"SlaveCapacityUpdate",method:a},{methodName:"PreviewBuildStatus",method:c},{methodName:"PreviewReload",method:l},{methodName:"QuestionsReceived",method:g},{methodName:"SpecificationUpdated",method:u},{methodName:"SingleQuestionReceived",method:p},{methodName:"QuestionSessionEnded",method:f},{methodName:"CreditsUpdated",method:k},{methodName:"InsufficientCredits",method:E},{methodName:"ProjectSessionStatusChanged",method:x},{methodName:"ClaudeLoginUrlReceived",method:w},{methodName:"ClaudeLoginCompleted",method:m}];return new K(e,j)}},St=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...w)=>t.startContainer(...w),s=(...w)=>t.terminateContainer(...w),r=()=>t.reconnect(),i=(...w)=>t.getContainerLogs(...w),a=()=>t.getDockerContainers(),c=(...w)=>t.streamContainerLogs(...w),l=(...w)=>t.stopContainerLogStream(...w),g=(...w)=>t.restartLabAgent(...w),u=(...w)=>t.terminateDockerContainer(...w),p=(...w)=>t.streamSlaveAgentLogs(...w),f=()=>t.stopSlaveAgentLogStream(),k=(...w)=>t.startClaudeLogin(...w),E=(...w)=>t.submitClaudeLoginCode(...w);e.on("StartContainer",o),e.on("TerminateContainer",s),e.on("Reconnect",r),e.on("GetContainerLogs",i),e.on("GetDockerContainers",a),e.on("StreamContainerLogs",c),e.on("StopContainerLogStream",l),e.on("RestartLabAgent",g),e.on("TerminateDockerContainer",u),e.on("StreamSlaveAgentLogs",p),e.on("StopSlaveAgentLogStream",f),e.on("StartClaudeLogin",k),e.on("SubmitClaudeLoginCode",E);let x=[{methodName:"StartContainer",method:o},{methodName:"TerminateContainer",method:s},{methodName:"Reconnect",method:r},{methodName:"GetContainerLogs",method:i},{methodName:"GetDockerContainers",method:a},{methodName:"StreamContainerLogs",method:c},{methodName:"StopContainerLogStream",method:l},{methodName:"RestartLabAgent",method:g},{methodName:"TerminateDockerContainer",method:u},{methodName:"StreamSlaveAgentLogs",method:p},{methodName:"StopSlaveAgentLogStream",method:f},{methodName:"StartClaudeLogin",method:k},{methodName:"SubmitClaudeLoginCode",method:E}];return new K(e,x)}},wt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...p)=>t.dockerContainersUpdated(...p),s=(...p)=>t.containerLogReceived(...p),r=(...p)=>t.agentRestartCompleted(...p),i=(...p)=>t.containerTerminationCompleted(...p),a=(...p)=>t.slaveCapacityUpdated(...p),c=(...p)=>t.slaveAgentLogReceived(...p),l=(...p)=>t.claudeLoginUrlReceived(...p),g=(...p)=>t.claudeLoginCompleted(...p);e.on("DockerContainersUpdated",o),e.on("ContainerLogReceived",s),e.on("AgentRestartCompleted",r),e.on("ContainerTerminationCompleted",i),e.on("SlaveCapacityUpdated",a),e.on("SlaveAgentLogReceived",c),e.on("ClaudeLoginUrlReceived",l),e.on("ClaudeLoginCompleted",g);let u=[{methodName:"DockerContainersUpdated",method:o},{methodName:"ContainerLogReceived",method:s},{methodName:"AgentRestartCompleted",method:r},{methodName:"ContainerTerminationCompleted",method:i},{methodName:"SlaveCapacityUpdated",method:a},{methodName:"SlaveAgentLogReceived",method:c},{methodName:"ClaudeLoginUrlReceived",method:l},{methodName:"ClaudeLoginCompleted",method:g}];return new K(e,u)}},vt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...l)=>t.testRunCreated(...l),s=(...l)=>t.testRunUpdated(...l),r=(...l)=>t.testSuiteCreated(...l),i=(...l)=>t.testCreated(...l),a=(...l)=>t.testUpdated(...l);e.on("TestRunCreated",o),e.on("TestRunUpdated",s),e.on("TestSuiteCreated",r),e.on("TestCreated",i),e.on("TestUpdated",a);let c=[{methodName:"TestRunCreated",method:o},{methodName:"TestRunUpdated",method:s},{methodName:"TestSuiteCreated",method:r},{methodName:"TestCreated",method:i},{methodName:"TestUpdated",method:a}];return new K(e,c)}};var Hn=$n(Fn),Fe=class{constructor(e){this.config=e;let t={"X-Container-Id":e.containerId,"X-Project-Key":e.projectKey};e.isByok&&(t["X-Is-Byok"]="true"),this.connection=new oe.HubConnectionBuilder().withUrl(`${e.masterUrl}/api/hubs/agent`,{headers:t}).withAutomaticReconnect({nextRetryDelayInMilliseconds:o=>{let s=o.previousRetryCount+1,r=Math.min(1e3*Math.pow(2,o.previousRetryCount),6e4);return console.log(`[SignalR] Reconnect attempt ${s} (will retry in ${r}ms)`),r}}).withServerTimeout(3e5).withKeepAliveInterval(1e4).configureLogging(oe.LogLevel.Information).build(),this.hubProxy=qt("IAgentHub").createHubProxy(this.connection),this.connection.onreconnecting(o=>{console.warn("[SignalR] Connection lost, attempting to reconnect...",o?.message)}),this.connection.onreconnected(async o=>{console.log("[SignalR] Reconnected to gateway (connectionId:",o,")");try{await this.hubProxy.registerAgent(this.config.containerId),console.log(`[SignalR] Re-registered as agent for container: ${this.config.containerId}`),await this.reportStatus(this.currentStatus,void 0,this.currentSessionId??void 0,this.currentProjectId??void 0)}catch(s){console.error("[SignalR] Failed to re-register agent after reconnect:",s instanceof Error?s.message:s)}}),this.connection.onclose(o=>{console.error("[SignalR] Connection closed:",o?.message),console.error("[SignalR] Connection state at close:",this.connection.state),process.exit(1)})}connection;hubProxy;receiverSubscription=null;currentStatus="WarmingUp";currentSessionId=null;currentProjectId=null;tunnelUrl=null;tokenRefreshInterval=null;currentRepoFullName=null;heartbeatInterval=null;async connect(){console.log(`[SignalR] Connecting to gateway: ${this.config.masterUrl}/api/hubs/agent`),this.config.isByok&&console.log("[SignalR] BYOK mode enabled - credits will not be deducted"),await this.connection.start();let e=this.connection.connection?.transport;console.log("[SignalR] Connected to gateway!"),console.log(`[SignalR] Transport: ${e?.constructor?.name||"unknown"}`),console.log(`[SignalR] Connection ID: ${this.connection.connectionId}`),await this.hubProxy.registerAgent(this.config.containerId),console.log(`[SignalR] Registered as agent for container: ${this.config.containerId}`)}registerReceiver(e){this.receiverSubscription&&this.receiverSubscription.dispose(),this.receiverSubscription=Yt("IAgentReceiver").register(this.connection,e)}getHubProxy(){return this.hubProxy}getMasterUrl(){return this.config.masterUrl}getProjectKey(){return this.config.projectKey}getConnection(){return this.connection}setTunnelUrl(e){this.tunnelUrl=e}async reportStatus(e,t,o,s){if(this.currentStatus=e,o&&(this.currentSessionId=o),s&&(this.currentProjectId=s),this.connection.state===oe.HubConnectionState.Connected)try{let r={status:e,error:t,sessionId:o,projectId:s,tunnelUrl:this.tunnelUrl??void 0};await this.hubProxy.reportStatus(this.config.containerId,r),console.log(`[Status] ${e}${t?` (${t})`:""}${this.tunnelUrl?` [${this.tunnelUrl}]`:""}${o?` [session: ${o}]`:""}`)}catch(r){console.error("[SignalR] Failed to report status:",r)}}async getSecrets(){let e=await this.hubProxy.getSecrets();if(!e.success)throw new Error(`Failed to get secrets: ${e.error}`);return e.secrets||{}}startHeartbeat(e=3e4){this.heartbeatInterval||(this.heartbeatInterval=setInterval(async()=>{if(this.connection.state===oe.HubConnectionState.Connected)try{await this.hubProxy.reportStatus(this.config.containerId,{status:this.currentStatus,sessionId:this.currentSessionId??void 0,projectId:this.currentProjectId??void 0,tunnelUrl:this.tunnelUrl??void 0})}catch(t){console.error("[Heartbeat] Failed:",t instanceof Error?t.message:t)}},e),console.log(`[Heartbeat] Started (every ${e/1e3}s)`))}stopHeartbeat(){this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null,console.log("[Heartbeat] Stopped"))}async startTokenRefresh(){await this.refreshGitHubToken(),this.tokenRefreshInterval=setInterval(async()=>{await this.refreshGitHubToken()},3e6),console.log("[TokenRefresh] Started (refreshing every 50 minutes)")}stopTokenRefresh(){this.tokenRefreshInterval&&(clearInterval(this.tokenRefreshInterval),this.tokenRefreshInterval=null,console.log("[TokenRefresh] Stopped"))}async refreshGitHubToken(){console.log(`[TokenRefresh] Requesting new token from backend... (${new Date().toISOString()})`);try{let e=await this.hubProxy.refreshGitHubToken();if(!e.success){console.error(`[TokenRefresh] \u274C Backend returned failure: ${e.error}`);return}if(!e.token){console.error("[TokenRefresh] \u274C No token in response (success=true but token is empty)");return}let t=e.token.substring(0,8)+"...";if(console.log(`[TokenRefresh] Got token (prefix: ${t}), updating git credentials...`),await this.updateGitCredentials(e.token,e.repoFullName??void 0),e.expiresAt){let o=new Date(e.expiresAt).toISOString(),s=Math.round((new Date(e.expiresAt).getTime()-Date.now())/6e4);console.log(`[TokenRefresh] \u2713 Refreshed (prefix: ${t}, expires: ${o}, ~${s}min left)${e.repoFullName?` (repo: ${e.repoFullName})`:""}`)}else console.log("[TokenRefresh] \u2713 Refreshed (PAT mode, no expiry)");this.currentRepoFullName=e.repoFullName??null}catch(e){console.error("[TokenRefresh] \u274C Exception:",e instanceof Error?e.message:e)}}async reportError(e){if(this.connection.state!==oe.HubConnectionState.Connected){console.error("[SignalR] Cannot report error - not connected");return}try{let t={message:e.message,stackTrace:e.stackTrace,errorType:e.errorType,operation:e.operation,sessionId:e.sessionId??this.currentSessionId??void 0,isFatal:e.isFatal??!1},o=await this.hubProxy.reportError(this.config.containerId,t);o.success?console.log(`[Error Report] Reported: ${e.errorType??"Error"} - ${e.message}`):console.error(`[Error Report] Failed to report: ${o.error}`)}catch(t){console.error("[SignalR] Failed to report error:",t instanceof Error?t.message:t)}}async updateGitCredentials(e,t){let o=Qt.join(Jt.homedir(),".git-credentials"),s=`https://x-access-token:${e}@github.com
1359
+ `).filter(Boolean)}catch(P){return[`Error reading logs: ${P instanceof Error?P.message:String(P)}`]}};return{startBackend:d,startFrontend:C,stopBackend:U,stopFrontend:$,restartServices:un,checkHealth:pe,waitForHealth:Pt,getProcesses:()=>({backend:m,frontend:j}),checkBackendBuild:Rt,checkFrontendTypes:Tt,runTypeChecks:gn,tailLogs:It,checkSwaggerEndpoints:async S=>{let h=ne.join(e,"swagger.json");if(!I.existsSync(h))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let v=JSON.parse(I.readFileSync(h,"utf-8")),P=Object.keys(v.paths||{}),N=[];for(let D of P)if(D.toLowerCase().includes(S.toLowerCase())){let R=Object.keys(v.paths[D]);for(let Z of R)N.push(`${Z.toUpperCase()} ${D}`)}return{foundEndpoints:N,totalEndpoints:P.length}}catch(v){return{foundEndpoints:[`Error parsing swagger.json: ${v instanceof Error?v.message:String(v)}`],totalEndpoints:0}}}}}function Mn(n){let e=n.toLowerCase();return e.includes("exception")||e.includes("fail:")||e.includes("[err]")||e.includes("[error]")}import{execSync as ie}from"child_process";function Me(n){let e=async()=>{try{return ie("git status --porcelain",{cwd:n,encoding:"utf-8"}).trim().length>0}catch{return!1}},t=async()=>{try{return ie("git branch --show-current",{cwd:n,encoding:"utf-8"}).trim()}catch{return"unknown"}};return{hasChanges:e,commitAndPush:async(s,r)=>{try{if(!await e())return{success:!0,noChanges:!0};let i=s.length>60?s.substring(0,60)+"...":s,c=`${r?"[agent] (partial)":"[agent]"} ${i}`;ie("git add -A",{cwd:n}),ie(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:n,encoding:"utf-8"});let l=ie("git rev-parse --short HEAD",{cwd:n,encoding:"utf-8"}).trim();try{ie("git push",{cwd:n,stdio:"pipe"})}catch(g){let u=g instanceof Error?g.message:String(g);if(u.includes("no upstream branch")){let p=await t();ie(`git push --set-upstream origin ${p}`,{cwd:n,stdio:"pipe"})}else return console.error("[Git] Push failed:",u),{success:!1,commitHash:l,commitSucceeded:!0,pushFailed:!0,error:u}}return{success:!0,commitHash:l}}catch(i){let a=i instanceof Error?i.message:String(i);return console.error("[Git] Error:",a),{success:!1,error:a}}},getCurrentBranch:t}}import*as oe from"@microsoft/signalr";import*as zt from"fs";import*as Jt from"os";import*as Qt from"path";import{exec as Fn}from"child_process";import{promisify as $n}from"util";var K=class{constructor(e,t){this.connection=e;this.receiverMethod=t}dispose=()=>{for(let e of this.receiverMethod)this.connection.off(e.methodName,e.method)}},qt=n=>{if(n==="IDeploymentWatcherHub")return et.Instance;if(n==="IDeploymentHub")return nt.Instance;if(n==="IKanbanHub")return st.Instance;if(n==="IAgentHub")return it.Instance;if(n==="ISlaveHub")return ct.Instance;if(n==="ISlaveWatcherHub")return pt.Instance;if(n==="ITestHub")return ut.Instance},Yt=n=>{if(n==="IDeploymentWatcherClient")return mt.Instance;if(n==="IDeploymentHubClient")return ht.Instance;if(n==="IKanbanBoardClient")return ft.Instance;if(n==="IAgentReceiver")return yt.Instance;if(n==="IBackofficeReceiver")return bt.Instance;if(n==="ISlaveHubClient")return St.Instance;if(n==="ISlaveWatcherClient")return wt.Instance;if(n==="ITestHubClient")return vt.Instance},et=class n{static Instance=new n;constructor(){}createHubProxy=e=>new tt(e)},tt=class{constructor(e){this.connection=e}watchMachine=async e=>await this.connection.invoke("WatchMachine",e);unwatchMachine=async e=>await this.connection.invoke("UnwatchMachine",e);startStreamingLogs=async e=>await this.connection.invoke("StartStreamingLogs",e);stopStreamingLogs=async e=>await this.connection.invoke("StopStreamingLogs",e)},nt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new ot(e)},ot=class{constructor(e){this.connection=e}registerMachine=async(e,t)=>await this.connection.invoke("RegisterMachine",e,t);getSecrets=async()=>await this.connection.invoke("GetSecrets");reportDeploymentStatus=async e=>await this.connection.invoke("ReportDeploymentStatus",e);reportHealth=async e=>await this.connection.invoke("ReportHealth",e);reportMachineStatus=async e=>await this.connection.invoke("ReportMachineStatus",e);sendDeploymentLog=async e=>await this.connection.invoke("SendDeploymentLog",e)},st=class n{static Instance=new n;constructor(){}createHubProxy=e=>new rt(e)},rt=class{constructor(e){this.connection=e}joinBoard=async e=>await this.connection.invoke("JoinBoard",e);leaveBoard=async e=>await this.connection.invoke("LeaveBoard",e)},it=class n{static Instance=new n;constructor(){}createHubProxy=e=>new at(e)},at=class{constructor(e){this.connection=e}registerAgent=async e=>await this.connection.invoke("RegisterAgent",e);getSecrets=async()=>await this.connection.invoke("GetSecrets");reportStatus=async(e,t)=>await this.connection.invoke("ReportStatus",e,t);reportSessionOutput=async(e,t,o)=>await this.connection.invoke("ReportSessionOutput",e,t,o);reportSessionCost=async(e,t,o)=>await this.connection.invoke("ReportSessionCost",e,t,o);reportInsight=async(e,t)=>await this.connection.invoke("ReportInsight",e,t);setClaudeSessionId=async(e,t)=>await this.connection.invoke("SetClaudeSessionId",e,t);sessionCompleted=async(e,t,o)=>await this.connection.invoke("SessionCompleted",e,t,o);initSessionCompleted=async(e,t,o,s)=>await this.connection.invoke("InitSessionCompleted",e,t,o,s);reportPreviewBuild=async(e,t,o)=>await this.connection.invoke("ReportPreviewBuild",e,t,o);saveSpecification=async(e,t,o,s)=>await this.connection.invoke("SaveSpecification",e,t,o,s);getSpecification=async(e,t)=>await this.connection.invoke("GetSpecification",e,t);listSpecifications=async e=>await this.connection.invoke("ListSpecifications",e);deleteSpecification=async(e,t)=>await this.connection.invoke("DeleteSpecification",e,t);watchContainer=async e=>await this.connection.invoke("WatchContainer",e);watchSession=async e=>await this.connection.invoke("WatchSession",e);watchProject=async e=>await this.connection.invoke("WatchProject",e);unwatchProject=async e=>await this.connection.invoke("UnwatchProject",e);watchSlaves=async()=>await this.connection.invoke("WatchSlaves");unwatchSlaves=async()=>await this.connection.invoke("UnwatchSlaves");sendPrompt=async(e,t,o,s,r)=>await this.connection.invoke("SendPrompt",e,t,o,s,r);stopSession=async e=>await this.connection.invoke("StopSession",e);switchSession=async(e,t)=>await this.connection.invoke("SwitchSession",e,t);createSession=async e=>await this.connection.invoke("CreateSession",e);refreshGitHubToken=async()=>await this.connection.invoke("RefreshGitHubToken");reportError=async(e,t)=>await this.connection.invoke("ReportError",e,t);startClaudeLogin=async e=>await this.connection.invoke("StartClaudeLogin",e);submitClaudeLoginCode=async(e,t)=>await this.connection.invoke("SubmitClaudeLoginCode",e,t)},ct=class n{static Instance=new n;constructor(){}createHubProxy=e=>new lt(e)},lt=class{constructor(e){this.connection=e}register=async(e,t)=>await this.connection.invoke("Register",e,t);getSecrets=async()=>await this.connection.invoke("GetSecrets");containerCreated=async e=>await this.connection.invoke("ContainerCreated",e);containerReady=async e=>await this.connection.invoke("ContainerReady",e);reportCapacity=async e=>await this.connection.invoke("ReportCapacity",e);reportError=async e=>await this.connection.invoke("ReportError",e);reportDockerContainers=async e=>await this.connection.invoke("ReportDockerContainers",e);reportContainerLog=async e=>await this.connection.invoke("ReportContainerLog",e);reportAgentRestarted=async(e,t,o)=>await this.connection.invoke("ReportAgentRestarted",e,t,o);reportContainerTerminated=async(e,t,o)=>await this.connection.invoke("ReportContainerTerminated",e,t,o);reportSlaveAgentLog=async e=>await this.connection.invoke("ReportSlaveAgentLog",e);reportClaudeLoginUrl=async e=>await this.connection.invoke("ReportClaudeLoginUrl",e);reportClaudeLoginResult=async e=>await this.connection.invoke("ReportClaudeLoginResult",e)},pt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new dt(e)},dt=class{constructor(e){this.connection=e}watchSlave=async e=>await this.connection.invoke("WatchSlave",e);unwatchSlave=async e=>await this.connection.invoke("UnwatchSlave",e);requestDockerContainers=async e=>await this.connection.invoke("RequestDockerContainers",e);startStreamingContainerLogs=async(e,t,o)=>await this.connection.invoke("StartStreamingContainerLogs",e,t,o);stopStreamingContainerLogs=async(e,t)=>await this.connection.invoke("StopStreamingContainerLogs",e,t);restartLabAgent=async(e,t)=>await this.connection.invoke("RestartLabAgent",e,t);terminateContainer=async(e,t)=>await this.connection.invoke("TerminateContainer",e,t);startStreamingSlaveAgentLogs=async(e,t)=>await this.connection.invoke("StartStreamingSlaveAgentLogs",e,t);stopStreamingSlaveAgentLogs=async e=>await this.connection.invoke("StopStreamingSlaveAgentLogs",e);startClaudeLogin=async(e,t)=>await this.connection.invoke("StartClaudeLogin",e,t);submitClaudeLoginCode=async(e,t,o)=>await this.connection.invoke("SubmitClaudeLoginCode",e,t,o)},ut=class n{static Instance=new n;constructor(){}createHubProxy=e=>new gt(e)},gt=class{constructor(e){this.connection=e}joinProject=async e=>await this.connection.invoke("JoinProject",e);leaveProject=async e=>await this.connection.invoke("LeaveProject",e)},mt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...a)=>t.deploymentStatusUpdated(...a),s=(...a)=>t.deploymentLogReceived(...a),r=(...a)=>t.machineStatusUpdated(...a);e.on("DeploymentStatusUpdated",o),e.on("DeploymentLogReceived",s),e.on("MachineStatusUpdated",r);let i=[{methodName:"DeploymentStatusUpdated",method:o},{methodName:"DeploymentLogReceived",method:s},{methodName:"MachineStatusUpdated",method:r}];return new K(e,i)}},ht=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...c)=>t.deploy(...c),s=(...c)=>t.stop(...c),r=(...c)=>t.startLogStreaming(...c),i=(...c)=>t.stopLogStreaming(...c);e.on("Deploy",o),e.on("Stop",s),e.on("StartLogStreaming",r),e.on("StopLogStreaming",i);let a=[{methodName:"Deploy",method:o},{methodName:"Stop",method:s},{methodName:"StartLogStreaming",method:r},{methodName:"StopLogStreaming",method:i}];return new K(e,a)}},ft=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...m)=>t.boardUpdated(...m),s=(...m)=>t.boardDeleted(...m),r=(...m)=>t.columnCreated(...m),i=(...m)=>t.columnUpdated(...m),a=(...m)=>t.columnDeleted(...m),c=(...m)=>t.cardCreated(...m),l=(...m)=>t.cardUpdated(...m),g=(...m)=>t.cardDeleted(...m),u=(...m)=>t.subtaskCreated(...m),p=(...m)=>t.subtaskUpdated(...m),f=(...m)=>t.subtaskDeleted(...m),k=(...m)=>t.noteCreated(...m),E=(...m)=>t.noteUpdated(...m),x=(...m)=>t.noteDeleted(...m);e.on("BoardUpdated",o),e.on("BoardDeleted",s),e.on("ColumnCreated",r),e.on("ColumnUpdated",i),e.on("ColumnDeleted",a),e.on("CardCreated",c),e.on("CardUpdated",l),e.on("CardDeleted",g),e.on("SubtaskCreated",u),e.on("SubtaskUpdated",p),e.on("SubtaskDeleted",f),e.on("NoteCreated",k),e.on("NoteUpdated",E),e.on("NoteDeleted",x);let w=[{methodName:"BoardUpdated",method:o},{methodName:"BoardDeleted",method:s},{methodName:"ColumnCreated",method:r},{methodName:"ColumnUpdated",method:i},{methodName:"ColumnDeleted",method:a},{methodName:"CardCreated",method:c},{methodName:"CardUpdated",method:l},{methodName:"CardDeleted",method:g},{methodName:"SubtaskCreated",method:u},{methodName:"SubtaskUpdated",method:p},{methodName:"SubtaskDeleted",method:f},{methodName:"NoteCreated",method:k},{methodName:"NoteUpdated",method:E},{methodName:"NoteDeleted",method:x}];return new K(e,w)}},yt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...u)=>t.initSession(...u),s=(...u)=>t.runPrompt(...u),r=(...u)=>t.setModel(...u),i=()=>t.stopAgent(),a=()=>t.ping(),c=(...u)=>t.switchSession(...u),l=(...u)=>t.projectPromptUpdated(...u);e.on("InitSession",o),e.on("RunPrompt",s),e.on("SetModel",r),e.on("StopAgent",i),e.on("Ping",a),e.on("SwitchSession",c),e.on("ProjectPromptUpdated",l);let g=[{methodName:"InitSession",method:o},{methodName:"RunPrompt",method:s},{methodName:"SetModel",method:r},{methodName:"StopAgent",method:i},{methodName:"Ping",method:a},{methodName:"SwitchSession",method:c},{methodName:"ProjectPromptUpdated",method:l}];return new K(e,g)}},bt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...y)=>t.sessionOutput(...y),s=(...y)=>t.sessionCost(...y),r=(...y)=>t.sessionCompleted(...y),i=(...y)=>t.containerStatus(...y),a=(...y)=>t.slaveCapacityUpdate(...y),c=(...y)=>t.previewBuildStatus(...y),l=(...y)=>t.previewReload(...y),g=(...y)=>t.questionsReceived(...y),u=(...y)=>t.specificationUpdated(...y),p=(...y)=>t.singleQuestionReceived(...y),f=(...y)=>t.questionSessionEnded(...y),k=(...y)=>t.creditsUpdated(...y),E=(...y)=>t.insufficientCredits(...y),x=(...y)=>t.projectSessionStatusChanged(...y),w=(...y)=>t.claudeLoginUrlReceived(...y),m=(...y)=>t.claudeLoginCompleted(...y);e.on("SessionOutput",o),e.on("SessionCost",s),e.on("SessionCompleted",r),e.on("ContainerStatus",i),e.on("SlaveCapacityUpdate",a),e.on("PreviewBuildStatus",c),e.on("PreviewReload",l),e.on("QuestionsReceived",g),e.on("SpecificationUpdated",u),e.on("SingleQuestionReceived",p),e.on("QuestionSessionEnded",f),e.on("CreditsUpdated",k),e.on("InsufficientCredits",E),e.on("ProjectSessionStatusChanged",x),e.on("ClaudeLoginUrlReceived",w),e.on("ClaudeLoginCompleted",m);let j=[{methodName:"SessionOutput",method:o},{methodName:"SessionCost",method:s},{methodName:"SessionCompleted",method:r},{methodName:"ContainerStatus",method:i},{methodName:"SlaveCapacityUpdate",method:a},{methodName:"PreviewBuildStatus",method:c},{methodName:"PreviewReload",method:l},{methodName:"QuestionsReceived",method:g},{methodName:"SpecificationUpdated",method:u},{methodName:"SingleQuestionReceived",method:p},{methodName:"QuestionSessionEnded",method:f},{methodName:"CreditsUpdated",method:k},{methodName:"InsufficientCredits",method:E},{methodName:"ProjectSessionStatusChanged",method:x},{methodName:"ClaudeLoginUrlReceived",method:w},{methodName:"ClaudeLoginCompleted",method:m}];return new K(e,j)}},St=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...w)=>t.startContainer(...w),s=(...w)=>t.terminateContainer(...w),r=()=>t.reconnect(),i=(...w)=>t.getContainerLogs(...w),a=()=>t.getDockerContainers(),c=(...w)=>t.streamContainerLogs(...w),l=(...w)=>t.stopContainerLogStream(...w),g=(...w)=>t.restartLabAgent(...w),u=(...w)=>t.terminateDockerContainer(...w),p=(...w)=>t.streamSlaveAgentLogs(...w),f=()=>t.stopSlaveAgentLogStream(),k=(...w)=>t.startClaudeLogin(...w),E=(...w)=>t.submitClaudeLoginCode(...w);e.on("StartContainer",o),e.on("TerminateContainer",s),e.on("Reconnect",r),e.on("GetContainerLogs",i),e.on("GetDockerContainers",a),e.on("StreamContainerLogs",c),e.on("StopContainerLogStream",l),e.on("RestartLabAgent",g),e.on("TerminateDockerContainer",u),e.on("StreamSlaveAgentLogs",p),e.on("StopSlaveAgentLogStream",f),e.on("StartClaudeLogin",k),e.on("SubmitClaudeLoginCode",E);let x=[{methodName:"StartContainer",method:o},{methodName:"TerminateContainer",method:s},{methodName:"Reconnect",method:r},{methodName:"GetContainerLogs",method:i},{methodName:"GetDockerContainers",method:a},{methodName:"StreamContainerLogs",method:c},{methodName:"StopContainerLogStream",method:l},{methodName:"RestartLabAgent",method:g},{methodName:"TerminateDockerContainer",method:u},{methodName:"StreamSlaveAgentLogs",method:p},{methodName:"StopSlaveAgentLogStream",method:f},{methodName:"StartClaudeLogin",method:k},{methodName:"SubmitClaudeLoginCode",method:E}];return new K(e,x)}},wt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...p)=>t.dockerContainersUpdated(...p),s=(...p)=>t.containerLogReceived(...p),r=(...p)=>t.agentRestartCompleted(...p),i=(...p)=>t.containerTerminationCompleted(...p),a=(...p)=>t.slaveCapacityUpdated(...p),c=(...p)=>t.slaveAgentLogReceived(...p),l=(...p)=>t.claudeLoginUrlReceived(...p),g=(...p)=>t.claudeLoginCompleted(...p);e.on("DockerContainersUpdated",o),e.on("ContainerLogReceived",s),e.on("AgentRestartCompleted",r),e.on("ContainerTerminationCompleted",i),e.on("SlaveCapacityUpdated",a),e.on("SlaveAgentLogReceived",c),e.on("ClaudeLoginUrlReceived",l),e.on("ClaudeLoginCompleted",g);let u=[{methodName:"DockerContainersUpdated",method:o},{methodName:"ContainerLogReceived",method:s},{methodName:"AgentRestartCompleted",method:r},{methodName:"ContainerTerminationCompleted",method:i},{methodName:"SlaveCapacityUpdated",method:a},{methodName:"SlaveAgentLogReceived",method:c},{methodName:"ClaudeLoginUrlReceived",method:l},{methodName:"ClaudeLoginCompleted",method:g}];return new K(e,u)}},vt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...l)=>t.testRunCreated(...l),s=(...l)=>t.testRunUpdated(...l),r=(...l)=>t.testSuiteCreated(...l),i=(...l)=>t.testCreated(...l),a=(...l)=>t.testUpdated(...l);e.on("TestRunCreated",o),e.on("TestRunUpdated",s),e.on("TestSuiteCreated",r),e.on("TestCreated",i),e.on("TestUpdated",a);let c=[{methodName:"TestRunCreated",method:o},{methodName:"TestRunUpdated",method:s},{methodName:"TestSuiteCreated",method:r},{methodName:"TestCreated",method:i},{methodName:"TestUpdated",method:a}];return new K(e,c)}};var Hn=$n(Fn),Fe=class{constructor(e){this.config=e;let t={"X-Container-Id":e.containerId,"X-Project-Key":e.projectKey};e.isByok&&(t["X-Is-Byok"]="true"),this.connection=new oe.HubConnectionBuilder().withUrl(`${e.masterUrl}/api/hubs/agent`,{headers:t}).withAutomaticReconnect({nextRetryDelayInMilliseconds:o=>{let s=o.previousRetryCount+1,r=Math.min(1e3*Math.pow(2,o.previousRetryCount),6e4);return console.log(`[SignalR] Reconnect attempt ${s} (will retry in ${r}ms)`),r}}).withServerTimeout(3e5).withKeepAliveInterval(1e4).configureLogging(oe.LogLevel.Information).build(),this.hubProxy=qt("IAgentHub").createHubProxy(this.connection),this.connection.onreconnecting(o=>{console.warn("[SignalR] Connection lost, attempting to reconnect...",o?.message)}),this.connection.onreconnected(async o=>{console.log("[SignalR] Reconnected to gateway (connectionId:",o,")");try{await this.hubProxy.registerAgent(this.config.containerId),console.log(`[SignalR] Re-registered as agent for container: ${this.config.containerId}`),await this.reportStatus(this.currentStatus,void 0,this.currentSessionId??void 0,this.currentProjectId??void 0)}catch(s){console.error("[SignalR] Failed to re-register agent after reconnect:",s instanceof Error?s.message:s)}}),this.connection.onclose(o=>{console.error("[SignalR] Connection closed:",o?.message),console.error("[SignalR] Connection state at close:",this.connection.state),process.exit(1)})}connection;hubProxy;receiverSubscription=null;currentStatus="WarmingUp";currentSessionId=null;currentProjectId=null;tunnelUrl=null;tokenRefreshInterval=null;currentRepoFullName=null;heartbeatInterval=null;async connect(){console.log(`[SignalR] Connecting to gateway: ${this.config.masterUrl}/api/hubs/agent`),this.config.isByok&&console.log("[SignalR] BYOK mode enabled - credits will not be deducted"),await this.connection.start();let e=this.connection.connection?.transport;console.log("[SignalR] Connected to gateway!"),console.log(`[SignalR] Transport: ${e?.constructor?.name||"unknown"}`),console.log(`[SignalR] Connection ID: ${this.connection.connectionId}`),await this.hubProxy.registerAgent(this.config.containerId),console.log(`[SignalR] Registered as agent for container: ${this.config.containerId}`)}registerReceiver(e){this.receiverSubscription&&this.receiverSubscription.dispose(),this.receiverSubscription=Yt("IAgentReceiver").register(this.connection,e)}getHubProxy(){return this.hubProxy}getMasterUrl(){return this.config.masterUrl}getProjectKey(){return this.config.projectKey}getConnection(){return this.connection}setTunnelUrl(e){this.tunnelUrl=e}async reportStatus(e,t,o,s){if(this.currentStatus=e,o&&(this.currentSessionId=o),s&&(this.currentProjectId=s),this.connection.state===oe.HubConnectionState.Connected)try{let r={status:e,error:t,sessionId:o,projectId:s,tunnelUrl:this.tunnelUrl??void 0};await this.hubProxy.reportStatus(this.config.containerId,r),console.log(`[Status] ${e}${t?` (${t})`:""}${this.tunnelUrl?` [${this.tunnelUrl}]`:""}${o?` [session: ${o}]`:""}`)}catch(r){console.error("[SignalR] Failed to report status:",r)}}async getSecrets(){let e=await this.hubProxy.getSecrets();if(!e.success)throw new Error(`Failed to get secrets: ${e.error}`);return e.secrets||{}}startHeartbeat(e=3e4){this.heartbeatInterval||(this.heartbeatInterval=setInterval(async()=>{if(this.connection.state===oe.HubConnectionState.Connected)try{await this.hubProxy.reportStatus(this.config.containerId,{status:this.currentStatus,sessionId:this.currentSessionId??void 0,projectId:this.currentProjectId??void 0,tunnelUrl:this.tunnelUrl??void 0})}catch(t){console.error("[Heartbeat] Failed:",t instanceof Error?t.message:t)}},e),console.log(`[Heartbeat] Started (every ${e/1e3}s)`))}stopHeartbeat(){this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null,console.log("[Heartbeat] Stopped"))}async startTokenRefresh(){await this.refreshGitHubToken(),this.tokenRefreshInterval=setInterval(async()=>{await this.refreshGitHubToken()},3e6),console.log("[TokenRefresh] Started (refreshing every 50 minutes)")}stopTokenRefresh(){this.tokenRefreshInterval&&(clearInterval(this.tokenRefreshInterval),this.tokenRefreshInterval=null,console.log("[TokenRefresh] Stopped"))}async refreshGitHubToken(){console.log(`[TokenRefresh] Requesting new token from backend... (${new Date().toISOString()})`);try{let e=await this.hubProxy.refreshGitHubToken();if(!e.success){console.error(`[TokenRefresh] \u274C Backend returned failure: ${e.error}`);return}if(!e.token){console.error("[TokenRefresh] \u274C No token in response (success=true but token is empty)");return}let t=e.token.substring(0,8)+"...";if(console.log(`[TokenRefresh] Got token (prefix: ${t}), updating git credentials...`),await this.updateGitCredentials(e.token,e.repoFullName??void 0),e.expiresAt){let o=new Date(e.expiresAt).toISOString(),s=Math.round((new Date(e.expiresAt).getTime()-Date.now())/6e4);console.log(`[TokenRefresh] \u2713 Refreshed (prefix: ${t}, expires: ${o}, ~${s}min left)${e.repoFullName?` (repo: ${e.repoFullName})`:""}`)}else console.log("[TokenRefresh] \u2713 Refreshed (PAT mode, no expiry)");this.currentRepoFullName=e.repoFullName??null}catch(e){console.error("[TokenRefresh] \u274C Exception:",e instanceof Error?e.message:e)}}async reportError(e){if(this.connection.state!==oe.HubConnectionState.Connected){console.error("[SignalR] Cannot report error - not connected");return}try{let t={message:e.message,stackTrace:e.stackTrace,errorType:e.errorType,operation:e.operation,sessionId:e.sessionId??this.currentSessionId??void 0,isFatal:e.isFatal??!1},o=await this.hubProxy.reportError(this.config.containerId,t);o.success?console.log(`[Error Report] Reported: ${e.errorType??"Error"} - ${e.message}`):console.error(`[Error Report] Failed to report: ${o.error}`)}catch(t){console.error("[SignalR] Failed to report error:",t instanceof Error?t.message:t)}}async updateGitCredentials(e,t){let o=Qt.join(Jt.homedir(),".git-credentials"),s=`https://x-access-token:${e}@github.com
1360
1360
  `;if(await zt.promises.writeFile(o,s,{mode:384}),t)try{let r=`https://x-access-token:${e}@github.com/${t}.git`;await Hn(`git remote set-url origin "${r}"`,{cwd:"/workspace"})}catch(r){console.error("[TokenRefresh] Could not update remote URL:",r instanceof Error?r.message:r)}}};function Bn(n){let e=n.match(/name:\s*"([^"]+)"/);if(e)return e[1];let t=n.match(/^#\s+(.+)$/m);return t?t[1].trim():"Untitled Specification"}var $e=class{constructor(e,t){this.hubProxy=e;this.projectId=t}async saveSpecification(e,t){let o=Bn(t),s=await this.hubProxy.saveSpecification(this.projectId,e,o,t);if(!s.success)throw new Error(s.error||"Failed to save specification")}async getSpecification(e){let t=await this.hubProxy.getSpecification(this.projectId,e);return t.success&&t.content||null}async listSpecifications(){let e=await this.hubProxy.listSpecifications(this.projectId);return!e.success||!e.specifications?[]:e.specifications.map(t=>({slug:t.slug,name:t.name,status:t.status,version:"1.0.0"}))}async deleteSpecification(e){return(await this.hubProxy.deleteSpecification(this.projectId,e)).success}async specificationExists(e){let t=await this.hubProxy.getSpecification(this.projectId,e);return t.success&&t.content!=null}};import{exec as Wn,execSync as Gn,spawn as Kn}from"child_process";import{promisify as qn}from"util";import{createHash as Vt}from"crypto";import*as _ from"fs";import*as F from"path";var He=class{domain;accountId;tunnelId;apiToken;zoneId;tunnelApiBase;constructor(){this.domain=process.env.CLOUDFLARE_DEPLOY_DOMAIN||process.env.DEPLOY_DOMAIN||"vibecodementor.net",this.accountId=process.env.CLOUDFLARE_ACCOUNT_ID||"",this.tunnelId=process.env.CLOUDFLARE_TUNNEL_ID||"",this.apiToken=process.env.CLOUDFLARE_API_TOKEN||"",this.zoneId=process.env.CLOUDFLARE_ZONE_ID||"",this.tunnelApiBase=`https://api.cloudflare.com/client/v4/accounts/${this.accountId}/cfd_tunnel/${this.tunnelId}/configurations`}isConfigured(){return!!(this.accountId&&this.tunnelId&&this.apiToken&&this.zoneId)}buildHostname(e){let t=this.domain.split("."),o=t.length>2?t.slice(-2).join("."):this.domain;return`${e}.${o}`}async addRoute(e,t){let o=this.buildHostname(e);if(console.log(`[TunnelManager] Adding route: ${o} -> localhost:${t}`),!this.isConfigured())return console.log("[TunnelManager] Not configured, skipping route addition"),`https://${o}`;try{let s=await this.getConfig(),r=s.ingress.findIndex(a=>a.hostname===o);if(r!==-1)s.ingress[r].service=`http://localhost:${t}`;else{let a=s.ingress.findIndex(l=>!l.hostname),c={hostname:o,service:`http://localhost:${t}`};a!==-1?s.ingress.splice(a,0,c):(s.ingress.push(c),s.ingress.push({service:"http_status:404"}))}await this.putConfig(s),await this.ensureDnsPointsToTunnel(o);let i=`https://${o}`;return console.log(`[TunnelManager] \u2713 Route added: ${i}`),i}catch(s){throw console.error("[TunnelManager] Failed to add route:",s),s}}async removeRoute(e){let t=this.buildHostname(e);if(console.log(`[TunnelManager] Removing route: ${t}`),!this.isConfigured()){console.log("[TunnelManager] Not configured, skipping route removal");return}try{let o=await this.getConfig();o.ingress=o.ingress.filter(s=>s.hostname!==t),o.ingress.some(s=>!s.hostname)||o.ingress.push({service:"http_status:404"}),await this.putConfig(o),console.log(`[TunnelManager] \u2713 Route removed: ${t}`)}catch(o){throw console.error("[TunnelManager] Failed to remove route:",o),o}}async getConfig(){let t=await(await fetch(this.tunnelApiBase,{method:"GET",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"}})).json();if(!t.success)throw new Error(`Cloudflare API error: ${t.errors.map(o=>o.message).join(", ")}`);return t.result?.config||{ingress:[{service:"http_status:404"}]}}async putConfig(e){let o=await(await fetch(this.tunnelApiBase,{method:"PUT",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"},body:JSON.stringify({config:e})})).json();if(!o.success)throw new Error(`Cloudflare API error: ${o.errors.map(s=>s.message).join(", ")}`);console.log("[TunnelManager] Configuration updated via Cloudflare API")}async ensureDnsPointsToTunnel(e){let t=`${this.tunnelId}.cfargotunnel.com`,o=`https://api.cloudflare.com/client/v4/zones/${this.zoneId}/dns_records`;try{let r=await(await fetch(`${o}?name=${e}&type=CNAME`,{method:"GET",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"}})).json();if(r.success&&r.result?.length){let i=r.result[0];if(i.content===t){console.log(`[TunnelManager] DNS already points to correct tunnel: ${e}`);return}console.log(`[TunnelManager] Updating DNS: ${e} from ${i.content} to ${t}`);let c=await(await fetch(`${o}/${i.id}`,{method:"PATCH",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"},body:JSON.stringify({type:"CNAME",name:e,content:t,proxied:!0})})).json();c.success?console.log(`[TunnelManager] \u2713 DNS updated: ${e} -> ${t}`):console.error(`[TunnelManager] Failed to update DNS: ${c.errors.map(l=>l.message).join(", ")}`)}else{console.log(`[TunnelManager] Creating DNS record: ${e} -> ${t}`);let a=await(await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"},body:JSON.stringify({type:"CNAME",name:e,content:t,proxied:!0})})).json();a.success?console.log(`[TunnelManager] \u2713 DNS record created: ${e} -> ${t}`):console.error(`[TunnelManager] Failed to create DNS: ${a.errors.map(c=>c.message).join(", ")}`)}}catch(s){console.error(`[TunnelManager] Error updating DNS for ${e}:`,s)}}};var kt=qn(Wn),A=class{start;label;constructor(e){this.label=e,this.start=Date.now(),console.log(`[TIMING] \u23F1 START: ${e}`)}stop(){let e=Date.now()-this.start,t=(e/1e3).toFixed(2);return console.log(`[TIMING] \u2713 DONE: ${this.label} (${t}s)`),e}};function M(n,e={}){return new Promise((t,o)=>{let s=Kn(n,[],{shell:!0,stdio:"inherit",cwd:e.cwd}),r=null;e.timeout&&(r=setTimeout(()=>{s.kill(),o(new Error(`Command timed out: ${n}`))},e.timeout)),s.on("close",i=>{r&&clearTimeout(r),i===0?t():o(new Error(`Command failed with code ${i}: ${n}`))}),s.on("error",i=>{r&&clearTimeout(r),o(i)})})}var Xt="main",Be=class{constructor(e,t,o,s){this.connection=e;this.serviceManager=t;this.workspaceDir=o;this.gitHubPat=s}currentBranchName=Xt;currentRepoUrl="";lastLockfileHash=null;tunnelManager=null;currentPreviewSubdomain=null;getTunnelManager(){return this.tunnelManager||(this.tunnelManager=new He),this.tunnelManager}async prewarmWorkspace(){let e=new A("TOTAL INIT"),t=process.env.REPO_URL,o=process.env.BRANCH_NAME||Xt,s=process.env.PREVIEW_SUBDOMAIN,r=process.env.PREVIEW_HOSTNAME,i=process.env.PROJECT_GITHUB_PAT,a=t?.includes("x-access-token:")??!1,c=a?t?.match(/x-access-token:([^@]{0,8})/)?.[1]+"...":"PAT";if(console.log("[Init] === Single-Phase Init Starting ==="),console.log(`[Init] Repo: ${t?this.extractRepoPath(t):"NOT SET"}`),console.log(`[Init] Branch: ${o}`),console.log(`[Init] Auth method: ${a?"GitHub App token":"PAT"} (prefix: ${c})`),console.log(`[Init] Preview: ${s||"none"}`),console.log(`[Init] Container ID: ${process.env.CONTAINER_ID||"unknown"}`),console.log(`[Init] Session ID: ${process.env.SESSION_ID||"none"}`),console.log(`[Init] Timestamp: ${new Date().toISOString()}`),!t)throw console.error("[Init] \u274C REPO_URL not set - cannot initialize workspace"),new Error("REPO_URL environment variable is required");i&&(this.gitHubPat=i);let l=new A("Clean workspace");Gn("rm -rf /workspace/* /workspace/.* 2>/dev/null || true",{stdio:"inherit"}),l.stop();let g=new A("Clone repository");await this.cloneRepository(t,o),this.currentRepoUrl=t,this.currentBranchName=o,g.stop(),await this.installDependencies(),this.lastLockfileHash=this.getLockfileHash(),console.log("[Init] Starting services...");let u=new A("Start backend (dotnet)");await this.serviceManager.startBackend(),u.stop();let p=new A("Start frontend (vite)");await this.serviceManager.startFrontend(),p.stop();let f=new A("Wait for health check");await this.serviceManager.waitForHealth(3e4),f.stop(),s&&r&&await this.setupPreviewSubdomainFromEnv(s,r),await this.connection.startTokenRefresh(),e.stop(),console.log("[Init] \u2713 Workspace ready")}async handleInitSession(e){console.log(`[InitSession] Session ${e.sessionId} starting...`);let t=this.extractRepoPath(e.repoUrl),o=this.extractRepoPath(this.currentRepoUrl),s=t!==o,r=e.branchName!==this.currentBranchName;s||r?(console.log("[InitSession] Repo/branch mismatch - updating workspace..."),console.log(`[InitSession] Current: ${o}@${this.currentBranchName}`),console.log(`[InitSession] Requested: ${t}@${e.branchName}`),await this.connection.reportStatus("Ready",void 0,e.sessionId,e.projectId),await this.connection.getHubProxy().initSessionCompleted(process.env.CONTAINER_ID||"unknown",e.sessionId,!0,""),this.handleRepoChange(e).catch(async a=>{let c=a instanceof Error?a.message:"Unknown error";console.error("[InitSession] Background update failed:",c),await this.connection.reportStatus("Error",c,e.sessionId,e.projectId)})):(console.log("[InitSession] Workspace already matches - ready immediately"),await this.connection.reportStatus("Ready",void 0,e.sessionId,e.projectId),await this.connection.getHubProxy().initSessionCompleted(process.env.CONTAINER_ID||"unknown",e.sessionId,!0,"")),console.log(`[InitSession] \u2713 Ready for session ${e.sessionId}`)}async setupPreviewSubdomainFromEnv(e,t){let o=new A("Setup preview subdomain");console.log(`[Preview] Setting up preview subdomain: ${e} (${t})`);let s=this.getTunnelManager();if(!s){console.log("[Preview] TunnelManager not available, skipping subdomain setup"),o.stop();return}if(!s.isConfigured()){console.log("[Preview] Cloudflare not configured, skipping subdomain setup"),o.stop();return}try{let r=parseInt(process.env.ALLOCATED_HOST_PORT||"5173"),i=await s.addRoute(e,r);this.currentPreviewSubdomain=e,this.connection.setTunnelUrl(i),o.stop(),console.log(`[Preview] \u2713 Preview subdomain configured: ${i}`)}catch(r){o.stop(),console.error("[Preview] Failed to set up subdomain route:",r)}}async handleRepoChange(e){let t=new A("TOTAL REPO CHANGE");e.gitHubPat&&e.gitHubPat!==this.gitHubPat&&(console.log("[RepoChange] Updating git credentials"),this.gitHubPat=e.gitHubPat,await M(`echo "https://${e.gitHubPat}@github.com" > ~/.git-credentials`));let o=this.extractRepoPath(e.repoUrl),s=this.extractRepoPath(this.currentRepoUrl);if(o!==s){let i=new A("Clone new repository");await this.cloneRepository(e.repoUrl,e.branchName),this.currentRepoUrl=e.repoUrl,this.currentBranchName=e.branchName,i.stop(),await this.installDependencies();let a=new A("Restart services");await this.serviceManager.restartServices("both"),a.stop()}else{let i=new A(`Switch branch to ${e.branchName}`);await this.switchBranch(e.branchName),i.stop(),await this.checkNeedsReinstall()&&await this.installDependencies();let c=new A("Restart services");await this.serviceManager.restartServices("both"),c.stop()}e.previewSubdomain&&e.previewHostname&&await this.setupPreviewSubdomainFromEnv(e.previewSubdomain,e.previewHostname),t.stop(),console.log("[RepoChange] \u2713 Workspace updated")}extractRepoPath(e){let t=e.match(/github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/);return t?t[1]:e}async cloneRepository(e,t){let o=this.extractRepoPath(e),s=e.includes("x-access-token:"),r=s?e.match(/x-access-token:([^@]{0,8})/)?.[1]+"...":"PAT";console.log("[Clone] === Git Clone Start ==="),console.log(`[Clone] Repo: ${o}`),console.log(`[Clone] Branch: ${t}`),console.log(`[Clone] Auth: ${s?"GitHub App token":"PAT"} (prefix: ${r})`),console.log(`[Clone] Timestamp: ${new Date().toISOString()}`);let i=6,a=[0,3e3,5e3,8e3,12e3,15e3];for(let c=1;c<=i;c++){await M("rm -rf /workspace/* /workspace/.* 2>/dev/null || true");try{console.log(`[Clone] Attempt ${c}/${i}...`);let l=Date.now();await M(`git clone -b ${t} "${e}" /workspace`,{timeout:12e4});let g=((Date.now()-l)/1e3).toFixed(2);console.log(`[Clone] \u2713 Clone succeeded on attempt ${c} (${g}s)`),await M('cd /workspace && git config user.email "agent@dotnetmentor.se" && git config user.name "Agent"'),console.log("[Clone] \u2713 Repository cloned and configured");return}catch(l){let g=l instanceof Error?l.message:String(l);console.error(`[Clone] \u274C Attempt ${c}/${i} failed: ${g}`);let u=0;try{let{stdout:p}=await kt(`git ls-remote --heads "${e}" 2>&1`,{timeout:15e3}),f=p.trim();u=f?f.split(`
1361
1361
  `).length:0,console.log(`[Clone] ls-remote: ${u} branch(es) found${f?`: ${f.split(`
1362
1362
  `).slice(0,3).join(", ")}`:" (empty repo \u2014 likely still generating from template)"}`)}catch(p){let f=p instanceof Error?p.message:String(p);console.error(`[Clone] ls-remote also failed: ${f}`)}if(c<i){let p=a[c]||15e3,f=u===0?"repo appears empty (template still generating)":`branch '${t}' not found`;console.log(`[Clone] Retrying in ${p/1e3}s... (${f})`),await new Promise(k=>setTimeout(k,p))}else throw console.error(`[Clone] \u274C All ${i} attempts failed for ${o}`),await this.connection.reportError({message:`Git clone failed after ${i} attempts: ${g}`,errorType:"GitCloneError",operation:"cloneRepository",isFatal:!0}),l}}}async switchBranch(e){if(console.log(`[Branch] Switching from ${this.currentBranchName} to ${e}`),e===this.currentBranchName)console.log(`[Branch] Already on ${e}, pulling latest...`),await M(`git pull origin ${e}`,{cwd:this.workspaceDir,timeout:6e4});else{await M("git fetch origin",{cwd:this.workspaceDir,timeout:6e4});let{stdout:t}=await kt(`git ls-remote --heads origin ${e}`,{cwd:this.workspaceDir,timeout:3e4});t.trim().length>0?await M(`git checkout -B ${e} origin/${e}`,{cwd:this.workspaceDir,timeout:3e4}):(console.log(`[Branch] Branch ${e} doesn't exist on remote, creating from main...`),await M(`git checkout -b ${e}`,{cwd:this.workspaceDir,timeout:3e4})),this.currentBranchName=e}console.log(`[Branch] \u2713 Now on ${e}`)}getLockfileHash(){let e=F.join(this.workspaceDir,"packages/backoffice-web/package-lock.json");return _.existsSync(e)?Vt("sha256").update(_.readFileSync(e)).digest("hex"):null}async checkNeedsReinstall(){let e=this.getLockfileHash();return!e||!this.lastLockfileHash?!0:e!==this.lastLockfileHash}async checkCodeDiff(e,t){if(e===t)return!1;try{let{stdout:o}=await kt(`git diff ${e}..HEAD --name-only`,{cwd:this.workspaceDir,timeout:3e4}),s=o.trim();if(!s)return console.log(`[CodeDiff] No file differences between ${e} and ${t}`),!1;let r=s.split(`
package/dist/cli.js CHANGED
@@ -1356,7 +1356,7 @@ You have access to **Playwright MCP** tools to verify the UI works correctly aft
1356
1356
  Recent logs:
1357
1357
  ${D.join(`
1358
1358
  `)}`:"";h.backendError||(h.backendError=`Backend failed to start.${R}`)}return P&&!N.web&&(h.success=!1,h.frontendError||(h.frontendError="Frontend failed to start")),h},Rt=async()=>{if(!l||!I.existsSync(l))return{success:!0};try{return re(f,{cwd:l,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),{success:!0}}catch(S){let h=S;return{success:!1,errors:h.stdout||h.stderr||"Build failed"}}},Tt=async()=>{if(!g||!I.existsSync(ne.join(g,"package.json")))return{success:!0};try{return re(E,{cwd:g,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),{success:!0}}catch(S){let h=S;return{success:!1,errors:h.stdout||h.stderr||"Type check failed"}}},gn=async()=>{let[S,h]=await Promise.all([Rt(),Tt()]);return{backend:S,frontend:h}},It=async(S,h)=>{let v=S==="backend"?x:w;if(!I.existsSync(v))return[`Log file not found: ${v}`];try{return re(`tail -n ${h} ${v}`,{encoding:"utf-8"}).split(`
1359
- `).filter(Boolean)}catch(P){return[`Error reading logs: ${P instanceof Error?P.message:String(P)}`]}};return{startBackend:d,startFrontend:C,stopBackend:U,stopFrontend:$,restartServices:un,checkHealth:pe,waitForHealth:Pt,getProcesses:()=>({backend:m,frontend:j}),checkBackendBuild:Rt,checkFrontendTypes:Tt,runTypeChecks:gn,tailLogs:It,checkSwaggerEndpoints:async S=>{let h=ne.join(e,"swagger.json");if(!I.existsSync(h))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let v=JSON.parse(I.readFileSync(h,"utf-8")),P=Object.keys(v.paths||{}),N=[];for(let D of P)if(D.toLowerCase().includes(S.toLowerCase())){let R=Object.keys(v.paths[D]);for(let Z of R)N.push(`${Z.toUpperCase()} ${D}`)}return{foundEndpoints:N,totalEndpoints:P.length}}catch(v){return{foundEndpoints:[`Error parsing swagger.json: ${v instanceof Error?v.message:String(v)}`],totalEndpoints:0}}}}}function Mn(n){let e=n.toLowerCase();return e.includes("exception")||e.includes("fail:")||e.includes("[err]")||e.includes("[error]")}import{execSync as ie}from"child_process";function Me(n){let e=async()=>{try{return ie("git status --porcelain",{cwd:n,encoding:"utf-8"}).trim().length>0}catch{return!1}},t=async()=>{try{return ie("git branch --show-current",{cwd:n,encoding:"utf-8"}).trim()}catch{return"unknown"}};return{hasChanges:e,commitAndPush:async(s,r)=>{try{if(!await e())return{success:!0,noChanges:!0};let i=s.length>60?s.substring(0,60)+"...":s,c=`${r?"[agent] (partial)":"[agent]"} ${i}`;ie("git add -A",{cwd:n}),ie(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:n,encoding:"utf-8"});let l=ie("git rev-parse --short HEAD",{cwd:n,encoding:"utf-8"}).trim();try{ie("git push",{cwd:n,stdio:"pipe"})}catch(g){let u=g instanceof Error?g.message:String(g);if(u.includes("no upstream branch")){let p=await t();ie(`git push --set-upstream origin ${p}`,{cwd:n,stdio:"pipe"})}else return console.error("[Git] Push failed:",u),{success:!1,commitHash:l,commitSucceeded:!0,pushFailed:!0,error:u}}return{success:!0,commitHash:l}}catch(i){let a=i instanceof Error?i.message:String(i);return console.error("[Git] Error:",a),{success:!1,error:a}}},getCurrentBranch:t}}import*as oe from"@microsoft/signalr";import*as zt from"fs";import*as Jt from"os";import*as Qt from"path";import{exec as Fn}from"child_process";import{promisify as $n}from"util";var K=class{constructor(e,t){this.connection=e;this.receiverMethod=t}dispose=()=>{for(let e of this.receiverMethod)this.connection.off(e.methodName,e.method)}},qt=n=>{if(n==="IDeploymentWatcherHub")return et.Instance;if(n==="IDeploymentHub")return nt.Instance;if(n==="IKanbanHub")return st.Instance;if(n==="IAgentHub")return it.Instance;if(n==="ISlaveHub")return ct.Instance;if(n==="ISlaveWatcherHub")return pt.Instance;if(n==="ITestHub")return ut.Instance},Yt=n=>{if(n==="IDeploymentWatcherClient")return mt.Instance;if(n==="IDeploymentHubClient")return ht.Instance;if(n==="IKanbanBoardClient")return ft.Instance;if(n==="IAgentReceiver")return yt.Instance;if(n==="IBackofficeReceiver")return bt.Instance;if(n==="ISlaveHubClient")return St.Instance;if(n==="ISlaveWatcherClient")return wt.Instance;if(n==="ITestHubClient")return vt.Instance},et=class n{static Instance=new n;constructor(){}createHubProxy=e=>new tt(e)},tt=class{constructor(e){this.connection=e}watchMachine=async e=>await this.connection.invoke("WatchMachine",e);unwatchMachine=async e=>await this.connection.invoke("UnwatchMachine",e);startStreamingLogs=async e=>await this.connection.invoke("StartStreamingLogs",e);stopStreamingLogs=async e=>await this.connection.invoke("StopStreamingLogs",e)},nt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new ot(e)},ot=class{constructor(e){this.connection=e}registerMachine=async(e,t)=>await this.connection.invoke("RegisterMachine",e,t);getSecrets=async()=>await this.connection.invoke("GetSecrets");reportDeploymentStatus=async e=>await this.connection.invoke("ReportDeploymentStatus",e);reportHealth=async e=>await this.connection.invoke("ReportHealth",e);reportMachineStatus=async e=>await this.connection.invoke("ReportMachineStatus",e);sendDeploymentLog=async e=>await this.connection.invoke("SendDeploymentLog",e)},st=class n{static Instance=new n;constructor(){}createHubProxy=e=>new rt(e)},rt=class{constructor(e){this.connection=e}joinBoard=async e=>await this.connection.invoke("JoinBoard",e);leaveBoard=async e=>await this.connection.invoke("LeaveBoard",e)},it=class n{static Instance=new n;constructor(){}createHubProxy=e=>new at(e)},at=class{constructor(e){this.connection=e}registerAgent=async e=>await this.connection.invoke("RegisterAgent",e);getSecrets=async()=>await this.connection.invoke("GetSecrets");reportStatus=async(e,t)=>await this.connection.invoke("ReportStatus",e,t);reportSessionOutput=async(e,t,o)=>await this.connection.invoke("ReportSessionOutput",e,t,o);reportSessionCost=async(e,t,o)=>await this.connection.invoke("ReportSessionCost",e,t,o);reportInsight=async(e,t)=>await this.connection.invoke("ReportInsight",e,t);setClaudeSessionId=async(e,t)=>await this.connection.invoke("SetClaudeSessionId",e,t);sessionCompleted=async(e,t,o)=>await this.connection.invoke("SessionCompleted",e,t,o);initSessionCompleted=async(e,t,o,s)=>await this.connection.invoke("InitSessionCompleted",e,t,o,s);reportPreviewBuild=async(e,t,o)=>await this.connection.invoke("ReportPreviewBuild",e,t,o);saveSpecification=async(e,t,o,s)=>await this.connection.invoke("SaveSpecification",e,t,o,s);getSpecification=async(e,t)=>await this.connection.invoke("GetSpecification",e,t);listSpecifications=async e=>await this.connection.invoke("ListSpecifications",e);deleteSpecification=async(e,t)=>await this.connection.invoke("DeleteSpecification",e,t);watchContainer=async e=>await this.connection.invoke("WatchContainer",e);watchSession=async e=>await this.connection.invoke("WatchSession",e);watchProject=async e=>await this.connection.invoke("WatchProject",e);unwatchProject=async e=>await this.connection.invoke("UnwatchProject",e);watchSlaves=async()=>await this.connection.invoke("WatchSlaves");unwatchSlaves=async()=>await this.connection.invoke("UnwatchSlaves");sendPrompt=async(e,t,o,s)=>await this.connection.invoke("SendPrompt",e,t,o,s);stopSession=async e=>await this.connection.invoke("StopSession",e);switchSession=async(e,t)=>await this.connection.invoke("SwitchSession",e,t);createSession=async e=>await this.connection.invoke("CreateSession",e);refreshGitHubToken=async()=>await this.connection.invoke("RefreshGitHubToken");reportError=async(e,t)=>await this.connection.invoke("ReportError",e,t);startClaudeLogin=async e=>await this.connection.invoke("StartClaudeLogin",e);submitClaudeLoginCode=async(e,t)=>await this.connection.invoke("SubmitClaudeLoginCode",e,t)},ct=class n{static Instance=new n;constructor(){}createHubProxy=e=>new lt(e)},lt=class{constructor(e){this.connection=e}register=async(e,t)=>await this.connection.invoke("Register",e,t);getSecrets=async()=>await this.connection.invoke("GetSecrets");containerCreated=async e=>await this.connection.invoke("ContainerCreated",e);containerReady=async e=>await this.connection.invoke("ContainerReady",e);reportCapacity=async e=>await this.connection.invoke("ReportCapacity",e);reportError=async e=>await this.connection.invoke("ReportError",e);reportDockerContainers=async e=>await this.connection.invoke("ReportDockerContainers",e);reportContainerLog=async e=>await this.connection.invoke("ReportContainerLog",e);reportAgentRestarted=async(e,t,o)=>await this.connection.invoke("ReportAgentRestarted",e,t,o);reportContainerTerminated=async(e,t,o)=>await this.connection.invoke("ReportContainerTerminated",e,t,o);reportSlaveAgentLog=async e=>await this.connection.invoke("ReportSlaveAgentLog",e);reportClaudeLoginUrl=async e=>await this.connection.invoke("ReportClaudeLoginUrl",e);reportClaudeLoginResult=async e=>await this.connection.invoke("ReportClaudeLoginResult",e)},pt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new dt(e)},dt=class{constructor(e){this.connection=e}watchSlave=async e=>await this.connection.invoke("WatchSlave",e);unwatchSlave=async e=>await this.connection.invoke("UnwatchSlave",e);requestDockerContainers=async e=>await this.connection.invoke("RequestDockerContainers",e);startStreamingContainerLogs=async(e,t,o)=>await this.connection.invoke("StartStreamingContainerLogs",e,t,o);stopStreamingContainerLogs=async(e,t)=>await this.connection.invoke("StopStreamingContainerLogs",e,t);restartLabAgent=async(e,t)=>await this.connection.invoke("RestartLabAgent",e,t);terminateContainer=async(e,t)=>await this.connection.invoke("TerminateContainer",e,t);startStreamingSlaveAgentLogs=async(e,t)=>await this.connection.invoke("StartStreamingSlaveAgentLogs",e,t);stopStreamingSlaveAgentLogs=async e=>await this.connection.invoke("StopStreamingSlaveAgentLogs",e);startClaudeLogin=async(e,t)=>await this.connection.invoke("StartClaudeLogin",e,t);submitClaudeLoginCode=async(e,t,o)=>await this.connection.invoke("SubmitClaudeLoginCode",e,t,o)},ut=class n{static Instance=new n;constructor(){}createHubProxy=e=>new gt(e)},gt=class{constructor(e){this.connection=e}joinProject=async e=>await this.connection.invoke("JoinProject",e);leaveProject=async e=>await this.connection.invoke("LeaveProject",e)},mt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...a)=>t.deploymentStatusUpdated(...a),s=(...a)=>t.deploymentLogReceived(...a),r=(...a)=>t.machineStatusUpdated(...a);e.on("DeploymentStatusUpdated",o),e.on("DeploymentLogReceived",s),e.on("MachineStatusUpdated",r);let i=[{methodName:"DeploymentStatusUpdated",method:o},{methodName:"DeploymentLogReceived",method:s},{methodName:"MachineStatusUpdated",method:r}];return new K(e,i)}},ht=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...c)=>t.deploy(...c),s=(...c)=>t.stop(...c),r=(...c)=>t.startLogStreaming(...c),i=(...c)=>t.stopLogStreaming(...c);e.on("Deploy",o),e.on("Stop",s),e.on("StartLogStreaming",r),e.on("StopLogStreaming",i);let a=[{methodName:"Deploy",method:o},{methodName:"Stop",method:s},{methodName:"StartLogStreaming",method:r},{methodName:"StopLogStreaming",method:i}];return new K(e,a)}},ft=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...m)=>t.boardUpdated(...m),s=(...m)=>t.boardDeleted(...m),r=(...m)=>t.columnCreated(...m),i=(...m)=>t.columnUpdated(...m),a=(...m)=>t.columnDeleted(...m),c=(...m)=>t.cardCreated(...m),l=(...m)=>t.cardUpdated(...m),g=(...m)=>t.cardDeleted(...m),u=(...m)=>t.subtaskCreated(...m),p=(...m)=>t.subtaskUpdated(...m),f=(...m)=>t.subtaskDeleted(...m),k=(...m)=>t.noteCreated(...m),E=(...m)=>t.noteUpdated(...m),x=(...m)=>t.noteDeleted(...m);e.on("BoardUpdated",o),e.on("BoardDeleted",s),e.on("ColumnCreated",r),e.on("ColumnUpdated",i),e.on("ColumnDeleted",a),e.on("CardCreated",c),e.on("CardUpdated",l),e.on("CardDeleted",g),e.on("SubtaskCreated",u),e.on("SubtaskUpdated",p),e.on("SubtaskDeleted",f),e.on("NoteCreated",k),e.on("NoteUpdated",E),e.on("NoteDeleted",x);let w=[{methodName:"BoardUpdated",method:o},{methodName:"BoardDeleted",method:s},{methodName:"ColumnCreated",method:r},{methodName:"ColumnUpdated",method:i},{methodName:"ColumnDeleted",method:a},{methodName:"CardCreated",method:c},{methodName:"CardUpdated",method:l},{methodName:"CardDeleted",method:g},{methodName:"SubtaskCreated",method:u},{methodName:"SubtaskUpdated",method:p},{methodName:"SubtaskDeleted",method:f},{methodName:"NoteCreated",method:k},{methodName:"NoteUpdated",method:E},{methodName:"NoteDeleted",method:x}];return new K(e,w)}},yt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...u)=>t.initSession(...u),s=(...u)=>t.runPrompt(...u),r=(...u)=>t.setModel(...u),i=()=>t.stopAgent(),a=()=>t.ping(),c=(...u)=>t.switchSession(...u),l=(...u)=>t.projectPromptUpdated(...u);e.on("InitSession",o),e.on("RunPrompt",s),e.on("SetModel",r),e.on("StopAgent",i),e.on("Ping",a),e.on("SwitchSession",c),e.on("ProjectPromptUpdated",l);let g=[{methodName:"InitSession",method:o},{methodName:"RunPrompt",method:s},{methodName:"SetModel",method:r},{methodName:"StopAgent",method:i},{methodName:"Ping",method:a},{methodName:"SwitchSession",method:c},{methodName:"ProjectPromptUpdated",method:l}];return new K(e,g)}},bt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...y)=>t.sessionOutput(...y),s=(...y)=>t.sessionCost(...y),r=(...y)=>t.sessionCompleted(...y),i=(...y)=>t.containerStatus(...y),a=(...y)=>t.slaveCapacityUpdate(...y),c=(...y)=>t.previewBuildStatus(...y),l=(...y)=>t.previewReload(...y),g=(...y)=>t.questionsReceived(...y),u=(...y)=>t.specificationUpdated(...y),p=(...y)=>t.singleQuestionReceived(...y),f=(...y)=>t.questionSessionEnded(...y),k=(...y)=>t.creditsUpdated(...y),E=(...y)=>t.insufficientCredits(...y),x=(...y)=>t.projectSessionStatusChanged(...y),w=(...y)=>t.claudeLoginUrlReceived(...y),m=(...y)=>t.claudeLoginCompleted(...y);e.on("SessionOutput",o),e.on("SessionCost",s),e.on("SessionCompleted",r),e.on("ContainerStatus",i),e.on("SlaveCapacityUpdate",a),e.on("PreviewBuildStatus",c),e.on("PreviewReload",l),e.on("QuestionsReceived",g),e.on("SpecificationUpdated",u),e.on("SingleQuestionReceived",p),e.on("QuestionSessionEnded",f),e.on("CreditsUpdated",k),e.on("InsufficientCredits",E),e.on("ProjectSessionStatusChanged",x),e.on("ClaudeLoginUrlReceived",w),e.on("ClaudeLoginCompleted",m);let j=[{methodName:"SessionOutput",method:o},{methodName:"SessionCost",method:s},{methodName:"SessionCompleted",method:r},{methodName:"ContainerStatus",method:i},{methodName:"SlaveCapacityUpdate",method:a},{methodName:"PreviewBuildStatus",method:c},{methodName:"PreviewReload",method:l},{methodName:"QuestionsReceived",method:g},{methodName:"SpecificationUpdated",method:u},{methodName:"SingleQuestionReceived",method:p},{methodName:"QuestionSessionEnded",method:f},{methodName:"CreditsUpdated",method:k},{methodName:"InsufficientCredits",method:E},{methodName:"ProjectSessionStatusChanged",method:x},{methodName:"ClaudeLoginUrlReceived",method:w},{methodName:"ClaudeLoginCompleted",method:m}];return new K(e,j)}},St=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...w)=>t.startContainer(...w),s=(...w)=>t.terminateContainer(...w),r=()=>t.reconnect(),i=(...w)=>t.getContainerLogs(...w),a=()=>t.getDockerContainers(),c=(...w)=>t.streamContainerLogs(...w),l=(...w)=>t.stopContainerLogStream(...w),g=(...w)=>t.restartLabAgent(...w),u=(...w)=>t.terminateDockerContainer(...w),p=(...w)=>t.streamSlaveAgentLogs(...w),f=()=>t.stopSlaveAgentLogStream(),k=(...w)=>t.startClaudeLogin(...w),E=(...w)=>t.submitClaudeLoginCode(...w);e.on("StartContainer",o),e.on("TerminateContainer",s),e.on("Reconnect",r),e.on("GetContainerLogs",i),e.on("GetDockerContainers",a),e.on("StreamContainerLogs",c),e.on("StopContainerLogStream",l),e.on("RestartLabAgent",g),e.on("TerminateDockerContainer",u),e.on("StreamSlaveAgentLogs",p),e.on("StopSlaveAgentLogStream",f),e.on("StartClaudeLogin",k),e.on("SubmitClaudeLoginCode",E);let x=[{methodName:"StartContainer",method:o},{methodName:"TerminateContainer",method:s},{methodName:"Reconnect",method:r},{methodName:"GetContainerLogs",method:i},{methodName:"GetDockerContainers",method:a},{methodName:"StreamContainerLogs",method:c},{methodName:"StopContainerLogStream",method:l},{methodName:"RestartLabAgent",method:g},{methodName:"TerminateDockerContainer",method:u},{methodName:"StreamSlaveAgentLogs",method:p},{methodName:"StopSlaveAgentLogStream",method:f},{methodName:"StartClaudeLogin",method:k},{methodName:"SubmitClaudeLoginCode",method:E}];return new K(e,x)}},wt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...p)=>t.dockerContainersUpdated(...p),s=(...p)=>t.containerLogReceived(...p),r=(...p)=>t.agentRestartCompleted(...p),i=(...p)=>t.containerTerminationCompleted(...p),a=(...p)=>t.slaveCapacityUpdated(...p),c=(...p)=>t.slaveAgentLogReceived(...p),l=(...p)=>t.claudeLoginUrlReceived(...p),g=(...p)=>t.claudeLoginCompleted(...p);e.on("DockerContainersUpdated",o),e.on("ContainerLogReceived",s),e.on("AgentRestartCompleted",r),e.on("ContainerTerminationCompleted",i),e.on("SlaveCapacityUpdated",a),e.on("SlaveAgentLogReceived",c),e.on("ClaudeLoginUrlReceived",l),e.on("ClaudeLoginCompleted",g);let u=[{methodName:"DockerContainersUpdated",method:o},{methodName:"ContainerLogReceived",method:s},{methodName:"AgentRestartCompleted",method:r},{methodName:"ContainerTerminationCompleted",method:i},{methodName:"SlaveCapacityUpdated",method:a},{methodName:"SlaveAgentLogReceived",method:c},{methodName:"ClaudeLoginUrlReceived",method:l},{methodName:"ClaudeLoginCompleted",method:g}];return new K(e,u)}},vt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...l)=>t.testRunCreated(...l),s=(...l)=>t.testRunUpdated(...l),r=(...l)=>t.testSuiteCreated(...l),i=(...l)=>t.testCreated(...l),a=(...l)=>t.testUpdated(...l);e.on("TestRunCreated",o),e.on("TestRunUpdated",s),e.on("TestSuiteCreated",r),e.on("TestCreated",i),e.on("TestUpdated",a);let c=[{methodName:"TestRunCreated",method:o},{methodName:"TestRunUpdated",method:s},{methodName:"TestSuiteCreated",method:r},{methodName:"TestCreated",method:i},{methodName:"TestUpdated",method:a}];return new K(e,c)}};var Hn=$n(Fn),Fe=class{constructor(e){this.config=e;let t={"X-Container-Id":e.containerId,"X-Project-Key":e.projectKey};e.isByok&&(t["X-Is-Byok"]="true"),this.connection=new oe.HubConnectionBuilder().withUrl(`${e.masterUrl}/api/hubs/agent`,{headers:t}).withAutomaticReconnect({nextRetryDelayInMilliseconds:o=>{let s=o.previousRetryCount+1,r=Math.min(1e3*Math.pow(2,o.previousRetryCount),6e4);return console.log(`[SignalR] Reconnect attempt ${s} (will retry in ${r}ms)`),r}}).withServerTimeout(3e5).withKeepAliveInterval(1e4).configureLogging(oe.LogLevel.Information).build(),this.hubProxy=qt("IAgentHub").createHubProxy(this.connection),this.connection.onreconnecting(o=>{console.warn("[SignalR] Connection lost, attempting to reconnect...",o?.message)}),this.connection.onreconnected(async o=>{console.log("[SignalR] Reconnected to gateway (connectionId:",o,")");try{await this.hubProxy.registerAgent(this.config.containerId),console.log(`[SignalR] Re-registered as agent for container: ${this.config.containerId}`),await this.reportStatus(this.currentStatus,void 0,this.currentSessionId??void 0,this.currentProjectId??void 0)}catch(s){console.error("[SignalR] Failed to re-register agent after reconnect:",s instanceof Error?s.message:s)}}),this.connection.onclose(o=>{console.error("[SignalR] Connection closed:",o?.message),console.error("[SignalR] Connection state at close:",this.connection.state),process.exit(1)})}connection;hubProxy;receiverSubscription=null;currentStatus="WarmingUp";currentSessionId=null;currentProjectId=null;tunnelUrl=null;tokenRefreshInterval=null;currentRepoFullName=null;heartbeatInterval=null;async connect(){console.log(`[SignalR] Connecting to gateway: ${this.config.masterUrl}/api/hubs/agent`),this.config.isByok&&console.log("[SignalR] BYOK mode enabled - credits will not be deducted"),await this.connection.start();let e=this.connection.connection?.transport;console.log("[SignalR] Connected to gateway!"),console.log(`[SignalR] Transport: ${e?.constructor?.name||"unknown"}`),console.log(`[SignalR] Connection ID: ${this.connection.connectionId}`),await this.hubProxy.registerAgent(this.config.containerId),console.log(`[SignalR] Registered as agent for container: ${this.config.containerId}`)}registerReceiver(e){this.receiverSubscription&&this.receiverSubscription.dispose(),this.receiverSubscription=Yt("IAgentReceiver").register(this.connection,e)}getHubProxy(){return this.hubProxy}getMasterUrl(){return this.config.masterUrl}getProjectKey(){return this.config.projectKey}getConnection(){return this.connection}setTunnelUrl(e){this.tunnelUrl=e}async reportStatus(e,t,o,s){if(this.currentStatus=e,o&&(this.currentSessionId=o),s&&(this.currentProjectId=s),this.connection.state===oe.HubConnectionState.Connected)try{let r={status:e,error:t,sessionId:o,projectId:s,tunnelUrl:this.tunnelUrl??void 0};await this.hubProxy.reportStatus(this.config.containerId,r),console.log(`[Status] ${e}${t?` (${t})`:""}${this.tunnelUrl?` [${this.tunnelUrl}]`:""}${o?` [session: ${o}]`:""}`)}catch(r){console.error("[SignalR] Failed to report status:",r)}}async getSecrets(){let e=await this.hubProxy.getSecrets();if(!e.success)throw new Error(`Failed to get secrets: ${e.error}`);return e.secrets||{}}startHeartbeat(e=3e4){this.heartbeatInterval||(this.heartbeatInterval=setInterval(async()=>{if(this.connection.state===oe.HubConnectionState.Connected)try{await this.hubProxy.reportStatus(this.config.containerId,{status:this.currentStatus,sessionId:this.currentSessionId??void 0,projectId:this.currentProjectId??void 0,tunnelUrl:this.tunnelUrl??void 0})}catch(t){console.error("[Heartbeat] Failed:",t instanceof Error?t.message:t)}},e),console.log(`[Heartbeat] Started (every ${e/1e3}s)`))}stopHeartbeat(){this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null,console.log("[Heartbeat] Stopped"))}async startTokenRefresh(){await this.refreshGitHubToken(),this.tokenRefreshInterval=setInterval(async()=>{await this.refreshGitHubToken()},3e6),console.log("[TokenRefresh] Started (refreshing every 50 minutes)")}stopTokenRefresh(){this.tokenRefreshInterval&&(clearInterval(this.tokenRefreshInterval),this.tokenRefreshInterval=null,console.log("[TokenRefresh] Stopped"))}async refreshGitHubToken(){console.log(`[TokenRefresh] Requesting new token from backend... (${new Date().toISOString()})`);try{let e=await this.hubProxy.refreshGitHubToken();if(!e.success){console.error(`[TokenRefresh] \u274C Backend returned failure: ${e.error}`);return}if(!e.token){console.error("[TokenRefresh] \u274C No token in response (success=true but token is empty)");return}let t=e.token.substring(0,8)+"...";if(console.log(`[TokenRefresh] Got token (prefix: ${t}), updating git credentials...`),await this.updateGitCredentials(e.token,e.repoFullName??void 0),e.expiresAt){let o=new Date(e.expiresAt).toISOString(),s=Math.round((new Date(e.expiresAt).getTime()-Date.now())/6e4);console.log(`[TokenRefresh] \u2713 Refreshed (prefix: ${t}, expires: ${o}, ~${s}min left)${e.repoFullName?` (repo: ${e.repoFullName})`:""}`)}else console.log("[TokenRefresh] \u2713 Refreshed (PAT mode, no expiry)");this.currentRepoFullName=e.repoFullName??null}catch(e){console.error("[TokenRefresh] \u274C Exception:",e instanceof Error?e.message:e)}}async reportError(e){if(this.connection.state!==oe.HubConnectionState.Connected){console.error("[SignalR] Cannot report error - not connected");return}try{let t={message:e.message,stackTrace:e.stackTrace,errorType:e.errorType,operation:e.operation,sessionId:e.sessionId??this.currentSessionId??void 0,isFatal:e.isFatal??!1},o=await this.hubProxy.reportError(this.config.containerId,t);o.success?console.log(`[Error Report] Reported: ${e.errorType??"Error"} - ${e.message}`):console.error(`[Error Report] Failed to report: ${o.error}`)}catch(t){console.error("[SignalR] Failed to report error:",t instanceof Error?t.message:t)}}async updateGitCredentials(e,t){let o=Qt.join(Jt.homedir(),".git-credentials"),s=`https://x-access-token:${e}@github.com
1359
+ `).filter(Boolean)}catch(P){return[`Error reading logs: ${P instanceof Error?P.message:String(P)}`]}};return{startBackend:d,startFrontend:C,stopBackend:U,stopFrontend:$,restartServices:un,checkHealth:pe,waitForHealth:Pt,getProcesses:()=>({backend:m,frontend:j}),checkBackendBuild:Rt,checkFrontendTypes:Tt,runTypeChecks:gn,tailLogs:It,checkSwaggerEndpoints:async S=>{let h=ne.join(e,"swagger.json");if(!I.existsSync(h))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let v=JSON.parse(I.readFileSync(h,"utf-8")),P=Object.keys(v.paths||{}),N=[];for(let D of P)if(D.toLowerCase().includes(S.toLowerCase())){let R=Object.keys(v.paths[D]);for(let Z of R)N.push(`${Z.toUpperCase()} ${D}`)}return{foundEndpoints:N,totalEndpoints:P.length}}catch(v){return{foundEndpoints:[`Error parsing swagger.json: ${v instanceof Error?v.message:String(v)}`],totalEndpoints:0}}}}}function Mn(n){let e=n.toLowerCase();return e.includes("exception")||e.includes("fail:")||e.includes("[err]")||e.includes("[error]")}import{execSync as ie}from"child_process";function Me(n){let e=async()=>{try{return ie("git status --porcelain",{cwd:n,encoding:"utf-8"}).trim().length>0}catch{return!1}},t=async()=>{try{return ie("git branch --show-current",{cwd:n,encoding:"utf-8"}).trim()}catch{return"unknown"}};return{hasChanges:e,commitAndPush:async(s,r)=>{try{if(!await e())return{success:!0,noChanges:!0};let i=s.length>60?s.substring(0,60)+"...":s,c=`${r?"[agent] (partial)":"[agent]"} ${i}`;ie("git add -A",{cwd:n}),ie(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:n,encoding:"utf-8"});let l=ie("git rev-parse --short HEAD",{cwd:n,encoding:"utf-8"}).trim();try{ie("git push",{cwd:n,stdio:"pipe"})}catch(g){let u=g instanceof Error?g.message:String(g);if(u.includes("no upstream branch")){let p=await t();ie(`git push --set-upstream origin ${p}`,{cwd:n,stdio:"pipe"})}else return console.error("[Git] Push failed:",u),{success:!1,commitHash:l,commitSucceeded:!0,pushFailed:!0,error:u}}return{success:!0,commitHash:l}}catch(i){let a=i instanceof Error?i.message:String(i);return console.error("[Git] Error:",a),{success:!1,error:a}}},getCurrentBranch:t}}import*as oe from"@microsoft/signalr";import*as zt from"fs";import*as Jt from"os";import*as Qt from"path";import{exec as Fn}from"child_process";import{promisify as $n}from"util";var K=class{constructor(e,t){this.connection=e;this.receiverMethod=t}dispose=()=>{for(let e of this.receiverMethod)this.connection.off(e.methodName,e.method)}},qt=n=>{if(n==="IDeploymentWatcherHub")return et.Instance;if(n==="IDeploymentHub")return nt.Instance;if(n==="IKanbanHub")return st.Instance;if(n==="IAgentHub")return it.Instance;if(n==="ISlaveHub")return ct.Instance;if(n==="ISlaveWatcherHub")return pt.Instance;if(n==="ITestHub")return ut.Instance},Yt=n=>{if(n==="IDeploymentWatcherClient")return mt.Instance;if(n==="IDeploymentHubClient")return ht.Instance;if(n==="IKanbanBoardClient")return ft.Instance;if(n==="IAgentReceiver")return yt.Instance;if(n==="IBackofficeReceiver")return bt.Instance;if(n==="ISlaveHubClient")return St.Instance;if(n==="ISlaveWatcherClient")return wt.Instance;if(n==="ITestHubClient")return vt.Instance},et=class n{static Instance=new n;constructor(){}createHubProxy=e=>new tt(e)},tt=class{constructor(e){this.connection=e}watchMachine=async e=>await this.connection.invoke("WatchMachine",e);unwatchMachine=async e=>await this.connection.invoke("UnwatchMachine",e);startStreamingLogs=async e=>await this.connection.invoke("StartStreamingLogs",e);stopStreamingLogs=async e=>await this.connection.invoke("StopStreamingLogs",e)},nt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new ot(e)},ot=class{constructor(e){this.connection=e}registerMachine=async(e,t)=>await this.connection.invoke("RegisterMachine",e,t);getSecrets=async()=>await this.connection.invoke("GetSecrets");reportDeploymentStatus=async e=>await this.connection.invoke("ReportDeploymentStatus",e);reportHealth=async e=>await this.connection.invoke("ReportHealth",e);reportMachineStatus=async e=>await this.connection.invoke("ReportMachineStatus",e);sendDeploymentLog=async e=>await this.connection.invoke("SendDeploymentLog",e)},st=class n{static Instance=new n;constructor(){}createHubProxy=e=>new rt(e)},rt=class{constructor(e){this.connection=e}joinBoard=async e=>await this.connection.invoke("JoinBoard",e);leaveBoard=async e=>await this.connection.invoke("LeaveBoard",e)},it=class n{static Instance=new n;constructor(){}createHubProxy=e=>new at(e)},at=class{constructor(e){this.connection=e}registerAgent=async e=>await this.connection.invoke("RegisterAgent",e);getSecrets=async()=>await this.connection.invoke("GetSecrets");reportStatus=async(e,t)=>await this.connection.invoke("ReportStatus",e,t);reportSessionOutput=async(e,t,o)=>await this.connection.invoke("ReportSessionOutput",e,t,o);reportSessionCost=async(e,t,o)=>await this.connection.invoke("ReportSessionCost",e,t,o);reportInsight=async(e,t)=>await this.connection.invoke("ReportInsight",e,t);setClaudeSessionId=async(e,t)=>await this.connection.invoke("SetClaudeSessionId",e,t);sessionCompleted=async(e,t,o)=>await this.connection.invoke("SessionCompleted",e,t,o);initSessionCompleted=async(e,t,o,s)=>await this.connection.invoke("InitSessionCompleted",e,t,o,s);reportPreviewBuild=async(e,t,o)=>await this.connection.invoke("ReportPreviewBuild",e,t,o);saveSpecification=async(e,t,o,s)=>await this.connection.invoke("SaveSpecification",e,t,o,s);getSpecification=async(e,t)=>await this.connection.invoke("GetSpecification",e,t);listSpecifications=async e=>await this.connection.invoke("ListSpecifications",e);deleteSpecification=async(e,t)=>await this.connection.invoke("DeleteSpecification",e,t);watchContainer=async e=>await this.connection.invoke("WatchContainer",e);watchSession=async e=>await this.connection.invoke("WatchSession",e);watchProject=async e=>await this.connection.invoke("WatchProject",e);unwatchProject=async e=>await this.connection.invoke("UnwatchProject",e);watchSlaves=async()=>await this.connection.invoke("WatchSlaves");unwatchSlaves=async()=>await this.connection.invoke("UnwatchSlaves");sendPrompt=async(e,t,o,s,r)=>await this.connection.invoke("SendPrompt",e,t,o,s,r);stopSession=async e=>await this.connection.invoke("StopSession",e);switchSession=async(e,t)=>await this.connection.invoke("SwitchSession",e,t);createSession=async e=>await this.connection.invoke("CreateSession",e);refreshGitHubToken=async()=>await this.connection.invoke("RefreshGitHubToken");reportError=async(e,t)=>await this.connection.invoke("ReportError",e,t);startClaudeLogin=async e=>await this.connection.invoke("StartClaudeLogin",e);submitClaudeLoginCode=async(e,t)=>await this.connection.invoke("SubmitClaudeLoginCode",e,t)},ct=class n{static Instance=new n;constructor(){}createHubProxy=e=>new lt(e)},lt=class{constructor(e){this.connection=e}register=async(e,t)=>await this.connection.invoke("Register",e,t);getSecrets=async()=>await this.connection.invoke("GetSecrets");containerCreated=async e=>await this.connection.invoke("ContainerCreated",e);containerReady=async e=>await this.connection.invoke("ContainerReady",e);reportCapacity=async e=>await this.connection.invoke("ReportCapacity",e);reportError=async e=>await this.connection.invoke("ReportError",e);reportDockerContainers=async e=>await this.connection.invoke("ReportDockerContainers",e);reportContainerLog=async e=>await this.connection.invoke("ReportContainerLog",e);reportAgentRestarted=async(e,t,o)=>await this.connection.invoke("ReportAgentRestarted",e,t,o);reportContainerTerminated=async(e,t,o)=>await this.connection.invoke("ReportContainerTerminated",e,t,o);reportSlaveAgentLog=async e=>await this.connection.invoke("ReportSlaveAgentLog",e);reportClaudeLoginUrl=async e=>await this.connection.invoke("ReportClaudeLoginUrl",e);reportClaudeLoginResult=async e=>await this.connection.invoke("ReportClaudeLoginResult",e)},pt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new dt(e)},dt=class{constructor(e){this.connection=e}watchSlave=async e=>await this.connection.invoke("WatchSlave",e);unwatchSlave=async e=>await this.connection.invoke("UnwatchSlave",e);requestDockerContainers=async e=>await this.connection.invoke("RequestDockerContainers",e);startStreamingContainerLogs=async(e,t,o)=>await this.connection.invoke("StartStreamingContainerLogs",e,t,o);stopStreamingContainerLogs=async(e,t)=>await this.connection.invoke("StopStreamingContainerLogs",e,t);restartLabAgent=async(e,t)=>await this.connection.invoke("RestartLabAgent",e,t);terminateContainer=async(e,t)=>await this.connection.invoke("TerminateContainer",e,t);startStreamingSlaveAgentLogs=async(e,t)=>await this.connection.invoke("StartStreamingSlaveAgentLogs",e,t);stopStreamingSlaveAgentLogs=async e=>await this.connection.invoke("StopStreamingSlaveAgentLogs",e);startClaudeLogin=async(e,t)=>await this.connection.invoke("StartClaudeLogin",e,t);submitClaudeLoginCode=async(e,t,o)=>await this.connection.invoke("SubmitClaudeLoginCode",e,t,o)},ut=class n{static Instance=new n;constructor(){}createHubProxy=e=>new gt(e)},gt=class{constructor(e){this.connection=e}joinProject=async e=>await this.connection.invoke("JoinProject",e);leaveProject=async e=>await this.connection.invoke("LeaveProject",e)},mt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...a)=>t.deploymentStatusUpdated(...a),s=(...a)=>t.deploymentLogReceived(...a),r=(...a)=>t.machineStatusUpdated(...a);e.on("DeploymentStatusUpdated",o),e.on("DeploymentLogReceived",s),e.on("MachineStatusUpdated",r);let i=[{methodName:"DeploymentStatusUpdated",method:o},{methodName:"DeploymentLogReceived",method:s},{methodName:"MachineStatusUpdated",method:r}];return new K(e,i)}},ht=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...c)=>t.deploy(...c),s=(...c)=>t.stop(...c),r=(...c)=>t.startLogStreaming(...c),i=(...c)=>t.stopLogStreaming(...c);e.on("Deploy",o),e.on("Stop",s),e.on("StartLogStreaming",r),e.on("StopLogStreaming",i);let a=[{methodName:"Deploy",method:o},{methodName:"Stop",method:s},{methodName:"StartLogStreaming",method:r},{methodName:"StopLogStreaming",method:i}];return new K(e,a)}},ft=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...m)=>t.boardUpdated(...m),s=(...m)=>t.boardDeleted(...m),r=(...m)=>t.columnCreated(...m),i=(...m)=>t.columnUpdated(...m),a=(...m)=>t.columnDeleted(...m),c=(...m)=>t.cardCreated(...m),l=(...m)=>t.cardUpdated(...m),g=(...m)=>t.cardDeleted(...m),u=(...m)=>t.subtaskCreated(...m),p=(...m)=>t.subtaskUpdated(...m),f=(...m)=>t.subtaskDeleted(...m),k=(...m)=>t.noteCreated(...m),E=(...m)=>t.noteUpdated(...m),x=(...m)=>t.noteDeleted(...m);e.on("BoardUpdated",o),e.on("BoardDeleted",s),e.on("ColumnCreated",r),e.on("ColumnUpdated",i),e.on("ColumnDeleted",a),e.on("CardCreated",c),e.on("CardUpdated",l),e.on("CardDeleted",g),e.on("SubtaskCreated",u),e.on("SubtaskUpdated",p),e.on("SubtaskDeleted",f),e.on("NoteCreated",k),e.on("NoteUpdated",E),e.on("NoteDeleted",x);let w=[{methodName:"BoardUpdated",method:o},{methodName:"BoardDeleted",method:s},{methodName:"ColumnCreated",method:r},{methodName:"ColumnUpdated",method:i},{methodName:"ColumnDeleted",method:a},{methodName:"CardCreated",method:c},{methodName:"CardUpdated",method:l},{methodName:"CardDeleted",method:g},{methodName:"SubtaskCreated",method:u},{methodName:"SubtaskUpdated",method:p},{methodName:"SubtaskDeleted",method:f},{methodName:"NoteCreated",method:k},{methodName:"NoteUpdated",method:E},{methodName:"NoteDeleted",method:x}];return new K(e,w)}},yt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...u)=>t.initSession(...u),s=(...u)=>t.runPrompt(...u),r=(...u)=>t.setModel(...u),i=()=>t.stopAgent(),a=()=>t.ping(),c=(...u)=>t.switchSession(...u),l=(...u)=>t.projectPromptUpdated(...u);e.on("InitSession",o),e.on("RunPrompt",s),e.on("SetModel",r),e.on("StopAgent",i),e.on("Ping",a),e.on("SwitchSession",c),e.on("ProjectPromptUpdated",l);let g=[{methodName:"InitSession",method:o},{methodName:"RunPrompt",method:s},{methodName:"SetModel",method:r},{methodName:"StopAgent",method:i},{methodName:"Ping",method:a},{methodName:"SwitchSession",method:c},{methodName:"ProjectPromptUpdated",method:l}];return new K(e,g)}},bt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...y)=>t.sessionOutput(...y),s=(...y)=>t.sessionCost(...y),r=(...y)=>t.sessionCompleted(...y),i=(...y)=>t.containerStatus(...y),a=(...y)=>t.slaveCapacityUpdate(...y),c=(...y)=>t.previewBuildStatus(...y),l=(...y)=>t.previewReload(...y),g=(...y)=>t.questionsReceived(...y),u=(...y)=>t.specificationUpdated(...y),p=(...y)=>t.singleQuestionReceived(...y),f=(...y)=>t.questionSessionEnded(...y),k=(...y)=>t.creditsUpdated(...y),E=(...y)=>t.insufficientCredits(...y),x=(...y)=>t.projectSessionStatusChanged(...y),w=(...y)=>t.claudeLoginUrlReceived(...y),m=(...y)=>t.claudeLoginCompleted(...y);e.on("SessionOutput",o),e.on("SessionCost",s),e.on("SessionCompleted",r),e.on("ContainerStatus",i),e.on("SlaveCapacityUpdate",a),e.on("PreviewBuildStatus",c),e.on("PreviewReload",l),e.on("QuestionsReceived",g),e.on("SpecificationUpdated",u),e.on("SingleQuestionReceived",p),e.on("QuestionSessionEnded",f),e.on("CreditsUpdated",k),e.on("InsufficientCredits",E),e.on("ProjectSessionStatusChanged",x),e.on("ClaudeLoginUrlReceived",w),e.on("ClaudeLoginCompleted",m);let j=[{methodName:"SessionOutput",method:o},{methodName:"SessionCost",method:s},{methodName:"SessionCompleted",method:r},{methodName:"ContainerStatus",method:i},{methodName:"SlaveCapacityUpdate",method:a},{methodName:"PreviewBuildStatus",method:c},{methodName:"PreviewReload",method:l},{methodName:"QuestionsReceived",method:g},{methodName:"SpecificationUpdated",method:u},{methodName:"SingleQuestionReceived",method:p},{methodName:"QuestionSessionEnded",method:f},{methodName:"CreditsUpdated",method:k},{methodName:"InsufficientCredits",method:E},{methodName:"ProjectSessionStatusChanged",method:x},{methodName:"ClaudeLoginUrlReceived",method:w},{methodName:"ClaudeLoginCompleted",method:m}];return new K(e,j)}},St=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...w)=>t.startContainer(...w),s=(...w)=>t.terminateContainer(...w),r=()=>t.reconnect(),i=(...w)=>t.getContainerLogs(...w),a=()=>t.getDockerContainers(),c=(...w)=>t.streamContainerLogs(...w),l=(...w)=>t.stopContainerLogStream(...w),g=(...w)=>t.restartLabAgent(...w),u=(...w)=>t.terminateDockerContainer(...w),p=(...w)=>t.streamSlaveAgentLogs(...w),f=()=>t.stopSlaveAgentLogStream(),k=(...w)=>t.startClaudeLogin(...w),E=(...w)=>t.submitClaudeLoginCode(...w);e.on("StartContainer",o),e.on("TerminateContainer",s),e.on("Reconnect",r),e.on("GetContainerLogs",i),e.on("GetDockerContainers",a),e.on("StreamContainerLogs",c),e.on("StopContainerLogStream",l),e.on("RestartLabAgent",g),e.on("TerminateDockerContainer",u),e.on("StreamSlaveAgentLogs",p),e.on("StopSlaveAgentLogStream",f),e.on("StartClaudeLogin",k),e.on("SubmitClaudeLoginCode",E);let x=[{methodName:"StartContainer",method:o},{methodName:"TerminateContainer",method:s},{methodName:"Reconnect",method:r},{methodName:"GetContainerLogs",method:i},{methodName:"GetDockerContainers",method:a},{methodName:"StreamContainerLogs",method:c},{methodName:"StopContainerLogStream",method:l},{methodName:"RestartLabAgent",method:g},{methodName:"TerminateDockerContainer",method:u},{methodName:"StreamSlaveAgentLogs",method:p},{methodName:"StopSlaveAgentLogStream",method:f},{methodName:"StartClaudeLogin",method:k},{methodName:"SubmitClaudeLoginCode",method:E}];return new K(e,x)}},wt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...p)=>t.dockerContainersUpdated(...p),s=(...p)=>t.containerLogReceived(...p),r=(...p)=>t.agentRestartCompleted(...p),i=(...p)=>t.containerTerminationCompleted(...p),a=(...p)=>t.slaveCapacityUpdated(...p),c=(...p)=>t.slaveAgentLogReceived(...p),l=(...p)=>t.claudeLoginUrlReceived(...p),g=(...p)=>t.claudeLoginCompleted(...p);e.on("DockerContainersUpdated",o),e.on("ContainerLogReceived",s),e.on("AgentRestartCompleted",r),e.on("ContainerTerminationCompleted",i),e.on("SlaveCapacityUpdated",a),e.on("SlaveAgentLogReceived",c),e.on("ClaudeLoginUrlReceived",l),e.on("ClaudeLoginCompleted",g);let u=[{methodName:"DockerContainersUpdated",method:o},{methodName:"ContainerLogReceived",method:s},{methodName:"AgentRestartCompleted",method:r},{methodName:"ContainerTerminationCompleted",method:i},{methodName:"SlaveCapacityUpdated",method:a},{methodName:"SlaveAgentLogReceived",method:c},{methodName:"ClaudeLoginUrlReceived",method:l},{methodName:"ClaudeLoginCompleted",method:g}];return new K(e,u)}},vt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...l)=>t.testRunCreated(...l),s=(...l)=>t.testRunUpdated(...l),r=(...l)=>t.testSuiteCreated(...l),i=(...l)=>t.testCreated(...l),a=(...l)=>t.testUpdated(...l);e.on("TestRunCreated",o),e.on("TestRunUpdated",s),e.on("TestSuiteCreated",r),e.on("TestCreated",i),e.on("TestUpdated",a);let c=[{methodName:"TestRunCreated",method:o},{methodName:"TestRunUpdated",method:s},{methodName:"TestSuiteCreated",method:r},{methodName:"TestCreated",method:i},{methodName:"TestUpdated",method:a}];return new K(e,c)}};var Hn=$n(Fn),Fe=class{constructor(e){this.config=e;let t={"X-Container-Id":e.containerId,"X-Project-Key":e.projectKey};e.isByok&&(t["X-Is-Byok"]="true"),this.connection=new oe.HubConnectionBuilder().withUrl(`${e.masterUrl}/api/hubs/agent`,{headers:t}).withAutomaticReconnect({nextRetryDelayInMilliseconds:o=>{let s=o.previousRetryCount+1,r=Math.min(1e3*Math.pow(2,o.previousRetryCount),6e4);return console.log(`[SignalR] Reconnect attempt ${s} (will retry in ${r}ms)`),r}}).withServerTimeout(3e5).withKeepAliveInterval(1e4).configureLogging(oe.LogLevel.Information).build(),this.hubProxy=qt("IAgentHub").createHubProxy(this.connection),this.connection.onreconnecting(o=>{console.warn("[SignalR] Connection lost, attempting to reconnect...",o?.message)}),this.connection.onreconnected(async o=>{console.log("[SignalR] Reconnected to gateway (connectionId:",o,")");try{await this.hubProxy.registerAgent(this.config.containerId),console.log(`[SignalR] Re-registered as agent for container: ${this.config.containerId}`),await this.reportStatus(this.currentStatus,void 0,this.currentSessionId??void 0,this.currentProjectId??void 0)}catch(s){console.error("[SignalR] Failed to re-register agent after reconnect:",s instanceof Error?s.message:s)}}),this.connection.onclose(o=>{console.error("[SignalR] Connection closed:",o?.message),console.error("[SignalR] Connection state at close:",this.connection.state),process.exit(1)})}connection;hubProxy;receiverSubscription=null;currentStatus="WarmingUp";currentSessionId=null;currentProjectId=null;tunnelUrl=null;tokenRefreshInterval=null;currentRepoFullName=null;heartbeatInterval=null;async connect(){console.log(`[SignalR] Connecting to gateway: ${this.config.masterUrl}/api/hubs/agent`),this.config.isByok&&console.log("[SignalR] BYOK mode enabled - credits will not be deducted"),await this.connection.start();let e=this.connection.connection?.transport;console.log("[SignalR] Connected to gateway!"),console.log(`[SignalR] Transport: ${e?.constructor?.name||"unknown"}`),console.log(`[SignalR] Connection ID: ${this.connection.connectionId}`),await this.hubProxy.registerAgent(this.config.containerId),console.log(`[SignalR] Registered as agent for container: ${this.config.containerId}`)}registerReceiver(e){this.receiverSubscription&&this.receiverSubscription.dispose(),this.receiverSubscription=Yt("IAgentReceiver").register(this.connection,e)}getHubProxy(){return this.hubProxy}getMasterUrl(){return this.config.masterUrl}getProjectKey(){return this.config.projectKey}getConnection(){return this.connection}setTunnelUrl(e){this.tunnelUrl=e}async reportStatus(e,t,o,s){if(this.currentStatus=e,o&&(this.currentSessionId=o),s&&(this.currentProjectId=s),this.connection.state===oe.HubConnectionState.Connected)try{let r={status:e,error:t,sessionId:o,projectId:s,tunnelUrl:this.tunnelUrl??void 0};await this.hubProxy.reportStatus(this.config.containerId,r),console.log(`[Status] ${e}${t?` (${t})`:""}${this.tunnelUrl?` [${this.tunnelUrl}]`:""}${o?` [session: ${o}]`:""}`)}catch(r){console.error("[SignalR] Failed to report status:",r)}}async getSecrets(){let e=await this.hubProxy.getSecrets();if(!e.success)throw new Error(`Failed to get secrets: ${e.error}`);return e.secrets||{}}startHeartbeat(e=3e4){this.heartbeatInterval||(this.heartbeatInterval=setInterval(async()=>{if(this.connection.state===oe.HubConnectionState.Connected)try{await this.hubProxy.reportStatus(this.config.containerId,{status:this.currentStatus,sessionId:this.currentSessionId??void 0,projectId:this.currentProjectId??void 0,tunnelUrl:this.tunnelUrl??void 0})}catch(t){console.error("[Heartbeat] Failed:",t instanceof Error?t.message:t)}},e),console.log(`[Heartbeat] Started (every ${e/1e3}s)`))}stopHeartbeat(){this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null,console.log("[Heartbeat] Stopped"))}async startTokenRefresh(){await this.refreshGitHubToken(),this.tokenRefreshInterval=setInterval(async()=>{await this.refreshGitHubToken()},3e6),console.log("[TokenRefresh] Started (refreshing every 50 minutes)")}stopTokenRefresh(){this.tokenRefreshInterval&&(clearInterval(this.tokenRefreshInterval),this.tokenRefreshInterval=null,console.log("[TokenRefresh] Stopped"))}async refreshGitHubToken(){console.log(`[TokenRefresh] Requesting new token from backend... (${new Date().toISOString()})`);try{let e=await this.hubProxy.refreshGitHubToken();if(!e.success){console.error(`[TokenRefresh] \u274C Backend returned failure: ${e.error}`);return}if(!e.token){console.error("[TokenRefresh] \u274C No token in response (success=true but token is empty)");return}let t=e.token.substring(0,8)+"...";if(console.log(`[TokenRefresh] Got token (prefix: ${t}), updating git credentials...`),await this.updateGitCredentials(e.token,e.repoFullName??void 0),e.expiresAt){let o=new Date(e.expiresAt).toISOString(),s=Math.round((new Date(e.expiresAt).getTime()-Date.now())/6e4);console.log(`[TokenRefresh] \u2713 Refreshed (prefix: ${t}, expires: ${o}, ~${s}min left)${e.repoFullName?` (repo: ${e.repoFullName})`:""}`)}else console.log("[TokenRefresh] \u2713 Refreshed (PAT mode, no expiry)");this.currentRepoFullName=e.repoFullName??null}catch(e){console.error("[TokenRefresh] \u274C Exception:",e instanceof Error?e.message:e)}}async reportError(e){if(this.connection.state!==oe.HubConnectionState.Connected){console.error("[SignalR] Cannot report error - not connected");return}try{let t={message:e.message,stackTrace:e.stackTrace,errorType:e.errorType,operation:e.operation,sessionId:e.sessionId??this.currentSessionId??void 0,isFatal:e.isFatal??!1},o=await this.hubProxy.reportError(this.config.containerId,t);o.success?console.log(`[Error Report] Reported: ${e.errorType??"Error"} - ${e.message}`):console.error(`[Error Report] Failed to report: ${o.error}`)}catch(t){console.error("[SignalR] Failed to report error:",t instanceof Error?t.message:t)}}async updateGitCredentials(e,t){let o=Qt.join(Jt.homedir(),".git-credentials"),s=`https://x-access-token:${e}@github.com
1360
1360
  `;if(await zt.promises.writeFile(o,s,{mode:384}),t)try{let r=`https://x-access-token:${e}@github.com/${t}.git`;await Hn(`git remote set-url origin "${r}"`,{cwd:"/workspace"})}catch(r){console.error("[TokenRefresh] Could not update remote URL:",r instanceof Error?r.message:r)}}};function Bn(n){let e=n.match(/name:\s*"([^"]+)"/);if(e)return e[1];let t=n.match(/^#\s+(.+)$/m);return t?t[1].trim():"Untitled Specification"}var $e=class{constructor(e,t){this.hubProxy=e;this.projectId=t}async saveSpecification(e,t){let o=Bn(t),s=await this.hubProxy.saveSpecification(this.projectId,e,o,t);if(!s.success)throw new Error(s.error||"Failed to save specification")}async getSpecification(e){let t=await this.hubProxy.getSpecification(this.projectId,e);return t.success&&t.content||null}async listSpecifications(){let e=await this.hubProxy.listSpecifications(this.projectId);return!e.success||!e.specifications?[]:e.specifications.map(t=>({slug:t.slug,name:t.name,status:t.status,version:"1.0.0"}))}async deleteSpecification(e){return(await this.hubProxy.deleteSpecification(this.projectId,e)).success}async specificationExists(e){let t=await this.hubProxy.getSpecification(this.projectId,e);return t.success&&t.content!=null}};import{exec as Wn,execSync as Gn,spawn as Kn}from"child_process";import{promisify as qn}from"util";import{createHash as Vt}from"crypto";import*as _ from"fs";import*as F from"path";var He=class{domain;accountId;tunnelId;apiToken;zoneId;tunnelApiBase;constructor(){this.domain=process.env.CLOUDFLARE_DEPLOY_DOMAIN||process.env.DEPLOY_DOMAIN||"vibecodementor.net",this.accountId=process.env.CLOUDFLARE_ACCOUNT_ID||"",this.tunnelId=process.env.CLOUDFLARE_TUNNEL_ID||"",this.apiToken=process.env.CLOUDFLARE_API_TOKEN||"",this.zoneId=process.env.CLOUDFLARE_ZONE_ID||"",this.tunnelApiBase=`https://api.cloudflare.com/client/v4/accounts/${this.accountId}/cfd_tunnel/${this.tunnelId}/configurations`}isConfigured(){return!!(this.accountId&&this.tunnelId&&this.apiToken&&this.zoneId)}buildHostname(e){let t=this.domain.split("."),o=t.length>2?t.slice(-2).join("."):this.domain;return`${e}.${o}`}async addRoute(e,t){let o=this.buildHostname(e);if(console.log(`[TunnelManager] Adding route: ${o} -> localhost:${t}`),!this.isConfigured())return console.log("[TunnelManager] Not configured, skipping route addition"),`https://${o}`;try{let s=await this.getConfig(),r=s.ingress.findIndex(a=>a.hostname===o);if(r!==-1)s.ingress[r].service=`http://localhost:${t}`;else{let a=s.ingress.findIndex(l=>!l.hostname),c={hostname:o,service:`http://localhost:${t}`};a!==-1?s.ingress.splice(a,0,c):(s.ingress.push(c),s.ingress.push({service:"http_status:404"}))}await this.putConfig(s),await this.ensureDnsPointsToTunnel(o);let i=`https://${o}`;return console.log(`[TunnelManager] \u2713 Route added: ${i}`),i}catch(s){throw console.error("[TunnelManager] Failed to add route:",s),s}}async removeRoute(e){let t=this.buildHostname(e);if(console.log(`[TunnelManager] Removing route: ${t}`),!this.isConfigured()){console.log("[TunnelManager] Not configured, skipping route removal");return}try{let o=await this.getConfig();o.ingress=o.ingress.filter(s=>s.hostname!==t),o.ingress.some(s=>!s.hostname)||o.ingress.push({service:"http_status:404"}),await this.putConfig(o),console.log(`[TunnelManager] \u2713 Route removed: ${t}`)}catch(o){throw console.error("[TunnelManager] Failed to remove route:",o),o}}async getConfig(){let t=await(await fetch(this.tunnelApiBase,{method:"GET",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"}})).json();if(!t.success)throw new Error(`Cloudflare API error: ${t.errors.map(o=>o.message).join(", ")}`);return t.result?.config||{ingress:[{service:"http_status:404"}]}}async putConfig(e){let o=await(await fetch(this.tunnelApiBase,{method:"PUT",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"},body:JSON.stringify({config:e})})).json();if(!o.success)throw new Error(`Cloudflare API error: ${o.errors.map(s=>s.message).join(", ")}`);console.log("[TunnelManager] Configuration updated via Cloudflare API")}async ensureDnsPointsToTunnel(e){let t=`${this.tunnelId}.cfargotunnel.com`,o=`https://api.cloudflare.com/client/v4/zones/${this.zoneId}/dns_records`;try{let r=await(await fetch(`${o}?name=${e}&type=CNAME`,{method:"GET",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"}})).json();if(r.success&&r.result?.length){let i=r.result[0];if(i.content===t){console.log(`[TunnelManager] DNS already points to correct tunnel: ${e}`);return}console.log(`[TunnelManager] Updating DNS: ${e} from ${i.content} to ${t}`);let c=await(await fetch(`${o}/${i.id}`,{method:"PATCH",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"},body:JSON.stringify({type:"CNAME",name:e,content:t,proxied:!0})})).json();c.success?console.log(`[TunnelManager] \u2713 DNS updated: ${e} -> ${t}`):console.error(`[TunnelManager] Failed to update DNS: ${c.errors.map(l=>l.message).join(", ")}`)}else{console.log(`[TunnelManager] Creating DNS record: ${e} -> ${t}`);let a=await(await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${this.apiToken}`,"Content-Type":"application/json"},body:JSON.stringify({type:"CNAME",name:e,content:t,proxied:!0})})).json();a.success?console.log(`[TunnelManager] \u2713 DNS record created: ${e} -> ${t}`):console.error(`[TunnelManager] Failed to create DNS: ${a.errors.map(c=>c.message).join(", ")}`)}}catch(s){console.error(`[TunnelManager] Error updating DNS for ${e}:`,s)}}};var kt=qn(Wn),A=class{start;label;constructor(e){this.label=e,this.start=Date.now(),console.log(`[TIMING] \u23F1 START: ${e}`)}stop(){let e=Date.now()-this.start,t=(e/1e3).toFixed(2);return console.log(`[TIMING] \u2713 DONE: ${this.label} (${t}s)`),e}};function M(n,e={}){return new Promise((t,o)=>{let s=Kn(n,[],{shell:!0,stdio:"inherit",cwd:e.cwd}),r=null;e.timeout&&(r=setTimeout(()=>{s.kill(),o(new Error(`Command timed out: ${n}`))},e.timeout)),s.on("close",i=>{r&&clearTimeout(r),i===0?t():o(new Error(`Command failed with code ${i}: ${n}`))}),s.on("error",i=>{r&&clearTimeout(r),o(i)})})}var Xt="main",Be=class{constructor(e,t,o,s){this.connection=e;this.serviceManager=t;this.workspaceDir=o;this.gitHubPat=s}currentBranchName=Xt;currentRepoUrl="";lastLockfileHash=null;tunnelManager=null;currentPreviewSubdomain=null;getTunnelManager(){return this.tunnelManager||(this.tunnelManager=new He),this.tunnelManager}async prewarmWorkspace(){let e=new A("TOTAL INIT"),t=process.env.REPO_URL,o=process.env.BRANCH_NAME||Xt,s=process.env.PREVIEW_SUBDOMAIN,r=process.env.PREVIEW_HOSTNAME,i=process.env.PROJECT_GITHUB_PAT,a=t?.includes("x-access-token:")??!1,c=a?t?.match(/x-access-token:([^@]{0,8})/)?.[1]+"...":"PAT";if(console.log("[Init] === Single-Phase Init Starting ==="),console.log(`[Init] Repo: ${t?this.extractRepoPath(t):"NOT SET"}`),console.log(`[Init] Branch: ${o}`),console.log(`[Init] Auth method: ${a?"GitHub App token":"PAT"} (prefix: ${c})`),console.log(`[Init] Preview: ${s||"none"}`),console.log(`[Init] Container ID: ${process.env.CONTAINER_ID||"unknown"}`),console.log(`[Init] Session ID: ${process.env.SESSION_ID||"none"}`),console.log(`[Init] Timestamp: ${new Date().toISOString()}`),!t)throw console.error("[Init] \u274C REPO_URL not set - cannot initialize workspace"),new Error("REPO_URL environment variable is required");i&&(this.gitHubPat=i);let l=new A("Clean workspace");Gn("rm -rf /workspace/* /workspace/.* 2>/dev/null || true",{stdio:"inherit"}),l.stop();let g=new A("Clone repository");await this.cloneRepository(t,o),this.currentRepoUrl=t,this.currentBranchName=o,g.stop(),await this.installDependencies(),this.lastLockfileHash=this.getLockfileHash(),console.log("[Init] Starting services...");let u=new A("Start backend (dotnet)");await this.serviceManager.startBackend(),u.stop();let p=new A("Start frontend (vite)");await this.serviceManager.startFrontend(),p.stop();let f=new A("Wait for health check");await this.serviceManager.waitForHealth(3e4),f.stop(),s&&r&&await this.setupPreviewSubdomainFromEnv(s,r),await this.connection.startTokenRefresh(),e.stop(),console.log("[Init] \u2713 Workspace ready")}async handleInitSession(e){console.log(`[InitSession] Session ${e.sessionId} starting...`);let t=this.extractRepoPath(e.repoUrl),o=this.extractRepoPath(this.currentRepoUrl),s=t!==o,r=e.branchName!==this.currentBranchName;s||r?(console.log("[InitSession] Repo/branch mismatch - updating workspace..."),console.log(`[InitSession] Current: ${o}@${this.currentBranchName}`),console.log(`[InitSession] Requested: ${t}@${e.branchName}`),await this.connection.reportStatus("Ready",void 0,e.sessionId,e.projectId),await this.connection.getHubProxy().initSessionCompleted(process.env.CONTAINER_ID||"unknown",e.sessionId,!0,""),this.handleRepoChange(e).catch(async a=>{let c=a instanceof Error?a.message:"Unknown error";console.error("[InitSession] Background update failed:",c),await this.connection.reportStatus("Error",c,e.sessionId,e.projectId)})):(console.log("[InitSession] Workspace already matches - ready immediately"),await this.connection.reportStatus("Ready",void 0,e.sessionId,e.projectId),await this.connection.getHubProxy().initSessionCompleted(process.env.CONTAINER_ID||"unknown",e.sessionId,!0,"")),console.log(`[InitSession] \u2713 Ready for session ${e.sessionId}`)}async setupPreviewSubdomainFromEnv(e,t){let o=new A("Setup preview subdomain");console.log(`[Preview] Setting up preview subdomain: ${e} (${t})`);let s=this.getTunnelManager();if(!s){console.log("[Preview] TunnelManager not available, skipping subdomain setup"),o.stop();return}if(!s.isConfigured()){console.log("[Preview] Cloudflare not configured, skipping subdomain setup"),o.stop();return}try{let r=parseInt(process.env.ALLOCATED_HOST_PORT||"5173"),i=await s.addRoute(e,r);this.currentPreviewSubdomain=e,this.connection.setTunnelUrl(i),o.stop(),console.log(`[Preview] \u2713 Preview subdomain configured: ${i}`)}catch(r){o.stop(),console.error("[Preview] Failed to set up subdomain route:",r)}}async handleRepoChange(e){let t=new A("TOTAL REPO CHANGE");e.gitHubPat&&e.gitHubPat!==this.gitHubPat&&(console.log("[RepoChange] Updating git credentials"),this.gitHubPat=e.gitHubPat,await M(`echo "https://${e.gitHubPat}@github.com" > ~/.git-credentials`));let o=this.extractRepoPath(e.repoUrl),s=this.extractRepoPath(this.currentRepoUrl);if(o!==s){let i=new A("Clone new repository");await this.cloneRepository(e.repoUrl,e.branchName),this.currentRepoUrl=e.repoUrl,this.currentBranchName=e.branchName,i.stop(),await this.installDependencies();let a=new A("Restart services");await this.serviceManager.restartServices("both"),a.stop()}else{let i=new A(`Switch branch to ${e.branchName}`);await this.switchBranch(e.branchName),i.stop(),await this.checkNeedsReinstall()&&await this.installDependencies();let c=new A("Restart services");await this.serviceManager.restartServices("both"),c.stop()}e.previewSubdomain&&e.previewHostname&&await this.setupPreviewSubdomainFromEnv(e.previewSubdomain,e.previewHostname),t.stop(),console.log("[RepoChange] \u2713 Workspace updated")}extractRepoPath(e){let t=e.match(/github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/);return t?t[1]:e}async cloneRepository(e,t){let o=this.extractRepoPath(e),s=e.includes("x-access-token:"),r=s?e.match(/x-access-token:([^@]{0,8})/)?.[1]+"...":"PAT";console.log("[Clone] === Git Clone Start ==="),console.log(`[Clone] Repo: ${o}`),console.log(`[Clone] Branch: ${t}`),console.log(`[Clone] Auth: ${s?"GitHub App token":"PAT"} (prefix: ${r})`),console.log(`[Clone] Timestamp: ${new Date().toISOString()}`);let i=6,a=[0,3e3,5e3,8e3,12e3,15e3];for(let c=1;c<=i;c++){await M("rm -rf /workspace/* /workspace/.* 2>/dev/null || true");try{console.log(`[Clone] Attempt ${c}/${i}...`);let l=Date.now();await M(`git clone -b ${t} "${e}" /workspace`,{timeout:12e4});let g=((Date.now()-l)/1e3).toFixed(2);console.log(`[Clone] \u2713 Clone succeeded on attempt ${c} (${g}s)`),await M('cd /workspace && git config user.email "agent@dotnetmentor.se" && git config user.name "Agent"'),console.log("[Clone] \u2713 Repository cloned and configured");return}catch(l){let g=l instanceof Error?l.message:String(l);console.error(`[Clone] \u274C Attempt ${c}/${i} failed: ${g}`);let u=0;try{let{stdout:p}=await kt(`git ls-remote --heads "${e}" 2>&1`,{timeout:15e3}),f=p.trim();u=f?f.split(`
1361
1361
  `).length:0,console.log(`[Clone] ls-remote: ${u} branch(es) found${f?`: ${f.split(`
1362
1362
  `).slice(0,3).join(", ")}`:" (empty repo \u2014 likely still generating from template)"}`)}catch(p){let f=p instanceof Error?p.message:String(p);console.error(`[Clone] ls-remote also failed: ${f}`)}if(c<i){let p=a[c]||15e3,f=u===0?"repo appears empty (template still generating)":`branch '${t}' not found`;console.log(`[Clone] Retrying in ${p/1e3}s... (${f})`),await new Promise(k=>setTimeout(k,p))}else throw console.error(`[Clone] \u274C All ${i} attempts failed for ${o}`),await this.connection.reportError({message:`Git clone failed after ${i} attempts: ${g}`,errorType:"GitCloneError",operation:"cloneRepository",isFatal:!0}),l}}}async switchBranch(e){if(console.log(`[Branch] Switching from ${this.currentBranchName} to ${e}`),e===this.currentBranchName)console.log(`[Branch] Already on ${e}, pulling latest...`),await M(`git pull origin ${e}`,{cwd:this.workspaceDir,timeout:6e4});else{await M("git fetch origin",{cwd:this.workspaceDir,timeout:6e4});let{stdout:t}=await kt(`git ls-remote --heads origin ${e}`,{cwd:this.workspaceDir,timeout:3e4});t.trim().length>0?await M(`git checkout -B ${e} origin/${e}`,{cwd:this.workspaceDir,timeout:3e4}):(console.log(`[Branch] Branch ${e} doesn't exist on remote, creating from main...`),await M(`git checkout -b ${e}`,{cwd:this.workspaceDir,timeout:3e4})),this.currentBranchName=e}console.log(`[Branch] \u2713 Now on ${e}`)}getLockfileHash(){let e=F.join(this.workspaceDir,"packages/backoffice-web/package-lock.json");return _.existsSync(e)?Vt("sha256").update(_.readFileSync(e)).digest("hex"):null}async checkNeedsReinstall(){let e=this.getLockfileHash();return!e||!this.lastLockfileHash?!0:e!==this.lastLockfileHash}async checkCodeDiff(e,t){if(e===t)return!1;try{let{stdout:o}=await kt(`git diff ${e}..HEAD --name-only`,{cwd:this.workspaceDir,timeout:3e4}),s=o.trim();if(!s)return console.log(`[CodeDiff] No file differences between ${e} and ${t}`),!1;let r=s.split(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glenn-code",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
4
4
  "description": "Glenn Code - Connect your local development environment to DNM Lab",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -47,7 +47,7 @@
47
47
  "typescript": "^5.6.0"
48
48
  },
49
49
  "dependencies": {
50
- "@anthropic-ai/claude-agent-sdk": "0.2.44",
50
+ "@anthropic-ai/claude-agent-sdk": "0.2.72",
51
51
  "@microsoft/signalr": "^8.0.7",
52
52
  "@modelcontextprotocol/sdk": "^1.26.0",
53
53
  "inquirer": "^13.1.0",