@kood/claude-code 0.5.1 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/index.js +604 -261
  2. package/package.json +1 -1
  3. package/templates/.claude/agents/analyst.md +6 -14
  4. package/templates/.claude/agents/architect.md +6 -14
  5. package/templates/.claude/agents/code-reviewer.md +8 -14
  6. package/templates/.claude/agents/dependency-manager.md +8 -14
  7. package/templates/.claude/agents/deployment-validator.md +8 -14
  8. package/templates/.claude/agents/designer.md +8 -0
  9. package/templates/.claude/agents/document-writer.md +75 -316
  10. package/templates/.claude/agents/explore.md +8 -3
  11. package/templates/.claude/agents/git-operator.md +63 -17
  12. package/templates/.claude/agents/implementation-executor.md +14 -37
  13. package/templates/.claude/agents/ko-to-en-translator.md +8 -13
  14. package/templates/.claude/agents/lint-fixer.md +8 -172
  15. package/templates/.claude/agents/planner.md +6 -14
  16. package/templates/.claude/agents/refactor-advisor.md +8 -14
  17. package/templates/.claude/commands/git-all.md +3 -167
  18. package/templates/.claude/commands/git-session.md +3 -71
  19. package/templates/.claude/commands/lint-fix.md +119 -82
  20. package/templates/.claude/commands/lint-init.md +2 -54
  21. package/templates/.claude/commands/pre-deploy.md +143 -82
  22. package/templates/.claude/commands/version-update.md +171 -66
  23. package/templates/.claude/instructions/agent-patterns/agent-coordination.md +208 -0
  24. package/templates/.claude/instructions/agent-patterns/index.md +264 -0
  25. package/templates/.claude/instructions/agent-patterns/model-routing.md +167 -0
  26. package/templates/.claude/instructions/agent-patterns/parallel-execution.md +91 -0
  27. package/templates/.claude/instructions/agent-patterns/read-parallelization.md +106 -0
  28. package/templates/.claude/instructions/document-templates/ralph-templates.md +71 -0
  29. package/templates/.claude/instructions/index.md +350 -0
  30. package/templates/.claude/instructions/multi-agent/agent-roster.md +811 -0
  31. package/templates/.claude/{PARALLEL_AGENTS.md → instructions/multi-agent/coordination-guide.md} +27 -336
  32. package/templates/.claude/instructions/{parallel-agent-execution.md → multi-agent/execution-patterns.md} +127 -438
  33. package/templates/.claude/instructions/multi-agent/index.md +282 -0
  34. package/templates/.claude/instructions/multi-agent/performance-optimization.md +456 -0
  35. package/templates/.claude/instructions/tech-stack/design-standards.md +282 -0
  36. package/templates/.claude/instructions/tech-stack/index.md +70 -0
  37. package/templates/.claude/instructions/tech-stack/prisma-patterns.md +352 -0
  38. package/templates/.claude/instructions/tech-stack/tanstack-patterns.md +275 -0
  39. package/templates/.claude/instructions/validation/forbidden-patterns.md +281 -0
  40. package/templates/.claude/instructions/validation/index.md +32 -0
  41. package/templates/.claude/instructions/validation/required-behaviors.md +331 -0
  42. package/templates/.claude/instructions/validation/verification-checklist.md +318 -0
  43. package/templates/.claude/instructions/workflow-patterns/index.md +18 -0
  44. package/templates/.claude/instructions/workflow-patterns/phase-based-workflow.md +250 -0
  45. package/templates/.claude/instructions/workflow-patterns/sequential-thinking.md +217 -0
  46. package/templates/.claude/instructions/workflow-patterns/todowrite-pattern.md +215 -0
  47. package/templates/.claude/skills/bug-fix/SKILL.md +972 -0
  48. package/templates/.claude/skills/docs-creator/AGENTS.md +54 -173
  49. package/templates/.claude/skills/docs-creator/SKILL.md +146 -254
  50. package/templates/.claude/skills/docs-refactor/AGENTS.md +61 -187
  51. package/templates/.claude/skills/docs-refactor/SKILL.md +84 -315
  52. package/templates/.claude/skills/execute/SKILL.md +454 -154
  53. package/templates/.claude/skills/figma-to-code/AGENTS.md +4 -1
  54. package/templates/.claude/skills/figma-to-code/SKILL.md +306 -0
  55. package/templates/.claude/skills/global-uiux-design/AGENTS.md +4 -1
  56. package/templates/.claude/skills/global-uiux-design/SKILL.md +455 -125
  57. package/templates/.claude/skills/korea-uiux-design/AGENTS.md +4 -1
  58. package/templates/.claude/skills/korea-uiux-design/SKILL.md +461 -116
  59. package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +177 -0
  60. package/templates/.claude/skills/plan/SKILL.md +1157 -87
  61. package/templates/.claude/skills/prd/SKILL.md +367 -66
  62. package/templates/.claude/skills/ralph/AGENTS.md +4 -1
  63. package/templates/.claude/skills/ralph/SKILL.md +100 -14
  64. package/templates/.claude/skills/refactor/AGENTS.md +269 -0
  65. package/templates/.claude/skills/refactor/SKILL.md +1572 -0
  66. package/templates/.claude/skills/stitch-design/README.md +34 -0
  67. package/templates/.claude/skills/stitch-design/SKILL.md +213 -0
  68. package/templates/.claude/skills/stitch-design/examples/DESIGN.md +154 -0
  69. package/templates/.claude/skills/stitch-loop/README.md +54 -0
  70. package/templates/.claude/skills/stitch-loop/SKILL.md +316 -0
  71. package/templates/.claude/skills/stitch-loop/examples/SITE.md +73 -0
  72. package/templates/.claude/skills/stitch-loop/examples/next-prompt.md +25 -0
  73. package/templates/.claude/skills/stitch-loop/resources/baton-schema.md +61 -0
  74. package/templates/.claude/skills/stitch-loop/resources/site-template.md +104 -0
  75. package/templates/.claude/skills/stitch-react/README.md +36 -0
  76. package/templates/.claude/skills/stitch-react/SKILL.md +323 -0
  77. package/templates/.claude/skills/stitch-react/examples/gold-standard-card.tsx +88 -0
  78. package/templates/.claude/skills/stitch-react/package-lock.json +231 -0
  79. package/templates/.claude/skills/stitch-react/package.json +16 -0
  80. package/templates/.claude/skills/stitch-react/resources/architecture-checklist.md +15 -0
  81. package/templates/.claude/skills/stitch-react/resources/component-template.tsx +37 -0
  82. package/templates/.claude/skills/stitch-react/resources/stitch-api-reference.md +14 -0
  83. package/templates/.claude/skills/stitch-react/resources/style-guide.json +24 -0
  84. package/templates/.claude/skills/stitch-react/scripts/fetch-stitch.sh +30 -0
  85. package/templates/.claude/skills/stitch-react/scripts/validate.js +77 -0
  86. package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +149 -0
  87. package/templates/.claude/commands/bug-fix.md +0 -510
  88. package/templates/.claude/commands/refactor.md +0 -788
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
5
 
