@kood/claude-code 0.6.5 → 0.6.7

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 (137) hide show
  1. package/dist/index.js +255 -149
  2. package/package.json +1 -1
  3. package/templates/.claude/agents/researcher.md +8 -1
  4. package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
  5. package/templates/.claude/scripts/deploy/build-run.sh +36 -0
  6. package/templates/.claude/scripts/deploy/deploy-check.sh +38 -0
  7. package/templates/.claude/scripts/git/git-all.sh +57 -0
  8. package/templates/.claude/scripts/git/git-clean-check.sh +31 -0
  9. package/templates/.claude/scripts/git/git-commit.sh +51 -0
  10. package/templates/.claude/scripts/git/git-info.sh +34 -0
  11. package/templates/.claude/scripts/git/git-push.sh +50 -0
  12. package/templates/.claude/scripts/lint/lint-check.sh +56 -0
  13. package/templates/.claude/scripts/lint/lint-file.sh +41 -0
  14. package/templates/.claude/scripts/pm/pm-detect.sh +25 -0
  15. package/templates/.claude/scripts/pm/pm-run.sh +41 -0
  16. package/templates/.claude/scripts/version/version-bump.sh +54 -0
  17. package/templates/.claude/scripts/version/version-find.sh +49 -0
  18. package/templates/.claude/skills/docs-fetch/SKILL.md +5 -4
  19. package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
  20. package/templates/.claude/skills/project-optimizer/SKILL.md +374 -0
  21. package/templates/.claude/skills/project-optimizer/rules/arch-config-centralize.md +66 -0
  22. package/templates/.claude/skills/project-optimizer/rules/arch-hot-path.md +35 -0
  23. package/templates/.claude/skills/project-optimizer/rules/arch-interface-segregation.md +51 -0
  24. package/templates/.claude/skills/project-optimizer/rules/arch-module-boundary.md +42 -0
  25. package/templates/.claude/skills/project-optimizer/rules/build-cache.md +57 -0
  26. package/templates/.claude/skills/project-optimizer/rules/build-code-split.md +56 -0
  27. package/templates/.claude/skills/project-optimizer/rules/build-incremental.md +65 -0
  28. package/templates/.claude/skills/project-optimizer/rules/build-minify.md +61 -0
  29. package/templates/.claude/skills/project-optimizer/rules/build-tree-shake.md +60 -0
  30. package/templates/.claude/skills/project-optimizer/rules/code-complexity.md +65 -0
  31. package/templates/.claude/skills/project-optimizer/rules/code-dead-elimination.md +32 -0
  32. package/templates/.claude/skills/project-optimizer/rules/code-duplication.md +54 -0
  33. package/templates/.claude/skills/project-optimizer/rules/code-error-handling.md +75 -0
  34. package/templates/.claude/skills/project-optimizer/rules/code-naming.md +52 -0
  35. package/templates/.claude/skills/project-optimizer/rules/concurrency-defer-await.md +54 -0
  36. package/templates/.claude/skills/project-optimizer/rules/concurrency-parallel.md +90 -0
  37. package/templates/.claude/skills/project-optimizer/rules/concurrency-pipeline.md +68 -0
  38. package/templates/.claude/skills/project-optimizer/rules/concurrency-pool.md +68 -0
  39. package/templates/.claude/skills/project-optimizer/rules/deps-lightweight-alt.md +37 -0
  40. package/templates/.claude/skills/project-optimizer/rules/deps-peer-align.md +44 -0
  41. package/templates/.claude/skills/project-optimizer/rules/deps-security-audit.md +45 -0
  42. package/templates/.claude/skills/project-optimizer/rules/deps-unused-removal.md +25 -0
  43. package/templates/.claude/skills/project-optimizer/rules/deps-version-pin.md +40 -0
  44. package/templates/.claude/skills/project-optimizer/rules/dx-ci-speed.md +47 -0
  45. package/templates/.claude/skills/project-optimizer/rules/dx-dev-server.md +35 -0
  46. package/templates/.claude/skills/project-optimizer/rules/dx-lint-config.md +36 -0
  47. package/templates/.claude/skills/project-optimizer/rules/dx-test-coverage.md +34 -0
  48. package/templates/.claude/skills/project-optimizer/rules/dx-type-safety.md +49 -0
  49. package/templates/.claude/skills/project-optimizer/rules/io-batch-queries.md +67 -0
  50. package/templates/.claude/skills/project-optimizer/rules/io-cache-layer.md +67 -0
  51. package/templates/.claude/skills/project-optimizer/rules/io-connection-reuse.md +67 -0
  52. package/templates/.claude/skills/project-optimizer/rules/io-serialize-minimal.md +61 -0
  53. package/templates/.claude/skills/project-optimizer/rules/io-stream.md +75 -0
  54. package/templates/.claude/skills/project-optimizer/rules/memory-bounded-cache.md +65 -0
  55. package/templates/.claude/skills/project-optimizer/rules/memory-large-data.md +64 -0
  56. package/templates/.claude/skills/project-optimizer/rules/memory-lazy-init.md +78 -0
  57. package/templates/.claude/skills/project-optimizer/rules/memory-leak-prevention.md +79 -0
  58. package/templates/.claude/skills/project-optimizer/rules/memory-pool-reuse.md +70 -0
  59. package/templates/.claude/skills/sql-optimizer/SKILL.md +437 -0
  60. package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
  61. package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +53 -14
  62. package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +93 -27
  63. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +42 -19
  64. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-optimistic-updates.md +109 -0
  65. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-suspense-query.md +74 -0
  66. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-use-hook.md +81 -0
  67. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-react-compiler.md +81 -0
  68. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-beforeload-auth.md +121 -0
  69. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-file-conventions.md +104 -0
  70. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-link-navigation.md +119 -0
  71. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-nested-layouts.md +155 -0
  72. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-path-params.md +89 -0
  73. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-pending-component.md +110 -0
  74. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-preload-strategy.md +91 -0
  75. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-router-context.md +120 -0
  76. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-search-params.md +114 -0
  77. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +1 -1
  78. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-error-boundaries.md +79 -0
  79. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-middleware.md +85 -0
  80. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +56 -21
  81. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-streaming.md +84 -0
  82. package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-validator.md +71 -0
  83. package/templates/.claude/skills/tauri-react-best-practices/AGENTS.md +527 -0
  84. package/templates/.claude/skills/tauri-react-best-practices/SKILL.md +570 -0
  85. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-barrel-imports.md +140 -0
  86. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-cargo-profile.md +96 -0
  87. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-frontend-treeshake.md +242 -0
  88. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-lazy-components.md +255 -0
  89. package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-remove-unused-commands.md +160 -0
  90. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-ci-pipeline.md +269 -0
  91. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-signing.md +207 -0
  92. package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-updater.md +226 -0
  93. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-async-commands.md +172 -0
  94. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-batch-commands.md +133 -0
  95. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-binary-response.md +198 -0
  96. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-channel-streaming.md +186 -0
  97. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-error-handling.md +250 -0
  98. package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-type-safe.md +227 -0
  99. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-derived-state.md +231 -0
  100. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-functional-setstate.md +191 -0
  101. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-index-maps.md +276 -0
  102. package/templates/.claude/skills/tauri-react-best-practices/rules/perf-lazy-state-init.md +196 -0
  103. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-lifecycle.md +265 -0
  104. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-mobile-compat.md +199 -0
  105. package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-permission-scope.md +193 -0
  106. package/templates/.claude/skills/tauri-react-best-practices/rules/react-error-boundary.md +239 -0
  107. package/templates/.claude/skills/tauri-react-best-practices/rules/react-event-listener.md +151 -0
  108. package/templates/.claude/skills/tauri-react-best-practices/rules/react-file-src.md +155 -0
  109. package/templates/.claude/skills/tauri-react-best-practices/rules/react-invoke-hook.md +139 -0
  110. package/templates/.claude/skills/tauri-react-best-practices/rules/react-optimistic-update.md +211 -0
  111. package/templates/.claude/skills/tauri-react-best-practices/rules/security-capability-split.md +205 -0
  112. package/templates/.claude/skills/tauri-react-best-practices/rules/security-csp.md +207 -0
  113. package/templates/.claude/skills/tauri-react-best-practices/rules/security-least-privilege.md +106 -0
  114. package/templates/.claude/skills/tauri-react-best-practices/rules/security-no-wildcard.md +253 -0
  115. package/templates/.claude/skills/tauri-react-best-practices/rules/security-scope-paths.md +160 -0
  116. package/templates/.claude/skills/tauri-react-best-practices/rules/state-async-mutex.md +270 -0
  117. package/templates/.claude/skills/tauri-react-best-practices/rules/state-mutex-pattern.md +265 -0
  118. package/templates/.claude/skills/tauri-react-best-practices/rules/state-react-sync.md +375 -0
  119. package/templates/.claude/skills/tauri-react-best-practices/rules/state-single-container.md +275 -0
  120. package/templates/tanstack-start/docs/architecture.md +238 -167
  121. package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +777 -38
  122. package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +549 -37
  123. package/templates/tanstack-start/docs/library/tanstack-router/index.md +895 -111
  124. package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +641 -43
  125. package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +889 -38
  126. package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +891 -29
  127. package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +972 -36
  128. package/templates/tanstack-start/docs/library/tanstack-start/index.md +1525 -881
  129. package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +1099 -20
  130. package/templates/tanstack-start/docs/library/tanstack-start/routing.md +796 -30
  131. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +953 -35
  132. package/templates/tanstack-start/docs/library/tanstack-start/setup.md +371 -15
  133. package/templates/tauri/CLAUDE.md +189 -0
  134. package/templates/tauri/docs/guides/distribution.md +261 -0
  135. package/templates/tauri/docs/guides/getting-started.md +302 -0
  136. package/templates/tauri/docs/guides/mobile.md +288 -0
  137. package/templates/tauri/docs/library/tauri/index.md +510 -0
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ var banner = () => {
23
23
 
24
24
  // src/commands/init.ts
25
25
  import fs8 from "fs-extra";
26
+ import os from "os";
26
27
 
27
28
  // src/features/templates/template-path-resolver.ts
28
29
  import path2 from "path";
@@ -117,6 +118,11 @@ var templateMetadata = {
117
118
  name: "NPX CLI",
118
119
  description: "NPX\uB85C \uC2E4\uD589 \uAC00\uB2A5\uD55C CLI \uB3C4\uAD6C \uD504\uB85C\uC81D\uD2B8",
119
120
  stack: "Node.js, TypeScript, Commander.js"
121
+ },
122
+ tauri: {
123
+ name: "Tauri",
124
+ description: "Cross-platform Desktop & Mobile \uC571 \uD504\uB85C\uC81D\uD2B8",
125
+ stack: "Rust, React, TypeScript, Vite"
120
126
  }
121
127
  };
