vg-coder-cli 1.0.16 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/PUBLISHING.md +86 -0
- package/README.md +92 -318
- package/SYSTEM_PROMPT.md +157 -0
- package/init-nx-monorepo.sh +107 -0
- package/package.json +11 -4
- package/src/server/api-server.js +6 -1
- package/src/server/views/dashboard.html +69 -4
- package/vg/.vscode/extensions.json +8 -0
- package/vg/.vscode/launch.json +23 -0
- package/vg/README.md +85 -0
- package/vg/apps/api/project.json +83 -0
- package/vg/apps/api/src/app/analyze.controller.ts +17 -0
- package/vg/apps/api/src/app/analyze.service.ts +57 -0
- package/vg/apps/api/src/app/app.controller.ts +12 -0
- package/vg/apps/api/src/app/app.module.ts +29 -0
- package/vg/apps/api/src/app/app.service.ts +8 -0
- package/vg/apps/api/src/app/clean.controller.ts +40 -0
- package/vg/apps/api/src/app/execute.controller.ts +19 -0
- package/vg/apps/api/src/app/execute.service.ts +46 -0
- package/vg/apps/api/src/app/info.controller.ts +12 -0
- package/vg/apps/api/src/app/info.service.ts +65 -0
- package/vg/apps/api/src/assets/.gitkeep +0 -0
- package/vg/apps/api/src/main.ts +28 -0
- package/vg/apps/api/webpack.config.js +25 -0
- package/vg/apps/api-e2e/jest.config.cts +18 -0
- package/vg/apps/api-e2e/project.json +17 -0
- package/vg/apps/api-e2e/src/support/global-setup.ts +16 -0
- package/vg/apps/api-e2e/src/support/global-teardown.ts +10 -0
- package/vg/apps/api-e2e/src/support/test-setup.ts +9 -0
- package/vg/apps/ng-app/jest.config.ts +21 -0
- package/vg/apps/ng-app/project.json +110 -0
- package/vg/apps/ng-app/proxy.conf.json +8 -0
- package/vg/apps/ng-app/public/favicon.ico +0 -0
- package/vg/apps/ng-app/src/app/app.config.ts +17 -0
- package/vg/apps/ng-app/src/app/app.html +1 -0
- package/vg/apps/ng-app/src/app/app.routes.ts +7 -0
- package/vg/apps/ng-app/src/app/app.scss +0 -0
- package/vg/apps/ng-app/src/app/app.ts +12 -0
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.html +87 -0
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.scss +290 -0
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.ts +236 -0
- package/vg/apps/ng-app/src/app/nx-welcome.ts +872 -0
- package/vg/apps/ng-app/src/app/services/api.service.ts +28 -0
- package/vg/apps/ng-app/src/index.html +13 -0
- package/vg/apps/ng-app/src/main.ts +5 -0
- package/vg/apps/ng-app/src/styles.scss +1 -0
- package/vg/apps/ng-app/src/test-setup.ts +6 -0
- package/vg/jest.config.ts +6 -0
- package/vg/nx.json +85 -0
- package/vg/package-lock.json +30707 -0
- package/vg/package.json +75 -0
- package/vg/packages/client/data-access/README.md +7 -0
- package/vg/packages/client/data-access/jest.config.ts +21 -0
- package/vg/packages/client/data-access/project.json +21 -0
- package/vg/packages/client/data-access/src/index.ts +1 -0
- package/vg/packages/client/data-access/src/lib/data-access/data-access.html +1 -0
- package/vg/packages/client/data-access/src/lib/data-access/data-access.scss +0 -0
- package/vg/packages/client/data-access/src/lib/data-access/data-access.ts +9 -0
- package/vg/packages/client/data-access/src/test-setup.ts +6 -0
- package/vg/packages/core/README.md +11 -0
- package/vg/packages/core/jest.config.ts +10 -0
- package/vg/packages/core/package.json +11 -0
- package/vg/packages/core/project.json +26 -0
- package/vg/packages/core/src/index.ts +6 -0
- package/vg/packages/core/src/lib/core.ts +3 -0
- package/vg/packages/core/src/lib/detectors/project-detector.ts +343 -0
- package/vg/packages/core/src/lib/ignore/ignore-manager.ts +315 -0
- package/vg/packages/core/src/lib/scanner/file-scanner.ts +675 -0
- package/vg/packages/core/src/lib/tokenizer/token-manager.ts +435 -0
- package/vg/packages/core/src/lib/utils/bash-executor.ts +146 -0
- package/vg/packages/shared/data-types/README.md +11 -0
- package/vg/packages/shared/data-types/jest.config.ts +10 -0
- package/vg/packages/shared/data-types/package.json +11 -0
- package/vg/packages/shared/data-types/project.json +26 -0
- package/vg/packages/shared/data-types/src/index.ts +1 -0
- package/vg/packages/shared/data-types/src/lib/data-types.ts +3 -0
- package/vg/start-dev.sh +22 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
max-width: 1000px;
|
|
3
|
+
margin: 0 auto;
|
|
4
|
+
padding: 20px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.header {
|
|
8
|
+
background: white;
|
|
9
|
+
border-radius: 12px;
|
|
10
|
+
padding: 30px;
|
|
11
|
+
margin-bottom: 30px;
|
|
12
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.header h1 {
|
|
16
|
+
color: #667eea;
|
|
17
|
+
font-size: 2.5em;
|
|
18
|
+
margin-bottom: 10px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.header p {
|
|
22
|
+
color: #666;
|
|
23
|
+
font-size: 1.1em;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.status {
|
|
27
|
+
display: inline-block;
|
|
28
|
+
padding: 8px 16px;
|
|
29
|
+
background: #10b981;
|
|
30
|
+
color: white;
|
|
31
|
+
border-radius: 20px;
|
|
32
|
+
font-size: 0.9em;
|
|
33
|
+
margin-top: 10px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.system-prompt-card {
|
|
37
|
+
background: white;
|
|
38
|
+
border-radius: 12px;
|
|
39
|
+
padding: 25px;
|
|
40
|
+
margin-bottom: 30px;
|
|
41
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.system-prompt-header {
|
|
45
|
+
display: flex;
|
|
46
|
+
justify-content: space-between;
|
|
47
|
+
align-items: center;
|
|
48
|
+
margin-bottom: 15px;
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
user-select: none;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.system-prompt-header h2 {
|
|
54
|
+
color: #667eea;
|
|
55
|
+
font-size: 1.5em;
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: 10px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.toggle-icon {
|
|
62
|
+
transition: transform 0.3s ease;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.toggle-icon.open {
|
|
66
|
+
transform: rotate(180deg);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.system-prompt-content {
|
|
70
|
+
max-height: 0;
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
transition: max-height 0.3s ease;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.system-prompt-content.open {
|
|
76
|
+
max-height: 2000px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.prompt-text {
|
|
80
|
+
background: #f9fafb;
|
|
81
|
+
border: 2px solid #e5e7eb;
|
|
82
|
+
border-radius: 8px;
|
|
83
|
+
padding: 20px;
|
|
84
|
+
font-family: 'Courier New', monospace;
|
|
85
|
+
font-size: 0.9em;
|
|
86
|
+
line-height: 1.6;
|
|
87
|
+
white-space: pre-wrap;
|
|
88
|
+
max-height: 400px;
|
|
89
|
+
overflow-y: auto;
|
|
90
|
+
margin-bottom: 15px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.endpoints {
|
|
94
|
+
display: grid;
|
|
95
|
+
gap: 20px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.endpoint-card {
|
|
99
|
+
background: white;
|
|
100
|
+
border-radius: 12px;
|
|
101
|
+
padding: 30px;
|
|
102
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.endpoint-header {
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
gap: 15px;
|
|
109
|
+
margin-bottom: 20px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.method {
|
|
113
|
+
padding: 8px 16px;
|
|
114
|
+
border-radius: 6px;
|
|
115
|
+
font-weight: bold;
|
|
116
|
+
font-size: 0.9em;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.method.post {
|
|
120
|
+
background: #10b981;
|
|
121
|
+
color: white;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.endpoint-path {
|
|
125
|
+
font-family: 'Courier New', monospace;
|
|
126
|
+
color: #333;
|
|
127
|
+
font-size: 1.2em;
|
|
128
|
+
font-weight: 600;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.endpoint-desc {
|
|
132
|
+
color: #666;
|
|
133
|
+
margin-bottom: 20px;
|
|
134
|
+
line-height: 1.6;
|
|
135
|
+
font-size: 1.05em;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.form-group {
|
|
139
|
+
margin-bottom: 20px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.form-group label {
|
|
143
|
+
display: block;
|
|
144
|
+
margin-bottom: 8px;
|
|
145
|
+
color: #333;
|
|
146
|
+
font-weight: 600;
|
|
147
|
+
font-size: 1em;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.form-group input,
|
|
151
|
+
.form-group textarea {
|
|
152
|
+
width: 100%;
|
|
153
|
+
padding: 12px;
|
|
154
|
+
border: 2px solid #e5e7eb;
|
|
155
|
+
border-radius: 8px;
|
|
156
|
+
font-size: 1em;
|
|
157
|
+
font-family: 'Courier New', monospace;
|
|
158
|
+
transition: border-color 0.3s ease;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.form-group input:focus,
|
|
162
|
+
.form-group textarea:focus {
|
|
163
|
+
outline: none;
|
|
164
|
+
border-color: #667eea;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.form-group textarea {
|
|
168
|
+
min-height: 150px;
|
|
169
|
+
resize: vertical;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.btn-group {
|
|
173
|
+
display: flex;
|
|
174
|
+
gap: 10px;
|
|
175
|
+
margin-top: 20px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.btn {
|
|
179
|
+
background: #667eea;
|
|
180
|
+
color: white;
|
|
181
|
+
border: none;
|
|
182
|
+
padding: 14px 28px;
|
|
183
|
+
border-radius: 8px;
|
|
184
|
+
cursor: pointer;
|
|
185
|
+
font-size: 1em;
|
|
186
|
+
font-weight: 600;
|
|
187
|
+
transition: all 0.3s ease;
|
|
188
|
+
display: inline-flex;
|
|
189
|
+
align-items: center;
|
|
190
|
+
gap: 8px;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.btn:hover {
|
|
194
|
+
background: #5568d3;
|
|
195
|
+
transform: translateY(-2px);
|
|
196
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.btn:disabled {
|
|
200
|
+
background: #9ca3af;
|
|
201
|
+
cursor: not-allowed;
|
|
202
|
+
transform: none;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.btn-copy {
|
|
206
|
+
background: #10b981;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.btn-copy:hover {
|
|
210
|
+
background: #059669;
|
|
211
|
+
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.btn-copy.copied {
|
|
215
|
+
background: #6366f1;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.response {
|
|
219
|
+
margin-top: 20px;
|
|
220
|
+
padding: 20px;
|
|
221
|
+
border-radius: 8px;
|
|
222
|
+
background: #f9fafb;
|
|
223
|
+
border-left: 4px solid #667eea;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.response.success {
|
|
227
|
+
border-left-color: #10b981;
|
|
228
|
+
background: #f0fdf4;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.response.error {
|
|
232
|
+
border-left-color: #ef4444;
|
|
233
|
+
background: #fef2f2;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.response pre {
|
|
237
|
+
margin: 0;
|
|
238
|
+
font-family: 'Courier New', monospace;
|
|
239
|
+
font-size: 0.95em;
|
|
240
|
+
white-space: pre-wrap;
|
|
241
|
+
word-wrap: break-word;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.loading {
|
|
245
|
+
display: inline-block;
|
|
246
|
+
width: 16px;
|
|
247
|
+
height: 16px;
|
|
248
|
+
border: 3px solid rgba(255, 255, 255, .3);
|
|
249
|
+
border-radius: 50%;
|
|
250
|
+
border-top-color: white;
|
|
251
|
+
animation: spin 1s ease-in-out infinite;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@keyframes spin {
|
|
255
|
+
to {
|
|
256
|
+
transform: rotate(360deg);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.toast {
|
|
261
|
+
position: fixed;
|
|
262
|
+
top: 20px;
|
|
263
|
+
right: 20px;
|
|
264
|
+
padding: 16px 24px;
|
|
265
|
+
border-radius: 8px;
|
|
266
|
+
color: white;
|
|
267
|
+
font-weight: 600;
|
|
268
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
269
|
+
opacity: 0;
|
|
270
|
+
transform: translateY(-20px);
|
|
271
|
+
transition: all 0.3s ease;
|
|
272
|
+
z-index: 1000;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.toast.show {
|
|
276
|
+
opacity: 1;
|
|
277
|
+
transform: translateY(0);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.toast.success {
|
|
281
|
+
background: #10b981;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.toast.error {
|
|
285
|
+
background: #ef4444;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.toast.info {
|
|
289
|
+
background: #3b82f6;
|
|
290
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { Component, OnInit } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { ApiService } from '../services/api.service';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'app-dashboard',
|
|
8
|
+
standalone: true,
|
|
9
|
+
imports: [CommonModule, FormsModule],
|
|
10
|
+
templateUrl: './dashboard.component.html',
|
|
11
|
+
styleUrls: ['./dashboard.component.scss']
|
|
12
|
+
})
|
|
13
|
+
export class DashboardComponent implements OnInit {
|
|
14
|
+
systemPrompt = '';
|
|
15
|
+
isPromptOpen = false;
|
|
16
|
+
analyzePath = '.';
|
|
17
|
+
analyzeResult: string | null = null;
|
|
18
|
+
analyzeLoading = false;
|
|
19
|
+
|
|
20
|
+
bashScript = '';
|
|
21
|
+
executeResult: any = null;
|
|
22
|
+
executeLoading = false;
|
|
23
|
+
|
|
24
|
+
toastMessage = '';
|
|
25
|
+
toastType = 'success';
|
|
26
|
+
showToast = false;
|
|
27
|
+
|
|
28
|
+
constructor(private apiService: ApiService) { }
|
|
29
|
+
|
|
30
|
+
ngOnInit() {
|
|
31
|
+
this.systemPrompt = `# VG Coder AI System Prompt
|
|
32
|
+
|
|
33
|
+
## Command Prefixes
|
|
34
|
+
|
|
35
|
+
### /ask - Question & Answer Mode
|
|
36
|
+
Khi người dùng hỏi với prefix /ask, họ đang muốn tìm hiểu hoặc được giải thích về một vấn đề.
|
|
37
|
+
|
|
38
|
+
**Response Format:** Markdown
|
|
39
|
+
- Trả lời chi tiết, rõ ràng
|
|
40
|
+
- Sử dụng code blocks, lists, tables khi cần
|
|
41
|
+
- Cung cấp ví dụ minh họa
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### /plan - Planning Mode
|
|
46
|
+
Khi người dùng muốn lên kế hoạch với prefix /plan, tạo một implementation plan chi tiết.
|
|
47
|
+
|
|
48
|
+
**Response Format:** Markdown checklist với bash commands
|
|
49
|
+
- Chia nhỏ thành các bước cụ thể
|
|
50
|
+
- Mỗi bước có bash command tương ứng
|
|
51
|
+
- Sắp xếp theo thứ tự logic
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### /fix - Bug Fix Mode
|
|
56
|
+
Khi người dùng cần fix bug với prefix /fix, phân tích lỗi và đưa ra giải pháp.
|
|
57
|
+
|
|
58
|
+
**Response Format:** Markdown + Bash script
|
|
59
|
+
1. **Phân tích lỗi:** Giải thích nguyên nhân
|
|
60
|
+
2. **Giải pháp:** Mô tả cách fix
|
|
61
|
+
3. **Bash script:** Code để fix (nếu cần)
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### /code - Code Generation Mode
|
|
66
|
+
Khi người dùng hỏi với prefix /code, trả về **BASH SCRIPT DUY NHẤT** để tạo/cập nhật files.
|
|
67
|
+
|
|
68
|
+
## ⚠️ QUY TẮC BẮT BUỘC
|
|
69
|
+
|
|
70
|
+
### 1. Chỉ bao gồm files có thay đổi
|
|
71
|
+
- ❌ **KHÔNG** bao gồm files không có sự thay đổi nội dung
|
|
72
|
+
- ✅ Nếu nội dung file sau chỉnh sửa giống 100% bản cũ → **BỎ QUA**
|
|
73
|
+
|
|
74
|
+
### 2. Format Script Chuẩn
|
|
75
|
+
|
|
76
|
+
**Mỗi file PHẢI theo cú pháp:**
|
|
77
|
+
\`\`\`bash
|
|
78
|
+
mkdir -p $(dirname "path/to/file.ext")
|
|
79
|
+
cat <<'EOF' > path/to/file.ext
|
|
80
|
+
... toàn bộ nội dung file sau khi chỉnh sửa ...
|
|
81
|
+
EOF
|
|
82
|
+
\`\`\`
|
|
83
|
+
|
|
84
|
+
### 3. Chi tiết quan trọng
|
|
85
|
+
- ✅ **LUÔN** có \`mkdir -p $(dirname "...")\` trước mỗi file
|
|
86
|
+
- ✅ Sử dụng \`<<'EOF'\` (có dấu nháy đơn) để tránh bash expansion
|
|
87
|
+
- ✅ Ghi đè hoàn toàn file bằng nội dung mới
|
|
88
|
+
- ✅ Tự động tạo file và thư mục cha nếu chưa tồn tại
|
|
89
|
+
- ✅ Đường dẫn giống với file mẫu đính kèm
|
|
90
|
+
|
|
91
|
+
### 4. Example Output
|
|
92
|
+
|
|
93
|
+
\`\`\`bash
|
|
94
|
+
# Create/Update component file
|
|
95
|
+
mkdir -p $(dirname "src/components/Button/index.tsx")
|
|
96
|
+
cat <<'EOF' > src/components/Button/index.tsx
|
|
97
|
+
import React from 'react';
|
|
98
|
+
|
|
99
|
+
export const Button = () => {
|
|
100
|
+
return <button>Click me</button>;
|
|
101
|
+
};
|
|
102
|
+
EOF
|
|
103
|
+
|
|
104
|
+
# Create/Update styles
|
|
105
|
+
mkdir -p $(dirname "src/components/Button/styles.css")
|
|
106
|
+
cat <<'EOF' > src/components/Button/styles.css
|
|
107
|
+
.button {
|
|
108
|
+
padding: 10px 20px;
|
|
109
|
+
background: blue;
|
|
110
|
+
}
|
|
111
|
+
EOF
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Integration với VG Coder CLI
|
|
117
|
+
|
|
118
|
+
Bash scripts được generate sẽ được thực thi qua:
|
|
119
|
+
\`\`\`bash
|
|
120
|
+
POST http://localhost:6868/api/execute
|
|
121
|
+
{
|
|
122
|
+
"bash": "mkdir -p $(dirname \\"src/...\\")\\\\ncat <<'EOF' > ..."
|
|
123
|
+
}
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
API sẽ:
|
|
127
|
+
1. ✅ Validate bash syntax trong \`.vg/temp-execute\`
|
|
128
|
+
2. ✅ Execute tại working directory nếu syntax OK
|
|
129
|
+
3. ✅ Trả về stdout/stderr/exitCode
|
|
130
|
+
4. ✅ Auto cleanup temp directory
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Best Practices
|
|
135
|
+
|
|
136
|
+
### DO ✅
|
|
137
|
+
- Luôn dùng \`mkdir -p $(dirname "...")\` trước mỗi file
|
|
138
|
+
- Sử dụng \`<<'EOF'\` để tránh variable expansion
|
|
139
|
+
- Ghi đè toàn bộ nội dung file
|
|
140
|
+
- Chỉ include files có thay đổi thực sự
|
|
141
|
+
|
|
142
|
+
### DON'T ❌
|
|
143
|
+
- Không tạo file mà không tạo thư mục cha
|
|
144
|
+
- Không dùng \`<<EOF\` (thiếu quotes) nếu có \`$\` trong content
|
|
145
|
+
- Không include files không thay đổi
|
|
146
|
+
- Không dùng relative paths phức tạp`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
toggleSystemPrompt() {
|
|
150
|
+
this.isPromptOpen = !this.isPromptOpen;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
copySystemPrompt() {
|
|
154
|
+
navigator.clipboard.writeText(this.systemPrompt).then(() => {
|
|
155
|
+
this.showToastMessage('✅ Copied System Prompt!', 'success');
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async analyze() {
|
|
160
|
+
this.analyzeLoading = true;
|
|
161
|
+
this.apiService.analyze(this.analyzePath).subscribe({
|
|
162
|
+
next: (res) => {
|
|
163
|
+
this.analyzeResult = res;
|
|
164
|
+
this.analyzeLoading = false;
|
|
165
|
+
|
|
166
|
+
// Download file
|
|
167
|
+
const blob = new Blob([res], { type: 'text/plain' });
|
|
168
|
+
const url = window.URL.createObjectURL(blob);
|
|
169
|
+
const a = document.createElement('a');
|
|
170
|
+
a.href = url;
|
|
171
|
+
a.download = 'project.txt';
|
|
172
|
+
a.click();
|
|
173
|
+
|
|
174
|
+
this.showToastMessage('✅ Analysis completed & downloaded!', 'success');
|
|
175
|
+
},
|
|
176
|
+
error: (err) => {
|
|
177
|
+
this.analyzeLoading = false;
|
|
178
|
+
this.showToastMessage('❌ Analysis failed: ' + err.message, 'error');
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
copyAnalyzeResult() {
|
|
184
|
+
if (this.analyzeResult) {
|
|
185
|
+
navigator.clipboard.writeText(this.analyzeResult).then(() => {
|
|
186
|
+
this.showToastMessage('✅ Copied project.txt!', 'success');
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async execute() {
|
|
192
|
+
if (!this.bashScript.trim()) return;
|
|
193
|
+
|
|
194
|
+
this.executeLoading = true;
|
|
195
|
+
this.apiService.execute(this.bashScript).subscribe({
|
|
196
|
+
next: (res) => {
|
|
197
|
+
this.executeResult = res;
|
|
198
|
+
this.executeLoading = false;
|
|
199
|
+
if (res.success) {
|
|
200
|
+
this.showToastMessage('✅ Execution successful!', 'success');
|
|
201
|
+
} else {
|
|
202
|
+
this.showToastMessage('❌ Execution failed!', 'error');
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
error: (err) => {
|
|
206
|
+
this.executeLoading = false;
|
|
207
|
+
this.executeResult = { error: err.message };
|
|
208
|
+
this.showToastMessage('❌ Execution error: ' + err.message, 'error');
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async executeFromClipboard() {
|
|
214
|
+
try {
|
|
215
|
+
const text = await navigator.clipboard.readText();
|
|
216
|
+
if (!text.trim()) {
|
|
217
|
+
this.showToastMessage('⚠️ Clipboard is empty!', 'error');
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.bashScript = text;
|
|
222
|
+
this.execute();
|
|
223
|
+
} catch (err: any) {
|
|
224
|
+
this.showToastMessage('❌ Clipboard error: ' + err.message, 'error');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
showToastMessage(msg: string, type: 'success' | 'error' | 'info') {
|
|
229
|
+
this.toastMessage = msg;
|
|
230
|
+
this.toastType = type;
|
|
231
|
+
this.showToast = true;
|
|
232
|
+
setTimeout(() => {
|
|
233
|
+
this.showToast = false;
|
|
234
|
+
}, 3000);
|
|
235
|
+
}
|
|
236
|
+
}
|