@heyai-rules/pilo-masterkit 2.1.0 → 2.2.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/src/bin/cli.js CHANGED
@@ -1,354 +1,424 @@
1
- #!/usr/bin/env node
2
-
3
- const {
4
- intro,
5
- outro,
6
- select,
7
- multiselect,
8
- text,
9
- spinner,
10
- cancel,
11
- isCancel,
12
- note,
13
- } = require("@clack/prompts");
14
- const pc = require("picocolors");
15
- const path = require("node:path");
16
- const { spawnSync } = require("node:child_process");
17
- const installer = require("../lib/installer");
18
-
19
- /**
20
- * Translations
21
- */
22
- const i18n = {
23
- vi: {
24
- intro: " THIẾT LẬP HỒ SƠ VẬN HÀNH ",
25
- langQuestion: "Giao thức ngôn ngữ chính?",
26
- modeQuestion: "Phạm vi cài đặt:",
27
- modeAll: "Elite / Đầy đủ",
28
- modeAllHint: "Triển khai TẤT CẢ các module .agent & AI host",
29
- modeSelective: "Surgical / Tùy chọn",
30
- modeSelectiveHint: "Tối ưu hóa theo Stack & IDE mục tiêu",
31
- stackQuestion: "Stack kỹ thuật mục tiêu (Dùng Space để chọn nhiều):",
32
- aiQuestion: "Trình điều phối AI mục tiêu:",
33
- scopeQuestion: "Quy mô dự án?",
34
- scopePersonal: "Cá nhân",
35
- scopeSmall: "Nhóm nhỏ (SME)",
36
- scopeMedium: "Doanh nghiệp vừa",
37
- scopeEnterprise: "Tập đoàn/Hệ thống lớn",
38
- typeQuestion: "Loại sản phẩm?",
39
- typeWeb: "Ứng dụng Web (Fullstack/Frontend)",
40
- typeApi: "Hệ thống API / Backend",
41
- typeMobile: "Ứng dụng Di động",
42
- typeLib: "Thư viện / Công cụ (SDK)",
43
- typeResearch: "Nghiên cứu / Phân tích dữ liệu",
44
- nameQuestion: "Đặt tên cho AI Agent của bạn? (Mặc định: Pilo)",
45
- namePlaceholder: "Pilo",
46
- installing: "Đang mapping kiến trúc dự án...",
47
- calibrating: "Đang hiệu chuẩn các gói AI Host...",
48
- optimizing: "Đang tối ưu hóa quy trình vận hành...",
49
- ready: "Giao thức vận hành đã được khởi tạo. Lực lượng đặc nhiệm AI của bạn đã trực tuyến.",
50
- readReadme: "Đọc README.md để khám phá các Slash Command có sẵn.",
51
- done: "Hoàn tất!",
52
- summaryTitle: "TỔNG KẾT TRIỂN KHAI",
53
- systemReady: "HỆ THỐNG SẴN SÀNG",
54
- shutdown: "Hệ thống dừng.",
55
- outro: " ĐIỀU PHỐI TƯƠNG LAI VỚI KỶ LUẬT VÀ TÂM HỒN ⚡"
56
- },
57
- en: {
58
- intro: " SELECT YOUR OPERATIONAL PROFILE ",
59
- langQuestion: "Primary Language Protocol?",
60
- modeQuestion: "Installation Spectrum:",
61
- modeAll: "Elite / Full",
62
- modeAllHint: "Deploy ALL .agent modules & ALL AI hosts",
63
- modeSelective: "Surgical / Selective",
64
- modeSelectiveHint: "Optimize by Stack & Target IDE",
65
- stackQuestion: "Target Technical Stack (Use Space to select multiple):",
66
- aiQuestion: "Target AI Orchestrator:",
67
- scopeQuestion: "Project Scope?",
68
- scopePersonal: "Personal",
69
- scopeSmall: "Small Team",
70
- scopeMedium: "Medium Enterprise",
71
- scopeEnterprise: "Large Enterprise/System",
72
- typeQuestion: "Product Type?",
73
- typeWeb: "Web Application",
74
- typeApi: "API / Backend System",
75
- typeMobile: "Mobile Application",
76
- typeLib: "Library / SDK",
77
- typeResearch: "Research / Data Analysis",
78
- nameQuestion: "Name your AI Agent? (Default: Pilo)",
79
- namePlaceholder: "Pilo",
80
- installing: "Mapping project architecture...",
81
- calibrating: "Calibrating AI Host bundles...",
82
- optimizing: "Optimizing operational workflows...",
83
- ready: "Operational protocol initialized. Your AI Task Force is now online.",
84
- readReadme: "Read README.md to explore available Slash Commands.",
85
- done: "Done!",
86
- summaryTitle: "DEPLOYMENT SUMMARY",
87
- systemReady: "SYSTEM READY",
88
- shutdown: "System shutdown.",
89
- outro: " ORCHESTRATING THE FUTURE WITH DISCIPLINE AND SOUL ⚡"
90
- }
91
- };
92
-
93
- /**
94
- * Print a premium stylized banner
95
- */
96
- function printBanner() {
97
- console.log("\n" + pc.magenta(" ██████╗ ██╗██╗ ██████╗ ███╗ ███╗ █████╗ ███████╗████████╗███████╗██████╗ "))
98
- console.log(pc.magenta(" ██╔══██╗██║██║ ██╔═══██╗ ████╗ ████║██╔══██╗██╔════╝╚══██╔══╝██╔════╝██╔══██╗"))
99
- console.log(pc.magenta(" ██████╔╝██║██║ ██║ ██║ ██╔████╔██║███████║███████╗ ██║ █████╗ ██████╔╝"))
100
- console.log(pc.magenta(" ██╔═══╝ ██║██║ ██║ ██║ ██║╚██╔╝██║██╔══██║╚════██║ ██║ ██╔══╝ ██╔══██╗"))
101
- console.log(pc.magenta(" ██║ ██║███████╗╚██████╔╝ ██║ ╚═╝ ██║██║ ██║███████║ ██║ ███████╗██║ ██║"))
102
- console.log(pc.magenta(" ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝"))
103
- console.log(pc.bold(pc.cyan("\n SYSTEM INITIALIZER v2.1\n")));
104
- }
105
-
106
- /**
107
- * Basic argument parser
108
- */
109
- function parseArgs(args) {
110
- const options = {
111
- command: 'init',
112
- targetDir: '.',
113
- profile: null,
114
- template: null,
115
- aiHost: null,
116
- stack: null,
117
- locale: 'vi'
118
- };
119
-
120
- for (let i = 0; i < args.length; i++) {
121
- const arg = args[i];
122
- if (arg === 'init') {
123
- options.command = 'init';
124
- } else if (arg.startsWith('--profile=')) {
125
- options.profile = arg.split('=')[1];
126
- } else if (arg === '--profile' && args[i+1]) {
127
- options.profile = args[++i];
128
- } else if (arg.startsWith('--template:')) {
129
- options.template = arg.replace('--template:', '');
130
- } else if (arg.startsWith('--ai=')) {
131
- options.aiHost = arg.split('=')[1];
132
- } else if (arg.startsWith('--stack=')) {
133
- const stacks = arg.split('=')[1].split(',');
134
- options.stack = stacks;
135
- } else if (arg.startsWith('--locale=')) {
136
- options.locale = arg.split('=')[1];
137
- } else if (!arg.startsWith('-')) {
138
- options.targetDir = arg;
139
- }
140
- }
141
- return options;
142
- }
143
-
144
- /**
145
- * Run external scaffold
146
- */
147
- function runScaffold(options, t) {
148
- const [templateName] = options.template.split(' ');
149
-
150
- const s = spinner();
151
- s.start(pc.cyan(`⚡ Scaffolding upstream project: ${pc.bold(templateName)}...`));
152
-
153
- let command = '';
154
- let args = [];
155
-
156
- if (templateName.startsWith('react')) {
157
- command = 'npm';
158
- args = ['create', 'vite@latest', options.targetDir, '--', '--template', 'react-ts'];
159
- } else if (templateName.startsWith('next')) {
160
- command = 'npx';
161
- args = ['create-next-app@latest', options.targetDir, '--typescript', '--tailwind', '--eslint', '--app', '--src-dir', '--import-alias', '"@/*"'];
162
- } else {
163
- command = 'npm';
164
- args = ['create', `${templateName}@latest`, options.targetDir];
165
- }
166
-
167
- s.stop(pc.green("✓ Upstream command detected."));
168
-
169
- const result = spawnSync(command, args, { stdio: 'inherit', shell: true });
170
- if (result.status !== 0) {
171
- console.error(pc.red('\n✖ Scaffolding failed. Check command outputs above.'));
172
- process.exit(1);
173
- }
174
- }
175
-
176
- /**
177
- * Interactive Wizard
178
- */
179
- async function runWizard(options) {
180
- printBanner();
181
-
182
- const locale = await select({
183
- message: "Primary Language Protocol?",
184
- options: [
185
- { value: "vi", label: "Vietnamese (Tiếng Việt)", hint: "Support localized documentation" },
186
- { value: "en", label: "English", hint: "Global standard" },
187
- ],
188
- });
189
- if (isCancel(locale)) return cancel("System shutdown.");
190
-
191
- const t = i18n[locale];
192
-
193
- intro(pc.bgMagenta(pc.white(t.intro)));
194
-
195
- const mode = await select({
196
- message: t.modeQuestion,
197
- options: [
198
- { value: "all", label: t.modeAll, hint: t.modeAllHint },
199
- { value: "selective", label: t.modeSelective, hint: t.modeSelectiveHint },
200
- ],
201
- });
202
- if (isCancel(mode)) return cancel(t.shutdown);
203
-
204
- if (mode === 'all') {
205
- return { mode: 'all', locale };
206
- }
207
-
208
- const stack = await multiselect({
209
- message: t.stackQuestion,
210
- options: [
211
- { value: "typescript", label: "TypeScript Ecosystem", hint: "React / Next / Node" },
212
- { value: "python", label: "Python AI & Data", hint: "FastAPI / PyTorch" },
213
- { value: "ai_agentic", label: "Agentic Engineering", hint: "MCP / Autonomy" },
214
- { value: "rust", label: "Rust Systems", hint: "Cargo / High Performance" },
215
- { value: "laravel", label: "Laravel PHP", hint: "Modern Backend" },
216
- { value: "mobile", label: "Cross-Platform Mobile", hint: "Flutter / SwiftUI" },
217
- { value: "cpp", label: "C++ Low Level", hint: "Performance Critical" },
218
- { value: "java", label: "Enterprise Java", hint: "Spring Boot" },
219
- { value: "kotlin", label: "Kotlin/JVM", hint: "Modern App Dev" },
220
- { value: "go", label: "Go Microservices", hint: "Cloud Native" },
221
- { value: "marketing_research", label: "Deep Research", hint: "Analysis & Content" },
222
- ],
223
- required: true,
224
- });
225
- if (isCancel(stack)) return cancel(t.shutdown);
226
-
227
- const aiHost = await select({
228
- message: t.aiQuestion,
229
- options: [
230
- { value: "claude", label: "Claude Code / CLI", hint: "Best for agentic tasks" },
231
- { value: "cursor", label: "Cursor IDE", hint: ".mdc rules integration" },
232
- { value: "gemini", label: "Google Gemini", hint: "Massive context support" },
233
- { value: "github", label: "GitHub Copilot", hint: "Integrated experience" },
234
- { value: "codex", label: "Codex / Custom", hint: "General AGENTS.md" },
235
- { value: "none", label: "None / Rules Only", hint: "Pure .agent directory" },
236
- ],
237
- });
238
- if (isCancel(aiHost)) return cancel(t.shutdown);
239
-
240
- // Missing Steps Added
241
- const scope = await select({
242
- message: t.scopeQuestion,
243
- options: [
244
- { value: "personal", label: t.scopePersonal },
245
- { value: "small", label: t.scopeSmall },
246
- { value: "medium", label: t.scopeMedium },
247
- { value: "enterprise", label: t.scopeEnterprise },
248
- ]
249
- });
250
- if (isCancel(scope)) return cancel(t.shutdown);
251
-
252
- const type = await select({
253
- message: t.typeQuestion,
254
- options: [
255
- { value: "web", label: t.typeWeb },
256
- { value: "api", label: t.typeApi },
257
- { value: "mobile", label: t.typeMobile },
258
- { value: "library", label: t.typeLib },
259
- { value: "research", label: t.typeResearch },
260
- ]
261
- });
262
- if (isCancel(type)) return cancel(t.shutdown);
263
-
264
- const agentName = await text({
265
- message: t.nameQuestion,
266
- placeholder: t.namePlaceholder,
267
- defaultValue: t.namePlaceholder
268
- });
269
- if (isCancel(agentName)) return cancel(t.shutdown);
270
-
271
- return { mode: 'selective', locale, stack, aiHost, scope, type, agentName };
272
- }
273
-
274
- /**
275
- * Print Summary Table
276
- */
277
- function printSummary(config, targetDir, t) {
278
- const mode = config.mode === 'all' ? pc.magenta(t.modeAll) : pc.cyan(t.modeSelective);
279
- const stackContent = Array.isArray(config.stack) ? config.stack.join(', ').toUpperCase() : (config.stack ? config.stack.toUpperCase() : "ALL");
280
- const stack = pc.yellow(stackContent);
281
- const ai = config.aiHost ? pc.green(config.aiHost.toUpperCase()) : pc.dim("ALL");
282
-
283
- console.log("\n" + pc.dim("┌──────────────────────────────────────────────────────────┐"));
284
- console.log(`${pc.dim("")} ${pc.bold(t.summaryTitle)} ${pc.dim("│")}`);
285
- console.log(pc.dim("├──────────────────────────────────────────────────────────┤"));
286
- console.log(`${pc.dim("│")} Mode : ${mode.padEnd(50)} ${pc.dim("│")}`);
287
- console.log(`${pc.dim("│")} Stack : ${stack.padEnd(60)} ${pc.dim("│")}`);
288
- console.log(`${pc.dim("│")} AI Host : ${ai.padEnd(50)} ${pc.dim("│")}`);
289
- if (config.agentName) {
290
- console.log(`${pc.dim("│")} Agent : ${pc.white(config.agentName).padEnd(50)} ${pc.dim("│")}`);
291
- }
292
- console.log(`${pc.dim("")} Target : ${pc.dim(targetDir).padEnd(50)} ${pc.dim("│")}`);
293
- console.log(pc.dim("└──────────────────────────────────────────────────────────┘\n"));
294
- }
295
-
296
- async function main() {
297
- const args = process.argv.slice(2);
298
- const options = parseArgs(args);
299
- const targetDir = path.resolve(process.cwd(), options.targetDir);
300
-
301
- const t = i18n[options.locale] || i18n.vi;
302
-
303
- if (options.template) {
304
- runScaffold(options, t);
305
- }
306
-
307
- let config;
308
- if (options.profile === 'all') {
309
- printBanner();
310
- config = { mode: 'all', locale: options.locale };
311
- } else if (options.stack && options.aiHost) {
312
- config = { mode: 'selective', stack: options.stack, aiHost: options.aiHost, locale: options.locale };
313
- } else if (!options.template && options.profile !== 'all') {
314
- const result = await runWizard(options);
315
- if (!result) return;
316
- config = result;
317
- } else {
318
- config = { mode: 'selective', stack: options.stack || ['typescript'], aiHost: options.aiHost || 'claude', locale: options.locale };
319
- }
320
-
321
- const activeT = i18n[config.locale] || i18n.vi;
322
- const s = spinner();
323
-
324
- const steps = [
325
- { msg: activeT.installing, action: async () => {
326
- if (config.mode === 'all') {
327
- await installer.installProfileAll(targetDir, config);
328
- } else {
329
- await installer.installSelective({ ...config, targetDir });
330
- }
331
- }},
332
- { msg: activeT.calibrating, action: async () => {} },
333
- { msg: activeT.optimizing, action: async () => {} }
334
- ];
335
-
336
- for (const step of steps) {
337
- s.start(pc.magenta(step.msg));
338
- await step.action();
339
- await new Promise(r => setTimeout(r, 600));
340
- s.stop(pc.green(`✓ ${step.msg}`));
341
- }
342
-
343
- printSummary(config, targetDir, activeT);
344
-
345
- note(
346
- pc.white(activeT.ready + "\n") +
347
- pc.bold(pc.yellow(activeT.readReadme)),
348
- activeT.systemReady
349
- );
350
-
351
- outro(pc.magenta(pc.bold(activeT.outro)));
352
- }
353
-
354
- main().catch(console.error);
1
+ #!/usr/bin/env node
2
+
3
+ const {
4
+ intro,
5
+ outro,
6
+ select,
7
+ multiselect,
8
+ text,
9
+ spinner,
10
+ cancel,
11
+ isCancel,
12
+ note,
13
+ } = require("@clack/prompts");
14
+ const pc = require("picocolors");
15
+ const path = require("node:path");
16
+ const { spawnSync } = require("node:child_process");
17
+ const installer = require("../lib/installer");
18
+
19
+ /**
20
+ * Translations (Bilingual i18n)
21
+ */
22
+ const i18n = {
23
+ vi: {
24
+ intro: " THIẾT LẬP HỒ SƠ VẬN HÀNH ",
25
+ langQuestion: "Giao thức ngôn ngữ chính?",
26
+ modeQuestion: "Phạm vi cài đặt:",
27
+ modeAll: "Elite / Đầy đủ",
28
+ modeAllHint: "Triển khai TẤT CẢ các module .agent & AI host",
29
+ modeSelective: "Surgical / Tùy chọn",
30
+ modeSelectiveHint: "Tối ưu hóa theo Stack & IDE mục tiêu",
31
+ stackQuestion: "Stack kỹ thuật mục tiêu (Dùng Space để chọn nhiều):",
32
+ aiQuestion: "Trình điều phối AI mục tiêu:",
33
+ scopeQuestion: "Quy mô dự án?",
34
+ scopePersonal: "Cá nhân",
35
+ scopeSmall: "Nhóm nhỏ (SME)",
36
+ scopeMedium: "Doanh nghiệp vừa",
37
+ scopeEnterprise: "Tập đoàn/Hệ thống lớn",
38
+ typeQuestion: "Loại sản phẩm?",
39
+ typeLanding: "Landing Page / Trang tĩnh",
40
+ typeLandingHint: "Trang giới thiệu, portfolio, chỉ Frontend",
41
+ typeWebapp: "Webapp Tiêu chuẩn (Fullstack)",
42
+ typeWebappHint: "Dashboard, SaaS, CMS, Ecommerce",
43
+ typeCross: "Hệ sinh thái Đa nền tảng",
44
+ typeCrossHint: "Web + Mobile + Desktop dùng chung dữ liệu",
45
+ typeDesktop: "Ứng dụng Desktop (Windows/macOS)",
46
+ typeDesktopHint: "Electron, Tauri, ứng dụng cài đặt",
47
+ typeMobile: "Ứng dụng Di động (Native/Hybrid)",
48
+ typeMobileHint: "Flutter, React Native, SwiftUI",
49
+ typeApi: "API & Backend Hub",
50
+ typeApiHint: "Microservices, Serverless, REST/GraphQL",
51
+ typeLib: "Công cụ & Thư viện (SDK/CLI)",
52
+ typeLibHint: "Package dùng chung, DevTools, CLI",
53
+ typeResearch: "Nghiên cứu & Phân tích dữ liệu",
54
+ typeResearchHint: "Data Science, Machine Learning, Reports",
55
+ deployQuestion: "Nền tảng triển khai mục tiêu?",
56
+ deployVercel: "Vercel",
57
+ deployVercelHint: "Chuẩn cho Next.js, React, Static sites",
58
+ deployGhPages: "GitHub Pages",
59
+ deployGhPagesHint: "Hosting miễn phí cho các trang tĩnh",
60
+ deployDocker: "Docker / Container",
61
+ deployDockerHint: "Đóng gói cho Cloud/VPS/Kubernetes",
62
+ deployCustom: "Tùy chọn (Tự thiết lập)",
63
+ deployCustomHint: "Agent sẽ hỗ trợ hướng dẫn tổng quát",
64
+ nameQuestion: "Đặt tên cho AI Agent của bạn? (Mặc định: Pilo)",
65
+ namePlaceholder: "Pilo",
66
+ installing: "Đang mapping kiến trúc dự án...",
67
+ calibrating: "Đang hiệu chuẩn các gói AI Host...",
68
+ optimizing: "Đang tối ưu hóa quy trình vận hành...",
69
+ generatingWiki: "Đang khởi tạo Wiki lệnh tùy chỉnh...",
70
+ ready: "Giao thức vận hành đã được khởi tạo. Lực lượng đặc nhiệm AI của bạn đã trực tuyến.",
71
+ activateAgent: (name) => `Kích hoạt Agent bằng cách gọi: '${pc.bold(pc.cyan(`Chào ${name}`))}' hoặc '${pc.bold(pc.cyan(`Wakeup ${name}`))}' để bắt đầu phiên làm việc.`,
72
+ wikiReady: "Xem PILO_WIKI.md để tra cứu toàn bộ Slash Commands dành riêng cho dự án của bạn.",
73
+ done: "Hoàn tất!",
74
+ summaryTitle: "TỔNG KẾT TRIỂN KHAI",
75
+ systemReady: "HỆ THỐNG SẴN SÀNG",
76
+ shutdown: "Hệ thống dừng.",
77
+ outro: " ĐIỀU PHỐI TƯƠNG LAI VỚI KỶ LUẬT VÀ TÂM HỒN ⚡"
78
+ },
79
+ en: {
80
+ intro: " SELECT YOUR OPERATIONAL PROFILE ",
81
+ langQuestion: "Primary Language Protocol?",
82
+ modeQuestion: "Installation Spectrum:",
83
+ modeAll: "Elite / Full",
84
+ modeAllHint: "Deploy ALL .agent modules & ALL AI hosts",
85
+ modeSelective: "Surgical / Selective",
86
+ modeSelectiveHint: "Optimize by Stack & Target IDE",
87
+ stackQuestion: "Target Technical Stack (Use Space to select multiple):",
88
+ aiQuestion: "Target AI Orchestrator:",
89
+ scopeQuestion: "Project Scope?",
90
+ scopePersonal: "Personal",
91
+ scopeSmall: "Small Team",
92
+ scopeMedium: "Medium Enterprise",
93
+ scopeEnterprise: "Large Enterprise/System",
94
+ typeQuestion: "Product Type?",
95
+ typeLanding: "Landing Page / Static Site",
96
+ typeLandingHint: "Portfolio, showcase, frontend-only",
97
+ typeWebapp: "Standard Webapp (Fullstack)",
98
+ typeWebappHint: "Dashboard, SaaS, CMS, Ecommerce",
99
+ typeCross: "Cross-Platform Suite",
100
+ typeCrossHint: "Web + Mobile + Desktop sharing data",
101
+ typeDesktop: "Desktop Application (Windows/macOS)",
102
+ typeDesktopHint: "Electron, Tauri, installable apps",
103
+ typeMobile: "Mobile Application (Native/Hybrid)",
104
+ typeMobileHint: "Flutter, React Native, SwiftUI",
105
+ typeApi: "API & Backend Hub",
106
+ typeApiHint: "Microservices, Serverless, REST/GraphQL",
107
+ typeLib: "Library & Tools (SDK/CLI)",
108
+ typeLibHint: "Shared packages, DevTools, CLI",
109
+ typeResearch: "Research & Data Analysis",
110
+ typeResearchHint: "Data Science, Machine Learning, Reports",
111
+ deployQuestion: "Target Deployment Platform?",
112
+ deployVercel: "Vercel",
113
+ deployVercelHint: "Best for Next.js, React, Static sites",
114
+ deployGhPages: "GitHub Pages",
115
+ deployGhPagesHint: "Free hosting for static sites",
116
+ deployDocker: "Docker / Container",
117
+ deployDockerHint: "Package for Cloud/VPS/Kubernetes",
118
+ deployCustom: "Custom (Self-managed)",
119
+ deployCustomHint: "Agent will provide general guidance",
120
+ nameQuestion: "Name your AI Agent? (Default: Pilo)",
121
+ namePlaceholder: "Pilo",
122
+ installing: "Mapping project architecture...",
123
+ calibrating: "Calibrating AI Host bundles...",
124
+ optimizing: "Optimizing operational workflows...",
125
+ generatingWiki: "Generating custom command wiki...",
126
+ ready: "Operational protocol initialized. Your AI Task Force is now online.",
127
+ activateAgent: (name) => `Activate your Agent by calling: '${pc.bold(pc.cyan(`Hey ${name}`))}' or '${pc.bold(pc.cyan(`Wakeup ${name}`))}' to start the session.`,
128
+ wikiReady: "Check PILO_WIKI.md for a full list of Slash Commands tailored to your project.",
129
+ done: "Done!",
130
+ summaryTitle: "DEPLOYMENT SUMMARY",
131
+ systemReady: "SYSTEM READY",
132
+ shutdown: "System shutdown.",
133
+ outro: "⚡ ORCHESTRATING THE FUTURE WITH DISCIPLINE AND SOUL ⚡"
134
+ }
135
+ };
136
+
137
+ /**
138
+ * Print a premium stylized banner
139
+ */
140
+ function printBanner() {
141
+ console.log("\n" + pc.magenta(" ██████╗ ██╗██╗ ██████╗ ███╗ ███╗ █████╗ ███████╗████████╗███████╗██████╗ "))
142
+ console.log(pc.magenta(" ██╔══██╗██║██║ ██╔═══██╗ ████╗ ████║██╔══██╗██╔════╝╚══██╔══╝██╔════╝██╔══██╗"))
143
+ console.log(pc.magenta(" ██████╔╝██║██║ ██║ ██║ ██╔████╔██║███████║███████╗ ██║ █████╗ ██████╔╝"))
144
+ console.log(pc.magenta(" ██╔═══╝ ██║██║ ██║ ██║ ██║╚██╔╝██║██╔══██║╚════██║ ██║ ██╔══╝ ██╔══██╗"))
145
+ console.log(pc.magenta(" ██║ ██║███████╗╚██████╔╝ ██║ ╚═╝ ██║██║ ██║███████║ ██║ ███████╗██║ ██║"))
146
+ console.log(pc.magenta(" ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝"))
147
+ console.log(pc.bold(pc.cyan("\n SYSTEM INITIALIZER v2.2\n")));
148
+ }
149
+
150
+ /**
151
+ * Basic argument parser
152
+ */
153
+ function parseArgs(args) {
154
+ const options = {
155
+ command: 'init',
156
+ targetDir: '.',
157
+ profile: null,
158
+ template: null,
159
+ aiHost: null,
160
+ stack: null,
161
+ locale: 'vi'
162
+ };
163
+
164
+ for (let i = 0; i < args.length; i++) {
165
+ const arg = args[i];
166
+ if (arg === 'init') {
167
+ options.command = 'init';
168
+ } else if (arg.startsWith('--profile=')) {
169
+ options.profile = arg.split('=')[1];
170
+ } else if (arg === '--profile' && args[i+1]) {
171
+ options.profile = args[++i];
172
+ } else if (arg.startsWith('--template:')) {
173
+ options.template = arg.replace('--template:', '');
174
+ } else if (arg.startsWith('--ai=')) {
175
+ options.aiHost = arg.split('=')[1];
176
+ } else if (arg.startsWith('--stack=')) {
177
+ const stacks = arg.split('=')[1].split(',');
178
+ options.stack = stacks;
179
+ } else if (arg.startsWith('--locale=')) {
180
+ options.locale = arg.split('=')[1];
181
+ } else if (!arg.startsWith('-')) {
182
+ options.targetDir = arg;
183
+ }
184
+ }
185
+ return options;
186
+ }
187
+
188
+ /**
189
+ * Run external scaffold
190
+ */
191
+ function runScaffold(options, t) {
192
+ const [templateName] = options.template.split(' ');
193
+
194
+ const s = spinner();
195
+ s.start(pc.cyan(`⚡ Scaffolding upstream project: ${pc.bold(templateName)}...`));
196
+
197
+ let command = '';
198
+ let args = [];
199
+
200
+ if (templateName.startsWith('react')) {
201
+ command = 'npm';
202
+ args = ['create', 'vite@latest', options.targetDir, '--', '--template', 'react-ts'];
203
+ } else if (templateName.startsWith('next')) {
204
+ command = 'npx';
205
+ args = ['create-next-app@latest', options.targetDir, '--typescript', '--tailwind', '--eslint', '--app', '--src-dir', '--import-alias', '"@/*"'];
206
+ } else {
207
+ command = 'npm';
208
+ args = ['create', `${templateName}@latest`, options.targetDir];
209
+ }
210
+
211
+ s.stop(pc.green(" Upstream command detected."));
212
+
213
+ const result = spawnSync(command, args, { stdio: 'inherit', shell: true });
214
+ if (result.status !== 0) {
215
+ console.error(pc.red('\n✖ Scaffolding failed. Check command outputs above.'));
216
+ process.exit(1);
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Interactive Wizard
222
+ */
223
+ async function runWizard(options) {
224
+ printBanner();
225
+
226
+ const locale = await select({
227
+ message: "Primary Language Protocol?",
228
+ options: [
229
+ { value: "vi", label: "Vietnamese (Tiếng Việt)", hint: "Support localized documentation" },
230
+ { value: "en", label: "English", hint: "Global standard" },
231
+ ],
232
+ });
233
+ if (isCancel(locale)) return cancel("System shutdown.");
234
+
235
+ const t = i18n[locale];
236
+
237
+ intro(pc.bgMagenta(pc.white(t.intro)));
238
+
239
+ const mode = await select({
240
+ message: t.modeQuestion,
241
+ options: [
242
+ { value: "all", label: t.modeAll, hint: t.modeAllHint },
243
+ { value: "selective", label: t.modeSelective, hint: t.modeSelectiveHint },
244
+ ],
245
+ });
246
+ if (isCancel(mode)) return cancel(t.shutdown);
247
+
248
+ if (mode === 'all') {
249
+ // Even in 'all' mode, ask for agent name for personalized outro
250
+ const agentName = await text({
251
+ message: t.nameQuestion,
252
+ placeholder: t.namePlaceholder,
253
+ defaultValue: t.namePlaceholder
254
+ });
255
+ if (isCancel(agentName)) return cancel(t.shutdown);
256
+ return { mode: 'all', locale, agentName };
257
+ }
258
+
259
+ const stack = await multiselect({
260
+ message: t.stackQuestion,
261
+ options: [
262
+ { value: "typescript", label: "TypeScript Standard", hint: "React, Next.js, Node.js (Fullstack)" },
263
+ { value: "python", label: "Python Intelligence", hint: "FastAPI, PyTorch, LangChain" },
264
+ { value: "ai_agentic", label: "Agentic Engineering", hint: "MCP, Claude SDK, Autonomy" },
265
+ { value: "rust", label: "Rust/C++ Engineering", hint: "High-performance systems" },
266
+ { value: "laravel", label: "PHP Modern (Laravel)", hint: "Web backend, APIs" },
267
+ { value: "mobile", label: "Mobile Multi-platform", hint: "Flutter, React Native, SwiftUI" },
268
+ { value: "java", label: "Java/Kotlin Enterprise", hint: "Spring Boot, Ktor, Microservices" },
269
+ { value: "go", label: "Go Cloud Services", hint: "Microservices, Cloud-native" },
270
+ { value: "marketing_research", label: "Deep Research & Content", hint: "Analysis, SEO, Market Intel" },
271
+ ],
272
+ required: true,
273
+ });
274
+ if (isCancel(stack)) return cancel(t.shutdown);
275
+
276
+ const aiHost = await select({
277
+ message: t.aiQuestion,
278
+ options: [
279
+ { value: "claude", label: "Claude Code / CLI", hint: "Best for agentic tasks" },
280
+ { value: "cursor", label: "Cursor IDE", hint: ".mdc rules integration" },
281
+ { value: "gemini", label: "Google Gemini", hint: "Massive context support" },
282
+ { value: "github", label: "GitHub Copilot", hint: "Integrated experience" },
283
+ { value: "codex", label: "Codex / Custom", hint: "General AGENTS.md" },
284
+ { value: "none", label: "None / Rules Only", hint: "Pure .agent directory" },
285
+ ],
286
+ });
287
+ if (isCancel(aiHost)) return cancel(t.shutdown);
288
+
289
+ const scope = await select({
290
+ message: t.scopeQuestion,
291
+ options: [
292
+ { value: "personal", label: t.scopePersonal },
293
+ { value: "small", label: t.scopeSmall },
294
+ { value: "medium", label: t.scopeMedium },
295
+ { value: "enterprise", label: t.scopeEnterprise },
296
+ ]
297
+ });
298
+ if (isCancel(scope)) return cancel(t.shutdown);
299
+
300
+ const type = await select({
301
+ message: t.typeQuestion,
302
+ options: [
303
+ { value: "landing", label: t.typeLanding, hint: t.typeLandingHint },
304
+ { value: "webapp", label: t.typeWebapp, hint: t.typeWebappHint },
305
+ { value: "cross_platform", label: t.typeCross, hint: t.typeCrossHint },
306
+ { value: "desktop", label: t.typeDesktop, hint: t.typeDesktopHint },
307
+ { value: "mobile", label: t.typeMobile, hint: t.typeMobileHint },
308
+ { value: "api", label: t.typeApi, hint: t.typeApiHint },
309
+ { value: "library", label: t.typeLib, hint: t.typeLibHint },
310
+ { value: "research", label: t.typeResearch, hint: t.typeResearchHint },
311
+ ]
312
+ });
313
+ if (isCancel(type)) return cancel(t.shutdown);
314
+
315
+ const deploy = await select({
316
+ message: t.deployQuestion,
317
+ options: [
318
+ { value: "vercel", label: t.deployVercel, hint: t.deployVercelHint },
319
+ { value: "gh_pages", label: t.deployGhPages, hint: t.deployGhPagesHint },
320
+ { value: "docker", label: t.deployDocker, hint: t.deployDockerHint },
321
+ { value: "custom", label: t.deployCustom, hint: t.deployCustomHint },
322
+ ]
323
+ });
324
+ if (isCancel(deploy)) return cancel(t.shutdown);
325
+
326
+ const agentName = await text({
327
+ message: t.nameQuestion,
328
+ placeholder: t.namePlaceholder,
329
+ defaultValue: t.namePlaceholder
330
+ });
331
+ if (isCancel(agentName)) return cancel(t.shutdown);
332
+
333
+ return { mode: 'selective', locale, stack, aiHost, scope, type, deploy, agentName };
334
+ }
335
+
336
+ /**
337
+ * Print Summary Table
338
+ */
339
+ function printSummary(config, targetDir, t) {
340
+ const mode = config.mode === 'all' ? pc.magenta(t.modeAll) : pc.cyan(t.modeSelective);
341
+ const stackContent = Array.isArray(config.stack) ? config.stack.join(', ').toUpperCase() : (config.stack ? config.stack.toUpperCase() : "ALL");
342
+ const stack = pc.yellow(stackContent);
343
+ const ai = config.aiHost ? pc.green(config.aiHost.toUpperCase()) : pc.dim("ALL");
344
+
345
+ console.log("\n" + pc.dim("┌──────────────────────────────────────────────────────────┐"));
346
+ console.log(`${pc.dim("│")} ${pc.bold(t.summaryTitle)} ${pc.dim("")}`);
347
+ console.log(pc.dim("├──────────────────────────────────────────────────────────┤"));
348
+ console.log(`${pc.dim("│")} Mode : ${mode.padEnd(50)} ${pc.dim("│")}`);
349
+ console.log(`${pc.dim("│")} Stack : ${stack.padEnd(60)} ${pc.dim("│")}`);
350
+ console.log(`${pc.dim("│")} AI Host : ${ai.padEnd(50)} ${pc.dim("│")}`);
351
+ if (config.agentName) {
352
+ console.log(`${pc.dim("│")} Agent : ${pc.white(config.agentName).padEnd(50)} ${pc.dim("│")}`);
353
+ }
354
+ if (config.deploy) {
355
+ console.log(`${pc.dim("│")} Deploy : ${pc.blue(config.deploy.toUpperCase()).padEnd(50)} ${pc.dim("│")}`);
356
+ }
357
+ console.log(`${pc.dim("│")} Target : ${pc.dim(targetDir).padEnd(50)} ${pc.dim("│")}`);
358
+ console.log(pc.dim("└──────────────────────────────────────────────────────────┘\n"));
359
+ }
360
+
361
+ async function main() {
362
+ const args = process.argv.slice(2);
363
+ const options = parseArgs(args);
364
+ const targetDir = path.resolve(process.cwd(), options.targetDir);
365
+
366
+ const t = i18n[options.locale] || i18n.vi;
367
+
368
+ if (options.template) {
369
+ runScaffold(options, t);
370
+ }
371
+
372
+ let config;
373
+ if (options.profile === 'all') {
374
+ printBanner();
375
+ config = { mode: 'all', locale: options.locale, agentName: 'Pilo' };
376
+ } else if (options.stack && options.aiHost) {
377
+ config = { mode: 'selective', stack: options.stack, aiHost: options.aiHost, locale: options.locale, agentName: 'Pilo' };
378
+ } else if (!options.template && options.profile !== 'all') {
379
+ const result = await runWizard(options);
380
+ if (!result) return;
381
+ config = result;
382
+ } else {
383
+ config = { mode: 'selective', stack: options.stack || ['typescript'], aiHost: options.aiHost || 'claude', locale: options.locale, agentName: 'Pilo' };
384
+ }
385
+
386
+ const activeT = i18n[config.locale] || i18n.vi;
387
+ const agentName = config.agentName || 'Pilo';
388
+ const s = spinner();
389
+
390
+ const steps = [
391
+ { msg: activeT.installing, action: async () => {
392
+ if (config.mode === 'all') {
393
+ await installer.installProfileAll(targetDir, config);
394
+ } else {
395
+ await installer.installSelective({ ...config, targetDir });
396
+ }
397
+ }},
398
+ { msg: activeT.calibrating, action: async () => {} },
399
+ { msg: activeT.optimizing, action: async () => {} },
400
+ { msg: activeT.generatingWiki, action: async () => {
401
+ await installer.generateWiki(targetDir, config);
402
+ }}
403
+ ];
404
+
405
+ for (const step of steps) {
406
+ s.start(pc.magenta(step.msg));
407
+ await step.action();
408
+ await new Promise(r => setTimeout(r, 600));
409
+ s.stop(pc.green(`✓ ${step.msg}`));
410
+ }
411
+
412
+ printSummary(config, targetDir, activeT);
413
+
414
+ note(
415
+ pc.white(activeT.ready + "\n") +
416
+ pc.bold(pc.yellow(activeT.activateAgent(agentName))) + "\n" +
417
+ pc.dim(activeT.wikiReady),
418
+ activeT.systemReady
419
+ );
420
+
421
+ outro(pc.magenta(pc.bold(activeT.outro)));
422
+ }
423
+
424
+ main().catch(console.error);