glenn-code 1.0.35 → 1.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Glenn Code - Bundled and minified
2
2
  // (c) DNM Lab - All rights reserved
3
3
 
4
- import G from"inquirer";import*as M from"fs";import*as Q from"path";import*as dn from"os";import{fileURLToPath as Qn}from"url";import{createSdkMcpServer as fn}from"@anthropic-ai/claude-agent-sdk";import{tool as be}from"@anthropic-ai/claude-agent-sdk";import{z as ye}from"zod";import*as Se from"fs";import*as Et from"path";var Y=null;function pe(n){Y=n}function Ye(n){return n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}var lo=be("save_specification",`Save a specification to the database.
4
+ import Y from"inquirer";import*as M from"fs";import*as X from"path";import*as dn from"os";import{fileURLToPath as Qn}from"url";import{createSdkMcpServer as fn}from"@anthropic-ai/claude-agent-sdk";import{tool as we}from"@anthropic-ai/claude-agent-sdk";import{z as Se}from"zod";import*as ve from"fs";import*as Et from"path";var J=null;function de(n){J=n}function ze(n){return n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}var lo=we("save_specification",`Save a specification to the database.
5
5
 
6
6
  IMPORTANT: First write the specification content to a file using the Write tool, then call this with the file path.
7
7
 
@@ -12,17 +12,17 @@ Workflow:
12
12
 
13
13
  Example:
14
14
  1. Write tool \u2192 save to /tmp/user-auth-spec.md
15
- 2. save_specification(name: "User Authentication", filePath: "/tmp/user-auth-spec.md")`,{name:ye.string().describe("Specification name (e.g., 'User Authentication')"),filePath:ye.string().describe("Path to the file containing the specification content (written via Write tool)")},async n=>{if(!Y)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let e=Et.resolve(n.filePath);if(!Se.existsSync(e))return{content:[{type:"text",text:`\u274C File not found: ${n.filePath}. Use Write tool first to create the file.`}]};let t=Se.readFileSync(e,"utf-8"),o=Ye(n.name);return await Y.saveSpecification(o,t),{content:[{type:"text",text:`\u2705 Saved specification: ${o}.spec.md`}]}}),po=be("read_specification","Read the content of a specification.",{name:ye.string().describe("Name of the specification to read")},async n=>{if(!Y)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let e=Ye(n.name),t=await Y.getSpecification(e);return t?{content:[{type:"text",text:t}]}:{content:[{type:"text",text:`\u274C Specification "${n.name}" not found.`}]}}),uo=be("list_specifications","List all specifications.",{},async()=>{if(!Y)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let n=await Y.listSpecifications();return n.length===0?{content:[{type:"text",text:"\u{1F4CB} No specifications found."}]}:{content:[{type:"text",text:`\u{1F4CB} Specifications:
15
+ 2. save_specification(name: "User Authentication", filePath: "/tmp/user-auth-spec.md")`,{name:Se.string().describe("Specification name (e.g., 'User Authentication')"),filePath:Se.string().describe("Path to the file containing the specification content (written via Write tool)")},async n=>{if(!J)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let e=Et.resolve(n.filePath);if(!ve.existsSync(e))return{content:[{type:"text",text:`\u274C File not found: ${n.filePath}. Use Write tool first to create the file.`}]};let t=ve.readFileSync(e,"utf-8"),o=ze(n.name);return await J.saveSpecification(o,t),{content:[{type:"text",text:`\u2705 Saved specification: ${o}.spec.md`}]}}),po=we("read_specification","Read the content of a specification.",{name:Se.string().describe("Name of the specification to read")},async n=>{if(!J)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let e=ze(n.name),t=await J.getSpecification(e);return t?{content:[{type:"text",text:t}]}:{content:[{type:"text",text:`\u274C Specification "${n.name}" not found.`}]}}),uo=we("list_specifications","List all specifications.",{},async()=>{if(!J)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let n=await J.listSpecifications();return n.length===0?{content:[{type:"text",text:"\u{1F4CB} No specifications found."}]}:{content:[{type:"text",text:`\u{1F4CB} Specifications:
16
16
 
17
17
  ${n.map(t=>`- ${t.name} (${t.slug}.spec.md)`).join(`
18
- `)}`}]}}),go=be("delete_specification","Delete a specification.",{name:ye.string().describe("Name of the specification to delete")},async n=>{if(!Y)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let e=Ye(n.name);return await Y.deleteSpecification(e)?{content:[{type:"text",text:`\u{1F5D1}\uFE0F Deleted: ${e}.spec.md`}]}:{content:[{type:"text",text:`\u274C Specification "${n.name}" not found.`}]}});import{tool as ee}from"@anthropic-ai/claude-agent-sdk";import{z as ae}from"zod";var T=null;function we(n){T=n}var At=ee("restart_services",`Rebuild and restart services. Call this after making backend changes (.cs files) to apply them.
18
+ `)}`}]}}),go=we("delete_specification","Delete a specification.",{name:Se.string().describe("Name of the specification to delete")},async n=>{if(!J)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let e=ze(n.name);return await J.deleteSpecification(e)?{content:[{type:"text",text:`\u{1F5D1}\uFE0F Deleted: ${e}.spec.md`}]}:{content:[{type:"text",text:`\u274C Specification "${n.name}" not found.`}]}});import{tool as ee}from"@anthropic-ai/claude-agent-sdk";import{z as ce}from"zod";var T=null;function ke(n){T=n}var At=ee("restart_services",`Rebuild and restart services. Call this after making backend changes (.cs files) to apply them.
19
19
 
20
20
  Parameters:
21
21
  - target: "backend" (default) | "frontend" | "both"
22
22
 
23
23
  Use target="backend" after .cs file changes (faster, only restarts .NET).
24
24
  Use target="frontend" if Vite is stuck (rare, HMR usually works).
25
- Use target="both" if unsure or both need restart.`,{target:ae.enum(["backend","frontend","both"]).default("backend").describe("Which service to restart")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=n.target||"backend";console.log(`[MCP] restart_services called (target: ${e})`);let t=await T.restartServices(e);if(!t.success){let s=[];return t.backendError&&s.push(`Backend: ${t.backendError}`),t.frontendError&&s.push(`Frontend: ${t.frontendError}`),{content:[{type:"text",text:`\u274C Restart failed:
25
+ Use target="both" if unsure or both need restart.`,{target:ce.enum(["backend","frontend","both"]).default("backend").describe("Which service to restart")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=n.target||"backend";console.log(`[MCP] restart_services called (target: ${e})`);let t=await T.restartServices(e);if(!t.success){let s=[];return t.backendError&&s.push(`Backend: ${t.backendError}`),t.frontendError&&s.push(`Frontend: ${t.frontendError}`),{content:[{type:"text",text:`\u274C Restart failed:
26
26
  ${s.join(`
27
27
 
28
28
  `)}`}]}}return{content:[{type:"text",text:`\u2705 ${e==="both"?"Backend and frontend":e==="backend"?"Backend":"Frontend"} restarted successfully.`}]}}),xt=ee("stop_services",`Stop running services. Call this BEFORE running scaffold to prevent port conflicts and ensure clean migrations.
@@ -30,12 +30,12 @@ ${s.join(`
30
30
  Parameters:
31
31
  - target: "backend" (default) | "frontend" | "both"
32
32
 
33
- Use target="backend" before running scaffold (required for migrations).`,{target:ae.enum(["backend","frontend","both"]).default("backend").describe("Which service to stop")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=n.target||"backend";console.log(`[MCP] stop_services called (target: ${e})`);let t=e==="backend"||e==="both",o=e==="frontend"||e==="both";t&&await T.stopBackend(),o&&await T.stopFrontend();let s=5e3,r=Date.now(),i=!t,a=!o;for(;Date.now()-r<s;){let u=await T.checkHealth();if(t&&!u.api&&(i=!0),o&&!u.web&&(a=!0),i&&a)break;await new Promise(d=>setTimeout(d,500))}let c=e==="both"?"Backend and frontend":e==="backend"?"Backend":"Frontend";return{content:[{type:"text",text:i&&a?`\u2705 ${c} stopped successfully.`:`\u26A0\uFE0F ${c} stop requested but health check still shows running. Proceeding anyway.`}]}}),Dt=ee("start_services",`Start services. Call this AFTER running scaffold to bring services back up.
33
+ Use target="backend" before running scaffold (required for migrations).`,{target:ce.enum(["backend","frontend","both"]).default("backend").describe("Which service to stop")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=n.target||"backend";console.log(`[MCP] stop_services called (target: ${e})`);let t=e==="backend"||e==="both",o=e==="frontend"||e==="both";t&&await T.stopBackend(),o&&await T.stopFrontend();let s=5e3,r=Date.now(),i=!t,a=!o;for(;Date.now()-r<s;){let u=await T.checkHealth();if(t&&!u.api&&(i=!0),o&&!u.web&&(a=!0),i&&a)break;await new Promise(d=>setTimeout(d,500))}let l=e==="both"?"Backend and frontend":e==="backend"?"Backend":"Frontend";return{content:[{type:"text",text:i&&a?`\u2705 ${l} stopped successfully.`:`\u26A0\uFE0F ${l} stop requested but health check still shows running. Proceeding anyway.`}]}}),Dt=ee("start_services",`Start services. Call this AFTER running scaffold to bring services back up.
34
34
 
35
35
  Parameters:
36
36
  - target: "backend" (default) | "frontend" | "both"
37
37
 
38
- Use target="backend" after running scaffold.`,{target:ae.enum(["backend","frontend","both"]).default("backend").describe("Which service to start")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=n.target||"backend";console.log(`[MCP] start_services called (target: ${e})`);let t=e==="backend"||e==="both",o=e==="frontend"||e==="both";t&&await T.startBackend(),o&&await T.startFrontend();let s=await T.waitForHealth(15e3),r=!t||s.api,i=!o||s.web,a=r&&i,c=e==="both"?"Backend and frontend":e==="backend"?"Backend":"Frontend";if(!a){let l=[];return t&&!s.api&&l.push("Backend failed to start"),o&&!s.web&&l.push("Frontend failed to start"),{content:[{type:"text",text:`\u274C ${c} failed to start: ${l.join(", ")}`}]}}return{content:[{type:"text",text:`\u2705 ${c} started successfully.`}]}}),jt=ee("check_service_health",`Check if services are running and healthy. Returns current status of backend API and frontend.
38
+ Use target="backend" after running scaffold.`,{target:ce.enum(["backend","frontend","both"]).default("backend").describe("Which service to start")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=n.target||"backend";console.log(`[MCP] start_services called (target: ${e})`);let t=e==="backend"||e==="both",o=e==="frontend"||e==="both";t&&await T.startBackend(),o&&await T.startFrontend();let s=await T.waitForHealth(15e3),r=!t||s.api,i=!o||s.web,a=r&&i,l=e==="both"?"Backend and frontend":e==="backend"?"Backend":"Frontend";if(!a){let c=[];return t&&!s.api&&c.push("Backend failed to start"),o&&!s.web&&c.push("Frontend failed to start"),{content:[{type:"text",text:`\u274C ${l} failed to start: ${c.join(", ")}`}]}}return{content:[{type:"text",text:`\u2705 ${l} started successfully.`}]}}),jt=ee("check_service_health",`Check if services are running and healthy. Returns current status of backend API and frontend.
39
39
  Note: This only checks if ports are responding, NOT build/type errors. Use check_backend_build or check_frontend_types for that.`,{},async()=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let n=await T.checkHealth();return{content:[{type:"text",text:`Service Health:
40
40
  \u{1F5A5}\uFE0F Backend API: ${n.api?"\u2705 running":"\u274C not running"}
41
41
  \u{1F310} Frontend: ${n.web?"\u2705 running":"\u274C not running"}`}]}}),Lt=ee("check_backend_build","Run dotnet build to check for C# compilation errors. Use this after fixing backend code to verify the fix works.",{},async()=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};console.log("[MCP] check_backend_build called");let n=await T.checkBackendBuild();return n.success?{content:[{type:"text",text:"\u2705 Backend build succeeded - no errors"}]}:{content:[{type:"text",text:`\u274C Backend build failed:
@@ -46,16 +46,16 @@ ${n.errors}`}]}}),yo=ee("tail_service_log",`Get the last N lines of service logs
46
46
 
47
47
  Parameters:
48
48
  - target: "backend" | "frontend"
49
- - lines: number (default 50)`,{target:ae.enum(["backend","frontend"]).describe("Which log to read"),lines:ae.number().default(50).describe("Number of lines to read")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=await T.tailLogs(n.target,n.lines);return{content:[{type:"text",text:`Last ${n.lines} lines of ${n.target} log:
49
+ - lines: number (default 50)`,{target:ce.enum(["backend","frontend"]).describe("Which log to read"),lines:ce.number().default(50).describe("Number of lines to read")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=await T.tailLogs(n.target,n.lines);return{content:[{type:"text",text:`Last ${n.lines} lines of ${n.target} log:
50
50
 
51
51
  ${e.join(`
52
52
  `)}`}]}}),bo=ee("check_swagger_endpoints",`Search for endpoints in the generated swagger.json. Use this to verify that new backend endpoints are correctly exposed.
53
53
 
54
54
  Parameters:
55
- - pattern: string (e.g., "users", "api/reports")`,{pattern:ae.string().describe("Text to search for in endpoint paths")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=await T.checkSwaggerEndpoints(n.pattern);return e.foundEndpoints.length===0?{content:[{type:"text",text:`\u274C No endpoints found matching "${n.pattern}" (Total endpoints: ${e.totalEndpoints})`}]}:{content:[{type:"text",text:`\u2705 Found ${e.foundEndpoints.length} matching endpoints:
55
+ - pattern: string (e.g., "users", "api/reports")`,{pattern:ce.string().describe("Text to search for in endpoint paths")},async n=>{if(!T)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=await T.checkSwaggerEndpoints(n.pattern);return e.foundEndpoints.length===0?{content:[{type:"text",text:`\u274C No endpoints found matching "${n.pattern}" (Total endpoints: ${e.totalEndpoints})`}]}:{content:[{type:"text",text:`\u2705 Found ${e.foundEndpoints.length} matching endpoints:
56
56
 
57
57
  ${e.foundEndpoints.join(`
58
- `)}`}]}});import*as de from"fs";import*as hn from"path";import*as j from"fs";import*as ve from"path";function ue(n){let e=ve.join(n,".sdd","specifications");function t(){j.existsSync(e)||j.mkdirSync(e,{recursive:!0})}function o(s){return ve.join(e,`${s}.spec.md`)}return{async saveSpecification(s,r){t(),j.writeFileSync(o(s),r,"utf-8")},async getSpecification(s){t();let r=o(s);return j.existsSync(r)?j.readFileSync(r,"utf-8"):null},async listSpecifications(){return t(),j.readdirSync(e).filter(r=>r.endsWith(".spec.md")).map(r=>{let i=j.readFileSync(ve.join(e,r),"utf-8"),a=i.match(/name: "([^"]+)"/),c=i.match(/status: (\w+)/),l=i.match(/version: "([^"]+)"/);return{slug:r.replace(".spec.md",""),name:a?.[1]||r,status:c?.[1]||"unknown",version:l?.[1]||"1.0.0"}})},async deleteSpecification(s){t();let r=o(s);return j.existsSync(r)?(j.unlinkSync(r),!0):!1},async specificationExists(s){return t(),j.existsSync(o(s))}}}function ze(){return fn({name:"agent-insights",version:"1.0.0",tools:[At,xt,Dt,jt,Lt,Ut]})}import{query as Ln}from"@anthropic-ai/claude-agent-sdk";var Je={description:"Delegate to this agent when scaffolding new entities or creating CRUD features. This agent handles entity generation using the scaffold CLI with multi-entity support.",model:"inherit",prompt:`You are a scaffolding specialist. Your ONLY job is:
58
+ `)}`}]}});import*as ue from"fs";import*as hn from"path";import*as N from"fs";import*as Ce from"path";function ge(n){let e=Ce.join(n,".sdd","specifications");function t(){N.existsSync(e)||N.mkdirSync(e,{recursive:!0})}function o(s){return Ce.join(e,`${s}.spec.md`)}return{async saveSpecification(s,r){t(),N.writeFileSync(o(s),r,"utf-8")},async getSpecification(s){t();let r=o(s);return N.existsSync(r)?N.readFileSync(r,"utf-8"):null},async listSpecifications(){return t(),N.readdirSync(e).filter(r=>r.endsWith(".spec.md")).map(r=>{let i=N.readFileSync(Ce.join(e,r),"utf-8"),a=i.match(/name: "([^"]+)"/),l=i.match(/status: (\w+)/),c=i.match(/version: "([^"]+)"/);return{slug:r.replace(".spec.md",""),name:a?.[1]||r,status:l?.[1]||"unknown",version:c?.[1]||"1.0.0"}})},async deleteSpecification(s){t();let r=o(s);return N.existsSync(r)?(N.unlinkSync(r),!0):!1},async specificationExists(s){return t(),N.existsSync(o(s))}}}function Je(){return fn({name:"agent-insights",version:"1.0.0",tools:[At,xt,Dt,jt,Lt,Ut]})}import{query as Ln}from"@anthropic-ai/claude-agent-sdk";var Qe={description:"Delegate to this agent when scaffolding new entities or creating CRUD features. This agent handles entity generation using the scaffold CLI with multi-entity support.",model:"inherit",prompt:`You are a scaffolding specialist. Your ONLY job is:
59
59
  1. Read the spec if referenced in the card description
60
60
  2. Check existing features (quick ls)
61
61
  3. Write ALL entities to ONE /tmp/scaffold.json (big bang, no phasing!)
@@ -262,7 +262,7 @@ DO NOT phase/split into multiple runs - that's slower and error-prone.
262
262
  - Enrollment depends on Student + CourseOffering - CLI handles it
263
263
  - ONE scaffold run creates ALL 6 entities with correct FK relationships
264
264
 
265
- REMEMBER: Read spec (if referenced) \u2192 ls \u2192 Write \u2192 Run \u2192 Restart \u2192 STOP. No verification needed.`};var ke={description:"Delegate to this agent to fix errors, type issues, or bugs in the code",model:"inherit",prompt:`You are a bug-fixing specialist. Your job is to FIX errors, not just report them.
265
+ REMEMBER: Read spec (if referenced) \u2192 ls \u2192 Write \u2192 Run \u2192 Restart \u2192 STOP. No verification needed.`};var _e={description:"Delegate to this agent to fix errors, type issues, or bugs in the code",model:"inherit",prompt:`You are a bug-fixing specialist. Your job is to FIX errors, not just report them.
266
266
 
267
267
  ## Process
268
268
  1. Read the error message carefully - understand WHAT and WHERE
@@ -292,7 +292,7 @@ REMEMBER: Read spec (if referenced) \u2192 ls \u2192 Write \u2192 Run \u2192 Res
292
292
  - Fix the ROOT CAUSE, not symptoms
293
293
  - Make minimal changes
294
294
  - Don't add unnecessary code
295
- - If multiple files have the same issue, fix all of them`};var Ce={description:"Delegate to this agent for specification-driven development. Use when the user wants to plan, specify, or design a feature before implementation.",model:"inherit",prompt:`You are a Product Discovery & Specification specialist.
295
+ - If multiple files have the same issue, fix all of them`};var Pe={description:"Delegate to this agent for specification-driven development. Use when the user wants to plan, specify, or design a feature before implementation.",model:"inherit",prompt:`You are a Product Discovery & Specification specialist.
296
296
 
297
297
  You think like a product person, not a developer. You create specifications that describe WHAT to build and WHY \u2014 using scenarios, user stories, and clear scope. Technical implementation details belong in Kanban cards, not in the spec.
298
298
 
@@ -456,7 +456,7 @@ Save your spec. The spec will appear in the user's UI.
456
456
  - Maximum 7 questions - don't exhaust the user!
457
457
  - Write like a PRODUCT PERSON, not an engineer
458
458
  - Scenarios should make the reader SEE the product
459
- - Technical details belong in Kanban cards, not here`};var Qe={description:"Delegate to this agent for writing new backend features (non-scaffold). Custom endpoints, queries, commands, business logic.",model:"inherit",prompt:`You are a backend specialist for .NET 9 / ASP.NET Core.
459
+ - Technical details belong in Kanban cards, not here`};var Ve={description:"Delegate to this agent for writing new backend features (non-scaffold). Custom endpoints, queries, commands, business logic.",model:"inherit",prompt:`You are a backend specialist for .NET 9 / ASP.NET Core.
460
460
 
461
461
  ## YOUR ROLE
462
462
  Write custom backend code that goes BEYOND what scaffold generates:
@@ -548,7 +548,7 @@ public class Get{EntityB}LookupHandler : IQueryHandler<Get{EntityB}LookupQuery,
548
548
  2. If build succeeds, generate swagger: \`mcp__agent-insights__restart_services\` (this regenerates swagger)
549
549
  3. Report what you created and STOP
550
550
 
551
- **\u26A0\uFE0F CRITICAL:** Always generate swagger before frontend work begins!`};var Ve={description:"Delegate to this agent for writing frontend features. Components, hooks, pages using generated API hooks.",model:"inherit",prompt:`You are a frontend specialist for React 19 + TypeScript + MUI.
551
+ **\u26A0\uFE0F CRITICAL:** Always generate swagger before frontend work begins!`};var Xe={description:"Delegate to this agent for writing frontend features. Components, hooks, pages using generated API hooks.",model:"inherit",prompt:`You are a frontend specialist for React 19 + TypeScript + MUI.
552
552
 
553
553
  ## YOUR ROLE
554
554
  Write frontend code using GENERATED API hooks (never manual fetch):
@@ -641,7 +641,7 @@ queryClient.invalidateQueries({ queryKey: getGetApi{Entities}QueryKey() })
641
641
  ## WHEN DONE
642
642
  1. Run typecheck: \`cd /workspace/packages/backoffice-web && npx tsc --noEmit\`
643
643
  2. If errors, fix them
644
- 3. Report what you created and STOP`};var _e={description:"Delegate to this agent to help the user write or improve their project context. This agent researches the codebase, asks strategic questions about product goals and users, then writes comprehensive project context.",model:"inherit",prompt:`You are a Project Context Specialist - an expert at understanding codebases and extracting the essential context that helps AI agents work effectively on projects.
644
+ 3. Report what you created and STOP`};var Re={description:"Delegate to this agent to help the user write or improve their project context. This agent researches the codebase, asks strategic questions about product goals and users, then writes comprehensive project context.",model:"inherit",prompt:`You are a Project Context Specialist - an expert at understanding codebases and extracting the essential context that helps AI agents work effectively on projects.
645
645
 
646
646
  ## \u26D4 CRITICAL RULES - READ FIRST
647
647
 
@@ -835,13 +835,13 @@ Before saving, verify your context:
835
835
  3. **Show patterns** - Include small code examples for common tasks
836
836
  4. **Prioritize** - Put most critical info in <critical_rules>
837
837
  5. **Keep it scannable** - Use bullets, clear sections
838
- 6. **Update, don't replace** - If context exists, improve it rather than starting fresh`};import*as ce from"fs";import*as Mt from"path";var Pe=class{buffer=[];flushInterval=null;sessionId=null;outputDir;flushIntervalMs;constructor(e){this.outputDir=e.outputDir||"/tmp/agent-debug",this.flushIntervalMs=e.flushIntervalMs||3e3,e.enabled&&(this.ensureOutputDir(),this.startFlushInterval())}ensureOutputDir(){ce.existsSync(this.outputDir)||ce.mkdirSync(this.outputDir,{recursive:!0})}startFlushInterval(){this.flushInterval=setInterval(()=>{this.flush()},this.flushIntervalMs)}setSessionId(e){this.sessionId=e}log(e){let o={timestamp:new Date().toISOString(),message:e};this.buffer.push(JSON.stringify(o,null,2)+`
838
+ 6. **Update, don't replace** - If context exists, improve it rather than starting fresh`};import*as le from"fs";import*as Mt from"path";var Te=class{buffer=[];flushInterval=null;sessionId=null;outputDir;flushIntervalMs;constructor(e){this.outputDir=e.outputDir||"/tmp/agent-debug",this.flushIntervalMs=e.flushIntervalMs||3e3,e.enabled&&(this.ensureOutputDir(),this.startFlushInterval())}ensureOutputDir(){le.existsSync(this.outputDir)||le.mkdirSync(this.outputDir,{recursive:!0})}startFlushInterval(){this.flushInterval=setInterval(()=>{this.flush()},this.flushIntervalMs)}setSessionId(e){this.sessionId=e}log(e){let o={timestamp:new Date().toISOString(),message:e};this.buffer.push(JSON.stringify(o,null,2)+`
839
839
  ---
840
- `)}getLogFilePath(){let t=(this.sessionId||"unknown").replace(/[^a-zA-Z0-9-]/g,"_").slice(0,50),o=new Date().toISOString().split("T")[0];return Mt.join(this.outputDir,`session-${o}-${t}.log`)}flush(){if(this.buffer.length===0)return;let e=this.buffer.join("");this.buffer=[];let t=this.getLogFilePath();ce.appendFileSync(t,e)}stop(){this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.flush()}};function Ft(n){return n?typeof n=="boolean"?n?new Pe({enabled:!0}):null:n.enabled?new Pe(n):null:null}import{z as b}from"zod";import*as Te from"fs/promises";import*as te from"path";var $t=b.object({port:b.number(),startCommand:b.string(),buildCommand:b.string().optional(),typecheckCommand:b.string().optional(),logFile:b.string().optional(),healthEndpoint:b.string().optional(),extensions:b.array(b.string())}),yn=b.object({port:b.number(),type:b.enum(["postgres","mysql","sqlite","mongodb"])}),bn=b.object({command:b.string(),schemaPath:b.string().optional()}),Sn=b.object({email:b.string().optional(),name:b.string().optional(),commitPrefix:b.string().optional()}),wn=b.object({enabled:b.boolean(),port:b.number().optional()}),Re=b.object({version:b.literal("1.0"),paths:b.object({workspace:b.string(),backend:b.string().optional(),frontend:b.string().optional(),features:b.object({backend:b.string().optional(),frontend:b.string().optional()}).optional()}),services:b.object({backend:$t.optional(),frontend:$t.optional(),database:yn.optional()}).optional(),scaffold:bn.optional(),git:Sn.optional(),techStack:b.object({backend:b.array(b.string()).optional(),frontend:b.array(b.string()).optional(),patterns:b.array(b.string()).optional()}).optional(),tunnel:wn.optional()});function z(n){return{version:"1.0",paths:{workspace:n||process.env.WORKSPACE_DIR||"/workspace",backend:"packages/dotnet-api",frontend:"packages/backoffice-web",features:{backend:"Source/Features",frontend:"src/applications/super-admin/features"}},services:{backend:{port:5338,startCommand:"dotnet run",buildCommand:"dotnet build",typecheckCommand:"dotnet build --no-restore",logFile:"/tmp/api.log",healthEndpoint:"http://localhost:5338",extensions:[".cs",".csproj"]},frontend:{port:5173,startCommand:"npm run dev",typecheckCommand:"npx tsc -p tsconfig.app.json --noEmit",logFile:"/tmp/web.log",healthEndpoint:"http://localhost:5173",extensions:[".ts",".tsx",".json"]},database:{port:43594,type:"postgres"}},scaffold:{command:"scaffold --schema /tmp/scaffold.json --output /workspace --force --full",schemaPath:"/tmp/scaffold.json"},git:{email:"agent@dotnetmentor.se",name:"Agent",commitPrefix:"[agent]"},techStack:{backend:[".NET 9","PostgreSQL","MediatR (CQRS)","EF Core"],frontend:["React 19","TypeScript","Vite","MUI","TanStack Query"],patterns:["Vertical slices","CQRS","Soft delete","Timestamps"]},tunnel:{enabled:!0,port:5173}}}var vn="project-config.json",kn=".sdd";async function Ie(n){let{workspaceDir:e,providedConfig:t,requireConfig:o}=n;if(t)return{config:Re.parse(t),source:"provided"};let s=te.join(e,kn,vn);try{let r=await Te.readFile(s,"utf-8"),i=JSON.parse(r);return{config:Re.parse(i),source:"file",configPath:s}}catch(r){r instanceof Error&&"code"in r&&r.code!=="ENOENT"&&console.warn(`[Config] Warning: Invalid project-config.json at ${s}:`,r instanceof b.ZodError?r.issues:r.message)}if(o)throw new Error(`No project configuration found at ${s} and requireConfig is true`);return{config:z(e),source:"default"}}function Ee(n,e){if(e)return te.isAbsolute(e)?e:te.join(n.paths.workspace,e)}function H(n){return Ee(n,n.paths.backend)}function B(n){return Ee(n,n.paths.frontend)}function Ae(n){let e=H(n);if(!(!e||!n.paths.features?.backend))return te.join(e,n.paths.features.backend)}function ge(n){let e=B(n);if(!(!e||!n.paths.features?.frontend))return te.join(e,n.paths.features.frontend)}function xe(n){let e=[];return n.techStack?.backend?.length&&e.push(`**Backend:** ${n.techStack.backend.join(", ")}`),n.techStack?.frontend?.length&&e.push(`**Frontend:** ${n.techStack.frontend.join(", ")}`),n.techStack?.patterns?.length&&e.push(`**Patterns:** ${n.techStack.patterns.join(", ")}`),e.join(`
841
- `)}function De(n){let e=[];return n.services?.backend&&e.push(`| Backend | ${H(n)} | ${n.services.backend.port} | ${n.services.backend.logFile||"N/A"} |`),n.services?.frontend&&e.push(`| Frontend | ${B(n)} | ${n.services.frontend.port} | ${n.services.frontend.logFile||"N/A"} |`),n.services?.database&&e.push(`| Database (${n.services.database.type}) | localhost | ${n.services.database.port} | - |`),e.length===0?"":`| Service | Location | Port | Logs |
840
+ `)}getLogFilePath(){let t=(this.sessionId||"unknown").replace(/[^a-zA-Z0-9-]/g,"_").slice(0,50),o=new Date().toISOString().split("T")[0];return Mt.join(this.outputDir,`session-${o}-${t}.log`)}flush(){if(this.buffer.length===0)return;let e=this.buffer.join("");this.buffer=[];let t=this.getLogFilePath();le.appendFileSync(t,e)}stop(){this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.flush()}};function Ft(n){return n?typeof n=="boolean"?n?new Te({enabled:!0}):null:n.enabled?new Te(n):null:null}import{z as b}from"zod";import*as Ee from"fs/promises";import*as te from"path";var $t=b.object({port:b.number(),startCommand:b.string(),buildCommand:b.string().optional(),typecheckCommand:b.string().optional(),logFile:b.string().optional(),healthEndpoint:b.string().optional(),extensions:b.array(b.string())}),yn=b.object({port:b.number(),type:b.enum(["postgres","mysql","sqlite","mongodb"])}),bn=b.object({command:b.string(),schemaPath:b.string().optional()}),Sn=b.object({email:b.string().optional(),name:b.string().optional(),commitPrefix:b.string().optional()}),wn=b.object({enabled:b.boolean(),port:b.number().optional()}),Ie=b.object({version:b.literal("1.0"),paths:b.object({workspace:b.string(),backend:b.string().optional(),frontend:b.string().optional(),features:b.object({backend:b.string().optional(),frontend:b.string().optional()}).optional()}),services:b.object({backend:$t.optional(),frontend:$t.optional(),database:yn.optional()}).optional(),scaffold:bn.optional(),git:Sn.optional(),techStack:b.object({backend:b.array(b.string()).optional(),frontend:b.array(b.string()).optional(),patterns:b.array(b.string()).optional()}).optional(),tunnel:wn.optional()});function Q(n){return{version:"1.0",paths:{workspace:n||process.env.WORKSPACE_DIR||"/workspace",backend:"packages/dotnet-api",frontend:"packages/backoffice-web",features:{backend:"Source/Features",frontend:"src/applications/super-admin/features"}},services:{backend:{port:5338,startCommand:"dotnet run",buildCommand:"dotnet build",typecheckCommand:"dotnet build --no-restore",logFile:"/tmp/api.log",healthEndpoint:"http://localhost:5338",extensions:[".cs",".csproj"]},frontend:{port:5173,startCommand:"npm run dev",typecheckCommand:"npx tsc -p tsconfig.app.json --noEmit",logFile:"/tmp/web.log",healthEndpoint:"http://localhost:5173",extensions:[".ts",".tsx",".json"]},database:{port:43594,type:"postgres"}},scaffold:{command:"scaffold --schema /tmp/scaffold.json --output /workspace --force --full",schemaPath:"/tmp/scaffold.json"},git:{email:"agent@dotnetmentor.se",name:"Agent",commitPrefix:"[agent]"},techStack:{backend:[".NET 9","PostgreSQL","MediatR (CQRS)","EF Core"],frontend:["React 19","TypeScript","Vite","MUI","TanStack Query"],patterns:["Vertical slices","CQRS","Soft delete","Timestamps"]},tunnel:{enabled:!0,port:5173}}}var vn="project-config.json",kn=".sdd";async function Ae(n){let{workspaceDir:e,providedConfig:t,requireConfig:o}=n;if(t)return{config:Ie.parse(t),source:"provided"};let s=te.join(e,kn,vn);try{let r=await Ee.readFile(s,"utf-8"),i=JSON.parse(r);return{config:Ie.parse(i),source:"file",configPath:s}}catch(r){r instanceof Error&&"code"in r&&r.code!=="ENOENT"&&console.warn(`[Config] Warning: Invalid project-config.json at ${s}:`,r instanceof b.ZodError?r.issues:r.message)}if(o)throw new Error(`No project configuration found at ${s} and requireConfig is true`);return{config:Q(e),source:"default"}}function xe(n,e){if(e)return te.isAbsolute(e)?e:te.join(n.paths.workspace,e)}function G(n){return xe(n,n.paths.backend)}function K(n){return xe(n,n.paths.frontend)}function De(n){let e=G(n);if(!(!e||!n.paths.features?.backend))return te.join(e,n.paths.features.backend)}function me(n){let e=K(n);if(!(!e||!n.paths.features?.frontend))return te.join(e,n.paths.features.frontend)}function je(n){let e=[];return n.techStack?.backend?.length&&e.push(`**Backend:** ${n.techStack.backend.join(", ")}`),n.techStack?.frontend?.length&&e.push(`**Frontend:** ${n.techStack.frontend.join(", ")}`),n.techStack?.patterns?.length&&e.push(`**Patterns:** ${n.techStack.patterns.join(", ")}`),e.join(`
841
+ `)}function Le(n){let e=[];return n.services?.backend&&e.push(`| Backend | ${G(n)} | ${n.services.backend.port} | ${n.services.backend.logFile||"N/A"} |`),n.services?.frontend&&e.push(`| Frontend | ${K(n)} | ${n.services.frontend.port} | ${n.services.frontend.logFile||"N/A"} |`),n.services?.database&&e.push(`| Database (${n.services.database.type}) | localhost | ${n.services.database.port} | - |`),e.length===0?"":`| Service | Location | Port | Logs |
842
842
  |---------|----------|------|------|
843
843
  ${e.join(`
844
- `)}`}function Ht(n={}){let{debugMode:e=!1,projectPrompt:t=null,isLocal:o=!1,projectConfig:s=z(),useDefaultStack:r=!0}=n,i=t?`
844
+ `)}`}function Ht(n={}){let{debugMode:e=!1,projectPrompt:t=null,isLocal:o=!1,projectConfig:s=Q(),useDefaultStack:r=!0}=n,i=t?`
845
845
  <project_context>
