@kood/claude-code 0.5.9 → 0.6.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.
Files changed (63) hide show
  1. package/dist/index.js +127 -135
  2. package/package.json +1 -1
  3. package/templates/.claude/agents/build-fixer.md +371 -0
  4. package/templates/.claude/agents/critic.md +223 -0
  5. package/templates/.claude/agents/deep-executor.md +320 -0
  6. package/templates/.claude/agents/dependency-manager.md +0 -1
  7. package/templates/.claude/agents/deployment-validator.md +0 -1
  8. package/templates/.claude/agents/designer.md +0 -1
  9. package/templates/.claude/agents/document-writer.md +0 -1
  10. package/templates/.claude/agents/git-operator.md +15 -0
  11. package/templates/.claude/agents/implementation-executor.md +0 -1
  12. package/templates/.claude/agents/ko-to-en-translator.md +0 -1
  13. package/templates/.claude/agents/lint-fixer.md +0 -1
  14. package/templates/.claude/agents/planner.md +11 -7
  15. package/templates/.claude/agents/qa-tester.md +488 -0
  16. package/templates/.claude/agents/researcher.md +189 -0
  17. package/templates/.claude/agents/scientist.md +544 -0
  18. package/templates/.claude/agents/security-reviewer.md +549 -0
  19. package/templates/.claude/agents/tdd-guide.md +413 -0
  20. package/templates/.claude/agents/vision.md +165 -0
  21. package/templates/.claude/commands/pre-deploy.md +79 -2
  22. package/templates/.claude/instructions/agent-patterns/model-routing.md +2 -2
  23. package/templates/.claude/skills/brainstorm/SKILL.md +889 -0
  24. package/templates/.claude/skills/bug-fix/SKILL.md +69 -0
  25. package/templates/.claude/skills/crawler/SKILL.md +156 -0
  26. package/templates/.claude/skills/crawler/references/anti-bot-checklist.md +162 -0
  27. package/templates/.claude/skills/crawler/references/code-templates.md +119 -0
  28. package/templates/.claude/skills/crawler/references/crawling-patterns.md +167 -0
  29. package/templates/.claude/skills/crawler/references/document-templates.md +147 -0
  30. package/templates/.claude/skills/crawler/references/network-crawling.md +141 -0
  31. package/templates/.claude/skills/crawler/references/playwriter-commands.md +172 -0
  32. package/templates/.claude/skills/crawler/references/pre-crawl-checklist.md +221 -0
  33. package/templates/.claude/skills/crawler/references/selector-strategies.md +140 -0
  34. package/templates/.claude/skills/execute/SKILL.md +5 -0
  35. package/templates/.claude/skills/feedback/SKILL.md +570 -0
  36. package/templates/.claude/skills/figma-to-code/SKILL.md +1 -0
  37. package/templates/.claude/skills/global-uiux-design/SKILL.md +1 -0
  38. package/templates/.claude/skills/korea-uiux-design/SKILL.md +1 -0
  39. package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +1 -0
  40. package/templates/.claude/skills/plan/SKILL.md +44 -0
  41. package/templates/.claude/skills/ralph/SKILL.md +16 -18
  42. package/templates/.claude/skills/refactor/SKILL.md +19 -0
  43. package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +1 -0
  44. package/templates/.claude/skills/stitch-design/README.md +0 -34
  45. package/templates/.claude/skills/stitch-design/SKILL.md +0 -213
  46. package/templates/.claude/skills/stitch-design/examples/DESIGN.md +0 -154
  47. package/templates/.claude/skills/stitch-loop/README.md +0 -54
  48. package/templates/.claude/skills/stitch-loop/SKILL.md +0 -316
  49. package/templates/.claude/skills/stitch-loop/examples/SITE.md +0 -73
  50. package/templates/.claude/skills/stitch-loop/examples/next-prompt.md +0 -25
  51. package/templates/.claude/skills/stitch-loop/resources/baton-schema.md +0 -61
  52. package/templates/.claude/skills/stitch-loop/resources/site-template.md +0 -104
  53. package/templates/.claude/skills/stitch-react/README.md +0 -36
  54. package/templates/.claude/skills/stitch-react/SKILL.md +0 -323
  55. package/templates/.claude/skills/stitch-react/examples/gold-standard-card.tsx +0 -88
  56. package/templates/.claude/skills/stitch-react/package-lock.json +0 -231
  57. package/templates/.claude/skills/stitch-react/package.json +0 -16
  58. package/templates/.claude/skills/stitch-react/resources/architecture-checklist.md +0 -15
  59. package/templates/.claude/skills/stitch-react/resources/component-template.tsx +0 -37
  60. package/templates/.claude/skills/stitch-react/resources/stitch-api-reference.md +0 -14
  61. package/templates/.claude/skills/stitch-react/resources/style-guide.json +0 -24
  62. package/templates/.claude/skills/stitch-react/scripts/fetch-stitch.sh +0 -30
  63. package/templates/.claude/skills/stitch-react/scripts/validate.js +0 -77
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ var banner = () => {
22
22
  };
