galaxy-code 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/cli.bundle.js +588 -0
  2. package/package.json +6 -6
  3. package/dist/app.d.ts +0 -7
  4. package/dist/app.js +0 -597
  5. package/dist/auto-updater.d.ts +0 -21
  6. package/dist/auto-updater.js +0 -144
  7. package/dist/cli.d.ts +0 -2
  8. package/dist/cli.js +0 -159
  9. package/dist/cli.min.js +0 -589
  10. package/dist/connections/claude.d.ts +0 -71
  11. package/dist/connections/claude.js +0 -303
  12. package/dist/connections/gemini.d.ts +0 -40
  13. package/dist/connections/gemini.js +0 -232
  14. package/dist/connections/index.d.ts +0 -11
  15. package/dist/connections/index.js +0 -11
  16. package/dist/connections/ollama.d.ts +0 -37
  17. package/dist/connections/ollama.js +0 -73
  18. package/dist/connections/types.d.ts +0 -22
  19. package/dist/connections/types.js +0 -7
  20. package/dist/env.d.ts +0 -1
  21. package/dist/env.js +0 -29
  22. package/dist/prompts/ba-it-analyzer.d.ts +0 -1
  23. package/dist/prompts/ba-it-analyzer.js +0 -143
  24. package/dist/prompts/index.d.ts +0 -11
  25. package/dist/prompts/index.js +0 -11
  26. package/dist/prompts/orchestrator.d.ts +0 -8
  27. package/dist/prompts/orchestrator.js +0 -88
  28. package/dist/prompts/planning-agent.d.ts +0 -8
  29. package/dist/prompts/planning-agent.js +0 -195
  30. package/dist/prompts/universal-agent.d.ts +0 -7
  31. package/dist/prompts/universal-agent.js +0 -111
  32. package/dist/providers/agent-selector.d.ts +0 -29
  33. package/dist/providers/agent-selector.js +0 -84
  34. package/dist/providers/claude-agent.d.ts +0 -29
  35. package/dist/providers/claude-agent.js +0 -121
  36. package/dist/providers/gemini-agent.d.ts +0 -36
  37. package/dist/providers/gemini-agent.js +0 -168
  38. package/dist/providers/index.d.ts +0 -12
  39. package/dist/providers/index.js +0 -12
  40. package/dist/providers/ollama-agent.d.ts +0 -53
  41. package/dist/providers/ollama-agent.js +0 -276
  42. package/dist/providers/orchestrator.d.ts +0 -16
  43. package/dist/providers/orchestrator.js +0 -76
  44. package/dist/tools/ba-it-analyzer.d.ts +0 -66
  45. package/dist/tools/ba-it-analyzer.js +0 -90
  46. package/dist/tools/code-generate-agent.d.ts +0 -51
  47. package/dist/tools/code-generate-agent.js +0 -159
  48. package/dist/tools/command-runner.d.ts +0 -14
  49. package/dist/tools/command-runner.js +0 -120
  50. package/dist/tools/document-parser.d.ts +0 -11
  51. package/dist/tools/document-parser.js +0 -83
  52. package/dist/tools/file-operations.d.ts +0 -17
  53. package/dist/tools/file-operations.js +0 -127
  54. package/dist/tools/galaxy-ui-integration.d.ts +0 -94
  55. package/dist/tools/galaxy-ui-integration.js +0 -244
  56. package/dist/tools/git-operations.d.ts +0 -11
  57. package/dist/tools/git-operations.js +0 -114
  58. package/dist/tools/index.d.ts +0 -10
  59. package/dist/tools/index.js +0 -10
  60. package/dist/tools/planning-agent.d.ts +0 -29
  61. package/dist/tools/planning-agent.js +0 -134
  62. package/dist/tools/progress-reporter.d.ts +0 -19
  63. package/dist/tools/progress-reporter.js +0 -52
  64. package/dist/tools/registry.d.ts +0 -21
  65. package/dist/tools/registry.js +0 -695
  66. package/dist/tools/tool-event-emitter.d.ts +0 -24
  67. package/dist/tools/tool-event-emitter.js +0 -25
  68. package/dist/tools/types.d.ts +0 -31
  69. package/dist/tools/types.js +0 -1
  70. package/dist/types.d.ts +0 -39
  71. package/dist/types.js +0 -8
  72. package/dist/update-checker.d.ts +0 -22
  73. package/dist/update-checker.js +0 -85
  74. package/dist/utils/config-manager.d.ts +0 -102
  75. package/dist/utils/config-manager.js +0 -326
  76. package/dist/utils/devtools.d.ts +0 -21
  77. package/dist/utils/devtools.js +0 -61
  78. package/dist/utils/message-formatters.d.ts +0 -32
  79. package/dist/utils/message-formatters.js +0 -590
  80. package/dist/utils/progress-tracker.d.ts +0 -59
  81. package/dist/utils/progress-tracker.js +0 -213
