aiwf 0.3.3 β 0.3.4
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/.aiwf/config/language.json +1 -1
- package/.aiwf/sessions/session_1752877859489_1t7n2fhdb.json +7 -0
- package/.aiwf/sessions/session_1752877859515_cwdv211ry.json +7 -0
- package/.aiwf/sessions/session_1752877860664_huziadmbo.json +7 -0
- package/.aiwf/sessions/session_1752877860666_kyr5u1np6.json +7 -0
- package/.aiwf/sessions/session_1752877861848_9yinepw3t.json +7 -0
- package/.aiwf/sessions/session_1752877861874_y32sputuc.json +7 -0
- package/.aiwf/sessions/session_1752877862685_ivxbl5rhz.json +7 -0
- package/.aiwf/sessions/session_1752877862820_wnq4glvxi.json +7 -0
- package/.aiwf/sessions/session_1752877864632_3ebnpaelb.json +7 -0
- package/.aiwf/sessions/session_1752877864879_b9zgjcb7d.json +7 -0
- package/.aiwf/sessions/session_1752877865533_x14m1vodi.json +7 -0
- package/.aiwf/sessions/session_1752877865562_gkoh19n7d.json +7 -0
- package/.aiwf/sessions/session_1752877866333_wp8qpdcoh.json +7 -0
- package/.aiwf/sessions/session_1752877866509_dawntfpab.json +7 -0
- package/.aiwf/sessions/session_1752877866890_plc5vfucl.json +7 -0
- package/.aiwf/sessions/session_1752877866895_ga8hmq3oi.json +7 -0
- package/.aiwf/sessions/session_1752877867761_ayjp4v5f5.json +7 -0
- package/.aiwf/sessions/session_1752877867892_lfz6jy252.json +7 -0
- package/.aiwf/sessions/session_1752877868139_7bqd9ubli.json +7 -0
- package/.aiwf/sessions/session_1752877868162_zq3ofjbsh.json +7 -0
- package/.aiwf/sessions/session_1752877869054_7rlgm9jt6.json +7 -0
- package/.aiwf/sessions/session_1752877869477_ax3nhbxzr.json +7 -0
- package/.aiwf/sessions/session_1752877870095_6hgp4vl1e.json +7 -0
- package/.aiwf/sessions/session_1752877870381_qfcrdg4li.json +7 -0
- package/.aiwf/sessions/session_1752877871895_pgd5vllhz.json +7 -0
- package/.aiwf/sessions/session_1752877872199_jbhv2g2da.json +7 -0
- package/.aiwf/sessions/session_1752877872680_x04wpffu6.json +7 -0
- package/.aiwf/sessions/session_1752877872895_3y4vbeauo.json +7 -0
- package/.aiwf/sessions/session_1752877873178_3maolzc6b.json +7 -0
- package/.aiwf/sessions/session_1752877873180_ytm83j07f.json +7 -0
- package/.aiwf/sessions/session_1752877874217_dp56c9t42.json +7 -0
- package/.aiwf/sessions/session_1752877874415_epwp1g1og.json +7 -0
- package/.aiwf/sessions/session_1752877874454_heicyuryb.json +7 -0
- package/.aiwf/sessions/session_1752877874869_1c2illeu5.json +7 -0
- package/.aiwf/sessions/session_1752877874879_k1vo4vxyx.json +7 -0
- package/.aiwf/sessions/session_1752877874913_bwgyiz9bp.json +7 -0
- package/.aiwf/sessions/session_1752877876218_44807kztz.json +7 -0
- package/.aiwf/sessions/session_1752877876515_qkhjv5kpw.json +7 -0
- package/.aiwf/sessions/session_1752877876543_p605aud1m.json +7 -0
- package/.aiwf/sessions/session_1752877876819_l65w7ifck.json +7 -0
- package/.aiwf/sessions/session_1752877876867_xrhzss4we.json +7 -0
- package/.aiwf/sessions/session_1752877876872_u7aso54qb.json +7 -0
- package/.aiwf/sessions/session_1752877877705_telnfg4o6.json +7 -0
- package/.aiwf/sessions/session_1752877878285_6s45im2ib.json +7 -0
- package/.aiwf/sessions/session_1752877878506_v0dvguqhz.json +7 -0
- package/.aiwf/sessions/session_1752877878581_3ri3yc66a.json +7 -0
- package/.aiwf/sessions/session_1752877878756_a82x9s2pd.json +7 -0
- package/.aiwf/sessions/session_1752877878886_20pjsfour.json +7 -0
- package/.aiwf/sessions/session_1752877880266_fm1ydjw0g.json +7 -0
- package/.aiwf/sessions/session_1752877881149_xbat4z03d.json +7 -0
- package/.aiwf/sessions/session_1752877881551_qy5sic9qs.json +7 -0
- package/.aiwf/sessions/session_1752877881554_24ugd96wu.json +7 -0
- package/.aiwf/sessions/session_1752877881797_e9mm25uh0.json +7 -0
- package/.aiwf/sessions/session_1752877881822_bxvjj8c9g.json +7 -0
- package/.aiwf/sessions/session_1752877881890_jv7l6jve3.json +7 -0
- package/.aiwf/sessions/session_1752877881991_f0qugdtcq.json +7 -0
- package/.aiwf/sessions/session_1752877883387_0bvw9rvnx.json +7 -0
- package/.aiwf/sessions/session_1752877883820_q6g2md2up.json +7 -0
- package/.aiwf/sessions/session_1752877884393_sqr7trvjl.json +7 -0
- package/.aiwf/sessions/session_1752877884500_whtypmzlf.json +7 -0
- package/.aiwf/sessions/session_1752877884645_y9mvvxli1.json +7 -0
- package/.aiwf/sessions/session_1752877884733_hk46eenel.json +7 -0
- package/.aiwf/sessions/session_1752877884738_c62j6214r.json +7 -0
- package/.aiwf/sessions/session_1752877884771_temhxehoz.json +7 -0
- package/.aiwf/sessions/session_1752877885643_6v5fcktc7.json +7 -0
- package/.aiwf/sessions/session_1752877886426_ee8di2fqh.json +7 -0
- package/.aiwf/sessions/session_1752877886549_3xj6tdoew.json +7 -0
- package/.aiwf/sessions/session_1752877886604_aj80yyfco.json +7 -0
- package/.aiwf/sessions/session_1752877886702_2b8841vyg.json +7 -0
- package/.aiwf/sessions/session_1752877886712_ntqc8b8bz.json +7 -0
- package/.aiwf/sessions/session_1752877886968_946m8tbw6.json +7 -0
- package/.aiwf/sessions/session_1752877887008_wg6zfg8dn.json +7 -0
- package/.aiwf/sessions/session_1752877888479_ciiu2qiqs.json +7 -0
- package/.aiwf/sessions/session_1752877889330_ravg8l66k.json +7 -0
- package/.aiwf/sessions/session_1752877889542_7zepkhjkc.json +7 -0
- package/.aiwf/sessions/session_1752877889638_ev4htqiu0.json +7 -0
- package/.aiwf/sessions/session_1752877889956_szphy2qma.json +7 -0
- package/.aiwf/sessions/session_1752877890220_o6aaa57tt.json +7 -0
- package/.aiwf/sessions/session_1752877890527_v2loy5vu1.json +7 -0
- package/.aiwf/sessions/session_1752877890572_cwq8fiuma.json +7 -0
- package/.aiwf/sessions/session_1752877892200_sgcwq1alt.json +7 -0
- package/.aiwf/sessions/session_1752877892268_v8kexpbc5.json +7 -0
- package/.aiwf/sessions/session_1752877892384_1gbbgrp4y.json +7 -0
- package/.aiwf/sessions/session_1752877893568_9p2n5p31a.json +7 -0
- package/.aiwf/sessions/session_1752877893727_un34a5tvp.json +7 -0
- package/.aiwf/sessions/session_1752877893778_01j79sw9i.json +7 -0
- package/.aiwf/sessions/session_1752877894053_jrhba6wko.json +7 -0
- package/.aiwf/sessions/session_1752877894082_x3bghawox.json +7 -0
- package/.aiwf/sessions/session_1752877894500_iytiav2ku.json +7 -0
- package/.aiwf/sessions/session_1752877894667_ucn0gc2ge.json +7 -0
- package/.aiwf/test-results-s02.json +4 -4
- package/.claude/commands/aiwf/aiwf_changelog.md +82 -0
- package/.claude/commands/aiwf/aiwf_code_review.md +88 -0
- package/.claude/commands/aiwf/aiwf_commit.md +160 -0
- package/.claude/commands/aiwf/aiwf_compress_aggressive_persona.md +53 -0
- package/.claude/commands/aiwf/aiwf_compress_context.md +116 -0
- package/.claude/commands/aiwf/aiwf_compress_minimal_persona.md +48 -0
- package/.claude/commands/aiwf/aiwf_compress_stats.md +79 -0
- package/.claude/commands/aiwf/aiwf_compress_with_persona.md +51 -0
- package/.claude/commands/aiwf/aiwf_create_feature_ledger.md +54 -0
- package/.claude/commands/aiwf/aiwf_create_general_task.md +147 -0
- package/.claude/commands/aiwf/aiwf_create_milestone_plan.md +194 -0
- package/.claude/commands/aiwf/aiwf_create_prd.md +280 -0
- package/.claude/commands/aiwf/aiwf_create_sprint_tasks.md +189 -0
- package/.claude/commands/aiwf/aiwf_create_sprints_from_milestone.md +121 -0
- package/.claude/commands/aiwf/aiwf_default_mode.md +44 -0
- package/.claude/commands/aiwf/aiwf_discuss_review.md +29 -0
- package/.claude/commands/aiwf/aiwf_do_task.md +109 -0
- package/.claude/commands/aiwf/aiwf_docs.md +225 -0
- package/.claude/commands/aiwf/aiwf_evaluate.md +92 -0
- package/.claude/commands/aiwf/aiwf_get_feature_details.md +78 -0
- package/.claude/commands/aiwf/aiwf_infinite.md +202 -0
- package/.claude/commands/aiwf/aiwf_initialize.md +134 -0
- package/.claude/commands/aiwf/aiwf_issue_create.md +65 -0
- package/.claude/commands/aiwf/aiwf_link_feature_to_milestone.md +57 -0
- package/.claude/commands/aiwf/aiwf_list_features.md +54 -0
- package/.claude/commands/aiwf/aiwf_mermaid.md +272 -0
- package/.claude/commands/aiwf/aiwf_persona_architect.md +48 -0
- package/.claude/commands/aiwf/aiwf_persona_backend.md +37 -0
- package/.claude/commands/aiwf/aiwf_persona_data_analyst.md +37 -0
- package/.claude/commands/aiwf/aiwf_persona_frontend.md +37 -0
- package/.claude/commands/aiwf/aiwf_persona_security.md +48 -0
- package/.claude/commands/aiwf/aiwf_persona_status.md +50 -0
- package/.claude/commands/aiwf/aiwf_pr_create.md +76 -0
- package/.claude/commands/aiwf/aiwf_prime.md +9 -0
- package/.claude/commands/aiwf/aiwf_project_review.md +261 -0
- package/.claude/commands/aiwf/aiwf_switch_language.md +160 -0
- package/.claude/commands/aiwf/aiwf_test.md +124 -0
- package/.claude/commands/aiwf/aiwf_testing_review.md +198 -0
- package/.claude/commands/aiwf/aiwf_tm-run-all-subtask.md +210 -0
- package/.claude/commands/aiwf/aiwf_ultrathink_code_advanced.md +460 -0
- package/.claude/commands/aiwf/aiwf_ultrathink_code_basic.md +165 -0
- package/.claude/commands/aiwf/aiwf_ultrathink_general.md +305 -0
- package/.claude/commands/aiwf/aiwf_update_docs_kr.md +25 -0
- package/.claude/commands/aiwf/aiwf_update_feature_status.md +53 -0
- package/.claude/commands/aiwf/aiwf_yolo.md +300 -0
- package/.eslintrc.json +26 -0
- package/.prettierrc +10 -0
- package/CLAUDE.md +154 -54
- package/README.ko.md +25 -0
- package/README.md +25 -0
- package/TEST_RECOVERY_PLAN.md +68 -0
- package/docs/CLEANUP_RECOMMENDATIONS.md +86 -0
- package/docs/CLI_USAGE_GUIDE.md +479 -0
- package/package.json +9 -9
- package/scripts/update-feature-status.js +70 -0
- package/{lib β src/cli}/cache-cli.js +4 -4
- package/src/cli/index.js +165 -0
- package/{language-cli.js β src/cli/language-cli.js} +11 -4
- package/src/commands/cache-templates.js +209 -0
- package/src/commands/create-offline.js +86 -0
- package/src/commands/create-project.js +151 -0
- package/src/lib/backup-manager.js +270 -0
- package/src/lib/file-downloader.js +208 -0
- package/src/lib/installer.js +676 -0
- package/src/lib/rollback-manager.js +418 -0
- package/src/lib/validator.js +561 -0
- package/src/utils/git-integration.js +173 -0
- package/{language-utils.js β src/utils/language-utils.js} +2 -1
- package/src/utils/messages.js +136 -0
- package/src/utils/paths.js +130 -0
- package/tests/application.test.js +2 -2
- package/tests/installer.test.js +2 -2
- package/tests/integration/ai-persona-system.test.js +4 -4
- package/tests/integration/test-persona-system/docs/README.md +1 -0
- package/tests/integration/test-persona-system/package.json +1 -0
- package/tests/integration/test-persona-system/src/auth.js +1 -0
- package/tests/integration/test-persona-system/src/index.js +1 -0
- package/tests/integration/test-persona-system/test/test.js +1 -0
- package/tests/language-utils.test.js +1 -1
- package/tests/temp_invalid_json/invalid.json +1 -0
- package/tests/unit/ai-persona-manager.test.js +7 -7
- package/.aiwf/05_DOCUMENTATION/performance-report.md +0 -33
- package/.aiwf/test-cache/86c7f9e80251abb8bedd58953ab0d1779e46b4f43ea33b63bffdb778106373b0.json +0 -6
- package/.aiwf/test-cache/9e252a90b80fce0585d7ed0646e7a9b4343e109f661f42a3ae678ba1ec5e22c7.json +0 -7
- package/.aiwf/token-data/alerts.json +0 -293
- package/.aiwf/token-data/monitor-config.json +0 -12
- package/CHANGELOG_M02.md +0 -52
- package/claude-code/aiwf/ko/templates/web-app/template/package-lock.json +0 -10022
- package/claude-code/aiwf/ko/token-data/alerts.json +0 -293
- package/claude-code/aiwf/ko/token-data/monitor-config.json +0 -12
- package/docs/m02-dod-checklist.md +0 -125
- package/docs/m02-gap-analysis.md +0 -214
- package/docs/m02-milestone-completion-report.md +0 -186
- package/docs/m02-milestone-executive-summary.md +0 -68
- package/index.js +0 -1951
- package/lib/cache-integration.js +0 -401
- package/lib/file-batch-processor.js +0 -401
- package/lib/performance-benchmark.js +0 -621
- package/lib/template-manager.js +0 -310
- package/scripts/validate-commands.cjs +0 -338
- /package/{lib β src/lib}/ai-persona-manager.js +0 -0
- /package/{lib β src/lib}/cache-system.js +0 -0
- /package/{lib β src/lib}/context-engine.js +0 -0
- /package/{lib β src/lib}/memory-profiler.js +0 -0
- /package/{lib β src/lib}/metrics-collector.js +0 -0
- /package/{lib β src/lib}/offline-detector.js +0 -0
- /package/{lib β src/lib}/task-analyzer.js +0 -0
- /package/{lib β src/lib}/template-cache-system.js +0 -0
- /package/{lib β src/lib}/template-downloader.js +0 -0
- /package/{lib β src/lib}/template-version-manager.js +0 -0
- /package/{lib β src/lib}/token-optimizer.js +0 -0
package/src/cli/index.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { program } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { installAIWF } from '../lib/installer.js';
|
|
6
|
+
import AIToolCommand from '../commands/ai-tool.js';
|
|
7
|
+
import { CacheCLI } from './cache-cli.js';
|
|
8
|
+
|
|
9
|
+
// Parse version from package.json
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { dirname, join } from 'path';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = dirname(__filename);
|
|
16
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
|
|
17
|
+
|
|
18
|
+
// Main program setup
|
|
19
|
+
program
|
|
20
|
+
.name('aiwf')
|
|
21
|
+
.version(packageJson.version)
|
|
22
|
+
.description('AIWF - AI Workflow Framework');
|
|
23
|
+
|
|
24
|
+
// Install command (default action)
|
|
25
|
+
program
|
|
26
|
+
.command('install', { isDefault: true })
|
|
27
|
+
.description('Install AIWF framework')
|
|
28
|
+
.option('-f, --force', 'Force install without prompts')
|
|
29
|
+
.action((options) => installAIWF({ ...options, debugLog: true }));
|
|
30
|
+
|
|
31
|
+
// AI Tool command
|
|
32
|
+
program
|
|
33
|
+
.command('ai-tool <subcommand> [tool-name]')
|
|
34
|
+
.description('Manage AI tool integrations')
|
|
35
|
+
.action(async (subcommand, toolName) => {
|
|
36
|
+
const aiToolCmd = new AIToolCommand();
|
|
37
|
+
const args = [subcommand];
|
|
38
|
+
if (toolName) args.push(toolName);
|
|
39
|
+
await aiToolCmd.execute(args);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Cache management commands
|
|
43
|
+
const cache = program.command('cache');
|
|
44
|
+
cache.description('Manage offline template cache');
|
|
45
|
+
|
|
46
|
+
cache
|
|
47
|
+
.command('download')
|
|
48
|
+
.description('Download templates for offline use')
|
|
49
|
+
.option('--all', 'Download all templates')
|
|
50
|
+
.option('--type <type>', 'Download specific type (ai-tools, projects)')
|
|
51
|
+
.action(async (options) => {
|
|
52
|
+
const cacheCLI = new CacheCLI();
|
|
53
|
+
try {
|
|
54
|
+
await cacheCLI.init();
|
|
55
|
+
await cacheCLI.downloadCommand(options);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(chalk.red('Cache download failed:', error.message));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
} finally {
|
|
60
|
+
await cacheCLI.cleanup();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
cache
|
|
65
|
+
.command('list')
|
|
66
|
+
.description('List cached templates')
|
|
67
|
+
.option('--type <type>', 'Filter by type (ai-tools, projects)')
|
|
68
|
+
.action(async (options) => {
|
|
69
|
+
const cacheCLI = new CacheCLI();
|
|
70
|
+
try {
|
|
71
|
+
await cacheCLI.init();
|
|
72
|
+
await cacheCLI.listCommand(options);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error(chalk.red('Cache list failed:', error.message));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
} finally {
|
|
77
|
+
await cacheCLI.cleanup();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
cache
|
|
82
|
+
.command('clean')
|
|
83
|
+
.description('Clean up cached templates')
|
|
84
|
+
.option('--all', 'Clear all cached templates')
|
|
85
|
+
.option('--max-age <days>', 'Maximum age in days (default: 7)', '7')
|
|
86
|
+
.action(async (options) => {
|
|
87
|
+
const cacheCLI = new CacheCLI();
|
|
88
|
+
try {
|
|
89
|
+
await cacheCLI.init();
|
|
90
|
+
await cacheCLI.cleanCommand(options);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error(chalk.red('Cache clean failed:', error.message));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
} finally {
|
|
95
|
+
await cacheCLI.cleanup();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
cache
|
|
100
|
+
.command('update')
|
|
101
|
+
.description('Check for template updates')
|
|
102
|
+
.option('--install', 'Install available updates')
|
|
103
|
+
.action(async (options) => {
|
|
104
|
+
const cacheCLI = new CacheCLI();
|
|
105
|
+
try {
|
|
106
|
+
await cacheCLI.init();
|
|
107
|
+
await cacheCLI.updateCommand(options);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error(chalk.red('Cache update failed:', error.message));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
} finally {
|
|
112
|
+
await cacheCLI.cleanup();
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
cache
|
|
117
|
+
.command('status')
|
|
118
|
+
.description('Show cache system status')
|
|
119
|
+
.action(async () => {
|
|
120
|
+
const cacheCLI = new CacheCLI();
|
|
121
|
+
try {
|
|
122
|
+
await cacheCLI.init();
|
|
123
|
+
await cacheCLI.statusCommand();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error(chalk.red('Cache status failed:', error.message));
|
|
126
|
+
process.exit(1);
|
|
127
|
+
} finally {
|
|
128
|
+
await cacheCLI.cleanup();
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Language management commands
|
|
133
|
+
const lang = program.command('lang');
|
|
134
|
+
lang.description('Manage language settings / μΈμ΄ μ€μ κ΄λ¦¬');
|
|
135
|
+
|
|
136
|
+
lang
|
|
137
|
+
.command('status')
|
|
138
|
+
.alias('s')
|
|
139
|
+
.description('Show current language configuration / νμ¬ μΈμ΄ μ€μ νμ')
|
|
140
|
+
.action(async () => {
|
|
141
|
+
const { showLanguageStatus } = await import('./language-cli.js');
|
|
142
|
+
await showLanguageStatus();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
lang
|
|
146
|
+
.command('set [language]')
|
|
147
|
+
.alias('switch')
|
|
148
|
+
.description('Set or change language / μΈμ΄ μ€μ λλ λ³κ²½')
|
|
149
|
+
.option('-a, --auto-detect [boolean]', 'Enable/disable auto detection / μλ κ°μ§ νμ±ν/λΉνμ±ν')
|
|
150
|
+
.action(async (language, options) => {
|
|
151
|
+
const { setLanguage } = await import('./language-cli.js');
|
|
152
|
+
await setLanguage(language, options);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
lang
|
|
156
|
+
.command('reset')
|
|
157
|
+
.alias('r')
|
|
158
|
+
.description('Reset language configuration to auto-detection / μΈμ΄ μ€μ μ μλ κ°μ§λ‘ μ΄κΈ°ν')
|
|
159
|
+
.action(async () => {
|
|
160
|
+
const { resetLanguage } = await import('./language-cli.js');
|
|
161
|
+
await resetLanguage();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Parse command line arguments
|
|
165
|
+
program.parse(process.argv);
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
getLocalizedMessage,
|
|
18
18
|
SUPPORTED_LANGUAGES,
|
|
19
19
|
DEFAULT_LANGUAGE
|
|
20
|
-
} from '
|
|
20
|
+
} from '../utils/language-utils.js';
|
|
21
21
|
|
|
22
22
|
const program = new Command();
|
|
23
23
|
|
|
@@ -75,7 +75,7 @@ function getCliMessage(key, language = DEFAULT_LANGUAGE) {
|
|
|
75
75
|
/**
|
|
76
76
|
* μΈμ΄ μ€μ μν νμ
|
|
77
77
|
*/
|
|
78
|
-
async function showLanguageStatus() {
|
|
78
|
+
export async function showLanguageStatus() {
|
|
79
79
|
try {
|
|
80
80
|
const status = await getLanguageStatus();
|
|
81
81
|
const currentLang = status.effectiveLanguage;
|
|
@@ -121,7 +121,7 @@ async function showLanguageStatus() {
|
|
|
121
121
|
/**
|
|
122
122
|
* μΈμ΄ μ€μ λ³κ²½
|
|
123
123
|
*/
|
|
124
|
-
async function setLanguage(language = null, options = {}) {
|
|
124
|
+
export async function setLanguage(language = null, options = {}) {
|
|
125
125
|
try {
|
|
126
126
|
let targetLanguage = language;
|
|
127
127
|
let autoDetect = options.autoDetect;
|
|
@@ -190,7 +190,7 @@ async function setLanguage(language = null, options = {}) {
|
|
|
190
190
|
/**
|
|
191
191
|
* μΈμ΄ μ€μ μ΄κΈ°ν
|
|
192
192
|
*/
|
|
193
|
-
async function resetLanguage() {
|
|
193
|
+
export async function resetLanguage() {
|
|
194
194
|
try {
|
|
195
195
|
const currentStatus = await getLanguageStatus();
|
|
196
196
|
const currentLang = currentStatus.effectiveLanguage;
|
|
@@ -273,6 +273,13 @@ program
|
|
|
273
273
|
|
|
274
274
|
// CLI μ€ν
|
|
275
275
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
276
|
+
// Deprecated κ²½κ³ νμ
|
|
277
|
+
console.log(chalk.yellow('β οΈ DEPRECATED: `aiwf-lang` is deprecated.'));
|
|
278
|
+
console.log(chalk.yellow(' Please use `aiwf lang` instead:'));
|
|
279
|
+
console.log(chalk.gray(' aiwf-lang status β aiwf lang status'));
|
|
280
|
+
console.log(chalk.gray(' aiwf-lang set β aiwf lang set'));
|
|
281
|
+
console.log(chalk.gray(' aiwf-lang reset β aiwf lang reset\n'));
|
|
282
|
+
|
|
276
283
|
program.parse(process.argv);
|
|
277
284
|
}
|
|
278
285
|
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
const tar = require('tar');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const ora = require('ora');
|
|
9
|
+
|
|
10
|
+
const CACHE_DIR = path.join(__dirname, '../.cache');
|
|
11
|
+
const TEMPLATES_DIR = path.join(__dirname, '../templates');
|
|
12
|
+
const DEPENDENCIES_CACHE = path.join(CACHE_DIR, 'dependencies');
|
|
13
|
+
|
|
14
|
+
// κ° ν
νλ¦Ώμ μ£Όμ μμ‘΄μ± λͺ©λ‘
|
|
15
|
+
const TEMPLATE_DEPENDENCIES = {
|
|
16
|
+
'web-app': [
|
|
17
|
+
'react@18',
|
|
18
|
+
'react-dom@18',
|
|
19
|
+
'vite@4',
|
|
20
|
+
'typescript@5',
|
|
21
|
+
'tailwindcss@3'
|
|
22
|
+
],
|
|
23
|
+
'api-server': [
|
|
24
|
+
'express@4',
|
|
25
|
+
'typescript@5',
|
|
26
|
+
'jsonwebtoken@9',
|
|
27
|
+
'swagger-ui-express@5'
|
|
28
|
+
],
|
|
29
|
+
'npm-library': [
|
|
30
|
+
'typescript@5',
|
|
31
|
+
'rollup@3',
|
|
32
|
+
'jest@29'
|
|
33
|
+
]
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
async function cacheTemplates() {
|
|
37
|
+
console.log(chalk.cyan('\nπ¦ AIWF ν
νλ¦Ώ μΊμ μμ€ν
\n'));
|
|
38
|
+
|
|
39
|
+
const spinner = ora('μΊμ λλ ν 리 μ€λΉ μ€...').start();
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// μΊμ λλ ν 리 μμ±
|
|
43
|
+
await fs.ensureDir(CACHE_DIR);
|
|
44
|
+
await fs.ensureDir(DEPENDENCIES_CACHE);
|
|
45
|
+
|
|
46
|
+
spinner.text = 'ν
νλ¦Ώ μμΆ μ€...';
|
|
47
|
+
|
|
48
|
+
// κ° ν
νλ¦Ώμ μμΆνμ¬ μΊμ
|
|
49
|
+
const templates = await fs.readdir(TEMPLATES_DIR);
|
|
50
|
+
|
|
51
|
+
for (const template of templates) {
|
|
52
|
+
const templatePath = path.join(TEMPLATES_DIR, template);
|
|
53
|
+
const stat = await fs.stat(templatePath);
|
|
54
|
+
|
|
55
|
+
if (stat.isDirectory()) {
|
|
56
|
+
const cachePath = path.join(CACHE_DIR, `${template}.tar.gz`);
|
|
57
|
+
|
|
58
|
+
await tar.create(
|
|
59
|
+
{
|
|
60
|
+
gzip: true,
|
|
61
|
+
file: cachePath,
|
|
62
|
+
cwd: TEMPLATES_DIR
|
|
63
|
+
},
|
|
64
|
+
[template]
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
spinner.text = `${template} ν
νλ¦Ώ μΊμ μλ£`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
spinner.text = 'ν
νλ¦Ώ λ©νλ°μ΄ν° μμ± μ€...';
|
|
72
|
+
|
|
73
|
+
// μΊμ λ©νλ°μ΄ν° μμ±
|
|
74
|
+
const metadata = {
|
|
75
|
+
version: require('../../package.json').version,
|
|
76
|
+
cachedAt: new Date().toISOString(),
|
|
77
|
+
templates: {},
|
|
78
|
+
dependencies: {}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
for (const template of templates) {
|
|
82
|
+
const configPath = path.join(TEMPLATES_DIR, template, 'config.json');
|
|
83
|
+
if (await fs.pathExists(configPath)) {
|
|
84
|
+
const config = await fs.readJson(configPath);
|
|
85
|
+
metadata.templates[template] = {
|
|
86
|
+
name: config.name,
|
|
87
|
+
displayName: config.displayName,
|
|
88
|
+
description: config.description,
|
|
89
|
+
size: (await fs.stat(path.join(CACHE_DIR, `${template}.tar.gz`))).size
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await fs.writeJson(path.join(CACHE_DIR, 'metadata.json'), metadata, { spaces: 2 });
|
|
95
|
+
|
|
96
|
+
spinner.succeed('ν
νλ¦Ώ μΊμ μλ£!');
|
|
97
|
+
|
|
98
|
+
// μΊμ ν΅κ³ μΆλ ₯
|
|
99
|
+
console.log(chalk.green('\nβ
μΊμ μμ± μλ£\n'));
|
|
100
|
+
console.log('μΊμλ ν
νλ¦Ώ:');
|
|
101
|
+
for (const [template, info] of Object.entries(metadata.templates)) {
|
|
102
|
+
console.log(chalk.gray(` - ${info.displayName}: ${(info.size / 1024).toFixed(2)} KB`));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const totalSize = Object.values(metadata.templates)
|
|
106
|
+
.reduce((sum, info) => sum + info.size, 0);
|
|
107
|
+
console.log(chalk.gray(`\nμ΄ μΊμ ν¬κΈ°: ${(totalSize / 1024 / 1024).toFixed(2)} MB`));
|
|
108
|
+
|
|
109
|
+
} catch (error) {
|
|
110
|
+
spinner.fail('μΊμ μμ± μ€ μ€λ₯κ° λ°μνμ΅λλ€.');
|
|
111
|
+
console.error(chalk.red(error.message));
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function restoreFromCache(templateName, targetPath) {
|
|
117
|
+
const cachePath = path.join(CACHE_DIR, `${templateName}.tar.gz`);
|
|
118
|
+
|
|
119
|
+
if (!await fs.pathExists(cachePath)) {
|
|
120
|
+
throw new Error(`μΊμλ ν
νλ¦Ώμ μ°Ύμ μ μμ΅λλ€: ${templateName}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await tar.extract({
|
|
124
|
+
file: cachePath,
|
|
125
|
+
cwd: targetPath
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// ν
νλ¦Ώ λ΄μ©μ μμ λλ ν λ¦¬λ‘ μ΄λ
|
|
129
|
+
const extractedPath = path.join(targetPath, templateName, 'template');
|
|
130
|
+
const files = await fs.readdir(extractedPath);
|
|
131
|
+
|
|
132
|
+
for (const file of files) {
|
|
133
|
+
await fs.move(
|
|
134
|
+
path.join(extractedPath, file),
|
|
135
|
+
path.join(targetPath, file)
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// μμ λλ ν 리 μμ
|
|
140
|
+
await fs.remove(path.join(targetPath, templateName));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function checkCache() {
|
|
144
|
+
const metadataPath = path.join(CACHE_DIR, 'metadata.json');
|
|
145
|
+
|
|
146
|
+
if (!await fs.pathExists(metadataPath)) {
|
|
147
|
+
return { valid: false, reason: 'μΊμκ° μ‘΄μ¬νμ§ μμ΅λλ€' };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const metadata = await fs.readJson(metadataPath);
|
|
151
|
+
const packageVersion = require('../../package.json').version;
|
|
152
|
+
|
|
153
|
+
if (metadata.version !== packageVersion) {
|
|
154
|
+
return { valid: false, reason: 'λ²μ μ΄ μΌμΉνμ§ μμ΅λλ€' };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// μΊμκ° 7μΌ μ΄μ μ€λλ κ²½μ°
|
|
158
|
+
const cacheAge = Date.now() - new Date(metadata.cachedAt).getTime();
|
|
159
|
+
const sevenDays = 7 * 24 * 60 * 60 * 1000;
|
|
160
|
+
|
|
161
|
+
if (cacheAge > sevenDays) {
|
|
162
|
+
return { valid: false, reason: 'μΊμκ° μ€λλμμ΅λλ€' };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return { valid: true, metadata };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// CLI λͺ
λ Ήμ΄ μ²λ¦¬
|
|
169
|
+
if (require.main === module) {
|
|
170
|
+
const command = process.argv[2];
|
|
171
|
+
|
|
172
|
+
switch (command) {
|
|
173
|
+
case 'create':
|
|
174
|
+
cacheTemplates().catch(error => {
|
|
175
|
+
console.error(chalk.red('μ€λ₯:', error.message));
|
|
176
|
+
process.exit(1);
|
|
177
|
+
});
|
|
178
|
+
break;
|
|
179
|
+
|
|
180
|
+
case 'check':
|
|
181
|
+
checkCache().then(result => {
|
|
182
|
+
if (result.valid) {
|
|
183
|
+
console.log(chalk.green('β
μΊμκ° μ ν¨ν©λλ€'));
|
|
184
|
+
console.log(chalk.gray(`μμ±μΌ: ${result.metadata.cachedAt}`));
|
|
185
|
+
} else {
|
|
186
|
+
console.log(chalk.yellow(`β οΈ ${result.reason}`));
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
case 'clear':
|
|
192
|
+
fs.remove(CACHE_DIR).then(() => {
|
|
193
|
+
console.log(chalk.green('β
μΊμκ° μμ λμμ΅λλ€'));
|
|
194
|
+
});
|
|
195
|
+
break;
|
|
196
|
+
|
|
197
|
+
default:
|
|
198
|
+
console.log(`
|
|
199
|
+
μ¬μ©λ²: node cache-templates.js [command]
|
|
200
|
+
|
|
201
|
+
λͺ
λ Ήμ΄:
|
|
202
|
+
create ν
νλ¦Ώ μΊμ μμ±
|
|
203
|
+
check μΊμ μν νμΈ
|
|
204
|
+
clear μΊμ μμ
|
|
205
|
+
`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = { cacheTemplates, restoreFromCache, checkCache };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const ora = require('ora');
|
|
7
|
+
const { checkCache, restoreFromCache } = require('./cache-templates');
|
|
8
|
+
|
|
9
|
+
async function createProjectOffline(template, projectName, targetDir) {
|
|
10
|
+
const spinner = ora('μ€νλΌμΈ λͺ¨λλ‘ νλ‘μ νΈ μμ± μ€...').start();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// μΊμ νμΈ
|
|
14
|
+
const cacheStatus = await checkCache();
|
|
15
|
+
|
|
16
|
+
if (!cacheStatus.valid) {
|
|
17
|
+
spinner.fail(`μΊμ λ¬Έμ : ${cacheStatus.reason}`);
|
|
18
|
+
console.log(chalk.yellow('\nμ¨λΌμΈ λͺ¨λλ‘ μ ννκ±°λ μΊμλ₯Ό μ
λ°μ΄νΈνμΈμ.'));
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
spinner.text = 'μΊμμμ ν
νλ¦Ώ 볡μ μ€...';
|
|
23
|
+
|
|
24
|
+
// μΊμμμ ν
νλ¦Ώ 볡μ
|
|
25
|
+
await restoreFromCache(template, targetDir);
|
|
26
|
+
|
|
27
|
+
// νλ μ΄μ€νλ κ΅μ²΄
|
|
28
|
+
const replacements = {
|
|
29
|
+
'{{projectName}}': projectName,
|
|
30
|
+
'{{createdAt}}': new Date().toISOString(),
|
|
31
|
+
'{{year}}': new Date().getFullYear().toString()
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
await replacePlaceholders(targetDir, replacements);
|
|
35
|
+
|
|
36
|
+
spinner.succeed('νλ‘μ νΈκ° μ€νλΌμΈ λͺ¨λλ‘ μμ±λμμ΅λλ€!');
|
|
37
|
+
|
|
38
|
+
console.log(chalk.green(`\nβ
${projectName} νλ‘μ νΈκ° μμ±λμμ΅λλ€!\n`));
|
|
39
|
+
console.log(chalk.yellow('β οΈ μ€νλΌμΈ λͺ¨λλ‘ μμ±λμμ΅λλ€.'));
|
|
40
|
+
console.log('μΈν°λ· μ°κ²° ν λ€μ λͺ
λ Ήμ΄λ₯Ό μ€ννμΈμ:\n');
|
|
41
|
+
console.log(chalk.cyan(` cd ${targetDir}`));
|
|
42
|
+
console.log(chalk.cyan(' npm install\n'));
|
|
43
|
+
|
|
44
|
+
return true;
|
|
45
|
+
|
|
46
|
+
} catch (error) {
|
|
47
|
+
spinner.fail('μ€νλΌμΈ νλ‘μ νΈ μμ± μ€ν¨');
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function replacePlaceholders(dir, replacements) {
|
|
53
|
+
const files = await fs.readdir(dir);
|
|
54
|
+
|
|
55
|
+
for (const file of files) {
|
|
56
|
+
const filePath = path.join(dir, file);
|
|
57
|
+
const stat = await fs.stat(filePath);
|
|
58
|
+
|
|
59
|
+
if (stat.isDirectory() && file !== 'node_modules') {
|
|
60
|
+
await replacePlaceholders(filePath, replacements);
|
|
61
|
+
} else if (stat.isFile() && !file.endsWith('.jpg') && !file.endsWith('.png')) {
|
|
62
|
+
try {
|
|
63
|
+
let content = await fs.readFile(filePath, 'utf8');
|
|
64
|
+
|
|
65
|
+
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
66
|
+
content = content.replace(new RegExp(placeholder, 'g'), value);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await fs.writeFile(filePath, content, 'utf8');
|
|
70
|
+
} catch (error) {
|
|
71
|
+
// λ°μ΄λ리 νμΌ λ¬΄μ
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// λ€νΈμν¬ μ°κ²° νμΈ
|
|
78
|
+
function isOnline() {
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
|
+
require('dns').lookup('registry.npmjs.org', (err) => {
|
|
81
|
+
resolve(!err);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = { createProjectOffline, isOnline };
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const prompts = require('prompts');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const ora = require('ora');
|
|
8
|
+
|
|
9
|
+
const TEMPLATES_DIR = path.join(__dirname, '../templates');
|
|
10
|
+
|
|
11
|
+
async function createProject() {
|
|
12
|
+
console.log(chalk.cyan('\nπ AIWF νλ‘μ νΈ μμ±κΈ°\n'));
|
|
13
|
+
|
|
14
|
+
// μ¬μ© κ°λ₯ν ν
νλ¦Ώ μ°ΎκΈ°
|
|
15
|
+
const templates = fs.readdirSync(TEMPLATES_DIR)
|
|
16
|
+
.filter(dir => fs.existsSync(path.join(TEMPLATES_DIR, dir, 'config.json')));
|
|
17
|
+
|
|
18
|
+
const templateConfigs = templates.map(template => {
|
|
19
|
+
const config = JSON.parse(
|
|
20
|
+
fs.readFileSync(path.join(TEMPLATES_DIR, template, 'config.json'), 'utf8')
|
|
21
|
+
);
|
|
22
|
+
return {
|
|
23
|
+
value: template,
|
|
24
|
+
title: config.displayName,
|
|
25
|
+
description: config.description
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const questions = [
|
|
30
|
+
{
|
|
31
|
+
type: 'select',
|
|
32
|
+
name: 'template',
|
|
33
|
+
message: 'ν
νλ¦Ώμ μ ννμΈμ',
|
|
34
|
+
choices: templateConfigs,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: 'text',
|
|
38
|
+
name: 'projectName',
|
|
39
|
+
message: 'νλ‘μ νΈ μ΄λ¦',
|
|
40
|
+
validate: value => {
|
|
41
|
+
if (!value) return 'νλ‘μ νΈ μ΄λ¦μ μ
λ ₯νμΈμ';
|
|
42
|
+
if (!/^[a-z0-9-]+$/.test(value)) {
|
|
43
|
+
return 'μλ¬Έμ, μ«μ, νμ΄νλ§ μ¬μ© κ°λ₯ν©λλ€';
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: prev => prev === 'npm-library' ? 'text' : null,
|
|
50
|
+
name: 'description',
|
|
51
|
+
message: 'νλ‘μ νΈ μ€λͺ
',
|
|
52
|
+
initial: 'A new AIWF project'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: prev => prev === 'npm-library' ? 'text' : null,
|
|
56
|
+
name: 'author',
|
|
57
|
+
message: 'μμ±μ',
|
|
58
|
+
initial: ''
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
name: 'directory',
|
|
63
|
+
message: 'νλ‘μ νΈ λλ ν 리',
|
|
64
|
+
initial: prev => prev.projectName,
|
|
65
|
+
validate: value => {
|
|
66
|
+
if (!value) return 'λλ ν 리λ₯Ό μ
λ ₯νμΈμ';
|
|
67
|
+
if (fs.existsSync(value)) {
|
|
68
|
+
return 'μ΄λ―Έ μ‘΄μ¬νλ λλ ν 리μ
λλ€';
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const answers = await prompts(questions);
|
|
76
|
+
|
|
77
|
+
if (!answers.template || !answers.projectName) {
|
|
78
|
+
console.log(chalk.red('\nβ νλ‘μ νΈ μμ±μ΄ μ·¨μλμμ΅λλ€.'));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const spinner = ora('νλ‘μ νΈ μμ± μ€...').start();
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const templatePath = path.join(TEMPLATES_DIR, answers.template, 'template');
|
|
86
|
+
const targetPath = path.resolve(answers.directory);
|
|
87
|
+
|
|
88
|
+
// ν
νλ¦Ώ 볡μ¬
|
|
89
|
+
await fs.copy(templatePath, targetPath);
|
|
90
|
+
|
|
91
|
+
// νλ μ΄μ€νλ κ΅μ²΄
|
|
92
|
+
const replacements = {
|
|
93
|
+
'{{projectName}}': answers.projectName,
|
|
94
|
+
'{{description}}': answers.description || '',
|
|
95
|
+
'{{author}}': answers.author || '',
|
|
96
|
+
'{{year}}': new Date().getFullYear().toString(),
|
|
97
|
+
'{{createdAt}}': new Date().toISOString(),
|
|
98
|
+
'{{username}}': answers.author?.toLowerCase().replace(/\s+/g, '') || 'username'
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// λͺ¨λ νμΌμμ νλ μ΄μ€νλ κ΅μ²΄
|
|
102
|
+
await replacePlaceholders(targetPath, replacements);
|
|
103
|
+
|
|
104
|
+
spinner.succeed('νλ‘μ νΈκ° μ±κ³΅μ μΌλ‘ μμ±λμμ΅λλ€!');
|
|
105
|
+
|
|
106
|
+
console.log(chalk.green(`\nβ
${answers.projectName} νλ‘μ νΈκ° μμ±λμμ΅λλ€!\n`));
|
|
107
|
+
console.log('λ€μ λͺ
λ Ήμ΄λ‘ μμνμΈμ:\n');
|
|
108
|
+
console.log(chalk.cyan(` cd ${answers.directory}`));
|
|
109
|
+
console.log(chalk.cyan(' npm install'));
|
|
110
|
+
console.log(chalk.cyan(' npm run dev\n'));
|
|
111
|
+
console.log('AIWF λͺ
λ Ήμ΄:');
|
|
112
|
+
console.log(chalk.gray(' npm run aiwf status # νλ‘μ νΈ μν νμΈ'));
|
|
113
|
+
console.log(chalk.gray(' npm run aiwf feature # Feature Ledger κ΄λ¦¬\n'));
|
|
114
|
+
|
|
115
|
+
} catch (error) {
|
|
116
|
+
spinner.fail('νλ‘μ νΈ μμ± μ€ μ€λ₯κ° λ°μνμ΅λλ€.');
|
|
117
|
+
console.error(chalk.red(error.message));
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function replacePlaceholders(dir, replacements) {
|
|
123
|
+
const files = await fs.readdir(dir);
|
|
124
|
+
|
|
125
|
+
for (const file of files) {
|
|
126
|
+
const filePath = path.join(dir, file);
|
|
127
|
+
const stat = await fs.stat(filePath);
|
|
128
|
+
|
|
129
|
+
if (stat.isDirectory()) {
|
|
130
|
+
await replacePlaceholders(filePath, replacements);
|
|
131
|
+
} else if (stat.isFile()) {
|
|
132
|
+
let content = await fs.readFile(filePath, 'utf8');
|
|
133
|
+
|
|
134
|
+
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
135
|
+
content = content.replace(new RegExp(placeholder, 'g'), value);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
await fs.writeFile(filePath, content, 'utf8');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// CLI μ€ν
|
|
144
|
+
if (require.main === module) {
|
|
145
|
+
createProject().catch(error => {
|
|
146
|
+
console.error(chalk.red('μ€λ₯:', error.message));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = { createProject };
|