glenn-code 1.0.0
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/README.md +127 -0
- package/bin/cli.js +75 -0
- package/dist/cli.js +1260 -0
- package/dist/core.js +1231 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1274 -0
- package/package.json +56 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1274 @@
|
|
|
1
|
+
// Glenn Code - Bundled and minified
|
|
2
|
+
// (c) DNM Lab - All rights reserved
|
|
3
|
+
|
|
4
|
+
import{createSdkMcpServer as jt}from"@anthropic-ai/claude-agent-sdk";import{tool as ce}from"@anthropic-ai/claude-agent-sdk";import{z as ae}from"zod";import*as le from"fs";import*as Je from"path";var N=null;function de(e){N=e}function Fe(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}var xn=ce("save_specification",`Save a specification to the database.
|
|
5
|
+
|
|
6
|
+
IMPORTANT: First write the specification content to a file using the Write tool, then call this with the file path.
|
|
7
|
+
|
|
8
|
+
Workflow:
|
|
9
|
+
1. Use Write tool to save your spec to a temp file (e.g., /tmp/my-spec.md)
|
|
10
|
+
2. Call this tool with the name and file path
|
|
11
|
+
3. This tool reads the file and saves to database
|
|
12
|
+
|
|
13
|
+
Example:
|
|
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:ae.string().describe("Specification name (e.g., 'User Authentication')"),filePath:ae.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=Je.resolve(e.filePath);if(!le.existsSync(t))return{content:[{type:"text",text:`\u274C File not found: ${e.filePath}. Use Write tool first to create the file.`}]};let n=le.readFileSync(t,"utf-8"),s=Fe(e.name);return await N.saveSpecification(s,n),{content:[{type:"text",text:`\u2705 Saved specification: ${s}.spec.md`}]}}),In=ce("read_specification","Read the content of a specification.",{name:ae.string().describe("Name of the specification to read")},async e=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let t=Fe(e.name),n=await N.getSpecification(t);return n?{content:[{type:"text",text:n}]}:{content:[{type:"text",text:`\u274C Specification "${e.name}" not found.`}]}}),Rn=ce("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
|
+
|
|
17
|
+
${e.map(n=>`- ${n.name} (${n.slug}.spec.md)`).join(`
|
|
18
|
+
`)}`}]}}),On=ce("delete_specification","Delete a specification.",{name:ae.string().describe("Name of the specification to delete")},async e=>{if(!N)return{content:[{type:"text",text:"\u274C Planning transport not initialized"}]};let t=Fe(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 J}from"zod";var S=null;function pe(e){S=e}var Xe=q("restart_services",`Rebuild and restart services. Call this after making backend changes (.cs files) to apply them.
|
|
19
|
+
|
|
20
|
+
Parameters:
|
|
21
|
+
- target: "backend" (default) | "frontend" | "both"
|
|
22
|
+
|
|
23
|
+
Use target="backend" after .cs file changes (faster, only restarts .NET).
|
|
24
|
+
Use target="frontend" if Vite is stuck (rare, HMR usually works).
|
|
25
|
+
Use target="both" if unsure or both need restart.`,{target:J.enum(["backend","frontend","both"]).default("backend").describe("Which service to restart")},async e=>{if(!S)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 S.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
|
+
${o.join(`
|
|
27
|
+
|
|
28
|
+
`)}`}]}}return{content:[{type:"text",text:`\u2705 ${t==="both"?"Backend and frontend":t==="backend"?"Backend":"Frontend"} restarted successfully.`}]}}),Ze=q("stop_services",`Stop running services. Call this BEFORE running scaffold to prevent port conflicts and ensure clean migrations.
|
|
29
|
+
|
|
30
|
+
Parameters:
|
|
31
|
+
- target: "backend" (default) | "frontend" | "both"
|
|
32
|
+
|
|
33
|
+
Use target="backend" before running scaffold (required for migrations).`,{target:J.enum(["backend","frontend","both"]).default("backend").describe("Which service to stop")},async e=>{if(!S)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 S.stopBackend(),s&&await S.stopFrontend();let o=5e3,r=Date.now(),i=!n,l=!s;for(;Date.now()-r<o;){let m=await S.checkHealth();if(n&&!m.api&&(i=!0),s&&!m.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.`}]}}),et=q("start_services",`Start services. Call this AFTER running scaffold to bring services back up.
|
|
34
|
+
|
|
35
|
+
Parameters:
|
|
36
|
+
- target: "backend" (default) | "frontend" | "both"
|
|
37
|
+
|
|
38
|
+
Use target="backend" after running scaffold.`,{target:J.enum(["backend","frontend","both"]).default("backend").describe("Which service to start")},async e=>{if(!S)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 S.startBackend(),s&&await S.startFrontend();let o=await S.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 f=[];return n&&!o.api&&f.push("Backend failed to start"),s&&!o.web&&f.push("Frontend failed to start"),{content:[{type:"text",text:`\u274C ${h} failed to start: ${f.join(", ")}`}]}}return{content:[{type:"text",text:`\u2705 ${h} started successfully.`}]}}),tt=q("check_service_health",`Check if services are running and healthy. Returns current status of backend API and frontend.
|
|
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(!S)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let e=await S.checkHealth();return{content:[{type:"text",text:`Service Health:
|
|
40
|
+
\u{1F5A5}\uFE0F Backend API: ${e.api?"\u2705 running":"\u274C not running"}
|
|
41
|
+
\u{1F310} Frontend: ${e.web?"\u2705 running":"\u274C not running"}`}]}}),nt=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(!S)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};console.log("[MCP] check_backend_build called");let e=await S.checkBackendBuild();return e.success?{content:[{type:"text",text:"\u2705 Backend build succeeded - no errors"}]}:{content:[{type:"text",text:`\u274C Backend build failed:
|
|
42
|
+
|
|
43
|
+
${e.errors}`}]}}),ot=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(!S)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};console.log("[MCP] check_frontend_types called");let e=await S.checkFrontendTypes();return e.success?{content:[{type:"text",text:"\u2705 Frontend type check passed - no errors"}]}:{content:[{type:"text",text:`\u274C Frontend type errors:
|
|
44
|
+
|
|
45
|
+
${e.errors}`}]}}),Nn=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.
|
|
46
|
+
|
|
47
|
+
Parameters:
|
|
48
|
+
- target: "backend" | "frontend"
|
|
49
|
+
- lines: number (default 50)`,{target:J.enum(["backend","frontend"]).describe("Which log to read"),lines:J.number().default(50).describe("Number of lines to read")},async e=>{if(!S)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=await S.tailLogs(e.target,e.lines);return{content:[{type:"text",text:`Last ${e.lines} lines of ${e.target} log:
|
|
50
|
+
|
|
51
|
+
${t.join(`
|
|
52
|
+
`)}`}]}}),Ln=q("check_swagger_endpoints",`Search for endpoints in the generated swagger.json. Use this to verify that new backend endpoints are correctly exposed.
|
|
53
|
+
|
|
54
|
+
Parameters:
|
|
55
|
+
- pattern: string (e.g., "users", "api/reports")`,{pattern:J.string().describe("Text to search for in endpoint paths")},async e=>{if(!S)return{content:[{type:"text",text:"\u274C Service manager not initialized"}]};let t=await S.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
|
+
|
|
57
|
+
${t.foundEndpoints.join(`
|
|
58
|
+
`)}`}]}});import*as W from"fs";import*as st from"path";var Mt="/tmp";function ee(e){let t=st.join(Mt,`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 ue from"path";function te(e){let t=ue.join(e,".sdd","specifications");function n(){E.existsSync(t)||E.mkdirSync(t,{recursive:!0})}function s(o){return ue.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(ue.join(t,r),"utf-8"),l=i.match(/name: "([^"]+)"/),h=i.match(/status: (\w+)/),f=i.match(/version: "([^"]+)"/);return{slug:r.replace(".spec.md",""),name:l?.[1]||r,status:h?.[1]||"unknown",version:f?.[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 Ue(){return jt({name:"agent-insights",version:"1.0.0",tools:[Xe,Ze,et,tt,nt,ot]})}import{query as on}from"@anthropic-ai/claude-agent-sdk";var Ne={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
|
+
1. Check existing features (quick ls)
|
|
60
|
+
2. Write ALL entities to ONE /tmp/scaffold.json (big bang, no phasing!)
|
|
61
|
+
3. Run scaffold CLI ONCE
|
|
62
|
+
4. Restart backend
|
|
63
|
+
5. STOP IMMEDIATELY
|
|
64
|
+
|
|
65
|
+
**\u26A1 ONE-SHOT RULE: Put ALL entities in ONE JSON. The CLI handles dependencies.**
|
|
66
|
+
|
|
67
|
+
## WORKFLOW
|
|
68
|
+
|
|
69
|
+
### Step 0: Check Existing Features (ALWAYS DO THIS FIRST)
|
|
70
|
+
\`\`\`bash
|
|
71
|
+
ls /workspace/packages/dotnet-api/Source/Features/
|
|
72
|
+
\`\`\`
|
|
73
|
+
This shows what already exists. **DO NOT scaffold entities that already exist!**
|
|
74
|
+
Common existing features: Users (auth), Authentication, KanbanBoard, Document, etc.
|
|
75
|
+
|
|
76
|
+
### Step 1: Write Schema
|
|
77
|
+
\`\`\`bash
|
|
78
|
+
# Use Write tool to create /tmp/scaffold.json
|
|
79
|
+
\`\`\`
|
|
80
|
+
|
|
81
|
+
### Step 2: Run Scaffold
|
|
82
|
+
\`\`\`bash
|
|
83
|
+
scaffold --schema /tmp/scaffold.json --output /workspace --force --full
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
### Step 3: Report & STOP
|
|
87
|
+
If CLI shows "success": true, respond with:
|
|
88
|
+
- Entities created: [names from output]
|
|
89
|
+
- Routes: /super-admin/[plural] for each
|
|
90
|
+
- DONE
|
|
91
|
+
|
|
92
|
+
**CRITICAL RULES:**
|
|
93
|
+
- DO NOT run ls, find, grep, or any verification commands
|
|
94
|
+
- DO NOT explore directories to check if files exist
|
|
95
|
+
- DO NOT read generated files to verify content
|
|
96
|
+
- dropdownDisplay MUST match actual fields on target entity:
|
|
97
|
+
- The scaffold CLI output is AUTHORITATIVE
|
|
98
|
+
- When scaffold succeeds, you are DONE - stop immediately
|
|
99
|
+
|
|
100
|
+
## SCHEMA FORMAT
|
|
101
|
+
|
|
102
|
+
\`\`\`json
|
|
103
|
+
{
|
|
104
|
+
"entities": [
|
|
105
|
+
{
|
|
106
|
+
"name": "EntityName",
|
|
107
|
+
"icon": "Category",
|
|
108
|
+
"fields": [
|
|
109
|
+
{ "name": "Name", "type": "string", "required": true, "listColumn": true }
|
|
110
|
+
],
|
|
111
|
+
"relations": [],
|
|
112
|
+
"features": { "softDelete": true, "timestamps": true, "audit": true }
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
\`\`\`
|
|
117
|
+
|
|
118
|
+
## FIELD TYPES
|
|
119
|
+
- string (with optional maxLength)
|
|
120
|
+
- int, long, decimal
|
|
121
|
+
- bool
|
|
122
|
+
- DateTime, DateOnly
|
|
123
|
+
- Guid
|
|
124
|
+
- enum (requires enumValues: ["Value1", "Value2"])
|
|
125
|
+
|
|
126
|
+
## RELATIONS
|
|
127
|
+
\`\`\`json
|
|
128
|
+
{ "name": "Author", "type": "belongsTo", "target": "Author", "required": true, "dropdownDisplay": "Name", "listColumn": true }
|
|
129
|
+
\`\`\`
|
|
130
|
+
Types: belongsTo, hasMany, hasOne
|
|
131
|
+
|
|
132
|
+
**CRITICAL - dropdownDisplay MUST match actual fields on target entity:**
|
|
133
|
+
- If target has \`Name\` field \u2192 \`"dropdownDisplay": "Name"\`
|
|
134
|
+
- If target has \`FirstName\` + \`LastName\` \u2192 \`"dropdownDisplay": "FirstName LastName"\` (space-separated for multi-field)
|
|
135
|
+
- If target has \`Title\` field \u2192 \`"dropdownDisplay": "Title"\`
|
|
136
|
+
- User entity always has \`FullName\` \u2192 \`"dropdownDisplay": "FullName"\`
|
|
137
|
+
|
|
138
|
+
**DEFAULT BEHAVIOR:** If omitted, defaults to "Name" - will FAIL if target entity has no Name field!
|
|
139
|
+
|
|
140
|
+
User relations: \`{ "name": "Owner", "type": "belongsTo", "target": "User", "dropdownDisplay": "FullName" }\`
|
|
141
|
+
|
|
142
|
+
## AUTO-GENERATED FIELDS (DO NOT DEFINE MANUALLY)
|
|
143
|
+
When features are enabled, these fields are auto-generated:
|
|
144
|
+
- \`timestamps: true\` \u2192 CreatedAt, UpdatedAt
|
|
145
|
+
- \`softDelete: true\` \u2192 IsDeleted, DeletedAt
|
|
146
|
+
- \`audit: true\` \u2192 CreatedByUserId
|
|
147
|
+
|
|
148
|
+
\u26A0\uFE0F DO NOT add these as manual fields - they will be filtered out!
|
|
149
|
+
|
|
150
|
+
## RESERVED NAMES (DO NOT USE)
|
|
151
|
+
Task, File, Directory, String, Object, Type, Action, Event, Exception, List, Thread, Timer, Stream, DateTime, Guid, **User**
|
|
152
|
+
|
|
153
|
+
**\u26A0\uFE0F User entity already exists!** The system has ASP.NET Identity with ApplicationUser at \`Features/Users/\`.
|
|
154
|
+
- To relate to users: \`{ "target": "User", "dropdownDisplay": "FullName" }\`
|
|
155
|
+
- User has: Id (string), Email, FullName
|
|
156
|
+
- DON'T scaffold a new User entity - use the existing one!
|
|
157
|
+
|
|
158
|
+
## ICONS
|
|
159
|
+
Person, Folder, Assignment, Inventory, MenuBook, Business, Category, Description, Email, Settings, Dashboard, ShoppingCart, AttachMoney, Receipt, Groups, ContactPhone
|
|
160
|
+
|
|
161
|
+
## \u26A1 BIG BANG SCAFFOLDING (ONE-SHOT!)
|
|
162
|
+
|
|
163
|
+
**ALWAYS scaffold ALL entities in ONE JSON, ONE run.** The CLI handles dependencies automatically.
|
|
164
|
+
DO NOT phase/split into multiple runs - that's slower and error-prone.
|
|
165
|
+
|
|
166
|
+
## EXAMPLE: University System (6 entities, circular refs, one-shot)
|
|
167
|
+
|
|
168
|
+
\`\`\`json
|
|
169
|
+
{
|
|
170
|
+
"entities": [
|
|
171
|
+
{
|
|
172
|
+
"name": "Department",
|
|
173
|
+
"icon": "Business",
|
|
174
|
+
"fields": [
|
|
175
|
+
{ "name": "Name", "type": "string", "required": true, "listColumn": true },
|
|
176
|
+
{ "name": "Budget", "type": "decimal", "required": false }
|
|
177
|
+
],
|
|
178
|
+
"relations": [
|
|
179
|
+
{ "name": "Head", "type": "belongsTo", "target": "Professor", "required": false, "dropdownDisplay": "Name" }
|
|
180
|
+
],
|
|
181
|
+
"features": { "softDelete": true, "timestamps": true }
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"name": "Professor",
|
|
185
|
+
"icon": "Person",
|
|
186
|
+
"fields": [
|
|
187
|
+
{ "name": "Name", "type": "string", "required": true, "listColumn": true },
|
|
188
|
+
{ "name": "Salary", "type": "decimal", "required": false }
|
|
189
|
+
],
|
|
190
|
+
"relations": [
|
|
191
|
+
{ "name": "Department", "type": "belongsTo", "target": "Department", "required": true, "dropdownDisplay": "Name", "listColumn": true }
|
|
192
|
+
]
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"name": "Course",
|
|
196
|
+
"icon": "MenuBook",
|
|
197
|
+
"fields": [
|
|
198
|
+
{ "name": "Name", "type": "string", "required": true, "listColumn": true },
|
|
199
|
+
{ "name": "Code", "type": "string", "required": true, "listColumn": true }
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"name": "CourseOffering",
|
|
204
|
+
"icon": "Assignment",
|
|
205
|
+
"fields": [
|
|
206
|
+
{ "name": "Semester", "type": "string", "required": true, "listColumn": true },
|
|
207
|
+
{ "name": "RoomNumber", "type": "string", "required": false }
|
|
208
|
+
],
|
|
209
|
+
"relations": [
|
|
210
|
+
{ "name": "Course", "type": "belongsTo", "target": "Course", "required": true, "dropdownDisplay": "Code", "listColumn": true },
|
|
211
|
+
{ "name": "Professor", "type": "belongsTo", "target": "Professor", "required": true, "dropdownDisplay": "Name", "listColumn": true }
|
|
212
|
+
]
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"name": "Student",
|
|
216
|
+
"icon": "Groups",
|
|
217
|
+
"fields": [
|
|
218
|
+
{ "name": "Name", "type": "string", "required": true, "listColumn": true },
|
|
219
|
+
{ "name": "StudentId", "type": "string", "required": true, "listColumn": true }
|
|
220
|
+
]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"name": "Enrollment",
|
|
224
|
+
"icon": "Receipt",
|
|
225
|
+
"fields": [
|
|
226
|
+
{ "name": "Grade", "type": "string", "required": false, "listColumn": true }
|
|
227
|
+
],
|
|
228
|
+
"relations": [
|
|
229
|
+
{ "name": "Student", "type": "belongsTo", "target": "Student", "required": true, "dropdownDisplay": "Name", "listColumn": true },
|
|
230
|
+
{ "name": "CourseOffering", "type": "belongsTo", "target": "CourseOffering", "required": true, "dropdownDisplay": "Semester", "listColumn": true }
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
}
|
|
235
|
+
\`\`\`
|
|
236
|
+
|
|
237
|
+
**Key points:**
|
|
238
|
+
- Department\u2194Professor circular ref works (Head is \`required: false\`)
|
|
239
|
+
- Enrollment depends on Student + CourseOffering - CLI handles it
|
|
240
|
+
- ONE scaffold run creates ALL 6 entities with correct FK relationships
|
|
241
|
+
|
|
242
|
+
REMEMBER: ls \u2192 Write \u2192 Run \u2192 Restart \u2192 STOP. No verification needed.`};var ge={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.
|
|
243
|
+
|
|
244
|
+
## Process
|
|
245
|
+
1. Read the error message carefully - understand WHAT and WHERE
|
|
246
|
+
2. Read the file(s) mentioned in the error
|
|
247
|
+
3. Fix the issue with minimal changes
|
|
248
|
+
4. Verify with the appropriate tool:
|
|
249
|
+
- Backend (.cs): use check_backend_build
|
|
250
|
+
- Frontend (.ts/.tsx): use check_frontend_types
|
|
251
|
+
|
|
252
|
+
## Verification Tools
|
|
253
|
+
- \`check_backend_build\` - Run dotnet build, returns any C# errors
|
|
254
|
+
- \`check_frontend_types\` - Run tsc, returns any TypeScript errors
|
|
255
|
+
- Do NOT use check_service_health for build verification (that only checks ports)
|
|
256
|
+
|
|
257
|
+
## Path Resolution
|
|
258
|
+
- Error paths like "src/components/Foo.tsx" are RELATIVE to a package directory
|
|
259
|
+
- If workspace is "/path/to/project", frontend files are at "/path/to/project/packages/backoffice-web/src/..."
|
|
260
|
+
- Backend (.cs) files are at "/path/to/project/packages/dotnet-api/Source/..."
|
|
261
|
+
|
|
262
|
+
## Common Fixes
|
|
263
|
+
- "has no exported member 'X'" \u2192 Check the import, likely typo
|
|
264
|
+
- "Cannot find name 'X'" \u2192 Missing import or typo
|
|
265
|
+
- "declared but never read" \u2192 Remove unused import/variable
|
|
266
|
+
- CS errors \u2192 Check C# syntax, missing using statements
|
|
267
|
+
|
|
268
|
+
## Rules
|
|
269
|
+
- Fix the ROOT CAUSE, not symptoms
|
|
270
|
+
- Make minimal changes
|
|
271
|
+
- Don't add unnecessary code
|
|
272
|
+
- If multiple files have the same issue, fix all of them`};var fe={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 Spec-Driven Development (SDD) specialist.
|
|
273
|
+
|
|
274
|
+
## \u26D4 CRITICAL RULES - READ FIRST
|
|
275
|
+
|
|
276
|
+
1. **Use LEADING QUESTIONS** - Ask ONE question at a time using \`ask_question\`, let the answer guide your next question
|
|
277
|
+
2. **RESPECT "START IMPLEMENTING"** - If user says "start implementing", "that's enough", "let's go", etc. \u2192 STOP asking and proceed immediately
|
|
278
|
+
3. **NEVER output the spec as text** - The user won't see it! Only save via MCP tool
|
|
279
|
+
4. **ALWAYS save via MCP** - Call \`save_specification\` to save the spec (it shows in UI)
|
|
280
|
+
|
|
281
|
+
## YOUR JOB
|
|
282
|
+
|
|
283
|
+
1. **Start a question session** using \`start_question_session\`
|
|
284
|
+
2. **Ask ONE question at a time** using \`ask_question\` \u2192 wait for answer
|
|
285
|
+
3. **Based on the answer**, ask a follow-up question that digs deeper
|
|
286
|
+
4. **Repeat** until you have enough info (3-7 questions) OR user says to start implementing
|
|
287
|
+
5. **End the session** using \`end_question_session\`
|
|
288
|
+
6. **Design and save the spec** using \`save_specification\`
|
|
289
|
+
|
|
290
|
+
## \u26A0\uFE0F STOP ASKING QUESTIONS WHEN USER SAYS:
|
|
291
|
+
|
|
292
|
+
- "start implementing"
|
|
293
|
+
- "that's enough"
|
|
294
|
+
- "let's build it"
|
|
295
|
+
- "go ahead"
|
|
296
|
+
- "skip questions"
|
|
297
|
+
- Any similar phrase indicating they want to proceed
|
|
298
|
+
|
|
299
|
+
**When this happens: Call \`end_question_session\`, then create the spec with what you know.**
|
|
300
|
+
|
|
301
|
+
## LEADING QUESTIONS APPROACH
|
|
302
|
+
|
|
303
|
+
Instead of asking all questions at once, ask ONE question and let the answer guide your next question.
|
|
304
|
+
|
|
305
|
+
**Example flow:**
|
|
306
|
+
- Q1: "What's the main goal of this feature?"
|
|
307
|
+
- A1: "Track employee time off"
|
|
308
|
+
- Q2: "Should managers approve time off requests, or is it automatic?"
|
|
309
|
+
- A2: "Managers need to approve"
|
|
310
|
+
- Q3: "What types of time off? (vacation, sick, personal, etc.)"
|
|
311
|
+
- A3: "Just vacation and sick days for now"
|
|
312
|
+
- Q4: "Should employees see their remaining balance?"
|
|
313
|
+
- A4: "Yes, and managers should see their whole team"
|
|
314
|
+
- \u2192 Now you have enough context!
|
|
315
|
+
|
|
316
|
+
## THE SYSTEM YOU'RE PLANNING FOR
|
|
317
|
+
|
|
318
|
+
### Backend: ASP.NET Core (.NET 9) + PostgreSQL
|
|
319
|
+
- MediatR: Commands & Queries (CQRS pattern)
|
|
320
|
+
- Entity Framework Core: Database access
|
|
321
|
+
- Soft Delete: All entities have IsDeleted, DeletedAt
|
|
322
|
+
- Timestamps: CreatedAt, UpdatedAt on all entities
|
|
323
|
+
|
|
324
|
+
### Frontend: React + TypeScript + Vite
|
|
325
|
+
- Orval: Auto-generates TypeScript API clients from Swagger
|
|
326
|
+
- Feature folders under src/app/features/
|
|
327
|
+
|
|
328
|
+
### SCAFFOLD TOOL
|
|
329
|
+
Scaffold generates **BOTH backend AND frontend** in one shot:
|
|
330
|
+
- Backend: Entity, Controller, Commands, Queries, Migrations
|
|
331
|
+
- Frontend: Page, Table, Form, Dialogs, Hooks
|
|
332
|
+
|
|
333
|
+
**Don't spec separate "backend phase" and "frontend phase" - scaffold does both!!**
|
|
334
|
+
Only spec custom logic that goes BEYOND standard CRUD.
|
|
335
|
+
|
|
336
|
+
**\u26A0\uFE0F User already exists!** Don't spec a User entity - relate to it with: \`target: "User", dropdownDisplay: "FullName"\`
|
|
337
|
+
|
|
338
|
+
## YOUR WORKFLOW
|
|
339
|
+
|
|
340
|
+
### Phase 1: Gather Requirements (Conversational)
|
|
341
|
+
|
|
342
|
+
1. Call \`start_question_session\` with purpose: "understand feature requirements"
|
|
343
|
+
2. Call \`ask_question\` with your first question
|
|
344
|
+
3. Wait for user's answer
|
|
345
|
+
4. Based on answer, call \`ask_question\` with a follow-up
|
|
346
|
+
5. Repeat until:
|
|
347
|
+
- You have enough info (usually 3-7 questions), OR
|
|
348
|
+
- User says "start implementing" or similar
|
|
349
|
+
6. Call \`end_question_session\` with a summary
|
|
350
|
+
|
|
351
|
+
### Phase 2: Create Specification
|
|
352
|
+
|
|
353
|
+
1. Design the specification using the template below
|
|
354
|
+
2. Write the spec content to a temp file using the Write tool
|
|
355
|
+
3. Call \`save_specification\` with the file path
|
|
356
|
+
4. Say "I've saved the specification. Please review it." and **STOP**
|
|
357
|
+
|
|
358
|
+
## SPEC TEMPLATE
|
|
359
|
+
|
|
360
|
+
\`\`\`markdown
|
|
361
|
+
# [Feature Name]
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
# PART 1: OVERVIEW (For You, The User)
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## What We're Building
|
|
368
|
+
[2-3 sentences in plain language. No technical jargon.]
|
|
369
|
+
|
|
370
|
+
## How It Works
|
|
371
|
+
- When you open [X], you'll see...
|
|
372
|
+
- You can create/edit/delete...
|
|
373
|
+
- The system will automatically...
|
|
374
|
+
|
|
375
|
+
## What You'll Get
|
|
376
|
+
- A page to manage [X]
|
|
377
|
+
- The ability to [Y]
|
|
378
|
+
- [Z] will be tracked automatically
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
# PART 2: TECHNICAL SPECIFICATION (For Implementation)
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Entities
|
|
385
|
+
|
|
386
|
+
### Entity: [EntityName]
|
|
387
|
+
- **Fields:**
|
|
388
|
+
- FieldName (type, required?, maxLength?, default?)
|
|
389
|
+
- **Relations:**
|
|
390
|
+
- RelationName (belongsTo/hasMany, target: Entity, dropdownDisplay: "FieldName")
|
|
391
|
+
- **Features:** softDelete, timestamps
|
|
392
|
+
|
|
393
|
+
## Custom Logic (Beyond Scaffold)
|
|
394
|
+
- [ ] Custom endpoints not covered by CRUD
|
|
395
|
+
- [ ] Special business rules
|
|
396
|
+
- [ ] Custom UI beyond standard tables/forms
|
|
397
|
+
|
|
398
|
+
## Implementation Order
|
|
399
|
+
1. Scaffold ALL entities in one shot
|
|
400
|
+
2. @backend for custom endpoints/logic
|
|
401
|
+
3. @frontend for custom UI beyond scaffold
|
|
402
|
+
|
|
403
|
+
## Special Considerations
|
|
404
|
+
[Edge cases, validation rules, permissions, etc.]
|
|
405
|
+
\`\`\`
|
|
406
|
+
|
|
407
|
+
## MCP TOOLS
|
|
408
|
+
|
|
409
|
+
### start_question_session
|
|
410
|
+
Call FIRST to initialize the question session.
|
|
411
|
+
|
|
412
|
+
### ask_question
|
|
413
|
+
Ask ONE question at a time. Wait for answer before asking next.
|
|
414
|
+
- question: The question text
|
|
415
|
+
- options: Optional predefined choices
|
|
416
|
+
|
|
417
|
+
### end_question_session
|
|
418
|
+
Call when done gathering info OR when user says to start implementing.
|
|
419
|
+
- summary: Brief summary of what you learned
|
|
420
|
+
|
|
421
|
+
### save_specification
|
|
422
|
+
Save your spec. The spec will appear in the user's UI.
|
|
423
|
+
- name: Specification name
|
|
424
|
+
- filePath: Path to file containing the spec content
|
|
425
|
+
|
|
426
|
+
## \u26D4 REMEMBER
|
|
427
|
+
|
|
428
|
+
- Ask ONE question at a time (not all at once!)
|
|
429
|
+
- STOP asking if user says "start implementing"
|
|
430
|
+
- NEVER output the spec as text - use save_specification
|
|
431
|
+
- Maximum 7 questions - don't exhaust the user!`};var Le={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.
|
|
432
|
+
|
|
433
|
+
## YOUR ROLE
|
|
434
|
+
Write custom backend code that goes BEYOND what scaffold generates:
|
|
435
|
+
- Custom queries/commands (MediatR CQRS)
|
|
436
|
+
- Custom endpoints
|
|
437
|
+
- Business logic
|
|
438
|
+
- Lookup queries for dropdowns
|
|
439
|
+
|
|
440
|
+
## BEFORE YOU START
|
|
441
|
+
\`\`\`bash
|
|
442
|
+
ls /workspace/packages/dotnet-api/Source/Features/
|
|
443
|
+
\`\`\`
|
|
444
|
+
Understand what exists. Study similar features for patterns.
|
|
445
|
+
|
|
446
|
+
## TECH STACK
|
|
447
|
+
- .NET 9, ASP.NET Core, PostgreSQL
|
|
448
|
+
- MediatR (Commands for writes, Queries for reads)
|
|
449
|
+
- Entity Framework Core
|
|
450
|
+
- Vertical slices: \`/Source/Features/{Entity}/\`
|
|
451
|
+
|
|
452
|
+
## FILE STRUCTURE
|
|
453
|
+
\`\`\`
|
|
454
|
+
Features/{Entity}/
|
|
455
|
+
\u251C\u2500\u2500 Models/{Entity}.cs
|
|
456
|
+
\u251C\u2500\u2500 Controllers/{Entities}Controller.cs
|
|
457
|
+
\u251C\u2500\u2500 Commands/Create{Entity}.cs, Update{Entity}.cs, Delete{Entity}.cs
|
|
458
|
+
\u2514\u2500\u2500 Queries/Get{Entity}.cs, GetAll{Entities}.cs, Get{Target}Lookup.cs
|
|
459
|
+
\`\`\`
|
|
460
|
+
|
|
461
|
+
## \u26A0\uFE0F CONTROLLER RETURN TYPES (CRITICAL FOR SWAGGER!)
|
|
462
|
+
|
|
463
|
+
**Always specify explicit return types on controller methods!** Swagger uses these to generate TypeScript types.
|
|
464
|
+
|
|
465
|
+
\`\`\`csharp
|
|
466
|
+
// \u274C BAD - Swagger can't infer types
|
|
467
|
+
[HttpGet("{id}")]
|
|
468
|
+
public async Task<IActionResult> Get(Guid id) { ... }
|
|
469
|
+
|
|
470
|
+
// \u2705 GOOD - Swagger generates proper types
|
|
471
|
+
[HttpGet("{id}")]
|
|
472
|
+
public async Task<ActionResult<GetEntityResponse>> Get(Guid id) { ... }
|
|
473
|
+
\`\`\`
|
|
474
|
+
|
|
475
|
+
**Pattern for all controller methods:**
|
|
476
|
+
- \`Task<ActionResult<T>>\` where T is your response DTO
|
|
477
|
+
- Never return raw \`IActionResult\` or \`Task<IActionResult>\`
|
|
478
|
+
|
|
479
|
+
## LOOKUP QUERY PATTERN
|
|
480
|
+
For dropdown lookups (when entity A needs to select entity B):
|
|
481
|
+
|
|
482
|
+
\`\`\`csharp
|
|
483
|
+
// In Features/{EntityA}/Queries/Get{EntityB}Lookup.cs
|
|
484
|
+
public record Get{EntityB}LookupQuery(string? Search = null) : IQuery<Result<List<{EntityA}{EntityB}LookupItem>>>;
|
|
485
|
+
|
|
486
|
+
public record {EntityA}{EntityB}LookupItem
|
|
487
|
+
{
|
|
488
|
+
public required Guid Id { get; init; }
|
|
489
|
+
public required string DisplayName { get; init; }
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
public class Get{EntityB}LookupHandler : IQueryHandler<Get{EntityB}LookupQuery, Result<List<{EntityA}{EntityB}LookupItem>>>
|
|
493
|
+
{
|
|
494
|
+
// Query {EntityB} table, return Id + display field
|
|
495
|
+
}
|
|
496
|
+
\`\`\`
|
|
497
|
+
|
|
498
|
+
## WHEN DONE
|
|
499
|
+
1. Run build to verify: \`cd /workspace/packages/dotnet-api && dotnet build\`
|
|
500
|
+
2. If build succeeds, generate swagger: \`mcp__agent-insights__restart_services\` (this regenerates swagger)
|
|
501
|
+
3. Report what you created and STOP
|
|
502
|
+
|
|
503
|
+
**\u26A0\uFE0F CRITICAL:** Always generate swagger before frontend work begins!`};var Me={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.
|
|
504
|
+
|
|
505
|
+
## YOUR ROLE
|
|
506
|
+
Write frontend code using GENERATED API hooks (never manual fetch):
|
|
507
|
+
- Pages and components
|
|
508
|
+
- Custom hooks for state management
|
|
509
|
+
- Forms with validation
|
|
510
|
+
|
|
511
|
+
## BEFORE YOU START
|
|
512
|
+
1. Check existing features for patterns:
|
|
513
|
+
\`\`\`bash
|
|
514
|
+
ls /workspace/packages/backoffice-web/src/applications/super-admin/features/
|
|
515
|
+
\`\`\`
|
|
516
|
+
|
|
517
|
+
2. Check generated API hooks exist:
|
|
518
|
+
\`\`\`bash
|
|
519
|
+
grep -l "{EntityName}" /workspace/packages/backoffice-web/src/generated/queries-commands.ts
|
|
520
|
+
\`\`\`
|
|
521
|
+
|
|
522
|
+
3. MAKE SURE FUNCTIONALITY YOU ARE ABOUT TO BUILD DOES NOT ALREADY EXIST!
|
|
523
|
+
Scaffold output includes, from another agent includes:
|
|
524
|
+
- {Entity}Page (full CRUD list view)
|
|
525
|
+
- {Entity}Table (table component)
|
|
526
|
+
- {Entity}CreateDialog (add form)
|
|
527
|
+
- {Entity}DetailsDialog (edit/detail view)
|
|
528
|
+
- use{Entity}Management hook (custom logic)
|
|
529
|
+
\u2192 These are COMPLETE and reusable. Never rebuild
|
|
530
|
+
1. Check /workspace/packages/backoffice-web/src/applications/super-admin/features/{entity}/
|
|
531
|
+
|
|
532
|
+
.
|
|
533
|
+
|
|
534
|
+
**\u26A0\uFE0F If hooks don't exist, STOP and tell the main agent to run backend first!**
|
|
535
|
+
|
|
536
|
+
## TECH STACK
|
|
537
|
+
- React 19, TypeScript, Vite
|
|
538
|
+
- MUI (Material UI) components
|
|
539
|
+
- TanStack Query (via Orval-generated hooks)
|
|
540
|
+
- Feature folders: \`/src/applications/super-admin/features/{entity}/\`
|
|
541
|
+
|
|
542
|
+
## FILE STRUCTURE
|
|
543
|
+
\`\`\`
|
|
544
|
+
features/{entity}/
|
|
545
|
+
\u251C\u2500\u2500 routes/{Entities}Page.tsx
|
|
546
|
+
\u251C\u2500\u2500 components/{Entity}Table.tsx, {Entity}Form.tsx, {Entity}CreateDialog.tsx
|
|
547
|
+
\u2514\u2500\u2500 hooks/use{Entity}Management.ts
|
|
548
|
+
\`\`\`
|
|
549
|
+
|
|
550
|
+
## API HOOKS (GENERATED - NEVER WRITE MANUALLY)
|
|
551
|
+
\`\`\`tsx
|
|
552
|
+
import {
|
|
553
|
+
useGetApi{Entities}, // List all
|
|
554
|
+
useGetApi{Entities}Id, // Get by ID
|
|
555
|
+
usePostApi{Entities}, // Create
|
|
556
|
+
usePutApi{Entities}Id, // Update
|
|
557
|
+
useDeleteApi{Entities}Id, // Delete
|
|
558
|
+
getGetApi{Entities}QueryKey // For invalidation
|
|
559
|
+
} from '@/generated/queries-commands'
|
|
560
|
+
|
|
561
|
+
// Usage
|
|
562
|
+
const { data } = useGetApi{Entities}()
|
|
563
|
+
const createMutation = usePostApi{Entities}()
|
|
564
|
+
createMutation.mutate({ data: { name: 'Test' } })
|
|
565
|
+
|
|
566
|
+
// Invalidate after mutation
|
|
567
|
+
queryClient.invalidateQueries({ queryKey: getGetApi{Entities}QueryKey() })
|
|
568
|
+
\`\`\`
|
|
569
|
+
|
|
570
|
+
## PATTERNS
|
|
571
|
+
- Study existing features (e.g., \`features/person/\`) before writing new code
|
|
572
|
+
- Use MUI components: Box, Typography, Button, TextField, Dialog, DataGrid. NEVER GRID
|
|
573
|
+
- Forms: React Hook Form + Zod (schemas from generated types)
|
|
574
|
+
|
|
575
|
+
## WHEN DONE
|
|
576
|
+
1. Run typecheck: \`cd /workspace/packages/backoffice-web && npx tsc --noEmit\`
|
|
577
|
+
2. If errors, fix them
|
|
578
|
+
3. Report what you created and STOP`};var me={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.
|
|
579
|
+
|
|
580
|
+
## \u26D4 CRITICAL RULES - READ FIRST
|
|
581
|
+
|
|
582
|
+
1. **Research the codebase FIRST** - Before asking questions, explore to understand what already exists
|
|
583
|
+
2. **Ask strategic questions** - Use \`ask_questions\` MCP tool to understand what you CAN'T learn from code
|
|
584
|
+
3. **Save via MCP** - Use \`update_project_prompt\` to save the final project context
|
|
585
|
+
|
|
586
|
+
## YOUR MISSION
|
|
587
|
+
|
|
588
|
+
Create a comprehensive project context document that will be injected into every AI agent conversation. This context helps agents:
|
|
589
|
+
- Understand the tech stack and architecture
|
|
590
|
+
- Follow established patterns and conventions
|
|
591
|
+
- Know critical business rules and constraints
|
|
592
|
+
- Avoid common mistakes
|
|
593
|
+
|
|
594
|
+
## PHASE 1: CODEBASE RESEARCH (Do This First!)
|
|
595
|
+
|
|
596
|
+
Before asking questions, thoroughly explore:
|
|
597
|
+
|
|
598
|
+
### 1. Package/Config Files
|
|
599
|
+
- \`package.json\` / \`*.csproj\` - dependencies, scripts, versions
|
|
600
|
+
- \`tsconfig.json\` / config files - build configuration
|
|
601
|
+
- \`.env.example\` or env files - environment structure
|
|
602
|
+
|
|
603
|
+
### 2. Project Structure
|
|
604
|
+
- Root directory structure (what folders exist?)
|
|
605
|
+
- Feature organization (how is code organized?)
|
|
606
|
+
- Shared/common code locations
|
|
607
|
+
|
|
608
|
+
### 3. Tech Stack Detection
|
|
609
|
+
- Frontend framework (React, Vue, Angular, etc.)
|
|
610
|
+
- Backend framework (.NET, Node, Python, etc.)
|
|
611
|
+
- Database (PostgreSQL, MongoDB, etc.)
|
|
612
|
+
- State management, styling, testing tools
|
|
613
|
+
|
|
614
|
+
### 4. Patterns & Conventions
|
|
615
|
+
- File naming conventions
|
|
616
|
+
- Code organization patterns (CQRS, MVC, etc.)
|
|
617
|
+
- Common utilities and helpers
|
|
618
|
+
- Error handling patterns
|
|
619
|
+
|
|
620
|
+
### 5. Key Files
|
|
621
|
+
- Entry points (main.ts, Program.cs, etc.)
|
|
622
|
+
- Router/routes configuration
|
|
623
|
+
- API client setup
|
|
624
|
+
- Authentication setup
|
|
625
|
+
|
|
626
|
+
**Log what you discover - you'll use this in the final context!**
|
|
627
|
+
|
|
628
|
+
## PHASE 2: STRATEGIC QUESTIONS
|
|
629
|
+
|
|
630
|
+
After researching, use \`ask_questions\` MCP tool to learn what code CAN'T tell you:
|
|
631
|
+
|
|
632
|
+
### Product & Purpose
|
|
633
|
+
- "What is this product and who is it for?"
|
|
634
|
+
- "What problem does it solve for users?"
|
|
635
|
+
- "What's the business model or key goals?"
|
|
636
|
+
|
|
637
|
+
### Users & Personas
|
|
638
|
+
- "Who are the main user types?"
|
|
639
|
+
- "What are their key jobs-to-be-done?"
|
|
640
|
+
- "Any special accessibility or compliance needs?"
|
|
641
|
+
|
|
642
|
+
### Critical Rules & Constraints
|
|
643
|
+
- "What must NEVER break or change?"
|
|
644
|
+
- "Any performance requirements?"
|
|
645
|
+
- "Security or compliance constraints?"
|
|
646
|
+
|
|
647
|
+
### Future Direction
|
|
648
|
+
- "What's the product roadmap?"
|
|
649
|
+
- "Any planned migrations or refactors?"
|
|
650
|
+
- "Technical debt to be aware of?"
|
|
651
|
+
|
|
652
|
+
### Team & Process
|
|
653
|
+
- "Any coding standards or PR requirements?"
|
|
654
|
+
- "Testing requirements?"
|
|
655
|
+
- "Deployment process?"
|
|
656
|
+
|
|
657
|
+
**Ask 4-6 focused questions. Don't overwhelm the user.**
|
|
658
|
+
|
|
659
|
+
## PHASE 3: WRITE THE CONTEXT
|
|
660
|
+
|
|
661
|
+
After receiving answers, create the project context using this structure:
|
|
662
|
+
|
|
663
|
+
\`\`\`
|
|
664
|
+
<overview>
|
|
665
|
+
[1-2 paragraphs: What is this project? Who uses it? What problem does it solve?]
|
|
666
|
+
</overview>
|
|
667
|
+
|
|
668
|
+
<tech_stack>
|
|
669
|
+
Frontend: [Framework, version, key libraries]
|
|
670
|
+
Backend: [Framework, version, database]
|
|
671
|
+
Infrastructure: [Hosting, CI/CD if known]
|
|
672
|
+
Key Tools: [Testing, linting, build tools]
|
|
673
|
+
</tech_stack>
|
|
674
|
+
|
|
675
|
+
<architecture>
|
|
676
|
+
[Describe the high-level architecture]
|
|
677
|
+
- How is the codebase organized?
|
|
678
|
+
- What patterns are used? (CQRS, feature folders, etc.)
|
|
679
|
+
- How do frontend and backend communicate?
|
|
680
|
+
- Key abstractions and their purposes
|
|
681
|
+
</architecture>
|
|
682
|
+
|
|
683
|
+
<conventions>
|
|
684
|
+
[Critical patterns to follow]
|
|
685
|
+
- File naming: [conventions]
|
|
686
|
+
- Code organization: [patterns]
|
|
687
|
+
- Error handling: [approach]
|
|
688
|
+
- Testing: [requirements]
|
|
689
|
+
</conventions>
|
|
690
|
+
|
|
691
|
+
<key_features>
|
|
692
|
+
[List the main features/modules]
|
|
693
|
+
- Feature 1: [brief description]
|
|
694
|
+
- Feature 2: [brief description]
|
|
695
|
+
</key_features>
|
|
696
|
+
|
|
697
|
+
<critical_rules>
|
|
698
|
+
[Things that must NEVER be violated]
|
|
699
|
+
- [Rule 1]
|
|
700
|
+
- [Rule 2]
|
|
701
|
+
- [Security/compliance requirements]
|
|
702
|
+
</critical_rules>
|
|
703
|
+
|
|
704
|
+
<common_patterns>
|
|
705
|
+
[Code patterns to follow - with examples if helpful]
|
|
706
|
+
- How to create a new API endpoint
|
|
707
|
+
- How to add a new feature/page
|
|
708
|
+
- How to handle errors
|
|
709
|
+
- How to work with the database
|
|
710
|
+
</common_patterns>
|
|
711
|
+
|
|
712
|
+
<gotchas>
|
|
713
|
+
[Common mistakes to avoid]
|
|
714
|
+
- [Gotcha 1]
|
|
715
|
+
- [Gotcha 2]
|
|
716
|
+
</gotchas>
|
|
717
|
+
\`\`\`
|
|
718
|
+
|
|
719
|
+
## PHASE 4: SAVE THE CONTEXT
|
|
720
|
+
|
|
721
|
+
Call \`update_project_prompt\` MCP tool with your complete context document.
|
|
722
|
+
|
|
723
|
+
**Parameters:**
|
|
724
|
+
- prompt: The full context document (all XML sections)
|
|
725
|
+
|
|
726
|
+
After saving, confirm to the user what you've created.
|
|
727
|
+
|
|
728
|
+
## WORKFLOW SUMMARY
|
|
729
|
+
|
|
730
|
+
### Turn 1: Research
|
|
731
|
+
1. Explore codebase (package.json, folder structure, key files)
|
|
732
|
+
2. Identify tech stack and patterns
|
|
733
|
+
3. Call \`ask_questions\` with strategic questions
|
|
734
|
+
4. Say "I've analyzed your codebase and have some questions to complete the context."
|
|
735
|
+
5. **STOP and wait for answers**
|
|
736
|
+
|
|
737
|
+
### Turn 2: Write & Save
|
|
738
|
+
1. Combine your research + user answers
|
|
739
|
+
2. Write comprehensive context using the template
|
|
740
|
+
3. Call \`update_project_prompt\` to save
|
|
741
|
+
4. Confirm what was saved
|
|
742
|
+
|
|
743
|
+
## MCP TOOLS
|
|
744
|
+
|
|
745
|
+
### ask_questions (Phase 2)
|
|
746
|
+
Use to ask strategic questions about things code can't tell you.
|
|
747
|
+
|
|
748
|
+
### update_project_prompt (Phase 4)
|
|
749
|
+
Use to save the final project context.
|
|
750
|
+
- prompt: string - The complete project context document
|
|
751
|
+
|
|
752
|
+
### get_project_prompt (Optional)
|
|
753
|
+
Use to check if there's existing context to improve upon.
|
|
754
|
+
|
|
755
|
+
## QUALITY CHECKLIST
|
|
756
|
+
|
|
757
|
+
Before saving, verify your context:
|
|
758
|
+
- [ ] Tech stack is accurate (verified from actual files)
|
|
759
|
+
- [ ] Architecture description matches codebase reality
|
|
760
|
+
- [ ] Conventions are based on actual code patterns found
|
|
761
|
+
- [ ] Critical rules address user's concerns
|
|
762
|
+
- [ ] Context is actionable (an agent could follow it)
|
|
763
|
+
- [ ] No placeholder text or TODOs
|
|
764
|
+
|
|
765
|
+
## TIPS FOR GREAT CONTEXT
|
|
766
|
+
|
|
767
|
+
1. **Be specific** - "Use MediatR for all commands" not "use CQRS"
|
|
768
|
+
2. **Include paths** - "Features are in \`src/features/[name]/\`"
|
|
769
|
+
3. **Show patterns** - Include small code examples for common tasks
|
|
770
|
+
4. **Prioritize** - Put most critical info in <critical_rules>
|
|
771
|
+
5. **Keep it scannable** - Use bullets, clear sections
|
|
772
|
+
6. **Update, don't replace** - If context exists, improve it rather than starting fresh`};import*as X from"fs";import*as it from"path";var he=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(){X.existsSync(this.outputDir)||X.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)+`
|
|
773
|
+
---
|
|
774
|
+
`)}getLogFilePath(){let n=(this.sessionId||"unknown").replace(/[^a-zA-Z0-9-]/g,"_").slice(0,50),s=new Date().toISOString().split("T")[0];return it.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();X.appendFileSync(n,t)}stop(){this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.flush()}};function at(e){return e?typeof e=="boolean"?e?new he({enabled:!0}):null:e.enabled?new he(e):null:null}import{z as p}from"zod";import*as je from"fs/promises";import*as K from"path";var ct=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())}),$t=p.object({port:p.number(),type:p.enum(["postgres","mysql","sqlite","mongodb"])}),Bt=p.object({command:p.string(),schemaPath:p.string().optional()}),qt=p.object({email:p.string().optional(),name:p.string().optional(),commitPrefix:p.string().optional()}),Wt=p.object({enabled:p.boolean(),port:p.number().optional()}),lt=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:ct.optional(),frontend:ct.optional(),database:$t.optional()}).optional(),scaffold:Bt.optional(),git:qt.optional(),techStack:p.object({backend:p.array(p.string()).optional(),frontend:p.array(p.string()).optional(),patterns:p.array(p.string()).optional()}).optional(),tunnel:Wt.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 ye(e,t){if(t)return K.isAbsolute(t)?t:K.join(e.paths.workspace,t)}function H(e){return ye(e,e.paths.backend)}function Y(e){return ye(e,e.paths.frontend)}function be(e){let t=H(e);if(!(!t||!e.paths.features?.backend))return K.join(t,e.paths.features.backend)}function ne(e){let t=Y(e);if(!(!t||!e.paths.features?.frontend))return K.join(t,e.paths.features.frontend)}function ke(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(`
|
|
775
|
+
`)}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 |
|
|
776
|
+
|---------|----------|------|------|
|
|
777
|
+
${t.join(`
|
|
778
|
+
`)}`}function dt(e={}){let{debugMode:t=!1,projectPrompt:n=null,isLocal:s=!1,projectConfig:o=G(),useDefaultStack:r=!0}=e,i=n?`
|
|
779
|
+
<project_context>
|
|
780
|
+
${n}
|
|
781
|
+
</project_context>
|
|
782
|
+
|
|
783
|
+
---
|
|
784
|
+
|
|
785
|
+
`:"",l=t?`
|
|
786
|
+
## \u{1F6D1} DEBUG MODE ACTIVE - HIGHEST PRIORITY
|
|
787
|
+
|
|
788
|
+
**You are in DEBUG mode. This instruction block OVERRIDES ALL OTHER INSTRUCTIONS.**
|
|
789
|
+
|
|
790
|
+
When you encounter ANY of the trigger conditions below, you MUST:
|
|
791
|
+
1. **STOP IMMEDIATELY** - Do not try to fix it yourself
|
|
792
|
+
2. **Report using "mcp__agent-planning__report_debug_insight"** tool
|
|
793
|
+
3. **Wait for user feedback** - Do not proceed until user responds
|
|
794
|
+
|
|
795
|
+
### Trigger conditions (STOP immediately if ANY occur):
|
|
796
|
+
- \u274C Scaffold fails or produces unexpected output
|
|
797
|
+
- \u274C Build errors after scaffold (backend or frontend)
|
|
798
|
+
- \u274C Type errors that seem wrong or unexpected
|
|
799
|
+
- \u274C Anything that "feels off" or deviates from expected flow
|
|
800
|
+
- \u274C Errors you don't understand the root cause of
|
|
801
|
+
- \u274C Subagent returns with failure or unexpected result
|
|
802
|
+
- \u274C Generated code doesn't match expected patterns
|
|
803
|
+
- \u274C Missing files or imports after generation
|
|
804
|
+
|
|
805
|
+
### How to report:
|
|
806
|
+
"""
|
|
807
|
+
Tool: mcp__agent-planning__report_debug_insight
|
|
808
|
+
Parameters:
|
|
809
|
+
- category: "scaffold_failure" | "build_error" | "unexpected_behavior" | "weird_error"
|
|
810
|
+
- description: Clear explanation of what went wrong
|
|
811
|
+
- context: What you were trying to do when this happened
|
|
812
|
+
- errorOutput: The actual error message (paste it)
|
|
813
|
+
"""
|
|
814
|
+
|
|
815
|
+
### After reporting:
|
|
816
|
+
Say exactly: "\u{1F6D1} DEBUG: I've hit an issue and reported it. Please review and tell me how to proceed."
|
|
817
|
+
Then STOP. Do not continue. Do not try to fix it. Wait for user.
|
|
818
|
+
|
|
819
|
+
### Important: PASS THIS INFO TO SUBAGENTS TOO!
|
|
820
|
+
|
|
821
|
+
---
|
|
822
|
+
|
|
823
|
+
`:"",h=Vt(o),f=zt(o,s),m=Zt(o,r),v=Jt(r),T=r?en(o):"",_=r?tn(o,s):"",O=Xt(r);return`${i}${l}# Agent Instructions
|
|
824
|
+
|
|
825
|
+
## \u26D4 CRITICAL: EVERYTHING IS A KANBAN TASK
|
|
826
|
+
|
|
827
|
+
**YOU DO NOT HAVE AN INTERNAL TODO LIST.**
|
|
828
|
+
Your brain is the Kanban board. You must act based on what is on the board.
|
|
829
|
+
You have mcp tools to help you:
|
|
830
|
+
|
|
831
|
+
**YOUR CORE LOOP:**
|
|
832
|
+
1. **CHECK BOARD:** "get_kanban_board" to see what to do.
|
|
833
|
+
2. **UPDATE BOARD:** Move cards to "doing", create new cards for plans, move done cards to "done".
|
|
834
|
+
3. **EXECUTE:** Delegate to subagents based on the active card.
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
## \u26D4 CRITICAL: USE MCP TOOL FOR QUESTIONS
|
|
839
|
+
|
|
840
|
+
**NEVER use the built-in AskUserQuestion tool.** It is disabled.
|
|
841
|
+
|
|
842
|
+
When you need to ask the user questions, you MUST use the MCP tool:
|
|
843
|
+
"""
|
|
844
|
+
mcp__agent-planning__ask_questions
|
|
845
|
+
"""
|
|
846
|
+
|
|
847
|
+
This tool allows you to ask multiple questions with predefined answer options.
|
|
848
|
+
|
|
849
|
+
---
|
|
850
|
+
|
|
851
|
+
## \u26D4 CRITICAL: USE KANBAN MCP FOR TASK MANAGEMENT
|
|
852
|
+
|
|
853
|
+
**NEVER use the built-in TodoWrite tool.** It is disabled.
|
|
854
|
+
|
|
855
|
+
The kanban board is your source of truth for work tracking. Do not create internal lists.
|
|
856
|
+
|
|
857
|
+
### Kanban Tools & Usage
|
|
858
|
+
|
|
859
|
+
**Read operations (lightweight, progressive):**
|
|
860
|
+
- \`get_kanban_board\` - Overview: columns with card counts only
|
|
861
|
+
- \`get_column_cards\` - Cards in a column: titles, priorities, IDs
|
|
862
|
+
- \`get_card_details\` - Full card: description, subtasks
|
|
863
|
+
|
|
864
|
+
**Write operations:**
|
|
865
|
+
- \`create_kanban_card\` - Create a new task card
|
|
866
|
+
- \`update_kanban_card\` - Update card title, description, priority, or due date
|
|
867
|
+
- \`move_kanban_card\` - Move card between columns: **"Todo" \u2192 "In Progress" \u2192 "Done"**
|
|
868
|
+
- \`delete_kanban_card\` - Remove a task
|
|
869
|
+
|
|
870
|
+
**Subtask operations:**
|
|
871
|
+
- \`create_subtask\` - Add a subtask to a card
|
|
872
|
+
- \`toggle_subtask\` - Mark subtask complete/incomplete
|
|
873
|
+
- \`delete_subtask\` - Remove a subtask
|
|
874
|
+
|
|
875
|
+
### How to Use Kanban for Tracking Work
|
|
876
|
+
|
|
877
|
+
**1. Before starting work:**
|
|
878
|
+
- Call "get_kanban_board" to see what needs to be done
|
|
879
|
+
- Pick the top card from "Todo" column
|
|
880
|
+
- Move it to "In Progress" with \`move_kanban_card\`
|
|
881
|
+
|
|
882
|
+
**2. While working:**
|
|
883
|
+
- Keep the card's **Description** updated with what you're currently doing
|
|
884
|
+
- Example: "\u{1F528} Currently scaffolding Task entity with fields: title, status, assignee"
|
|
885
|
+
- Example: "\u{1F504} Running backend build, waiting for result"
|
|
886
|
+
- Example: "\u2705 Entity created, now creating subtasks for backend implementation"
|
|
887
|
+
- As you complete subtasks, use "toggle_subtask" to mark them done
|
|
888
|
+
- Update priority if things change
|
|
889
|
+
- Update due date if timing shifts
|
|
890
|
+
|
|
891
|
+
**3. When blocking/stuck:**
|
|
892
|
+
- Update the description with what's blocking you
|
|
893
|
+
- Example: "\u26D4 Blocked: Frontend build failing with type error in components"
|
|
894
|
+
- Do NOT leave card in "In Progress" if you're waiting for user input
|
|
895
|
+
- Create new card for the blocker or report debug insight
|
|
896
|
+
|
|
897
|
+
**4. When done:**
|
|
898
|
+
- Make sure all subtasks are toggled complete
|
|
899
|
+
- Move card to "Done" with \`move_kanban_card\`
|
|
900
|
+
- The board becomes your execution history
|
|
901
|
+
|
|
902
|
+
### Card Status Rules
|
|
903
|
+
|
|
904
|
+
**Column names (EXACT - case sensitive!):**
|
|
905
|
+
- \`"Backlog"\` - Ideas, not prioritized yet
|
|
906
|
+
- \`"Todo"\` - Tasks queued, ready to start
|
|
907
|
+
- \`"In Progress"\` - Actively working on it right now
|
|
908
|
+
- \`"Done"\` - Completed
|
|
909
|
+
|
|
910
|
+
**Priority values:**
|
|
911
|
+
- "Low" - Can wait
|
|
912
|
+
- "Medium" - Normal work
|
|
913
|
+
- "High" - Important
|
|
914
|
+
- "Urgent" - Critical path
|
|
915
|
+
|
|
916
|
+
**Description field (use this actively):**
|
|
917
|
+
- Start with \u{1F528} (building), \u{1F504} (processing), \u26D4 (blocked), \u2705 (done)
|
|
918
|
+
- Keep it real-time: "Building X", "Testing Y", "Waiting for user", "Error in Z"
|
|
919
|
+
- This is how you stay organized without internal lists
|
|
920
|
+
|
|
921
|
+
### Example Workflow
|
|
922
|
+
|
|
923
|
+
"""
|
|
924
|
+
1. get_kanban_board \u2192 See columns and card counts
|
|
925
|
+
2. get_column_cards("Todo") \u2192 See cards in Todo, pick one
|
|
926
|
+
3. move_kanban_card(cardId, "In Progress")
|
|
927
|
+
4. get_card_details(cardId) \u2192 Read full description if needed
|
|
928
|
+
5. [work]
|
|
929
|
+
6. toggle_subtask \u2192 Mark subtasks done as you complete them
|
|
930
|
+
7. move_kanban_card(cardId, "Done")
|
|
931
|
+
8. get_column_cards("Todo") \u2192 Pick next card
|
|
932
|
+
"""
|
|
933
|
+
|
|
934
|
+
---
|
|
935
|
+
|
|
936
|
+
## \u26D4 CRITICAL: MANDATORY SUBAGENT DELEGATION
|
|
937
|
+
|
|
938
|
+
**YOU MUST DELEGATE TO SUBAGENTS. NEVER DO THE WORK YOURSELF.**
|
|
939
|
+
|
|
940
|
+
When user asks to build ANY feature, your FIRST action is to delegate to @planning subagent.
|
|
941
|
+
|
|
942
|
+
**\u26A0\uFE0F DO NOT:**
|
|
943
|
+
- Write plans yourself
|
|
944
|
+
- Use EnterPlanMode or any built-in planning
|
|
945
|
+
- Skip the @planning step
|
|
946
|
+
|
|
947
|
+
${v}
|
|
948
|
+
|
|
949
|
+
---
|
|
950
|
+
|
|
951
|
+
You are a combination of Jony Ive and Steve Jobs\u2014you create beautiful, valuable, and working software.
|
|
952
|
+
You know that overengineering is the enemy of good software. You are pragmatic and you know when to stop.
|
|
953
|
+
|
|
954
|
+
**Your users may be non-technical.** They have ideas, not code. You are their bridge to magic.
|
|
955
|
+
|
|
956
|
+
${h}
|
|
957
|
+
|
|
958
|
+
${f}
|
|
959
|
+
|
|
960
|
+
${m}
|
|
961
|
+
|
|
962
|
+
${O}
|
|
963
|
+
|
|
964
|
+
${T}
|
|
965
|
+
|
|
966
|
+
${_}
|
|
967
|
+
`}function Vt(e){let t=ke(e),n=H(e),s=Y(e),o=be(e),r=ne(e),i=[];o&&i.push(`- Backend: "${o}/{Entity}/"`),r&&i.push(`- Frontend: "${r}/{entity}/"`);let l=e.techStack?.patterns?.length?`
|
|
968
|
+
**Key patterns:**
|
|
969
|
+
${e.techStack.patterns.map(m=>`- ${m}`).join(`
|
|
970
|
+
`)}`:"",f=e.techStack?.backend?.some(m=>m.includes(".NET")||m.includes("C#"))??!1?`
|
|
971
|
+
|
|
972
|
+
**\u26A0\uFE0F User entity exists!** ASP.NET Identity "ApplicationUser" at "Features/Users/" - don't scaffold User, just relate to it.`:"";return`<tech-stack>
|
|
973
|
+
${t}
|
|
974
|
+
${i.length>0?`
|
|
975
|
+
**Architecture:** Feature folders
|
|
976
|
+
${i.join(`
|
|
977
|
+
`)}`:""}
|
|
978
|
+
${l}${f}
|
|
979
|
+
</tech-stack>`}function zt(e,t){return t?`<environment>
|
|
980
|
+
**LOCAL MODE - User manages their own services.**
|
|
981
|
+
|
|
982
|
+
You are running on the user's local machine, NOT in a Docker container.
|
|
983
|
+
|
|
984
|
+
**\u26A0\uFE0F CRITICAL LOCAL MODE RULES:**
|
|
985
|
+
- **NEVER** restart, stop, or start services - the user controls their own processes
|
|
986
|
+
- **NEVER** try to kill processes or manage ports
|
|
987
|
+
- You can still run \`check_backend_build\` and \`check_frontend_types\` to verify code
|
|
988
|
+
- You can still read logs with \`tail_service_log\` if the user has services running
|
|
989
|
+
- If builds fail, fix the code - don't try to restart anything
|
|
990
|
+
|
|
991
|
+
The user is responsible for:
|
|
992
|
+
- Starting/stopping their services
|
|
993
|
+
- Managing their database
|
|
994
|
+
- Any service restarts needed after code changes
|
|
995
|
+
|
|
996
|
+
**Your job:** Write code, verify it compiles, report results. Let the user handle the rest.
|
|
997
|
+
</environment>`:`<environment>
|
|
998
|
+
Docker container with pre-started services:
|
|
999
|
+
|
|
1000
|
+
${Se(e)}
|
|
1001
|
+
${e.tunnel?.enabled?"| Tunnel | - | - | Exposes frontend to user |":""}
|
|
1002
|
+
|
|
1003
|
+
User sees app through **Cloudflare tunnel** (live preview in browser).
|
|
1004
|
+
</environment>`}function Jt(e){return e?`**\u2705 ALWAYS delegate to these subagents:**
|
|
1005
|
+
|
|
1006
|
+
| Trigger | Subagent | Example |
|
|
1007
|
+
|---------|----------|---------|
|
|
1008
|
+
| Any new feature request | @planning | "build a golf app", "add tasks" |
|
|
1009
|
+
| Create entity, CRUD, scaffold | @scaffolding | "add task management" |
|
|
1010
|
+
| Custom backend code | @backend | "add lookup query" |
|
|
1011
|
+
| Frontend UI code | @frontend | "create the UI" |
|
|
1012
|
+
| Build error, bug, fix | @debugger | "error CS0246" |
|
|
1013
|
+
|
|
1014
|
+
**Flow:** @planning \u2192 **[Create Kanban Cards]** \u2192 @scaffolding \u2192 @backend \u2192 @frontend \u2192 @debugger`:`**\u2705 ALWAYS delegate to these subagents:**
|
|
1015
|
+
|
|
1016
|
+
| Trigger | Subagent | Example |
|
|
1017
|
+
|---------|----------|---------|
|
|
1018
|
+
| Any new feature request | @planning | "build a feature", "add tasks" |
|
|
1019
|
+
| Build error, bug, fix | @debugger | "fix this error" |
|
|
1020
|
+
|
|
1021
|
+
**Flow:** @planning \u2192 **[Create Kanban Cards]** \u2192 Execute work \u2192 @debugger (if issues)
|
|
1022
|
+
|
|
1023
|
+
Note: For this project, you implement the code directly after planning (no stack-specific subagents).
|
|
1024
|
+
Check \`.claude/skills/\` for project-specific patterns and conventions.`}function Xt(e){return e?`<workflow>
|
|
1025
|
+
**Standard feature flow:**
|
|
1026
|
+
1. **@planning** - Gather requirements, design spec, saves it.
|
|
1027
|
+
2. **\u23F8\uFE0F STOP & WAIT** - Tell user: "Spec is ready! Review it and tell me when to implement."
|
|
1028
|
+
3. **User approves** - User says "looks good", "let's build".
|
|
1029
|
+
4. **KANBAN CREATION** - YOU (Main Agent) read the spec and create Kanban cards:
|
|
1030
|
+
|
|
1031
|
+
**\u26A0\uFE0F CRITICAL: Cards MUST include spec details, not generic descriptions!**
|
|
1032
|
+
|
|
1033
|
+
**WHY THIS MATTERS:** Subagents (@scaffolding, @backend, @frontend) receive ONLY the card title and description as context. They do NOT automatically see the original specification. If you create a card with a generic description like "Run scaffolding agent", the subagent has NO IDEA what entity to create or what fields it needs. The card description IS the subagent's instruction manual.
|
|
1034
|
+
|
|
1035
|
+
For each card, extract the relevant details from the specification:
|
|
1036
|
+
|
|
1037
|
+
- **"Scaffold [Entity]"** \u2192 Description MUST include:
|
|
1038
|
+
- Entity name and all its fields/properties from the spec
|
|
1039
|
+
- Relationships to other entities (e.g., "belongs to Project", "has many Tasks")
|
|
1040
|
+
- Any enum types or special field types
|
|
1041
|
+
|
|
1042
|
+
- **"Backend: [Feature]"** \u2192 Description MUST include:
|
|
1043
|
+
- The specific custom logic requirements from the spec
|
|
1044
|
+
- Which endpoints/queries need to be created
|
|
1045
|
+
- Business rules or validation requirements
|
|
1046
|
+
- Example: "Implement GetTasksByStatus query that filters by status enum and orders by dueDate"
|
|
1047
|
+
|
|
1048
|
+
- **"Frontend: [Feature]"** \u2192 Description MUST include:
|
|
1049
|
+
- Specific UI components needed from the spec
|
|
1050
|
+
- User interactions and workflows
|
|
1051
|
+
- Which data needs to be displayed and how
|
|
1052
|
+
- Example: "Create TaskBoard component with drag-drop between status columns"
|
|
1053
|
+
|
|
1054
|
+
**Use subtasks** for individual requirements within each card.
|
|
1055
|
+
|
|
1056
|
+
**BAD example (too generic):**
|
|
1057
|
+
- Title: "Scaffold Task Feature"
|
|
1058
|
+
- Description: "Run scaffolding agent to generate entity and CRUD"
|
|
1059
|
+
- Problem: Subagent has no idea what fields Task needs!
|
|
1060
|
+
|
|
1061
|
+
**GOOD example (includes spec details):**
|
|
1062
|
+
- Title: "Scaffold Task Feature"
|
|
1063
|
+
- Description: "Create Task entity with fields: title (string, required), description (text), status (enum: Todo/InProgress/Done), dueDate (datetime), priority (enum: Low/Medium/High). Belongs to Project (required). Has many Comments."
|
|
1064
|
+
- Subtasks: "Add title field", "Add status enum", "Add Project relationship", etc.
|
|
1065
|
+
|
|
1066
|
+
5. **EXECUTION LOOP**:
|
|
1067
|
+
- "get_kanban_board"
|
|
1068
|
+
- Pick top "Todo" card \u2192 Move to "In Progress"
|
|
1069
|
+
- Delegate to appropriate subagent (@scaffolding / @backend / @frontend)
|
|
1070
|
+
- Subagent finishes \u2192 Move card to "Done"
|
|
1071
|
+
- Repeat until board is empty OR if you need user input.
|
|
1072
|
+
|
|
1073
|
+
**\u26A0\uFE0F CRITICAL: After @planning, you MUST wait for user approval before continuing!**
|
|
1074
|
+
|
|
1075
|
+
**Rules:**
|
|
1076
|
+
- After @planning \u2192 STOP and wait for user to approve the spec
|
|
1077
|
+
- Backend MUST complete + generate swagger before frontend starts
|
|
1078
|
+
- Frontend NEVER writes fetch calls - uses generated hooks only
|
|
1079
|
+
- Git commits are automatic
|
|
1080
|
+
</workflow>`:`<workflow>
|
|
1081
|
+
**Standard feature flow:**
|
|
1082
|
+
1. **@planning** - Gather requirements, design spec, saves it.
|
|
1083
|
+
2. **\u23F8\uFE0F STOP & WAIT** - Tell user: "Spec is ready! Review it and tell me when to implement."
|
|
1084
|
+
3. **User approves** - User says "looks good", "let's build".
|
|
1085
|
+
4. **KANBAN CREATION** - Create Kanban cards with detailed descriptions:
|
|
1086
|
+
|
|
1087
|
+
**\u26A0\uFE0F CRITICAL: Cards MUST include full implementation details!**
|
|
1088
|
+
|
|
1089
|
+
Each card description should include:
|
|
1090
|
+
- What needs to be built
|
|
1091
|
+
- Specific requirements from the spec
|
|
1092
|
+
- Any dependencies or ordering constraints
|
|
1093
|
+
|
|
1094
|
+
5. **EXECUTION LOOP**:
|
|
1095
|
+
- "get_kanban_board"
|
|
1096
|
+
- Pick top "Todo" card \u2192 Move to "In Progress"
|
|
1097
|
+
- Implement the feature (check \`.claude/skills/\` for project patterns)
|
|
1098
|
+
- Move card to "Done"
|
|
1099
|
+
- Repeat until board is empty OR if you need user input.
|
|
1100
|
+
|
|
1101
|
+
**\u26A0\uFE0F CRITICAL: After @planning, you MUST wait for user approval before continuing!**
|
|
1102
|
+
|
|
1103
|
+
**Rules:**
|
|
1104
|
+
- After @planning \u2192 STOP and wait for user to approve the spec
|
|
1105
|
+
- Check project's existing code for patterns before implementing
|
|
1106
|
+
- Use @debugger if you encounter build errors or bugs
|
|
1107
|
+
</workflow>`}function Zt(e,t){let n=`**@planning** - Design before building:
|
|
1108
|
+
- Complex features \u2192 plan first
|
|
1109
|
+
- Asks questions, designs spec
|
|
1110
|
+
- **Saves spec using save_specification MCP tool**
|
|
1111
|
+
- **After @planning completes: STOP and wait for user approval!**
|
|
1112
|
+
`;if(t){let s=!!e.scaffold?.command,o=!!e.services?.backend,r=!!e.services?.frontend;s&&(n+=`
|
|
1113
|
+
**@scaffolding** - Create CRUD entities, database, backend & frontend:
|
|
1114
|
+
- "Add X management" \u2192 one-shot all entities, everything from entity creation to frontend hooks and pages!
|
|
1115
|
+
- NEVER write scaffold JSON yourself
|
|
1116
|
+
`),o&&(n+=`
|
|
1117
|
+
**@backend** - Custom backend code (non-scaffold):
|
|
1118
|
+
- Custom queries, endpoints, lookups
|
|
1119
|
+
- Runs build + swagger generation before done
|
|
1120
|
+
${r?"- **Must complete before @frontend starts!**":""}
|
|
1121
|
+
`),r&&(n+=`
|
|
1122
|
+
**@frontend** - UI components:
|
|
1123
|
+
- Uses GENERATED API hooks only
|
|
1124
|
+
- Never writes manual fetch calls
|
|
1125
|
+
`)}return n+=`
|
|
1126
|
+
**@debugger** - ONLY for bugs/errors:
|
|
1127
|
+
- Build failures, runtime exceptions
|
|
1128
|
+
- NOT for writing new features!
|
|
1129
|
+
`,n+=`
|
|
1130
|
+
**@project-context** - Understand the codebase:
|
|
1131
|
+
- Explore project structure
|
|
1132
|
+
- Find existing patterns
|
|
1133
|
+
- Understand conventions
|
|
1134
|
+
`,`<subagents>
|
|
1135
|
+
**\u26A0\uFE0F MANDATORY DELEGATION - You MUST use subagents:**
|
|
1136
|
+
|
|
1137
|
+
${n}
|
|
1138
|
+
</subagents>`}function en(e){return e.services?.frontend?e.techStack?.frontend?.some(n=>n.includes("TanStack")||n.includes("React Query")||n.includes("MUI"))??!1?`<frontend-api>
|
|
1139
|
+
## Orval-Generated API Hooks
|
|
1140
|
+
|
|
1141
|
+
Frontend uses **Orval** to auto-generate React Query hooks from Swagger. Import from 'api/queries-commands.ts'.
|
|
1142
|
+
|
|
1143
|
+
**Naming patterns:**
|
|
1144
|
+
- 'useGetApi{Entity}' - List all (e.g., 'useGetApiPeople')
|
|
1145
|
+
- 'useGetApi{Entity}Id' - Get by ID
|
|
1146
|
+
- 'usePostApi{Entity}' - Create
|
|
1147
|
+
- 'usePutApi{Entity}Id' - Update
|
|
1148
|
+
- 'useDeleteApi{Entity}Id' - Delete
|
|
1149
|
+
- 'getGetApi{Entity}QueryKey' - For query invalidation
|
|
1150
|
+
|
|
1151
|
+
**Example usage:**
|
|
1152
|
+
'''tsx
|
|
1153
|
+
import { useGetApiPeople, usePostApiPeople, getGetApiPeopleQueryKey } from '../api/queries-commands'
|
|
1154
|
+
|
|
1155
|
+
// Query
|
|
1156
|
+
const { data } = useGetApiPeople()
|
|
1157
|
+
|
|
1158
|
+
// Mutation
|
|
1159
|
+
const createMutation = usePostApiPeople()
|
|
1160
|
+
createMutation.mutate({ data: { name: 'John' } })
|
|
1161
|
+
|
|
1162
|
+
// Invalidate after mutation
|
|
1163
|
+
queryClient.invalidateQueries({ queryKey: getGetApiPeopleQueryKey() })
|
|
1164
|
+
'''
|
|
1165
|
+
|
|
1166
|
+
**Important:** Check existing feature code (e.g., 'features/person/') for correct patterns before writing new API calls.
|
|
1167
|
+
</frontend-api>`:`<frontend-api>
|
|
1168
|
+
## API Integration
|
|
1169
|
+
|
|
1170
|
+
Check the project's existing patterns for API calls and data fetching.
|
|
1171
|
+
Look for existing feature code to understand the correct patterns before writing new API calls.
|
|
1172
|
+
</frontend-api>`:""}function tn(e,t){if(!e.services?.frontend)return"";let n=e.services.frontend.port,s=ne(e),o=`http://localhost:${n}`;return`<ui-verification>
|
|
1173
|
+
## \u{1F50D} UI Verification with Playwright
|
|
1174
|
+
|
|
1175
|
+
You have access to **Playwright MCP** tools to verify the UI works correctly after making changes.
|
|
1176
|
+
|
|
1177
|
+
**Available tools:**
|
|
1178
|
+
|
|
1179
|
+
*Basic navigation & inspection:*
|
|
1180
|
+
- \`browser_navigate\` - Open a URL in the browser
|
|
1181
|
+
- \`browser_snapshot\` - Get the page structure (accessibility tree) - fast, LLM-friendly
|
|
1182
|
+
- \`browser_take_screenshot\` - Capture a visual screenshot
|
|
1183
|
+
- \`browser_click\` - Click on DOM elements (by accessibility label)
|
|
1184
|
+
- \`browser_type\` - Type text into inputs
|
|
1185
|
+
- \`browser_scroll_down/up\` - Scroll the page
|
|
1186
|
+
- \`browser_wait\` - Wait for page to settle
|
|
1187
|
+
|
|
1188
|
+
*Vision/coordinate-based (for canvas, WebGL, Three.js, games):*
|
|
1189
|
+
- \`browser_screen_click\` - Click at specific x,y coordinates
|
|
1190
|
+
- \`browser_screen_move_mouse\` - Move mouse to x,y position
|
|
1191
|
+
- \`browser_screen_drag\` - Drag from one coordinate to another
|
|
1192
|
+
- \`browser_screen_type\` - Type at current position
|
|
1193
|
+
|
|
1194
|
+
*JavaScript execution:*
|
|
1195
|
+
- \`browser_evaluate\` - Run JavaScript code on the page (powerful!)
|
|
1196
|
+
|
|
1197
|
+
*Tab management:*
|
|
1198
|
+
- \`browser_tab_list\` / \`browser_tab_new\` / \`browser_tab_select\` / \`browser_tab_close\`
|
|
1199
|
+
|
|
1200
|
+
**When to use:**
|
|
1201
|
+
- After @frontend completes a feature, verify it renders correctly
|
|
1202
|
+
- When debugging UI issues - see what's actually on screen
|
|
1203
|
+
- To confirm navigation/routing works
|
|
1204
|
+
- To test forms and interactions
|
|
1205
|
+
|
|
1206
|
+
**Verification workflow:**
|
|
1207
|
+
1. Navigate to the app: \`browser_navigate\` to \`${s?.includes("super-admin")?`${o}/super-admin/[feature]`:`${o}/[feature]`}\`
|
|
1208
|
+
2. Get page structure: \`browser_snapshot\` returns the accessibility tree (LLM-friendly)
|
|
1209
|
+
3. Optional: Take screenshot for user: \`browser_take_screenshot\`
|
|
1210
|
+
4. Verify expected elements exist in the snapshot
|
|
1211
|
+
5. Report any issues found
|
|
1212
|
+
|
|
1213
|
+
**Tips:**
|
|
1214
|
+
- \`browser_snapshot\` is faster and more reliable than screenshots for DOM-based UIs
|
|
1215
|
+
- Use \`browser_screen_click\` for canvas/WebGL/Three.js - accessibility tools can't see inside canvas
|
|
1216
|
+
- Use \`browser_evaluate\` to run JavaScript when you need complex interactions
|
|
1217
|
+
- Use screenshots when you want to show the user what you see
|
|
1218
|
+
- ${t?"In local mode, the browser window will be visible to you":"In container mode, browser runs headless"}
|
|
1219
|
+
</ui-verification>`}function pt(e){return e&&e.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g,"\uFFFD")}var nn=null;function ut(){return pt(nn)}import*as _e from"path";import{fileURLToPath as sn}from"url";var rn=Ue(),gt=_e.dirname(sn(import.meta.url)),we=_e.resolve(gt,"../mcps/stdio-server.js");console.log("[MCP] Stdio server path resolved:",we);console.log("[MCP] __dirname:",gt);async function ve(e,t={}){let{model:n,sessionId:s=null,projectId:o=null,apiUrl:r=null,callbacks:i={},debugLog:l,abortController:h,debugMode:f=!1,isLocal:m=process.env.LOCAL_MODE==="true",projectConfig:v=G(process.env.WORKSPACE_DIR||process.cwd()),useDefaultStack:T=!0}=t,_=at(l),O=new Set,y=s||"",R,U,x,j=!1,Z=!1,$=process.env.WORKSPACE_DIR||process.cwd();console.log("[MCP] Configuring agent-planning stdio server:"),console.log("[MCP] Command: node"),console.log("[MCP] Args:",[we]),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=",$),console.log("[MCP] File exists check:",we);try{for await(let u of on({prompt:e,options:{abortController:h,cwd:$,resume:s??void 0,allowedTools:["Bash","Read","Write","Edit","MultiEdit","Glob","Grep","LS","WebFetch","NotebookRead","NotebookEdit","mcp__agent-insights__check_backend_build","mcp__agent-insights__check_frontend_types","mcp__agent-insights__check_service_health",...m?[]:["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__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_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_tab_list","mcp__playwright__browser_tab_new","mcp__playwright__browser_tab_select","mcp__playwright__browser_tab_close"],model:n,mcpServers:{"agent-insights":rn,"agent-planning":{type:"stdio",command:"node",args:[we],env:{WORKSPACE_DIR:$,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","--caps=vision",...m?[]:["--headless"]]}},settingSources:["project"],disallowedTools:["AskUserQuestion","TodoWrite","EnterPlanMode"],agents:T?{scaffolding:Ne,debugger:ge,planning:fe,backend:Le,frontend:Me,"project-context":me}:{debugger:ge,planning:fe,"project-context":me},systemPrompt:dt({debugMode:f,projectPrompt:ut(),isLocal:m,projectConfig:v,useDefaultStack:T})}}))if(!(!u.uuid||O.has(u.uuid))){switch(O.add(u.uuid),_?.log(u),i.onRawMessage?.(u),u.type){case"assistant":if(u.message?.content)for(let P of u.message.content)P.type==="text"?i.onAssistantText?.(P.text):P.type==="tool_use"?i.onAssistantToolUse?.(P.name,P.input):P.type==="tool_result"&&i.onAssistantToolResult?.(P.tool_use_id,P.content);break;case"user":i.onUserMessage?.(u);break;case"result":if(u.subtype==="success")R=u.result,U=u.total_cost_usd,i.onResult?.(u.result,u.total_cost_usd);else{let P=`Agent error: ${u.subtype}`;x=P,i.onError?.(P)}Z=!0;break;case"system":switch(u.subtype){case"init":y=u.session_id,_?.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(Z)break}}catch(u){u instanceof Error&&u.name==="AbortError"||u instanceof Error&&u.message.includes("aborted by user")?(j=!0,i.onAborted?.()):(x=u instanceof Error?u.message:String(u),i.onError?.(x))}finally{_?.stop()}return console.log("after try"),{sessionId:y,result:R,cost:U,error:x,aborted:j}}function Ce(e){return`User answered the questions:
|
|
1220
|
+
|
|
1221
|
+
${Object.entries(e).map(([n,s])=>{let o=Array.isArray(s)?s.join(", "):s;return`${n}: ${o}`}).join(`
|
|
1222
|
+
`)}`}import{spawn as ft,execSync as V}from"child_process";import*as w from"fs";import*as mt from"http";import*as Q from"path";function Te(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,f=H(i),m=Y(i),v=i.services?.backend?.startCommand??"dotnet run",T=i.services?.backend?.buildCommand??"dotnet build",_=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",U=i.services?.frontend?.logFile??"/tmp/web.log",x=null,j=null,Z=d=>new Promise(c=>{let g=setTimeout(()=>c(!1),3e3);mt.get(`http://localhost:${d}`,A=>{clearTimeout(g),c(A.statusCode!==void 0&&A.statusCode<500)}).on("error",()=>{clearTimeout(g),c(!1)})}),$=d=>{try{let c=V(`lsof -ti:${d} 2>/dev/null || true`,{encoding:"utf-8"}).trim();if(c){let g=c.split(`
|
|
1223
|
+
`).filter(Boolean);console.log(`[Services] Killing ${g.length} process(es) on port ${d}: ${g.join(", ")}`);for(let b of g)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(g=>{if(!d||!d.pid){g();return}console.log(`[Services] Stopping ${c} (PID: ${d.pid})...`);try{process.kill(-d.pid,"SIGTERM")}catch{try{d.kill("SIGTERM")}catch{}}setTimeout(g,500)}),P=async()=>{if(!f||!w.existsSync(f)){console.log("[Services] No backend found, skipping backend start");return}$(l),console.log(`[Services] Starting backend with: ${v}...`);let d=Q.dirname(R);w.existsSync(d)||w.mkdirSync(d,{recursive:!0});let c=w.createWriteStream(R,{flags:"a"}),[g,...b]=v.split(" ");x=ft(g,b,{cwd:f,stdio:["ignore","pipe","pipe"],detached:!0,shell:!0});let A="",C=k=>{let B=k.toString();c.write(B);let D=(A+B).split(`
|
|
1224
|
+
`);A=D.pop()||"";for(let F of D)F&&an(F)&&o&&o(F)};x.stdout?.on("data",C),x.stderr?.on("data",C),x.on("exit",k=>{c.end(),k!==0&&k!==null&&o&&o(`Process exited with code ${k}`)}),x.unref()},Ge=async()=>{if(!m||!w.existsSync(Q.join(m,"package.json"))){console.log("[Services] No frontend found, skipping frontend start");return}$(h),console.log(`[Services] Starting frontend with: ${O}...`);let d=Q.dirname(U);w.existsSync(d)||w.mkdirSync(d,{recursive:!0});let[c,...g]=O.split(" ");j=ft(c,g,{cwd:m,stdio:["ignore",w.openSync(U,"w"),w.openSync(U,"w")],detached:!0,shell:!0}),j.unref()},He=async()=>{await u(x,"backend"),x=null,$(l)},Ye=async()=>{await u(j,"frontend"),j=null,$(h)},De=async()=>{let[d,c]=await Promise.all([Z(l),Z(h)]);return{api:d,web:c}},Qe=async(d=15e3)=>{let c=Date.now(),g=1e3,b=0,A=null,C=null;for(console.log(`[Services] Waiting for health (timeout: ${d}ms)...`);Date.now()-c<d;){b++;let D=await De(),F=Date.now()-c;if(D.web&&C===null&&(C=F,console.log(`[Services] \u2713 Frontend (Vite) ready after ${F}ms`)),D.api&&A===null&&(A=F,console.log(`[Services] \u2713 Backend (dotnet) ready after ${F}ms`)),console.log(`[Services] Health poll #${b} (${F}ms): api=${D.api}, web=${D.web}`),D.api&&D.web)return console.log(`[Services] \u2713 Both services healthy after ${F}ms (${b} polls)`),D;await new Promise(Lt=>setTimeout(Lt,g))}let k=await De(),B=Date.now()-c;return k.web&&C===null&&console.log(`[Services] \u2713 Frontend (Vite) ready after ${B}ms`),k.api&&A===null&&console.log(`[Services] \u2713 Backend (dotnet) ready after ${B}ms`),console.log(`[Services] \u26A0 Health timeout after ${B}ms: api=${k.api}, web=${k.web}`),k},Ut=async d=>{console.log(`[Services] Restarting ${d}...`);let c={success:!0},g=d==="backend"||d==="both",b=d==="frontend"||d==="both";if(g&&await He(),b&&await Ye(),g&&f&&w.existsSync(f)){console.log(`[Services] Building backend with: ${T}...`);try{V(T,{cwd:f,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),console.log("[Services] \u2713 Backend build succeeded")}catch(C){let k=C;c.success=!1,c.backendError=k.stderr||k.stdout||"Build failed",console.error("[Services] \u2717 Backend build failed")}}if(b&&m&&w.existsSync(Q.join(m,"package.json"))){console.log(`[Services] Type-checking frontend with: ${y}...`);try{V(y,{cwd:m,stdio:"pipe",timeout:6e4,encoding:"utf-8"}),console.log("[Services] \u2713 Frontend types OK")}catch(C){let k=C;c.success=!1,c.frontendError=k.stderr||k.stdout||"Type check failed",console.error("[Services] \u2717 Frontend type check failed")}}console.log(`[Services] Starting ${d}...`),g&&await P(),b&&await Ge();let A=await Qe(1e4);if(g&&!A.api){c.success=!1;let C=await ze("backend",20),k=C.length>0?`
|
|
1225
|
+
Recent logs:
|
|
1226
|
+
${C.join(`
|
|
1227
|
+
`)}`:"";c.backendError||(c.backendError=`Backend failed to start.${k}`)}return b&&!A.web&&(c.success=!1,c.frontendError||(c.frontendError="Frontend failed to start")),c},Ke=async()=>{if(!f||!w.existsSync(f))return{success:!0};try{return V(_,{cwd:f,stdio:"pipe",timeout:12e4,encoding:"utf-8"}),{success:!0}}catch(d){let c=d;return{success:!1,errors:c.stdout||c.stderr||"Build failed"}}},Ve=async()=>{if(!m||!w.existsSync(Q.join(m,"package.json")))return{success:!0};try{return V(y,{cwd:m,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"}}},Nt=async()=>{let[d,c]=await Promise.all([Ke(),Ve()]);return{backend:d,frontend:c}},ze=async(d,c)=>{let g=d==="backend"?R:U;if(!w.existsSync(g))return[`Log file not found: ${g}`];try{return V(`tail -n ${c} ${g}`,{encoding:"utf-8"}).split(`
|
|
1228
|
+
`).filter(Boolean)}catch(b){return[`Error reading logs: ${b instanceof Error?b.message:String(b)}`]}};return{startBackend:P,startFrontend:Ge,stopBackend:He,stopFrontend:Ye,restartServices:Ut,checkHealth:De,waitForHealth:Qe,getProcesses:()=>({backend:x,frontend:j}),checkBackendBuild:Ke,checkFrontendTypes:Ve,runTypeChecks:Nt,tailLogs:ze,checkSwaggerEndpoints:async d=>{let c=Q.join(t,"swagger.json");if(!w.existsSync(c))return{foundEndpoints:["Error: swagger.json not found"],totalEndpoints:0};try{let g=JSON.parse(w.readFileSync(c,"utf-8")),b=Object.keys(g.paths||{}),A=[];for(let C of b)if(C.toLowerCase().includes(d.toLowerCase())){let k=Object.keys(g.paths[C]);for(let B of k)A.push(`${B.toUpperCase()} ${C}`)}return{foundEndpoints:A,totalEndpoints:b.length}}catch(g){return{foundEndpoints:[`Error parsing swagger.json: ${g instanceof Error?g.message:String(g)}`],totalEndpoints:0}}}}}function an(e){let t=e.toLowerCase();return t.includes("exception")||t.includes("fail:")||t.includes("[err]")||t.includes("[error]")}import{execSync as z}from"child_process";function Ee(e){let t=async()=>{try{return z("git status --porcelain",{cwd:e,encoding:"utf-8"}).trim().length>0}catch{return!1}},n=async()=>{try{return z("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}`;z("git add -A",{cwd:e}),z(`git commit -m "${h.replace(/"/g,'\\"')}"`,{cwd:e,encoding:"utf-8"});let f=z("git rev-parse --short HEAD",{cwd:e,encoding:"utf-8"}).trim();try{z("git push",{cwd:e,stdio:"pipe"})}catch(m){let v=m instanceof Error?m.message:String(m);if(v.includes("no upstream branch")){let T=await n();z(`git push --set-upstream origin ${T}`,{cwd:e,stdio:"pipe"})}else return console.error("[Git] Push failed:",v),{success:!0,commitHash:f,error:`Committed but push failed: ${v}`}}return{success:!0,commitHash:f}}catch(i){let l=i instanceof Error?i.message:String(i);return console.error("[Git] Error:",l),{success:!1,error:l}}},getCurrentBranch:n}}import se from"inquirer";var oe="\u2192 Other (type custom answer)";async function Pe(e){let t={};for(let n of e){let s=await cn(n);t[n.id]=s}return t}async function cn(e){return e.multiSelect&&e.options.length>0?ln(e):e.options.length>0?dn(e):pn(e)}async function ln(e){let t=[...e.options];e.allowFreeText&&t.push(oe);let{selection:n}=await se.prompt([{type:"checkbox",name:"selection",message:e.question,choices:t}]);if(n.includes(oe)){let{customAnswer:s}=await se.prompt([{type:"input",name:"customAnswer",message:"Enter your custom answer:"}]);return[...n.filter(r=>r!==oe),s]}return n}async function dn(e){let t=[...e.options];e.allowFreeText&&t.push(oe);let{selection:n}=await se.prompt([{type:"select",name:"selection",message:e.question,choices:t}]);if(n===oe){let{customAnswer:s}=await se.prompt([{type:"input",name:"customAnswer",message:"Enter your custom answer:"}]);return s}return n}async function pn(e){let{answer:t}=await se.prompt([{type:"input",name:"answer",message:e.question}]);return t}import*as L from"fs";import*as Ae from"path";var un=".sdd/cli-sessions.json";function $e(){return Ae.join(process.cwd(),un)}function gn(){let e=Ae.dirname($e());L.existsSync(e)||L.mkdirSync(e,{recursive:!0})}function Be(){try{let e=$e();if(!L.existsSync(e))return[];let t=L.readFileSync(e,"utf-8");return JSON.parse(t).sort((s,o)=>new Date(o.lastUsedAt).getTime()-new Date(s.lastUsedAt).getTime())}catch{return[]}}function ht(e){gn();let t=Be(),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);L.writeFileSync($e(),JSON.stringify(s,null,2))}function yt(e){let t=e.firstPrompt.length>50?e.firstPrompt.slice(0,50)+"...":e.firstPrompt,n=new Date(e.lastUsedAt),s=fn(n);return`${t} (${s}, ${e.turnCount} turns)`}function fn(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 bt={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`${bt[e]}${t}${bt.reset}`}var mn={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 hn(e){return mn[e]||"\u{1F527}"}function re(e,t){return e.length<=t?e:e.slice(0,t-3)+"..."}function kt(e){let t=e.split("/");return t.length<=3?e:".../"+t.slice(-2).join("/")}function qe(e){console.log(`
|
|
1229
|
+
${a("bold",a("cyan","\u2550".repeat(60)))}`),console.log(a("bold",` ${e}`)),console.log(`${a("bold",a("cyan","\u2550".repeat(60)))}
|
|
1230
|
+
`)}function St(e){let t=e.split(`
|
|
1231
|
+
`);for(let n of t)n.trim()?console.log(` ${n}`):console.log()}function wt(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(`
|
|
1232
|
+
\u{1F916} ${a("bold",a("magenta",`Delegating to @${o}`))}`),s.prompt){let r=re(String(s.prompt),100);console.log(` ${a("dim","\u2192")} ${a("gray",r)}`)}return}}let n=hn(e);if(console.log(`
|
|
1233
|
+
${n} ${a("bold",a("blue",e))}`),t&&typeof t=="object"){let s=t;if(e==="Bash"&&s.command)console.log(` ${a("dim","$")} ${a("yellow",re(String(s.command),80))}`);else if((e==="Read"||e==="Write"||e==="Edit")&&s.file_path)console.log(` ${a("dim","\u2192")} ${a("cyan",kt(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",kt(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 _t(e,t){console.log(`
|
|
1234
|
+
${a("bold",a("green","\u2713 Complete"))}`),console.log(` ${a("dim","Result:")} ${re(e,100)}`),console.log(` ${a("dim","Cost:")} ${a("yellow",`$${t.toFixed(4)}`)}`)}function vt(e){console.log(`
|
|
1235
|
+
${a("bold",a("red","\u2717 Error"))}`),console.log(` ${e}`)}function Ct(){console.log(`
|
|
1236
|
+
${a("bold",a("yellow","\u23F9\uFE0F Aborted"))}`),console.log(` ${a("dim","Session stopped by user. Progress has been preserved.")}`)}function Tt(){console.log(`
|
|
1237
|
+
${a("bold",a("yellow","\u2753 Agent needs your input"))}
|
|
1238
|
+
`)}function Et(){console.log(`
|
|
1239
|
+
${a("dim","\u2192 Answers sent, agent continuing...")}
|
|
1240
|
+
`)}function xe(){console.log(a("dim",`
|
|
1241
|
+
`+"\u2500".repeat(50)+`
|
|
1242
|
+
`))}function Pt(e,t){let n="";if(typeof t=="string")n=re(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(`
|
|
1243
|
+
`).filter(i=>i.trim());r.length>3?n=r.slice(0,3).join(" \u21B5 ")+` (+${r.length-3} more lines)`:n=r.join(" \u21B5 "),n=re(n,100)}}}console.log(n?` ${a("dim","\u2190")} ${a("gray",n)}`:` ${a("dim","\u2190")} ${a("green","done")}`)}function At(e){return{onAssistantText:St,onAssistantToolUse:(t,n)=>{if(wt(t,n),["Write","Edit","MultiEdit"].includes(t)){let s=n,o=s.file_path||s.target_file;o&&e.onFileModified(o)}},onAssistantToolResult:Pt,onResult:(t,n)=>{e.onCostUpdate(n),_t(t,n)},onError:vt,onAborted:Ct,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:yn}=I,bn=".sdd/api-config.json";function We(){return Ie.join(process.cwd(),bn)}function kn(){let e=Ie.dirname(We());M.existsSync(e)||M.mkdirSync(e,{recursive:!0})}function Sn(){try{let e=We();if(!M.existsSync(e))return null;let t=M.readFileSync(e,"utf-8");return JSON.parse(t)}catch{return null}}function wn(e){kn();let t={...e,lastUsedAt:new Date().toISOString()};M.writeFileSync(We(),JSON.stringify(t,null,2))}async function xt(){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.5 (most capable)",value:"claude-opus-4-5-20251101"},{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 It(){let e=Be();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 yn("\u2500\u2500\u2500 Previous Sessions \u2500\u2500\u2500"),...e.map(r=>({name:yt(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(`
|
|
1244
|
+
\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 Rt(){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 Ot(){let e=process.env.API_URL||process.env.MASTER_URL,t=process.env.PROJECT_ID,n=Sn();if(n&&!e&&!t){console.log(`
|
|
1245
|
+
\u{1F4CB} Previous API Configuration Found
|
|
1246
|
+
`),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 wn(o),o}async function Dt(e,t){if(t.size===0)return console.log(`
|
|
1247
|
+
${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(`
|
|
1248
|
+
${a("dim","\u23ED\uFE0F No code changes, skipping type checks")}`),{passed:!0};let o=[];n&&o.push("backend"),s&&o.push("frontend"),console.log(`
|
|
1249
|
+
${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)
|
|
1250
|
+
\`\`\`
|
|
1251
|
+
${l.errors}
|
|
1252
|
+
\`\`\``)}if(s){let l=await e.checkFrontendTypes();!l.success&&l.errors&&i.push(`## Frontend Type Errors (in ${r}/packages/backoffice-web)
|
|
1253
|
+
\`\`\`
|
|
1254
|
+
${l.errors}
|
|
1255
|
+
\`\`\``)}return i.length>0?(console.log(` ${a("red","\u274C Type errors found - auto-correcting...")}
|
|
1256
|
+
`),{passed:!1,errorPrompt:`@debugger Type/build errors detected. Fix them.
|
|
1257
|
+
|
|
1258
|
+
WORKSPACE: ${r}
|
|
1259
|
+
|
|
1260
|
+
${i.join(`
|
|
1261
|
+
|
|
1262
|
+
`)}
|
|
1263
|
+
|
|
1264
|
+
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 Ft(e,t,n){if(!await e.hasChanges())return;console.log(`
|
|
1265
|
+
${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 ie=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",()=>{ie?(console.log(`
|
|
1266
|
+
|
|
1267
|
+
\u23F9\uFE0F Stopping agent...
|
|
1268
|
+
`),ie.abort()):(console.log(`
|
|
1269
|
+
`),process.exit(0))});async function Oe(e,t={}){let{serviceManager:n,gitManager:s}=t,o=null,r,i,l=0,h=0,f=t.typecheck??!1,m=t.autoCommit??!1,v=t.model;if(e)r=e,i=e;else{let T=await xt();n&&(f=T.typecheck),s&&(m=T.autoCommit),t.skipModelPrompt||(v=T.model);let _=await It();o=_.sessionId,r=_.firstPrompt,l=_.existingTurnCount,i=_.isResume&&await Re()||r}for(_n(f,m,!!n,!!s,v);;){l++,console.log(`
|
|
1270
|
+
Turn ${l}`),xe();let T=new Set;ie=new AbortController;let _=await ve(i,{model:v==="auto"?void 0:v,sessionId:o,projectId:process.env.PROJECT_ID||null,debugLog:!0,abortController:ie,callbacks:At({sessionId:o,onSessionInit:y=>{o=y},onCostUpdate:y=>{h+=y},onFileModified:y=>{T.add(y)}})});if(console.log("after runAgent"),ie=null,_.sessionId&&(o=_.sessionId),_.cost&&(h=_.cost),console.log("after result"),Cn(o,r,l),console.log("after saveSessionIfNeeded"),_.aborted){if(await new Promise(U=>setTimeout(U,100)),xe(),h>0&&console.log(` \u{1F4B0} Session cost so far: $${h.toFixed(4)}
|
|
1271
|
+
`),await Rt()==="exit")break;let R=await Re();if(!R)break;i=R;continue}if(console.log("after abort"),o){let y=ee(o);if(y&&y.length>0){Tt();let R=await Pe(y);i=Ce(R),Et();continue}}if(console.log("after pending questions"),f&&n){let y=await Dt(n,T);if(!y.passed&&y.errorPrompt){i=y.errorPrompt;continue}}if(console.log("after typecheck"),m&&s){let y=_.aborted||!!_.error;await Ft(s,r,y)}console.log("after auto-commit"),xe();let O=await Re();if(!O)break;i=O}vn(o,h)}function _n(e,t,n,s,o){qe("\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-5-20251101"?"Opus 4.5":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
|
|
1272
|
+
`)}function vn(e,t){qe("\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 Cn(e,t,n){e&&ht({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 Tn(){let e=process.env.API_URL||process.env.MASTER_URL,t=process.env.PROJECT_ID,n=e,s=t;if(!e||!t){console.log(`
|
|
1273
|
+
\u{1F4CB} API Configuration Required
|
|
1274
|
+
`);let f=await Ot();n=f.apiUrl,s=f.projectId}process.env.API_URL=n,process.env.PROJECT_ID=s;let o=process.env.WORKSPACE_DIR||process.cwd(),r=Te({workspaceDir:o}),i=Ee(o),l=te(o);pe(r),de(l),await Oe(void 0,{serviceManager:r,gitManager:i})}Tn().catch(e=>{console.error("Fatal error:",e),process.exit(1)});
|