glenn-code 1.0.33 → 1.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Glenn Code - Bundled and minified
2
2
  // (c) DNM Lab - All rights reserved
3
3
 
4
- import{createSdkMcpServer as Bt}from"@anthropic-ai/claude-agent-sdk";import{tool as de}from"@anthropic-ai/claude-agent-sdk";import{z as le}from"zod";import*as pe from"fs";import*as Ze from"path";var N=null;function ue(e){N=e}function Ue(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}var Rn=de("save_specification",`Save a specification to the database.
4
+ import{createSdkMcpServer as Bt}from"@anthropic-ai/claude-agent-sdk";import{tool as ge}from"@anthropic-ai/claude-agent-sdk";import{z as ue}from"zod";import*as fe from"fs";import*as Ze from"path";var N=null;function me(e){N=e}function je(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}var Rn=ge("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,50 +12,50 @@ 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:le.string().describe("Specification name (e.g., 'User Authentication')"),filePath:le.string().describe("Path to the file containing the specification content (written via Write tool)")},async e=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let t=Ze.resolve(e.filePath);if(!pe.existsSync(t))return{content:[{type:"text",text:`\u274C File not found: ${e.filePath}. Use Write tool first to create the file.`}]};let n=pe.readFileSync(t,"utf-8"),s=Ue(e.name);return await N.saveSpecification(s,n),{content:[{type:"text",text:`\u2705 Saved specification: ${s}.spec.md`}]}}),On=de("read_specification","Read the content of a specification.",{name:le.string().describe("Name of the specification to read")},async e=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let t=Ue(e.name),n=await N.getSpecification(t);return n?{content:[{type:"text",text:n}]}:{content:[{type:"text",text:`\u274C Specification "${e.name}" not found.`}]}}),Dn=de("list_specifications","List all specifications.",{},async()=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let e=await N.listSpecifications();return e.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:ue.string().describe("Specification name (e.g., 'User Authentication')"),filePath:ue.string().describe("Path to the file containing the specification content (written via Write tool)")},async e=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let t=Ze.resolve(e.filePath);if(!fe.existsSync(t))return{content:[{type:"text",text:`\u274C File not found: ${e.filePath}. Use Write tool first to create the file.`}]};let n=fe.readFileSync(t,"utf-8"),s=je(e.name);return await N.saveSpecification(s,n),{content:[{type:"text",text:`\u2705 Saved specification: ${s}.spec.md`}]}}),On=ge("read_specification","Read the content of a specification.",{name:ue.string().describe("Name of the specification to read")},async e=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let t=je(e.name),n=await N.getSpecification(t);return n?{content:[{type:"text",text:n}]}:{content:[{type:"text",text:`\u274C Specification "${e.name}" not found.`}]}}),Dn=ge("list_specifications","List all specifications.",{},async()=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let e=await N.listSpecifications();return e.length===0?{content:[{type:"text",text:"\u{1F4CB} No specifications found."}]}:{content:[{type:"text",text:`\u{1F4CB} Specifications:
16
16
 
17
17
  ${e.map(n=>`- ${n.name} (${n.slug}.spec.md)`).join(`
18
- `)}`}]}}),Un=de("delete_specification","Delete a specification.",{name:le.string().describe("Name of the specification to delete")},async e=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let t=Ue(e.name);return await N.deleteSpecification(t)?{content:[{type:"text",text:`\u{1F5D1}\uFE0F Deleted: ${t}.spec.md`}]}:{content:[{type:"text",text:`\u274C Specification "${e.name}" not found.`}]}});import{tool as q}from"@anthropic-ai/claude-agent-sdk";import{z as X}from"zod";var k=null;function ge(e){k=e}var et=q("restart_services",`Rebuild and restart services. Call this after making backend changes (.cs files) to apply them.
18
+ `)}`}]}}),Un=ge("delete_specification","Delete a specification.",{name:ue.string().describe("Name of the specification to delete")},async e=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let t=je(e.name);return await N.deleteSpecification(t)?{content:[{type:"text",text:`\u{1F5D1}\uFE0F Deleted: ${t}.spec.md`}]}:{content:[{type:"text",text:`\u274C Specification "${e.name}" not found.`}]}});import{tool as B}from"@anthropic-ai/claude-agent-sdk";import{z as ee}from"zod";var k=null;function he(e){k=e}var et=B("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:X.enum(["backend","frontend","both"]).default("backend").describe("Which service to restart")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=e.target||"backend";console.log(`[MCP] restart_services called (target: ${t})`);let n=await k.restartServices(t);if(!n.success){let o=[];return n.backendError&&o.push(`Backend: ${n.backendError}`),n.frontendError&&o.push(`Frontend: ${n.frontendError}`),{content:[{type:"text",text:`\u274C Restart failed:
25
+ Use target="both" if unsure or both need restart.`,{target:ee.enum(["backend","frontend","both"]).default("backend").describe("Which service to restart")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=e.target||"backend";console.log(`[MCP] restart_services called (target: ${t})`);let n=await k.restartServices(t);if(!n.success){let o=[];return n.backendError&&o.push(`Backend: ${n.backendError}`),n.frontendError&&o.push(`Frontend: ${n.frontendError}`),{content:[{type:"text",text:`\u274C Restart failed:
26
26
  ${o.join(`
27
27
 
28
- `)}`}]}}return{content:[{type:"text",text:`\u2705 ${t==="both"?"Backend and frontend":t==="backend"?"Backend":"Frontend"} restarted successfully.`}]}}),tt=q("stop_services",`Stop running services. Call this BEFORE running scaffold to prevent port conflicts and ensure clean migrations.
28
+ `)}`}]}}return{content:[{type:"text",text:`\u2705 ${t==="both"?"Backend and frontend":t==="backend"?"Backend":"Frontend"} restarted successfully.`}]}}),tt=B("stop_services",`Stop running services. Call this BEFORE running scaffold to prevent port conflicts and ensure clean migrations.
29
29
 
30
30
  Parameters:
31
31
  - target: "backend" (default) | "frontend" | "both"
32
32
 
33
- Use target="backend" before running scaffold (required for migrations).`,{target:X.enum(["backend","frontend","both"]).default("backend").describe("Which service to stop")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=e.target||"backend";console.log(`[MCP] stop_services called (target: ${t})`);let n=t==="backend"||t==="both",s=t==="frontend"||t==="both";n&&await k.stopBackend(),s&&await k.stopFrontend();let o=5e3,r=Date.now(),i=!n,l=!s;for(;Date.now()-r<o;){let g=await k.checkHealth();if(n&&!g.api&&(i=!0),s&&!g.web&&(l=!0),i&&l)break;await new Promise(v=>setTimeout(v,500))}let h=t==="both"?"Backend and frontend":t==="backend"?"Backend":"Frontend";return{content:[{type:"text",text:i&&l?`\u2705 ${h} stopped successfully.`:`\u26A0\uFE0F ${h} stop requested but health check still shows running. Proceeding anyway.`}]}}),nt=q("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:ee.enum(["backend","frontend","both"]).default("backend").describe("Which service to stop")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=e.target||"backend";console.log(`[MCP] stop_services called (target: ${t})`);let n=t==="backend"||t==="both",s=t==="frontend"||t==="both";n&&await k.stopBackend(),s&&await k.stopFrontend();let o=5e3,r=Date.now(),i=!n,l=!s;for(;Date.now()-r<o;){let g=await k.checkHealth();if(n&&!g.api&&(i=!0),s&&!g.web&&(l=!0),i&&l)break;await new Promise(v=>setTimeout(v,500))}let h=t==="both"?"Backend and frontend":t==="backend"?"Backend":"Frontend";return{content:[{type:"text",text:i&&l?`\u2705 ${h} stopped successfully.`:`\u26A0\uFE0F ${h} stop requested but health check still shows running. Proceeding anyway.`}]}}),nt=B("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:X.enum(["backend","frontend","both"]).default("backend").describe("Which service to start")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=e.target||"backend";console.log(`[MCP] start_services called (target: ${t})`);let n=t==="backend"||t==="both",s=t==="frontend"||t==="both";n&&await k.startBackend(),s&&await k.startFrontend();let o=await k.waitForHealth(15e3),r=!n||o.api,i=!s||o.web,l=r&&i,h=t==="both"?"Backend and frontend":t==="backend"?"Backend":"Frontend";if(!l){let m=[];return n&&!o.api&&m.push("Backend failed to start"),s&&!o.web&&m.push("Frontend failed to start"),{content:[{type:"text",text:`\u274C ${h} failed to start: ${m.join(", ")}`}]}}return{content:[{type:"text",text:`\u2705 ${h} started successfully.`}]}}),ot=q("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:ee.enum(["backend","frontend","both"]).default("backend").describe("Which service to start")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=e.target||"backend";console.log(`[MCP] start_services called (target: ${t})`);let n=t==="backend"||t==="both",s=t==="frontend"||t==="both";n&&await k.startBackend(),s&&await k.startFrontend();let o=await k.waitForHealth(15e3),r=!n||o.api,i=!s||o.web,l=r&&i,h=t==="both"?"Backend and frontend":t==="backend"?"Backend":"Frontend";if(!l){let m=[];return n&&!o.api&&m.push("Backend failed to start"),s&&!o.web&&m.push("Frontend failed to start"),{content:[{type:"text",text:`\u274C ${h} failed to start: ${m.join(", ")}`}]}}return{content:[{type:"text",text:`\u2705 ${h} started successfully.`}]}}),ot=B("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(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=await k.checkHealth();return{content:[{type:"text",text:`Service Health:
40
40
  \u{1F5A5}\uFE0F Backend API: ${e.api?"\u2705 running":"\u274C not running"}
41
- \u{1F310} Frontend: ${e.web?"\u2705 running":"\u274C not running"}`}]}}),st=q("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(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};console.log("[MCP] check_backend_build called");let e=await k.checkBackendBuild();return e.success?{content:[{type:"text",text:"\u2705 Backend build succeeded - no errors"}]}:{content:[{type:"text",text:`\u274C Backend build failed:
41
+ \u{1F310} Frontend: ${e.web?"\u2705 running":"\u274C not running"}`}]}}),st=B("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(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};console.log("[MCP] check_backend_build called");let e=await k.checkBackendBuild();return e.success?{content:[{type:"text",text:"\u2705 Backend build succeeded - no errors"}]}:{content:[{type:"text",text:`\u274C Backend build failed:
42
42
 
43
- ${e.errors}`}]}}),rt=q("check_frontend_types","Run TypeScript type check (tsc) on frontend code. Use this after fixing frontend code to verify the fix works.",{},async()=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};console.log("[MCP] check_frontend_types called");let e=await k.checkFrontendTypes();return e.success?{content:[{type:"text",text:"\u2705 Frontend type check passed - no errors"}]}:{content:[{type:"text",text:`\u274C Frontend type errors:
43
+ ${e.errors}`}]}}),rt=B("check_frontend_types","Run TypeScript type check (tsc) on frontend code. Use this after fixing frontend code to verify the fix works.",{},async()=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};console.log("[MCP] check_frontend_types called");let e=await k.checkFrontendTypes();return e.success?{content:[{type:"text",text:"\u2705 Frontend type check passed - no errors"}]}:{content:[{type:"text",text:`\u274C Frontend type errors:
44
44
 
45
- ${e.errors}`}]}}),jn=q("tail_service_log",`Get the last N lines of service logs. Use this to debug startup failures or verify that the application is running correctly.
45
+ ${e.errors}`}]}}),jn=B("tail_service_log",`Get the last N lines of service logs. Use this to debug startup failures or verify that the application is running correctly.
46
46
 
47
47
  Parameters:
48
48
  - target: "backend" | "frontend"
49
- - lines: number (default 50)`,{target:X.enum(["backend","frontend"]).describe("Which log to read"),lines:X.number().default(50).describe("Number of lines to read")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=await k.tailLogs(e.target,e.lines);return{content:[{type:"text",text:`Last ${e.lines} lines of ${e.target} log:
49
+ - lines: number (default 50)`,{target:ee.enum(["backend","frontend"]).describe("Which log to read"),lines:ee.number().default(50).describe("Number of lines to read")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=await k.tailLogs(e.target,e.lines);return{content:[{type:"text",text:`Last ${e.lines} lines of ${e.target} log:
50
50
 
51
51
  ${t.join(`
52
- `)}`}]}}),Mn=q("check_swagger_endpoints",`Search for endpoints in the generated swagger.json. Use this to verify that new backend endpoints are correctly exposed.
52
+ `)}`}]}}),Mn=B("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:X.string().describe("Text to search for in endpoint paths")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=await k.checkSwaggerEndpoints(e.pattern);return t.foundEndpoints.length===0?{content:[{type:"text",text:`\u274C No endpoints found matching "${e.pattern}" (Total endpoints: ${t.totalEndpoints})`}]}:{content:[{type:"text",text:`\u2705 Found ${t.foundEndpoints.length} matching endpoints:
55
+ - pattern: string (e.g., "users", "api/reports")`,{pattern:ee.string().describe("Text to search for in endpoint paths")},async e=>{if(!k)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=await k.checkSwaggerEndpoints(e.pattern);return t.foundEndpoints.length===0?{content:[{type:"text",text:`\u274C No endpoints found matching "${e.pattern}" (Total endpoints: ${t.totalEndpoints})`}]}:{content:[{type:"text",text:`\u2705 Found ${t.foundEndpoints.length} matching endpoints:
56
56
 
57
57
  ${t.foundEndpoints.join(`
58
- `)}`}]}});import*as W from"fs";import*as it from"path";var $t="/tmp";function te(e){let t=it.join($t,`agent-questions-${e}.json`);if(!W.existsSync(t))return null;try{let n=W.readFileSync(t,"utf-8");return W.unlinkSync(t),JSON.parse(n)}catch{return null}}import*as E from"fs";import*as fe from"path";function ne(e){let t=fe.join(e,".sdd","specifications");function n(){E.existsSync(t)||E.mkdirSync(t,{recursive:!0})}function s(o){return fe.join(t,`${o}.spec.md`)}return{async saveSpecification(o,r){n(),E.writeFileSync(s(o),r,"utf-8")},async getSpecification(o){n();let r=s(o);return E.existsSync(r)?E.readFileSync(r,"utf-8"):null},async listSpecifications(){return n(),E.readdirSync(t).filter(r=>r.endsWith(".spec.md")).map(r=>{let i=E.readFileSync(fe.join(t,r),"utf-8"),l=i.match(/name: "([^"]+)"/),h=i.match(/status: (\w+)/),m=i.match(/version: "([^"]+)"/);return{slug:r.replace(".spec.md",""),name:l?.[1]||r,status:h?.[1]||"unknown",version:m?.[1]||"1.0.0"}})},async deleteSpecification(o){n();let r=s(o);return E.existsSync(r)?(E.unlinkSync(r),!0):!1},async specificationExists(o){return n(),E.existsSync(s(o))}}}function Fe(){return Bt({name:"agent-insights",version:"1.0.0",tools:[et,tt,nt,ot,st,rt]})}import{query as rn}from"@anthropic-ai/claude-agent-sdk";var Le={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 q from"fs";import*as it from"path";var $t="/tmp";function oe(e){let t=it.join($t,`agent-questions-${e}.json`);if(!q.existsSync(t))return null;try{let n=q.readFileSync(t,"utf-8");return q.unlinkSync(t),JSON.parse(n)}catch{return null}}import*as A from"fs";import*as ye from"path";function se(e){let t=ye.join(e,".sdd","specifications");function n(){A.existsSync(t)||A.mkdirSync(t,{recursive:!0})}function s(o){return ye.join(t,`${o}.spec.md`)}return{async saveSpecification(o,r){n(),A.writeFileSync(s(o),r,"utf-8")},async getSpecification(o){n();let r=s(o);return A.existsSync(r)?A.readFileSync(r,"utf-8"):null},async listSpecifications(){return n(),A.readdirSync(t).filter(r=>r.endsWith(".spec.md")).map(r=>{let i=A.readFileSync(ye.join(t,r),"utf-8"),l=i.match(/name: "([^"]+)"/),h=i.match(/status: (\w+)/),m=i.match(/version: "([^"]+)"/);return{slug:r.replace(".spec.md",""),name:l?.[1]||r,status:h?.[1]||"unknown",version:m?.[1]||"1.0.0"}})},async deleteSpecification(o){n();let r=s(o);return A.existsSync(r)?(A.unlinkSync(r),!0):!1},async specificationExists(o){return n(),A.existsSync(s(o))}}}function Me(){return Bt({name:"agent-insights",version:"1.0.0",tools:[et,tt,nt,ot,st,rt]})}import{query as rn}from"@anthropic-ai/claude-agent-sdk";var $e={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 me={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 be={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 he={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 we={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 Ne={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 Be={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 je={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 qe={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 ye={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 ke={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 Z from"fs";import*as ct from"path";var be=class{buffer=[];flushInterval=null;sessionId=null;outputDir;flushIntervalMs;constructor(t){this.outputDir=t.outputDir||"/tmp/agent-debug",this.flushIntervalMs=t.flushIntervalMs||3e3,t.enabled&&(this.ensureOutputDir(),this.startFlushInterval())}ensureOutputDir(){Z.existsSync(this.outputDir)||Z.mkdirSync(this.outputDir,{recursive:!0})}startFlushInterval(){this.flushInterval=setInterval(()=>{this.flush()},this.flushIntervalMs)}setSessionId(t){this.sessionId=t}log(t){let s={timestamp:new Date().toISOString(),message:t};this.buffer.push(JSON.stringify(s,null,2)+`
838
+ 6. **Update, don't replace** - If context exists, improve it rather than starting fresh`};import*as te from"fs";import*as ct from"path";var _e=class{buffer=[];flushInterval=null;sessionId=null;outputDir;flushIntervalMs;constructor(t){this.outputDir=t.outputDir||"/tmp/agent-debug",this.flushIntervalMs=t.flushIntervalMs||3e3,t.enabled&&(this.ensureOutputDir(),this.startFlushInterval())}ensureOutputDir(){te.existsSync(this.outputDir)||te.mkdirSync(this.outputDir,{recursive:!0})}startFlushInterval(){this.flushInterval=setInterval(()=>{this.flush()},this.flushIntervalMs)}setSessionId(t){this.sessionId=t}log(t){let s={timestamp:new Date().toISOString(),message:t};this.buffer.push(JSON.stringify(s,null,2)+`
839
839
  ---
840
- `)}getLogFilePath(){let n=(this.sessionId||"unknown").replace(/[^a-zA-Z0-9-]/g,"_").slice(0,50),s=new Date().toISOString().split("T")[0];return ct.join(this.outputDir,`session-${s}-${n}.log`)}flush(){if(this.buffer.length===0)return;let t=this.buffer.join("");this.buffer=[];let n=this.getLogFilePath();Z.appendFileSync(n,t)}stop(){this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.flush()}};function lt(e){return e?typeof e=="boolean"?e?new be({enabled:!0}):null:e.enabled?new be(e):null:null}import{z as p}from"zod";import*as Me from"fs/promises";import*as Q from"path";var dt=p.object({port:p.number(),startCommand:p.string(),buildCommand:p.string().optional(),typecheckCommand:p.string().optional(),logFile:p.string().optional(),healthEndpoint:p.string().optional(),extensions:p.array(p.string())}),qt=p.object({port:p.number(),type:p.enum(["postgres","mysql","sqlite","mongodb"])}),Wt=p.object({command:p.string(),schemaPath:p.string().optional()}),Gt=p.object({email:p.string().optional(),name:p.string().optional(),commitPrefix:p.string().optional()}),Ht=p.object({enabled:p.boolean(),port:p.number().optional()}),pt=p.object({version:p.literal("1.0"),paths:p.object({workspace:p.string(),backend:p.string().optional(),frontend:p.string().optional(),features:p.object({backend:p.string().optional(),frontend:p.string().optional()}).optional()}),services:p.object({backend:dt.optional(),frontend:dt.optional(),database:qt.optional()}).optional(),scaffold:Wt.optional(),git:Gt.optional(),techStack:p.object({backend:p.array(p.string()).optional(),frontend:p.array(p.string()).optional(),patterns:p.array(p.string()).optional()}).optional(),tunnel:Ht.optional()});function G(e){return{version:"1.0",paths:{workspace:e||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}}}function we(e,t){if(t)return Q.isAbsolute(t)?t:Q.join(e.paths.workspace,t)}function H(e){return we(e,e.paths.backend)}function Y(e){return we(e,e.paths.frontend)}function ke(e){let t=H(e);if(!(!t||!e.paths.features?.backend))return Q.join(t,e.paths.features.backend)}function oe(e){let t=Y(e);if(!(!t||!e.paths.features?.frontend))return Q.join(t,e.paths.features.frontend)}function _e(e){let t=[];return e.techStack?.backend?.length&&t.push(`**Backend:** ${e.techStack.backend.join(", ")}`),e.techStack?.frontend?.length&&t.push(`**Frontend:** ${e.techStack.frontend.join(", ")}`),e.techStack?.patterns?.length&&t.push(`**Patterns:** ${e.techStack.patterns.join(", ")}`),t.join(`
841
- `)}function Se(e){let t=[];return e.services?.backend&&t.push(`| Backend | ${H(e)} | ${e.services.backend.port} | ${e.services.backend.logFile||"N/A"} |`),e.services?.frontend&&t.push(`| Frontend | ${Y(e)} | ${e.services.frontend.port} | ${e.services.frontend.logFile||"N/A"} |`),e.services?.database&&t.push(`| Database (${e.services.database.type}) | localhost | ${e.services.database.port} | - |`),t.length===0?"":`| Service | Location | Port | Logs |
840
+ `)}getLogFilePath(){let n=(this.sessionId||"unknown").replace(/[^a-zA-Z0-9-]/g,"_").slice(0,50),s=new Date().toISOString().split("T")[0];return ct.join(this.outputDir,`session-${s}-${n}.log`)}flush(){if(this.buffer.length===0)return;let t=this.buffer.join("");this.buffer=[];let n=this.getLogFilePath();te.appendFileSync(n,t)}stop(){this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.flush()}};function lt(e){return e?typeof e=="boolean"?e?new _e({enabled:!0}):null:e.enabled?new _e(e):null:null}import{z as p}from"zod";import*as We from"fs/promises";import*as z from"path";var dt=p.object({port:p.number(),startCommand:p.string(),buildCommand:p.string().optional(),typecheckCommand:p.string().optional(),logFile:p.string().optional(),healthEndpoint:p.string().optional(),extensions:p.array(p.string())}),qt=p.object({port:p.number(),type:p.enum(["postgres","mysql","sqlite","mongodb"])}),Wt=p.object({command:p.string(),schemaPath:p.string().optional()}),Gt=p.object({email:p.string().optional(),name:p.string().optional(),commitPrefix:p.string().optional()}),Ht=p.object({enabled:p.boolean(),port:p.number().optional()}),pt=p.object({version:p.literal("1.0"),paths:p.object({workspace:p.string(),backend:p.string().optional(),frontend:p.string().optional(),features:p.object({backend:p.string().optional(),frontend:p.string().optional()}).optional()}),services:p.object({backend:dt.optional(),frontend:dt.optional(),database:qt.optional()}).optional(),scaffold:Wt.optional(),git:Gt.optional(),techStack:p.object({backend:p.array(p.string()).optional(),frontend:p.array(p.string()).optional(),patterns:p.array(p.string()).optional()}).optional(),tunnel:Ht.optional()});function W(e){return{version:"1.0",paths:{workspace:e||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}}}function Se(e,t){if(t)return z.isAbsolute(t)?t:z.join(e.paths.workspace,t)}function G(e){return Se(e,e.paths.backend)}function H(e){return Se(e,e.paths.frontend)}function ve(e){let t=G(e);if(!(!t||!e.paths.features?.backend))return z.join(t,e.paths.features.backend)}function re(e){let t=H(e);if(!(!t||!e.paths.features?.frontend))return z.join(t,e.paths.features.frontend)}function Te(e){let t=[];return e.techStack?.backend?.length&&t.push(`**Backend:** ${e.techStack.backend.join(", ")}`),e.techStack?.frontend?.length&&t.push(`**Frontend:** ${e.techStack.frontend.join(", ")}`),e.techStack?.patterns?.length&&t.push(`**Patterns:** ${e.techStack.patterns.join(", ")}`),t.join(`
841
+ `)}function Ce(e){let t=[];return e.services?.backend&&t.push(`| Backend | ${G(e)} | ${e.services.backend.port} | ${e.services.backend.logFile||"N/A"} |`),e.services?.frontend&&t.push(`| Frontend | ${H(e)} | ${e.services.frontend.port} | ${e.services.frontend.logFile||"N/A"} |`),e.services?.database&&t.push(`| Database (${e.services.database.type}) | localhost | ${e.services.database.port} | - |`),t.length===0?"":`| Service | Location | Port | Logs |
842
842
  |---------|----------|------|------|
843
843
  ${t.join(`
844
- `)}`}function ut(e={}){let{debugMode:t=!1,projectPrompt:n=null,isLocal:s=!1,projectConfig:o=G(),useDefaultStack:r=!0}=e,i=n?`
844
+ `)}`}function ut(e={}){let{debugMode:t=!1,projectPrompt:n=null,isLocal:s=!1,projectConfig:o=W(),useDefaultStack:r=!0}=e,i=n?`
845
845
  <project_context>
846
846
  ${n}
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
- `:"",h=Jt(o),m=Xt(o,s),g=tn(o,r),v=Zt(r),C=r?nn(o):"",S=r?on(o,s):"",O=en(r);return`${i}${l}# Agent Instructions
889
+ `:"",h=Jt(o),m=Xt(o,s),g=tn(o,r),v=Zt(r),C=r?nn(o):"",S=r?on(o,s):"",I=en(r);return`${i}${l}# Agent Instructions
890
890
 
891
891
  ## \u26D4 CRITICAL: EVERYTHING IS A KANBAN TASK
892
892
 
@@ -1038,12 +1038,12 @@ ${m}
1038
1038
 
1039
1039
  ${g}
1040
1040
 
1041
- ${O}
1041
+ ${I}
1042
1042
 
1043
1043
  ${C}
1044
1044
 
1045
1045
  ${S}
1046
- `}function Jt(e){let t=_e(e),n=H(e),s=Y(e),o=ke(e),r=oe(e),i=[];o&&i.push(`- Backend: "${o}/{Entity}/"`),r&&i.push(`- Frontend: "${r}/{entity}/"`);let l=e.techStack?.patterns?.length?`
1046
+ `}function Jt(e){let t=Te(e),n=G(e),s=H(e),o=ve(e),r=re(e),i=[];o&&i.push(`- Backend: "${o}/{Entity}/"`),r&&i.push(`- Frontend: "${r}/{entity}/"`);let l=e.techStack?.patterns?.length?`
1047
1047
  **Key patterns:**
1048
1048
  ${e.techStack.patterns.map(g=>`- ${g}`).join(`
1049
1049
  `)}`:"",m=e.techStack?.backend?.some(g=>g.includes(".NET")||g.includes("C#"))??!1?`
@@ -1076,7 +1076,7 @@ The user is responsible for:
1076
1076
  </environment>`:`<environment>
1077
1077
  Docker container with pre-started services:
1078
1078
 
1079
- ${Se(e)}
1079
+ ${Ce(e)}
1080
1080
  ${e.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 on(e,t){if(!e.services?.frontend)return"";let n=e.services.frontend.port,s=oe(e),o=`http://localhost:${n}`;return`<ui-verification>
1271
+ </frontend-api>`:""}function on(e,t){if(!e.services?.frontend)return"";let n=e.services.frontend.port,s=re(e),o=`http://localhost:${n}`;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,34 +1350,34 @@ 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
  - ${t?"In local mode, the browser window will be visible to you":"In container mode, browser runs headless"}
1353
- </ui-verification>`}function gt(e){return e&&e.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"\uFFFD")}var sn=null;function ft(){return gt(sn)}import*as z from"path";import*as Be from"fs";import{fileURLToPath as an}from"url";var cn=Fe(),$e=z.dirname(an(import.meta.url)),mt=[z.resolve($e,"../mcps/stdio-server.js"),z.resolve($e,"./adapters/mcps/stdio-server.js")],se=mt.find(e=>Be.existsSync(e))||mt[0];console.log("[MCP] Stdio server path resolved:",se);console.log("[MCP] __dirname:",$e);console.log("[MCP] File exists:",Be.existsSync(se));async function ve(e,t={}){let{model:n,sessionId:s=null,projectId:o=null,apiUrl:r=null,callbacks:i={},debugLog:l,abortController:h,debugMode:m=!1,isLocal:g=process.env.LOCAL_MODE==="true",projectConfig:v=G(process.env.WORKSPACE_DIR||process.cwd()),useDefaultStack:C=!0}=t,S=lt(l),O=new Set,y=s||"",R,F,x,$=!1,ee=!1,L=process.env.WORKSPACE_DIR||process.cwd();console.log("[MCP] Configuring agent-planning stdio server:"),console.log("[MCP] Command: node"),console.log("[MCP] Args:",[se]),console.log("[MCP] Env: API_URL=",process.env.API_URL||"http://localhost:5338",", PROJECT_ID=",o||process.env.PROJECT_ID||"",", PROJECT_KEY=",process.env.PROJECT_KEY?"***set***":"(not set)",", WORKSPACE_DIR=",L),console.log("[MCP] File exists check:",se);try{for await(let u of rn({prompt:e,options:{abortController:h,cwd:L,resume:s??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",...g?[]:["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:n,mcpServers:{"agent-insights":cn,"agent-planning":{type:"stdio",command:"node",args:[se],env:{WORKSPACE_DIR:L,API_URL:r||process.env.API_URL||process.env.MASTER_URL||"http://localhost:5338",PROJECT_ID:o||process.env.PROJECT_ID||"",PROJECT_KEY:process.env.PROJECT_KEY||""}},playwright:{type:"stdio",command:"npx",args:["@playwright/mcp@latest",...g?[]:["--browser=firefox"],"--caps=vision",`--user-data-dir=${z.join(L,".playwright-data")}`,...g?[]:["--headless"]]}},settingSources:["project"],disallowedTools:["AskUserQuestion","TodoWrite","EnterPlanMode"],agents:C?{scaffolding:Le,debugger:me,planning:he,backend:Ne,frontend:je,"project-context":ye}:{debugger:me,planning:he,"project-context":ye},systemPrompt:ut({debugMode:m,projectPrompt:ft(),isLocal:g,projectConfig:v,useDefaultStack:C})}}))if(!(!u.uuid||O.has(u.uuid))){switch(O.add(u.uuid),S?.log(u),i.onRawMessage?.(u),u.type){case"assistant":if(u.message?.content)for(let A of u.message.content)A.type==="text"?i.onAssistantText?.(A.text):A.type==="tool_use"?i.onAssistantToolUse?.(A.name,A.input):A.type==="tool_result"&&i.onAssistantToolResult?.(A.tool_use_id,A.content);break;case"user":i.onUserMessage?.(u);break;case"result":if(u.subtype==="success")R=u.result,F=u.total_cost_usd,i.onResult?.(u.result,u.total_cost_usd);else{let A=`Agent error: ${u.subtype}`;x=A,i.onError?.(A)}ee=!0;break;case"system":switch(u.subtype){case"init":y=u.session_id,S?.setSessionId(u.session_id),i.onSystemInit?.(u.session_id);break;case"status":i.onSystemStatus?.(JSON.stringify(u));break;case"compact_boundary":break;case"hook_response":break}break;case"stream_event":i.onStreamEvent?.(u);break;case"tool_progress":i.onToolProgress?.(u);break;case"auth_status":i.onAuthStatus?.(u);break}if(ee)break}}catch(u){u instanceof Error&&u.name==="AbortError"||u instanceof Error&&u.message.includes("aborted by user")?($=!0,i.onAborted?.()):(x=u instanceof Error?u.message:String(u),i.onError?.(x))}finally{S?.stop()}return console.log("after try"),{sessionId:y,result:R,cost:F,error:x,aborted:$}}function Te(e){return`User answered the questions:
1353
+ </ui-verification>`}function gt(e){return e&&e.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"\uFFFD")}var sn=null;function ft(){return gt(sn)}import*as V from"path";import*as Ee from"fs";import{fileURLToPath as an}from"url";var cn=Me(),Ge=V.dirname(an(import.meta.url)),mt=[V.resolve(Ge,"../mcps/stdio-server.js"),V.resolve(Ge,"./adapters/mcps/stdio-server.js")],ie=mt.find(e=>Ee.existsSync(e))||mt[0];console.log("[MCP] Stdio server path resolved:",ie);console.log("[MCP] __dirname:",Ge);console.log("[MCP] File exists:",Ee.existsSync(ie));async function Ae(e,t={}){let{model:n,sessionId:s=null,projectId:o=null,apiUrl:r=null,callbacks:i={},debugLog:l,abortController:h,debugMode:m=!1,isLocal:g=process.env.LOCAL_MODE==="true",projectConfig:v=W(process.env.WORKSPACE_DIR||process.cwd()),useDefaultStack:C=!0,anthropicApiKey:S}=t,I=lt(l),y=new Set,R=s||"",L,O,D,ne=!1,K=!1,Q=process.env.WORKSPACE_DIR||process.cwd();console.log("[MCP] Configuring agent-planning stdio server:"),console.log("[MCP] Command: node"),console.log("[MCP] Args:",[ie]),console.log("[MCP] Env: API_URL=",process.env.API_URL||"http://localhost:5338",", PROJECT_ID=",o||process.env.PROJECT_ID||"",", PROJECT_KEY=",process.env.PROJECT_KEY?"***set***":"(not set)",", WORKSPACE_DIR=",Q),console.log("[MCP] File exists check:",ie);try{for await(let u of rn({prompt:e,options:{abortController:h,cwd:Q,resume:s??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",...g?[]:["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:n,env:(()=>{if(Ee.existsSync("/tmp/.use-own-subscription")){let{ANTHROPIC_API_KEY:pe,...Z}=process.env;return Z}if(S!==void 0){if(S)return{...process.env,ANTHROPIC_API_KEY:S};let{ANTHROPIC_API_KEY:pe,...Z}=process.env;return Z}})(),mcpServers:{"agent-insights":cn,"agent-planning":{type:"stdio",command:"node",args:[ie],env:{WORKSPACE_DIR:Q,API_URL:r||process.env.API_URL||process.env.MASTER_URL||"http://localhost:5338",PROJECT_ID:o||process.env.PROJECT_ID||"",PROJECT_KEY:process.env.PROJECT_KEY||""}},playwright:{type:"stdio",command:"npx",args:["@playwright/mcp@latest",...g?[]:["--browser=firefox"],"--caps=vision",`--user-data-dir=${V.join(Q,".playwright-data")}`,...g?[]:["--headless"]]}},settingSources:["project"],disallowedTools:["AskUserQuestion","TodoWrite","EnterPlanMode"],agents:C?{scaffolding:$e,debugger:be,planning:we,backend:Be,frontend:qe,"project-context":ke}:{debugger:be,planning:we,"project-context":ke},systemPrompt:ut({debugMode:m,projectPrompt:ft(),isLocal:g,projectConfig:v,useDefaultStack:C})}}))if(!(!u.uuid||y.has(u.uuid))){switch(y.add(u.uuid),I?.log(u),i.onRawMessage?.(u),u.type){case"assistant":if(u.message?.content)for(let E of u.message.content)E.type==="text"?i.onAssistantText?.(E.text):E.type==="tool_use"?i.onAssistantToolUse?.(E.name,E.input):E.type==="tool_result"&&i.onAssistantToolResult?.(E.tool_use_id,E.content);break;case"user":i.onUserMessage?.(u);break;case"result":if(u.subtype==="success")L=u.result,O=u.total_cost_usd,i.onResult?.(u.result,u.total_cost_usd);else{let E=`Agent error: ${u.subtype}`;D=E,i.onError?.(E)}K=!0;break;case"system":switch(u.subtype){case"init":R=u.session_id,I?.setSessionId(u.session_id),i.onSystemInit?.(u.session_id);break;case"status":i.onSystemStatus?.(JSON.stringify(u));break;case"compact_boundary":break;case"hook_response":break}break;case"stream_event":i.onStreamEvent?.(u);break;case"tool_progress":i.onToolProgress?.(u);break;case"auth_status":i.onAuthStatus?.(u);break}if(K)break}}catch(u){u instanceof Error&&u.name==="AbortError"||u instanceof Error&&u.message.includes("aborted by user")?(ne=!0,i.onAborted?.()):(D=u instanceof Error?u.message:String(u),i.onError?.(D))}finally{I?.stop()}return console.log("after try"),{sessionId:R,result:L,cost:O,error:D,aborted:ne}}function Pe(e){return`User answered the questions:
1354
1354
 
1355
1355
  ${Object.entries(e).map(([n,s])=>{let o=Array.isArray(s)?s.join(", "):s;return`${n}: ${o}`}).join(`
1356
- `)}`}import{spawn as ht,execSync as V}from"child_process";import*as _ from"fs";import*as yt from"http";import*as K from"path";function Ce(e){let{workspaceDir:t,apiPort:n,webPort:s,onBackendError:o,onFrontendError:r,projectConfig:i=G(t)}=e,l=n??i.services?.backend?.port??5338,h=s??i.services?.frontend?.port??5173,m=H(i),g=Y(i),v=i.services?.backend?.startCommand??"dotnet run",C=i.services?.backend?.buildCommand??"dotnet build",S=i.services?.backend?.typecheckCommand??"dotnet build --no-restore",O=i.services?.frontend?.startCommand??"npm run dev",y=i.services?.frontend?.typecheckCommand??"npx tsc -p tsconfig.app.json --noEmit",R=i.services?.backend?.logFile??"/tmp/api.log",F=i.services?.frontend?.logFile??"/tmp/web.log",x=null,$=null,ee=d=>new Promise(c=>{let f=setTimeout(()=>c(!1),3e3);yt.get(`http://localhost:${d}`,P=>{clearTimeout(f),c(P.statusCode!==void 0&&P.statusCode<500)}).on("error",()=>{clearTimeout(f),c(!1)})}),L=d=>{try{let c=V(`lsof -ti:${d} 2>/dev/null || true`,{encoding:"utf-8"}).trim();if(c){let f=c.split(`
1357
- `).filter(Boolean);console.log(`[Services] Killing ${f.length} process(es) on port ${d}: ${f.join(", ")}`);for(let b of f)try{process.kill(parseInt(b,10),"SIGKILL")}catch{}}}catch{try{V(`fuser -k ${d}/tcp 2>/dev/null || true`,{encoding:"utf-8"})}catch{}}},u=(d,c)=>new Promise(f=>{if(!d||!d.pid){f();return}console.log(`[Services] Stopping ${c} (PID: ${d.pid})...`);try{process.kill(-d.pid,"SIGTERM")}catch{try{d.kill("SIGTERM")}catch{}}setTimeout(f,500)}),A=async()=>{if(!m||!_.existsSync(m)){console.log("[Services] No backend found, skipping backend start");return}L(l),console.log(`[Services] Starting backend with: ${v}...`);let d=K.dirname(R);_.existsSync(d)||_.mkdirSync(d,{recursive:!0});let c=_.createWriteStream(R,{flags:"a"}),[f,...b]=v.split(" ");x=ht(f,b,{cwd:m,stdio:["ignore","pipe","pipe"],detached:!0,shell:!0});let P="",T=w=>{let B=w.toString();c.write(B);let D=(P+B).split(`
1358
- `);P=D.pop()||"";for(let U of D)U&&ln(U)&&o&&o(U)};x.stdout?.on("data",T),x.stderr?.on("data",T),x.on("exit",w=>{c.end(),w!==0&&w!==null&&o&&o(`Process exited with code ${w}`)}),x.unref()},Ye=async()=>{if(!g||!_.existsSync(K.join(g,"package.json"))){console.log("[Services] No frontend found, skipping frontend start");return}L(h),console.log(`[Services] Starting frontend with: ${O}...`);let d=K.dirname(F);_.existsSync(d)||_.mkdirSync(d,{recursive:!0});let[c,...f]=O.split(" ");$=ht(c,f,{cwd:g,stdio:["ignore",_.openSync(F,"w"),_.openSync(F,"w")],detached:!0,shell:!0}),$.unref()},Ke=async()=>{await u(x,"backend"),x=null,L(l)},Qe=async()=>{await u($,"frontend"),$=null,L(h)},De=async()=>{let[d,c]=await Promise.all([ee(l),ee(h)]);return{api:d,web:c}},ze=async(d=15e3)=>{let c=Date.now(),f=1e3,b=0,P=null,T=null;for(console.log(`[Services] Waiting for health (timeout: ${d}ms)...`);Date.now()-c<d;){b++;let D=await De(),U=Date.now()-c;if(D.web&&T===null&&(T=U,console.log(`[Services] \u2713 Frontend (Vite) ready after ${U}ms`)),D.api&&P===null&&(P=U,console.log(`[Services] \u2713 Backend (dotnet) ready after ${U}ms`)),console.log(`[Services] Health poll #${b} (${U}ms): api=${D.api}, web=${D.web}`),D.api&&D.web)return console.log(`[Services] \u2713 Both services healthy after ${U}ms (${b} polls)`),D;await new Promise(Mt=>setTimeout(Mt,f))}let w=await De(),B=Date.now()-c;return w.web&&T===null&&console.log(`[Services] \u2713 Frontend (Vite) ready after ${B}ms`),w.api&&P===null&&console.log(`[Services] \u2713 Backend (dotnet) ready after ${B}ms`),console.log(`[Services] \u26A0 Health timeout after ${B}ms: api=${w.api}, web=${w.web}`),w},Nt=async d=>{console.log(`[Services] Restarting ${d}...`);let c={success:!0},f=d==="backend"||d==="both",b=d==="frontend"||d==="both";if(f&&await Ke(),b&&await Qe(),f&&m&&_.existsSync(m)){console.log(`[Services] Building backend with: ${C}...`);try{V(C,{cwd:m,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),console.log("[Services] \u2713 Backend build succeeded")}catch(T){let w=T;c.success=!1,c.backendError=w.stderr||w.stdout||"Build failed",console.error("[Services] \u2717 Backend build failed")}}if(b&&g&&_.existsSync(K.join(g,"package.json"))){console.log(`[Services] Type-checking frontend with: ${y}...`);try{V(y,{cwd:g,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),console.log("[Services] \u2713 Frontend types OK")}catch(T){let w=T;c.success=!1,c.frontendError=w.stderr||w.stdout||"Type check failed",console.error("[Services] \u2717 Frontend type check failed")}}console.log(`[Services] Starting ${d}...`),f&&await A(),b&&await Ye();let P=await ze(1e4);if(f&&!P.api){c.success=!1;let T=await Xe("backend",20),w=T.length>0?`
1356
+ `)}`}import{spawn as ht,execSync as J}from"child_process";import*as _ from"fs";import*as yt from"http";import*as Y from"path";function xe(e){let{workspaceDir:t,apiPort:n,webPort:s,onBackendError:o,onFrontendError:r,projectConfig:i=W(t)}=e,l=n??i.services?.backend?.port??5338,h=s??i.services?.frontend?.port??5173,m=G(i),g=H(i),v=i.services?.backend?.startCommand??"dotnet run",C=i.services?.backend?.buildCommand??"dotnet build",S=i.services?.backend?.typecheckCommand??"dotnet build --no-restore",I=i.services?.frontend?.startCommand??"npm run dev",y=i.services?.frontend?.typecheckCommand??"npx tsc -p tsconfig.app.json --noEmit",R=i.services?.backend?.logFile??"/tmp/api.log",L=i.services?.frontend?.logFile??"/tmp/web.log",O=null,D=null,ne=d=>new Promise(c=>{let f=setTimeout(()=>c(!1),3e3);yt.get(`http://localhost:${d}`,P=>{clearTimeout(f),c(P.statusCode!==void 0&&P.statusCode<500)}).on("error",()=>{clearTimeout(f),c(!1)})}),K=d=>{try{let c=J(`lsof -ti:${d} 2>/dev/null || true`,{encoding:"utf-8"}).trim();if(c){let f=c.split(`
1357
+ `).filter(Boolean);console.log(`[Services] Killing ${f.length} process(es) on port ${d}: ${f.join(", ")}`);for(let b of f)try{process.kill(parseInt(b,10),"SIGKILL")}catch{}}}catch{try{J(`fuser -k ${d}/tcp 2>/dev/null || true`,{encoding:"utf-8"})}catch{}}},Q=(d,c)=>new Promise(f=>{if(!d||!d.pid){f();return}console.log(`[Services] Stopping ${c} (PID: ${d.pid})...`);try{process.kill(-d.pid,"SIGTERM")}catch{try{d.kill("SIGTERM")}catch{}}setTimeout(f,500)}),u=async()=>{if(!m||!_.existsSync(m)){console.log("[Services] No backend found, skipping backend start");return}K(l),console.log(`[Services] Starting backend with: ${v}...`);let d=Y.dirname(R);_.existsSync(d)||_.mkdirSync(d,{recursive:!0});let c=_.createWriteStream(R,{flags:"a"}),[f,...b]=v.split(" ");O=ht(f,b,{cwd:m,stdio:["ignore","pipe","pipe"],detached:!0,shell:!0});let P="",T=w=>{let $=w.toString();c.write($);let U=(P+$).split(`
1358
+ `);P=U.pop()||"";for(let F of U)F&&ln(F)&&o&&o(F)};O.stdout?.on("data",T),O.stderr?.on("data",T),O.on("exit",w=>{c.end(),w!==0&&w!==null&&o&&o(`Process exited with code ${w}`)}),O.unref()},E=async()=>{if(!g||!_.existsSync(Y.join(g,"package.json"))){console.log("[Services] No frontend found, skipping frontend start");return}K(h),console.log(`[Services] Starting frontend with: ${I}...`);let d=Y.dirname(L);_.existsSync(d)||_.mkdirSync(d,{recursive:!0});let[c,...f]=I.split(" ");D=ht(c,f,{cwd:g,stdio:["ignore",_.openSync(L,"w"),_.openSync(L,"w")],detached:!0,shell:!0}),D.unref()},pe=async()=>{await Q(O,"backend"),O=null,K(l)},Z=async()=>{await Q(D,"frontend"),D=null,K(h)},Ne=async()=>{let[d,c]=await Promise.all([ne(l),ne(h)]);return{api:d,web:c}},ze=async(d=15e3)=>{let c=Date.now(),f=1e3,b=0,P=null,T=null;for(console.log(`[Services] Waiting for health (timeout: ${d}ms)...`);Date.now()-c<d;){b++;let U=await Ne(),F=Date.now()-c;if(U.web&&T===null&&(T=F,console.log(`[Services] \u2713 Frontend (Vite) ready after ${F}ms`)),U.api&&P===null&&(P=F,console.log(`[Services] \u2713 Backend (dotnet) ready after ${F}ms`)),console.log(`[Services] Health poll #${b} (${F}ms): api=${U.api}, web=${U.web}`),U.api&&U.web)return console.log(`[Services] \u2713 Both services healthy after ${F}ms (${b} polls)`),U;await new Promise(Mt=>setTimeout(Mt,f))}let w=await Ne(),$=Date.now()-c;return w.web&&T===null&&console.log(`[Services] \u2713 Frontend (Vite) ready after ${$}ms`),w.api&&P===null&&console.log(`[Services] \u2713 Backend (dotnet) ready after ${$}ms`),console.log(`[Services] \u26A0 Health timeout after ${$}ms: api=${w.api}, web=${w.web}`),w},Nt=async d=>{console.log(`[Services] Restarting ${d}...`);let c={success:!0},f=d==="backend"||d==="both",b=d==="frontend"||d==="both";if(f&&await pe(),b&&await Z(),f&&m&&_.existsSync(m)){console.log(`[Services] Building backend with: ${C}...`);try{J(C,{cwd:m,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),console.log("[Services] \u2713 Backend build succeeded")}catch(T){let w=T;c.success=!1,c.backendError=w.stderr||w.stdout||"Build failed",console.error("[Services] \u2717 Backend build failed")}}if(b&&g&&_.existsSync(Y.join(g,"package.json"))){console.log(`[Services] Type-checking frontend with: ${y}...`);try{J(y,{cwd:g,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),console.log("[Services] \u2713 Frontend types OK")}catch(T){let w=T;c.success=!1,c.frontendError=w.stderr||w.stdout||"Type check failed",console.error("[Services] \u2717 Frontend type check failed")}}console.log(`[Services] Starting ${d}...`),f&&await u(),b&&await E();let P=await ze(1e4);if(f&&!P.api){c.success=!1;let T=await Xe("backend",20),w=T.length>0?`
1359
1359
  Recent logs:
1360
1360
  ${T.join(`
1361
- `)}`:"";c.backendError||(c.backendError=`Backend failed to start.${w}`)}return b&&!P.web&&(c.success=!1,c.frontendError||(c.frontendError="Frontend failed to start")),c},Ve=async()=>{if(!m||!_.existsSync(m))return{success:!0};try{return V(S,{cwd:m,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),{success:!0}}catch(d){let c=d;return{success:!1,errors:c.stdout||c.stderr||"Build failed"}}},Je=async()=>{if(!g||!_.existsSync(K.join(g,"package.json")))return{success:!0};try{return V(y,{cwd:g,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),{success:!0}}catch(d){let c=d;return{success:!1,errors:c.stdout||c.stderr||"Type check failed"}}},jt=async()=>{let[d,c]=await Promise.all([Ve(),Je()]);return{backend:d,frontend:c}},Xe=async(d,c)=>{let f=d==="backend"?R:F;if(!_.existsSync(f))return[`Log file not found: ${f}`];try{return V(`tail -n ${c} ${f}`,{encoding:"utf-8"}).split(`
1362
- `).filter(Boolean)}catch(b){return[`Error reading logs: ${b instanceof Error?b.message:String(b)}`]}};return{startBackend:A,startFrontend:Ye,stopBackend:Ke,stopFrontend:Qe,restartServices:Nt,checkHealth:De,waitForHealth:ze,getProcesses:()=>({backend:x,frontend:$}),checkBackendBuild:Ve,checkFrontendTypes:Je,runTypeChecks:jt,tailLogs:Xe,checkSwaggerEndpoints:async d=>{let c=K.join(t,"swagger.json");if(!_.existsSync(c))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let f=JSON.parse(_.readFileSync(c,"utf-8")),b=Object.keys(f.paths||{}),P=[];for(let T of b)if(T.toLowerCase().includes(d.toLowerCase())){let w=Object.keys(f.paths[T]);for(let B of w)P.push(`${B.toUpperCase()} ${T}`)}return{foundEndpoints:P,totalEndpoints:b.length}}catch(f){return{foundEndpoints:[`Error parsing swagger.json: ${f instanceof Error?f.message:String(f)}`],totalEndpoints:0}}}}}function ln(e){let t=e.toLowerCase();return t.includes("exception")||t.includes("fail:")||t.includes("[err]")||t.includes("[error]")}import{execSync as J}from"child_process";function Ee(e){let t=async()=>{try{return J("git status --porcelain",{cwd:e,encoding:"utf-8"}).trim().length>0}catch{return!1}},n=async()=>{try{return J("git branch --show-current",{cwd:e,encoding:"utf-8"}).trim()}catch{return"unknown"}};return{hasChanges:t,commitAndPush:async(o,r)=>{try{if(!await t())return{success:!0,noChanges:!0};let i=o.length>60?o.substring(0,60)+"...":o,h=`${r?"[agent] (partial)":"[agent]"} ${i}`;J("git add -A",{cwd:e}),J(`git commit -m "${h.replace(/"/g,'\\"')}"`,{cwd:e,encoding:"utf-8"});let m=J("git rev-parse --short HEAD",{cwd:e,encoding:"utf-8"}).trim();try{J("git push",{cwd:e,stdio:"pipe"})}catch(g){let v=g instanceof Error?g.message:String(g);if(v.includes("no upstream branch")){let C=await n();J(`git push --set-upstream origin ${C}`,{cwd:e,stdio:"pipe"})}else return console.error("[Git] Push failed:",v),{success:!1,commitHash:m,commitSucceeded:!0,pushFailed:!0,error:v}}return{success:!0,commitHash:m}}catch(i){let l=i instanceof Error?i.message:String(i);return console.error("[Git] Error:",l),{success:!1,error:l}}},getCurrentBranch:n}}import ie from"inquirer";var re="\u2192 Other (type custom answer)";async function Ae(e){let t={};for(let n of e){let s=await dn(n);t[n.id]=s}return t}async function dn(e){return e.multiSelect&&e.options.length>0?pn(e):e.options.length>0?un(e):gn(e)}async function pn(e){let t=[...e.options];e.allowFreeText&&t.push(re);let{selection:n}=await ie.prompt([{type:"checkbox",name:"selection",message:e.question,choices:t}]);if(n.includes(re)){let{customAnswer:s}=await ie.prompt([{type:"input",name:"customAnswer",message:"Enter your custom answer:"}]);return[...n.filter(r=>r!==re),s]}return n}async function un(e){let t=[...e.options];e.allowFreeText&&t.push(re);let{selection:n}=await ie.prompt([{type:"select",name:"selection",message:e.question,choices:t}]);if(n===re){let{customAnswer:s}=await ie.prompt([{type:"input",name:"customAnswer",message:"Enter your custom answer:"}]);return s}return n}async function gn(e){let{answer:t}=await ie.prompt([{type:"input",name:"answer",message:e.question}]);return t}import*as j from"fs";import*as Pe from"path";var fn=".sdd/cli-sessions.json";function qe(){return Pe.join(process.cwd(),fn)}function mn(){let e=Pe.dirname(qe());j.existsSync(e)||j.mkdirSync(e,{recursive:!0})}function We(){try{let e=qe();if(!j.existsSync(e))return[];let t=j.readFileSync(e,"utf-8");return JSON.parse(t).sort((s,o)=>new Date(o.lastUsedAt).getTime()-new Date(s.lastUsedAt).getTime())}catch{return[]}}function bt(e){mn();let t=We(),n=t.findIndex(o=>o.sessionId===e.sessionId);n>=0?t[n]={...t[n],lastUsedAt:e.lastUsedAt,turnCount:e.turnCount}:t.unshift(e);let s=t.slice(0,20);j.writeFileSync(qe(),JSON.stringify(s,null,2))}function wt(e){let t=e.firstPrompt.length>50?e.firstPrompt.slice(0,50)+"...":e.firstPrompt,n=new Date(e.lastUsedAt),s=hn(n);return`${t} (${s}, ${e.turnCount} turns)`}function hn(e){let n=new Date().getTime()-e.getTime(),s=Math.floor(n/6e4),o=Math.floor(n/36e5),r=Math.floor(n/864e5);return s<1?"just now":s<60?`${s}m ago`:o<24?`${o}h ago`:r<7?`${r}d ago`:e.toLocaleDateString()}var kt={reset:"\x1B[0m",dim:"\x1B[2m",bold:"\x1B[1m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",red:"\x1B[31m",gray:"\x1B[90m"};function a(e,t){return`${kt[e]}${t}${kt.reset}`}var yn={Bash:"\u26A1",Read:"\u{1F4D6}",Write:"\u270F\uFE0F",Edit:"\u{1F527}",MultiEdit:"\u{1F527}",Glob:"\u{1F50D}",Grep:"\u{1F50E}",LS:"\u{1F4C1}",WebFetch:"\u{1F310}",NotebookRead:"\u{1F4D3}",NotebookEdit:"\u{1F4DD}",Task:"\u{1F4CB}",ask_questions:"\u2753",save_specification:"\u{1F4C4}",list_specifications:"\u{1F4CB}",read_specification:"\u{1F4D6}",delete_specification:"\u{1F5D1}\uFE0F",scaffold_entity:"\u{1F3D7}\uFE0F"};function bn(e){return yn[e]||"\u{1F527}"}function ae(e,t){return e.length<=t?e:e.slice(0,t-3)+"..."}function _t(e){let t=e.split("/");return t.length<=3?e:".../"+t.slice(-2).join("/")}function Ge(e){console.log(`
1361
+ `)}`:"";c.backendError||(c.backendError=`Backend failed to start.${w}`)}return b&&!P.web&&(c.success=!1,c.frontendError||(c.frontendError="Frontend failed to start")),c},Ve=async()=>{if(!m||!_.existsSync(m))return{success:!0};try{return J(S,{cwd:m,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),{success:!0}}catch(d){let c=d;return{success:!1,errors:c.stdout||c.stderr||"Build failed"}}},Je=async()=>{if(!g||!_.existsSync(Y.join(g,"package.json")))return{success:!0};try{return J(y,{cwd:g,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),{success:!0}}catch(d){let c=d;return{success:!1,errors:c.stdout||c.stderr||"Type check failed"}}},jt=async()=>{let[d,c]=await Promise.all([Ve(),Je()]);return{backend:d,frontend:c}},Xe=async(d,c)=>{let f=d==="backend"?R:L;if(!_.existsSync(f))return[`Log file not found: ${f}`];try{return J(`tail -n ${c} ${f}`,{encoding:"utf-8"}).split(`
1362
+ `).filter(Boolean)}catch(b){return[`Error reading logs: ${b instanceof Error?b.message:String(b)}`]}};return{startBackend:u,startFrontend:E,stopBackend:pe,stopFrontend:Z,restartServices:Nt,checkHealth:Ne,waitForHealth:ze,getProcesses:()=>({backend:O,frontend:D}),checkBackendBuild:Ve,checkFrontendTypes:Je,runTypeChecks:jt,tailLogs:Xe,checkSwaggerEndpoints:async d=>{let c=Y.join(t,"swagger.json");if(!_.existsSync(c))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let f=JSON.parse(_.readFileSync(c,"utf-8")),b=Object.keys(f.paths||{}),P=[];for(let T of b)if(T.toLowerCase().includes(d.toLowerCase())){let w=Object.keys(f.paths[T]);for(let $ of w)P.push(`${$.toUpperCase()} ${T}`)}return{foundEndpoints:P,totalEndpoints:b.length}}catch(f){return{foundEndpoints:[`Error parsing swagger.json: ${f instanceof Error?f.message:String(f)}`],totalEndpoints:0}}}}}function ln(e){let t=e.toLowerCase();return t.includes("exception")||t.includes("fail:")||t.includes("[err]")||t.includes("[error]")}import{execSync as X}from"child_process";function Ie(e){let t=async()=>{try{return X("git status --porcelain",{cwd:e,encoding:"utf-8"}).trim().length>0}catch{return!1}},n=async()=>{try{return X("git branch --show-current",{cwd:e,encoding:"utf-8"}).trim()}catch{return"unknown"}};return{hasChanges:t,commitAndPush:async(o,r)=>{try{if(!await t())return{success:!0,noChanges:!0};let i=o.length>60?o.substring(0,60)+"...":o,h=`${r?"[agent] (partial)":"[agent]"} ${i}`;X("git add -A",{cwd:e}),X(`git commit -m "${h.replace(/"/g,'\\"')}"`,{cwd:e,encoding:"utf-8"});let m=X("git rev-parse --short HEAD",{cwd:e,encoding:"utf-8"}).trim();try{X("git push",{cwd:e,stdio:"pipe"})}catch(g){let v=g instanceof Error?g.message:String(g);if(v.includes("no upstream branch")){let C=await n();X(`git push --set-upstream origin ${C}`,{cwd:e,stdio:"pipe"})}else return console.error("[Git] Push failed:",v),{success:!1,commitHash:m,commitSucceeded:!0,pushFailed:!0,error:v}}return{success:!0,commitHash:m}}catch(i){let l=i instanceof Error?i.message:String(i);return console.error("[Git] Error:",l),{success:!1,error:l}}},getCurrentBranch:n}}import ce from"inquirer";var ae="\u2192 Other (type custom answer)";async function Re(e){let t={};for(let n of e){let s=await dn(n);t[n.id]=s}return t}async function dn(e){return e.multiSelect&&e.options.length>0?pn(e):e.options.length>0?un(e):gn(e)}async function pn(e){let t=[...e.options];e.allowFreeText&&t.push(ae);let{selection:n}=await ce.prompt([{type:"checkbox",name:"selection",message:e.question,choices:t}]);if(n.includes(ae)){let{customAnswer:s}=await ce.prompt([{type:"input",name:"customAnswer",message:"Enter your custom answer:"}]);return[...n.filter(r=>r!==ae),s]}return n}async function un(e){let t=[...e.options];e.allowFreeText&&t.push(ae);let{selection:n}=await ce.prompt([{type:"select",name:"selection",message:e.question,choices:t}]);if(n===ae){let{customAnswer:s}=await ce.prompt([{type:"input",name:"customAnswer",message:"Enter your custom answer:"}]);return s}return n}async function gn(e){let{answer:t}=await ce.prompt([{type:"input",name:"answer",message:e.question}]);return t}import*as j from"fs";import*as Oe from"path";var fn=".sdd/cli-sessions.json";function He(){return Oe.join(process.cwd(),fn)}function mn(){let e=Oe.dirname(He());j.existsSync(e)||j.mkdirSync(e,{recursive:!0})}function Ye(){try{let e=He();if(!j.existsSync(e))return[];let t=j.readFileSync(e,"utf-8");return JSON.parse(t).sort((s,o)=>new Date(o.lastUsedAt).getTime()-new Date(s.lastUsedAt).getTime())}catch{return[]}}function bt(e){mn();let t=Ye(),n=t.findIndex(o=>o.sessionId===e.sessionId);n>=0?t[n]={...t[n],lastUsedAt:e.lastUsedAt,turnCount:e.turnCount}:t.unshift(e);let s=t.slice(0,20);j.writeFileSync(He(),JSON.stringify(s,null,2))}function wt(e){let t=e.firstPrompt.length>50?e.firstPrompt.slice(0,50)+"...":e.firstPrompt,n=new Date(e.lastUsedAt),s=hn(n);return`${t} (${s}, ${e.turnCount} turns)`}function hn(e){let n=new Date().getTime()-e.getTime(),s=Math.floor(n/6e4),o=Math.floor(n/36e5),r=Math.floor(n/864e5);return s<1?"just now":s<60?`${s}m ago`:o<24?`${o}h ago`:r<7?`${r}d ago`:e.toLocaleDateString()}var kt={reset:"\x1B[0m",dim:"\x1B[2m",bold:"\x1B[1m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",red:"\x1B[31m",gray:"\x1B[90m"};function a(e,t){return`${kt[e]}${t}${kt.reset}`}var yn={Bash:"\u26A1",Read:"\u{1F4D6}",Write:"\u270F\uFE0F",Edit:"\u{1F527}",MultiEdit:"\u{1F527}",Glob:"\u{1F50D}",Grep:"\u{1F50E}",LS:"\u{1F4C1}",WebFetch:"\u{1F310}",NotebookRead:"\u{1F4D3}",NotebookEdit:"\u{1F4DD}",Task:"\u{1F4CB}",ask_questions:"\u2753",save_specification:"\u{1F4C4}",list_specifications:"\u{1F4CB}",read_specification:"\u{1F4D6}",delete_specification:"\u{1F5D1}\uFE0F",scaffold_entity:"\u{1F3D7}\uFE0F"};function bn(e){return yn[e]||"\u{1F527}"}function le(e,t){return e.length<=t?e:e.slice(0,t-3)+"..."}function _t(e){let t=e.split("/");return t.length<=3?e:".../"+t.slice(-2).join("/")}function Ke(e){console.log(`
1363
1363
  ${a("bold",a("cyan","\u2550".repeat(60)))}`),console.log(a("bold",` ${e}`)),console.log(`${a("bold",a("cyan","\u2550".repeat(60)))}
1364
1364
  `)}function St(e){let t=e.split(`
1365
1365
  `);for(let n of t)n.trim()?console.log(` ${n}`):console.log()}function vt(e,t){if(t&&typeof t=="object"){let s=t;if(e==="Task"&&s.subagent_type){let o=String(s.subagent_type);if(console.log(`
1366
- \u{1F916} ${a("bold",a("magenta",`Delegating to @${o}`))}`),s.prompt){let r=ae(String(s.prompt),100);console.log(` ${a("dim","\u2192")} ${a("gray",r)}`)}return}}let n=bn(e);if(console.log(`
1367
- ${n} ${a("bold",a("blue",e))}`),t&&typeof t=="object"){let s=t;if(e==="Bash"&&s.command)console.log(` ${a("dim","$")} ${a("yellow",ae(String(s.command),80))}`);else if((e==="Read"||e==="Write"||e==="Edit")&&s.file_path)console.log(` ${a("dim","\u2192")} ${a("cyan",_t(String(s.file_path)))}`);else if(e==="Grep"&&s.pattern)console.log(` ${a("dim","/")}${a("magenta",String(s.pattern))}${a("dim","/")}`);else if(e==="LS"&&s.path)console.log(` ${a("dim","\u2192")} ${a("cyan",_t(String(s.path)))}`);else if(e==="scaffold_entity"&&s.name)console.log(` ${a("dim","\u2192")} Creating entity: ${a("green",String(s.name))}`);else if(e==="ask_questions"&&s.questions){let o=s.questions;console.log(` ${a("dim","\u2192")} ${o.length} question(s)`)}else e==="save_specification"&&s.name&&console.log(` ${a("dim","\u2192")} ${a("green",String(s.name))}`)}}function Tt(e,t){console.log(`
1368
- ${a("bold",a("green","\u2713 Complete"))}`),console.log(` ${a("dim","Result:")} ${ae(e,100)}`),console.log(` ${a("dim","Cost:")} ${a("yellow",`$${t.toFixed(4)}`)}`)}function Ct(e){console.log(`
1366
+ \u{1F916} ${a("bold",a("magenta",`Delegating to @${o}`))}`),s.prompt){let r=le(String(s.prompt),100);console.log(` ${a("dim","\u2192")} ${a("gray",r)}`)}return}}let n=bn(e);if(console.log(`
1367
+ ${n} ${a("bold",a("blue",e))}`),t&&typeof t=="object"){let s=t;if(e==="Bash"&&s.command)console.log(` ${a("dim","$")} ${a("yellow",le(String(s.command),80))}`);else if((e==="Read"||e==="Write"||e==="Edit")&&s.file_path)console.log(` ${a("dim","\u2192")} ${a("cyan",_t(String(s.file_path)))}`);else if(e==="Grep"&&s.pattern)console.log(` ${a("dim","/")}${a("magenta",String(s.pattern))}${a("dim","/")}`);else if(e==="LS"&&s.path)console.log(` ${a("dim","\u2192")} ${a("cyan",_t(String(s.path)))}`);else if(e==="scaffold_entity"&&s.name)console.log(` ${a("dim","\u2192")} Creating entity: ${a("green",String(s.name))}`);else if(e==="ask_questions"&&s.questions){let o=s.questions;console.log(` ${a("dim","\u2192")} ${o.length} question(s)`)}else e==="save_specification"&&s.name&&console.log(` ${a("dim","\u2192")} ${a("green",String(s.name))}`)}}function Tt(e,t){console.log(`
1368
+ ${a("bold",a("green","\u2713 Complete"))}`),console.log(` ${a("dim","Result:")} ${le(e,100)}`),console.log(` ${a("dim","Cost:")} ${a("yellow",`$${t.toFixed(4)}`)}`)}function Ct(e){console.log(`
1369
1369
  ${a("bold",a("red","\u2717 Error"))}`),console.log(` ${e}`)}function Et(){console.log(`
1370
1370
  ${a("bold",a("yellow","\u23F9\uFE0F Aborted"))}`),console.log(` ${a("dim","Session stopped by user. Progress has been preserved.")}`)}function At(){console.log(`
1371
1371
  ${a("bold",a("yellow","\u2753 Agent needs your input"))}
1372
1372
  `)}function Pt(){console.log(`
1373
1373
  ${a("dim","\u2192 Answers sent, agent continuing...")}
1374
- `)}function xe(){console.log(a("dim",`
1374
+ `)}function De(){console.log(a("dim",`
1375
1375
  `+"\u2500".repeat(50)+`
1376
- `))}function xt(e,t){let n="";if(typeof t=="string")n=ae(t,100);else if(Array.isArray(t)){let s=t.find(o=>typeof o=="object"&&o!==null&&o.type==="text");if(s&&typeof s=="object"){let o=s.text;if(typeof o=="string"){let r=o.split(`
1377
- `).filter(i=>i.trim());r.length>3?n=r.slice(0,3).join(" \u21B5 ")+` (+${r.length-3} more lines)`:n=r.join(" \u21B5 "),n=ae(n,100)}}}console.log(n?` ${a("dim","\u2190")} ${a("gray",n)}`:` ${a("dim","\u2190")} ${a("green","done")}`)}function It(e){return{onAssistantText:St,onAssistantToolUse:(t,n)=>{if(vt(t,n),["Write","Edit","MultiEdit"].includes(t)){let s=n,o=s.file_path||s.target_file;o&&e.onFileModified(o)}},onAssistantToolResult:xt,onResult:(t,n)=>{e.onCostUpdate(n),Tt(t,n)},onError:Ct,onAborted:Et,onSystemInit:t=>{e.sessionId||(e.onSessionInit(t),console.log(` Session: ${t.slice(0,12)}...`))}}}import I from"inquirer";import*as M from"fs";import*as Ie from"path";var{Separator:wn}=I,kn=".sdd/api-config.json";function He(){return Ie.join(process.cwd(),kn)}function _n(){let e=Ie.dirname(He());M.existsSync(e)||M.mkdirSync(e,{recursive:!0})}function Sn(){try{let e=He();if(!M.existsSync(e))return null;let t=M.readFileSync(e,"utf-8");return JSON.parse(t)}catch{return null}}function vn(e){_n();let t={...e,lastUsedAt:new Date().toISOString()};M.writeFileSync(He(),JSON.stringify(t,null,2))}async function Rt(){let{options:e}=await I.prompt([{type:"checkbox",name:"options",message:"Session options:",choices:[{name:"\u{1F50D} Auto-typecheck (self-correcting mode)",value:"typecheck"},{name:"\u{1F4E6} Auto-commit & push",value:"autoCommit"}]}]),{model:t}=await I.prompt([{type:"list",name:"model",message:"Select Claude model:",choices:[{name:"\u{1F916} Auto (let Claude choose)",value:"auto"},{name:"\u{1F9E0} Opus 4.6 (most capable)",value:"claude-opus-4-6"},{name:"\u26A1 Sonnet 4.5 (fast & capable)",value:"claude-sonnet-4-5-20250929"},{name:"\u{1F4A8} Haiku 4.5 (fastest)",value:"claude-haiku-4-5-20251001"}],default:"auto"}]);return{typecheck:e.includes("typecheck"),autoCommit:e.includes("autoCommit"),model:t}}async function Ot(){let e=We();if(e.length===0){let{prompt:r}=await I.prompt([{type:"input",name:"prompt",message:"What would you like to build?"}]);return{sessionId:null,firstPrompt:r,isResume:!1,existingTurnCount:0}}let t=[{name:"\u{1F195} Start new session",value:"new"},new wn("\u2500\u2500\u2500 Previous Sessions \u2500\u2500\u2500"),...e.map(r=>({name:wt(r),value:r.sessionId}))],{selection:n}=await I.prompt([{type:"select",name:"selection",message:"Select a session:",choices:t}]);if(n==="new"){let{prompt:r}=await I.prompt([{type:"input",name:"prompt",message:"What would you like to build?"}]);return{sessionId:null,firstPrompt:r,isResume:!1,existingTurnCount:0}}let s=e.find(r=>r.sessionId===n);console.log(`
1378
- \u{1F4C2} Resuming session: ${s.firstPrompt.slice(0,50)}...`);let{prompt:o}=await I.prompt([{type:"input",name:"prompt",message:"Continue with:"}]);return{sessionId:s.sessionId,firstPrompt:s.firstPrompt,isResume:!0,existingTurnCount:s.turnCount||0}}async function Re(){let{action:e}=await I.prompt([{type:"select",name:"action",message:"What would you like to do?",choices:[{name:"\u{1F4DD} Send follow-up message",value:"followup"},{name:"\u{1F6AA} Exit",value:"exit"}]}]);if(e==="exit")return null;let{prompt:t}=await I.prompt([{type:"input",name:"prompt",message:"Your message:"}]);return t}async function Dt(){let{action:e}=await I.prompt([{type:"select",name:"action",message:"What would you like to do?",choices:[{name:"Continue with a new prompt",value:"continue"},{name:"Exit (session saved)",value:"exit"}]}]);return e}async function Ut(){let e=process.env.API_URL||process.env.MASTER_URL,t=process.env.PROJECT_ID,n=Sn();if(n&&!e&&!t){console.log(`
1376
+ `))}function xt(e,t){let n="";if(typeof t=="string")n=le(t,100);else if(Array.isArray(t)){let s=t.find(o=>typeof o=="object"&&o!==null&&o.type==="text");if(s&&typeof s=="object"){let o=s.text;if(typeof o=="string"){let r=o.split(`
1377
+ `).filter(i=>i.trim());r.length>3?n=r.slice(0,3).join(" \u21B5 ")+` (+${r.length-3} more lines)`:n=r.join(" \u21B5 "),n=le(n,100)}}}console.log(n?` ${a("dim","\u2190")} ${a("gray",n)}`:` ${a("dim","\u2190")} ${a("green","done")}`)}function It(e){return{onAssistantText:St,onAssistantToolUse:(t,n)=>{if(vt(t,n),["Write","Edit","MultiEdit"].includes(t)){let s=n,o=s.file_path||s.target_file;o&&e.onFileModified(o)}},onAssistantToolResult:xt,onResult:(t,n)=>{e.onCostUpdate(n),Tt(t,n)},onError:Ct,onAborted:Et,onSystemInit:t=>{e.sessionId||(e.onSessionInit(t),console.log(` Session: ${t.slice(0,12)}...`))}}}import x from"inquirer";import*as M from"fs";import*as Ue from"path";var{Separator:wn}=x,kn=".sdd/api-config.json";function Qe(){return Ue.join(process.cwd(),kn)}function _n(){let e=Ue.dirname(Qe());M.existsSync(e)||M.mkdirSync(e,{recursive:!0})}function Sn(){try{let e=Qe();if(!M.existsSync(e))return null;let t=M.readFileSync(e,"utf-8");return JSON.parse(t)}catch{return null}}function vn(e){_n();let t={...e,lastUsedAt:new Date().toISOString()};M.writeFileSync(Qe(),JSON.stringify(t,null,2))}async function Rt(){let{options:e}=await x.prompt([{type:"checkbox",name:"options",message:"Session options:",choices:[{name:"\u{1F50D} Auto-typecheck (self-correcting mode)",value:"typecheck"},{name:"\u{1F4E6} Auto-commit & push",value:"autoCommit"}]}]),{model:t}=await x.prompt([{type:"list",name:"model",message:"Select Claude model:",choices:[{name:"\u{1F916} Auto (let Claude choose)",value:"auto"},{name:"\u{1F9E0} Opus 4.6 (most capable)",value:"claude-opus-4-6"},{name:"\u26A1 Sonnet 4.5 (fast & capable)",value:"claude-sonnet-4-5-20250929"},{name:"\u{1F4A8} Haiku 4.5 (fastest)",value:"claude-haiku-4-5-20251001"}],default:"auto"}]);return{typecheck:e.includes("typecheck"),autoCommit:e.includes("autoCommit"),model:t}}async function Ot(){let e=Ye();if(e.length===0){let{prompt:r}=await x.prompt([{type:"input",name:"prompt",message:"What would you like to build?"}]);return{sessionId:null,firstPrompt:r,isResume:!1,existingTurnCount:0}}let t=[{name:"\u{1F195} Start new session",value:"new"},new wn("\u2500\u2500\u2500 Previous Sessions \u2500\u2500\u2500"),...e.map(r=>({name:wt(r),value:r.sessionId}))],{selection:n}=await x.prompt([{type:"select",name:"selection",message:"Select a session:",choices:t}]);if(n==="new"){let{prompt:r}=await x.prompt([{type:"input",name:"prompt",message:"What would you like to build?"}]);return{sessionId:null,firstPrompt:r,isResume:!1,existingTurnCount:0}}let s=e.find(r=>r.sessionId===n);console.log(`
1378
+ \u{1F4C2} Resuming session: ${s.firstPrompt.slice(0,50)}...`);let{prompt:o}=await x.prompt([{type:"input",name:"prompt",message:"Continue with:"}]);return{sessionId:s.sessionId,firstPrompt:s.firstPrompt,isResume:!0,existingTurnCount:s.turnCount||0}}async function Fe(){let{action:e}=await x.prompt([{type:"select",name:"action",message:"What would you like to do?",choices:[{name:"\u{1F4DD} Send follow-up message",value:"followup"},{name:"\u{1F6AA} Exit",value:"exit"}]}]);if(e==="exit")return null;let{prompt:t}=await x.prompt([{type:"input",name:"prompt",message:"Your message:"}]);return t}async function Dt(){let{action:e}=await x.prompt([{type:"select",name:"action",message:"What would you like to do?",choices:[{name:"Continue with a new prompt",value:"continue"},{name:"Exit (session saved)",value:"exit"}]}]);return e}async function Ut(){let e=process.env.API_URL||process.env.MASTER_URL,t=process.env.PROJECT_ID,n=Sn();if(n&&!e&&!t){console.log(`
1379
1379
  \u{1F4CB} Previous API Configuration Found
1380
- `),console.log(` \u{1F517} API URL: ${n.apiUrl}`),console.log(` \u{1F194} Project ID: ${n.projectId}`);let{action:r}=await I.prompt([{type:"select",name:"action",message:"What would you like to do?",choices:[{name:"\u2705 Proceed with saved configuration",value:"proceed"},{name:"\u{1F504} Override with new configuration",value:"override"}]}]);if(r==="proceed")return{apiUrl:n.apiUrl,projectId:n.projectId}}let s=await I.prompt([{type:"input",name:"apiUrl",message:"API URL (backend endpoint):",default:e||n?.apiUrl||"http://localhost:5338",validate:r=>{if(!r.trim())return"API URL is required";try{return new URL(r),!0}catch{return"Please enter a valid URL"}}},{type:"input",name:"projectId",message:"Project ID:",default:t||n?.projectId,validate:r=>r.trim()?!0:"Project ID is required"}]),o={apiUrl:s.apiUrl,projectId:s.projectId};return vn(o),o}async function Ft(e,t){if(t.size===0)return console.log(`
1380
+ `),console.log(` \u{1F517} API URL: ${n.apiUrl}`),console.log(` \u{1F194} Project ID: ${n.projectId}`);let{action:r}=await x.prompt([{type:"select",name:"action",message:"What would you like to do?",choices:[{name:"\u2705 Proceed with saved configuration",value:"proceed"},{name:"\u{1F504} Override with new configuration",value:"override"}]}]);if(r==="proceed")return{apiUrl:n.apiUrl,projectId:n.projectId}}let s=await x.prompt([{type:"input",name:"apiUrl",message:"API URL (backend endpoint):",default:e||n?.apiUrl||"http://localhost:5338",validate:r=>{if(!r.trim())return"API URL is required";try{return new URL(r),!0}catch{return"Please enter a valid URL"}}},{type:"input",name:"projectId",message:"Project ID:",default:t||n?.projectId,validate:r=>r.trim()?!0:"Project ID is required"}]),o={apiUrl:s.apiUrl,projectId:s.projectId};return vn(o),o}async function Ft(e,t){if(t.size===0)return console.log(`
1381
1381
  ${a("dim","\u23ED\uFE0F No code changes, skipping type checks")}`),{passed:!0};let n=[...t].some(l=>l.includes("dotnet-api")||l.endsWith(".cs")),s=[...t].some(l=>l.includes("backoffice-web")||l.endsWith(".ts")||l.endsWith(".tsx"));if(!n&&!s)return console.log(`
1382
1382
  ${a("dim","\u23ED\uFE0F No code changes, skipping type checks")}`),{passed:!0};let o=[];n&&o.push("backend"),s&&o.push("frontend"),console.log(`
1383
1383
  ${a("dim",`\u{1F50D} Type checking ${o.join(" & ")}...`)}`);let r=process.env.WORKSPACE_DIR||process.cwd(),i=[];if(n){let l=await e.checkBackendBuild();!l.success&&l.errors&&i.push(`## Backend Build Errors (in ${r}/packages/dotnet-api)
@@ -1396,13 +1396,13 @@ ${i.join(`
1396
1396
  `)}
1397
1397
 
1398
1398
  File paths like "src/..." are relative to the package directory shown in parentheses.`}):(console.log(` ${a("green","\u2713 All type checks passed")}`),{passed:!0})}async function Lt(e,t,n){if(!await e.hasChanges())return;console.log(`
1399
- ${a("dim","\u{1F4E6} Committing changes...")}`);let o=await e.commitAndPush(t,n);if(o.noChanges)console.log(` ${a("dim","No changes to commit")}`);else if(o.success){let r=await e.getCurrentBranch();console.log(` ${a("green","\u2713 Committed")} ${a("dim",o.commitHash||"")}`),console.log(` ${a("dim",` \u2192 Pushed to ${r}`)}`),o.error&&console.log(` ${a("yellow",`\u26A0\uFE0F ${o.error}`)}`)}else console.log(` ${a("red",`\u274C Git error: ${o.error}`)}`)}var ce=null;process.stdout.on("error",e=>{e.code!=="EPIPE"&&console.error("stdout error:",e)});process.stderr.on("error",e=>{e.code!=="EPIPE"&&console.error("stderr error:",e)});process.on("SIGINT",()=>{ce?(console.log(`
1399
+ ${a("dim","\u{1F4E6} Committing changes...")}`);let o=await e.commitAndPush(t,n);if(o.noChanges)console.log(` ${a("dim","No changes to commit")}`);else if(o.success){let r=await e.getCurrentBranch();console.log(` ${a("green","\u2713 Committed")} ${a("dim",o.commitHash||"")}`),console.log(` ${a("dim",` \u2192 Pushed to ${r}`)}`),o.error&&console.log(` ${a("yellow",`\u26A0\uFE0F ${o.error}`)}`)}else console.log(` ${a("red",`\u274C Git error: ${o.error}`)}`)}var de=null;process.stdout.on("error",e=>{e.code!=="EPIPE"&&console.error("stdout error:",e)});process.stderr.on("error",e=>{e.code!=="EPIPE"&&console.error("stderr error:",e)});process.on("SIGINT",()=>{de?(console.log(`
1400
1400
 
1401
1401
  \u23F9\uFE0F Stopping agent...
1402
- `),ce.abort()):(console.log(`
1403
- `),process.exit(0))});async function Oe(e,t={}){let{serviceManager:n,gitManager:s}=t,o=null,r,i,l=0,h=0,m=t.typecheck??!1,g=t.autoCommit??!1,v=t.model;if(e)r=e,i=e;else{let C=await Rt();n&&(m=C.typecheck),s&&(g=C.autoCommit),t.skipModelPrompt||(v=C.model);let S=await Ot();o=S.sessionId,r=S.firstPrompt,l=S.existingTurnCount,i=S.isResume&&await Re()||r}for(Tn(m,g,!!n,!!s,v);;){l++,console.log(`
1404
- Turn ${l}`),xe();let C=new Set;ce=new AbortController;let S=await ve(i,{model:v==="auto"?void 0:v,sessionId:o,projectId:process.env.PROJECT_ID||null,debugLog:!0,abortController:ce,callbacks:It({sessionId:o,onSessionInit:y=>{o=y},onCostUpdate:y=>{h+=y},onFileModified:y=>{C.add(y)}})});if(console.log("after runAgent"),ce=null,S.sessionId&&(o=S.sessionId),S.cost&&(h=S.cost),console.log("after result"),En(o,r,l),console.log("after saveSessionIfNeeded"),S.aborted){if(await new Promise(F=>setTimeout(F,100)),xe(),h>0&&console.log(` \u{1F4B0} Session cost so far: $${h.toFixed(4)}
1405
- `),await Dt()==="exit")break;let R=await Re();if(!R)break;i=R;continue}if(console.log("after abort"),o){let y=te(o);if(y&&y.length>0){At();let R=await Ae(y);i=Te(R),Pt();continue}}if(console.log("after pending questions"),m&&n){let y=await Ft(n,C);if(!y.passed&&y.errorPrompt){i=y.errorPrompt;continue}}if(console.log("after typecheck"),g&&s){let y=S.aborted||!!S.error;await Lt(s,r,y)}console.log("after auto-commit"),xe();let O=await Re();if(!O)break;i=O}Cn(o,h)}function Tn(e,t,n,s,o){Ge("\u{1F680} Agent Started"),console.log(" \u{1F4DD} Debug logs \u2192 /tmp/agent-debug/"),o&&console.log(` \u{1F916} Model: ${o==="auto"?"Auto":o==="claude-opus-4-6"?"Opus 4.6":o==="claude-sonnet-4-5-20250929"?"Sonnet 4.5":o==="claude-haiku-4-5-20251001"?"Haiku 4.5":"Unknown"}`),e&&n&&console.log(" \u{1F50D} Auto-typecheck enabled (self-correcting mode)"),t&&s&&console.log(" \u{1F4E6} Auto-commit enabled"),console.log(` \u{1F4A1} Press Ctrl+C to stop the agent
1406
- `)}function Cn(e,t){Ge("\u2705 Session Complete"),e&&console.log(" \u{1F4BE} Session saved - you can resume it next time"),t>0&&console.log(` \u{1F4B0} Total cost: $${t.toFixed(4)}`),console.log()}function En(e,t,n){e&&bt({sessionId:e,firstPrompt:t,createdAt:new Date().toISOString(),lastUsedAt:new Date().toISOString(),turnCount:n})}process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT=process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT||"60000";async function An(){let e=process.env.API_URL||process.env.MASTER_URL,t=process.env.PROJECT_ID,n=e,s=t;if(!e||!t){console.log(`
1402
+ `),de.abort()):(console.log(`
1403
+ `),process.exit(0))});async function Le(e,t={}){let{serviceManager:n,gitManager:s}=t,o=null,r,i,l=0,h=0,m=t.typecheck??!1,g=t.autoCommit??!1,v=t.model;if(e)r=e,i=e;else{let C=await Rt();n&&(m=C.typecheck),s&&(g=C.autoCommit),t.skipModelPrompt||(v=C.model);let S=await Ot();o=S.sessionId,r=S.firstPrompt,l=S.existingTurnCount,i=S.isResume&&await Fe()||r}for(Tn(m,g,!!n,!!s,v);;){l++,console.log(`
1404
+ Turn ${l}`),De();let C=new Set;de=new AbortController;let S=await Ae(i,{model:v==="auto"?void 0:v,sessionId:o,projectId:process.env.PROJECT_ID||null,debugLog:!0,abortController:de,callbacks:It({sessionId:o,onSessionInit:y=>{o=y},onCostUpdate:y=>{h+=y},onFileModified:y=>{C.add(y)}})});if(console.log("after runAgent"),de=null,S.sessionId&&(o=S.sessionId),S.cost&&(h=S.cost),console.log("after result"),En(o,r,l),console.log("after saveSessionIfNeeded"),S.aborted){if(await new Promise(L=>setTimeout(L,100)),De(),h>0&&console.log(` \u{1F4B0} Session cost so far: $${h.toFixed(4)}
1405
+ `),await Dt()==="exit")break;let R=await Fe();if(!R)break;i=R;continue}if(console.log("after abort"),o){let y=oe(o);if(y&&y.length>0){At();let R=await Re(y);i=Pe(R),Pt();continue}}if(console.log("after pending questions"),m&&n){let y=await Ft(n,C);if(!y.passed&&y.errorPrompt){i=y.errorPrompt;continue}}if(console.log("after typecheck"),g&&s){let y=S.aborted||!!S.error;await Lt(s,r,y)}console.log("after auto-commit"),De();let I=await Fe();if(!I)break;i=I}Cn(o,h)}function Tn(e,t,n,s,o){Ke("\u{1F680} Agent Started"),console.log(" \u{1F4DD} Debug logs \u2192 /tmp/agent-debug/"),o&&console.log(` \u{1F916} Model: ${o==="auto"?"Auto":o==="claude-opus-4-6"?"Opus 4.6":o==="claude-sonnet-4-5-20250929"?"Sonnet 4.5":o==="claude-haiku-4-5-20251001"?"Haiku 4.5":"Unknown"}`),e&&n&&console.log(" \u{1F50D} Auto-typecheck enabled (self-correcting mode)"),t&&s&&console.log(" \u{1F4E6} Auto-commit enabled"),console.log(` \u{1F4A1} Press Ctrl+C to stop the agent
1406
+ `)}function Cn(e,t){Ke("\u2705 Session Complete"),e&&console.log(" \u{1F4BE} Session saved - you can resume it next time"),t>0&&console.log(` \u{1F4B0} Total cost: $${t.toFixed(4)}`),console.log()}function En(e,t,n){e&&bt({sessionId:e,firstPrompt:t,createdAt:new Date().toISOString(),lastUsedAt:new Date().toISOString(),turnCount:n})}process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT=process.env.CLAUDE_CODE_STREAM_CLOSE_TIMEOUT||"60000";async function An(){let e=process.env.API_URL||process.env.MASTER_URL,t=process.env.PROJECT_ID,n=e,s=t;if(!e||!t){console.log(`
1407
1407
  \u{1F4CB} API Configuration Required
1408
- `);let m=await Ut();n=m.apiUrl,s=m.projectId}process.env.API_URL=n,process.env.PROJECT_ID=s;let o=process.env.WORKSPACE_DIR||process.cwd(),r=Ce({workspaceDir:o}),i=Ee(o),l=ne(o);ge(r),ue(l),await Oe(void 0,{serviceManager:r,gitManager:i})}An().catch(e=>{console.error("Fatal error:",e),process.exit(1)});
1408
+ `);let m=await Ut();n=m.apiUrl,s=m.projectId}process.env.API_URL=n,process.env.PROJECT_ID=s;let o=process.env.WORKSPACE_DIR||process.cwd(),r=xe({workspaceDir:o}),i=Ie(o),l=se(o);he(r),me(l),await Le(void 0,{serviceManager:r,gitManager:i})}An().catch(e=>{console.error("Fatal error:",e),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glenn-code",
3
- "version": "1.0.33",
3
+ "version": "1.0.35",
4
4
  "description": "Glenn Code - Connect your local development environment to DNM Lab",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -47,9 +47,9 @@
47
47
  "typescript": "^5.6.0"
48
48
  },
49
49
  "dependencies": {
50
- "@anthropic-ai/claude-agent-sdk": "0.2.41",
50
+ "@anthropic-ai/claude-agent-sdk": "0.2.44",
51
51
  "@microsoft/signalr": "^8.0.7",
52
- "@modelcontextprotocol/sdk": "^1.25.1",
52
+ "@modelcontextprotocol/sdk": "^1.26.0",
53
53
  "inquirer": "^13.1.0",
54
54
  "zod": "4.3.6"
55
55
  }