@pkgseer/cli 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +183 -123
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-zaq9c2d8.js → chunk-48mwa8wt.js} +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
version
|
|
4
|
-
} from "./shared/chunk-
|
|
4
|
+
} from "./shared/chunk-48mwa8wt.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -23,6 +23,7 @@ var CliPackageInfoDocument = gql`
|
|
|
23
23
|
license
|
|
24
24
|
homepage
|
|
25
25
|
repositoryUrl
|
|
26
|
+
downloadsLastMonth
|
|
26
27
|
}
|
|
27
28
|
security {
|
|
28
29
|
vulnerabilityCount
|
|
@@ -1782,6 +1783,27 @@ function registerConfigShowCommand(program) {
|
|
|
1782
1783
|
}
|
|
1783
1784
|
|
|
1784
1785
|
// src/commands/shared.ts
|
|
1786
|
+
function parsePackageSpec(spec) {
|
|
1787
|
+
let registry = "npm";
|
|
1788
|
+
let rest = spec;
|
|
1789
|
+
if (spec.includes(":")) {
|
|
1790
|
+
const colonIndex = spec.indexOf(":");
|
|
1791
|
+
const potentialRegistry = spec.slice(0, colonIndex).toLowerCase();
|
|
1792
|
+
if (["npm", "pypi", "hex"].includes(potentialRegistry)) {
|
|
1793
|
+
registry = potentialRegistry;
|
|
1794
|
+
rest = spec.slice(colonIndex + 1);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
const atIndex = rest.lastIndexOf("@");
|
|
1798
|
+
if (atIndex > 0) {
|
|
1799
|
+
return {
|
|
1800
|
+
registry,
|
|
1801
|
+
name: rest.slice(0, atIndex),
|
|
1802
|
+
version: rest.slice(atIndex + 1)
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
return { registry, name: rest };
|
|
1806
|
+
}
|
|
1785
1807
|
function toGraphQLRegistry(registry) {
|
|
1786
1808
|
const map = {
|
|
1787
1809
|
npm: "NPM",
|
|
@@ -2242,7 +2264,7 @@ Examples:
|
|
|
2242
2264
|
# Multiple pages
|
|
2243
2265
|
pkgseer docs get 24293-shared-plugins-during-build-2 npm/express/4.18.2/readme`;
|
|
2244
2266
|
function registerDocsGetCommand(program) {
|
|
2245
|
-
program.command("get <refs...>").summary("Fetch documentation page(s)").description(GET_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-
|
|
2267
|
+
program.command("get <refs...>").summary("Fetch documentation page(s)").description(GET_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-V, --pkg-version <version>", "Package version").option("--json", "Output as JSON").option("--verbose", "Include metadata (ID, format, source, links, etc.)").option("--preview-lines <n>", "Lines of content to show (0 for full content; default 20)").action(async (refs, options) => {
|
|
2246
2268
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
2247
2269
|
const deps = await createContainer();
|
|
2248
2270
|
await docsGetAction(refs, options, deps);
|
|
@@ -2272,13 +2294,15 @@ function formatDocsList(docs) {
|
|
|
2272
2294
|
return lines.join(`
|
|
2273
2295
|
`);
|
|
2274
2296
|
}
|
|
2275
|
-
async function docsListAction(
|
|
2297
|
+
async function docsListAction(packageArg, options, deps) {
|
|
2276
2298
|
const { pkgseerService } = deps;
|
|
2277
|
-
const
|
|
2278
|
-
const
|
|
2299
|
+
const parsed = parsePackageSpec(packageArg);
|
|
2300
|
+
const registry = toGraphQLRegistry(parsed.registry !== "npm" ? parsed.registry : options.registry);
|
|
2301
|
+
const version2 = parsed.version ?? options.pkgVersion;
|
|
2302
|
+
const result = await pkgseerService.cliDocsList(registry, parsed.name, version2);
|
|
2279
2303
|
handleErrors(result.errors, options.json ?? false);
|
|
2280
2304
|
if (!result.data.listPackageDocs) {
|
|
2281
|
-
outputError(`Package not found: ${
|
|
2305
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
2282
2306
|
return;
|
|
2283
2307
|
}
|
|
2284
2308
|
if (options.json) {
|
|
@@ -2302,19 +2326,21 @@ Shows all documentation pages with titles, globally unique page IDs,
|
|
|
2302
2326
|
word counts, and descriptions. Use the page ID with 'docs get'
|
|
2303
2327
|
to fetch the full content of a specific page.
|
|
2304
2328
|
|
|
2329
|
+
Package format: [registry:]name[@version]
|
|
2330
|
+
|
|
2305
2331
|
Examples:
|
|
2306
2332
|
pkgseer docs list lodash
|
|
2307
|
-
pkgseer docs list requests
|
|
2308
|
-
pkgseer docs list phoenix
|
|
2333
|
+
pkgseer docs list pypi:requests
|
|
2334
|
+
pkgseer docs list hex:phoenix@1.7.0 --json`;
|
|
2309
2335
|
function registerDocsListCommand(program) {
|
|
2310
|
-
program.command("list <package>").summary("List documentation pages").description(LIST_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-
|
|
2336
|
+
program.command("list <package>").summary("List documentation pages").description(LIST_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-V, --pkg-version <version>", "Package version").option("--json", "Output as JSON").action(async (packageName, options) => {
|
|
2311
2337
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
2312
2338
|
const deps = await createContainer();
|
|
2313
2339
|
await docsListAction(packageName, options, deps);
|
|
2314
2340
|
});
|
|
2315
2341
|
});
|
|
2316
2342
|
}
|
|
2317
|
-
// src/commands/
|
|
2343
|
+
// src/commands/search.ts
|
|
2318
2344
|
var colors = {
|
|
2319
2345
|
reset: "\x1B[0m",
|
|
2320
2346
|
bold: "\x1B[1m",
|
|
@@ -2344,37 +2370,11 @@ function toSearchMode(mode) {
|
|
|
2344
2370
|
}
|
|
2345
2371
|
function parsePackageList(input2) {
|
|
2346
2372
|
return input2.split(",").map((spec) => {
|
|
2347
|
-
const
|
|
2348
|
-
const atIndex = trimmed.lastIndexOf("@");
|
|
2349
|
-
let regPkg;
|
|
2350
|
-
let version2;
|
|
2351
|
-
if (atIndex > 0) {
|
|
2352
|
-
regPkg = trimmed.slice(0, atIndex);
|
|
2353
|
-
version2 = trimmed.slice(atIndex + 1);
|
|
2354
|
-
} else {
|
|
2355
|
-
regPkg = trimmed;
|
|
2356
|
-
}
|
|
2357
|
-
const slashIndex = regPkg.indexOf("/");
|
|
2358
|
-
if (slashIndex === -1) {
|
|
2359
|
-
return {
|
|
2360
|
-
registry: "NPM",
|
|
2361
|
-
name: regPkg,
|
|
2362
|
-
version: version2
|
|
2363
|
-
};
|
|
2364
|
-
}
|
|
2365
|
-
const beforeSlash = regPkg.slice(0, slashIndex);
|
|
2366
|
-
const afterSlash = regPkg.slice(slashIndex + 1);
|
|
2367
|
-
if (beforeSlash.startsWith("@")) {
|
|
2368
|
-
return {
|
|
2369
|
-
registry: "NPM",
|
|
2370
|
-
name: regPkg,
|
|
2371
|
-
version: version2
|
|
2372
|
-
};
|
|
2373
|
-
}
|
|
2373
|
+
const parsed = parsePackageSpec(spec.trim());
|
|
2374
2374
|
return {
|
|
2375
|
-
registry: toGraphQLRegistry(
|
|
2376
|
-
name:
|
|
2377
|
-
version:
|
|
2375
|
+
registry: toGraphQLRegistry(parsed.registry),
|
|
2376
|
+
name: parsed.name,
|
|
2377
|
+
version: parsed.version
|
|
2378
2378
|
};
|
|
2379
2379
|
});
|
|
2380
2380
|
}
|
|
@@ -2394,7 +2394,7 @@ function formatEntry(entry, useColors) {
|
|
|
2394
2394
|
if (entry.type === "CODE") {
|
|
2395
2395
|
const title = entry.title ?? "Unknown";
|
|
2396
2396
|
const location = entry.filePath ? `${entry.filePath}:${entry.startLine ?? "?"}-${entry.endLine ?? "?"}` : "";
|
|
2397
|
-
const lang = entry.language ? `
|
|
2397
|
+
const lang = entry.language ? ` * ${entry.language}` : "";
|
|
2398
2398
|
if (useColors) {
|
|
2399
2399
|
lines.push(`${badge} ${colors.bold}${title}${colors.reset}`);
|
|
2400
2400
|
if (location) {
|
|
@@ -2446,7 +2446,7 @@ function formatPackageHeader(entry, prevEntry, useColors) {
|
|
|
2446
2446
|
return "";
|
|
2447
2447
|
}
|
|
2448
2448
|
const header = `${pkg} (${registry})`;
|
|
2449
|
-
const separator = "
|
|
2449
|
+
const separator = "=".repeat(Math.min(50, header.length + 10));
|
|
2450
2450
|
if (useColors) {
|
|
2451
2451
|
return `
|
|
2452
2452
|
${colors.yellow}${header}${colors.reset}
|
|
@@ -2478,10 +2478,10 @@ function formatSearchResults(results, useColors) {
|
|
|
2478
2478
|
const codeCount = entries.filter((e) => e?.type === "CODE").length;
|
|
2479
2479
|
const docCount = entries.filter((e) => e?.type === "DOC" || e?.type === "REPO_DOC").length;
|
|
2480
2480
|
if (useColors) {
|
|
2481
|
-
lines.push(`${colors.dim}
|
|
2481
|
+
lines.push(`${colors.dim}---------------------------------------------------${colors.reset}`);
|
|
2482
2482
|
lines.push(`${colors.dim}Results: ${entries.length} total (${codeCount} code, ${docCount} docs)${colors.reset}`);
|
|
2483
2483
|
} else {
|
|
2484
|
-
lines.push("
|
|
2484
|
+
lines.push("---------------------------------------------------");
|
|
2485
2485
|
lines.push(`Results: ${entries.length} total (${codeCount} code, ${docCount} docs)`);
|
|
2486
2486
|
}
|
|
2487
2487
|
const indexingWarnings = formatIndexingWarnings(results.indexingStatus);
|
|
@@ -2661,7 +2661,7 @@ function summarizeSearchResults(results) {
|
|
|
2661
2661
|
return lines.join(`
|
|
2662
2662
|
`);
|
|
2663
2663
|
}
|
|
2664
|
-
async function
|
|
2664
|
+
async function searchAction(queryArg, options, deps, defaultMode = "ALL") {
|
|
2665
2665
|
const { pkgseerService } = deps;
|
|
2666
2666
|
const query = Array.isArray(queryArg) ? queryArg.join(" ") : queryArg ?? "";
|
|
2667
2667
|
if (!query.trim()) {
|
|
@@ -2678,7 +2678,7 @@ async function docsSearchAction(queryArg, options, deps) {
|
|
|
2678
2678
|
}
|
|
2679
2679
|
const packages = parsePackageList(options.packages);
|
|
2680
2680
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : 25;
|
|
2681
|
-
const mode = toSearchMode(options.mode);
|
|
2681
|
+
const mode = options.mode ? toSearchMode(options.mode) : defaultMode;
|
|
2682
2682
|
const useColors = shouldUseColors(options.noColor);
|
|
2683
2683
|
const result = await pkgseerService.combinedSearch(packages, query, {
|
|
2684
2684
|
mode,
|
|
@@ -2713,36 +2713,79 @@ Searches both code (functions, classes) and documentation pages
|
|
|
2713
2713
|
using the combined search endpoint. Returns results with snippets
|
|
2714
2714
|
showing matches.
|
|
2715
2715
|
|
|
2716
|
+
Package format: [registry:]name[@version]
|
|
2717
|
+
|
|
2716
2718
|
Examples:
|
|
2717
2719
|
# Search a single package (code + docs)
|
|
2718
|
-
pkgseer
|
|
2720
|
+
pkgseer search "error handling" -P express
|
|
2719
2721
|
|
|
2720
2722
|
# Search code only
|
|
2721
|
-
pkgseer
|
|
2723
|
+
pkgseer search "Router.use" -P express --mode code
|
|
2722
2724
|
|
|
2723
2725
|
# Search docs only
|
|
2724
|
-
pkgseer
|
|
2726
|
+
pkgseer search "middleware" -P express --mode docs
|
|
2725
2727
|
|
|
2726
2728
|
# Search multiple packages
|
|
2727
|
-
pkgseer
|
|
2729
|
+
pkgseer search "auth" -P express,passport
|
|
2728
2730
|
|
|
2729
2731
|
# With registry prefix (for non-npm packages)
|
|
2730
|
-
pkgseer
|
|
2732
|
+
pkgseer search "orm" -P pypi:django,pypi:sqlalchemy
|
|
2731
2733
|
|
|
2732
2734
|
# With specific version
|
|
2733
|
-
pkgseer
|
|
2735
|
+
pkgseer search "routing" -P express@4.18.2
|
|
2734
2736
|
|
|
2735
2737
|
# Output for piping
|
|
2736
|
-
pkgseer
|
|
2738
|
+
pkgseer search "routing" -P express --refs-only
|
|
2737
2739
|
|
|
2738
2740
|
# JSON output
|
|
2739
|
-
pkgseer
|
|
2741
|
+
pkgseer search "error" -P express --json`;
|
|
2740
2742
|
function addSearchOptions(cmd) {
|
|
2741
2743
|
return cmd.option("-P, --packages <packages>", "Packages to search (comma-separated). Format: name or registry/name[@version]. Examples: express | express,lodash | pypi/django@4.2").option("-m, --mode <mode>", "Search mode: all (default), code, docs").option("-l, --limit <n>", "Max results (default: 25)").option("-v, --verbose", "Expanded output with more details").option("--refs-only", "Output only references (for piping)").option("--count", "Output result counts by package").option("--format <format>", "Output format: human|summary|json", "human").option("--no-color", "Disable colored output").option("--json", "Output as JSON");
|
|
2742
2744
|
}
|
|
2743
|
-
function
|
|
2744
|
-
const cmd = program.command("search [query...]").summary("Search code and documentation").description(SEARCH_DESCRIPTION);
|
|
2745
|
+
function registerSearchCommand(program) {
|
|
2746
|
+
const cmd = program.command("search [query...]").summary("Search code and documentation across packages").description(SEARCH_DESCRIPTION);
|
|
2745
2747
|
addSearchOptions(cmd).action(async (query, options) => {
|
|
2748
|
+
await withCliErrorHandling(options.json ?? false, async () => {
|
|
2749
|
+
const deps = await createContainer();
|
|
2750
|
+
await searchAction(query, options, deps);
|
|
2751
|
+
});
|
|
2752
|
+
});
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
// src/commands/docs/search.ts
|
|
2756
|
+
async function docsSearchAction(queryArg, options, deps) {
|
|
2757
|
+
await searchAction(queryArg, options, deps, "DOCS");
|
|
2758
|
+
}
|
|
2759
|
+
var DOCS_SEARCH_DESCRIPTION = `Search documentation across packages.
|
|
2760
|
+
|
|
2761
|
+
Searches documentation pages in package docs. For searching both
|
|
2762
|
+
code and docs, use the top-level 'pkgseer search' command instead.
|
|
2763
|
+
|
|
2764
|
+
Package format: [registry:]name[@version]
|
|
2765
|
+
|
|
2766
|
+
Examples:
|
|
2767
|
+
# Search documentation
|
|
2768
|
+
pkgseer docs search "middleware" -P express
|
|
2769
|
+
|
|
2770
|
+
# Search multiple packages
|
|
2771
|
+
pkgseer docs search "auth" -P express,passport
|
|
2772
|
+
|
|
2773
|
+
# With registry prefix (for non-npm packages)
|
|
2774
|
+
pkgseer docs search "orm" -P pypi:django,pypi:sqlalchemy
|
|
2775
|
+
|
|
2776
|
+
# With specific version
|
|
2777
|
+
pkgseer docs search "routing" -P express@4.18.2
|
|
2778
|
+
|
|
2779
|
+
# JSON output
|
|
2780
|
+
pkgseer docs search "error" -P express --json
|
|
2781
|
+
|
|
2782
|
+
Note: For code search, use 'pkgseer search --mode code' instead.`;
|
|
2783
|
+
function addDocsSearchOptions(cmd) {
|
|
2784
|
+
return cmd.option("-P, --packages <packages>", "Packages to search (comma-separated). Format: [registry:]name[@version]. Examples: express | express,lodash | pypi:django@4.2").option("-l, --limit <n>", "Max results (default: 25)").option("-v, --verbose", "Expanded output with more details").option("--refs-only", "Output only references (for piping)").option("--count", "Output result counts by package").option("--format <format>", "Output format: human|summary|json", "human").option("--no-color", "Disable colored output").option("--json", "Output as JSON");
|
|
2785
|
+
}
|
|
2786
|
+
function registerDocsSearchCommand(program) {
|
|
2787
|
+
const cmd = program.command("search [query...]").summary("Search documentation").description(DOCS_SEARCH_DESCRIPTION);
|
|
2788
|
+
addDocsSearchOptions(cmd).action(async (query, options) => {
|
|
2746
2789
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
2747
2790
|
const deps = await createContainer();
|
|
2748
2791
|
await docsSearchAction(query, options, deps);
|
|
@@ -3869,50 +3912,55 @@ Search and analyze packages across npm, PyPI, and Hex. All commands support \`--
|
|
|
3869
3912
|
|
|
3870
3913
|
\`\`\`bash
|
|
3871
3914
|
# Search code and docs across packages
|
|
3872
|
-
${invocation} search "<query>" -P lodash,express
|
|
3873
|
-
${invocation} search "<query>" -P requests
|
|
3874
|
-
${invocation} search "authentication" -P phoenix,plug
|
|
3915
|
+
${invocation} search "<query>" -P lodash,express # npm packages
|
|
3916
|
+
${invocation} search "<query>" -P pypi:requests # PyPI packages
|
|
3917
|
+
${invocation} search "authentication" -P hex:phoenix,hex:plug
|
|
3875
3918
|
|
|
3876
3919
|
# Search modes
|
|
3877
|
-
${invocation} search "<query>" -P <packages> --code # Code only
|
|
3878
|
-
${invocation} search "<query>" -P <packages> --docs # Docs only
|
|
3920
|
+
${invocation} search "<query>" -P <packages> --mode code # Code only
|
|
3921
|
+
${invocation} search "<query>" -P <packages> --mode docs # Docs only
|
|
3879
3922
|
|
|
3880
|
-
#
|
|
3881
|
-
${invocation} docs search "<query>"
|
|
3923
|
+
# Docs-only search (shorthand)
|
|
3924
|
+
${invocation} docs search "<query>" -P <packages>
|
|
3882
3925
|
\`\`\`
|
|
3883
3926
|
|
|
3884
3927
|
## Package Analysis
|
|
3885
3928
|
|
|
3929
|
+
Package format: \`[registry:]name[@version]\`
|
|
3930
|
+
|
|
3886
3931
|
\`\`\`bash
|
|
3887
3932
|
# Overview: metadata, versions, quickstart
|
|
3888
|
-
${invocation} pkg info
|
|
3933
|
+
${invocation} pkg info lodash
|
|
3934
|
+
${invocation} pkg info pypi:requests
|
|
3889
3935
|
|
|
3890
3936
|
# Quality score (0-100) with category breakdown
|
|
3891
|
-
${invocation} pkg quality
|
|
3937
|
+
${invocation} pkg quality express@4.18.0
|
|
3938
|
+
${invocation} pkg quality pypi:django@4.2
|
|
3892
3939
|
|
|
3893
3940
|
# Security: CVEs, severity, upgrade paths
|
|
3894
|
-
${invocation} pkg vulns
|
|
3941
|
+
${invocation} pkg vulns lodash@4.17.21
|
|
3895
3942
|
|
|
3896
3943
|
# Dependencies: direct, transitive, tree view
|
|
3897
|
-
${invocation} pkg deps
|
|
3944
|
+
${invocation} pkg deps express --transitive
|
|
3898
3945
|
|
|
3899
3946
|
# Compare up to 10 packages
|
|
3900
3947
|
${invocation} pkg compare lodash underscore ramda
|
|
3901
|
-
${invocation} pkg compare
|
|
3948
|
+
${invocation} pkg compare axios pypi:httpx # cross-registry
|
|
3902
3949
|
\`\`\`
|
|
3903
3950
|
|
|
3904
3951
|
## Documentation
|
|
3905
3952
|
|
|
3906
3953
|
\`\`\`bash
|
|
3907
|
-
${invocation} docs list
|
|
3908
|
-
${invocation} docs get <package>/<page-id>
|
|
3954
|
+
${invocation} docs list pypi:requests # List pages
|
|
3955
|
+
${invocation} docs get <package>/<page-id> # Fetch content
|
|
3956
|
+
${invocation} docs search "<query>" -P <packages> # Search docs only
|
|
3909
3957
|
\`\`\`
|
|
3910
3958
|
|
|
3911
3959
|
## Tips
|
|
3912
3960
|
|
|
3913
|
-
-
|
|
3961
|
+
- Package format: \`[registry:]name[@version]\` (e.g., \`pypi:django@4.2\`)
|
|
3962
|
+
- Default registry: npm
|
|
3914
3963
|
- Use \`--json\` for structured output when parsing
|
|
3915
|
-
- Version defaults to latest; use \`-v\` for specific
|
|
3916
3964
|
`;
|
|
3917
3965
|
}
|
|
3918
3966
|
function extractSkillVersion(content) {
|
|
@@ -5155,27 +5203,6 @@ in MCP configuration files. Use 'pkgseer mcp' for interactive setup.`).action(as
|
|
|
5155
5203
|
}
|
|
5156
5204
|
|
|
5157
5205
|
// src/commands/pkg/compare.ts
|
|
5158
|
-
function parsePackageSpec(spec) {
|
|
5159
|
-
let registry = "npm";
|
|
5160
|
-
let rest = spec;
|
|
5161
|
-
if (spec.includes(":")) {
|
|
5162
|
-
const colonIndex = spec.indexOf(":");
|
|
5163
|
-
const potentialRegistry = spec.slice(0, colonIndex).toLowerCase();
|
|
5164
|
-
if (["npm", "pypi", "hex"].includes(potentialRegistry)) {
|
|
5165
|
-
registry = potentialRegistry;
|
|
5166
|
-
rest = spec.slice(colonIndex + 1);
|
|
5167
|
-
}
|
|
5168
|
-
}
|
|
5169
|
-
const atIndex = rest.lastIndexOf("@");
|
|
5170
|
-
if (atIndex > 0) {
|
|
5171
|
-
return {
|
|
5172
|
-
registry,
|
|
5173
|
-
name: rest.slice(0, atIndex),
|
|
5174
|
-
version: rest.slice(atIndex + 1)
|
|
5175
|
-
};
|
|
5176
|
-
}
|
|
5177
|
-
return { registry, name: rest };
|
|
5178
|
-
}
|
|
5179
5206
|
function formatPackageComparison(comparison) {
|
|
5180
5207
|
const lines = [];
|
|
5181
5208
|
lines.push("\uD83D\uDCCA Package Comparison");
|
|
@@ -5296,14 +5323,16 @@ function formatPackageDependencies(data, transitiveRequested) {
|
|
|
5296
5323
|
return lines.join(`
|
|
5297
5324
|
`);
|
|
5298
5325
|
}
|
|
5299
|
-
async function pkgDepsAction(
|
|
5326
|
+
async function pkgDepsAction(packageArg, options, deps) {
|
|
5300
5327
|
const { pkgseerService } = deps;
|
|
5301
|
-
const
|
|
5328
|
+
const parsed = parsePackageSpec(packageArg);
|
|
5329
|
+
const registry = toGraphQLRegistry(parsed.registry !== "npm" ? parsed.registry : options.registry);
|
|
5330
|
+
const version2 = parsed.version ?? options.pkgVersion;
|
|
5302
5331
|
const transitiveRequested = options.transitive ?? false;
|
|
5303
|
-
const result = await pkgseerService.cliPackageDeps(registry,
|
|
5332
|
+
const result = await pkgseerService.cliPackageDeps(registry, parsed.name, version2, options.transitive, options.maxDepth ? Number.parseInt(options.maxDepth, 10) : undefined);
|
|
5304
5333
|
handleErrors(result.errors, options.json ?? false);
|
|
5305
5334
|
if (!result.data.packageDependencies) {
|
|
5306
|
-
outputError(`Package not found: ${
|
|
5335
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
5307
5336
|
return;
|
|
5308
5337
|
}
|
|
5309
5338
|
const format = options.json ? "json" : options.format ?? "human";
|
|
@@ -5342,12 +5371,14 @@ var DEPS_DESCRIPTION = `Get package dependencies.
|
|
|
5342
5371
|
Lists direct dependencies and shows version constraints and
|
|
5343
5372
|
dependency types (runtime, dev, optional).
|
|
5344
5373
|
|
|
5374
|
+
Package format: [registry:]name[@version]
|
|
5375
|
+
|
|
5345
5376
|
Examples:
|
|
5346
5377
|
pkgseer pkg deps express
|
|
5347
|
-
pkgseer pkg deps lodash --transitive
|
|
5348
|
-
pkgseer pkg deps requests --
|
|
5378
|
+
pkgseer pkg deps lodash@4.17.21 --transitive
|
|
5379
|
+
pkgseer pkg deps pypi:requests@2.28.0 --json`;
|
|
5349
5380
|
function registerPkgDepsCommand(program) {
|
|
5350
|
-
program.command("deps <package>").summary("Get package dependencies").description(DEPS_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-
|
|
5381
|
+
program.command("deps <package>").summary("Get package dependencies").description(DEPS_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-V, --pkg-version <version>", "Package version").option("-t, --transitive", "Include transitive dependencies").option("--max-depth <n>", "Maximum transitive depth (1-10, defaults to server)").option("--format <format>", "Output format: human|summary|json", "human").option("--json", "Output as JSON").action(async (packageName, options) => {
|
|
5351
5382
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
5352
5383
|
const deps = await createContainer();
|
|
5353
5384
|
await pkgDepsAction(packageName, options, deps);
|
|
@@ -5355,6 +5386,15 @@ function registerPkgDepsCommand(program) {
|
|
|
5355
5386
|
});
|
|
5356
5387
|
}
|
|
5357
5388
|
// src/commands/pkg/info.ts
|
|
5389
|
+
function formatDownloads(count) {
|
|
5390
|
+
if (count >= 1e6) {
|
|
5391
|
+
return `${(count / 1e6).toFixed(1)}M`;
|
|
5392
|
+
}
|
|
5393
|
+
if (count >= 1000) {
|
|
5394
|
+
return `${(count / 1000).toFixed(1)}K`;
|
|
5395
|
+
}
|
|
5396
|
+
return count.toLocaleString();
|
|
5397
|
+
}
|
|
5358
5398
|
function formatPackageSummary(data) {
|
|
5359
5399
|
const lines = [];
|
|
5360
5400
|
const pkg = data.package;
|
|
@@ -5374,6 +5414,11 @@ function formatPackageSummary(data) {
|
|
|
5374
5414
|
["License", pkg.license]
|
|
5375
5415
|
]));
|
|
5376
5416
|
lines.push("");
|
|
5417
|
+
if (pkg.downloadsLastMonth != null && pkg.downloadsLastMonth > 0) {
|
|
5418
|
+
lines.push("Downloads:");
|
|
5419
|
+
lines.push(keyValueTable([["Last Month", formatDownloads(pkg.downloadsLastMonth)]]));
|
|
5420
|
+
lines.push("");
|
|
5421
|
+
}
|
|
5377
5422
|
if (pkg.homepage || pkg.repositoryUrl) {
|
|
5378
5423
|
lines.push("Links:");
|
|
5379
5424
|
const links = [];
|
|
@@ -5396,13 +5441,14 @@ function formatPackageSummary(data) {
|
|
|
5396
5441
|
return lines.join(`
|
|
5397
5442
|
`);
|
|
5398
5443
|
}
|
|
5399
|
-
async function pkgInfoAction(
|
|
5444
|
+
async function pkgInfoAction(packageArg, options, deps) {
|
|
5400
5445
|
const { pkgseerService } = deps;
|
|
5401
|
-
const
|
|
5402
|
-
const
|
|
5446
|
+
const parsed = parsePackageSpec(packageArg);
|
|
5447
|
+
const registry = toGraphQLRegistry(parsed.registry !== "npm" ? parsed.registry : options.registry);
|
|
5448
|
+
const result = await pkgseerService.cliPackageInfo(registry, parsed.name);
|
|
5403
5449
|
handleErrors(result.errors, options.json ?? false);
|
|
5404
5450
|
if (!result.data.packageSummary) {
|
|
5405
|
-
outputError(`Package not found: ${
|
|
5451
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
5406
5452
|
return;
|
|
5407
5453
|
}
|
|
5408
5454
|
if (options.json) {
|
|
@@ -5423,16 +5469,18 @@ async function pkgInfoAction(packageName, options, deps) {
|
|
|
5423
5469
|
}
|
|
5424
5470
|
var INFO_DESCRIPTION = `Get package summary and metadata.
|
|
5425
5471
|
|
|
5426
|
-
Displays
|
|
5472
|
+
Displays information about a package's latest version including:
|
|
5427
5473
|
- Basic metadata (version, license, description)
|
|
5428
5474
|
- Download statistics
|
|
5429
|
-
- Security advisories
|
|
5430
5475
|
- Quick start instructions
|
|
5431
5476
|
|
|
5477
|
+
Note: This command shows the latest version only.
|
|
5478
|
+
For version-specific info, use 'pkg vulns', 'pkg quality', or 'pkg deps'.
|
|
5479
|
+
|
|
5432
5480
|
Examples:
|
|
5433
5481
|
pkgseer pkg info lodash
|
|
5434
|
-
pkgseer pkg info requests
|
|
5435
|
-
pkgseer pkg info phoenix --
|
|
5482
|
+
pkgseer pkg info pypi:requests
|
|
5483
|
+
pkgseer pkg info hex:phoenix --json`;
|
|
5436
5484
|
function registerPkgInfoCommand(program) {
|
|
5437
5485
|
program.command("info <package>").summary("Get package summary and metadata").description(INFO_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("--json", "Output as JSON").action(async (packageName, options) => {
|
|
5438
5486
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
@@ -5460,13 +5508,15 @@ function formatPackageQuality(data) {
|
|
|
5460
5508
|
return lines.join(`
|
|
5461
5509
|
`);
|
|
5462
5510
|
}
|
|
5463
|
-
async function pkgQualityAction(
|
|
5511
|
+
async function pkgQualityAction(packageArg, options, deps) {
|
|
5464
5512
|
const { pkgseerService } = deps;
|
|
5465
|
-
const
|
|
5466
|
-
const
|
|
5513
|
+
const parsed = parsePackageSpec(packageArg);
|
|
5514
|
+
const registry = toGraphQLRegistry(parsed.registry !== "npm" ? parsed.registry : options.registry);
|
|
5515
|
+
const version2 = parsed.version ?? options.pkgVersion;
|
|
5516
|
+
const result = await pkgseerService.cliPackageQuality(registry, parsed.name, version2);
|
|
5467
5517
|
handleErrors(result.errors, options.json ?? false);
|
|
5468
5518
|
if (!result.data.packageQuality) {
|
|
5469
|
-
outputError(`Package not found: ${
|
|
5519
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
5470
5520
|
return;
|
|
5471
5521
|
}
|
|
5472
5522
|
const format = options.json ? "json" : options.format ?? "human";
|
|
@@ -5494,12 +5544,14 @@ Analyzes package quality across multiple dimensions:
|
|
|
5494
5544
|
- Security practices
|
|
5495
5545
|
- Community engagement
|
|
5496
5546
|
|
|
5547
|
+
Package format: [registry:]name[@version]
|
|
5548
|
+
|
|
5497
5549
|
Examples:
|
|
5498
5550
|
pkgseer pkg quality lodash
|
|
5499
|
-
pkgseer pkg quality express
|
|
5500
|
-
pkgseer pkg quality requests --
|
|
5551
|
+
pkgseer pkg quality express@4.18.0
|
|
5552
|
+
pkgseer pkg quality pypi:requests@2.28.0 --json`;
|
|
5501
5553
|
function registerPkgQualityCommand(program) {
|
|
5502
|
-
program.command("quality <package>").summary("Get package quality score").description(QUALITY_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-
|
|
5554
|
+
program.command("quality <package>").summary("Get package quality score").description(QUALITY_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-V, --pkg-version <version>", "Package version").option("--format <format>", "Output format: human|summary|json", "human").option("--json", "Output as JSON").action(async (packageName, options) => {
|
|
5503
5555
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
5504
5556
|
const deps = await createContainer();
|
|
5505
5557
|
await pkgQualityAction(packageName, options, deps);
|
|
@@ -5559,13 +5611,15 @@ function formatPackageVulnerabilities(data) {
|
|
|
5559
5611
|
return lines.join(`
|
|
5560
5612
|
`);
|
|
5561
5613
|
}
|
|
5562
|
-
async function pkgVulnsAction(
|
|
5614
|
+
async function pkgVulnsAction(packageArg, options, deps) {
|
|
5563
5615
|
const { pkgseerService } = deps;
|
|
5564
|
-
const
|
|
5565
|
-
const
|
|
5616
|
+
const parsed = parsePackageSpec(packageArg);
|
|
5617
|
+
const registry = toGraphQLRegistry(parsed.registry !== "npm" ? parsed.registry : options.registry);
|
|
5618
|
+
const version2 = parsed.version ?? options.pkgVersion;
|
|
5619
|
+
const result = await pkgseerService.cliPackageVulns(registry, parsed.name, version2);
|
|
5566
5620
|
handleErrors(result.errors, options.json ?? false);
|
|
5567
5621
|
if (!result.data.packageVulnerabilities) {
|
|
5568
|
-
outputError(`Package not found: ${
|
|
5622
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
5569
5623
|
return;
|
|
5570
5624
|
}
|
|
5571
5625
|
if (options.json) {
|
|
@@ -5594,12 +5648,14 @@ Scans for known security vulnerabilities and provides:
|
|
|
5594
5648
|
- Affected version ranges
|
|
5595
5649
|
- Upgrade recommendations
|
|
5596
5650
|
|
|
5651
|
+
Package format: [registry:]name[@version]
|
|
5652
|
+
|
|
5597
5653
|
Examples:
|
|
5598
5654
|
pkgseer pkg vulns lodash
|
|
5599
|
-
pkgseer pkg vulns express
|
|
5600
|
-
pkgseer pkg vulns requests --
|
|
5655
|
+
pkgseer pkg vulns express@4.17.0
|
|
5656
|
+
pkgseer pkg vulns pypi:requests@2.28.0 --json`;
|
|
5601
5657
|
function registerPkgVulnsCommand(program) {
|
|
5602
|
-
program.command("vulns <package>").summary("Check for security vulnerabilities").description(VULNS_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-
|
|
5658
|
+
program.command("vulns <package>").summary("Check for security vulnerabilities").description(VULNS_DESCRIPTION).option("-r, --registry <registry>", "Package registry", "npm").option("-V, --pkg-version <version>", "Package version").option("--json", "Output as JSON").action(async (packageName, options) => {
|
|
5603
5659
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
5604
5660
|
const deps = await createContainer();
|
|
5605
5661
|
await pkgVulnsAction(packageName, options, deps);
|
|
@@ -6038,6 +6094,9 @@ Getting started:
|
|
|
6038
6094
|
pkgseer login Authenticate with your account
|
|
6039
6095
|
pkgseer skill init Install AI agent skill
|
|
6040
6096
|
|
|
6097
|
+
Search:
|
|
6098
|
+
pkgseer search <query> -P <packages> Search code and docs
|
|
6099
|
+
|
|
6041
6100
|
Package commands:
|
|
6042
6101
|
pkgseer pkg info <package> Get package summary
|
|
6043
6102
|
pkgseer pkg vulns <package> Check vulnerabilities
|
|
@@ -6048,7 +6107,7 @@ Package commands:
|
|
|
6048
6107
|
Documentation commands:
|
|
6049
6108
|
pkgseer docs list <package> List doc pages
|
|
6050
6109
|
pkgseer docs get <pkg> <page> Fetch a doc page
|
|
6051
|
-
pkgseer docs search <query> Search
|
|
6110
|
+
pkgseer docs search <query> Search docs only
|
|
6052
6111
|
|
|
6053
6112
|
Learn more at https://pkgseer.dev`);
|
|
6054
6113
|
registerInitCommand(program);
|
|
@@ -6056,6 +6115,7 @@ registerMcpCommand(program);
|
|
|
6056
6115
|
registerSkillCommand(program);
|
|
6057
6116
|
registerLoginCommand(program);
|
|
6058
6117
|
registerLogoutCommand(program);
|
|
6118
|
+
registerSearchCommand(program);
|
|
6059
6119
|
var auth = program.command("auth").description("View and manage authentication");
|
|
6060
6120
|
registerAuthStatusCommand(auth);
|
|
6061
6121
|
var config = program.command("config").description("View and manage configuration");
|
package/dist/index.js
CHANGED