antigravity-ide 3.5.54 → 3.5.55
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/cli/create.js +300 -251
- package/package.json +1 -1
package/cli/create.js
CHANGED
|
@@ -11,214 +11,263 @@ const { getProjectConfig, getSkillsForCategories } = require('./prompts');
|
|
|
11
11
|
const gradient = require('gradient-string');
|
|
12
12
|
|
|
13
13
|
async function createProject(projectName, options) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
14
|
+
try {
|
|
15
|
+
// Determine target directory
|
|
16
|
+
const isCurrentDir = !projectName || projectName === '.';
|
|
17
|
+
const targetName = isCurrentDir ? path.basename(process.cwd()) : projectName;
|
|
18
|
+
|
|
19
|
+
// Get configuration (pass targetName if specifically provided/determined as CWD target)
|
|
20
|
+
// If isCurrentDir is true, we pass '.' to prompts to tell it to skip the name question
|
|
21
|
+
const config = await getProjectConfig(options.skipPrompts, isCurrentDir ? targetName : projectName);
|
|
22
|
+
|
|
23
|
+
// Resolve final project path
|
|
24
|
+
const projectPath = isCurrentDir ? process.cwd() : path.resolve(process.cwd(), config.projectName);
|
|
25
|
+
const finalProjectName = config.projectName;
|
|
26
|
+
|
|
27
|
+
// Check if directory exists (only if NOT current dir)
|
|
28
|
+
if (!isCurrentDir && fs.existsSync(projectPath)) {
|
|
29
|
+
console.error(chalk.red(`\n❌ Directory "${finalProjectName}" already exists.\n`));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log('\n');
|
|
34
|
+
console.log(gradient.cristal('━'.repeat(60)));
|
|
35
|
+
console.log(chalk.bold(' 📦 Creating Google Antigravity Project'));
|
|
36
|
+
console.log(gradient.cristal('━'.repeat(60)));
|
|
37
|
+
console.log('');
|
|
38
|
+
|
|
39
|
+
// Create project directory
|
|
40
|
+
const spinner = ora('Creating project structure...').start();
|
|
41
|
+
fs.mkdirSync(projectPath, { recursive: true });
|
|
42
|
+
|
|
43
|
+
// Copy base structure
|
|
44
|
+
await copyBaseStructure(projectPath, config);
|
|
45
|
+
spinner.succeed('Project structure created');
|
|
46
|
+
|
|
47
|
+
// Copy selected skills
|
|
48
|
+
if (config.template !== 'minimal' && config.skillCategories?.length > 0) {
|
|
49
|
+
spinner.start('Installing selected skills...');
|
|
50
|
+
await copySkills(projectPath, config.skillCategories, config.engineMode);
|
|
51
|
+
spinner.succeed(`Installed ${config.skillCategories.length} skill categories`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Copy workflows
|
|
55
|
+
if (config.workflows?.length > 0) {
|
|
56
|
+
spinner.start('Setting up workflows...');
|
|
57
|
+
await copyWorkflows(projectPath, config.workflows);
|
|
58
|
+
spinner.succeed(`Configured ${config.workflows.length} workflows`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
// Generate configuration files
|
|
64
|
+
spinner.start('Generating configuration files...');
|
|
65
|
+
await generateConfigs(projectPath, config);
|
|
66
|
+
spinner.succeed('Configuration files created');
|
|
67
|
+
|
|
68
|
+
// Initialize git
|
|
69
|
+
spinner.start('Initializing git repository...');
|
|
70
|
+
try {
|
|
71
|
+
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
72
|
+
spinner.succeed('Git repository initialized');
|
|
73
|
+
} catch (error) {
|
|
74
|
+
spinner.warn('Git initialization skipped (git not found)');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Print success message
|
|
78
|
+
printSuccessMessage(finalProjectName, config);
|
|
79
|
+
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(chalk.red('\n❌ Error creating project:'), error.message);
|
|
82
|
+
process.exit(1);
|
|
31
83
|
}
|
|
84
|
+
}
|
|
32
85
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
86
|
+
// Helper to handle core file conflicts (auto-create backup if exists)
|
|
87
|
+
function handleCoreFileConflict(filePath, fileName) {
|
|
88
|
+
if (!fs.existsSync(filePath)) {
|
|
89
|
+
return { shouldWrite: true, targetPath: filePath };
|
|
90
|
+
}
|
|
38
91
|
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
|
|
92
|
+
// File exists - create backup with .new extension
|
|
93
|
+
const dir = path.dirname(filePath);
|
|
94
|
+
const ext = path.extname(fileName);
|
|
95
|
+
const base = path.basename(fileName, ext);
|
|
96
|
+
const newPath = path.join(dir, `${base}.new${ext}`);
|
|
97
|
+
return { shouldWrite: true, targetPath: newPath, isBackup: true };
|
|
98
|
+
}
|
|
42
99
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
100
|
+
// Helper to determine file filter based on engine mode
|
|
101
|
+
function getEngineFilter(engineMode) {
|
|
102
|
+
return (src, dest) => {
|
|
103
|
+
// If mode is 'standard' (Node.js focus), exclude Python files
|
|
104
|
+
if (engineMode === 'standard') {
|
|
105
|
+
const lowerSrc = src.toLowerCase();
|
|
106
|
+
// Exclude Python source, compiled files, and package configs
|
|
107
|
+
if (lowerSrc.endsWith('.py') ||
|
|
108
|
+
lowerSrc.endsWith('.pyc') ||
|
|
109
|
+
lowerSrc.endsWith('requirements.txt') ||
|
|
110
|
+
lowerSrc.endsWith('pipfile') ||
|
|
111
|
+
lowerSrc.endsWith('pyproject.toml') ||
|
|
112
|
+
lowerSrc.includes('__pycache__') ||
|
|
113
|
+
lowerSrc.includes('venv/') ||
|
|
114
|
+
lowerSrc.includes('.venv/')) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// 'advanced' mode (or others) includes everything
|
|
119
|
+
return true;
|
|
120
|
+
};
|
|
121
|
+
}
|
|
46
122
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
spinner.succeed(`Installed ${config.skillCategories.length} skill categories`);
|
|
52
|
-
}
|
|
123
|
+
async function copyBaseStructure(projectPath, config) {
|
|
124
|
+
const sourceAgentDir = path.join(__dirname, '..', '.agent');
|
|
125
|
+
const destAgentDir = path.join(projectPath, '.agent');
|
|
126
|
+
const filter = getEngineFilter(config.engineMode);
|
|
53
127
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
spinner.start('Setting up workflows...');
|
|
57
|
-
await copyWorkflows(projectPath, config.workflows);
|
|
58
|
-
spinner.succeed(`Configured ${config.workflows.length} workflows`);
|
|
59
|
-
}
|
|
128
|
+
// Create base .agent directory
|
|
129
|
+
fs.mkdirSync(destAgentDir, { recursive: true });
|
|
60
130
|
|
|
131
|
+
// Copy all subdirectories from .agent (except skills, which are handled separately)
|
|
132
|
+
if (fs.existsSync(sourceAgentDir)) {
|
|
133
|
+
const entries = fs.readdirSync(sourceAgentDir, { withFileTypes: true });
|
|
61
134
|
|
|
135
|
+
for (const entry of entries) {
|
|
136
|
+
if (entry.name === 'skills' || entry.name === 'GEMINI.md' || entry.name === 'START_HERE.md') {
|
|
137
|
+
continue; // Handle these separately
|
|
138
|
+
}
|
|
62
139
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
await generateConfigs(projectPath, config);
|
|
66
|
-
spinner.succeed('Configuration files created');
|
|
140
|
+
const sourceEntryPath = path.join(sourceAgentDir, entry.name);
|
|
141
|
+
const destEntryPath = path.join(destAgentDir, entry.name);
|
|
67
142
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
72
|
-
spinner.succeed('Git repository initialized');
|
|
73
|
-
} catch (error) {
|
|
74
|
-
spinner.warn('Git initialization skipped (git not found)');
|
|
143
|
+
await fs.copy(sourceEntryPath, destEntryPath, { filter });
|
|
144
|
+
}
|
|
75
145
|
}
|
|
76
146
|
|
|
77
|
-
//
|
|
78
|
-
|
|
147
|
+
// Ensure 'skills' dir exists even if empty
|
|
148
|
+
fs.mkdirSync(path.join(destAgentDir, 'skills'), { recursive: true });
|
|
79
149
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
}
|
|
150
|
+
// Copy GEMINI.md based on rules (core file - auto backup if exists)
|
|
151
|
+
const geminiPath = path.join(destAgentDir, 'GEMINI.md');
|
|
152
|
+
const geminiDecision = handleCoreFileConflict(geminiPath, 'GEMINI.md');
|
|
85
153
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// If mode is 'standard' (Node.js focus), exclude Python files
|
|
90
|
-
if (engineMode === 'standard') {
|
|
91
|
-
const lowerSrc = src.toLowerCase();
|
|
92
|
-
// Exclude Python source, compiled files, and package configs
|
|
93
|
-
if (lowerSrc.endsWith('.py') ||
|
|
94
|
-
lowerSrc.endsWith('.pyc') ||
|
|
95
|
-
lowerSrc.endsWith('requirements.txt') ||
|
|
96
|
-
lowerSrc.endsWith('pipfile') ||
|
|
97
|
-
lowerSrc.endsWith('pyproject.toml') ||
|
|
98
|
-
lowerSrc.includes('__pycache__') ||
|
|
99
|
-
lowerSrc.includes('venv/') ||
|
|
100
|
-
lowerSrc.includes('.venv/')) {
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// 'advanced' mode (or others) includes everything
|
|
105
|
-
return true;
|
|
106
|
-
};
|
|
107
|
-
}
|
|
154
|
+
if (geminiDecision.shouldWrite) {
|
|
155
|
+
const geminiContent = generateGeminiMd(config.rules, config.language, config.industryDomain, config.agentName);
|
|
156
|
+
fs.writeFileSync(geminiDecision.targetPath, geminiContent);
|
|
108
157
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// Create base .agent directory
|
|
115
|
-
fs.mkdirSync(destAgentDir, { recursive: true });
|
|
116
|
-
|
|
117
|
-
// Copy all subdirectories from .agent (except skills, which are handled separately)
|
|
118
|
-
if (fs.existsSync(sourceAgentDir)) {
|
|
119
|
-
const entries = fs.readdirSync(sourceAgentDir, { withFileTypes: true });
|
|
120
|
-
|
|
121
|
-
for (const entry of entries) {
|
|
122
|
-
if (entry.name === 'skills' || entry.name === 'GEMINI.md' || entry.name === 'START_HERE.md') {
|
|
123
|
-
continue; // Handle these separately
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const sourceEntryPath = path.join(sourceAgentDir, entry.name);
|
|
127
|
-
const destEntryPath = path.join(destAgentDir, entry.name);
|
|
128
|
-
|
|
129
|
-
await fs.copy(sourceEntryPath, destEntryPath, { filter });
|
|
158
|
+
if (geminiDecision.isBackup) {
|
|
159
|
+
console.log(chalk.yellow(` ℹ️ GEMINI.md exists, created ${path.basename(geminiDecision.targetPath)}`));
|
|
160
|
+
} else {
|
|
161
|
+
console.log(chalk.green(' ✓ Created GEMINI.md'));
|
|
162
|
+
}
|
|
130
163
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const rootDir = path.join(__dirname, '..');
|
|
149
|
-
|
|
150
|
-
files.forEach(file => {
|
|
151
|
-
const source = path.join(rootDir, file);
|
|
152
|
-
const dest = path.join(projectPath, file);
|
|
153
|
-
if (fs.existsSync(source)) {
|
|
154
|
-
fs.copyFileSync(source, dest);
|
|
164
|
+
|
|
165
|
+
// Copy START_HERE.md (core file - auto backup if exists)
|
|
166
|
+
const startHereSource = path.join(sourceAgentDir, 'START_HERE.md');
|
|
167
|
+
const startHereDest = path.join(destAgentDir, 'START_HERE.md');
|
|
168
|
+
|
|
169
|
+
if (fs.existsSync(startHereSource)) {
|
|
170
|
+
const startHereDecision = handleCoreFileConflict(startHereDest, 'START_HERE.md');
|
|
171
|
+
|
|
172
|
+
if (startHereDecision.shouldWrite) {
|
|
173
|
+
fs.copyFileSync(startHereSource, startHereDecision.targetPath);
|
|
174
|
+
|
|
175
|
+
if (startHereDecision.isBackup) {
|
|
176
|
+
console.log(chalk.yellow(` ℹ️ START_HERE.md exists, created ${path.basename(startHereDecision.targetPath)}`));
|
|
177
|
+
} else {
|
|
178
|
+
console.log(chalk.green(' ✓ Created START_HERE.md'));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
155
181
|
}
|
|
156
|
-
|
|
182
|
+
|
|
183
|
+
// Copy basic files (README, .gitignore) - only if they don't exist
|
|
184
|
+
const files = ['README.md', '.gitignore'];
|
|
185
|
+
const rootDir = path.join(__dirname, '..');
|
|
186
|
+
|
|
187
|
+
files.forEach(file => {
|
|
188
|
+
const source = path.join(rootDir, file);
|
|
189
|
+
const dest = path.join(projectPath, file);
|
|
190
|
+
if (fs.existsSync(source) && !fs.existsSync(dest)) {
|
|
191
|
+
fs.copyFileSync(source, dest);
|
|
192
|
+
console.log(chalk.green(` ✓ Created ${file}`));
|
|
193
|
+
} else if (fs.existsSync(dest)) {
|
|
194
|
+
console.log(chalk.yellow(` ℹ️ Skipped ${file} (already exists)`));
|
|
195
|
+
}
|
|
196
|
+
});
|
|
157
197
|
}
|
|
158
198
|
|
|
159
199
|
async function copySkills(projectPath, categories, engineMode) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
200
|
+
const skillsSourceDir = path.join(__dirname, '..', '.agent', 'skills');
|
|
201
|
+
const skillsDestDir = path.join(projectPath, '.agent', 'skills');
|
|
202
|
+
const filter = getEngineFilter(engineMode);
|
|
203
|
+
|
|
204
|
+
// Check if source directory exists
|
|
205
|
+
if (!fs.existsSync(skillsSourceDir)) {
|
|
206
|
+
console.warn(chalk.yellow(`\n⚠️ Warning: Skills directory not found at ${skillsSourceDir}`));
|
|
207
|
+
console.warn(' The .agent folder might be missing from the package.');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const selectedSkills = getSkillsForCategories(categories);
|
|
212
|
+
|
|
213
|
+
for (const skill of selectedSkills) {
|
|
214
|
+
const skillPath = path.join(skillsSourceDir, skill);
|
|
215
|
+
if (fs.existsSync(skillPath)) {
|
|
216
|
+
const destPath = path.join(skillsDestDir, skill);
|
|
217
|
+
await fs.copy(skillPath, destPath, { filter });
|
|
218
|
+
} else {
|
|
219
|
+
// Optional: Warn about missing specific skills if needed
|
|
220
|
+
}
|
|
180
221
|
}
|
|
181
|
-
}
|
|
182
222
|
}
|
|
183
223
|
|
|
184
224
|
async function copyWorkflows(projectPath, workflows) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
225
|
+
const workflowsSourceDir = path.join(__dirname, '..', '.agent', 'workflows');
|
|
226
|
+
const workflowsDestDir = path.join(projectPath, '.agent', 'workflows');
|
|
227
|
+
|
|
228
|
+
for (const workflow of workflows) {
|
|
229
|
+
const workflowFile = `${workflow}.md`;
|
|
230
|
+
const source = path.join(workflowsSourceDir, workflowFile);
|
|
231
|
+
if (fs.existsSync(source)) {
|
|
232
|
+
await fs.copy(source, path.join(workflowsDestDir, workflowFile));
|
|
233
|
+
}
|
|
193
234
|
}
|
|
194
|
-
}
|
|
195
235
|
}
|
|
196
236
|
|
|
197
237
|
|
|
198
238
|
|
|
199
239
|
async function generateConfigs(projectPath, config) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
240
|
+
// Generate package.json only if it doesn't exist
|
|
241
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
242
|
+
|
|
243
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
244
|
+
const packageJson = {
|
|
245
|
+
name: config.projectName,
|
|
246
|
+
version: '1.0.0',
|
|
247
|
+
description: 'AI Agent project powered by Google Antigravity',
|
|
248
|
+
private: true,
|
|
249
|
+
scripts: {
|
|
250
|
+
dev: 'echo "No dev server configured"',
|
|
251
|
+
build: 'echo "No build script"'
|
|
252
|
+
},
|
|
253
|
+
keywords: ['ai', 'agent', 'google-antigravity'],
|
|
254
|
+
author: '',
|
|
255
|
+
license: 'MIT'
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
fs.writeFileSync(
|
|
259
|
+
packageJsonPath,
|
|
260
|
+
JSON.stringify(packageJson, null, 2)
|
|
261
|
+
);
|
|
262
|
+
console.log(chalk.green(' ✓ Created package.json'));
|
|
263
|
+
} else {
|
|
264
|
+
console.log(chalk.yellow(' ℹ️ Skipped package.json (already exists)'));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Generate .editorconfig only if it doesn't exist
|
|
268
|
+
const editorconfigPath = path.join(projectPath, '.editorconfig');
|
|
269
|
+
if (!fs.existsSync(editorconfigPath)) {
|
|
270
|
+
const editorConfig = `root = true
|
|
222
271
|
|
|
223
272
|
[*]
|
|
224
273
|
charset = utf-8
|
|
@@ -243,39 +292,39 @@ bin/* text eol=lf
|
|
|
243
292
|
}
|
|
244
293
|
|
|
245
294
|
function generateGeminiMd(rules, language = 'en', industry = 'other', agentName = 'Antigravity') {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
295
|
+
const strictness = {
|
|
296
|
+
strict: {
|
|
297
|
+
autoRun: 'false',
|
|
298
|
+
confirmLevel: 'Ask before every file modification and command execution'
|
|
299
|
+
},
|
|
300
|
+
balanced: {
|
|
301
|
+
autoRun: 'true for safe read operations',
|
|
302
|
+
confirmLevel: 'Ask before destructive operations'
|
|
303
|
+
},
|
|
304
|
+
flexible: {
|
|
305
|
+
autoRun: 'true',
|
|
306
|
+
confirmLevel: 'Minimal confirmation, high autonomy'
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const config = strictness[rules] || strictness.balanced;
|
|
311
|
+
const isVi = language === 'vi';
|
|
312
|
+
|
|
313
|
+
// Define Industry Focus strings
|
|
314
|
+
const industryMap = {
|
|
315
|
+
finance: isVi ? 'Tài chính & Fintech (An toàn, Chính xác)' : 'Finance & Fintech (Security, Precision)',
|
|
316
|
+
education: isVi ? 'Giáo dục & EdTech (Trực quan, Giải thích)' : 'Education & EdTech (Intuitive, Explanatory)',
|
|
317
|
+
fnb: isVi ? 'F&B & Nhà hàng (Tốc độ, Tiện lợi)' : 'F&B & Restaurant (Speed, Convenience)',
|
|
318
|
+
personal: isVi ? 'Cá nhân & Portfolio (Sáng tạo, Cá nhân hóa)' : 'Personal & Portfolio (Creative, Personalized)',
|
|
319
|
+
healthcare: isVi ? 'Y tế & Sức khỏe (Bảo mật, Tin cậy)' : 'Healthcare & HealthTech (Privacy, Reliability)',
|
|
320
|
+
logistics: isVi ? 'Vận tải & Logistics (Hiệu quả, Real-time)' : 'Logistics & Supply Chain (Efficiency, Real-time)',
|
|
321
|
+
other: isVi ? 'Phát triển chung' : 'General Development',
|
|
322
|
+
other: isVi ? 'Phát triển chung' : 'General Development'
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const industryFocus = industryMap[industry] || industryMap.other;
|
|
326
|
+
|
|
327
|
+
const contentEn = `---
|
|
279
328
|
trigger: always_on
|
|
280
329
|
---
|
|
281
330
|
|
|
@@ -335,7 +384,7 @@ Add your project-specific instructions here.
|
|
|
335
384
|
*Generated by Google Antigravity*
|
|
336
385
|
`;
|
|
337
386
|
|
|
338
|
-
|
|
387
|
+
const contentVi = `---
|
|
339
388
|
trigger: always_on
|
|
340
389
|
---
|
|
341
390
|
|
|
@@ -399,48 +448,48 @@ Thêm các hướng dẫn cụ thể cho dự án của bạn tại đây.
|
|
|
399
448
|
*Được tạo bởi Google Antigravity*
|
|
400
449
|
`;
|
|
401
450
|
|
|
402
|
-
|
|
451
|
+
return isVi ? contentVi : contentEn;
|
|
403
452
|
}
|
|
404
453
|
|
|
405
454
|
function printSuccessMessage(projectName, config) {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
455
|
+
console.log('\n');
|
|
456
|
+
console.log(gradient.rainbow('━'.repeat(60)));
|
|
457
|
+
console.log(gradient.morning.multiline(' ✓ SUCCESS! Project Ready'));
|
|
458
|
+
console.log(gradient.rainbow('━'.repeat(60)));
|
|
459
|
+
|
|
460
|
+
// Concise config display
|
|
461
|
+
console.log('');
|
|
462
|
+
console.log(chalk.bold('📋 Config'));
|
|
463
|
+
console.log(chalk.gray(' Project: ') + gradient.cristal(projectName));
|
|
464
|
+
console.log(chalk.gray(' Template: ') + chalk.cyan(config.template));
|
|
465
|
+
console.log(chalk.gray(' Skills: ') + chalk.cyan(config.skillCategories?.join(', ') || 'none'));
|
|
466
|
+
|
|
467
|
+
// AI Activation Instructions (NEW)
|
|
468
|
+
console.log('');
|
|
469
|
+
console.log(gradient.pastel('━'.repeat(60)));
|
|
470
|
+
console.log(chalk.bold.cyan(config.language === 'vi' ? '🤖 Kích hoạt AI Agent' : '🤖 AI Agent Activation'));
|
|
471
|
+
console.log('');
|
|
472
|
+
|
|
473
|
+
if (config.language === 'vi') {
|
|
474
|
+
console.log(chalk.gray(' 1. Mở dự án: ') + chalk.white(`cd ${projectName}`));
|
|
475
|
+
console.log(chalk.gray(' 2. Mở khung chat: ') + chalk.white('(Claude, Gemini, v.v...)'));
|
|
476
|
+
console.log(chalk.gray(' 3. Kích hoạt: ') + chalk.green('Đọc nội dung .agent/GEMINI.md'));
|
|
477
|
+
} else {
|
|
478
|
+
console.log(chalk.gray(' 1. Open project: ') + chalk.white(`cd ${projectName}`));
|
|
479
|
+
console.log(chalk.gray(' 2. Open AI chat: ') + chalk.white('(Claude, Gemini, etc.)'));
|
|
480
|
+
console.log(chalk.gray(' 3. Activate: ') + chalk.green('Read .agent/START_HERE.md'));
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Stats Display
|
|
484
|
+
console.log('');
|
|
485
|
+
console.log(gradient.pastel(' ✨ Installed: ') + chalk.white('20+ Master Skills') + chalk.gray(' • ') + chalk.white('15+ Agents') + chalk.gray(' • ') + chalk.white('13 Shared Modules'));
|
|
486
|
+
|
|
487
|
+
console.log('');
|
|
488
|
+
console.log(chalk.dim(config.language === 'vi' ? ' AI sẽ tự động tải các kỹ năng và quy tắc.' : ' The AI will load all skills and rules automatically.'));
|
|
489
|
+
console.log(gradient.pastel('━'.repeat(60)));
|
|
490
|
+
console.log('');
|
|
491
|
+
console.log(chalk.gray(' Developed with 💡 by Dokhacgiakhoa'));
|
|
492
|
+
console.log('');
|
|
444
493
|
}
|
|
445
494
|
|
|
446
495
|
module.exports = {
|