create-claude-kanban 2.0.4 → 3.1.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/dist/index.js CHANGED
@@ -6,33 +6,678 @@ import pc from "picocolors";
6
6
 
7
7
  // src/prompts/project-info.ts
8
8
  import * as p from "@clack/prompts";
9
- var PROJECT_TYPE_OPTIONS = [
10
- { value: "web-app", label: "\uC6F9 \uC560\uD50C\uB9AC\uCF00\uC774\uC158 (SPA/SSR)" },
11
- { value: "mobile", label: "\uBAA8\uBC14\uC77C \uC571 (React Native/Flutter)" },
12
- { value: "api", label: "API \uC11C\uBC84 / \uBC31\uC5D4\uB4DC" },
13
- { value: "data-pipeline", label: "\uB370\uC774\uD130 \uD30C\uC774\uD504\uB77C\uC778" },
14
- { value: "ai-ml", label: "AI/ML \uD504\uB85C\uC81D\uD2B8" },
15
- { value: "content", label: "\uCF58\uD150\uCE20/\uB9C8\uCF00\uD305 \uC0AC\uC774\uD2B8" },
16
- { value: "admin", label: "\uC0AC\uB0B4 \uB3C4\uAD6C / \uC5B4\uB4DC\uBBFC" },
17
- { value: "library", label: "\uB77C\uC774\uBE0C\uB7EC\uB9AC / SDK" }
18
- ];
9
+
10
+ // src/i18n.ts
11
+ var lang = "en";
12
+ function setLang(l) {
13
+ lang = l;
14
+ }
15
+ function t(key, vars) {
16
+ let msg = messages[lang]?.[key] ?? key;
17
+ if (vars) {
18
+ for (const [k, v] of Object.entries(vars)) {
19
+ msg = msg.replaceAll(`{${k}}`, String(v));
20
+ }
21
+ }
22
+ return msg;
23
+ }
24
+ var messages = {
25
+ ko: {
26
+ // ─── common ───
27
+ "common.cancelled": "\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
28
+ "common.error": "\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.",
29
+ "common.none": "\uC5C6\uC74C",
30
+ "common.noneParens": "(\uC5C6\uC74C)",
31
+ // ─── index.ts ───
32
+ "index.filesHeader": "\uC0DD\uC131 \uC644\uB8CC",
33
+ "index.fileKanbanServer": "\uCE78\uBC18 \uC11C\uBC84 (\uBA40\uD2F0\uD504\uB85C\uC81D\uD2B8)",
34
+ "index.fileKanbanUI": "\uCE78\uBC18 UI (\uD504\uB85C\uC81D\uD2B8 \uD0ED)",
35
+ "index.fileConfig": "\uC124\uC815 \uD30C\uC77C (\uD504\uB85C\uC81D\uD2B8 {count}\uAC1C)",
36
+ "index.fileAgents": "\uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 {count}\uAC1C",
37
+ "index.fileContext": "\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8",
38
+ "index.fileOrchestrator": "\uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815",
39
+ "index.fileEnv": "\uD658\uACBD\uBCC0\uC218 \uD15C\uD50C\uB9BF",
40
+ "index.startCmd": "\uB85C \uC2DC\uC791\uD558\uC138\uC694!",
41
+ // ─── scaffold.ts ───
42
+ "scaffold.dirCreating": "\uB514\uB809\uD1A0\uB9AC \uC0DD\uC131 \uC911...",
43
+ "scaffold.dirDone": "\uB514\uB809\uD1A0\uB9AC \uC0DD\uC131 \uC644\uB8CC",
44
+ "scaffold.kanbanServerCopying": "\uCE78\uBC18 \uC11C\uBC84 \uBCF5\uC0AC \uC911...",
45
+ "scaffold.kanbanServerDone": "\uCE78\uBC18 \uC11C\uBC84 \uBCF5\uC0AC \uC644\uB8CC",
46
+ "scaffold.kanbanUICopying": "\uCE78\uBC18 UI \uBCF5\uC0AC \uC911...",
47
+ "scaffold.kanbanUIDone": "\uCE78\uBC18 UI \uBCF5\uC0AC \uC644\uB8CC",
48
+ "scaffold.configCreating": "\uC124\uC815 \uD30C\uC77C \uC0DD\uC131 \uC911...",
49
+ "scaffold.configDone": "\uC124\uC815 \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC",
50
+ "scaffold.projectListCreating": "\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC0DD\uC131 \uC911...",
51
+ "scaffold.projectListDone": "\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC0DD\uC131 \uC644\uB8CC",
52
+ "scaffold.contextCreating": "\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8 \uC0DD\uC131 \uC911...",
53
+ "scaffold.contextDone": "\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8 \uC0DD\uC131 \uC644\uB8CC",
54
+ "scaffold.agentsCreating": "\uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 \uC0DD\uC131 \uC911...",
55
+ "scaffold.agentsDone": "\uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 {count}\uAC1C \uC0DD\uC131 \uC644\uB8CC",
56
+ "scaffold.orchestratorCreating": "\uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815 \uC0DD\uC131 \uC911...",
57
+ "scaffold.orchestratorDone": "\uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815 \uC0DD\uC131 \uC644\uB8CC",
58
+ "scaffold.envCreating": ".env.example \uC0DD\uC131 \uC911...",
59
+ "scaffold.envDone": ".env.example \uC0DD\uC131 \uC644\uB8CC",
60
+ "scaffold.noConstraints": "(\uC5C6\uC74C)",
61
+ // ─── prompts/project-info.ts ───
62
+ "projectInfo.phase": "Phase 1: \uD504\uB85C\uC81D\uD2B8 \uAE30\uBCF8 \uC815\uBCF4",
63
+ "projectInfo.nameMsg": "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984?",
64
+ "projectInfo.nameValidation": "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694",
65
+ "projectInfo.descMsg": "\uD55C \uC904 \uC124\uBA85?",
66
+ "projectInfo.descPlaceholder": "\uD504\uB85C\uC81D\uD2B8 \uAC04\uB2E8 \uC124\uBA85",
67
+ "projectInfo.descValidation": "\uC124\uBA85\uC744 \uC785\uB825\uD558\uC138\uC694",
68
+ "projectInfo.typesMsg": "\uD504\uB85C\uC81D\uD2B8 \uC131\uACA9? (\uBCF5\uC218 \uC120\uD0DD \uAC00\uB2A5)",
69
+ "projectInfo.typeWebApp": "\uC6F9 \uC560\uD50C\uB9AC\uCF00\uC774\uC158 (SPA/SSR)",
70
+ "projectInfo.typeMobile": "\uBAA8\uBC14\uC77C \uC571 (React Native/Flutter)",
71
+ "projectInfo.typeApi": "API \uC11C\uBC84 / \uBC31\uC5D4\uB4DC",
72
+ "projectInfo.typeDataPipeline": "\uB370\uC774\uD130 \uD30C\uC774\uD504\uB77C\uC778",
73
+ "projectInfo.typeAiMl": "AI/ML \uD504\uB85C\uC81D\uD2B8",
74
+ "projectInfo.typeContent": "\uCF58\uD150\uCE20/\uB9C8\uCF00\uD305 \uC0AC\uC774\uD2B8",
75
+ "projectInfo.typeAdmin": "\uC0AC\uB0B4 \uB3C4\uAD6C / \uC5B4\uB4DC\uBBFC",
76
+ "projectInfo.typeLibrary": "\uB77C\uC774\uBE0C\uB7EC\uB9AC / SDK",
77
+ // ─── prompts/tech-stack.ts ───
78
+ "techStack.phase": "Phase 2: \uAE30\uC220 \uC2A4\uD0DD & \uAD6C\uC870",
79
+ "techStack.detectedTech": "\uAC10\uC9C0\uB41C \uAE30\uC220: {techs}",
80
+ "techStack.frontendMsg": "\uD504\uB860\uD2B8\uC5D4\uB4DC \uC2A4\uD0DD?",
81
+ "techStack.frontendNone": "\uC5C6\uC74C (\uBC31\uC5D4\uB4DC only)",
82
+ "techStack.backendMsg": "\uBC31\uC5D4\uB4DC / \uC778\uD504\uB77C? (\uBCF5\uC218 \uC120\uD0DD)",
83
+ "techStack.deployMsg": "\uBC30\uD3EC \uD658\uACBD?",
84
+ "techStack.deployDocker": "Docker \uC790\uCCB4 \uC11C\uBC84",
85
+ "techStack.deployUndecided": "\uC544\uC9C1 \uBBF8\uC815",
86
+ "techStack.detectedDirs": "\uAC10\uC9C0\uB41C \uB514\uB809\uD1A0\uB9AC:\n{dirs}",
87
+ "techStack.useDetected": "\uC774 \uAD6C\uC870\uB97C \uADF8\uB300\uB85C \uC0AC\uC6A9\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
88
+ "techStack.customDirsMsg": "\uB514\uB809\uD1A0\uB9AC \uAD6C\uC870 (\uC27C\uD45C \uAD6C\uBD84, \uC608: src/:\uC18C\uC2A4,docs/:\uBB38\uC11C)",
89
+ "techStack.customDirsPlaceholder": "src/:\uC18C\uC2A4 \uCF54\uB4DC, docs/:\uBB38\uC11C, tests/:\uD14C\uC2A4\uD2B8",
90
+ "techStack.mainDirsMsg": "\uC8FC\uC694 \uB514\uB809\uD1A0\uB9AC \uAD6C\uC870 (\uC27C\uD45C \uAD6C\uBD84, \uC608: src/:\uC18C\uC2A4,docs/:\uBB38\uC11C)",
91
+ // ─── prompts/context-files.ts ───
92
+ "contextFiles.phase": "Phase 3: \uAE30\uC874 \uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C",
93
+ "contextFiles.hasClaudeMdMsg": "CLAUDE.md \uB610\uB294 \uD504\uB85C\uC81D\uD2B8 \uAC00\uC774\uB4DC \uD30C\uC77C\uC774 \uC788\uB098\uC694?",
94
+ "contextFiles.hasClaudeMdYes": "\uC788\uC74C \u2192 \uACBD\uB85C \uC785\uB825",
95
+ "contextFiles.hasClaudeMdNo": "\uC5C6\uC74C \u2192 \uCD94\uAC00 \uC9C8\uBB38\uC73C\uB85C \uC218\uC9D1",
96
+ "contextFiles.claudeMdPathMsg": "CLAUDE.md \uACBD\uB85C?",
97
+ "contextFiles.fileNotFound": "\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {path}",
98
+ "contextFiles.summaryStack": "\uC2A4\uD0DD: {value}",
99
+ "contextFiles.summaryBackend": "\uBC31\uC5D4\uB4DC: {value}",
100
+ "contextFiles.summaryNaming": "\uB124\uC774\uBC0D: {value}",
101
+ "contextFiles.summaryTools": "\uB3C4\uAD6C: {value}",
102
+ "contextFiles.summaryFonts": "\uD3F0\uD2B8: {value}",
103
+ "contextFiles.parseSuccess": "\uD30C\uC77C \uBD84\uC11D \uC644\uB8CC:\n {summary}\n \u2192 \uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8\uC5D0 \uC790\uB3D9 \uBC18\uC601\uB429\uB2C8\uB2E4.",
104
+ "contextFiles.parseEmpty": "\uD30C\uC77C\uC744 \uC77D\uC5C8\uC9C0\uB9CC \uC790\uB3D9 \uD30C\uC2F1\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC5C8\uC2B5\uB2C8\uB2E4. \uC218\uB3D9 \uC9C8\uBB38\uC744 \uC9C4\uD589\uD569\uB2C8\uB2E4.",
105
+ "contextFiles.parseError": "\uD30C\uC77C \uD30C\uC2F1 \uC911 \uC624\uB958 \uBC1C\uC0DD. \uC218\uB3D9 \uC9C8\uBB38\uC73C\uB85C \uC804\uD658\uD569\uB2C8\uB2E4.",
106
+ "contextFiles.codingStyleMsg": "\uCF54\uB529 \uC2A4\uD0C0\uC77C \uC120\uD638? (\uBCF5\uC218 \uC120\uD0DD)",
107
+ "contextFiles.concernsMsg": "\uC8FC\uC758\uD574\uC57C \uD560 \uC0AC\uD56D? (\uBCF5\uC218 \uC120\uD0DD)",
108
+ "contextFiles.refDocsMsg": "\uCD94\uAC00 \uCC38\uACE0 \uBB38\uC11C\uAC00 \uC788\uB098\uC694? (\uBCF5\uC218 \uC120\uD0DD)",
109
+ "contextFiles.docPathMsg": "{type} \uD30C\uC77C \uACBD\uB85C?",
110
+ "contextFiles.docPathValidation": "\uACBD\uB85C\uB97C \uC785\uB825\uD558\uC138\uC694",
111
+ // coding style options
112
+ "contextFiles.styleFunctional": "\uD568\uC218\uD615 \uCEF4\uD3EC\uB10C\uD2B8 only (\uD074\uB798\uC2A4 \uAE08\uC9C0)",
113
+ "contextFiles.styleNamedExport": "Named export \uC120\uD638",
114
+ "contextFiles.styleNoAny": "any \uD0C0\uC785 \uAE08\uC9C0 (unknown \uC120\uD638)",
115
+ "contextFiles.styleKoComment": "\uD55C\uAD6D\uC5B4 \uC8FC\uC11D / \uD55C\uAD6D\uC5B4 \uCEE4\uBC0B",
116
+ "contextFiles.styleEnComment": "\uC601\uBB38 \uC8FC\uC11D / \uC601\uBB38 \uCEE4\uBC0B",
117
+ "contextFiles.styleJsdoc": "JSDoc \uC8FC\uC11D",
118
+ "contextFiles.styleEslint": "ESLint + Prettier \uC801\uC6A9",
119
+ "contextFiles.styleDefault": "\uAE30\uBCF8\uAC12 \uC0AC\uC6A9 (\uBCC4\uB3C4 \uC120\uD638 \uC5C6\uC74C)",
120
+ // concern options
121
+ "contextFiles.concernI18n": "\uB2E4\uAD6D\uC5B4 \uC9C0\uC6D0 (i18n)",
122
+ "contextFiles.concernDarkMode": "\uB2E4\uD06C\uBAA8\uB4DC",
123
+ "contextFiles.concernA11y": "\uC811\uADFC\uC131 (a11y)",
124
+ "contextFiles.concernSeo": "SEO \uCD5C\uC801\uD654",
125
+ "contextFiles.concernPerformance": "\uC131\uB2A5 \uCD5C\uC801\uD654 (Core Web Vitals)",
126
+ "contextFiles.concernSecurity": "\uBCF4\uC548 (\uC778\uC99D/\uAD8C\uD55C/XSS/CSRF)",
127
+ "contextFiles.concernResponsive": "\uBAA8\uBC14\uC77C \uBC18\uC751\uD615 \uD544\uC218",
128
+ "contextFiles.concernNone": "\uC5C6\uC74C",
129
+ // reference doc options
130
+ "contextFiles.refApiSpec": "API \uBA85\uC138 (OpenAPI/Swagger)",
131
+ "contextFiles.refDesignSystem": "\uB514\uC790\uC778 \uC2DC\uC2A4\uD15C \uBB38\uC11C",
132
+ "contextFiles.refDbSchema": "DB \uC2A4\uD0A4\uB9C8 / ERD",
133
+ "contextFiles.refWbs": "\uAE30\uC874 WBS / \uD0DC\uC2A4\uD06C \uBAA9\uB85D",
134
+ "contextFiles.refBrandGuide": "\uBE0C\uB79C\uB4DC \uAC00\uC774\uB4DC\uB77C\uC778",
135
+ "contextFiles.refNone": "\uC5C6\uC74C",
136
+ // ─── prompts/agents.ts ───
137
+ "agents.phase": "Phase 4: \uC5D0\uC774\uC804\uD2B8 \uAD6C\uC131",
138
+ "agents.workTypeMsg": "\uC5B4\uB5A4 \uC791\uC5C5\uC744 \uC8FC\uB85C \uD558\uC2DC\uB098\uC694? (\uBCF5\uC218 \uC120\uD0DD)",
139
+ "agents.recommended": "\uC791\uC5C5 \uC720\uD615 \uAE30\uBC18 \uCD94\uCC9C \uC5D0\uC774\uC804\uD2B8:\n{list}\n \u25FC orchestrator \u2190 \uD56D\uC0C1 \uD3EC\uD568",
140
+ "agents.customizeMsg": "\uC5D0\uC774\uC804\uD2B8\uB97C \uCD94\uAC00/\uC81C\uAC70\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
141
+ "agents.selectMsg": "\uCD5C\uC885 \uC5D0\uC774\uC804\uD2B8 \uC120\uD0DD (orchestrator\uB294 \uD56D\uC0C1 \uD3EC\uD568)",
142
+ "agents.modelMsg": "\uC5D0\uC774\uC804\uD2B8 \uBAA8\uB378 \uAE30\uBCF8\uAC12?",
143
+ // work type options
144
+ "agents.workFrontend": "\uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C (UI/\uCEF4\uD3EC\uB10C\uD2B8)",
145
+ "agents.workBackend": "\uBC31\uC5D4\uB4DC \uAC1C\uBC1C (API/DB/\uC11C\uBC84)",
146
+ "agents.workQa": "\uD14C\uC2A4\uD2B8/QA (\uC720\uB2DB/E2E/\uC131\uB2A5)",
147
+ "agents.workDesign": "\uB514\uC790\uC778 \uC2DC\uC2A4\uD15C \uAD00\uB9AC",
148
+ "agents.workDevops": "DevOps / CI\xB7CD / \uBC30\uD3EC",
149
+ "agents.workResearch": "\uC870\uC0AC/\uBD84\uC11D/\uB9AC\uC11C\uCE58",
150
+ "agents.workDocs": "\uBB38\uC11C \uC791\uC131",
151
+ "agents.workContent": "\uCF58\uD150\uCE20 \uAE30\uD68D",
152
+ "agents.workStrategy": "\uC804\uB7B5/\uC544\uD0A4\uD14D\uCC98 \uC124\uACC4",
153
+ "agents.workItems": "\uBB38\uD56D/\uD034\uC988 \uAC1C\uBC1C",
154
+ // agent options
155
+ "agents.agentFrontend": "frontend \u2014 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C",
156
+ "agents.agentBackend": "backend \u2014 \uBC31\uC5D4\uB4DC \uAC1C\uBC1C",
157
+ "agents.agentQa": "qa \u2014 \uD14C\uC2A4\uD2B8/\uD488\uC9C8",
158
+ "agents.agentDesigner": "designer \u2014 \uB514\uC790\uC778 \uC2DC\uC2A4\uD15C",
159
+ "agents.agentDevops": "devops \u2014 \uC778\uD504\uB77C/\uBC30\uD3EC",
160
+ "agents.agentResearcher": "researcher \u2014 \uC870\uC0AC/\uBD84\uC11D",
161
+ "agents.agentStrategist": "strategist \u2014 \uC544\uD0A4\uD14D\uCC98/\uC804\uB7B5",
162
+ "agents.agentContentPlanner": "content-planner \u2014 \uCF58\uD150\uCE20 \uAE30\uD68D",
163
+ "agents.agentItemAuthor": "item-author \u2014 \uBB38\uD56D \uAC1C\uBC1C",
164
+ "agents.agentDocWriter": "doc-writer \u2014 \uBB38\uC11C \uC791\uC131",
165
+ // model options
166
+ "agents.modelSonnet": "sonnet (\uB300\uBD80\uBD84) + opus (orchestrator/strategist \uC790\uB3D9)",
167
+ "agents.modelOpus": "\uC804\uBD80 opus (\uACE0\uD488\uC9C8, \uBE44\uC6A9 \uB192\uC74C)",
168
+ "agents.modelSonnetOnly": "\uC804\uBD80 sonnet (\uADE0\uD615)",
169
+ // ─── prompts/orchestrator.ts ───
170
+ "orchestrator.phase": "Phase 5: \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uCEE8\uD14D\uC2A4\uD2B8",
171
+ "orchestrator.goalsMsg": "{name} \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130\uAC00 \uC54C\uC544\uC57C \uD560 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uD45C\uB294?",
172
+ "orchestrator.goalsPlaceholder": "\uC608: 2026\uB144 4\uC6D4 \uB860\uCE6D, \uACB0\uC81C \uC5F0\uB3D9 \uC644\uB8CC \uD544\uC218, \uBAA8\uBC14\uC77C \uBC18\uC751\uD615",
173
+ "orchestrator.goalsValidation": "\uBAA9\uD45C\uB97C \uC785\uB825\uD558\uC138\uC694",
174
+ "orchestrator.stageMsg": "\uD604\uC7AC \uD504\uB85C\uC81D\uD2B8 \uB2E8\uACC4\uB294?",
175
+ "orchestrator.constraintsMsg": "\uC791\uC5C5 \uC6B0\uC120\uC21C\uC704 \uB610\uB294 \uC81C\uC57D\uC0AC\uD56D? (\uC5C6\uC73C\uBA74 \uC5D4\uD130)",
176
+ "orchestrator.constraintsPlaceholder": "\uC608: .env \uCEE4\uBC0B \uAE08\uC9C0, \uD14C\uC2A4\uD2B8 \uCEE4\uBC84\uB9AC\uC9C0 80% \uC720\uC9C0",
177
+ // stage options
178
+ "orchestrator.stageIdea": "\uC544\uC774\uB514\uC5B4/\uAE30\uD68D \uB2E8\uACC4",
179
+ "orchestrator.stageDevPreMvp": "\uAC1C\uBC1C \uC9C4\uD589 \uC911 (MVP \uC804)",
180
+ "orchestrator.stageMvpDone": "MVP \uC644\uC131, \uAC1C\uC120 \uC911",
181
+ "orchestrator.stageProduction": "\uC6B4\uC601 \uC911 (\uC720\uC9C0\uBCF4\uC218/\uAE30\uB2A5 \uCD94\uAC00)",
182
+ "orchestrator.stageRefactor": "\uB9AC\uD329\uD1A0\uB9C1/\uB9C8\uC774\uADF8\uB808\uC774\uC158",
183
+ // ─── prompts/multi-project.ts ───
184
+ "multiProject.phase": "Phase 6: \uBA40\uD2F0\uD504\uB85C\uC81D\uD2B8 (\uC120\uD0DD)",
185
+ "multiProject.addMoreMsg": "\uCD94\uAC00 \uD504\uB85C\uC81D\uD2B8\uB97C \uB4F1\uB85D\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
186
+ "multiProject.addMoreNo": "\uC9C0\uAE08\uC740 1\uAC1C\uB9CC",
187
+ "multiProject.addMoreYes": "\uCD94\uAC00 \uB4F1\uB85D",
188
+ "multiProject.nameMsg": "\uCD94\uAC00 \uD504\uB85C\uC81D\uD2B8 \uC774\uB984?",
189
+ "multiProject.namePlaceholder": "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984",
190
+ "multiProject.nameValidation": "\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694",
191
+ "multiProject.descMsg": "\uD55C \uC904 \uC124\uBA85?",
192
+ "multiProject.descPlaceholder": "\uD504\uB85C\uC81D\uD2B8 \uC124\uBA85",
193
+ "multiProject.colorMsg": "\uD0DC\uADF8 \uC0C9\uC0C1?",
194
+ "multiProject.agentMsg": "\uC5D0\uC774\uC804\uD2B8 \uAD6C\uC131?",
195
+ "multiProject.agentShared": "\uAE30\uBCF8 \uD504\uB85C\uC81D\uD2B8\uC640 \uB3D9\uC77C\uD55C \uC5D0\uC774\uC804\uD2B8 \uACF5\uC720",
196
+ "multiProject.agentSeparate": "\uC774 \uD504\uB85C\uC81D\uD2B8 \uC804\uC6A9 \uC5D0\uC774\uC804\uD2B8 \uBCC4\uB3C4 \uAD6C\uC131",
197
+ "multiProject.anotherMsg": "\uB610 \uB2E4\uB978 \uD504\uB85C\uC81D\uD2B8\uB97C \uCD94\uAC00\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
198
+ // color labels
199
+ "multiProject.colorBlue": "\uD30C\uB791",
200
+ "multiProject.colorGreen": "\uCD08\uB85D",
201
+ "multiProject.colorOrange": "\uC8FC\uD669",
202
+ "multiProject.colorPurple": "\uBCF4\uB77C",
203
+ "multiProject.colorRed": "\uBE68\uAC15",
204
+ "multiProject.colorPink": "\uBD84\uD64D",
205
+ "multiProject.colorTeal": "\uCCAD\uB85D",
206
+ // ─── prompts/infra.ts ───
207
+ "infra.phase": "Phase 7: \uC778\uD504\uB77C",
208
+ "infra.slackMsg": "Slack \uC5F0\uB3D9?",
209
+ "infra.slackYes": "\uC5F0\uB3D9\uD568 (Bot Token + Socket Mode)",
210
+ "infra.slackNo": "\uB098\uC911\uC5D0 \uC124\uC815",
211
+ "infra.slackCommandMsg": "Slack \uCEE4\uB9E8\uB4DC \uC774\uB984?",
212
+ "infra.portMsg": "\uCE78\uBC18 \uC11C\uBC84 \uD3EC\uD2B8?",
213
+ "infra.portValidation": "\uC720\uD6A8\uD55C \uD3EC\uD2B8 \uBC88\uD638\uB97C \uC785\uB825\uD558\uC138\uC694 (1-65535)",
214
+ "infra.targetDirMsg": "\uD30C\uC77C\uC744 \uC5B4\uB514\uC5D0 \uC0DD\uC131\uD560\uAE4C\uC694?",
215
+ "infra.targetDirPlaceholder": "(\uD604\uC7AC \uB514\uB809\uD1A0\uB9AC)",
216
+ // ─── generators/env-file.ts ───
217
+ "envGen.kanbanServer": "# \uCE78\uBC18 \uC11C\uBC84",
218
+ "envGen.slackIntegration": "# Slack \uC5F0\uB3D9",
219
+ "envGen.slackLater": "# Slack \uC5F0\uB3D9 (\uB098\uC911\uC5D0 \uC124\uC815)",
220
+ // ─── generators/project-context.ts ───
221
+ // frontend labels
222
+ "contextGen.frontendNone": "(\uC5C6\uC74C)",
223
+ // deploy labels
224
+ "contextGen.deployDocker": "Docker \uC790\uCCB4 \uC11C\uBC84",
225
+ "contextGen.deployUndecided": "\uBBF8\uC815",
226
+ // stage labels
227
+ "contextGen.stageIdea": "\uC544\uC774\uB514\uC5B4/\uAE30\uD68D \uB2E8\uACC4",
228
+ "contextGen.stageDevPreMvp": "\uAC1C\uBC1C \uC9C4\uD589 \uC911 (MVP \uC804)",
229
+ "contextGen.stageMvpDone": "MVP \uC644\uC131, \uAC1C\uC120 \uC911",
230
+ "contextGen.stageProduction": "\uC6B4\uC601 \uC911 (\uC720\uC9C0\uBCF4\uC218/\uAE30\uB2A5 \uCD94\uAC00)",
231
+ "contextGen.stageRefactor": "\uB9AC\uD329\uD1A0\uB9C1/\uB9C8\uC774\uADF8\uB808\uC774\uC158",
232
+ // project type labels
233
+ "contextGen.typeWebApp": "\uC6F9 \uC560\uD50C\uB9AC\uCF00\uC774\uC158",
234
+ "contextGen.typeMobile": "\uBAA8\uBC14\uC77C \uC571",
235
+ "contextGen.typeApi": "API \uC11C\uBC84",
236
+ "contextGen.typeDataPipeline": "\uB370\uC774\uD130 \uD30C\uC774\uD504\uB77C\uC778",
237
+ "contextGen.typeAiMl": "AI/ML",
238
+ "contextGen.typeContent": "\uCF58\uD150\uCE20/\uB9C8\uCF00\uD305",
239
+ "contextGen.typeAdmin": "\uC0AC\uB0B4 \uB3C4\uAD6C",
240
+ "contextGen.typeLibrary": "\uB77C\uC774\uBE0C\uB7EC\uB9AC/SDK",
241
+ // coding style labels
242
+ "contextGen.styleFunctional": "\uD568\uC218\uD615 \uCEF4\uD3EC\uB10C\uD2B8 only (\uD074\uB798\uC2A4 \uAE08\uC9C0)",
243
+ "contextGen.styleNamedExport": "Named export \uC120\uD638",
244
+ "contextGen.styleNoAny": "any \uD0C0\uC785 \uAE08\uC9C0 (unknown \uC120\uD638)",
245
+ "contextGen.styleKoComment": "\uD55C\uAD6D\uC5B4 \uC8FC\uC11D / \uD55C\uAD6D\uC5B4 \uCEE4\uBC0B",
246
+ "contextGen.styleEnComment": "\uC601\uBB38 \uC8FC\uC11D / \uC601\uBB38 \uCEE4\uBC0B",
247
+ "contextGen.styleJsdoc": "JSDoc \uC8FC\uC11D",
248
+ "contextGen.styleEslint": "ESLint + Prettier \uC801\uC6A9",
249
+ "contextGen.styleDefault": "\uAE30\uBCF8\uAC12 \uC0AC\uC6A9",
250
+ // concern labels
251
+ "contextGen.concernI18n": "\uB2E4\uAD6D\uC5B4 \uC9C0\uC6D0 (i18n)",
252
+ "contextGen.concernDarkMode": "\uB2E4\uD06C\uBAA8\uB4DC",
253
+ "contextGen.concernA11y": "\uC811\uADFC\uC131 (a11y)",
254
+ "contextGen.concernSeo": "SEO \uCD5C\uC801\uD654",
255
+ "contextGen.concernPerformance": "\uC131\uB2A5 \uCD5C\uC801\uD654 (Core Web Vitals)",
256
+ "contextGen.concernSecurity": "\uBCF4\uC548 (\uC778\uC99D/\uAD8C\uD55C/XSS/CSRF)",
257
+ "contextGen.concernResponsive": "\uBAA8\uBC14\uC77C \uBC18\uC751\uD615 \uD544\uC218",
258
+ "contextGen.concernNone": "\uC5C6\uC74C",
259
+ // generated document sections
260
+ "contextGen.title": "{name} \u2014 \uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8",
261
+ "contextGen.intro": "\uC774 \uBB38\uC11C\uB294 \uBAA8\uB4E0 \uC5D0\uC774\uC804\uD2B8\uAC00 \uACF5\uC720\uD558\uB294 \uD504\uB85C\uC81D\uD2B8 \uAE30\uBCF8 \uC815\uBCF4\uB2E4.\n\uAC01 \uC5D0\uC774\uC804\uD2B8\uB294 \uC774 \uBB38\uC11C\uB97C \uC219\uC9C0\uD55C \uC0C1\uD0DC\uC5D0\uC11C \uC790\uAE30 \uC5ED\uD560\uC744 \uC218\uD589\uD55C\uB2E4.",
262
+ "contextGen.sectionOverview": "\uD504\uB85C\uC81D\uD2B8 \uAC1C\uC694",
263
+ "contextGen.labelType": "\uC131\uACA9",
264
+ "contextGen.labelStage": "\uB2E8\uACC4",
265
+ "contextGen.sectionStack": "\uAE30\uC220 \uC2A4\uD0DD",
266
+ "contextGen.labelFrontend": "\uD504\uB860\uD2B8\uC5D4\uB4DC",
267
+ "contextGen.backendFallback": "(\uC9C1\uC811 \uC785\uB825\uD558\uC138\uC694)",
268
+ "contextGen.labelDeploy": "\uBC30\uD3EC",
269
+ "contextGen.sectionDirs": "\uB514\uB809\uD1A0\uB9AC \uAD6C\uC870",
270
+ "contextGen.defaultDirSrc": "\uC18C\uC2A4 \uCF54\uB4DC",
271
+ "contextGen.defaultDirDocs": "\uBB38\uC11C",
272
+ "contextGen.defaultDirTools": "\uAC1C\uBC1C \uB3C4\uAD6C",
273
+ "contextGen.sectionConventions": "\uCF54\uB529 \uCEE8\uBCA4\uC158",
274
+ "contextGen.noConventionsClaudeMd": "(CLAUDE.md\uC5D0\uC11C \uC790\uB3D9 \uCD94\uCD9C\uB41C \uCEE8\uBCA4\uC158 \uC5C6\uC74C)",
275
+ "contextGen.noConventionsManual": "(\uD504\uB85C\uC81D\uD2B8\uC5D0 \uB9DE\uAC8C \uC218\uC815\uD558\uC138\uC694)",
276
+ "contextGen.sectionBrand": "\uBE0C\uB79C\uB4DC/\uB514\uC790\uC778",
277
+ "contextGen.labelFonts": "\uD3F0\uD2B8",
278
+ "contextGen.labelColors": "\uC0C9\uC0C1",
279
+ "contextGen.labelI18n": "\uB2E4\uAD6D\uC5B4",
280
+ "contextGen.sectionGoals": "\uD504\uB85C\uC81D\uD2B8 \uBAA9\uD45C",
281
+ "contextGen.goalsPlaceholder": "(\uBAA9\uD45C\uB97C \uC785\uB825\uD558\uC138\uC694)",
282
+ "contextGen.sectionConstraints": "\uC81C\uC57D\uC0AC\uD56D",
283
+ "contextGen.constraintsPlaceholder": "(\uC81C\uC57D\uC0AC\uD56D \uC5C6\uC74C)",
284
+ "contextGen.sectionRefDocs": "\uCC38\uACE0 \uBB38\uC11C",
285
+ "contextGen.noRefDocs": "(\uC5C6\uC74C)",
286
+ "contextGen.sectionProtocol": "\uC791\uC5C5 \uD504\uB85C\uD1A0\uCF5C",
287
+ "contextGen.protocolKanban": "\uCE78\uBC18 \uC11C\uBC84",
288
+ "contextGen.protocolSlack": "Slack \uBCF4\uACE0",
289
+ "contextGen.protocolLogs": "\uB85C\uADF8 \uB514\uB809\uD1A0\uB9AC",
290
+ "contextGen.protocolStatus": "\uC0C1\uD0DC \uD50C\uB85C\uC6B0",
291
+ "contextGen.protocolInstruction": "\uBAA8\uB4E0 \uC5D0\uC774\uC804\uD2B8\uB294 \uC791\uC5C5 \uC2DC\uC791/\uC644\uB8CC \uC2DC \uB2E4\uC74C 3\uACF3\uC5D0 \uAE30\uB85D\uC744 \uB0A8\uAE34\uB2E4:",
292
+ "contextGen.protocolSlackReport": "Slack \uBCF4\uACE0",
293
+ "contextGen.protocolKanbanUpdate": "\uCE78\uBC18 \uC5C5\uB370\uC774\uD2B8",
294
+ "contextGen.protocolLogFile": "\uB85C\uADF8 \uD30C\uC77C",
295
+ "contextGen.protocolSlackExample": "\uBA54\uC2DC\uC9C0",
296
+ // ─── generators/agent-prompt.ts (base sections only) ───
297
+ "agentGen.projectLabel": "\uD504\uB85C\uC81D\uD2B8",
298
+ "agentGen.descLabel": "\uC124\uBA85",
299
+ "agentGen.kanbanApiLabel": "\uCE78\uBC18 API",
300
+ "agentGen.slackApiLabel": "Slack API",
301
+ "agentGen.logDirLabel": "\uB85C\uADF8 \uB514\uB809\uD1A0\uB9AC",
302
+ "agentGen.slackReportingDesc": "\uC791\uC5C5 \uC2DC\uC791\uACFC \uC644\uB8CC \uC2DC Slack\uC5D0 \uBCF4\uACE0\uD55C\uB2E4 (\uD0DC\uC2A4\uD06C \uC2A4\uB808\uB4DC\uB85C \uC790\uB3D9 \uC815\uB9AC):",
303
+ "agentGen.slackForbid": "`$SLACK_AGENT_WEBHOOK` \uC9C1\uC811 \uC0AC\uC6A9 \uAE08\uC9C0. \uBC18\uB4DC\uC2DC \uC704 API\uB97C \uD1B5\uD574 \uBCF4\uACE0.",
304
+ "agentGen.slackTaskIdNote": "`{TASK_ID}`\uB294 buildExecutorPrompt\uC5D0\uC11C \uC2E4\uC81C ID\uAC00 \uC8FC\uC785\uB41C\uB2E4.",
305
+ "agentGen.kanbanStart": "\uC2DC\uC791",
306
+ "agentGen.kanbanDone": "\uC644\uB8CC",
307
+ "agentGen.kanbanActiveForm": "\uC218\uD589 \uC911 \uC124\uBA85",
308
+ "agentGen.kanbanReportFormat": "\uC218\uD589 \uB0B4\uC5ED \uC694\uC57D 1\uC904. \uD6C4\uC18D: \uB2E4\uC74C \uC791\uC5C5 \uC81C\uC548",
309
+ "agentGen.reportDesc": "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC \uBCF4\uACE0\uC11C \uC791\uC131:",
310
+ "agentGen.reportPathLabel": "\uACBD\uB85C",
311
+ "agentGen.reportContentDesc": "\uB0B4\uC6A9: \uBCC0\uACBD \uD30C\uC77C \uBAA9\uB85D, \uBCC0\uACBD \uB0B4\uC6A9, \uAC80\uC99D \uACB0\uACFC, \uD6C4\uC18D \uC791\uC5C5",
312
+ "agentGen.fontsLabel": "\uD3F0\uD2B8",
313
+ "agentGen.colorsLabel": "\uC0C9\uC0C1",
314
+ // ─── utils/detect-structure.ts ───
315
+ "detect.src": "\uC18C\uC2A4 \uCF54\uB4DC",
316
+ "detect.app": "\uC571 \uC18C\uC2A4 (Next.js/Remix)",
317
+ "detect.pages": "\uD398\uC774\uC9C0 (Next.js)",
318
+ "detect.components": "\uCEF4\uD3EC\uB10C\uD2B8",
319
+ "detect.lib": "\uB77C\uC774\uBE0C\uB7EC\uB9AC/\uC720\uD2F8",
320
+ "detect.api": "API \uB77C\uC6B0\uD2B8",
321
+ "detect.server": "\uC11C\uBC84 \uCF54\uB4DC",
322
+ "detect.supabase": "Supabase (Edge Functions/\uB9C8\uC774\uADF8\uB808\uC774\uC158)",
323
+ "detect.firebase": "Firebase",
324
+ "detect.prisma": "Prisma \uC2A4\uD0A4\uB9C8",
325
+ "detect.docs": "\uBB38\uC11C",
326
+ "detect.tests": "\uD14C\uC2A4\uD2B8",
327
+ "detect.e2e": "E2E \uD14C\uC2A4\uD2B8",
328
+ "detect.cypress": "Cypress \uD14C\uC2A4\uD2B8",
329
+ "detect.public": "\uC815\uC801 \uD30C\uC77C",
330
+ "detect.static": "\uC815\uC801 \uD30C\uC77C",
331
+ "detect.assets": "\uC5D0\uC14B",
332
+ "detect.styles": "\uC2A4\uD0C0\uC77C",
333
+ "detect.scripts": "\uC2A4\uD06C\uB9BD\uD2B8",
334
+ "detect.tools": "\uAC1C\uBC1C \uB3C4\uAD6C",
335
+ "detect.github": "GitHub Actions"
336
+ },
337
+ en: {
338
+ // ─── common ───
339
+ "common.cancelled": "Cancelled.",
340
+ "common.error": "An error occurred.",
341
+ "common.none": "None",
342
+ "common.noneParens": "(None)",
343
+ // ─── index.ts ───
344
+ "index.filesHeader": "Files created",
345
+ "index.fileKanbanServer": "Kanban server (multi-project)",
346
+ "index.fileKanbanUI": "Kanban UI (project tabs)",
347
+ "index.fileConfig": "Config file ({count} projects)",
348
+ "index.fileAgents": "{count} agent prompts",
349
+ "index.fileContext": "Project context",
350
+ "index.fileOrchestrator": "Orchestrator config",
351
+ "index.fileEnv": "Env template",
352
+ "index.startCmd": "to get started!",
353
+ // ─── scaffold.ts ───
354
+ "scaffold.dirCreating": "Creating directories...",
355
+ "scaffold.dirDone": "Directories created",
356
+ "scaffold.kanbanServerCopying": "Copying kanban server...",
357
+ "scaffold.kanbanServerDone": "Kanban server copied",
358
+ "scaffold.kanbanUICopying": "Copying kanban UI...",
359
+ "scaffold.kanbanUIDone": "Kanban UI copied",
360
+ "scaffold.configCreating": "Generating config...",
361
+ "scaffold.configDone": "Config generated",
362
+ "scaffold.projectListCreating": "Generating project list...",
363
+ "scaffold.projectListDone": "Project list generated",
364
+ "scaffold.contextCreating": "Generating project context...",
365
+ "scaffold.contextDone": "Project context generated",
366
+ "scaffold.agentsCreating": "Generating agent prompts...",
367
+ "scaffold.agentsDone": "{count} agent prompts generated",
368
+ "scaffold.orchestratorCreating": "Generating orchestrator config...",
369
+ "scaffold.orchestratorDone": "Orchestrator config generated",
370
+ "scaffold.envCreating": "Generating .env.example...",
371
+ "scaffold.envDone": ".env.example generated",
372
+ "scaffold.noConstraints": "(None)",
373
+ // ─── prompts/project-info.ts ───
374
+ "projectInfo.phase": "Phase 1: Project basics",
375
+ "projectInfo.nameMsg": "Project name?",
376
+ "projectInfo.nameValidation": "Please enter a project name",
377
+ "projectInfo.descMsg": "One-line description?",
378
+ "projectInfo.descPlaceholder": "Brief project description",
379
+ "projectInfo.descValidation": "Please enter a description",
380
+ "projectInfo.typesMsg": "Project type? (multiple selection)",
381
+ "projectInfo.typeWebApp": "Web application (SPA/SSR)",
382
+ "projectInfo.typeMobile": "Mobile app (React Native/Flutter)",
383
+ "projectInfo.typeApi": "API server / Backend",
384
+ "projectInfo.typeDataPipeline": "Data pipeline",
385
+ "projectInfo.typeAiMl": "AI/ML project",
386
+ "projectInfo.typeContent": "Content/Marketing site",
387
+ "projectInfo.typeAdmin": "Internal tool / Admin",
388
+ "projectInfo.typeLibrary": "Library / SDK",
389
+ // ─── prompts/tech-stack.ts ───
390
+ "techStack.phase": "Phase 2: Tech stack & structure",
391
+ "techStack.detectedTech": "Detected: {techs}",
392
+ "techStack.frontendMsg": "Frontend stack?",
393
+ "techStack.frontendNone": "None (backend only)",
394
+ "techStack.backendMsg": "Backend / Infra? (multiple selection)",
395
+ "techStack.deployMsg": "Deployment?",
396
+ "techStack.deployDocker": "Docker self-hosted",
397
+ "techStack.deployUndecided": "Undecided",
398
+ "techStack.detectedDirs": "Detected directories:\n{dirs}",
399
+ "techStack.useDetected": "Use this structure as-is?",
400
+ "techStack.customDirsMsg": "Directory structure (comma-separated, e.g. src/:source,docs/:docs)",
401
+ "techStack.customDirsPlaceholder": "src/:source code, docs/:docs, tests/:tests",
402
+ "techStack.mainDirsMsg": "Main directory structure (comma-separated, e.g. src/:source,docs/:docs)",
403
+ // ─── prompts/context-files.ts ───
404
+ "contextFiles.phase": "Phase 3: Existing context files",
405
+ "contextFiles.hasClaudeMdMsg": "Do you have a CLAUDE.md or project guide file?",
406
+ "contextFiles.hasClaudeMdYes": "Yes \u2192 enter path",
407
+ "contextFiles.hasClaudeMdNo": "No \u2192 collect via questions",
408
+ "contextFiles.claudeMdPathMsg": "CLAUDE.md path?",
409
+ "contextFiles.fileNotFound": "File not found: {path}",
410
+ "contextFiles.summaryStack": "Stack: {value}",
411
+ "contextFiles.summaryBackend": "Backend: {value}",
412
+ "contextFiles.summaryNaming": "Naming: {value}",
413
+ "contextFiles.summaryTools": "Tools: {value}",
414
+ "contextFiles.summaryFonts": "Fonts: {value}",
415
+ "contextFiles.parseSuccess": "File analysis complete:\n {summary}\n \u2192 Will be auto-applied to agent prompts.",
416
+ "contextFiles.parseEmpty": "File was read but no auto-parsable items found. Proceeding with manual questions.",
417
+ "contextFiles.parseError": "Error parsing file. Switching to manual questions.",
418
+ "contextFiles.codingStyleMsg": "Coding style preferences? (multiple selection)",
419
+ "contextFiles.concernsMsg": "Concerns? (multiple selection)",
420
+ "contextFiles.refDocsMsg": "Any reference docs? (multiple selection)",
421
+ "contextFiles.docPathMsg": "{type} file path?",
422
+ "contextFiles.docPathValidation": "Please enter a path",
423
+ // coding style options
424
+ "contextFiles.styleFunctional": "Functional components only (no classes)",
425
+ "contextFiles.styleNamedExport": "Prefer named exports",
426
+ "contextFiles.styleNoAny": "No 'any' type (prefer unknown)",
427
+ "contextFiles.styleKoComment": "Korean comments / Korean commits",
428
+ "contextFiles.styleEnComment": "English comments / English commits",
429
+ "contextFiles.styleJsdoc": "JSDoc comments",
430
+ "contextFiles.styleEslint": "ESLint + Prettier enabled",
431
+ "contextFiles.styleDefault": "Default (no preference)",
432
+ // concern options
433
+ "contextFiles.concernI18n": "i18n (internationalization)",
434
+ "contextFiles.concernDarkMode": "Dark mode",
435
+ "contextFiles.concernA11y": "Accessibility (a11y)",
436
+ "contextFiles.concernSeo": "SEO optimization",
437
+ "contextFiles.concernPerformance": "Performance (Core Web Vitals)",
438
+ "contextFiles.concernSecurity": "Security (Auth/XSS/CSRF)",
439
+ "contextFiles.concernResponsive": "Mobile responsive required",
440
+ "contextFiles.concernNone": "None",
441
+ // reference doc options
442
+ "contextFiles.refApiSpec": "API spec (OpenAPI/Swagger)",
443
+ "contextFiles.refDesignSystem": "Design system docs",
444
+ "contextFiles.refDbSchema": "DB schema / ERD",
445
+ "contextFiles.refWbs": "Existing WBS / Task list",
446
+ "contextFiles.refBrandGuide": "Brand guidelines",
447
+ "contextFiles.refNone": "None",
448
+ // ─── prompts/agents.ts ───
449
+ "agents.phase": "Phase 4: Agent configuration",
450
+ "agents.workTypeMsg": "What work do you mainly do? (multiple selection)",
451
+ "agents.recommended": "Recommended agents based on work types:\n{list}\n \u25FC orchestrator \u2190 always included",
452
+ "agents.customizeMsg": "Customize agents?",
453
+ "agents.selectMsg": "Final agent selection (orchestrator always included)",
454
+ "agents.modelMsg": "Default agent model?",
455
+ // work type options
456
+ "agents.workFrontend": "Frontend development (UI/components)",
457
+ "agents.workBackend": "Backend development (API/DB/server)",
458
+ "agents.workQa": "Testing/QA (unit/E2E/perf)",
459
+ "agents.workDesign": "Design system management",
460
+ "agents.workDevops": "DevOps / CI\xB7CD / Deploy",
461
+ "agents.workResearch": "Research/Analysis",
462
+ "agents.workDocs": "Documentation",
463
+ "agents.workContent": "Content planning",
464
+ "agents.workStrategy": "Strategy/Architecture design",
465
+ "agents.workItems": "Quiz/Item development",
466
+ // agent options
467
+ "agents.agentFrontend": "frontend \u2014 Frontend dev",
468
+ "agents.agentBackend": "backend \u2014 Backend dev",
469
+ "agents.agentQa": "qa \u2014 Testing/Quality",
470
+ "agents.agentDesigner": "designer \u2014 Design system",
471
+ "agents.agentDevops": "devops \u2014 Infra/Deploy",
472
+ "agents.agentResearcher": "researcher \u2014 Research/Analysis",
473
+ "agents.agentStrategist": "strategist \u2014 Architecture/Strategy",
474
+ "agents.agentContentPlanner": "content-planner \u2014 Content planning",
475
+ "agents.agentItemAuthor": "item-author \u2014 Item authoring",
476
+ "agents.agentDocWriter": "doc-writer \u2014 Documentation",
477
+ // model options
478
+ "agents.modelSonnet": "sonnet (most) + opus (orchestrator/strategist auto)",
479
+ "agents.modelOpus": "All opus (high quality, higher cost)",
480
+ "agents.modelSonnetOnly": "All sonnet (balanced)",
481
+ // ─── prompts/orchestrator.ts ───
482
+ "orchestrator.phase": "Phase 5: Orchestrator context",
483
+ "orchestrator.goalsMsg": "What project goals should the {name} orchestrator know?",
484
+ "orchestrator.goalsPlaceholder": "e.g. Launch April 2026, payment integration required, mobile responsive",
485
+ "orchestrator.goalsValidation": "Please enter goals",
486
+ "orchestrator.stageMsg": "Current project stage?",
487
+ "orchestrator.constraintsMsg": "Priorities or constraints? (Enter to skip)",
488
+ "orchestrator.constraintsPlaceholder": "e.g. No .env commits, maintain 80% test coverage",
489
+ // stage options
490
+ "orchestrator.stageIdea": "Idea/Planning stage",
491
+ "orchestrator.stageDevPreMvp": "Development in progress (pre-MVP)",
492
+ "orchestrator.stageMvpDone": "MVP done, improving",
493
+ "orchestrator.stageProduction": "In production (maintenance/features)",
494
+ "orchestrator.stageRefactor": "Refactoring/Migration",
495
+ // ─── prompts/multi-project.ts ───
496
+ "multiProject.phase": "Phase 6: Multi-project (optional)",
497
+ "multiProject.addMoreMsg": "Add more projects?",
498
+ "multiProject.addMoreNo": "Just one for now",
499
+ "multiProject.addMoreYes": "Add more",
500
+ "multiProject.nameMsg": "Additional project name?",
501
+ "multiProject.namePlaceholder": "Project name",
502
+ "multiProject.nameValidation": "Please enter a name",
503
+ "multiProject.descMsg": "One-line description?",
504
+ "multiProject.descPlaceholder": "Project description",
505
+ "multiProject.colorMsg": "Tag color?",
506
+ "multiProject.agentMsg": "Agent configuration?",
507
+ "multiProject.agentShared": "Share agents with main project",
508
+ "multiProject.agentSeparate": "Separate agents for this project",
509
+ "multiProject.anotherMsg": "Add another project?",
510
+ // color labels
511
+ "multiProject.colorBlue": "Blue",
512
+ "multiProject.colorGreen": "Green",
513
+ "multiProject.colorOrange": "Orange",
514
+ "multiProject.colorPurple": "Purple",
515
+ "multiProject.colorRed": "Red",
516
+ "multiProject.colorPink": "Pink",
517
+ "multiProject.colorTeal": "Teal",
518
+ // ─── prompts/infra.ts ───
519
+ "infra.phase": "Phase 7: Infrastructure",
520
+ "infra.slackMsg": "Slack integration?",
521
+ "infra.slackYes": "Enable (Bot Token + Socket Mode)",
522
+ "infra.slackNo": "Set up later",
523
+ "infra.slackCommandMsg": "Slack command name?",
524
+ "infra.portMsg": "Kanban server port?",
525
+ "infra.portValidation": "Enter a valid port number (1-65535)",
526
+ "infra.targetDirMsg": "Where to generate files?",
527
+ "infra.targetDirPlaceholder": "(current directory)",
528
+ // ─── generators/env-file.ts ───
529
+ "envGen.kanbanServer": "# Kanban server",
530
+ "envGen.slackIntegration": "# Slack integration",
531
+ "envGen.slackLater": "# Slack integration (set up later)",
532
+ // ─── generators/project-context.ts ───
533
+ // frontend labels
534
+ "contextGen.frontendNone": "(None)",
535
+ // deploy labels
536
+ "contextGen.deployDocker": "Docker self-hosted",
537
+ "contextGen.deployUndecided": "Undecided",
538
+ // stage labels
539
+ "contextGen.stageIdea": "Idea/Planning stage",
540
+ "contextGen.stageDevPreMvp": "Development in progress (pre-MVP)",
541
+ "contextGen.stageMvpDone": "MVP done, improving",
542
+ "contextGen.stageProduction": "In production (maintenance/features)",
543
+ "contextGen.stageRefactor": "Refactoring/Migration",
544
+ // project type labels
545
+ "contextGen.typeWebApp": "Web application",
546
+ "contextGen.typeMobile": "Mobile app",
547
+ "contextGen.typeApi": "API server",
548
+ "contextGen.typeDataPipeline": "Data pipeline",
549
+ "contextGen.typeAiMl": "AI/ML",
550
+ "contextGen.typeContent": "Content/Marketing",
551
+ "contextGen.typeAdmin": "Internal tool",
552
+ "contextGen.typeLibrary": "Library/SDK",
553
+ // coding style labels
554
+ "contextGen.styleFunctional": "Functional components only (no classes)",
555
+ "contextGen.styleNamedExport": "Prefer named exports",
556
+ "contextGen.styleNoAny": "No 'any' type (prefer unknown)",
557
+ "contextGen.styleKoComment": "Korean comments/commits",
558
+ "contextGen.styleEnComment": "English comments/commits",
559
+ "contextGen.styleJsdoc": "JSDoc comments",
560
+ "contextGen.styleEslint": "ESLint + Prettier enabled",
561
+ "contextGen.styleDefault": "Default",
562
+ // concern labels
563
+ "contextGen.concernI18n": "i18n",
564
+ "contextGen.concernDarkMode": "Dark mode",
565
+ "contextGen.concernA11y": "Accessibility (a11y)",
566
+ "contextGen.concernSeo": "SEO optimization",
567
+ "contextGen.concernPerformance": "Performance (Core Web Vitals)",
568
+ "contextGen.concernSecurity": "Security (Auth/XSS/CSRF)",
569
+ "contextGen.concernResponsive": "Mobile responsive required",
570
+ "contextGen.concernNone": "None",
571
+ // generated document sections
572
+ "contextGen.title": "{name} \u2014 Project Context",
573
+ "contextGen.intro": "This document contains shared project information for all agents.\nEach agent performs its role with this context in mind.",
574
+ "contextGen.sectionOverview": "Project Overview",
575
+ "contextGen.labelType": "Type",
576
+ "contextGen.labelStage": "Stage",
577
+ "contextGen.sectionStack": "Tech Stack",
578
+ "contextGen.labelFrontend": "Frontend",
579
+ "contextGen.backendFallback": "(enter manually)",
580
+ "contextGen.labelDeploy": "Deploy",
581
+ "contextGen.sectionDirs": "Directory Structure",
582
+ "contextGen.defaultDirSrc": "Source code",
583
+ "contextGen.defaultDirDocs": "Docs",
584
+ "contextGen.defaultDirTools": "Dev tools",
585
+ "contextGen.sectionConventions": "Coding Conventions",
586
+ "contextGen.noConventionsClaudeMd": "(No conventions auto-extracted from CLAUDE.md)",
587
+ "contextGen.noConventionsManual": "(Customize for your project)",
588
+ "contextGen.sectionBrand": "Brand/Design",
589
+ "contextGen.labelFonts": "Fonts",
590
+ "contextGen.labelColors": "Colors",
591
+ "contextGen.labelI18n": "i18n",
592
+ "contextGen.sectionGoals": "Project Goals",
593
+ "contextGen.goalsPlaceholder": "(Enter your goals)",
594
+ "contextGen.sectionConstraints": "Constraints",
595
+ "contextGen.constraintsPlaceholder": "(No constraints)",
596
+ "contextGen.sectionRefDocs": "Reference Docs",
597
+ "contextGen.noRefDocs": "(None)",
598
+ "contextGen.sectionProtocol": "Work Protocol",
599
+ "contextGen.protocolKanban": "Kanban server",
600
+ "contextGen.protocolSlack": "Slack reporting",
601
+ "contextGen.protocolLogs": "Log directory",
602
+ "contextGen.protocolStatus": "Status flow",
603
+ "contextGen.protocolInstruction": "All agents must log to these 3 locations on task start/completion:",
604
+ "contextGen.protocolSlackReport": "Slack report",
605
+ "contextGen.protocolKanbanUpdate": "Kanban update",
606
+ "contextGen.protocolLogFile": "Log file",
607
+ "contextGen.protocolSlackExample": "message",
608
+ // ─── generators/agent-prompt.ts (base sections only) ───
609
+ "agentGen.projectLabel": "Project",
610
+ "agentGen.descLabel": "Description",
611
+ "agentGen.kanbanApiLabel": "Kanban API",
612
+ "agentGen.slackApiLabel": "Slack API",
613
+ "agentGen.logDirLabel": "Log directory",
614
+ "agentGen.slackReportingDesc": "Report to Slack on task start/completion (auto-threaded per task):",
615
+ "agentGen.slackForbid": "Do not use `$SLACK_AGENT_WEBHOOK` directly. Always report via the API above.",
616
+ "agentGen.slackTaskIdNote": "`{TASK_ID}` is injected with the actual ID by buildExecutorPrompt.",
617
+ "agentGen.kanbanStart": "Start",
618
+ "agentGen.kanbanDone": "Done",
619
+ "agentGen.kanbanActiveForm": "Active description",
620
+ "agentGen.kanbanReportFormat": "One-line summary. Follow-up: suggest next task",
621
+ "agentGen.reportDesc": "Write a report after completion:",
622
+ "agentGen.reportPathLabel": "Path",
623
+ "agentGen.reportContentDesc": "Content: changed files, changes, verification results, follow-up tasks",
624
+ "agentGen.fontsLabel": "Fonts",
625
+ "agentGen.colorsLabel": "Colors",
626
+ // ─── utils/detect-structure.ts ───
627
+ "detect.src": "Source code",
628
+ "detect.app": "App source (Next.js/Remix)",
629
+ "detect.pages": "Pages (Next.js)",
630
+ "detect.components": "Components",
631
+ "detect.lib": "Library/Utils",
632
+ "detect.api": "API routes",
633
+ "detect.server": "Server code",
634
+ "detect.supabase": "Supabase (Edge Functions/Migrations)",
635
+ "detect.firebase": "Firebase",
636
+ "detect.prisma": "Prisma schema",
637
+ "detect.docs": "Docs",
638
+ "detect.tests": "Tests",
639
+ "detect.e2e": "E2E tests",
640
+ "detect.cypress": "Cypress tests",
641
+ "detect.public": "Static files",
642
+ "detect.static": "Static files",
643
+ "detect.assets": "Assets",
644
+ "detect.styles": "Styles",
645
+ "detect.scripts": "Scripts",
646
+ "detect.tools": "Dev tools",
647
+ "detect.github": "GitHub Actions"
648
+ }
649
+ };
650
+
651
+ // src/prompts/project-info.ts
652
+ function getProjectTypeOptions() {
653
+ return [
654
+ { value: "web-app", label: t("projectInfo.typeWebApp") },
655
+ { value: "mobile", label: t("projectInfo.typeMobile") },
656
+ { value: "api", label: t("projectInfo.typeApi") },
657
+ { value: "data-pipeline", label: t("projectInfo.typeDataPipeline") },
658
+ { value: "ai-ml", label: t("projectInfo.typeAiMl") },
659
+ { value: "content", label: t("projectInfo.typeContent") },
660
+ { value: "admin", label: t("projectInfo.typeAdmin") },
661
+ { value: "library", label: t("projectInfo.typeLibrary") }
662
+ ];
663
+ }
19
664
  async function promptProjectInfo() {
20
- p.log.step("Phase 1: \uD504\uB85C\uC81D\uD2B8 \uAE30\uBCF8 \uC815\uBCF4");
665
+ p.log.step(t("projectInfo.phase"));
21
666
  const name = await p.text({
22
- message: "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984?",
667
+ message: t("projectInfo.nameMsg"),
23
668
  placeholder: "MyProject",
24
- validate: (v) => v.trim() ? void 0 : "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694"
669
+ validate: (v) => v.trim() ? void 0 : t("projectInfo.nameValidation")
25
670
  });
26
671
  if (p.isCancel(name)) return null;
27
672
  const description = await p.text({
28
- message: "\uD55C \uC904 \uC124\uBA85?",
29
- placeholder: "\uD504\uB85C\uC81D\uD2B8 \uAC04\uB2E8 \uC124\uBA85",
30
- validate: (v) => v.trim() ? void 0 : "\uC124\uBA85\uC744 \uC785\uB825\uD558\uC138\uC694"
673
+ message: t("projectInfo.descMsg"),
674
+ placeholder: t("projectInfo.descPlaceholder"),
675
+ validate: (v) => v.trim() ? void 0 : t("projectInfo.descValidation")
31
676
  });
32
677
  if (p.isCancel(description)) return null;
33
678
  const types = await p.multiselect({
34
- message: "\uD504\uB85C\uC81D\uD2B8 \uC131\uACA9? (\uBCF5\uC218 \uC120\uD0DD \uAC00\uB2A5)",
35
- options: [...PROJECT_TYPE_OPTIONS],
679
+ message: t("projectInfo.typesMsg"),
680
+ options: getProjectTypeOptions(),
36
681
  required: true
37
682
  });
38
683
  if (p.isCancel(types)) return null;
@@ -49,33 +694,35 @@ import * as p2 from "@clack/prompts";
49
694
  // src/utils/detect-structure.ts
50
695
  import fs from "fs-extra";
51
696
  import path from "path";
52
- var DIR_CHECKS = [
53
- ["src", "\uC18C\uC2A4 \uCF54\uB4DC"],
54
- ["app", "\uC571 \uC18C\uC2A4 (Next.js/Remix)"],
55
- ["pages", "\uD398\uC774\uC9C0 (Next.js)"],
56
- ["components", "\uCEF4\uD3EC\uB10C\uD2B8"],
57
- ["lib", "\uB77C\uC774\uBE0C\uB7EC\uB9AC/\uC720\uD2F8"],
58
- ["api", "API \uB77C\uC6B0\uD2B8"],
59
- ["server", "\uC11C\uBC84 \uCF54\uB4DC"],
60
- ["supabase", "Supabase (Edge Functions/\uB9C8\uC774\uADF8\uB808\uC774\uC158)"],
61
- ["firebase", "Firebase"],
62
- ["prisma", "Prisma \uC2A4\uD0A4\uB9C8"],
63
- ["docs", "\uBB38\uC11C"],
64
- ["tests", "\uD14C\uC2A4\uD2B8"],
65
- ["__tests__", "\uD14C\uC2A4\uD2B8"],
66
- ["e2e", "E2E \uD14C\uC2A4\uD2B8"],
67
- ["cypress", "Cypress \uD14C\uC2A4\uD2B8"],
68
- ["public", "\uC815\uC801 \uD30C\uC77C"],
69
- ["static", "\uC815\uC801 \uD30C\uC77C"],
70
- ["assets", "\uC5D0\uC14B"],
71
- ["styles", "\uC2A4\uD0C0\uC77C"],
72
- ["scripts", "\uC2A4\uD06C\uB9BD\uD2B8"],
73
- ["tools", "\uAC1C\uBC1C \uB3C4\uAD6C"],
74
- [".github", "GitHub Actions"]
75
- ];
697
+ function getDirChecks() {
698
+ return [
699
+ ["src", t("detect.src")],
700
+ ["app", t("detect.app")],
701
+ ["pages", t("detect.pages")],
702
+ ["components", t("detect.components")],
703
+ ["lib", t("detect.lib")],
704
+ ["api", t("detect.api")],
705
+ ["server", t("detect.server")],
706
+ ["supabase", t("detect.supabase")],
707
+ ["firebase", t("detect.firebase")],
708
+ ["prisma", t("detect.prisma")],
709
+ ["docs", t("detect.docs")],
710
+ ["tests", t("detect.tests")],
711
+ ["__tests__", t("detect.tests")],
712
+ ["e2e", t("detect.e2e")],
713
+ ["cypress", t("detect.cypress")],
714
+ ["public", t("detect.public")],
715
+ ["static", t("detect.static")],
716
+ ["assets", t("detect.assets")],
717
+ ["styles", t("detect.styles")],
718
+ ["scripts", t("detect.scripts")],
719
+ ["tools", t("detect.tools")],
720
+ [".github", t("detect.github")]
721
+ ];
722
+ }
76
723
  function detectStructure(targetDir) {
77
724
  const dirs = [];
78
- for (const [dirPath, desc] of DIR_CHECKS) {
725
+ for (const [dirPath, desc] of getDirChecks()) {
79
726
  const full = path.join(targetDir, dirPath);
80
727
  if (fs.existsSync(full) && fs.statSync(full).isDirectory()) {
81
728
  dirs.push({ path: `${dirPath}/`, description: desc });
@@ -98,39 +745,45 @@ function detectProjectSignals(targetDir) {
98
745
  }
99
746
 
100
747
  // src/prompts/tech-stack.ts
101
- var FRONTEND_OPTIONS = [
102
- { value: "react-ts", label: "React + TypeScript" },
103
- { value: "nextjs", label: "Next.js" },
104
- { value: "vue-nuxt", label: "Vue / Nuxt" },
105
- { value: "svelte", label: "Svelte / SvelteKit" },
106
- { value: "angular", label: "Angular" },
107
- { value: "none", label: "\uC5C6\uC74C (\uBC31\uC5D4\uB4DC only)" }
108
- ];
109
- var BACKEND_OPTIONS = [
110
- { value: "supabase", label: "Supabase" },
111
- { value: "firebase", label: "Firebase" },
112
- { value: "node", label: "Node.js (Express/Fastify)" },
113
- { value: "python", label: "Python (FastAPI/Django)" },
114
- { value: "go", label: "Go" },
115
- { value: "postgresql", label: "PostgreSQL" },
116
- { value: "mysql", label: "MySQL" },
117
- { value: "mongodb", label: "MongoDB" },
118
- { value: "redis", label: "Redis" },
119
- { value: "aws", label: "AWS" },
120
- { value: "gcp", label: "GCP" },
121
- { value: "azure", label: "Azure" },
122
- { value: "docker", label: "Docker / K8s" }
123
- ];
124
- var DEPLOY_OPTIONS = [
125
- { value: "vercel", label: "Vercel" },
126
- { value: "netlify", label: "Netlify" },
127
- { value: "aws", label: "AWS (EC2/ECS/Lambda)" },
128
- { value: "gcp", label: "GCP (Cloud Run/App Engine)" },
129
- { value: "docker", label: "Docker \uC790\uCCB4 \uC11C\uBC84" },
130
- { value: "undecided", label: "\uC544\uC9C1 \uBBF8\uC815" }
131
- ];
748
+ function getFrontendOptions() {
749
+ return [
750
+ { value: "react-ts", label: "React + TypeScript" },
751
+ { value: "nextjs", label: "Next.js" },
752
+ { value: "vue-nuxt", label: "Vue / Nuxt" },
753
+ { value: "svelte", label: "Svelte / SvelteKit" },
754
+ { value: "angular", label: "Angular" },
755
+ { value: "none", label: t("techStack.frontendNone") }
756
+ ];
757
+ }
758
+ function getBackendOptions() {
759
+ return [
760
+ { value: "supabase", label: "Supabase" },
761
+ { value: "firebase", label: "Firebase" },
762
+ { value: "node", label: "Node.js (Express/Fastify)" },
763
+ { value: "python", label: "Python (FastAPI/Django)" },
764
+ { value: "go", label: "Go" },
765
+ { value: "postgresql", label: "PostgreSQL" },
766
+ { value: "mysql", label: "MySQL" },
767
+ { value: "mongodb", label: "MongoDB" },
768
+ { value: "redis", label: "Redis" },
769
+ { value: "aws", label: "AWS" },
770
+ { value: "gcp", label: "GCP" },
771
+ { value: "azure", label: "Azure" },
772
+ { value: "docker", label: "Docker / K8s" }
773
+ ];
774
+ }
775
+ function getDeployOptions() {
776
+ return [
777
+ { value: "vercel", label: "Vercel" },
778
+ { value: "netlify", label: "Netlify" },
779
+ { value: "aws", label: "AWS (EC2/ECS/Lambda)" },
780
+ { value: "gcp", label: "GCP (Cloud Run/App Engine)" },
781
+ { value: "docker", label: t("techStack.deployDocker") },
782
+ { value: "undecided", label: t("techStack.deployUndecided") }
783
+ ];
784
+ }
132
785
  async function promptTechStack(targetDir) {
133
- p2.log.step("Phase 2: \uAE30\uC220 \uC2A4\uD0DD & \uAD6C\uC870");
786
+ p2.log.step(t("techStack.phase"));
134
787
  const signals = detectProjectSignals(targetDir);
135
788
  const hints = [];
136
789
  if (signals.hasTypeScript) hints.push("TypeScript");
@@ -141,17 +794,17 @@ async function promptTechStack(targetDir) {
141
794
  if (signals.hasDocker) hints.push("Docker");
142
795
  if (signals.hasVercel) hints.push("Vercel");
143
796
  if (hints.length > 0) {
144
- p2.log.info(`\uAC10\uC9C0\uB41C \uAE30\uC220: ${hints.join(", ")}`);
797
+ p2.log.info(t("techStack.detectedTech", { techs: hints.join(", ") }));
145
798
  }
146
799
  const frontend = await p2.select({
147
- message: "\uD504\uB860\uD2B8\uC5D4\uB4DC \uC2A4\uD0DD?",
148
- options: [...FRONTEND_OPTIONS],
800
+ message: t("techStack.frontendMsg"),
801
+ options: getFrontendOptions(),
149
802
  initialValue: signals.hasNextConfig ? "nextjs" : signals.hasPackageJson ? "react-ts" : "none"
150
803
  });
151
804
  if (p2.isCancel(frontend)) return null;
152
805
  const backend = await p2.multiselect({
153
- message: "\uBC31\uC5D4\uB4DC / \uC778\uD504\uB77C? (\uBCF5\uC218 \uC120\uD0DD)",
154
- options: [...BACKEND_OPTIONS],
806
+ message: t("techStack.backendMsg"),
807
+ options: getBackendOptions(),
155
808
  required: false,
156
809
  initialValues: [
157
810
  ...signals.hasSupabase ? ["supabase"] : [],
@@ -160,8 +813,8 @@ async function promptTechStack(targetDir) {
160
813
  });
161
814
  if (p2.isCancel(backend)) return null;
162
815
  const deploy = await p2.select({
163
- message: "\uBC30\uD3EC \uD658\uACBD?",
164
- options: [...DEPLOY_OPTIONS],
816
+ message: t("techStack.deployMsg"),
817
+ options: getDeployOptions(),
165
818
  initialValue: signals.hasVercel ? "vercel" : "undecided"
166
819
  });
167
820
  if (p2.isCancel(deploy)) return null;
@@ -169,26 +822,25 @@ async function promptTechStack(targetDir) {
169
822
  let directories = detected;
170
823
  if (detected.length > 0) {
171
824
  const dirList = detected.map((d) => ` ${d.path.padEnd(18)} \u2190 ${d.description}`).join("\n");
172
- p2.log.info(`\uAC10\uC9C0\uB41C \uB514\uB809\uD1A0\uB9AC:
173
- ${dirList}`);
825
+ p2.log.info(t("techStack.detectedDirs", { dirs: dirList }));
174
826
  const useDetected = await p2.confirm({
175
- message: "\uC774 \uAD6C\uC870\uB97C \uADF8\uB300\uB85C \uC0AC\uC6A9\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
827
+ message: t("techStack.useDetected"),
176
828
  initialValue: true
177
829
  });
178
830
  if (p2.isCancel(useDetected)) return null;
179
831
  if (!useDetected) {
180
832
  const customDirs = await p2.text({
181
- message: "\uB514\uB809\uD1A0\uB9AC \uAD6C\uC870 (\uC27C\uD45C \uAD6C\uBD84, \uC608: src/:\uC18C\uC2A4,docs/:\uBB38\uC11C)",
182
- placeholder: "src/:\uC18C\uC2A4 \uCF54\uB4DC, docs/:\uBB38\uC11C, tests/:\uD14C\uC2A4\uD2B8"
833
+ message: t("techStack.customDirsMsg"),
834
+ placeholder: t("techStack.customDirsPlaceholder")
183
835
  });
184
836
  if (p2.isCancel(customDirs)) return null;
185
837
  directories = parseDirectoryInput(customDirs);
186
838
  }
187
839
  } else {
188
840
  const customDirs = await p2.text({
189
- message: "\uC8FC\uC694 \uB514\uB809\uD1A0\uB9AC \uAD6C\uC870 (\uC27C\uD45C \uAD6C\uBD84, \uC608: src/:\uC18C\uC2A4,docs/:\uBB38\uC11C)",
190
- placeholder: "src/:\uC18C\uC2A4 \uCF54\uB4DC, docs/:\uBB38\uC11C, tests/:\uD14C\uC2A4\uD2B8",
191
- initialValue: "src/:\uC18C\uC2A4 \uCF54\uB4DC, docs/:\uBB38\uC11C, tests/:\uD14C\uC2A4\uD2B8"
841
+ message: t("techStack.mainDirsMsg"),
842
+ placeholder: t("techStack.customDirsPlaceholder"),
843
+ initialValue: t("techStack.customDirsPlaceholder")
192
844
  });
193
845
  if (p2.isCancel(customDirs)) return null;
194
846
  directories = parseDirectoryInput(customDirs);
@@ -234,22 +886,22 @@ function parseClaudeMd(filePath) {
234
886
  if (matchAny(h, ["\uC2A4\uD0DD", "stack", "\uAE30\uC220", "tech"])) {
235
887
  parseStack(content, ctx);
236
888
  }
237
- if (matchAny(h, ["\uCEE8\uBCA4\uC158", "convention", "\uADDC\uCE59", "rule", "\uC2A4\uD0C0\uC77C", "style guide", "\uCF54\uB529"])) {
889
+ if (matchAny(h, ["\uCEE8\uBCA4\uC158", "convention", "\uADDC\uCE59", "rule", "rules", "\uC2A4\uD0C0\uC77C", "style guide", "\uCF54\uB529", "coding"])) {
238
890
  parseConventions(content, ctx);
239
891
  }
240
- if (matchAny(h, ["\uB514\uB809\uD1A0\uB9AC", "directory", "\uAD6C\uC870", "structure", "\uACBD\uB85C"])) {
892
+ if (matchAny(h, ["\uB514\uB809\uD1A0\uB9AC", "directory", "\uAD6C\uC870", "structure", "\uACBD\uB85C", "path", "paths"])) {
241
893
  parsePaths(content, ctx);
242
894
  }
243
- if (matchAny(h, ["\uBCF4\uC548", "security", "\uC8FC\uC758", "caution", "\uAE08\uC9C0"])) {
895
+ if (matchAny(h, ["\uBCF4\uC548", "security", "\uC8FC\uC758", "caution", "\uAE08\uC9C0", "forbidden", "restriction"])) {
244
896
  ctx.security.push(...extractListItems(content));
245
897
  }
246
- if (matchAny(h, ["\uD3F0\uD2B8", "font", "\uD0C0\uC774\uD3EC"])) {
898
+ if (matchAny(h, ["\uD3F0\uD2B8", "font", "\uD0C0\uC774\uD3EC", "typography", "typeface"])) {
247
899
  ctx.fonts.push(...extractListItems(content));
248
900
  }
249
- if (matchAny(h, ["\uC0C9\uC0C1", "color", "palette", "\uBE0C\uB79C\uB4DC"])) {
901
+ if (matchAny(h, ["\uC0C9\uC0C1", "color", "palette", "\uBE0C\uB79C\uB4DC", "brand", "theme"])) {
250
902
  extractColors(content, ctx);
251
903
  }
252
- if (matchAny(h, ["i18n", "\uAD6D\uC81C\uD654", "\uB2E4\uAD6D\uC5B4", "locale"])) {
904
+ if (matchAny(h, ["i18n", "\uAD6D\uC81C\uD654", "\uB2E4\uAD6D\uC5B4", "locale", "internationalization", "localization"])) {
253
905
  ctx.i18n.push(...extractListItems(content));
254
906
  }
255
907
  }
@@ -300,8 +952,8 @@ function parseStack(content, ctx) {
300
952
  const key = tableMatch[1].toLowerCase();
301
953
  const val = tableMatch[2].trim();
302
954
  if (key.includes("\uD504\uB860\uD2B8") || key.includes("front")) ctx.stack.frontend = val;
303
- if (key.includes("\uBC31\uC5D4\uB4DC") || key.includes("back") || key.includes("\uC11C\uBC84")) ctx.stack.backend = val;
304
- if (key.includes("\uBC30\uD3EC") || key.includes("deploy") || key.includes("\uD638\uC2A4\uD305")) ctx.stack.deploy = val;
955
+ if (key.includes("\uBC31\uC5D4\uB4DC") || key.includes("back") || key.includes("\uC11C\uBC84") || key.includes("server")) ctx.stack.backend = val;
956
+ if (key.includes("\uBC30\uD3EC") || key.includes("deploy") || key.includes("\uD638\uC2A4\uD305") || key.includes("hosting")) ctx.stack.deploy = val;
305
957
  }
306
958
  }
307
959
  for (const item of items) {
@@ -321,7 +973,7 @@ function parseConventions(content, ctx) {
321
973
  const items = extractListItems(content);
322
974
  for (const item of items) {
323
975
  const lower = item.toLowerCase();
324
- if (lower.includes("case") || lower.includes("naming") || lower.includes("\uB124\uC774\uBC0D") || lower.includes("\uD30C\uC77C\uBA85")) {
976
+ if (lower.includes("case") || lower.includes("naming") || lower.includes("\uB124\uC774\uBC0D") || lower.includes("\uD30C\uC77C\uBA85") || lower.includes("filename")) {
325
977
  ctx.conventions.naming.push(item);
326
978
  } else if (lower.includes("lint") || lower.includes("prettier") || lower.includes("eslint") || lower.includes("vitest") || lower.includes("jest") || lower.includes("playwright")) {
327
979
  ctx.conventions.tools.push(item);
@@ -364,56 +1016,62 @@ function extractColors(text7, ctx) {
364
1016
  }
365
1017
 
366
1018
  // src/prompts/context-files.ts
367
- var CODING_STYLE_OPTIONS = [
368
- { value: "functional-only", label: "\uD568\uC218\uD615 \uCEF4\uD3EC\uB10C\uD2B8 only (\uD074\uB798\uC2A4 \uAE08\uC9C0)" },
369
- { value: "named-export", label: "Named export \uC120\uD638" },
370
- { value: "no-any", label: "any \uD0C0\uC785 \uAE08\uC9C0 (unknown \uC120\uD638)" },
371
- { value: "ko-comment", label: "\uD55C\uAD6D\uC5B4 \uC8FC\uC11D / \uD55C\uAD6D\uC5B4 \uCEE4\uBC0B" },
372
- { value: "en-comment", label: "\uC601\uBB38 \uC8FC\uC11D / \uC601\uBB38 \uCEE4\uBC0B" },
373
- { value: "jsdoc", label: "JSDoc \uC8FC\uC11D" },
374
- { value: "eslint-prettier", label: "ESLint + Prettier \uC801\uC6A9" },
375
- { value: "default", label: "\uAE30\uBCF8\uAC12 \uC0AC\uC6A9 (\uBCC4\uB3C4 \uC120\uD638 \uC5C6\uC74C)" }
376
- ];
377
- var CONCERN_OPTIONS = [
378
- { value: "i18n", label: "\uB2E4\uAD6D\uC5B4 \uC9C0\uC6D0 (i18n)" },
379
- { value: "dark-mode", label: "\uB2E4\uD06C\uBAA8\uB4DC" },
380
- { value: "a11y", label: "\uC811\uADFC\uC131 (a11y)" },
381
- { value: "seo", label: "SEO \uCD5C\uC801\uD654" },
382
- { value: "performance", label: "\uC131\uB2A5 \uCD5C\uC801\uD654 (Core Web Vitals)" },
383
- { value: "security", label: "\uBCF4\uC548 (\uC778\uC99D/\uAD8C\uD55C/XSS/CSRF)" },
384
- { value: "responsive", label: "\uBAA8\uBC14\uC77C \uBC18\uC751\uD615 \uD544\uC218" },
385
- { value: "none", label: "\uC5C6\uC74C" }
386
- ];
387
- var REFERENCE_DOC_OPTIONS = [
388
- { value: "api-spec", label: "API \uBA85\uC138 (OpenAPI/Swagger)" },
389
- { value: "design-system", label: "\uB514\uC790\uC778 \uC2DC\uC2A4\uD15C \uBB38\uC11C" },
390
- { value: "db-schema", label: "DB \uC2A4\uD0A4\uB9C8 / ERD" },
391
- { value: "wbs", label: "\uAE30\uC874 WBS / \uD0DC\uC2A4\uD06C \uBAA9\uB85D" },
392
- { value: "brand-guide", label: "\uBE0C\uB79C\uB4DC \uAC00\uC774\uB4DC\uB77C\uC778" },
393
- { value: "none", label: "\uC5C6\uC74C" }
394
- ];
1019
+ function getCodingStyleOptions() {
1020
+ return [
1021
+ { value: "functional-only", label: t("contextFiles.styleFunctional") },
1022
+ { value: "named-export", label: t("contextFiles.styleNamedExport") },
1023
+ { value: "no-any", label: t("contextFiles.styleNoAny") },
1024
+ { value: "ko-comment", label: t("contextFiles.styleKoComment") },
1025
+ { value: "en-comment", label: t("contextFiles.styleEnComment") },
1026
+ { value: "jsdoc", label: t("contextFiles.styleJsdoc") },
1027
+ { value: "eslint-prettier", label: t("contextFiles.styleEslint") },
1028
+ { value: "default", label: t("contextFiles.styleDefault") }
1029
+ ];
1030
+ }
1031
+ function getConcernOptions() {
1032
+ return [
1033
+ { value: "i18n", label: t("contextFiles.concernI18n") },
1034
+ { value: "dark-mode", label: t("contextFiles.concernDarkMode") },
1035
+ { value: "a11y", label: t("contextFiles.concernA11y") },
1036
+ { value: "seo", label: t("contextFiles.concernSeo") },
1037
+ { value: "performance", label: t("contextFiles.concernPerformance") },
1038
+ { value: "security", label: t("contextFiles.concernSecurity") },
1039
+ { value: "responsive", label: t("contextFiles.concernResponsive") },
1040
+ { value: "none", label: t("contextFiles.concernNone") }
1041
+ ];
1042
+ }
1043
+ function getReferenceDocOptions() {
1044
+ return [
1045
+ { value: "api-spec", label: t("contextFiles.refApiSpec") },
1046
+ { value: "design-system", label: t("contextFiles.refDesignSystem") },
1047
+ { value: "db-schema", label: t("contextFiles.refDbSchema") },
1048
+ { value: "wbs", label: t("contextFiles.refWbs") },
1049
+ { value: "brand-guide", label: t("contextFiles.refBrandGuide") },
1050
+ { value: "none", label: t("contextFiles.refNone") }
1051
+ ];
1052
+ }
395
1053
  async function promptContextFiles(targetDir) {
396
- p3.log.step("Phase 3: \uAE30\uC874 \uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C");
1054
+ p3.log.step(t("contextFiles.phase"));
397
1055
  let claudeMdPath;
398
1056
  let parsedContext;
399
1057
  let codingStyle = [];
400
1058
  let concerns = [];
401
1059
  const hasClaudeMd = await p3.select({
402
- message: "CLAUDE.md \uB610\uB294 \uD504\uB85C\uC81D\uD2B8 \uAC00\uC774\uB4DC \uD30C\uC77C\uC774 \uC788\uB098\uC694?",
1060
+ message: t("contextFiles.hasClaudeMdMsg"),
403
1061
  options: [
404
- { value: "yes", label: "\uC788\uC74C \u2192 \uACBD\uB85C \uC785\uB825" },
405
- { value: "no", label: "\uC5C6\uC74C \u2192 \uCD94\uAC00 \uC9C8\uBB38\uC73C\uB85C \uC218\uC9D1" }
1062
+ { value: "yes", label: t("contextFiles.hasClaudeMdYes") },
1063
+ { value: "no", label: t("contextFiles.hasClaudeMdNo") }
406
1064
  ]
407
1065
  });
408
1066
  if (p3.isCancel(hasClaudeMd)) return null;
409
1067
  if (hasClaudeMd === "yes") {
410
1068
  const mdPath = await p3.text({
411
- message: "CLAUDE.md \uACBD\uB85C?",
1069
+ message: t("contextFiles.claudeMdPathMsg"),
412
1070
  placeholder: "./CLAUDE.md",
413
1071
  initialValue: "./CLAUDE.md",
414
1072
  validate: (v) => {
415
1073
  const resolved = path2.resolve(targetDir, v.trim());
416
- return fs3.existsSync(resolved) ? void 0 : `\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${resolved}`;
1074
+ return fs3.existsSync(resolved) ? void 0 : t("contextFiles.fileNotFound", { path: resolved });
417
1075
  }
418
1076
  });
419
1077
  if (p3.isCancel(mdPath)) return null;
@@ -421,53 +1079,51 @@ async function promptContextFiles(targetDir) {
421
1079
  try {
422
1080
  parsedContext = parseClaudeMd(claudeMdPath);
423
1081
  const summary = [];
424
- if (parsedContext.stack.frontend) summary.push(`\uC2A4\uD0DD: ${parsedContext.stack.frontend}`);
425
- if (parsedContext.stack.backend) summary.push(`\uBC31\uC5D4\uB4DC: ${parsedContext.stack.backend}`);
426
- if (parsedContext.conventions.naming.length) summary.push(`\uB124\uC774\uBC0D: ${parsedContext.conventions.naming.join(", ")}`);
427
- if (parsedContext.conventions.tools.length) summary.push(`\uB3C4\uAD6C: ${parsedContext.conventions.tools.join(", ")}`);
428
- if (parsedContext.fonts.length) summary.push(`\uD3F0\uD2B8: ${parsedContext.fonts.join(", ")}`);
1082
+ if (parsedContext.stack.frontend) summary.push(t("contextFiles.summaryStack", { value: parsedContext.stack.frontend }));
1083
+ if (parsedContext.stack.backend) summary.push(t("contextFiles.summaryBackend", { value: parsedContext.stack.backend }));
1084
+ if (parsedContext.conventions.naming.length) summary.push(t("contextFiles.summaryNaming", { value: parsedContext.conventions.naming.join(", ") }));
1085
+ if (parsedContext.conventions.tools.length) summary.push(t("contextFiles.summaryTools", { value: parsedContext.conventions.tools.join(", ") }));
1086
+ if (parsedContext.fonts.length) summary.push(t("contextFiles.summaryFonts", { value: parsedContext.fonts.join(", ") }));
429
1087
  if (summary.length > 0) {
430
- p3.log.success(`\uD30C\uC77C \uBD84\uC11D \uC644\uB8CC:
431
- ${summary.join("\n ")}
432
- \u2192 \uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8\uC5D0 \uC790\uB3D9 \uBC18\uC601\uB429\uB2C8\uB2E4.`);
1088
+ p3.log.success(t("contextFiles.parseSuccess", { summary: summary.join("\n ") }));
433
1089
  } else {
434
- p3.log.info("\uD30C\uC77C\uC744 \uC77D\uC5C8\uC9C0\uB9CC \uC790\uB3D9 \uD30C\uC2F1\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC5C8\uC2B5\uB2C8\uB2E4. \uC218\uB3D9 \uC9C8\uBB38\uC744 \uC9C4\uD589\uD569\uB2C8\uB2E4.");
1090
+ p3.log.info(t("contextFiles.parseEmpty"));
435
1091
  parsedContext = void 0;
436
1092
  }
437
1093
  } catch {
438
- p3.log.warn("\uD30C\uC77C \uD30C\uC2F1 \uC911 \uC624\uB958 \uBC1C\uC0DD. \uC218\uB3D9 \uC9C8\uBB38\uC73C\uB85C \uC804\uD658\uD569\uB2C8\uB2E4.");
1094
+ p3.log.warn(t("contextFiles.parseError"));
439
1095
  parsedContext = void 0;
440
1096
  }
441
1097
  }
442
1098
  if (!parsedContext) {
443
1099
  const styleResult = await p3.multiselect({
444
- message: "\uCF54\uB529 \uC2A4\uD0C0\uC77C \uC120\uD638? (\uBCF5\uC218 \uC120\uD0DD)",
445
- options: [...CODING_STYLE_OPTIONS],
1100
+ message: t("contextFiles.codingStyleMsg"),
1101
+ options: getCodingStyleOptions(),
446
1102
  required: false
447
1103
  });
448
1104
  if (p3.isCancel(styleResult)) return null;
449
1105
  codingStyle = styleResult;
450
1106
  const concernResult = await p3.multiselect({
451
- message: "\uC8FC\uC758\uD574\uC57C \uD560 \uC0AC\uD56D? (\uBCF5\uC218 \uC120\uD0DD)",
452
- options: [...CONCERN_OPTIONS],
1107
+ message: t("contextFiles.concernsMsg"),
1108
+ options: getConcernOptions(),
453
1109
  required: false
454
1110
  });
455
1111
  if (p3.isCancel(concernResult)) return null;
456
1112
  concerns = concernResult;
457
1113
  }
458
1114
  const refDocTypes = await p3.multiselect({
459
- message: "\uCD94\uAC00 \uCC38\uACE0 \uBB38\uC11C\uAC00 \uC788\uB098\uC694? (\uBCF5\uC218 \uC120\uD0DD)",
460
- options: [...REFERENCE_DOC_OPTIONS],
1115
+ message: t("contextFiles.refDocsMsg"),
1116
+ options: getReferenceDocOptions(),
461
1117
  required: false
462
1118
  });
463
1119
  if (p3.isCancel(refDocTypes)) return null;
464
1120
  const referenceDocs = [];
465
- const selectedTypes = refDocTypes.filter((t) => t !== "none");
1121
+ const selectedTypes = refDocTypes.filter((v) => v !== "none");
466
1122
  for (const docType of selectedTypes) {
467
1123
  const docPath = await p3.text({
468
- message: `${docType} \uD30C\uC77C \uACBD\uB85C?`,
1124
+ message: t("contextFiles.docPathMsg", { type: docType }),
469
1125
  placeholder: `./docs/${docType}`,
470
- validate: (v) => v.trim() ? void 0 : "\uACBD\uB85C\uB97C \uC785\uB825\uD558\uC138\uC694"
1126
+ validate: (v) => v.trim() ? void 0 : t("contextFiles.docPathValidation")
471
1127
  });
472
1128
  if (p3.isCancel(docPath)) return null;
473
1129
  referenceDocs.push({ type: docType, path: docPath.trim() });
@@ -495,40 +1151,46 @@ var WORK_TYPE_TO_AGENTS = {
495
1151
  "strategy": ["strategist"],
496
1152
  "items": ["item-author"]
497
1153
  };
498
- var WORK_TYPE_OPTIONS = [
499
- { value: "frontend", label: "\uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C (UI/\uCEF4\uD3EC\uB10C\uD2B8)" },
500
- { value: "backend", label: "\uBC31\uC5D4\uB4DC \uAC1C\uBC1C (API/DB/\uC11C\uBC84)" },
501
- { value: "qa", label: "\uD14C\uC2A4\uD2B8/QA (\uC720\uB2DB/E2E/\uC131\uB2A5)" },
502
- { value: "design", label: "\uB514\uC790\uC778 \uC2DC\uC2A4\uD15C \uAD00\uB9AC" },
503
- { value: "devops", label: "DevOps / CI\xB7CD / \uBC30\uD3EC" },
504
- { value: "research", label: "\uC870\uC0AC/\uBD84\uC11D/\uB9AC\uC11C\uCE58" },
505
- { value: "docs", label: "\uBB38\uC11C \uC791\uC131" },
506
- { value: "content", label: "\uCF58\uD150\uCE20 \uAE30\uD68D" },
507
- { value: "strategy", label: "\uC804\uB7B5/\uC544\uD0A4\uD14D\uCC98 \uC124\uACC4" },
508
- { value: "items", label: "\uBB38\uD56D/\uD034\uC988 \uAC1C\uBC1C" }
509
- ];
510
- var ALL_AGENT_OPTIONS = [
511
- { value: "frontend", label: "frontend \u2014 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C" },
512
- { value: "backend", label: "backend \u2014 \uBC31\uC5D4\uB4DC \uAC1C\uBC1C" },
513
- { value: "qa", label: "qa \u2014 \uD14C\uC2A4\uD2B8/\uD488\uC9C8" },
514
- { value: "designer", label: "designer \u2014 \uB514\uC790\uC778 \uC2DC\uC2A4\uD15C" },
515
- { value: "devops", label: "devops \u2014 \uC778\uD504\uB77C/\uBC30\uD3EC" },
516
- { value: "researcher", label: "researcher \u2014 \uC870\uC0AC/\uBD84\uC11D" },
517
- { value: "strategist", label: "strategist \u2014 \uC544\uD0A4\uD14D\uCC98/\uC804\uB7B5" },
518
- { value: "content-planner", label: "content-planner \u2014 \uCF58\uD150\uCE20 \uAE30\uD68D" },
519
- { value: "item-author", label: "item-author \u2014 \uBB38\uD56D \uAC1C\uBC1C" },
520
- { value: "doc-writer", label: "doc-writer \u2014 \uBB38\uC11C \uC791\uC131" }
521
- ];
522
- var MODEL_OPTIONS = [
523
- { value: "sonnet", label: "sonnet (\uB300\uBD80\uBD84) + opus (orchestrator/strategist \uC790\uB3D9)" },
524
- { value: "opus", label: "\uC804\uBD80 opus (\uACE0\uD488\uC9C8, \uBE44\uC6A9 \uB192\uC74C)" },
525
- { value: "sonnet-only", label: "\uC804\uBD80 sonnet (\uADE0\uD615)" }
526
- ];
1154
+ function getWorkTypeOptions() {
1155
+ return [
1156
+ { value: "frontend", label: t("agents.workFrontend") },
1157
+ { value: "backend", label: t("agents.workBackend") },
1158
+ { value: "qa", label: t("agents.workQa") },
1159
+ { value: "design", label: t("agents.workDesign") },
1160
+ { value: "devops", label: t("agents.workDevops") },
1161
+ { value: "research", label: t("agents.workResearch") },
1162
+ { value: "docs", label: t("agents.workDocs") },
1163
+ { value: "content", label: t("agents.workContent") },
1164
+ { value: "strategy", label: t("agents.workStrategy") },
1165
+ { value: "items", label: t("agents.workItems") }
1166
+ ];
1167
+ }
1168
+ function getAllAgentOptions() {
1169
+ return [
1170
+ { value: "frontend", label: t("agents.agentFrontend") },
1171
+ { value: "backend", label: t("agents.agentBackend") },
1172
+ { value: "qa", label: t("agents.agentQa") },
1173
+ { value: "designer", label: t("agents.agentDesigner") },
1174
+ { value: "devops", label: t("agents.agentDevops") },
1175
+ { value: "researcher", label: t("agents.agentResearcher") },
1176
+ { value: "strategist", label: t("agents.agentStrategist") },
1177
+ { value: "content-planner", label: t("agents.agentContentPlanner") },
1178
+ { value: "item-author", label: t("agents.agentItemAuthor") },
1179
+ { value: "doc-writer", label: t("agents.agentDocWriter") }
1180
+ ];
1181
+ }
1182
+ function getModelOptions() {
1183
+ return [
1184
+ { value: "sonnet", label: t("agents.modelSonnet") },
1185
+ { value: "opus", label: t("agents.modelOpus") },
1186
+ { value: "sonnet-only", label: t("agents.modelSonnetOnly") }
1187
+ ];
1188
+ }
527
1189
  async function promptAgents() {
528
- p4.log.step("Phase 4: \uC5D0\uC774\uC804\uD2B8 \uAD6C\uC131");
1190
+ p4.log.step(t("agents.phase"));
529
1191
  const workTypes = await p4.multiselect({
530
- message: "\uC5B4\uB5A4 \uC791\uC5C5\uC744 \uC8FC\uB85C \uD558\uC2DC\uB098\uC694? (\uBCF5\uC218 \uC120\uD0DD)",
531
- options: [...WORK_TYPE_OPTIONS],
1192
+ message: t("agents.workTypeMsg"),
1193
+ options: getWorkTypeOptions(),
532
1194
  required: true
533
1195
  });
534
1196
  if (p4.isCancel(workTypes)) return null;
@@ -539,19 +1201,17 @@ async function promptAgents() {
539
1201
  }
540
1202
  const recommendedList = [...recommended];
541
1203
  const recDisplay = recommendedList.map((a) => ` \u25FC ${a}`).join("\n");
542
- p4.log.info(`\uC791\uC5C5 \uC720\uD615 \uAE30\uBC18 \uCD94\uCC9C \uC5D0\uC774\uC804\uD2B8:
543
- ${recDisplay}
544
- \u25FC orchestrator \u2190 \uD56D\uC0C1 \uD3EC\uD568`);
1204
+ p4.log.info(t("agents.recommended", { list: recDisplay }));
545
1205
  const customize = await p4.confirm({
546
- message: "\uC5D0\uC774\uC804\uD2B8\uB97C \uCD94\uAC00/\uC81C\uAC70\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
1206
+ message: t("agents.customizeMsg"),
547
1207
  initialValue: false
548
1208
  });
549
1209
  if (p4.isCancel(customize)) return null;
550
1210
  let selectedAgents;
551
1211
  if (customize) {
552
1212
  const result = await p4.multiselect({
553
- message: "\uCD5C\uC885 \uC5D0\uC774\uC804\uD2B8 \uC120\uD0DD (orchestrator\uB294 \uD56D\uC0C1 \uD3EC\uD568)",
554
- options: [...ALL_AGENT_OPTIONS],
1213
+ message: t("agents.selectMsg"),
1214
+ options: getAllAgentOptions(),
555
1215
  initialValues: recommendedList.filter((a) => a !== "orchestrator"),
556
1216
  required: true
557
1217
  });
@@ -561,8 +1221,8 @@ ${recDisplay}
561
1221
  selectedAgents = recommendedList;
562
1222
  }
563
1223
  const defaultModel = await p4.select({
564
- message: "\uC5D0\uC774\uC804\uD2B8 \uBAA8\uB378 \uAE30\uBCF8\uAC12?",
565
- options: [...MODEL_OPTIONS]
1224
+ message: t("agents.modelMsg"),
1225
+ options: getModelOptions()
566
1226
  });
567
1227
  if (p4.isCancel(defaultModel)) return null;
568
1228
  const modelOverrides = {};
@@ -581,29 +1241,31 @@ ${recDisplay}
581
1241
 
582
1242
  // src/prompts/orchestrator.ts
583
1243
  import * as p5 from "@clack/prompts";
584
- var STAGE_OPTIONS = [
585
- { value: "idea", label: "\uC544\uC774\uB514\uC5B4/\uAE30\uD68D \uB2E8\uACC4" },
586
- { value: "dev-pre-mvp", label: "\uAC1C\uBC1C \uC9C4\uD589 \uC911 (MVP \uC804)" },
587
- { value: "mvp-done", label: "MVP \uC644\uC131, \uAC1C\uC120 \uC911" },
588
- { value: "production", label: "\uC6B4\uC601 \uC911 (\uC720\uC9C0\uBCF4\uC218/\uAE30\uB2A5 \uCD94\uAC00)" },
589
- { value: "refactor", label: "\uB9AC\uD329\uD1A0\uB9C1/\uB9C8\uC774\uADF8\uB808\uC774\uC158" }
590
- ];
1244
+ function getStageOptions() {
1245
+ return [
1246
+ { value: "idea", label: t("orchestrator.stageIdea") },
1247
+ { value: "dev-pre-mvp", label: t("orchestrator.stageDevPreMvp") },
1248
+ { value: "mvp-done", label: t("orchestrator.stageMvpDone") },
1249
+ { value: "production", label: t("orchestrator.stageProduction") },
1250
+ { value: "refactor", label: t("orchestrator.stageRefactor") }
1251
+ ];
1252
+ }
591
1253
  async function promptOrchestrator(projectName) {
592
- p5.log.step("Phase 5: \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uCEE8\uD14D\uC2A4\uD2B8");
1254
+ p5.log.step(t("orchestrator.phase"));
593
1255
  const goals = await p5.text({
594
- message: `${projectName} \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130\uAC00 \uC54C\uC544\uC57C \uD560 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uD45C\uB294?`,
595
- placeholder: "\uC608: 2026\uB144 4\uC6D4 \uB860\uCE6D, \uACB0\uC81C \uC5F0\uB3D9 \uC644\uB8CC \uD544\uC218, \uBAA8\uBC14\uC77C \uBC18\uC751\uD615",
596
- validate: (v) => v.trim() ? void 0 : "\uBAA9\uD45C\uB97C \uC785\uB825\uD558\uC138\uC694"
1256
+ message: t("orchestrator.goalsMsg", { name: projectName }),
1257
+ placeholder: t("orchestrator.goalsPlaceholder"),
1258
+ validate: (v) => v.trim() ? void 0 : t("orchestrator.goalsValidation")
597
1259
  });
598
1260
  if (p5.isCancel(goals)) return null;
599
1261
  const stage = await p5.select({
600
- message: "\uD604\uC7AC \uD504\uB85C\uC81D\uD2B8 \uB2E8\uACC4\uB294?",
601
- options: [...STAGE_OPTIONS]
1262
+ message: t("orchestrator.stageMsg"),
1263
+ options: getStageOptions()
602
1264
  });
603
1265
  if (p5.isCancel(stage)) return null;
604
1266
  const constraints = await p5.text({
605
- message: "\uC791\uC5C5 \uC6B0\uC120\uC21C\uC704 \uB610\uB294 \uC81C\uC57D\uC0AC\uD56D? (\uC5C6\uC73C\uBA74 \uC5D4\uD130)",
606
- placeholder: "\uC608: .env \uCEE4\uBC0B \uAE08\uC9C0, \uD14C\uC2A4\uD2B8 \uCEE4\uBC84\uB9AC\uC9C0 80% \uC720\uC9C0",
1267
+ message: t("orchestrator.constraintsMsg"),
1268
+ placeholder: t("orchestrator.constraintsPlaceholder"),
607
1269
  initialValue: ""
608
1270
  });
609
1271
  if (p5.isCancel(constraints)) return null;
@@ -616,22 +1278,24 @@ async function promptOrchestrator(projectName) {
616
1278
 
617
1279
  // src/prompts/multi-project.ts
618
1280
  import * as p6 from "@clack/prompts";
619
- var COLOR_OPTIONS = [
620
- { value: "#3B82F6", label: "\uD30C\uB791 (#3B82F6)" },
621
- { value: "#22C55E", label: "\uCD08\uB85D (#22C55E)" },
622
- { value: "#F97316", label: "\uC8FC\uD669 (#F97316)" },
623
- { value: "#8B5CF6", label: "\uBCF4\uB77C (#8B5CF6)" },
624
- { value: "#EF4444", label: "\uBE68\uAC15 (#EF4444)" },
625
- { value: "#EC4899", label: "\uBD84\uD64D (#EC4899)" },
626
- { value: "#14B8A6", label: "\uCCAD\uB85D (#14B8A6)" }
627
- ];
1281
+ function getColorOptions() {
1282
+ return [
1283
+ { value: "#3B82F6", label: `${t("multiProject.colorBlue")} (#3B82F6)` },
1284
+ { value: "#22C55E", label: `${t("multiProject.colorGreen")} (#22C55E)` },
1285
+ { value: "#F97316", label: `${t("multiProject.colorOrange")} (#F97316)` },
1286
+ { value: "#8B5CF6", label: `${t("multiProject.colorPurple")} (#8B5CF6)` },
1287
+ { value: "#EF4444", label: `${t("multiProject.colorRed")} (#EF4444)` },
1288
+ { value: "#EC4899", label: `${t("multiProject.colorPink")} (#EC4899)` },
1289
+ { value: "#14B8A6", label: `${t("multiProject.colorTeal")} (#14B8A6)` }
1290
+ ];
1291
+ }
628
1292
  async function promptMultiProject() {
629
- p6.log.step("Phase 6: \uBA40\uD2F0\uD504\uB85C\uC81D\uD2B8 (\uC120\uD0DD)");
1293
+ p6.log.step(t("multiProject.phase"));
630
1294
  const addMore = await p6.select({
631
- message: "\uCD94\uAC00 \uD504\uB85C\uC81D\uD2B8\uB97C \uB4F1\uB85D\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
1295
+ message: t("multiProject.addMoreMsg"),
632
1296
  options: [
633
- { value: "no", label: "\uC9C0\uAE08\uC740 1\uAC1C\uB9CC" },
634
- { value: "yes", label: "\uCD94\uAC00 \uB4F1\uB85D" }
1297
+ { value: "no", label: t("multiProject.addMoreNo") },
1298
+ { value: "yes", label: t("multiProject.addMoreYes") }
635
1299
  ]
636
1300
  });
637
1301
  if (p6.isCancel(addMore)) return null;
@@ -639,26 +1303,26 @@ async function promptMultiProject() {
639
1303
  const projects = [];
640
1304
  while (true) {
641
1305
  const name = await p6.text({
642
- message: "\uCD94\uAC00 \uD504\uB85C\uC81D\uD2B8 \uC774\uB984?",
643
- placeholder: "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984",
644
- validate: (v) => v.trim() ? void 0 : "\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694"
1306
+ message: t("multiProject.nameMsg"),
1307
+ placeholder: t("multiProject.namePlaceholder"),
1308
+ validate: (v) => v.trim() ? void 0 : t("multiProject.nameValidation")
645
1309
  });
646
1310
  if (p6.isCancel(name)) return null;
647
1311
  const desc = await p6.text({
648
- message: "\uD55C \uC904 \uC124\uBA85?",
649
- placeholder: "\uD504\uB85C\uC81D\uD2B8 \uC124\uBA85"
1312
+ message: t("multiProject.descMsg"),
1313
+ placeholder: t("multiProject.descPlaceholder")
650
1314
  });
651
1315
  if (p6.isCancel(desc)) return null;
652
1316
  const color = await p6.select({
653
- message: "\uD0DC\uADF8 \uC0C9\uC0C1?",
654
- options: [...COLOR_OPTIONS]
1317
+ message: t("multiProject.colorMsg"),
1318
+ options: getColorOptions()
655
1319
  });
656
1320
  if (p6.isCancel(color)) return null;
657
1321
  const shared = await p6.select({
658
- message: "\uC5D0\uC774\uC804\uD2B8 \uAD6C\uC131?",
1322
+ message: t("multiProject.agentMsg"),
659
1323
  options: [
660
- { value: "yes", label: "\uAE30\uBCF8 \uD504\uB85C\uC81D\uD2B8\uC640 \uB3D9\uC77C\uD55C \uC5D0\uC774\uC804\uD2B8 \uACF5\uC720" },
661
- { value: "no", label: "\uC774 \uD504\uB85C\uC81D\uD2B8 \uC804\uC6A9 \uC5D0\uC774\uC804\uD2B8 \uBCC4\uB3C4 \uAD6C\uC131" }
1324
+ { value: "yes", label: t("multiProject.agentShared") },
1325
+ { value: "no", label: t("multiProject.agentSeparate") }
662
1326
  ]
663
1327
  });
664
1328
  if (p6.isCancel(shared)) return null;
@@ -671,7 +1335,7 @@ async function promptMultiProject() {
671
1335
  sharedAgents: shared === "yes"
672
1336
  });
673
1337
  const another = await p6.confirm({
674
- message: "\uB610 \uB2E4\uB978 \uD504\uB85C\uC81D\uD2B8\uB97C \uCD94\uAC00\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
1338
+ message: t("multiProject.anotherMsg"),
675
1339
  initialValue: false
676
1340
  });
677
1341
  if (p6.isCancel(another)) return null;
@@ -683,19 +1347,19 @@ async function promptMultiProject() {
683
1347
  // src/prompts/infra.ts
684
1348
  import * as p7 from "@clack/prompts";
685
1349
  async function promptInfra(projectName) {
686
- p7.log.step("Phase 7: \uC778\uD504\uB77C");
1350
+ p7.log.step(t("infra.phase"));
687
1351
  const slackChoice = await p7.select({
688
- message: "Slack \uC5F0\uB3D9?",
1352
+ message: t("infra.slackMsg"),
689
1353
  options: [
690
- { value: "yes", label: "\uC5F0\uB3D9\uD568 (Bot Token + Socket Mode)" },
691
- { value: "no", label: "\uB098\uC911\uC5D0 \uC124\uC815" }
1354
+ { value: "yes", label: t("infra.slackYes") },
1355
+ { value: "no", label: t("infra.slackNo") }
692
1356
  ]
693
1357
  });
694
1358
  if (p7.isCancel(slackChoice)) return null;
695
1359
  let slackCommand = "";
696
1360
  if (slackChoice === "yes") {
697
1361
  const cmd = await p7.text({
698
- message: "Slack \uCEE4\uB9E8\uB4DC \uC774\uB984?",
1362
+ message: t("infra.slackCommandMsg"),
699
1363
  placeholder: `/${projectName.toLowerCase().replace(/[^a-z0-9]/g, "")}`,
700
1364
  initialValue: `/${projectName.toLowerCase().replace(/[^a-z0-9]/g, "")}`
701
1365
  });
@@ -703,19 +1367,19 @@ async function promptInfra(projectName) {
703
1367
  slackCommand = cmd.trim();
704
1368
  }
705
1369
  const portInput = await p7.text({
706
- message: "\uCE78\uBC18 \uC11C\uBC84 \uD3EC\uD2B8?",
1370
+ message: t("infra.portMsg"),
707
1371
  placeholder: "4040",
708
1372
  initialValue: "4040",
709
1373
  validate: (v) => {
710
1374
  const n = parseInt(v, 10);
711
- if (isNaN(n) || n < 1 || n > 65535) return "\uC720\uD6A8\uD55C \uD3EC\uD2B8 \uBC88\uD638\uB97C \uC785\uB825\uD558\uC138\uC694 (1-65535)";
1375
+ if (isNaN(n) || n < 1 || n > 65535) return t("infra.portValidation");
712
1376
  return void 0;
713
1377
  }
714
1378
  });
715
1379
  if (p7.isCancel(portInput)) return null;
716
1380
  const targetDir = await p7.text({
717
- message: "\uD30C\uC77C\uC744 \uC5B4\uB514\uC5D0 \uC0DD\uC131\uD560\uAE4C\uC694?",
718
- placeholder: "./ (\uD604\uC7AC \uB514\uB809\uD1A0\uB9AC)",
1381
+ message: t("infra.targetDirMsg"),
1382
+ placeholder: `./ ${t("infra.targetDirPlaceholder")}`,
719
1383
  initialValue: "./"
720
1384
  });
721
1385
  if (p7.isCancel(targetDir)) return null;
@@ -816,8 +1480,7 @@ var FRONTEND_LABELS = {
816
1480
  nextjs: "Next.js",
817
1481
  "vue-nuxt": "Vue / Nuxt",
818
1482
  svelte: "Svelte / SvelteKit",
819
- angular: "Angular",
820
- none: "(\uC5C6\uC74C)"
1483
+ angular: "Angular"
821
1484
  };
822
1485
  var BACKEND_LABELS = {
823
1486
  supabase: "Supabase",
@@ -831,142 +1494,154 @@ var BACKEND_LABELS = {
831
1494
  redis: "Redis",
832
1495
  aws: "AWS",
833
1496
  gcp: "GCP",
834
- azure: "Azure",
835
- docker: "Docker / K8s"
836
- };
837
- var DEPLOY_LABELS = {
838
- vercel: "Vercel",
839
- netlify: "Netlify",
840
- aws: "AWS",
841
- gcp: "GCP",
842
- docker: "Docker \uC790\uCCB4 \uC11C\uBC84",
843
- undecided: "\uBBF8\uC815"
844
- };
845
- var STAGE_LABELS = {
846
- idea: "\uC544\uC774\uB514\uC5B4/\uAE30\uD68D \uB2E8\uACC4",
847
- "dev-pre-mvp": "\uAC1C\uBC1C \uC9C4\uD589 \uC911 (MVP \uC804)",
848
- "mvp-done": "MVP \uC644\uC131, \uAC1C\uC120 \uC911",
849
- production: "\uC6B4\uC601 \uC911 (\uC720\uC9C0\uBCF4\uC218/\uAE30\uB2A5 \uCD94\uAC00)",
850
- refactor: "\uB9AC\uD329\uD1A0\uB9C1/\uB9C8\uC774\uADF8\uB808\uC774\uC158"
851
- };
852
- var PROJECT_TYPE_LABELS = {
853
- "web-app": "\uC6F9 \uC560\uD50C\uB9AC\uCF00\uC774\uC158",
854
- mobile: "\uBAA8\uBC14\uC77C \uC571",
855
- api: "API \uC11C\uBC84",
856
- "data-pipeline": "\uB370\uC774\uD130 \uD30C\uC774\uD504\uB77C\uC778",
857
- "ai-ml": "AI/ML",
858
- content: "\uCF58\uD150\uCE20/\uB9C8\uCF00\uD305",
859
- admin: "\uC0AC\uB0B4 \uB3C4\uAD6C",
860
- library: "\uB77C\uC774\uBE0C\uB7EC\uB9AC/SDK"
861
- };
862
- var CODING_STYLE_LABELS = {
863
- "functional-only": "\uD568\uC218\uD615 \uCEF4\uD3EC\uB10C\uD2B8 only (\uD074\uB798\uC2A4 \uAE08\uC9C0)",
864
- "named-export": "Named export \uC120\uD638",
865
- "no-any": "any \uD0C0\uC785 \uAE08\uC9C0 (unknown \uC120\uD638)",
866
- "ko-comment": "\uD55C\uAD6D\uC5B4 \uC8FC\uC11D / \uD55C\uAD6D\uC5B4 \uCEE4\uBC0B",
867
- "en-comment": "\uC601\uBB38 \uC8FC\uC11D / \uC601\uBB38 \uCEE4\uBC0B",
868
- jsdoc: "JSDoc \uC8FC\uC11D",
869
- "eslint-prettier": "ESLint + Prettier \uC801\uC6A9",
870
- default: "\uAE30\uBCF8\uAC12 \uC0AC\uC6A9"
871
- };
872
- var CONCERN_LABELS = {
873
- i18n: "\uB2E4\uAD6D\uC5B4 \uC9C0\uC6D0 (i18n)",
874
- "dark-mode": "\uB2E4\uD06C\uBAA8\uB4DC",
875
- a11y: "\uC811\uADFC\uC131 (a11y)",
876
- seo: "SEO \uCD5C\uC801\uD654",
877
- performance: "\uC131\uB2A5 \uCD5C\uC801\uD654 (Core Web Vitals)",
878
- security: "\uBCF4\uC548 (\uC778\uC99D/\uAD8C\uD55C/XSS/CSRF)",
879
- responsive: "\uBAA8\uBC14\uC77C \uBC18\uC751\uD615 \uD544\uC218",
880
- none: "\uC5C6\uC74C"
1497
+ azure: "Azure"
881
1498
  };
1499
+ function getDeployLabels() {
1500
+ return {
1501
+ vercel: "Vercel",
1502
+ netlify: "Netlify",
1503
+ aws: "AWS",
1504
+ gcp: "GCP",
1505
+ docker: t("contextGen.deployDocker"),
1506
+ undecided: t("contextGen.deployUndecided")
1507
+ };
1508
+ }
1509
+ function getStageLabels() {
1510
+ return {
1511
+ idea: t("contextGen.stageIdea"),
1512
+ "dev-pre-mvp": t("contextGen.stageDevPreMvp"),
1513
+ "mvp-done": t("contextGen.stageMvpDone"),
1514
+ production: t("contextGen.stageProduction"),
1515
+ refactor: t("contextGen.stageRefactor")
1516
+ };
1517
+ }
1518
+ function getProjectTypeLabels() {
1519
+ return {
1520
+ "web-app": t("contextGen.typeWebApp"),
1521
+ mobile: t("contextGen.typeMobile"),
1522
+ api: t("contextGen.typeApi"),
1523
+ "data-pipeline": t("contextGen.typeDataPipeline"),
1524
+ "ai-ml": t("contextGen.typeAiMl"),
1525
+ content: t("contextGen.typeContent"),
1526
+ admin: t("contextGen.typeAdmin"),
1527
+ library: t("contextGen.typeLibrary")
1528
+ };
1529
+ }
1530
+ function getCodingStyleLabels() {
1531
+ return {
1532
+ "functional-only": t("contextGen.styleFunctional"),
1533
+ "named-export": t("contextGen.styleNamedExport"),
1534
+ "no-any": t("contextGen.styleNoAny"),
1535
+ "ko-comment": t("contextGen.styleKoComment"),
1536
+ "en-comment": t("contextGen.styleEnComment"),
1537
+ jsdoc: t("contextGen.styleJsdoc"),
1538
+ "eslint-prettier": t("contextGen.styleEslint"),
1539
+ default: t("contextGen.styleDefault")
1540
+ };
1541
+ }
1542
+ function getConcernLabels() {
1543
+ return {
1544
+ i18n: t("contextGen.concernI18n"),
1545
+ "dark-mode": t("contextGen.concernDarkMode"),
1546
+ a11y: t("contextGen.concernA11y"),
1547
+ seo: t("contextGen.concernSeo"),
1548
+ performance: t("contextGen.concernPerformance"),
1549
+ security: t("contextGen.concernSecurity"),
1550
+ responsive: t("contextGen.concernResponsive"),
1551
+ none: t("contextGen.concernNone")
1552
+ };
1553
+ }
882
1554
  function generateProjectContext(answers) {
883
1555
  const { project, techStack, contextFiles, orchestrator, infra } = answers;
884
- const frontendLabel = FRONTEND_LABELS[techStack.frontend] || techStack.frontend;
1556
+ const frontendLabel = techStack.frontend === "none" ? t("contextGen.frontendNone") : FRONTEND_LABELS[techStack.frontend] || techStack.frontend;
885
1557
  const backendList = techStack.backend.map((b) => `- ${BACKEND_LABELS[b] || b}`).join("\n");
886
- const deployLabel = DEPLOY_LABELS[techStack.deploy] || techStack.deploy;
887
- const stageLabel = STAGE_LABELS[orchestrator.stage] || orchestrator.stage;
888
- const typeLabels = project.types.map((t) => PROJECT_TYPE_LABELS[t] || t).join(", ");
889
- const dirLines = techStack.directories.length > 0 ? techStack.directories.map((d) => `- \`${d.path}\` \u2014 ${d.description}`).join("\n") : "- `src/` \u2014 \uC18C\uC2A4 \uCF54\uB4DC\n- `docs/` \u2014 \uBB38\uC11C\n- `tools/` \u2014 \uAC1C\uBC1C \uB3C4\uAD6C";
1558
+ const deployLabel = getDeployLabels()[techStack.deploy] || techStack.deploy;
1559
+ const stageLabel = getStageLabels()[orchestrator.stage] || orchestrator.stage;
1560
+ const typeLabels = project.types.map((pt) => getProjectTypeLabels()[pt] || pt).join(", ");
1561
+ const dirLines = techStack.directories.length > 0 ? techStack.directories.map((d) => `- \`${d.path}\` \u2014 ${d.description}`).join("\n") : `- \`src/\` \u2014 ${t("contextGen.defaultDirSrc")}
1562
+ - \`docs/\` \u2014 ${t("contextGen.defaultDirDocs")}
1563
+ - \`tools/\` \u2014 ${t("contextGen.defaultDirTools")}`;
890
1564
  let conventionLines;
891
1565
  if (contextFiles.parsedContext) {
892
1566
  const pc2 = contextFiles.parsedContext;
893
1567
  const items = [];
894
1568
  if (pc2.conventions.naming.length) items.push(...pc2.conventions.naming.map((n) => `- ${n}`));
895
1569
  if (pc2.conventions.style.length) items.push(...pc2.conventions.style.map((s) => `- ${s}`));
896
- if (pc2.conventions.tools.length) items.push(...pc2.conventions.tools.map((t) => `- ${t}`));
1570
+ if (pc2.conventions.tools.length) items.push(...pc2.conventions.tools.map((v) => `- ${v}`));
897
1571
  if (pc2.security.length) items.push(...pc2.security.map((s) => `- \u26A0\uFE0F ${s}`));
898
- conventionLines = items.length > 0 ? items.join("\n") : "- (CLAUDE.md\uC5D0\uC11C \uC790\uB3D9 \uCD94\uCD9C\uB41C \uCEE8\uBCA4\uC158 \uC5C6\uC74C)";
1572
+ conventionLines = items.length > 0 ? items.join("\n") : `- ${t("contextGen.noConventionsClaudeMd")}`;
899
1573
  } else {
1574
+ const CODING_STYLE_LABELS = getCodingStyleLabels();
1575
+ const CONCERN_LABELS = getConcernLabels();
900
1576
  const styleItems = contextFiles.codingStyle.filter((s) => s !== "default").map((s) => `- ${CODING_STYLE_LABELS[s] || s}`);
901
1577
  const concernItems = contextFiles.concerns.filter((c) => c !== "none").map((c) => `- ${CONCERN_LABELS[c] || c}`);
902
- conventionLines = [...styleItems, ...concernItems].join("\n") || "- (\uD504\uB85C\uC81D\uD2B8\uC5D0 \uB9DE\uAC8C \uC218\uC815\uD558\uC138\uC694)";
1578
+ conventionLines = [...styleItems, ...concernItems].join("\n") || `- ${t("contextGen.noConventionsManual")}`;
903
1579
  }
904
- const refDocLines = contextFiles.referenceDocs.length > 0 ? contextFiles.referenceDocs.map((d) => `- **${d.type}**: \`${d.path}\``).join("\n") : "- (\uC5C6\uC74C)";
905
- const goalsSection = orchestrator.goals || "(\uBAA9\uD45C\uB97C \uC785\uB825\uD558\uC138\uC694)";
906
- const constraintsSection = orchestrator.constraints || "(\uC81C\uC57D\uC0AC\uD56D \uC5C6\uC74C)";
1580
+ const refDocLines = contextFiles.referenceDocs.length > 0 ? contextFiles.referenceDocs.map((d) => `- **${d.type}**: \`${d.path}\``).join("\n") : `- ${t("contextGen.noRefDocs")}`;
1581
+ const goalsSection = orchestrator.goals || t("contextGen.goalsPlaceholder");
1582
+ const constraintsSection = orchestrator.constraints || t("contextGen.constraintsPlaceholder");
907
1583
  let brandSection = "";
908
1584
  if (contextFiles.parsedContext) {
909
1585
  const pc2 = contextFiles.parsedContext;
910
1586
  const items = [];
911
- if (pc2.fonts.length) items.push(`- **\uD3F0\uD2B8**: ${pc2.fonts.join(", ")}`);
912
- if (pc2.colors.length) items.push(`- **\uC0C9\uC0C1**: ${pc2.colors.join(", ")}`);
913
- if (pc2.i18n.length) items.push(`- **\uB2E4\uAD6D\uC5B4**: ${pc2.i18n.join(", ")}`);
1587
+ if (pc2.fonts.length) items.push(`- **${t("contextGen.labelFonts")}**: ${pc2.fonts.join(", ")}`);
1588
+ if (pc2.colors.length) items.push(`- **${t("contextGen.labelColors")}**: ${pc2.colors.join(", ")}`);
1589
+ if (pc2.i18n.length) items.push(`- **${t("contextGen.labelI18n")}**: ${pc2.i18n.join(", ")}`);
914
1590
  if (items.length) brandSection = `
915
- ## \uBE0C\uB79C\uB4DC/\uB514\uC790\uC778
1591
+ ## ${t("contextGen.sectionBrand")}
916
1592
 
917
1593
  ${items.join("\n")}
918
1594
  `;
919
1595
  }
920
- return `# ${project.name} \u2014 \uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8
1596
+ return `# ${t("contextGen.title", { name: project.name })}
921
1597
 
922
- \uC774 \uBB38\uC11C\uB294 \uBAA8\uB4E0 \uC5D0\uC774\uC804\uD2B8\uAC00 \uACF5\uC720\uD558\uB294 \uD504\uB85C\uC81D\uD2B8 \uAE30\uBCF8 \uC815\uBCF4\uB2E4.
923
- \uAC01 \uC5D0\uC774\uC804\uD2B8\uB294 \uC774 \uBB38\uC11C\uB97C \uC219\uC9C0\uD55C \uC0C1\uD0DC\uC5D0\uC11C \uC790\uAE30 \uC5ED\uD560\uC744 \uC218\uD589\uD55C\uB2E4.
1598
+ ${t("contextGen.intro")}
924
1599
 
925
- ## \uD504\uB85C\uC81D\uD2B8 \uAC1C\uC694
1600
+ ## ${t("contextGen.sectionOverview")}
926
1601
 
927
1602
  ${project.description}
928
1603
 
929
- - **\uC131\uACA9**: ${typeLabels}
930
- - **\uB2E8\uACC4**: ${stageLabel}
1604
+ - **${t("contextGen.labelType")}**: ${typeLabels}
1605
+ - **${t("contextGen.labelStage")}**: ${stageLabel}
931
1606
 
932
- ## \uAE30\uC220 \uC2A4\uD0DD
1607
+ ## ${t("contextGen.sectionStack")}
933
1608
 
934
- - **\uD504\uB860\uD2B8\uC5D4\uB4DC**: ${frontendLabel}
935
- ${backendList || "- (\uC9C1\uC811 \uC785\uB825\uD558\uC138\uC694)"}
936
- - **\uBC30\uD3EC**: ${deployLabel}
1609
+ - **${t("contextGen.labelFrontend")}**: ${frontendLabel}
1610
+ ${backendList || `- ${t("contextGen.backendFallback")}`}
1611
+ - **${t("contextGen.labelDeploy")}**: ${deployLabel}
937
1612
 
938
- ## \uB514\uB809\uD1A0\uB9AC \uAD6C\uC870
1613
+ ## ${t("contextGen.sectionDirs")}
939
1614
 
940
1615
  ${dirLines}
941
1616
 
942
- ## \uCF54\uB529 \uCEE8\uBCA4\uC158
1617
+ ## ${t("contextGen.sectionConventions")}
943
1618
 
944
1619
  ${conventionLines}
945
1620
  ${brandSection}
946
- ## \uD504\uB85C\uC81D\uD2B8 \uBAA9\uD45C
1621
+ ## ${t("contextGen.sectionGoals")}
947
1622
 
948
1623
  ${goalsSection}
949
1624
 
950
- ## \uC81C\uC57D\uC0AC\uD56D
1625
+ ## ${t("contextGen.sectionConstraints")}
951
1626
 
952
1627
  ${constraintsSection}
953
1628
 
954
- ## \uCC38\uACE0 \uBB38\uC11C
1629
+ ## ${t("contextGen.sectionRefDocs")}
955
1630
 
956
1631
  ${refDocLines}
957
1632
 
958
- ## \uC791\uC5C5 \uD504\uB85C\uD1A0\uCF5C
1633
+ ## ${t("contextGen.sectionProtocol")}
959
1634
 
960
- - **\uCE78\uBC18 \uC11C\uBC84**: \`http://localhost:${infra.port}\`
961
- - **Slack \uBCF4\uACE0**: \`POST http://localhost:${infra.port}/api/tasks/{TASK_ID}/slack\`
962
- - **\uB85C\uADF8 \uB514\uB809\uD1A0\uB9AC**: \`.claude/logs/\`
963
- - **\uC0C1\uD0DC \uD50C\uB85C\uC6B0**: pending \u2192 in_progress \u2192 in_review \u2192 completed
1635
+ - **${t("contextGen.protocolKanban")}**: \`http://localhost:${infra.port}\`
1636
+ - **${t("contextGen.protocolSlack")}**: \`POST http://localhost:${infra.port}/api/tasks/{TASK_ID}/slack\`
1637
+ - **${t("contextGen.protocolLogs")}**: \`.claude/logs/\`
1638
+ - **${t("contextGen.protocolStatus")}**: pending \u2192 in_progress \u2192 in_review \u2192 completed
964
1639
 
965
- \uBAA8\uB4E0 \uC5D0\uC774\uC804\uD2B8\uB294 \uC791\uC5C5 \uC2DC\uC791/\uC644\uB8CC \uC2DC \uB2E4\uC74C 3\uACF3\uC5D0 \uAE30\uB85D\uC744 \uB0A8\uAE34\uB2E4:
1640
+ ${t("contextGen.protocolInstruction")}
966
1641
 
967
- 1. **Slack \uBCF4\uACE0**: \`curl -s -X POST http://localhost:${infra.port}/api/tasks/{TASK_ID}/slack -H "Content-Type: application/json" -d '{"text":"\uBA54\uC2DC\uC9C0"}'\`
968
- 2. **\uCE78\uBC18 \uC5C5\uB370\uC774\uD2B8**: \`PUT http://localhost:${infra.port}/api/tasks/{id}\` (status, reportSummary, reportPath)
969
- 3. **\uB85C\uADF8 \uD30C\uC77C**: \`.claude/logs/{YYYY-MM-DD}_{task-slug}.md\`
1642
+ 1. **${t("contextGen.protocolSlackReport")}**: \`curl -s -X POST http://localhost:${infra.port}/api/tasks/{TASK_ID}/slack -H "Content-Type: application/json" -d '{"text":"${t("contextGen.protocolSlackExample")}"}' \`
1643
+ 2. **${t("contextGen.protocolKanbanUpdate")}**: \`PUT http://localhost:${infra.port}/api/tasks/{id}\` (status, reportSummary, reportPath)
1644
+ 3. **${t("contextGen.protocolLogFile")}**: \`.claude/logs/{YYYY-MM-DD}_{task-slug}.md\`
970
1645
  `;
971
1646
  }
972
1647
 
@@ -1156,30 +1831,30 @@ var AGENT_DISPLAY_NAMES = {
1156
1831
  function buildBaseSections(answers) {
1157
1832
  const port = answers.infra.port;
1158
1833
  return `## Project Context
1159
- - **\uD504\uB85C\uC81D\uD2B8**: ${answers.project.name}
1160
- - **\uC124\uBA85**: ${answers.project.description}
1161
- - **\uCE78\uBC18 API**: \`http://localhost:${port}/api/tasks\`
1162
- - **Slack API**: \`POST http://localhost:${port}/api/tasks/{TASK_ID}/slack\`
1163
- - **\uB85C\uADF8 \uB514\uB809\uD1A0\uB9AC**: \`.claude/logs/\`
1834
+ - **${t("agentGen.projectLabel")}**: ${answers.project.name}
1835
+ - **${t("agentGen.descLabel")}**: ${answers.project.description}
1836
+ - **${t("agentGen.kanbanApiLabel")}**: \`http://localhost:${port}/api/tasks\`
1837
+ - **${t("agentGen.slackApiLabel")}**: \`POST http://localhost:${port}/api/tasks/{TASK_ID}/slack\`
1838
+ - **${t("agentGen.logDirLabel")}**: \`.claude/logs/\`
1164
1839
 
1165
1840
  ## Slack Reporting
1166
- \uC791\uC5C5 \uC2DC\uC791\uACFC \uC644\uB8CC \uC2DC Slack\uC5D0 \uBCF4\uACE0\uD55C\uB2E4 (\uD0DC\uC2A4\uD06C \uC2A4\uB808\uB4DC\uB85C \uC790\uB3D9 \uC815\uB9AC):
1841
+ ${t("agentGen.slackReportingDesc")}
1167
1842
  \`\`\`bash
1168
1843
  curl -s -X POST http://localhost:${port}/api/tasks/{TASK_ID}/slack \\
1169
- -H "Content-Type: application/json" -d '{"text":"\uBA54\uC2DC\uC9C0"}'
1844
+ -H "Content-Type: application/json" -d '{"text":"${t("contextGen.protocolSlackExample")}"}'
1170
1845
  \`\`\`
1171
- \`$SLACK_AGENT_WEBHOOK\` \uC9C1\uC811 \uC0AC\uC6A9 \uAE08\uC9C0. \uBC18\uB4DC\uC2DC \uC704 API\uB97C \uD1B5\uD574 \uBCF4\uACE0.
1172
- \`{TASK_ID}\`\uB294 buildExecutorPrompt\uC5D0\uC11C \uC2E4\uC81C ID\uAC00 \uC8FC\uC785\uB41C\uB2E4.
1846
+ ${t("agentGen.slackForbid")}
1847
+ ${t("agentGen.slackTaskIdNote")}
1173
1848
 
1174
1849
  ## Kanban Update
1175
- 1. \uC2DC\uC791: \`PUT /api/tasks/{id}\` \u2014 \`status: "in_progress"\`, \`activeForm: "\uC218\uD589 \uC911 \uC124\uBA85"\`
1176
- 2. \uC644\uB8CC: \`PUT /api/tasks/{id}\` \u2014 \`status: "completed"\`, \`reportPath\`, \`reportSummary\`
1177
- 3. reportSummary \uD3EC\uB9F7: \`\uC218\uD589 \uB0B4\uC5ED \uC694\uC57D 1\uC904. \uD6C4\uC18D: \uB2E4\uC74C \uC791\uC5C5 \uC81C\uC548\`
1850
+ 1. ${t("agentGen.kanbanStart")}: \`PUT /api/tasks/{id}\` \u2014 \`status: "in_progress"\`, \`activeForm: "${t("agentGen.kanbanActiveForm")}"\`
1851
+ 2. ${t("agentGen.kanbanDone")}: \`PUT /api/tasks/{id}\` \u2014 \`status: "completed"\`, \`reportPath\`, \`reportSummary\`
1852
+ 3. reportSummary: \`${t("agentGen.kanbanReportFormat")}\`
1178
1853
 
1179
1854
  ## Report File
1180
- \uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC \uBCF4\uACE0\uC11C \uC791\uC131:
1181
- - \uACBD\uB85C: \`.claude/logs/{YYYY-MM-DD}_{task-slug}.md\`
1182
- - \uB0B4\uC6A9: \uBCC0\uACBD \uD30C\uC77C \uBAA9\uB85D, \uBCC0\uACBD \uB0B4\uC6A9, \uAC80\uC99D \uACB0\uACFC, \uD6C4\uC18D \uC791\uC5C5`;
1855
+ ${t("agentGen.reportDesc")}
1856
+ - ${t("agentGen.reportPathLabel")}: \`.claude/logs/{YYYY-MM-DD}_{task-slug}.md\`
1857
+ - ${t("agentGen.reportContentDesc")}`;
1183
1858
  }
1184
1859
  function buildConventionsSection(answers) {
1185
1860
  const lines = [];
@@ -1187,10 +1862,10 @@ function buildConventionsSection(answers) {
1187
1862
  if (ctx) {
1188
1863
  if (ctx.conventions.naming.length) lines.push(...ctx.conventions.naming.map((n) => `- ${n}`));
1189
1864
  if (ctx.conventions.style.length) lines.push(...ctx.conventions.style.map((s) => `- ${s}`));
1190
- if (ctx.conventions.tools.length) lines.push(...ctx.conventions.tools.map((t) => `- ${t}`));
1865
+ if (ctx.conventions.tools.length) lines.push(...ctx.conventions.tools.map((v) => `- ${v}`));
1191
1866
  if (ctx.security.length) lines.push(...ctx.security.map((s) => `- \u26A0\uFE0F ${s}`));
1192
- if (ctx.fonts.length) lines.push(`- \uD3F0\uD2B8: ${ctx.fonts.join(", ")}`);
1193
- if (ctx.colors.length) lines.push(`- \uC0C9\uC0C1: ${ctx.colors.join(", ")}`);
1867
+ if (ctx.fonts.length) lines.push(`- ${t("agentGen.fontsLabel")}: ${ctx.fonts.join(", ")}`);
1868
+ if (ctx.colors.length) lines.push(`- ${t("agentGen.colorsLabel")}: ${ctx.colors.join(", ")}`);
1194
1869
  } else {
1195
1870
  for (const s of answers.contextFiles.codingStyle) {
1196
1871
  if (s !== "default") lines.push(`- ${s}`);
@@ -1253,13 +1928,13 @@ ${constraints}
1253
1928
  // src/generators/env-file.ts
1254
1929
  function generateEnvFile(answers) {
1255
1930
  const lines = [
1256
- "# \uCE78\uBC18 \uC11C\uBC84",
1931
+ t("envGen.kanbanServer"),
1257
1932
  `PORT=${answers.infra.port}`,
1258
1933
  ""
1259
1934
  ];
1260
1935
  if (answers.infra.slackEnabled) {
1261
1936
  lines.push(
1262
- "# Slack \uC5F0\uB3D9",
1937
+ t("envGen.slackIntegration"),
1263
1938
  "SLACK_BOT_TOKEN=xoxb-...",
1264
1939
  "SLACK_APP_TOKEN=xapp-...",
1265
1940
  "SLACK_CHANNEL_ID=C...",
@@ -1268,7 +1943,7 @@ function generateEnvFile(answers) {
1268
1943
  );
1269
1944
  } else {
1270
1945
  lines.push(
1271
- "# Slack \uC5F0\uB3D9 (\uB098\uC911\uC5D0 \uC124\uC815)",
1946
+ t("envGen.slackLater"),
1272
1947
  "# SLACK_BOT_TOKEN=xoxb-...",
1273
1948
  "# SLACK_APP_TOKEN=xapp-...",
1274
1949
  "# SLACK_CHANNEL_ID=C...",
@@ -1304,7 +1979,7 @@ async function scaffold(answers) {
1304
1979
  const targetDir = path5.resolve(answers.infra.targetDir);
1305
1980
  const templatesDir = getTemplatesDir();
1306
1981
  const s = p8.spinner();
1307
- s.start("\uB514\uB809\uD1A0\uB9AC \uC0DD\uC131 \uC911...");
1982
+ s.start(t("scaffold.dirCreating"));
1308
1983
  await fs6.ensureDir(path5.join(targetDir, "tools"));
1309
1984
  await fs6.ensureDir(path5.join(targetDir, ".claude", "agents"));
1310
1985
  await fs6.ensureDir(path5.join(targetDir, ".claude", "logs"));
@@ -1312,29 +1987,29 @@ async function scaffold(answers) {
1312
1987
  for (const proj of answers.additionalProjects) {
1313
1988
  await fs6.ensureDir(path5.join(targetDir, ".claude", "tasks", proj.id));
1314
1989
  }
1315
- s.stop("\uB514\uB809\uD1A0\uB9AC \uC0DD\uC131 \uC644\uB8CC");
1316
- s.start("\uCE78\uBC18 \uC11C\uBC84 \uBCF5\uC0AC \uC911...");
1990
+ s.stop(t("scaffold.dirDone"));
1991
+ s.start(t("scaffold.kanbanServerCopying"));
1317
1992
  const kanbanSrc = path5.join(templatesDir, "kanban.cjs");
1318
1993
  const kanbanDest = path5.join(targetDir, "tools", "kanban.cjs");
1319
1994
  if (fs6.existsSync(kanbanSrc)) {
1320
1995
  await fs6.copy(kanbanSrc, kanbanDest);
1321
1996
  }
1322
- s.stop("\uCE78\uBC18 \uC11C\uBC84 \uBCF5\uC0AC \uC644\uB8CC");
1323
- s.start("\uCE78\uBC18 UI \uBCF5\uC0AC \uC911...");
1997
+ s.stop(t("scaffold.kanbanServerDone"));
1998
+ s.start(t("scaffold.kanbanUICopying"));
1324
1999
  const htmlSrc = path5.join(templatesDir, "kanban.html");
1325
2000
  const htmlDest = path5.join(targetDir, "tools", "kanban.html");
1326
2001
  if (fs6.existsSync(htmlSrc)) {
1327
2002
  await fs6.copy(htmlSrc, htmlDest);
1328
2003
  }
1329
- s.stop("\uCE78\uBC18 UI \uBCF5\uC0AC \uC644\uB8CC");
1330
- s.start("\uC124\uC815 \uD30C\uC77C \uC0DD\uC131 \uC911...");
2004
+ s.stop(t("scaffold.kanbanUIDone"));
2005
+ s.start(t("scaffold.configCreating"));
1331
2006
  const config = generateConfig(answers);
1332
2007
  await fs6.writeFile(
1333
2008
  path5.join(targetDir, "kanban.config.json"),
1334
2009
  JSON.stringify(config, null, 2)
1335
2010
  );
1336
- s.stop("\uC124\uC815 \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC");
1337
- s.start("\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC0DD\uC131 \uC911...");
2011
+ s.stop(t("scaffold.configDone"));
2012
+ s.start(t("scaffold.projectListCreating"));
1338
2013
  const projects = config.projects.map((proj) => ({
1339
2014
  ...proj,
1340
2015
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -1343,15 +2018,15 @@ async function scaffold(answers) {
1343
2018
  path5.join(targetDir, ".claude", "tasks", "_projects.json"),
1344
2019
  JSON.stringify(projects, null, 2)
1345
2020
  );
1346
- s.stop("\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC0DD\uC131 \uC644\uB8CC");
1347
- s.start("\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8 \uC0DD\uC131 \uC911...");
2021
+ s.stop(t("scaffold.projectListDone"));
2022
+ s.start(t("scaffold.contextCreating"));
1348
2023
  const projectContext = generateProjectContext(answers);
1349
2024
  await fs6.writeFile(
1350
2025
  path5.join(targetDir, ".claude", "agents", "_project-context.md"),
1351
2026
  projectContext
1352
2027
  );
1353
- s.stop("\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8 \uC0DD\uC131 \uC644\uB8CC");
1354
- s.start("\uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 \uC0DD\uC131 \uC911...");
2028
+ s.stop(t("scaffold.contextDone"));
2029
+ s.start(t("scaffold.agentsCreating"));
1355
2030
  for (const agent of answers.agents.selectedAgents) {
1356
2031
  const model = getModelForAgent(agent, answers.agents.defaultModel, answers.agents.modelOverrides);
1357
2032
  const prompt = generateAgentPrompt(agent, answers, model, templatesDir);
@@ -1360,8 +2035,8 @@ async function scaffold(answers) {
1360
2035
  prompt
1361
2036
  );
1362
2037
  }
1363
- s.stop(`\uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 ${answers.agents.selectedAgents.length}\uAC1C \uC0DD\uC131 \uC644\uB8CC`);
1364
- s.start("\uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815 \uC0DD\uC131 \uC911...");
2038
+ s.stop(t("scaffold.agentsDone", { count: answers.agents.selectedAgents.length }));
2039
+ s.start(t("scaffold.orchestratorCreating"));
1365
2040
  const orchSrc = path5.join(templatesDir, "orchestrator.md");
1366
2041
  if (fs6.existsSync(orchSrc)) {
1367
2042
  let orchContent = await fs6.readFile(orchSrc, "utf-8");
@@ -1369,7 +2044,7 @@ async function scaffold(answers) {
1369
2044
  orchContent = orchContent.replace(/\{\{port\}\}/g, String(answers.infra.port));
1370
2045
  orchContent = orchContent.replace(/\{\{goals\}\}/g, answers.orchestrator.goals);
1371
2046
  orchContent = orchContent.replace(/\{\{stage\}\}/g, answers.orchestrator.stage);
1372
- orchContent = orchContent.replace(/\{\{constraints\}\}/g, answers.orchestrator.constraints || "(\uC5C6\uC74C)");
2047
+ orchContent = orchContent.replace(/\{\{constraints\}\}/g, answers.orchestrator.constraints || t("scaffold.noConstraints"));
1373
2048
  const agentRows = answers.agents.selectedAgents.map((a) => {
1374
2049
  const model = getModelForAgent(a, answers.agents.defaultModel, answers.agents.modelOverrides);
1375
2050
  return `| ${a} | ${model} |`;
@@ -1380,14 +2055,14 @@ async function scaffold(answers) {
1380
2055
  orchContent
1381
2056
  );
1382
2057
  }
1383
- s.stop("\uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815 \uC0DD\uC131 \uC644\uB8CC");
1384
- s.start(".env.example \uC0DD\uC131 \uC911...");
2058
+ s.stop(t("scaffold.orchestratorDone"));
2059
+ s.start(t("scaffold.envCreating"));
1385
2060
  const envContent = generateEnvFile(answers);
1386
2061
  await fs6.writeFile(
1387
2062
  path5.join(targetDir, ".env.example"),
1388
2063
  envContent
1389
2064
  );
1390
- s.stop(".env.example \uC0DD\uC131 \uC644\uB8CC");
2065
+ s.stop(t("scaffold.envDone"));
1391
2066
  await initGit(targetDir);
1392
2067
  }
1393
2068
 
@@ -1395,27 +2070,39 @@ async function scaffold(answers) {
1395
2070
  async function main() {
1396
2071
  console.log();
1397
2072
  p9.intro(`${pc.bgCyan(pc.black(" create-claude-kanban "))} ${pc.dim("v2.0.0")}`);
2073
+ const langChoice = await p9.select({
2074
+ message: "Language / \uC5B8\uC5B4",
2075
+ options: [
2076
+ { value: "en", label: "English" },
2077
+ { value: "ko", label: "\uD55C\uAD6D\uC5B4" }
2078
+ ]
2079
+ });
2080
+ if (p9.isCancel(langChoice)) {
2081
+ p9.cancel("Cancelled.");
2082
+ process.exit(0);
2083
+ }
2084
+ setLang(langChoice);
1398
2085
  const answers = await runPrompts();
1399
2086
  if (!answers) {
1400
- p9.cancel("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
2087
+ p9.cancel(t("common.cancelled"));
1401
2088
  process.exit(0);
1402
2089
  }
1403
2090
  await scaffold(answers);
1404
2091
  const projectCount = 1 + answers.additionalProjects.length;
1405
2092
  const files = [
1406
- `tools/kanban.cjs \u2014 \uCE78\uBC18 \uC11C\uBC84 (\uBA40\uD2F0\uD504\uB85C\uC81D\uD2B8)`,
1407
- `tools/kanban.html \u2014 \uCE78\uBC18 UI (\uD504\uB85C\uC81D\uD2B8 \uD0ED)`,
1408
- `kanban.config.json \u2014 \uC124\uC815 \uD30C\uC77C (\uD504\uB85C\uC81D\uD2B8 ${projectCount}\uAC1C)`,
1409
- `.claude/agents/ \u2014 \uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 ${answers.agents.selectedAgents.length}\uAC1C`,
1410
- `.claude/agents/_project-context.md \u2014 \uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8`,
1411
- `.claude/orchestrator.md \u2014 \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815`,
1412
- `.env.example \u2014 \uD658\uACBD\uBCC0\uC218 \uD15C\uD50C\uB9BF`
2093
+ `tools/kanban.cjs \u2014 ${t("index.fileKanbanServer")}`,
2094
+ `tools/kanban.html \u2014 ${t("index.fileKanbanUI")}`,
2095
+ `kanban.config.json \u2014 ${t("index.fileConfig", { count: projectCount })}`,
2096
+ `.claude/agents/ \u2014 ${t("index.fileAgents", { count: answers.agents.selectedAgents.length })}`,
2097
+ `.claude/agents/_project-context.md \u2014 ${t("index.fileContext")}`,
2098
+ `.claude/orchestrator.md \u2014 ${t("index.fileOrchestrator")}`,
2099
+ `.env.example \u2014 ${t("index.fileEnv")}`
1413
2100
  ];
1414
- p9.note(files.join("\n"), "\uC0DD\uC131 \uC644\uB8CC");
1415
- p9.outro(`${pc.green("node tools/kanban.cjs")} \uB85C \uC2DC\uC791\uD558\uC138\uC694!`);
2101
+ p9.note(files.join("\n"), t("index.filesHeader"));
2102
+ p9.outro(`${pc.green("node tools/kanban.cjs")} ${t("index.startCmd")}`);
1416
2103
  }
1417
2104
  main().catch((err) => {
1418
- p9.cancel("\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
2105
+ p9.cancel(t("common.error"));
1419
2106
  console.error(err);
1420
2107
  process.exit(1);
1421
2108
  });