122
128
  var generateIndexClaudeMd = (templates) => {
@@ -319,6 +325,7 @@ var createExtrasCopier = (extrasType) => {
319
325
  var copyCommands = createExtrasCopier("commands");
320
326
  var copyAgents = createExtrasCopier("agents");
321
327
  var copyInstructions = createExtrasCopier("instructions");
328
+ var copyScripts = createExtrasCopier("scripts");
322
329
  var getSkillsToInstall = async (skillsSrc, templates) => {
323
330
  const metadataMap = await loadAllSkillMetadata(skillsSrc);
324
331
  const isNonUITemplate = templates.some((t) => NON_UI_TEMPLATES.includes(t));
@@ -363,6 +370,7 @@ var checkExistingClaudeFiles = async (targetDir) => {
363
370
  const commandsDir = path8.join(targetDir, ".claude", "commands");
364
371
  const agentsDir = path8.join(targetDir, ".claude", "agents");
365
372
  const instructionsDir = path8.join(targetDir, ".claude", "instructions");
373
+ const scriptsDir = path8.join(targetDir, ".claude", "scripts");
366
374
  if (await fs6.pathExists(skillsDir)) {
367
375
  existingFiles.push(".claude/skills/");
368
376
  }
@@ -375,6 +383,9 @@ var checkExistingClaudeFiles = async (targetDir) => {
375
383
  if (await fs6.pathExists(instructionsDir)) {
376
384
  existingFiles.push(".claude/instructions/");
377
385
  }
386
+ if (await fs6.pathExists(scriptsDir)) {
387
+ existingFiles.push(".claude/scripts/");
388
+ }
378
389
  return existingFiles;
379
390
  };
380
391
  var checkAllExtrasExist = async (_templates) => {
@@ -383,13 +394,150 @@ var checkAllExtrasExist = async (_templates) => {
383
394
  const commandsSrc = path8.join(claudeDir, "commands");
384
395
  const agentsSrc = path8.join(claudeDir, "agents");
385
396
  const instructionsSrc = path8.join(claudeDir, "instructions");
397
+ const scriptsSrc = path8.join(claudeDir, "scripts");
386
398
  const hasSkills = await hasFiles(skillsSrc);
387
399
  const hasCommands = await hasFiles(commandsSrc);
388
400
  const hasAgents = await hasFiles(agentsSrc);
389
401
  const hasInstructions = await hasFiles(instructionsSrc);
390
- return { hasSkills, hasCommands, hasAgents, hasInstructions };
402
+ const hasScripts = await hasFiles(scriptsSrc);
403
+ return { hasSkills, hasCommands, hasAgents, hasInstructions, hasScripts };
391
404
  };
392
405
 
406
+ // src/features/extras/extras-installer.ts
407
+ function logExistingFilesUpdate(existingClaudeFiles) {
408
+ if (existingClaudeFiles.length > 0) {
409
+ logger.info("Updating existing extras:");
410
+ existingClaudeFiles.forEach((f) => logger.step(f));
411
+ }
412
+ }
413
+ async function installSkillsIfNeeded(templates, targetDir, shouldInstall, hasSkills) {
414
+ if (!shouldInstall) {
415
+ return { files: 0, directories: 0 };
416
+ }
417
+ if (!hasSkills) {
418
+ logger.warn("No skills found in selected templates.");
419
+ return { files: 0, directories: 0 };
420
+ }
421
+ logger.blank();
422
+ logger.info("Installing skills...");
423
+ const skillsResult = await copySkills(templates, targetDir);
424
+ logger.success(
425
+ `Skills: ${skillsResult.files} files, ${skillsResult.directories} directories`
426
+ );
427
+ return skillsResult;
428
+ }
429
+ async function installCommandsIfNeeded(templates, targetDir, shouldInstall, hasCommands) {
430
+ if (!shouldInstall) {
431
+ return { files: 0, directories: 0 };
432
+ }
433
+ if (!hasCommands) {
434
+ logger.warn("No commands found in selected templates.");
435
+ return { files: 0, directories: 0 };
436
+ }
437
+ logger.blank();
438
+ logger.info("Installing commands...");
439
+ const commandsResult = await copyCommands(templates, targetDir);
440
+ logger.success(
441
+ `Commands: ${commandsResult.files} files, ${commandsResult.directories} directories`
442
+ );
443
+ return commandsResult;
444
+ }
445
+ async function installAgentsIfNeeded(templates, targetDir, shouldInstall, hasAgents) {
446
+ if (!shouldInstall) {
447
+ return { files: 0, directories: 0 };
448
+ }
449
+ if (!hasAgents) {
450
+ logger.warn("No agents found in selected templates.");
451
+ return { files: 0, directories: 0 };
452
+ }
453
+ logger.blank();
454
+ logger.info("Installing agents...");
455
+ const agentsResult = await copyAgents(templates, targetDir);
456
+ logger.success(
457
+ `Agents: ${agentsResult.files} files, ${agentsResult.directories} directories`
458
+ );
459
+ return agentsResult;
460
+ }
461
+ async function installScriptsIfNeeded(templates, targetDir, shouldInstall, hasScripts) {
462
+ if (!shouldInstall) {
463
+ return { files: 0, directories: 0 };
464
+ }
465
+ if (!hasScripts) {
466
+ logger.warn("No scripts found in selected templates.");
467
+ return { files: 0, directories: 0 };
468
+ }
469
+ logger.blank();
470
+ logger.info("Installing scripts...");
471
+ const scriptsResult = await copyScripts(templates, targetDir);
472
+ logger.success(
473
+ `Scripts: ${scriptsResult.files} files, ${scriptsResult.directories} directories`
474
+ );
475
+ return scriptsResult;
476
+ }
477
+ async function installInstructionsIfNeeded(templates, targetDir, shouldInstall, hasInstructions) {
478
+ if (!shouldInstall) {
479
+ return { files: 0, directories: 0 };
480
+ }
481
+ if (!hasInstructions) {
482
+ logger.warn("No instructions found in selected templates.");
483
+ return { files: 0, directories: 0 };
484
+ }
485
+ logger.blank();
486
+ logger.info("Installing instructions...");
487
+ const instructionsResult = await copyInstructions(templates, targetDir);
488
+ logger.success(
489
+ `Instructions: ${instructionsResult.files} files, ${instructionsResult.directories} directories`
490
+ );
491
+ return instructionsResult;
492
+ }
493
+ async function installExtras(templates, targetDir, flags, availability) {
494
+ const {
495
+ installSkills,
496
+ installCommands,
497
+ installAgents,
498
+ installInstructions,
499
+ installScripts
500
+ } = flags;
501
+ if (!installSkills && !installCommands && !installAgents && !installInstructions && !installScripts) {
502
+ return { files: 0, directories: 0 };
503
+ }
504
+ const existingClaudeFiles = await checkExistingClaudeFiles(targetDir);
505
+ logExistingFilesUpdate(existingClaudeFiles);
506
+ const skillsResult = await installSkillsIfNeeded(
507
+ templates,
508
+ targetDir,
509
+ installSkills,
510
+ availability.hasSkills
511
+ );
512
+ const commandsResult = await installCommandsIfNeeded(
513
+ templates,
514
+ targetDir,
515
+ installCommands,
516
+ availability.hasCommands
517
+ );
518
+ const agentsResult = await installAgentsIfNeeded(
519
+ templates,
520
+ targetDir,
521
+ installAgents,
522
+ availability.hasAgents
523
+ );
524
+ const instructionsResult = await installInstructionsIfNeeded(
525
+ templates,
526
+ targetDir,
527
+ installInstructions,
528
+ availability.hasInstructions
529
+ );
530
+ const scriptsResult = await installScriptsIfNeeded(
531
+ templates,
532
+ targetDir,
533
+ installScripts,
534
+ availability.hasScripts
535
+ );
536
+ const totalFiles = skillsResult.files + commandsResult.files + agentsResult.files + instructionsResult.files + scriptsResult.files;
537
+ const totalDirectories = skillsResult.directories + commandsResult.directories + agentsResult.directories + instructionsResult.directories + scriptsResult.directories;
538
+ return { files: totalFiles, directories: totalDirectories };
539
+ }
540
+
393
541
  // src/shared/prompts/prompt-helpers.ts
394
542
  import prompts from "prompts";
395
543
  async function promptConfirm(message, initial = false) {
@@ -401,6 +549,15 @@ async function promptConfirm(message, initial = false) {
401
549
  });
402
550
  return { confirmed: response.confirmed ?? false };
403
551
  }
552
+ async function promptSelect(message, choices) {
553
+ const response = await prompts({
554
+ type: "select",
555
+ name: "value",
556
+ message,
557
+ choices
558
+ });
559
+ return { value: response.value };
560
+ }
404
561
  async function promptMultiselect(message, choices, options) {
405
562
  const response = await prompts({
406
563
  type: "multiselect",
@@ -461,17 +618,20 @@ async function promptExtrasSelection(options) {
461
618
  commands,
462
619
  agents,
463
620
  instructions,
621
+ scripts,
464
622
  hasSkills,
465
623
  hasCommands,
466
624
  hasAgents,
467
- hasInstructions
625
+ hasInstructions,
626
+ hasScripts
468
627
  } = options;
469
628
  let installSkills = skills ?? false;
470
629
  let installCommands = commands ?? false;
471
630
  const installAgents = agents ?? hasAgents;
472
631
  const installInstructions = instructions ?? hasInstructions;
473
- const noOptionsProvided = skills === void 0 && commands === void 0 && agents === void 0 && instructions === void 0;
474
- if (noOptionsProvided && (hasSkills || hasCommands || hasAgents || hasInstructions)) {
632
+ const installScripts = scripts ?? hasScripts;
633
+ const noOptionsProvided = skills === void 0 && commands === void 0 && agents === void 0 && instructions === void 0 && scripts === void 0;
634
+ if (noOptionsProvided && (hasSkills || hasCommands || hasAgents || hasInstructions || hasScripts)) {
475
635
  logger.blank();
476
636
  if (hasSkills) {
477
637
  const result = await promptConfirm(
@@ -492,126 +652,41 @@ async function promptExtrasSelection(options) {
492
652
  installSkills,
493
653
  installCommands,
494
654
  installAgents,
495
- installInstructions
655
+ installInstructions,
656
+ installScripts
496
657
  };
497
658
  }
498
-
499
- // src/features/extras/extras-installer.ts
500
- async function handleDuplicateFiles(existingClaudeFiles, force) {
501
- if (existingClaudeFiles.length === 0 || force) {
502
- return true;
503
- }
504
- logger.warn("The following .claude files/folders already exist:");
505
- existingClaudeFiles.forEach((f) => logger.step(f));
506
- logger.blank();
507
- const response = await promptConfirm(
508
- "Overwrite existing .claude files?",
509
- false
510
- );
511
- return response.confirmed;
512
- }
513
- async function installSkillsIfNeeded(templates, targetDir, shouldInstall, hasSkills) {
514
- if (!shouldInstall) {
515
- return { files: 0, directories: 0 };
516
- }
517
- if (!hasSkills) {
518
- logger.warn("No skills found in selected templates.");
519
- return { files: 0, directories: 0 };
520
- }
521
- logger.blank();
522
- logger.info("Installing skills...");
523
- const skillsResult = await copySkills(templates, targetDir);
524
- logger.success(
525
- `Skills: ${skillsResult.files} files, ${skillsResult.directories} directories`
526
- );
527
- return skillsResult;
528
- }
529
- async function installCommandsIfNeeded(templates, targetDir, shouldInstall, hasCommands) {
530
- if (!shouldInstall) {
531
- return { files: 0, directories: 0 };
532
- }
533
- if (!hasCommands) {
534
- logger.warn("No commands found in selected templates.");
535
- return { files: 0, directories: 0 };
536
- }
537
- logger.blank();
538
- logger.info("Installing commands...");
539
- const commandsResult = await copyCommands(templates, targetDir);
540
- logger.success(
541
- `Commands: ${commandsResult.files} files, ${commandsResult.directories} directories`
542
- );
543
- return commandsResult;
544
- }
545
- async function installAgentsIfNeeded(templates, targetDir, shouldInstall, hasAgents) {
546
- if (!shouldInstall) {
547
- return { files: 0, directories: 0 };
548
- }
549
- if (!hasAgents) {
550
- logger.warn("No agents found in selected templates.");
551
- return { files: 0, directories: 0 };
552
- }
553
- logger.blank();
554
- logger.info("Installing agents...");
555
- const agentsResult = await copyAgents(templates, targetDir);
556
- logger.success(
557
- `Agents: ${agentsResult.files} files, ${agentsResult.directories} directories`
558
- );
559
- return agentsResult;
560
- }
561
- async function installInstructionsIfNeeded(templates, targetDir, shouldInstall, hasInstructions) {
562
- if (!shouldInstall) {
563
- return { files: 0, directories: 0 };
564
- }
565
- if (!hasInstructions) {
566
- logger.warn("No instructions found in selected templates.");
567
- return { files: 0, directories: 0 };
659
+ async function promptScopeSelection(options) {
660
+ const { providedScope } = options;
661
+ if (providedScope) {
662
+ if (providedScope !== "project" && providedScope !== "user") {
663
+ logger.error(
664
+ `Invalid scope: "${providedScope}". Use "project" or "user".`
665
+ );
666
+ process.exit(1);
667
+ }
668
+ return { scope: providedScope };
568
669
  }
569
- logger.blank();
570
- logger.info("Installing instructions...");
571
- const instructionsResult = await copyInstructions(templates, targetDir);
572
- logger.success(
573
- `Instructions: ${instructionsResult.files} files, ${instructionsResult.directories} directories`
670
+ const response = await promptSelect(
671
+ "Select installation scope:",
672
+ [
673
+ {
674
+ title: "Project",
675
+ description: "Install to current project (.claude/)",
676
+ value: "project"
677
+ },
678
+ {
679
+ title: "User",
680
+ description: "Install to user home (~/.claude/)",
681
+ value: "user"
682
+ }
683
+ ]
574
684
  );
575
- return instructionsResult;
576
- }
577
- async function installExtras(templates, targetDir, flags, availability, force) {
578
- const { installSkills, installCommands, installAgents, installInstructions } = flags;
579
- if (!installSkills && !installCommands && !installAgents && !installInstructions) {
580
- return { files: 0, directories: 0 };
581
- }
582
- const existingClaudeFiles = await checkExistingClaudeFiles(targetDir);
583
- const shouldProceed = await handleDuplicateFiles(existingClaudeFiles, force);
584
- if (!shouldProceed) {
585
- logger.info("Skipping extras installation.");
586
- return { files: 0, directories: 0 };
685
+ if (!response.value) {
686
+ logger.info("Operation cancelled.");
687
+ process.exit(0);
587
688
  }
588
- const skillsResult = await installSkillsIfNeeded(
589
- templates,
590
- targetDir,
591
- installSkills,
592
- availability.hasSkills
593
- );
594
- const commandsResult = await installCommandsIfNeeded(
595
- templates,
596
- targetDir,
597
- installCommands,
598
- availability.hasCommands
599
- );
600
- const agentsResult = await installAgentsIfNeeded(
601
- templates,
602
- targetDir,
603
- installAgents,
604
- availability.hasAgents
605
- );
606
- const instructionsResult = await installInstructionsIfNeeded(
607
- templates,
608
- targetDir,
609
- installInstructions,
610
- availability.hasInstructions
611
- );
612
- const totalFiles = skillsResult.files + commandsResult.files + agentsResult.files + instructionsResult.files;
613
- const totalDirectories = skillsResult.directories + commandsResult.directories + agentsResult.directories + instructionsResult.directories;
614
- return { files: totalFiles, directories: totalDirectories };
689
+ return { scope: response.value };
615
690
  }
616
691
 
617
692
  // src/shared/gitignore-manager.ts
@@ -684,7 +759,8 @@ async function updateGitignore(targetDir) {
684
759
  var TEMPLATE_DESCRIPTIONS = {
685
760
  "tanstack-start": "TanStack Start + React \uD480\uC2A4\uD0DD \uD504\uB85C\uC81D\uD2B8",
686
761
  hono: "Hono \uC11C\uBC84 \uD504\uB808\uC784\uC6CC\uD06C \uD504\uB85C\uC81D\uD2B8",
687
- npx: "NPX CLI \uB3C4\uAD6C \uD504\uB85C\uC81D\uD2B8"
762
+ npx: "NPX CLI \uB3C4\uAD6C \uD504\uB85C\uC81D\uD2B8",
763
+ tauri: "Tauri \uB370\uC2A4\uD06C\uD1B1/\uBAA8\uBC14\uC77C \uD06C\uB85C\uC2A4\uD50C\uB7AB\uD3FC \uC571"
688
764
  };
689
765
  async function validateTargetDirectory(targetDir) {
690
766
  try {
@@ -756,29 +832,38 @@ async function installTemplates(templates, targetDir) {
756
832
  logger.success(`Total: ${totalFiles} files, ${totalDirectories} directories`);
757
833
  return { files: totalFiles, directories: totalDirectories };
758
834
  }
759
- async function promptForExtrasInstallation(options, hasSkills, hasCommands, hasAgents, hasInstructions) {
835
+ async function promptForExtrasInstallation(options, hasSkills, hasCommands, hasAgents, hasInstructions, hasScripts) {
760
836
  return await promptExtrasSelection({
761
837
  skills: options.skills,
762
838
  commands: options.commands,
763
839
  agents: options.agents,
764
840
  instructions: options.instructions,
841
+ scripts: options.scripts,
765
842
  hasSkills,
766
843
  hasCommands,
767
844
  hasAgents,
768
- hasInstructions
845
+ hasInstructions,
846
+ hasScripts
769
847
  });
770
848
  }
771
- function showInstallationSummary(templates, flags, hasSkills, hasCommands, hasAgents, hasInstructions) {
772
- const { installSkills, installCommands, installAgents, installInstructions } = flags;
773
- const hasExtrasInstalled = installSkills && hasSkills || installCommands && hasCommands || installAgents && hasAgents || installInstructions && hasInstructions;
849
+ function showInstallationSummary(templates, flags, hasSkills, hasCommands, hasAgents, hasInstructions, hasScripts, scope) {
850
+ const {
851
+ installSkills,
852
+ installCommands,
853
+ installAgents,
854
+ installInstructions,
855
+ installScripts
856
+ } = flags;
857
+ const hasExtrasInstalled = installSkills && hasSkills || installCommands && hasCommands || installAgents && hasAgents || installInstructions && hasInstructions || installScripts && hasScripts;
774
858
  if (templates.length === 0 && !hasExtrasInstalled) {
775
859
  logger.blank();
776
860
  logger.info("No templates or extras installed.");
777
861
  logger.blank();
778
862
  return;
779
863
  }
864
+ const scopeLabel = scope === "user" ? "(user scope \u2192 ~/.claude/)" : "(project scope)";
780
865
  logger.blank();
781
- logger.success("Claude Code documentation installed!");
866
+ logger.success(`Claude Code documentation installed! ${scopeLabel}`);
782
867
  if (templates.length > 0) {
783
868
  logger.blank();
784
869
  logger.info("Installed templates:");
@@ -799,6 +884,9 @@ function showInstallationSummary(templates, flags, hasSkills, hasCommands, hasAg
799
884
  if (installInstructions && hasInstructions) {
800
885
  logger.step("Instructions \u2192 .claude/instructions/");
801
886
  }
887
+ if (installScripts && hasScripts) {
888
+ logger.step("Scripts \u2192 .claude/scripts/");
889
+ }
802
890
  }
803
891
  logger.blank();
804
892
  logger.info("Next steps:");
@@ -812,48 +900,65 @@ function showInstallationSummary(templates, flags, hasSkills, hasCommands, hasAg
812
900
  logger.blank();
813
901
  }
814
902
  var init = async (options) => {
815
- const targetDir = options.cwd || process.cwd();
816
- await validateTargetDirectory(targetDir);
903
+ const projectDir = options.cwd || process.cwd();
904
+ await validateTargetDirectory(projectDir);
905
+ const { scope } = await promptScopeSelection({
906
+ providedScope: options.scope
907
+ });
908
+ const targetDir = scope === "user" ? os.homedir() : projectDir;
909
+ const isUserScope = scope === "user";
910
+ if (isUserScope) {
911
+ logger.blank();
912
+ logger.info(`Installing to ~/.claude/ (user scope)`);
913
+ }
817
914
  const availableTemplates = await listAvailableTemplates();
818
915
  if (availableTemplates.length === 0) {
819
916
  logger.error("No templates found. Package may be corrupted.");
820
917
  process.exit(1);
821
918
  }
822
- const templates = await selectTemplates(options, availableTemplates);
823
- if (templates.length > 0) {
824
- await confirmOverwriteIfNeeded(targetDir, options.force ?? false);
825
- await installTemplates(templates, targetDir);
919
+ let templates = [];
920
+ if (!isUserScope) {
921
+ templates = await selectTemplates(options, availableTemplates);
922
+ if (templates.length > 0) {
923
+ await confirmOverwriteIfNeeded(targetDir, options.force ?? false);
924
+ await installTemplates(templates, targetDir);
925
+ }
826
926
  }
827
927
  const templatesToCheck = templates.length > 0 ? templates : availableTemplates;
828
- const { hasSkills, hasCommands, hasAgents, hasInstructions } = await checkAllExtrasExist(templatesToCheck);
928
+ const { hasSkills, hasCommands, hasAgents, hasInstructions, hasScripts } = await checkAllExtrasExist(templatesToCheck);
829
929
  const flags = await promptForExtrasInstallation(
830
930
  options,
831
931
  hasSkills,
832
932
  hasCommands,
833
933
  hasAgents,
834
- hasInstructions
835
- );
836
- await installExtras(
837
- templatesToCheck,
838
- targetDir,
839
- flags,
840
- { hasSkills, hasCommands, hasAgents, hasInstructions },
841
- options.force ?? false
934
+ hasInstructions,
935
+ hasScripts
842
936
  );
937
+ await installExtras(templatesToCheck, targetDir, flags, {
938
+ hasSkills,
939
+ hasCommands,
940
+ hasAgents,
941
+ hasInstructions,
942
+ hasScripts
943
+ });
843
944
  showInstallationSummary(
844
945
  templates,
845
946
  flags,
846
947
  hasSkills,
847
948
  hasCommands,
848
949
  hasAgents,
849
- hasInstructions
950
+ hasInstructions,
951
+ hasScripts,
952
+ scope
850
953
  );
851
- try {
852
- await updateGitignore(targetDir);
853
- } catch (error) {
854
- logger.warn(
855
- `Failed to update .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`
856
- );
954
+ if (!isUserScope) {
955
+ try {
956
+ await updateGitignore(targetDir);
957
+ } catch (error) {
958
+ logger.warn(
959
+ `Failed to update .gitignore: ${error instanceof Error ? error.message : "Unknown error"}`
960
+ );
961
+ }
857
962
  }
858
963
  };
859
964
 
@@ -863,7 +968,7 @@ program.name("claude-code").description("Claude Code documentation installer for
863
968
  program.option(
864
969
  "-t, --template <names>",
865
970
  "template names (comma-separated: tanstack-start,hono)"
866
- ).option("-f, --force", "overwrite existing files without prompting").option("--cwd <path>", "target directory (default: current directory)").option("--list", "list available templates").option("-s, --skills", "install skills to .claude/skills/").option("-c, --commands", "install commands to .claude/commands/").option("-a, --agents", "install agents to .claude/agents/").action(async (options) => {
971
+ ).option("-f, --force", "overwrite existing files without prompting").option("--cwd <path>", "target directory (default: current directory)").option("--list", "list available templates").option("-s, --skills", "install skills to .claude/skills/").option("-c, --commands", "install commands to .claude/commands/").option("-a, --agents", "install agents to .claude/agents/").option("--scope <scope>", "installation scope (project|user)").action(async (options) => {
867
972
  banner();
868
973
  if (options.list) {
869
974
  const templates = await listAvailableTemplates();
@@ -876,6 +981,7 @@ program.option(
876
981
  templates: options.template?.split(",").map((t) => t.trim()),
877
982
  force: options.force,
878
983
  cwd: options.cwd,
984
+ scope: options.scope,
879
985
  skills: options.skills,
880
986
  commands: options.commands,
881
987
  agents: options.agents
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kood/claude-code",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "Claude Code documentation installer for projects",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.js",
@@ -61,7 +61,7 @@ permissionMode: default
61
61
  |------|------|------|
62
62
  | **1. 분석** | 질문 분해, 키워드 추출, 버전 확인 | - |
63
63
  | **2. 검색** | 공식 문서 → GitHub → Stack Overflow | WebSearch |
64
- | **3. 수집** | 관련 페이지 내용 읽기 | WebFetch |
64
+ | **3. 수집** | 관련 페이지 내용 읽기 (JS 렌더링 필요 시 `r.jina.ai` 폴백) | WebFetch |
65
65
  | **4. 검증** | 버전 일치 확인, 교차 검증 | - |
66
66
  | **5. 종합** | 핵심 요약 + 상세 내용 + 출처 | - |
67
67
 
@@ -78,6 +78,13 @@ permissionMode: default
78
78
  "[라이브러리명] migration guide v[버전]"
79
79
  ```
80
80
 
81
+ ## Jina Reader (JS 렌더링 / WebFetch 실패 시 폴백)
82
+ ```
83
+ WebFetch('https://r.jina.ai/{공식문서URL}', '{추출할 내용}')
84
+ → JS 렌더링 지원, 광고/네비 제거, 클린 마크다운 변환
85
+ → WebFetch로 빈 결과 시 Jina Reader 시도
86
+ ```
87
+
81
88
  ## GitHub
82
89
  ```
83
90
  "site:github.com [org]/[repo] [키워드]"
@@ -298,6 +298,7 @@ WebSearch({ query: "AI agent frameworks comparison" })
298
298
  | **WebSearch** | 연도 포함, 영어+한국어 병렬 |
299
299
  | **SearXNG** | `time_range=year` + 연도 키워드 |
300
300
  | **Firecrawl** | 공식 문서 URL 직접 지정 |
301
+ | **Jina Reader** | `WebFetch('https://r.jina.ai/{URL}')` — JS 렌더링 클린 MD 변환 |
301
302
  | **GitHub** | `created:>YYYY-01-01` 필터, stars 정렬 |
302
303
 
303
304
  ---
@@ -314,6 +315,7 @@ Tier 1 (MCP, ToolSearch로 감지):
314
315
  Tier 2 (내장, 항상 가용):
315
316
  WebSearch → 웹 검색 (연도 키워드 필수)
316
317
  WebFetch → 페이지 직접 읽기
318
+ Jina Reader → WebFetch('https://r.jina.ai/{URL}') 클린 마크다운 변환
317
319
  gh CLI → GitHub API (Bash via explore)
318
320
 
319
321
  Tier 3: Playwright → SPA/JS 렌더링 필요 시 (crawler skill)
@@ -323,10 +325,10 @@ Tier 3: Playwright → SPA/JS 렌더링 필요 시 (crawler skill)
323
325
 
324
326
  | MCP 도구 | 용도 | 미설치 시 폴백 |
325
327
  |----------|------|--------------|
326
- | `firecrawl_map/scrape/crawl` | 사이트 구조/페이지 수집 | WebFetch (페이지별) |
328
+ | `firecrawl_map/scrape/crawl` | 사이트 구조/페이지 수집 | Jina Reader → WebFetch (페이지별) |
327
329
  | SearXNG `web_search` | 246+ 엔진 메타검색 | WebSearch (내장) |
328
330
  | `search_repositories/code/issues` | GitHub 리포/코드/이슈 | `gh search` (Bash) |
329
- | `resolve-library-id` + `query-docs` | 라이브러리 문서 조회 | WebFetch (직접) |
331
+ | `resolve-library-id` + `query-docs` | 라이브러리 문서 조회 | Jina Reader → WebFetch (직접) |
330
332
 
331
333
  ### MCP 감지 (Phase 0 공통)
332
334
 
@@ -339,6 +341,51 @@ ToolSearch("context7") → Context7 활성화
339
341
 
340
342
  ---
341
343
 
344
+ ## Jina Reader (`r.jina.ai`)
345
+
346
+ **용도:** URL → 클린 마크다운 변환 (JS 렌더링 지원, 광고/네비 제거)
347
+
348
+ | 특성 | 설명 |
349
+ |------|------|
350
+ | **엔드포인트** | `https://r.jina.ai/{URL}` |
351
+ | **호출 방법** | `WebFetch('https://r.jina.ai/{URL}', '{프롬프트}')` |
352
+ | **장점** | JS 렌더링, 클린 MD, 광고/네비 자동 제거, 무료 |
353
+ | **한계** | 검색 기능 없음 (URL 필수), 대량 크롤링 비적합 |
354
+
355
+ ### 활용 시나리오
356
+
357
+ | 시나리오 | 사용 |
358
+ |----------|------|
359
+ | **WebFetch 실패** | JS 렌더링 필요 페이지 → Jina Reader 폴백 |
360
+ | **Firecrawl 미설치** | 개별 페이지 클린 MD 변환 |
361
+ | **공식 문서 읽기** | SPA 기반 문서 사이트 (React, Vue 등) |
362
+ | **블로그/미디어** | 광고 제거된 본문만 추출 |
363
+
364
+ ### 사용 패턴
365
+
366
+ ```typescript
367
+ // ✅ 기본: URL을 클린 마크다운으로 변환
368
+ WebFetch('https://r.jina.ai/https://react.dev/reference/react/use', '핵심 API 사용법 추출')
369
+
370
+ // ✅ WebFetch 실패 시 Jina 폴백
371
+ WebFetch('https://docs.example.com/guide') // → 빈 결과 (JS 렌더링 필요)
372
+ WebFetch('https://r.jina.ai/https://docs.example.com/guide', '가이드 내용 추출') // → 클린 MD
373
+
374
+ // ✅ Firecrawl 미설치 시 개별 페이지 대안
375
+ WebFetch('https://r.jina.ai/https://prisma.io/docs/orm/prisma-schema', 'Prisma 스키마 문법 추출')
376
+
377
+ // ❌ 검색 용도로 사용 (검색은 WebSearch/SearXNG 사용)
378
+ WebFetch('https://r.jina.ai/react hooks tutorial') // 잘못된 사용
379
+ ```
380
+
381
+ ### 폴백 체인 (페이지 읽기)
382
+
383
+ ```
384
+ Firecrawl scrape → Jina Reader → WebFetch (직접) → Playwright (최후 수단)
385
+ ```
386
+
387
+ ---
388
+
342
389
  ## 수집 후 검증
343
390
 
344
391
  | 단계 | 검증 |