23
23
 
24
24
  // src/commands/init.ts
25
- import fs7 from "fs-extra";
25
+ import fs8 from "fs-extra";
26
26
 
27
27
  // src/features/templates/template-path-resolver.ts
28
28
  import path2 from "path";
@@ -232,37 +232,85 @@ var checkExistingFiles = async (targetDir) => {
232
232
  };
233
233
 
234
234
  // src/features/extras/extras-copier.ts
235
- import fs4 from "fs-extra";
236
- import path6 from "path";
235
+ import fs5 from "fs-extra";
236
+ import path7 from "path";
237
237
 
238
238
  // src/shared/constants.ts
239
- var FRAMEWORK_SPECIFIC_SKILLS_MAP = {
240
- nextjs: ["nextjs-react-best-practices", "korea-uiux-design", "figma-to-code"],
241
- "tanstack-start": [
242
- "tanstack-start-react-best-practices",
243
- "korea-uiux-design",
244
- "figma-to-code"
245
- ]
246
- // hono와 npx는 프레임워크별 스킬 없음
239
+ var NON_UI_TEMPLATES = ["hono", "npx"];
240
+
241
+ // src/features/extras/skill-metadata.ts
242
+ import fs4 from "fs-extra";
243
+ import path6 from "path";
244
+ var parseSkillMetadata = async (skillPath) => {
245
+ const skillMdPath = path6.join(skillPath, "SKILL.md");
246
+ if (!await fs4.pathExists(skillMdPath)) {
247
+ return null;
248
+ }
249
+ const content = await fs4.readFile(skillMdPath, "utf-8");
250
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
251
+ if (!frontmatterMatch) {
252
+ return null;
253
+ }
254
+ const frontmatter = frontmatterMatch[1];
255
+ const metadata = {
256
+ name: "",
257
+ description: ""
258
+ };
259
+ const lines = frontmatter.split("\n");
260
+ for (const line of lines) {
261
+ const colonIndex = line.indexOf(":");
262
+ if (colonIndex === -1) continue;
263
+ const key = line.slice(0, colonIndex).trim();
264
+ const value = line.slice(colonIndex + 1).trim();
265
+ switch (key) {
266
+ case "name":
267
+ metadata.name = value;
268
+ break;
269
+ case "description":
270
+ metadata.description = value;
271
+ break;
272
+ case "user-invocable":
273
+ metadata.userInvocable = value === "true";
274
+ break;
275
+ case "ui-only":
276
+ metadata.uiOnly = value === "true";
277
+ break;
278
+ case "framework":
279
+ metadata.framework = value;
280
+ break;
281
+ }
282
+ }
283
+ return metadata;
284
+ };
285
+ var loadAllSkillMetadata = async (skillsSrc) => {
286
+ const metadataMap = /* @__PURE__ */ new Map();
287
+ if (!await fs4.pathExists(skillsSrc)) {
288
+ return metadataMap;
289
+ }
290
+ const entries = await fs4.readdir(skillsSrc, { withFileTypes: true });
291
+ for (const entry of entries) {
292
+ if (entry.isDirectory()) {
293
+ const skillPath = path6.join(skillsSrc, entry.name);
294
+ const metadata = await parseSkillMetadata(skillPath);
295
+ if (metadata) {
296
+ if (!metadata.name) {
297
+ metadata.name = entry.name;
298
+ }
299
+ metadataMap.set(entry.name, metadata);
300
+ }
301
+ }
302
+ }
303
+ return metadataMap;
247
304
  };
248
- var COMMON_SKILLS = [
249
- "global-uiux-design",
250
- "docs-creator",
251
- "docs-refactor",
252
- "plan",
253
- "prd",
254
- "ralph",
255
- "execute"
256
- ];
257
305
 
258
306
  // src/features/extras/extras-copier.ts
259
307
  var createExtrasCopier = (extrasType) => {
260
308
  return async (_templates, targetDir) => {
261
309
  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);
310
+ const targetExtrasDir = path7.join(targetDir, ".claude", extrasType);
311
+ const extrasSrc = path7.join(getTemplatesDir(), ".claude", extrasType);
312
+ if (await fs5.pathExists(extrasSrc)) {
313
+ await fs5.ensureDir(targetExtrasDir);
266
314
  await copyRecursive(extrasSrc, targetExtrasDir, counter);
267
315
  }
268
316
  return counter;
@@ -271,85 +319,71 @@ var createExtrasCopier = (extrasType) => {
271
319
  var copyCommands = createExtrasCopier("commands");
272
320
  var copyAgents = createExtrasCopier("agents");
273
321
  var copyInstructions = createExtrasCopier("instructions");
322
+ var getSkillsToInstall = async (skillsSrc, templates) => {
323
+ const metadataMap = await loadAllSkillMetadata(skillsSrc);
324
+ const isNonUITemplate = templates.some((t) => NON_UI_TEMPLATES.includes(t));
325
+ const skillsToInstall = [];
326
+ for (const [skillName, metadata] of metadataMap) {
327
+ if (isNonUITemplate && metadata.uiOnly) {
328
+ continue;
329
+ }
330
+ if (metadata.framework && !templates.includes(metadata.framework)) {
331
+ continue;
332
+ }
333
+ skillsToInstall.push(skillName);
334
+ }
335
+ return skillsToInstall;
336
+ };
274
337
  var copySkills = async (templates, targetDir) => {
275
338
  const counter = { files: 0, directories: 0 };
276
- const targetSkillsDir = path6.join(targetDir, ".claude", "skills");
277
- const skillsSrc = path6.join(getTemplatesDir(), ".claude", "skills");
278
- if (!await fs4.pathExists(skillsSrc)) {
339
+ const targetSkillsDir = path7.join(targetDir, ".claude", "skills");
340
+ const skillsSrc = path7.join(getTemplatesDir(), ".claude", "skills");
341
+ if (!await fs5.pathExists(skillsSrc)) {
279
342
  return counter;
280
343
  }
281
- await fs4.ensureDir(targetSkillsDir);
282
- const skillsToCopy = /* @__PURE__ */ new Set();
283
- const skillTemplateMap = /* @__PURE__ */ new Map();
284
- COMMON_SKILLS.forEach((skill) => skillsToCopy.add(skill));
285
- for (const template of templates) {
286
- const skills = FRAMEWORK_SPECIFIC_SKILLS_MAP[template] || [];
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
- });
294
- }
295
- for (const skill of skillsToCopy) {
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);
301
- }
302
- await copyRecursive(skillSrc, skillDest, counter);
303
- }
304
- }
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
- });
344
+ await fs5.ensureDir(targetSkillsDir);
345
+ const skillsToInstall = await getSkillsToInstall(skillsSrc, templates);
346
+ for (const skill of skillsToInstall) {
347
+ const skillSrc = path7.join(skillsSrc, skill);
348
+ const skillDest = path7.join(targetSkillsDir, skill);
349
+ if (await fs5.pathExists(skillDest)) {
350
+ await fs5.remove(skillDest);
312
351
  }
352
+ await copyRecursive(skillSrc, skillDest, counter);
313
353
  }
