create-claude-kanban 1.0.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 ADDED
@@ -0,0 +1,640 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import * as p3 from "@clack/prompts";
5
+ import pc from "picocolors";
6
+
7
+ // src/prompts.ts
8
+ import * as p from "@clack/prompts";
9
+ var TECH_STACK_OPTIONS = [
10
+ { value: "react-ts", label: "React + TypeScript" },
11
+ { value: "nextjs", label: "Next.js" },
12
+ { value: "vue", label: "Vue" },
13
+ { value: "python", label: "Python (FastAPI/Django)" },
14
+ { value: "node", label: "Node.js (Express/Fastify)" }
15
+ ];
16
+ var INFRA_OPTIONS = [
17
+ { value: "supabase", label: "Supabase" },
18
+ { value: "firebase", label: "Firebase" },
19
+ { value: "postgresql", label: "PostgreSQL" },
20
+ { value: "mongodb", label: "MongoDB" },
21
+ { value: "aws", label: "AWS" },
22
+ { value: "vercel", label: "Vercel" },
23
+ { value: "docker", label: "Docker" }
24
+ ];
25
+ var AGENT_OPTIONS = [
26
+ { value: "frontend", label: "frontend (\uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C)" },
27
+ { value: "backend", label: "backend (\uBC31\uC5D4\uB4DC \uAC1C\uBC1C)" },
28
+ { value: "qa", label: "qa (\uD14C\uC2A4\uD2B8/\uD488\uC9C8)" },
29
+ { value: "designer", label: "designer (\uB514\uC790\uC778 \uC2DC\uC2A4\uD15C)" },
30
+ { value: "devops", label: "devops (\uC778\uD504\uB77C/\uBC30\uD3EC)" },
31
+ { value: "researcher", label: "researcher (\uC870\uC0AC/\uBD84\uC11D)" },
32
+ { value: "orchestrator", label: "orchestrator (\uD0DC\uC2A4\uD06C \uBD84\uBC30/\uC870\uC728)" },
33
+ { value: "strategist", label: "strategist (\uC544\uD0A4\uD14D\uCC98/\uC804\uB7B5)" },
34
+ { value: "content-planner", label: "content-planner (\uCF58\uD150\uCE20 \uAE30\uD68D)" },
35
+ { value: "item-author", label: "item-author (\uBB38\uD56D \uAC1C\uBC1C)" },
36
+ { value: "doc-writer", label: "doc-writer (\uBB38\uC11C \uC791\uC131)" }
37
+ ];
38
+ var MODEL_OPTIONS = [
39
+ { value: "sonnet", label: "sonnet (\uB300\uBD80\uBD84 \uC5D0\uC774\uC804\uD2B8)" },
40
+ { value: "opus", label: "opus (\uACE0\uB09C\uB3C4 \uC5D0\uC774\uC804\uD2B8)" },
41
+ { value: "haiku", label: "haiku (\uACBD\uB7C9 \uC5D0\uC774\uC804\uD2B8)" }
42
+ ];
43
+ var OPUS_AGENTS = /* @__PURE__ */ new Set(["orchestrator", "strategist", "item-author"]);
44
+ var HAIKU_AGENTS = /* @__PURE__ */ new Set(["doc-writer"]);
45
+ function getModelForAgent(agent, defaultModel) {
46
+ if (OPUS_AGENTS.has(agent)) return "opus";
47
+ if (HAIKU_AGENTS.has(agent)) return "haiku";
48
+ return defaultModel;
49
+ }
50
+ async function runPrompts() {
51
+ const projectName = await p.text({
52
+ message: "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984?",
53
+ placeholder: "MyProject",
54
+ validate: (v) => v.trim() ? void 0 : "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694"
55
+ });
56
+ if (p.isCancel(projectName)) return null;
57
+ const description = await p.text({
58
+ message: "\uD504\uB85C\uC81D\uD2B8 \uC124\uBA85 (\uD55C \uC904)?",
59
+ placeholder: "\uD504\uB85C\uC81D\uD2B8 \uAC04\uB2E8 \uC124\uBA85",
60
+ validate: (v) => v.trim() ? void 0 : "\uC124\uBA85\uC744 \uC785\uB825\uD558\uC138\uC694"
61
+ });
62
+ if (p.isCancel(description)) return null;
63
+ const techStack = await p.multiselect({
64
+ message: "\uAE30\uC220 \uC2A4\uD0DD? (\uBCF5\uC218 \uC120\uD0DD)",
65
+ options: [...TECH_STACK_OPTIONS],
66
+ required: false
67
+ });
68
+ if (p.isCancel(techStack)) return null;
69
+ const infra = await p.multiselect({
70
+ message: "\uC8FC\uC694 \uC778\uD504\uB77C? (\uBCF5\uC218 \uC120\uD0DD)",
71
+ options: [...INFRA_OPTIONS],
72
+ required: false
73
+ });
74
+ if (p.isCancel(infra)) return null;
75
+ const agents = await p.multiselect({
76
+ message: "\uC5B4\uB5A4 \uC5D0\uC774\uC804\uD2B8\uB97C \uAD6C\uC131\uD560\uAE4C\uC694? (\uBCF5\uC218 \uC120\uD0DD)",
77
+ options: [...AGENT_OPTIONS],
78
+ initialValues: ["frontend", "backend", "qa", "orchestrator", "researcher"],
79
+ required: true
80
+ });
81
+ if (p.isCancel(agents)) return null;
82
+ const defaultModel = await p.select({
83
+ message: "\uC5D0\uC774\uC804\uD2B8\uBCC4 \uBAA8\uB378 \uAE30\uBCF8\uAC12?",
84
+ options: [...MODEL_OPTIONS]
85
+ });
86
+ if (p.isCancel(defaultModel)) return null;
87
+ const slackChoice = await p.select({
88
+ message: "Slack \uC5F0\uB3D9?",
89
+ options: [
90
+ { value: "yes", label: "\uC5F0\uB3D9\uD568 (Bot Token + Socket Mode)" },
91
+ { value: "no", label: "\uB098\uC911\uC5D0 \uC124\uC815" }
92
+ ]
93
+ });
94
+ if (p.isCancel(slackChoice)) return null;
95
+ const portInput = await p.text({
96
+ message: "\uCE78\uBC18 \uC11C\uBC84 \uD3EC\uD2B8?",
97
+ placeholder: "4040",
98
+ initialValue: "4040",
99
+ validate: (v) => {
100
+ const n = parseInt(v, 10);
101
+ if (isNaN(n) || n < 1 || n > 65535) return "\uC720\uD6A8\uD55C \uD3EC\uD2B8 \uBC88\uD638\uB97C \uC785\uB825\uD558\uC138\uC694 (1-65535)";
102
+ return void 0;
103
+ }
104
+ });
105
+ if (p.isCancel(portInput)) return null;
106
+ const targetDir = await p.text({
107
+ message: "\uD30C\uC77C\uC744 \uC5B4\uB514\uC5D0 \uC0DD\uC131\uD560\uAE4C\uC694?",
108
+ placeholder: "./ (\uD604\uC7AC \uB514\uB809\uD1A0\uB9AC)",
109
+ initialValue: "./"
110
+ });
111
+ if (p.isCancel(targetDir)) return null;
112
+ return {
113
+ projectName,
114
+ description,
115
+ techStack,
116
+ infra,
117
+ agents,
118
+ defaultModel,
119
+ slackEnabled: slackChoice === "yes",
120
+ port: parseInt(portInput, 10),
121
+ targetDir
122
+ };
123
+ }
124
+
125
+ // src/scaffold.ts
126
+ import path3 from "path";
127
+ import fs3 from "fs-extra";
128
+ import * as p2 from "@clack/prompts";
129
+ import { fileURLToPath } from "url";
130
+
131
+ // src/generators/config.ts
132
+ function generateConfig(answers) {
133
+ const agents = {};
134
+ for (const agent of answers.agents) {
135
+ agents[agent] = {
136
+ model: getModelForAgent(agent, answers.defaultModel),
137
+ aliases: []
138
+ };
139
+ }
140
+ return {
141
+ projectName: answers.projectName,
142
+ description: answers.description,
143
+ port: answers.port,
144
+ agents,
145
+ slack: {
146
+ enabled: answers.slackEnabled,
147
+ command: `/${answers.projectName.toLowerCase().replace(/[^a-z0-9]/g, "")}`
148
+ },
149
+ paths: {
150
+ agents: ".claude/agents",
151
+ tasks: ".claude/tasks",
152
+ logs: ".claude/logs"
153
+ }
154
+ };
155
+ }
156
+
157
+ // src/generators/project-context.ts
158
+ var TECH_LABELS = {
159
+ "react-ts": "React + TypeScript",
160
+ nextjs: "Next.js",
161
+ vue: "Vue",
162
+ python: "Python (FastAPI/Django)",
163
+ node: "Node.js (Express/Fastify)"
164
+ };
165
+ var INFRA_LABELS = {
166
+ supabase: "Supabase",
167
+ firebase: "Firebase",
168
+ postgresql: "PostgreSQL",
169
+ mongodb: "MongoDB",
170
+ aws: "AWS",
171
+ vercel: "Vercel",
172
+ docker: "Docker"
173
+ };
174
+ function generateProjectContext(answers) {
175
+ const techList = answers.techStack.map((t) => `- ${TECH_LABELS[t] || t}`).join("\n");
176
+ const infraList = answers.infra.map((i) => `- ${INFRA_LABELS[i] || i}`).join("\n");
177
+ return `# ${answers.projectName} \u2014 \uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8
178
+
179
+ \uC774 \uBB38\uC11C\uB294 \uBAA8\uB4E0 \uC5D0\uC774\uC804\uD2B8\uAC00 \uACF5\uC720\uD558\uB294 \uD504\uB85C\uC81D\uD2B8 \uAE30\uBCF8 \uC815\uBCF4\uB2E4.
180
+ \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.
181
+
182
+ ## \uD504\uB85C\uC81D\uD2B8 \uAC1C\uC694
183
+
184
+ ${answers.description}
185
+
186
+ ## \uAE30\uC220 \uC2A4\uD0DD
187
+
188
+ ${techList || "- (\uC9C1\uC811 \uC785\uB825\uD558\uC138\uC694)"}
189
+
190
+ ## \uC778\uD504\uB77C
191
+
192
+ ${infraList || "- (\uC9C1\uC811 \uC785\uB825\uD558\uC138\uC694)"}
193
+
194
+ ## \uB514\uB809\uD1A0\uB9AC \uAD6C\uC870
195
+
196
+ > \uD504\uB85C\uC81D\uD2B8\uC5D0 \uB9DE\uAC8C \uC544\uB798\uB97C \uC218\uC815\uD558\uC138\uC694.
197
+
198
+ - \`src/\` \u2014 \uC18C\uC2A4 \uCF54\uB4DC
199
+ - \`docs/\` \u2014 \uBB38\uC11C
200
+ - \`tools/\` \u2014 \uAC1C\uBC1C \uB3C4\uAD6C (\uCE78\uBC18 \uB4F1)
201
+
202
+ ## \uCF54\uB529 \uCEE8\uBCA4\uC158
203
+
204
+ > \uD504\uB85C\uC81D\uD2B8\uC5D0 \uB9DE\uAC8C \uC544\uB798\uB97C \uC218\uC815\uD558\uC138\uC694.
205
+
206
+ - TypeScript strict mode
207
+ - ESLint + Prettier
208
+ - \`console.log\` \uAE08\uC9C0 (\uD504\uB85C\uB355\uC158)
209
+
210
+ ## \uC791\uC5C5 \uD504\uB85C\uD1A0\uCF5C
211
+
212
+ - **\uCE78\uBC18 \uC11C\uBC84**: \`http://localhost:${answers.port}\`
213
+ - **Slack \uBCF4\uACE0**: \`POST http://localhost:${answers.port}/api/tasks/{TASK_ID}/slack\`
214
+ - **\uB85C\uADF8 \uB514\uB809\uD1A0\uB9AC**: \`.claude/logs/\`
215
+ - **\uC0C1\uD0DC \uD50C\uB85C\uC6B0**: pending \u2192 in_progress \u2192 in_review \u2192 completed
216
+
217
+ \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:
218
+
219
+ 1. **Slack \uBCF4\uACE0**: \`curl -s -X POST http://localhost:${answers.port}/api/tasks/{TASK_ID}/slack -H "Content-Type: application/json" -d '{"text":"\uBA54\uC2DC\uC9C0"}'\`
220
+ 2. **\uCE78\uBC18 \uC5C5\uB370\uC774\uD2B8**: \`PUT http://localhost:${answers.port}/api/tasks/{id}\` (status, reportSummary, reportPath)
221
+ 3. **\uB85C\uADF8 \uD30C\uC77C**: \`.claude/logs/{YYYY-MM-DD}_{task-slug}.md\`
222
+ `;
223
+ }
224
+
225
+ // src/generators/agent-prompt.ts
226
+ import path from "path";
227
+ import fs from "fs-extra";
228
+ var AGENT_TEMPLATES = {
229
+ frontend: {
230
+ role: "\uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C, UI \uAD6C\uD604, \uCEF4\uD3EC\uB10C\uD2B8 \uC791\uC5C5\uC744 \uB2F4\uB2F9\uD558\uB294 \uC5D0\uC774\uC804\uD2B8.",
231
+ responsibilities: [
232
+ "\uCEF4\uD3EC\uB10C\uD2B8 \uC2E0\uADDC \uAC1C\uBC1C \uBC0F \uC218\uC815",
233
+ "\uD398\uC774\uC9C0 \uB808\uC774\uC544\uC6C3, \uB77C\uC6B0\uD305 \uC5F0\uACB0",
234
+ "CSS/\uC2A4\uD0C0\uC77C\uB9C1 (\uB514\uC790\uC778 \uD1A0\uD070 \uAE30\uBC18)",
235
+ "\uBC18\uC751\uD615 \uB300\uC751 (\uBAA8\uBC14\uC77C/\uD0DC\uBE14\uB9BF/\uB370\uC2A4\uD06C\uD1B1)",
236
+ "\uD074\uB77C\uC774\uC5B8\uD2B8 \uC0C1\uD0DC \uAD00\uB9AC",
237
+ "\uD3FC \uAC80\uC99D, \uC0AC\uC6A9\uC790 \uC778\uD130\uB799\uC158 \uCC98\uB9AC"
238
+ ],
239
+ constraints: [
240
+ "\uD560\uB2F9\uBC1B\uC740 \uD0DC\uC2A4\uD06C \uBC94\uC704\uB9CC \uC218\uD589. \uBC94\uC704 \uBC16 \uC791\uC5C5 \uBC1C\uACAC \uC2DC Orchestrator\uC5D0 \uBCF4\uACE0.",
241
+ "DB/API \uBCC0\uACBD \uAE08\uC9C0 \u2014 backend agent \uC601\uC5ED.",
242
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
243
+ ],
244
+ standards: "- TypeScript strict. `any` \uAE08\uC9C0.\n- ESLint \uACBD\uACE0 \uC99D\uAC00 \uAE08\uC9C0.\n- \uCEF4\uD3EC\uB10C\uD2B8: PascalCase \uD30C\uC77C\uBA85."
245
+ },
246
+ backend: {
247
+ role: "\uBC31\uC5D4\uB4DC API, \uB370\uC774\uD130\uBCA0\uC774\uC2A4, \uC11C\uBC84 \uB85C\uC9C1\uC744 \uB2F4\uB2F9\uD558\uB294 \uC5D0\uC774\uC804\uD2B8.",
248
+ responsibilities: [
249
+ "API \uC5D4\uB4DC\uD3EC\uC778\uD2B8 \uAC1C\uBC1C/\uC218\uC815",
250
+ "DB \uC2A4\uD0A4\uB9C8 \uC124\uACC4, \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uC791\uC131",
251
+ "\uC11C\uBE44\uC2A4 \uD568\uC218 \uAD6C\uD604",
252
+ "\uC778\uC99D/\uC778\uAC00 \uB85C\uC9C1",
253
+ "\uB370\uC774\uD130 \uAC80\uC99D, \uC5D0\uB7EC \uCC98\uB9AC"
254
+ ],
255
+ constraints: [
256
+ "\uD504\uB860\uD2B8\uC5D4\uB4DC \uCEF4\uD3EC\uB10C\uD2B8 \uC218\uC815 \uAE08\uC9C0 \u2014 frontend agent \uC601\uC5ED.",
257
+ "DB \uC2A4\uD0A4\uB9C8 \uBCC0\uACBD \uC2DC \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uD30C\uC77C\uB85C \uBCC4\uB3C4 \uC791\uC131.",
258
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
259
+ ],
260
+ standards: "- Parameterized query \uD544\uC218 (SQL injection \uBC29\uC9C0).\n- \uD658\uACBD\uBCC0\uC218 \uD558\uB4DC\uCF54\uB529 \uAE08\uC9C0.\n- \uBBFC\uAC10 \uC815\uBCF4 \uCF54\uB4DC \uD3EC\uD568 \uAE08\uC9C0."
261
+ },
262
+ qa: {
263
+ role: "\uCF54\uB4DC \uD488\uC9C8, \uD14C\uC2A4\uD2B8, \uB9B0\uD2B8, \uBC84\uADF8 \uD0D0\uC9C0, \uAC80\uC99D\uC744 \uB2F4\uB2F9\uD558\uB294 \uC5D0\uC774\uC804\uD2B8.",
264
+ responsibilities: [
265
+ "\uCF54\uB4DC \uB9AC\uBDF0 \u2014 \uBC84\uADF8, \uBCF4\uC548 \uCDE8\uC57D\uC810, \uC131\uB2A5 \uC774\uC288 \uD0D0\uC9C0",
266
+ "\uD14C\uC2A4\uD2B8 \uC791\uC131",
267
+ "\uB9B0\uD2B8 \uACBD\uACE0/\uC5D0\uB7EC \uC218\uC815",
268
+ "\uBE4C\uB4DC \uC5D0\uB7EC \uC9C4\uB2E8 \uBC0F \uC218\uC815",
269
+ "\uBBF8\uC0AC\uC6A9 \uD30C\uC77C, dead code \uD0D0\uC9C0",
270
+ "\uB2E4\uB978 \uC5D0\uC774\uC804\uD2B8 \uACB0\uACFC\uBB3C \uAC80\uC99D"
271
+ ],
272
+ constraints: [
273
+ "\uAE30\uB2A5 \uCD94\uAC00 \uAE08\uC9C0. \uBC84\uADF8 \uC218\uC815\uACFC \uD488\uC9C8 \uAC1C\uC120\uB9CC.",
274
+ "\uAE30\uC874 \uB3D9\uC791 \uBCC0\uACBD \uC2DC \uD14C\uC2A4\uD2B8\uB85C \uD655\uC778.",
275
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
276
+ ]
277
+ },
278
+ designer: {
279
+ role: "\uB514\uC790\uC778 \uC2DC\uC2A4\uD15C, UI/UX \uC124\uACC4, \uBE44\uC8FC\uC5BC \uAC00\uC774\uB4DC\uB97C \uB2F4\uB2F9\uD558\uB294 \uC5D0\uC774\uC804\uD2B8.",
280
+ responsibilities: [
281
+ "\uB514\uC790\uC778 \uD1A0\uD070 \uAD00\uB9AC (\uC0C9\uC0C1, \uD0C0\uC774\uD3EC, \uAC04\uACA9, \uADF8\uB9BC\uC790, radius)",
282
+ "\uCEF4\uD3EC\uB10C\uD2B8 \uB514\uC790\uC778",
283
+ "\uD398\uC774\uC9C0 \uB808\uC774\uC544\uC6C3 \uC124\uACC4",
284
+ "\uB2E4\uD06C \uBAA8\uB4DC / \uD14C\uB9C8 \uC2DC\uC2A4\uD15C",
285
+ "\uBC18\uC751\uD615 \uBE0C\uB808\uC774\uD06C\uD3EC\uC778\uD2B8 \uAD00\uB9AC",
286
+ "\uC811\uADFC\uC131 (\uC0C9\uC0C1 \uB300\uBE44, \uD3EC\uCEE4\uC2A4 \uC0C1\uD0DC)"
287
+ ],
288
+ constraints: [
289
+ "\uB514\uC790\uC778 \uD1A0\uD070 \uBCC0\uACBD \uC2DC \uC601\uD5A5 \uBC94\uC704 \uC0AC\uC804 \uBD84\uC11D \uD544\uC218.",
290
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
291
+ ]
292
+ },
293
+ devops: {
294
+ role: "\uBC30\uD3EC, CI/CD, \uBE4C\uB4DC, \uC778\uD504\uB77C, \uD658\uACBD \uC124\uC815\uC744 \uB2F4\uB2F9\uD558\uB294 \uC5D0\uC774\uC804\uD2B8.",
295
+ responsibilities: [
296
+ "\uBC30\uD3EC \uC124\uC815 \uBC0F \uD2B8\uB7EC\uBE14\uC288\uD305",
297
+ "\uD658\uACBD \uBCC0\uC218 \uAD00\uB9AC",
298
+ "\uBE4C\uB4DC \uCD5C\uC801\uD654",
299
+ "CI/CD \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC791\uC131/\uC218\uC815",
300
+ "\uC758\uC874\uC131 \uAD00\uB9AC (\uBCF4\uC548 \uCDE8\uC57D\uC810, \uBC84\uC804 \uC5C5\uB370\uC774\uD2B8)"
301
+ ],
302
+ constraints: [
303
+ "\uD504\uB85C\uB355\uC158 \uD658\uACBD \uC9C1\uC811 \uBCC0\uACBD \uAE08\uC9C0. \uC124\uC815 \uD30C\uC77C \uC218\uC815\uB9CC.",
304
+ "\uD658\uACBD \uBCC0\uC218 \uAC12 \uCF54\uB4DC/\uB85C\uADF8 \uB178\uCD9C \uAE08\uC9C0.",
305
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
306
+ ]
307
+ },
308
+ researcher: {
309
+ role: "\uC870\uC0AC, \uBD84\uC11D, \uBB38\uC11C\uD654\uB97C \uB2F4\uB2F9\uD558\uB294 \uB9AC\uC11C\uCC98 \uC5D0\uC774\uC804\uD2B8.\n\uCF54\uB4DC\uB97C \uC218\uC815\uD558\uC9C0 \uC54A\uACE0, \uC815\uBCF4\uB97C \uC218\uC9D1\uD558\uC5EC \uAD6C\uC870\uD654\uB41C \uBCF4\uACE0\uC11C\uB97C \uC791\uC131\uD55C\uB2E4.",
310
+ responsibilities: [
311
+ "\uCF54\uB4DC\uBCA0\uC774\uC2A4 \uD604\uD669 \uBD84\uC11D",
312
+ "\uAE30\uC220 \uC870\uC0AC (\uB77C\uC774\uBE0C\uB7EC\uB9AC \uBE44\uAD50, API \uBB38\uC11C \uBD84\uC11D)",
313
+ "\uACBD\uC7C1\uC0AC/\uC2DC\uC7A5 \uC870\uC0AC (WebSearch \uD65C\uC6A9)",
314
+ "\uAE30\uC874 \uCF54\uB4DC \uBB38\uC81C\uC810 \uBC0F \uAC1C\uC120 \uBC29\uD5A5 \uB3C4\uCD9C",
315
+ "\uAD6C\uC870\uD654\uB41C \uBCF4\uACE0\uC11C \uC791\uC131"
316
+ ],
317
+ constraints: [
318
+ "\uCF54\uB4DC \uC218\uC815 \uAE08\uC9C0. \uC77D\uAE30 \uC804\uC6A9 \uC870\uC0AC\uB9CC.",
319
+ "\uCD94\uCE21 \uAE08\uC9C0. \uCF54\uB4DC \uAE30\uBC18 \uC0AC\uC2E4\uB9CC \uBCF4\uACE0.",
320
+ "\uD30C\uC77C \uACBD\uB85C\uB294 \uD56D\uC0C1 \uC808\uB300 \uACBD\uB85C\uB85C \uBA85\uC2DC.",
321
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
322
+ ]
323
+ },
324
+ orchestrator: {
325
+ role: "\uD504\uB85C\uC81D\uD2B8\uC758 \uC911\uC559 \uAD00\uC81C \uC5D0\uC774\uC804\uD2B8. \uD0DC\uC2A4\uD06C \uBD84\uD574, \uC5D0\uC774\uC804\uD2B8 \uBC30\uBD84, \uACB0\uACFC \uAC80\uC99D, \uC885\uD569 \uBCF4\uACE0\uB97C \uC218\uD589\uD55C\uB2E4.",
326
+ responsibilities: [
327
+ "\uCE78\uBC18 \uBCF4\uB4DC\uC5D0\uC11C pending \uD0DC\uC2A4\uD06C \uD655\uC778 \uBC0F \uBD84\uC11D",
328
+ "\uD0DC\uC2A4\uD06C\uB97C \uC11C\uBE0C\uD0DC\uC2A4\uD06C\uB85C \uBD84\uD574 (\uC758\uC874\uC131 \uD30C\uC545)",
329
+ "\uAC01 \uC11C\uBE0C\uD0DC\uC2A4\uD06C\uC5D0 \uC801\uD569\uD55C \uC5D0\uC774\uC804\uD2B8 \uBC30\uBD84",
330
+ "\uC5D0\uC774\uC804\uD2B8 \uACB0\uACFC\uBB3C \uAC80\uC99D",
331
+ "\uC885\uD569 \uBCF4\uACE0\uC11C \uC791\uC131"
332
+ ],
333
+ constraints: [
334
+ "\uC9C1\uC811 \uCF54\uB4DC\uB97C \uC218\uC815\uD558\uC9C0 \uC54A\uB294\uB2E4. \uAD00\uB9AC, \uAC80\uC99D, \uBCF4\uACE0\uB9CC \uC218\uD589.",
335
+ "\uC0AC\uC6A9\uC790 \uC2B9\uC778 \uC5C6\uC774 \uB2E4\uC74C \uB2E8\uACC4\uB85C \uC9C4\uD589\uD558\uC9C0 \uC54A\uB294\uB2E4.",
336
+ "\uC5D0\uC774\uC804\uD2B8 \uACB0\uACFC\uB97C \uB9F9\uC2E0\uD558\uC9C0 \uC54A\uB294\uB2E4. \uBC18\uB4DC\uC2DC \uAC80\uC99D \uD6C4 \uC644\uB8CC \uCC98\uB9AC."
337
+ ]
338
+ },
339
+ strategist: {
340
+ role: "\uC544\uD0A4\uD14D\uCC98 \uC124\uACC4, \uAE30\uC220 \uC758\uC0AC\uACB0\uC815, \uB9AC\uD329\uD1A0\uB9C1 \uC804\uB7B5\uC744 \uB2F4\uB2F9\uD558\uB294 \uC804\uB7B5 \uC5D0\uC774\uC804\uD2B8.\n\uC9C1\uC811 \uCF54\uB4DC\uB97C \uC218\uC815\uD558\uC9C0 \uC54A\uACE0, \uC758\uC0AC\uACB0\uC815 \uBB38\uC11C\uC640 \uC2E4\uD589 \uACC4\uD68D\uC744 \uC791\uC131\uD55C\uB2E4.",
341
+ responsibilities: [
342
+ "\uC2DC\uC2A4\uD15C \uC544\uD0A4\uD14D\uCC98 \uC124\uACC4 \uBC0F \uB9AC\uBDF0",
343
+ "\uAE30\uC220 \uC2A4\uD0DD \uC120\uD0DD \uADFC\uAC70 \uC81C\uC2DC (\uC120\uD0DD\uC9C0 \uBE44\uAD50)",
344
+ "\uB9AC\uD329\uD1A0\uB9C1 \uC804\uB7B5 (\uB2E8\uACC4\uBCC4 \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uACC4\uD68D)",
345
+ "\uC131\uB2A5/\uD655\uC7A5\uC131/\uC720\uC9C0\uBCF4\uC218\uC131 \uAD00\uC810 \uC758\uC0AC\uACB0\uC815",
346
+ "ADR(Architecture Decision Record) \uC791\uC131"
347
+ ],
348
+ constraints: [
349
+ "\uCF54\uB4DC \uC9C1\uC811 \uC218\uC815 \uAE08\uC9C0. \uC124\uACC4\uC640 \uACC4\uD68D\uB9CC.",
350
+ "\uC120\uD0DD\uC9C0 \uCD5C\uC18C 2\uAC1C \uC774\uC0C1. \uAC01\uAC01 \uC7A5\uB2E8\uC810 + \uACF5\uC218 \uBA85\uC2DC.",
351
+ "\uD604\uC7AC \uCF54\uB4DC\uBCA0\uC774\uC2A4 \uAE30\uBC18 \uC2E4\uD604 \uAC00\uB2A5\uD55C \uACC4\uD68D\uB9CC \uC81C\uC2DC.",
352
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
353
+ ]
354
+ },
355
+ "content-planner": {
356
+ role: "\uCF58\uD150\uCE20 \uAE30\uD68D, \uC790\uB8CC \uC870\uC0AC, \uCEE4\uB9AC\uD058\uB7FC \uC124\uACC4\uB97C \uB2F4\uB2F9\uD558\uB294 \uCF58\uD150\uCE20 \uAE30\uD68D \uC5D0\uC774\uC804\uD2B8.",
357
+ responsibilities: [
358
+ "\uCEE4\uB9AC\uD058\uB7FC \uC124\uACC4 \u2014 \uBAA9\uCC28 \uAD6C\uC131, \uD559\uC2B5 \uBAA9\uD45C \uC124\uC815",
359
+ "\uC790\uB8CC \uC870\uC0AC \u2014 \uCD5C\uC2E0 \uD2B8\uB80C\uB4DC, \uAE30\uC220 \uB3D9\uD5A5, \uC0AC\uB840 \uC218\uC9D1",
360
+ "\uCF58\uD150\uCE20 \uC791\uC131/\uC218\uC815",
361
+ "\uD559\uC2B5 \uD750\uB984 \uAC80\uC99D"
362
+ ],
363
+ constraints: [
364
+ "\uCF54\uB4DC \uC9C1\uC811 \uC218\uC815 \uAE08\uC9C0 \u2014 \uCF58\uD150\uCE20\uB9CC \uB2F4\uB2F9.",
365
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
366
+ ]
367
+ },
368
+ "item-author": {
369
+ role: "\uBB38\uD56D \uAC1C\uBC1C, \uAC80\uC218, \uB8E8\uBE0C\uB9AD \uC124\uACC4\uB97C \uB2F4\uB2F9\uD558\uB294 \uCD9C\uC81C \uC5D0\uC774\uC804\uD2B8.",
370
+ responsibilities: [
371
+ "\uBB38\uD56D \uC2E0\uADDC \uC791\uC131",
372
+ "\uAE30\uC874 \uBB38\uD56D \uC624\uB958/\uBAA8\uD638\uD568/\uB09C\uC774\uB3C4 \uAC80\uD1A0",
373
+ "\uCC44\uC810 \uAE30\uC900 \uC124\uACC4",
374
+ "\uB09C\uC774\uB3C4 \uBC30\uBD84 \uAD00\uB9AC"
375
+ ],
376
+ constraints: [
377
+ "\uBB38\uD56D \uB0B4\uC6A9\uC758 \uC815\uD655\uC131 \uCD5C\uC6B0\uC120. \uBD88\uD655\uC2E4\uD55C \uC815\uBCF4 \uAE30\uBC18 \uCD9C\uC81C \uAE08\uC9C0.",
378
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
379
+ ]
380
+ },
381
+ "doc-writer": {
382
+ role: "\uD504\uB85C\uC81D\uD2B8 \uBB38\uC11C, \uBCF4\uACE0\uC11C, \uAC00\uC774\uB4DC\uB97C \uC791\uC131\uD558\uB294 \uBB38\uC11C \uC5D0\uC774\uC804\uD2B8.",
383
+ responsibilities: [
384
+ "\uD504\uB85C\uC81D\uD2B8 \uAE30\uC220 \uBB38\uC11C \uC791\uC131 (\uC544\uD0A4\uD14D\uCC98, API, \uBC30\uD3EC \uAC00\uC774\uB4DC)",
385
+ "\uC791\uC5C5 \uBCF4\uACE0\uC11C, \uBD84\uC11D \uACB0\uACFC\uB97C \uAD6C\uC870\uD654\uB41C \uBB38\uC11C\uB85C \uC815\uB9AC",
386
+ "\uBB38\uC11C \uAC04 \uB9C1\uD06C \uCCB4\uACC4 \uAD00\uB9AC",
387
+ "\uBB38\uC11C \uC2A4\uD0C0\uC77C \uC77C\uAD00\uC131 \uC720\uC9C0"
388
+ ],
389
+ constraints: [
390
+ "\uCF54\uB4DC \uC218\uC815 \uAE08\uC9C0. \uBB38\uC11C\uB9CC \uB2F4\uB2F9.",
391
+ "\uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC Slack + \uCE78\uBC18 + \uB9AC\uD3EC\uD2B8 \uD30C\uC77C 3\uACF3 \uBAA8\uB450 \uAE30\uB85D."
392
+ ]
393
+ }
394
+ };
395
+ function buildBaseSections(answers) {
396
+ return `## Project Context
397
+ - **\uD504\uB85C\uC81D\uD2B8**: ${answers.projectName}
398
+ - **\uCE78\uBC18 API**: \`http://localhost:${answers.port}/api/tasks\`
399
+ - **Slack API**: \`POST http://localhost:${answers.port}/api/tasks/{TASK_ID}/slack\`
400
+ - **\uB85C\uADF8 \uB514\uB809\uD1A0\uB9AC**: \`.claude/logs/\`
401
+
402
+ ## Slack Reporting
403
+ \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):
404
+ \`\`\`bash
405
+ curl -s -X POST http://localhost:${answers.port}/api/tasks/{TASK_ID}/slack \\
406
+ -H "Content-Type: application/json" -d '{"text":"\uBA54\uC2DC\uC9C0"}'
407
+ \`\`\`
408
+ \`$SLACK_AGENT_WEBHOOK\` \uC9C1\uC811 \uC0AC\uC6A9 \uAE08\uC9C0. \uBC18\uB4DC\uC2DC \uC704 API\uB97C \uD1B5\uD574 \uBCF4\uACE0.
409
+ \`{TASK_ID}\`\uB294 buildExecutorPrompt\uC5D0\uC11C \uC2E4\uC81C ID\uAC00 \uC8FC\uC785\uB41C\uB2E4.
410
+
411
+ ## Kanban Update
412
+ 1. \uC2DC\uC791: \`PUT /api/tasks/{id}\` \u2014 \`status: "in_progress"\`, \`activeForm: "\uC218\uD589 \uC911 \uC124\uBA85"\`
413
+ 2. \uC644\uB8CC: \`PUT /api/tasks/{id}\` \u2014 \`status: "completed"\`, \`reportPath\`, \`reportSummary\`
414
+ 3. reportSummary \uD3EC\uB9F7: \`\uC218\uD589 \uB0B4\uC5ED \uC694\uC57D 1\uC904. \uD6C4\uC18D: \uB2E4\uC74C \uC791\uC5C5 \uC81C\uC548\`
415
+
416
+ ## Report File
417
+ \uC644\uB8CC \uD6C4 \uBC18\uB4DC\uC2DC \uBCF4\uACE0\uC11C \uC791\uC131:
418
+ - \uACBD\uB85C: \`.claude/logs/{YYYY-MM-DD}_{task-slug}.md\`
419
+ - \uB0B4\uC6A9: \uBCC0\uACBD \uD30C\uC77C \uBAA9\uB85D, \uBCC0\uACBD \uB0B4\uC6A9, \uAC80\uC99D \uACB0\uACFC, \uD6C4\uC18D \uC791\uC5C5`;
420
+ }
421
+ var AGENT_DISPLAY_NAMES = {
422
+ frontend: "Frontend Agent",
423
+ backend: "Backend Agent",
424
+ qa: "QA Agent",
425
+ designer: "Designer Agent",
426
+ devops: "DevOps Agent",
427
+ researcher: "Researcher Agent",
428
+ orchestrator: "Orchestrator Agent",
429
+ strategist: "Strategist Agent",
430
+ "content-planner": "Content Planner Agent",
431
+ "item-author": "Item Author Agent",
432
+ "doc-writer": "Document Writer Agent"
433
+ };
434
+ function generateAgentPrompt(agent, answers, model, templatesDir) {
435
+ const templatePath = path.join(templatesDir, "agents", `${agent}.md`);
436
+ if (fs.existsSync(templatePath)) {
437
+ let content2 = fs.readFileSync(templatePath, "utf-8");
438
+ content2 = content2.replace(/\{\{projectName\}\}/g, answers.projectName);
439
+ content2 = content2.replace(/\{\{port\}\}/g, String(answers.port));
440
+ content2 = content2.replace(/\{\{description\}\}/g, answers.description);
441
+ return content2;
442
+ }
443
+ const tmpl = AGENT_TEMPLATES[agent];
444
+ if (!tmpl) {
445
+ return `# ${agent} Agent
446
+
447
+ ## Role
448
+ Custom agent.
449
+
450
+ ${buildBaseSections(answers)}`;
451
+ }
452
+ const displayName = AGENT_DISPLAY_NAMES[agent] || `${agent} Agent`;
453
+ const responsibilities = tmpl.responsibilities.map((r, i) => `${i + 1}. ${r}`).join("\n");
454
+ const constraints = tmpl.constraints.map((c) => `- ${c}`).join("\n");
455
+ let content = `# ${displayName}
456
+
457
+ ## Role
458
+ ${tmpl.role}
459
+
460
+ ${buildBaseSections(answers)}
461
+
462
+ ## Responsibilities
463
+ ${responsibilities}
464
+ `;
465
+ if (tmpl.standards) {
466
+ content += `
467
+ ## Code Standards
468
+ ${tmpl.standards}
469
+ `;
470
+ }
471
+ content += `
472
+ ## Constraints
473
+ ${constraints}
474
+ `;
475
+ return content;
476
+ }
477
+
478
+ // src/generators/env-file.ts
479
+ function generateEnvFile(answers) {
480
+ const lines = [
481
+ "# \uCE78\uBC18 \uC11C\uBC84",
482
+ `PORT=${answers.port}`,
483
+ ""
484
+ ];
485
+ if (answers.slackEnabled) {
486
+ lines.push(
487
+ "# Slack \uC5F0\uB3D9",
488
+ "SLACK_BOT_TOKEN=xoxb-...",
489
+ "SLACK_APP_TOKEN=xapp-...",
490
+ "SLACK_CHANNEL_ID=C...",
491
+ "SLACK_ADMIN_USERS=U...,U...",
492
+ ""
493
+ );
494
+ } else {
495
+ lines.push(
496
+ "# Slack \uC5F0\uB3D9 (\uB098\uC911\uC5D0 \uC124\uC815)",
497
+ "# SLACK_BOT_TOKEN=xoxb-...",
498
+ "# SLACK_APP_TOKEN=xapp-...",
499
+ "# SLACK_CHANNEL_ID=C...",
500
+ "# SLACK_ADMIN_USERS=U...,U...",
501
+ ""
502
+ );
503
+ }
504
+ return lines.join("\n");
505
+ }
506
+
507
+ // src/utils/pkg-manager.ts
508
+ function detectPackageManager() {
509
+ const ua = process.env.npm_config_user_agent;
510
+ if (!ua) return "npm";
511
+ if (ua.startsWith("pnpm")) return "pnpm";
512
+ if (ua.startsWith("yarn")) return "yarn";
513
+ if (ua.startsWith("bun")) return "bun";
514
+ return "npm";
515
+ }
516
+
517
+ // src/utils/git.ts
518
+ import { execSync } from "child_process";
519
+ import path2 from "path";
520
+ import fs2 from "fs-extra";
521
+ async function initGit(targetDir) {
522
+ const gitDir = path2.join(targetDir, ".git");
523
+ if (fs2.existsSync(gitDir)) return;
524
+ try {
525
+ execSync("git init", { cwd: targetDir, stdio: "ignore" });
526
+ } catch {
527
+ }
528
+ }
529
+
530
+ // src/scaffold.ts
531
+ var __filename = fileURLToPath(import.meta.url);
532
+ var __dirname = path3.dirname(__filename);
533
+ function getTemplatesDir() {
534
+ const devPath = path3.join(__dirname, "..", "templates");
535
+ if (fs3.existsSync(devPath)) return devPath;
536
+ const pkgPath = path3.join(__dirname, "..", "templates");
537
+ return pkgPath;
538
+ }
539
+ async function scaffold(answers) {
540
+ const targetDir = path3.resolve(answers.targetDir);
541
+ const templatesDir = getTemplatesDir();
542
+ const s = p2.spinner();
543
+ s.start("\uB514\uB809\uD1A0\uB9AC \uC0DD\uC131 \uC911...");
544
+ await fs3.ensureDir(path3.join(targetDir, "tools"));
545
+ await fs3.ensureDir(path3.join(targetDir, ".claude", "agents"));
546
+ await fs3.ensureDir(path3.join(targetDir, ".claude", "logs"));
547
+ await fs3.ensureDir(path3.join(targetDir, ".claude", "tasks", "kanban"));
548
+ s.stop("\uB514\uB809\uD1A0\uB9AC \uC0DD\uC131 \uC644\uB8CC");
549
+ s.start("\uCE78\uBC18 \uC11C\uBC84 \uBCF5\uC0AC \uC911...");
550
+ const kanbanSrc = path3.join(templatesDir, "kanban.cjs");
551
+ const kanbanDest = path3.join(targetDir, "tools", "kanban.cjs");
552
+ if (fs3.existsSync(kanbanSrc)) {
553
+ await fs3.copy(kanbanSrc, kanbanDest);
554
+ }
555
+ s.stop("\uCE78\uBC18 \uC11C\uBC84 \uBCF5\uC0AC \uC644\uB8CC");
556
+ s.start("\uCE78\uBC18 UI \uBCF5\uC0AC \uC911...");
557
+ const htmlSrc = path3.join(templatesDir, "kanban.html");
558
+ const htmlDest = path3.join(targetDir, "tools", "kanban.html");
559
+ if (fs3.existsSync(htmlSrc)) {
560
+ await fs3.copy(htmlSrc, htmlDest);
561
+ }
562
+ s.stop("\uCE78\uBC18 UI \uBCF5\uC0AC \uC644\uB8CC");
563
+ s.start("\uC124\uC815 \uD30C\uC77C \uC0DD\uC131 \uC911...");
564
+ const config = generateConfig(answers);
565
+ await fs3.writeFile(
566
+ path3.join(targetDir, "kanban.config.json"),
567
+ JSON.stringify(config, null, 2)
568
+ );
569
+ s.stop("\uC124\uC815 \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC");
570
+ s.start("\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8 \uC0DD\uC131 \uC911...");
571
+ const projectContext = generateProjectContext(answers);
572
+ await fs3.writeFile(
573
+ path3.join(targetDir, ".claude", "agents", "_project-context.md"),
574
+ projectContext
575
+ );
576
+ s.stop("\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8 \uC0DD\uC131 \uC644\uB8CC");
577
+ s.start("\uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 \uC0DD\uC131 \uC911...");
578
+ for (const agent of answers.agents) {
579
+ const model = getModelForAgent(agent, answers.defaultModel);
580
+ const prompt = generateAgentPrompt(agent, answers, model, templatesDir);
581
+ await fs3.writeFile(
582
+ path3.join(targetDir, ".claude", "agents", `${agent}.md`),
583
+ prompt
584
+ );
585
+ }
586
+ s.stop(`\uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 ${answers.agents.length}\uAC1C \uC0DD\uC131 \uC644\uB8CC`);
587
+ s.start("\uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815 \uC0DD\uC131 \uC911...");
588
+ const orchSrc = path3.join(templatesDir, "orchestrator.md");
589
+ if (fs3.existsSync(orchSrc)) {
590
+ let orchContent = await fs3.readFile(orchSrc, "utf-8");
591
+ orchContent = orchContent.replace(/\{\{projectName\}\}/g, answers.projectName);
592
+ orchContent = orchContent.replace(/\{\{port\}\}/g, String(answers.port));
593
+ const agentRows = answers.agents.map((a) => {
594
+ const model = getModelForAgent(a, answers.defaultModel);
595
+ return `| ${a} | ${model} |`;
596
+ });
597
+ orchContent = orchContent.replace("{{agentTable}}", agentRows.join("\n"));
598
+ await fs3.writeFile(
599
+ path3.join(targetDir, ".claude", "orchestrator.md"),
600
+ orchContent
601
+ );
602
+ }
603
+ s.stop("\uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815 \uC0DD\uC131 \uC644\uB8CC");
604
+ s.start(".env.example \uC0DD\uC131 \uC911...");
605
+ const envContent = generateEnvFile(answers);
606
+ await fs3.writeFile(
607
+ path3.join(targetDir, ".env.example"),
608
+ envContent
609
+ );
610
+ s.stop(".env.example \uC0DD\uC131 \uC644\uB8CC");
611
+ const pm = detectPackageManager();
612
+ await initGit(targetDir);
613
+ }
614
+
615
+ // src/index.ts
616
+ async function main() {
617
+ console.log();
618
+ p3.intro(`${pc.bgCyan(pc.black(" create-claude-kanban "))} ${pc.dim("v1.0.0")}`);
619
+ const answers = await runPrompts();
620
+ if (!answers) {
621
+ p3.cancel("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
622
+ process.exit(0);
623
+ }
624
+ await scaffold(answers);
625
+ const files = [
626
+ `tools/kanban.cjs \u2014 \uCE78\uBC18 \uC11C\uBC84`,
627
+ `tools/kanban.html \u2014 \uCE78\uBC18 UI`,
628
+ `kanban.config.json \u2014 \uC124\uC815 \uD30C\uC77C`,
629
+ `.claude/agents/ \u2014 \uC5D0\uC774\uC804\uD2B8 \uD504\uB86C\uD504\uD2B8 ${answers.agents.length}\uAC1C`,
630
+ `.claude/orchestrator.md \u2014 \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uD130 \uC124\uC815`,
631
+ `.env.example \u2014 \uD658\uACBD\uBCC0\uC218 \uD15C\uD50C\uB9BF`
632
+ ];
633
+ p3.note(files.join("\n"), "\uC0DD\uC131 \uC644\uB8CC");
634
+ p3.outro(`${pc.green("node tools/kanban.cjs")} \uB85C \uC2DC\uC791\uD558\uC138\uC694!`);
635
+ }
636
+ main().catch((err) => {
637
+ p3.cancel("\uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
638
+ console.error(err);
639
+ process.exit(1);
640
+ });
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "create-claude-kanban",
3
+ "version": "1.0.0",
4
+ "description": "Scaffold a multi-agent kanban system for Claude Code projects",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-claude-kanban": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "templates"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsup",
15
+ "dev": "tsup --watch",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "claude",
20
+ "kanban",
21
+ "agent",
22
+ "scaffold",
23
+ "cli"
24
+ ],
25
+ "license": "MIT",
26
+ "dependencies": {
27
+ "@clack/prompts": "^0.9.1",
28
+ "picocolors": "^1.1.1",
29
+ "fs-extra": "^11.2.0"
30
+ },
31
+ "devDependencies": {
32
+ "tsup": "^8.3.5",
33
+ "typescript": "^5.7.0",
34
+ "@types/fs-extra": "^11.0.4",
35
+ "@types/node": "^22.0.0"
36
+ }
37
+ }