winter-super-cli 2026.5.28 → 2026.5.29
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/bin/winter.js +2 -1
- package/package.json +1 -1
- package/src/ai/benchmark.js +352 -0
- package/src/ai/prompts/system-prompt.js +70 -81
- package/src/ai/providers.js +12 -9
- package/src/ai/reasoning.js +5 -81
- package/src/cli/commands.js +62 -0
- package/src/cli/context-loader.js +64 -1
- package/src/cli/conversation-format.js +90 -12
- package/src/cli/prompt-builder.js +43 -17
- package/src/cli/repl-commands.js +14 -3
- package/src/cli/repl.js +325 -209
- package/src/tools/executor.js +78 -9
package/src/cli/repl.js
CHANGED
|
@@ -21,6 +21,7 @@ import { formatMarkdown } from './markdown-format.js';
|
|
|
21
21
|
import { Spinner } from './spinner.js';
|
|
22
22
|
import { ContextLoader } from './context-loader.js';
|
|
23
23
|
import { PromptBuilder } from './prompt-builder.js';
|
|
24
|
+
import { classifyModelTier, isSmallModel } from '../ai/model-capabilities.js';
|
|
24
25
|
import {
|
|
25
26
|
addUsage as mergeUsage,
|
|
26
27
|
buildToolCallSignature as buildToolCallSignatureText,
|
|
@@ -65,6 +66,7 @@ export class WinterREPL {
|
|
|
65
66
|
this.contextLoader = new ContextLoader({ projectPath: this.projectPath, session: this.session, tools: this.tools });
|
|
66
67
|
this.promptBuilder = new PromptBuilder({
|
|
67
68
|
session: this.session,
|
|
69
|
+
ai: this.ai,
|
|
68
70
|
tools: this.tools,
|
|
69
71
|
projectPath: this.projectPath,
|
|
70
72
|
sessionPermissionGrants: this.sessionPermissionGrants,
|
|
@@ -228,6 +230,111 @@ export class WinterREPL {
|
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
|
|
233
|
+
// ── Tự động tạo design.md, skill.md, rule.md nếu chưa có ──────────────
|
|
234
|
+
const autoCreateDocs = [
|
|
235
|
+
{
|
|
236
|
+
filename: 'design.md',
|
|
237
|
+
generate: async () => {
|
|
238
|
+
const designDir = this.getResourcePaths().designs;
|
|
239
|
+
let brands = [];
|
|
240
|
+
try {
|
|
241
|
+
const entries = await fsPromises.readdir(designDir, { withFileTypes: true });
|
|
242
|
+
brands = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
|
|
243
|
+
} catch {}
|
|
244
|
+
return `# Design Resources
|
|
245
|
+
|
|
246
|
+
Danh sách các design system có sẵn trong local resources:
|
|
247
|
+
|
|
248
|
+
## Available Brands (${brands.length})
|
|
249
|
+
|
|
250
|
+
${brands.length > 0 ? brands.map(b => `- ${b}`).join('\n') : '- Không tìm thấy design system nào.'}
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
*File này được tự động tạo bởi Winter CLI.*`;
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
filename: 'skill.md',
|
|
258
|
+
generate: async () => {
|
|
259
|
+
const catalog = await this.contextLoader.getStartupSkillCatalog();
|
|
260
|
+
const skills = [...catalog].sort();
|
|
261
|
+
return `# Available Skills
|
|
262
|
+
|
|
263
|
+
Danh sách các skill có sẵn trong hệ thống:
|
|
264
|
+
|
|
265
|
+
## Core Skills
|
|
266
|
+
- **coding**: Code analysis, generation, review
|
|
267
|
+
- **design**: Design system integration
|
|
268
|
+
- **debug**: Debugging assistance
|
|
269
|
+
- **refactor**: Code refactoring
|
|
270
|
+
- **test**: Test generation
|
|
271
|
+
- **security**: Security review
|
|
272
|
+
- **performance**: Performance optimization
|
|
273
|
+
|
|
274
|
+
## All Available Skills (${skills.length})
|
|
275
|
+
|
|
276
|
+
${skills.map(s => `- ${s}`).join('\n')}
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
*File này được tự động tạo bởi Winter CLI.*`;
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
filename: 'rule.md',
|
|
284
|
+
generate: async () => {
|
|
285
|
+
const parts = ['# Project Rules', '', '## Quy tắc dự án', ''];
|
|
286
|
+
// Load từ các instruction files đã có
|
|
287
|
+
const files = await this.readProjectInstructionFiles();
|
|
288
|
+
for (const file of files) {
|
|
289
|
+
if (file.relativePath === 'rule.md') continue; // skip self
|
|
290
|
+
parts.push(`- [${file.relativePath}](./${file.relativePath})`);
|
|
291
|
+
}
|
|
292
|
+
// Liệt kê các thư mục rules
|
|
293
|
+
const rulesDirs = [
|
|
294
|
+
this.getResourcePaths().codex.rules,
|
|
295
|
+
this.getUserResourcePaths()?.codexRules,
|
|
296
|
+
].filter(Boolean);
|
|
297
|
+
for (const dir of rulesDirs) {
|
|
298
|
+
try {
|
|
299
|
+
const entries = await fsPromises.readdir(dir, { withFileTypes: true });
|
|
300
|
+
const ruleFiles = entries.filter(e => e.isFile() && e.name.endsWith('.md')).map(e => e.name);
|
|
301
|
+
if (ruleFiles.length > 0) {
|
|
302
|
+
parts.push('', `## Rules from ${path.basename(path.dirname(dir))}/${path.basename(dir)}`, '');
|
|
303
|
+
for (const f of ruleFiles) {
|
|
304
|
+
parts.push(`- ${f}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
} catch {}
|
|
308
|
+
}
|
|
309
|
+
// Liệt kê local resource rules
|
|
310
|
+
parts.push('', '## Local Resource Guidelines', '');
|
|
311
|
+
parts.push('- Karpathy tools guidelines available in local resources');
|
|
312
|
+
parts.push('- Agents.md project guidelines available in local resources');
|
|
313
|
+
parts.push('', '---', '*File này được tự động tạo bởi Winter CLI.*');
|
|
314
|
+
return parts.join('\n');
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
];
|
|
318
|
+
|
|
319
|
+
for (const doc of autoCreateDocs) {
|
|
320
|
+
const filePath = path.join(this.projectPath, doc.filename);
|
|
321
|
+
try {
|
|
322
|
+
await fsPromises.stat(filePath);
|
|
323
|
+
// File đã tồn tại, bỏ qua
|
|
324
|
+
} catch {
|
|
325
|
+
// File chưa tồn tại, tự động tạo
|
|
326
|
+
try {
|
|
327
|
+
const content = await doc.generate();
|
|
328
|
+
await fsPromises.writeFile(filePath, content, 'utf8');
|
|
329
|
+
console.log(`${colors.green}✓ Đã tự động tạo file ${doc.filename} từ local resources!${colors.reset}`);
|
|
330
|
+
const memoryKey = `[Quy tắc dự án từ ${doc.filename}]`;
|
|
331
|
+
await this.session.replaceMemory(memoryKey, content);
|
|
332
|
+
} catch (err) {
|
|
333
|
+
// Bỏ qua nếu không tạo được
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
231
338
|
await this.bootstrapProjectCapabilities();
|
|
232
339
|
|
|
233
340
|
const activeProvider = this.ai.getActiveProvider();
|
|
@@ -286,21 +393,23 @@ export class WinterREPL {
|
|
|
286
393
|
});
|
|
287
394
|
|
|
288
395
|
// Hiển thị prompt lần đầu tiên ngay khi khởi động xong
|
|
289
|
-
this.
|
|
396
|
+
this.showInputPrompt();
|
|
290
397
|
|
|
291
398
|
this.rl.on('line', (line) => {
|
|
292
399
|
this.inputQueue = this.inputQueue
|
|
293
400
|
.then(async () => {
|
|
401
|
+
this.closeInputBox();
|
|
294
402
|
const input = line.trim();
|
|
295
403
|
if (input) {
|
|
296
404
|
await this.handleInput(input);
|
|
297
405
|
} else {
|
|
298
|
-
if (this.running && !this.readlineClosed) this.
|
|
406
|
+
if (this.running && !this.readlineClosed) this.showInputPrompt();
|
|
299
407
|
}
|
|
300
408
|
})
|
|
301
409
|
.catch((error) => {
|
|
410
|
+
this.closeInputBox();
|
|
302
411
|
console.log(`\n${colors.red}✖ Error: ${error.message}${colors.reset}\n`);
|
|
303
|
-
if (this.running && !this.readlineClosed) this.
|
|
412
|
+
if (this.running && !this.readlineClosed) this.showInputPrompt();
|
|
304
413
|
});
|
|
305
414
|
});
|
|
306
415
|
|
|
@@ -312,6 +421,28 @@ export class WinterREPL {
|
|
|
312
421
|
});
|
|
313
422
|
}
|
|
314
423
|
|
|
424
|
+
showInputPrompt() {
|
|
425
|
+
if (!this.running || this.readlineClosed) return;
|
|
426
|
+
const w = Math.max(20, terminalWidth() - 2);
|
|
427
|
+
process.stdout.write(`
|
|
428
|
+
${colors.magenta}╭${'─'.repeat(w)}╮${colors.reset}
|
|
429
|
+
`);
|
|
430
|
+
process.stdout.write(`${colors.magenta}│${colors.reset} `);
|
|
431
|
+
this.rl.setPrompt(`${colors.bright}${colors.cyan}winter❄️: ${colors.reset}`);
|
|
432
|
+
this.rl.prompt();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
closeInputBox() {
|
|
436
|
+
const w = Math.max(20, terminalWidth() - 2);
|
|
437
|
+
readline.moveCursor(process.stdout, 0, -1);
|
|
438
|
+
readline.cursorTo(process.stdout, terminalWidth() - 1);
|
|
439
|
+
process.stdout.write(`${colors.magenta}│${colors.reset}`);
|
|
440
|
+
process.stdout.write(`
|
|
441
|
+
`);
|
|
442
|
+
process.stdout.write(`${colors.magenta}╰${'─'.repeat(w)}╯${colors.reset}
|
|
443
|
+
`);
|
|
444
|
+
}
|
|
445
|
+
|
|
315
446
|
showStatus() {
|
|
316
447
|
console.log(`${colors.dim}Project: ${this.projectPath}${colors.reset}`);
|
|
317
448
|
console.log(`${colors.dim}Provider: ${this.ai.getActiveProvider()}${colors.reset}`);
|
|
@@ -500,7 +631,7 @@ export class WinterREPL {
|
|
|
500
631
|
const nextTask = this.taskQueue.shift();
|
|
501
632
|
setTimeout(() => this.processInputTask(nextTask), 0);
|
|
502
633
|
} else {
|
|
503
|
-
if (!this.readlineClosed) this.
|
|
634
|
+
if (!this.readlineClosed) this.showInputPrompt();
|
|
504
635
|
}
|
|
505
636
|
}
|
|
506
637
|
}
|
|
@@ -946,10 +1077,20 @@ ${colors.reset}
|
|
|
946
1077
|
case 'research':
|
|
947
1078
|
return byName(['Read', 'Grep', 'Glob', 'WebFetch', 'WebSearch']);
|
|
948
1079
|
default:
|
|
949
|
-
return byName(['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep'
|
|
1080
|
+
return byName(['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep']);
|
|
950
1081
|
}
|
|
951
1082
|
}
|
|
952
1083
|
|
|
1084
|
+
getActiveModelTier() {
|
|
1085
|
+
const providerName = this.ai?.getActiveProvider?.();
|
|
1086
|
+
const model = this.ai?.providers?.[providerName]?.model || '';
|
|
1087
|
+
return classifyModelTier(model, providerName);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
shouldUseCompactPrompt() {
|
|
1091
|
+
return isSmallModel(this.getActiveModelTier());
|
|
1092
|
+
}
|
|
1093
|
+
|
|
953
1094
|
selectExecutionProfile(messages = [], options = {}) {
|
|
954
1095
|
if (typeof this.ai?.selectExecutionProfile === 'function') {
|
|
955
1096
|
const profile = this.ai.selectExecutionProfile(messages, options);
|
|
@@ -1001,9 +1142,10 @@ ${colors.reset}
|
|
|
1001
1142
|
let finalContent = '';
|
|
1002
1143
|
let reachedToolLimit = true;
|
|
1003
1144
|
let usedTools = false;
|
|
1145
|
+
let verified = false;
|
|
1004
1146
|
const toolSummaries = [];
|
|
1005
1147
|
const totalUsage = {};
|
|
1006
|
-
|
|
1148
|
+
const toolSignatureHistory = [];
|
|
1007
1149
|
const executionProfile = this.selectExecutionProfile(messages, { enableTools: true });
|
|
1008
1150
|
try {
|
|
1009
1151
|
for (let i = 0; i < 8; i++) {
|
|
@@ -1042,13 +1184,21 @@ ${colors.reset}
|
|
|
1042
1184
|
if (this.spinner) this.spinner.stop();
|
|
1043
1185
|
|
|
1044
1186
|
const currentToolSignature = this.buildToolCallSignature(toolCalls);
|
|
1045
|
-
if (currentToolSignature
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1187
|
+
if (currentToolSignature) {
|
|
1188
|
+
toolSignatureHistory.push(currentToolSignature);
|
|
1189
|
+
if (toolSignatureHistory.length > 3) {
|
|
1190
|
+
toolSignatureHistory.shift();
|
|
1191
|
+
}
|
|
1192
|
+
// Only break if 3+ consecutive identical signatures — 2 repeats is normal iteration
|
|
1193
|
+
if (toolSignatureHistory.length === 3 &&
|
|
1194
|
+
toolSignatureHistory[0] === currentToolSignature &&
|
|
1195
|
+
toolSignatureHistory[1] === currentToolSignature) {
|
|
1196
|
+
console.log(`
|
|
1197
|
+
${colors.yellow}ℹ AI tool loop detected (3 consecutive identical tool calls). Breaking out.${colors.reset}`);
|
|
1198
|
+
reachedToolLimit = false;
|
|
1199
|
+
break;
|
|
1200
|
+
}
|
|
1050
1201
|
}
|
|
1051
|
-
lastToolSignature = currentToolSignature;
|
|
1052
1202
|
|
|
1053
1203
|
const BOX_WIDTH = terminalWidth(76, 116, 92);
|
|
1054
1204
|
messages.push({
|
|
@@ -1061,12 +1211,17 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1061
1211
|
const { toolName, toolArgs } = tc;
|
|
1062
1212
|
const canonicalToolName = this.tools.normalizeToolName(toolName);
|
|
1063
1213
|
const argParseError = toolArgs?.__toolArgParseError;
|
|
1064
|
-
const
|
|
1214
|
+
const recoveredArgs = argParseError ? this.recoverToolArgs(canonicalToolName, toolArgs.__rawToolArgs) : null;
|
|
1215
|
+
const canUseRecoveredArgs = recoveredArgs && Object.keys(recoveredArgs).length > 0;
|
|
1216
|
+
const normalizedArgs = argParseError && !canUseRecoveredArgs
|
|
1217
|
+
? {}
|
|
1218
|
+
: this.tools.normalizeToolInput?.(canonicalToolName, canUseRecoveredArgs ? recoveredArgs : toolArgs) ?? toolArgs;
|
|
1219
|
+
const enrichedArgs = argParseError && !canUseRecoveredArgs ? {} : this.enrichToolArgs(canonicalToolName, normalizedArgs, messages);
|
|
1065
1220
|
|
|
1066
1221
|
const icon = canonicalToolName === 'Bash' ? '⚙' : canonicalToolName === 'Read' ? '📖' : canonicalToolName === 'Write' ? '✏️' : canonicalToolName === 'Edit' ? '🔧' : canonicalToolName === 'Grep' ? '🔍' : canonicalToolName === 'Glob' ? '📂' : '⚡';
|
|
1067
1222
|
|
|
1068
1223
|
let proceed = true;
|
|
1069
|
-
if (await this.shouldPromptForToolPermission(canonicalToolName) && !argParseError) {
|
|
1224
|
+
if (await this.shouldPromptForToolPermission(canonicalToolName) && (!argParseError || canUseRecoveredArgs)) {
|
|
1070
1225
|
const cmd = enrichedArgs.command || enrichedArgs.cmd || 'unknown';
|
|
1071
1226
|
if (this.sessionPermissionGrants.has(canonicalToolName)) {
|
|
1072
1227
|
proceed = true;
|
|
@@ -1088,11 +1243,12 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1088
1243
|
}
|
|
1089
1244
|
|
|
1090
1245
|
let result;
|
|
1091
|
-
if (argParseError) {
|
|
1246
|
+
if (argParseError && !canUseRecoveredArgs) {
|
|
1092
1247
|
result = {
|
|
1093
1248
|
success: false,
|
|
1094
1249
|
error: `Invalid ${canonicalToolName} tool arguments JSON: ${toolArgs.__toolArgParseError}`,
|
|
1095
1250
|
rawArgs: toolArgs.__rawToolArgs,
|
|
1251
|
+
recovery: 'Use valid JSON object arguments, for example {"file_path":"README.md"} for Read or {"command":"npm test"} for Bash.',
|
|
1096
1252
|
};
|
|
1097
1253
|
} else if (!proceed) {
|
|
1098
1254
|
result = { success: false, error: 'User denied permission to execute this command.' };
|
|
@@ -1142,7 +1298,7 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1142
1298
|
console.log(`\n${colors.yellow}${finalContent}${colors.reset}\n`);
|
|
1143
1299
|
}
|
|
1144
1300
|
|
|
1145
|
-
return finalContent;
|
|
1301
|
+
return { finalContent, usedTools };
|
|
1146
1302
|
}
|
|
1147
1303
|
|
|
1148
1304
|
async requestAssistantTurn(messages, options, startedAt, totalUsage) {
|
|
@@ -1430,7 +1586,7 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1430
1586
|
}
|
|
1431
1587
|
|
|
1432
1588
|
enrichToolArgs(toolName, toolArgs = {}, messages = []) {
|
|
1433
|
-
const args = toolArgs && typeof toolArgs === 'object' ? { ...toolArgs } : {};
|
|
1589
|
+
const args = this.tools.normalizeToolInput?.(toolName, toolArgs) || (toolArgs && typeof toolArgs === 'object' ? { ...toolArgs } : {});
|
|
1434
1590
|
const fallbackPath = this.extractPathFromMessages(messages);
|
|
1435
1591
|
|
|
1436
1592
|
if (fallbackPath) {
|
|
@@ -1460,6 +1616,21 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1460
1616
|
return args;
|
|
1461
1617
|
}
|
|
1462
1618
|
|
|
1619
|
+
recoverToolArgs(toolName, rawArgs) {
|
|
1620
|
+
const raw = String(rawArgs || '').trim();
|
|
1621
|
+
if (!raw) return null;
|
|
1622
|
+
if (/^[{[]/.test(raw)) return null;
|
|
1623
|
+
|
|
1624
|
+
const cleaned = raw
|
|
1625
|
+
.replace(/^```(?:json|tool|tool_call)?\s*/i, '')
|
|
1626
|
+
.replace(/```$/i, '')
|
|
1627
|
+
.trim()
|
|
1628
|
+
.replace(/^['"]|['"]$/g, '');
|
|
1629
|
+
if (!cleaned) return null;
|
|
1630
|
+
|
|
1631
|
+
return this.tools.normalizeToolInput?.(toolName, cleaned) || null;
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1463
1634
|
extractPathFromMessages(messages = []) {
|
|
1464
1635
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1465
1636
|
const content = messages[i]?.content;
|
|
@@ -1793,7 +1964,7 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1793
1964
|
async chat(message, imageAttachments = []) {
|
|
1794
1965
|
try {
|
|
1795
1966
|
const needsTools = true;
|
|
1796
|
-
const context = await this.getProjectContext();
|
|
1967
|
+
const context = await this.getProjectContext(message);
|
|
1797
1968
|
const messages = [
|
|
1798
1969
|
{ role: 'system', content: this.getSystemPrompt(context) }
|
|
1799
1970
|
];
|
|
@@ -1802,7 +1973,7 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1802
1973
|
const promptHistory = this.getCompressedPromptHistory({
|
|
1803
1974
|
limit: 20,
|
|
1804
1975
|
keepRecent: 14,
|
|
1805
|
-
maxTotalChars: 12000,
|
|
1976
|
+
maxTotalChars: this.shouldUseCompactPrompt() ? 5000 : 12000,
|
|
1806
1977
|
});
|
|
1807
1978
|
if (promptHistory.summary) {
|
|
1808
1979
|
messages.push({ role: 'system', content: `Compressed prior conversation:\n${promptHistory.summary}` });
|
|
@@ -1827,16 +1998,100 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1827
1998
|
}
|
|
1828
1999
|
|
|
1829
2000
|
const tools = this.getAgentTools('general');
|
|
1830
|
-
const finalContent = await this.runConversation(messages, 'Thinking', tools);
|
|
2001
|
+
const { finalContent, usedTools } = await this.runConversation(messages, 'Thinking', tools);
|
|
1831
2002
|
|
|
1832
2003
|
await this.session.addToHistory({ role: 'user', content: message });
|
|
1833
2004
|
await this.session.addToHistory({ role: 'assistant', content: finalContent });
|
|
1834
2005
|
|
|
2006
|
+
// Tự động verify: nếu AI đã dùng tools (sửa code), chạy test/build
|
|
2007
|
+
if (usedTools && finalContent) {
|
|
2008
|
+
await this.verifyAndHeal(messages, tools, 5);
|
|
2009
|
+
}
|
|
2010
|
+
|
|
1835
2011
|
} catch (error) {
|
|
1836
2012
|
console.log(`\n${colors.red}✖ Error: ${error.message}${colors.reset}\n`);
|
|
1837
2013
|
}
|
|
1838
2014
|
}
|
|
1839
2015
|
|
|
2016
|
+
/**
|
|
2017
|
+
* Chạy verification commands (test, build) và trả về kết quả
|
|
2018
|
+
*/
|
|
2019
|
+
async runVerification(commands = ['npm test']) {
|
|
2020
|
+
const { execSync } = await import('child_process');
|
|
2021
|
+
const results = [];
|
|
2022
|
+
|
|
2023
|
+
for (const cmd of commands) {
|
|
2024
|
+
try {
|
|
2025
|
+
const output = execSync(cmd, {
|
|
2026
|
+
timeout: 120000,
|
|
2027
|
+
encoding: 'utf8',
|
|
2028
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
2029
|
+
});
|
|
2030
|
+
results.push({ cmd, passed: true, output: output.trim() });
|
|
2031
|
+
} catch (error) {
|
|
2032
|
+
const stderr = error.stderr || '';
|
|
2033
|
+
const stdout = error.stdout || '';
|
|
2034
|
+
results.push({ cmd, passed: false, output: (stdout + '\n' + stderr).trim() });
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
return {
|
|
2039
|
+
passed: results.every(r => r.passed),
|
|
2040
|
+
details: results,
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
/**
|
|
2045
|
+
* Vòng lặp tự động verify + sửa lỗi:
|
|
2046
|
+
* - Chạy test/build
|
|
2047
|
+
* - Nếu fail, gửi lỗi cho AI fix
|
|
2048
|
+
* - Lặp đến khi pass hết hoặc hết số lần thử
|
|
2049
|
+
*/
|
|
2050
|
+
async verifyAndHeal(messages, tools, maxAttempts = 5) {
|
|
2051
|
+
const verifCommands = ['npm test'];
|
|
2052
|
+
|
|
2053
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2054
|
+
console.log(`\n${colors.cyan}=== Verification Attempt ${attempt}/${maxAttempts} ===${colors.reset}`);
|
|
2055
|
+
|
|
2056
|
+
const result = await this.runVerification(verifCommands);
|
|
2057
|
+
|
|
2058
|
+
if (result.passed) {
|
|
2059
|
+
console.log(`\n${colors.green}✅ All verifications passed!${colors.reset}\n`);
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
// Collect error details
|
|
2064
|
+
const errorDetails = result.details
|
|
2065
|
+
.filter(r => !r.passed)
|
|
2066
|
+
.map(r => `Command: ${r.cmd}\n${r.output}`)
|
|
2067
|
+
.join('\n\n---\n\n');
|
|
2068
|
+
|
|
2069
|
+
console.log(`\n${colors.yellow}⚠ Verification failed. Sending errors back to AI for fix...${colors.reset}\n`);
|
|
2070
|
+
|
|
2071
|
+
// Push error output as user message for AI to fix
|
|
2072
|
+
const fixPrompt = `VERIFICATION FAILED (attempt ${attempt}/${maxAttempts}):
|
|
2073
|
+
|
|
2074
|
+
The following commands produced errors:
|
|
2075
|
+
|
|
2076
|
+
${errorDetails}
|
|
2077
|
+
|
|
2078
|
+
The system will re-run verification automatically after you fix. Please FIX ALL ERRORS above.
|
|
2079
|
+
Do NOT stop until all errors are resolved.`;
|
|
2080
|
+
|
|
2081
|
+
messages.push({ role: 'user', content: fixPrompt });
|
|
2082
|
+
|
|
2083
|
+
// Let the AI fix the issues
|
|
2084
|
+
const { usedTools: fixUsedTools } = await this.runConversation(messages, 'Fixing', tools);
|
|
2085
|
+
|
|
2086
|
+
if (!fixUsedTools) {
|
|
2087
|
+
console.log(`\n${colors.red}⚠ AI did not attempt to fix the errors. Stopping.${colors.reset}\n`);
|
|
2088
|
+
break;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
console.log(`\n${colors.red}⚠ Max verification attempts (${maxAttempts}) reached. Some issues may remain.${colors.reset}\n`);
|
|
2093
|
+
}
|
|
2094
|
+
|
|
1840
2095
|
shouldUseTools(message = '', imageAttachments = []) {
|
|
1841
2096
|
return true;
|
|
1842
2097
|
}
|
|
@@ -1863,12 +2118,16 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1863
2118
|
}
|
|
1864
2119
|
|
|
1865
2120
|
async runAgent(role, task) {
|
|
1866
|
-
const context = await this.getProjectContext();
|
|
2121
|
+
const context = await this.getProjectContext(task);
|
|
1867
2122
|
const messages = [
|
|
1868
2123
|
{ role: 'system', content: this.getAgentSystemPrompt(role, context) }
|
|
1869
2124
|
];
|
|
1870
2125
|
|
|
1871
|
-
const promptHistory = this.getCompressedPromptHistory({
|
|
2126
|
+
const promptHistory = this.getCompressedPromptHistory({
|
|
2127
|
+
limit: this.shouldUseCompactPrompt() ? 14 : 30,
|
|
2128
|
+
keepRecent: this.shouldUseCompactPrompt() ? 8 : 14,
|
|
2129
|
+
maxTotalChars: this.shouldUseCompactPrompt() ? 5000 : 12000,
|
|
2130
|
+
});
|
|
1872
2131
|
if (promptHistory.summary) {
|
|
1873
2132
|
messages.push({ role: 'system', content: `Compressed prior conversation:\n${promptHistory.summary}` });
|
|
1874
2133
|
}
|
|
@@ -1878,19 +2137,29 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1878
2137
|
|
|
1879
2138
|
messages.push({ role: 'user', content: `Task: ${task}` });
|
|
1880
2139
|
|
|
1881
|
-
const
|
|
2140
|
+
const agentTools = this.getAgentTools(role);
|
|
2141
|
+
const { finalContent, usedTools } = await this.runConversation(messages, `Subagent [${role}]`, agentTools);
|
|
1882
2142
|
|
|
1883
2143
|
await this.session.addToHistory({ role: 'user', content: `[subagent:${role}] ${task}` });
|
|
1884
2144
|
await this.session.addToHistory({ role: 'assistant', content: finalContent });
|
|
2145
|
+
|
|
2146
|
+
if (usedTools && finalContent) {
|
|
2147
|
+
await this.verifyAndHeal(messages, agentTools, 3);
|
|
2148
|
+
}
|
|
1885
2149
|
}
|
|
1886
2150
|
|
|
1887
|
-
async getProjectContext() {
|
|
2151
|
+
async getProjectContext(task = '') {
|
|
1888
2152
|
const context = [];
|
|
2153
|
+
const requiredLocalResources = await this.getRequiredLocalResourceSummary();
|
|
2154
|
+
if (requiredLocalResources) {
|
|
2155
|
+
context.push(requiredLocalResources);
|
|
2156
|
+
}
|
|
2157
|
+
|
|
1889
2158
|
const projectInstructionFiles = await this.readProjectInstructionFiles();
|
|
1890
2159
|
|
|
1891
2160
|
for (const file of projectInstructionFiles) {
|
|
1892
2161
|
try {
|
|
1893
|
-
const preview = this.compactText(file.content, 900, 'project instruction');
|
|
2162
|
+
const preview = this.compactText(file.content, this.shouldUseCompactPrompt() ? 450 : 900, 'project instruction');
|
|
1894
2163
|
context.push(`[${file.relativePath}]\n${preview}`);
|
|
1895
2164
|
} catch { }
|
|
1896
2165
|
}
|
|
@@ -1900,11 +2169,12 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1900
2169
|
const stat = await fs.stat(packageJsonPath);
|
|
1901
2170
|
if (stat.isFile()) {
|
|
1902
2171
|
const content = await fs.readFile(packageJsonPath, 'utf-8');
|
|
1903
|
-
context.push(`[package.json]\n${this.compactText(content, 1200, 'package.json')}`);
|
|
2172
|
+
context.push(`[package.json]\n${this.compactText(content, this.shouldUseCompactPrompt() ? 650 : 1200, 'package.json')}`);
|
|
1904
2173
|
}
|
|
1905
2174
|
} catch { }
|
|
1906
2175
|
|
|
1907
|
-
const
|
|
2176
|
+
const shouldIncludeResources = /\b(resource|resources|skill|skills|plugin|plugins|claude|codex|agent|agents|design|ui|figma|brand|mcp)\b/i.test(String(task || ''));
|
|
2177
|
+
const localResources = shouldIncludeResources ? await this.getLocalResourceContext() : '';
|
|
1908
2178
|
if (localResources) {
|
|
1909
2179
|
context.push(localResources);
|
|
1910
2180
|
}
|
|
@@ -1918,26 +2188,30 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1918
2188
|
|
|
1919
2189
|
const gitSummary = execSync('git diff --stat --summary', { cwd: this.projectPath, encoding: 'utf8', stdio: 'pipe', maxBuffer: 1024 * 50 }).trim();
|
|
1920
2190
|
if (gitSummary) {
|
|
1921
|
-
context.push(`[Git Summary]\n${this.compactText(gitSummary, 1200, 'git summary')}`);
|
|
2191
|
+
context.push(`[Git Summary]\n${this.compactText(gitSummary, this.shouldUseCompactPrompt() ? 650 : 1200, 'git summary')}`);
|
|
1922
2192
|
}
|
|
1923
2193
|
|
|
1924
2194
|
// Get brief git diff for context
|
|
1925
2195
|
const gitDiff = execSync('git diff', { cwd: this.projectPath, encoding: 'utf8', stdio: 'pipe', maxBuffer: 1024 * 50 }).trim().split('\n').slice(0, 30).join('\n');
|
|
1926
2196
|
if (gitDiff) {
|
|
1927
|
-
context.push(`[Git Diff]\n${this.compactText(gitDiff, 1800, 'git diff')}`);
|
|
2197
|
+
context.push(`[Git Diff]\n${this.compactText(gitDiff, this.shouldUseCompactPrompt() ? 900 : 1800, 'git diff')}`);
|
|
1928
2198
|
}
|
|
1929
2199
|
}
|
|
1930
2200
|
} catch (e) {
|
|
1931
2201
|
// Not a git repo or git not installed
|
|
1932
2202
|
}
|
|
1933
2203
|
|
|
1934
|
-
return this.compactText(context.join('\n\n') || 'No project context found.', 9000, 'project context');
|
|
2204
|
+
return this.compactText(context.join('\n\n') || 'No project context found.', this.shouldUseCompactPrompt() ? 4200 : 9000, 'project context');
|
|
1935
2205
|
}
|
|
1936
2206
|
|
|
1937
2207
|
async getLocalResourceContext() {
|
|
1938
2208
|
return this.contextLoader.getLocalResourceContext();
|
|
1939
2209
|
}
|
|
1940
2210
|
|
|
2211
|
+
async getRequiredLocalResourceSummary() {
|
|
2212
|
+
return this.contextLoader.getRequiredLocalResourceSummary();
|
|
2213
|
+
}
|
|
2214
|
+
|
|
1941
2215
|
async bootstrapProjectCapabilities() {
|
|
1942
2216
|
const sessionContext = this.session.getContext() || {};
|
|
1943
2217
|
|
|
@@ -1947,10 +2221,10 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1947
2221
|
'Inspect rules, resources, and likely skills before doing any task work.'
|
|
1948
2222
|
);
|
|
1949
2223
|
await this.session.addPlanStep(plan.id, {
|
|
1950
|
-
description: 'Read
|
|
2224
|
+
description: 'Read required local resources, project rules, and attached skill libraries.',
|
|
1951
2225
|
});
|
|
1952
2226
|
await this.session.addPlanStep(plan.id, {
|
|
1953
|
-
description: '
|
|
2227
|
+
description: 'Ground every model in required resource rules before making changes.',
|
|
1954
2228
|
});
|
|
1955
2229
|
await this.session.updateContext('bootstrapPlan', {
|
|
1956
2230
|
id: plan.id,
|
|
@@ -1959,6 +2233,12 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
1959
2233
|
});
|
|
1960
2234
|
}
|
|
1961
2235
|
|
|
2236
|
+
const requiredLocalResources = await this.getRequiredLocalResourceSummary();
|
|
2237
|
+
if (requiredLocalResources) {
|
|
2238
|
+
await this.session.updateContext('requiredLocalResources', requiredLocalResources);
|
|
2239
|
+
await this.session.replaceMemory('[Required local resources]', requiredLocalResources, 'resource');
|
|
2240
|
+
}
|
|
2241
|
+
|
|
1962
2242
|
const skillSnapshot = await this.inferStartupSkills();
|
|
1963
2243
|
await this.session.updateContext('availableSkillCatalog', skillSnapshot.availableSkills);
|
|
1964
2244
|
await this.session.updateContext('activeSkills', skillSnapshot.activeSkills);
|
|
@@ -2018,119 +2298,18 @@ ${colors.yellow}ℹ AI tool loop detected. Breaking out.${colors.reset}`);
|
|
|
2018
2298
|
}
|
|
2019
2299
|
getSystemPrompt(context = '') {
|
|
2020
2300
|
this.hydrateSessionToolPermissions();
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
process.platform === 'win32'
|
|
2029
|
-
? 'Shell rule: Use shell:"powershell" for PowerShell cmdlets, shell:"cmd" for cmd.exe syntax, and shell:"auto" when unsure.'
|
|
2030
|
-
: 'Shell rule: Use the native POSIX shell on non-Windows hosts and leave shell unspecified unless a specific shell is required.',
|
|
2031
|
-
].join('\n');
|
|
2032
|
-
|
|
2033
|
-
let memoryStr = memories.length > 0 ? `\n## Memories (Important Context)\n${this.summarizePromptList(memories, {
|
|
2034
|
-
limit: 8,
|
|
2035
|
-
maxEntryChars: 220,
|
|
2036
|
-
maxTotalChars: 1600,
|
|
2037
|
-
mapper: memory => memory.text,
|
|
2038
|
-
})}` : '';
|
|
2039
|
-
let plansStr = plans.length > 0 ? `\n## Active Plans & Tasks\n${this.summarizePromptList(plans, {
|
|
2040
|
-
limit: 6,
|
|
2041
|
-
maxEntryChars: 260,
|
|
2042
|
-
maxTotalChars: 1600,
|
|
2043
|
-
mapper: plan => `[${plan.status}] ${plan.title}: ${plan.description}`,
|
|
2044
|
-
})}` : '';
|
|
2045
|
-
let skillsStr = Array.isArray(sessionContext.activeSkills) && sessionContext.activeSkills.length > 0
|
|
2046
|
-
? `\n## Auto-applied Skills\n${sessionContext.activeSkills.slice(0, 12).map(skill => `- ${skill}`).join('\n')}${sessionContext.activeSkills.length > 12 ? '\n- ...' : ''}`
|
|
2047
|
-
: '';
|
|
2048
|
-
let startupPlanStr = sessionContext.bootstrapPlan?.title
|
|
2049
|
-
? `\n## Startup Plan\n- ${sessionContext.bootstrapPlan.title}: ${sessionContext.bootstrapPlan.description}`
|
|
2050
|
-
: '';
|
|
2051
|
-
const sessionSignalsStr = `\n${this.buildSessionSignalsPrompt()}`;
|
|
2052
|
-
|
|
2053
|
-
return `You are Winter, an expert AI coding assistant.
|
|
2054
|
-
|
|
2055
|
-
## CRITICAL AI RULES (MUST FOLLOW STRICTLY):
|
|
2056
|
-
1. [THINKING BEFORE CODING]: State assumptions, constraints, and a brief plan before making changes. Be thorough enough to be useful, and do not invent facts.
|
|
2057
|
-
2. [DESIGN EXCELLENCE]: Use rich aesthetics. Default to modern UI frameworks if applicable. Never output plain, ugly HTML/CSS. Ensure responsive, premium feel with micro-animations.
|
|
2058
|
-
3. [CODE QUALITY]: Write clean, modular, SOLID code. Check for syntax errors carefully. Do not generate incomplete code blocks.
|
|
2059
|
-
4. [NO HALLUCINATION]: If you don't know, use tools (Grep/Read/Web) to find out. Do not guess file paths or APIs.
|
|
2060
|
-
5. [TOOL EXECUTION FIRST]: NEVER output full code blocks to the chat and tell the user to copy-paste. ALWAYS use the 'Write' or 'Edit' tool to apply changes directly to their files! The user cannot copy-paste code. You MUST do the work using tools.
|
|
2061
|
-
|
|
2062
|
-
## AGENT OPERATING MODE
|
|
2063
|
-
- Treat the repository, its memories, skills, rules, and bundled local resources as first-class context.
|
|
2064
|
-
- Before answering a task that may depend on project state, rules, skills, memories, local resources, or external facts, proactively call the relevant tool(s) to inspect them.
|
|
2065
|
-
- Prefer using the full tool set when needed: Read, Write, Edit, Bash, Glob, Grep, TaskCreate, TaskUpdate, TaskList, BrowserDebug, WebFetch, WebSearch.
|
|
2066
|
-
- If a question is ambiguous, inspect the project context first instead of guessing.
|
|
2067
|
-
- Winter's job is to amplify weaker models: decompose problems, pull the right context, and use tools to reach a stronger answer than raw inference alone would produce.
|
|
2068
|
-
- Always begin with a short plan before coding or tool execution, then refine the plan if new facts appear.
|
|
2069
|
-
|
|
2070
|
-
## Runtime Environment
|
|
2071
|
-
${environmentSummary}
|
|
2072
|
-
${sessionSignalsStr}
|
|
2073
|
-
|
|
2074
|
-
## CRITICAL LANGUAGE RULE
|
|
2075
|
-
**You MUST always respond in Vietnamese (tiếng Việt).** Never respond in Chinese, Japanese, Korean or any other language unless the user explicitly asks you to. This is non-negotiable.
|
|
2076
|
-
|
|
2077
|
-
## Core Principles
|
|
2078
|
-
1. **Think Before Coding** - State assumptions, ask when unclear
|
|
2079
|
-
2. **Simplicity First** - Minimum code that solves the problem
|
|
2080
|
-
3. **Surgical Changes** - Touch only what you must
|
|
2081
|
-
4. **Goal-Driven Execution** - Define success criteria, verify results
|
|
2082
|
-
|
|
2083
|
-
## Tools Available
|
|
2084
|
-
- Read, Write, Edit - File operations
|
|
2085
|
-
- Write - Create/overwrite files directly. Use this instead of Bash echo/cat/heredoc for writing code.
|
|
2086
|
-
- Edit - Replace exact text in existing files.
|
|
2087
|
-
- Bash - Execute shell commands. Current OS is ${process.platform === 'win32' ? 'Windows; Bash auto-detects PowerShell and cmd.exe syntax. Use shell="powershell" or shell="cmd" when needed.' : process.platform}.
|
|
2088
|
-
- Glob - Find files
|
|
2089
|
-
- Grep - Search content
|
|
2090
|
-
- TaskCreate, TaskUpdate, TaskList - Task management
|
|
2091
|
-
- WebFetch, WebSearch - Research
|
|
2092
|
-
- Vision - Analyze images/screenshots for debugging
|
|
2093
|
-
|
|
2094
|
-
## Guidelines
|
|
2095
|
-
- Call tools when they help - be proactive
|
|
2096
|
-
- You DO have file write tools. Never say "there is no write tool"; use Write or Edit.
|
|
2097
|
-
- If a tool name fails, call the canonical tool name next: Write, Edit, Read, Bash, Glob, or Grep.
|
|
2098
|
-
- On Windows, Bash accepts both PowerShell and cmd.exe commands. Prefer Write with full content for file writes.
|
|
2099
|
-
- After using tools, always provide a direct final answer to the user.
|
|
2100
|
-
- Never claim that you changed files unless a Write, Edit, Bash, or equivalent tool result shows the change succeeded in this turn.
|
|
2101
|
-
- Never emit XML or provider-specific pseudo tool syntax like <minimax:tool_call>. Use the actual tool-calling API only.
|
|
2102
|
-
- If a file path is unknown, search with Glob/Grep first instead of inventing names like Nav.tsx or Footer.tsx.
|
|
2103
|
-
- Answer normal questions directly without unnecessary legal or policy disclaimers.
|
|
2104
|
-
- If a request is illegal, unsafe, or harmful, refuse briefly and offer a safe alternative.
|
|
2105
|
-
- Read files before modifying
|
|
2106
|
-
- Make surgical changes
|
|
2107
|
-
- Verify your work
|
|
2108
|
-
- Follow project conventions (check CLAUDE.md)
|
|
2109
|
-
- When user attaches an image, analyze it carefully for UI bugs, errors, layout issues
|
|
2110
|
-
|
|
2111
|
-
## Project
|
|
2112
|
-
Working directory: ${this.projectPath}
|
|
2113
|
-
Current session: ${this.session.getSessionId().substring(0, 8)}
|
|
2114
|
-
${memoryStr}${plansStr}${skillsStr}${startupPlanStr}
|
|
2115
|
-
${context ? `\n## Project Context\n${this.compactText(context, 6000, 'project context')}` : ''}
|
|
2116
|
-
|
|
2117
|
-
Be helpful, be precise, and get things done. Always respond in Vietnamese.`;
|
|
2301
|
+
this.promptBuilder.session = this.session;
|
|
2302
|
+
this.promptBuilder.ai = this.ai;
|
|
2303
|
+
this.promptBuilder.tools = this.tools;
|
|
2304
|
+
this.promptBuilder.sessionPermissionGrants = this.sessionPermissionGrants;
|
|
2305
|
+
return this.promptBuilder.buildSystemPrompt(context, {
|
|
2306
|
+
projectContextBudget: this.shouldUseCompactPrompt() ? 2200 : 3200,
|
|
2307
|
+
});
|
|
2118
2308
|
}
|
|
2119
2309
|
|
|
2120
2310
|
getFastSystemPrompt() {
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
? `\nContext nhớ ngắn:\n${this.summarizePromptList(memories.slice(-8), {
|
|
2124
|
-
limit: 8,
|
|
2125
|
-
maxEntryChars: 160,
|
|
2126
|
-
maxTotalChars: 1200,
|
|
2127
|
-
mapper: memory => memory.text,
|
|
2128
|
-
})}`
|
|
2129
|
-
: '';
|
|
2130
|
-
|
|
2131
|
-
return `Bạn là Winter, trợ lý AI trả lời ngắn gọn bằng tiếng Việt.
|
|
2132
|
-
Ưu tiên dùng tool và context khi cần; không bịa thông tin.
|
|
2133
|
-
Nếu người dùng yêu cầu sửa file/chạy lệnh/đọc dự án thì hãy gọi tool tương ứng thay vì chỉ nói chung chung.${memoryStr}`;
|
|
2311
|
+
this.promptBuilder.session = this.session;
|
|
2312
|
+
return this.promptBuilder.buildFastSystemPrompt();
|
|
2134
2313
|
}
|
|
2135
2314
|
|
|
2136
2315
|
// Tab completion
|
|
@@ -2150,73 +2329,10 @@ Be helpful, be precise, and get things done. Always respond in Vietnamese.`;
|
|
|
2150
2329
|
}
|
|
2151
2330
|
|
|
2152
2331
|
getAgentSystemPrompt(role, context = '') {
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
let memoryStr = memories.length > 0 ? `\n## Memories (Important Context)\n${this.summarizePromptList(memories, {
|
|
2158
|
-
limit: 8,
|
|
2159
|
-
maxEntryChars: 220,
|
|
2160
|
-
maxTotalChars: 1600,
|
|
2161
|
-
mapper: memory => memory.text,
|
|
2162
|
-
})}` : '';
|
|
2163
|
-
let plansStr = plans.length > 0 ? `\n## Active Plans & Tasks\n${this.summarizePromptList(plans, {
|
|
2164
|
-
limit: 6,
|
|
2165
|
-
maxEntryChars: 260,
|
|
2166
|
-
maxTotalChars: 1600,
|
|
2167
|
-
mapper: plan => `[${plan.status}] ${plan.title}: ${plan.description}`,
|
|
2168
|
-
})}` : '';
|
|
2169
|
-
let skillsStr = Array.isArray(sessionContext.activeSkills) && sessionContext.activeSkills.length > 0
|
|
2170
|
-
? `\n## Auto-applied Skills\n${sessionContext.activeSkills.slice(0, 12).map(skill => `- ${skill}`).join('\n')}${sessionContext.activeSkills.length > 12 ? '\n- ...' : ''}`
|
|
2171
|
-
: '';
|
|
2172
|
-
let startupPlanStr = sessionContext.bootstrapPlan?.title
|
|
2173
|
-
? `\n## Startup Plan\n- ${sessionContext.bootstrapPlan.title}: ${sessionContext.bootstrapPlan.description}`
|
|
2174
|
-
: '';
|
|
2175
|
-
|
|
2176
|
-
let rolePrompt = '';
|
|
2177
|
-
switch (role) {
|
|
2178
|
-
case 'plan':
|
|
2179
|
-
rolePrompt = `You are a Winter planning subagent. Break the request into a concise step-by-step plan, note dependencies, and keep the response short.`;
|
|
2180
|
-
break;
|
|
2181
|
-
case 'review':
|
|
2182
|
-
rolePrompt = `You are a Winter review subagent. Critique the request or implementation with specific issues, edge cases, and concrete improvements.`;
|
|
2183
|
-
break;
|
|
2184
|
-
case 'debug':
|
|
2185
|
-
rolePrompt = `You are a Winter debugging subagent. Focus on root cause, reproduction, and the smallest fix.`;
|
|
2186
|
-
break;
|
|
2187
|
-
case 'research':
|
|
2188
|
-
rolePrompt = `You are a Winter research subagent. Gather the important facts, compare options, and summarize only what matters.`;
|
|
2189
|
-
break;
|
|
2190
|
-
case 'browser':
|
|
2191
|
-
rolePrompt = `You are a Winter browser subagent. Bạn CÓ QUYỀN sử dụng tool 'BrowserDebug' để tương tác với trình duyệt. Hãy dùng nó để mở URL, chụp ảnh màn hình (nếu cần), hoặc chạy JS để kiểm tra trang web.`;
|
|
2192
|
-
break;
|
|
2193
|
-
default:
|
|
2194
|
-
rolePrompt = `You are a Winter coding subagent. Solve the task directly, use tools when needed, and return a concise result.`;
|
|
2195
|
-
break;
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
|
-
return `## CRITICAL AI RULES (MUST FOLLOW STRICTLY):
|
|
2199
|
-
1. [THINKING BEFORE CODING]: State assumptions, constraints, and a brief plan before making changes. Be thorough enough to be useful, and do not invent facts.
|
|
2200
|
-
2. [DESIGN EXCELLENCE]: Use rich aesthetics. Default to modern UI frameworks if applicable. Never output plain, ugly HTML/CSS. Ensure responsive, premium feel with micro-animations.
|
|
2201
|
-
3. [CODE QUALITY]: Write clean, modular, SOLID code. Check for syntax errors carefully. Do not generate incomplete code blocks.
|
|
2202
|
-
4. [NO HALLUCINATION]: If you don't know, use tools (Grep/Read/Web) to find out. Do not guess file paths or APIs.
|
|
2203
|
-
5. [TOOL EXECUTION FIRST]: You DO have file tools. Use Write to create/overwrite files and Edit to patch files. Never say there is no write tool.
|
|
2204
|
-
|
|
2205
|
-
${rolePrompt}
|
|
2206
|
-
|
|
2207
|
-
## Tool Rules
|
|
2208
|
-
- Canonical tools: Read, Write, Edit, Bash, Glob, Grep, TaskCreate, TaskUpdate, TaskList, BrowserDebug, WebFetch, WebSearch.
|
|
2209
|
-
- Treat skills, memories, bundled resources, local project rules, and the tool list as operational context. Use them proactively when relevant.
|
|
2210
|
-
- Current OS is ${process.platform === 'win32' ? 'Windows; Bash auto-detects PowerShell and cmd.exe syntax. Use shell="powershell" or shell="cmd" when needed.' : process.platform}.
|
|
2211
|
-
- Prefer Write/Edit for writing files. Bash accepts both PowerShell and cmd.exe on Windows, but do not use long echo chains for code files.
|
|
2212
|
-
- If a tool call fails because of an unknown alias, call the canonical tool name next.
|
|
2213
|
-
- Always start with a brief plan, then refine it when new facts appear.
|
|
2214
|
-
|
|
2215
|
-
## Project
|
|
2216
|
-
Working directory: ${this.projectPath}
|
|
2217
|
-
Current session: ${this.session.getSessionId().substring(0, 8)}
|
|
2218
|
-
${memoryStr}${plansStr}${skillsStr}${startupPlanStr}
|
|
2219
|
-
${context ? `\n## Project Context\n${this.compactText(context, 6000, 'project context')}` : ''}`;
|
|
2332
|
+
this.promptBuilder.session = this.session;
|
|
2333
|
+
this.promptBuilder.ai = this.ai;
|
|
2334
|
+
this.promptBuilder.tools = this.tools;
|
|
2335
|
+
return this.promptBuilder.buildAgentSystemPrompt(role, context);
|
|
2220
2336
|
}
|
|
2221
2337
|
|
|
2222
2338
|
async handleMcpCommand(args) {
|