846
846
  ${t}
847
847
  </project_context>
@@ -886,7 +886,7 @@ Then STOP. Do not continue. Do not try to fix it. Wait for user.
886
886
 
887
887
  ---
888
888
 
889
- `:"",c=Tn(s),l=In(s,o),u=xn(s,r),d=En(r),p=r?Dn(s):"",y=r?jn(s,o):"",k=An(r);return`${i}${a}# Agent Instructions
889
+ `:"",l=Tn(s),c=In(s,o),u=xn(s,r),d=En(r),p=r?Dn(s):"",h=r?jn(s,o):"",C=An(r);return`${i}${a}# Agent Instructions
890
890
 
891
891
  ## \u26D4 CRITICAL: EVERYTHING IS A KANBAN TASK
892
892
 
@@ -1032,21 +1032,21 @@ Examples: "L\xE4gg till", "\xC4ndra", "V\xE4lj anv\xE4ndare", "F\xF6rnamn", "Eft
1032
1032
 
1033
1033
  **Code stays in English:** Variable names, function names, and code comments should remain in English for maintainability.
1034
1034
 
1035
- ${c}
1036
-
1037
1035
  ${l}
1038
1036
 
1037
+ ${c}
1038
+
1039
1039
  ${u}
1040
1040
 
1041
- ${k}
1041
+ ${C}
1042
1042
 
1043
1043
  ${p}
1044
1044
 
1045
- ${y}
1046
- `}function Tn(n){let e=xe(n),t=H(n),o=B(n),s=Ae(n),r=ge(n),i=[];s&&i.push(`- Backend: "${s}/{Entity}/"`),r&&i.push(`- Frontend: "${r}/{entity}/"`);let a=n.techStack?.patterns?.length?`
1045
+ ${h}
1046
+ `}function Tn(n){let e=je(n),t=G(n),o=K(n),s=De(n),r=me(n),i=[];s&&i.push(`- Backend: "${s}/{Entity}/"`),r&&i.push(`- Frontend: "${r}/{entity}/"`);let a=n.techStack?.patterns?.length?`
1047
1047
  **Key patterns:**
1048
1048
  ${n.techStack.patterns.map(u=>`- ${u}`).join(`
1049
- `)}`:"",l=n.techStack?.backend?.some(u=>u.includes(".NET")||u.includes("C#"))??!1?`
1049
+ `)}`:"",c=n.techStack?.backend?.some(u=>u.includes(".NET")||u.includes("C#"))??!1?`
1050
1050
 
1051
1051
  **\u26A0\uFE0F User entity exists!** ASP.NET Identity "ApplicationUser" at "Features/Users/" - don't scaffold User, just relate to it.`:"";return`<tech-stack>
1052
1052
  ${e}
@@ -1054,7 +1054,7 @@ ${i.length>0?`
1054
1054
  **Architecture:** Feature folders