314
- return {
315
- ...counter,
316
- ...duplicateSkills.length > 0 && { duplicateSkills }
317
- };
354
+ return counter;
318
355
  };
319
356
 
320
357
  // src/features/extras/extras-checker.ts
321
- import fs5 from "fs-extra";
322
- import path7 from "path";
358
+ import fs6 from "fs-extra";
359
+ import path8 from "path";
323
360
  var checkExistingClaudeFiles = async (targetDir) => {
324
361
  const existingFiles = [];
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)) {
362
+ const skillsDir = path8.join(targetDir, ".claude", "skills");
363
+ const commandsDir = path8.join(targetDir, ".claude", "commands");
364
+ const agentsDir = path8.join(targetDir, ".claude", "agents");
365
+ const instructionsDir = path8.join(targetDir, ".claude", "instructions");
366
+ if (await fs6.pathExists(skillsDir)) {
330
367
  existingFiles.push(".claude/skills/");
331
368
  }
332
- if (await fs5.pathExists(commandsDir)) {
369
+ if (await fs6.pathExists(commandsDir)) {
333
370
  existingFiles.push(".claude/commands/");
334
371
  }
335
- if (await fs5.pathExists(agentsDir)) {
372
+ if (await fs6.pathExists(agentsDir)) {
336
373
  existingFiles.push(".claude/agents/");
337
374
  }
338
- if (await fs5.pathExists(instructionsDir)) {
375
+ if (await fs6.pathExists(instructionsDir)) {
339
376
  existingFiles.push(".claude/instructions/");
340
377
  }
341
378
  return existingFiles;
342
379
  };
343
- var checkAllExtrasExist = async (templates) => {
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");
348
- const hasFrameworkSkills = templates.some((template) => {
349
- const skills = FRAMEWORK_SPECIFIC_SKILLS_MAP[template];
350
- return skills && skills.length > 0;
351
- });
352
- const hasSkills = COMMON_SKILLS.length > 0 || hasFrameworkSkills;
380
+ var checkAllExtrasExist = async (_templates) => {
381
+ const claudeDir = path8.join(getTemplatesDir(), ".claude");
382
+ const skillsSrc = path8.join(claudeDir, "skills");
383
+ const commandsSrc = path8.join(claudeDir, "commands");
384
+ const agentsSrc = path8.join(claudeDir, "agents");
385
+ const instructionsSrc = path8.join(claudeDir, "instructions");
386
+ const hasSkills = await hasFiles(skillsSrc);
353
387
  const hasCommands = await hasFiles(commandsSrc);
354
388
  const hasAgents = await hasFiles(agentsSrc);
355
389
  const hasInstructions = await hasFiles(instructionsSrc);
@@ -367,15 +401,6 @@ async function promptConfirm(message, initial = false) {
367
401
  });
368
402
  return { confirmed: response.confirmed ?? false };
369
403
  }
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
404
  async function promptMultiselect(message, choices, options) {
380
405
  const response = await prompts({
381
406
  type: "multiselect",
@@ -447,8 +472,8 @@ async function promptExtrasSelection(options) {
447
472
  } = options;
448
473
  let installSkills = skills ?? false;
449
474
  let installCommands = commands ?? false;
450
- let installAgents = agents ?? hasAgents;
451
- let installInstructions = instructions ?? hasInstructions;
475
+ const installAgents = agents ?? hasAgents;
476
+ const installInstructions = instructions ?? hasInstructions;
452
477
  const noOptionsProvided = skills === void 0 && commands === void 0 && agents === void 0 && instructions === void 0;
453
478
  if (noOptionsProvided && (hasSkills || hasCommands || hasAgents || hasInstructions)) {
454
479
  logger.blank();
@@ -489,32 +514,6 @@ async function handleDuplicateFiles(existingClaudeFiles, force) {
489
514
  );
490
515
  return response.confirmed;
491
516
  }
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
517
  async function installSkillsIfNeeded(templates, targetDir, shouldInstall, hasSkills) {
519
518
  if (!shouldInstall) {
520
519
  return { files: 0, directories: 0 };
@@ -526,13 +525,6 @@ async function installSkillsIfNeeded(templates, targetDir, shouldInstall, hasSki
526
525
  logger.blank();
527
526
  logger.info("Installing skills...");
528
527
  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
528
  logger.success(
537
529
  `Skills: ${skillsResult.files} files, ${skillsResult.directories} directories`
538
530
  );
@@ -627,8 +619,8 @@ async function installExtras(templates, targetDir, flags, availability, force) {
627
619
  }
628
620
 
629
621
  // src/shared/gitignore-manager.ts
630
- import fs6 from "fs-extra";
631
- import path8 from "path";
622
+ import fs7 from "fs-extra";
623
+ import path9 from "path";
632
624
  var CLAUDE_GENERATED_FOLDERS = [
633
625
  ".claude/plan/",
634
626
  ".claude/ralph/",
@@ -636,14 +628,14 @@ var CLAUDE_GENERATED_FOLDERS = [
636
628
  ".claude/prd/"
637
629
  ];
638
630
  async function updateGitignore(targetDir) {
639
- const gitignorePath = path8.join(targetDir, ".gitignore");
631
+ const gitignorePath = path9.join(targetDir, ".gitignore");
640
632
  const sectionComment = "# Claude Code generated files";
641
633
  let content = "";
642
634
  let hasGitignore = false;
643
635
  try {
644
- content = await fs6.readFile(gitignorePath, "utf-8");
636
+ content = await fs7.readFile(gitignorePath, "utf-8");
645
637
  hasGitignore = true;
646
- } catch (error) {
638
+ } catch {
647
639
  content = "";
648
640
  }
649
641
  const linesToAdd = [];
@@ -684,7 +676,7 @@ async function updateGitignore(targetDir) {
684
676
  newContent += linesToAdd.join("\n") + "\n";
685
677
  }
686
678
  }
687
- await fs6.writeFile(gitignorePath, newContent, "utf-8");
679
+ await fs7.writeFile(gitignorePath, newContent, "utf-8");
688
680
  if (hasGitignore) {
689
681
  logger.success(`.gitignore updated with ${linesToAdd.length} patterns`);
690
682
  } else {
@@ -700,7 +692,7 @@ var TEMPLATE_DESCRIPTIONS = {
700
692
  };
701
693
  async function validateTargetDirectory(targetDir) {
702
694
  try {
703
- const stat = await fs7.stat(targetDir);
695
+ const stat = await fs8.stat(targetDir);
704
696
  if (!stat.isDirectory()) {
705
697
  logger.error(`Target is not a directory: ${targetDir}`);
706
698
  process.exit(1);
@@ -714,7 +706,7 @@ async function validateTargetDirectory(targetDir) {
714
706
  process.exit(1);
715
707
  }
716
708
  try {
717
- await fs7.access(targetDir, fs7.constants.W_OK);
709
+ await fs8.access(targetDir, fs8.constants.W_OK);
718
710
  } catch {
719
711
  logger.error(`No write permission for: ${targetDir}`);
720
712
  process.exit(1);
@@ -854,7 +846,7 @@ var init = async (options) => {
854
846
 
855
847
  // src/index.ts
856
848
  var program = new Command();
857
- program.name("claude-code").description("Claude Code documentation installer for projects").version("0.5.9");
849
+ program.name("claude-code").description("Claude Code documentation installer for projects").version("0.6.0");
858
850
  program.option(
859
851
  "-t, --template <names>",
860
852
  "template names (comma-separated: tanstack-start,hono)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kood/claude-code",
3
- "version": "0.5.9",
3
+ "version": "0.6.0",
4
4
  "description": "Claude Code documentation installer for projects",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.js",