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
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { getMessages } from '../utils/messages.js';
|
|
6
|
+
import { getToolDirectory as getToolDirectoryPath } from '../utils/paths.js';
|
|
7
|
+
|
|
8
|
+
// Backup file patterns for each tool
|
|
9
|
+
const BACKUP_PATTERNS = {
|
|
10
|
+
claudeCode: /^claude-commands-aiwf-.*\.bak$/,
|
|
11
|
+
geminiCLI: /^gemini-prompts-aiwf-.*\.bak$/,
|
|
12
|
+
cursor: /^cursor-rules-.*\.bak$/,
|
|
13
|
+
windsurf: /^windsurf-rules-.*\.bak$/,
|
|
14
|
+
aiwf: /^aiwf-.*\.bak$/
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Backup file prefixes
|
|
18
|
+
const BACKUP_PREFIXES = {
|
|
19
|
+
claudeCode: 'claude-commands-aiwf-',
|
|
20
|
+
geminiCLI: 'gemini-prompts-aiwf-',
|
|
21
|
+
cursor: 'cursor-rules-',
|
|
22
|
+
windsurf: 'windsurf-rules-',
|
|
23
|
+
aiwf: 'aiwf-'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Tool names for localization
|
|
27
|
+
const TOOL_NAMES = {
|
|
28
|
+
ko: {
|
|
29
|
+
aiwf: 'AIWF μ½μ΄ ꡬ쑰',
|
|
30
|
+
claudeCode: 'Claude Code λͺ
λ Ήμ΄',
|
|
31
|
+
'claude-code': 'Claude Code λͺ
λ Ήμ΄',
|
|
32
|
+
geminiCLI: 'Gemini-CLI ν둬ννΈ',
|
|
33
|
+
'gemini-cli': 'Gemini-CLI ν둬ννΈ',
|
|
34
|
+
cursor: 'Cursor IDE κ·μΉ',
|
|
35
|
+
windsurf: 'Windsurf IDE κ·μΉ'
|
|
36
|
+
},
|
|
37
|
+
en: {
|
|
38
|
+
aiwf: 'AIWF Core Structure',
|
|
39
|
+
claudeCode: 'Claude Code Commands',
|
|
40
|
+
'claude-code': 'Claude Code Commands',
|
|
41
|
+
geminiCLI: 'Gemini-CLI Prompts',
|
|
42
|
+
'gemini-cli': 'Gemini-CLI Prompts',
|
|
43
|
+
cursor: 'Cursor IDE Rules',
|
|
44
|
+
windsurf: 'Windsurf IDE Rules'
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get tool directory path
|
|
50
|
+
* @param {string} tool - Tool name
|
|
51
|
+
* @returns {string|null} Directory path or null
|
|
52
|
+
*/
|
|
53
|
+
export function getToolDirectory(tool) {
|
|
54
|
+
return getToolDirectoryPath(tool);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get localized tool name
|
|
59
|
+
* @param {string} tool - Tool name
|
|
60
|
+
* @param {string} language - Language code
|
|
61
|
+
* @returns {string} Localized tool name
|
|
62
|
+
*/
|
|
63
|
+
export function getToolName(tool, language) {
|
|
64
|
+
return TOOL_NAMES[language]?.[tool] || tool;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Restore original path from backup filename
|
|
69
|
+
* @param {string} backupFileName - Backup file name
|
|
70
|
+
* @param {string} tool - Tool name
|
|
71
|
+
* @returns {string|null} Original path or null
|
|
72
|
+
*/
|
|
73
|
+
function restoreOriginalPath(backupFileName, tool) {
|
|
74
|
+
const baseDir = getToolDirectory(tool);
|
|
75
|
+
if (!baseDir) return null;
|
|
76
|
+
|
|
77
|
+
let originalFileName = backupFileName;
|
|
78
|
+
|
|
79
|
+
// Remove tool-specific prefix
|
|
80
|
+
const prefix = BACKUP_PREFIXES[tool];
|
|
81
|
+
if (prefix && originalFileName.startsWith(prefix)) {
|
|
82
|
+
originalFileName = originalFileName.substring(prefix.length);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Remove .bak extension
|
|
86
|
+
if (originalFileName.endsWith('.bak')) {
|
|
87
|
+
originalFileName = originalFileName.substring(0, originalFileName.length - 4);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Replace hyphens with slashes (subdirectory structure)
|
|
91
|
+
originalFileName = originalFileName.replace(/-/g, '/');
|
|
92
|
+
|
|
93
|
+
return path.join(baseDir, originalFileName);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get backup files for a specific tool
|
|
98
|
+
* @param {string} tool - Tool name
|
|
99
|
+
* @param {string} backupDir - Backup directory path
|
|
100
|
+
* @returns {Promise<Array>} Array of backup file info
|
|
101
|
+
*/
|
|
102
|
+
async function getBackupFilesForTool(tool, backupDir) {
|
|
103
|
+
const toolBackupFiles = [];
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const backupFiles = await fs.readdir(backupDir);
|
|
107
|
+
const pattern = BACKUP_PATTERNS[tool];
|
|
108
|
+
|
|
109
|
+
if (pattern) {
|
|
110
|
+
const matchingFiles = backupFiles.filter(file => pattern.test(file));
|
|
111
|
+
for (const file of matchingFiles) {
|
|
112
|
+
toolBackupFiles.push({
|
|
113
|
+
backupFile: path.join(backupDir, file),
|
|
114
|
+
originalPath: restoreOriginalPath(file, tool)
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
// Backup directory doesn't exist or can't be read
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return toolBackupFiles;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Restore a single backup file
|
|
127
|
+
* @param {Object} backup - Backup file info
|
|
128
|
+
* @returns {Promise<boolean>} Success status
|
|
129
|
+
*/
|
|
130
|
+
async function restoreBackupFile(backup) {
|
|
131
|
+
try {
|
|
132
|
+
// Ensure target directory exists
|
|
133
|
+
const targetDir = path.dirname(backup.originalPath);
|
|
134
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
135
|
+
|
|
136
|
+
// Copy backup file to original location
|
|
137
|
+
await fs.copyFile(backup.backupFile, backup.originalPath);
|
|
138
|
+
return true;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Rollback a specific tool
|
|
146
|
+
* @param {string} tool - Tool name
|
|
147
|
+
* @param {string} backupDir - Backup directory path
|
|
148
|
+
* @param {string} language - Language code
|
|
149
|
+
* @returns {Promise<Object>} Rollback result
|
|
150
|
+
*/
|
|
151
|
+
export async function rollbackTool(tool, backupDir, language = 'ko') {
|
|
152
|
+
const messages = getMessages(language);
|
|
153
|
+
const spinner = ora(
|
|
154
|
+
language === 'ko' ? `${tool} λꡬλ₯Ό λ‘€λ°±νλ μ€...` : `Rolling back ${tool}...`
|
|
155
|
+
).start();
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
// 1. Remove tool directory
|
|
159
|
+
const toolDir = getToolDirectory(tool);
|
|
160
|
+
if (toolDir) {
|
|
161
|
+
const dirExists = await fs
|
|
162
|
+
.access(toolDir)
|
|
163
|
+
.then(() => true)
|
|
164
|
+
.catch(() => false);
|
|
165
|
+
if (dirExists) {
|
|
166
|
+
await fs.rm(toolDir, { recursive: true, force: true });
|
|
167
|
+
spinner.text =
|
|
168
|
+
language === 'ko' ? `${tool} λλ ν 리 μμ μλ£` : `${tool} directory removed`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 2. Restore from backup
|
|
173
|
+
const backupFiles = await getBackupFilesForTool(tool, backupDir);
|
|
174
|
+
let restoredCount = 0;
|
|
175
|
+
|
|
176
|
+
for (const backup of backupFiles) {
|
|
177
|
+
const restored = await restoreBackupFile(backup);
|
|
178
|
+
if (restored) {
|
|
179
|
+
restoredCount++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (restoredCount > 0) {
|
|
184
|
+
spinner.succeed(
|
|
185
|
+
chalk.green(
|
|
186
|
+
language === 'ko'
|
|
187
|
+
? `${tool} λ‘€λ°± μλ£ (${restoredCount}κ° νμΌ λ³΅μ)`
|
|
188
|
+
: `${tool} rolled back successfully (${restoredCount} files restored)`
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
|
+
return { success: true, restoredCount };
|
|
192
|
+
} else {
|
|
193
|
+
spinner.warn(
|
|
194
|
+
chalk.yellow(
|
|
195
|
+
language === 'ko'
|
|
196
|
+
? `${tool} λ‘€λ°±: 볡μν λ°±μ
νμΌμ΄ μμ`
|
|
197
|
+
: `${tool} rollback: No backup files to restore`
|
|
198
|
+
)
|
|
199
|
+
);
|
|
200
|
+
return { success: true, restoredCount: 0 };
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
spinner.fail(
|
|
204
|
+
chalk.red(
|
|
205
|
+
language === 'ko'
|
|
206
|
+
? `${tool} λ‘€λ°± μ€ν¨: ${error.message}`
|
|
207
|
+
: `Failed to rollback ${tool}: ${error.message}`
|
|
208
|
+
)
|
|
209
|
+
);
|
|
210
|
+
return { success: false, error: error.message };
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Enhanced rollback function with backup directory
|
|
216
|
+
* @param {string} tool - Tool name
|
|
217
|
+
* @param {string} backupDir - Backup directory path
|
|
218
|
+
* @param {string} language - Language code
|
|
219
|
+
* @returns {Promise<boolean>} Success status
|
|
220
|
+
*/
|
|
221
|
+
export async function rollbackToolEnhanced(tool, backupDir, language = 'ko') {
|
|
222
|
+
const spinner = ora(`Rolling back ${tool}...`).start();
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
// Get tool directory mapping
|
|
226
|
+
const toolDir = getToolDirectory(tool);
|
|
227
|
+
if (!toolDir) {
|
|
228
|
+
spinner.fail(`Unknown tool: ${tool}`);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Remove installed directory
|
|
233
|
+
try {
|
|
234
|
+
await fs.access(toolDir);
|
|
235
|
+
await fs.rm(toolDir, { recursive: true, force: true });
|
|
236
|
+
spinner.text = `Removed ${toolDir}`;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
// Directory doesn't exist, skip
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Restore from backup if available
|
|
242
|
+
if (backupDir) {
|
|
243
|
+
const backupFiles = await getBackupFilesForTool(tool, backupDir);
|
|
244
|
+
for (const backup of backupFiles) {
|
|
245
|
+
await restoreBackupFile(backup);
|
|
246
|
+
spinner.text = `Restored ${backup.originalPath}`;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
spinner.succeed(`${tool} rolled back successfully`);
|
|
251
|
+
return true;
|
|
252
|
+
} catch (error) {
|
|
253
|
+
spinner.fail(`Failed to rollback ${tool}: ${error.message}`);
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Generate installation report
|
|
260
|
+
* @param {Object} validationResults - Validation results
|
|
261
|
+
* @param {string} language - Language code
|
|
262
|
+
* @param {string} installationType - Installation type
|
|
263
|
+
*/
|
|
264
|
+
export function generateInstallationReport(
|
|
265
|
+
validationResults,
|
|
266
|
+
language,
|
|
267
|
+
installationType = 'install'
|
|
268
|
+
) {
|
|
269
|
+
const messages = getMessages(language);
|
|
270
|
+
|
|
271
|
+
// Header
|
|
272
|
+
console.log(chalk.blue.bold('\n' + '='.repeat(60)));
|
|
273
|
+
console.log(
|
|
274
|
+
chalk.blue.bold(
|
|
275
|
+
language === 'ko'
|
|
276
|
+
? 'π AIWF μ€μΉ κ²μ¦ λ° λ¦¬ν¬νΈ'
|
|
277
|
+
: 'π AIWF Installation Validation & Report'
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
console.log(chalk.blue.bold('='.repeat(60)));
|
|
281
|
+
|
|
282
|
+
// Installation type
|
|
283
|
+
const installTypeText = {
|
|
284
|
+
install: language === 'ko' ? 'μ μ€μΉ' : 'Fresh Installation',
|
|
285
|
+
update: language === 'ko' ? 'μ
λ°μ΄νΈ' : 'Update',
|
|
286
|
+
reinstall: language === 'ko' ? 'μ¬μ€μΉ' : 'Reinstallation'
|
|
287
|
+
};
|
|
288
|
+
console.log(
|
|
289
|
+
chalk.gray(
|
|
290
|
+
`μ€μΉ μ ν / Installation Type: ${installTypeText[installationType] || installTypeText.install}`
|
|
291
|
+
)
|
|
292
|
+
);
|
|
293
|
+
console.log(chalk.gray(`κ²μ¦ μκ° / Validation Time: ${new Date().toLocaleString()}`));
|
|
294
|
+
|
|
295
|
+
// Overall summary
|
|
296
|
+
const { overall } = validationResults;
|
|
297
|
+
const statusIcon = overall.success ? 'β
' : 'β';
|
|
298
|
+
const statusColor = overall.success ? chalk.green : chalk.red;
|
|
299
|
+
|
|
300
|
+
console.log(
|
|
301
|
+
statusColor(
|
|
302
|
+
`\n${statusIcon} μ 체 μν / Overall Status: ${overall.success ? 'PASSED' : 'FAILED'}`
|
|
303
|
+
)
|
|
304
|
+
);
|
|
305
|
+
console.log(chalk.gray(` κ²μ¦ν λꡬ / Tools Checked: ${overall.toolsChecked}`));
|
|
306
|
+
console.log(chalk.gray(` μ±κ³΅ν λꡬ / Tools Passed: ${overall.toolsPassed}`));
|
|
307
|
+
|
|
308
|
+
if (overall.toolsFailed > 0) {
|
|
309
|
+
console.log(chalk.red(` μ€ν¨ν λꡬ / Tools Failed: ${overall.toolsFailed}`));
|
|
310
|
+
console.log(chalk.red(` μ΄ μ΄μ μ / Total Issues: ${overall.totalIssues}`));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Individual tool results
|
|
314
|
+
console.log(chalk.blue('\n=== κ°λ³ λꡬ κ²°κ³Ό / Individual Tool Results ==='));
|
|
315
|
+
|
|
316
|
+
for (const [toolName, result] of Object.entries(validationResults.tools)) {
|
|
317
|
+
const toolIcon = result.success ? 'β
' : 'β';
|
|
318
|
+
const toolColor = result.success ? chalk.green : chalk.red;
|
|
319
|
+
|
|
320
|
+
console.log(toolColor(`\n${toolIcon} ${result.description} (${toolName})`));
|
|
321
|
+
console.log(chalk.gray(` λλ ν 리 / Directory: ${result.baseDir}`));
|
|
322
|
+
console.log(chalk.gray(` νμΌ μ / Files Found: ${result.checks.fileCount}`));
|
|
323
|
+
console.log(
|
|
324
|
+
chalk.gray(` μ΄ ν¬κΈ° / Total Size: ${(result.checks.totalSize / 1024).toFixed(2)} KB`)
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
if (result.checks.issues.length > 0) {
|
|
328
|
+
console.log(chalk.red(` μ΄μ / Issues:`));
|
|
329
|
+
for (const issue of result.checks.issues) {
|
|
330
|
+
console.log(chalk.red(` β’ ${issue}`));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (result.checks.requiredFiles.length > 0) {
|
|
335
|
+
console.log(chalk.gray(` νμ νμΌ / Required Files:`));
|
|
336
|
+
for (const fileCheck of result.checks.requiredFiles) {
|
|
337
|
+
const fileIcon = fileCheck.valid ? 'β
' : 'β';
|
|
338
|
+
const fileColor = fileCheck.valid ? chalk.gray : chalk.red;
|
|
339
|
+
console.log(
|
|
340
|
+
fileColor(
|
|
341
|
+
` ${fileIcon} ${fileCheck.file} (${(fileCheck.size / 1024).toFixed(2)} KB)`
|
|
342
|
+
)
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Recommendations
|
|
349
|
+
console.log(chalk.blue('\n=== κΆμ₯μ¬ν / Recommendations ==='));
|
|
350
|
+
if (overall.success) {
|
|
351
|
+
console.log(chalk.green('π λͺ¨λ λκ΅¬κ° μ¬λ°λ₯΄κ² μ€μΉλμ΄ κ²μ¦λμμ΅λλ€!'));
|
|
352
|
+
console.log(chalk.green('π All tools are properly installed and validated!'));
|
|
353
|
+
console.log(chalk.blue('\nλ€μ λ¨κ³ / Next Steps:'));
|
|
354
|
+
console.log(chalk.white(' 1. Claude Codeμμ νλ‘μ νΈλ₯Ό μ΄μ΄λ³΄μΈμ'));
|
|
355
|
+
console.log(chalk.white(' 2. /project:aiwf:initialize λͺ
λ Ήμ΄λ‘ νλ‘μ νΈλ₯Ό μ΄κΈ°ννμΈμ'));
|
|
356
|
+
console.log(chalk.white(' 3. νλ‘μ νΈ κ΄λ¦¬λ₯Ό μμνμΈμ!'));
|
|
357
|
+
} else {
|
|
358
|
+
console.log(chalk.yellow('β οΈ μΌλΆ μ΄μκ° λ°κ²¬λμμ΅λλ€. μμ μΈλΆμ¬νμ νμΈνμΈμ.'));
|
|
359
|
+
console.log(chalk.yellow('β οΈ Some issues were found. See details above.'));
|
|
360
|
+
|
|
361
|
+
// Solutions for failed tools
|
|
362
|
+
const failedTools = Object.entries(validationResults.tools)
|
|
363
|
+
.filter(([_, result]) => !result.success)
|
|
364
|
+
.map(([tool, _]) => tool);
|
|
365
|
+
|
|
366
|
+
if (failedTools.length > 0) {
|
|
367
|
+
console.log(chalk.blue('\nν΄κ²° λ°©μ / Solutions:'));
|
|
368
|
+
console.log(chalk.yellow(' β’ μ 체 μ¬μ€μΉλ₯Ό μλν΄λ³΄μΈμ'));
|
|
369
|
+
console.log(chalk.yellow(' β’ μ€ν¨ν λκ΅¬λ§ λ‘€λ°± ν λ€μ μ€μΉνμΈμ'));
|
|
370
|
+
console.log(chalk.yellow(' β’ λ€νΈμν¬ μ°κ²°μ νμΈνκ³ λ€μ μλνμΈμ'));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
console.log(chalk.blue.bold('\n' + '='.repeat(60)));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Enhanced installation report generation
|
|
379
|
+
* @param {Object} results - Installation results
|
|
380
|
+
* @param {string} language - Language code
|
|
381
|
+
*/
|
|
382
|
+
export function generateInstallationReportEnhanced(results, language) {
|
|
383
|
+
const msg = getMessages(language);
|
|
384
|
+
|
|
385
|
+
console.log(
|
|
386
|
+
'\n' + chalk.bold(language === 'ko' ? 'π μ€μΉ 리ν¬νΈ' : 'π Installation Report')
|
|
387
|
+
);
|
|
388
|
+
console.log('β'.repeat(50));
|
|
389
|
+
|
|
390
|
+
if (results.success.length > 0) {
|
|
391
|
+
console.log(
|
|
392
|
+
chalk.green(
|
|
393
|
+
language === 'ko' ? 'β
μ±κ³΅μ μΌλ‘ μ€μΉλ λꡬ:' : 'β
Successfully Installed Tools:'
|
|
394
|
+
)
|
|
395
|
+
);
|
|
396
|
+
results.success.forEach(tool => {
|
|
397
|
+
console.log(chalk.green(` β ${getToolName(tool, language)}`));
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (results.failed.length > 0) {
|
|
402
|
+
console.log(
|
|
403
|
+
chalk.red(language === 'ko' ? '\nβ μ€μΉ μ€ν¨ν λꡬ:' : '\nβ Failed to Install:')
|
|
404
|
+
);
|
|
405
|
+
results.failed.forEach(({ tool, reason }) => {
|
|
406
|
+
console.log(chalk.red(` β ${getToolName(tool, language)}: ${reason}`));
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (results.warnings.length > 0) {
|
|
411
|
+
console.log(chalk.yellow(language === 'ko' ? '\nβ οΈ κ²½κ³ :' : '\nβ οΈ Warnings:'));
|
|
412
|
+
results.warnings.forEach(warning => {
|
|
413
|
+
console.log(chalk.yellow(` β ${warning}`));
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
console.log('β'.repeat(50));
|
|
418
|
+
}
|