1055
1055
  ${i.join(`
1056
1056
  `)}`:""}
1057
- ${a}${l}
1057
+ ${a}${c}
1058
1058
  </tech-stack>`}function In(n,e){return e?`<environment>
1059
1059
  **LOCAL MODE - User manages their own services.**
1060
1060
 
@@ -1076,7 +1076,7 @@ The user is responsible for:
1076
1076
  </environment>`:`<environment>
1077
1077
  Docker container with pre-started services:
1078
1078
 
1079
- ${De(n)}
1079
+ ${Le(n)}
1080
1080
  ${n.tunnel?.enabled?"| Tunnel | - | - | Exposes frontend to user |":""}
1081
1081
 
1082
1082
  User sees app through **Cloudflare tunnel** (live preview in browser).
@@ -1268,7 +1268,7 @@ queryClient.invalidateQueries({ queryKey: getGetApiPeopleQueryKey() })
1268
1268
 
1269
1269
  Check the project's existing patterns for API calls and data fetching.
1270
1270
  Look for existing feature code to understand the correct patterns before writing new API calls.
1271
- </frontend-api>`:""}function jn(n,e){if(!n.services?.frontend)return"";let t=n.services.frontend.port,o=ge(n),s=`http://localhost:${t}`;return`<ui-verification>
1271
+ </frontend-api>`:""}function jn(n,e){if(!n.services?.frontend)return"";let t=n.services.frontend.port,o=me(n),s=`http://localhost:${t}`;return`<ui-verification>
1272
1272
  ## \u{1F50D} UI Verification with Playwright
1273
1273
 
1274
1274
  You have access to **Playwright MCP** tools to verify the UI works correctly after making changes.
@@ -1350,20 +1350,20 @@ You have access to **Playwright MCP** tools to verify the UI works correctly aft
1350
1350
  - **Multi-tab apps**: Use \`browser_tabs\` to manage multiple windows/tabs in legacy applications
1351
1351
  - **Large snapshots**: For pages with huge dropdowns (e.g., country lists), use \`browser_evaluate\` to collapse them first
1352
1352
  - ${e?"In local mode, the browser window will be visible to you":"In container mode, browser runs headless"}
1353
- </ui-verification>`}function me(n){return n&&n.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"\uFFFD")}var je=null;function Xe(n){je=me(n),console.log(`[ProjectPrompt] Updated (${je?je.length:0} chars)`)}function Bt(){return me(je)}import*as se from"path";import*as Le from"fs";import{fileURLToPath as Un}from"url";var Nn=ze(),Ze=se.dirname(Un(import.meta.url)),Wt=[se.resolve(Ze,"../mcps/stdio-server.js"),se.resolve(Ze,"./adapters/mcps/stdio-server.js")],he=Wt.find(n=>Le.existsSync(n))||Wt[0];console.log("[MCP] Stdio server path resolved:",he);console.log("[MCP] __dirname:",Ze);console.log("[MCP] File exists:",Le.existsSync(he));async function Ue(n,e={}){let{model:t,sessionId:o=null,projectId:s=null,apiUrl:r=null,callbacks:i={},debugLog:a,abortController:c,debugMode:l=!1,isLocal:u=process.env.LOCAL_MODE==="true",projectConfig:d=z(process.env.WORKSPACE_DIR||process.cwd()),useDefaultStack:p=!0,anthropicApiKey:y}=e,k=Ft(a),E=new Set,x=o||"",w,g,U,K=!1,q=!1,m=process.env.WORKSPACE_DIR||process.cwd();console.log("[MCP] Configuring agent-planning stdio server:"),console.log("[MCP] Command: node"),console.log("[MCP] Args:",[he]),console.log("[MCP] Env: API_URL=",process.env.API_URL||"http://localhost:5338",", PROJECT_ID=",s||process.env.PROJECT_ID||"",", PROJECT_KEY=",process.env.PROJECT_KEY?"***set***":"(not set)",", WORKSPACE_DIR=",m),console.log("[MCP] File exists check:",he);try{for await(let h of Ln({prompt:n,options:{abortController:c,cwd:m,resume:o??void 0,allowedTools:["Bash","Read","Write","Edit","MultiEdit","Glob","Grep","LS","WebFetch","NotebookRead","NotebookEdit","Skill","mcp__agent-insights__check_backend_build","mcp__agent-insights__check_frontend_types","mcp__agent-insights__check_service_health",...u?[]:["mcp__agent-insights__stop_services","mcp__agent-insights__start_services","mcp__agent-insights__restart_services"],"mcp__agent-planning__start_question_session","mcp__agent-planning__ask_question","mcp__agent-planning__end_question_session","mcp__agent-planning__save_specification","mcp__agent-planning__list_specifications","mcp__agent-planning__read_specification","mcp__agent-planning__delete_specification","mcp__agent-planning__report_learning","mcp__agent-planning__report_bug","mcp__agent-planning__report_debug_insight","mcp__agent-planning__get_kanban_board","mcp__agent-planning__get_column_cards","mcp__agent-planning__get_card_details","mcp__agent-planning__create_kanban_card","mcp__agent-planning__update_kanban_card","mcp__agent-planning__move_kanban_card","mcp__agent-planning__delete_kanban_card","mcp__agent-planning__create_subtask","mcp__agent-planning__toggle_subtask","mcp__agent-planning__delete_subtask","mcp__agent-planning__get_project_prompt","mcp__agent-planning__update_project_prompt","mcp__agent-planning__create_command","mcp__agent-planning__get_test_suites","mcp__agent-planning__get_test_suite_details","mcp__agent-planning__get_test_details","mcp__agent-planning__run_test","mcp__agent-planning__run_test_suite","mcp__agent-planning__report_test_status","mcp__agent-planning__create_test_suite","mcp__agent-planning__create_test","mcp__agent-planning__update_test","mcp__agent-planning__reference_projects_list","mcp__agent-planning__reference_project_tree","mcp__agent-planning__reference_project_read_file","mcp__agent-planning__reference_project_download","mcp__agent-planning__reference_project_update_status","mcp__playwright__browser_navigate","mcp__playwright__browser_snapshot","mcp__playwright__browser_take_screenshot","mcp__playwright__browser_click","mcp__playwright__browser_type","mcp__playwright__browser_scroll_down","mcp__playwright__browser_scroll_up","mcp__playwright__browser_go_back","mcp__playwright__browser_go_forward","mcp__playwright__browser_wait","mcp__playwright__browser_fill_form","mcp__playwright__browser_select_option","mcp__playwright__browser_press_key","mcp__playwright__browser_hover","mcp__playwright__browser_drag","mcp__playwright__browser_file_upload","mcp__playwright__browser_handle_dialog","mcp__playwright__browser_close","mcp__playwright__browser_resize","mcp__playwright__browser_console_messages","mcp__playwright__browser_network_requests","mcp__playwright__browser_screen_capture","mcp__playwright__browser_screen_move_mouse","mcp__playwright__browser_screen_click","mcp__playwright__browser_screen_drag","mcp__playwright__browser_screen_type","mcp__playwright__browser_evaluate","mcp__playwright__browser_run_code","mcp__playwright__browser_tabs","mcp__playwright__browser_tab_list","mcp__playwright__browser_tab_new","mcp__playwright__browser_tab_select","mcp__playwright__browser_tab_close"],model:t,env:(()=>{if(Le.existsSync("/tmp/.use-own-subscription")){let{ANTHROPIC_API_KEY:V,...X}=process.env;return X}if(y!==void 0){if(y)return{...process.env,ANTHROPIC_API_KEY:y};let{ANTHROPIC_API_KEY:V,...X}=process.env;return X}})(),mcpServers:{"agent-insights":Nn,"agent-planning":{type:"stdio",command:"node",args:[he],env:{WORKSPACE_DIR:m,API_URL:r||process.env.API_URL||process.env.MASTER_URL||"http://localhost:5338",PROJECT_ID:s||process.env.PROJECT_ID||"",PROJECT_KEY:process.env.PROJECT_KEY||""}},playwright:{type:"stdio",command:"npx",args:["@playwright/mcp@latest",...u?[]:["--browser=firefox"],"--caps=vision",`--user-data-dir=${se.join(m,".playwright-data")}`,...u?[]:["--headless"]]}},settingSources:["project"],disallowedTools:["AskUserQuestion","TodoWrite","EnterPlanMode"],agents:p?{scaffolding:Je,debugger:ke,planning:Ce,backend:Qe,frontend:Ve,"project-context":_e}:{debugger:ke,planning:Ce,"project-context":_e},systemPrompt:Ht({debugMode:l,projectPrompt:Bt(),isLocal:u,projectConfig:d,useDefaultStack:p})}}))if(!(!h.uuid||E.has(h.uuid))){switch(E.add(h.uuid),k?.log(h),i.onRawMessage?.(h),h.type){case"assistant":if(h.message?.content)for(let C of h.message.content)C.type==="text"?i.onAssistantText?.(C.text):C.type==="tool_use"?i.onAssistantToolUse?.(C.name,C.input):C.type==="tool_result"&&i.onAssistantToolResult?.(C.tool_use_id,C.content);break;case"user":i.onUserMessage?.(h);break;case"result":if(h.subtype==="success")w=h.result,g=h.total_cost_usd,i.onResult?.(h.result,h.total_cost_usd);else{let C=`Agent error: ${h.subtype}`;U=C,i.onError?.(C)}q=!0;break;case"system":switch(h.subtype){case"init":x=h.session_id,k?.setSessionId(h.session_id),i.onSystemInit?.(h.session_id);break;case"status":i.onSystemStatus?.(JSON.stringify(h));break;case"compact_boundary":break;case"hook_response":break}break;case"stream_event":i.onStreamEvent?.(h);break;case"tool_progress":i.onToolProgress?.(h);break;case"auth_status":i.onAuthStatus?.(h);break}if(q)break}}catch(h){h instanceof Error&&h.name==="AbortError"||h instanceof Error&&h.message.includes("aborted by user")?(K=!0,i.onAborted?.()):(U=h instanceof Error?h.message:String(h),i.onError?.(U))}finally{k?.stop()}return console.log("after try"),{sessionId:x,result:w,cost:g,error:U,aborted:K}}import{spawn as Gt,execSync as re}from"child_process";import*as I from"fs";import*as Kt from"http";import*as ne from"path";function Ne(n){let{workspaceDir:e,apiPort:t,webPort:o,onBackendError:s,onFrontendError:r,projectConfig:i=z(e)}=n,a=t??i.services?.backend?.port??5338,c=o??i.services?.frontend?.port??5173,l=H(i),u=B(i),d=i.services?.backend?.startCommand??"dotnet run",p=i.services?.backend?.buildCommand??"dotnet build",y=i.services?.backend?.typecheckCommand??"dotnet build --no-restore",k=i.services?.frontend?.startCommand??"npm run dev",E=i.services?.frontend?.typecheckCommand??"npx tsc -p tsconfig.app.json --noEmit",x=i.services?.backend?.logFile??"/tmp/api.log",w=i.services?.frontend?.logFile??"/tmp/web.log",g=null,U=null,K=S=>new Promise(f=>{let v=setTimeout(()=>f(!1),3e3);Kt.get(`http://localhost:${S}`,L=>{clearTimeout(v),f(L.statusCode!==void 0&&L.statusCode<500)}).on("error",()=>{clearTimeout(v),f(!1)})}),q=S=>{try{let f=re(`lsof -ti:${S} 2>/dev/null || true`,{encoding:"utf-8"}).trim();if(f){let v=f.split(`
1354
- `).filter(Boolean);console.log(`[Services] Killing ${v.length} process(es) on port ${S}: ${v.join(", ")}`);for(let P of v)try{process.kill(parseInt(P,10),"SIGKILL")}catch{}}}catch{try{re(`fuser -k ${S}/tcp 2>/dev/null || true`,{encoding:"utf-8"})}catch{}}},m=(S,f)=>new Promise(v=>{if(!S||!S.pid){v();return}console.log(`[Services] Stopping ${f} (PID: ${S.pid})...`);try{process.kill(-S.pid,"SIGTERM")}catch{try{S.kill("SIGTERM")}catch{}}setTimeout(v,500)}),h=async()=>{if(!l||!I.existsSync(l)){console.log("[Services] No backend found, skipping backend start");return}q(a),console.log(`[Services] Starting backend with: ${d}...`);let S=ne.dirname(x);I.existsSync(S)||I.mkdirSync(S,{recursive:!0});let f=I.createWriteStream(x,{flags:"a"}),[v,...P]=d.split(" ");g=Gt(v,P,{cwd:l,stdio:["ignore","pipe","pipe"],detached:!0,shell:!0});let L="",D=R=>{let Z=R.toString();f.write(Z);let F=(L+Z).split(`
1355
- `);L=F.pop()||"";for(let $ of F)$&&Mn($)&&s&&s($)};g.stdout?.on("data",D),g.stderr?.on("data",D),g.on("exit",R=>{f.end(),R!==0&&R!==null&&s&&s(`Process exited with code ${R}`)}),g.unref()},C=async()=>{if(!u||!I.existsSync(ne.join(u,"package.json"))){console.log("[Services] No frontend found, skipping frontend start");return}q(c),console.log(`[Services] Starting frontend with: ${k}...`);let S=ne.dirname(w);I.existsSync(S)||I.mkdirSync(S,{recursive:!0});let[f,...v]=k.split(" ");U=Gt(f,v,{cwd:u,stdio:["ignore",I.openSync(w,"w"),I.openSync(w,"w")],detached:!0,shell:!0}),U.unref()},V=async()=>{await m(g,"backend"),g=null,q(a)},X=async()=>{await m(U,"frontend"),U=null,q(c)},qe=async()=>{let[S,f]=await Promise.all([K(a),K(c)]);return{api:S,web:f}},Pt=async(S=15e3)=>{let f=Date.now(),v=1e3,P=0,L=null,D=null;for(console.log(`[Services] Waiting for health (timeout: ${S}ms)...`);Date.now()-f<S;){P++;let F=await qe(),$=Date.now()-f;if(F.web&&D===null&&(D=$,console.log(`[Services] \u2713 Frontend (Vite) ready after ${$}ms`)),F.api&&L===null&&(L=$,console.log(`[Services] \u2713 Backend (dotnet) ready after ${$}ms`)),console.log(`[Services] Health poll #${P} (${$}ms): api=${F.api}, web=${F.web}`),F.api&&F.web)return console.log(`[Services] \u2713 Both services healthy after ${$}ms (${P} polls)`),F;await new Promise(mn=>setTimeout(mn,v))}let R=await qe(),Z=Date.now()-f;return R.web&&D===null&&console.log(`[Services] \u2713 Frontend (Vite) ready after ${Z}ms`),R.api&&L===null&&console.log(`[Services] \u2713 Backend (dotnet) ready after ${Z}ms`),console.log(`[Services] \u26A0 Health timeout after ${Z}ms: api=${R.api}, web=${R.web}`),R},un=async S=>{console.log(`[Services] Restarting ${S}...`);let f={success:!0},v=S==="backend"||S==="both",P=S==="frontend"||S==="both";if(v&&await V(),P&&await X(),v&&l&&I.existsSync(l)){console.log(`[Services] Building backend with: ${p}...`);try{re(p,{cwd:l,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),console.log("[Services] \u2713 Backend build succeeded")}catch(D){let R=D;f.success=!1,f.backendError=R.stderr||R.stdout||"Build failed",console.error("[Services] \u2717 Backend build failed")}}if(P&&u&&I.existsSync(ne.join(u,"package.json"))){console.log(`[Services] Type-checking frontend with: ${E}...`);try{re(E,{cwd:u,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),console.log("[Services] \u2713 Frontend types OK")}catch(D){let R=D;f.success=!1,f.frontendError=R.stderr||R.stdout||"Type check failed",console.error("[Services] \u2717 Frontend type check failed")}}console.log(`[Services] Starting ${S}...`),v&&await h(),P&&await C();let L=await Pt(1e4);if(v&&!L.api){f.success=!1;let D=await It("backend",20),R=D.length>0?`
1353
+ </ui-verification>`}function he(n){return n&&n.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"\uFFFD")}var Ue=null;function Ze(n){Ue=he(n),console.log(`[ProjectPrompt] Updated (${Ue?Ue.length:0} chars)`)}function Bt(){return he(Ue)}import*as re from"path";import*as Ne from"fs";import{fileURLToPath as Un}from"url";var Nn=Je(),et=re.dirname(Un(import.meta.url)),Wt=[re.resolve(et,"../mcps/stdio-server.js"),re.resolve(et,"./adapters/mcps/stdio-server.js")],fe=Wt.find(n=>Ne.existsSync(n))||Wt[0];console.log("[MCP] Stdio server path resolved:",fe);console.log("[MCP] __dirname:",et);console.log("[MCP] File exists:",Ne.existsSync(fe));async function Oe(n,e={}){let{model:t,sessionId:o=null,projectId:s=null,apiUrl:r=null,callbacks:i={},debugLog:a,abortController:l,debugMode:c=!1,isLocal:u=process.env.LOCAL_MODE==="true",projectConfig:d=Q(process.env.WORKSPACE_DIR||process.cwd()),useDefaultStack:p=!0,anthropicApiKey:h}=e,C=Ft(a),E=new Set,x=o||"",w,m,D,y=!1,H=!1,z=process.env.WORKSPACE_DIR||process.cwd();console.log("[MCP] Configuring agent-planning stdio server:"),console.log("[MCP] Command: node"),console.log("[MCP] Args:",[fe]),console.log("[MCP] Env: API_URL=",process.env.API_URL||"http://localhost:5338",", PROJECT_ID=",s||process.env.PROJECT_ID||"",", PROJECT_KEY=",process.env.PROJECT_KEY?"***set***":"(not set)",", WORKSPACE_DIR=",z),console.log("[MCP] File exists check:",fe);try{for await(let v of Ln({prompt:n,options:{abortController:l,cwd:z,resume:o??void 0,allowedTools:["Bash","Read","Write","Edit","MultiEdit","Glob","Grep","LS","WebFetch","NotebookRead","NotebookEdit","Skill","mcp__agent-insights__check_backend_build","mcp__agent-insights__check_frontend_types","mcp__agent-insights__check_service_health",...u?[]:["mcp__agent-insights__stop_services","mcp__agent-insights__start_services","mcp__agent-insights__restart_services"],"mcp__agent-planning__start_question_session","mcp__agent-planning__ask_question","mcp__agent-planning__end_question_session","mcp__agent-planning__save_specification","mcp__agent-planning__list_specifications","mcp__agent-planning__read_specification","mcp__agent-planning__delete_specification","mcp__agent-planning__report_learning","mcp__agent-planning__report_bug","mcp__agent-planning__report_debug_insight","mcp__agent-planning__get_kanban_board","mcp__agent-planning__get_column_cards","mcp__agent-planning__get_card_details","mcp__agent-planning__create_kanban_card","mcp__agent-planning__update_kanban_card","mcp__agent-planning__move_kanban_card","mcp__agent-planning__delete_kanban_card","mcp__agent-planning__create_subtask","mcp__agent-planning__toggle_subtask","mcp__agent-planning__delete_subtask","mcp__agent-planning__get_project_prompt","mcp__agent-planning__update_project_prompt","mcp__agent-planning__create_command","mcp__agent-planning__get_test_suites","mcp__agent-planning__get_test_suite_details","mcp__agent-planning__get_test_details","mcp__agent-planning__run_test","mcp__agent-planning__run_test_suite","mcp__agent-planning__report_test_status","mcp__agent-planning__create_test_suite","mcp__agent-planning__create_test","mcp__agent-planning__update_test","mcp__agent-planning__reference_projects_list","mcp__agent-planning__reference_project_tree","mcp__agent-planning__reference_project_read_file","mcp__agent-planning__reference_project_download","mcp__agent-planning__reference_project_update_status","mcp__playwright__browser_navigate","mcp__playwright__browser_snapshot","mcp__playwright__browser_take_screenshot","mcp__playwright__browser_click","mcp__playwright__browser_type","mcp__playwright__browser_scroll_down","mcp__playwright__browser_scroll_up","mcp__playwright__browser_go_back","mcp__playwright__browser_go_forward","mcp__playwright__browser_wait","mcp__playwright__browser_fill_form","mcp__playwright__browser_select_option","mcp__playwright__browser_press_key","mcp__playwright__browser_hover","mcp__playwright__browser_drag","mcp__playwright__browser_file_upload","mcp__playwright__browser_handle_dialog","mcp__playwright__browser_close","mcp__playwright__browser_resize","mcp__playwright__browser_console_messages","mcp__playwright__browser_network_requests","mcp__playwright__browser_screen_capture","mcp__playwright__browser_screen_move_mouse","mcp__playwright__browser_screen_click","mcp__playwright__browser_screen_drag","mcp__playwright__browser_screen_type","mcp__playwright__browser_evaluate","mcp__playwright__browser_run_code","mcp__playwright__browser_tabs","mcp__playwright__browser_tab_list","mcp__playwright__browser_tab_new","mcp__playwright__browser_tab_select","mcp__playwright__browser_tab_close"],model:t,env:(()=>{if(Ne.existsSync("/tmp/.use-own-subscription")){let{ANTHROPIC_API_KEY:j,...L}=process.env;return L}if(h!==void 0){if(h)return{...process.env,ANTHROPIC_API_KEY:h};let{ANTHROPIC_API_KEY:j,...L}=process.env;return L}})(),mcpServers:{"agent-insights":Nn,"agent-planning":{type:"stdio",command:"node",args:[fe],env:{WORKSPACE_DIR:z,API_URL:r||process.env.API_URL||process.env.MASTER_URL||"http://localhost:5338",PROJECT_ID:s||process.env.PROJECT_ID||"",PROJECT_KEY:process.env.PROJECT_KEY||""}},playwright:{type:"stdio",command:"npx",args:["@playwright/mcp@latest",...u?[]:["--browser=firefox"],"--caps=vision",`--user-data-dir=${re.join(z,".playwright-data")}`,...u?[]:["--headless"]]}},settingSources:["project"],disallowedTools:["AskUserQuestion","TodoWrite","EnterPlanMode"],agents:p?{scaffolding:Qe,debugger:_e,planning:Pe,backend:Ve,frontend:Xe,"project-context":Re}:{debugger:_e,planning:Pe,"project-context":Re},systemPrompt:Ht({debugMode:c,projectPrompt:Bt(),isLocal:u,projectConfig:d,useDefaultStack:p})}}))if(!(!v.uuid||E.has(v.uuid))){switch(E.add(v.uuid),C?.log(v),i.onRawMessage?.(v),v.type){case"assistant":if(v.message?.content)for(let g of v.message.content)g.type==="text"?i.onAssistantText?.(g.text):g.type==="tool_use"?i.onAssistantToolUse?.(g.name,g.input):g.type==="tool_result"&&i.onAssistantToolResult?.(g.tool_use_id,g.content);break;case"user":i.onUserMessage?.(v);break;case"result":if(v.subtype==="success")w=v.result,m=v.total_cost_usd,i.onResult?.(v.result,v.total_cost_usd);else{let g=`Agent error: ${v.subtype}`;D=g,i.onError?.(g)}H=!0;break;case"system":switch(v.subtype){case"init":x=v.session_id,C?.setSessionId(v.session_id),i.onSystemInit?.(v.session_id);break;case"status":i.onSystemStatus?.(JSON.stringify(v));break;case"compact_boundary":break;case"hook_response":break}break;case"stream_event":i.onStreamEvent?.(v);break;case"tool_progress":i.onToolProgress?.(v);break;case"auth_status":i.onAuthStatus?.(v);break}if(H)break}}catch(v){v instanceof Error&&v.name==="AbortError"||v instanceof Error&&v.message.includes("aborted by user")?(y=!0,i.onAborted?.()):(D=v instanceof Error?v.message:String(v),i.onError?.(D))}finally{C?.stop()}return console.log("after try"),{sessionId:x,result:w,cost:m,error:D,aborted:y}}import{spawn as Gt,execSync as ie}from"child_process";import*as I from"fs";import*as Kt from"http";import*as ne from"path";function Me(n){let{workspaceDir:e,apiPort:t,webPort:o,onBackendError:s,onFrontendError:r,projectConfig:i=Q(e)}=n,a=t??i.services?.backend?.port??5338,l=o??i.services?.frontend?.port??5173,c=G(i),u=K(i),d=i.services?.backend?.startCommand??"dotnet run",p=i.services?.backend?.buildCommand??"dotnet build",h=i.services?.backend?.typecheckCommand??"dotnet build --no-restore",C=i.services?.frontend?.startCommand??"npm run dev",E=i.services?.frontend?.typecheckCommand??"npx tsc -p tsconfig.app.json --noEmit",x=i.services?.backend?.logFile??"/tmp/api.log",w=i.services?.frontend?.logFile??"/tmp/web.log",m=null,D=null,y=S=>new Promise(f=>{let k=setTimeout(()=>f(!1),3e3);Kt.get(`http://localhost:${S}`,O=>{clearTimeout(k),f(O.statusCode!==void 0&&O.statusCode<500)}).on("error",()=>{clearTimeout(k),f(!1)})}),H=S=>{try{let f=ie(`lsof -ti:${S} 2>/dev/null || true`,{encoding:"utf-8"}).trim();if(f){let k=f.split(`
1354
+ `).filter(Boolean);console.log(`[Services] Killing ${k.length} process(es) on port ${S}: ${k.join(", ")}`);for(let P of k)try{process.kill(parseInt(P,10),"SIGKILL")}catch{}}}catch{try{ie(`fuser -k ${S}/tcp 2>/dev/null || true`,{encoding:"utf-8"})}catch{}}},z=(S,f)=>new Promise(k=>{if(!S||!S.pid){k();return}console.log(`[Services] Stopping ${f} (PID: ${S.pid})...`);try{process.kill(-S.pid,"SIGTERM")}catch{try{S.kill("SIGTERM")}catch{}}setTimeout(k,500)}),v=async()=>{if(!c||!I.existsSync(c)){console.log("[Services] No backend found, skipping backend start");return}H(a),console.log(`[Services] Starting backend with: ${d}...`);let S=ne.dirname(x);I.existsSync(S)||I.mkdirSync(S,{recursive:!0});let f=I.createWriteStream(x,{flags:"a"}),[k,...P]=d.split(" ");m=Gt(k,P,{cwd:c,stdio:["ignore","pipe","pipe"],detached:!0,shell:!0});let O="",U=R=>{let Z=R.toString();f.write(Z);let B=(O+Z).split(`
1355
+ `);O=B.pop()||"";for(let W of B)W&&Mn(W)&&s&&s(W)};m.stdout?.on("data",U),m.stderr?.on("data",U),m.on("exit",R=>{f.end(),R!==0&&R!==null&&s&&s(`Process exited with code ${R}`)}),m.unref()},g=async()=>{if(!u||!I.existsSync(ne.join(u,"package.json"))){console.log("[Services] No frontend found, skipping frontend start");return}H(l),console.log(`[Services] Starting frontend with: ${C}...`);let S=ne.dirname(w);I.existsSync(S)||I.mkdirSync(S,{recursive:!0});let[f,...k]=C.split(" ");D=Gt(f,k,{cwd:u,stdio:["ignore",I.openSync(w,"w"),I.openSync(w,"w")],detached:!0,shell:!0}),D.unref()},j=async()=>{await z(m,"backend"),m=null,H(a)},L=async()=>{await z(D,"frontend"),D=null,H(l)},se=async()=>{let[S,f]=await Promise.all([y(a),y(l)]);return{api:S,web:f}},be=async(S=15e3)=>{let f=Date.now(),k=1e3,P=0,O=null,U=null;for(console.log(`[Services] Waiting for health (timeout: ${S}ms)...`);Date.now()-f<S;){P++;let B=await se(),W=Date.now()-f;if(B.web&&U===null&&(U=W,console.log(`[Services] \u2713 Frontend (Vite) ready after ${W}ms`)),B.api&&O===null&&(O=W,console.log(`[Services] \u2713 Backend (dotnet) ready after ${W}ms`)),console.log(`[Services] Health poll #${P} (${W}ms): api=${B.api}, web=${B.web}`),B.api&&B.web)return console.log(`[Services] \u2713 Both services healthy after ${W}ms (${P} polls)`),B;await new Promise(mn=>setTimeout(mn,k))}let R=await se(),Z=Date.now()-f;return R.web&&U===null&&console.log(`[Services] \u2713 Frontend (Vite) ready after ${Z}ms`),R.api&&O===null&&console.log(`[Services] \u2713 Backend (dotnet) ready after ${Z}ms`),console.log(`[Services] \u26A0 Health timeout after ${Z}ms: api=${R.api}, web=${R.web}`),R},un=async S=>{console.log(`[Services] Restarting ${S}...`);let f={success:!0},k=S==="backend"||S==="both",P=S==="frontend"||S==="both";if(k&&await j(),P&&await L(),k&&c&&I.existsSync(c)){console.log(`[Services] Building backend with: ${p}...`);try{ie(p,{cwd:c,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),console.log("[Services] \u2713 Backend build succeeded")}catch(U){let R=U;f.success=!1,f.backendError=R.stderr||R.stdout||"Build failed",console.error("[Services] \u2717 Backend build failed")}}if(P&&u&&I.existsSync(ne.join(u,"package.json"))){console.log(`[Services] Type-checking frontend with: ${E}...`);try{ie(E,{cwd:u,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),console.log("[Services] \u2713 Frontend types OK")}catch(U){let R=U;f.success=!1,f.frontendError=R.stderr||R.stdout||"Type check failed",console.error("[Services] \u2717 Frontend type check failed")}}console.log(`[Services] Starting ${S}...`),k&&await v(),P&&await g();let O=await be(1e4);if(k&&!O.api){f.success=!1;let U=await It("backend",20),R=U.length>0?`
1356
1356
  Recent logs:
1357
- ${D.join(`
1358
- `)}`:"";f.backendError||(f.backendError=`Backend failed to start.${R}`)}return P&&!L.web&&(f.success=!1,f.frontendError||(f.frontendError="Frontend failed to start")),f},Rt=async()=>{if(!l||!I.existsSync(l))return{success:!0};try{return re(y,{cwd:l,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),{success:!0}}catch(S){let f=S;return{success:!1,errors:f.stdout||f.stderr||"Build failed"}}},Tt=async()=>{if(!u||!I.existsSync(ne.join(u,"package.json")))return{success:!0};try{return re(E,{cwd:u,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),{success:!0}}catch(S){let f=S;return{success:!1,errors:f.stdout||f.stderr||"Type check failed"}}},gn=async()=>{let[S,f]=await Promise.all([Rt(),Tt()]);return{backend:S,frontend:f}},It=async(S,f)=>{let v=S==="backend"?x:w;if(!I.existsSync(v))return[`Log file not found: ${v}`];try{return re(`tail -n ${f} ${v}`,{encoding:"utf-8"}).split(`
1359
- `).filter(Boolean)}catch(P){return[`Error reading logs: ${P instanceof Error?P.message:String(P)}`]}};return{startBackend:h,startFrontend:C,stopBackend:V,stopFrontend:X,restartServices:un,checkHealth:qe,waitForHealth:Pt,getProcesses:()=>({backend:g,frontend:U}),checkBackendBuild:Rt,checkFrontendTypes:Tt,runTypeChecks:gn,tailLogs:It,checkSwaggerEndpoints:async S=>{let f=ne.join(e,"swagger.json");if(!I.existsSync(f))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let v=JSON.parse(I.readFileSync(f,"utf-8")),P=Object.keys(v.paths||{}),L=[];for(let D of P)if(D.toLowerCase().includes(S.toLowerCase())){let R=Object.keys(v.paths[D]);for(let Z of R)L.push(`${Z.toUpperCase()} ${D}`)}return{foundEndpoints:L,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 Oe(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(u){let d=u instanceof Error?u.message:String(u);if(d.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:",d),{success:!1,commitHash:l,commitSucceeded:!0,pushFailed:!0,error:d}}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 W=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)},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 W(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 W(e,a)}},ft=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...g)=>t.boardUpdated(...g),s=(...g)=>t.boardDeleted(...g),r=(...g)=>t.columnCreated(...g),i=(...g)=>t.columnUpdated(...g),a=(...g)=>t.columnDeleted(...g),c=(...g)=>t.cardCreated(...g),l=(...g)=>t.cardUpdated(...g),u=(...g)=>t.cardDeleted(...g),d=(...g)=>t.subtaskCreated(...g),p=(...g)=>t.subtaskUpdated(...g),y=(...g)=>t.subtaskDeleted(...g),k=(...g)=>t.noteCreated(...g),E=(...g)=>t.noteUpdated(...g),x=(...g)=>t.noteDeleted(...g);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",u),e.on("SubtaskCreated",d),e.on("SubtaskUpdated",p),e.on("SubtaskDeleted",y),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:u},{methodName:"SubtaskCreated",method:d},{methodName:"SubtaskUpdated",method:p},{methodName:"SubtaskDeleted",method:y},{methodName:"NoteCreated",method:k},{methodName:"NoteUpdated",method:E},{methodName:"NoteDeleted",method:x}];return new W(e,w)}},yt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...d)=>t.initSession(...d),s=(...d)=>t.runPrompt(...d),r=(...d)=>t.setModel(...d),i=()=>t.stopAgent(),a=()=>t.ping(),c=(...d)=>t.switchSession(...d),l=(...d)=>t.projectPromptUpdated(...d);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 u=[{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 W(e,u)}},bt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...g)=>t.sessionOutput(...g),s=(...g)=>t.sessionCost(...g),r=(...g)=>t.sessionCompleted(...g),i=(...g)=>t.containerStatus(...g),a=(...g)=>t.slaveCapacityUpdate(...g),c=(...g)=>t.previewBuildStatus(...g),l=(...g)=>t.previewReload(...g),u=(...g)=>t.questionsReceived(...g),d=(...g)=>t.specificationUpdated(...g),p=(...g)=>t.singleQuestionReceived(...g),y=(...g)=>t.questionSessionEnded(...g),k=(...g)=>t.creditsUpdated(...g),E=(...g)=>t.insufficientCredits(...g),x=(...g)=>t.projectSessionStatusChanged(...g);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",u),e.on("SpecificationUpdated",d),e.on("SingleQuestionReceived",p),e.on("QuestionSessionEnded",y),e.on("CreditsUpdated",k),e.on("InsufficientCredits",E),e.on("ProjectSessionStatusChanged",x);let w=[{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:u},{methodName:"SpecificationUpdated",method:d},{methodName:"SingleQuestionReceived",method:p},{methodName:"QuestionSessionEnded",method:y},{methodName:"CreditsUpdated",method:k},{methodName:"InsufficientCredits",method:E},{methodName:"ProjectSessionStatusChanged",method:x}];return new W(e,w)}},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),u=(...w)=>t.restartLabAgent(...w),d=(...w)=>t.terminateDockerContainer(...w),p=(...w)=>t.streamSlaveAgentLogs(...w),y=()=>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",u),e.on("TerminateDockerContainer",d),e.on("StreamSlaveAgentLogs",p),e.on("StopSlaveAgentLogStream",y),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:u},{methodName:"TerminateDockerContainer",method:d},{methodName:"StreamSlaveAgentLogs",method:p},{methodName:"StopSlaveAgentLogStream",method:y},{methodName:"StartClaudeLogin",method:k},{methodName:"SubmitClaudeLoginCode",method:E}];return new W(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),u=(...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",u);let d=[{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:u}];return new W(e,d)}},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 W(e,c)}};var Hn=$n(Fn),Me=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
- `;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 Fe=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 O from"path";var $e=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 N(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",He=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 $e),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 u=new A("Clone repository");await this.cloneRepository(t,o),this.currentRepoUrl=t,this.currentBranchName=o,u.stop(),await this.installDependencies(),this.lastLockfileHash=this.getLockfileHash(),console.log("[Init] Starting services...");let d=new A("Start backend (dotnet)");await this.serviceManager.startBackend(),d.stop();let p=new A("Start frontend (vite)");await this.serviceManager.startFrontend(),p.stop();let y=new A("Wait for health check");await this.serviceManager.waitForHealth(3e4),y.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 N(`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 N("rm -rf /workspace/* /workspace/.* 2>/dev/null || true");try{console.log(`[Clone] Attempt ${c}/${i}...`);let l=Date.now();await N(`git clone -b ${t} "${e}" /workspace`,{timeout:12e4});let u=((Date.now()-l)/1e3).toFixed(2);console.log(`[Clone] \u2713 Clone succeeded on attempt ${c} (${u}s)`),await N('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 u=l instanceof Error?l.message:String(l);console.error(`[Clone] \u274C Attempt ${c}/${i} failed: ${u}`);let d=0;try{let{stdout:p}=await kt(`git ls-remote --heads "${e}" 2>&1`,{timeout:15e3}),y=p.trim();d=y?y.split(`
1361
- `).length:0,console.log(`[Clone] ls-remote: ${d} branch(es) found${y?`: ${y.split(`
1362
- `).slice(0,3).join(", ")}`:" (empty repo \u2014 likely still generating from template)"}`)}catch(p){let y=p instanceof Error?p.message:String(p);console.error(`[Clone] ls-remote also failed: ${y}`)}if(c<i){let p=a[c]||15e3,y=d===0?"repo appears empty (template still generating)":`branch '${t}' not found`;console.log(`[Clone] Retrying in ${p/1e3}s... (${y})`),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: ${u}`,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 N(`git pull origin ${e}`,{cwd:this.workspaceDir,timeout:6e4});else{await N("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 N(`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 N(`git checkout -b ${e}`,{cwd:this.workspaceDir,timeout:3e4})),this.currentBranchName=e}console.log(`[Branch] \u2713 Now on ${e}`)}getLockfileHash(){let e=O.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(`
1363
- `).filter(c=>c.length>0);console.log(`[CodeDiff] ${r.length} files changed between ${e} and ${t}`);let i=[".cs",".tsx",".ts",".json",".csproj"],a=r.some(c=>i.some(l=>c.endsWith(l)));return a&&console.log("[CodeDiff] Found code changes that require service restart"),a}catch(o){return console.error("[CodeDiff] Failed to check diff:",o instanceof Error?o.message:o),!0}}async installDependencies(){let e=new A("TOTAL INSTALL DEPENDENCIES");if(_.existsSync(O.join(this.workspaceDir,"packages/dotnet-api"))){let t=new A("dotnet restore");await N("dotnet restore",{cwd:O.join(this.workspaceDir,"packages/dotnet-api"),timeout:12e4}),t.stop()}if(_.existsSync(O.join(this.workspaceDir,"packages/backoffice-web/package.json"))){let t=O.join(this.workspaceDir,"packages/backoffice-web"),o=O.join(t,"node_modules"),s=O.join(t,"package-lock.json"),r=O.join(o,".lockhash"),i="/opt/cache";_.mkdirSync(i,{recursive:!0});let a=_.existsSync(s)?Vt("sha256").update(_.readFileSync(s)).digest("hex"):null,c=_.existsSync(r)?_.readFileSync(r,"utf-8").trim():null,l=O.join(i,"node_modules","current_hash"),u=_.existsSync(l)?_.readFileSync(l,"utf-8").trim():null,d=u?O.join(i,"node_modules",u):null,p=a?O.join(i,"node_modules",a):null;if(console.log(`[Install] node_modules exists: ${_.existsSync(o)}`),console.log(`[Install] lockHash (current branch): ${a?.substring(0,8)||"null"}`),console.log(`[Install] installedHash: ${c?.substring(0,8)||"null"}`),console.log(`[Install] dockerCacheHash (from image): ${u?.substring(0,8)||"null"}`),console.log(`[Install] exactMatchCache exists: ${p?_.existsSync(p):!1}`),console.log(`[Install] dockerCachedNodeModules exists: ${d?_.existsSync(d):!1}`),!_.existsSync(o)){if(p&&_.existsSync(p)){let k=new A("Copy exact-match cached node_modules");console.log(`[Install] Copying exact-match cached node_modules (hash ${a?.substring(0,8)})...`),await N(`cp -r "${p}" "${o}"`),a&&_.writeFileSync(r,a),c=a,k.stop()}else if(d&&_.existsSync(d)){let k=new A("Copy Docker-cached node_modules (as base)");console.log(`[Install] Copying Docker-cached node_modules as base (hash ${u?.substring(0,8)}, need ${a?.substring(0,8)})...`),await N(`cp -r "${d}" "${o}"`),k.stop()}}let y=!_.existsSync(o)||a&&a!==c;if(console.log(`[Install] needsInstall: ${y}`),!y)console.log("[Install] npm install skipped (cache OK)");else{let k=new A("npm install --prefer-offline");await N("npm install --prefer-offline --no-progress --fund=false",{cwd:t,timeout:18e4}),k.stop(),a&&(_.mkdirSync(o,{recursive:!0}),_.writeFileSync(r,a))}this.lastLockfileHash=a}e.stop()}};function Zt(n,e,t){let o=n.getHubProxy(),s=process.env.CONTAINER_ID||"unknown";return{onAssistantText:async r=>{let i={type:"Text",content:r,isError:!1};await o.reportSessionOutput(s,e,i).catch(a=>{console.error("Failed to report assistant text:",a)})},onAssistantToolUse:async(r,i)=>{if(["Write","Edit","MultiEdit"].includes(r)){let c=i,l=c.file_path||c.target_file;l&&t.onFileModified(l)}let a={type:"ToolUse",toolName:r,toolInput:JSON.stringify(i),isError:!1};await o.reportSessionOutput(s,e,a).catch(c=>{console.error("Failed to report tool use:",c)})},onResult:async(r,i)=>{let a={type:"System",event:"completed",content:r,cost:i,isError:!1};await o.reportSessionOutput(s,e,a).catch(c=>{console.error("Failed to report result:",c)})},onError:async r=>{let i={type:"System",event:"error",content:r,isError:!0};await o.reportSessionOutput(s,e,i).catch(a=>{console.error("Failed to report error:",a)})},onAborted:async()=>{let r={type:"System",event:"aborted",content:"Agent stopped by user",isError:!1};await o.reportSessionOutput(s,e,r).catch(i=>{console.error("Failed to report abort:",i)})},onSystemInit:async r=>{console.log(`[Callbacks] Claude session initialized: ${r}`),t.onClaudeSessionId(r),await o.setClaudeSessionId(e,r).catch(i=>{console.error("Failed to set Claude session ID:",i)})},onRawMessage:r=>{if(r.type==="assistant"&&r.message?.usage){let i=r.message.usage,a={totalCostUsd:Yn(i),inputTokens:i.input_tokens||0,outputTokens:i.output_tokens||0,cacheCreationTokens:i.cache_creation_input_tokens||0,cacheReadTokens:i.cache_read_input_tokens||0};o.reportSessionCost(s,e,a).catch(c=>{console.error("Failed to report cost:",c)})}}}}var Be={inputPerMillion:3,outputPerMillion:15,cacheReadPerMillion:.3,cacheCreationPerMillion:3.75};function Yn(n){return(n.input_tokens||0)/1e6*Be.inputPerMillion+(n.output_tokens||0)/1e6*Be.outputPerMillion+(n.cache_read_input_tokens||0)/1e6*Be.cacheReadPerMillion+(n.cache_creation_input_tokens||0)/1e6*Be.cacheCreationPerMillion}import*as le from"fs";import*as en from"path";function tn(n,e){let t=en.join(n,`.agent-questions-${e}.json`);if(!le.existsSync(t))return null;try{let o=le.readFileSync(t,"utf-8");return le.unlinkSync(t),JSON.parse(o)}catch(o){return console.error("Failed to read questions file:",o),null}}async function nn(n,e,t,o){if(e.size===0)return console.log("[TypeCheck] No code changes, skipping type checks"),{passed:!0};let s=o?H(o):`${t}/packages/dotnet-api`,r=o?B(o):`${t}/packages/backoffice-web`,i=o?.services?.backend?.extensions??[".cs",".csproj"],a=o?.services?.frontend?.extensions??[".ts",".tsx"],c=s&&[...e].some(p=>p.includes(s)||i.some(y=>p.endsWith(y))),l=r&&[...e].some(p=>p.includes(r)||a.some(y=>p.endsWith(y)));if(!c&&!l)return console.log("[TypeCheck] No code changes, skipping type checks"),{passed:!0};let u=[];c&&u.push("backend"),l&&u.push("frontend"),console.log(`[TypeCheck] Checking ${u.join(" & ")}...`);let d=[];if(c){let p=await n.checkBackendBuild();!p.success&&p.errors&&d.push(`## Backend Build Errors (in ${s})
1357
+ ${U.join(`
1358
+ `)}`:"";f.backendError||(f.backendError=`Backend failed to start.${R}`)}return P&&!O.web&&(f.success=!1,f.frontendError||(f.frontendError="Frontend failed to start")),f},Rt=async()=>{if(!c||!I.existsSync(c))return{success:!0};try{return ie(h,{cwd:c,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),{success:!0}}catch(S){let f=S;return{success:!1,errors:f.stdout||f.stderr||"Build failed"}}},Tt=async()=>{if(!u||!I.existsSync(ne.join(u,"package.json")))return{success:!0};try{return ie(E,{cwd:u,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),{success:!0}}catch(S){let f=S;return{success:!1,errors:f.stdout||f.stderr||"Type check failed"}}},gn=async()=>{let[S,f]=await Promise.all([Rt(),Tt()]);return{backend:S,frontend:f}},It=async(S,f)=>{let k=S==="backend"?x:w;if(!I.existsSync(k))return[`Log file not found: ${k}`];try{return ie(`tail -n ${f} ${k}`,{encoding:"utf-8"}).split(`
1359
+ `).filter(Boolean)}catch(P){return[`Error reading logs: ${P instanceof Error?P.message:String(P)}`]}};return{startBackend:v,startFrontend:g,stopBackend:j,stopFrontend:L,restartServices:un,checkHealth:se,waitForHealth:be,getProcesses:()=>({backend:m,frontend:D}),checkBackendBuild:Rt,checkFrontendTypes:Tt,runTypeChecks:gn,tailLogs:It,checkSwaggerEndpoints:async S=>{let f=ne.join(e,"swagger.json");if(!I.existsSync(f))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let k=JSON.parse(I.readFileSync(f,"utf-8")),P=Object.keys(k.paths||{}),O=[];for(let U of P)if(U.toLowerCase().includes(S.toLowerCase())){let R=Object.keys(k.paths[U]);for(let Z of R)O.push(`${Z.toUpperCase()} ${U}`)}return{foundEndpoints:O,totalEndpoints:P.length}}catch(k){return{foundEndpoints:[`Error parsing swagger.json: ${k instanceof Error?k.message:String(k)}`],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 ae}from"child_process";function Fe(n){let e=async()=>{try{return ae("git status --porcelain",{cwd:n,encoding:"utf-8"}).trim().length>0}catch{return!1}},t=async()=>{try{return ae("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,l=`${r?"[agent] (partial)":"[agent]"} ${i}`;ae("git add -A",{cwd:n}),ae(`git commit -m "${l.replace(/"/g,'\\"')}"`,{cwd:n,encoding:"utf-8"});let c=ae("git rev-parse --short HEAD",{cwd:n,encoding:"utf-8"}).trim();try{ae("git push",{cwd:n,stdio:"pipe"})}catch(u){let d=u instanceof Error?u.message:String(u);if(d.includes("no upstream branch")){let p=await t();ae(`git push --set-upstream origin ${p}`,{cwd:n,stdio:"pipe"})}else return console.error("[Git] Push failed:",d),{success:!1,commitHash:c,commitSucceeded:!0,pushFailed:!0,error:d}}return{success:!0,commitHash:c}}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 q=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 tt.Instance;if(n==="IDeploymentHub")return ot.Instance;if(n==="IKanbanHub")return rt.Instance;if(n==="IAgentHub")return at.Instance;if(n==="ISlaveHub")return lt.Instance;if(n==="ISlaveWatcherHub")return dt.Instance;if(n==="ITestHub")return gt.Instance},Yt=n=>{if(n==="IDeploymentWatcherClient")return ht.Instance;if(n==="IDeploymentHubClient")return ft.Instance;if(n==="IKanbanBoardClient")return yt.Instance;if(n==="IAgentReceiver")return bt.Instance;if(n==="IBackofficeReceiver")return St.Instance;if(n==="ISlaveHubClient")return wt.Instance;if(n==="ISlaveWatcherClient")return vt.Instance;if(n==="ITestHubClient")return kt.Instance},tt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new nt(e)},nt=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)},ot=class n{static Instance=new n;constructor(){}createHubProxy=e=>new st(e)},st=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)},rt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new it(e)},it=class{constructor(e){this.connection=e}joinBoard=async e=>await this.connection.invoke("JoinBoard",e);leaveBoard=async e=>await this.connection.invoke("LeaveBoard",e)},at=class n{static Instance=new n;constructor(){}createHubProxy=e=>new ct(e)},ct=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)},lt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new pt(e)},pt=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)},dt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new ut(e)},ut=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)},gt=class n{static Instance=new n;constructor(){}createHubProxy=e=>new mt(e)},mt=class{constructor(e){this.connection=e}joinProject=async e=>await this.connection.invoke("JoinProject",e);leaveProject=async e=>await this.connection.invoke("LeaveProject",e)},ht=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 q(e,i)}},ft=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...l)=>t.deploy(...l),s=(...l)=>t.stop(...l),r=(...l)=>t.startLogStreaming(...l),i=(...l)=>t.stopLogStreaming(...l);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 q(e,a)}},yt=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),l=(...m)=>t.cardCreated(...m),c=(...m)=>t.cardUpdated(...m),u=(...m)=>t.cardDeleted(...m),d=(...m)=>t.subtaskCreated(...m),p=(...m)=>t.subtaskUpdated(...m),h=(...m)=>t.subtaskDeleted(...m),C=(...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",l),e.on("CardUpdated",c),e.on("CardDeleted",u),e.on("SubtaskCreated",d),e.on("SubtaskUpdated",p),e.on("SubtaskDeleted",h),e.on("NoteCreated",C),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:l},{methodName:"CardUpdated",method:c},{methodName:"CardDeleted",method:u},{methodName:"SubtaskCreated",method:d},{methodName:"SubtaskUpdated",method:p},{methodName:"SubtaskDeleted",method:h},{methodName:"NoteCreated",method:C},{methodName:"NoteUpdated",method:E},{methodName:"NoteDeleted",method:x}];return new q(e,w)}},bt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...d)=>t.initSession(...d),s=(...d)=>t.runPrompt(...d),r=(...d)=>t.setModel(...d),i=()=>t.stopAgent(),a=()=>t.ping(),l=(...d)=>t.switchSession(...d),c=(...d)=>t.projectPromptUpdated(...d);e.on("InitSession",o),e.on("RunPrompt",s),e.on("SetModel",r),e.on("StopAgent",i),e.on("Ping",a),e.on("SwitchSession",l),e.on("ProjectPromptUpdated",c);let u=[{methodName:"InitSession",method:o},{methodName:"RunPrompt",method:s},{methodName:"SetModel",method:r},{methodName:"StopAgent",method:i},{methodName:"Ping",method:a},{methodName:"SwitchSession",method:l},{methodName:"ProjectPromptUpdated",method:c}];return new q(e,u)}},St=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),l=(...y)=>t.previewBuildStatus(...y),c=(...y)=>t.previewReload(...y),u=(...y)=>t.questionsReceived(...y),d=(...y)=>t.specificationUpdated(...y),p=(...y)=>t.singleQuestionReceived(...y),h=(...y)=>t.questionSessionEnded(...y),C=(...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",l),e.on("PreviewReload",c),e.on("QuestionsReceived",u),e.on("SpecificationUpdated",d),e.on("SingleQuestionReceived",p),e.on("QuestionSessionEnded",h),e.on("CreditsUpdated",C),e.on("InsufficientCredits",E),e.on("ProjectSessionStatusChanged",x),e.on("ClaudeLoginUrlReceived",w),e.on("ClaudeLoginCompleted",m);let D=[{methodName:"SessionOutput",method:o},{methodName:"SessionCost",method:s},{methodName:"SessionCompleted",method:r},{methodName:"ContainerStatus",method:i},{methodName:"SlaveCapacityUpdate",method:a},{methodName:"PreviewBuildStatus",method:l},{methodName:"PreviewReload",method:c},{methodName:"QuestionsReceived",method:u},{methodName:"SpecificationUpdated",method:d},{methodName:"SingleQuestionReceived",method:p},{methodName:"QuestionSessionEnded",method:h},{methodName:"CreditsUpdated",method:C},{methodName:"InsufficientCredits",method:E},{methodName:"ProjectSessionStatusChanged",method:x},{methodName:"ClaudeLoginUrlReceived",method:w},{methodName:"ClaudeLoginCompleted",method:m}];return new q(e,D)}},wt=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(),l=(...w)=>t.streamContainerLogs(...w),c=(...w)=>t.stopContainerLogStream(...w),u=(...w)=>t.restartLabAgent(...w),d=(...w)=>t.terminateDockerContainer(...w),p=(...w)=>t.streamSlaveAgentLogs(...w),h=()=>t.stopSlaveAgentLogStream(),C=(...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",l),e.on("StopContainerLogStream",c),e.on("RestartLabAgent",u),e.on("TerminateDockerContainer",d),e.on("StreamSlaveAgentLogs",p),e.on("StopSlaveAgentLogStream",h),e.on("StartClaudeLogin",C),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:l},{methodName:"StopContainerLogStream",method:c},{methodName:"RestartLabAgent",method:u},{methodName:"TerminateDockerContainer",method:d},{methodName:"StreamSlaveAgentLogs",method:p},{methodName:"StopSlaveAgentLogStream",method:h},{methodName:"StartClaudeLogin",method:C},{methodName:"SubmitClaudeLoginCode",method:E}];return new q(e,x)}},vt=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),l=(...p)=>t.slaveAgentLogReceived(...p),c=(...p)=>t.claudeLoginUrlReceived(...p),u=(...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",l),e.on("ClaudeLoginUrlReceived",c),e.on("ClaudeLoginCompleted",u);let d=[{methodName:"DockerContainersUpdated",method:o},{methodName:"ContainerLogReceived",method:s},{methodName:"AgentRestartCompleted",method:r},{methodName:"ContainerTerminationCompleted",method:i},{methodName:"SlaveCapacityUpdated",method:a},{methodName:"SlaveAgentLogReceived",method:l},{methodName:"ClaudeLoginUrlReceived",method:c},{methodName:"ClaudeLoginCompleted",method:u}];return new q(e,d)}},kt=class n{static Instance=new n;constructor(){}register=(e,t)=>{let o=(...c)=>t.testRunCreated(...c),s=(...c)=>t.testRunUpdated(...c),r=(...c)=>t.testSuiteCreated(...c),i=(...c)=>t.testCreated(...c),a=(...c)=>t.testUpdated(...c);e.on("TestRunCreated",o),e.on("TestRunUpdated",s),e.on("TestSuiteCreated",r),e.on("TestCreated",i),e.on("TestUpdated",a);let l=[{methodName:"TestRunCreated",method:o},{methodName:"TestRunUpdated",method:s},{methodName:"TestSuiteCreated",method:r},{methodName:"TestCreated",method:i},{methodName:"TestUpdated",method:a}];return new q(e,l)}};var Hn=$n(Fn),$e=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
+ `;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 He=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 $ from"path";var Be=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(c=>!c.hostname),l={hostname:o,service:`http://localhost:${t}`};a!==-1?s.ingress.splice(a,0,l):(s.ingress.push(l),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 l=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();l.success?console.log(`[TunnelManager] \u2713 DNS updated: ${e} -> ${t}`):console.error(`[TunnelManager] Failed to update DNS: ${l.errors.map(c=>c.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(l=>l.message).join(", ")}`)}}catch(s){console.error(`[TunnelManager] Error updating DNS for ${e}:`,s)}}};var Ct=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 F(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",We=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 Be),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,l=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: ${l})`),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 c=new A("Clean workspace");Gn("rm -rf /workspace/* /workspace/.* 2>/dev/null || true",{stdio:"inherit"}),c.stop();let u=new A("Clone repository");await this.cloneRepository(t,o),this.currentRepoUrl=t,this.currentBranchName=o,u.stop(),await this.installDependencies(),this.lastLockfileHash=this.getLockfileHash(),console.log("[Init] Starting services...");let d=new A("Start backend (dotnet)");await this.serviceManager.startBackend(),d.stop();let p=new A("Start frontend (vite)");await this.serviceManager.startFrontend(),p.stop();let h=new A("Wait for health check");await this.serviceManager.waitForHealth(3e4),h.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 l=a instanceof Error?a.message:"Unknown error";console.error("[InitSession] Background update failed:",l),await this.connection.reportStatus("Error",l,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 F(`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 l=new A("Restart services");await this.serviceManager.restartServices("both"),l.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 l=1;l<=i;l++){await F("rm -rf /workspace/* /workspace/.* 2>/dev/null || true");try{console.log(`[Clone] Attempt ${l}/${i}...`);let c=Date.now();await F(`git clone -b ${t} "${e}" /workspace`,{timeout:12e4});let u=((Date.now()-c)/1e3).toFixed(2);console.log(`[Clone] \u2713 Clone succeeded on attempt ${l} (${u}s)`),await F('cd /workspace && git config user.email "agent@dotnetmentor.se" && git config user.name "Agent"'),console.log("[Clone] \u2713 Repository cloned and configured");return}catch(c){let u=c instanceof Error?c.message:String(c);console.error(`[Clone] \u274C Attempt ${l}/${i} failed: ${u}`);let d=0;try{let{stdout:p}=await Ct(`git ls-remote --heads "${e}" 2>&1`,{timeout:15e3}),h=p.trim();d=h?h.split(`
1361
+ `).length:0,console.log(`[Clone] ls-remote: ${d} branch(es) found${h?`: ${h.split(`
1362
+ `).slice(0,3).join(", ")}`:" (empty repo \u2014 likely still generating from template)"}`)}catch(p){let h=p instanceof Error?p.message:String(p);console.error(`[Clone] ls-remote also failed: ${h}`)}if(l<i){let p=a[l]||15e3,h=d===0?"repo appears empty (template still generating)":`branch '${t}' not found`;console.log(`[Clone] Retrying in ${p/1e3}s... (${h})`),await new Promise(C=>setTimeout(C,p))}else throw console.error(`[Clone] \u274C All ${i} attempts failed for ${o}`),await this.connection.reportError({message:`Git clone failed after ${i} attempts: ${u}`,errorType:"GitCloneError",operation:"cloneRepository",isFatal:!0}),c}}}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 F(`git pull origin ${e}`,{cwd:this.workspaceDir,timeout:6e4});else{await F("git fetch origin",{cwd:this.workspaceDir,timeout:6e4});let{stdout:t}=await Ct(`git ls-remote --heads origin ${e}`,{cwd:this.workspaceDir,timeout:3e4});t.trim().length>0?await F(`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 F(`git checkout -b ${e}`,{cwd:this.workspaceDir,timeout:3e4})),this.currentBranchName=e}console.log(`[Branch] \u2713 Now on ${e}`)}getLockfileHash(){let e=$.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 Ct(`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(`
1363
+ `).filter(l=>l.length>0);console.log(`[CodeDiff] ${r.length} files changed between ${e} and ${t}`);let i=[".cs",".tsx",".ts",".json",".csproj"],a=r.some(l=>i.some(c=>l.endsWith(c)));return a&&console.log("[CodeDiff] Found code changes that require service restart"),a}catch(o){return console.error("[CodeDiff] Failed to check diff:",o instanceof Error?o.message:o),!0}}async installDependencies(){let e=new A("TOTAL INSTALL DEPENDENCIES");if(_.existsSync($.join(this.workspaceDir,"packages/dotnet-api"))){let t=new A("dotnet restore");await F("dotnet restore",{cwd:$.join(this.workspaceDir,"packages/dotnet-api"),timeout:12e4}),t.stop()}if(_.existsSync($.join(this.workspaceDir,"packages/backoffice-web/package.json"))){let t=$.join(this.workspaceDir,"packages/backoffice-web"),o=$.join(t,"node_modules"),s=$.join(t,"package-lock.json"),r=$.join(o,".lockhash"),i="/opt/cache";_.mkdirSync(i,{recursive:!0});let a=_.existsSync(s)?Vt("sha256").update(_.readFileSync(s)).digest("hex"):null,l=_.existsSync(r)?_.readFileSync(r,"utf-8").trim():null,c=$.join(i,"node_modules","current_hash"),u=_.existsSync(c)?_.readFileSync(c,"utf-8").trim():null,d=u?$.join(i,"node_modules",u):null,p=a?$.join(i,"node_modules",a):null;if(console.log(`[Install] node_modules exists: ${_.existsSync(o)}`),console.log(`[Install] lockHash (current branch): ${a?.substring(0,8)||"null"}`),console.log(`[Install] installedHash: ${l?.substring(0,8)||"null"}`),console.log(`[Install] dockerCacheHash (from image): ${u?.substring(0,8)||"null"}`),console.log(`[Install] exactMatchCache exists: ${p?_.existsSync(p):!1}`),console.log(`[Install] dockerCachedNodeModules exists: ${d?_.existsSync(d):!1}`),!_.existsSync(o)){if(p&&_.existsSync(p)){let C=new A("Copy exact-match cached node_modules");console.log(`[Install] Copying exact-match cached node_modules (hash ${a?.substring(0,8)})...`),await F(`cp -r "${p}" "${o}"`),a&&_.writeFileSync(r,a),l=a,C.stop()}else if(d&&_.existsSync(d)){let C=new A("Copy Docker-cached node_modules (as base)");console.log(`[Install] Copying Docker-cached node_modules as base (hash ${u?.substring(0,8)}, need ${a?.substring(0,8)})...`),await F(`cp -r "${d}" "${o}"`),C.stop()}}let h=!_.existsSync(o)||a&&a!==l;if(console.log(`[Install] needsInstall: ${h}`),!h)console.log("[Install] npm install skipped (cache OK)");else{let C=new A("npm install --prefer-offline");await F("npm install --prefer-offline --no-progress --fund=false",{cwd:t,timeout:18e4}),C.stop(),a&&(_.mkdirSync(o,{recursive:!0}),_.writeFileSync(r,a))}this.lastLockfileHash=a}e.stop()}};function Zt(n,e,t){let o=n.getHubProxy(),s=process.env.CONTAINER_ID||"unknown";return{onAssistantText:async r=>{let i={type:"Text",content:r,isError:!1};await o.reportSessionOutput(s,e,i).catch(a=>{console.error("Failed to report assistant text:",a)})},onAssistantToolUse:async(r,i)=>{if(["Write","Edit","MultiEdit"].includes(r)){let l=i,c=l.file_path||l.target_file;c&&t.onFileModified(c)}let a={type:"ToolUse",toolName:r,toolInput:JSON.stringify(i),isError:!1};await o.reportSessionOutput(s,e,a).catch(l=>{console.error("Failed to report tool use:",l)})},onResult:async(r,i)=>{let a={type:"System",event:"completed",content:r,cost:i,isError:!1};await o.reportSessionOutput(s,e,a).catch(l=>{console.error("Failed to report result:",l)})},onError:async r=>{let i={type:"System",event:"error",content:r,isError:!0};await o.reportSessionOutput(s,e,i).catch(a=>{console.error("Failed to report error:",a)})},onAborted:async()=>{let r={type:"System",event:"aborted",content:"Agent stopped by user",isError:!1};await o.reportSessionOutput(s,e,r).catch(i=>{console.error("Failed to report abort:",i)})},onSystemInit:async r=>{console.log(`[Callbacks] Claude session initialized: ${r}`),t.onClaudeSessionId(r),await o.setClaudeSessionId(e,r).catch(i=>{console.error("Failed to set Claude session ID:",i)})},onRawMessage:r=>{if(r.type==="assistant"&&r.message?.usage){let i=r.message.usage,a={totalCostUsd:Yn(i),inputTokens:i.input_tokens||0,outputTokens:i.output_tokens||0,cacheCreationTokens:i.cache_creation_input_tokens||0,cacheReadTokens:i.cache_read_input_tokens||0};o.reportSessionCost(s,e,a).catch(l=>{console.error("Failed to report cost:",l)})}}}}var Ge={inputPerMillion:3,outputPerMillion:15,cacheReadPerMillion:.3,cacheCreationPerMillion:3.75};function Yn(n){return(n.input_tokens||0)/1e6*Ge.inputPerMillion+(n.output_tokens||0)/1e6*Ge.outputPerMillion+(n.cache_read_input_tokens||0)/1e6*Ge.cacheReadPerMillion+(n.cache_creation_input_tokens||0)/1e6*Ge.cacheCreationPerMillion}import*as pe from"fs";import*as en from"path";function tn(n,e){let t=en.join(n,`.agent-questions-${e}.json`);if(!pe.existsSync(t))return null;try{let o=pe.readFileSync(t,"utf-8");return pe.unlinkSync(t),JSON.parse(o)}catch(o){return console.error("Failed to read questions file:",o),null}}async function nn(n,e,t,o){if(e.size===0)return console.log("[TypeCheck] No code changes, skipping type checks"),{passed:!0};let s=o?G(o):`${t}/packages/dotnet-api`,r=o?K(o):`${t}/packages/backoffice-web`,i=o?.services?.backend?.extensions??[".cs",".csproj"],a=o?.services?.frontend?.extensions??[".ts",".tsx"],l=s&&[...e].some(p=>p.includes(s)||i.some(h=>p.endsWith(h))),c=r&&[...e].some(p=>p.includes(r)||a.some(h=>p.endsWith(h)));if(!l&&!c)return console.log("[TypeCheck] No code changes, skipping type checks"),{passed:!0};let u=[];l&&u.push("backend"),c&&u.push("frontend"),console.log(`[TypeCheck] Checking ${u.join(" & ")}...`);let d=[];if(l){let p=await n.checkBackendBuild();!p.success&&p.errors&&d.push(`## Backend Build Errors (in ${s})
1364
1364
  \`\`\`
1365
1365
  ${p.errors}
1366
- \`\`\``)}if(l){let p=await n.checkFrontendTypes();!p.success&&p.errors&&d.push(`## Frontend Type Errors (in ${r})
1366
+ \`\`\``)}if(c){let p=await n.checkFrontendTypes();!p.success&&p.errors&&d.push(`## Frontend Type Errors (in ${r})
1367
1367
  \`\`\`
1368
1368
  ${p.errors}
1369
1369
  \`\`\``)}return d.length>0?(console.log("[TypeCheck] \u274C Type errors found - will auto-correct"),{passed:!1,errorPrompt:`@debugger Type/build errors detected. Fix them.
@@ -1374,30 +1374,30 @@ ${d.join(`
1374
1374
 
1375
1375
  `)}
1376
1376
 
1377
- File paths like "src/..." are relative to the package directory shown in parentheses.`}):(console.log("[TypeCheck] \u2713 All type checks passed"),{passed:!0})}async function Ct(n,e,t,o,s){if(!await n.hasChanges()){console.log("[Git] No changes to commit");return}console.log("[Git] Committing changes...");let i=await n.commitAndPush(o,s);if(i.noChanges)console.log("[Git] No changes to commit");else if(i.pushFailed){let a=await n.getCurrentBranch();console.log(`[Git] \u2713 Committed ${i.commitHash||""}`),console.error(`[Git] \u274C Push failed: ${i.error}`),await e.getHubProxy().reportSessionOutput(process.env.CONTAINER_ID||"unknown",t,{type:"System",event:"push_failed",content:`Committed locally but failed to push to ${a}. Your changes are NOT on GitHub. Error: ${i.error}`,isError:!0}).catch(l=>{console.error("[Git] Failed to report push failure:",l)})}else if(i.success){let a=await n.getCurrentBranch();console.log(`[Git] \u2713 Committed ${i.commitHash||""}`),console.log(`[Git] \u2192 Pushed to ${a}`),await e.getHubProxy().reportSessionOutput(process.env.CONTAINER_ID||"unknown",t,{type:"System",event:"committed",content:`Changes committed to ${a}`,isError:!1}).catch(l=>{console.error("[Git] Failed to report commit:",l)})}else console.error(`[Git] \u274C Git error: ${i.error}`)}import*as J from"fs";import*as Ge from"path";var We=class{constructor(e,t,o,s,r=!0,i=!0,a,c,l=!0,u){this.connection=e;this.lifecycle=t;this.serviceManager=o;this.workspaceDir=s;this.enableAutoTypecheck=r;this.enableAutoCommit=i;this.setupPlanningTransport=a;this.projectConfig=c;this.useDefaultStack=l;this.anthropicApiKey=u;this.gitManager=Oe(s),this.claudeSessionIdMap=this.loadSessionMap()}currentSession=null;claudeSessionIdMap=new Map;currentAbortController=null;gitManager;get sessionMapPath(){return Ge.join(this.workspaceDir,".sdd","claude-session-map.json")}loadSessionMap(){try{if(J.existsSync(this.sessionMapPath)){let e=JSON.parse(J.readFileSync(this.sessionMapPath,"utf-8")),t=new Map(Object.entries(e));return console.log(`[Receiver] Loaded ${t.size} claude session mappings from disk`),t}else return console.log("[Receiver] No session map found on disk"),new Map}catch(e){console.warn("[Receiver] Failed to load session map from disk:",e)}return new Map}persistSessionMap(){try{let e=Ge.dirname(this.sessionMapPath);J.existsSync(e)||J.mkdirSync(e,{recursive:!0});let t=Object.fromEntries(this.claudeSessionIdMap);J.writeFileSync(this.sessionMapPath,JSON.stringify(t,null,2))}catch(e){console.warn("[Receiver] Failed to persist session map to disk:",e)}}async initSession(e){console.log(`[Receiver] InitSession for session ${e.sessionId}`),this.setupPlanningTransport&&e.projectId&&this.setupPlanningTransport(e.projectId),e.projectId&&await this.fetchProjectPrompt(e.projectId),this.currentSession={sessionId:e.sessionId,projectId:e.projectId,branchName:e.branchName,model:e.model==="auto"?void 0:e.model||"claude-haiku-4-5-20251001",debugMode:e.debugMode},await this.lifecycle.handleInitSession(e),e.prompt&&await this.runPrompt(e.sessionId,e.prompt,e.claudeSessionId)}async runPrompt(e,t,o,s=!1){let r=me(t);if(console.log(`[Receiver] RunPrompt for session ${e}${o?` (ClaudeSessionId: ${o})`:""}${s?" [DEBUG MODE]":""}: ${r.substring(0,50)}...`),(!this.currentSession||this.currentSession.sessionId!==e)&&(console.log(`[Receiver] Session mismatch: expected ${this.currentSession?.sessionId}, got ${e}, switching...`),await this.switchSession(e),!this.currentSession)){console.error("[Receiver] Failed to create session context");return}let i=this.claudeSessionIdMap.get(e);if(o&&i!==o){console.warn(`[Receiver] Claude session not found in container: ${o}`);let l=this.connection.getHubProxy();await l.reportSessionOutput(process.env.CONTAINER_ID||"unknown",e,{type:"System",event:"sessionNotFound",content:o,isError:!0}),await this.connection.reportStatus("Ready","Session lost - summary needed",e,this.currentSession.projectId),await l.sessionCompleted(process.env.CONTAINER_ID||"unknown",e,0);return}await this.connection.reportStatus("Active",void 0,e,this.currentSession.projectId),this.currentSession.debugMode=s,this.currentAbortController=new AbortController;let a=i||null,c=new Set;try{let l=await Ue(r,{model:this.currentSession.model,sessionId:a||null,projectId:this.currentSession.projectId||null,apiUrl:this.connection.getMasterUrl(),debugLog:!0,debugMode:s,abortController:this.currentAbortController,projectConfig:this.projectConfig,useDefaultStack:this.useDefaultStack,anthropicApiKey:this.anthropicApiKey,callbacks:Zt(this.connection,e,{onClaudeSessionId:p=>{this.claudeSessionIdMap.set(e,p),this.persistSessionMap()},onFileModified:p=>{c.add(p)}})}),u=tn(this.workspaceDir,e);if(u&&u.length>0){console.log(`[Receiver] ${u.length} pending questions found, waiting for user answers`),await this.connection.reportStatus("Ready",void 0,e,this.currentSession.projectId),await this.connection.getHubProxy().sessionCompleted(process.env.CONTAINER_ID||"unknown",e,0);return}if(this.enableAutoTypecheck&&!l.error&&!l.aborted){let p=await nn(this.serviceManager,c,this.workspaceDir,this.projectConfig);if(!p.passed&&p.errorPrompt){console.log("[Receiver] Type errors detected, auto-correcting..."),await this.runPrompt(e,p.errorPrompt,o);return}}this.enableAutoCommit&&!l.error&&!l.aborted?await Ct(this.gitManager,this.connection,e,t,!1):(l.error||l.aborted)&&this.enableAutoCommit&&await Ct(this.gitManager,this.connection,e,t,!0),await this.connection.reportStatus("Ready",void 0,e,this.currentSession.projectId),await this.connection.getHubProxy().sessionCompleted(process.env.CONTAINER_ID||"unknown",e,l.error?1:0)}catch(l){let u=l instanceof Error&&l.name==="AbortError",d=l instanceof Error?l.message:"Unknown error";u?console.log(`[Receiver] Agent aborted for session ${e}`):(console.error("[Receiver] Agent error:",d),await this.connection.reportStatus("Error",d,e,this.currentSession.projectId)),await this.connection.getHubProxy().sessionCompleted(process.env.CONTAINER_ID||"unknown",e,u?0:1)}finally{this.currentAbortController=null}}async setModel(e){console.log(`[Receiver] Model changed to: ${e}`),this.currentSession&&(this.currentSession.model=e==="auto"?void 0:e)}async stopAgent(){console.log("[Receiver] Stop command received"),this.currentAbortController&&this.currentAbortController.abort()}async ping(){await this.connection.getConnection().invoke("Pong",process.env.CONTAINER_ID||"unknown")}async switchSession(e){console.log(`[Receiver] SwitchSession to ${e}`),this.currentSession?this.currentSession.sessionId=e:(console.log(`[Receiver] Creating new session context for ${e}`),this.currentSession={sessionId:e,projectId:process.env.PROJECT_ID||"unknown",branchName:"main",model:void 0,debugMode:!1})}async projectPromptUpdated(e){console.log(`[Receiver] ProjectPromptUpdated received (${e.length} chars)`),Xe(e)}async fetchProjectPrompt(e){try{let t=this.connection.getMasterUrl(),o=this.connection.getProjectKey(),s=await fetch(`${t}/api/projects/${e}/prompt`,{method:"GET",headers:{"Content-Type":"application/json","X-Project-Key":o}});if(!s.ok){console.log(`[Receiver] Failed to fetch project prompt: ${s.status}`);return}let r=await s.json();r.prompt?(Xe(r.prompt),console.log(`[Receiver] Initial project prompt loaded (${r.prompt.length} chars)`)):console.log(`[Receiver] No project prompt set for project ${e}`)}catch(t){console.error("[Receiver] Error fetching project prompt:",t)}}};import*as sn from"http";import*as rn from"crypto";import{exec as zn}from"child_process";import on from"inquirer";function Jn(n){let e=process.platform,t;e==="darwin"?t=`open "${n}"`:e==="win32"?t=`start "" "${n}"`:t=`xdg-open "${n}"`,zn(t,o=>{})}async function an(n){let e=rn.randomBytes(32).toString("hex");return new Promise((t,o)=>{let s=sn.createServer((i,a)=>{if(a.setHeader("Access-Control-Allow-Origin",n),a.setHeader("Access-Control-Allow-Methods","POST, OPTIONS"),a.setHeader("Access-Control-Allow-Headers","Content-Type"),i.method==="OPTIONS"){a.writeHead(204),a.end();return}if(i.method==="POST"&&i.url==="/callback"){let c="";i.on("data",l=>{c+=l}),i.on("end",()=>{try{let l=JSON.parse(c);if(l.state!==e){a.writeHead(403,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Invalid state parameter"}));return}if(!l.masterUrl||!l.projectId||!l.projectKey||!l.projectName){a.writeHead(400,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Missing required fields"}));return}if(!l.projectKey.startsWith("pk_proj_")){a.writeHead(400,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Invalid project key format"}));return}a.writeHead(200,{"Content-Type":"application/json"}),a.end(JSON.stringify({success:!0})),clearTimeout(r),s.close(),t({masterUrl:l.masterUrl,projectId:l.projectId,projectKey:l.projectKey,projectName:l.projectName})}catch{a.writeHead(400,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Invalid JSON"}))}});return}a.writeHead(404),a.end()});s.listen(0,"127.0.0.1",()=>{let i=s.address();if(!i||typeof i=="string"){s.close(),o(new Error("Failed to start local server"));return}let a=i.port,c=`${n}/cli-connect?port=${a}&state=${e}`;console.log(`
1377
+ File paths like "src/..." are relative to the package directory shown in parentheses.`}):(console.log("[TypeCheck] \u2713 All type checks passed"),{passed:!0})}async function _t(n,e,t,o,s){if(!await n.hasChanges()){console.log("[Git] No changes to commit");return}console.log("[Git] Committing changes...");let i=await n.commitAndPush(o,s);if(i.noChanges)console.log("[Git] No changes to commit");else if(i.pushFailed){let a=await n.getCurrentBranch();console.log(`[Git] \u2713 Committed ${i.commitHash||""}`),console.error(`[Git] \u274C Push failed: ${i.error}`),await e.getHubProxy().reportSessionOutput(process.env.CONTAINER_ID||"unknown",t,{type:"System",event:"push_failed",content:`Committed locally but failed to push to ${a}. Your changes are NOT on GitHub. Error: ${i.error}`,isError:!0}).catch(c=>{console.error("[Git] Failed to report push failure:",c)})}else if(i.success){let a=await n.getCurrentBranch();console.log(`[Git] \u2713 Committed ${i.commitHash||""}`),console.log(`[Git] \u2192 Pushed to ${a}`),await e.getHubProxy().reportSessionOutput(process.env.CONTAINER_ID||"unknown",t,{type:"System",event:"committed",content:`Changes committed to ${a}`,isError:!1}).catch(c=>{console.error("[Git] Failed to report commit:",c)})}else console.error(`[Git] \u274C Git error: ${i.error}`)}import*as V from"fs";import*as qe from"path";var Ke=class{constructor(e,t,o,s,r=!0,i=!0,a,l,c=!0,u){this.connection=e;this.lifecycle=t;this.serviceManager=o;this.workspaceDir=s;this.enableAutoTypecheck=r;this.enableAutoCommit=i;this.setupPlanningTransport=a;this.projectConfig=l;this.useDefaultStack=c;this.anthropicApiKey=u;this.gitManager=Fe(s),this.claudeSessionIdMap=this.loadSessionMap()}currentSession=null;claudeSessionIdMap=new Map;currentAbortController=null;gitManager;get sessionMapPath(){return qe.join(this.workspaceDir,".sdd","claude-session-map.json")}loadSessionMap(){try{if(V.existsSync(this.sessionMapPath)){let e=JSON.parse(V.readFileSync(this.sessionMapPath,"utf-8")),t=new Map(Object.entries(e));return console.log(`[Receiver] Loaded ${t.size} claude session mappings from disk`),t}else return console.log("[Receiver] No session map found on disk"),new Map}catch(e){console.warn("[Receiver] Failed to load session map from disk:",e)}return new Map}persistSessionMap(){try{let e=qe.dirname(this.sessionMapPath);V.existsSync(e)||V.mkdirSync(e,{recursive:!0});let t=Object.fromEntries(this.claudeSessionIdMap);V.writeFileSync(this.sessionMapPath,JSON.stringify(t,null,2))}catch(e){console.warn("[Receiver] Failed to persist session map to disk:",e)}}async initSession(e){console.log(`[Receiver] InitSession for session ${e.sessionId}`),this.setupPlanningTransport&&e.projectId&&this.setupPlanningTransport(e.projectId),e.projectId&&await this.fetchProjectPrompt(e.projectId),this.currentSession={sessionId:e.sessionId,projectId:e.projectId,branchName:e.branchName,model:e.model==="auto"?void 0:e.model||"claude-haiku-4-5-20251001",debugMode:e.debugMode},await this.lifecycle.handleInitSession(e),e.prompt&&await this.runPrompt(e.sessionId,e.prompt,e.claudeSessionId)}async runPrompt(e,t,o,s=!1){let r=he(t);if(console.log(`[Receiver] RunPrompt for session ${e}${o?` (ClaudeSessionId: ${o})`:""}${s?" [DEBUG MODE]":""}: ${r.substring(0,50)}...`),(!this.currentSession||this.currentSession.sessionId!==e)&&(console.log(`[Receiver] Session mismatch: expected ${this.currentSession?.sessionId}, got ${e}, switching...`),await this.switchSession(e),!this.currentSession)){console.error("[Receiver] Failed to create session context");return}let i=this.claudeSessionIdMap.get(e);if(o&&i!==o){console.warn(`[Receiver] Claude session not found in container: ${o}`);let c=this.connection.getHubProxy();await c.reportSessionOutput(process.env.CONTAINER_ID||"unknown",e,{type:"System",event:"sessionNotFound",content:o,isError:!0}),await this.connection.reportStatus("Ready","Session lost - summary needed",e,this.currentSession.projectId),await c.sessionCompleted(process.env.CONTAINER_ID||"unknown",e,0);return}await this.connection.reportStatus("Active",void 0,e,this.currentSession.projectId),this.currentSession.debugMode=s,this.currentAbortController=new AbortController;let a=i||null,l=new Set;try{let c=await Oe(r,{model:this.currentSession.model,sessionId:a||null,projectId:this.currentSession.projectId||null,apiUrl:this.connection.getMasterUrl(),debugLog:!0,debugMode:s,abortController:this.currentAbortController,projectConfig:this.projectConfig,useDefaultStack:this.useDefaultStack,anthropicApiKey:this.anthropicApiKey,callbacks:Zt(this.connection,e,{onClaudeSessionId:p=>{this.claudeSessionIdMap.set(e,p),this.persistSessionMap()},onFileModified:p=>{l.add(p)}})}),u=tn(this.workspaceDir,e);if(u&&u.length>0){console.log(`[Receiver] ${u.length} pending questions found, waiting for user answers`),await this.connection.reportStatus("Ready",void 0,e,this.currentSession.projectId),await this.connection.getHubProxy().sessionCompleted(process.env.CONTAINER_ID||"unknown",e,0);return}if(this.enableAutoTypecheck&&!c.error&&!c.aborted){let p=await nn(this.serviceManager,l,this.workspaceDir,this.projectConfig);if(!p.passed&&p.errorPrompt){console.log("[Receiver] Type errors detected, auto-correcting..."),await this.runPrompt(e,p.errorPrompt,o);return}}this.enableAutoCommit&&!c.error&&!c.aborted?await _t(this.gitManager,this.connection,e,t,!1):(c.error||c.aborted)&&this.enableAutoCommit&&await _t(this.gitManager,this.connection,e,t,!0),await this.connection.reportStatus("Ready",void 0,e,this.currentSession.projectId),await this.connection.getHubProxy().sessionCompleted(process.env.CONTAINER_ID||"unknown",e,c.error?1:0)}catch(c){let u=c instanceof Error&&c.name==="AbortError",d=c instanceof Error?c.message:"Unknown error";u?console.log(`[Receiver] Agent aborted for session ${e}`):(console.error("[Receiver] Agent error:",d),await this.connection.reportStatus("Error",d,e,this.currentSession.projectId)),await this.connection.getHubProxy().sessionCompleted(process.env.CONTAINER_ID||"unknown",e,u?0:1)}finally{this.currentAbortController=null}}async setModel(e){console.log(`[Receiver] Model changed to: ${e}`),this.currentSession&&(this.currentSession.model=e==="auto"?void 0:e)}async stopAgent(){console.log("[Receiver] Stop command received"),this.currentAbortController&&this.currentAbortController.abort()}async ping(){await this.connection.getConnection().invoke("Pong",process.env.CONTAINER_ID||"unknown")}async switchSession(e){console.log(`[Receiver] SwitchSession to ${e}`),this.currentSession?this.currentSession.sessionId=e:(console.log(`[Receiver] Creating new session context for ${e}`),this.currentSession={sessionId:e,projectId:process.env.PROJECT_ID||"unknown",branchName:"main",model:void 0,debugMode:!1})}async projectPromptUpdated(e){console.log(`[Receiver] ProjectPromptUpdated received (${e.length} chars)`),Ze(e)}async fetchProjectPrompt(e){try{let t=this.connection.getMasterUrl(),o=this.connection.getProjectKey(),s=await fetch(`${t}/api/projects/${e}/prompt`,{method:"GET",headers:{"Content-Type":"application/json","X-Project-Key":o}});if(!s.ok){console.log(`[Receiver] Failed to fetch project prompt: ${s.status}`);return}let r=await s.json();r.prompt?(Ze(r.prompt),console.log(`[Receiver] Initial project prompt loaded (${r.prompt.length} chars)`)):console.log(`[Receiver] No project prompt set for project ${e}`)}catch(t){console.error("[Receiver] Error fetching project prompt:",t)}}};import*as sn from"http";import*as rn from"crypto";import{exec as zn}from"child_process";import on from"inquirer";function Jn(n){let e=process.platform,t;e==="darwin"?t=`open "${n}"`:e==="win32"?t=`start "" "${n}"`:t=`xdg-open "${n}"`,zn(t,o=>{})}async function an(n){let e=rn.randomBytes(32).toString("hex");return new Promise((t,o)=>{let s=sn.createServer((i,a)=>{if(a.setHeader("Access-Control-Allow-Origin",n),a.setHeader("Access-Control-Allow-Methods","POST, OPTIONS"),a.setHeader("Access-Control-Allow-Headers","Content-Type"),i.method==="OPTIONS"){a.writeHead(204),a.end();return}if(i.method==="POST"&&i.url==="/callback"){let l="";i.on("data",c=>{l+=c}),i.on("end",()=>{try{let c=JSON.parse(l);if(c.state!==e){a.writeHead(403,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Invalid state parameter"}));return}if(!c.masterUrl||!c.projectId||!c.projectKey||!c.projectName){a.writeHead(400,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Missing required fields"}));return}if(!c.projectKey.startsWith("pk_proj_")){a.writeHead(400,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Invalid project key format"}));return}a.writeHead(200,{"Content-Type":"application/json"}),a.end(JSON.stringify({success:!0})),clearTimeout(r),s.close(),t({masterUrl:c.masterUrl,projectId:c.projectId,projectKey:c.projectKey,projectName:c.projectName})}catch{a.writeHead(400,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Invalid JSON"}))}});return}a.writeHead(404),a.end()});s.listen(0,"127.0.0.1",()=>{let i=s.address();if(!i||typeof i=="string"){s.close(),o(new Error("Failed to start local server"));return}let a=i.port,l=`${n}/cli-connect?port=${a}&state=${e}`;console.log(`
1378
1378
  \u{1F310} Opening browser for authentication...`),console.log(` If the browser doesn't open, visit this URL:
1379
- `),console.log(` ${c}
1379
+ `),console.log(` ${l}
1380
1380
  `),console.log(` Waiting for you to select a project...
1381
- `),Jn(c)});let r=setTimeout(()=>{s.close(),o(new Error("Browser authentication timed out after 5 minutes"))},5*60*1e3)})}async function cn(){let n=process.env.GLENN_CODE_APP_URL,e=process.env.GLENN_CODE_URL_PICKER==="true";if(n)return n;if(e){let{url:t}=await on.prompt([{type:"select",name:"url",message:"Which environment?",choices:[{name:"glenncode.ai (production)",value:"https://glenncode.ai"},{name:"glenncode.cc (staging)",value:"https://glenncode.cc"},{name:"localhost:4173 (development)",value:"http://localhost:4173"},{name:"Enter custom URL",value:"custom"}]}]);if(t==="custom"){let{customUrl:o}=await on.prompt([{type:"input",name:"customUrl",message:"Enter the URL:",validate:s=>{try{return new URL(s),!0}catch{return"Please enter a valid URL"}}}]);return o}return t}return"https://glenncode.ai"}process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT=process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT||"60000";var ln=Q.dirname(Qn(import.meta.url));function Vn(){let n=[Q.resolve(ln,"../package.json"),Q.resolve(ln,"../../../package.json")];for(let e of n)try{if(M.existsSync(e)){let t=JSON.parse(M.readFileSync(e,"utf-8"));if(t.name==="glenn-code")return t.version||"unknown"}}catch{}return"unknown"}function Xn(n){let{useDefaultStack:e,projectConfig:t,configSource:o,tunnelPort:s,enableAutoTypecheck:r,enableAutoCommit:i}=n;if(console.log(`
1382
- \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`),console.log("\u2551 AGENT CONFIGURATION \u2551"),console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),e?(console.log("\u2551 Mode: DEFAULT STACK (.NET/React) \u2551"),console.log("\u2551 Agents: scaffolding, backend, frontend, debugger, \u2551"),console.log("\u2551 planning, project-context \u2551")):(console.log("\u2551 Mode: CUSTOM STACK (generic agents only) \u2551"),console.log("\u2551 Agents: debugger, planning, project-context \u2551")),console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),console.log(`\u2551 Config source: ${o.padEnd(42)}\u2551`),console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),console.log("\u2551 SERVICES: \u2551"),t.services?.backend){let a=t.services.backend;console.log(`\u2551 Backend: port ${a.port}, extensions: ${a.extensions?.join(", ")||"N/A"}`.padEnd(62)+"\u2551")}else console.log("\u2551 Backend: not configured \u2551");if(t.services?.frontend){let a=t.services.frontend;console.log(`\u2551 Frontend: port ${a.port}, extensions: ${a.extensions?.join(", ")||"N/A"}`.padEnd(62)+"\u2551")}else console.log("\u2551 Frontend: not configured \u2551");t.techStack&&(console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),console.log("\u2551 TECH STACK: \u2551"),t.techStack.backend?.length&&console.log(`\u2551 Backend: ${t.techStack.backend.join(", ")}`.padEnd(62)+"\u2551"),t.techStack.frontend?.length&&console.log(`\u2551 Frontend: ${t.techStack.frontend.join(", ")}`.padEnd(62)+"\u2551"),t.techStack.patterns?.length&&console.log(`\u2551 Patterns: ${t.techStack.patterns.join(", ")}`.padEnd(62)+"\u2551")),console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),console.log("\u2551 SETTINGS: \u2551"),console.log(`\u2551 Tunnel port: ${s}`.padEnd(62)+"\u2551"),console.log(`\u2551 Auto-typecheck: ${r?"enabled":"disabled"}`.padEnd(62)+"\u2551"),console.log(`\u2551 Auto-commit: ${i?"enabled":"disabled"}`.padEnd(62)+"\u2551"),console.log(`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1383
- `)}var Zn=".sdd/local-signalr-config.json";function _t(n){return Q.join(n,Zn)}function eo(n){try{let e=_t(n);if(!M.existsSync(e))return null;let t=M.readFileSync(e,"utf-8");return JSON.parse(t)}catch{return null}}function Ke(n,e){let t=Q.dirname(_t(n));M.existsSync(t)||M.mkdirSync(t,{recursive:!0}),M.writeFileSync(_t(n),JSON.stringify(e,null,2))}function fe(){return`local-${dn.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${Date.now().toString(36)}`}function to(n){return!!(n.version||n.paths||n.services||n.techStack)}function no(n,e){return to(n)?{version:n.version||"1.0",paths:n.paths||{workspace:e},services:n.services,techStack:n.techStack,tunnel:n.tunnel,scaffold:n.scaffold,git:n.git}:null}async function oo(n){console.log(`
1381
+ `),Jn(l)});let r=setTimeout(()=>{s.close(),o(new Error("Browser authentication timed out after 5 minutes"))},5*60*1e3)})}async function cn(){let n=process.env.GLENN_CODE_APP_URL,e=process.env.GLENN_CODE_URL_PICKER==="true";if(n)return n;if(e){let{url:t}=await on.prompt([{type:"select",name:"url",message:"Which environment?",choices:[{name:"glenncode.ai (production)",value:"https://glenncode.ai"},{name:"glenncode.cc (staging)",value:"https://glenncode.cc"},{name:"localhost:4173 (development)",value:"http://localhost:4173"},{name:"Enter custom URL",value:"custom"}]}]);if(t==="custom"){let{customUrl:o}=await on.prompt([{type:"input",name:"customUrl",message:"Enter the URL:",validate:s=>{try{return new URL(s),!0}catch{return"Please enter a valid URL"}}}]);return o}return t}return"https://glenncode.ai"}process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT=process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT||"60000";var ln=X.dirname(Qn(import.meta.url));function Vn(){let n=[X.resolve(ln,"../package.json"),X.resolve(ln,"../../../package.json")];for(let e of n)try{if(M.existsSync(e)){let t=JSON.parse(M.readFileSync(e,"utf-8"));if(t.name==="glenn-code")return t.version||"unknown"}}catch{}return"unknown"}function Xn(n){let{useDefaultStack:e,projectConfig:t,configSource:o,tunnelPort:s,tunnelUrl:r,enableAutoTypecheck:i,enableAutoCommit:a}=n;if(console.log(`
1382
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`),console.log("\u2551 AGENT CONFIGURATION \u2551"),console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),e?(console.log("\u2551 Mode: DEFAULT STACK (.NET/React) \u2551"),console.log("\u2551 Agents: scaffolding, backend, frontend, debugger, \u2551"),console.log("\u2551 planning, project-context \u2551")):(console.log("\u2551 Mode: CUSTOM STACK (generic agents only) \u2551"),console.log("\u2551 Agents: debugger, planning, project-context \u2551")),console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),console.log(`\u2551 Config source: ${o.padEnd(42)}\u2551`),console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),console.log("\u2551 SERVICES: \u2551"),t.services?.backend){let l=t.services.backend;console.log(`\u2551 Backend: port ${l.port}, extensions: ${l.extensions?.join(", ")||"N/A"}`.padEnd(62)+"\u2551")}else console.log("\u2551 Backend: not configured \u2551");if(t.services?.frontend){let l=t.services.frontend;console.log(`\u2551 Frontend: port ${l.port}, extensions: ${l.extensions?.join(", ")||"N/A"}`.padEnd(62)+"\u2551")}else console.log("\u2551 Frontend: not configured \u2551");t.techStack&&(console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),console.log("\u2551 TECH STACK: \u2551"),t.techStack.backend?.length&&console.log(`\u2551 Backend: ${t.techStack.backend.join(", ")}`.padEnd(62)+"\u2551"),t.techStack.frontend?.length&&console.log(`\u2551 Frontend: ${t.techStack.frontend.join(", ")}`.padEnd(62)+"\u2551"),t.techStack.patterns?.length&&console.log(`\u2551 Patterns: ${t.techStack.patterns.join(", ")}`.padEnd(62)+"\u2551")),console.log("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"),console.log("\u2551 SETTINGS: \u2551"),console.log(`\u2551 Tunnel: ${r||`localhost:${s}`}`.padEnd(62)+"\u2551"),console.log(`\u2551 Auto-typecheck: ${i?"enabled":"disabled"}`.padEnd(62)+"\u2551"),console.log(`\u2551 Auto-commit: ${a?"enabled":"disabled"}`.padEnd(62)+"\u2551"),console.log(`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1383
+ `)}var Zn=".sdd/local-signalr-config.json";function Pt(n){return X.join(n,Zn)}function eo(n){try{let e=Pt(n);if(!M.existsSync(e))return null;let t=M.readFileSync(e,"utf-8");return JSON.parse(t)}catch{return null}}function Ye(n,e){let t=X.dirname(Pt(n));M.existsSync(t)||M.mkdirSync(t,{recursive:!0}),M.writeFileSync(Pt(n),JSON.stringify(e,null,2))}function ye(){return`local-${dn.hostname().toLowerCase().replace(/[^a-z0-9]/g,"-")}-${Date.now().toString(36)}`}function to(n){return!!(n.version||n.paths||n.services||n.techStack)}function no(n,e){return to(n)?{version:n.version||"1.0",paths:n.paths||{workspace:e},services:n.services,techStack:n.techStack,tunnel:n.tunnel,scaffold:n.scaffold,git:n.git}:null}async function oo(n){console.log(`
1384
1384
  \u{1F527} Interactive Project Config Builder
1385
1385
  `),console.log(" Answer the following questions to configure your project."),console.log(` Press Enter to skip optional questions.
1386
- `);let{projectType:e}=await G.prompt([{type:"select",name:"projectType",message:"What type of project is this?",choices:[{name:"Frontend only (React, Next.js, Vue, etc.)",value:"frontend"},{name:"Backend only (Node, Python, Go, etc.)",value:"backend"},{name:"Fullstack (Frontend + Backend)",value:"fullstack"},{name:"Skip - use default .NET/React stack",value:"skip"}]}]);if(e==="skip")return null;let t={version:"1.0",paths:{workspace:"."}};if(e==="frontend"||e==="fullstack"){console.log(`
1387
- \u{1F4F1} Frontend Configuration:`);let s=await G.prompt([{type:"input",name:"path",message:"Frontend path (relative to workspace):",default:e==="fullstack"?"./frontend":"."},{type:"number",name:"port",message:"Dev server port:",default:3e3},{type:"input",name:"startCommand",message:"Start command (or Enter to skip):",default:"npm run dev"},{type:"input",name:"typecheckCommand",message:"Typecheck command (or Enter to skip):",default:"npx tsc --noEmit"},{type:"input",name:"extensions",message:"File extensions (comma-separated):",default:".ts,.tsx,.js,.jsx"}]);t.paths={workspace:t.paths?.workspace||".",...t.paths,frontend:s.path||"."},t.services={...t.services,frontend:{port:s.port||3e3,startCommand:s.startCommand||"npm run dev",typecheckCommand:s.typecheckCommand||void 0,extensions:s.extensions?s.extensions.split(",").map(r=>r.trim()):[".ts",".tsx",".js",".jsx"]}},t.tunnel={enabled:!0,port:s.port||3e3}}if(e==="backend"||e==="fullstack"){console.log(`
1388
- \u2699\uFE0F Backend Configuration:`);let s=await G.prompt([{type:"input",name:"path",message:"Backend path (relative to workspace):",default:e==="fullstack"?"./backend":"."},{type:"number",name:"port",message:"API server port:",default:8080},{type:"input",name:"startCommand",message:"Start command (or Enter to skip):",default:""},{type:"input",name:"buildCommand",message:"Build command (or Enter to skip):",default:""},{type:"input",name:"extensions",message:"File extensions (comma-separated):",default:".ts,.js"}]);t.paths={workspace:t.paths?.workspace||".",...t.paths,backend:s.path||"."},t.services={...t.services,backend:{port:s.port||8080,startCommand:s.startCommand||void 0,buildCommand:s.buildCommand||void 0,extensions:s.extensions?s.extensions.split(",").map(r=>r.trim()):[".ts",".js"]}},e==="backend"&&(t.tunnel={enabled:!0,port:s.port||8080})}console.log(`
1389
- \u{1F4DA} Tech Stack (optional - helps AI understand your project):`);let{addTechStack:o}=await G.prompt([{type:"confirm",name:"addTechStack",message:"Add tech stack info?",default:!1}]);if(o){let s=await G.prompt([{type:"input",name:"frontend",message:"Frontend technologies (comma-separated, or Enter to skip):",default:""},{type:"input",name:"backend",message:"Backend technologies (comma-separated, or Enter to skip):",default:""},{type:"input",name:"patterns",message:"Patterns/practices (comma-separated, or Enter to skip):",default:""}]);t.techStack={},s.frontend&&(t.techStack.frontend=s.frontend.split(",").map(r=>r.trim())),s.backend&&(t.techStack.backend=s.backend.split(",").map(r=>r.trim())),s.patterns&&(t.techStack.patterns=s.patterns.split(",").map(r=>r.trim()))}return t}function pn(n){try{let e={},t=n.match(/MASTER_URL=(\S+)/);t&&(e.masterUrl=t[1].trim());let o=n.match(/PROJECT_ID=(\S+)/);o&&(e.projectId=o[1].trim());let s=n.match(/PROJECT_KEY=(\S+)/);return s&&(e.projectKey=s[1].trim()),e.masterUrl&&e.projectId&&e.projectKey?e:null}catch{return null}}async function so(n){let e=eo(n);console.log(`
1386
+ `);let{projectType:e}=await Y.prompt([{type:"select",name:"projectType",message:"What type of project is this?",choices:[{name:"Frontend only (React, Next.js, Vue, etc.)",value:"frontend"},{name:"Backend only (Node, Python, Go, etc.)",value:"backend"},{name:"Fullstack (Frontend + Backend)",value:"fullstack"},{name:"Skip - use default .NET/React stack",value:"skip"}]}]);if(e==="skip")return null;let t={version:"1.0",paths:{workspace:"."}};if(e==="frontend"||e==="fullstack"){console.log(`
1387
+ \u{1F4F1} Frontend Configuration:`);let s=await Y.prompt([{type:"input",name:"path",message:"Frontend path (relative to workspace):",default:e==="fullstack"?"./frontend":"."},{type:"number",name:"port",message:"Dev server port:",default:3e3},{type:"input",name:"startCommand",message:"Start command (or Enter to skip):",default:"npm run dev"},{type:"input",name:"typecheckCommand",message:"Typecheck command (or Enter to skip):",default:"npx tsc --noEmit"},{type:"input",name:"extensions",message:"File extensions (comma-separated):",default:".ts,.tsx,.js,.jsx"}]);t.paths={workspace:t.paths?.workspace||".",...t.paths,frontend:s.path||"."},t.services={...t.services,frontend:{port:s.port||3e3,startCommand:s.startCommand||"npm run dev",typecheckCommand:s.typecheckCommand||void 0,extensions:s.extensions?s.extensions.split(",").map(r=>r.trim()):[".ts",".tsx",".js",".jsx"]}},t.tunnel={enabled:!0,port:s.port||3e3}}if(e==="backend"||e==="fullstack"){console.log(`
1388
+ \u2699\uFE0F Backend Configuration:`);let s=await Y.prompt([{type:"input",name:"path",message:"Backend path (relative to workspace):",default:e==="fullstack"?"./backend":"."},{type:"number",name:"port",message:"API server port:",default:8080},{type:"input",name:"startCommand",message:"Start command (or Enter to skip):",default:""},{type:"input",name:"buildCommand",message:"Build command (or Enter to skip):",default:""},{type:"input",name:"extensions",message:"File extensions (comma-separated):",default:".ts,.js"}]);t.paths={workspace:t.paths?.workspace||".",...t.paths,backend:s.path||"."},t.services={...t.services,backend:{port:s.port||8080,startCommand:s.startCommand||void 0,buildCommand:s.buildCommand||void 0,extensions:s.extensions?s.extensions.split(",").map(r=>r.trim()):[".ts",".js"]}},e==="backend"&&(t.tunnel={enabled:!0,port:s.port||8080})}console.log(`
1389
+ \u{1F4DA} Tech Stack (optional - helps AI understand your project):`);let{addTechStack:o}=await Y.prompt([{type:"confirm",name:"addTechStack",message:"Add tech stack info?",default:!1}]);if(o){let s=await Y.prompt([{type:"input",name:"frontend",message:"Frontend technologies (comma-separated, or Enter to skip):",default:""},{type:"input",name:"backend",message:"Backend technologies (comma-separated, or Enter to skip):",default:""},{type:"input",name:"patterns",message:"Patterns/practices (comma-separated, or Enter to skip):",default:""}]);t.techStack={},s.frontend&&(t.techStack.frontend=s.frontend.split(",").map(r=>r.trim())),s.backend&&(t.techStack.backend=s.backend.split(",").map(r=>r.trim())),s.patterns&&(t.techStack.patterns=s.patterns.split(",").map(r=>r.trim()))}return t}function pn(n){try{let e={},t=n.match(/MASTER_URL=(\S+)/);t&&(e.masterUrl=t[1].trim());let o=n.match(/PROJECT_ID=(\S+)/);o&&(e.projectId=o[1].trim());let s=n.match(/PROJECT_KEY=(\S+)/);return s&&(e.projectKey=s[1].trim()),e.masterUrl&&e.projectId&&e.projectKey?e:null}catch{return null}}async function so(n){let e=eo(n);console.log(`
1390
1390
  \u{1F3E0} Local SignalR Mode - Jack into the real system
1391
- `);let t=e?.masterUrl&&e?.projectId&&e?.projectKey,{configMethod:o}=await G.prompt([{type:"select",name:"configMethod",message:"How would you like to configure?",choices:[...t?[{name:`Use saved config (${e.projectId})`,value:"saved"}]:[],{name:"Connect via browser",value:"browser"},{name:"Paste config from frontend",value:"paste"},{name:"Enter manually",value:"manual"},{name:"Build project config interactively",value:"interactive"}]}]);if(o==="saved"&&t){let a=no(e,n),c=a?.tunnel?.port||e.tunnelPort||5173;return console.log(`
1392
- \u{1F4CB} Using saved configuration:`),console.log(` Master URL: ${e.masterUrl}`),console.log(` Project ID: ${e.projectId}`),console.log(` Project Key: ${e.projectKey.substring(0,16)}...`),console.log(` Container ID: ${e.containerId}`),console.log(` Tunnel: ${e.enableTunnel!==!1?`enabled (port ${c})`:"disabled"}`),a&&console.log(" Project config: embedded in local-signalr-config.json"),{masterUrl:e.masterUrl,projectId:e.projectId,projectKey:e.projectKey,containerId:e.containerId||fe(),enableTunnel:e.enableTunnel!==!1,tunnelPort:c,embeddedProjectConfig:a}}if(o==="browser"){let a=await cn();console.log(`
1393
- \u{1F517} Connecting via ${a}...`);let c=await an(a),l=e?.containerId||fe(),u=e?.tunnelPort||5173,d={masterUrl:c.masterUrl,projectId:c.projectId,projectKey:c.projectKey,containerId:l,enableTunnel:!0,tunnelPort:u};return console.log(`
1394
- \u2705 Connected to project "${c.projectName}"`),console.log(` Master URL: ${d.masterUrl}`),console.log(` Project ID: ${d.projectId}`),console.log(` Project Key: ${d.projectKey.substring(0,16)}...`),console.log(` Container ID: ${d.containerId}`),Ke(n,d),{...d,embeddedProjectConfig:null}}if(o==="paste"){let{pastedConfig:a}=await G.prompt([{type:"input",name:"pastedConfig",message:"Paste the config (MASTER_URL=... PROJECT_ID=... PROJECT_KEY=...):",validate:p=>pn(p)?!0:"Could not parse config. Make sure it contains MASTER_URL=..., PROJECT_ID=..., and PROJECT_KEY=..."}]),c=pn(a),l=e?.containerId||fe(),u=e?.tunnelPort||5173,d={masterUrl:c.masterUrl,projectId:c.projectId,projectKey:c.projectKey,containerId:l,enableTunnel:!0,tunnelPort:u};return console.log(`
1395
- \u{1F4CB} Parsed configuration:`),console.log(` Master URL: ${d.masterUrl}`),console.log(` Project ID: ${d.projectId}`),console.log(` Project Key: ${d.projectKey.substring(0,16)}...`),console.log(` Container ID: ${d.containerId}`),console.log(` Tunnel: enabled (port ${u})`),Ke(n,d),{...d,embeddedProjectConfig:null}}if(o==="interactive"){console.log(`
1396
- \u{1F50C} Connection Configuration:`);let a=await G.prompt([{type:"input",name:"masterUrl",message:"Master URL (backend):",default:e?.masterUrl||process.env.MASTER_URL||"http://localhost:5338",validate:p=>{if(!p.trim())return"Master URL is required";try{return new URL(p),!0}catch{return"Please enter a valid URL"}}},{type:"input",name:"projectId",message:"Project ID:",default:e?.projectId||process.env.PROJECT_ID,validate:p=>p.trim()?!0:"Project ID is required"},{type:"password",name:"projectKey",message:"Project Key (pk_proj_...):",mask:"*",default:e?.projectKey||process.env.PROJECT_KEY,validate:p=>p.trim()?p.startsWith("pk_proj_")?!0:"Project Key must start with pk_proj_":"Project Key is required"}]),c=await oo(n),l=e?.containerId||fe(),u=c?.tunnel?.port||e?.tunnelPort||5173,d={masterUrl:a.masterUrl,projectId:a.projectId,projectKey:a.projectKey,containerId:l,enableTunnel:!0,tunnelPort:u,...c&&{version:c.version,paths:c.paths,services:c.services,techStack:c.techStack,tunnel:c.tunnel}};return console.log(`
1397
- \u{1F4CB} Configuration built:`),console.log(` Master URL: ${d.masterUrl}`),console.log(` Project ID: ${d.projectId}`),console.log(` Project Key: ${d.projectKey.substring(0,16)}...`),console.log(` Container ID: ${d.containerId}`),console.log(` Tunnel: enabled (port ${u})`),console.log(c?" Project config: custom stack":" Project config: default .NET/React stack"),Ke(n,d),{masterUrl:d.masterUrl,projectId:d.projectId,projectKey:d.projectKey,containerId:d.containerId,enableTunnel:d.enableTunnel,tunnelPort:d.tunnelPort,embeddedProjectConfig:c}}let s=await G.prompt([{type:"input",name:"masterUrl",message:"Master URL (backend):",default:e?.masterUrl||process.env.MASTER_URL||"http://localhost:5338",validate:a=>{if(!a.trim())return"Master URL is required";try{return new URL(a),!0}catch{return"Please enter a valid URL"}}},{type:"input",name:"projectId",message:"Project ID:",default:e?.projectId||process.env.PROJECT_ID,validate:a=>a.trim()?!0:"Project ID is required"},{type:"password",name:"projectKey",message:"Project Key (pk_proj_...):",mask:"*",default:e?.projectKey||process.env.PROJECT_KEY,validate:a=>a.trim()?a.startsWith("pk_proj_")?!0:"Project Key must start with pk_proj_":"Project Key is required"},{type:"input",name:"containerId",message:"Container ID (unique identifier for this agent):",default:e?.containerId||fe()},{type:"confirm",name:"enableTunnel",message:"Enable preview URL reporting (report local dev server URL to backend)?",default:e?.enableTunnel!==!1}]),r=e?.tunnelPort||5173;s.enableTunnel&&(r=(await G.prompt([{type:"number",name:"tunnelPort",message:"Preview port (local dev server port to report):",default:r}])).tunnelPort||r);let i={...s,tunnelPort:r};return Ke(n,i),{...i,embeddedProjectConfig:null}}async function ro(){let n=process.env.LOCAL_MODE==="true",e=process.env.WORKSPACE_DIR||process.cwd(),t=Vn();console.log(n?`=== Glenn Code v${t} ===`:`=== SignalR Agent v${t} ===`),console.log(`Workspace: ${e}`),n&&!M.existsSync(Q.join(e,".git"))&&console.warn("\u26A0\uFE0F Warning: Not a git repository. Some features may not work.");let o,s,r=!1,i=5173,a=null;if(n){let m=await so(e);o={masterUrl:m.masterUrl,containerId:m.containerId,projectKey:m.projectKey,workspaceDir:e,isByok:!0},s=m.projectId,r=m.enableTunnel,i=m.tunnelPort,a=m.embeddedProjectConfig,process.env.PROJECT_ID=m.projectId,process.env.CONTAINER_ID=m.containerId,process.env.PROJECT_KEY=m.projectKey}else{let m=process.env.PROJECT_KEY;m||(console.error("\u274C PROJECT_KEY environment variable is required"),process.exit(1)),o={masterUrl:process.env.MASTER_URL||"http://host.docker.internal:5338",containerId:process.env.CONTAINER_ID||"unknown",projectKey:m,workspaceDir:e}}console.log(`
1398
- \u{1F50C} Connecting to backend...`),console.log(` Container ID: ${o.containerId}`),console.log(` Project Key: ${o.projectKey.substring(0,16)}...`),console.log(` Gateway URL: ${o.masterUrl}`);let c=new Me(o);process.on("unhandledRejection",async m=>{let h=m instanceof Error?m.message:String(m),C=m instanceof Error?m.stack:void 0;if(h.includes("ProcessTransport is not ready for writing")||h.includes("Cannot write to terminated process")){console.warn(`[Process] Suppressed benign unhandled rejection: ${h}`);return}console.error("[Process] Unhandled rejection:",h);try{await c.reportError({message:`Unhandled rejection: ${h}`,stackTrace:C,errorType:"UnhandledRejection",operation:"global",isFatal:!1})}catch{}}),process.on("uncaughtException",async m=>{console.error("[Process] Uncaught exception:",m.message),console.error(m.stack);try{await c.reportError({message:`Uncaught exception: ${m.message}`,stackTrace:m.stack,errorType:"UncaughtException",operation:"global",isFatal:!0})}catch{}setTimeout(()=>process.exit(1),1e3)});let l=0,u=10;for(;l<u;)try{await c.connect();break}catch(m){if(l++,console.error(`Connection attempt ${l} failed:`,m instanceof Error?m.message:m),l<u){let h=Math.min(1e3*Math.pow(2,l),3e4);await new Promise(C=>setTimeout(C,h))}}l>=u&&(console.error("\u274C Failed to connect to gateway after max retries"),process.exit(1)),n&&console.log("\u2705 Connected to backend");let d=await c.getSecrets();n?(console.log("\u2705 Handshake complete"),d.gitHubPat&&console.log(" GitHub PAT received from backend")):console.log("\u2705 Secrets received");let p,y=!0,k="default";if(n){if(a)p=a,k="embedded in local-signalr-config.json",y=!1,console.log("[Config] Using embedded project config from local-signalr-config.json");else{let m=await Ie({workspaceDir:o.workspaceDir});p=m.config,k=m.source==="file"?m.configPath||".sdd/project-config.json":"default (no config file)",m.source==="file"&&(y=!1)}y||p.tunnel?.port&&(i=p.tunnel.port)}let E=Ne({workspaceDir:o.workspaceDir,projectConfig:p});we(E);let x=ue(o.workspaceDir);pe(x);let w=m=>{console.log(`[Planning] Setting up SignalR transport for project ${m}`),x=new Fe(c.getHubProxy(),m),pe(x)};n&&s&&w(s);let g;n?g={prewarmWorkspace:async()=>{console.log("[LocalMode] Skipping prewarm - using existing workspace")},handleInitSession:async m=>{console.log(`[LocalMode] Session init for ${m.sessionId}`),console.log("[LocalMode] Skipping branch switch - using current branch"),await c.reportStatus("Ready",void 0,m.sessionId,m.projectId),await c.getHubProxy().initSessionCompleted(o.containerId,m.sessionId,!0,"")}}:g=new He(c,E,o.workspaceDir,d.gitHubPat||null);let U=process.env.DISABLE_AUTO_TYPECHECK!=="true",K=process.env.DISABLE_AUTO_COMMIT!=="true"&&!n;n&&p?Xn({useDefaultStack:y,projectConfig:p,configSource:k,tunnelPort:i,enableAutoTypecheck:U,enableAutoCommit:K}):(console.log(`[Config] Auto-typecheck: ${U?"enabled":"disabled"}`),console.log(`[Config] Auto-commit: ${K?"enabled":"disabled"}`));let q=new We(c,g,E,o.workspaceDir,U,K,w,p,y,d.anthropicApiKey);if(c.registerReceiver(q),n){if(r){let m=`http://localhost:${i}`;c.setTunnelUrl(m),console.log(`
1399
- \u{1F310} Preview available at: ${m}`)}await c.reportStatus("Ready",void 0,void 0,s),console.log(`
1391
+ `);let t=e?.masterUrl&&e?.projectId&&e?.projectKey,{configMethod:o}=await Y.prompt([{type:"select",name:"configMethod",message:"How would you like to configure?",choices:[...t?[{name:`Use saved config (${e.projectId})`,value:"saved"}]:[],{name:"Connect via browser",value:"browser"},{name:"Paste config from frontend",value:"paste"},{name:"Enter manually",value:"manual"},{name:"Build project config interactively",value:"interactive"}]}]);if(o==="saved"&&t){let a=no(e,n),l=a?.tunnel?.port||e.tunnelPort||5173;return console.log(`
1392
+ \u{1F4CB} Using saved configuration:`),console.log(` Master URL: ${e.masterUrl}`),console.log(` Project ID: ${e.projectId}`),console.log(` Project Key: ${e.projectKey.substring(0,16)}...`),console.log(` Container ID: ${e.containerId}`),console.log(` Tunnel: ${e.enableTunnel!==!1?e.tunnelUrl||`enabled (port ${l})`:"disabled"}`),a&&console.log(" Project config: embedded in local-signalr-config.json"),{masterUrl:e.masterUrl,projectId:e.projectId,projectKey:e.projectKey,containerId:e.containerId||ye(),enableTunnel:e.enableTunnel!==!1,tunnelPort:l,tunnelUrl:e.tunnelUrl,embeddedProjectConfig:a}}if(o==="browser"){let a=await cn();console.log(`
1393
+ \u{1F517} Connecting via ${a}...`);let l=await an(a),c=e?.containerId||ye(),u=e?.tunnelPort||5173,d={masterUrl:l.masterUrl,projectId:l.projectId,projectKey:l.projectKey,containerId:c,enableTunnel:!0,tunnelPort:u};return console.log(`
1394
+ \u2705 Connected to project "${l.projectName}"`),console.log(` Master URL: ${d.masterUrl}`),console.log(` Project ID: ${d.projectId}`),console.log(` Project Key: ${d.projectKey.substring(0,16)}...`),console.log(` Container ID: ${d.containerId}`),Ye(n,d),{...d,embeddedProjectConfig:null}}if(o==="paste"){let{pastedConfig:a}=await Y.prompt([{type:"input",name:"pastedConfig",message:"Paste the config (MASTER_URL=... PROJECT_ID=... PROJECT_KEY=...):",validate:p=>pn(p)?!0:"Could not parse config. Make sure it contains MASTER_URL=..., PROJECT_ID=..., and PROJECT_KEY=..."}]),l=pn(a),c=e?.containerId||ye(),u=e?.tunnelPort||5173,d={masterUrl:l.masterUrl,projectId:l.projectId,projectKey:l.projectKey,containerId:c,enableTunnel:!0,tunnelPort:u};return console.log(`
1395
+ \u{1F4CB} Parsed configuration:`),console.log(` Master URL: ${d.masterUrl}`),console.log(` Project ID: ${d.projectId}`),console.log(` Project Key: ${d.projectKey.substring(0,16)}...`),console.log(` Container ID: ${d.containerId}`),console.log(` Tunnel: enabled (port ${u})`),Ye(n,d),{...d,embeddedProjectConfig:null}}if(o==="interactive"){console.log(`
1396
+ \u{1F50C} Connection Configuration:`);let a=await Y.prompt([{type:"input",name:"masterUrl",message:"Master URL (backend):",default:e?.masterUrl||process.env.MASTER_URL||"http://localhost:5338",validate:p=>{if(!p.trim())return"Master URL is required";try{return new URL(p),!0}catch{return"Please enter a valid URL"}}},{type:"input",name:"projectId",message:"Project ID:",default:e?.projectId||process.env.PROJECT_ID,validate:p=>p.trim()?!0:"Project ID is required"},{type:"password",name:"projectKey",message:"Project Key (pk_proj_...):",mask:"*",default:e?.projectKey||process.env.PROJECT_KEY,validate:p=>p.trim()?p.startsWith("pk_proj_")?!0:"Project Key must start with pk_proj_":"Project Key is required"}]),l=await oo(n),c=e?.containerId||ye(),u=l?.tunnel?.port||e?.tunnelPort||5173,d={masterUrl:a.masterUrl,projectId:a.projectId,projectKey:a.projectKey,containerId:c,enableTunnel:!0,tunnelPort:u,...l&&{version:l.version,paths:l.paths,services:l.services,techStack:l.techStack,tunnel:l.tunnel}};return console.log(`
1397
+ \u{1F4CB} Configuration built:`),console.log(` Master URL: ${d.masterUrl}`),console.log(` Project ID: ${d.projectId}`),console.log(` Project Key: ${d.projectKey.substring(0,16)}...`),console.log(` Container ID: ${d.containerId}`),console.log(` Tunnel: enabled (port ${u})`),console.log(l?" Project config: custom stack":" Project config: default .NET/React stack"),Ye(n,d),{masterUrl:d.masterUrl,projectId:d.projectId,projectKey:d.projectKey,containerId:d.containerId,enableTunnel:d.enableTunnel,tunnelPort:d.tunnelPort,tunnelUrl:d.tunnelUrl,embeddedProjectConfig:l}}let s=await Y.prompt([{type:"input",name:"masterUrl",message:"Master URL (backend):",default:e?.masterUrl||process.env.MASTER_URL||"http://localhost:5338",validate:a=>{if(!a.trim())return"Master URL is required";try{return new URL(a),!0}catch{return"Please enter a valid URL"}}},{type:"input",name:"projectId",message:"Project ID:",default:e?.projectId||process.env.PROJECT_ID,validate:a=>a.trim()?!0:"Project ID is required"},{type:"password",name:"projectKey",message:"Project Key (pk_proj_...):",mask:"*",default:e?.projectKey||process.env.PROJECT_KEY,validate:a=>a.trim()?a.startsWith("pk_proj_")?!0:"Project Key must start with pk_proj_":"Project Key is required"},{type:"input",name:"containerId",message:"Container ID (unique identifier for this agent):",default:e?.containerId||ye()},{type:"confirm",name:"enableTunnel",message:"Enable preview URL reporting (report local dev server URL to backend)?",default:e?.enableTunnel!==!1}]),r=e?.tunnelPort||5173;s.enableTunnel&&(r=(await Y.prompt([{type:"number",name:"tunnelPort",message:"Preview port (local dev server port to report):",default:r}])).tunnelPort||r);let i={...s,tunnelPort:r};return Ye(n,i),{...i,embeddedProjectConfig:null}}async function ro(){let n=process.env.LOCAL_MODE==="true",e=process.env.WORKSPACE_DIR||process.cwd(),t=Vn();console.log(n?`=== Glenn Code v${t} ===`:`=== SignalR Agent v${t} ===`),console.log(`Workspace: ${e}`),n&&!M.existsSync(X.join(e,".git"))&&console.warn("\u26A0\uFE0F Warning: Not a git repository. Some features may not work.");let o,s,r=!1,i=5173,a,l=null;if(n){let g=await so(e);o={masterUrl:g.masterUrl,containerId:g.containerId,projectKey:g.projectKey,workspaceDir:e,isByok:!0},s=g.projectId,r=g.enableTunnel,i=g.tunnelPort,a=g.tunnelUrl,l=g.embeddedProjectConfig,process.env.PROJECT_ID=g.projectId,process.env.CONTAINER_ID=g.containerId,process.env.PROJECT_KEY=g.projectKey}else{let g=process.env.PROJECT_KEY;g||(console.error("\u274C PROJECT_KEY environment variable is required"),process.exit(1)),o={masterUrl:process.env.MASTER_URL||"http://host.docker.internal:5338",containerId:process.env.CONTAINER_ID||"unknown",projectKey:g,workspaceDir:e,isByok:M.existsSync("/tmp/.use-own-subscription")}}console.log(`
1398
+ \u{1F50C} Connecting to backend...`),console.log(` Container ID: ${o.containerId}`),console.log(` Project Key: ${o.projectKey.substring(0,16)}...`),console.log(` Gateway URL: ${o.masterUrl}`);let c=new $e(o);process.on("unhandledRejection",async g=>{let j=g instanceof Error?g.message:String(g),L=g instanceof Error?g.stack:void 0;if(j.includes("ProcessTransport is not ready for writing")||j.includes("Cannot write to terminated process")){console.warn(`[Process] Suppressed benign unhandled rejection: ${j}`);return}console.error("[Process] Unhandled rejection:",j);try{await c.reportError({message:`Unhandled rejection: ${j}`,stackTrace:L,errorType:"UnhandledRejection",operation:"global",isFatal:!1})}catch{}}),process.on("uncaughtException",async g=>{console.error("[Process] Uncaught exception:",g.message),console.error(g.stack);try{await c.reportError({message:`Uncaught exception: ${g.message}`,stackTrace:g.stack,errorType:"UncaughtException",operation:"global",isFatal:!0})}catch{}setTimeout(()=>process.exit(1),1e3)});let u=0,d=10;for(;u<d;)try{await c.connect();break}catch(g){if(u++,console.error(`Connection attempt ${u} failed:`,g instanceof Error?g.message:g),u<d){let j=Math.min(1e3*Math.pow(2,u),3e4);await new Promise(L=>setTimeout(L,j))}}u>=d&&(console.error("\u274C Failed to connect to gateway after max retries"),process.exit(1)),n&&console.log("\u2705 Connected to backend");let p=await c.getSecrets();n?(console.log("\u2705 Handshake complete"),p.gitHubPat&&console.log(" GitHub PAT received from backend")):console.log("\u2705 Secrets received");let h,C=!0,E="default";if(n){if(l)h=l,E="embedded in local-signalr-config.json",C=!1,console.log("[Config] Using embedded project config from local-signalr-config.json");else{let g=await Ae({workspaceDir:o.workspaceDir});h=g.config,E=g.source==="file"?g.configPath||".sdd/project-config.json":"default (no config file)",g.source==="file"&&(C=!1)}C||h.tunnel?.port&&(i=h.tunnel.port)}let x=Me({workspaceDir:o.workspaceDir,projectConfig:h});ke(x);let w=ge(o.workspaceDir);de(w);let m=g=>{console.log(`[Planning] Setting up SignalR transport for project ${g}`),w=new He(c.getHubProxy(),g),de(w)};n&&s&&m(s);let D;n?D={prewarmWorkspace:async()=>{console.log("[LocalMode] Skipping prewarm - using existing workspace")},handleInitSession:async g=>{console.log(`[LocalMode] Session init for ${g.sessionId}`),console.log("[LocalMode] Skipping branch switch - using current branch"),await c.reportStatus("Ready",void 0,g.sessionId,g.projectId),await c.getHubProxy().initSessionCompleted(o.containerId,g.sessionId,!0,"")}}:D=new We(c,x,o.workspaceDir,p.gitHubPat||null);let y=process.env.DISABLE_AUTO_TYPECHECK!=="true",H=process.env.DISABLE_AUTO_COMMIT!=="true"&&!n;n&&h?Xn({useDefaultStack:C,projectConfig:h,configSource:E,tunnelPort:i,tunnelUrl:a,enableAutoTypecheck:y,enableAutoCommit:H}):(console.log(`[Config] Auto-typecheck: ${y?"enabled":"disabled"}`),console.log(`[Config] Auto-commit: ${H?"enabled":"disabled"}`));let z=o.isByok?null:p.anthropicApiKey,v=new Ke(c,D,x,o.workspaceDir,y,H,m,h,C,z);if(c.registerReceiver(v),n){if(r){let g=a||`http://localhost:${i}`;c.setTunnelUrl(g),console.log(`
1399
+ \u{1F310} Preview available at: ${g}`)}await c.reportStatus("Ready",void 0,void 0,s),console.log(`
1400
1400
  \u2705 Agent ready and waiting for commands`),console.log(` Open the frontend and select this agent to start working
1401
1401
  `),console.log(` Press Ctrl+C to disconnect
1402
1402
  `),c.startHeartbeat(3e4),process.on("SIGINT",async()=>{console.log(`
1403
- \u{1F44B} Disconnecting...`),c.stopHeartbeat(),await c.reportStatus("Error"),process.exit(0)})}else{let m=process.env.SESSION_ID,h=process.env.PROJECT_ID;await c.reportStatus("Initiating",void 0,m,h);try{await g.prewarmWorkspace()}catch(C){let V=C instanceof Error?C.message:String(C),X=C instanceof Error?C.stack:void 0;throw await c.reportError({message:`Container initialization failed: ${V}`,stackTrace:X,errorType:"ContainerInitError",operation:"prewarmWorkspace",sessionId:m,isFatal:!0}),await c.reportStatus("Error",V,m,h),C}await c.reportStatus("WarmedUp",void 0,m,h),console.log("\u2705 Agent initialized, waiting for InitSession"),console.log(` Session: ${m||"none"}`),console.log(` Repo: ${process.env.REPO_URL?"configured":"NOT SET"}`)}}import.meta.url===`file://${process.argv[1]}`&&ro().catch(n=>{console.error("Fatal error:",n),process.exit(1)});export{ro as startSignalRAgent};
1403
+ \u{1F44B} Disconnecting...`),c.stopHeartbeat(),await c.reportStatus("Error"),process.exit(0)})}else{let g=process.env.SESSION_ID,j=process.env.PROJECT_ID;await c.reportStatus("Initiating",void 0,g,j);try{await D.prewarmWorkspace()}catch(L){let se=L instanceof Error?L.message:String(L),be=L instanceof Error?L.stack:void 0;throw await c.reportError({message:`Container initialization failed: ${se}`,stackTrace:be,errorType:"ContainerInitError",operation:"prewarmWorkspace",sessionId:g,isFatal:!0}),await c.reportStatus("Error",se,g,j),L}await c.reportStatus("WarmedUp",void 0,g,j),console.log("\u2705 Agent initialized, waiting for InitSession"),console.log(` Session: ${g||"none"}`),console.log(` Repo: ${process.env.REPO_URL?"configured":"NOT SET"}`)}}import.meta.url===`file://${process.argv[1]}`&&ro().catch(n=>{console.error("Fatal error:",n),process.exit(1)});export{ro as startSignalRAgent};