aiwf 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/CLAUDE.md +220 -0
- package/LICENSE +1 -1
- package/README.ko.md +90 -62
- package/README.md +89 -62
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/01_PROJECT_DOCS/ARCHITECTURE.md +1 -1
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/02_REQUIREMENTS/M01_Backend_Setup/M01_milestone_meta.md +5 -1
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/02_REQUIREMENTS/M01_Backend_Setup/PRD_AMEND_01_Auth_Flow_Update.md +5 -1
- package/claude-code/{simone/.simone/03_SPRINTS/CLAUDE.MD → aiwf/en/.aiwf/03_SPRINTS/CLAUDE.md} +28 -7
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/03_SPRINTS/S01_M01_Initial_API/S01_sprint_meta.md +8 -1
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/03_SPRINTS/S01_M01_Initial_API/T01_S01_Setup_Project_Structure.md +5 -1
- package/claude-code/aiwf/en/.aiwf/04_GENERAL_TASKS/CLAUDE.md +96 -0
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/04_GENERAL_TASKS/T002_API_Rate_Limiting.md +7 -2
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/04_GENERAL_TASKS/TX001_Refactor_Logging_Module.md +7 -2
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/05_ARCHITECTURAL_DECISIONS/ADR001_Chosen_Database_System.md +7 -1
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/05_ARCHITECTURAL_DECISIONS/ADR002_API_Authentication_Method.md +7 -1
- package/claude-code/aiwf/en/.aiwf/10_STATE_OF_PROJECT/2025-06-12-12-00-needs-focus.md +139 -0
- package/claude-code/aiwf/en/.aiwf/10_STATE_OF_PROJECT/2025-06-12-12-00-test-alignment.md +155 -0
- package/claude-code/aiwf/en/.aiwf/10_STATE_OF_PROJECT/2025-06-13-00-50-solid-progress.md +122 -0
- package/claude-code/aiwf/en/.aiwf/10_STATE_OF_PROJECT/2025-06-14-08-30-infrastructure-challenges.md +141 -0
- package/claude-code/aiwf/en/.aiwf/10_STATE_OF_PROJECT/2025-06-16-21-48-critical-foundation-issues.md +177 -0
- package/claude-code/aiwf/en/.aiwf/10_STATE_OF_PROJECT/2025-06-17-15-08-solid-progress.md +149 -0
- package/claude-code/aiwf/en/.aiwf/10_STATE_OF_PROJECT/index.json +5 -0
- package/claude-code/aiwf/en/.aiwf/10_STATE_OF_PROJECT/sync-index.js +78 -0
- package/claude-code/aiwf/en/.aiwf/98_PROMPTS/github_integration.md +130 -0
- package/claude-code/aiwf/en/.aiwf/98_PROMPTS/useful-prompts.md +31 -0
- package/claude-code/aiwf/en/.aiwf/98_PROMPTS/vibe-front-prompts.md +89 -0
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/99_TEMPLATES/task_template.md +1 -0
- package/claude-code/{simone/.simone/CLAUDE.MD → aiwf/en/.aiwf/CLAUDE.md} +13 -4
- package/claude-code/{simone/.simone → aiwf/en/.aiwf}/README.md +6 -6
- package/claude-code/aiwf/en/.claude/CLAUDE_BE.md +276 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_changelog.md +82 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_code_review.md +88 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_commit.md +160 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_create_general_task.md +147 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_create_milestone_plan.md +194 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_create_prd.md +272 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_create_sprint_tasks.md +189 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_create_sprints_from_milestone.md +121 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_discuss_review.md +29 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_do_task.md +109 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_infinite.md +202 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_initialize.md +134 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_issue_create.md +65 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_mermaid.md +272 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_pr_create.md +76 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_prime.md +9 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_prime_context.md +5 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_project_review.md +261 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_test.md +125 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_testing_review.md +198 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_tm-run-all-subtask.md +206 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_ultrathink_code_advanced.md +460 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_ultrathink_code_basic.md +165 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_ultrathink_general.md +362 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_yolo.md +300 -0
- package/claude-code/aiwf/en/.claude/mcp.json +31 -0
- package/claude-code/aiwf/en/.claude/settings.json +102 -0
- package/claude-code/aiwf/ko/.aiwf/00_PROJECT_MANIFEST.md +49 -0
- package/claude-code/aiwf/ko/.aiwf/01_PROJECT_DOCS/ARCHITECTURE.md +55 -0
- package/claude-code/aiwf/ko/.aiwf/02_REQUIREMENTS/CLAUDE.md +78 -0
- package/claude-code/aiwf/ko/.aiwf/02_REQUIREMENTS/M01_Backend_Setup/M01_milestone_meta.md +42 -0
- package/claude-code/aiwf/ko/.aiwf/02_REQUIREMENTS/M01_Backend_Setup/PRD_AMEND_01_Auth_Flow_Update.md +73 -0
- package/claude-code/aiwf/ko/.aiwf/02_REQUIREMENTS/M01_Backend_Setup/PRD_Backend_Setup.md +98 -0
- package/claude-code/aiwf/ko/.aiwf/02_REQUIREMENTS/M01_Backend_Setup/SPECS_API_V1.md +232 -0
- package/claude-code/aiwf/ko/.aiwf/03_SPRINTS/CLAUDE.md +83 -0
- package/claude-code/aiwf/ko/.aiwf/03_SPRINTS/S01_M01_Initial_API/S01_sprint_meta.md +49 -0
- package/claude-code/aiwf/ko/.aiwf/03_SPRINTS/S01_M01_Initial_API/T01_S01_Setup_Project_Structure.md +60 -0
- package/claude-code/aiwf/ko/.aiwf/04_GENERAL_TASKS/CLAUDE.md +96 -0
- package/claude-code/aiwf/ko/.aiwf/04_GENERAL_TASKS/T002_API_Rate_Limiting.md +54 -0
- package/claude-code/aiwf/ko/.aiwf/04_GENERAL_TASKS/TX001_Refactor_Logging_Module.md +58 -0
- package/claude-code/aiwf/ko/.aiwf/05_ARCHITECTURAL_DECISIONS/ADR001_Chosen_Database_System.md +119 -0
- package/claude-code/aiwf/ko/.aiwf/05_ARCHITECTURAL_DECISIONS/ADR002_API_Authentication_Method.md +124 -0
- package/claude-code/aiwf/ko/.aiwf/10_STATE_OF_PROJECT/2025-06-12-12-00-needs-focus.md +139 -0
- package/claude-code/aiwf/ko/.aiwf/10_STATE_OF_PROJECT/2025-06-12-12-00-test-alignment.md +155 -0
- package/claude-code/aiwf/ko/.aiwf/10_STATE_OF_PROJECT/2025-06-13-00-50-solid-progress.md +122 -0
- package/claude-code/aiwf/ko/.aiwf/10_STATE_OF_PROJECT/2025-06-14-08-30-infrastructure-challenges.md +141 -0
- package/claude-code/aiwf/ko/.aiwf/10_STATE_OF_PROJECT/2025-06-16-21-48-critical-foundation-issues.md +177 -0
- package/claude-code/aiwf/ko/.aiwf/10_STATE_OF_PROJECT/2025-06-17-15-08-solid-progress.md +149 -0
- package/claude-code/aiwf/ko/.aiwf/10_STATE_OF_PROJECT/index.json +5 -0
- package/claude-code/aiwf/ko/.aiwf/10_STATE_OF_PROJECT/sync-index.js +78 -0
- package/claude-code/aiwf/ko/.aiwf/98_PROMPTS/github_integration.md +130 -0
- package/claude-code/aiwf/ko/.aiwf/98_PROMPTS/useful-prompts.md +31 -0
- package/claude-code/aiwf/ko/.aiwf/98_PROMPTS/vibe-front-prompts.md +89 -0
- package/claude-code/aiwf/ko/.aiwf/99_TEMPLATES/adr_template.md +49 -0
- package/claude-code/aiwf/ko/.aiwf/99_TEMPLATES/milestone_meta_template.md +25 -0
- package/claude-code/aiwf/ko/.aiwf/99_TEMPLATES/project_manifest_template.md +39 -0
- package/claude-code/aiwf/ko/.aiwf/99_TEMPLATES/sprint_meta_template.md +23 -0
- package/claude-code/aiwf/ko/.aiwf/99_TEMPLATES/task_template.md +36 -0
- package/claude-code/aiwf/ko/.aiwf/CLAUDE.md +76 -0
- package/claude-code/aiwf/ko/.aiwf/README.md +97 -0
- package/claude-code/aiwf/ko/.claude/CLAUDE_BE.md +276 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_changelog.md +82 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_code_review.md +88 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_commit.md +160 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_general_task.md +147 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_milestone_plan.md +194 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_prd.md +280 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_sprint_tasks.md +189 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_sprints_from_milestone.md +121 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_discuss_review.md +29 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_do_task.md +109 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_infinite.md +202 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_initialize.md +134 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_issue_create.md +65 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_mermaid.md +272 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_pr_create.md +76 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_prime.md +9 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_prime_context.md +8 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_project_review.md +261 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_test.md +125 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_testing_review.md +198 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_tm-run-all-subtask.md +210 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_ultrathink_code_advanced.md +460 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_ultrathink_code_basic.md +165 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_ultrathink_general.md +362 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_yolo.md +300 -0
- package/claude-code/aiwf/ko/.claude/mcp.json +31 -0
- package/claude-code/aiwf/ko/.claude/settings.json +102 -0
- package/{AI-WORKFLOW.md → docs/AI-WORKFLOW.ko.md} +31 -24
- package/docs/AI-WORKFLOW.md +292 -0
- package/docs/COMMANDS_GUIDE.ko.md +637 -0
- package/docs/COMMANDS_GUIDE.md +636 -0
- package/docs/CONTRIBUTING.md +406 -0
- package/docs/DEVELOPMENT_GUIDE.md +727 -0
- package/{PRD.ko.md → docs/PRD.ko.md} +9 -9
- package/{PRD.md → docs/PRD.md} +9 -9
- package/docs/moonklabs-metadata-system-prd.md +127 -0
- package/index.js +272 -121
- package/package.json +12 -7
- package/COMMANDS_GUIDE.md +0 -462
- package/claude-code/simone/.simone/04_GENERAL_TASKS/CLAUDE.MD +0 -51
- package/claude-code/simone/CHANGELOG.md +0 -71
- package/claude-code/simone/LICENSE +0 -21
- package/claude-code/simone/README.md +0 -219
- package/claude-code/simone/SYNC_GUIDE.md +0 -172
- package/claude-code/simone/sync-simone.sh +0 -138
- /package/claude-code/{simone/.simone → aiwf/en/.aiwf}/00_PROJECT_MANIFEST.md +0 -0
- /package/claude-code/{simone/.simone → aiwf/en/.aiwf}/02_REQUIREMENTS/CLAUDE.md +0 -0
- /package/claude-code/{simone/.simone → aiwf/en/.aiwf}/02_REQUIREMENTS/M01_Backend_Setup/PRD_Backend_Setup.md +0 -0
- /package/claude-code/{simone/.simone → aiwf/en/.aiwf}/02_REQUIREMENTS/M01_Backend_Setup/SPECS_API_V1.md +0 -0
- /package/claude-code/{simone/.simone → aiwf/en/.aiwf}/99_TEMPLATES/adr_template.md +0 -0
- /package/claude-code/{simone/.simone → aiwf/en/.aiwf}/99_TEMPLATES/milestone_meta_template.md +0 -0
- /package/claude-code/{simone/.simone → aiwf/en/.aiwf}/99_TEMPLATES/project_manifest_template.md +0 -0
- /package/claude-code/{simone/.simone → aiwf/en/.aiwf}/99_TEMPLATES/sprint_meta_template.md +0 -0
package/index.js
CHANGED
|
@@ -17,11 +17,11 @@ const program = new Command();
|
|
|
17
17
|
|
|
18
18
|
const GITHUB_API_URL = 'https://api.github.com/repos/moonklabs/aiwf';
|
|
19
19
|
const GITHUB_RAW_URL = 'https://raw.githubusercontent.com/moonklabs/aiwf/master';
|
|
20
|
-
const GITHUB_CONTENT_PREFIX = 'claude-code/
|
|
20
|
+
const GITHUB_CONTENT_PREFIX = 'claude-code/aiwf';
|
|
21
21
|
|
|
22
22
|
async function fetchGitHubContent(url) {
|
|
23
23
|
return new Promise((resolve, reject) => {
|
|
24
|
-
https.get(url, { headers: { 'User-Agent': '
|
|
24
|
+
https.get(url, { headers: { 'User-Agent': 'aiwf' } }, (res) => {
|
|
25
25
|
let data = '';
|
|
26
26
|
res.on('data', chunk => data += chunk);
|
|
27
27
|
res.on('end', () => {
|
|
@@ -40,7 +40,7 @@ async function fetchGitHubContent(url) {
|
|
|
40
40
|
|
|
41
41
|
async function downloadFile(url, destPath) {
|
|
42
42
|
return new Promise((resolve, reject) => {
|
|
43
|
-
https.get(url, { headers: { 'User-Agent': '
|
|
43
|
+
https.get(url, { headers: { 'User-Agent': 'aiwf' } }, (response) => {
|
|
44
44
|
if (response.statusCode !== 200) {
|
|
45
45
|
response.destroy();
|
|
46
46
|
reject(new Error(`Failed to download ${url}: ${response.statusCode}`));
|
|
@@ -69,10 +69,12 @@ async function getDirectoryStructure(path = '') {
|
|
|
69
69
|
return JSON.parse(content);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
const COMMANDS_DIR = '.claude/commands/aiwf';
|
|
73
|
+
|
|
72
74
|
async function checkExistingInstallation() {
|
|
73
|
-
const
|
|
74
|
-
const claudeCommandsExists = await fs.access(
|
|
75
|
-
return
|
|
75
|
+
const aiwfExists = await fs.access('.aiwf').then(() => true).catch(() => false);
|
|
76
|
+
const claudeCommandsExists = await fs.access(COMMANDS_DIR).then(() => true).catch(() => false);
|
|
77
|
+
return aiwfExists || claudeCommandsExists;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
// 백업 폴더명 생성 함수
|
|
@@ -85,7 +87,7 @@ function getBackupDirName() {
|
|
|
85
87
|
const h = pad(now.getHours());
|
|
86
88
|
const min = pad(now.getMinutes());
|
|
87
89
|
const s = pad(now.getSeconds());
|
|
88
|
-
return `.
|
|
90
|
+
return `.aiwf/backup_${y}${m}${d}_${h}${min}${s}`;
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
let BACKUP_DIR = null;
|
|
@@ -97,11 +99,11 @@ async function backupFile(filePath, backupDir) {
|
|
|
97
99
|
await fs.mkdir(backupDir, { recursive: true });
|
|
98
100
|
const backupPath = `${filePath}.bak`;
|
|
99
101
|
await fs.copyFile(filePath, backupPath);
|
|
100
|
-
// 상대경로 보존: .claude/commands/
|
|
102
|
+
// 상대경로 보존: .claude/commands/aiwf/foo.md -> backupDir/claude-commands-aiwf-foo.md.bak
|
|
101
103
|
let bakFileName;
|
|
102
|
-
if (filePath.startsWith('
|
|
104
|
+
if (filePath.startsWith(COMMANDS_DIR + '/')) {
|
|
103
105
|
bakFileName = filePath.replace(/\//g, '-').replace(/^\./, '') + '.bak';
|
|
104
|
-
} else if (filePath.startsWith('.
|
|
106
|
+
} else if (filePath.startsWith('.aiwf/')) {
|
|
105
107
|
bakFileName = filePath.replace(/\//g, '-').replace(/^\./, '') + '.bak';
|
|
106
108
|
} else {
|
|
107
109
|
bakFileName = path.basename(filePath) + '.bak';
|
|
@@ -116,18 +118,18 @@ async function backupFile(filePath, backupDir) {
|
|
|
116
118
|
return null;
|
|
117
119
|
}
|
|
118
120
|
|
|
119
|
-
async function backupCommandsAndDocs() {
|
|
121
|
+
async function backupCommandsAndDocs(msg) {
|
|
120
122
|
if (!BACKUP_DIR) BACKUP_DIR = getBackupDirName();
|
|
121
|
-
const spinner = ora(
|
|
123
|
+
const spinner = ora(msg.backingUp).start();
|
|
122
124
|
const backedUpFiles = [];
|
|
123
125
|
await fs.mkdir(BACKUP_DIR, { recursive: true });
|
|
124
126
|
try {
|
|
125
127
|
// Files that will be updated and need backup
|
|
126
128
|
const filesToBackup = [
|
|
127
|
-
'.
|
|
128
|
-
'.
|
|
129
|
-
'.
|
|
130
|
-
'.
|
|
129
|
+
'.aiwf/CLAUDE.md',
|
|
130
|
+
'.aiwf/02_REQUIREMENTS/CLAUDE.md',
|
|
131
|
+
'.aiwf/03_SPRINTS/CLAUDE.md',
|
|
132
|
+
'.aiwf/04_GENERAL_TASKS/CLAUDE.md'
|
|
131
133
|
];
|
|
132
134
|
// Backup CLAUDE.md files
|
|
133
135
|
for (const file of filesToBackup) {
|
|
@@ -137,13 +139,12 @@ async function backupCommandsAndDocs() {
|
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
// Backup all command files
|
|
140
|
-
const
|
|
141
|
-
const commandsExist = await fs.access(commandsDir).then(() => true).catch(() => false);
|
|
142
|
+
const commandsExist = await fs.access(COMMANDS_DIR).then(() => true).catch(() => false);
|
|
142
143
|
if (commandsExist) {
|
|
143
144
|
try {
|
|
144
|
-
const commandFiles = await fs.readdir(
|
|
145
|
+
const commandFiles = await fs.readdir(COMMANDS_DIR);
|
|
145
146
|
for (const file of commandFiles) {
|
|
146
|
-
const filePath = path.join(
|
|
147
|
+
const filePath = path.join(COMMANDS_DIR, file);
|
|
147
148
|
const stat = await fs.stat(filePath);
|
|
148
149
|
if (stat.isFile() && file.endsWith('.md')) {
|
|
149
150
|
const backupPath = await backupFile(filePath, BACKUP_DIR);
|
|
@@ -157,18 +158,18 @@ async function backupCommandsAndDocs() {
|
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
if (backedUpFiles.length > 0) {
|
|
160
|
-
spinner.succeed(chalk.green(
|
|
161
|
+
spinner.succeed(chalk.green(msg.backupComplete.replace('{count}', backedUpFiles.length)));
|
|
161
162
|
} else {
|
|
162
|
-
spinner.succeed(chalk.gray(
|
|
163
|
+
spinner.succeed(chalk.gray(msg.noFilesToBackup));
|
|
163
164
|
}
|
|
164
165
|
return backedUpFiles;
|
|
165
166
|
} catch (error) {
|
|
166
|
-
spinner.fail(chalk.red(
|
|
167
|
+
spinner.fail(chalk.red(msg.backupFailed));
|
|
167
168
|
throw error;
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
async function downloadDirectory(githubPath, localPath, spinner) {
|
|
172
|
+
async function downloadDirectory(githubPath, localPath, spinner, msg) {
|
|
172
173
|
await fs.mkdir(localPath, { recursive: true });
|
|
173
174
|
|
|
174
175
|
const items = await getDirectoryStructure(githubPath);
|
|
@@ -177,9 +178,9 @@ async function downloadDirectory(githubPath, localPath, spinner) {
|
|
|
177
178
|
const itemLocalPath = path.join(localPath, item.name);
|
|
178
179
|
|
|
179
180
|
if (item.type === 'dir') {
|
|
180
|
-
await downloadDirectory(item.path, itemLocalPath, spinner);
|
|
181
|
+
await downloadDirectory(item.path, itemLocalPath, spinner, msg);
|
|
181
182
|
} else if (item.type === 'file') {
|
|
182
|
-
spinner.text =
|
|
183
|
+
spinner.text = msg.downloadingFile.replace('{path}', item.path);
|
|
183
184
|
await downloadFile(item.download_url, itemLocalPath);
|
|
184
185
|
}
|
|
185
186
|
}
|
|
@@ -191,11 +192,154 @@ function logWithSpinner(spinner, message, debugLog) {
|
|
|
191
192
|
if (spinner) spinner.text = message;
|
|
192
193
|
}
|
|
193
194
|
|
|
194
|
-
|
|
195
|
+
// 언어별 메시지 정의
|
|
196
|
+
const messages = {
|
|
197
|
+
ko: {
|
|
198
|
+
welcome: '\n🎉 AIWF에 오신 것을 환영합니다!\n',
|
|
199
|
+
description: '이 설치 프로그램은 AIWF AI 프롬프트 프레임워크를 설정합니다',
|
|
200
|
+
optimized: '특별히 Claude Code 에 최적화 되어있습니다.\n',
|
|
201
|
+
selectLanguage: 'Please select language / 언어를 선택해주세요:',
|
|
202
|
+
korean: '한국어 (Korean)',
|
|
203
|
+
english: 'English',
|
|
204
|
+
existingDetected: '기존 AIWF 설치가 감지되었습니다. 무엇을 하시겠습니까?',
|
|
205
|
+
updateOption: '업데이트 (명령어와 문서만 업데이트하고 작업 내용은 보존)',
|
|
206
|
+
skipOption: '설치 건너뛰기',
|
|
207
|
+
cancelOption: '취소',
|
|
208
|
+
installCancelled: '\n설치가 취소되었습니다.',
|
|
209
|
+
backingUp: '기존 명령어 및 문서 백업 중...',
|
|
210
|
+
fetching: 'GitHub에서 AIWF 프레임워크를 가져오는 중...',
|
|
211
|
+
downloading: 'AIWF 프레임워크 파일을 다운로드하는 중...',
|
|
212
|
+
updatingDocs: '문서를 업데이트하는 중...',
|
|
213
|
+
downloadingCommands: 'AIWF 명령어를 새로 다운로드하는 중...',
|
|
214
|
+
updateSuccess: '✅ AIWF 프레임워크가 성공적으로 업데이트되었습니다!',
|
|
215
|
+
installSuccess: '✅ AIWF 프레임워크가 성공적으로 설치되었습니다!',
|
|
216
|
+
enjoy: '\nEnjoy AIWF! 🚀\n',
|
|
217
|
+
backupComplete: '{count}개 파일 백업 완료 (*.bak)',
|
|
218
|
+
noFilesToBackup: '백업할 기존 파일이 없습니다',
|
|
219
|
+
backupFailed: '백업 실패',
|
|
220
|
+
downloadingFile: '{path} 다운로드 중...',
|
|
221
|
+
downloadingTemplates: '템플릿 디렉토리를 다운로드 중...',
|
|
222
|
+
templatesNotFound: '템플릿 디렉토리를 찾을 수 없어 건너뜁니다...',
|
|
223
|
+
deletingOldCommands: '기존 AIWF 명령어 폴더를 삭제하는 중...',
|
|
224
|
+
commandsNotFound: '명령어 디렉토리를 찾을 수 없어 건너뜁니다...',
|
|
225
|
+
downloadingRulesGlobal: 'rules/global 폴더를 다운로드 중...',
|
|
226
|
+
rulesGlobalNotFound: 'rules/global 폴더를 찾을 수 없어 건너뜁니다...',
|
|
227
|
+
downloadingRulesManual: 'rules/manual 폴더를 다운로드 중...',
|
|
228
|
+
rulesManualNotFound: 'rules/manual 폴더를 찾을 수 없어 건너뜁니다...',
|
|
229
|
+
updateHistory: '🔄 업데이트 내역:',
|
|
230
|
+
updatedCommands: '내의 명령어',
|
|
231
|
+
updatedDocs: '문서 (CLAUDE.md 파일)',
|
|
232
|
+
workPreserved: '💾 작업 내용은 보존되었습니다:',
|
|
233
|
+
allFilesPreserved: '모든 작업, 스프린트, 및 프로젝트 파일이 변경되지 않음',
|
|
234
|
+
backupCreated: '백업은 *.bak 파일로 만들어짐',
|
|
235
|
+
structureCreated: '📁 생성된 구조:',
|
|
236
|
+
aiwfRoot: '프로젝트 관리 루트',
|
|
237
|
+
claudeCommands: 'Claude 사용자 명령어',
|
|
238
|
+
nextSteps: '🚀 다음 단계:',
|
|
239
|
+
nextStep1: 'Claude Code에서 이 프로젝트를 엽니다',
|
|
240
|
+
nextStep2: '/aiwf_<command> 명령어를 사용하여 프로젝트를 관리하세요',
|
|
241
|
+
nextStep3: '/aiwf_initialize를 실행하여 프로젝트를 설정하세요',
|
|
242
|
+
gettingStarted: '✨ 시작하려면:',
|
|
243
|
+
startStep1: '새 터미널을 열거나 쉘 프로필을 소싱하세요 (예: source ~/.zshrc)',
|
|
244
|
+
startStep2: '다음을 실행하세요: claude 를 실행하여 사용 가능한 명령어를 확인하세요.',
|
|
245
|
+
checkDocs: '자세한 내용은 .aiwf 디렉토리의 문서를 확인하세요.',
|
|
246
|
+
updateFailed: '업데이트 실패',
|
|
247
|
+
installFailed: '설치 실패',
|
|
248
|
+
noBackupFound: '복원할 백업 폴더가 없습니다.',
|
|
249
|
+
restoringFromBackup: '백업에서 복원 중...',
|
|
250
|
+
restoreSuccess: '성공적으로 복원되었습니다.',
|
|
251
|
+
restoreFailed: '복원에 실패했습니다.',
|
|
252
|
+
cannotRestore: '파일을 복원할 수 없습니다. 수동 확인이 필요합니다.'
|
|
253
|
+
},
|
|
254
|
+
en: {
|
|
255
|
+
welcome: '\n🎉 Welcome to AIWF!\n',
|
|
256
|
+
description: 'This installer sets up the AIWF AI prompt framework',
|
|
257
|
+
optimized: 'Specially optimized for Claude Code.\n',
|
|
258
|
+
selectLanguage: 'Please select language / 언어를 선택해주세요:',
|
|
259
|
+
korean: '한국어 (Korean)',
|
|
260
|
+
english: 'English',
|
|
261
|
+
existingDetected: 'Existing AIWF installation detected. What would you like to do?',
|
|
262
|
+
updateOption: 'Update (Update commands and docs only, preserve work content)',
|
|
263
|
+
skipOption: 'Skip installation',
|
|
264
|
+
cancelOption: 'Cancel',
|
|
265
|
+
installCancelled: '\nInstallation cancelled.',
|
|
266
|
+
backingUp: 'Backing up existing commands and documents...',
|
|
267
|
+
fetching: 'Fetching AIWF framework from GitHub...',
|
|
268
|
+
downloading: 'Downloading AIWF framework files...',
|
|
269
|
+
updatingDocs: 'Updating documentation...',
|
|
270
|
+
downloadingCommands: 'Downloading AIWF commands...',
|
|
271
|
+
updateSuccess: '✅ AIWF framework updated successfully!',
|
|
272
|
+
installSuccess: '✅ AIWF framework installed successfully!',
|
|
273
|
+
enjoy: '\nEnjoy AIWF! 🚀\n',
|
|
274
|
+
backupComplete: '{count} files backed up (*.bak)',
|
|
275
|
+
noFilesToBackup: 'No existing files to backup',
|
|
276
|
+
backupFailed: 'Backup failed',
|
|
277
|
+
downloadingFile: 'Downloading {path}...',
|
|
278
|
+
downloadingTemplates: 'Downloading template directories...',
|
|
279
|
+
templatesNotFound: 'Template directories not found, skipping...',
|
|
280
|
+
deletingOldCommands: 'Deleting existing AIWF commands folder...',
|
|
281
|
+
commandsNotFound: 'Commands directory not found, skipping...',
|
|
282
|
+
downloadingRulesGlobal: 'Downloading rules/global folder...',
|
|
283
|
+
rulesGlobalNotFound: 'rules/global folder not found, skipping...',
|
|
284
|
+
downloadingRulesManual: 'Downloading rules/manual folder...',
|
|
285
|
+
rulesManualNotFound: 'rules/manual folder not found, skipping...',
|
|
286
|
+
updateHistory: '🔄 Update History:',
|
|
287
|
+
updatedCommands: '/ commands',
|
|
288
|
+
updatedDocs: 'Documentation (CLAUDE.md files)',
|
|
289
|
+
workPreserved: '💾 Work preserved:',
|
|
290
|
+
allFilesPreserved: 'All work, sprints, and project files unchanged',
|
|
291
|
+
backupCreated: 'Backups created as *.bak files',
|
|
292
|
+
structureCreated: '📁 Structure created:',
|
|
293
|
+
aiwfRoot: 'Project management root',
|
|
294
|
+
claudeCommands: 'Claude user commands',
|
|
295
|
+
nextSteps: '🚀 Next steps:',
|
|
296
|
+
nextStep1: 'Open this project in Claude Code',
|
|
297
|
+
nextStep2: 'Use /aiwf_<command> commands to manage your project',
|
|
298
|
+
nextStep3: 'Run /aiwf_initialize to set up your project',
|
|
299
|
+
gettingStarted: '✨ Getting started:',
|
|
300
|
+
startStep1: 'Open a new terminal or source your shell profile (e.g. source ~/.zshrc)',
|
|
301
|
+
startStep2: 'Run: claude to see available commands.',
|
|
302
|
+
checkDocs: 'For more details, check the documentation in the .aiwf directory.',
|
|
303
|
+
updateFailed: 'Update failed',
|
|
304
|
+
installFailed: 'Installation failed',
|
|
305
|
+
noBackupFound: 'No backup folder found to restore.',
|
|
306
|
+
restoringFromBackup: 'Restoring from backup...',
|
|
307
|
+
restoreSuccess: 'Successfully restored.',
|
|
308
|
+
restoreFailed: 'Restore failed.',
|
|
309
|
+
cannotRestore: 'Cannot restore file. Manual verification required.'
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
async function installAIWF(options = {}) {
|
|
195
314
|
const debugLog = options.debugLog || false;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
315
|
+
|
|
316
|
+
// 언어 선택
|
|
317
|
+
let selectedLanguage = 'en'; // 기본값은 영어
|
|
318
|
+
if (!options.force) {
|
|
319
|
+
const languageResponse = await prompts({
|
|
320
|
+
type: 'select',
|
|
321
|
+
name: 'language',
|
|
322
|
+
message: 'Please select language / 언어를 선택해주세요:',
|
|
323
|
+
choices: [
|
|
324
|
+
{ title: 'English', value: 'en' },
|
|
325
|
+
{ title: '한국어 (Korean)', value: 'ko' }
|
|
326
|
+
]
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
if (languageResponse.language) {
|
|
330
|
+
selectedLanguage = languageResponse.language;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const msg = messages[selectedLanguage];
|
|
335
|
+
|
|
336
|
+
console.log(chalk.blue.bold(msg.welcome));
|
|
337
|
+
console.log(chalk.gray(msg.description));
|
|
338
|
+
console.log(chalk.gray(msg.optimized));
|
|
339
|
+
|
|
340
|
+
// 언어별 경로 설정
|
|
341
|
+
const languagePath = selectedLanguage === 'en' ? 'en' : 'ko';
|
|
342
|
+
const GITHUB_CONTENT_LANGUAGE_PREFIX = `${GITHUB_CONTENT_PREFIX}/${languagePath}`;
|
|
199
343
|
|
|
200
344
|
const hasExisting = await checkExistingInstallation();
|
|
201
345
|
|
|
@@ -203,51 +347,51 @@ async function installMoonklabs(options = {}) {
|
|
|
203
347
|
const response = await prompts({
|
|
204
348
|
type: 'select',
|
|
205
349
|
name: 'action',
|
|
206
|
-
message:
|
|
350
|
+
message: msg.existingDetected,
|
|
207
351
|
choices: [
|
|
208
|
-
{ title:
|
|
209
|
-
{ title:
|
|
210
|
-
{ title:
|
|
352
|
+
{ title: msg.updateOption, value: 'update' },
|
|
353
|
+
{ title: msg.skipOption, value: 'skip' },
|
|
354
|
+
{ title: msg.cancelOption, value: 'cancel' }
|
|
211
355
|
]
|
|
212
356
|
});
|
|
213
357
|
|
|
214
358
|
if (response.action === 'skip' || response.action === 'cancel') {
|
|
215
|
-
console.log(chalk.yellow(
|
|
359
|
+
console.log(chalk.yellow(msg.installCancelled));
|
|
216
360
|
process.exit(0);
|
|
217
361
|
}
|
|
218
362
|
|
|
219
363
|
if (response.action === 'update') {
|
|
220
|
-
await backupCommandsAndDocs();
|
|
364
|
+
await backupCommandsAndDocs(msg);
|
|
221
365
|
}
|
|
222
366
|
}
|
|
223
367
|
|
|
224
|
-
const spinner = ora(
|
|
368
|
+
const spinner = ora(msg.fetching).start();
|
|
225
369
|
|
|
226
370
|
try {
|
|
227
|
-
// Create .
|
|
228
|
-
const
|
|
229
|
-
'.
|
|
230
|
-
'.
|
|
231
|
-
'.
|
|
232
|
-
'.
|
|
233
|
-
'.
|
|
234
|
-
'.
|
|
235
|
-
'.
|
|
236
|
-
'.
|
|
237
|
-
'.
|
|
371
|
+
// Create .aiwf directory structure
|
|
372
|
+
const aiwfDirs = [
|
|
373
|
+
'.aiwf',
|
|
374
|
+
'.aiwf/01_PROJECT_DOCS',
|
|
375
|
+
'.aiwf/02_REQUIREMENTS',
|
|
376
|
+
'.aiwf/03_SPRINTS',
|
|
377
|
+
'.aiwf/04_GENERAL_TASKS',
|
|
378
|
+
'.aiwf/05_ARCHITECTURE_DECISIONS',
|
|
379
|
+
'.aiwf/10_STATE_OF_PROJECT',
|
|
380
|
+
'.aiwf/98_PROMPTS',
|
|
381
|
+
'.aiwf/99_TEMPLATES'
|
|
238
382
|
];
|
|
239
383
|
|
|
240
|
-
for (const dir of
|
|
384
|
+
for (const dir of aiwfDirs) {
|
|
241
385
|
await fs.mkdir(dir, { recursive: true });
|
|
242
386
|
}
|
|
243
387
|
|
|
244
388
|
// Only download manifest on fresh installs
|
|
245
389
|
if (!hasExisting) {
|
|
246
|
-
logWithSpinner(spinner,
|
|
390
|
+
logWithSpinner(spinner, msg.downloading, debugLog);
|
|
247
391
|
// Get the root manifest
|
|
248
392
|
try {
|
|
249
|
-
const manifestUrl = `${GITHUB_RAW_URL}/${
|
|
250
|
-
await downloadFile(manifestUrl, '.
|
|
393
|
+
const manifestUrl = `${GITHUB_RAW_URL}/${GITHUB_CONTENT_LANGUAGE_PREFIX}/.aiwf/00_PROJECT_MANIFEST.md`;
|
|
394
|
+
await downloadFile(manifestUrl, '.aiwf/00_PROJECT_MANIFEST.md');
|
|
251
395
|
} catch (error) {
|
|
252
396
|
// If manifest doesn't exist, that's okay
|
|
253
397
|
}
|
|
@@ -255,59 +399,66 @@ async function installMoonklabs(options = {}) {
|
|
|
255
399
|
|
|
256
400
|
// Download templates on fresh install
|
|
257
401
|
try {
|
|
258
|
-
logWithSpinner(spinner,
|
|
259
|
-
await downloadDirectory(`${
|
|
260
|
-
await downloadDirectory(`${
|
|
402
|
+
logWithSpinner(spinner, msg.downloadingTemplates, debugLog);
|
|
403
|
+
await downloadDirectory(`${GITHUB_CONTENT_LANGUAGE_PREFIX}/.aiwf/98_PROMPTS`, '.aiwf/98_PROMPTS', spinner, msg);
|
|
404
|
+
await downloadDirectory(`${GITHUB_CONTENT_LANGUAGE_PREFIX}/.aiwf/99_TEMPLATES`, '.aiwf/99_TEMPLATES', spinner, msg);
|
|
261
405
|
} catch (error) {
|
|
262
|
-
logWithSpinner(spinner,
|
|
406
|
+
logWithSpinner(spinner, msg.templatesNotFound, debugLog);
|
|
263
407
|
}
|
|
264
408
|
|
|
265
409
|
// Always update CLAUDE.md documentation files
|
|
266
|
-
logWithSpinner(spinner,
|
|
410
|
+
logWithSpinner(spinner, msg.updatingDocs, debugLog);
|
|
267
411
|
const claudeFiles = [
|
|
268
|
-
'.
|
|
269
|
-
'.
|
|
270
|
-
'.
|
|
271
|
-
'.
|
|
412
|
+
'.aiwf/CLAUDE.md',
|
|
413
|
+
'.aiwf/02_REQUIREMENTS/CLAUDE.md',
|
|
414
|
+
'.aiwf/03_SPRINTS/CLAUDE.md',
|
|
415
|
+
'.aiwf/04_GENERAL_TASKS/CLAUDE.md'
|
|
272
416
|
];
|
|
273
417
|
|
|
274
418
|
for (const claudeFile of claudeFiles) {
|
|
275
419
|
try {
|
|
276
|
-
const claudeUrl = `${GITHUB_RAW_URL}/${
|
|
420
|
+
const claudeUrl = `${GITHUB_RAW_URL}/${GITHUB_CONTENT_LANGUAGE_PREFIX}/${claudeFile}`;
|
|
277
421
|
await downloadFile(claudeUrl, claudeFile);
|
|
278
422
|
} catch (error) {
|
|
279
423
|
// If CLAUDE.md doesn't exist, that's okay
|
|
280
424
|
}
|
|
281
425
|
}
|
|
282
426
|
|
|
283
|
-
//
|
|
284
|
-
await fs.
|
|
427
|
+
// Delete and recreate commands directory
|
|
428
|
+
const commandsExist = await fs.access(COMMANDS_DIR).then(() => true).catch(() => false);
|
|
429
|
+
|
|
430
|
+
if (commandsExist) {
|
|
431
|
+
logWithSpinner(spinner, msg.deletingOldCommands, debugLog);
|
|
432
|
+
await fs.rm(COMMANDS_DIR, { recursive: true, force: true });
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
await fs.mkdir(COMMANDS_DIR, { recursive: true });
|
|
285
436
|
|
|
286
|
-
// Always update commands
|
|
287
|
-
logWithSpinner(spinner,
|
|
437
|
+
// Always update commands (clean download)
|
|
438
|
+
logWithSpinner(spinner, msg.downloadingCommands, debugLog);
|
|
288
439
|
try {
|
|
289
|
-
await downloadDirectory(`${
|
|
440
|
+
await downloadDirectory(`${GITHUB_CONTENT_LANGUAGE_PREFIX}/${COMMANDS_DIR}`, COMMANDS_DIR, spinner, msg);
|
|
290
441
|
} catch (error) {
|
|
291
|
-
logWithSpinner(spinner,
|
|
442
|
+
logWithSpinner(spinner, msg.commandsNotFound, debugLog);
|
|
292
443
|
}
|
|
293
444
|
|
|
294
445
|
// 2. rules/global 폴더 다운로드 (임시 폴더)
|
|
295
|
-
let tmpRulesGlobal = '.
|
|
446
|
+
let tmpRulesGlobal = '.aiwf/_tmp_rules_global';
|
|
296
447
|
try {
|
|
297
|
-
logWithSpinner(spinner,
|
|
298
|
-
await downloadDirectory(`rules/global`, tmpRulesGlobal, spinner);
|
|
448
|
+
logWithSpinner(spinner, msg.downloadingRulesGlobal, debugLog);
|
|
449
|
+
await downloadDirectory(`rules/global`, tmpRulesGlobal, spinner, msg);
|
|
299
450
|
} catch (error) {
|
|
300
|
-
logWithSpinner(spinner,
|
|
451
|
+
logWithSpinner(spinner, msg.rulesGlobalNotFound, debugLog);
|
|
301
452
|
tmpRulesGlobal = null;
|
|
302
453
|
}
|
|
303
454
|
|
|
304
455
|
// 2-1. rules/manual 폴더 다운로드 (임시 폴더)
|
|
305
|
-
let tmpRulesManual = '.
|
|
456
|
+
let tmpRulesManual = '.aiwf/_tmp_rules_manual';
|
|
306
457
|
try {
|
|
307
|
-
logWithSpinner(spinner,
|
|
308
|
-
await downloadDirectory(`rules/manual`, tmpRulesManual, spinner);
|
|
458
|
+
logWithSpinner(spinner, msg.downloadingRulesManual, debugLog);
|
|
459
|
+
await downloadDirectory(`rules/manual`, tmpRulesManual, spinner, msg);
|
|
309
460
|
} catch (error) {
|
|
310
|
-
logWithSpinner(spinner,
|
|
461
|
+
logWithSpinner(spinner, msg.rulesManualNotFound, debugLog);
|
|
311
462
|
tmpRulesManual = null;
|
|
312
463
|
}
|
|
313
464
|
|
|
@@ -372,57 +523,57 @@ async function installMoonklabs(options = {}) {
|
|
|
372
523
|
}
|
|
373
524
|
|
|
374
525
|
if (hasExisting) {
|
|
375
|
-
spinner.succeed(chalk.green(
|
|
376
|
-
console.log(chalk.blue(
|
|
377
|
-
console.log(chalk.gray(
|
|
378
|
-
console.log(chalk.gray(
|
|
379
|
-
console.log(chalk.green(
|
|
380
|
-
console.log(chalk.gray(
|
|
381
|
-
console.log(chalk.gray(
|
|
526
|
+
spinner.succeed(chalk.green(msg.updateSuccess));
|
|
527
|
+
console.log(chalk.blue(`\n${msg.updateHistory}`));
|
|
528
|
+
console.log(chalk.gray(` • ${COMMANDS_DIR}${msg.updatedCommands}`));
|
|
529
|
+
console.log(chalk.gray(` • ${msg.updatedDocs}`));
|
|
530
|
+
console.log(chalk.green(`\n${msg.workPreserved}`));
|
|
531
|
+
console.log(chalk.gray(` • ${msg.allFilesPreserved}`));
|
|
532
|
+
console.log(chalk.gray(` • ${msg.backupCreated}`));
|
|
382
533
|
} else {
|
|
383
|
-
spinner.succeed(chalk.green(
|
|
384
|
-
console.log(chalk.blue(
|
|
385
|
-
console.log(chalk.gray(
|
|
386
|
-
console.log(chalk.gray(
|
|
387
|
-
|
|
388
|
-
console.log(chalk.green(
|
|
389
|
-
console.log(chalk.white(
|
|
390
|
-
console.log(chalk.white(
|
|
391
|
-
console.log(chalk.white(
|
|
392
|
-
|
|
393
|
-
console.log(chalk.blue(
|
|
394
|
-
console.log(chalk.gray(
|
|
395
|
-
console.log(chalk.gray(` 2.
|
|
396
|
-
console.log(chalk.gray(
|
|
534
|
+
spinner.succeed(chalk.green(msg.installSuccess));
|
|
535
|
+
console.log(chalk.blue(`\n${msg.structureCreated}`));
|
|
536
|
+
console.log(chalk.gray(` .aiwf/ - ${msg.aiwfRoot}`));
|
|
537
|
+
console.log(chalk.gray(` .claude/commands/ - ${msg.claudeCommands}`));
|
|
538
|
+
|
|
539
|
+
console.log(chalk.green(`\n${msg.nextSteps}`));
|
|
540
|
+
console.log(chalk.white(` 1. ${msg.nextStep1}`));
|
|
541
|
+
console.log(chalk.white(` 2. ${msg.nextStep2}`));
|
|
542
|
+
console.log(chalk.white(` 3. ${msg.nextStep3}\n`));
|
|
543
|
+
|
|
544
|
+
console.log(chalk.blue(`\n${msg.gettingStarted}`));
|
|
545
|
+
console.log(chalk.gray(` 1. ${msg.startStep1}`));
|
|
546
|
+
console.log(chalk.gray(` 2. ${msg.startStep2}`));
|
|
547
|
+
console.log(chalk.gray(`\n${msg.checkDocs}`));
|
|
397
548
|
}
|
|
398
549
|
|
|
399
|
-
console.log(chalk.green(
|
|
550
|
+
console.log(chalk.green(msg.enjoy));
|
|
400
551
|
|
|
401
552
|
} catch (error) {
|
|
402
553
|
if (hasExisting) {
|
|
403
|
-
spinner.fail(chalk.red(
|
|
404
|
-
await restoreFromBackup(spinner);
|
|
554
|
+
spinner.fail(chalk.red(msg.updateFailed));
|
|
555
|
+
await restoreFromBackup(spinner, msg);
|
|
405
556
|
} else {
|
|
406
|
-
spinner.fail(chalk.red(
|
|
557
|
+
spinner.fail(chalk.red(msg.installFailed));
|
|
407
558
|
}
|
|
408
559
|
console.error(chalk.red(error.message));
|
|
409
560
|
process.exit(1);
|
|
410
561
|
}
|
|
411
562
|
}
|
|
412
563
|
|
|
413
|
-
async function restoreFromBackup(spinner) {
|
|
564
|
+
async function restoreFromBackup(spinner, msg) {
|
|
414
565
|
if (!BACKUP_DIR) {
|
|
415
566
|
// 가장 최근 backup 폴더 사용
|
|
416
|
-
const
|
|
417
|
-
const dirs = (await fs.readdir(
|
|
567
|
+
const aiwfDir = '.aiwf';
|
|
568
|
+
const dirs = (await fs.readdir(aiwfDir)).filter(f => f.startsWith('backup_'));
|
|
418
569
|
if (dirs.length === 0) {
|
|
419
|
-
spinner.fail(chalk.red(
|
|
570
|
+
spinner.fail(chalk.red(msg.noBackupFound));
|
|
420
571
|
return;
|
|
421
572
|
}
|
|
422
573
|
dirs.sort();
|
|
423
|
-
BACKUP_DIR = path.join(
|
|
574
|
+
BACKUP_DIR = path.join(aiwfDir, dirs[dirs.length - 1]);
|
|
424
575
|
}
|
|
425
|
-
spinner.start(chalk.yellow(
|
|
576
|
+
spinner.start(chalk.yellow(msg.restoringFromBackup));
|
|
426
577
|
try {
|
|
427
578
|
let backupFiles = [];
|
|
428
579
|
try {
|
|
@@ -431,16 +582,16 @@ async function restoreFromBackup(spinner) {
|
|
|
431
582
|
backupFiles = [];
|
|
432
583
|
}
|
|
433
584
|
for (const backup of backupFiles) {
|
|
434
|
-
// 원래 위치 추정: claude-commands-
|
|
585
|
+
// 원래 위치 추정: claude-commands-aiwf-foo.md.bak -> .claude/commands/aiwf/foo.md
|
|
435
586
|
let originalFile;
|
|
436
|
-
if (backup.startsWith('
|
|
437
|
-
// .
|
|
587
|
+
if (backup.startsWith('aiwf-')) {
|
|
588
|
+
// .aiwf/ 하위
|
|
438
589
|
const rel = backup.replace(/-/g, '/').replace('.bak', '');
|
|
439
590
|
originalFile = '.' + rel;
|
|
440
|
-
} else if (backup.startsWith('claude-commands-
|
|
441
|
-
// .claude/commands/
|
|
442
|
-
const rel = backup.replace('claude-commands-
|
|
443
|
-
originalFile = path.join(
|
|
591
|
+
} else if (backup.startsWith('claude-commands-aiwf-')) {
|
|
592
|
+
// .claude/commands/aiwf/ 하위
|
|
593
|
+
const rel = backup.replace('claude-commands-aiwf-', '').replace(/-/g, '/').replace('.bak', '');
|
|
594
|
+
originalFile = path.join(COMMANDS_DIR, rel);
|
|
444
595
|
} else {
|
|
445
596
|
// 기타
|
|
446
597
|
originalFile = backup.replace('.bak', '');
|
|
@@ -448,21 +599,21 @@ async function restoreFromBackup(spinner) {
|
|
|
448
599
|
try {
|
|
449
600
|
await fs.rename(path.join(BACKUP_DIR, backup), originalFile);
|
|
450
601
|
} catch (e) {
|
|
451
|
-
console.warn(chalk.yellow(`'${backup}'
|
|
602
|
+
console.warn(chalk.yellow(`'${backup}' ${msg.cannotRestore}`));
|
|
452
603
|
}
|
|
453
604
|
}
|
|
454
|
-
spinner.succeed(chalk.green(
|
|
605
|
+
spinner.succeed(chalk.green(msg.restoreSuccess));
|
|
455
606
|
} catch (error) {
|
|
456
|
-
spinner.fail(chalk.red(
|
|
607
|
+
spinner.fail(chalk.red(msg.restoreFailed));
|
|
457
608
|
console.error(error);
|
|
458
609
|
}
|
|
459
610
|
}
|
|
460
611
|
|
|
461
612
|
program
|
|
462
|
-
.name('
|
|
613
|
+
.name('aiwf')
|
|
463
614
|
.version('1.0.1')
|
|
464
|
-
.description('
|
|
465
|
-
.option('-f, --force', '
|
|
466
|
-
.action((options) =>
|
|
615
|
+
.description('AIWF Installer')
|
|
616
|
+
.option('-f, --force', 'Force install without prompts')
|
|
617
|
+
.action((options) => installAIWF({ ...options, debugLog: true }));
|
|
467
618
|
|
|
468
619
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiwf",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "AI Workflow Framework for
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "AI Workflow Framework for Claude Code with multi-language support (Korean/English)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -11,21 +11,26 @@
|
|
|
11
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
|
-
"
|
|
14
|
+
"aiwf",
|
|
15
15
|
"ai",
|
|
16
16
|
"workflow",
|
|
17
|
-
"framework"
|
|
17
|
+
"framework",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"multilingual",
|
|
20
|
+
"korean",
|
|
21
|
+
"english",
|
|
22
|
+
"project-management"
|
|
18
23
|
],
|
|
19
24
|
"author": "moonklabs",
|
|
20
25
|
"license": "MIT",
|
|
21
26
|
"repository": {
|
|
22
27
|
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/
|
|
28
|
+
"url": "git+https://github.com/aiwf/aiwf.git"
|
|
24
29
|
},
|
|
25
30
|
"bugs": {
|
|
26
|
-
"url": "https://github.com/
|
|
31
|
+
"url": "https://github.com/aiwf/aiwf/issues"
|
|
27
32
|
},
|
|
28
|
-
"homepage": "https://github.com/
|
|
33
|
+
"homepage": "https://github.com/aiwf/aiwf#readme",
|
|
29
34
|
"engines": {
|
|
30
35
|
"node": ">=14.0.0"
|
|
31
36
|
},
|