@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.
- package/dist/index.js +255 -149
- package/package.json +1 -1
- package/templates/.claude/agents/researcher.md +8 -1
- package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
- package/templates/.claude/scripts/deploy/build-run.sh +36 -0
- package/templates/.claude/scripts/deploy/deploy-check.sh +38 -0
- package/templates/.claude/scripts/git/git-all.sh +57 -0
- package/templates/.claude/scripts/git/git-clean-check.sh +31 -0
- package/templates/.claude/scripts/git/git-commit.sh +51 -0
- package/templates/.claude/scripts/git/git-info.sh +34 -0
- package/templates/.claude/scripts/git/git-push.sh +50 -0
- package/templates/.claude/scripts/lint/lint-check.sh +56 -0
- package/templates/.claude/scripts/lint/lint-file.sh +41 -0
- package/templates/.claude/scripts/pm/pm-detect.sh +25 -0
- package/templates/.claude/scripts/pm/pm-run.sh +41 -0
- package/templates/.claude/scripts/version/version-bump.sh +54 -0
- package/templates/.claude/scripts/version/version-find.sh +49 -0
- package/templates/.claude/skills/docs-fetch/SKILL.md +5 -4
- package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
- package/templates/.claude/skills/project-optimizer/SKILL.md +374 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-config-centralize.md +66 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-hot-path.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-interface-segregation.md +51 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-module-boundary.md +42 -0
- package/templates/.claude/skills/project-optimizer/rules/build-cache.md +57 -0
- package/templates/.claude/skills/project-optimizer/rules/build-code-split.md +56 -0
- package/templates/.claude/skills/project-optimizer/rules/build-incremental.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/build-minify.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/build-tree-shake.md +60 -0
- package/templates/.claude/skills/project-optimizer/rules/code-complexity.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/code-dead-elimination.md +32 -0
- package/templates/.claude/skills/project-optimizer/rules/code-duplication.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/code-error-handling.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/code-naming.md +52 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-defer-await.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-parallel.md +90 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pipeline.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pool.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-lightweight-alt.md +37 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-peer-align.md +44 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-security-audit.md +45 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-unused-removal.md +25 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-version-pin.md +40 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-ci-speed.md +47 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-dev-server.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-lint-config.md +36 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-test-coverage.md +34 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-type-safety.md +49 -0
- package/templates/.claude/skills/project-optimizer/rules/io-batch-queries.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-cache-layer.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-connection-reuse.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-serialize-minimal.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/io-stream.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-bounded-cache.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-large-data.md +64 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-lazy-init.md +78 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-leak-prevention.md +79 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-pool-reuse.md +70 -0
- package/templates/.claude/skills/sql-optimizer/SKILL.md +437 -0
- package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +53 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +93 -27
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +42 -19
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-optimistic-updates.md +109 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-suspense-query.md +74 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-use-hook.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-react-compiler.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-beforeload-auth.md +121 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-file-conventions.md +104 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-link-navigation.md +119 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-nested-layouts.md +155 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-path-params.md +89 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-pending-component.md +110 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-preload-strategy.md +91 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-router-context.md +120 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-search-params.md +114 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +1 -1
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-error-boundaries.md +79 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-middleware.md +85 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +56 -21
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-streaming.md +84 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-validator.md +71 -0
- package/templates/.claude/skills/tauri-react-best-practices/AGENTS.md +527 -0
- package/templates/.claude/skills/tauri-react-best-practices/SKILL.md +570 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-barrel-imports.md +140 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-cargo-profile.md +96 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-frontend-treeshake.md +242 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-lazy-components.md +255 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-remove-unused-commands.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-ci-pipeline.md +269 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-signing.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-updater.md +226 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-async-commands.md +172 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-batch-commands.md +133 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-binary-response.md +198 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-channel-streaming.md +186 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-error-handling.md +250 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-type-safe.md +227 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-derived-state.md +231 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-functional-setstate.md +191 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-index-maps.md +276 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-lazy-state-init.md +196 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-lifecycle.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-mobile-compat.md +199 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-permission-scope.md +193 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-error-boundary.md +239 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-event-listener.md +151 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-file-src.md +155 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-invoke-hook.md +139 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-optimistic-update.md +211 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-capability-split.md +205 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-csp.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-least-privilege.md +106 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-no-wildcard.md +253 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-scope-paths.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-async-mutex.md +270 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-mutex-pattern.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-react-sync.md +375 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-single-container.md +275 -0
- package/templates/tanstack-start/docs/architecture.md +238 -167
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +777 -38
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +549 -37
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +895 -111
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +641 -43
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +889 -38
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +891 -29
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +972 -36
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +1525 -881
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +1099 -20
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +796 -30
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +953 -35
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +371 -15
- package/templates/tauri/CLAUDE.md +189 -0
- package/templates/tauri/docs/guides/distribution.md +261 -0
- package/templates/tauri/docs/guides/getting-started.md +302 -0
- package/templates/tauri/docs/guides/mobile.md +288 -0
- 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
|
-
|
|
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
|
|
474
|
-
|
|
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
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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
|
-
|
|
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 {
|
|
773
|
-
|
|
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(
|
|
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
|
|
816
|
-
await validateTargetDirectory(
|
|
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
|
-
|
|
823
|
-
if (
|
|
824
|
-
await
|
|
825
|
-
|
|
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
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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
|
@@ -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
|
| 단계 | 검증 |
|