ctx7 0.3.1 → 0.3.3
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/README.md +39 -1
- package/dist/index.js +255 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ctx7
|
|
2
2
|
|
|
3
|
-
CLI for
|
|
3
|
+
CLI for [Context7](https://context7.com) - query up-to-date library documentation and manage AI coding skills.
|
|
4
4
|
|
|
5
5
|
Skills are reusable prompt instructions that enhance your AI coding assistant with specialized capabilities like working with specific frameworks, libraries, or coding patterns.
|
|
6
6
|
|
|
@@ -26,6 +26,18 @@ ctx7 setup --claude
|
|
|
26
26
|
ctx7 setup --opencode
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
### Library Documentation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Find a library
|
|
33
|
+
ctx7 library react
|
|
34
|
+
ctx7 library nextjs "app router"
|
|
35
|
+
|
|
36
|
+
# Get documentation
|
|
37
|
+
ctx7 docs /facebook/react "useEffect cleanup"
|
|
38
|
+
ctx7 docs /vercel/next.js "middleware"
|
|
39
|
+
```
|
|
40
|
+
|
|
29
41
|
### Skills
|
|
30
42
|
|
|
31
43
|
```bash
|
|
@@ -44,6 +56,32 @@ ctx7 skills list --claude
|
|
|
44
56
|
|
|
45
57
|
## Usage
|
|
46
58
|
|
|
59
|
+
### Find a library
|
|
60
|
+
|
|
61
|
+
Resolve a library name to a Context7 library ID.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
ctx7 library react
|
|
65
|
+
ctx7 library nextjs "app router setup"
|
|
66
|
+
ctx7 library prisma "database relations"
|
|
67
|
+
|
|
68
|
+
# Output as JSON
|
|
69
|
+
ctx7 library react --json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Query documentation
|
|
73
|
+
|
|
74
|
+
Fetch documentation for a specific library using its Context7 ID.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
ctx7 docs /facebook/react "useEffect cleanup"
|
|
78
|
+
ctx7 docs /vercel/next.js "middleware authentication"
|
|
79
|
+
ctx7 docs /prisma/prisma "one-to-many relations"
|
|
80
|
+
|
|
81
|
+
# Output as JSON
|
|
82
|
+
ctx7 docs /facebook/react "hooks" --json
|
|
83
|
+
```
|
|
84
|
+
|
|
47
85
|
### Setup
|
|
48
86
|
|
|
49
87
|
Configure Context7 MCP and a rule for your AI coding agents. Authenticates via OAuth, generates an API key, and writes the config.
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import pc10 from "picocolors";
|
|
6
6
|
import figlet from "figlet";
|
|
7
7
|
|
|
8
8
|
// src/commands/skill.ts
|
|
@@ -289,6 +289,65 @@ async function handleGenerateResponse(response, libraryName, onEvent) {
|
|
|
289
289
|
}
|
|
290
290
|
return { content, libraryName: finalLibraryName, error };
|
|
291
291
|
}
|
|
292
|
+
function getAuthHeaders(accessToken) {
|
|
293
|
+
const headers = {};
|
|
294
|
+
const apiKey = process.env.CONTEXT7_API_KEY;
|
|
295
|
+
if (apiKey) {
|
|
296
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
297
|
+
} else if (accessToken) {
|
|
298
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
299
|
+
}
|
|
300
|
+
return headers;
|
|
301
|
+
}
|
|
302
|
+
async function resolveLibrary(libraryName, query, accessToken) {
|
|
303
|
+
const params = new URLSearchParams({ libraryName });
|
|
304
|
+
if (query) {
|
|
305
|
+
params.set("query", query);
|
|
306
|
+
}
|
|
307
|
+
const response = await fetch(`${baseUrl}/api/v2/libs/search?${params}`, {
|
|
308
|
+
headers: getAuthHeaders(accessToken)
|
|
309
|
+
});
|
|
310
|
+
if (!response.ok) {
|
|
311
|
+
const errorData = await response.json().catch(() => ({}));
|
|
312
|
+
return {
|
|
313
|
+
results: [],
|
|
314
|
+
error: errorData.error || `HTTP error ${response.status}`,
|
|
315
|
+
message: errorData.message
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
return await response.json();
|
|
319
|
+
}
|
|
320
|
+
async function getLibraryContext(libraryId, query, options, accessToken) {
|
|
321
|
+
const params = new URLSearchParams({ libraryId, query });
|
|
322
|
+
if (options?.type) {
|
|
323
|
+
params.set("type", options.type);
|
|
324
|
+
}
|
|
325
|
+
const response = await fetch(`${baseUrl}/api/v2/context?${params}`, {
|
|
326
|
+
headers: getAuthHeaders(accessToken)
|
|
327
|
+
});
|
|
328
|
+
if (!response.ok) {
|
|
329
|
+
const errorData = await response.json().catch(() => ({}));
|
|
330
|
+
if (response.status === 301 && errorData.redirectUrl) {
|
|
331
|
+
return {
|
|
332
|
+
codeSnippets: [],
|
|
333
|
+
infoSnippets: [],
|
|
334
|
+
error: errorData.error || "library_redirected",
|
|
335
|
+
message: errorData.message,
|
|
336
|
+
redirectUrl: errorData.redirectUrl
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
codeSnippets: [],
|
|
341
|
+
infoSnippets: [],
|
|
342
|
+
error: errorData.error || `HTTP error ${response.status}`,
|
|
343
|
+
message: errorData.message
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
if (options?.type === "txt") {
|
|
347
|
+
return await response.text();
|
|
348
|
+
}
|
|
349
|
+
return await response.json();
|
|
350
|
+
}
|
|
292
351
|
|
|
293
352
|
// src/utils/logger.ts
|
|
294
353
|
import pc from "picocolors";
|
|
@@ -483,7 +542,7 @@ ${pc3.dim(pathLines.join("\n"))}`,
|
|
|
483
542
|
}
|
|
484
543
|
const universalLabel = `Universal \u2014 ${UNIVERSAL_AGENTS_LABEL} ${pc3.dim(`(${universalPath})`)}`;
|
|
485
544
|
const choices = [
|
|
486
|
-
{ name: universalLabel, value: "universal", checked:
|
|
545
|
+
{ name: universalLabel, value: "universal", checked: false }
|
|
487
546
|
];
|
|
488
547
|
for (const ide of VENDOR_SPECIFIC_AGENTS) {
|
|
489
548
|
choices.push({
|
|
@@ -1175,6 +1234,12 @@ async function generateCommand(options) {
|
|
|
1175
1234
|
}
|
|
1176
1235
|
searchSpinner.succeed(pc6.green(`Found ${searchResult.results.length} relevant sources`));
|
|
1177
1236
|
log.blank();
|
|
1237
|
+
if (searchResult.searchFilterApplied) {
|
|
1238
|
+
log.warn(
|
|
1239
|
+
"Your results only include libraries matching your access settings. To search across all public libraries, update your settings at https://context7.com/dashboard?tab=libraries"
|
|
1240
|
+
);
|
|
1241
|
+
log.blank();
|
|
1242
|
+
}
|
|
1178
1243
|
let selectedLibraries;
|
|
1179
1244
|
try {
|
|
1180
1245
|
const formatProjectId = (id) => {
|
|
@@ -1853,11 +1918,14 @@ async function searchCommand(query) {
|
|
|
1853
1918
|
trackEvent("search_query", { query, resultCount: data.results.length });
|
|
1854
1919
|
log.blank();
|
|
1855
1920
|
const indexWidth = data.results.length.toString().length;
|
|
1856
|
-
const
|
|
1921
|
+
const nameWithRepo = (s) => `${s.name} ${pc7.dim(`(${s.project})`)}`;
|
|
1922
|
+
const nameWithRepoLen = (s) => `${s.name} (${s.project})`.length;
|
|
1923
|
+
const maxNameLen = Math.max(...data.results.map(nameWithRepoLen));
|
|
1857
1924
|
const installsColWidth = 10;
|
|
1858
1925
|
const choices = data.results.map((s, index) => {
|
|
1859
1926
|
const indexStr = pc7.dim(`${(index + 1).toString().padStart(indexWidth)}.`);
|
|
1860
|
-
const
|
|
1927
|
+
const rawLen = nameWithRepoLen(s);
|
|
1928
|
+
const displayName = nameWithRepo(s) + " ".repeat(maxNameLen - rawLen);
|
|
1861
1929
|
const installsRaw = s.installCount ? String(s.installCount) : "-";
|
|
1862
1930
|
const paddedInstalls = formatInstallCount(s.installCount, pc7.dim("-")) + " ".repeat(installsColWidth - installsRaw.length);
|
|
1863
1931
|
const trust = formatTrustScore(s.trustScore);
|
|
@@ -1876,7 +1944,7 @@ async function searchCommand(query) {
|
|
|
1876
1944
|
pc7.white(s.description || "No description")
|
|
1877
1945
|
];
|
|
1878
1946
|
return {
|
|
1879
|
-
name: `${indexStr} ${
|
|
1947
|
+
name: `${indexStr} ${displayName} ${paddedInstalls}${trust}`,
|
|
1880
1948
|
value: s,
|
|
1881
1949
|
description: metadataLines.join("\n")
|
|
1882
1950
|
};
|
|
@@ -2124,14 +2192,17 @@ async function suggestCommand(options) {
|
|
|
2124
2192
|
searchSpinner.succeed(`Found ${skills.length} relevant skill(s)`);
|
|
2125
2193
|
trackEvent("suggest_results", { depCount: deps.length, skillCount: skills.length });
|
|
2126
2194
|
log.blank();
|
|
2127
|
-
const
|
|
2195
|
+
const nameWithRepo = (s) => `${s.name} ${pc7.dim(`(${s.project})`)}`;
|
|
2196
|
+
const nameWithRepoLen = (s) => `${s.name} (${s.project})`.length;
|
|
2197
|
+
const maxNameLen = Math.max(...skills.map(nameWithRepoLen));
|
|
2128
2198
|
const installsColWidth = 10;
|
|
2129
2199
|
const trustColWidth = 12;
|
|
2130
2200
|
const maxMatchedLen = Math.max(...skills.map((s) => s.matchedDep.length));
|
|
2131
2201
|
const indexWidth = skills.length.toString().length;
|
|
2132
2202
|
const choices = skills.map((s, index) => {
|
|
2133
2203
|
const indexStr = pc7.dim(`${(index + 1).toString().padStart(indexWidth)}.`);
|
|
2134
|
-
const
|
|
2204
|
+
const rawLen = nameWithRepoLen(s);
|
|
2205
|
+
const displayName = nameWithRepo(s) + " ".repeat(maxNameLen - rawLen);
|
|
2135
2206
|
const installsRaw = s.installCount ? String(s.installCount) : "-";
|
|
2136
2207
|
const paddedInstalls = formatInstallCount(s.installCount, pc7.dim("-")) + " ".repeat(installsColWidth - installsRaw.length);
|
|
2137
2208
|
const trustRaw = s.trustScore !== void 0 && s.trustScore >= 0 ? s.trustScore.toFixed(1) : "-";
|
|
@@ -2153,7 +2224,7 @@ async function suggestCommand(options) {
|
|
|
2153
2224
|
pc7.white(s.description || "No description")
|
|
2154
2225
|
];
|
|
2155
2226
|
return {
|
|
2156
|
-
name: `${indexStr} ${
|
|
2227
|
+
name: `${indexStr} ${displayName} ${paddedInstalls}${trust}${matched}`,
|
|
2157
2228
|
value: s,
|
|
2158
2229
|
description: metadataLines.join("\n")
|
|
2159
2230
|
};
|
|
@@ -2687,6 +2758,175 @@ async function setupCommand(options) {
|
|
|
2687
2758
|
trackEvent("setup", { agents: agents2, scope, authMode: auth.mode });
|
|
2688
2759
|
}
|
|
2689
2760
|
|
|
2761
|
+
// src/commands/docs.ts
|
|
2762
|
+
import pc9 from "picocolors";
|
|
2763
|
+
import ora5 from "ora";
|
|
2764
|
+
var isTTY = process.stdout.isTTY;
|
|
2765
|
+
function getReputationLabel(score) {
|
|
2766
|
+
if (score === void 0 || score < 0) return "Unknown";
|
|
2767
|
+
if (score >= 7) return "High";
|
|
2768
|
+
if (score >= 4) return "Medium";
|
|
2769
|
+
return "Low";
|
|
2770
|
+
}
|
|
2771
|
+
function getAccessToken() {
|
|
2772
|
+
const tokens = loadTokens();
|
|
2773
|
+
if (!tokens || isTokenExpired(tokens)) return void 0;
|
|
2774
|
+
return tokens.access_token;
|
|
2775
|
+
}
|
|
2776
|
+
function formatLibraryResult(lib, index) {
|
|
2777
|
+
const lines = [];
|
|
2778
|
+
lines.push(`${pc9.dim(`${index + 1}.`)} ${pc9.bold(`Title: ${lib.title}`)}`);
|
|
2779
|
+
lines.push(` ${pc9.cyan(`Context7-compatible library ID: ${lib.id}`)}`);
|
|
2780
|
+
if (lib.description) {
|
|
2781
|
+
lines.push(` ${pc9.dim(`Description: ${lib.description}`)}`);
|
|
2782
|
+
}
|
|
2783
|
+
if (lib.totalSnippets) {
|
|
2784
|
+
lines.push(` ${pc9.dim(`Code Snippets: ${lib.totalSnippets}`)}`);
|
|
2785
|
+
}
|
|
2786
|
+
if (lib.trustScore !== void 0) {
|
|
2787
|
+
lines.push(` ${pc9.dim(`Source Reputation: ${getReputationLabel(lib.trustScore)}`)}`);
|
|
2788
|
+
}
|
|
2789
|
+
if (lib.benchmarkScore !== void 0 && lib.benchmarkScore > 0) {
|
|
2790
|
+
lines.push(` ${pc9.dim(`Benchmark Score: ${lib.benchmarkScore}`)}`);
|
|
2791
|
+
}
|
|
2792
|
+
if (lib.versions && lib.versions.length > 0) {
|
|
2793
|
+
lines.push(` ${pc9.dim(`Versions: ${lib.versions.join(", ")}`)}`);
|
|
2794
|
+
}
|
|
2795
|
+
return lines.join("\n");
|
|
2796
|
+
}
|
|
2797
|
+
async function resolveCommand(library, query, options) {
|
|
2798
|
+
trackEvent("command", { name: "library" });
|
|
2799
|
+
const spinner = isTTY ? ora5(`Searching for "${library}"...`).start() : null;
|
|
2800
|
+
const accessToken = getAccessToken();
|
|
2801
|
+
let data;
|
|
2802
|
+
try {
|
|
2803
|
+
data = await resolveLibrary(library, query, accessToken);
|
|
2804
|
+
} catch (err) {
|
|
2805
|
+
spinner?.fail(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2806
|
+
if (!spinner) log.error(err instanceof Error ? err.message : String(err));
|
|
2807
|
+
process.exitCode = 1;
|
|
2808
|
+
return;
|
|
2809
|
+
}
|
|
2810
|
+
if (data.error) {
|
|
2811
|
+
spinner?.fail(data.message || data.error);
|
|
2812
|
+
if (!spinner) log.error(data.message || data.error);
|
|
2813
|
+
process.exitCode = 1;
|
|
2814
|
+
return;
|
|
2815
|
+
}
|
|
2816
|
+
if (!data.results || data.results.length === 0) {
|
|
2817
|
+
spinner?.warn(`No libraries found matching "${library}"`);
|
|
2818
|
+
if (!spinner) log.warn(`No libraries found matching "${library}"`);
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2821
|
+
const results = data.results;
|
|
2822
|
+
spinner?.stop();
|
|
2823
|
+
if (options.json) {
|
|
2824
|
+
console.log(JSON.stringify(results, null, 2));
|
|
2825
|
+
return;
|
|
2826
|
+
}
|
|
2827
|
+
log.blank();
|
|
2828
|
+
if (data.searchFilterApplied) {
|
|
2829
|
+
log.warn(
|
|
2830
|
+
"Your results only include libraries matching your access settings. To search across all public libraries, update your settings at https://context7.com/dashboard?tab=libraries"
|
|
2831
|
+
);
|
|
2832
|
+
log.blank();
|
|
2833
|
+
}
|
|
2834
|
+
for (let i = 0; i < results.length; i++) {
|
|
2835
|
+
log.plain(formatLibraryResult(results[i], i));
|
|
2836
|
+
log.blank();
|
|
2837
|
+
}
|
|
2838
|
+
if (isTTY && results.length > 0) {
|
|
2839
|
+
const best = results[0];
|
|
2840
|
+
log.plain(
|
|
2841
|
+
`${pc9.bold("Quick command:")}
|
|
2842
|
+
${pc9.cyan(`ctx7 docs "${best.id}" "<your question>"`)}`
|
|
2843
|
+
);
|
|
2844
|
+
log.blank();
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
async function queryCommand(libraryId, query, options) {
|
|
2848
|
+
trackEvent("command", { name: "docs" });
|
|
2849
|
+
if (!libraryId.startsWith("/")) {
|
|
2850
|
+
log.error(`Invalid library ID: ${libraryId}`);
|
|
2851
|
+
log.info(`Library IDs start with "/" (e.g., /facebook/react)`);
|
|
2852
|
+
log.info(`Run "ctx7 library <name>" to find the correct ID`);
|
|
2853
|
+
process.exitCode = 1;
|
|
2854
|
+
return;
|
|
2855
|
+
}
|
|
2856
|
+
const spinner = isTTY ? ora5(`Fetching docs for "${libraryId}"...`).start() : null;
|
|
2857
|
+
const accessToken = getAccessToken();
|
|
2858
|
+
const outputType = options.json ? "json" : "txt";
|
|
2859
|
+
let result;
|
|
2860
|
+
try {
|
|
2861
|
+
result = await getLibraryContext(libraryId, query, { type: outputType }, accessToken);
|
|
2862
|
+
} catch (err) {
|
|
2863
|
+
spinner?.fail(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2864
|
+
if (!spinner) log.error(err instanceof Error ? err.message : String(err));
|
|
2865
|
+
process.exitCode = 1;
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
if (typeof result === "string") {
|
|
2869
|
+
spinner?.stop();
|
|
2870
|
+
console.log(result);
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2873
|
+
const ctx = result;
|
|
2874
|
+
if (ctx.error) {
|
|
2875
|
+
if (ctx.redirectUrl) {
|
|
2876
|
+
spinner?.warn("Library has been redirected");
|
|
2877
|
+
if (!spinner) log.warn("Library has been redirected");
|
|
2878
|
+
log.info(`New ID: ${pc9.cyan(ctx.redirectUrl)}`);
|
|
2879
|
+
log.info(`Run: ${pc9.cyan(`ctx7 docs "${ctx.redirectUrl}" "${query}"`)}`);
|
|
2880
|
+
process.exitCode = 1;
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
spinner?.fail(ctx.message || ctx.error);
|
|
2884
|
+
if (!spinner) log.error(ctx.message || ctx.error);
|
|
2885
|
+
process.exitCode = 1;
|
|
2886
|
+
return;
|
|
2887
|
+
}
|
|
2888
|
+
const total = (ctx.codeSnippets?.length || 0) + (ctx.infoSnippets?.length || 0);
|
|
2889
|
+
if (total === 0) {
|
|
2890
|
+
spinner?.warn(`No documentation found for: "${query}"`);
|
|
2891
|
+
if (!spinner) log.warn(`No documentation found for: "${query}"`);
|
|
2892
|
+
return;
|
|
2893
|
+
}
|
|
2894
|
+
spinner?.stop();
|
|
2895
|
+
if (options.json) {
|
|
2896
|
+
console.log(JSON.stringify(ctx, null, 2));
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
2899
|
+
log.blank();
|
|
2900
|
+
if (ctx.codeSnippets) {
|
|
2901
|
+
for (const snippet of ctx.codeSnippets) {
|
|
2902
|
+
log.plain(pc9.bold(snippet.codeTitle));
|
|
2903
|
+
if (snippet.codeDescription) log.dim(snippet.codeDescription);
|
|
2904
|
+
log.blank();
|
|
2905
|
+
for (const code of snippet.codeList) {
|
|
2906
|
+
log.plain("```" + code.language);
|
|
2907
|
+
log.plain(code.code);
|
|
2908
|
+
log.plain("```");
|
|
2909
|
+
log.blank();
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
if (ctx.infoSnippets) {
|
|
2914
|
+
for (const snippet of ctx.infoSnippets) {
|
|
2915
|
+
if (snippet.breadcrumb) log.plain(pc9.bold(snippet.breadcrumb));
|
|
2916
|
+
log.plain(snippet.content);
|
|
2917
|
+
log.blank();
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
function registerDocsCommands(program2) {
|
|
2922
|
+
program2.command("library").argument("<name>", "Library name to search for").argument("[query]", "Question or task for relevance ranking").option("--json", "Output as JSON").description("Resolve a library name to a Context7 library ID").action(async (name, query, options) => {
|
|
2923
|
+
await resolveCommand(name, query, options);
|
|
2924
|
+
});
|
|
2925
|
+
program2.command("docs").argument("<libraryId>", "Context7 library ID (e.g., /facebook/react)").argument("<query>", "Question or task to get docs for").option("--json", "Output as JSON").description("Query documentation for a library").action(async (libraryId, query, options) => {
|
|
2926
|
+
await queryCommand(libraryId, query, options);
|
|
2927
|
+
});
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2690
2930
|
// src/constants.ts
|
|
2691
2931
|
import { readFileSync as readFileSync2 } from "fs";
|
|
2692
2932
|
import { fileURLToPath } from "url";
|
|
@@ -2698,8 +2938,8 @@ var NAME = pkg.name;
|
|
|
2698
2938
|
|
|
2699
2939
|
// src/index.ts
|
|
2700
2940
|
var brand = {
|
|
2701
|
-
primary:
|
|
2702
|
-
dim:
|
|
2941
|
+
primary: pc10.green,
|
|
2942
|
+
dim: pc10.dim
|
|
2703
2943
|
};
|
|
2704
2944
|
var program = new Command();
|
|
2705
2945
|
program.name("ctx7").description("Context7 CLI - Manage AI coding skills and documentation context").version(VERSION).option("--base-url <url>").hook("preAction", (thisCommand) => {
|
|
@@ -2728,6 +2968,10 @@ Examples:
|
|
|
2728
2968
|
${brand.primary("npx ctx7 skills list --claude")}
|
|
2729
2969
|
${brand.primary("npx ctx7 skills remove pdf")}
|
|
2730
2970
|
|
|
2971
|
+
${brand.dim("# Query library documentation")}
|
|
2972
|
+
${brand.primary('npx ctx7 library react "how to use hooks"')}
|
|
2973
|
+
${brand.primary('npx ctx7 docs /facebook/react "useEffect examples"')}
|
|
2974
|
+
|
|
2731
2975
|
Visit ${brand.primary("https://context7.com")} to browse skills
|
|
2732
2976
|
`
|
|
2733
2977
|
);
|
|
@@ -2735,6 +2979,7 @@ registerSkillCommands(program);
|
|
|
2735
2979
|
registerSkillAliases(program);
|
|
2736
2980
|
registerAuthCommands(program);
|
|
2737
2981
|
registerSetupCommand(program);
|
|
2982
|
+
registerDocsCommands(program);
|
|
2738
2983
|
program.action(() => {
|
|
2739
2984
|
console.log("");
|
|
2740
2985
|
const banner = figlet.textSync("Context7", { font: "ANSI Shadow" });
|