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.
Files changed (203) hide show
  1. package/.aiwf/config/language.json +1 -1
  2. package/.aiwf/sessions/session_1752877859489_1t7n2fhdb.json +7 -0
  3. package/.aiwf/sessions/session_1752877859515_cwdv211ry.json +7 -0
  4. package/.aiwf/sessions/session_1752877860664_huziadmbo.json +7 -0
  5. package/.aiwf/sessions/session_1752877860666_kyr5u1np6.json +7 -0
  6. package/.aiwf/sessions/session_1752877861848_9yinepw3t.json +7 -0
  7. package/.aiwf/sessions/session_1752877861874_y32sputuc.json +7 -0
  8. package/.aiwf/sessions/session_1752877862685_ivxbl5rhz.json +7 -0
  9. package/.aiwf/sessions/session_1752877862820_wnq4glvxi.json +7 -0
  10. package/.aiwf/sessions/session_1752877864632_3ebnpaelb.json +7 -0
  11. package/.aiwf/sessions/session_1752877864879_b9zgjcb7d.json +7 -0
  12. package/.aiwf/sessions/session_1752877865533_x14m1vodi.json +7 -0
  13. package/.aiwf/sessions/session_1752877865562_gkoh19n7d.json +7 -0
  14. package/.aiwf/sessions/session_1752877866333_wp8qpdcoh.json +7 -0
  15. package/.aiwf/sessions/session_1752877866509_dawntfpab.json +7 -0
  16. package/.aiwf/sessions/session_1752877866890_plc5vfucl.json +7 -0
  17. package/.aiwf/sessions/session_1752877866895_ga8hmq3oi.json +7 -0
  18. package/.aiwf/sessions/session_1752877867761_ayjp4v5f5.json +7 -0
  19. package/.aiwf/sessions/session_1752877867892_lfz6jy252.json +7 -0
  20. package/.aiwf/sessions/session_1752877868139_7bqd9ubli.json +7 -0
  21. package/.aiwf/sessions/session_1752877868162_zq3ofjbsh.json +7 -0
  22. package/.aiwf/sessions/session_1752877869054_7rlgm9jt6.json +7 -0
  23. package/.aiwf/sessions/session_1752877869477_ax3nhbxzr.json +7 -0
  24. package/.aiwf/sessions/session_1752877870095_6hgp4vl1e.json +7 -0
  25. package/.aiwf/sessions/session_1752877870381_qfcrdg4li.json +7 -0
  26. package/.aiwf/sessions/session_1752877871895_pgd5vllhz.json +7 -0
  27. package/.aiwf/sessions/session_1752877872199_jbhv2g2da.json +7 -0
  28. package/.aiwf/sessions/session_1752877872680_x04wpffu6.json +7 -0
  29. package/.aiwf/sessions/session_1752877872895_3y4vbeauo.json +7 -0
  30. package/.aiwf/sessions/session_1752877873178_3maolzc6b.json +7 -0
  31. package/.aiwf/sessions/session_1752877873180_ytm83j07f.json +7 -0
  32. package/.aiwf/sessions/session_1752877874217_dp56c9t42.json +7 -0
  33. package/.aiwf/sessions/session_1752877874415_epwp1g1og.json +7 -0
  34. package/.aiwf/sessions/session_1752877874454_heicyuryb.json +7 -0
  35. package/.aiwf/sessions/session_1752877874869_1c2illeu5.json +7 -0
  36. package/.aiwf/sessions/session_1752877874879_k1vo4vxyx.json +7 -0
  37. package/.aiwf/sessions/session_1752877874913_bwgyiz9bp.json +7 -0
  38. package/.aiwf/sessions/session_1752877876218_44807kztz.json +7 -0
  39. package/.aiwf/sessions/session_1752877876515_qkhjv5kpw.json +7 -0
  40. package/.aiwf/sessions/session_1752877876543_p605aud1m.json +7 -0
  41. package/.aiwf/sessions/session_1752877876819_l65w7ifck.json +7 -0
  42. package/.aiwf/sessions/session_1752877876867_xrhzss4we.json +7 -0
  43. package/.aiwf/sessions/session_1752877876872_u7aso54qb.json +7 -0
  44. package/.aiwf/sessions/session_1752877877705_telnfg4o6.json +7 -0
  45. package/.aiwf/sessions/session_1752877878285_6s45im2ib.json +7 -0
  46. package/.aiwf/sessions/session_1752877878506_v0dvguqhz.json +7 -0
  47. package/.aiwf/sessions/session_1752877878581_3ri3yc66a.json +7 -0
  48. package/.aiwf/sessions/session_1752877878756_a82x9s2pd.json +7 -0
  49. package/.aiwf/sessions/session_1752877878886_20pjsfour.json +7 -0
  50. package/.aiwf/sessions/session_1752877880266_fm1ydjw0g.json +7 -0
  51. package/.aiwf/sessions/session_1752877881149_xbat4z03d.json +7 -0
  52. package/.aiwf/sessions/session_1752877881551_qy5sic9qs.json +7 -0
  53. package/.aiwf/sessions/session_1752877881554_24ugd96wu.json +7 -0
  54. package/.aiwf/sessions/session_1752877881797_e9mm25uh0.json +7 -0
  55. package/.aiwf/sessions/session_1752877881822_bxvjj8c9g.json +7 -0
  56. package/.aiwf/sessions/session_1752877881890_jv7l6jve3.json +7 -0
  57. package/.aiwf/sessions/session_1752877881991_f0qugdtcq.json +7 -0
  58. package/.aiwf/sessions/session_1752877883387_0bvw9rvnx.json +7 -0
  59. package/.aiwf/sessions/session_1752877883820_q6g2md2up.json +7 -0
  60. package/.aiwf/sessions/session_1752877884393_sqr7trvjl.json +7 -0
  61. package/.aiwf/sessions/session_1752877884500_whtypmzlf.json +7 -0
  62. package/.aiwf/sessions/session_1752877884645_y9mvvxli1.json +7 -0
  63. package/.aiwf/sessions/session_1752877884733_hk46eenel.json +7 -0
  64. package/.aiwf/sessions/session_1752877884738_c62j6214r.json +7 -0
  65. package/.aiwf/sessions/session_1752877884771_temhxehoz.json +7 -0
  66. package/.aiwf/sessions/session_1752877885643_6v5fcktc7.json +7 -0
  67. package/.aiwf/sessions/session_1752877886426_ee8di2fqh.json +7 -0
  68. package/.aiwf/sessions/session_1752877886549_3xj6tdoew.json +7 -0
  69. package/.aiwf/sessions/session_1752877886604_aj80yyfco.json +7 -0
  70. package/.aiwf/sessions/session_1752877886702_2b8841vyg.json +7 -0
  71. package/.aiwf/sessions/session_1752877886712_ntqc8b8bz.json +7 -0
  72. package/.aiwf/sessions/session_1752877886968_946m8tbw6.json +7 -0
  73. package/.aiwf/sessions/session_1752877887008_wg6zfg8dn.json +7 -0
  74. package/.aiwf/sessions/session_1752877888479_ciiu2qiqs.json +7 -0
  75. package/.aiwf/sessions/session_1752877889330_ravg8l66k.json +7 -0
  76. package/.aiwf/sessions/session_1752877889542_7zepkhjkc.json +7 -0
  77. package/.aiwf/sessions/session_1752877889638_ev4htqiu0.json +7 -0
  78. package/.aiwf/sessions/session_1752877889956_szphy2qma.json +7 -0
  79. package/.aiwf/sessions/session_1752877890220_o6aaa57tt.json +7 -0
  80. package/.aiwf/sessions/session_1752877890527_v2loy5vu1.json +7 -0
  81. package/.aiwf/sessions/session_1752877890572_cwq8fiuma.json +7 -0
  82. package/.aiwf/sessions/session_1752877892200_sgcwq1alt.json +7 -0
  83. package/.aiwf/sessions/session_1752877892268_v8kexpbc5.json +7 -0
  84. package/.aiwf/sessions/session_1752877892384_1gbbgrp4y.json +7 -0
  85. package/.aiwf/sessions/session_1752877893568_9p2n5p31a.json +7 -0
  86. package/.aiwf/sessions/session_1752877893727_un34a5tvp.json +7 -0
  87. package/.aiwf/sessions/session_1752877893778_01j79sw9i.json +7 -0
  88. package/.aiwf/sessions/session_1752877894053_jrhba6wko.json +7 -0
  89. package/.aiwf/sessions/session_1752877894082_x3bghawox.json +7 -0
  90. package/.aiwf/sessions/session_1752877894500_iytiav2ku.json +7 -0
  91. package/.aiwf/sessions/session_1752877894667_ucn0gc2ge.json +7 -0
  92. package/.aiwf/test-results-s02.json +4 -4
  93. package/.claude/commands/aiwf/aiwf_changelog.md +82 -0
  94. package/.claude/commands/aiwf/aiwf_code_review.md +88 -0
  95. package/.claude/commands/aiwf/aiwf_commit.md +160 -0
  96. package/.claude/commands/aiwf/aiwf_compress_aggressive_persona.md +53 -0
  97. package/.claude/commands/aiwf/aiwf_compress_context.md +116 -0
  98. package/.claude/commands/aiwf/aiwf_compress_minimal_persona.md +48 -0
  99. package/.claude/commands/aiwf/aiwf_compress_stats.md +79 -0
  100. package/.claude/commands/aiwf/aiwf_compress_with_persona.md +51 -0
  101. package/.claude/commands/aiwf/aiwf_create_feature_ledger.md +54 -0
  102. package/.claude/commands/aiwf/aiwf_create_general_task.md +147 -0
  103. package/.claude/commands/aiwf/aiwf_create_milestone_plan.md +194 -0
  104. package/.claude/commands/aiwf/aiwf_create_prd.md +280 -0
  105. package/.claude/commands/aiwf/aiwf_create_sprint_tasks.md +189 -0
  106. package/.claude/commands/aiwf/aiwf_create_sprints_from_milestone.md +121 -0
  107. package/.claude/commands/aiwf/aiwf_default_mode.md +44 -0
  108. package/.claude/commands/aiwf/aiwf_discuss_review.md +29 -0
  109. package/.claude/commands/aiwf/aiwf_do_task.md +109 -0
  110. package/.claude/commands/aiwf/aiwf_docs.md +225 -0
  111. package/.claude/commands/aiwf/aiwf_evaluate.md +92 -0
  112. package/.claude/commands/aiwf/aiwf_get_feature_details.md +78 -0
  113. package/.claude/commands/aiwf/aiwf_infinite.md +202 -0
  114. package/.claude/commands/aiwf/aiwf_initialize.md +134 -0
  115. package/.claude/commands/aiwf/aiwf_issue_create.md +65 -0
  116. package/.claude/commands/aiwf/aiwf_link_feature_to_milestone.md +57 -0
  117. package/.claude/commands/aiwf/aiwf_list_features.md +54 -0
  118. package/.claude/commands/aiwf/aiwf_mermaid.md +272 -0
  119. package/.claude/commands/aiwf/aiwf_persona_architect.md +48 -0
  120. package/.claude/commands/aiwf/aiwf_persona_backend.md +37 -0
  121. package/.claude/commands/aiwf/aiwf_persona_data_analyst.md +37 -0
  122. package/.claude/commands/aiwf/aiwf_persona_frontend.md +37 -0
  123. package/.claude/commands/aiwf/aiwf_persona_security.md +48 -0
  124. package/.claude/commands/aiwf/aiwf_persona_status.md +50 -0
  125. package/.claude/commands/aiwf/aiwf_pr_create.md +76 -0
  126. package/.claude/commands/aiwf/aiwf_prime.md +9 -0
  127. package/.claude/commands/aiwf/aiwf_project_review.md +261 -0
  128. package/.claude/commands/aiwf/aiwf_switch_language.md +160 -0
  129. package/.claude/commands/aiwf/aiwf_test.md +124 -0
  130. package/.claude/commands/aiwf/aiwf_testing_review.md +198 -0
  131. package/.claude/commands/aiwf/aiwf_tm-run-all-subtask.md +210 -0
  132. package/.claude/commands/aiwf/aiwf_ultrathink_code_advanced.md +460 -0
  133. package/.claude/commands/aiwf/aiwf_ultrathink_code_basic.md +165 -0
  134. package/.claude/commands/aiwf/aiwf_ultrathink_general.md +305 -0
  135. package/.claude/commands/aiwf/aiwf_update_docs_kr.md +25 -0
  136. package/.claude/commands/aiwf/aiwf_update_feature_status.md +53 -0
  137. package/.claude/commands/aiwf/aiwf_yolo.md +300 -0
  138. package/.eslintrc.json +26 -0
  139. package/.prettierrc +10 -0
  140. package/CLAUDE.md +154 -54
  141. package/README.ko.md +25 -0
  142. package/README.md +25 -0
  143. package/TEST_RECOVERY_PLAN.md +68 -0
  144. package/docs/CLEANUP_RECOMMENDATIONS.md +86 -0
  145. package/docs/CLI_USAGE_GUIDE.md +479 -0
  146. package/package.json +9 -9
  147. package/scripts/update-feature-status.js +70 -0
  148. package/{lib → src/cli}/cache-cli.js +4 -4
  149. package/src/cli/index.js +165 -0
  150. package/{language-cli.js → src/cli/language-cli.js} +11 -4
  151. package/src/commands/cache-templates.js +209 -0
  152. package/src/commands/create-offline.js +86 -0
  153. package/src/commands/create-project.js +151 -0
  154. package/src/lib/backup-manager.js +270 -0
  155. package/src/lib/file-downloader.js +208 -0
  156. package/src/lib/installer.js +676 -0
  157. package/src/lib/rollback-manager.js +418 -0
  158. package/src/lib/validator.js +561 -0
  159. package/src/utils/git-integration.js +173 -0
  160. package/{language-utils.js → src/utils/language-utils.js} +2 -1
  161. package/src/utils/messages.js +136 -0
  162. package/src/utils/paths.js +130 -0
  163. package/tests/application.test.js +2 -2
  164. package/tests/installer.test.js +2 -2
  165. package/tests/integration/ai-persona-system.test.js +4 -4
  166. package/tests/integration/test-persona-system/docs/README.md +1 -0
  167. package/tests/integration/test-persona-system/package.json +1 -0
  168. package/tests/integration/test-persona-system/src/auth.js +1 -0
  169. package/tests/integration/test-persona-system/src/index.js +1 -0
  170. package/tests/integration/test-persona-system/test/test.js +1 -0
  171. package/tests/language-utils.test.js +1 -1
  172. package/tests/temp_invalid_json/invalid.json +1 -0
  173. package/tests/unit/ai-persona-manager.test.js +7 -7
  174. package/.aiwf/05_DOCUMENTATION/performance-report.md +0 -33
  175. package/.aiwf/test-cache/86c7f9e80251abb8bedd58953ab0d1779e46b4f43ea33b63bffdb778106373b0.json +0 -6
  176. package/.aiwf/test-cache/9e252a90b80fce0585d7ed0646e7a9b4343e109f661f42a3ae678ba1ec5e22c7.json +0 -7
  177. package/.aiwf/token-data/alerts.json +0 -293
  178. package/.aiwf/token-data/monitor-config.json +0 -12
  179. package/CHANGELOG_M02.md +0 -52
  180. package/claude-code/aiwf/ko/templates/web-app/template/package-lock.json +0 -10022
  181. package/claude-code/aiwf/ko/token-data/alerts.json +0 -293
  182. package/claude-code/aiwf/ko/token-data/monitor-config.json +0 -12
  183. package/docs/m02-dod-checklist.md +0 -125
  184. package/docs/m02-gap-analysis.md +0 -214
  185. package/docs/m02-milestone-completion-report.md +0 -186
  186. package/docs/m02-milestone-executive-summary.md +0 -68
  187. package/index.js +0 -1951
  188. package/lib/cache-integration.js +0 -401
  189. package/lib/file-batch-processor.js +0 -401
  190. package/lib/performance-benchmark.js +0 -621
  191. package/lib/template-manager.js +0 -310
  192. package/scripts/validate-commands.cjs +0 -338
  193. /package/{lib → src/lib}/ai-persona-manager.js +0 -0
  194. /package/{lib → src/lib}/cache-system.js +0 -0
  195. /package/{lib → src/lib}/context-engine.js +0 -0
  196. /package/{lib → src/lib}/memory-profiler.js +0 -0
  197. /package/{lib → src/lib}/metrics-collector.js +0 -0
  198. /package/{lib → src/lib}/offline-detector.js +0 -0
  199. /package/{lib → src/lib}/task-analyzer.js +0 -0
  200. /package/{lib → src/lib}/template-cache-system.js +0 -0
  201. /package/{lib → src/lib}/template-downloader.js +0 -0
  202. /package/{lib → src/lib}/template-version-manager.js +0 -0
  203. /package/{lib → src/lib}/token-optimizer.js +0 -0