6
- // src/utils/logger.ts
6
+ // src/shared/logger.ts
7
7
  import pc from "picocolors";
8
8
  var logger = {
9
9
  info: (msg) => console.log(pc.cyan("\u2139"), msg),
@@ -22,25 +22,70 @@ var banner = () => {
22
22
  };
23
23
 
24
24
  // src/commands/init.ts
25
- import prompts from "prompts";
25
+ import fs7 from "fs-extra";
26
26
 
27
- // src/utils/copy.ts
28
- import fs from "fs-extra";
29
- import path from "path";
27
+ // src/features/templates/template-path-resolver.ts
28
+ import path2 from "path";
30
29
  import { fileURLToPath } from "url";
30
+
31
+ // src/shared/validators/path-validators.ts
32
+ import path from "path";
33
+ var validateTemplateName = (template) => {
34
+ const sanitized = path.basename(template);
35
+ if (sanitized !== template || template.includes("..")) {
36
+ throw new Error(`Invalid template name: "${template}"`);
37
+ }
38
+ };
39
+ var validateTargetDir = (targetDir) => {
40
+ const resolved = path.resolve(targetDir);
41
+ const protectedPaths = [
42
+ "/",
43
+ "/usr",
44
+ "/etc",
45
+ "/bin",
46
+ "/sbin",
47
+ "/home",
48
+ "/var",
49
+ "/root"
50
+ ];
51
+ if (process.platform === "win32") {
52
+ const winProtected = [
53
+ "C:\\Windows",
54
+ "C:\\Program Files",
55
+ "C:\\Program Files (x86)"
56
+ ];
57
+ protectedPaths.push(...winProtected);
58
+ }
59
+ for (const protectedPath of protectedPaths) {
60
+ if (resolved === protectedPath || resolved.startsWith(protectedPath + path.sep)) {
61
+ throw new Error(`Cannot modify protected system path: ${resolved}`);
62
+ }
63
+ }
64
+ };
65
+
66
+ // src/features/templates/template-path-resolver.ts
31
67
  var __filename2 = fileURLToPath(import.meta.url);
32
- var __dirname2 = path.dirname(__filename2);
68
+ var __dirname2 = path2.dirname(__filename2);
33
69
  var getTemplatesDir = () => {
34
- return path.resolve(__dirname2, "../templates");
70
+ return path2.resolve(__dirname2, "../templates");
35
71
  };
72
+ var getTemplatePath = (template) => {
73
+ validateTemplateName(template);
74
+ return path2.join(getTemplatesDir(), template);
75
+ };
76
+
77
+ // src/features/templates/template-installer.ts
78
+ import fs2 from "fs-extra";
79
+ import path4 from "path";
80
+
81
+ // src/shared/filesystem/copy-utils.ts
82
+ import fs from "fs-extra";
83
+ import path3 from "path";
36
84
  var hasFiles = async (dir) => {
37
85
  if (!await fs.pathExists(dir)) return false;
38
86
  const items = await fs.readdir(dir);
39
87
  return items.length > 0;
40
88
  };
41
- var getTemplatePath = (template) => {
42
- return path.join(getTemplatesDir(), template);
43
- };
44
89
  var copyRecursive = async (src, dest, counter) => {
45
90
  const stat = await fs.stat(src);
46
91
  if (stat.isDirectory()) {
@@ -48,102 +93,149 @@ var copyRecursive = async (src, dest, counter) => {
48
93
  counter.directories++;
49
94
  const items = await fs.readdir(src);
50
95
  for (const item of items) {
51
- await copyRecursive(path.join(src, item), path.join(dest, item), counter);
96
+ await copyRecursive(path3.join(src, item), path3.join(dest, item), counter);
52
97
  }
53
98
  } else {
54
99
  await fs.copy(src, dest);
55
100
  counter.files++;
56
101
  }
57
102
  };
103
+
104
+ // src/features/templates/template-metadata.ts
105
+ var templateMetadata = {
106
+ "tanstack-start": {
107
+ name: "TanStack Start",
108
+ description: "React + TanStack Router SSR \uD480\uC2A4\uD0DD \uD504\uB85C\uC81D\uD2B8",
109
+ stack: "React, TanStack Router, Vite, TypeScript"
110
+ },
111
+ hono: {
112
+ name: "Hono",
113
+ description: "Edge Runtime \uBC31\uC5D4\uB4DC API \uD504\uB85C\uC81D\uD2B8",
114
+ stack: "Hono, TypeScript, Cloudflare Workers"
115
+ },
116
+ npx: {
117
+ name: "NPX CLI",
118
+ description: "NPX\uB85C \uC2E4\uD589 \uAC00\uB2A5\uD55C CLI \uB3C4\uAD6C \uD504\uB85C\uC81D\uD2B8",
119
+ stack: "Node.js, TypeScript, Commander.js"
120
+ }
121
+ };
122
+ var generateIndexClaudeMd = (templates) => {
123
+ const templateSections = templates.map((template) => {
124
+ const meta = templateMetadata[template] || {
125
+ name: template,
126
+ description: `${template} \uD504\uB85C\uC81D\uD2B8`,
127
+ stack: "TypeScript"
128
+ };
129
+ return `### ${meta.name}
130
+ - **\uC6A9\uB3C4:** ${meta.description}
131
+ - **\uC8FC\uC694 \uC2A4\uD0DD:** ${meta.stack}
132
+ - **\uAC00\uC774\uB4DC:** [docs/${template}/CLAUDE.md](docs/${template}/CLAUDE.md)`;
133
+ }).join("\n\n");
134
+ return `# CLAUDE.md
135
+
136
+ > \uC774 \uD504\uB85C\uC81D\uD2B8\uB294 \uC5EC\uB7EC \uD504\uB808\uC784\uC6CC\uD06C\uC758 Claude Code \uAC00\uC774\uB4DC\uB97C \uD3EC\uD568\uD569\uB2C8\uB2E4.
137
+
138
+ ## \uC0AC\uC6A9 \uBC29\uBC95
139
+
140
+ \uC544\uB798 \uD15C\uD50C\uB9BF \uC911 **\uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC0AC\uC6A9 \uC911\uC778 \uD504\uB808\uC784\uC6CC\uD06C**\uB97C \uC120\uD0DD\uD558\uC5EC \uD574\uB2F9 \uAC00\uC774\uB4DC\uB97C \uB530\uB974\uC138\uC694.
141
+
142
+ ## \uD15C\uD50C\uB9BF \uBAA9\uB85D
143
+
144
+ ${templateSections}
145
+
146
+ ---
147
+
148
+ **\uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uC5D0 \uB9DE\uB294 \uAC00\uC774\uB4DC\uB97C CLAUDE.md\uC758 \`@\` \uC778\uC2A4\uD2B8\uB7ED\uC158\uC5D0 \uCD94\uAC00\uD558\uC138\uC694.**
149
+ `;
150
+ };
151
+
152
+ // src/features/templates/template-installer.ts
58
153
  var copySingleTemplate = async (template, targetDir) => {
154
+ validateTargetDir(targetDir);
59
155
  const templatePath = getTemplatePath(template);
60
- if (!await fs.pathExists(templatePath)) {
156
+ if (!await fs2.pathExists(templatePath)) {
61
157
  throw new Error(`Template "${template}" not found at ${templatePath}`);
62
158
  }
63
159
  const counter = { files: 0, directories: 0 };
64
- const claudeMdSrc = path.join(templatePath, "CLAUDE.md");
65
- if (await fs.pathExists(claudeMdSrc)) {
66
- await fs.copy(claudeMdSrc, path.join(targetDir, "CLAUDE.md"));
160
+ const claudeMdSrc = path4.join(templatePath, "CLAUDE.md");
161
+ if (await fs2.pathExists(claudeMdSrc)) {
162
+ await fs2.copy(claudeMdSrc, path4.join(targetDir, "CLAUDE.md"));
67
163
  counter.files++;
68
164
  }
69
- const docsSrc = path.join(templatePath, "docs");
70
- const docsDest = path.join(targetDir, "docs");
71
- if (await fs.pathExists(docsSrc)) {
72
- if (await fs.pathExists(docsDest)) {
73
- await fs.remove(docsDest);
165
+ const docsSrc = path4.join(templatePath, "docs");
166
+ const docsDest = path4.join(targetDir, "docs");
167
+ if (await fs2.pathExists(docsSrc)) {
168
+ if (await fs2.pathExists(docsDest)) {
169
+ await fs2.remove(docsDest);
74
170
  }
75
171
  await copyRecursive(docsSrc, docsDest, counter);
76
172
  }
77
173
  return counter;
78
174
  };
79
175
  var copyMultipleTemplates = async (templates, targetDir) => {
176
+ validateTargetDir(targetDir);
80
177
  const counter = { files: 0, directories: 0 };
81
- const docsDir = path.join(targetDir, "docs");
82
- if (await fs.pathExists(docsDir)) {
83
- await fs.remove(docsDir);
178
+ const docsDir = path4.join(targetDir, "docs");
179
+ if (await fs2.pathExists(docsDir)) {
180
+ await fs2.remove(docsDir);
84
181
  }
85
182
  for (const template of templates) {
86
183
  const templatePath = getTemplatePath(template);
87
- if (!await fs.pathExists(templatePath)) {
184
+ if (!await fs2.pathExists(templatePath)) {
88
185
  throw new Error(`Template "${template}" not found at ${templatePath}`);
89
186
  }
90
187
  await copyRecursive(
91
188
  templatePath,
92
- path.join(targetDir, "docs", template),
189
+ path4.join(targetDir, "docs", template),
93
190
  counter
94
191
  );
95
192
  }
96
193
  const indexContent = generateIndexClaudeMd(templates);
97
- await fs.writeFile(path.join(targetDir, "CLAUDE.md"), indexContent);
194
+ await fs2.writeFile(path4.join(targetDir, "CLAUDE.md"), indexContent);
98
195
  counter.files++;
99
196
  return counter;
100
197
  };
101
- var generateIndexClaudeMd = (templates) => {
102
- const templateLinks = templates.map((t) => `- [${t}](docs/${t}/CLAUDE.md)`).join("\n");
103
- return `# CLAUDE.md
104
-
105
- > \uC774 \uD504\uB85C\uC81D\uD2B8\uB294 \uC5EC\uB7EC \uD15C\uD50C\uB9BF\uC758 Claude Code \uBB38\uC11C\uB97C \uD3EC\uD568\uD569\uB2C8\uB2E4.
106
-
107
- ## \uD15C\uD50C\uB9BF \uBB38\uC11C
108
198
 
109
- ${templateLinks}
110
-
111
- ## \uC0AC\uC6A9\uBC95
112
-
113
- \uAC01 \uD15C\uD50C\uB9BF\uC758 \`CLAUDE.md\`\uB97C \uCC38\uC870\uD558\uC5EC \uD574\uB2F9 \uAE30\uC220 \uC2A4\uD0DD\uC758 \uAC00\uC774\uB4DC\uB77C\uC778\uC744 \uD655\uC778\uD558\uC138\uC694.
114
- `;
115
- };
116
- var checkExistingFiles = async (targetDir) => {
117
- const existingFiles = [];
118
- const claudeMd = path.join(targetDir, "CLAUDE.md");
119
- const docsDir = path.join(targetDir, "docs");
120
- if (await fs.pathExists(claudeMd)) {
121
- existingFiles.push("CLAUDE.md");
122
- }
123
- if (await fs.pathExists(docsDir)) {
124
- existingFiles.push("docs/");
125
- }
126
- return existingFiles;
127
- };
199
+ // src/features/templates/template-discovery.ts
200
+ import fs3 from "fs-extra";
201
+ import path5 from "path";
128
202
  var listAvailableTemplates = async () => {
129
203
  const templatesDir = getTemplatesDir();
130
- if (!await fs.pathExists(templatesDir)) {
204
+ if (!await fs3.pathExists(templatesDir)) {
131
205
  return [];
132
206
  }
133
- const items = await fs.readdir(templatesDir);
207
+ const items = await fs3.readdir(templatesDir);
134
208
  const templates = [];
135
209
  for (const item of items) {
136
210
  if (item.startsWith(".")) {
137
211
  continue;
138
212
  }
139
- const itemPath = path.join(templatesDir, item);
140
- const stat = await fs.stat(itemPath);
213
+ const itemPath = path5.join(templatesDir, item);
214
+ const stat = await fs3.stat(itemPath);
141
215
  if (stat.isDirectory()) {
142
216
  templates.push(item);
143
217
  }
144
218
  }
145
219
  return templates;
146
220
  };
221
+ var checkExistingFiles = async (targetDir) => {
222
+ const existingFiles = [];
223
+ const claudeMd = path5.join(targetDir, "CLAUDE.md");
224
+ const docsDir = path5.join(targetDir, "docs");
225
+ if (await fs3.pathExists(claudeMd)) {
226
+ existingFiles.push("CLAUDE.md");
227
+ }
228
+ if (await fs3.pathExists(docsDir)) {
229
+ existingFiles.push("docs/");
230
+ }
231
+ return existingFiles;
232
+ };
233
+
234
+ // src/features/extras/extras-copier.ts
235
+ import fs4 from "fs-extra";
236
+ import path6 from "path";
237
+
238
+ // src/shared/constants.ts
147
239
  var FRAMEWORK_SPECIFIC_SKILLS_MAP = {
148
240
  nextjs: ["nextjs-react-best-practices", "korea-uiux-design", "figma-to-code"],
149
241
  "tanstack-start": [
@@ -162,91 +254,97 @@ var COMMON_SKILLS = [
162
254
  "ralph",
163
255
  "execute"
164
256
  ];
257
+
258
+ // src/features/extras/extras-copier.ts
259
+ var createExtrasCopier = (extrasType) => {
260
+ return async (_templates, targetDir) => {
261
+ const counter = { files: 0, directories: 0 };
262
+ const targetExtrasDir = path6.join(targetDir, ".claude", extrasType);
263
+ const extrasSrc = path6.join(getTemplatesDir(), ".claude", extrasType);
264
+ if (await fs4.pathExists(extrasSrc)) {
265
+ await fs4.ensureDir(targetExtrasDir);
266
+ await copyRecursive(extrasSrc, targetExtrasDir, counter);
267
+ }
268
+ return counter;
269
+ };
270
+ };
271
+ var copyCommands = createExtrasCopier("commands");
272
+ var copyAgents = createExtrasCopier("agents");
273
+ var copyInstructions = createExtrasCopier("instructions");
165
274
  var copySkills = async (templates, targetDir) => {
166
275
  const counter = { files: 0, directories: 0 };
167
- const targetSkillsDir = path.join(targetDir, ".claude", "skills");
168
- const skillsSrc = path.join(getTemplatesDir(), ".claude", "skills");
169
- if (!await fs.pathExists(skillsSrc)) {
276
+ const targetSkillsDir = path6.join(targetDir, ".claude", "skills");
277
+ const skillsSrc = path6.join(getTemplatesDir(), ".claude", "skills");
278
+ if (!await fs4.pathExists(skillsSrc)) {
170
279
  return counter;
171
280
  }
172
- await fs.ensureDir(targetSkillsDir);
281
+ await fs4.ensureDir(targetSkillsDir);
173
282
  const skillsToCopy = /* @__PURE__ */ new Set();
283
+ const skillTemplateMap = /* @__PURE__ */ new Map();
174
284
  COMMON_SKILLS.forEach((skill) => skillsToCopy.add(skill));
175
285
  for (const template of templates) {
176
286
  const skills = FRAMEWORK_SPECIFIC_SKILLS_MAP[template] || [];
177
- skills.forEach((skill) => skillsToCopy.add(skill));
287
+ skills.forEach((skill) => {
288
+ skillsToCopy.add(skill);
289
+ if (!skillTemplateMap.has(skill)) {
290
+ skillTemplateMap.set(skill, /* @__PURE__ */ new Set());
291
+ }
292
+ skillTemplateMap.get(skill).add(template);
293
+ });
178
294
  }
179
295
  for (const skill of skillsToCopy) {
180
- const skillSrc = path.join(skillsSrc, skill);
181
- const skillDest = path.join(targetSkillsDir, skill);
182
- if (await fs.pathExists(skillSrc)) {
183
- if (await fs.pathExists(skillDest)) {
184
- await fs.remove(skillDest);
296
+ const skillSrc = path6.join(skillsSrc, skill);
297
+ const skillDest = path6.join(targetSkillsDir, skill);
298
+ if (await fs4.pathExists(skillSrc)) {
299
+ if (await fs4.pathExists(skillDest)) {
300
+ await fs4.remove(skillDest);
185
301
  }
186
302
  await copyRecursive(skillSrc, skillDest, counter);
187
303
  }
188
304
  }
189
- return counter;
190
- };
191
- var copyCommands = async (_templates, targetDir) => {
192
- const counter = { files: 0, directories: 0 };
193
- const targetCommandsDir = path.join(targetDir, ".claude", "commands");
194
- const commandsSrc = path.join(getTemplatesDir(), ".claude", "commands");
195
- if (await fs.pathExists(commandsSrc)) {
196
- await fs.ensureDir(targetCommandsDir);
197
- await copyRecursive(commandsSrc, targetCommandsDir, counter);
305
+ const duplicateSkills = [];
306
+ for (const [skill, templateSet] of skillTemplateMap.entries()) {
307
+ if (templateSet.size > 1) {
308
+ duplicateSkills.push({
309
+ skill,
310
+ templates: Array.from(templateSet).sort()
311
+ });
312
+ }
198
313
  }
199
- return counter;
314
+ return {
315
+ ...counter,
316
+ ...duplicateSkills.length > 0 && { duplicateSkills }
317
+ };
200
318
  };
319
+
320
+ // src/features/extras/extras-checker.ts
321
+ import fs5 from "fs-extra";
322
+ import path7 from "path";
201
323
  var checkExistingClaudeFiles = async (targetDir) => {
202
324
  const existingFiles = [];
203
- const skillsDir = path.join(targetDir, ".claude", "skills");
204
- const commandsDir = path.join(targetDir, ".claude", "commands");
205
- const agentsDir = path.join(targetDir, ".claude", "agents");
206
- const instructionsDir = path.join(targetDir, ".claude", "instructions");
207
- if (await fs.pathExists(skillsDir)) {
325
+ const skillsDir = path7.join(targetDir, ".claude", "skills");
326
+ const commandsDir = path7.join(targetDir, ".claude", "commands");
327
+ const agentsDir = path7.join(targetDir, ".claude", "agents");
328
+ const instructionsDir = path7.join(targetDir, ".claude", "instructions");
329
+ if (await fs5.pathExists(skillsDir)) {
208
330
  existingFiles.push(".claude/skills/");
209
331
  }
210
- if (await fs.pathExists(commandsDir)) {
332
+ if (await fs5.pathExists(commandsDir)) {
211
333
  existingFiles.push(".claude/commands/");
212
334
  }
213
- if (await fs.pathExists(agentsDir)) {
335
+ if (await fs5.pathExists(agentsDir)) {
214
336
  existingFiles.push(".claude/agents/");
215
337
  }
216
- if (await fs.pathExists(instructionsDir)) {
338
+ if (await fs5.pathExists(instructionsDir)) {
217
339
  existingFiles.push(".claude/instructions/");
218
340
  }
219
341
  return existingFiles;
220
342
  };
221
- var copyAgents = async (_templates, targetDir) => {
222
- const counter = { files: 0, directories: 0 };
223
- const targetAgentsDir = path.join(targetDir, ".claude", "agents");
224
- const agentsSrc = path.join(getTemplatesDir(), ".claude", "agents");
225
- if (await fs.pathExists(agentsSrc)) {
226
- await fs.ensureDir(targetAgentsDir);
227
- await copyRecursive(agentsSrc, targetAgentsDir, counter);
228
- }
229
- return counter;
230
- };
231
- var copyInstructions = async (_templates, targetDir) => {
232
- const counter = { files: 0, directories: 0 };
233
- const targetInstructionsDir = path.join(targetDir, ".claude", "instructions");
234
- const instructionsSrc = path.join(
235
- getTemplatesDir(),
236
- ".claude",
237
- "instructions"
238
- );
239
- if (await fs.pathExists(instructionsSrc)) {
240
- await fs.ensureDir(targetInstructionsDir);
241
- await copyRecursive(instructionsSrc, targetInstructionsDir, counter);
242
- }
243
- return counter;
244
- };
245
343
  var checkAllExtrasExist = async (templates) => {
246
- const claudeDir = path.join(getTemplatesDir(), ".claude");
247
- const commandsSrc = path.join(claudeDir, "commands");
248
- const agentsSrc = path.join(claudeDir, "agents");
249
- const instructionsSrc = path.join(claudeDir, "instructions");
344
+ const claudeDir = path7.join(getTemplatesDir(), ".claude");
345
+ const commandsSrc = path7.join(claudeDir, "commands");
346
+ const agentsSrc = path7.join(claudeDir, "agents");
347
+ const instructionsSrc = path7.join(claudeDir, "instructions");
250
348
  const hasFrameworkSkills = templates.some((template) => {
251
349
  const skills = FRAMEWORK_SPECIFIC_SKILLS_MAP[template];
252
350
  return skills && skills.length > 0;
@@ -258,38 +356,60 @@ var checkAllExtrasExist = async (templates) => {
258
356
  return { hasSkills, hasCommands, hasAgents, hasInstructions };
259
357
  };
260
358
 
261
- // src/commands/init.ts
262
- var TEMPLATE_DESCRIPTIONS = {
263
- "tanstack-start": "TanStack Start + React \uD480\uC2A4\uD0DD \uD504\uB85C\uC81D\uD2B8",
264
- hono: "Hono \uC11C\uBC84 \uD504\uB808\uC784\uC6CC\uD06C \uD504\uB85C\uC81D\uD2B8",
265
- npx: "NPX CLI \uB3C4\uAD6C \uD504\uB85C\uC81D\uD2B8"
266
- };
267
- var init = async (options) => {
268
- const targetDir = options.cwd || process.cwd();
269
- const availableTemplates = await listAvailableTemplates();
270
- if (availableTemplates.length === 0) {
271
- logger.error("No templates found. Package may be corrupted.");
272
- process.exit(1);
273
- }
274
- let templates = options.templates || [];
359
+ // src/shared/prompts/prompt-helpers.ts
360
+ import prompts from "prompts";
361
+ async function promptConfirm(message, initial = false) {
362
+ const response = await prompts({
363
+ type: "confirm",
364
+ name: "confirmed",
365
+ message,
366
+ initial
367
+ });
368
+ return { confirmed: response.confirmed ?? false };
369
+ }
370
+ async function promptSelect(message, choices) {
371
+ const response = await prompts({
372
+ type: "select",
373
+ name: "value",
374
+ message,
375
+ choices
376
+ });
377
+ return { value: response.value };
378
+ }
379
+ async function promptMultiselect(message, choices, options) {
380
+ const response = await prompts({
381
+ type: "multiselect",
382
+ name: "values",
383
+ message,
384
+ choices,
385
+ min: options?.min,
386
+ hint: options?.hint
387
+ });
388
+ return { values: response.values || [] };
389
+ }
390
+
391
+ // src/shared/prompts/prompt-functions.ts
392
+ async function promptTemplateSelection(options) {
393
+ const { providedTemplates, availableTemplates, templateDescriptions } = options;
394
+ let templates = providedTemplates || [];
275
395
  if (templates.length === 0) {
276
- const response = await prompts({
277
- type: "multiselect",
278
- name: "templates",
279
- message: "Select templates (space to select, enter to confirm):",
280
- choices: availableTemplates.map((t) => ({
396
+ const response = await promptMultiselect(
397
+ "Select templates (space to select, enter to confirm):",
398
+ availableTemplates.map((t) => ({
281
399
  title: t,
282
- description: TEMPLATE_DESCRIPTIONS[t] || "",
400
+ description: templateDescriptions[t] || "",
283
401
  value: t
284
402
  })),
285
- min: 1,
286
- hint: "- Space to select. Return to submit"
287
- });
288
- if (!response.templates || response.templates.length === 0) {
403
+ {
404
+ min: 1,
405
+ hint: "- Space to select. Return to submit"
406
+ }
407
+ );
408
+ if (response.values.length === 0) {
289
409
  logger.warn("Operation cancelled.");
290
410
  process.exit(0);
291
411
  }
292
- templates = response.templates;
412
+ templates = response.values;
293
413
  }
294
414
  const invalidTemplates = templates.filter(
295
415
  (t) => !availableTemplates.includes(t)
@@ -299,22 +419,301 @@ var init = async (options) => {
299
419
  logger.info(`Available templates: ${availableTemplates.join(", ")}`);
300
420
  process.exit(1);
301
421
  }
302
- const existingFiles = await checkExistingFiles(targetDir);
303
- if (existingFiles.length > 0 && !options.force) {
422
+ return { templates };
423
+ }
424
+ async function promptOverwrite(options) {
425
+ const { existingFiles, force } = options;
426
+ if (existingFiles.length > 0 && !force) {
304
427
  logger.warn("The following files/folders already exist:");
305
428
  existingFiles.forEach((f) => logger.step(f));
306
429
  logger.blank();
307
- const response = await prompts({
308
- type: "confirm",
309
- name: "overwrite",
310
- message: "Overwrite existing files?",
311
- initial: false
312
- });
313
- if (!response.overwrite) {
430
+ const result = await promptConfirm("Overwrite existing files?", false);
431
+ if (!result.confirmed) {
314
432
  logger.info("Operation cancelled.");
315
433
  process.exit(0);
316
434
  }
317
435
  }
436
+ }
437
+ async function promptExtrasSelection(options) {
438
+ const {
439
+ skills,
440
+ commands,
441
+ agents,
442
+ instructions,
443
+ hasSkills,
444
+ hasCommands,
445
+ hasAgents,
446
+ hasInstructions
447
+ } = options;
448
+ let installSkills = skills ?? false;
449
+ let installCommands = commands ?? false;
450
+ let installAgents = agents ?? hasAgents;
451
+ let installInstructions = instructions ?? hasInstructions;
452
+ const noOptionsProvided = skills === void 0 && commands === void 0 && agents === void 0 && instructions === void 0;
453
+ if (noOptionsProvided && (hasSkills || hasCommands || hasAgents || hasInstructions)) {
454
+ logger.blank();
455
+ if (hasSkills) {
456
+ const result = await promptConfirm(
457
+ "Install skills to .claude/skills/?",
458
+ false
459
+ );
460
+ installSkills = result.confirmed;
461
+ }
462
+ if (hasCommands) {
463
+ const result = await promptConfirm(
464
+ "Install commands to .claude/commands/?",
465
+ false
466
+ );
467
+ installCommands = result.confirmed;
468
+ }
469
+ }
470
+ return {
471
+ installSkills,
472
+ installCommands,
473
+ installAgents,
474
+ installInstructions
475
+ };
476
+ }
477
+
478
+ // src/features/extras/extras-installer.ts
479
+ async function handleDuplicateFiles(existingClaudeFiles, force) {
480
+ if (existingClaudeFiles.length === 0 || force) {
481
+ return true;
482
+ }
483
+ logger.warn("The following .claude files/folders already exist:");
484
+ existingClaudeFiles.forEach((f) => logger.step(f));
485
+ logger.blank();
486
+ const response = await promptConfirm(
487
+ "Overwrite existing .claude files?",
488
+ false
489
+ );
490
+ return response.confirmed;
491
+ }
492
+ async function handleDuplicateSkills(duplicateSkills, templates, targetDir) {
493
+ logger.blank();
494
+ logger.warn("The following skills are included in multiple templates:");
495
+ duplicateSkills.forEach(({ skill, templates: skillTemplates }) => {
496
+ logger.step(`${skill} (${skillTemplates.join(", ")})`);
497
+ });
498
+ logger.blank();
499
+ const response = await promptSelect(
500
+ "Which template's version should be used?",
501
+ templates.map((t) => ({
502
+ title: t,
503
+ value: t
504
+ }))
505
+ );
506
+ if (response.value) {
507
+ logger.info(`Reinstalling skills with ${response.value} template...`);
508
+ const reinstallResult = await copySkills([response.value], targetDir);
509
+ logger.success(
510
+ `Skills: ${reinstallResult.files} files, ${reinstallResult.directories} directories`
511
+ );
512
+ return reinstallResult;
513
+ } else {
514
+ logger.warn("No template selected. Using all templates.");
515
+ return { files: 0, directories: 0 };
516
+ }
517
+ }
518
+ async function installSkillsIfNeeded(templates, targetDir, shouldInstall, hasSkills) {
519
+ if (!shouldInstall) {
520
+ return { files: 0, directories: 0 };
521
+ }
522
+ if (!hasSkills) {
523
+ logger.warn("No skills found in selected templates.");
524
+ return { files: 0, directories: 0 };
525
+ }
526
+ logger.blank();
527
+ logger.info("Installing skills...");
528
+ const skillsResult = await copySkills(templates, targetDir);
529
+ if (skillsResult.duplicateSkills && skillsResult.duplicateSkills.length > 0) {
530
+ return await handleDuplicateSkills(
531
+ skillsResult.duplicateSkills,
532
+ templates,
533
+ targetDir
534
+ );
535
+ }
536
+ logger.success(
537
+ `Skills: ${skillsResult.files} files, ${skillsResult.directories} directories`
538
+ );
539
+ return skillsResult;
540
+ }
541
+ async function installCommandsIfNeeded(templates, targetDir, shouldInstall, hasCommands) {
542
+ if (!shouldInstall) {
543
+ return { files: 0, directories: 0 };
544
+ }
545
+ if (!hasCommands) {
546
+ logger.warn("No commands found in selected templates.");
547
+ return { files: 0, directories: 0 };
548
+ }
549
+ logger.blank();
550
+ logger.info("Installing commands...");
551
+ const commandsResult = await copyCommands(templates, targetDir);
552
+ logger.success(
553
+ `Commands: ${commandsResult.files} files, ${commandsResult.directories} directories`
554
+ );
555
+ return commandsResult;
556
+ }
557
+ async function installAgentsIfNeeded(templates, targetDir, shouldInstall, hasAgents) {
558
+ if (!shouldInstall) {
559
+ return { files: 0, directories: 0 };
560
+ }
561
+ if (!hasAgents) {
562
+ logger.warn("No agents found in selected templates.");
563
+ return { files: 0, directories: 0 };
564
+ }
565
+ logger.blank();
566
+ logger.info("Installing agents...");
567
+ const agentsResult = await copyAgents(templates, targetDir);
568
+ logger.success(
569
+ `Agents: ${agentsResult.files} files, ${agentsResult.directories} directories`
570
+ );
571
+ return agentsResult;
572
+ }
573
+ async function installInstructionsIfNeeded(templates, targetDir, shouldInstall, hasInstructions) {
574
+ if (!shouldInstall) {
575
+ return { files: 0, directories: 0 };
576
+ }
577
+ if (!hasInstructions) {
578
+ logger.warn("No instructions found in selected templates.");
579
+ return { files: 0, directories: 0 };
580
+ }
581
+ logger.blank();
582
+ logger.info("Installing instructions...");
583
+ const instructionsResult = await copyInstructions(templates, targetDir);
584
+ logger.success(
585
+ `Instructions: ${instructionsResult.files} files, ${instructionsResult.directories} directories`
586
+ );
587
+ return instructionsResult;
588
+ }
589
+ async function installExtras(templates, targetDir, flags, availability, force) {
590
+ const { installSkills, installCommands, installAgents, installInstructions } = flags;
591
+ if (!installSkills && !installCommands && !installAgents && !installInstructions) {
592
+ return { files: 0, directories: 0 };
593
+ }
594
+ const existingClaudeFiles = await checkExistingClaudeFiles(targetDir);
595
+ const shouldProceed = await handleDuplicateFiles(existingClaudeFiles, force);
596
+ if (!shouldProceed) {
597
+ logger.info("Skipping extras installation.");
598
+ return { files: 0, directories: 0 };
599
+ }
600
+ const skillsResult = await installSkillsIfNeeded(
601
+ templates,
602
+ targetDir,
603
+ installSkills,
604
+ availability.hasSkills
605
+ );
606
+ const commandsResult = await installCommandsIfNeeded(
607
+ templates,
608
+ targetDir,
609
+ installCommands,
610
+ availability.hasCommands
611
+ );
612
+ const agentsResult = await installAgentsIfNeeded(
613
+ templates,
614
+ targetDir,
615
+ installAgents,
616
+ availability.hasAgents
617
+ );
618
+ const instructionsResult = await installInstructionsIfNeeded(
619
+ templates,
620
+ targetDir,
621
+ installInstructions,
622
+ availability.hasInstructions
623
+ );
624
+ const totalFiles = skillsResult.files + commandsResult.files + agentsResult.files + instructionsResult.files;
625
+ const totalDirectories = skillsResult.directories + commandsResult.directories + agentsResult.directories + instructionsResult.directories;
626
+ return { files: totalFiles, directories: totalDirectories };
627
+ }
628
+
629
+ // src/shared/gitignore-manager.ts
630
+ import fs6 from "fs-extra";
631
+ import path8 from "path";
632
+ var CLAUDE_GENERATED_FOLDERS = ["CLAUDE.md", "docs/", ".claude/"];
633
+ async function updateGitignore(targetDir) {
634
+ const gitignorePath = path8.join(targetDir, ".gitignore");
635
+ const sectionComment = "# Claude Code generated files";
636
+ let content = "";
637
+ let hasGitignore = false;
638
+ try {
639
+ content = await fs6.readFile(gitignorePath, "utf-8");
640
+ hasGitignore = true;
641
+ } catch (error) {
642
+ content = "";
643
+ }
644
+ if (content.includes(sectionComment)) {
645
+ logger.info(".gitignore already contains Claude Code section");
646
+ return;
647
+ }
648
+ const linesToAdd = [];
649
+ const existingLines = content.split("\n").map((line) => line.trim());
650
+ for (const folder of CLAUDE_GENERATED_FOLDERS) {
651
+ if (!existingLines.includes(folder)) {
652
+ linesToAdd.push(folder);
653
+ }
654
+ }
655
+ if (linesToAdd.length === 0) {
656
+ logger.info(".gitignore already contains all Claude Code patterns");
657
+ return;
658
+ }
659
+ let newContent = content;
660
+ if (newContent && !newContent.endsWith("\n")) {
661
+ newContent += "\n";
662
+ }
663
+ if (newContent) {
664
+ newContent += "\n";
665
+ }
666
+ newContent += sectionComment + "\n";
667
+ newContent += linesToAdd.join("\n") + "\n";
668
+ await fs6.writeFile(gitignorePath, newContent, "utf-8");
669
+ if (hasGitignore) {
670
+ logger.success(`.gitignore updated with ${linesToAdd.length} patterns`);
671
+ } else {
672
+ logger.success(`.gitignore created with ${linesToAdd.length} patterns`);
673
+ }
674
+ }
675
+
676
+ // src/commands/init.ts
677
+ var TEMPLATE_DESCRIPTIONS = {
678
+ "tanstack-start": "TanStack Start + React \uD480\uC2A4\uD0DD \uD504\uB85C\uC81D\uD2B8",
679
+ hono: "Hono \uC11C\uBC84 \uD504\uB808\uC784\uC6CC\uD06C \uD504\uB85C\uC81D\uD2B8",
680
+ npx: "NPX CLI \uB3C4\uAD6C \uD504\uB85C\uC81D\uD2B8"
681
+ };
682
+ async function validateTargetDirectory(targetDir) {
683
+ try {
684
+ const stat = await fs7.stat(targetDir);
685
+ if (!stat.isDirectory()) {
686
+ logger.error(`Target is not a directory: ${targetDir}`);
687
+ process.exit(1);
688
+ }
689
+ } catch (error) {
690
+ if (error.code === "ENOENT") {
691
+ logger.error(`Target directory does not exist: ${targetDir}`);
692
+ } else {
693
+ logger.error(`Cannot access target directory: ${targetDir}`);
694
+ }
695
+ process.exit(1);
696
+ }
697
+ try {
698
+ await fs7.access(targetDir, fs7.constants.W_OK);
699
+ } catch {
700
+ logger.error(`No write permission for: ${targetDir}`);
701
+ process.exit(1);
702
+ }
703
+ }
704
+ async function selectTemplates(options, availableTemplates) {
705
+ const result = await promptTemplateSelection({
706
+ providedTemplates: options.templates,
707
+ availableTemplates,
708
+ templateDescriptions: TEMPLATE_DESCRIPTIONS
709
+ });
710
+ return result.templates;
711
+ }
712
+ async function confirmOverwriteIfNeeded(targetDir, force) {
713
+ const existingFiles = await checkExistingFiles(targetDir);
714
+ await promptOverwrite({ existingFiles, force });
715
+ }
716
+ async function installTemplates(templates, targetDir) {
318
717
  const isSingleTemplate = templates.length === 1;
319
718
  let totalFiles = 0;
320
719
  let totalDirectories = 0;
@@ -348,125 +747,27 @@ var init = async (options) => {
348
747
  }
349
748
  logger.blank();
350
749
  logger.success(`Total: ${totalFiles} files, ${totalDirectories} directories`);
351
- const { hasSkills, hasCommands, hasAgents, hasInstructions } = await checkAllExtrasExist(templates);
352
- let installSkills = options.skills ?? false;
353
- let installCommands = options.commands ?? false;
354
- let installAgents = options.agents ?? false;
355
- let installInstructions = options.instructions ?? false;
356
- const noOptionsProvided = options.skills === void 0 && options.commands === void 0 && options.agents === void 0 && options.instructions === void 0;
357
- if (noOptionsProvided && (hasSkills || hasCommands || hasAgents || hasInstructions)) {
358
- logger.blank();
359
- if (hasSkills) {
360
- const skillsResponse = await prompts({
361
- type: "confirm",
362
- name: "install",
363
- message: "Install skills to .claude/skills/?",
364
- initial: false
365
- });
366
- installSkills = skillsResponse.install ?? false;
367
- }
368
- if (hasCommands) {
369
- const commandsResponse = await prompts({
370
- type: "confirm",
371
- name: "install",
372
- message: "Install commands to .claude/commands/?",
373
- initial: false
374
- });
375
- installCommands = commandsResponse.install ?? false;
376
- }
377
- if (hasAgents) {
378
- const agentsResponse = await prompts({
379
- type: "confirm",
380
- name: "install",
381
- message: "Install agents to .claude/agents/?",
382
- initial: false
383
- });
384
- installAgents = agentsResponse.install ?? false;
385
- }
386
- if (hasInstructions) {
387
- const instructionsResponse = await prompts({
388
- type: "confirm",
389
- name: "install",
390
- message: "Install instructions to .claude/instructions/?",
391
- initial: false
392
- });
393
- installInstructions = instructionsResponse.install ?? false;
394
- }
395
- }
396
- if (installSkills || installCommands || installAgents || installInstructions) {
397
- const existingClaudeFiles = await checkExistingClaudeFiles(targetDir);
398
- if (existingClaudeFiles.length > 0 && !options.force) {
399
- logger.warn("The following .claude files/folders already exist:");
400
- existingClaudeFiles.forEach((f) => logger.step(f));
401
- logger.blank();
402
- const response = await prompts({
403
- type: "confirm",
404
- name: "overwrite",
405
- message: "Overwrite existing .claude files?",
406
- initial: false
407
- });
408
- if (!response.overwrite) {
409
- logger.info("Skipping extras installation.");
410
- installSkills = false;
411
- installCommands = false;
412
- installAgents = false;
413
- installInstructions = false;
414
- }
415
- }
416
- if (installSkills && hasSkills) {
417
- logger.blank();
418
- logger.info("Installing skills...");
419
- const skillsResult = await copySkills(templates, targetDir);
420
- totalFiles += skillsResult.files;
421
- totalDirectories += skillsResult.directories;
422
- logger.success(
423
- `Skills: ${skillsResult.files} files, ${skillsResult.directories} directories`
424
- );
425
- } else if (installSkills && !hasSkills) {
426
- logger.warn("No skills found in selected templates.");
427
- }
428
- if (installCommands && hasCommands) {
429
- logger.blank();
430
- logger.info("Installing commands...");
431
- const commandsResult = await copyCommands(templates, targetDir);
432
- totalFiles += commandsResult.files;
433
- totalDirectories += commandsResult.directories;
434
- logger.success(
435
- `Commands: ${commandsResult.files} files, ${commandsResult.directories} directories`
436
- );
437
- } else if (installCommands && !hasCommands) {
438
- logger.warn("No commands found in selected templates.");
439
- }
440
- if (installAgents && hasAgents) {
441
- logger.blank();
442
- logger.info("Installing agents...");
443
- const agentsResult = await copyAgents(templates, targetDir);
444
- totalFiles += agentsResult.files;
445
- totalDirectories += agentsResult.directories;
446
- logger.success(
447
- `Agents: ${agentsResult.files} files, ${agentsResult.directories} directories`
448
- );
449
- } else if (installAgents && !hasAgents) {
450
- logger.warn("No agents found in selected templates.");
451
- }
452
- if (installInstructions && hasInstructions) {
453
- logger.blank();
454
- logger.info("Installing instructions...");
455
- const instructionsResult = await copyInstructions(templates, targetDir);
456
- totalFiles += instructionsResult.files;
457
- totalDirectories += instructionsResult.directories;
458
- logger.success(
459
- `Instructions: ${instructionsResult.files} files, ${instructionsResult.directories} directories`
460
- );
461
- } else if (installInstructions && !hasInstructions) {
462
- logger.warn("No instructions found in selected templates.");
463
- }
464
- }
750
+ return { files: totalFiles, directories: totalDirectories };
751
+ }
752
+ async function promptForExtrasInstallation(options, hasSkills, hasCommands, hasAgents, hasInstructions) {
753
+ return await promptExtrasSelection({
754
+ skills: options.skills,
755
+ commands: options.commands,
756
+ agents: options.agents,
757
+ instructions: options.instructions,
758
+ hasSkills,
759
+ hasCommands,
760
+ hasAgents,
761
+ hasInstructions
762
+ });
763
+ }
764
+ function showInstallationSummary(templates, flags, hasSkills, hasCommands, hasAgents, hasInstructions) {
465
765
  logger.blank();
466
766
  logger.success("Claude Code documentation installed!");
467
767
  logger.blank();
468
768
  logger.info("Installed templates:");
469
769
  templates.forEach((t) => logger.step(t));
770
+ const { installSkills, installCommands, installAgents, installInstructions } = flags;
470
771
  if (installSkills && hasSkills || installCommands && hasCommands || installAgents && hasAgents || installInstructions && hasInstructions) {
471
772
  logger.blank();
472
773
  logger.info("Installed extras:");
@@ -488,11 +789,53 @@ var init = async (options) => {
488
789
  logger.step("Read CLAUDE.md for project guidelines");
489
790
  logger.step("Explore docs/ for detailed documentation");
490
791
  logger.blank();
792
+ }
793
+ var init = async (options) => {
794
+ const targetDir = options.cwd || process.cwd();
795
+ await validateTargetDirectory(targetDir);
796
+ const availableTemplates = await listAvailableTemplates();
797
+ if (availableTemplates.length === 0) {
798
+ logger.error("No templates found. Package may be corrupted.");
799
+ process.exit(1);
800
+ }
801
+ const templates = await selectTemplates(options, availableTemplates);
802
+ await confirmOverwriteIfNeeded(targetDir, options.force ?? false);
803
+ await installTemplates(templates, targetDir);
804
+ const { hasSkills, hasCommands, hasAgents, hasInstructions } = await checkAllExtrasExist(templates);
805
+ const flags = await promptForExtrasInstallation(
806
+ options,
807
+ hasSkills,
808
+ hasCommands,
809
+ hasAgents,
810
+ hasInstructions
811
+ );
812
+ await installExtras(
813
+ templates,
814
+ targetDir,
815
+ flags,
816
+ { hasSkills, hasCommands, hasAgents, hasInstructions },
817
+ options.force ?? false
818
+ );
819
+ showInstallationSummary(
820
+ templates,
821
+ flags,
822
+ hasSkills,
823
+ hasCommands,
824
+ hasAgents,
825
+ hasInstructions
826
+ );
827
+ try {
828
+ await updateGitignore(targetDir);
829
+ } catch (error) {
830
+ logger.warn(
831
+ `Failed to update .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`
832
+ );
833
+ }
491
834
  };
492
835
 
493
836
  // src/index.ts
494
837
  var program = new Command();
495
- program.name("claude-code").description("Claude Code documentation installer for projects").version("0.5.1");
838
+ program.name("claude-code").description("Claude Code documentation installer for projects").version("0.5.4");
496
839
  program.option(
497
840
  "-t, --template <names>",
498
841
  "template names (comma-separated: tanstack-start,hono)"