aiwf 0.3.3 β†’ 0.3.5

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.
Files changed (208) hide show
  1. package/.aiwf/config/language.json +1 -1
  2. package/.aiwf/metrics/metrics.json +18 -0
  3. package/.aiwf/personas/current.json +5 -0
  4. package/.aiwf/sessions/session_1752877859489_1t7n2fhdb.json +7 -0
  5. package/.aiwf/sessions/session_1752877859515_cwdv211ry.json +7 -0
  6. package/.aiwf/sessions/session_1752877860664_huziadmbo.json +7 -0
  7. package/.aiwf/sessions/session_1752877860666_kyr5u1np6.json +7 -0
  8. package/.aiwf/sessions/session_1752877861848_9yinepw3t.json +7 -0
  9. package/.aiwf/sessions/session_1752877861874_y32sputuc.json +7 -0
  10. package/.aiwf/sessions/session_1752877862685_ivxbl5rhz.json +7 -0
  11. package/.aiwf/sessions/session_1752877862820_wnq4glvxi.json +7 -0
  12. package/.aiwf/sessions/session_1752877864632_3ebnpaelb.json +7 -0
  13. package/.aiwf/sessions/session_1752877864879_b9zgjcb7d.json +7 -0
  14. package/.aiwf/sessions/session_1752877865533_x14m1vodi.json +7 -0
  15. package/.aiwf/sessions/session_1752877865562_gkoh19n7d.json +7 -0
  16. package/.aiwf/sessions/session_1752877866333_wp8qpdcoh.json +7 -0
  17. package/.aiwf/sessions/session_1752877866509_dawntfpab.json +7 -0
  18. package/.aiwf/sessions/session_1752877866890_plc5vfucl.json +7 -0
  19. package/.aiwf/sessions/session_1752877866895_ga8hmq3oi.json +7 -0
  20. package/.aiwf/sessions/session_1752877867761_ayjp4v5f5.json +7 -0
  21. package/.aiwf/sessions/session_1752877867892_lfz6jy252.json +7 -0
  22. package/.aiwf/sessions/session_1752877868139_7bqd9ubli.json +7 -0
  23. package/.aiwf/sessions/session_1752877868162_zq3ofjbsh.json +7 -0
  24. package/.aiwf/sessions/session_1752877869054_7rlgm9jt6.json +7 -0
  25. package/.aiwf/sessions/session_1752877869477_ax3nhbxzr.json +7 -0
  26. package/.aiwf/sessions/session_1752877870095_6hgp4vl1e.json +7 -0
  27. package/.aiwf/sessions/session_1752877870381_qfcrdg4li.json +7 -0
  28. package/.aiwf/sessions/session_1752877871895_pgd5vllhz.json +7 -0
  29. package/.aiwf/sessions/session_1752877872199_jbhv2g2da.json +7 -0
  30. package/.aiwf/sessions/session_1752877872680_x04wpffu6.json +7 -0
  31. package/.aiwf/sessions/session_1752877872895_3y4vbeauo.json +7 -0
  32. package/.aiwf/sessions/session_1752877873178_3maolzc6b.json +7 -0
  33. package/.aiwf/sessions/session_1752877873180_ytm83j07f.json +7 -0
  34. package/.aiwf/sessions/session_1752877874217_dp56c9t42.json +7 -0
  35. package/.aiwf/sessions/session_1752877874415_epwp1g1og.json +7 -0
  36. package/.aiwf/sessions/session_1752877874454_heicyuryb.json +7 -0
  37. package/.aiwf/sessions/session_1752877874869_1c2illeu5.json +7 -0
  38. package/.aiwf/sessions/session_1752877874879_k1vo4vxyx.json +7 -0
  39. package/.aiwf/sessions/session_1752877874913_bwgyiz9bp.json +7 -0
  40. package/.aiwf/sessions/session_1752877876218_44807kztz.json +7 -0
  41. package/.aiwf/sessions/session_1752877876515_qkhjv5kpw.json +7 -0
  42. package/.aiwf/sessions/session_1752877876543_p605aud1m.json +7 -0
  43. package/.aiwf/sessions/session_1752877876819_l65w7ifck.json +7 -0
  44. package/.aiwf/sessions/session_1752877876867_xrhzss4we.json +7 -0
  45. package/.aiwf/sessions/session_1752877876872_u7aso54qb.json +7 -0
  46. package/.aiwf/sessions/session_1752877877705_telnfg4o6.json +7 -0
  47. package/.aiwf/sessions/session_1752877878285_6s45im2ib.json +7 -0
  48. package/.aiwf/sessions/session_1752877878506_v0dvguqhz.json +7 -0
  49. package/.aiwf/sessions/session_1752877878581_3ri3yc66a.json +7 -0
  50. package/.aiwf/sessions/session_1752877878756_a82x9s2pd.json +7 -0
  51. package/.aiwf/sessions/session_1752877878886_20pjsfour.json +7 -0
  52. package/.aiwf/sessions/session_1752877880266_fm1ydjw0g.json +7 -0
  53. package/.aiwf/sessions/session_1752877881149_xbat4z03d.json +7 -0
  54. package/.aiwf/sessions/session_1752877881551_qy5sic9qs.json +7 -0
  55. package/.aiwf/sessions/session_1752877881554_24ugd96wu.json +7 -0
  56. package/.aiwf/sessions/session_1752877881797_e9mm25uh0.json +7 -0
  57. package/.aiwf/sessions/session_1752877881822_bxvjj8c9g.json +7 -0
  58. package/.aiwf/sessions/session_1752877881890_jv7l6jve3.json +7 -0
  59. package/.aiwf/sessions/session_1752877881991_f0qugdtcq.json +7 -0
  60. package/.aiwf/sessions/session_1752877883387_0bvw9rvnx.json +7 -0
  61. package/.aiwf/sessions/session_1752877883820_q6g2md2up.json +7 -0
  62. package/.aiwf/sessions/session_1752877884393_sqr7trvjl.json +7 -0
  63. package/.aiwf/sessions/session_1752877884500_whtypmzlf.json +7 -0
  64. package/.aiwf/sessions/session_1752877884645_y9mvvxli1.json +7 -0
  65. package/.aiwf/sessions/session_1752877884733_hk46eenel.json +7 -0
  66. package/.aiwf/sessions/session_1752877884738_c62j6214r.json +7 -0
  67. package/.aiwf/sessions/session_1752877884771_temhxehoz.json +7 -0
  68. package/.aiwf/sessions/session_1752877885643_6v5fcktc7.json +7 -0
  69. package/.aiwf/sessions/session_1752877886426_ee8di2fqh.json +7 -0
  70. package/.aiwf/sessions/session_1752877886549_3xj6tdoew.json +7 -0
  71. package/.aiwf/sessions/session_1752877886604_aj80yyfco.json +7 -0
  72. package/.aiwf/sessions/session_1752877886702_2b8841vyg.json +7 -0
  73. package/.aiwf/sessions/session_1752877886712_ntqc8b8bz.json +7 -0
  74. package/.aiwf/sessions/session_1752877886968_946m8tbw6.json +7 -0
  75. package/.aiwf/sessions/session_1752877887008_wg6zfg8dn.json +7 -0
  76. package/.aiwf/sessions/session_1752877888479_ciiu2qiqs.json +7 -0
  77. package/.aiwf/sessions/session_1752877889330_ravg8l66k.json +7 -0
  78. package/.aiwf/sessions/session_1752877889542_7zepkhjkc.json +7 -0
  79. package/.aiwf/sessions/session_1752877889638_ev4htqiu0.json +7 -0
  80. package/.aiwf/sessions/session_1752877889956_szphy2qma.json +7 -0
  81. package/.aiwf/sessions/session_1752877890220_o6aaa57tt.json +7 -0
  82. package/.aiwf/sessions/session_1752877890527_v2loy5vu1.json +7 -0
  83. package/.aiwf/sessions/session_1752877890572_cwq8fiuma.json +7 -0
  84. package/.aiwf/sessions/session_1752877892200_sgcwq1alt.json +7 -0
  85. package/.aiwf/sessions/session_1752877892268_v8kexpbc5.json +7 -0
  86. package/.aiwf/sessions/session_1752877892384_1gbbgrp4y.json +7 -0
  87. package/.aiwf/sessions/session_1752877893568_9p2n5p31a.json +7 -0
  88. package/.aiwf/sessions/session_1752877893727_un34a5tvp.json +7 -0
  89. package/.aiwf/sessions/session_1752877893778_01j79sw9i.json +7 -0
  90. package/.aiwf/sessions/session_1752877894053_jrhba6wko.json +7 -0
  91. package/.aiwf/sessions/session_1752877894082_x3bghawox.json +7 -0
  92. package/.aiwf/sessions/session_1752877894500_iytiav2ku.json +7 -0
  93. package/.aiwf/sessions/session_1752877894667_ucn0gc2ge.json +7 -0
  94. package/.aiwf/test-results-s02.json +4 -4
  95. package/.claude/commands/aiwf/aiwf_changelog.md +82 -0
  96. package/.claude/commands/aiwf/aiwf_code_review.md +88 -0
  97. package/.claude/commands/aiwf/aiwf_commit.md +160 -0
  98. package/.claude/commands/aiwf/aiwf_compress_aggressive_persona.md +53 -0
  99. package/.claude/commands/aiwf/aiwf_compress_context.md +116 -0
  100. package/.claude/commands/aiwf/aiwf_compress_minimal_persona.md +48 -0
  101. package/.claude/commands/aiwf/aiwf_compress_stats.md +79 -0
  102. package/.claude/commands/aiwf/aiwf_compress_with_persona.md +51 -0
  103. package/.claude/commands/aiwf/aiwf_create_feature_ledger.md +54 -0
  104. package/.claude/commands/aiwf/aiwf_create_general_task.md +147 -0
  105. package/.claude/commands/aiwf/aiwf_create_milestone_plan.md +194 -0
  106. package/.claude/commands/aiwf/aiwf_create_prd.md +280 -0
  107. package/.claude/commands/aiwf/aiwf_create_sprint_tasks.md +189 -0
  108. package/.claude/commands/aiwf/aiwf_create_sprints_from_milestone.md +121 -0
  109. package/.claude/commands/aiwf/aiwf_default_mode.md +44 -0
  110. package/.claude/commands/aiwf/aiwf_discuss_review.md +29 -0
  111. package/.claude/commands/aiwf/aiwf_do_task.md +109 -0
  112. package/.claude/commands/aiwf/aiwf_docs.md +225 -0
  113. package/.claude/commands/aiwf/aiwf_evaluate.md +92 -0
  114. package/.claude/commands/aiwf/aiwf_get_feature_details.md +78 -0
  115. package/.claude/commands/aiwf/aiwf_infinite.md +202 -0
  116. package/.claude/commands/aiwf/aiwf_initialize.md +134 -0
  117. package/.claude/commands/aiwf/aiwf_issue_create.md +65 -0
  118. package/.claude/commands/aiwf/aiwf_link_feature_to_milestone.md +57 -0
  119. package/.claude/commands/aiwf/aiwf_list_features.md +54 -0
  120. package/.claude/commands/aiwf/aiwf_mermaid.md +272 -0
  121. package/.claude/commands/aiwf/aiwf_persona_architect.md +48 -0
  122. package/.claude/commands/aiwf/aiwf_persona_backend.md +37 -0
  123. package/.claude/commands/aiwf/aiwf_persona_data_analyst.md +37 -0
  124. package/.claude/commands/aiwf/aiwf_persona_frontend.md +37 -0
  125. package/.claude/commands/aiwf/aiwf_persona_security.md +48 -0
  126. package/.claude/commands/aiwf/aiwf_persona_status.md +50 -0
  127. package/.claude/commands/aiwf/aiwf_pr_create.md +76 -0
  128. package/.claude/commands/aiwf/aiwf_prime.md +9 -0
  129. package/.claude/commands/aiwf/aiwf_project_review.md +261 -0
  130. package/.claude/commands/aiwf/aiwf_switch_language.md +160 -0
  131. package/.claude/commands/aiwf/aiwf_test.md +124 -0
  132. package/.claude/commands/aiwf/aiwf_testing_review.md +198 -0
  133. package/.claude/commands/aiwf/aiwf_tm-run-all-subtask.md +210 -0
  134. package/.claude/commands/aiwf/aiwf_ultrathink_code_advanced.md +460 -0
  135. package/.claude/commands/aiwf/aiwf_ultrathink_code_basic.md +165 -0
  136. package/.claude/commands/aiwf/aiwf_ultrathink_general.md +305 -0
  137. package/.claude/commands/aiwf/aiwf_update_docs_kr.md +25 -0
  138. package/.claude/commands/aiwf/aiwf_update_feature_status.md +53 -0
  139. package/.claude/commands/aiwf/aiwf_yolo.md +300 -0
  140. package/.eslintrc.json +26 -0
  141. package/.prettierrc +10 -0
  142. package/CHANGELOG.md +54 -5
  143. package/CLAUDE.md +154 -54
  144. package/README.ko.md +25 -0
  145. package/README.md +25 -0
  146. package/TEST_RECOVERY_PLAN.md +68 -0
  147. package/claude-code/aiwf/ko/commands/ai-persona.js +1 -1
  148. package/docs/CLEANUP_RECOMMENDATIONS.md +86 -0
  149. package/docs/CLI_USAGE_GUIDE.md +479 -0
  150. package/package.json +9 -9
  151. package/scripts/update-feature-status.js +70 -0
  152. package/{lib β†’ src/cli}/cache-cli.js +4 -4
  153. package/src/cli/index.js +206 -0
  154. package/{language-cli.js β†’ src/cli/language-cli.js} +11 -4
  155. package/src/commands/cache-templates.js +209 -0
  156. package/src/commands/create-offline.js +86 -0
  157. package/src/commands/create-project.js +151 -0
  158. package/src/commands/persona.js +288 -0
  159. package/src/lib/backup-manager.js +270 -0
  160. package/src/lib/file-downloader.js +208 -0
  161. package/src/lib/installer.js +676 -0
  162. package/src/lib/rollback-manager.js +418 -0
  163. package/src/lib/validator.js +561 -0
  164. package/src/utils/git-integration.js +173 -0
  165. package/{language-utils.js β†’ src/utils/language-utils.js} +2 -1
  166. package/src/utils/messages.js +136 -0
  167. package/src/utils/paths.js +130 -0
  168. package/tests/application.test.js +2 -2
  169. package/tests/installer.test.js +2 -2
  170. package/tests/integration/ai-persona-system.test.js +4 -4
  171. package/tests/integration/test-persona-system/docs/README.md +1 -0
  172. package/tests/integration/test-persona-system/package.json +1 -0
  173. package/tests/integration/test-persona-system/src/auth.js +1 -0
  174. package/tests/integration/test-persona-system/src/index.js +1 -0
  175. package/tests/integration/test-persona-system/test/test.js +1 -0
  176. package/tests/language-utils.test.js +1 -1
  177. package/tests/temp_invalid_json/invalid.json +1 -0
  178. package/tests/unit/ai-persona-manager.test.js +7 -7
  179. package/.aiwf/05_DOCUMENTATION/performance-report.md +0 -33
  180. package/.aiwf/test-cache/86c7f9e80251abb8bedd58953ab0d1779e46b4f43ea33b63bffdb778106373b0.json +0 -6
  181. package/.aiwf/test-cache/9e252a90b80fce0585d7ed0646e7a9b4343e109f661f42a3ae678ba1ec5e22c7.json +0 -7
  182. package/.aiwf/token-data/alerts.json +0 -293
  183. package/.aiwf/token-data/monitor-config.json +0 -12
  184. package/CHANGELOG_M02.md +0 -52
  185. package/claude-code/aiwf/ko/templates/web-app/template/package-lock.json +0 -10022
  186. package/claude-code/aiwf/ko/token-data/alerts.json +0 -293
  187. package/claude-code/aiwf/ko/token-data/monitor-config.json +0 -12
  188. package/docs/m02-dod-checklist.md +0 -125
  189. package/docs/m02-gap-analysis.md +0 -214
  190. package/docs/m02-milestone-completion-report.md +0 -186
  191. package/docs/m02-milestone-executive-summary.md +0 -68
  192. package/index.js +0 -1951
  193. package/lib/cache-integration.js +0 -401
  194. package/lib/file-batch-processor.js +0 -401
  195. package/lib/performance-benchmark.js +0 -621
  196. package/lib/template-manager.js +0 -310
  197. package/scripts/validate-commands.cjs +0 -338
  198. /package/{lib β†’ src/lib}/ai-persona-manager.js +0 -0
  199. /package/{lib β†’ src/lib}/cache-system.js +0 -0
  200. /package/{lib β†’ src/lib}/context-engine.js +0 -0
  201. /package/{lib β†’ src/lib}/memory-profiler.js +0 -0
  202. /package/{lib β†’ src/lib}/metrics-collector.js +0 -0
  203. /package/{lib β†’ src/lib}/offline-detector.js +0 -0
  204. /package/{lib β†’ src/lib}/task-analyzer.js +0 -0
  205. /package/{lib β†’ src/lib}/template-cache-system.js +0 -0
  206. /package/{lib β†’ src/lib}/template-downloader.js +0 -0
  207. /package/{lib β†’ src/lib}/template-version-manager.js +0 -0
  208. /package/{lib β†’ src/lib}/token-optimizer.js +0 -0