@@ -1,310 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from 'fs-extra';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
- import chalk from 'chalk';
7
-
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
-
10
- /**
11
- * AIWF 템플릿 관리자
12
- * 프로젝트 템플릿의 생성, 캐싱, 검증을 담당
13
- */
14
- export class TemplateManager {
15
- constructor() {
16
- this.templatesDir = path.resolve(__dirname, '../.aiwf/templates');
17
- this.cacheDir = path.resolve(__dirname, '../.aiwf/cache/templates');
18
- this.supportedTemplates = ['web-app', 'api-server', 'library'];
19
- }
20
-
21
- /**
22
- * 템플릿 목록 조회
23
- */
24
- async getAvailableTemplates() {
25
- const templates = [];
26
-
27
- for (const templateType of this.supportedTemplates) {
28
- const templatePath = path.join(this.templatesDir, templateType);
29
- const configPath = path.join(templatePath, 'template.json');
30
-
31
- if (await fs.pathExists(configPath)) {
32
- const config = await fs.readJson(configPath);
33
- templates.push({
34
- type: templateType,
35
- name: config.name,
36
- description: config.description,
37
- version: config.version,
38
- tech_stack: config.tech_stack,
39
- features: config.features
40
- });
41
- }
42
- }
43
-
44
- return templates;
45
- }
46
-
47
- /**
48
- * 템플릿 설정 로드
49
- */
50
- async getTemplateConfig(templateType) {
51
- const configPath = path.join(this.templatesDir, templateType, 'template.json');
52
-
53
- if (!await fs.pathExists(configPath)) {
54
- throw new Error(`Template config not found: ${templateType}`);
55
- }
56
-
57
- return await fs.readJson(configPath);
58
- }
59
-
60
- /**
61
- * 템플릿 검증
62
- */
63
- async validateTemplate(templateType) {
64
- const templatePath = path.join(this.templatesDir, templateType);
65
- const config = await this.getTemplateConfig(templateType);
66
-
67
- const issues = [];
68
-
69
- // 필수 파일 확인
70
- const requiredFiles = ['template.json', 'package.json'];
71
- for (const file of requiredFiles) {
72
- const filePath = path.join(templatePath, file);
73
- if (!await fs.pathExists(filePath)) {
74
- issues.push(`Missing required file: ${file}`);
75
- }
76
- }
77
-
78
- // 디렉토리 구조 확인
79
- if (config.file_structure) {
80
- for (const [dir, description] of Object.entries(config.file_structure)) {
81
- const dirPath = path.join(templatePath, dir);
82
- if (!await fs.pathExists(dirPath)) {
83
- issues.push(`Missing directory: ${dir} (${description})`);
84
- }
85
- }
86
- }
87
-
88
- // AIWF 통합 확인
89
- const aiwfPath = path.join(templatePath, '.aiwf');
90
- if (!await fs.pathExists(aiwfPath)) {
91
- issues.push('Missing .aiwf directory for AIWF integration');
92
- }
93
-
94
- return {
95
- valid: issues.length === 0,
96
- issues
97
- };
98
- }
99
-
100
- /**
101
- * 템플릿 캐시 생성 (오프라인 지원)
102
- */
103
- async cacheTemplate(templateType) {
104
- const templatePath = path.join(this.templatesDir, templateType);
105
- const cachePath = path.join(this.cacheDir, templateType);
106
-
107
- if (!await fs.pathExists(templatePath)) {
108
- throw new Error(`Template not found: ${templateType}`);
109
- }
110
-
111
- // 캐시 디렉토리 생성
112
- await fs.ensureDir(cachePath);
113
-
114
- // 템플릿 전체 복사
115
- await fs.copy(templatePath, cachePath, {
116
- overwrite: true,
117
- filter: (src) => {
118
- // node_modules나 .git 등은 제외
119
- return !src.includes('node_modules') && !src.includes('.git');
120
- }
121
- });
122
-
123
- // 캐시 메타데이터 생성
124
- const cacheMetadata = {
125
- templateType,
126
- cachedAt: new Date().toISOString(),
127
- version: (await this.getTemplateConfig(templateType)).version,
128
- checksum: await this.calculateChecksum(templatePath)
129
- };
130
-
131
- await fs.writeJson(
132
- path.join(cachePath, '.cache-metadata.json'),
133
- cacheMetadata,
134
- { spaces: 2 }
135
- );
136
-
137
- return cachePath;
138
- }
139
-
140
- /**
141
- * 캐시된 템플릿 사용 (오프라인 모드)
142
- */
143
- async getCachedTemplate(templateType) {
144
- const cachePath = path.join(this.cacheDir, templateType);
145
- const metadataPath = path.join(cachePath, '.cache-metadata.json');
146
-
147
- if (!await fs.pathExists(cachePath) || !await fs.pathExists(metadataPath)) {
148
- return null;
149
- }
150
-
151
- const metadata = await fs.readJson(metadataPath);
152
-
153
- return {
154
- path: cachePath,
155
- metadata
156
- };
157
- }
158
-
159
- /**
160
- * 템플릿 체크섬 계산
161
- */
162
- async calculateChecksum(templatePath) {
163
- const crypto = await import('crypto');
164
- const hash = crypto.createHash('md5');
165
-
166
- const files = await this.getAllFiles(templatePath);
167
- files.sort(); // 일관된 순서 보장
168
-
169
- for (const file of files) {
170
- const content = await fs.readFile(file);
171
- hash.update(content);
172
- }
173
-
174
- return hash.digest('hex');
175
- }
176
-
177
- /**
178
- * 디렉토리의 모든 파일 경로 조회 (재귀)
179
- */
180
- async getAllFiles(dirPath, files = []) {
181
- const items = await fs.readdir(dirPath);
182
-
183
- for (const item of items) {
184
- const fullPath = path.join(dirPath, item);
185
- const stat = await fs.stat(fullPath);
186
-
187
- if (stat.isDirectory()) {
188
- // node_modules, .git 등 제외
189
- if (!['node_modules', '.git', '.cache'].includes(item)) {
190
- await this.getAllFiles(fullPath, files);
191
- }
192
- } else {
193
- files.push(fullPath);
194
- }
195
- }
196
-
197
- return files;
198
- }
199
-
200
- /**
201
- * 모든 템플릿 캐시 생성
202
- */
203
- async cacheAllTemplates() {
204
- const results = [];
205
-
206
- for (const templateType of this.supportedTemplates) {
207
- try {
208
- const cachePath = await this.cacheTemplate(templateType);
209
- results.push({
210
- templateType,
211
- success: true,
212
- cachePath
213
- });
214
- } catch (error) {
215
- results.push({
216
- templateType,
217
- success: false,
218
- error: error.message
219
- });
220
- }
221
- }
222
-
223
- return results;
224
- }
225
-
226
- /**
227
- * 캐시 정보 조회
228
- */
229
- async getCacheInfo() {
230
- const cacheInfo = {
231
- cacheDir: this.cacheDir,
232
- templates: []
233
- };
234
-
235
- for (const templateType of this.supportedTemplates) {
236
- const cached = await this.getCachedTemplate(templateType);
237
-
238
- cacheInfo.templates.push({
239
- type: templateType,
240
- cached: !!cached,
241
- metadata: cached?.metadata || null
242
- });
243
- }
244
-
245
- return cacheInfo;
246
- }
247
-
248
- /**
249
- * 캐시 정리
250
- */
251
- async clearCache() {
252
- if (await fs.pathExists(this.cacheDir)) {
253
- await fs.remove(this.cacheDir);
254
- }
255
- await fs.ensureDir(this.cacheDir);
256
- }
257
-
258
- /**
259
- * 오프라인 모드 감지
260
- */
261
- async isOfflineMode() {
262
- // 네트워크 연결 확인 (간단한 방법)
263
- try {
264
- const dns = await import('dns');
265
- await new Promise((resolve, reject) => {
266
- dns.lookup('google.com', (err) => {
267
- if (err) reject(err);
268
- else resolve();
269
- });
270
- });
271
- return false; // 온라인
272
- } catch {
273
- return true; // 오프라인
274
- }
275
- }
276
-
277
- /**
278
- * 템플릿 소스 선택 (온라인/오프라인)
279
- */
280
- async getTemplateSource(templateType) {
281
- const isOffline = await this.isOfflineMode();
282
-
283
- if (isOffline) {
284
- console.log(chalk.yellow('🔄 오프라인 모드: 캐시된 템플릿을 사용합니다.'));
285
-
286
- const cached = await this.getCachedTemplate(templateType);
287
- if (!cached) {
288
- throw new Error(`오프라인 상태이며 캐시된 템플릿이 없습니다: ${templateType}`);
289
- }
290
-
291
- return cached.path;
292
- } else {
293
- // 온라인 상태: 최신 템플릿 사용
294
- const templatePath = path.join(this.templatesDir, templateType);
295
-
296
- if (!await fs.pathExists(templatePath)) {
297
- throw new Error(`템플릿을 찾을 수 없습니다: ${templateType}`);
298
- }
299
-
300
- // 백그라운드에서 캐시 업데이트
301
- this.cacheTemplate(templateType).catch(err => {
302
- console.warn(chalk.yellow(`캐시 업데이트 실패: ${err.message}`));
303
- });
304
-
305
- return templatePath;
306
- }
307
- }
308
- }
309
-
310
- export default TemplateManager;
@@ -1,338 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * AIWF 명령어 파일 일관성 검증 도구
5
- *
6
- * 이 스크립트는 다음을 검증합니다:
7
- * 1. 한국어/영어 명령어 파일 간의 일관성
8
- * 2. 명령어 파일명과 실제 명령어명의 매칭
9
- * 3. 누락된 명령어 파일 식별
10
- * 4. GitHub URL 참조 일관성
11
- */
12
-
13
- const fs = require('fs');
14
- const path = require('path');
15
-
16
- // 색상 출력을 위한 ANSI 코드
17
- const colors = {
18
- reset: '\x1b[0m',
19
- red: '\x1b[31m',
20
- green: '\x1b[32m',
21
- yellow: '\x1b[33m',
22
- blue: '\x1b[34m',
23
- cyan: '\x1b[36m'
24
- };
25
-
26
- function log(message, color = 'reset') {
27
- console.log(`${colors[color]}${message}${colors.reset}`);
28
- }
29
-
30
- // 명령어 파일 경로
31
- const KOREAN_COMMANDS_PATH = path.join(__dirname, '../claude-code/aiwf/ko/.claude/commands/aiwf');
32
- const ENGLISH_COMMANDS_PATH = path.join(__dirname, '../claude-code/aiwf/en/.claude/commands/aiwf');
33
-
34
- /**
35
- * 디렉토리에서 명령어 파일 목록을 가져옵니다
36
- */
37
- function getCommandFiles(dirPath) {
38
- try {
39
- return fs.readdirSync(dirPath)
40
- .filter(file => file.endsWith('.md'))
41
- .map(file => ({
42
- filename: file,
43
- path: path.join(dirPath, file)
44
- }));
45
- } catch (error) {
46
- log(`디렉토리를 읽을 수 없습니다: ${dirPath}`, 'red');
47
- return [];
48
- }
49
- }
50
-
51
- /**
52
- * 명령어 파일에서 메타데이터를 추출합니다
53
- */
54
- function extractCommandMetadata(filePath) {
55
- try {
56
- const content = fs.readFileSync(filePath, 'utf8');
57
- const lines = content.split('\n');
58
-
59
- // 파일명에서 명령어명 추출 (aiwf_*.md → aiwf_*)
60
- const filename = path.basename(filePath, '.md');
61
-
62
- // 첫 번째 # 제목 찾기
63
- const titleLine = lines.find(line => line.startsWith('# '));
64
- const title = titleLine ? titleLine.substring(2).trim() : '';
65
-
66
- // frontmatter에서 name 필드 찾기 (있는 경우)
67
- let frontmatterName = '';
68
- if (content.startsWith('---')) {
69
- const frontmatterEnd = content.indexOf('---', 3);
70
- if (frontmatterEnd > 0) {
71
- const frontmatter = content.substring(0, frontmatterEnd);
72
- const nameMatch = frontmatter.match(/name:\s*["']?([^"'\n]+)["']?/);
73
- if (nameMatch) {
74
- frontmatterName = nameMatch[1];
75
- }
76
- }
77
- }
78
-
79
- return {
80
- filename,
81
- title,
82
- frontmatterName,
83
- path: filePath
84
- };
85
- } catch (error) {
86
- log(`파일을 읽을 수 없습니다: ${filePath}`, 'red');
87
- return null;
88
- }
89
- }
90
-
91
- /**
92
- * 한국어와 영어 명령어 파일의 일관성을 검증합니다
93
- */
94
- function validateConsistency() {
95
- log('\n=== 명령어 파일 일관성 검증 ===', 'cyan');
96
-
97
- const koreanFiles = getCommandFiles(KOREAN_COMMANDS_PATH);
98
- const englishFiles = getCommandFiles(ENGLISH_COMMANDS_PATH);
99
-
100
- log(`한국어 명령어 파일: ${koreanFiles.length}개`, 'blue');
101
- log(`영어 명령어 파일: ${englishFiles.length}개`, 'blue');
102
-
103
- // 파일명 기준으로 매칭 (한국어는 _kr 접미사 제거)
104
- const koreanFileMap = new Map();
105
- const englishFileMap = new Map();
106
-
107
- koreanFiles.forEach(file => {
108
- const normalizedName = file.filename.replace('_kr.md', '.md');
109
- koreanFileMap.set(normalizedName, file);
110
- });
111
-
112
- englishFiles.forEach(file => {
113
- englishFileMap.set(file.filename, file);
114
- });
115
-
116
- // 누락된 파일 확인
117
- const allFileNames = new Set([...koreanFileMap.keys(), ...englishFileMap.keys()]);
118
- const missingInKorean = [];
119
- const missingInEnglish = [];
120
-
121
- allFileNames.forEach(filename => {
122
- if (!koreanFileMap.has(filename)) {
123
- missingInKorean.push(filename);
124
- }
125
- if (!englishFileMap.has(filename)) {
126
- missingInEnglish.push(filename);
127
- }
128
- });
129
-
130
- // 결과 출력
131
- if (missingInKorean.length > 0) {
132
- log('\n한국어 버전에서 누락된 파일:', 'yellow');
133
- missingInKorean.forEach(file => log(` - ${file}`, 'red'));
134
- }
135
-
136
- if (missingInEnglish.length > 0) {
137
- log('\n영어 버전에서 누락된 파일:', 'yellow');
138
- missingInEnglish.forEach(file => log(` - ${file}`, 'red'));
139
- }
140
-
141
- if (missingInKorean.length === 0 && missingInEnglish.length === 0) {
142
- log('\n✅ 모든 명령어 파일이 한국어/영어 버전으로 존재합니다', 'green');
143
- }
144
-
145
- return {
146
- koreanFiles: koreanFileMap,
147
- englishFiles: englishFileMap,
148
- missingInKorean,
149
- missingInEnglish
150
- };
151
- }
152
-
153
- /**
154
- * 명령어 파일의 메타데이터를 검증합니다
155
- */
156
- function validateMetadata() {
157
- log('\n=== 명령어 메타데이터 검증 ===', 'cyan');
158
-
159
- const koreanFiles = getCommandFiles(KOREAN_COMMANDS_PATH);
160
- const englishFiles = getCommandFiles(ENGLISH_COMMANDS_PATH);
161
-
162
- let issues = 0;
163
-
164
- // 한국어 파일 검증
165
- log('\n한국어 명령어 파일 검증:', 'blue');
166
- koreanFiles.forEach(file => {
167
- const metadata = extractCommandMetadata(file.path);
168
- if (metadata) {
169
- if (!metadata.title) {
170
- log(` ❌ ${file.filename}: 제목이 없습니다`, 'red');
171
- issues++;
172
- } else {
173
- log(` ✅ ${file.filename}: ${metadata.title}`, 'green');
174
- }
175
- }
176
- });
177
-
178
- // 영어 파일 검증
179
- log('\n영어 명령어 파일 검증:', 'blue');
180
- englishFiles.forEach(file => {
181
- const metadata = extractCommandMetadata(file.path);
182
- if (metadata) {
183
- if (!metadata.title) {
184
- log(` ❌ ${file.filename}: 제목이 없습니다`, 'red');
185
- issues++;
186
- } else {
187
- log(` ✅ ${file.filename}: ${metadata.title}`, 'green');
188
- }
189
- }
190
- });
191
-
192
- if (issues === 0) {
193
- log('\n✅ 모든 명령어 파일의 메타데이터가 올바릅니다', 'green');
194
- } else {
195
- log(`\n❌ ${issues}개의 메타데이터 이슈가 발견되었습니다`, 'red');
196
- }
197
-
198
- return issues;
199
- }
200
-
201
- /**
202
- * GitHub URL 참조를 검증합니다
203
- */
204
- function validateGitHubUrls() {
205
- log('\n=== GitHub URL 참조 검증 ===', 'cyan');
206
-
207
- const allFiles = [
208
- ...getCommandFiles(KOREAN_COMMANDS_PATH),
209
- ...getCommandFiles(ENGLISH_COMMANDS_PATH)
210
- ];
211
-
212
- let issues = 0;
213
-
214
- allFiles.forEach(file => {
215
- const content = fs.readFileSync(file.path, 'utf8');
216
-
217
- // moonklabs/aiwf 패턴 검색
218
- if (content.includes('moonklabs/aiwf')) {
219
- log(` ❌ ${file.filename}: 'moonklabs/aiwf' 참조 발견`, 'red');
220
- issues++;
221
- }
222
-
223
- // aiwf/aiwf 패턴 확인
224
- if (content.includes('aiwf/aiwf')) {
225
- log(` ✅ ${file.filename}: 올바른 'aiwf/aiwf' 참조`, 'green');
226
- }
227
- });
228
-
229
- if (issues === 0) {
230
- log('\n✅ 모든 GitHub URL 참조가 올바릅니다', 'green');
231
- } else {
232
- log(`\n❌ ${issues}개의 잘못된 GitHub URL 참조가 발견되었습니다`, 'red');
233
- }
234
-
235
- return issues;
236
- }
237
-
238
- /**
239
- * 특정 명령어 파일이 누락되었는지 확인합니다
240
- */
241
- function checkSpecificCommands() {
242
- log('\n=== 특정 명령어 파일 확인 ===', 'cyan');
243
-
244
- const requiredCommands = [
245
- 'aiwf_update_docs.md', // 영어 버전
246
- 'aiwf_update_docs_kr.md' // 한국어 버전
247
- ];
248
-
249
- let issues = 0;
250
-
251
- requiredCommands.forEach(commandFile => {
252
- const isKorean = commandFile.includes('_kr');
253
- const dirPath = isKorean ? KOREAN_COMMANDS_PATH : ENGLISH_COMMANDS_PATH;
254
- const filePath = path.join(dirPath, commandFile);
255
-
256
- if (fs.existsSync(filePath)) {
257
- log(` ✅ ${commandFile}: 존재`, 'green');
258
- } else {
259
- log(` ❌ ${commandFile}: 누락`, 'red');
260
- issues++;
261
- }
262
- });
263
-
264
- // aiwf_docs.md가 있는지 확인 (기존 파일)
265
- const legacyDocsKo = path.join(KOREAN_COMMANDS_PATH, 'aiwf_docs.md');
266
- const legacyDocsEn = path.join(ENGLISH_COMMANDS_PATH, 'aiwf_docs.md');
267
-
268
- if (fs.existsSync(legacyDocsKo)) {
269
- log(` ℹ️ aiwf_docs.md (한국어): 기존 파일 존재`, 'yellow');
270
- }
271
-
272
- if (fs.existsSync(legacyDocsEn)) {
273
- log(` ℹ️ aiwf_docs.md (영어): 기존 파일 존재`, 'yellow');
274
- }
275
-
276
- return issues;
277
- }
278
-
279
- /**
280
- * 검증 요약을 출력합니다
281
- */
282
- function printSummary(results) {
283
- log('\n=== 검증 요약 ===', 'cyan');
284
-
285
- const totalIssues = results.metadataIssues + results.githubUrlIssues + results.specificCommandIssues;
286
-
287
- log(`총 발견된 이슈: ${totalIssues}개`, totalIssues > 0 ? 'red' : 'green');
288
- log(`- 메타데이터 이슈: ${results.metadataIssues}개`, 'blue');
289
- log(`- GitHub URL 이슈: ${results.githubUrlIssues}개`, 'blue');
290
- log(`- 누락된 특정 명령어: ${results.specificCommandIssues}개`, 'blue');
291
- log(`- 한국어 버전 누락: ${results.consistency.missingInKorean.length}개`, 'blue');
292
- log(`- 영어 버전 누락: ${results.consistency.missingInEnglish.length}개`, 'blue');
293
-
294
- if (totalIssues === 0) {
295
- log('\n🎉 모든 검증이 통과되었습니다!', 'green');
296
- return true;
297
- } else {
298
- log('\n⚠️ 일부 이슈가 발견되었습니다. 위의 내용을 확인해주세요.', 'red');
299
- return false;
300
- }
301
- }
302
-
303
- /**
304
- * 메인 실행 함수
305
- */
306
- function main() {
307
- log('AIWF 명령어 파일 일관성 검증 도구', 'cyan');
308
- log('====================================', 'cyan');
309
-
310
- const consistency = validateConsistency();
311
- const metadataIssues = validateMetadata();
312
- const githubUrlIssues = validateGitHubUrls();
313
- const specificCommandIssues = checkSpecificCommands();
314
-
315
- const results = {
316
- consistency,
317
- metadataIssues,
318
- githubUrlIssues,
319
- specificCommandIssues
320
- };
321
-
322
- const success = printSummary(results);
323
-
324
- // 종료 코드 설정
325
- process.exit(success ? 0 : 1);
326
- }
327
-
328
- // 스크립트가 직접 실행될 때만 main 함수 호출
329
- if (require.main === module) {
330
- main();
331
- }
332
-
333
- module.exports = {
334
- validateConsistency,
335
- validateMetadata,
336
- validateGitHubUrls,
337
- checkSpecificCommands
338
- };
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes