@pkgseer/cli 0.4.7 → 0.4.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  version
4
- } from "./shared/chunk-z0xepgqq.js";
4
+ } from "./shared/chunk-bahf01jh.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
@@ -355,6 +355,7 @@ var TriggerIndexingDocument = gql`
355
355
  triggerIndexing(input: $input) {
356
356
  accepted
357
357
  skipped
358
+ alreadyIndexed
358
359
  }
359
360
  }
360
361
  `;
@@ -4879,6 +4880,7 @@ async function indexAction(packages, options, deps) {
4879
4880
  if (data) {
4880
4881
  console.log(`Accepted: ${data.accepted}`);
4881
4882
  console.log(`Skipped: ${data.skipped}`);
4883
+ console.log(`Already indexed: ${data.alreadyIndexed}`);
4882
4884
  } else {
4883
4885
  console.log("Indexing request submitted.");
4884
4886
  }
@@ -5117,16 +5119,39 @@ async function setupCodexViaCli(shellService) {
5117
5119
  }
5118
5120
  function showAvailableTools(hasProject, useColors) {
5119
5121
  console.log(`
5120
- Available MCP tools:`);
5121
- console.log(" • package_summary - Get package overview");
5122
- console.log(" package_vulnerabilities - Check for security issues");
5123
- console.log(" package_quality - Get quality score");
5124
- console.log(" package_dependencies - List dependencies");
5125
- console.log(" compare_packages - Compare multiple packages");
5126
- console.log(" list_package_docs - List documentation pages");
5127
- console.log(" fetch_package_doc - Fetch documentation content");
5128
- console.log(" search_package_docs - Search package documentation");
5129
- console.log(" • search_project_docs - Search docs across project dependencies");
5122
+ Available MCP tools (21):`);
5123
+ console.log("");
5124
+ console.log(" Navigate source:");
5125
+ console.log(" find_symbol - Read source code of functions/classes");
5126
+ console.log(" list_symbols - Browse public API or file symbols");
5127
+ console.log(" search_symbols - Full-text search within package code");
5128
+ console.log(" symbol_callers - Trace what calls a function");
5129
+ console.log(" symbol_callees - Trace what a function calls");
5130
+ console.log(" call_path - Find call path between two functions");
5131
+ console.log("");
5132
+ console.log(" Browse files:");
5133
+ console.log(" • list_repo_files - Explore package file structure");
5134
+ console.log(" • grep_repo_file - Search for patterns in source files");
5135
+ console.log(" • fetch_code_context - Read source by file path and line range");
5136
+ console.log("");
5137
+ console.log(" Search & docs:");
5138
+ console.log(" • search - Search code and docs across packages");
5139
+ console.log(" • search_project_docs - Search docs across project dependencies");
5140
+ console.log(" • list_package_docs - List documentation pages");
5141
+ console.log(" • fetch_package_doc - Fetch documentation content");
5142
+ console.log("");
5143
+ console.log(" Evaluate:");
5144
+ console.log(" • package_summary - Get package overview");
5145
+ console.log(" • package_quality - Get quality score");
5146
+ console.log(" • package_vulnerabilities - Check for security issues");
5147
+ console.log(" • compare_packages - Compare multiple packages");
5148
+ console.log(" • package_dependencies - List dependencies");
5149
+ console.log(" • version_diff - Compare changes between versions");
5150
+ console.log("");
5151
+ console.log(" Utility:");
5152
+ console.log(" • trigger_indexing - Pre-warm package indexes");
5153
+ console.log(" • search_status - Check async search progress");
5154
+ console.log(" • package_imports - See what a package imports");
5130
5155
  if (!hasProject) {
5131
5156
  console.log(dim(`
5132
5157
  Tip: Create pkgseer.yml to enable automatic project detection for search_project_docs.`, useColors));
@@ -6022,27 +6047,51 @@ function generateSkillContent(invocation = "pkgseer") {
6022
6047
  return `---
6023
6048
  name: pkgseer
6024
6049
  version: ${version}
6025
- 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.
6050
+ description: Navigate source code, trace call graphs, and search docs across npm/PyPI/Hex packages. Quality scores, vulnerability checks, dependency analysis, and cross-package comparison. Use when debugging third-party dependencies, understanding how a library works internally, tracing a stack trace into dependency code, evaluating or comparing packages, checking security vulnerabilities, or understanding what changed between versions.
6026
6051
  ---
6027
6052
 
6028
- # PkgSeer - Package Intelligence
6053
+ # PkgSeer - Package Source Code & Intelligence
6029
6054
 
6030
- Search and analyze packages across npm, PyPI, and Hex. All commands support \`--json\`.
6055
+ Navigate dependency source code and analyze packages across npm, PyPI, and Hex. All commands support \`--json\`.
6031
6056
 
6032
- ## Search (Primary Use Case)
6057
+ Use PkgSeer instead of guessing library behavior, cloning repos, or browsing GitHub.
6058
+
6059
+ ## Code Navigation (Debug & Understand Dependencies)
6060
+
6061
+ \`\`\`bash
6062
+ # Read source code of a function/class — use instead of guessing from training data
6063
+ ${invocation} code find express Router --include-code
6064
+ ${invocation} code find pypi:requests Session --include-code
6065
+
6066
+ # Trace what calls a function (find entry points, debug triggers)
6067
+ ${invocation} code callers -r npm -p express -n Router
6068
+
6069
+ # Trace what a function calls (follow execution path)
6070
+ ${invocation} code callees -r npm -p express -n Router
6071
+
6072
+ # Find how function A reaches function B
6073
+ ${invocation} code path -r npm -p express --from-name listen --to-name createServer
6074
+
6075
+ # Search for error messages or patterns in dependency source
6076
+ ${invocation} code search express "ERR_HTTP_HEADERS_SENT"
6077
+ ${invocation} code grep express src/router/index.js "handle"
6078
+
6079
+ # Browse package structure, API, and imports
6080
+ ${invocation} code files express --path-prefix src/
6081
+ ${invocation} code list express --scope exports
6082
+ ${invocation} code imports express --resolved-only
6083
+
6084
+ # Compare versions (detect breaking changes after upgrades)
6085
+ ${invocation} code diff express v4.18.2 v5.0.0
6086
+ \`\`\`
6087
+
6088
+ ## Search Across Packages
6033
6089
 
6034
6090
  \`\`\`bash
6035
- # Search code and docs across packages
6036
6091
  ${invocation} search "<query>" -P lodash,express # npm packages
6037
6092
  ${invocation} search "<query>" -P pypi:requests # PyPI packages
6038
- ${invocation} search "authentication" -P hex:phoenix,hex:plug
6039
-
6040
- # Search modes
6041
6093
  ${invocation} search "<query>" -P <packages> --mode code # Code only
6042
6094
  ${invocation} search "<query>" -P <packages> --mode docs # Docs only
6043
-
6044
- # Docs-only search (shorthand)
6045
- ${invocation} docs search "<query>" -P <packages>
6046
6095
  \`\`\`
6047
6096
 
6048
6097
  ## Package Analysis
@@ -6050,23 +6099,11 @@ ${invocation} docs search "<query>" -P <packages>
6050
6099
  Package format: \`[registry:]name[@version]\`
6051
6100
 
6052
6101
  \`\`\`bash
6053
- # Overview: metadata, versions, quickstart
6054
- ${invocation} pkg info lodash
6055
- ${invocation} pkg info pypi:requests
6056
-
6057
- # Quality score (0-100) with category breakdown
6058
- ${invocation} pkg quality express@4.18.0
6059
- ${invocation} pkg quality pypi:django@4.2
6060
-
6061
- # Security: CVEs, severity, upgrade paths
6062
- ${invocation} pkg vulns lodash@4.17.21
6063
-
6064
- # Dependencies: direct, transitive, tree view
6065
- ${invocation} pkg deps express --transitive
6066
-
6067
- # Compare up to 10 packages
6068
- ${invocation} pkg compare lodash underscore ramda
6069
- ${invocation} pkg compare axios pypi:httpx # cross-registry
6102
+ ${invocation} pkg info lodash # Overview, versions, quickstart
6103
+ ${invocation} pkg quality express@4.18.0 # Quality score (0-100)
6104
+ ${invocation} pkg vulns lodash@4.17.21 # CVEs, severity, upgrade paths
6105
+ ${invocation} pkg deps express --transitive # Dependency tree
6106
+ ${invocation} pkg compare lodash underscore ramda # Side-by-side comparison
6070
6107
  \`\`\`
6071
6108
 
6072
6109
  ## Documentation
@@ -6082,6 +6119,7 @@ ${invocation} docs search "<query>" -P <packages> # Search docs only
6082
6119
  - Package format: \`[registry:]name[@version]\` (e.g., \`pypi:django@4.2\`)
6083
6120
  - Default registry: npm
6084
6121
  - Use \`--json\` for structured output when parsing
6122
+ - Quick start: \`${invocation} code find <package> <function> --include-code\`
6085
6123
  `;
6086
6124
  }
6087
6125
  function extractSkillVersion(content) {
@@ -6214,7 +6252,8 @@ PkgSeer skill ${action} for ${toolName}!`, useColors));
6214
6252
  console.log(`Location: ${highlight(paths.skillPath, useColors)}`);
6215
6253
  console.log(dim(`
6216
6254
  The skill is now available. Try asking:
6217
- ` + ` "Search for authentication examples in express"
6255
+ ` + ` "How does express Router work internally?"
6256
+ ` + ` "What changed between express v4 and v5?"
6218
6257
  ` + ` "Is lodash secure? Check for vulnerabilities"
6219
6258
  ` + ' "Compare axios vs fetch vs got"', useColors));
6220
6259
  }
@@ -6828,8 +6867,9 @@ var argsSchema = {
6828
6867
  function createCallPathTool(pkgseerService) {
6829
6868
  return {
6830
6869
  name: "call_path",
6831
- description: "Find the shortest call path between two symbols in the same package. " + "Uses BFS to trace how function A eventually calls function B through intermediate calls. " + "Returns whether a path was found, with ordered call paths (shortest first) and hop details. " + "For direct callers/callees only, use symbol_callers or symbol_callees instead.",
6870
+ description: "Trace how execution flows from one function to another in a dependency " + "debug how a public API reaches an internal function or error handler. " + "Uses BFS through intermediate calls. " + "Returns ordered call paths (shortest first) with hop details. " + "For direct callers/callees only, use symbol_callers or symbol_callees instead.",
6832
6871
  schema: argsSchema,
6872
+ annotations: { readOnlyHint: true },
6833
6873
  handler: async (args, _extra) => {
6834
6874
  return withErrorHandling("find call path", async () => {
6835
6875
  const fromInput = toSymbolReferenceInput(args.from);
@@ -6871,6 +6911,7 @@ function createComparePackagesTool(pkgseerService) {
6871
6911
  name: "compare_packages",
6872
6912
  description: "Compare 2-10 packages side-by-side. Use this when evaluating alternatives (e.g., react vs preact vs solid-js). " + "Returns for each package: quality score, download counts, vulnerability count, license, and latest version. " + "Supports cross-registry comparison (npm, pypi, hex, crates). " + 'Format: [{"registry":"npm","name":"lodash"},{"registry":"npm","name":"underscore"}]',
6873
6913
  schema: argsSchema2,
6914
+ annotations: { readOnlyHint: true },
6874
6915
  handler: async ({ packages }, _extra) => {
6875
6916
  return withErrorHandling("compare packages", async () => {
6876
6917
  const input2 = packages.map((pkg) => ({
@@ -6902,8 +6943,9 @@ var argsSchema3 = {
6902
6943
  function createFetchCodeContextTool(pkgseerService) {
6903
6944
  return {
6904
6945
  name: "fetch_code_context",
6905
- description: "Fetch code content from a repository by file path and line range. " + "Returns full file by default, or a specific line range. " + "For symbol-based lookup, use find_symbol(include_code=true) instead. " + "Requires repo_url, git_ref (tag/commit/branch), and file_path.",
6946
+ description: "Read source code from a dependency's repository by file path and line range — " + "use when you have a file path from a stack trace or symbol lookup. " + "Returns full file or a specific line range. " + "Prefer find_symbol(include_code=true) for function/class lookup. " + "Requires repo_url, git_ref, and file_path.",
6906
6947
  schema: argsSchema3,
6948
+ annotations: { readOnlyHint: true },
6907
6949
  handler: async ({ repo_url, git_ref, file_path, start_line, end_line }, _extra) => {
6908
6950
  return withErrorHandling("fetch code context", async () => {
6909
6951
  const result = await pkgseerService.fetchCodeContext(repo_url, git_ref, file_path, {
@@ -6931,6 +6973,7 @@ function createFetchPackageDocTool(pkgseerService) {
6931
6973
  name: "fetch_package_doc",
6932
6974
  description: "Get full content of a documentation page. Requires page_id from list_package_docs. " + "Returns: title, full content (markdown/HTML), format type, navigation breadcrumbs, " + "source URL, and last updated timestamp. Use this when you need complete documentation, " + "not just search snippets.",
6933
6975
  schema: argsSchema4,
6976
+ annotations: { readOnlyHint: true },
6934
6977
  handler: async ({ page_id }, _extra) => {
6935
6978
  return withErrorHandling("fetch documentation page", async () => {
6936
6979
  const result = await pkgseerService.getDocPage(page_id);
@@ -6971,8 +7014,9 @@ var argsSchema5 = {
6971
7014
  function createFindSymbolTool(pkgseerService) {
6972
7015
  return {
6973
7016
  name: "find_symbol",
6974
- description: "Find functions, methods, or classes by name in a package. " + "Set include_code=true to get full source code inline, avoiding separate fetch_code_context calls. " + "Returns: symbol ref, name, qualified path, kind, file location, and optionally source code. " + "Omit name to get all public exports. Use namespace to filter by module path.",
7017
+ description: "Read source code of any function, class, or method in a third-party package — " + "use instead of guessing implementations from training data. " + "Set include_code=true for full source inline. " + "Returns: symbol ref, name, qualified path, kind, file location, and optionally source code. " + "Omit name to get all public exports. Use namespace to filter by module path.",
6975
7018
  schema: argsSchema5,
7019
+ annotations: { readOnlyHint: true },
6976
7020
  handler: async (args, _extra) => {
6977
7021
  return withErrorHandling("find symbol", async () => {
6978
7022
  const result = await pkgseerService.findSymbol(toGraphQLRegistry(args.registry), args.package_name, {
@@ -7016,8 +7060,9 @@ var argsSchema6 = {
7016
7060
  function createGrepRepoFileTool(pkgseerService) {
7017
7061
  return {
7018
7062
  name: "grep_repo_file",
7019
- description: "Search for a pattern within a file in a package's repository. " + "Case-insensitive substring matching. Returns matching lines with context. " + "Faster than fetch_code_context for large files. " + "Use list_repo_files to discover available file paths.",
7063
+ description: "Search for a pattern within a dependency's source file " + "find error messages, config keys, or specific patterns without cloning the repo. " + "Case-insensitive substring matching with context lines. " + "Faster than fetch_code_context for large files. " + "Use list_repo_files to discover file paths.",
7020
7064
  schema: argsSchema6,
7065
+ annotations: { readOnlyHint: true },
7021
7066
  handler: async (args, _extra) => {
7022
7067
  return withErrorHandling("grep repo file", async () => {
7023
7068
  const result = await pkgseerService.grepRepoFile(toGraphQLRegistry(args.registry), args.package_name, args.file_path, args.pattern, {
@@ -7050,8 +7095,9 @@ var argsSchema7 = {
7050
7095
  function createListPackageDocsTool(pkgseerService) {
7051
7096
  return {
7052
7097
  name: "list_package_docs",
7053
- description: "Discover available documentation pages for a package. Start here before fetching or searching docs. " + "Returns: page titles, unique IDs (needed for fetch_package_doc), word counts, and update timestamps. " + "Workflow: list_package_docs → fetch_package_doc for full content, or search_package_docs to find specific topics.",
7098
+ description: "Discover available documentation pages for a package. Start here before fetching or searching docs. " + "Returns: page titles, unique IDs (needed for fetch_package_doc), word counts, and update timestamps. " + "Workflow: list_package_docs → fetch_package_doc for full content, or search(mode='docs') to find specific topics.",
7054
7099
  schema: argsSchema7,
7100
+ annotations: { readOnlyHint: true },
7055
7101
  handler: async ({ registry, package_name, version: version2 }, _extra) => {
7056
7102
  return withErrorHandling("list package documentation", async () => {
7057
7103
  const result = await pkgseerService.listPackageDocs(toGraphQLRegistry(registry), package_name, version2);
@@ -7079,8 +7125,9 @@ var argsSchema8 = {
7079
7125
  function createListRepoFilesTool(pkgseerService) {
7080
7126
  return {
7081
7127
  name: "list_repo_files",
7082
- description: "List files in a package's indexed repository. " + "Returns file paths, names, languages, types (source/doc/config), and sizes. " + "Use path_prefix to filter by directory (e.g., 'src/'). " + "Useful for exploring package structure before searching or reading code.",
7128
+ description: "Explore a dependency's file structure — " + "see what source files, configs, and docs exist. " + "Returns file paths, names, languages, types (source/doc/config), and sizes. " + "Use path_prefix to filter by directory (e.g., 'src/'). " + "Good first step when investigating unfamiliar package internals.",
7083
7129
  schema: argsSchema8,
7130
+ annotations: { readOnlyHint: true },
7084
7131
  handler: async (args, _extra) => {
7085
7132
  return withErrorHandling("list repo files", async () => {
7086
7133
  const result = await pkgseerService.listRepoFiles(toGraphQLRegistry(args.registry), args.package_name, {
@@ -7122,8 +7169,9 @@ var argsSchema9 = {
7122
7169
  function createListSymbolsTool(pkgseerService) {
7123
7170
  return {
7124
7171
  name: "list_symbols",
7125
- description: "Browse symbols in a package by scope. " + "Use scope='exports' for public API with namespace grouping and optional popularity. " + "Use scope='file' with file_path for all symbols in a specific file. " + "Returns symbols with refs, names, qualified paths, kinds, and file locations. " + "Use find_symbol(name=<symbol>, include_code=true) to get source for any listed symbol.",
7172
+ description: "Browse a dependency's public API or file-level symbols. " + "Use scope='exports' for the public API with optional popularity ranking. " + "Use scope='file' with file_path for all symbols in a specific file. " + "Returns symbol refs, names, qualified paths, kinds, and file locations. " + "Use find_symbol(name=<symbol>, include_code=true) to read source for any result.",
7126
7173
  schema: argsSchema9,
7174
+ annotations: { readOnlyHint: true },
7127
7175
  handler: async (args, _extra) => {
7128
7176
  return withErrorHandling("list symbols", async () => {
7129
7177
  const scope = toListScope(args.scope);
@@ -7245,6 +7293,7 @@ function createPackageDependenciesTool(pkgseerService) {
7245
7293
  name: "package_dependencies",
7246
7294
  description: "Analyze package dependencies. By default returns direct dependencies only. " + "Set include_transitive=true to get the full dependency tree (use max_depth to limit large trees). " + "Returns: dependency names, version constraints, and for transitive deps, a graph with depth levels. " + "Use this to understand complexity before adding a package, or to find nested dependencies.",
7247
7295
  schema: argsSchema10,
7296
+ annotations: { readOnlyHint: true },
7248
7297
  handler: async ({ registry, package_name, version: version2, include_transitive, max_depth }, _extra) => {
7249
7298
  return withErrorHandling("fetch package dependencies", async () => {
7250
7299
  const result = await pkgseerService.getPackageDependencies(toGraphQLRegistry(registry), package_name, version2, include_transitive, max_depth);
@@ -7296,8 +7345,9 @@ var argsSchema11 = {
7296
7345
  function createPackageImportsTool(pkgseerService) {
7297
7346
  return {
7298
7347
  name: "package_imports",
7299
- description: "Get import statements in a package. " + "Returns parsed import/require/use statements with optional resolution to known packages. " + "Use resolved_only=true to see only imports that map to packages in the PkgSeer registry. " + "Includes: source path, imported names, and de-duplicated dependency list.",
7348
+ description: "See what a dependency imports — understand its internal dependencies and external package usage. " + "Returns parsed import/require/use statements with optional resolution to known packages. " + "Use resolved_only=true to see only imports that map to packages in the PkgSeer registry. " + "Includes: source path, imported names, and de-duplicated dependency list.",
7300
7349
  schema: argsSchema11,
7350
+ annotations: { readOnlyHint: true },
7301
7351
  handler: async (args, _extra) => {
7302
7352
  return withErrorHandling("fetch package imports", async () => {
7303
7353
  const result = await pkgseerService.packageImports(toGraphQLRegistry(args.registry), args.package_name, {
@@ -7330,6 +7380,7 @@ function createPackageQualityTool(pkgseerService) {
7330
7380
  name: "package_quality",
7331
7381
  description: "Evaluate package maintenance health and code quality. Use this to assess if a package is well-maintained " + "before adding it as a dependency. Returns: overall score (0-100), category scores (documentation, " + "testing, community, maintenance), and individual rule results with pass/fail status. " + "Useful for comparing quality between alternative packages.",
7332
7382
  schema: argsSchema12,
7383
+ annotations: { readOnlyHint: true },
7333
7384
  handler: async ({ registry, package_name, version: version2 }, _extra) => {
7334
7385
  return withErrorHandling("fetch package quality", async () => {
7335
7386
  const result = await pkgseerService.getPackageQuality(toGraphQLRegistry(registry), package_name, version2);
@@ -7354,6 +7405,7 @@ function createPackageSummaryTool(pkgseerService) {
7354
7405
  name: "package_summary",
7355
7406
  description: "Get a comprehensive overview of a package. Use this as your first tool when researching a package. " + "Returns: description, latest version, license, repository URL, download stats, " + "active security advisories count, and quickstart/installation instructions. " + "For deeper analysis, follow up with package_quality (maintenance health) or " + "package_vulnerabilities (security details).",
7356
7407
  schema: argsSchema13,
7408
+ annotations: { readOnlyHint: true },
7357
7409
  handler: async ({ registry, package_name }, _extra) => {
7358
7410
  return withErrorHandling("fetch package summary", async () => {
7359
7411
  const result = await pkgseerService.getPackageSummary(toGraphQLRegistry(registry), package_name);
@@ -7379,6 +7431,7 @@ function createPackageVulnerabilitiesTool(pkgseerService) {
7379
7431
  name: "package_vulnerabilities",
7380
7432
  description: "Check security vulnerabilities for a package. Use this before adding dependencies or when auditing existing ones. " + "Returns: list of CVEs/advisories with severity levels, affected version ranges, fixed versions, " + "and upgrade recommendations. If version is specified, shows only vulnerabilities affecting that version.",
7381
7433
  schema: argsSchema14,
7434
+ annotations: { readOnlyHint: true },
7382
7435
  handler: async ({ registry, package_name, version: version2 }, _extra) => {
7383
7436
  return withErrorHandling("fetch package vulnerabilities", async () => {
7384
7437
  const result = await pkgseerService.getPackageVulnerabilities(toGraphQLRegistry(registry), package_name, version2);
@@ -7446,6 +7499,7 @@ function createSearchTool(pkgseerService) {
7446
7499
  name: "search",
7447
7500
  description: "Search code and documentation across packages. Returns functions, classes, and doc pages " + "matching your query. Use mode='code' for code only, mode='docs' for docs only, or " + "mode='all' (default). Provide 1-20 packages. Results include relevance scores and snippets. " + "For full source of code results, use find_symbol(name=<title>, include_code=true). " + "If packages need indexing, waits up to waitTimeoutMs (default 10s) or returns searchRef — use search_status to poll.",
7448
7501
  schema: argsSchema15,
7502
+ annotations: { readOnlyHint: true },
7449
7503
  handler: async ({ packages, query, mode, limit, waitTimeoutMs }, _extra) => {
7450
7504
  return withErrorHandling("search packages", async () => {
7451
7505
  const normalizedQuery = query.trim();
@@ -7510,8 +7564,9 @@ function createSearchProjectDocsTool(deps) {
7510
7564
  const { pkgseerService, configService, defaultProjectDir } = deps;
7511
7565
  return {
7512
7566
  name: "search_project_docs",
7513
- description: "Searches documentation across all dependencies in a PkgSeer project using search terms and match modes (any/all). Returns ranked results from multiple packages. Use project_directory to specify which project's context to use, or project to search a specific project directly.",
7567
+ description: "Search documentation across all dependencies in a PkgSeer project " + "use when you need to find information but don't know which dependency has it. " + "Requires a pkgseer.yml project config (or pass project name directly). " + "Returns ranked results with snippets from multiple packages. " + "Use project_directory to specify which project's context to use. " + "For single-package doc search, use search(mode='docs') instead.",
7514
7568
  schema: argsSchema16,
7569
+ annotations: { readOnlyHint: true },
7515
7570
  handler: async ({
7516
7571
  project_directory,
7517
7572
  project,
@@ -7566,6 +7621,7 @@ function createSearchStatusTool(pkgseerService) {
7566
7621
  name: "search_status",
7567
7622
  description: "Check the status of an async search and get results if complete. " + "Use after search returns completed=false with a searchRef. Sessions expire after 1 hour. " + "Returns status (PENDING, INDEXING, SEARCHING, COMPLETED, TIMEOUT, FAILED), " + "progress info (packagesReady/packagesTotal), and results when COMPLETED.",
7568
7623
  schema: argsSchema17,
7624
+ annotations: { readOnlyHint: true },
7569
7625
  handler: async ({ searchRef }, _extra) => {
7570
7626
  return withErrorHandling("check search status", async () => {
7571
7627
  const progressResult = await pkgseerService.getSearchProgress(searchRef);
@@ -7631,8 +7687,9 @@ var argsSchema18 = {
7631
7687
  function createSearchSymbolsTool(pkgseerService) {
7632
7688
  return {
7633
7689
  name: "search_symbols",
7634
- description: "Full-text search within package code. " + "Searches across functions, classes, modules, and doc sections. " + "Supports query string or keyword list with match_mode. " + "Use file_path to filter by directory (e.g., 'src/'). " + "Returns matching code chunks with name, type, file path, line numbers, and content previews. " + "Follow-up: use find_symbol(name=<result.name>, include_code=true) to get full source.",
7690
+ description: "Search a dependency's source code by text — " + "find where error messages, exceptions, or patterns appear across functions, classes, and modules. " + "Supports query string or keyword list with match_mode. " + "Use file_path to filter by directory (e.g., 'src/'). " + "Returns matching code chunks with name, type, file path, line numbers, and content previews. " + "Follow up with find_symbol(name=<result.name>, include_code=true) for full source.",
7635
7691
  schema: argsSchema18,
7692
+ annotations: { readOnlyHint: true },
7636
7693
  handler: async (args, _extra) => {
7637
7694
  return withErrorHandling("search symbols", async () => {
7638
7695
  const result = await pkgseerService.searchSymbols(toGraphQLRegistry(args.registry), args.package_name, {
@@ -7682,8 +7739,9 @@ var argsSchema19 = {
7682
7739
  function createSymbolCalleesTool(pkgseerService) {
7683
7740
  return {
7684
7741
  name: "symbol_callees",
7685
- description: "Find what a symbol calls (its dependencies). " + "Returns direct callees at max_depth=1, or transitive call chains at higher depths. " + "Includes callee names, qualified paths, file locations, call lines, and external package references. " + "Get symbol_ref from find_symbol or list_symbols results. See symbol_callers for the reverse.",
7742
+ description: "Trace what a function calls internally — " + "understand dependency behavior by following its execution path. " + "Returns direct callees at max_depth=1, or transitive call chains at higher depths. " + "Includes callee names, qualified paths, file locations, call lines, and external package references. " + "Get symbol_ref from find_symbol or list_symbols. See symbol_callers for the reverse.",
7686
7743
  schema: argsSchema19,
7744
+ annotations: { readOnlyHint: true },
7687
7745
  handler: async (args, _extra) => {
7688
7746
  return withErrorHandling("find symbol callees", async () => {
7689
7747
  const symbolInput = toSymbolReferenceInput(args.symbol);
@@ -7722,8 +7780,9 @@ var argsSchema20 = {
7722
7780
  function createSymbolCallersTool(pkgseerService) {
7723
7781
  return {
7724
7782
  name: "symbol_callers",
7725
- description: "Find what calls a symbol (its dependents/callers). " + "Returns the target symbol and a list of callers with file locations and call line numbers. " + "Use same_package_only to limit to callers within the same package. " + "Get symbol_ref from find_symbol or list_symbols results. See symbol_callees for the reverse.",
7783
+ description: "Trace what calls a function in a dependency's source code — " + "find entry points or debug why behavior triggers. " + "Returns callers with file locations and call line numbers. " + "Use same_package_only for within-package callers only. " + "Get symbol_ref from find_symbol or list_symbols. See symbol_callees for the reverse.",
7726
7784
  schema: argsSchema20,
7785
+ annotations: { readOnlyHint: true },
7727
7786
  handler: async (args, _extra) => {
7728
7787
  return withErrorHandling("find symbol callers", async () => {
7729
7788
  const symbolInput = toSymbolReferenceInput(args.symbol);
@@ -7769,6 +7828,7 @@ function createTriggerIndexingTool(pkgseerService) {
7769
7828
  name: "trigger_indexing",
7770
7829
  description: "Pre-warm PkgSeer indexes by triggering indexing for packages and/or repositories. " + "Fire-and-forget: triggers jobs and returns immediately with accepted/skipped counts. " + "Use before search requests to ensure packages are indexed. " + "Rate limited to 10 requests per minute.",
7771
7830
  schema: argsSchema21,
7831
+ annotations: { readOnlyHint: false, idempotentHint: true },
7772
7832
  handler: async (args, _extra) => {
7773
7833
  return withErrorHandling("trigger indexing", async () => {
7774
7834
  const packages = args.packages?.map((p) => ({
@@ -7827,8 +7887,9 @@ var argsSchema22 = {
7827
7887
  function createVersionDiffTool(pkgseerService) {
7828
7888
  return {
7829
7889
  name: "version_diff",
7830
- description: "Compare symbols between two package versions. " + "Detects added, removed, moved, and modified symbols with severity " + "(breaking, behavior_change, non_breaking, internal). " + "Returns summary counts and per-symbol changes with file locations.",
7890
+ description: "Compare two versions of a dependency to understand what changed — " + "use when debugging issues after upgrades or planning migrations. " + "Detects added, removed, moved, and modified symbols with severity " + "(breaking, behavior_change, non_breaking, internal). " + "Returns summary counts and per-symbol changes with file locations.",
7831
7891
  schema: argsSchema22,
7892
+ annotations: { readOnlyHint: true },
7832
7893
  handler: async (args, _extra) => {
7833
7894
  return withErrorHandling("version diff", async () => {
7834
7895
  const result = await pkgseerService.versionDiff(toGraphQLRegistry(args.registry), args.package_name, args.from_version, args.to_version, {
@@ -7849,6 +7910,28 @@ function createVersionDiffTool(pkgseerService) {
7849
7910
  };
7850
7911
  }
7851
7912
  // src/commands/mcp.ts
7913
+ var PKGSEER_INSTRUCTIONS = `PkgSeer provides source code intelligence for third-party packages across npm, PyPI, Hex, and other registries. All tools are read-only except trigger_indexing (which only queues background work).
7914
+
7915
+ Use PkgSeer when:
7916
+ - A stack trace or error originates in a third-party dependency
7917
+ - You need to understand how a library function works internally
7918
+ - You want to trace call chains through dependency source code
7919
+ - You're evaluating, comparing, or auditing packages
7920
+ - You need to understand what changed between package versions
7921
+
7922
+ Instead of guessing library behavior from training data, use find_symbol(include_code=true) to read actual source.
7923
+ Instead of cloning repos to search code, use search_symbols or grep_repo_file.
7924
+ Instead of manually tracing call chains on GitHub, use symbol_callers and symbol_callees.
7925
+
7926
+ Tool groups:
7927
+ - Navigate source: find_symbol, list_symbols, search_symbols, symbol_callers, symbol_callees, call_path
7928
+ - Browse files: list_repo_files, grep_repo_file, fetch_code_context
7929
+ - Search across packages: search, search_project_docs
7930
+ - Browse docs: list_package_docs, fetch_package_doc
7931
+ - Evaluate: package_summary, package_quality, package_vulnerabilities, compare_packages, package_dependencies, version_diff
7932
+ - Utility: trigger_indexing, search_status, package_imports
7933
+
7934
+ Quick start: find_symbol(registry="npm", name="<function>", package_name="<pkg>", include_code=true) often answers the question in one call.`;
7852
7935
  var TOOL_FACTORIES = {
7853
7936
  package_summary: ({ pkgseerService }) => createPackageSummaryTool(pkgseerService),
7854
7937
  package_vulnerabilities: ({ pkgseerService }) => createPackageVulnerabilitiesTool(pkgseerService),
@@ -7904,10 +7987,7 @@ var PROJECT_READ_TOOLS = ["search_project_docs"];
7904
7987
  var ALL_TOOLS = [...PUBLIC_READ_TOOLS, ...PROJECT_READ_TOOLS];
7905
7988
  function createMcpServer(deps) {
7906
7989
  const { pkgseerService, configService, config, fileSystemService } = deps;
7907
- const server = new McpServer({
7908
- name: "pkgseer",
7909
- version: "0.1.0"
7910
- });
7990
+ const server = new McpServer({ name: "pkgseer", version: "0.1.0" }, { instructions: PKGSEER_INSTRUCTIONS });
7911
7991
  const defaultProjectDir = fileSystemService.getCwd();
7912
7992
  const enabledToolNames = config.enabled_tools ?? ALL_TOOLS;
7913
7993
  const toolsToRegister = enabledToolNames.filter((name) => ALL_TOOLS.includes(name));
@@ -7920,7 +8000,11 @@ function createMcpServer(deps) {
7920
8000
  for (const toolName of toolsToRegister) {
7921
8001
  const factory = TOOL_FACTORIES[toolName];
7922
8002
  const tool = factory(factoryDeps);
7923
- server.registerTool(tool.name, { description: tool.description, inputSchema: tool.schema }, tool.handler);
8003
+ server.registerTool(tool.name, {
8004
+ description: tool.description,
8005
+ inputSchema: tool.schema,
8006
+ annotations: tool.annotations
8007
+ }, tool.handler);
7924
8008
  }
7925
8009
  return server;
7926
8010
  }
@@ -7969,10 +8053,13 @@ function registerMcpCommand(program) {
7969
8053
  When run interactively (TTY), shows setup instructions.
7970
8054
  When run via stdio (non-TTY), starts the MCP server.
7971
8055
 
7972
- Available tools: package_summary, package_vulnerabilities,
7973
- package_dependencies, package_quality, compare_packages,
7974
- list_package_docs, fetch_package_doc, search_package_docs,
7975
- search_project_docs`).action(async () => {
8056
+ Available tools (21):
8057
+ Navigate source: find_symbol, list_symbols, search_symbols, symbol_callers, symbol_callees, call_path
8058
+ Browse files: list_repo_files, grep_repo_file, fetch_code_context
8059
+ Search: search, search_project_docs
8060
+ Docs: list_package_docs, fetch_package_doc
8061
+ Evaluate: package_summary, package_quality, package_vulnerabilities, compare_packages, package_dependencies, version_diff
8062
+ Utility: trigger_indexing, search_status, package_imports`).action(async () => {
7976
8063
  const deps = await createContainer();
7977
8064
  if (process.stdout.isTTY && process.stdin.isTTY) {
7978
8065
  showMcpSetupInstructions(deps);
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  version
3
- } from "./shared/chunk-z0xepgqq.js";
3
+ } from "./shared/chunk-bahf01jh.js";
4
4
  export {
5
5
  version
6
6
  };
@@ -1,4 +1,4 @@
1
1
  // package.json
2
- var version = "0.4.7";
2
+ var version = "0.4.9";
3
3
 
4
4
  export { version };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pkgseer/cli",
3
3
  "description": "CLI companion for PkgSeer - package intelligence for developers and AI assistants",
4
- "version": "0.4.7",
4
+ "version": "0.4.9",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",