@@ -0,0 +1,588 @@
1
+ #!/usr/bin/env node
2
+ var et=Object.defineProperty;var i=(r,e)=>et(r,"name",{value:e,configurable:!0});import mn from"react";import{render as gn}from"ink";import fn from"meow";import{config as tt}from"dotenv";import{fileURLToPath as nt}from"node:url";import{dirname as ot,join as rt}from"node:path";var st=nt(import.meta.url),it=ot(st),at=process.stdout.write,ct=process.stderr.write,lt=console.log,pt=console.info;process.stdout.write=()=>!0;process.stderr.write=()=>!0;console.log=()=>{};console.info=()=>{};tt({path:rt(it,"..",".env"),debug:!1,override:!1});process.stdout.write=at;process.stderr.write=ct;console.log=lt;console.info=pt;import Y from"node:process";import T,{useMemo as Be,useState as F,useEffect as Gt}from"react";import{Box as P,Static as Ft,Text as j,useApp as Rt,useInput as Bt}from"ink";import qt from"ink-text-input";import Ht from"ink-spinner";import Wt from"figlet";import{GoogleGenAI as vt,Type as L}from"@google/genai";import{Ollama as ut}from"ollama";var U=class{static{i(this,"OllamaConnection")}ollama;model="deepseek-v3.1:671b-cloud";constructor(e){this.model=e?.model??this.model;let t=e?.host??"https://ollama.com",n=t==="https://ollama.com"||t.includes("ollama.com"),o=e?.apiKey;this.ollama=new ut({host:t,headers:n?{Authorization:"Bearer "+o}:{}})}async generate(e){return await this.ollama.generate({model:e.model||this.model,prompt:e.prompt,system:e.system,stream:!1})}async chat(e){return(await this.ollama.chat({model:this.model,messages:[{role:"user",content:e}],stream:!1})).message.content}async chatWithTools(e){return await this.ollama.chat({model:e.model,messages:e.messages,tools:e.tools,stream:!1})}};var ke=`You are an EXPERT BUSINESS ANALYST for IT projects.
3
+
4
+ # Your Role:
5
+ Analyze user requests and create COMPREHENSIVE project specifications including:
6
+ 1. Type: create_project (new) or update_project (add feature to existing)
7
+ 2. Core Features (must-have vs nice-to-have)
8
+ 3. Technical Stack recommendations
9
+ 4. User Stories with acceptance criteria
10
+ 5. Data Model (entities, attributes, relationships)
11
+ 6. API endpoints for backend systems
12
+ 7. Complexity + time estimate
13
+ 8. Best practices & recommendations
14
+ 9. Clarification questions
15
+
16
+ # Language Rule:
17
+ **ALWAYS respond in ENGLISH** regardless of user's input language.
18
+ - All field values (descriptions, names, recommendations, etc.) MUST be in English
19
+ - This ensures consistent output format for downstream tools (planning, code generation)
20
+
21
+ # Output Format (VALID JSON - ALL content in English):
22
+ {
23
+ "type": "create_project | update_project",
24
+ "projectName": "Project name",
25
+ "projectType": "web-app | mobile-app | api | full-stack | desktop-app",
26
+ "description": "Brief summary",
27
+ "coreFeatures": [
28
+ {
29
+ "name": "Feature name",
30
+ "description": "Description",
31
+ "priority": "must-have | should-have | nice-to-have",
32
+ "userStory": "As a [user], I want [feature] so that [benefit]",
33
+ "acceptanceCriteria": ["Criterion 1", "Criterion 2"]
34
+ }
35
+ ],
36
+ "technicalStack": {
37
+ "frontend": ["React", "TypeScript"],
38
+ "backend": ["Node.js", "Express"],
39
+ "database": ["PostgreSQL"],
40
+ "thirdParty": ["Stripe"]
41
+ },
42
+ "userStories": [
43
+ {
44
+ "as": "role",
45
+ "iWant": "feature",
46
+ "soThat": "benefit",
47
+ "acceptanceCriteria": ["Given [context], when [action], then [result]"]
48
+ }
49
+ ],
50
+ "dataModel": [
51
+ {
52
+ "name": "Entity",
53
+ "description": "Purpose",
54
+ "attributes": ["id", "name", "createdAt"],
55
+ "relationships": ["User has many Orders"]
56
+ }
57
+ ],
58
+ "apiEndpoints": [
59
+ {
60
+ "method": "GET | POST | PUT | DELETE",
61
+ "path": "/api/resource",
62
+ "description": "Purpose",
63
+ "response": "{ data: [] }"
64
+ }
65
+ ],
66
+ "estimatedComplexity": "simple | medium | complex",
67
+ "estimatedTime": "1-2 weeks | 2-4 weeks | 1-3 months",
68
+ "recommendations": ["Recommendation with reasoning"],
69
+ "questionsForUser": ["Clarification question"]
70
+ }
71
+
72
+ # Example:
73
+
74
+ User: "Create an online phone store"
75
+
76
+ {
77
+ "type": "create_project",
78
+ "projectName": "Phone Store E-Commerce",
79
+ "projectType": "full-stack",
80
+ "description": "E-commerce platform for selling phones with product catalog, cart, checkout, and order management",
81
+ "coreFeatures": [
82
+ {
83
+ "name": "Product Catalog",
84
+ "description": "Display phones with images, prices, specs. Filter by brand, price, features. Search by name.",
85
+ "priority": "must-have",
86
+ "userStory": "As a customer, I want to browse phones with filters to find suitable products",
87
+ "acceptanceCriteria": ["Grid/list view", "Filter by brand/price", "Real-time search", "Pagination"]
88
+ },
89
+ {
90
+ "name": "Shopping Cart",
91
+ "description": "Add products, update quantity, remove items, calculate total",
92
+ "priority": "must-have",
93
+ "userStory": "As a customer, I want to manage my cart to buy multiple products",
94
+ "acceptanceCriteria": ["Add to cart", "Update quantity", "Remove items", "Calculate total"]
95
+ }
96
+ ],
97
+ "technicalStack": {
98
+ "frontend": ["Next.js", "TypeScript", "Tailwind"],
99
+ "backend": ["Node.js", "Express"],
100
+ "database": ["PostgreSQL", "Redis"],
101
+ "thirdParty": ["Stripe"]
102
+ },
103
+ "userStories": [
104
+ {
105
+ "as": "customer",
106
+ "iWant": "filter products by brand",
107
+ "soThat": "find phones quickly",
108
+ "acceptanceCriteria": ["Given home page, when filter 'Samsung', then show Samsung phones"]
109
+ }
110
+ ],
111
+ "dataModel": [
112
+ {
113
+ "name": "Product",
114
+ "description": "Phone product",
115
+ "attributes": ["id", "name", "brand", "price", "stock"],
116
+ "relationships": ["Product has many OrderItems"]
117
+ }
118
+ ],
119
+ "apiEndpoints": [
120
+ {
121
+ "method": "GET",
122
+ "path": "/api/products",
123
+ "description": "Get product list",
124
+ "response": "{ products: Product[] }"
125
+ }
126
+ ],
127
+ "estimatedComplexity": "complex",
128
+ "estimatedTime": "2-4 weeks",
129
+ "recommendations": [
130
+ "Use Next.js App Router for SSR and SEO",
131
+ "Implement Redis caching for product listing"
132
+ ],
133
+ "questionsForUser": [
134
+ "Online payment (Stripe) or COD only?",
135
+ "Multi-language support needed?"
136
+ ]
137
+ }
138
+
139
+ CRITICAL:
140
+ - VALID JSON ONLY (no markdown)
141
+ - COMPREHENSIVE MVP features
142
+ - Use user's language throughout
143
+ - SPECIFIC technical recommendations
144
+ - Realistic feature prioritization`;var se=class{static{i(this,"BAITAnalyzer")}ollama=null;model="gpt-oss:120b-cloud";constructor(){}getConnection(){return this.ollama||(this.ollama=new U({model:this.model})),this.ollama}async analyze(e,t){let n=`User Request: ${e}`;t&&(n+=`
145
+
146
+ Additional Context:
147
+ ${t}`);let o=await this.getConnection().generate({prompt:n,system:ke,model:this.model}),s=this.extractJSON(o.response);if(!s)throw new Error("Failed to extract JSON from BA analysis response");return JSON.parse(s)}extractJSON(e){let t=e.trim();t=t.replace(/```json\s*/g,""),t=t.replace(/```\s*/g,"");let n=t.indexOf("{");if(n===-1)return null;let o=0,s=!1,a=!1;for(let p=n;p<t.length;p++){let c=t[p];if(a){a=!1;continue}if(c==="\\"){a=!0;continue}if(c==='"'&&!a){s=!s;continue}if(!s){if(c==="{")o++;else if(c==="}"&&(o--,o===0))return t.substring(n,p+1)}}return null}};import{exec as dt}from"child_process";import{promisify as mt}from"util";import ie from"fs/promises";import we from"path";var gt=mt(dt),ae=class{static{i(this,"CommandRunner")}async runCommand(e,t,n=18e4){try{let{stdout:o,stderr:s}=await gt(e,{cwd:t,timeout:n,maxBuffer:10485760});return{stdout:o,stderr:s,exitCode:0,command:e}}catch(o){return{stdout:o.stdout||"",stderr:o.stderr||o.message,exitCode:o.code||1,command:e}}}async detectTestCommand(e){try{let t=we.join(e,"package.json"),n=await ie.readFile(t,"utf-8"),o=JSON.parse(n);if(o.scripts?.test)return o.scripts.test;let s=await this.detectPackageManager(e);return s==="bun"?"bun test":s==="pnpm"?"pnpm test":s==="yarn"?"yarn test":"npm test"}catch{return null}}async detectDevCommand(e){try{let t=we.join(e,"package.json"),n=await ie.readFile(t,"utf-8"),o=JSON.parse(n);if(o.scripts?.dev)return o.scripts.dev;if(o.scripts?.start)return o.scripts.start;let s=await this.detectPackageManager(e);return s==="bun"?"bun run dev":s==="pnpm"?"pnpm dev":s==="yarn"?"yarn dev":"npm run dev"}catch{return null}}async detectBuildCommand(e){try{let t=we.join(e,"package.json"),n=await ie.readFile(t,"utf-8");if(JSON.parse(n).scripts?.build){let s=await this.detectPackageManager(e);return s==="bun"?"bun run build":s==="pnpm"?"pnpm build":s==="yarn"?"yarn build":"npm run build"}return null}catch{return null}}async detectPackageManager(e){try{let t=await ie.readdir(e);return t.includes("bun.lockb")?"bun":t.includes("pnpm-lock.yaml")?"pnpm":t.includes("yarn.lock")?"yarn":"npm"}catch{return"bun"}}async installDependencies(e){let t=await this.detectPackageManager(e),n=t==="npm"?"npm install":t==="yarn"?"yarn install":t==="pnpm"?"pnpm install":"bun install";return this.runCommand(n,e,18e4)}};import{exec as ft}from"child_process";import{promisify as ht}from"util";var ce=ht(ft),le=class{static{i(this,"DocumentParser")}async parseDocument(e,t){try{switch(t){case"pdf":return await this.parsePDF(e);case"docx":return await this.parseDOCX(e);case"xlsx":return await this.parseXLSX(e);default:throw new Error(`Unsupported document type: ${t}`)}}catch(n){return`Failed to parse document: ${n.message}`}}async parsePDF(e){try{let{stdout:t}=await ce(`pdftotext "${e}" -`,{timeout:3e4,maxBuffer:10485760});return t||"No text content found in PDF"}catch(t){if(t.message.includes("command not found"))return"PDF parsing requires pdftotext (install: apt-get install poppler-utils)";throw t}}async parseDOCX(e){try{let{stdout:t}=await ce(`pandoc "${e}" -t plain`,{timeout:3e4,maxBuffer:10485760});return t||"No text content found in DOCX"}catch(t){if(t.message.includes("command not found"))return"DOCX parsing requires pandoc (install: apt-get install pandoc)";throw t}}async parseXLSX(e){try{let{stdout:t}=await ce(`ssconvert "${e}" fd://1`,{timeout:3e4,maxBuffer:10485760});return t||"No content found in XLSX"}catch(t){if(t.message.includes("command not found"))return"XLSX parsing requires ssconvert (install: apt-get install gnumeric)";throw t}}async checkDependencies(){let e=i(async t=>{try{return await ce(`which ${t}`,{timeout:1e3}),!0}catch{return!1}},"checkCommand");return{pdf:await e("pdftotext"),docx:await e("pandoc"),xlsx:await e("ssconvert")}}};import D from"fs/promises";import H from"path";import{exec as yt}from"child_process";import{promisify as xt}from"util";import Z from"os";var X=xt(yt),pe=class{static{i(this,"FileOperations")}async readFile(e){try{return await D.readFile(e,"utf-8")}catch(t){throw new Error(`Failed to read file ${e}: ${t.message}`)}}async writeFile(e,t){try{let n=!1,o;try{o=await D.readFile(e,"utf-8")}catch{n=!0}await D.mkdir(H.dirname(e),{recursive:!0}),await D.writeFile(e,t,"utf-8");let s=t.split(`
148
+ `),a=o?o.split(`
149
+ `):[],p=0,c=0;if(n)p=s.length;else{c=a.length,p=s.length;let u=new Set(a),d=new Set(s),y=a.filter(C=>!d.has(C)),h=s.filter(C=>!u.has(C));c=y.length,p=h.length}return{isNewFile:n,oldContent:o,newContent:t,linesAdded:p,linesRemoved:c,path:e}}catch(n){throw new Error(`Failed to write file ${e}: ${n.message}`)}}async listFiles(e,t=!1){try{if(t)if(Z.platform()==="win32"){let n=[],s=i(async a=>{if(!(n.length>=500))try{let p=await D.readdir(a,{withFileTypes:!0});for(let c of p){if(n.length>=500)break;let u=H.join(a,c.name);if(c.isDirectory()){let d=c.name.toLowerCase();if(d==="node_modules"||d===".git"||d==="dist"||d==="build")continue;await s(u)}else{let d=u.toLowerCase();!d.includes("node_modules")&&!d.includes(".git")&&!d.includes("dist")&&!d.includes("build")&&n.push(u)}}}catch{}},"walk");return await s(e),n.slice(0,500)}else{let{stdout:n}=await X(`find "${e}" -type f -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" -not -path "*/build/*" | head -500`,{timeout:1e4});return n.trim().split(`
150
+ `).filter(Boolean)}else return(await D.readdir(e,{withFileTypes:!0})).filter(o=>o.isFile()).map(o=>H.join(e,o.name))}catch(n){throw new Error(`Failed to list files in ${e}: ${n.message}`)}}async searchFiles(e,t){try{if(Z.platform()==="win32"){let n=[],s=i(async a=>{if(!(n.length>=100))try{let p=await D.readdir(a,{withFileTypes:!0});for(let c of p){if(n.length>=100)break;let u=H.join(a,c.name);if(c.isDirectory()){let d=c.name.toLowerCase();if(d==="node_modules"||d===".git"||d==="dist"||d==="build")continue;await s(u)}else{let d=H.extname(c.name).toLowerCase();if([".ts",".js",".tsx",".jsx",".json"].includes(d))try{(await D.readFile(u,"utf-8")).includes(t)&&n.push(u)}catch{}}}}catch{}},"searchInDirectory");return await s(e),n.slice(0,100)}else{let{stdout:n}=await X(`grep -r "${t}" "${e}" --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" --include="*.json" --exclude-dir="node_modules" --exclude-dir=".git" --exclude-dir="dist" -l | head -100`,{timeout:1e4});return n.trim().split(`
151
+ `).filter(Boolean)}}catch{return[]}}async getFileDiff(e){try{let{stdout:t}=await X(`git diff "${e}"`,{timeout:5e3});return t||"No changes"}catch(t){return`Not a git repository or file doesn't exist: ${t.message}`}}async applyPatch(e,t){try{let n=Z.tmpdir(),o=H.join(n,`patch-${Date.now()}.patch`);await D.writeFile(o,t),Z.platform()==="win32"?await X(`patch "${e}" < "${o}"`,{timeout:5e3}):await X(`patch "${e}" < "${o}"`,{timeout:5e3}),await D.unlink(o)}catch(n){throw new Error(`Failed to apply patch: ${n.message}`)}}async getFileTree(e){try{if(Z.platform()==="win32"){let n=i(async(s,a=0)=>{if(a>3)return[];let p=[];try{let c=await D.readdir(s,{withFileTypes:!0});for(let u of c){let d=" ".repeat(a),y=u.name.toLowerCase();if(!(y==="node_modules"||y===".git"||y==="dist"||y==="build"||y===".venv"||y==="venv"||y==="ios"||y==="android"||y===".expo"))if(u.isDirectory()){p.push(`${d}${u.name}/`);let h=await n(H.join(s,u.name),a+1);p.push(...h)}else p.push(`${d}${u.name}`)}}catch{}return p},"buildTree");return(await n(e)).join(`
152
+ `)}else{let{stdout:t}=await X(`tree -L 3 -I "node_modules|.git|dist|build|.venv|venv|ios|android|.expo" -a --charset ascii "${e}" 2>/dev/null || find "${e}" -maxdepth 3 -not -path "*/node_modules/*" -not -path "*/.git/*" | head -500`,{timeout:2e4});return t}}catch(t){return`Failed to generate file tree: ${t.message}`}}};import{exec as wt}from"child_process";import{promisify as Ct}from"util";var M=Ct(wt),ue=class{static{i(this,"GitOperations")}async getStatus(e){try{let{stdout:t}=await M("git status --short",{cwd:e,timeout:5e3});return t||"Working tree clean"}catch(t){return`Not a git repository: ${t.message}`}}async commit(e,t){try{await M("git add .",{cwd:e,timeout:5e3});let{stdout:n}=await M(`git commit -m "${t.replace(/"/g,'\\"')}"`,{cwd:e,timeout:1e4});return n}catch(n){return`Commit failed: ${n.message}`}}async push(e,t="origin",n){try{let o=n?` ${n}`:"",{stdout:s}=await M(`git push ${t}${o}`,{cwd:e,timeout:3e4});return s}catch(o){return`Push failed: ${o.message}`}}async pull(e,t="origin",n){try{let o=n?` ${n}`:"",{stdout:s}=await M(`git pull ${t}${o}`,{cwd:e,timeout:3e4});return s}catch(o){return`Pull failed: ${o.message}`}}async getDiff(e,t){try{let n=t?` "${t}"`:"",{stdout:o}=await M(`git diff${n}`,{cwd:e,timeout:1e4});return o||"No changes"}catch(n){return`Diff failed: ${n.message}`}}async getLog(e,t=10){try{let{stdout:n}=await M(`git log --oneline -${t}`,{cwd:e,timeout:5e3});return n}catch(n){return`Log failed: ${n.message}`}}async listBranches(e){try{let{stdout:t}=await M("git branch -a",{cwd:e,timeout:5e3});return t}catch(t){return`Branch list failed: ${t.message}`}}async createBranch(e,t){try{let{stdout:n}=await M(`git checkout -b "${t}"`,{cwd:e,timeout:5e3});return n}catch(n){return`Branch creation failed: ${n.message}`}}async switchBranch(e,t){try{let{stdout:n}=await M(`git checkout "${t}"`,{cwd:e,timeout:5e3});return n}catch(n){return`Branch switch failed: ${n.message}`}}};var Oe=i(()=>`You are a PLANNING AGENT for software development projects.
153
+
154
+ # Working Directory: ${process.cwd()}
155
+
156
+ # Your Role
157
+ Analyze user request and create actionable execution plan with 3-7 steps.
158
+
159
+ # Input
160
+ User Context: Simple description of what to build/implement
161
+ Example: "Create a todo app with Next.js" or "Add authentication to existing app"
162
+
163
+ # Output Schema
164
+ Output ONLY valid JSON (no markdown, no \`\`\`json wrapper):
165
+
166
+ \`\`\`json
167
+ {
168
+ "summary": "Brief plan description",
169
+ "steps": [
170
+ {
171
+ "step": 1,
172
+ "action": "Clear action description",
173
+ "tool": "tool_name",
174
+ "reasoning": "Why this step"
175
+ }
176
+ ],
177
+ "estimatedTime": "quick|medium|long"
178
+ }
179
+ \`\`\`
180
+
181
+ # Available Tools
182
+
183
+ **project_init:**
184
+ - command_run: Execute shell commands (npx create-*, npm init, git commands)
185
+ - install_dependencies: Install packages from package.json
186
+
187
+ **code_operations:**
188
+ - file_tree: View project structure
189
+ - file_read: Read file contents
190
+ - file_write: Create/update files
191
+ - file_delete: Remove files
192
+
193
+ **testing:**
194
+ - test_run: Execute test suite (only if System Context: Test Planning=ON)
195
+
196
+ **version_control:**
197
+ - git_commit: Commit changes with conventional message
198
+
199
+ # Planning Strategy
200
+
201
+ ## NEW Projects
202
+ \`\`\`
203
+ 1. command_run: Initialize project (create-next-app, create-vite, etc.)
204
+ 2. install_dependencies: Add required packages
205
+ 3. file_write: Core pages/components
206
+ 4. file_write: Additional features
207
+ 5. test_run: Run tests (if Test Planning=ON)
208
+ 6. git_commit: Save implementation
209
+ \`\`\`
210
+
211
+ ## ADD Features (Existing)
212
+ \`\`\`
213
+ 1. file_tree: Understand structure
214
+ 2. file_read: Check existing code (if needed)
215
+ 3. install_dependencies: Add new packages (if needed)
216
+ 4. file_write: Implement feature
217
+ 5. test_run: Verify changes (if Test Planning=ON)
218
+ 6. git_commit: Save changes
219
+ \`\`\`
220
+
221
+ # Planning Rules
222
+
223
+ 1. **Step Count**: 3-7 steps (balance detail vs simplicity)
224
+ 2. **Logical Order**: Setup \u2192 Dependencies \u2192 Implementation \u2192 Testing \u2192 Commit
225
+ 3. **System Context** (optional in input):
226
+ - Test Planning=ON \u2192 Include test_run step
227
+ - Test Planning=OFF \u2192 Skip test_run step
228
+ 4. **Time Estimates**:
229
+ - quick: 1-3 steps (<30min)
230
+ - medium: 4-6 steps (30min-2h)
231
+ - long: 7+ steps (>2h)
232
+
233
+ # Example 1: NEW Project
234
+
235
+ Input:
236
+ \`\`\`
237
+ User Context: Create a todo app with Next.js and TypeScript
238
+ \`\`\`
239
+
240
+ Output:
241
+ \`\`\`json
242
+ {
243
+ "summary": "Build Next.js todo app with TypeScript",
244
+ "steps": [
245
+ {
246
+ "step": 1,
247
+ "action": "Initialize Next.js project with TypeScript",
248
+ "tool": "command_run",
249
+ "reasoning": "Setup project foundation"
250
+ },
251
+ {
252
+ "step": 2,
253
+ "action": "Create TodoList component with CRUD operations",
254
+ "tool": "file_write",
255
+ "reasoning": "Core todo functionality"
256
+ },
257
+ {
258
+ "step": 3,
259
+ "action": "Create TodoItem component with state management",
260
+ "tool": "file_write",
261
+ "reasoning": "Individual todo UI and logic"
262
+ },
263
+ {
264
+ "step": 4,
265
+ "action": "Create main page integrating TodoList",
266
+ "tool": "file_write",
267
+ "reasoning": "App entry point"
268
+ },
269
+ {
270
+ "step": 5,
271
+ "action": "Commit changes: 'feat: initial todo app'",
272
+ "tool": "git_commit",
273
+ "reasoning": "Save implementation"
274
+ }
275
+ ],
276
+ "estimatedTime": "medium"
277
+ }
278
+ \`\`\`
279
+
280
+ # Example 2: ADD Feature
281
+
282
+ Input:
283
+ \`\`\`
284
+ User Context: Add user authentication to existing Express app
285
+ \`\`\`
286
+
287
+ Output:
288
+ \`\`\`json
289
+ {
290
+ "summary": "Add JWT authentication to Express app",
291
+ "steps": [
292
+ {
293
+ "step": 1,
294
+ "action": "Check existing project structure",
295
+ "tool": "file_tree",
296
+ "reasoning": "Understand current architecture"
297
+ },
298
+ {
299
+ "step": 2,
300
+ "action": "Install JWT and bcrypt packages",
301
+ "tool": "install_dependencies",
302
+ "reasoning": "Required for authentication"
303
+ },
304
+ {
305
+ "step": 3,
306
+ "action": "Create User model and authentication routes",
307
+ "tool": "file_write",
308
+ "reasoning": "Backend auth logic"
309
+ },
310
+ {
311
+ "step": 4,
312
+ "action": "Create authentication middleware",
313
+ "tool": "file_write",
314
+ "reasoning": "Route protection"
315
+ },
316
+ {
317
+ "step": 5,
318
+ "action": "Run tests for auth flow",
319
+ "tool": "test_run",
320
+ "reasoning": "Verify implementation (if Test Planning=ON)"
321
+ },
322
+ {
323
+ "step": 6,
324
+ "action": "Commit changes: 'feat: add JWT authentication'",
325
+ "tool": "git_commit",
326
+ "reasoning": "Save feature"
327
+ }
328
+ ],
329
+ "estimatedTime": "medium"
330
+ }
331
+ \`\`\`
332
+
333
+ # Critical Reminders
334
+ - **JSON Only**: Start with { and end with } (no markdown wrappers)
335
+ - **English Only**: All text fields in English
336
+ - **Be Specific**: Clear action descriptions (not "implement feature", but "Create TodoList component")
337
+ - **Realistic Steps**: Don't over-plan (3-7 steps max)
338
+ - **Tool Correctness**: Use appropriate tool for each step
339
+ - **Test Conditional**: Only include test_run if Test Planning=ON in input`,"planningSystemPrompt");var de=class{static{i(this,"PlanningAgent")}gemini=null;model="gemini-2.5-flash";constructor(){}getConnection(e){if(!this.gemini){let t=process.env.GOOGLE_AI_API_KEY||process.env.GEMINI_API_KEY;if(!t)throw new Error("PlanningAgent requires GOOGLE_AI_API_KEY or GEMINI_API_KEY in environment variables");this.gemini=new W({type:"gemini",model:this.model,apiKey:t},e)}return this.gemini}async generatePlan(e,t){try{let n=`User Context: ${e}`;if(t){let c=t.ba_it_analyze_response.result;n+=`
340
+
341
+ BA Analysis:
342
+ ${JSON.stringify({type:c.type,projectName:c.projectName,coreFeatures:c.coreFeatures.map(u=>u.name),technicalStack:c.technicalStack},null,2)}`}let o=Oe(),s=await this.getConnection(o).generate({prompt:n}),a=this.extractJSON(s.text);return a?JSON.parse(a):this.createFallbackPlan(e)}catch{return this.createFallbackPlan(e)}}extractJSON(e){let t=e.trim();t=t.replace(/```json\s*/g,""),t=t.replace(/```\s*/g,"");let n=t.indexOf("{");if(n===-1)return null;let o=0,s=!1,a=!1;for(let p=n;p<t.length;p++){let c=t[p];if(a){a=!1;continue}if(c==="\\"){a=!0;continue}if(c==='"'&&!a){s=!s;continue}if(!s){if(c==="{")o++;else if(c==="}"&&(o--,o===0))return t.substring(n,p+1)}}return null}createFallbackPlan(e){return{summary:"Basic implementation plan",steps:[{step:1,action:"Check project structure",status:"pending",tool:"file_tree",reasoning:"Understand existing codebase"},{step:2,action:`Implement: ${e}`,status:"pending",tool:"file_write",reasoning:"Create necessary files"},{step:3,action:"Test implementation",status:"pending",tool:"test_run",reasoning:"Verify functionality"}],estimatedTime:"medium"}}};var me=class{static{i(this,"CodeGenerateAgent")}ollama=null;model="qwen3-coder:480b-cloud";constructor(){}getConnection(){return this.ollama||(this.ollama=new U({model:this.model})),this.ollama}async execute(e){try{let t=this.buildSystemPrompt(),n=this.buildUserPrompt(e),o=await this.getConnection().generate({prompt:n,system:t,model:this.model}),s=this.parseActionPlan(o.response);return{step:e.step,featureName:e.featureName,actions:s}}catch{return{step:e.step,featureName:e.featureName,actions:[]}}}buildSystemPrompt(){return`You are an EXPERT CODE GENERATION PLANNER.
343
+
344
+ # Your Mission:
345
+ Generate a detailed action plan for implementing a feature. You do NOT execute - only plan.
346
+
347
+ # Available Actions:
348
+ 1. read_file - Read existing file for context
349
+ 2. write_file - Create/update a file
350
+ 3. run_command - Execute shell command
351
+ 4. search_files - Search for pattern in files
352
+
353
+ # Planning Guidelines:
354
+ 1. Start by reading relevant existing files
355
+ 2. Plan all necessary file writes (components, APIs, types, tests, etc.)
356
+ 3. Include dependency installations if needed
357
+ 4. Be thorough - include ALL files needed
358
+
359
+ # Code Quality Requirements:
360
+ - Production-ready, no TODOs or placeholders
361
+ - Full file content, not snippets
362
+ - Proper imports and exports
363
+ - Type safety (TypeScript)
364
+ - Error handling
365
+ - Comments for complex logic
366
+ - Follow framework best practices
367
+
368
+ # Output Format (VALID JSON ARRAY):
369
+ [
370
+ {"action": "read_file", "path": "package.json"},
371
+ {"action": "write_file", "path": "components/Feature.tsx", "content": "full content here"},
372
+ {"action": "write_file", "path": "api/feature.ts", "content": "full content here"},
373
+ {"action": "run_command", "command": "npm install new-package"}
374
+ ]
375
+
376
+ CRITICAL:
377
+ - Output ONLY the JSON array, nothing else. Start with [ and end with ]
378
+ - Include full file content in "content" field, not placeholders`}buildUserPrompt(e){let t=`# Feature Implementation Plan Request
379
+
380
+ **Feature**: ${e.featureName}
381
+ **Description**: ${e.featureDescription}
382
+ **Priority**: ${e.priority}
383
+
384
+ ## Technical Stack:
385
+ ${JSON.stringify(e.technicalStack,null,2)}
386
+ `;return e.userStories&&e.userStories.length>0&&(t+=`
387
+ ## User Stories:
388
+ `,e.userStories.forEach(n=>{t+=`- As ${n.as}, I want ${n.want}, so that ${n.so}
389
+ `})),e.dataModel&&e.dataModel.length>0&&(t+=`
390
+ ## Data Model:
391
+ ${JSON.stringify(e.dataModel,null,2)}
392
+ `),e.apiEndpoints&&e.apiEndpoints.length>0&&(t+=`
393
+ ## API Endpoints:
394
+ `,e.apiEndpoints.forEach(n=>{t+=`- ${n.method} ${n.path}: ${n.description}
395
+ `})),e.acceptanceCriteria&&e.acceptanceCriteria.length>0&&(t+=`
396
+ ## Acceptance Criteria:
397
+ `,e.acceptanceCriteria.forEach((n,o)=>{t+=`${o+1}. ${n}
398
+ `})),t+=`
399
+ ## Working Directory: ${process.cwd()}
400
+
401
+ Generate the action plan as JSON array to implement this feature completely.`,t}parseActionPlan(e){let t=e.trim();t=t.replace(/```json\s*/g,""),t=t.replace(/```\s*/g,"");let n=t.indexOf("["),o=t.lastIndexOf("]");if(n===-1||o===-1)return console.warn("Invalid action plan format - no JSON array found"),[];let s=t.substring(n,o+1);try{return JSON.parse(s).filter(p=>p.action==="read_file"||p.action==="write_file"||p.action==="run_command"||p.action==="search_files")}catch(a){return console.warn(`Failed to parse action plan: ${a}`),[]}}};import{EventEmitter as _t}from"events";var Ce=class extends _t{static{i(this,"ToolEventEmitter")}constructor(){super(),this.setMaxListeners(100)}emitToolExecution(e){let t={...e,timestamp:Date.now()};this.emit("tool-execution",t)}onToolExecution(e){return this.on("tool-execution",e),()=>this.off("tool-execution",e)}},B=new Ce;var ge=class{static{i(this,"PlanDisplay")}displayPlan(e){B.emitToolExecution({toolName:"plan_display",content:JSON.stringify(e),status:"success"});let t=`\u{1F4CB} Execution Plan: ${e.summary}
402
+ `;return t+=`Estimated Time: ${e.estimatedTime||"medium"}
403
+
404
+ `,e.steps.forEach(n=>{let o=n.status==="completed"?"\u2705":n.status==="failed"?"\u274C":n.status==="in-progress"?"\u26A1":"\u23F3";t+=`${o} Step ${n.step}: ${n.action}
405
+ `}),t}updateProgress(e){B.emitToolExecution({toolName:"progress_update",content:JSON.stringify(e),status:"success"});let n=`${e.status==="completed"?"\u2705":e.status==="failed"?"\u274C":e.status==="in-progress"?"\u26A1":"\u23F3"} Step ${e.step}: ${e.status}
406
+ `;return e.message&&(n+=` ${e.message}
407
+ `),e.filesCreated&&e.filesCreated.length>0&&(n+=` \u{1F4DD} Files created: ${e.filesCreated.join(", ")}
408
+ `),e.commandsRun&&e.commandsRun.length>0&&(n+=` \u{1F527} Commands run: ${e.commandsRun.join(", ")}
409
+ `),n}};import{execa as Ne}from"execa";var Tt="https://unpkg.com/galaxy-design@latest/dist/registry.json",ee="https://galaxy-design.vercel.app",fe={data:null,timestamp:0},St=300*1e3;async function he(){let r=Date.now();if(fe.data&&r-fe.timestamp<St)return fe.data;try{let e={Accept:"application/vnd.github.v3.raw"},t=process.env.GITHUB_TOKEN;t&&(e.Authorization=`Bearer ${t}`);let n=await fetch(Tt,{headers:e});if(!n.ok)throw new Error(`Failed to fetch registry: ${n.statusText}`);let o=await n.json();return fe={data:o,timestamp:r},o}catch(e){throw new Error(`Failed to fetch Galaxy UI registry: ${e instanceof Error?e.message:"Unknown error"}`)}}i(he,"fetchRegistry");async function $e(r){let e=await he(),t=Object.entries(e.components).map(([o,s])=>({name:o,description:s.description,category:s.type,docsUrl:`${ee}/components/${o}`})),n=r?.category&&r.category!=="all"?t.filter(o=>o.category===r.category):t;return{total:n.length,components:n}}i($e,"galaxyUIListComponents");async function je(r){let e=await he(),t=r.query.toLowerCase(),n=Object.entries(e.components).map(([o,s])=>{let a=o.toLowerCase().includes(t),p=s.description.toLowerCase().includes(t),c=s.type.toLowerCase().includes(t),u="low";a?u="high":c?u="medium":p&&(u="low");let d=a||p||c;return{name:o,description:s.description,category:s.type,docsUrl:`${ee}/components/${o}`,relevance:u,isMatch:d}}).filter(o=>o.isMatch).sort((o,s)=>{let a={high:0,medium:1,low:2};return a[o.relevance]-a[s.relevance]});return{total:n.length,components:n}}i(je,"galaxyUISearchComponents");async function De(r){let t=(await he()).components[r.name];if(!t)throw new Error(`Component "${r.name}" not found. Use galaxy_ui_list_components or galaxy_ui_search_components to find available components.`);let n=`${ee}/components/${r.name}`,o=r.framework?`${n}?framework=${r.framework}`:void 0;return{name:r.name,description:t.description,category:t.type,dependencies:t.dependencies||[],peerDependencies:t.peerDependencies||[],docsUrl:n,docsUrlFramework:o,installCommand:`npx galaxy-design add ${r.name}`}}i(De,"galaxyUIGetComponent");async function Me(){let r=await he(),e=new Map;for(let[n,o]of Object.entries(r.components)){let s=o.type;e.has(s)||e.set(s,[]),e.get(s).push(n)}return{categories:Array.from(e.entries()).map(([n,o])=>({name:n,count:o.length,components:o.sort()})).sort((n,o)=>o.count-n.count)}}i(Me,"galaxyUIGetCategories");async function Le(r){try{let e=["galaxy-design","add",...r.components];r.cwd&&e.push("--cwd",r.cwd);let t=await Ne("npx",e,{cwd:r.cwd||process.cwd(),stderr:"pipe",stdout:"pipe"});return{success:!0,message:`Successfully added components: ${r.components.join(", ")}`,output:t.stdout}}catch(e){let t=e;return{success:!1,message:`Failed to add components: ${r.components.join(", ")}`,output:t.stderr||t.stdout||"Unknown error"}}}i(Le,"galaxyUIAddComponents");async function Ue(r){try{let e=["galaxy-design@latest","init"];return r?.skipPrompts&&e.push("--yes"),r?.cwd&&e.push("--cwd",r.cwd),{success:!0,message:"Successfully initialized Galaxy UI",output:(await Ne("npx",e,{cwd:r?.cwd||process.cwd(),stderr:"pipe",stdout:"pipe"})).stdout}}catch(e){let t=e;return{success:!1,message:"Failed to initialize Galaxy UI",output:t.stderr||t.stdout||"Unknown error"}}}i(Ue,"galaxyUIInit");function Ge(r){if(r?.component){let t=r.language==="vi"?"/vi":"";return{url:`${ee}${t}/components/${r.component}`,description:`Documentation for ${r.component} component`}}let e=r?.language==="vi"?"/vi":"";return{url:`${ee}${e}`,description:"Galaxy UI CLI Documentation"}}i(Ge,"galaxyUIGetDocsUrl");var $=class{static{i(this,"ToolRegistry")}tools=new Map;fileOps=new pe;gitOps=new ue;commandRunner=new ae;baAnalyzer=new se;documentParser=new le;planningAgent=new de;codeGenerateAgent=new me;planDisplay=new ge;constructor(){this.registerAllTools()}registerAllTools(){this.register({name:"file_read",description:"Read content of a file",inputSchema:{type:"object",properties:{path:{type:"string",description:"File path to read"}},required:["path"]},execute:i(async e=>await this.fileOps.readFile(e.path),"execute")}),this.register({name:"file_write",description:"Write content to a file (creates directories if needed)",inputSchema:{type:"object",properties:{path:{type:"string",description:"File path to write"},content:{type:"string",description:"Content to write"}},required:["path","content"]},execute:i(async e=>{let t=await this.fileOps.writeFile(e.path,e.content);return JSON.stringify(t)},"execute")}),this.register({name:"file_list",description:"List files in a directory",inputSchema:{type:"object",properties:{path:{type:"string",description:"Directory path"},recursive:{type:"boolean",description:"Recursive listing",default:!1}},required:["path"]},execute:i(async e=>(await this.fileOps.listFiles(e.path,e.recursive)).join(`
410
+ `),"execute")}),this.register({name:"file_search",description:"Search for pattern in files",inputSchema:{type:"object",properties:{path:{type:"string",description:"Directory to search in"},pattern:{type:"string",description:"Pattern to search for"}},required:["path","pattern"]},execute:i(async e=>(await this.fileOps.searchFiles(e.path,e.pattern)).join(`
411
+ `)||"No matches found","execute")}),this.register({name:"file_tree",description:"Get file tree structure of a directory",inputSchema:{type:"object",properties:{path:{type:"string",description:"Directory path"}},required:["path"]},execute:i(async e=>await this.fileOps.getFileTree(e.path),"execute")}),this.register({name:"git_status",description:"Get git status of repository",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Working directory"}},required:["cwd"]},execute:i(async e=>await this.gitOps.getStatus(e.cwd||process.cwd()),"execute")}),this.register({name:"git_commit",description:"Commit changes with message",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Working directory"},message:{type:"string",description:"Commit message"}},required:["cwd","message"]},execute:i(async e=>await this.gitOps.commit(e.cwd||process.cwd(),e.message),"execute")}),this.register({name:"git_push",description:"Push commits to remote",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Working directory"},remote:{type:"string",description:"Remote name",default:"origin"},branch:{type:"string",description:"Branch name (optional)"}},required:["cwd"]},execute:i(async e=>await this.gitOps.push(e.cwd||process.cwd(),e.remote||"origin",e.branch),"execute")}),this.register({name:"git_pull",description:"Pull changes from remote",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Working directory"},remote:{type:"string",description:"Remote name",default:"origin"},branch:{type:"string",description:"Branch name (optional)"}},required:["cwd"]},execute:i(async e=>await this.gitOps.pull(e.cwd||process.cwd(),e.remote||"origin",e.branch),"execute")}),this.register({name:"git_diff",description:"Show git diff",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Working directory"},file:{type:"string",description:"Specific file (optional)"}},required:["cwd"]},execute:i(async e=>await this.gitOps.getDiff(e.cwd||process.cwd(),e.file),"execute")}),this.register({name:"git_log",description:"Show git commit history",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Working directory"},limit:{type:"number",description:"Number of commits",default:10}},required:["cwd"]},execute:i(async e=>await this.gitOps.getLog(e.cwd||process.cwd(),e.limit||10),"execute")}),this.register({name:"git_branches",description:"List all branches",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Working directory"}},required:["cwd"]},execute:i(async e=>await this.gitOps.listBranches(e.cwd||process.cwd()),"execute")}),this.register({name:"command_run",description:"Run a shell command",inputSchema:{type:"object",properties:{command:{type:"string",description:"Command to execute"},cwd:{type:"string",description:"Working directory"},timeout:{type:"number",description:"Timeout in ms",default:6e4}},required:["command","cwd"]},execute:i(async e=>{let t=await this.commandRunner.runCommand(e.command,e.cwd||process.cwd(),e.timeout||6e4);return`stdout:
412
+ ${t.stdout}
413
+
414
+ stderr:
415
+ ${t.stderr}`},"execute")}),this.register({name:"test_run",description:"Run tests in project",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Project directory"},command:{type:"string",description:"Custom test command (optional)"}},required:["cwd"]},execute:i(async e=>{let t=e.command||await this.commandRunner.detectTestCommand(e.cwd||process.cwd());if(!t)return"No test command found";let n=await this.commandRunner.runCommand(t,e.cwd||process.cwd(),12e4);return`Test Output:
416
+ ${n.stdout}
417
+
418
+ Errors:
419
+ ${n.stderr}`},"execute")}),this.register({name:"install_dependencies",description:"Install project dependencies (auto-detects package manager)",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Project directory"}},required:["cwd"]},execute:i(async e=>{let t=await this.commandRunner.installDependencies(e.cwd||process.cwd());return`Installation Output:
420
+ ${t.stdout}
421
+
422
+ Errors:
423
+ ${t.stderr}`},"execute")}),this.register({name:"ba_it_analyze",description:"Business Analyst for IT projects. Analyzes user requirements and creates comprehensive project specifications with features, tech stack, user stories, data model, and recommendations.",inputSchema:{type:"object",properties:{userRequest:{type:"string",description:"User's project request or requirement"},context:{type:"string",description:"Additional context about the project (optional)"}},required:["userRequest"]},execute:i(async e=>await this.baAnalyzer.analyze(e.userRequest,e.context),"execute")}),this.register({name:"document_parse",description:"Parse document and extract text. Supports: pdf, docx, xlsx (auto-detected from file extension)",inputSchema:{type:"object",properties:{path:{type:"string",description:"Document file path"},type:{type:"string",description:"Type: pdf, docx, xlsx (optional, auto-detected)"}},required:["path"]},execute:i(async e=>{let t=e.type?.toLowerCase();if(!t){let n=e.path.split(".").pop()?.toLowerCase();t=(n==="doc"?"docx":n==="xls"?"xlsx":n)||"docx"}return["pdf","docx","xlsx"].includes(t||"")?await this.documentParser.parseDocument(e.path,t):`Error: Unsupported document type "${t}". Supported: PDF, DOCX, XLSX`},"execute")}),this.register({name:"plan_display",description:"Display execution plans and progress updates. Emits events via EventEmitter for UI tracking.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"Plan summary"},steps:{type:"array",description:"Plan steps",items:{type:"object",properties:{step:{type:"number"},action:{type:"string"},status:{type:"string"},tool:{type:"string"},reasoning:{type:"string"}},required:["step","action","status"]}},estimatedTime:{type:"string",description:"Estimated time: quick|medium|long"}},required:["summary","steps"]},execute:i(async e=>this.planDisplay.displayPlan(e),"execute")}),this.register({name:"progress_update",description:"Update progress for execution steps. Emits events via EventEmitter for UI tracking.",inputSchema:{type:"object",properties:{step:{type:"number",description:"Step number"},status:{type:"string",description:"Step status: pending, in-progress, completed, failed"},message:{type:"string",description:"Optional status message"},filesCreated:{type:"array",description:"List of files created in this step",items:{type:"string"}},commandsRun:{type:"array",description:"List of commands executed in this step",items:{type:"string"}}},required:["step","status"]},execute:i(async e=>this.planDisplay.updateProgress(e),"execute")}),this.register({name:"code_generate",description:"Execute feature implementation with integrated tools. Generates code, writes files, runs commands automatically. Uses qwen3-coder:480b-cloud.",inputSchema:{type:"object",properties:{step:{type:"number",description:"Step number from plan"},featureName:{type:"string",description:"Feature name from coreFeatures"},featureDescription:{type:"string",description:"Feature description"},priority:{type:"string",description:"must-have | should-have | nice-to-have"},technicalStack:{type:"object",description:"Tech stack from BA analysis"},userStories:{type:"array",description:"User stories (optional)"},dataModel:{type:"array",description:"Data model entities (optional)"},apiEndpoints:{type:"array",description:"API endpoints (optional)"},acceptanceCriteria:{type:"array",description:"Acceptance criteria (optional)"}},required:["step","featureName","featureDescription","technicalStack"]},execute:i(async e=>await this.codeGenerateAgent.execute({step:e.step,featureName:e.featureName,featureDescription:e.featureDescription,priority:e.priority||"must-have",technicalStack:e.technicalStack,userStories:e.userStories,dataModel:e.dataModel,apiEndpoints:e.apiEndpoints,acceptanceCriteria:e.acceptanceCriteria}),"execute")}),this.register({name:"galaxy_ui_list",description:"List all Galaxy UI components. Optional filter by category: form, layout, navigation, interactive, overlay, data-display, utility",inputSchema:{type:"object",properties:{category:{type:"string",description:"Filter by category: form, layout, navigation, interactive, overlay, data-display, utility, all"}}},execute:i(async e=>{let t=await $e(e);return JSON.stringify(t,null,2)},"execute")}),this.register({name:"galaxy_ui_search",description:"Search Galaxy UI components by keyword in name, description, or category",inputSchema:{type:"object",properties:{query:{type:"string",description:"Search query"}},required:["query"]},execute:i(async e=>{let t=await je(e);return JSON.stringify(t,null,2)},"execute")}),this.register({name:"galaxy_ui_get_component",description:"Get detailed information about a specific Galaxy UI component including dependencies, docs URL, and install command",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name"},framework:{type:"string",description:"Framework: vue, react, angular (optional)"}},required:["name"]},execute:i(async e=>{let t=await De(e);return JSON.stringify(t,null,2)},"execute")}),this.register({name:"galaxy_ui_categories",description:"Get all Galaxy UI component categories with component counts",inputSchema:{type:"object",properties:{}},execute:i(async()=>{let e=await Me();return JSON.stringify(e,null,2)},"execute")}),this.register({name:"galaxy_ui_add",description:"Add Galaxy UI components to the project. Executes: npx galaxy-design@latest add [components...]",inputSchema:{type:"object",properties:{components:{type:"array",description:"Array of component names to add",items:{type:"string"}},cwd:{type:"string",description:"Working directory (optional)"}},required:["components"]},execute:i(async e=>{let t=await Le(e);return JSON.stringify(t,null,2)},"execute")}),this.register({name:"galaxy_ui_init",description:"Initialize Galaxy UI in the project. Executes: npx galaxy-design@latest init",inputSchema:{type:"object",properties:{cwd:{type:"string",description:"Working directory (optional)"},skipPrompts:{type:"boolean",description:"Skip prompts and use defaults (optional)"}}},execute:i(async e=>{let t=await Ue(e);return JSON.stringify(t,null,2)},"execute")}),this.register({name:"galaxy_ui_docs",description:"Get documentation URL for Galaxy UI components or main documentation",inputSchema:{type:"object",properties:{component:{type:"string",description:"Component name (optional)"},language:{type:"string",description:"Language: en or vi (optional)"}}},execute:i(async e=>{let t=Ge(e);return JSON.stringify(t,null,2)},"execute")})}register(e){if(this.tools.has(e.name))throw new Error(`Tool with name "${e.name}" is already registered.`);this.tools.set(e.name,e)}get(e){return this.tools.get(e)}list(){return[...this.tools.values()]}getToolsContext(e){return`Available Tools:
424
+ ${e.map(n=>this.tools.get(n)).map(n=>`- ${n?.name}: ${n?.description}`).join(`
425
+ `)}
426
+ `}getToolsByNames(e){return e?.map(t=>this.tools.get(t)).filter(t=>t!==void 0)||[...this.tools.values()]}async executeTool(e,t){let n=this.tools.get(e);if(!n)throw new Error(`Tool "${e}" not found in registry`);try{let o={},s=await n.execute(t,o),a=typeof s=="string"?s:JSON.stringify(s);return B.emitToolExecution({toolName:e,content:a,status:"success",toolInfo:{toolName:e,args:t,result:s}}),s}catch(o){let s=o instanceof Error?o.message:String(o);throw B.emitToolExecution({toolName:e,content:`Error: ${s}`,status:"error",error:s,toolInfo:{toolName:e,args:t}}),o}}},Fe=new $;var Et="gemini-2.5-flash",W=class{static{i(this,"GeminiConnection")}client;apiKey;chatSession;systemInstruction;model;toolsRegistry=Fe;constructor(e,t){this.apiKey=e?.apiKey,this.model=e?.model??"gemini-2.5-flash",this.client=new vt({apiKey:this.apiKey}),this.systemInstruction=t,this.initChat()}initChat(){this.chatSession=this.client.chats.create({model:this.model,config:{systemInstruction:this.systemInstruction,tools:[{functionDeclarations:this.getToolDeclarations()}],temperature:.7,thinkingConfig:{thinkingBudget:0}}})}async generate(e){let t=await this.client.models.generateContent({model:Et,contents:e.prompt});return{text:t.text??"",raw:t}}async chat(e,t){if(!this.chatSession)throw new Error("Chat session is not initialized.");let n=e,o,s=0,a=15;for(;n&&s<a;)if(s++,o=await this.chatSession.sendMessage({message:n}),o.functionCalls&&o.functionCalls.length>0){let p=[];for(let c of o.functionCalls)try{let u=c.name||"unknown",d=c.args||{},y=await this.toolsRegistry.executeTool(u,d),h=typeof y=="string"?y:JSON.stringify(y);t&&t("tool",h,u,{toolName:u,args:d,result:y}),p.push({functionResponse:{name:c.name,response:{result:h}}})}catch(u){let d=u instanceof Error?u.message:String(u);if(t){let y={toolName:c.name||"unknown",args:c.args||{},result:`\u274C Error: ${d}`};t("tool",`\u274C Error: ${d}`,c.name,y)}p.push({functionResponse:{name:c.name,response:{error:d}}})}n=p}else return o.text??"";if(s>=a)throw console.warn(`\u26A0\uFE0F Max iterations (${a}) reached. This may indicate:`),console.warn(" - Too many sequential tool calls"),console.warn(" - AI stuck in a reasoning loop"),console.warn(" - Consider reviewing system prompt or tool definitions"),new Error(`Max iterations (${a}) reached`);return""}getToolDeclarations(){return this.toolsRegistry.list().map(t=>this.convertToFunctionDeclaration(t))}convertToFunctionDeclaration(e){return{name:e.name,description:e.description,parameters:this.convertSchemaToGeminiSchema(e.inputSchema)}}convertSchemaToGeminiSchema(e){if(!e)return{type:L.OBJECT,properties:{}};let t={type:L.OBJECT,properties:{}};if(e.properties){t.properties={};for(let[n,o]of Object.entries(e.properties)){let s=o;t.properties[n]=this.convertPropertyToGeminiSchema(s)}}return e.required&&(t.required=e.required),t}convertPropertyToGeminiSchema(e){let t={type:this.mapTypeToGemini(e.type),description:e.description||""};if(e.type==="object"&&e.properties){t.properties={};for(let[n,o]of Object.entries(e.properties))t.properties[n]=this.convertPropertyToGeminiSchema(o);e.required&&(t.required=e.required)}return e.type==="array"&&(e.items&&typeof e.items=="object"?t.items=this.convertPropertyToGeminiSchema(e.items):t.items={type:L.STRING,description:""}),t}mapTypeToGemini(e){return{string:L.STRING,number:L.NUMBER,integer:L.INTEGER,boolean:L.BOOLEAN,object:L.OBJECT,array:L.ARRAY}[e.toLowerCase()]||L.STRING}};import At from"@anthropic-ai/sdk";var ye=class{static{i(this,"ClaudeConnection")}client;model;conversationHistory=[];conversationHistoryWithTools=[];systemPrompt;toolsRegistry=new $;constructor(e,t){let n=e?.apiKey;this.client=new At({apiKey:n}),this.model=e?.model||"claude-sonnet-4.5-20250929",this.systemPrompt=t}async chat(e){this.conversationHistory.push({role:"user",content:e});try{let t=await this.client.messages.create({model:this.model,max_tokens:8192,system:this.systemPrompt,messages:this.conversationHistory}),n=t.content[0]?.type==="text"?t.content[0].text:"";return this.conversationHistory.push({role:"assistant",content:n}),n}catch(t){throw console.error("Claude API Error:",t),t}}async*chatStream(e){this.conversationHistory.push({role:"user",content:e});try{let t=await this.client.messages.create({model:this.model,max_tokens:8192,system:this.systemPrompt,messages:this.conversationHistory,stream:!0}),n="";for await(let o of t)if(o.type==="content_block_delta"&&o.delta.type==="text_delta"){let s=o.delta.text||"";n+=s,yield s}this.conversationHistory.push({role:"assistant",content:n})}catch(t){throw console.error("Claude Stream Error:",t),t}}async generate(e,t){try{let n=await this.client.messages.create({model:this.model,max_tokens:8192,system:t||this.systemPrompt,messages:[{role:"user",content:e}]});return n.content[0]?.type==="text"?n.content[0].text:""}catch(n){throw console.error("Claude Generate Error:",n),n}}clearHistory(){this.conversationHistory=[]}getHistory(){return[...this.conversationHistory]}setSystemPrompt(e){this.systemPrompt=e}getModel(){return this.model}setModel(e){this.model=e}async chatWithTools(e,t,n){this.conversationHistoryWithTools.push({role:"user",content:e});let o=0,s=100;for(;o<s;){o++;let a=await this.client.messages.create({model:this.model,max_tokens:8192,system:this.systemPrompt,messages:this.conversationHistoryWithTools,tools:t});if(a.stop_reason!=="tool_use")return this.conversationHistoryWithTools.push({role:"assistant",content:a.content}),a.content.find(u=>u.type==="text")?.text||"";this.conversationHistoryWithTools.push({role:"assistant",content:a.content});let p=[];for(let c of a.content)if(c.type==="tool_use"){let u=c,d=u.name,y=u.input;if(d==="plan_task"||d==="progress_reporter")try{let h=await this.toolsRegistry.executeTool(d,y),C=typeof h=="string"?h:JSON.stringify(h);p.push({type:"tool_result",tool_use_id:u.id,content:C})}catch(h){let C=h instanceof Error?h.message:String(h);p.push({type:"tool_result",tool_use_id:u.id,content:`Error: ${C}`,is_error:!0})}else try{let h=await this.toolsRegistry.executeTool(d,y),C=typeof h=="string"?h:JSON.stringify(h);if(n){let v=!C.startsWith("\u274C");n("tool",C,d,{success:v,output:C})}p.push({type:"tool_result",tool_use_id:u.id,content:C})}catch(h){let C=h instanceof Error?h.message:String(h);n&&n("tool",`\u274C Error: ${C}`,d,{success:!1,error:C}),p.push({type:"tool_result",tool_use_id:u.id,content:`Error: ${C}`,is_error:!0})}}this.conversationHistoryWithTools.push({role:"user",content:p})}return console.warn(`\u26A0\uFE0F Safety limit (${s}) reached in Claude tool loop.`),"Maximum iteration limit reached. Please try again."}clearToolHistory(){this.conversationHistoryWithTools=[]}};function K(r){return`You are Galaxy AI - software development expert by kevinbui.
427
+
428
+ # Response Language
429
+ **Match user's language exactly** (detect from their input)
430
+
431
+ # Available Tools
432
+ ${r}
433
+
434
+ # Planning & Execution Workflow
435
+
436
+ ## When to Plan
437
+ Multi-step projects (apps, websites, features with 3+ steps) \u2192 Use planning workflow
438
+
439
+ ## Execution Loop
440
+ \`\`\`
441
+ 1. Analyze user request and create execution plan
442
+ 2. Display plan using plan_display tool
443
+ 3. Execute each step with appropriate tools
444
+ 4. Update progress using progress_update tool after each step
445
+ 5. All steps complete \u2192 Done
446
+ \`\`\`
447
+
448
+ ## Plan Display and Progress Update
449
+ **YOU MUST display plan using plan_display tool and update progress using progress_update tool.**
450
+
451
+ Example of CORRECT execution:
452
+ \`\`\`
453
+ Step 1: Display execution plan with plan_display
454
+ Step 2: command_run({command: "npx create-next-app..."})
455
+ Step 3: progress_update({step: 1, status: "completed"})
456
+ Step 4: file_write({path: "components/TodoList.tsx", content: "..."})
457
+ Step 5: progress_update({step: 2, status: "completed"})
458
+ \`\`\`
459
+
460
+ Example of WRONG execution (DO NOT DO THIS):
461
+ \`\`\`
462
+ Step 1: command_run(...) \u274C Missing plan display and progress update
463
+ Step 2: file_write(...) \u274C Missing plan display and progress update
464
+ \`\`\`
465
+
466
+ ## Example Flow
467
+ \`\`\`
468
+ User: "Create todo app with Next.js"
469
+
470
+ \u2192 Step 1: Display plan using plan_display tool
471
+ \u2192 Step 2: command_run({command: "npx create-next-app..."})
472
+ \u2192 Step 3: progress_update({step: 1, status: "completed"})
473
+ \u2192 Step 4: file_write({path: "components/TodoList.tsx", content: "..."})
474
+ \u2192 Step 5: progress_update({step: 2, status: "completed"})
475
+
476
+ ... repeat for all steps ...
477
+ \`\`\`
478
+
479
+ # Command Execution Rules
480
+
481
+ **Setup commands (create-*, npm init, etc.):**
482
+ 1. \u2705 Run ONCE with ALL default flags (--yes, --default, etc.)
483
+ 2. \u2705 Check result \u2192 Success? \u2192 STOP \u2192 Continue to file creation
484
+ 3. \u274C DON'T retry with different flags
485
+ 4. \u274C NEVER use "cd" - working directory managed automatically
486
+ 5. \u274C NEVER execute in /tmp or outside project
487
+
488
+ # Workflows
489
+
490
+ ## NEW Projects
491
+ \`\`\`
492
+ 1. Display plan using plan_display tool
493
+ 2. command_run: Setup with ALL flags \u2192 ONCE
494
+ 3. file_write: Pages, components, configs
495
+ 4. progress_update: After each major step
496
+ 5. Done: Complete functional app
497
+ \`\`\`
498
+
499
+ ## ADD Features (Existing Project)
500
+ \`\`\`
501
+ 1. Display plan using plan_display tool
502
+ 2. file_tree: Understand structure
503
+ 3. file_read: Check current code
504
+ 4. file_write: New/updated files
505
+ 5. command_run: Install deps (--yes)
506
+ 6. progress_update: After each major step
507
+ 7. Done
508
+ \`\`\`
509
+
510
+ # Detection
511
+ - **NEW**: "Create/Build/Make" + project/app/website
512
+ - **FEATURE**: "Add/Fix/Update" + mentions existing/current
513
+
514
+ # Core Rules
515
+ - **Code**: TypeScript preferred, clean, maintainable, error handling
516
+ - **Git** (if enabled): Conventional commits at logical checkpoints
517
+ - **Testing** (if enabled): Run after changes, fix failures
518
+ - **Errors**: Analyze \u2192 Try alternative approach \u2192 Explain
519
+ - **Progress**: ALWAYS display plan and update progress after completing each step
520
+
521
+ Remember: Execute commands ONCE \u2192 Check success \u2192 Build complete app!`}i(K,"buildUniversalAgentPrompt");var te=class{static{i(this,"ClaudeAgent")}connection;toolsRegistry=new $;toolNames=["file_read","file_write","file_tree","file_list","file_search","git_status","git_commit","git_push","git_pull","git_diff","git_log","git_branches","command_run","install_dependencies","test_run","document_parse","plan_display","progress_update","galaxy_ui_list","galaxy_ui_search","galaxy_ui_get_component","galaxy_ui_categories","galaxy_ui_add","galaxy_ui_init","galaxy_ui_docs"];constructor(e){let t=this.toolsRegistry.getToolsContext(this.toolNames),n=K(t);this.connection=new ye(e,n)}getAnthropicTools(){return this.toolsRegistry.getToolsByNames(this.toolNames).map(t=>({name:t.name,description:t.description,input_schema:t.inputSchema}))}async handleUserInput(e,t,n,o=0){try{let a=t?`[System Context: Git=${t.gitEnabled?"ON":"OFF"}, Test Planning=${t.testEnabled?"ON":"OFF"}]
522
+
523
+ ${e}`:e;n&&n("user",a);let p=await this.connection.chatWithTools(a,this.getAnthropicTools(),n);return n&&n("assistant",p),{content:p||"(No response)"}}catch(a){if(o<3){let p=Math.pow(2,o)*1e3;return await new Promise(c=>setTimeout(c,p)),await this.handleUserInput("Continued",t,n,o+1)}throw new Error(`Agent failed after 3 retries: ${a instanceof Error?a.message:String(a)}`)}}clearHistory(){this.connection.clearHistory(),this.connection.clearToolHistory()}};var J=class{static{i(this,"OllamaAgent")}connection;model;toolsRegistry=new $;conversationHistory=[];systemPrompt;toolNames=["file_read","file_write","file_tree","file_list","file_search","git_status","git_commit","git_push","git_pull","git_diff","git_log","git_branches","command_run","install_dependencies","test_run","plan_display","progress_update","galaxy_ui_list","galaxy_ui_search","galaxy_ui_get_component","galaxy_ui_categories","galaxy_ui_add","galaxy_ui_init","galaxy_ui_docs"];constructor(e){this.model=e?.model||"deepseek-v3.1:671b-cloud",this.connection=new U(e);let t=this.toolsRegistry.getToolsContext(this.toolNames);this.systemPrompt=K(t)}getOllamaTools(){return this.toolsRegistry.getToolsByNames(this.toolNames).map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.inputSchema}}))}async handleUserInput(e,t,n,o=0){try{let a=t?`[System Context: Git=${t.gitEnabled?"ON":"OFF"}, Test Planning=${t.testEnabled?"ON":"OFF"}]
524
+
525
+ ${e}`:e;this.conversationHistory.push({role:"user",content:a});let p=await this.connection.chatWithTools({model:this.model,messages:[{role:"system",content:this.systemPrompt},...this.conversationHistory],tools:this.getOllamaTools(),stream:!1}),c=100,u=0;for(;p.message.tool_calls&&u<c;){u++;let y=p.message.tool_calls;this.conversationHistory.push({role:"assistant",content:p.message.content||"",tool_calls:y});for(let h of y){let C=h.function.name,v=h.function.arguments;if(C==="plan_display"||C==="progress_update")try{let _=await this.toolsRegistry.executeTool(C,v),I=typeof _=="string"?_:JSON.stringify(_);this.conversationHistory.push({role:"tool",content:I}),C==="plan_display"&&this.conversationHistory.push({role:"user",content:'\u26A0\uFE0F CRITICAL: Now execute EACH step in the plan. After completing EACH step, you MUST call progress_update({step: N, status: "completed"|"failed"}). Start with step 1.'})}catch(_){let I=_ instanceof Error?_.message:String(_);this.conversationHistory.push({role:"tool",content:`Error: ${I}`})}else try{let _=await this.toolsRegistry.executeTool(C,v),I=typeof _=="string"?_:JSON.stringify(_);this.conversationHistory.push({role:"tool",content:I}),this.conversationHistory.push({role:"user",content:"\u26A0\uFE0F MANDATORY: If the tool you just executed was part of a plan step, you MUST immediately call progress_update with the step number and status (completed/failed). Do NOT skip this step."})}catch(_){let I=_ instanceof Error?_.message:String(_);this.conversationHistory.push({role:"tool",content:`Error: ${I}`}),this.conversationHistory.push({role:"user",content:'\u26A0\uFE0F MANDATORY: The tool execution failed. You MUST call progress_update with status="failed" for this step.'})}}p=await this.connection.chatWithTools({model:this.model,messages:[{role:"system",content:this.systemPrompt},...this.conversationHistory],tools:this.getOllamaTools(),stream:!1})}u>=c;let d=p.message.content||"";return this.conversationHistory.push({role:"assistant",content:d}),{content:d}}catch{if(o<3)return this.conversationHistory.length>0&&this.conversationHistory[this.conversationHistory.length-1]?.role==="user"&&this.conversationHistory.pop(),await new Promise(p=>setTimeout(p,1e5)),await this.handleUserInput("Continued",t,n,o+1);throw new Error("\u0110ang b\u1ECB l\u1ED7i. H\xE3y th\u1EED l\u1EA1i sau: ")}}clearHistory(){this.conversationHistory=[]}getHistory(){return[...this.conversationHistory]}setModel(e){this.model=e,this.connection=new U({model:e})}getModel(){return this.model}};var ne=class{static{i(this,"GeminiAgent")}connection;toolsRegistry=new $;conversationHistory=[];systemPrompt;toolNames=["file_read","file_write","file_tree","file_list","file_search","git_status","git_commit","git_push","git_pull","git_diff","git_log","git_branches","command_run","install_dependencies","test_run","document_parse","plan_display","progress_update","galaxy_ui_list","galaxy_ui_search","galaxy_ui_get_component","galaxy_ui_categories","galaxy_ui_add","galaxy_ui_init","galaxy_ui_docs"];constructor(e){let t=this.toolsRegistry.getToolsContext(this.toolNames);this.systemPrompt=K(t),this.connection=new W(e,this.systemPrompt)}async handleUserInput(e,t,n,o=0){try{let a=t?`[System Context: Git=${t.gitEnabled?"ON":"OFF"}, Test Planning=${t.testEnabled?"ON":"OFF"}]
526
+
527
+ ${e}`:e;this.conversationHistory.push({role:"user",content:a}),n&&n("user",a);let p=i((u,d,y,h)=>{if(n&&u==="tool"&&y){if(y==="plan_display"||y==="progress_update")return;let C=!d.startsWith("\u274C");n("tool",d,y,{success:C,output:h?.result||d})}},"geminiCallback"),c=await this.connection.chat(a,p);return this.conversationHistory.push({role:"assistant",content:c}),n&&n("assistant",c),{content:c||"(No response)"}}catch(a){if(o<3){this.conversationHistory.length>0&&this.conversationHistory[this.conversationHistory.length-1]?.role==="user"&&this.conversationHistory.pop();let p=Math.pow(2,o)*1e3;return await new Promise(c=>setTimeout(c,p)),await this.handleUserInput("Continued",t,n,o+1)}throw new Error(`Agent failed after 3 retries: ${a instanceof Error?a.message:String(a)}`)}}clearHistory(){this.conversationHistory=[],"clearHistory"in this.connection&&typeof this.connection.clearHistory=="function"&&this.connection.clearHistory()}getHistory(){return[...this.conversationHistory]}};import q from"node:fs";import oe from"node:path";import _e from"node:os";import{execSync as Te}from"node:child_process";var Se=class{static{i(this,"ConfigManager")}configPath;config;constructor(){this.configPath=this.getConfigPath(),this.config=this.loadConfig()}getConfigDir(){let e=_e.homedir();switch(_e.platform()){case"darwin":case"linux":return oe.join(e,".galaxy");case"win32":return oe.join(e,"AppData","Local","Galaxy");default:return oe.join(e,".galaxy")}}getConfigPath(){return oe.join(this.getConfigDir(),"config.json")}getDefaultConfig(){return{agent:[{type:"manual"}],git:!0,test:!0,autoUpdate:{enabled:!0,checkOnStartup:!0,silent:!1,maxAttempts:3,timeout:3e3,skipVersions:[],lastChecked:null,lastAttemptedVersion:null}}}loadConfig(){try{if(!q.existsSync(this.configPath))return console.log("\u{1F4DD} Creating default config at:",this.configPath),this.createDefaultConfig();let e=q.readFileSync(this.configPath,"utf-8"),t=JSON.parse(e);return this.validateConfig(t)}catch(e){return console.warn("\u26A0\uFE0F Failed to load config, using defaults:",e instanceof Error?e.message:String(e)),this.getDefaultConfig()}}validateConfig(e){let t=this.getDefaultConfig(),n=t.agent;e.agent&&Array.isArray(e.agent)&&(n=e.agent);let o={...t.autoUpdate,...e.autoUpdate||{}};return{agent:n,git:e.git??t.git,test:e.test??t.test,autoUpdate:o}}createDefaultConfig(){let e=this.getDefaultConfig();try{let t=this.getConfigDir();q.existsSync(t)||q.mkdirSync(t,{recursive:!0}),q.writeFileSync(this.configPath,JSON.stringify(e,null,2),"utf-8"),console.log("\u2705 Created default config file"),console.log("\u{1F4C1} Location:",this.configPath),console.log(""),console.log("You can customize settings by editing this file."),console.log("")}catch(t){console.error("\u274C Failed to create config file:",t instanceof Error?t.message:String(t))}return e}saveConfig(){try{let e=this.getConfigDir();q.existsSync(e)||q.mkdirSync(e,{recursive:!0}),q.writeFileSync(this.configPath,JSON.stringify(this.config,null,2),"utf-8")}catch(e){console.error("\u274C Failed to save config:",e instanceof Error?e.message:String(e))}}getMergedConfig(e={}){if(!this.config.agent||!Array.isArray(this.config.agent)||this.config.agent.length===0)return{model:"manual",git:e.git??this.config.git,test:e.test??this.config.test,agent:[],error:'Hi\u1EC7n t\u1EA1i ch\u01B0a c\xF3 agent n\xE0o \u0111\u01B0\u1EE3c c\u1EA5u h\xECnh. Vui l\xF2ng g\xF5 "galaxy --config" \u0111\u1EC3 xem file config v\xE0 th\xEAm agent.'};let t=this.config.agent.find(o=>o.type==="manual")??this.config.agent[0];if(!t)return{model:"manual",git:e.git??this.config.git,test:e.test??this.config.test,agent:this.config.agent,error:"Kh\xF4ng t\xECm th\u1EA5y agent h\u1EE3p l\u1EC7. Vui l\xF2ng ki\u1EC3m tra l\u1EA1i file c\u1EA5u h\xECnh."};let n=this.validateAgent(t);return n.error?{model:t.type,git:e.git??this.config.git,test:e.test??this.config.test,agent:this.config.agent,error:n.error}:{model:t.type,git:e.git??this.config.git,test:e.test??this.config.test,agent:this.config.agent}}validateAgent(e){if(e.type==="manual")return e.apiKey?{valid:!0}:{valid:!1,error:`Mode Manual c\u1EA7n API Key. Vui l\xF2ng:
528
+ 1. G\xF5 /config \u0111\u1EC3 m\u1EDF folder c\u1EA5u h\xECnh
529
+ 2. Th\xEAm "apiKey": "your-api-key" v\xE0o agent type "manual"
530
+ 3. Tho\xE1t CLI v\xE0 v\xE0o l\u1EA1i \u0111\u1EC3 nh\u1EADn API Key.`};if(e.type==="claude"&&!e.apiKey)return{valid:!1,error:`Hi\u1EC7n t\u1EA1i b\u1EA1n ch\u01B0a th\xEAm apikey cho model ${e.type}. Vui l\xF2ng:
531
+ 1. G\xF5 /config \u0111\u1EC3 m\u1EDF folder c\u1EA5u h\xECnh
532
+ 2. Th\xEAm "apiKey": "your-api-key" v\xE0o agent type "claude"
533
+ 3. Tho\xE1t CLI v\xE0 v\xE0o l\u1EA1i \u0111\u1EC3 nh\u1EADn API Key.`};if(e.type==="gemini"&&!e.apiKey)return{valid:!1,error:`Hi\u1EC7n t\u1EA1i b\u1EA1n ch\u01B0a th\xEAm apikey cho model ${e.type}. Vui l\xF2ng:
534
+ 1. G\xF5 /config \u0111\u1EC3 m\u1EDF folder c\u1EA5u h\xECnh
535
+ 2. Th\xEAm "apiKey": "your-api-key" v\xE0o agent type "gemini"
536
+ 3. Tho\xE1t CLI v\xE0 v\xE0o l\u1EA1i \u0111\u1EC3 nh\u1EADn API Key.`};if(e.type==="ollama"){if(!e.host)return{valid:!1,error:'Hi\u1EC7n t\u1EA1i b\u1EA1n ch\u01B0a c\xE0i \u0111\u1EB7t host cho Ollama. Vui l\xF2ng g\xF5 "galaxy --config" \u0111\u1EC3 xem file config v\xE0 th\xEAm host (v\xED d\u1EE5: "http://localhost:11434").'};if((e.host==="https://ollama.com"||e.host.includes("ollama.com"))&&!e.apiKey)return{valid:!1,error:`Hi\u1EC7n t\u1EA1i b\u1EA1n ch\u01B0a th\xEAm apikey cho model ollama. Vui l\xF2ng:
537
+ 1. G\xF5 /config \u0111\u1EC3 m\u1EDF folder c\u1EA5u h\xECnh
538
+ 2. Th\xEAm "apiKey": "your-api-key" v\xE0o agent type "ollama"
539
+ 3. Tho\xE1t CLI v\xE0 v\xE0o l\u1EA1i \u0111\u1EC3 nh\u1EADn API Key.`}}return{valid:!0}}updateConfig(e){this.config={...this.config,...e},this.saveConfig()}getConfig(){return{...this.config}}getConfigFilePath(){return this.configPath}resetConfig(){this.config=this.getDefaultConfig(),this.saveConfig(),console.log("\u2705 Config reset to defaults")}openConfigFolder(){let e=oe.dirname(this.configPath);try{let t=_e.platform();t==="darwin"?Te(`open "${e}"`):t==="win32"?Te(`start "" "${e}"`):Te(`xdg-open "${e}"`),console.log("\u2705 Opened config folder")}catch{console.log("\u274C Could not open folder automatically. Please open it manually.")}}displayConfig(){console.log(""),console.log("\u{1F4CA} Current Galaxy Configuration:"),console.log("\u2501".repeat(50)),console.log("\u{1F4C1} Config file:",this.configPath),console.log(""),console.log("Settings:"),console.log(" Agents:"),this.config.agent.forEach((e,t)=>{console.log(` ${t+1}. Type: ${e.type}${e.model?` | Model: ${e.model}`:""}`)}),console.log(" Git:",this.config.git?"ON":"OFF"),console.log(" Test:",this.config.test?"ON":"OFF"),console.log("\u2501".repeat(50)),console.log(""),this.openConfigFolder()}},G=new Se;import l from"react";import{Box as S,Text as g}from"ink";var It=i(()=>{let r=process.stdout?.columns;return typeof r=="number"&&Number.isFinite(r)?r:80},"getTerminalWidth"),xe=i((r,e)=>r.length<=e?r:r.slice(0,e-3)+"...","truncateLine");function Pt(r,e){let t=r.split(`
540
+ `),n=e.split(`
541
+ `),o=[],s=0,a=0;for(;s<t.length||a<n.length;){let p=t[s],c=n[a];p===c?(o.push({type:"context",oldLineNum:s+1,newLineNum:a+1,content:p||""}),s++,a++):s<t.length&&p!==void 0&&!n.includes(p)?(o.push({type:"remove",oldLineNum:s+1,content:p||""}),s++):a<n.length&&c!==void 0&&!t.includes(c)?(o.push({type:"add",newLineNum:a+1,content:c||""}),a++):(s<t.length&&(o.push({type:"remove",oldLineNum:s+1,content:p||""}),s++),a<n.length&&(o.push({type:"add",newLineNum:a+1,content:c||""}),a++))}return o}i(Pt,"generateDiff");function kt(r,e=2){let t=[],n=0;for(;n<r.length;){let o=r[n];if(o&&o.type!=="context")t.push(o),n++;else{let s=n,a=n;for(;a<r.length&&r[a]?.type==="context";)a++;let p=a-s;if(p<=e*2)for(let c=s;c<a;c++)r[c]&&t.push(r[c]);else{for(let u=s;u<s+e;u++)r[u]&&t.push(r[u]);let c=p-e*2;t.push({type:"context",content:`... ${c} unchanged lines ...`});for(let u=a-e;u<a;u++)r[u]&&t.push(r[u])}n=a}}return t}i(kt,"compressDiff");function Ot(r){try{let e=JSON.parse(r);if(e.steps&&Array.isArray(e.steps))return l.createElement(S,{flexDirection:"column"},l.createElement(g,{bold:!0,color:"cyan"},"\u{1F4CB} Execution Plan: ",e.summary),e.steps.map((t,n)=>{let o=t.status==="completed"?"\u2705":t.status==="failed"?"\u274C":t.status==="in-progress"?"\u26A1":"\u23F3";return l.createElement(S,{key:n,marginLeft:2},l.createElement(g,{color:t.status==="completed"?"green":t.status==="failed"?"red":"gray"},o," Step ",t.step,": ",t.action))}))}catch{let e=r.split(`
542
+ `),t=[];for(let n of e){let o=n.trim();o.match(/^[☒✓✅-]\s*\[x\]\s*/i)?t.push({completed:!0,text:o.replace(/^[☒✓✅-]\s*\[x\]\s*/i,"")}):o.match(/^[☐-]\s*\[\s*\]\s*/)?t.push({completed:!1,text:o.replace(/^[☐-]\s*\[\s*\]\s*/,"")}):o.match(/^[-*•]\s+/)&&t.push({completed:!1,text:o.replace(/^[-*•]\s+/,"")})}if(t.length>0)return l.createElement(S,{flexDirection:"column"},l.createElement(g,{bold:!0,color:"cyan"},"\u{1F4CB} Execution Plan"),t.map((n,o)=>l.createElement(S,{key:o,marginLeft:2},l.createElement(g,{color:n.completed?"green":"gray"},n.completed?"\u2612":"\u2610"," ",n.text))))}return l.createElement(g,null,r)}i(Ot,"formatTodos");function Nt(r,e){let t=r.split(`
543
+ `),n=[],o=1;for(let s=0;s<t.length;s++){let a=t[s]||"";if(a.startsWith("---")||a.startsWith("+++")){n.push(l.createElement(S,{key:s},l.createElement(g,{bold:!0,color:"cyan"},a)));continue}if(a.startsWith("@@")){n.push(l.createElement(S,{key:s},l.createElement(g,{bold:!0,color:"magenta"},a)));continue}if(a.startsWith("-")){n.push(l.createElement(S,{key:s},l.createElement(g,{dimColor:!0},String(o).padStart(4," ")),l.createElement(g,{color:"red"},` ${a}`))),o++;continue}if(a.startsWith("+")){n.push(l.createElement(S,{key:s},l.createElement(g,{dimColor:!0},String(o).padStart(4," ")),l.createElement(g,{color:"green"},` ${a}`))),o++;continue}n.push(l.createElement(S,{key:s},l.createElement(g,{dimColor:!0},String(o).padStart(4," ")),l.createElement(g,null,` ${a}`))),o++}return l.createElement(S,{flexDirection:"column"},e&&l.createElement(g,{bold:!0,color:"yellow"},`\u{1F4DD} ${e}`),n)}i(Nt,"formatDiff");function $t(r){let e=/```(\w+)?\n([\s\S]*?)```/g,t=[],n=0,o,s=0;for(;(o=e.exec(r))!==null;){o.index>n&&t.push(l.createElement(g,{key:`text-${s}`},r.slice(n,o.index)));let a=o[1]||"text",p=o[2];t.push(l.createElement(S,{key:`code-${s}`,flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1},l.createElement(g,{dimColor:!0},a),l.createElement(g,{color:"cyan"},p))),n=o.index+o[0].length,s++}return n<r.length&&t.push(l.createElement(g,{key:`text-${s}`},r.slice(n))),l.createElement(S,{flexDirection:"column"},t)}i($t,"formatCode");var jt=i((r,e)=>{let t=0,n="current directory";return e?.args?.path&&(n=e?.args.path),r&&(t=r.split(`
544
+ `).filter(s=>{let a=s.trim();return a&&!a.startsWith("Failed")}).length),l.createElement(S,{flexDirection:"column"},l.createElement(g,{bold:!0,color:"cyan"},"\u{1F4C1} LIST DIRECTORY ",l.createElement(g,{color:"gray"},"(",n,")")),l.createElement(S,{marginLeft:1},l.createElement(g,{color:"green"},"\u21B3 Listed ",t," items.")))},"formatFileTree"),Dt=i((r,e)=>{let t=0,n="file";if(e?.args?.path){let o=e.args.path.split("/");n=o[o.length-1]||e.args.path}return r&&(t=r.split(`
545
+ `).length),l.createElement(S,{flexDirection:"column"},l.createElement(g,{bold:!0,color:"cyan"},"\u{1F4C4} READ ",l.createElement(g,{color:"gray"},"(",n,")")),l.createElement(S,{marginLeft:1},l.createElement(g,{color:"green"},"\u21B3 Read ",t," lines.")))},"formatFileRead"),Mt=i((r,e)=>{let t="file",n=null;try{n=JSON.parse(r)}catch{e?.args?.content&&(n={isNewFile:!0,newContent:e.args.content,linesAdded:e.args.content.split(`
546
+ `).length,linesRemoved:0,path:e.args.path})}if(!n)return l.createElement(g,{wrap:"wrap"},r);if(n.path){let h=n.path.split("/");t=h[h.length-1]||n.path}let{isNewFile:o,oldContent:s,newContent:a,linesAdded:p,linesRemoved:c}=n,u=o?`Succeeded. File created. (+${p} added)`:`Succeeded. File edited. (+${p} added, -${c} removed)`,d=It(),y=d-15;if(o){let h=[],C=a.split(`
547
+ `),v=10;return(C.length>v?C.slice(0,v):C).forEach((I,k)=>{let E=xe(I,y);h.push(l.createElement(S,{key:k},l.createElement(g,{dimColor:!0},String(k+1).padStart(4," ")),l.createElement(g,{color:"green"},` + ${E}`)))}),C.length>v&&h.push(l.createElement(S,{key:"truncated"},l.createElement(g,{dimColor:!0},"... (",C.length-v," more lines)"))),l.createElement(S,{flexDirection:"column",width:d-2},l.createElement(g,{bold:!0,color:"cyan"},"\u{1F4DD} APPLY PATCH ",l.createElement(g,{color:"gray"},"(",t,")")),l.createElement(S,{marginLeft:1,marginBottom:1},l.createElement(g,{color:"green"},"\u21B3 ",u)),l.createElement(S,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,paddingY:0,width:d-4},h))}else{let h=Pt(s||"",a),C=kt(h,2),v=[];return C.forEach((_,I)=>{if(_.content.startsWith("...")&&_.content.includes("unchanged"))v.push(l.createElement(S,{key:I},l.createElement(g,{dimColor:!0},_.content)));else if(_.type==="add"){let k=xe(_.content,y);v.push(l.createElement(S,{key:I},l.createElement(g,{dimColor:!0}," ".padStart(4," ")),l.createElement(g,{dimColor:!0},"|"),l.createElement(g,{dimColor:!0},String(_.newLineNum).padStart(4," ")),l.createElement(g,{color:"green"},` + ${k}`)))}else if(_.type==="remove"){let k=xe(_.content,y);v.push(l.createElement(S,{key:I},l.createElement(g,{dimColor:!0},String(_.oldLineNum).padStart(4," ")),l.createElement(g,{dimColor:!0},"|"),l.createElement(g,{dimColor:!0}," ".padStart(4," ")),l.createElement(g,{color:"red"},` - ${k}`)))}else{let k=xe(_.content,y);v.push(l.createElement(S,{key:I},l.createElement(g,{dimColor:!0},String(_.oldLineNum).padStart(4," ")),l.createElement(g,{dimColor:!0},"|"),l.createElement(g,{dimColor:!0},String(_.newLineNum).padStart(4," ")),l.createElement(g,null,` ${k}`)))}}),v.length>30&&(v.splice(30),v.push(l.createElement(S,{key:"truncated"},l.createElement(g,{dimColor:!0},"... (diff truncated for display)")))),l.createElement(S,{flexDirection:"column",width:d-2},l.createElement(g,{bold:!0,color:"cyan"},"\u{1F4DD} APPLY PATCH ",l.createElement(g,{color:"gray"},"(",t,")")),l.createElement(S,{marginLeft:1,marginBottom:1},l.createElement(g,{color:"green"},"\u21B3 ",u)),l.createElement(S,{flexDirection:"column",borderStyle:"round",borderColor:"gray",paddingX:1,paddingY:0,width:d-4},v))}},"formatFileWrite"),Lt=i((r,e)=>{let t=!0,n=0,o="command";if(e?.args?.command&&(o=e.args.command),r){let c=r.match(/stdout:\n([\s\S]*?)\n\nstderr:/),u=r.match(/stderr:\n([\s\S]*)/);if(c&&c[1]&&(n=c[1].split(`
548
+ `).filter(y=>y.trim()).length),u&&u[1]){let d=u[1].trim();d&&d.toLowerCase().includes("error")&&(t=!1)}(r.toLowerCase().includes("command not found")||r.toLowerCase().includes("no such file")||r.toLowerCase().includes("permission denied"))&&(t=!1)}return l.createElement(S,{flexDirection:"column"},l.createElement(g,{bold:!0,color:"cyan"},"\u26A1 EXECUTE ",l.createElement(g,{color:"gray"},"(",o,")")),l.createElement(S,{marginLeft:1},l.createElement(g,{color:t?"green":"red"},"\u21B3 ",t?"\u2713":"\u2717"," ",t?"Success":"Failed",". Output: ",n," lines.")))},"formatCommandRun"),Ut=i(r=>r?r.replace(/^galaxy:/,""):"","normalizeToolName");function Re(r,e,t){let n=Ut(e),o=typeof r=="string"?r:JSON.stringify(r,null,2);switch(n){case"file_tree":return jt(o,t);case"file_read":return Dt(o,t);case"file_write":return Mt(o,t);case"command_run":return Lt(o,t);case"plan_task":return null;case"progress_reporter":return null;case"plan_display":return null;case"progress_update":return null;case"todos":return Ot(o);case"diff":return Nt(o,e);case"code":return $t(o);default:return l.createElement(g,{wrap:"wrap"},o)}}i(Re,"formatMessage");var qe="0.1.7",Jt=i(()=>{let r=Y.stdout?.columns;return typeof r=="number"&&Number.isFinite(r)?r:80},"getTerminalWidth"),Vt=i((r,e)=>{let t=r.replace(/\s+$/u,"");if(!t)return"";let n=Math.max(0,Math.floor((e-t.length)/2));return`${" ".repeat(n)}${t}`},"centerLine"),Xt=i(r=>{let e=Jt(),t=r.model;return[{id:"version",text:qe},{id:"hints",text:"ENTER to send \u2022 \\ + ENTER for a new line "},{id:"cwd",text:`Current folder: ${Y.cwd()}`},{id:"config",text:`Agent=${t} Git=${r.git?"ON":"OFF"} Test=${r.test?"ON":"OFF"}`}].map(o=>({id:o.id,text:Vt(o.text,e-50)}))},"getInforLines"),Kt=Wt.textSync("GALAXY",{font:"Standard",horizontalLayout:"default",verticalLayout:"default"});function be({config:r}){let{exit:e}=Rt(),[t,n]=F(""),[o,s]=F([{id:"banner"},...r.error?[{id:"config-error",author:"system",content:`\u26A0\uFE0F ${r.error}`,timestamp:Date.now()}]:[]]),[a,p]=F(!1),[c,u]=F([]),[d,y]=F([]),[h,C]=F([]),[v,_]=F(-1),[I,k]=F(0),[E,z]=F(r),Qe=Xt(E),Q=Be(()=>{if(E.model==="manual"){let f=E.agent.find(x=>x.type==="manual");return new J({type:"ollama",model:"qwen3-coder:480b-cloud",host:"https://ollama.com",apiKey:f?.apiKey})}let m=E.agent.find(f=>f.type===E.model);if(!m)return null;switch(E.model){case"claude":return new te(m);case"ollama":return new J(m);case"gemini":return new ne(m);default:return null}},[E.model,E.agent]),Ae=Be(()=>[{command:"/help",description:"Hi\u1EC3n th\u1ECB danh s\xE1ch l\u1EC7nh"},{command:"/exit",description:"Tho\xE1t kh\u1ECFi Galaxy CLI"},{command:"/clear",description:"X\xF3a l\u1ECBch s\u1EED h\u1ED9i tho\u1EA1i hi\u1EC7n t\u1EA1i"},{command:"/history",description:"Xem danh s\xE1ch 10 input g\u1EA7n nh\u1EA5t"},{command:"/pwd",description:"Hi\u1EC3n th\u1ECB th\u01B0 m\u1EE5c l\xE0m vi\u1EC7c hi\u1EC7n t\u1EA1i"},{command:"/information",description:"Hi\u1EC3n th\u1ECB th\xF4ng tin h\u1EC7 th\u1ED1ng"},{command:"/git",description:"B\u1EADt/t\u1EAFt git operations (/git true|false)"},{command:"/test",description:"B\u1EADt/t\u1EAFt test planning (/test true|false)"},{command:"/mode",description:"Ch\u1ECDn agent mode (/mode claude|gemini|ollama|manual)"},{command:"/config",description:"M\u1EDF th\u01B0 m\u1EE5c ch\u1EE9a file c\u1EA5u h\xECnh"}],[]);Gt(()=>{let m=B.onToolExecution(f=>{if(f.toolName==="plan_display"&&f.status==="success"&&f.toolInfo?.result)try{let w=f.toolInfo.result;if(w.steps&&Array.isArray(w.steps)){let A=w.steps.map((O,R)=>({step:O.step,action:O.action,status:R===0?"in-progress":"pending"}));y(A)}}catch{}if(f.toolName==="progress_update")try{let w=JSON.parse(f.content),A=w.step,O=w.status,R=O==="completed"?"completed":O==="failed"?"failed":"in-progress";y(N=>N.map(V=>V.step===A?{...V,status:R}:O==="completed"&&V.step===A+1&&V.status==="pending"?{...V,status:"in-progress"}:V))}catch{}let x={id:`tool-${Date.now()}-${Math.random()}`,author:"tool",toolName:f.toolName,content:f.content,toolInfo:f.toolInfo,timestamp:f.timestamp};s(w=>[...w,x])});return()=>{m()}},[]);let Ze=i(m=>{let[f,...x]=m.slice(1).split(/\s+/);switch(f){case"exit":b("system","Goodbye!"),e();return;case"help":b("system",["Danh s\xE1ch l\u1EC7nh:",...Ae.map(w=>`${w.command.padEnd(15," ")} ${w.description}`)].join(`
549
+ `));return;case"clear":s([{id:"banner"}]),y([]),Q&&"clearHistory"in Q&&Q.clearHistory(),b("system","\u2705 Cleared conversation and progress");return;case"history":if(h.length===0){b("system","No history yet.");return}{let A=[...h].slice(-10).reverse().map((O,R)=>`${R+1}. ${O.replace(/\n/g," ")}`);b("system",["Recent inputs:",...A].join(`
550
+ `))}return;case"pwd":b("system",`Working directory: ${Y.cwd()}`);return;case"information":{let w=E.model;b("system",["\u{1F4CA} System Information:","Name: Galaxy CLI",`Version: ${qe}`,`Current Project: ${Y.cwd()}`,`Agent Mode: ${w}`,`Git Operations: ${E.git?"ON":"OFF"}`,`Testing: ${E.test?"ON":"OFF"}`].join(`
551
+ `))}return;case"mode":{if(x.length===0){let N=E.model;E.model==="manual"?b("system",`\u{1F916} Agent Mode: ${N}
552
+
553
+ Using Orchestrator Agent with full tool access.`):b("system",`\u{1F916} Agent Mode: ${N}
554
+
555
+ Direct chat mode - no tools available.`);return}let w=x[0]?.toLowerCase()??"",A=["claude","gemini","ollama","manual"];if(!i(N=>A.includes(N),"isValidMode")(w)){b("system",`\u274C Invalid mode: ${w}
556
+ Valid modes: ${A.join(", ")}`);return}if(!E.agent.find(N=>N.type===w)){b("system",`\u274C Agent config for "${w}" not found in config file.
557
+ Please add it using /config command.`);return}z(N=>({...N,model:w})),s([{id:"banner"}]),y([]),b("system",`\u2705 Switched to ${w} mode
558
+ \u{1F504} Conversation cleared`)}return;case"git":if(x.length===0){b("system",`Git operations are currently ${E.git?"ON":"OFF"}`);return}{let w=x[0]?.toLowerCase()??"";w==="true"||w==="on"?(z(A=>({...A,git:!0})),b("system","\u2705 Git operations enabled")):w==="false"||w==="off"?(z(A=>({...A,git:!1})),b("system","\u274C Git operations disabled")):b("system","Usage: /git true|false")}return;case"test":if(x.length===0){b("system",`Testing is currently ${E.test?"ON":"OFF"}`);return}{let w=x[0]?.toLowerCase()??"";w==="true"||w==="on"?(z(A=>({...A,test:!0})),b("system","\u2705 Test planning enabled")):w==="false"||w==="off"?(z(A=>({...A,test:!1})),b("system","\u274C Test planning disabled")):b("system","Usage: /test true|false")}return;case"config":{let w=G.getConfigFilePath();G.openConfigFolder(),b("system",`\u{1F4C2} Config directory opened
559
+ \u{1F4C4} Config file: ${w}`)}return;default:b("system",`Unknown command: /${f}${x.length?" "+x.join(" "):""}`)}},"handleCommand"),Ie=i(async m=>{if(a)return;let f=m.trim();if(f){if(f.startsWith("/")){n(""),Ze(f);return}b("user",f),p(!0),n(""),C(x=>[...x,f]),_(-1);try{let x="";if(!Q)throw new Error("Agent connection not initialized");x=(await Q.handleUserInput(f,{gitEnabled:E.git,testEnabled:E.test},b)).content,x&&b("assistant",x)}catch(x){b("system",`\u274C Error: ${x instanceof Error?x.message:String(x)}`)}finally{p(!1)}}},"handleSubmit");Bt((m,f)=>{if(f.ctrl&&m==="c"&&e(),c.length>0&&t.startsWith("/")){f.upArrow||f.shift&&f.tab?k(x=>(x-1+c.length)%c.length):f.downArrow||f.tab?k(x=>(x+1)%c.length):(f.escape||f.return)&&(u([]),k(0));return}if(h.length>0&&!t.startsWith("/")){if(f.upArrow){let x=v===-1?h.length-1:Math.max(0,v-1);_(x),n(h[x]||"")}else if(f.downArrow){if(v===-1)return;let x=v+1;x>=h.length?(_(-1),n("")):(_(x),n(h[x]||""))}}});let b=i((m,f,x,w)=>{let A={id:`${Date.now()}-${m}-${Math.random().toString(16).slice(2)}`,author:m,content:f,toolName:x,toolInfo:w,timestamp:Date.now()};if(m==="tool"&&x==="plan_display"){let O=f.map((R,N)=>({...R,status:N===0?"in-progress":"pending"}));y(O),E.model}else s(O=>[...O,A])},"appendMessage"),Pe=d.find(m=>m.status==="in-progress");return T.createElement(T.Fragment,null,T.createElement(Ft,{items:o},m=>m.author==="user"?T.createElement(P,{key:m.id,flexDirection:"row",marginTop:1},T.createElement(j,{color:"red"},`> ${m.content}`)):m.author==="assistant"?T.createElement(P,{key:m.id,flexDirection:"column",marginTop:1,borderStyle:"round",borderColor:"blue",paddingX:1,paddingY:0},T.createElement(j,null,m.content)):m.author==="tool"?T.createElement(P,{key:m.id,flexDirection:"row",marginTop:1},Re(m.content||"",m.toolName,m.toolInfo)):m.author==="system"?T.createElement(P,{key:m.id,flexDirection:"row",marginTop:1},T.createElement(j,{color:"gray"},`\u2699 ${m.content}`)):T.createElement(P,{borderColor:"cyan",borderStyle:"round",flexDirection:"row",key:"banner-box",width:Y.stdout.columns},T.createElement(P,{flexDirection:"column"},T.createElement(j,{color:"cyan"},Kt)),T.createElement(P,{borderLeft:!0,borderLeftColor:"cyan",flexDirection:"column",marginLeft:2,marginTop:1},Qe.map(f=>T.createElement(j,{key:f.id,dimColor:!0},f.text))))),E.model==="manual"&&d.length>0&&T.createElement(P,{flexDirection:"column",paddingTop:1,paddingBottom:1},Pe&&T.createElement(P,{marginBottom:1},T.createElement(j,{bold:!0,color:"cyan"},"\u26A1 ",Pe.action)),d.map(m=>{let f=m.status==="completed"?"\u2611":m.status==="in-progress"?"\u2699":m.status==="failed"?"\u274C":"\u2610",x=m.status==="completed"?"green":m.status==="in-progress"?"cyan":m.status==="failed"?"red":"gray";return T.createElement(P,{key:m.step},T.createElement(j,{color:x},f," Step ",m.step,": ",m.action))})),T.createElement(P,{flexDirection:"row",paddingTop:1,width:Y.stdout.columns},a?T.createElement(j,null,T.createElement(j,{color:"cyan"},T.createElement(Ht,{type:"dots"}))," Thinking..."):null),T.createElement(P,{borderColor:"green",borderStyle:"round",flexDirection:"column",marginTop:1},T.createElement(P,{alignItems:"center",flexDirection:"row"},T.createElement(j,{color:"green"},"> "),T.createElement(qt,{value:t,showCursor:!a,onChange:a?()=>{}:m=>{if(n(m),m.startsWith("/")){let f=m.toLowerCase(),x=Ae.filter(w=>w.command.toLowerCase().startsWith(f));u(x),k(0)}else u([]),k(0)},onSubmit:a?()=>{}:m=>{if(m.trim().startsWith("/")&&c.length>0){let x=c[I]??c[0];Ie(x?.command||"");return}Ie(m)},placeholder:a?"Processing... (input disabled)":"Type and press Enter to send"}))),c.length>0&&T.createElement(P,{flexDirection:"column",marginTop:1,borderStyle:"round",borderColor:"gray"},c.map((m,f)=>T.createElement(P,{key:m.command,paddingX:1,paddingY:0,flexDirection:"row"},T.createElement(j,{color:f===I?"cyan":void 0},m.command.padEnd(15," ")),T.createElement(j,{dimColor:!0},m.description)))))}i(be,"App");import Yt from"semver";import{readFileSync as zt}from"node:fs";import{fileURLToPath as Qt}from"node:url";import{dirname as Zt,join as en}from"node:path";var tn=Qt(import.meta.url),nn=Zt(tn);function on(){try{let r=en(nn,"../package.json");return JSON.parse(zt(r,"utf-8")).version}catch{return"0.1.0"}}i(on,"getCurrentVersion");async function rn(r="galaxy-code",e=3e3){try{let t=new AbortController,n=setTimeout(()=>{t.abort()},e),o=await fetch(`https://registry.npmjs.org/${r}/latest`,{signal:t.signal,headers:{Accept:"application/json"}});return clearTimeout(n),o.ok?(await o.json()).version:null}catch(t){return t instanceof Error&&t.name!=="AbortError"&&console.debug("Failed to fetch latest version:",t.message),null}}i(rn,"fetchLatestVersion");async function He(r=3e3){try{let e=on(),t=await rn("galaxy-code",r);if(!t)return null;let n=Yt.gt(t,e);return{hasUpdate:n,currentVersion:e,latestVersion:t,updateAvailable:n}}catch(e){return console.debug("Error checking for update:",e),null}}i(He,"checkForUpdate");function We(r,e){return e.includes(r)}i(We,"shouldSkipVersion");import{execSync as sn,spawn as an}from"node:child_process";import{existsSync as ve,writeFileSync as cn,unlinkSync as ln}from"node:fs";import{tmpdir as Je}from"node:os";import{join as Ve}from"node:path";function pn(){let r=Ve(Je(),"galaxy-code-update.lock");return cn(r,Date.now().toString()),r}i(pn,"createLockFile");function Ee(r){try{ve(r)&&ln(r)}catch{}}i(Ee,"removeLockFile");function un(){let r=Ve(Je(),"galaxy-code-update.lock");if(!ve(r))return!1;try{let e=Number.parseInt(ve(r)?"":"0",10),t=Date.now(),n=300*1e3;return t-e>n?(Ee(r),!1):!0}catch{return!1}}i(un,"isUpdateInProgress");function dn(r){let e=r.message.toLowerCase();return e.includes("eacces")||e.includes("permission")||e.includes("eperm")}i(dn,"isPermissionError");async function Xe(r){if(un())return{success:!1,error:"\u0110ang c\xF3 process kh\xE1c \u0111ang c\u1EADp nh\u1EADt..."};let e=pn();try{let t=`npm install -g galaxy-code@${r}`;return sn(t,{stdio:"pipe",timeout:6e4}),Ee(e),{success:!0,needsRestart:!0}}catch(t){return Ee(e),t instanceof Error?dn(t)?{success:!1,error:`C\u1EA7n quy\u1EC1n admin \u0111\u1EC3 c\u1EADp nh\u1EADt. Vui l\xF2ng ch\u1EA1y:
560
+ sudo npm install -g galaxy-code@${r}`}:{success:!1,error:`C\u1EADp nh\u1EADt th\u1EA5t b\u1EA1i: ${t.message}`}:{success:!1,error:"C\u1EADp nh\u1EADt th\u1EA5t b\u1EA1i v\u1EDBi l\u1ED7i kh\xF4ng x\xE1c \u0111\u1ECBnh"}}}i(Xe,"performUpdate");function Ke(){let r=process.argv.slice(2);an("galaxy-code",r,{detached:!0,stdio:"inherit"}).unref(),process.exit(0)}i(Ke,"restartCLI");function Ye(r){console.log(""),console.log(`\u2705 \u0110\xE3 c\u1EADp nh\u1EADt l\xEAn phi\xEAn b\u1EA3n ${r} th\xE0nh c\xF4ng!`),console.log("")}i(Ye,"showUpdateSuccess");function ze(r){console.log(""),console.log("\u26A0\uFE0F Kh\xF4ng th\u1EC3 c\u1EADp nh\u1EADt t\u1EF1 \u0111\u1ED9ng"),console.log(r),console.log(""),console.log("\u0110ang ti\u1EBFp t\u1EE5c v\u1EDBi phi\xEAn b\u1EA3n hi\u1EC7n t\u1EA1i..."),console.log("")}i(ze,"showUpdateError");var re=fn(`
561
+ C\xE1ch s\u1EED d\u1EE5ng
562
+ $ galaxy [t\xF9y ch\u1ECDn]
563
+
564
+ T\xF9y ch\u1ECDn
565
+ --help Hi\u1EC3n th\u1ECB tr\u1EE3 gi\xFAp
566
+ --version Hi\u1EC3n th\u1ECB phi\xEAn b\u1EA3n
567
+ --git B\u1EADt git operations (m\u1EB7c \u0111\u1ECBnh: t\u1EEB config)
568
+ --test B\u1EADt test planning (m\u1EB7c \u0111\u1ECBnh: t\u1EEB config)
569
+ --config Hi\u1EC3n th\u1ECB c\u1EA5u h\xECnh hi\u1EC7n t\u1EA1i
570
+ --reset-config \u0110\u1EB7t l\u1EA1i c\u1EA5u h\xECnh v\u1EC1 m\u1EB7c \u0111\u1ECBnh
571
+ --dev B\u1EADt ch\u1EBF \u0111\u1ED9 ph\xE1t tri\u1EC3n v\u1EDBi DevTools
572
+ --no-auto-update T\u1EAFt auto-update khi kh\u1EDFi \u0111\u1ED9ng
573
+
574
+ V\xED d\u1EE5
575
+ $ galaxy
576
+ $ galaxy --test
577
+ $ galaxy --config
578
+ $ galaxy --reset-config
579
+ $ galaxy --dev # B\u1EADt DevTools
580
+
581
+ C\u1EA5u h\xECnh
582
+ V\u1ECB tr\xED file c\u1EA5u h\xECnh theo h\u1EC7 \u0111i\u1EC1u h\xE0nh:
583
+ - macOS/Linux: ~/.galaxy/config.json
584
+ - Windows: %LOCALAPPDATA%\\Galaxy\\config.json
585
+
586
+ Th\u1EE9 t\u1EF1 \u01B0u ti\xEAn: Tham s\u1ED1 CLI > config.json > m\u1EB7c \u0111\u1ECBnh
587
+
588
+ `,{importMeta:import.meta,flags:{git:{type:"boolean"},test:{type:"boolean"},config:{type:"boolean",default:!1},resetConfig:{type:"boolean",default:!1},dev:{type:"boolean",default:!1},noAutoUpdate:{type:"boolean",default:!1}}});async function hn(){let r=G.getConfig(),e=r.autoUpdate;if(!e.enabled||!e.checkOnStartup||re.flags.noAutoUpdate)return!1;try{let t=await He(e.timeout);if(!t||!t.hasUpdate||We(t.latestVersion,e.skipVersions))return!1;e.silent||(console.log(""),console.log(`\u{1F680} Ph\xE1t hi\u1EC7n phi\xEAn b\u1EA3n m\u1EDBi ${t.latestVersion}, \u0111ang c\u1EADp nh\u1EADt...`),console.log(""));let n=await Xe(t.latestVersion);if(n.success){if(Ye(t.latestVersion),G.updateConfig({...r,autoUpdate:{...e,lastChecked:Date.now(),lastAttemptedVersion:t.latestVersion}}),n.needsRestart)return Ke(),!0}else n.error&&ze(n.error)}catch(t){console.debug("Auto-update failed:",t)}return!1}i(hn,"handleAutoUpdate");(async()=>{if(re.flags.config&&(G.displayConfig(),process.exit(0)),re.flags.resetConfig&&(G.resetConfig(),process.exit(0)),await hn())return;let e=G.getMergedConfig({git:re.flags.git,test:re.flags.test});gn(mn.createElement(be,{config:e}))})();