@@ -0,0 +1,206 @@
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 PersonaCommand from '../commands/persona.js';
8
+ import { CacheCLI } from './cache-cli.js';
9
+
10
+ // Parse version from package.json
11
+ import { readFileSync } from 'fs';
12
+ import { fileURLToPath } from 'url';
13
+ import { dirname, join } from 'path';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
18
+
19
+ // Main program setup
20
+ program
21
+ .name('aiwf')
22
+ .version(packageJson.version)
23
+ .description('AIWF - AI Workflow Framework');
24
+
25
+ // Install command (default action)
26
+ program
27
+ .command('install', { isDefault: true })
28
+ .description('Install AIWF framework')
29
+ .option('-f, --force', 'Force install without prompts')
30
+ .action((options) => installAIWF({ ...options, debugLog: true }));
31
+
32
+ // AI Tool command
33
+ program
34
+ .command('ai-tool <subcommand> [tool-name]')
35
+ .description('Manage AI tool integrations')
36
+ .action(async (subcommand, toolName) => {
37
+ const aiToolCmd = new AIToolCommand();
38
+ const args = [subcommand];
39
+ if (toolName) args.push(toolName);
40
+ await aiToolCmd.execute(args);
41
+ });
42
+
43
+ // Cache management commands
44
+ const cache = program.command('cache');
45
+ cache.description('Manage offline template cache');
46
+
47
+ cache
48
+ .command('download')
49
+ .description('Download templates for offline use')
50
+ .option('--all', 'Download all templates')
51
+ .option('--type <type>', 'Download specific type (ai-tools, projects)')
52
+ .action(async (options) => {
53
+ const cacheCLI = new CacheCLI();
54
+ try {
55
+ await cacheCLI.init();
56
+ await cacheCLI.downloadCommand(options);
57
+ } catch (error) {
58
+ console.error(chalk.red('Cache download failed:', error.message));
59
+ process.exit(1);
60
+ } finally {
61
+ await cacheCLI.cleanup();
62
+ }
63
+ });
64
+
65
+ cache
66
+ .command('list')
67
+ .description('List cached templates')
68
+ .option('--type <type>', 'Filter by type (ai-tools, projects)')
69
+ .action(async (options) => {
70
+ const cacheCLI = new CacheCLI();
71
+ try {
72
+ await cacheCLI.init();
73
+ await cacheCLI.listCommand(options);
74
+ } catch (error) {
75
+ console.error(chalk.red('Cache list failed:', error.message));
76
+ process.exit(1);
77
+ } finally {
78
+ await cacheCLI.cleanup();
79
+ }
80
+ });
81
+
82
+ cache
83
+ .command('clean')
84
+ .description('Clean up cached templates')
85
+ .option('--all', 'Clear all cached templates')
86
+ .option('--max-age <days>', 'Maximum age in days (default: 7)', '7')
87
+ .action(async (options) => {
88
+ const cacheCLI = new CacheCLI();
89
+ try {
90
+ await cacheCLI.init();
91
+ await cacheCLI.cleanCommand(options);
92
+ } catch (error) {
93
+ console.error(chalk.red('Cache clean failed:', error.message));
94
+ process.exit(1);
95
+ } finally {
96
+ await cacheCLI.cleanup();
97
+ }
98
+ });
99
+
100
+ cache
101
+ .command('update')
102
+ .description('Check for template updates')
103
+ .option('--install', 'Install available updates')
104
+ .action(async (options) => {
105
+ const cacheCLI = new CacheCLI();
106
+ try {
107
+ await cacheCLI.init();
108
+ await cacheCLI.updateCommand(options);
109
+ } catch (error) {
110
+ console.error(chalk.red('Cache update failed:', error.message));
111
+ process.exit(1);
112
+ } finally {
113
+ await cacheCLI.cleanup();
114
+ }
115
+ });
116
+
117
+ cache
118
+ .command('status')
119
+ .description('Show cache system status')
120
+ .action(async () => {
121
+ const cacheCLI = new CacheCLI();
122
+ try {
123
+ await cacheCLI.init();
124
+ await cacheCLI.statusCommand();
125
+ } catch (error) {
126
+ console.error(chalk.red('Cache status failed:', error.message));
127
+ process.exit(1);
128
+ } finally {
129
+ await cacheCLI.cleanup();
130
+ }
131
+ });
132
+
133
+ // Language management commands
134
+ const lang = program.command('lang');
135
+ lang.description('Manage language settings / μ–Έμ–΄ μ„€μ • 관리');
136
+
137
+ lang
138
+ .command('status')
139
+ .alias('s')
140
+ .description('Show current language configuration / ν˜„μž¬ μ–Έμ–΄ μ„€μ • ν‘œμ‹œ')
141
+ .action(async () => {
142
+ const { showLanguageStatus } = await import('./language-cli.js');
143
+ await showLanguageStatus();
144
+ });
145
+
146
+ lang
147
+ .command('set [language]')
148
+ .alias('switch')
149
+ .description('Set or change language / μ–Έμ–΄ μ„€μ • λ˜λŠ” λ³€κ²½')
150
+ .option('-a, --auto-detect [boolean]', 'Enable/disable auto detection / μžλ™ 감지 ν™œμ„±ν™”/λΉ„ν™œμ„±ν™”')
151
+ .action(async (language, options) => {
152
+ const { setLanguage } = await import('./language-cli.js');
153
+ await setLanguage(language, options);
154
+ });
155
+
156
+ lang
157
+ .command('reset')
158
+ .alias('r')
159
+ .description('Reset language configuration to auto-detection / μ–Έμ–΄ 섀정을 μžλ™ κ°μ§€λ‘œ μ΄ˆκΈ°ν™”')
160
+ .action(async () => {
161
+ const { resetLanguage } = await import('./language-cli.js');
162
+ await resetLanguage();
163
+ });
164
+
165
+ // Persona management commands
166
+ const persona = program.command('persona');
167
+ persona.description('Manage AI personas / AI 페λ₯΄μ†Œλ‚˜ 관리');
168
+
169
+ persona
170
+ .command('status')
171
+ .alias('s')
172
+ .description('Show current persona status / ν˜„μž¬ 페λ₯΄μ†Œλ‚˜ μƒνƒœ ν‘œμ‹œ')
173
+ .action(async () => {
174
+ const personaCmd = new PersonaCommand();
175
+ await personaCmd.showStatus();
176
+ });
177
+
178
+ persona
179
+ .command('list')
180
+ .alias('ls')
181
+ .description('List available personas / μ‚¬μš© κ°€λŠ₯ν•œ 페λ₯΄μ†Œλ‚˜ λͺ©λ‘')
182
+ .action(async () => {
183
+ const personaCmd = new PersonaCommand();
184
+ await personaCmd.listPersonas();
185
+ });
186
+
187
+ persona
188
+ .command('set <persona-name>')
189
+ .alias('switch')
190
+ .description('Switch to specific persona / νŠΉμ • 페λ₯΄μ†Œλ‚˜λ‘œ μ „ν™˜')
191
+ .action(async (personaName) => {
192
+ const personaCmd = new PersonaCommand();
193
+ await personaCmd.setPersona(personaName);
194
+ });
195
+
196
+ persona
197
+ .command('reset')
198
+ .alias('r')
199
+ .description('Reset to default persona / κΈ°λ³Έ 페λ₯΄μ†Œλ‚˜λ‘œ 리셋')
200
+ .action(async () => {
201
+ const personaCmd = new PersonaCommand();
202
+ await personaCmd.resetPersona();
203
+ });
204
+
205
+ // Parse command line arguments
206
+ program.parse(process.argv);
@@ -17,7 +17,7 @@ import {
17
17
  getLocalizedMessage,
18
18
  SUPPORTED_LANGUAGES,
19
19
  DEFAULT_LANGUAGE
20
- } from './language-utils.js';
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 };