@pkgseer/cli 0.2.2 → 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 +184 -130
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-jyykfhaq.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);
|
|
@@ -3858,13 +3901,7 @@ function generateSkillContent(invocation = "pkgseer") {
|
|
|
3858
3901
|
return `---
|
|
3859
3902
|
name: pkgseer
|
|
3860
3903
|
version: ${version}
|
|
3861
|
-
description:
|
|
3862
|
-
Search code and documentation across npm, PyPI, and Hex packages.
|
|
3863
|
-
Find functions, classes, APIs, and usage examples. Also provides
|
|
3864
|
-
quality scores, security vulnerabilities, dependencies, and comparisons.
|
|
3865
|
-
Triggers on: "how does X work", "find examples of", "search for",
|
|
3866
|
-
"is X secure", "compare X vs Y", package evaluation, dependency decisions,
|
|
3867
|
-
"what package should I use for", API lookup, security audits.
|
|
3904
|
+
description: Search code/docs across npm, PyPI, Hex packages. Provides quality scores, security vulnerabilities, dependencies, comparisons. Use when user asks about package security, CVEs, vulnerabilities, code examples, API usage, package comparison, dependency analysis, or which package to use.
|
|
3868
3905
|
---
|
|
3869
3906
|
|
|
3870
3907
|
# PkgSeer - Package Intelligence
|
|
@@ -3875,50 +3912,55 @@ Search and analyze packages across npm, PyPI, and Hex. All commands support \`--
|
|
|
3875
3912
|
|
|
3876
3913
|
\`\`\`bash
|
|
3877
3914
|
# Search code and docs across packages
|
|
3878
|
-
${invocation} search "<query>" -P lodash,express
|
|
3879
|
-
${invocation} search "<query>" -P requests
|
|
3880
|
-
${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
|
|
3881
3918
|
|
|
3882
3919
|
# Search modes
|
|
3883
|
-
${invocation} search "<query>" -P <packages> --code # Code only
|
|
3884
|
-
${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
|
|
3885
3922
|
|
|
3886
|
-
#
|
|
3887
|
-
${invocation} docs search "<query>"
|
|
3923
|
+
# Docs-only search (shorthand)
|
|
3924
|
+
${invocation} docs search "<query>" -P <packages>
|
|
3888
3925
|
\`\`\`
|
|
3889
3926
|
|
|
3890
3927
|
## Package Analysis
|
|
3891
3928
|
|
|
3929
|
+
Package format: \`[registry:]name[@version]\`
|
|
3930
|
+
|
|
3892
3931
|
\`\`\`bash
|
|
3893
3932
|
# Overview: metadata, versions, quickstart
|
|
3894
|
-
${invocation} pkg info
|
|
3933
|
+
${invocation} pkg info lodash
|
|
3934
|
+
${invocation} pkg info pypi:requests
|
|
3895
3935
|
|
|
3896
3936
|
# Quality score (0-100) with category breakdown
|
|
3897
|
-
${invocation} pkg quality
|
|
3937
|
+
${invocation} pkg quality express@4.18.0
|
|
3938
|
+
${invocation} pkg quality pypi:django@4.2
|
|
3898
3939
|
|
|
3899
3940
|
# Security: CVEs, severity, upgrade paths
|
|
3900
|
-
${invocation} pkg vulns
|
|
3941
|
+
${invocation} pkg vulns lodash@4.17.21
|
|
3901
3942
|
|
|
3902
3943
|
# Dependencies: direct, transitive, tree view
|
|
3903
|
-
${invocation} pkg deps
|
|
3944
|
+
${invocation} pkg deps express --transitive
|
|
3904
3945
|
|
|
3905
3946
|
# Compare up to 10 packages
|
|
3906
3947
|
${invocation} pkg compare lodash underscore ramda
|
|
3907
|
-
${invocation} pkg compare
|
|
3948
|
+
${invocation} pkg compare axios pypi:httpx # cross-registry
|
|
3908
3949
|
\`\`\`
|
|
3909
3950
|
|
|
3910
3951
|
## Documentation
|
|
3911
3952
|
|
|
3912
3953
|
\`\`\`bash
|
|
3913
|
-
${invocation} docs list
|
|
3914
|
-
${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
|
|
3915
3957
|
\`\`\`
|
|
3916
3958
|
|
|
3917
3959
|
## Tips
|
|
3918
3960
|
|
|
3919
|
-
-
|
|
3961
|
+
- Package format: \`[registry:]name[@version]\` (e.g., \`pypi:django@4.2\`)
|
|
3962
|
+
- Default registry: npm
|
|
3920
3963
|
- Use \`--json\` for structured output when parsing
|
|
3921
|
-
- Version defaults to latest; use \`-v\` for specific
|
|
3922
3964
|
`;
|
|
3923
3965
|
}
|
|
3924
3966
|
function extractSkillVersion(content) {
|
|
@@ -5161,27 +5203,6 @@ in MCP configuration files. Use 'pkgseer mcp' for interactive setup.`).action(as
|
|
|
5161
5203
|
}
|
|
5162
5204
|
|
|
5163
5205
|
// src/commands/pkg/compare.ts
|
|
5164
|
-
function parsePackageSpec(spec) {
|
|
5165
|
-
let registry = "npm";
|
|
5166
|
-
let rest = spec;
|
|
5167
|
-
if (spec.includes(":")) {
|
|
5168
|
-
const colonIndex = spec.indexOf(":");
|
|
5169
|
-
const potentialRegistry = spec.slice(0, colonIndex).toLowerCase();
|
|
5170
|
-
if (["npm", "pypi", "hex"].includes(potentialRegistry)) {
|
|
5171
|
-
registry = potentialRegistry;
|
|
5172
|
-
rest = spec.slice(colonIndex + 1);
|
|
5173
|
-
}
|
|
5174
|
-
}
|
|
5175
|
-
const atIndex = rest.lastIndexOf("@");
|
|
5176
|
-
if (atIndex > 0) {
|
|
5177
|
-
return {
|
|
5178
|
-
registry,
|
|
5179
|
-
name: rest.slice(0, atIndex),
|
|
5180
|
-
version: rest.slice(atIndex + 1)
|
|
5181
|
-
};
|
|
5182
|
-
}
|
|
5183
|
-
return { registry, name: rest };
|
|
5184
|
-
}
|
|
5185
5206
|
function formatPackageComparison(comparison) {
|
|
5186
5207
|
const lines = [];
|
|
5187
5208
|
lines.push("\uD83D\uDCCA Package Comparison");
|
|
@@ -5302,14 +5323,16 @@ function formatPackageDependencies(data, transitiveRequested) {
|
|
|
5302
5323
|
return lines.join(`
|
|
5303
5324
|
`);
|
|
5304
5325
|
}
|
|
5305
|
-
async function pkgDepsAction(
|
|
5326
|
+
async function pkgDepsAction(packageArg, options, deps) {
|
|
5306
5327
|
const { pkgseerService } = deps;
|
|
5307
|
-
const
|
|
5328
|
+
const parsed = parsePackageSpec(packageArg);
|
|
5329
|
+
const registry = toGraphQLRegistry(parsed.registry !== "npm" ? parsed.registry : options.registry);
|
|
5330
|
+
const version2 = parsed.version ?? options.pkgVersion;
|
|
5308
5331
|
const transitiveRequested = options.transitive ?? false;
|
|
5309
|
-
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);
|
|
5310
5333
|
handleErrors(result.errors, options.json ?? false);
|
|
5311
5334
|
if (!result.data.packageDependencies) {
|
|
5312
|
-
outputError(`Package not found: ${
|
|
5335
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
5313
5336
|
return;
|
|
5314
5337
|
}
|
|
5315
5338
|
const format = options.json ? "json" : options.format ?? "human";
|
|
@@ -5348,12 +5371,14 @@ var DEPS_DESCRIPTION = `Get package dependencies.
|
|
|
5348
5371
|
Lists direct dependencies and shows version constraints and
|
|
5349
5372
|
dependency types (runtime, dev, optional).
|
|
5350
5373
|
|
|
5374
|
+
Package format: [registry:]name[@version]
|
|
5375
|
+
|
|
5351
5376
|
Examples:
|
|
5352
5377
|
pkgseer pkg deps express
|
|
5353
|
-
pkgseer pkg deps lodash --transitive
|
|
5354
|
-
pkgseer pkg deps requests --
|
|
5378
|
+
pkgseer pkg deps lodash@4.17.21 --transitive
|
|
5379
|
+
pkgseer pkg deps pypi:requests@2.28.0 --json`;
|
|
5355
5380
|
function registerPkgDepsCommand(program) {
|
|
5356
|
-
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) => {
|
|
5357
5382
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
5358
5383
|
const deps = await createContainer();
|
|
5359
5384
|
await pkgDepsAction(packageName, options, deps);
|
|
@@ -5361,6 +5386,15 @@ function registerPkgDepsCommand(program) {
|
|
|
5361
5386
|
});
|
|
5362
5387
|
}
|
|
5363
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
|
+
}
|
|
5364
5398
|
function formatPackageSummary(data) {
|
|
5365
5399
|
const lines = [];
|
|
5366
5400
|
const pkg = data.package;
|
|
@@ -5380,6 +5414,11 @@ function formatPackageSummary(data) {
|
|
|
5380
5414
|
["License", pkg.license]
|
|
5381
5415
|
]));
|
|
5382
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
|
+
}
|
|
5383
5422
|
if (pkg.homepage || pkg.repositoryUrl) {
|
|
5384
5423
|
lines.push("Links:");
|
|
5385
5424
|
const links = [];
|
|
@@ -5402,13 +5441,14 @@ function formatPackageSummary(data) {
|
|
|
5402
5441
|
return lines.join(`
|
|
5403
5442
|
`);
|
|
5404
5443
|
}
|
|
5405
|
-
async function pkgInfoAction(
|
|
5444
|
+
async function pkgInfoAction(packageArg, options, deps) {
|
|
5406
5445
|
const { pkgseerService } = deps;
|
|
5407
|
-
const
|
|
5408
|
-
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);
|
|
5409
5449
|
handleErrors(result.errors, options.json ?? false);
|
|
5410
5450
|
if (!result.data.packageSummary) {
|
|
5411
|
-
outputError(`Package not found: ${
|
|
5451
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
5412
5452
|
return;
|
|
5413
5453
|
}
|
|
5414
5454
|
if (options.json) {
|
|
@@ -5429,16 +5469,18 @@ async function pkgInfoAction(packageName, options, deps) {
|
|
|
5429
5469
|
}
|
|
5430
5470
|
var INFO_DESCRIPTION = `Get package summary and metadata.
|
|
5431
5471
|
|
|
5432
|
-
Displays
|
|
5472
|
+
Displays information about a package's latest version including:
|
|
5433
5473
|
- Basic metadata (version, license, description)
|
|
5434
5474
|
- Download statistics
|
|
5435
|
-
- Security advisories
|
|
5436
5475
|
- Quick start instructions
|
|
5437
5476
|
|
|
5477
|
+
Note: This command shows the latest version only.
|
|
5478
|
+
For version-specific info, use 'pkg vulns', 'pkg quality', or 'pkg deps'.
|
|
5479
|
+
|
|
5438
5480
|
Examples:
|
|
5439
5481
|
pkgseer pkg info lodash
|
|
5440
|
-
pkgseer pkg info requests
|
|
5441
|
-
pkgseer pkg info phoenix --
|
|
5482
|
+
pkgseer pkg info pypi:requests
|
|
5483
|
+
pkgseer pkg info hex:phoenix --json`;
|
|
5442
5484
|
function registerPkgInfoCommand(program) {
|
|
5443
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) => {
|
|
5444
5486
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
@@ -5466,13 +5508,15 @@ function formatPackageQuality(data) {
|
|
|
5466
5508
|
return lines.join(`
|
|
5467
5509
|
`);
|
|
5468
5510
|
}
|
|
5469
|
-
async function pkgQualityAction(
|
|
5511
|
+
async function pkgQualityAction(packageArg, options, deps) {
|
|
5470
5512
|
const { pkgseerService } = deps;
|
|
5471
|
-
const
|
|
5472
|
-
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);
|
|
5473
5517
|
handleErrors(result.errors, options.json ?? false);
|
|
5474
5518
|
if (!result.data.packageQuality) {
|
|
5475
|
-
outputError(`Package not found: ${
|
|
5519
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
5476
5520
|
return;
|
|
5477
5521
|
}
|
|
5478
5522
|
const format = options.json ? "json" : options.format ?? "human";
|
|
@@ -5500,12 +5544,14 @@ Analyzes package quality across multiple dimensions:
|
|
|
5500
5544
|
- Security practices
|
|
5501
5545
|
- Community engagement
|
|
5502
5546
|
|
|
5547
|
+
Package format: [registry:]name[@version]
|
|
5548
|
+
|
|
5503
5549
|
Examples:
|
|
5504
5550
|
pkgseer pkg quality lodash
|
|
5505
|
-
pkgseer pkg quality express
|
|
5506
|
-
pkgseer pkg quality requests --
|
|
5551
|
+
pkgseer pkg quality express@4.18.0
|
|
5552
|
+
pkgseer pkg quality pypi:requests@2.28.0 --json`;
|
|
5507
5553
|
function registerPkgQualityCommand(program) {
|
|
5508
|
-
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) => {
|
|
5509
5555
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
5510
5556
|
const deps = await createContainer();
|
|
5511
5557
|
await pkgQualityAction(packageName, options, deps);
|
|
@@ -5565,13 +5611,15 @@ function formatPackageVulnerabilities(data) {
|
|
|
5565
5611
|
return lines.join(`
|
|
5566
5612
|
`);
|
|
5567
5613
|
}
|
|
5568
|
-
async function pkgVulnsAction(
|
|
5614
|
+
async function pkgVulnsAction(packageArg, options, deps) {
|
|
5569
5615
|
const { pkgseerService } = deps;
|
|
5570
|
-
const
|
|
5571
|
-
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);
|
|
5572
5620
|
handleErrors(result.errors, options.json ?? false);
|
|
5573
5621
|
if (!result.data.packageVulnerabilities) {
|
|
5574
|
-
outputError(`Package not found: ${
|
|
5622
|
+
outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
|
|
5575
5623
|
return;
|
|
5576
5624
|
}
|
|
5577
5625
|
if (options.json) {
|
|
@@ -5600,12 +5648,14 @@ Scans for known security vulnerabilities and provides:
|
|
|
5600
5648
|
- Affected version ranges
|
|
5601
5649
|
- Upgrade recommendations
|
|
5602
5650
|
|
|
5651
|
+
Package format: [registry:]name[@version]
|
|
5652
|
+
|
|
5603
5653
|
Examples:
|
|
5604
5654
|
pkgseer pkg vulns lodash
|
|
5605
|
-
pkgseer pkg vulns express
|
|
5606
|
-
pkgseer pkg vulns requests --
|
|
5655
|
+
pkgseer pkg vulns express@4.17.0
|
|
5656
|
+
pkgseer pkg vulns pypi:requests@2.28.0 --json`;
|
|
5607
5657
|
function registerPkgVulnsCommand(program) {
|
|
5608
|
-
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) => {
|
|
5609
5659
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
5610
5660
|
const deps = await createContainer();
|
|
5611
5661
|
await pkgVulnsAction(packageName, options, deps);
|
|
@@ -6044,6 +6094,9 @@ Getting started:
|
|
|
6044
6094
|
pkgseer login Authenticate with your account
|
|
6045
6095
|
pkgseer skill init Install AI agent skill
|
|
6046
6096
|
|
|
6097
|
+
Search:
|
|
6098
|
+
pkgseer search <query> -P <packages> Search code and docs
|
|
6099
|
+
|
|
6047
6100
|
Package commands:
|
|
6048
6101
|
pkgseer pkg info <package> Get package summary
|
|
6049
6102
|
pkgseer pkg vulns <package> Check vulnerabilities
|
|
@@ -6054,7 +6107,7 @@ Package commands:
|
|
|
6054
6107
|
Documentation commands:
|
|
6055
6108
|
pkgseer docs list <package> List doc pages
|
|
6056
6109
|
pkgseer docs get <pkg> <page> Fetch a doc page
|
|
6057
|
-
pkgseer docs search <query> Search
|
|
6110
|
+
pkgseer docs search <query> Search docs only
|
|
6058
6111
|
|
|
6059
6112
|
Learn more at https://pkgseer.dev`);
|
|
6060
6113
|
registerInitCommand(program);
|
|
@@ -6062,6 +6115,7 @@ registerMcpCommand(program);
|
|
|
6062
6115
|
registerSkillCommand(program);
|
|
6063
6116
|
registerLoginCommand(program);
|
|
6064
6117
|
registerLogoutCommand(program);
|
|
6118
|
+
registerSearchCommand(program);
|
|
6065
6119
|
var auth = program.command("auth").description("View and manage authentication");
|
|
6066
6120
|
registerAuthStatusCommand(auth);
|
|
6067
6121
|
var config = program.command("config").description("View and manage configuration");
|
package/dist/index.js
CHANGED