@pkgseer/cli 0.3.1 → 0.4.0

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-55x4vqp2.js";
4
+ } from "./shared/chunk-c1e7ntb6.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
@@ -24,6 +24,7 @@ var CliPackageInfoDocument = gql`
24
24
  homepage
25
25
  repositoryUrl
26
26
  downloadsLastMonth
27
+ downloadsTotal
27
28
  }
28
29
  security {
29
30
  vulnerabilityCount
@@ -106,6 +107,7 @@ var CliComparePackagesDocument = gql`
106
107
  version
107
108
  license
108
109
  downloadsLastMonth
110
+ downloadsTotal
109
111
  vulnerabilityCount
110
112
  quality {
111
113
  score
@@ -234,6 +236,7 @@ var CombinedSearchDocument = gql`
234
236
  registry
235
237
  score
236
238
  snippet
239
+ matchLine
237
240
  filePath
238
241
  startLine
239
242
  endLine
@@ -262,13 +265,16 @@ var CombinedSearchDocument = gql`
262
265
  }
263
266
  `;
264
267
  var SearchProgressDocument = gql`
265
- query SearchProgress($searchRef: String!) {
266
- searchProgress(searchRef: $searchRef) {
268
+ query SearchProgress($searchRef: String!, $includeResults: Boolean) {
269
+ searchProgress(searchRef: $searchRef, includeResults: $includeResults) {
267
270
  searchRef
268
271
  status
269
272
  packagesTotal
270
273
  packagesReady
271
274
  elapsedMs
275
+ query
276
+ mode
277
+ expiresAt
272
278
  }
273
279
  }
274
280
  `;
@@ -287,6 +293,7 @@ var SearchResultsDocument = gql`
287
293
  registry
288
294
  score
289
295
  snippet
296
+ matchLine
290
297
  filePath
291
298
  startLine
292
299
  endLine
@@ -343,6 +350,14 @@ var CliDocsGetDocument = gql`
343
350
  }
344
351
  }
345
352
  `;
353
+ var TriggerIndexingDocument = gql`
354
+ mutation TriggerIndexing($input: TriggerIndexingInput!) {
355
+ triggerIndexing(input: $input) {
356
+ accepted
357
+ skipped
358
+ }
359
+ }
360
+ `;
346
361
  var CreateProjectDocument = gql`
347
362
  mutation CreateProject($input: CreateProjectInput!) {
348
363
  createProject(input: $input) {
@@ -372,6 +387,7 @@ var PackageSummaryDocument = gql`
372
387
  repositoryUrl
373
388
  license
374
389
  downloadsLastMonth
390
+ downloadsTotal
375
391
  downloadsRefreshedAt
376
392
  }
377
393
  security {
@@ -514,6 +530,7 @@ var ComparePackagesDocument = gql`
514
530
  latestVersion
515
531
  license
516
532
  downloadsLastMonth
533
+ downloadsTotal
517
534
  vulnerabilityCount
518
535
  quality {
519
536
  score
@@ -637,6 +654,237 @@ var SearchPackageDocsDocument = gql`
637
654
  }
638
655
  }
639
656
  `;
657
+ var FindSymbolDocument = gql`
658
+ query FindSymbol($registry: Registry!, $packageName: String!, $name: String, $namespace: String, $kind: SymbolKind, $publicOnly: Boolean, $version: String, $includeCode: Boolean, $contextLines: Int, $mode: NavigationMode, $waitTimeoutMs: Int) {
659
+ findSymbol(
660
+ registry: $registry
661
+ packageName: $packageName
662
+ name: $name
663
+ namespace: $namespace
664
+ kind: $kind
665
+ publicOnly: $publicOnly
666
+ version: $version
667
+ includeCode: $includeCode
668
+ contextLines: $contextLines
669
+ mode: $mode
670
+ waitTimeoutMs: $waitTimeoutMs
671
+ ) {
672
+ symbols {
673
+ symbolId
674
+ name
675
+ qualifiedPath
676
+ kind
677
+ arity
678
+ isPublic
679
+ filePath
680
+ startLine
681
+ endLine
682
+ code
683
+ callerCount
684
+ }
685
+ totalMatches
686
+ hasMore
687
+ indexedVersion
688
+ }
689
+ }
690
+ `;
691
+ var SearchSymbolsDocument = gql`
692
+ query SearchSymbols($registry: Registry!, $packageName: String!, $query: String!, $kind: SymbolKind, $version: String, $limit: Int, $mode: NavigationMode, $waitTimeoutMs: Int) {
693
+ searchSymbols(
694
+ registry: $registry
695
+ packageName: $packageName
696
+ query: $query
697
+ kind: $kind
698
+ version: $version
699
+ limit: $limit
700
+ mode: $mode
701
+ waitTimeoutMs: $waitTimeoutMs
702
+ ) {
703
+ results {
704
+ name
705
+ chunkType
706
+ filePath
707
+ startLine
708
+ endLine
709
+ preview
710
+ contentPreview
711
+ language
712
+ }
713
+ totalMatches
714
+ hasMore
715
+ indexedVersion
716
+ }
717
+ }
718
+ `;
719
+ var ListSymbolsDocument = gql`
720
+ query ListSymbols($registry: Registry!, $packageName: String!, $scope: ListScope!, $filePath: String, $namespace: String, $publicOnly: Boolean, $includePopularity: Boolean, $limit: Int, $version: String, $mode: NavigationMode, $waitTimeoutMs: Int) {
721
+ listSymbols(
722
+ registry: $registry
723
+ packageName: $packageName
724
+ scope: $scope
725
+ filePath: $filePath
726
+ namespace: $namespace
727
+ publicOnly: $publicOnly
728
+ includePopularity: $includePopularity
729
+ limit: $limit
730
+ version: $version
731
+ mode: $mode
732
+ waitTimeoutMs: $waitTimeoutMs
733
+ ) {
734
+ symbols {
735
+ symbolId
736
+ name
737
+ qualifiedPath
738
+ kind
739
+ arity
740
+ isPublic
741
+ filePath
742
+ startLine
743
+ endLine
744
+ callerCount
745
+ }
746
+ namespaces
747
+ total
748
+ hasMore
749
+ file {
750
+ path
751
+ language
752
+ }
753
+ error
754
+ }
755
+ }
756
+ `;
757
+ var SymbolDependenciesDocument = gql`
758
+ query SymbolDependencies($symbol: SymbolReferenceInput!, $maxDepth: Int, $maxResults: Int, $includeExternal: Boolean, $includeBuiltins: Boolean, $mode: NavigationMode, $waitTimeoutMs: Int) {
759
+ symbolDependencies(
760
+ symbol: $symbol
761
+ maxDepth: $maxDepth
762
+ maxResults: $maxResults
763
+ includeExternal: $includeExternal
764
+ includeBuiltins: $includeBuiltins
765
+ mode: $mode
766
+ waitTimeoutMs: $waitTimeoutMs
767
+ ) {
768
+ root {
769
+ symbolId
770
+ name
771
+ qualifiedPath
772
+ }
773
+ dependencies {
774
+ symbolId
775
+ name
776
+ qualifiedPath
777
+ kind
778
+ filePath
779
+ callLine
780
+ isExternal
781
+ depth
782
+ package {
783
+ registry
784
+ name
785
+ }
786
+ }
787
+ externalPackages
788
+ builtinCalls
789
+ missingPackages
790
+ total
791
+ hasMore
792
+ }
793
+ }
794
+ `;
795
+ var SymbolDependentsDocument = gql`
796
+ query SymbolDependents($symbol: SymbolReferenceInput!, $samePackageOnly: Boolean, $maxResults: Int, $mode: NavigationMode, $waitTimeoutMs: Int) {
797
+ symbolDependents(
798
+ symbol: $symbol
799
+ samePackageOnly: $samePackageOnly
800
+ maxResults: $maxResults
801
+ mode: $mode
802
+ waitTimeoutMs: $waitTimeoutMs
803
+ ) {
804
+ target {
805
+ symbolId
806
+ name
807
+ qualifiedPath
808
+ }
809
+ dependents {
810
+ symbolId
811
+ name
812
+ qualifiedPath
813
+ kind
814
+ isPublic
815
+ filePath
816
+ callLine
817
+ }
818
+ total
819
+ hasMore
820
+ }
821
+ }
822
+ `;
823
+ var PackageImportsDocument = gql`
824
+ query PackageImports($registry: Registry!, $packageName: String!, $filePath: String, $resolvedOnly: Boolean, $limit: Int, $version: String, $mode: NavigationMode, $waitTimeoutMs: Int) {
825
+ packageImports(
826
+ registry: $registry
827
+ packageName: $packageName
828
+ filePath: $filePath
829
+ resolvedOnly: $resolvedOnly
830
+ limit: $limit
831
+ version: $version
832
+ mode: $mode
833
+ waitTimeoutMs: $waitTimeoutMs
834
+ ) {
835
+ imports {
836
+ sourcePath
837
+ imported
838
+ alias
839
+ kind
840
+ filePath
841
+ line
842
+ isGlob
843
+ typeOnly
844
+ package
845
+ resolvedPackage {
846
+ registry
847
+ name
848
+ }
849
+ }
850
+ uniqueDependencies
851
+ unresolvedCount
852
+ }
853
+ }
854
+ `;
855
+ var CallPathDocument = gql`
856
+ query CallPath($from: SymbolReferenceInput!, $to: SymbolReferenceInput!, $maxDepth: Int, $mode: NavigationMode, $waitTimeoutMs: Int) {
857
+ callPath(
858
+ from: $from
859
+ to: $to
860
+ maxDepth: $maxDepth
861
+ mode: $mode
862
+ waitTimeoutMs: $waitTimeoutMs
863
+ ) {
864
+ pathFound
865
+ fromSymbol {
866
+ symbolId
867
+ name
868
+ qualifiedPath
869
+ }
870
+ toSymbol {
871
+ symbolId
872
+ name
873
+ qualifiedPath
874
+ }
875
+ paths {
876
+ length
877
+ hops {
878
+ symbolId
879
+ name
880
+ qualifiedPath
881
+ filePath
882
+ callLine
883
+ }
884
+ }
885
+ }
886
+ }
887
+ `;
640
888
  var SearchProjectDocsDocument = gql`
641
889
  query SearchProjectDocs($project: String!, $keywords: [String!], $matchMode: MatchMode, $includeSnippets: Boolean, $limit: Int) {
642
890
  searchProjectDocs(
@@ -679,6 +927,7 @@ var SearchProgressDocumentString = print(SearchProgressDocument);
679
927
  var SearchResultsDocumentString = print(SearchResultsDocument);
680
928
  var FetchCodeContextDocumentString = print(FetchCodeContextDocument);
681
929
  var CliDocsGetDocumentString = print(CliDocsGetDocument);
930
+ var TriggerIndexingDocumentString = print(TriggerIndexingDocument);
682
931
  var CreateProjectDocumentString = print(CreateProjectDocument);
683
932
  var PackageSummaryDocumentString = print(PackageSummaryDocument);
684
933
  var PackageVulnerabilitiesDocumentString = print(PackageVulnerabilitiesDocument);
@@ -689,6 +938,13 @@ var ListPackageDocsDocumentString = print(ListPackageDocsDocument);
689
938
  var FetchPackageDocDocumentString = print(FetchPackageDocDocument);
690
939
  var GetDocPageDocumentString = print(GetDocPageDocument);
691
940
  var SearchPackageDocsDocumentString = print(SearchPackageDocsDocument);
941
+ var FindSymbolDocumentString = print(FindSymbolDocument);
942
+ var SearchSymbolsDocumentString = print(SearchSymbolsDocument);
943
+ var ListSymbolsDocumentString = print(ListSymbolsDocument);
944
+ var SymbolDependenciesDocumentString = print(SymbolDependenciesDocument);
945
+ var SymbolDependentsDocumentString = print(SymbolDependentsDocument);
946
+ var PackageImportsDocumentString = print(PackageImportsDocument);
947
+ var CallPathDocumentString = print(CallPathDocument);
692
948
  var SearchProjectDocsDocumentString = print(SearchProjectDocsDocument);
693
949
  function getSdk(client, withWrapper = defaultWrapper) {
694
950
  return {
@@ -731,6 +987,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
731
987
  CliDocsGet(variables, requestHeaders) {
732
988
  return withWrapper((wrappedRequestHeaders) => client.rawRequest(CliDocsGetDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CliDocsGet", "query", variables);
733
989
  },
990
+ TriggerIndexing(variables, requestHeaders) {
991
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(TriggerIndexingDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "TriggerIndexing", "mutation", variables);
992
+ },
734
993
  CreateProject(variables, requestHeaders) {
735
994
  return withWrapper((wrappedRequestHeaders) => client.rawRequest(CreateProjectDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CreateProject", "mutation", variables);
736
995
  },
@@ -761,6 +1020,27 @@ function getSdk(client, withWrapper = defaultWrapper) {
761
1020
  SearchPackageDocs(variables, requestHeaders) {
762
1021
  return withWrapper((wrappedRequestHeaders) => client.rawRequest(SearchPackageDocsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SearchPackageDocs", "query", variables);
763
1022
  },
1023
+ FindSymbol(variables, requestHeaders) {
1024
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(FindSymbolDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "FindSymbol", "query", variables);
1025
+ },
1026
+ SearchSymbols(variables, requestHeaders) {
1027
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(SearchSymbolsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SearchSymbols", "query", variables);
1028
+ },
1029
+ ListSymbols(variables, requestHeaders) {
1030
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(ListSymbolsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "ListSymbols", "query", variables);
1031
+ },
1032
+ SymbolDependencies(variables, requestHeaders) {
1033
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(SymbolDependenciesDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SymbolDependencies", "query", variables);
1034
+ },
1035
+ SymbolDependents(variables, requestHeaders) {
1036
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(SymbolDependentsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SymbolDependents", "query", variables);
1037
+ },
1038
+ PackageImports(variables, requestHeaders) {
1039
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(PackageImportsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "PackageImports", "query", variables);
1040
+ },
1041
+ CallPath(variables, requestHeaders) {
1042
+ return withWrapper((wrappedRequestHeaders) => client.rawRequest(CallPathDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CallPath", "query", variables);
1043
+ },
764
1044
  SearchProjectDocs(variables, requestHeaders) {
765
1045
  return withWrapper((wrappedRequestHeaders) => client.rawRequest(SearchProjectDocsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SearchProjectDocs", "query", variables);
766
1046
  }
@@ -1093,7 +1373,15 @@ var TOOL_NAMES = [
1093
1373
  "search",
1094
1374
  "search_status",
1095
1375
  "fetch_code_context",
1096
- "search_project_docs"
1376
+ "search_project_docs",
1377
+ "find_symbol",
1378
+ "search_symbols",
1379
+ "list_symbols",
1380
+ "symbol_callers",
1381
+ "symbol_callees",
1382
+ "package_imports",
1383
+ "call_path",
1384
+ "trigger_indexing"
1097
1385
  ];
1098
1386
  var ToolNameSchema = z.enum(TOOL_NAMES);
1099
1387
  var SharedConfigFields = {
@@ -1495,8 +1783,11 @@ class PkgseerServiceImpl {
1495
1783
  });
1496
1784
  return { data: result.data, errors: result.errors };
1497
1785
  }
1498
- async getSearchProgress(searchRef) {
1499
- const result = await this.client.SearchProgress({ searchRef });
1786
+ async getSearchProgress(searchRef, options) {
1787
+ const result = await this.client.SearchProgress({
1788
+ searchRef,
1789
+ includeResults: options?.includeResults
1790
+ });
1500
1791
  return { data: result.data, errors: result.errors };
1501
1792
  }
1502
1793
  async getSearchResults(searchRef) {
@@ -1513,6 +1804,100 @@ class PkgseerServiceImpl {
1513
1804
  });
1514
1805
  return { data: result.data, errors: result.errors };
1515
1806
  }
1807
+ async findSymbol(registry, packageName, options) {
1808
+ const result = await this.client.FindSymbol({
1809
+ registry,
1810
+ packageName,
1811
+ name: options?.name,
1812
+ namespace: options?.namespace,
1813
+ kind: options?.kind,
1814
+ publicOnly: options?.publicOnly,
1815
+ version: options?.version,
1816
+ includeCode: options?.includeCode,
1817
+ contextLines: options?.contextLines,
1818
+ mode: options?.mode,
1819
+ waitTimeoutMs: options?.waitTimeoutMs
1820
+ });
1821
+ return { data: result.data, errors: result.errors };
1822
+ }
1823
+ async searchSymbols(registry, packageName, query, options) {
1824
+ const result = await this.client.SearchSymbols({
1825
+ registry,
1826
+ packageName,
1827
+ query,
1828
+ kind: options?.kind,
1829
+ version: options?.version,
1830
+ limit: options?.limit,
1831
+ mode: options?.mode,
1832
+ waitTimeoutMs: options?.waitTimeoutMs
1833
+ });
1834
+ return { data: result.data, errors: result.errors };
1835
+ }
1836
+ async listSymbols(registry, packageName, scope, options) {
1837
+ const result = await this.client.ListSymbols({
1838
+ registry,
1839
+ packageName,
1840
+ scope,
1841
+ filePath: options?.filePath,
1842
+ namespace: options?.namespace,
1843
+ publicOnly: options?.publicOnly,
1844
+ includePopularity: options?.includePopularity,
1845
+ limit: options?.limit,
1846
+ version: options?.version,
1847
+ mode: options?.mode,
1848
+ waitTimeoutMs: options?.waitTimeoutMs
1849
+ });
1850
+ return { data: result.data, errors: result.errors };
1851
+ }
1852
+ async symbolDependencies(symbol, options) {
1853
+ const result = await this.client.SymbolDependencies({
1854
+ symbol,
1855
+ maxDepth: options?.maxDepth,
1856
+ maxResults: options?.maxResults,
1857
+ includeExternal: options?.includeExternal,
1858
+ includeBuiltins: options?.includeBuiltins,
1859
+ mode: options?.mode,
1860
+ waitTimeoutMs: options?.waitTimeoutMs
1861
+ });
1862
+ return { data: result.data, errors: result.errors };
1863
+ }
1864
+ async symbolDependents(symbol, options) {
1865
+ const result = await this.client.SymbolDependents({
1866
+ symbol,
1867
+ samePackageOnly: options?.samePackageOnly,
1868
+ maxResults: options?.maxResults,
1869
+ mode: options?.mode,
1870
+ waitTimeoutMs: options?.waitTimeoutMs
1871
+ });
1872
+ return { data: result.data, errors: result.errors };
1873
+ }
1874
+ async packageImports(registry, packageName, options) {
1875
+ const result = await this.client.PackageImports({
1876
+ registry,
1877
+ packageName,
1878
+ filePath: options?.filePath,
1879
+ resolvedOnly: options?.resolvedOnly,
1880
+ limit: options?.limit,
1881
+ version: options?.version,
1882
+ mode: options?.mode,
1883
+ waitTimeoutMs: options?.waitTimeoutMs
1884
+ });
1885
+ return { data: result.data, errors: result.errors };
1886
+ }
1887
+ async callPath(from, to, options) {
1888
+ const result = await this.client.CallPath({
1889
+ from,
1890
+ to,
1891
+ maxDepth: options?.maxDepth,
1892
+ mode: options?.mode,
1893
+ waitTimeoutMs: options?.waitTimeoutMs
1894
+ });
1895
+ return { data: result.data, errors: result.errors };
1896
+ }
1897
+ async triggerIndexing(input) {
1898
+ const result = await this.client.TriggerIndexing({ input });
1899
+ return { data: result.data, errors: result.errors };
1900
+ }
1516
1901
  }
1517
1902
  // src/services/project-service.ts
1518
1903
  var PROJECT_NAME_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
@@ -1810,58 +2195,6 @@ function registerAuthStatusCommand(program) {
1810
2195
  });
1811
2196
  }
1812
2197
 
1813
- // src/commands/config-show.ts
1814
- async function configShowAction(deps) {
1815
- const { configService } = deps;
1816
- const { config, globalPath, projectPath } = await configService.loadMergedConfig();
1817
- if (!globalPath && !projectPath) {
1818
- console.log(`No configuration found.
1819
- `);
1820
- console.log(" Global config: ~/.pkgseer/config.yml");
1821
- console.log(` Project config: pkgseer.yml
1822
- `);
1823
- console.log("Create a config file to customize pkgseer behavior.");
1824
- return;
1825
- }
1826
- console.log(`Configuration sources:
1827
- `);
1828
- if (globalPath) {
1829
- console.log(` Global: ${globalPath}`);
1830
- }
1831
- if (projectPath) {
1832
- console.log(` Project: ${projectPath}`);
1833
- }
1834
- console.log(`
1835
- Merged configuration:
1836
- `);
1837
- if (config.enabled_tools !== undefined) {
1838
- if (config.enabled_tools.length > 0) {
1839
- console.log(" enabled_tools:");
1840
- for (const tool of config.enabled_tools) {
1841
- console.log(` - ${tool}`);
1842
- }
1843
- } else {
1844
- console.log(" enabled_tools: [] (no tools enabled)");
1845
- }
1846
- } else {
1847
- console.log(" enabled_tools: (all tools enabled by default)");
1848
- }
1849
- if (config.project) {
1850
- console.log(` project: ${config.project}`);
1851
- }
1852
- }
1853
- var SHOW_DESCRIPTION = `Display current configuration.
1854
-
1855
- Shows the merged configuration from global (~/.pkgseer/config.yml) and
1856
- project (pkgseer.yml) config files. Project config takes precedence
1857
- over global config for overlapping settings.`;
1858
- function registerConfigShowCommand(program) {
1859
- program.command("show").summary("Display current configuration").description(SHOW_DESCRIPTION).action(async () => {
1860
- const deps = await createContainer();
1861
- await configShowAction(deps);
1862
- });
1863
- }
1864
-
1865
2198
  // src/commands/shared.ts
1866
2199
  function parsePackageSpec(spec) {
1867
2200
  let registry = "npm";
@@ -1869,7 +2202,16 @@ function parsePackageSpec(spec) {
1869
2202
  if (spec.includes(":")) {
1870
2203
  const colonIndex = spec.indexOf(":");
1871
2204
  const potentialRegistry = spec.slice(0, colonIndex).toLowerCase();
1872
- if (["npm", "pypi", "hex", "crates"].includes(potentialRegistry)) {
2205
+ if ([
2206
+ "npm",
2207
+ "pypi",
2208
+ "hex",
2209
+ "crates",
2210
+ "nuget",
2211
+ "maven",
2212
+ "zig",
2213
+ "vcpkg"
2214
+ ].includes(potentialRegistry)) {
1873
2215
  registry = potentialRegistry;
1874
2216
  rest = spec.slice(colonIndex + 1);
1875
2217
  }
@@ -1889,7 +2231,11 @@ function toGraphQLRegistry(registry) {
1889
2231
  npm: "NPM",
1890
2232
  pypi: "PYPI",
1891
2233
  hex: "HEX",
1892
- crates: "CRATES"
2234
+ crates: "CRATES",
2235
+ nuget: "NUGET",
2236
+ maven: "MAVEN",
2237
+ zig: "ZIG",
2238
+ vcpkg: "VCPKG"
1893
2239
  };
1894
2240
  return map[registry.toLowerCase()] || "NPM";
1895
2241
  }
@@ -1935,6 +2281,11 @@ function formatNumber(num) {
1935
2281
  return "N/A";
1936
2282
  return num.toLocaleString();
1937
2283
  }
2284
+ function truncate(text, maxLength) {
2285
+ if (text.length <= maxLength)
2286
+ return text;
2287
+ return `${text.slice(0, maxLength - 3)}...`;
2288
+ }
1938
2289
  function keyValueTable(pairs) {
1939
2290
  const maxKeyLen = Math.max(...pairs.map(([k]) => k.length));
1940
2291
  return pairs.map(([key, value]) => ` ${key.padEnd(maxKeyLen)} ${value ?? "N/A"}`).join(`
@@ -2019,18 +2370,624 @@ async function withCliErrorHandling(json, fn) {
2019
2370
  outputError(`${message}. Hint: wait and retry.`, json);
2020
2371
  return;
2021
2372
  }
2022
- const colonMatch = message.match(/^([^:]+):/);
2023
- const shortMessage = colonMatch?.[1] ?? message;
2024
- outputError(shortMessage, json);
2373
+ const colonMatch = message.match(/^([^:]+):/);
2374
+ const shortMessage = colonMatch?.[1] ?? message;
2375
+ outputError(shortMessage, json);
2376
+ }
2377
+ }
2378
+ function formatScore(score) {
2379
+ if (score == null)
2380
+ return "N/A";
2381
+ const percentage = score > 1 ? Math.round(score) : Math.round(score * 100);
2382
+ const filled = Math.round(percentage / 5);
2383
+ const bar = "█".repeat(Math.min(filled, 20)) + "░".repeat(Math.max(20 - filled, 0));
2384
+ return `${bar} ${percentage}%`;
2385
+ }
2386
+
2387
+ // src/commands/code/shared.ts
2388
+ function parseSymbolRef(spec) {
2389
+ const hashIndex = spec.indexOf("#");
2390
+ if (hashIndex >= 0) {
2391
+ const packagePart = spec.slice(0, hashIndex);
2392
+ const symbolName = spec.slice(hashIndex + 1);
2393
+ const parsed2 = parsePackageSpec(packagePart);
2394
+ return {
2395
+ registry: toGraphQLRegistry(parsed2.registry),
2396
+ packageName: parsed2.name,
2397
+ symbolName: symbolName || undefined
2398
+ };
2399
+ }
2400
+ const parsed = parsePackageSpec(spec);
2401
+ return {
2402
+ registry: toGraphQLRegistry(parsed.registry),
2403
+ packageName: parsed.name
2404
+ };
2405
+ }
2406
+ function buildSymbolReference(spec, id) {
2407
+ if (id) {
2408
+ return { symbolId: Number.parseInt(id, 10) };
2409
+ }
2410
+ if (!spec) {
2411
+ throw new Error("Symbol reference required. Use registry:package#symbolName or --id <number>");
2412
+ }
2413
+ return parseSymbolRef(spec);
2414
+ }
2415
+ function parseIntOption(value, name) {
2416
+ if (value === undefined)
2417
+ return;
2418
+ const n = Number.parseInt(value, 10);
2419
+ if (Number.isNaN(n) || n < 0) {
2420
+ throw new Error(`${name} must be a non-negative integer`);
2421
+ }
2422
+ return n;
2423
+ }
2424
+ function parseWaitTimeout(wait) {
2425
+ if (wait === undefined)
2426
+ return;
2427
+ const ms = Number.parseInt(wait, 10);
2428
+ if (Number.isNaN(ms) || ms < 0 || ms > 30000) {
2429
+ throw new Error("--wait must be a number between 0 and 30000");
2430
+ }
2431
+ return ms;
2432
+ }
2433
+ function parseNavigationMode(mode) {
2434
+ if (!mode)
2435
+ return;
2436
+ const upper = mode.toUpperCase();
2437
+ if (upper === "SUMMARY" || upper === "DETAILED")
2438
+ return upper;
2439
+ throw new Error("--mode must be 'summary' or 'detailed'");
2440
+ }
2441
+ function formatSymbol(symbol) {
2442
+ const parts = [];
2443
+ const kindLabel = symbol.kind ? `[${symbol.kind}]` : "";
2444
+ const visibility = symbol.isPublic === false ? "(private) " : "";
2445
+ const arity = symbol.arity != null ? `/${symbol.arity}` : "";
2446
+ parts.push(`${kindLabel} ${visibility}${symbol.name}${arity}`.trim());
2447
+ if (symbol.qualifiedPath && symbol.qualifiedPath !== symbol.name) {
2448
+ parts.push(` Path: ${symbol.qualifiedPath}`);
2449
+ }
2450
+ if (symbol.filePath) {
2451
+ const loc = symbol.startLine ? `${symbol.filePath}:${symbol.startLine}` : symbol.filePath;
2452
+ parts.push(` File: ${loc}`);
2453
+ }
2454
+ const meta = [`id:${symbol.symbolId}`];
2455
+ if (symbol.callerCount != null) {
2456
+ meta.push(`callers:${symbol.callerCount}`);
2457
+ }
2458
+ parts.push(` ${meta.join(" ")}`);
2459
+ if (symbol.code) {
2460
+ parts.push("");
2461
+ parts.push(symbol.code.split(`
2462
+ `).map((line) => ` ${line}`).join(`
2463
+ `));
2464
+ }
2465
+ return parts.join(`
2466
+ `);
2467
+ }
2468
+ function formatDependencyEntry(entry) {
2469
+ const parts = [];
2470
+ const kindLabel = entry.kind ? `[${entry.kind}]` : "";
2471
+ const depthLabel = entry.depth ? ` (depth:${entry.depth})` : "";
2472
+ const extLabel = entry.isExternal ? " [external]" : "";
2473
+ parts.push(`${kindLabel} ${entry.name}${depthLabel}${extLabel}`.trim());
2474
+ if (entry.qualifiedPath && entry.qualifiedPath !== entry.name) {
2475
+ parts.push(` Path: ${entry.qualifiedPath}`);
2476
+ }
2477
+ if (entry.filePath) {
2478
+ const loc = entry.callLine ? `${entry.filePath}:${entry.callLine}` : entry.filePath;
2479
+ parts.push(` File: ${loc}`);
2480
+ }
2481
+ if (entry.package) {
2482
+ parts.push(` Package: ${entry.package.registry}:${entry.package.name}`);
2483
+ }
2484
+ if (entry.symbolId) {
2485
+ parts.push(` id:${entry.symbolId}`);
2486
+ }
2487
+ return parts.join(`
2488
+ `);
2489
+ }
2490
+
2491
+ // src/commands/code/callees.ts
2492
+ function formatCalleesResult(data) {
2493
+ const lines = [];
2494
+ lines.push(`Callees of ${data.root.qualifiedPath ?? data.root.name} (id:${data.root.symbolId})`);
2495
+ lines.push(`${data.total} callee(s)${data.hasMore ? " (more available)" : ""}`);
2496
+ if (data.externalPackages && data.externalPackages.length > 0) {
2497
+ lines.push(`External packages: ${data.externalPackages.join(", ")}`);
2498
+ }
2499
+ if (data.builtinCalls && data.builtinCalls.length > 0) {
2500
+ const builtins = data.builtinCalls.filter(Boolean);
2501
+ if (builtins.length > 0) {
2502
+ lines.push(`Builtin calls: ${builtins.join(", ")}`);
2503
+ }
2504
+ }
2505
+ lines.push("");
2506
+ for (const dep of data.dependencies) {
2507
+ lines.push(formatDependencyEntry(dep));
2508
+ lines.push("");
2509
+ }
2510
+ return lines.join(`
2511
+ `).trimEnd();
2512
+ }
2513
+ async function codeCalleesAction(symbolArg, options, deps) {
2514
+ const { pkgseerService } = deps;
2515
+ const symbolRef = buildSymbolReference(symbolArg, options.id);
2516
+ const result = await pkgseerService.symbolDependencies(symbolRef, {
2517
+ maxDepth: parseIntOption(options.maxDepth, "--max-depth"),
2518
+ maxResults: parseIntOption(options.limit, "--limit"),
2519
+ includeExternal: options.includeExternal,
2520
+ includeBuiltins: options.includeBuiltins,
2521
+ mode: parseNavigationMode(options.mode),
2522
+ waitTimeoutMs: parseWaitTimeout(options.wait)
2523
+ });
2524
+ handleErrors(result.errors, options.json ?? false);
2525
+ if (!result.data.symbolDependencies) {
2526
+ outputError("Symbol not found. Verify the symbol reference or use --id.", options.json ?? false);
2527
+ return;
2528
+ }
2529
+ if (options.json) {
2530
+ output(result.data.symbolDependencies, true);
2531
+ } else {
2532
+ console.log(formatCalleesResult(result.data.symbolDependencies));
2533
+ }
2534
+ }
2535
+ var CALLEES_DESCRIPTION = `Find what a symbol calls.
2536
+
2537
+ Shows functions and methods that the specified symbol depends on.
2538
+ Use registry:package#symbolName format or --id for direct lookup.
2539
+
2540
+ Examples:
2541
+ pkgseer code callees npm:express#Router
2542
+ pkgseer code callees --id 12345
2543
+ pkgseer code callees npm:lodash#merge --max-depth 2 --include-external`;
2544
+ function registerCodeCalleesCommand(program) {
2545
+ program.command("callees [symbol]").summary("Find what a symbol calls").description(CALLEES_DESCRIPTION).option("--id <id>", "Direct symbol ID").option("--max-depth <n>", "Max traversal depth").option("--limit <n>", "Max results").option("--include-external", "Include external package calls").option("--include-builtins", "Include builtin function calls").option("--mode <mode>", "Response detail: summary or detailed").option("--wait <ms>", "Max ms to wait for indexing (0-30000)").option("--json", "Output as JSON").action(async (symbolArg, options) => {
2546
+ await withCliErrorHandling(options.json ?? false, async () => {
2547
+ const deps = await createContainer();
2548
+ await codeCalleesAction(symbolArg, options, deps);
2549
+ });
2550
+ });
2551
+ }
2552
+ // src/commands/code/callers.ts
2553
+ function formatCallersResult(data) {
2554
+ const lines = [];
2555
+ lines.push(`Callers of ${data.target.qualifiedPath ?? data.target.name} (id:${data.target.symbolId})`);
2556
+ lines.push(`${data.total} caller(s)${data.hasMore ? " (more available)" : ""}`);
2557
+ lines.push("");
2558
+ for (const dep of data.dependents) {
2559
+ lines.push(formatDependencyEntry(dep));
2560
+ lines.push("");
2561
+ }
2562
+ return lines.join(`
2563
+ `).trimEnd();
2564
+ }
2565
+ async function codeCallersAction(symbolArg, options, deps) {
2566
+ const { pkgseerService } = deps;
2567
+ const symbolRef = buildSymbolReference(symbolArg, options.id);
2568
+ const result = await pkgseerService.symbolDependents(symbolRef, {
2569
+ samePackageOnly: options.samePackageOnly,
2570
+ maxResults: parseIntOption(options.limit, "--limit"),
2571
+ mode: parseNavigationMode(options.mode),
2572
+ waitTimeoutMs: parseWaitTimeout(options.wait)
2573
+ });
2574
+ handleErrors(result.errors, options.json ?? false);
2575
+ if (!result.data.symbolDependents) {
2576
+ outputError("Symbol not found. Verify the symbol reference or use --id.", options.json ?? false);
2577
+ return;
2578
+ }
2579
+ if (options.json) {
2580
+ output(result.data.symbolDependents, true);
2581
+ } else {
2582
+ console.log(formatCallersResult(result.data.symbolDependents));
2583
+ }
2584
+ }
2585
+ var CALLERS_DESCRIPTION = `Find what calls a symbol.
2586
+
2587
+ Shows functions and methods that call the specified symbol.
2588
+ Use registry:package#symbolName format or --id for direct lookup.
2589
+
2590
+ Examples:
2591
+ pkgseer code callers npm:express#Router
2592
+ pkgseer code callers --id 12345
2593
+ pkgseer code callers npm:lodash#debounce --same-package-only`;
2594
+ function registerCodeCallersCommand(program) {
2595
+ program.command("callers [symbol]").summary("Find what calls a symbol").description(CALLERS_DESCRIPTION).option("--id <id>", "Direct symbol ID").option("--same-package-only", "Only show callers from the same package").option("--limit <n>", "Max results").option("--mode <mode>", "Response detail: summary or detailed").option("--wait <ms>", "Max ms to wait for indexing (0-30000)").option("--json", "Output as JSON").action(async (symbolArg, options) => {
2596
+ await withCliErrorHandling(options.json ?? false, async () => {
2597
+ const deps = await createContainer();
2598
+ await codeCallersAction(symbolArg, options, deps);
2599
+ });
2600
+ });
2601
+ }
2602
+ // src/commands/code/find.ts
2603
+ function formatFindResult(data) {
2604
+ const lines = [];
2605
+ lines.push(`Found ${data.totalMatches} symbol(s)${data.hasMore ? " (more available)" : ""}`);
2606
+ if (data.indexedVersion) {
2607
+ lines.push(`Indexed version: ${data.indexedVersion}`);
2608
+ }
2609
+ lines.push("");
2610
+ for (const symbol of data.symbols) {
2611
+ lines.push(formatSymbol(symbol));
2612
+ lines.push("");
2613
+ }
2614
+ return lines.join(`
2615
+ `).trimEnd();
2616
+ }
2617
+ async function codeFindAction(packageArg, nameArg, options, deps) {
2618
+ const { pkgseerService } = deps;
2619
+ const parsed = parsePackageSpec(packageArg);
2620
+ const registry = toGraphQLRegistry(parsed.registry);
2621
+ const result = await pkgseerService.findSymbol(registry, parsed.name, {
2622
+ name: nameArg,
2623
+ namespace: options.namespace,
2624
+ kind: options.kind?.toUpperCase(),
2625
+ publicOnly: options.publicOnly,
2626
+ version: parsed.version,
2627
+ includeCode: options.includeCode,
2628
+ contextLines: parseIntOption(options.contextLines, "--context-lines"),
2629
+ mode: parseNavigationMode(options.mode),
2630
+ waitTimeoutMs: parseWaitTimeout(options.wait)
2631
+ });
2632
+ handleErrors(result.errors, options.json ?? false);
2633
+ if (!result.data.findSymbol) {
2634
+ outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
2635
+ return;
2636
+ }
2637
+ if (options.json) {
2638
+ output(result.data.findSymbol, true);
2639
+ } else {
2640
+ console.log(formatFindResult(result.data.findSymbol));
2641
+ }
2642
+ }
2643
+ var FIND_DESCRIPTION = `Find symbols (functions, classes, modules) by name.
2644
+
2645
+ Searches for symbols in a package by exact or partial name match.
2646
+ Returns symbol metadata, location, and optionally source code.
2647
+
2648
+ Examples:
2649
+ pkgseer code find npm:express Router
2650
+ pkgseer code find pypi:requests get --kind function
2651
+ pkgseer code find npm:lodash --namespace array --public-only
2652
+ pkgseer code find npm:express Router --include-code`;
2653
+ function registerCodeFindCommand(program) {
2654
+ program.command("find <package> [name]").summary("Find symbols by name").description(FIND_DESCRIPTION).option("--namespace <ns>", "Filter by namespace").option("--kind <kind>", "Filter by symbol kind (function, class, module, etc.)").option("--public-only", "Only show public symbols").option("--include-code", "Include source code in results").option("--context-lines <n>", "Lines of context around code").option("--mode <mode>", "Response detail: summary or detailed").option("--wait <ms>", "Max ms to wait for indexing (0-30000)").option("--json", "Output as JSON").action(async (packageArg, nameArg, options) => {
2655
+ await withCliErrorHandling(options.json ?? false, async () => {
2656
+ const deps = await createContainer();
2657
+ await codeFindAction(packageArg, nameArg, options, deps);
2658
+ });
2659
+ });
2660
+ }
2661
+ // src/commands/code/imports.ts
2662
+ function formatImport(entry) {
2663
+ const parts = [];
2664
+ const kindLabel = entry.kind ? `[${entry.kind}]` : "";
2665
+ const typeLabel = entry.typeOnly ? " (type)" : "";
2666
+ const aliasLabel = entry.alias ? ` as ${entry.alias}` : "";
2667
+ const imported = entry.imported ?? "*";
2668
+ parts.push(`${kindLabel} ${imported}${aliasLabel}${typeLabel}`.trim());
2669
+ if (entry.sourcePath) {
2670
+ parts.push(` from: ${entry.sourcePath}`);
2671
+ }
2672
+ if (entry.filePath) {
2673
+ const loc = entry.line ? `${entry.filePath}:${entry.line}` : entry.filePath;
2674
+ parts.push(` File: ${loc}`);
2675
+ }
2676
+ if (entry.resolvedPackage) {
2677
+ parts.push(` Resolves to: ${entry.resolvedPackage.registry}:${entry.resolvedPackage.name}`);
2678
+ } else if (entry.package) {
2679
+ parts.push(` Package: ${entry.package}`);
2680
+ }
2681
+ return parts.join(`
2682
+ `);
2683
+ }
2684
+ function formatImportsResult(data) {
2685
+ const lines = [];
2686
+ lines.push(`${data.imports.length} import(s)`);
2687
+ if (data.uniqueDependencies && data.uniqueDependencies.length > 0) {
2688
+ lines.push(`Unique dependencies: ${data.uniqueDependencies.join(", ")}`);
2689
+ }
2690
+ if (data.unresolvedCount != null && data.unresolvedCount > 0) {
2691
+ lines.push(`Unresolved: ${data.unresolvedCount}`);
2692
+ }
2693
+ lines.push("");
2694
+ for (const entry of data.imports) {
2695
+ lines.push(formatImport(entry));
2696
+ lines.push("");
2697
+ }
2698
+ return lines.join(`
2699
+ `).trimEnd();
2700
+ }
2701
+ async function codeImportsAction(packageArg, options, deps) {
2702
+ const { pkgseerService } = deps;
2703
+ const parsed = parsePackageSpec(packageArg);
2704
+ const registry = toGraphQLRegistry(parsed.registry);
2705
+ const result = await pkgseerService.packageImports(registry, parsed.name, {
2706
+ filePath: options.file,
2707
+ resolvedOnly: options.resolvedOnly,
2708
+ limit: parseIntOption(options.limit, "--limit"),
2709
+ version: parsed.version,
2710
+ mode: parseNavigationMode(options.mode),
2711
+ waitTimeoutMs: parseWaitTimeout(options.wait)
2712
+ });
2713
+ handleErrors(result.errors, options.json ?? false);
2714
+ if (!result.data.packageImports) {
2715
+ outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
2716
+ return;
2717
+ }
2718
+ if (options.json) {
2719
+ output(result.data.packageImports, true);
2720
+ } else {
2721
+ console.log(formatImportsResult(result.data.packageImports));
2722
+ }
2723
+ }
2724
+ var IMPORTS_DESCRIPTION = `List import statements in a package.
2725
+
2726
+ Shows what a package imports, including source paths, resolved packages,
2727
+ and import types. Useful for understanding package dependencies at code level.
2728
+
2729
+ Examples:
2730
+ pkgseer code imports npm:express
2731
+ pkgseer code imports npm:lodash --file src/index.js
2732
+ pkgseer code imports pypi:requests --resolved-only`;
2733
+ function registerCodeImportsCommand(program) {
2734
+ program.command("imports <package>").summary("List package import statements").description(IMPORTS_DESCRIPTION).option("--file <path>", "Filter by source file path").option("--resolved-only", "Only show resolved imports").option("--limit <n>", "Max results").option("--mode <mode>", "Response detail: summary or detailed").option("--wait <ms>", "Max ms to wait for indexing (0-30000)").option("--json", "Output as JSON").action(async (packageArg, options) => {
2735
+ await withCliErrorHandling(options.json ?? false, async () => {
2736
+ const deps = await createContainer();
2737
+ await codeImportsAction(packageArg, options, deps);
2738
+ });
2739
+ });
2740
+ }
2741
+ // src/commands/code/list.ts
2742
+ function formatListResult(data) {
2743
+ const lines = [];
2744
+ lines.push(`${data.total} symbol(s)${data.hasMore ? " (more available)" : ""}`);
2745
+ if (data.namespaces && data.namespaces.length > 0) {
2746
+ lines.push(`Namespaces: ${data.namespaces.join(", ")}`);
2747
+ }
2748
+ if (data.file) {
2749
+ lines.push(`File: ${data.file.path}${data.file.language ? ` (${data.file.language})` : ""}`);
2750
+ }
2751
+ if (data.error) {
2752
+ lines.push(`Warning: ${data.error}`);
2753
+ }
2754
+ lines.push("");
2755
+ for (const symbol of data.symbols) {
2756
+ lines.push(formatSymbol(symbol));
2757
+ lines.push("");
2758
+ }
2759
+ return lines.join(`
2760
+ `).trimEnd();
2761
+ }
2762
+ async function codeListAction(packageArg, options, deps) {
2763
+ const { pkgseerService } = deps;
2764
+ const parsed = parsePackageSpec(packageArg);
2765
+ const registry = toGraphQLRegistry(parsed.registry);
2766
+ const scope = options.scope?.toUpperCase() ?? "EXPORTS";
2767
+ if (scope !== "EXPORTS" && scope !== "FILE") {
2768
+ outputError("--scope must be 'exports' or 'file'", options.json ?? false);
2769
+ return;
2770
+ }
2771
+ if (scope === "FILE" && !options.file) {
2772
+ outputError("--file is required when --scope is 'file'", options.json ?? false);
2773
+ return;
2774
+ }
2775
+ const result = await pkgseerService.listSymbols(registry, parsed.name, scope, {
2776
+ filePath: options.file,
2777
+ namespace: options.namespace,
2778
+ publicOnly: options.publicOnly,
2779
+ includePopularity: options.includePopularity,
2780
+ limit: parseIntOption(options.limit, "--limit"),
2781
+ version: parsed.version,
2782
+ mode: parseNavigationMode(options.mode),
2783
+ waitTimeoutMs: parseWaitTimeout(options.wait)
2784
+ });
2785
+ handleErrors(result.errors, options.json ?? false);
2786
+ if (!result.data.listSymbols) {
2787
+ outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
2788
+ return;
2789
+ }
2790
+ if (options.json) {
2791
+ output(result.data.listSymbols, true);
2792
+ } else {
2793
+ console.log(formatListResult(result.data.listSymbols));
2794
+ }
2795
+ }
2796
+ var LIST_DESCRIPTION = `Browse symbols in a package.
2797
+
2798
+ Lists public exports (default) or file contents. Returns symbol names,
2799
+ types, locations, and optionally popularity data.
2800
+
2801
+ Examples:
2802
+ pkgseer code list npm:express
2803
+ pkgseer code list npm:lodash --namespace array
2804
+ pkgseer code list npm:express --scope file --file src/router.js
2805
+ pkgseer code list pypi:requests --include-popularity`;
2806
+ function registerCodeListCommand(program) {
2807
+ program.command("list <package>").summary("Browse symbols in a package").description(LIST_DESCRIPTION).option("--scope <scope>", "Scope: exports (default) or file").option("--file <path>", "File path (required when scope=file)").option("--namespace <ns>", "Filter by namespace").option("--public-only", "Only show public symbols").option("--include-popularity", "Include popularity data").option("--limit <n>", "Max results").option("--mode <mode>", "Response detail: summary or detailed").option("--wait <ms>", "Max ms to wait for indexing (0-30000)").option("--json", "Output as JSON").action(async (packageArg, options) => {
2808
+ await withCliErrorHandling(options.json ?? false, async () => {
2809
+ const deps = await createContainer();
2810
+ await codeListAction(packageArg, options, deps);
2811
+ });
2812
+ });
2813
+ }
2814
+ // src/commands/code/path.ts
2815
+ function formatPathResult(data) {
2816
+ const lines = [];
2817
+ const fromName = data.fromSymbol.qualifiedPath ?? data.fromSymbol.name;
2818
+ const toName = data.toSymbol.qualifiedPath ?? data.toSymbol.name;
2819
+ lines.push(`Call path: ${fromName} -> ${toName}`);
2820
+ if (!data.pathFound) {
2821
+ lines.push("No path found between these symbols.");
2822
+ return lines.join(`
2823
+ `);
2824
+ }
2825
+ lines.push(`${data.paths.length} path(s) found`);
2826
+ lines.push("");
2827
+ for (const [i, callPath] of data.paths.entries()) {
2828
+ lines.push(`Path ${i + 1} (${callPath.length} hop${callPath.length !== 1 ? "s" : ""}):`);
2829
+ for (const [j, hop] of callPath.hops.entries()) {
2830
+ const name = hop.qualifiedPath ?? hop.name ?? "unknown";
2831
+ const loc = hop.filePath ? hop.callLine ? ` ${hop.filePath}:${hop.callLine}` : ` ${hop.filePath}` : "";
2832
+ const idPart = hop.symbolId ? ` (id:${hop.symbolId})` : "";
2833
+ const arrow = j < callPath.hops.length - 1 ? " ->" : "";
2834
+ lines.push(` ${j + 1}. ${name}${idPart}${loc}${arrow}`);
2835
+ }
2836
+ lines.push("");
2837
+ }
2838
+ return lines.join(`
2839
+ `).trimEnd();
2840
+ }
2841
+ async function codePathAction(fromArg, toArg, options, deps) {
2842
+ const { pkgseerService } = deps;
2843
+ const fromRef = buildSymbolReference(fromArg, options.fromId);
2844
+ const toRef = buildSymbolReference(toArg, options.toId);
2845
+ const result = await pkgseerService.callPath(fromRef, toRef, {
2846
+ maxDepth: parseIntOption(options.maxDepth, "--max-depth"),
2847
+ mode: parseNavigationMode(options.mode),
2848
+ waitTimeoutMs: parseWaitTimeout(options.wait)
2849
+ });
2850
+ handleErrors(result.errors, options.json ?? false);
2851
+ if (!result.data.callPath) {
2852
+ outputError("Could not find call path. Verify the symbol references.", options.json ?? false);
2853
+ return;
2854
+ }
2855
+ if (options.json) {
2856
+ output(result.data.callPath, true);
2857
+ } else {
2858
+ console.log(formatPathResult(result.data.callPath));
2859
+ }
2860
+ }
2861
+ var PATH_DESCRIPTION = `Find call path between two symbols.
2862
+
2863
+ Discovers the shortest call path from one symbol to another.
2864
+ Use registry:package#symbolName format or --from-id/--to-id for direct lookup.
2865
+
2866
+ Examples:
2867
+ pkgseer code path npm:express#app npm:express#Router
2868
+ pkgseer code path --from-id 123 --to-id 456
2869
+ pkgseer code path npm:lodash#merge npm:lodash#cloneDeep --max-depth 5`;
2870
+ function registerCodePathCommand(program) {
2871
+ program.command("path [from] [to]").summary("Find call path between symbols").description(PATH_DESCRIPTION).option("--from-id <id>", "Source symbol ID").option("--to-id <id>", "Target symbol ID").option("--max-depth <n>", "Max path depth").option("--mode <mode>", "Response detail: summary or detailed").option("--wait <ms>", "Max ms to wait for indexing (0-30000)").option("--json", "Output as JSON").action(async (fromArg, toArg, options) => {
2872
+ await withCliErrorHandling(options.json ?? false, async () => {
2873
+ const deps = await createContainer();
2874
+ await codePathAction(fromArg, toArg, options, deps);
2875
+ });
2876
+ });
2877
+ }
2878
+ // src/commands/code/search.ts
2879
+ function formatSearchResult(data) {
2880
+ const lines = [];
2881
+ lines.push(`${data.totalMatches} match(es)${data.hasMore ? " (more available)" : ""}`);
2882
+ if (data.indexedVersion) {
2883
+ lines.push(`Indexed version: ${data.indexedVersion}`);
2884
+ }
2885
+ lines.push("");
2886
+ for (const entry of data.results) {
2887
+ const kindLabel = entry.chunkType ? `[${entry.chunkType}]` : "";
2888
+ const name = entry.name ?? "unnamed";
2889
+ lines.push(`${kindLabel} ${name}`.trim());
2890
+ if (entry.filePath) {
2891
+ const loc = entry.startLine ? `${entry.filePath}:${entry.startLine}` : entry.filePath;
2892
+ lines.push(` File: ${loc}`);
2893
+ }
2894
+ if (entry.preview) {
2895
+ lines.push(` ${truncate(entry.preview, 200)}`);
2896
+ }
2897
+ lines.push("");
2898
+ }
2899
+ return lines.join(`
2900
+ `).trimEnd();
2901
+ }
2902
+ async function codeSearchAction(packageArg, query, options, deps) {
2903
+ const { pkgseerService } = deps;
2904
+ const parsed = parsePackageSpec(packageArg);
2905
+ const registry = toGraphQLRegistry(parsed.registry);
2906
+ const result = await pkgseerService.searchSymbols(registry, parsed.name, query, {
2907
+ kind: options.kind?.toUpperCase(),
2908
+ version: parsed.version,
2909
+ limit: parseIntOption(options.limit, "--limit"),
2910
+ mode: parseNavigationMode(options.mode),
2911
+ waitTimeoutMs: parseWaitTimeout(options.wait)
2912
+ });
2913
+ handleErrors(result.errors, options.json ?? false);
2914
+ if (!result.data.searchSymbols) {
2915
+ outputError(`Package not found: ${parsed.name} in ${parsed.registry}`, options.json ?? false);
2916
+ return;
2917
+ }
2918
+ if (options.json) {
2919
+ output(result.data.searchSymbols, true);
2920
+ } else {
2921
+ console.log(formatSearchResult(result.data.searchSymbols));
2922
+ }
2923
+ }
2924
+ var SEARCH_DESCRIPTION = `Full-text search within package code.
2925
+
2926
+ Searches across functions, classes, modules, and doc sections.
2927
+ Returns matching code chunks with names, types, and previews.
2928
+
2929
+ Examples:
2930
+ pkgseer code search npm:express "middleware"
2931
+ pkgseer code search pypi:requests "timeout" --kind function
2932
+ pkgseer code search npm:lodash "deep clone" --limit 10`;
2933
+ function registerCodeSearchCommand(program) {
2934
+ program.command("search <package> <query>").summary("Full-text search in package code").description(SEARCH_DESCRIPTION).option("--kind <kind>", "Filter by chunk type (function, class, module, etc.)").option("--limit <n>", "Max results (default: 25, max: 50)").option("--mode <mode>", "Response detail: summary or detailed").option("--wait <ms>", "Max ms to wait for indexing (0-30000)").option("--json", "Output as JSON").action(async (packageArg, query, options) => {
2935
+ await withCliErrorHandling(options.json ?? false, async () => {
2936
+ const deps = await createContainer();
2937
+ await codeSearchAction(packageArg, query, options, deps);
2938
+ });
2939
+ });
2940
+ }
2941
+ // src/commands/config-show.ts
2942
+ async function configShowAction(deps) {
2943
+ const { configService } = deps;
2944
+ const { config, globalPath, projectPath } = await configService.loadMergedConfig();
2945
+ if (!globalPath && !projectPath) {
2946
+ console.log(`No configuration found.
2947
+ `);
2948
+ console.log(" Global config: ~/.pkgseer/config.yml");
2949
+ console.log(` Project config: pkgseer.yml
2950
+ `);
2951
+ console.log("Create a config file to customize pkgseer behavior.");
2952
+ return;
2953
+ }
2954
+ console.log(`Configuration sources:
2955
+ `);
2956
+ if (globalPath) {
2957
+ console.log(` Global: ${globalPath}`);
2958
+ }
2959
+ if (projectPath) {
2960
+ console.log(` Project: ${projectPath}`);
2961
+ }
2962
+ console.log(`
2963
+ Merged configuration:
2964
+ `);
2965
+ if (config.enabled_tools !== undefined) {
2966
+ if (config.enabled_tools.length > 0) {
2967
+ console.log(" enabled_tools:");
2968
+ for (const tool of config.enabled_tools) {
2969
+ console.log(` - ${tool}`);
2970
+ }
2971
+ } else {
2972
+ console.log(" enabled_tools: [] (no tools enabled)");
2973
+ }
2974
+ } else {
2975
+ console.log(" enabled_tools: (all tools enabled by default)");
2976
+ }
2977
+ if (config.project) {
2978
+ console.log(` project: ${config.project}`);
2025
2979
  }
2026
2980
  }
2027
- function formatScore(score) {
2028
- if (score == null)
2029
- return "N/A";
2030
- const percentage = score > 1 ? Math.round(score) : Math.round(score * 100);
2031
- const filled = Math.round(percentage / 5);
2032
- const bar = "█".repeat(Math.min(filled, 20)) + "░".repeat(Math.max(20 - filled, 0));
2033
- return `${bar} ${percentage}%`;
2981
+ var SHOW_DESCRIPTION = `Display current configuration.
2982
+
2983
+ Shows the merged configuration from global (~/.pkgseer/config.yml) and
2984
+ project (pkgseer.yml) config files. Project config takes precedence
2985
+ over global config for overlapping settings.`;
2986
+ function registerConfigShowCommand(program) {
2987
+ program.command("show").summary("Display current configuration").description(SHOW_DESCRIPTION).action(async () => {
2988
+ const deps = await createContainer();
2989
+ await configShowAction(deps);
2990
+ });
2034
2991
  }
2035
2992
 
2036
2993
  // src/commands/docs/get.ts
@@ -2401,7 +3358,7 @@ async function docsListAction(packageArg, options, deps) {
2401
3358
  console.log(formatDocsList(result.data.listPackageDocs));
2402
3359
  }
2403
3360
  }
2404
- var LIST_DESCRIPTION = `List available documentation pages for a package.
3361
+ var LIST_DESCRIPTION2 = `List available documentation pages for a package.
2405
3362
 
2406
3363
  Shows all documentation pages with titles, globally unique page IDs,
2407
3364
  word counts, and descriptions. Use the page ID with 'docs get'
@@ -2414,7 +3371,7 @@ Examples:
2414
3371
  pkgseer docs list pypi:requests
2415
3372
  pkgseer docs list hex:phoenix@1.7.0 --json`;
2416
3373
  function registerDocsListCommand(program) {
2417
- 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) => {
3374
+ program.command("list <package>").summary("List documentation pages").description(LIST_DESCRIPTION2).option("-r, --registry <registry>", "Package registry", "npm").option("-V, --pkg-version <version>", "Package version").option("--json", "Output as JSON").action(async (packageName, options) => {
2418
3375
  await withCliErrorHandling(options.json ?? false, async () => {
2419
3376
  const deps = await createContainer();
2420
3377
  await docsListAction(packageName, options, deps);
@@ -2689,7 +3646,7 @@ function abbrevLang(lang) {
2689
3646
  const lower = lang.toLowerCase();
2690
3647
  return LANG_ABBREV[lower] ?? lower;
2691
3648
  }
2692
- function truncate(text, maxLen) {
3649
+ function truncate2(text, maxLen) {
2693
3650
  if (text.length <= maxLen)
2694
3651
  return text;
2695
3652
  return `${text.slice(0, maxLen - 3)}...`;
@@ -2743,9 +3700,9 @@ function formatEntryCompact(entry, useColors) {
2743
3700
  if (entry.snippet) {
2744
3701
  const bestLine = findBestSnippetLine(entry.snippet);
2745
3702
  if (bestLine) {
2746
- snippet = ` ${truncate(bestLine, 80)}`;
3703
+ snippet = ` ${truncate2(bestLine, 80)}`;
2747
3704
  if (useColors) {
2748
- snippet = ` ${colors.dim}${truncate(bestLine, 80)}${colors.reset}`;
3705
+ snippet = ` ${colors.dim}${truncate2(bestLine, 80)}${colors.reset}`;
2749
3706
  }
2750
3707
  }
2751
3708
  }
@@ -3071,7 +4028,7 @@ function outputResults(results, options, useColors) {
3071
4028
  console.log(formatSearchResultsCompact(results, useColors));
3072
4029
  }
3073
4030
  }
3074
- var SEARCH_DESCRIPTION = `Search code and documentation across packages.
4031
+ var SEARCH_DESCRIPTION2 = `Search code and documentation across packages.
3075
4032
 
3076
4033
  Searches both code (functions, classes) and documentation pages
3077
4034
  using the combined search endpoint. Returns results with snippets
@@ -3107,7 +4064,7 @@ function addSearchOptions(cmd) {
3107
4064
  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").option("--wait <ms>", "Max milliseconds to wait for indexing (default: 30000)").option("--no-wait", "Return immediately without waiting for indexing").option("--resume <ref>", "Resume a previous search by reference").option("--no-poll", "Disable auto-polling for incomplete searches");
3108
4065
  }
3109
4066
  function registerSearchCommand(program) {
3110
- const cmd = program.command("search [query...]").summary("Search code and documentation across packages").description(SEARCH_DESCRIPTION);
4067
+ const cmd = program.command("search [query...]").summary("Search code and documentation across packages").description(SEARCH_DESCRIPTION2);
3111
4068
  addSearchOptions(cmd).action(async (query, options) => {
3112
4069
  await withCliErrorHandling(options.json ?? false, async () => {
3113
4070
  const deps = await createContainer();
@@ -3156,6 +4113,70 @@ function registerDocsSearchCommand(program) {
3156
4113
  });
3157
4114
  });
3158
4115
  }
4116
+ // src/commands/index-cmd.ts
4117
+ async function indexAction(packages, options, deps) {
4118
+ const { pkgseerService } = deps;
4119
+ const input2 = {};
4120
+ if (packages.length > 0) {
4121
+ input2.packages = packages.map((spec) => {
4122
+ const parsed = parsePackageSpec(spec);
4123
+ return {
4124
+ registry: toGraphQLRegistry(parsed.registry),
4125
+ name: parsed.name,
4126
+ version: parsed.version
4127
+ };
4128
+ });
4129
+ }
4130
+ if (options.repo && options.repo.length > 0) {
4131
+ input2.repositories = options.repo.map((url) => ({
4132
+ url,
4133
+ ref: options.ref,
4134
+ discoverPackages: options.discoverPackages
4135
+ }));
4136
+ }
4137
+ if (!input2.packages?.length && !input2.repositories?.length) {
4138
+ console.error("Error: Provide at least one package or --repo URL.");
4139
+ process.exit(1);
4140
+ }
4141
+ const result = await pkgseerService.triggerIndexing(input2);
4142
+ handleErrors(result.errors, options.json ?? false);
4143
+ const data = result.data.triggerIndexing;
4144
+ if (options.json) {
4145
+ output(data, true);
4146
+ } else {
4147
+ if (data) {
4148
+ console.log(`Accepted: ${data.accepted}`);
4149
+ console.log(`Skipped: ${data.skipped}`);
4150
+ } else {
4151
+ console.log("Indexing request submitted.");
4152
+ }
4153
+ }
4154
+ }
4155
+ var INDEX_DESCRIPTION = `Trigger pre-indexing for packages or repositories.
4156
+
4157
+ Requests that PkgSeer index the specified packages or repositories.
4158
+ Useful for warming up indexes before code navigation queries.
4159
+
4160
+ Package specs support registry:name@version format.
4161
+ Repository URLs should be GitHub repository URLs.
4162
+
4163
+ Examples:
4164
+ pkgseer index npm:express npm:lodash
4165
+ pkgseer index pypi:requests@2.31.0
4166
+ pkgseer index --repo https://github.com/expressjs/express
4167
+ pkgseer index --repo https://github.com/org/repo --ref v1.0.0 --discover-packages`;
4168
+ function registerIndexCommand(program) {
4169
+ program.command("index [packages...]").summary("Trigger pre-indexing for packages or repositories").description(INDEX_DESCRIPTION).option("--repo <url>", "Repository URL to index (repeatable)", collectValues, []).option("--ref <ref>", "Git ref for repository indexing").option("--discover-packages", "Discover and index packages in repository").option("--json", "Output as JSON").action(async (packages, options) => {
4170
+ await withCliErrorHandling(options.json ?? false, async () => {
4171
+ const deps = await createContainer();
4172
+ await indexAction(packages, options, deps);
4173
+ });
4174
+ });
4175
+ }
4176
+ function collectValues(value, previous) {
4177
+ return [...previous, value];
4178
+ }
4179
+
3159
4180
  // src/commands/shared-colors.ts
3160
4181
  var colors2 = {
3161
4182
  reset: "\x1B[0m",
@@ -4927,7 +5948,7 @@ function registerLogoutCommand(program) {
4927
5948
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4928
5949
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4929
5950
 
4930
- // src/tools/compare-packages.ts
5951
+ // src/tools/call-path.ts
4931
5952
  import { z as z3 } from "zod";
4932
5953
 
4933
5954
  // src/tools/shared.ts
@@ -4952,15 +5973,68 @@ function toGraphQLRegistry2(registry) {
4952
5973
  npm: "NPM",
4953
5974
  pypi: "PYPI",
4954
5975
  hex: "HEX",
4955
- crates: "CRATES"
5976
+ crates: "CRATES",
5977
+ nuget: "NUGET",
5978
+ maven: "MAVEN",
5979
+ zig: "ZIG",
5980
+ vcpkg: "VCPKG"
4956
5981
  };
4957
5982
  return map[registry.toLowerCase()] || "NPM";
4958
5983
  }
5984
+ function toNavigationMode(mode) {
5985
+ if (!mode)
5986
+ return;
5987
+ const upper = mode.toUpperCase();
5988
+ if (upper === "SUMMARY" || upper === "DETAILED")
5989
+ return upper;
5990
+ return;
5991
+ }
5992
+ var VALID_SYMBOL_KINDS = new Set([
5993
+ "FUNCTION",
5994
+ "METHOD",
5995
+ "CLASS",
5996
+ "MODULE",
5997
+ "INTERFACE",
5998
+ "TYPE",
5999
+ "DOC_SECTION"
6000
+ ]);
6001
+ function toSymbolKind(kind) {
6002
+ if (!kind)
6003
+ return;
6004
+ const upper = kind.toUpperCase();
6005
+ if (VALID_SYMBOL_KINDS.has(upper))
6006
+ return upper;
6007
+ return;
6008
+ }
6009
+ function toListScope(scope) {
6010
+ if (!scope)
6011
+ return;
6012
+ const upper = scope.toUpperCase();
6013
+ if (upper === "EXPORTS" || upper === "FILE")
6014
+ return upper;
6015
+ return;
6016
+ }
4959
6017
  var schemas = {
4960
- registry: z2.enum(["npm", "pypi", "hex", "crates"]).describe("Package registry (npm, pypi, hex, or crates)"),
6018
+ registry: z2.enum(["npm", "pypi", "hex", "crates", "nuget", "maven", "zig", "vcpkg"]).describe("Package registry (npm, pypi, hex, crates, nuget, maven, zig, or vcpkg)"),
4961
6019
  packageName: z2.string().max(255).describe("Name of the package"),
4962
- version: z2.string().max(100).optional().describe("Specific version (defaults to latest)")
6020
+ version: z2.string().max(100).optional().describe("Specific version (defaults to latest)"),
6021
+ navigationMode: z2.enum(["summary", "detailed"]).optional().describe("Response detail level. summary (default) returns core fields; detailed adds all optional fields."),
6022
+ waitTimeoutMs: z2.number().int().min(0).max(30000).optional().describe("Max milliseconds to wait for package indexing (0-30000). 0 = error immediately if not indexed."),
6023
+ symbolReference: z2.object({
6024
+ symbol_id: z2.number().int().optional().describe("Direct symbol ID (preferred when available)"),
6025
+ registry: z2.enum(["npm", "pypi", "hex", "crates", "nuget", "maven", "zig", "vcpkg"]).optional().describe("Package registry (required for name-based lookup)"),
6026
+ package_name: z2.string().max(255).optional().describe("Package name (required for name-based lookup)"),
6027
+ symbol_name: z2.string().max(500).optional().describe("Symbol name or qualified path (required for name-based lookup). Matches both short name and qualifiedPath.")
6028
+ })
4963
6029
  };
6030
+ function toSymbolReferenceInput(ref) {
6031
+ return {
6032
+ symbolId: ref.symbol_id,
6033
+ registry: ref.registry ? toGraphQLRegistry2(ref.registry) : undefined,
6034
+ packageName: ref.package_name,
6035
+ symbolName: ref.symbol_name
6036
+ };
6037
+ }
4964
6038
  function buildHintedMessage(operation, message) {
4965
6039
  const lower = message.toLowerCase();
4966
6040
  const isTimeout = lower.includes("-32001") || lower.includes("timeout") || lower.includes("timed out");
@@ -4998,20 +6072,60 @@ function notFoundError(packageName, registry) {
4998
6072
  return errorResult(`Package not found: ${packageName} in ${registry}`);
4999
6073
  }
5000
6074
 
6075
+ // src/tools/call-path.ts
6076
+ var argsSchema = {
6077
+ from: schemas.symbolReference.describe("Source symbol. Provide either symbol_id or registry + package_name + symbol_name."),
6078
+ to: schemas.symbolReference.describe("Destination symbol. Provide either symbol_id or registry + package_name + symbol_name."),
6079
+ max_depth: z3.number().int().min(1).max(10).optional().describe("Maximum path length to search (max hops between from and to)"),
6080
+ mode: schemas.navigationMode,
6081
+ wait_timeout_ms: schemas.waitTimeoutMs
6082
+ };
6083
+ function createCallPathTool(pkgseerService) {
6084
+ return {
6085
+ name: "call_path",
6086
+ description: "Find the shortest call path between two symbols in the same package. " + "Uses BFS to find how function A eventually calls function B through intermediate calls. " + "Returns: whether a path was found, source and destination symbols, " + "and ordered call paths (shortest first) with hop details.",
6087
+ schema: argsSchema,
6088
+ handler: async (args, _extra) => {
6089
+ return withErrorHandling("find call path", async () => {
6090
+ const fromInput = toSymbolReferenceInput(args.from);
6091
+ const toInput = toSymbolReferenceInput(args.to);
6092
+ if (!fromInput.symbolId && (!fromInput.symbolName || !fromInput.registry || !fromInput.packageName)) {
6093
+ return errorResult("Invalid 'from' symbol: provide either symbol_id or symbol_name with registry and package_name.");
6094
+ }
6095
+ if (!toInput.symbolId && (!toInput.symbolName || !toInput.registry || !toInput.packageName)) {
6096
+ return errorResult("Invalid 'to' symbol: provide either symbol_id or symbol_name with registry and package_name.");
6097
+ }
6098
+ const result = await pkgseerService.callPath(fromInput, toInput, {
6099
+ maxDepth: args.max_depth,
6100
+ mode: toNavigationMode(args.mode),
6101
+ waitTimeoutMs: args.wait_timeout_ms
6102
+ });
6103
+ const graphqlError = handleGraphQLErrors(result.errors);
6104
+ if (graphqlError)
6105
+ return graphqlError;
6106
+ if (!result.data.callPath) {
6107
+ return errorResult("Could not find call path. Verify the symbols exist and the package is indexed.");
6108
+ }
6109
+ return textResult(JSON.stringify(result.data.callPath, null, 2));
6110
+ });
6111
+ }
6112
+ };
6113
+ }
5001
6114
  // src/tools/compare-packages.ts
5002
- var packageInputSchema = z3.object({
5003
- registry: z3.enum(["npm", "pypi", "hex", "crates"]),
5004
- name: z3.string().max(255),
5005
- version: z3.string().max(100).optional()
6115
+ import { z as z4 } from "zod";
6116
+ var packageInputSchema = z4.object({
6117
+ registry: z4.enum(["npm", "pypi", "hex", "crates"]),
6118
+ name: z4.string().max(255),
6119
+ version: z4.string().max(100).optional()
5006
6120
  });
5007
- var argsSchema = {
5008
- packages: z3.array(packageInputSchema).min(2).max(10).describe("List of packages to compare (2-10 packages)")
6121
+ var argsSchema2 = {
6122
+ packages: z4.array(packageInputSchema).min(2).max(10).describe("List of packages to compare (2-10 packages)")
5009
6123
  };
5010
6124
  function createComparePackagesTool(pkgseerService) {
5011
6125
  return {
5012
6126
  name: "compare_packages",
5013
6127
  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"}]',
5014
- schema: argsSchema,
6128
+ schema: argsSchema2,
5015
6129
  handler: async ({ packages }, _extra) => {
5016
6130
  return withErrorHandling("compare packages", async () => {
5017
6131
  const input2 = packages.map((pkg) => ({
@@ -5032,19 +6146,19 @@ function createComparePackagesTool(pkgseerService) {
5032
6146
  };
5033
6147
  }
5034
6148
  // src/tools/fetch-code-context.ts
5035
- import { z as z4 } from "zod";
5036
- var argsSchema2 = {
5037
- repo_url: z4.string().min(1).describe("Repository URL (GitHub). Example: https://github.com/expressjs/express"),
5038
- git_ref: z4.string().min(1).describe("Git reference (tag, commit, or branch). Example: v4.18.2"),
5039
- file_path: z4.string().min(1).describe("Path to file in repository. Example: src/router/index.js"),
5040
- start_line: z4.number().int().positive().optional().describe("Starting line (1-indexed). If omitted, starts from line 1."),
5041
- end_line: z4.number().int().positive().optional().describe("Ending line. If omitted, returns to end of file.")
6149
+ import { z as z5 } from "zod";
6150
+ var argsSchema3 = {
6151
+ repo_url: z5.string().min(1).describe("Repository URL (GitHub). Example: https://github.com/expressjs/express"),
6152
+ git_ref: z5.string().min(1).describe("Git reference (tag, commit, or branch). Example: v4.18.2"),
6153
+ file_path: z5.string().min(1).describe("Path to file in repository. Example: src/router/index.js"),
6154
+ start_line: z5.number().int().positive().optional().describe("Starting line (1-indexed). If omitted, starts from line 1."),
6155
+ end_line: z5.number().int().positive().optional().describe("Ending line. If omitted, returns to end of file.")
5042
6156
  };
5043
6157
  function createFetchCodeContextTool(pkgseerService) {
5044
6158
  return {
5045
6159
  name: "fetch_code_context",
5046
6160
  description: "Fetch code content from a repository. Use this to expand code search results and see " + "more context around a match. Returns full file by default, or a specific line range. " + "Requires repo_url, git_ref (tag/commit/branch), and file_path from search results.",
5047
- schema: argsSchema2,
6161
+ schema: argsSchema3,
5048
6162
  handler: async ({ repo_url, git_ref, file_path, start_line, end_line }, _extra) => {
5049
6163
  return withErrorHandling("fetch code context", async () => {
5050
6164
  const result = await pkgseerService.fetchCodeContext(repo_url, git_ref, file_path, {
@@ -5063,15 +6177,15 @@ function createFetchCodeContextTool(pkgseerService) {
5063
6177
  };
5064
6178
  }
5065
6179
  // src/tools/fetch-package-doc.ts
5066
- import { z as z5 } from "zod";
5067
- var argsSchema3 = {
5068
- page_id: z5.string().max(500).describe("Globally unique documentation page identifier (from list_package_docs)")
6180
+ import { z as z6 } from "zod";
6181
+ var argsSchema4 = {
6182
+ page_id: z6.string().max(500).describe("Globally unique documentation page identifier (from list_package_docs)")
5069
6183
  };
5070
6184
  function createFetchPackageDocTool(pkgseerService) {
5071
6185
  return {
5072
6186
  name: "fetch_package_doc",
5073
6187
  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.",
5074
- schema: argsSchema3,
6188
+ schema: argsSchema4,
5075
6189
  handler: async ({ page_id }, _extra) => {
5076
6190
  return withErrorHandling("fetch documentation page", async () => {
5077
6191
  const result = await pkgseerService.getDocPage(page_id);
@@ -5086,8 +6200,60 @@ function createFetchPackageDocTool(pkgseerService) {
5086
6200
  }
5087
6201
  };
5088
6202
  }
6203
+ // src/tools/find-symbol.ts
6204
+ import { z as z7 } from "zod";
6205
+ var argsSchema5 = {
6206
+ registry: schemas.registry,
6207
+ package_name: schemas.packageName.describe("Name of the package to search for symbols"),
6208
+ name: z7.string().max(500).optional().describe("Symbol name to search for (exact match or prefix). Omit to return all public exports."),
6209
+ namespace: z7.string().max(500).optional().describe("Filter by namespace/module path prefix"),
6210
+ kind: z7.enum([
6211
+ "function",
6212
+ "method",
6213
+ "class",
6214
+ "module",
6215
+ "interface",
6216
+ "type",
6217
+ "doc_section"
6218
+ ]).optional().describe("Filter by symbol kind"),
6219
+ public_only: z7.boolean().optional().describe("Only return public/exported symbols"),
6220
+ version: schemas.version,
6221
+ include_code: z7.boolean().optional().describe("Include source code in results"),
6222
+ context_lines: z7.number().int().min(0).max(30).optional().describe("Lines of surrounding context when include_code=true (max 30)"),
6223
+ mode: schemas.navigationMode,
6224
+ wait_timeout_ms: schemas.waitTimeoutMs
6225
+ };
6226
+ function createFindSymbolTool(pkgseerService) {
6227
+ return {
6228
+ name: "find_symbol",
6229
+ description: "Find functions, methods, or classes by name in a package. " + "Use for targeted lookups when you know the symbol name. " + "Returns: symbol ID, name, qualified path, kind, file location, and optionally source code. " + "Omit name to get all public exports. Use namespace to filter by module path.",
6230
+ schema: argsSchema5,
6231
+ handler: async (args, _extra) => {
6232
+ return withErrorHandling("find symbol", async () => {
6233
+ const result = await pkgseerService.findSymbol(toGraphQLRegistry2(args.registry), args.package_name, {
6234
+ name: args.name,
6235
+ namespace: args.namespace,
6236
+ kind: toSymbolKind(args.kind),
6237
+ publicOnly: args.public_only,
6238
+ version: args.version,
6239
+ includeCode: args.include_code,
6240
+ contextLines: args.context_lines,
6241
+ mode: toNavigationMode(args.mode),
6242
+ waitTimeoutMs: args.wait_timeout_ms
6243
+ });
6244
+ const graphqlError = handleGraphQLErrors(result.errors);
6245
+ if (graphqlError)
6246
+ return graphqlError;
6247
+ if (!result.data.findSymbol) {
6248
+ return notFoundError(args.package_name, args.registry);
6249
+ }
6250
+ return textResult(JSON.stringify(result.data.findSymbol, null, 2));
6251
+ });
6252
+ }
6253
+ };
6254
+ }
5089
6255
  // src/tools/list-package-docs.ts
5090
- var argsSchema4 = {
6256
+ var argsSchema6 = {
5091
6257
  registry: schemas.registry,
5092
6258
  package_name: schemas.packageName.describe("Name of the package to list documentation for"),
5093
6259
  version: schemas.version
@@ -5096,7 +6262,7 @@ function createListPackageDocsTool(pkgseerService) {
5096
6262
  return {
5097
6263
  name: "list_package_docs",
5098
6264
  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.",
5099
- schema: argsSchema4,
6265
+ schema: argsSchema6,
5100
6266
  handler: async ({ registry, package_name, version: version2 }, _extra) => {
5101
6267
  return withErrorHandling("list package documentation", async () => {
5102
6268
  const result = await pkgseerService.listPackageDocs(toGraphQLRegistry2(registry), package_name, version2);
@@ -5111,14 +6277,69 @@ function createListPackageDocsTool(pkgseerService) {
5111
6277
  }
5112
6278
  };
5113
6279
  }
6280
+ // src/tools/list-symbols.ts
6281
+ import { z as z8 } from "zod";
6282
+ var argsSchema7 = {
6283
+ registry: schemas.registry,
6284
+ package_name: schemas.packageName.describe("Name of the package to browse symbols for"),
6285
+ scope: z8.enum(["exports", "file"]).describe("Browsing scope: 'exports' for public API, 'file' for all symbols in a specific file"),
6286
+ file_path: z8.string().max(1000).optional().describe("File path within the repo (required when scope=file)"),
6287
+ namespace: z8.string().max(500).optional().describe("Filter by namespace prefix (e.g., 'React' to see React.*)"),
6288
+ public_only: z8.boolean().optional().describe("Only return public symbols"),
6289
+ include_popularity: z8.boolean().optional().describe("Include callerCount for each symbol (slightly slower)"),
6290
+ limit: z8.number().int().min(1).max(100).optional().describe("Max symbols to return (max 100)"),
6291
+ version: schemas.version,
6292
+ mode: schemas.navigationMode,
6293
+ wait_timeout_ms: schemas.waitTimeoutMs
6294
+ };
6295
+ function createListSymbolsTool(pkgseerService) {
6296
+ return {
6297
+ name: "list_symbols",
6298
+ description: "Browse symbols in a package by scope. " + "Use scope='exports' for public API exploration with namespace grouping and optional popularity data. " + "Use scope='file' with file_path to see all symbols in a specific file. " + "Returns: symbols with IDs, names, qualified paths, kinds, and file locations.",
6299
+ schema: argsSchema7,
6300
+ handler: async (args, _extra) => {
6301
+ return withErrorHandling("list symbols", async () => {
6302
+ const scope = toListScope(args.scope);
6303
+ if (!scope) {
6304
+ return {
6305
+ content: [
6306
+ {
6307
+ type: "text",
6308
+ text: "Invalid scope. Use 'exports' or 'file'."
6309
+ }
6310
+ ],
6311
+ isError: true
6312
+ };
6313
+ }
6314
+ const result = await pkgseerService.listSymbols(toGraphQLRegistry2(args.registry), args.package_name, scope, {
6315
+ filePath: args.file_path,
6316
+ namespace: args.namespace,
6317
+ publicOnly: args.public_only,
6318
+ includePopularity: args.include_popularity,
6319
+ limit: args.limit,
6320
+ version: args.version,
6321
+ mode: toNavigationMode(args.mode),
6322
+ waitTimeoutMs: args.wait_timeout_ms
6323
+ });
6324
+ const graphqlError = handleGraphQLErrors(result.errors);
6325
+ if (graphqlError)
6326
+ return graphqlError;
6327
+ if (!result.data.listSymbols) {
6328
+ return notFoundError(args.package_name, args.registry);
6329
+ }
6330
+ return textResult(JSON.stringify(result.data.listSymbols, null, 2));
6331
+ });
6332
+ }
6333
+ };
6334
+ }
5114
6335
  // src/tools/package-dependencies.ts
5115
- import { z as z6 } from "zod";
5116
- var argsSchema5 = {
6336
+ import { z as z9 } from "zod";
6337
+ var argsSchema8 = {
5117
6338
  registry: schemas.registry,
5118
6339
  package_name: schemas.packageName.describe("Name of the package to retrieve dependencies for"),
5119
6340
  version: schemas.version,
5120
- include_transitive: z6.boolean().optional().describe("Whether to include transitive dependency DAG"),
5121
- max_depth: z6.number().int().min(1).max(10).optional().describe("Maximum depth for transitive traversal (1-10)")
6341
+ include_transitive: z9.boolean().optional().describe("Whether to include transitive dependency DAG"),
6342
+ max_depth: z9.number().int().min(1).max(10).optional().describe("Maximum depth for transitive traversal (1-10)")
5122
6343
  };
5123
6344
  function decodeDag(rawDag) {
5124
6345
  if (!rawDag || typeof rawDag !== "object")
@@ -5196,7 +6417,7 @@ function createPackageDependenciesTool(pkgseerService) {
5196
6417
  return {
5197
6418
  name: "package_dependencies",
5198
6419
  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.",
5199
- schema: argsSchema5,
6420
+ schema: argsSchema8,
5200
6421
  handler: async ({ registry, package_name, version: version2, include_transitive, max_depth }, _extra) => {
5201
6422
  return withErrorHandling("fetch package dependencies", async () => {
5202
6423
  const result = await pkgseerService.getPackageDependencies(toGraphQLRegistry2(registry), package_name, version2, include_transitive, max_depth);
@@ -5233,8 +6454,46 @@ function createPackageDependenciesTool(pkgseerService) {
5233
6454
  }
5234
6455
  };
5235
6456
  }
6457
+ // src/tools/package-imports.ts
6458
+ import { z as z10 } from "zod";
6459
+ var argsSchema9 = {
6460
+ registry: schemas.registry,
6461
+ package_name: schemas.packageName.describe("Name of the package to get imports for"),
6462
+ file_path: z10.string().max(1000).optional().describe("Filter to a specific file path"),
6463
+ resolved_only: z10.boolean().optional().describe("Only return imports resolved to a known package"),
6464
+ limit: z10.number().int().min(1).max(500).optional().describe("Max imports to return"),
6465
+ version: schemas.version,
6466
+ mode: schemas.navigationMode,
6467
+ wait_timeout_ms: schemas.waitTimeoutMs
6468
+ };
6469
+ function createPackageImportsTool(pkgseerService) {
6470
+ return {
6471
+ name: "package_imports",
6472
+ 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.",
6473
+ schema: argsSchema9,
6474
+ handler: async (args, _extra) => {
6475
+ return withErrorHandling("fetch package imports", async () => {
6476
+ const result = await pkgseerService.packageImports(toGraphQLRegistry2(args.registry), args.package_name, {
6477
+ filePath: args.file_path,
6478
+ resolvedOnly: args.resolved_only,
6479
+ limit: args.limit,
6480
+ version: args.version,
6481
+ mode: toNavigationMode(args.mode),
6482
+ waitTimeoutMs: args.wait_timeout_ms
6483
+ });
6484
+ const graphqlError = handleGraphQLErrors(result.errors);
6485
+ if (graphqlError)
6486
+ return graphqlError;
6487
+ if (!result.data.packageImports) {
6488
+ return notFoundError(args.package_name, args.registry);
6489
+ }
6490
+ return textResult(JSON.stringify(result.data.packageImports, null, 2));
6491
+ });
6492
+ }
6493
+ };
6494
+ }
5236
6495
  // src/tools/package-quality.ts
5237
- var argsSchema6 = {
6496
+ var argsSchema10 = {
5238
6497
  registry: schemas.registry,
5239
6498
  package_name: schemas.packageName.describe("Name of the package to analyze"),
5240
6499
  version: schemas.version
@@ -5243,7 +6502,7 @@ function createPackageQualityTool(pkgseerService) {
5243
6502
  return {
5244
6503
  name: "package_quality",
5245
6504
  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.",
5246
- schema: argsSchema6,
6505
+ schema: argsSchema10,
5247
6506
  handler: async ({ registry, package_name, version: version2 }, _extra) => {
5248
6507
  return withErrorHandling("fetch package quality", async () => {
5249
6508
  const result = await pkgseerService.getPackageQuality(toGraphQLRegistry2(registry), package_name, version2);
@@ -5259,7 +6518,7 @@ function createPackageQualityTool(pkgseerService) {
5259
6518
  };
5260
6519
  }
5261
6520
  // src/tools/package-summary.ts
5262
- var argsSchema7 = {
6521
+ var argsSchema11 = {
5263
6522
  registry: schemas.registry,
5264
6523
  package_name: schemas.packageName.describe("Name of the package to retrieve summary for")
5265
6524
  };
@@ -5267,7 +6526,7 @@ function createPackageSummaryTool(pkgseerService) {
5267
6526
  return {
5268
6527
  name: "package_summary",
5269
6528
  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).",
5270
- schema: argsSchema7,
6529
+ schema: argsSchema11,
5271
6530
  handler: async ({ registry, package_name }, _extra) => {
5272
6531
  return withErrorHandling("fetch package summary", async () => {
5273
6532
  const result = await pkgseerService.getPackageSummary(toGraphQLRegistry2(registry), package_name);
@@ -5283,7 +6542,7 @@ function createPackageSummaryTool(pkgseerService) {
5283
6542
  };
5284
6543
  }
5285
6544
  // src/tools/package-vulnerabilities.ts
5286
- var argsSchema8 = {
6545
+ var argsSchema12 = {
5287
6546
  registry: schemas.registry,
5288
6547
  package_name: schemas.packageName.describe("Name of the package to inspect for vulnerabilities"),
5289
6548
  version: schemas.version
@@ -5292,7 +6551,7 @@ function createPackageVulnerabilitiesTool(pkgseerService) {
5292
6551
  return {
5293
6552
  name: "package_vulnerabilities",
5294
6553
  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.",
5295
- schema: argsSchema8,
6554
+ schema: argsSchema12,
5296
6555
  handler: async ({ registry, package_name, version: version2 }, _extra) => {
5297
6556
  return withErrorHandling("fetch package vulnerabilities", async () => {
5298
6557
  const result = await pkgseerService.getPackageVulnerabilities(toGraphQLRegistry2(registry), package_name, version2);
@@ -5308,19 +6567,19 @@ function createPackageVulnerabilitiesTool(pkgseerService) {
5308
6567
  };
5309
6568
  }
5310
6569
  // src/tools/search.ts
5311
- import { z as z7 } from "zod";
5312
- var packageInputSchema2 = z7.object({
6570
+ import { z as z11 } from "zod";
6571
+ var packageInputSchema2 = z11.object({
5313
6572
  registry: schemas.registry,
5314
- name: z7.string().min(1).describe("Package name"),
5315
- version: z7.string().optional().describe("Specific version (defaults to latest)")
6573
+ name: z11.string().min(1).describe("Package name"),
6574
+ version: z11.string().optional().describe("Specific version (defaults to latest)")
5316
6575
  });
5317
6576
  var DEFAULT_AGENT_WAIT_TIMEOUT_MS = 1e4;
5318
- var argsSchema9 = {
5319
- packages: z7.array(packageInputSchema2).min(1).max(20).describe("Packages to search (1-20). Each package needs registry and name."),
5320
- query: z7.string().min(1).describe("Search query - natural language or keywords"),
5321
- mode: z7.enum(["all", "code", "docs"]).optional().describe('Search mode: "all" (default), "code" only, or "docs" only'),
5322
- limit: z7.number().int().min(1).max(100).optional().describe("Maximum results (default: 20)"),
5323
- waitTimeoutMs: z7.number().int().min(0).max(60000).optional().describe("Max milliseconds to wait for indexing (default: 10000, 0=immediate)")
6577
+ var argsSchema13 = {
6578
+ packages: z11.array(packageInputSchema2).min(1).max(20).describe("Packages to search (1-20). Each package needs registry and name."),
6579
+ query: z11.string().min(1).describe("Search query - natural language or keywords"),
6580
+ mode: z11.enum(["all", "code", "docs"]).optional().describe('Search mode: "all" (default), "code" only, or "docs" only'),
6581
+ limit: z11.number().int().min(1).max(100).optional().describe("Maximum results (default: 20)"),
6582
+ waitTimeoutMs: z11.number().int().min(0).max(60000).optional().describe("Max milliseconds to wait for indexing (default: 10000, 0=immediate)")
5324
6583
  };
5325
6584
  function toSearchMode2(mode) {
5326
6585
  if (!mode)
@@ -5359,7 +6618,7 @@ function createSearchTool(pkgseerService) {
5359
6618
  return {
5360
6619
  name: "search",
5361
6620
  description: "Search code and documentation across packages. Returns functions, classes, and documentation pages " + "matching your query. Use mode='code' for code only, mode='docs' for documentation only, or " + "mode='all' (default) for both. Provide 1-20 packages to search. Results include relevance scores " + "and snippets showing matches. If packages need indexing, the search will wait up to waitTimeoutMs " + "(default 10s). If not complete, returns progress info with searchRef for follow-up.",
5362
- schema: argsSchema9,
6621
+ schema: argsSchema13,
5363
6622
  handler: async ({ packages, query, mode, limit, waitTimeoutMs }, _extra) => {
5364
6623
  return withErrorHandling("search packages", async () => {
5365
6624
  const normalizedQuery = query.trim();
@@ -5411,21 +6670,21 @@ function createSearchTool(pkgseerService) {
5411
6670
  };
5412
6671
  }
5413
6672
  // src/tools/search-project-docs.ts
5414
- import { z as z8 } from "zod";
5415
- var argsSchema10 = {
5416
- project_directory: z8.string().optional().describe("Directory to search for pkgseer.yml configuration. " + "Use this to specify which project's context to use when the MCP server " + "is installed at user level. Defaults to MCP server's working directory."),
5417
- project: z8.string().optional().describe("Project name to search. Overrides value from pkgseer.yml if provided."),
5418
- terms: z8.array(z8.string()).optional().describe("Search terms to match. Provide a few key words or phrases that should appear in results."),
5419
- match_mode: z8.enum(["any", "or", "all", "and"]).optional().describe('How to combine terms: "any" (OR) or "all" (AND).'),
5420
- include_snippets: z8.boolean().optional().describe("Include content excerpts around matches"),
5421
- limit: z8.number().int().min(1).max(100).optional().describe("Maximum number of results to return")
6673
+ import { z as z12 } from "zod";
6674
+ var argsSchema14 = {
6675
+ project_directory: z12.string().optional().describe("Directory to search for pkgseer.yml configuration. " + "Use this to specify which project's context to use when the MCP server " + "is installed at user level. Defaults to MCP server's working directory."),
6676
+ project: z12.string().optional().describe("Project name to search. Overrides value from pkgseer.yml if provided."),
6677
+ terms: z12.array(z12.string()).optional().describe("Search terms to match. Provide a few key words or phrases that should appear in results."),
6678
+ match_mode: z12.enum(["any", "or", "all", "and"]).optional().describe('How to combine terms: "any" (OR) or "all" (AND).'),
6679
+ include_snippets: z12.boolean().optional().describe("Include content excerpts around matches"),
6680
+ limit: z12.number().int().min(1).max(100).optional().describe("Maximum number of results to return")
5422
6681
  };
5423
6682
  function createSearchProjectDocsTool(deps) {
5424
6683
  const { pkgseerService, configService, defaultProjectDir } = deps;
5425
6684
  return {
5426
6685
  name: "search_project_docs",
5427
6686
  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.",
5428
- schema: argsSchema10,
6687
+ schema: argsSchema14,
5429
6688
  handler: async ({
5430
6689
  project_directory,
5431
6690
  project,
@@ -5471,15 +6730,15 @@ function createSearchProjectDocsTool(deps) {
5471
6730
  };
5472
6731
  }
5473
6732
  // src/tools/search-status.ts
5474
- import { z as z9 } from "zod";
5475
- var argsSchema11 = {
5476
- searchRef: z9.string().min(1).describe("Search reference from a previous incomplete search")
6733
+ import { z as z13 } from "zod";
6734
+ var argsSchema15 = {
6735
+ searchRef: z13.string().min(1).describe("Search reference from a previous incomplete search")
5477
6736
  };
5478
6737
  function createSearchStatusTool(pkgseerService) {
5479
6738
  return {
5480
6739
  name: "search_status",
5481
6740
  description: "Check the status of an async search and get results if complete. " + "Use this after a search returns incomplete (completed=false) to poll for completion. " + "Returns status (PENDING, INDEXING, SEARCHING, COMPLETED, TIMEOUT, FAILED), " + "progress info (packagesReady/packagesTotal), and results when status is COMPLETED.",
5482
- schema: argsSchema11,
6741
+ schema: argsSchema15,
5483
6742
  handler: async ({ searchRef }, _extra) => {
5484
6743
  return withErrorHandling("check search status", async () => {
5485
6744
  const progressResult = await pkgseerService.getSearchProgress(searchRef);
@@ -5519,6 +6778,185 @@ function createSearchStatusTool(pkgseerService) {
5519
6778
  }
5520
6779
  };
5521
6780
  }
6781
+ // src/tools/search-symbols.ts
6782
+ import { z as z14 } from "zod";
6783
+ var argsSchema16 = {
6784
+ registry: schemas.registry,
6785
+ package_name: schemas.packageName.describe("Name of the package to search within"),
6786
+ query: z14.string().max(500).describe("Search query for full-text code search (max 500 chars)"),
6787
+ kind: z14.enum([
6788
+ "function",
6789
+ "method",
6790
+ "class",
6791
+ "module",
6792
+ "interface",
6793
+ "type",
6794
+ "doc_section"
6795
+ ]).optional().describe("Filter results by code chunk type"),
6796
+ version: schemas.version,
6797
+ limit: z14.number().int().min(1).max(50).optional().describe("Max results to return (max 50)"),
6798
+ mode: schemas.navigationMode,
6799
+ wait_timeout_ms: schemas.waitTimeoutMs
6800
+ };
6801
+ function createSearchSymbolsTool(pkgseerService) {
6802
+ return {
6803
+ name: "search_symbols",
6804
+ description: "Full-text search within package code. " + "Searches across functions, classes, modules, and doc sections. " + "Returns: matching code chunks with name, type, file path, line numbers, " + "and content previews. Use for finding implementations by keyword.",
6805
+ schema: argsSchema16,
6806
+ handler: async (args, _extra) => {
6807
+ return withErrorHandling("search symbols", async () => {
6808
+ const result = await pkgseerService.searchSymbols(toGraphQLRegistry2(args.registry), args.package_name, args.query, {
6809
+ kind: toSymbolKind(args.kind),
6810
+ version: args.version,
6811
+ limit: args.limit,
6812
+ mode: toNavigationMode(args.mode),
6813
+ waitTimeoutMs: args.wait_timeout_ms
6814
+ });
6815
+ const graphqlError = handleGraphQLErrors(result.errors);
6816
+ if (graphqlError)
6817
+ return graphqlError;
6818
+ if (!result.data.searchSymbols) {
6819
+ return notFoundError(args.package_name, args.registry);
6820
+ }
6821
+ return textResult(JSON.stringify(result.data.searchSymbols, null, 2));
6822
+ });
6823
+ }
6824
+ };
6825
+ }
6826
+ // src/tools/symbol-callees.ts
6827
+ import { z as z15 } from "zod";
6828
+ var argsSchema17 = {
6829
+ symbol: schemas.symbolReference.describe("Symbol to find callees for. Provide either symbol_id or registry + package_name + symbol_name."),
6830
+ max_depth: z15.number().int().min(1).max(5).optional().describe("BFS traversal depth (1 = direct callees only, 2+ = transitive, max 5)"),
6831
+ limit: z15.number().int().min(1).max(100).optional().describe("Maximum dependency entries to return"),
6832
+ include_external: z15.boolean().optional().describe("Include calls to symbols in other packages"),
6833
+ include_builtins: z15.boolean().optional().describe("Include calls to built-in/standard library functions (console, Math, etc.)"),
6834
+ mode: schemas.navigationMode,
6835
+ wait_timeout_ms: schemas.waitTimeoutMs
6836
+ };
6837
+ function createSymbolCalleesTool(pkgseerService) {
6838
+ return {
6839
+ name: "symbol_callees",
6840
+ 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. Use to understand a function's dependency footprint.",
6841
+ schema: argsSchema17,
6842
+ handler: async (args, _extra) => {
6843
+ return withErrorHandling("find symbol callees", async () => {
6844
+ const symbolInput = toSymbolReferenceInput(args.symbol);
6845
+ if (!symbolInput.symbolId && (!symbolInput.symbolName || !symbolInput.registry || !symbolInput.packageName)) {
6846
+ return errorResult("Provide either symbol_id or symbol_name with registry and package_name to identify the symbol.");
6847
+ }
6848
+ const result = await pkgseerService.symbolDependencies(symbolInput, {
6849
+ maxDepth: args.max_depth,
6850
+ maxResults: args.limit,
6851
+ includeExternal: args.include_external,
6852
+ includeBuiltins: args.include_builtins,
6853
+ mode: toNavigationMode(args.mode),
6854
+ waitTimeoutMs: args.wait_timeout_ms
6855
+ });
6856
+ const graphqlError = handleGraphQLErrors(result.errors);
6857
+ if (graphqlError)
6858
+ return graphqlError;
6859
+ if (!result.data.symbolDependencies) {
6860
+ return errorResult("Symbol not found. Verify the symbol reference and that the package is indexed.");
6861
+ }
6862
+ return textResult(JSON.stringify(result.data.symbolDependencies, null, 2));
6863
+ });
6864
+ }
6865
+ };
6866
+ }
6867
+ // src/tools/symbol-callers.ts
6868
+ import { z as z16 } from "zod";
6869
+ var argsSchema18 = {
6870
+ symbol: schemas.symbolReference.describe("Symbol to find callers for. Provide either symbol_id or registry + package_name + symbol_name."),
6871
+ same_package_only: z16.boolean().optional().describe("Only return callers from the same package"),
6872
+ limit: z16.number().int().min(1).max(100).optional().describe("Maximum entries to return"),
6873
+ mode: schemas.navigationMode,
6874
+ wait_timeout_ms: schemas.waitTimeoutMs
6875
+ };
6876
+ function createSymbolCallersTool(pkgseerService) {
6877
+ return {
6878
+ name: "symbol_callers",
6879
+ description: "Find what calls a symbol (its dependents/callers). " + "Returns: the target symbol and a list of symbols that call it, " + "with their file locations and call line numbers. " + "Use same_package_only to limit to callers within the same package.",
6880
+ schema: argsSchema18,
6881
+ handler: async (args, _extra) => {
6882
+ return withErrorHandling("find symbol callers", async () => {
6883
+ const symbolInput = toSymbolReferenceInput(args.symbol);
6884
+ if (!symbolInput.symbolId && (!symbolInput.symbolName || !symbolInput.registry || !symbolInput.packageName)) {
6885
+ return errorResult("Provide either symbol_id or symbol_name with registry and package_name to identify the symbol.");
6886
+ }
6887
+ const result = await pkgseerService.symbolDependents(symbolInput, {
6888
+ samePackageOnly: args.same_package_only,
6889
+ maxResults: args.limit,
6890
+ mode: toNavigationMode(args.mode),
6891
+ waitTimeoutMs: args.wait_timeout_ms
6892
+ });
6893
+ const graphqlError = handleGraphQLErrors(result.errors);
6894
+ if (graphqlError)
6895
+ return graphqlError;
6896
+ if (!result.data.symbolDependents) {
6897
+ return errorResult("Symbol not found. Verify the symbol reference and that the package is indexed.");
6898
+ }
6899
+ return textResult(JSON.stringify(result.data.symbolDependents, null, 2));
6900
+ });
6901
+ }
6902
+ };
6903
+ }
6904
+ // src/tools/trigger-indexing.ts
6905
+ import { z as z17 } from "zod";
6906
+ var packageInputSchema3 = z17.object({
6907
+ registry: schemas.registry,
6908
+ name: z17.string().max(255).describe("Package name"),
6909
+ version: z17.string().max(100).optional().describe("Specific version to index")
6910
+ });
6911
+ var repositoryInputSchema = z17.object({
6912
+ url: z17.string().max(2000).describe("GitHub repository URL"),
6913
+ ref: z17.string().max(200).optional().describe("Git ref to index (tag, branch, commit). Defaults to HEAD"),
6914
+ discover_packages: z17.boolean().optional().describe("If true, discover packages published from this repo and trigger their metadata fetch")
6915
+ });
6916
+ var argsSchema19 = {
6917
+ packages: z17.array(packageInputSchema3).max(100).optional().describe("Package versions to index (max 100)"),
6918
+ repositories: z17.array(repositoryInputSchema).max(50).optional().describe("Repository URLs to index (max 50)")
6919
+ };
6920
+ function createTriggerIndexingTool(pkgseerService) {
6921
+ return {
6922
+ name: "trigger_indexing",
6923
+ 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.",
6924
+ schema: argsSchema19,
6925
+ handler: async (args, _extra) => {
6926
+ return withErrorHandling("trigger indexing", async () => {
6927
+ const packages = args.packages?.map((p) => ({
6928
+ registry: toGraphQLRegistry2(p.registry),
6929
+ name: p.name,
6930
+ version: p.version
6931
+ }));
6932
+ const repositories = args.repositories?.map((r) => ({
6933
+ url: r.url,
6934
+ ref: r.ref,
6935
+ discoverPackages: r.discover_packages
6936
+ }));
6937
+ const result = await pkgseerService.triggerIndexing({
6938
+ packages,
6939
+ repositories
6940
+ });
6941
+ const graphqlError = handleGraphQLErrors(result.errors);
6942
+ if (graphqlError)
6943
+ return graphqlError;
6944
+ if (!result.data.triggerIndexing) {
6945
+ return {
6946
+ content: [
6947
+ {
6948
+ type: "text",
6949
+ text: "Indexing request failed. Check authentication and input."
6950
+ }
6951
+ ],
6952
+ isError: true
6953
+ };
6954
+ }
6955
+ return textResult(JSON.stringify(result.data.triggerIndexing, null, 2));
6956
+ });
6957
+ }
6958
+ };
6959
+ }
5522
6960
  // src/commands/mcp.ts
5523
6961
  var TOOL_FACTORIES = {
5524
6962
  package_summary: ({ pkgseerService }) => createPackageSummaryTool(pkgseerService),
@@ -5535,7 +6973,15 @@ var TOOL_FACTORIES = {
5535
6973
  pkgseerService,
5536
6974
  configService,
5537
6975
  defaultProjectDir
5538
- })
6976
+ }),
6977
+ find_symbol: ({ pkgseerService }) => createFindSymbolTool(pkgseerService),
6978
+ search_symbols: ({ pkgseerService }) => createSearchSymbolsTool(pkgseerService),
6979
+ list_symbols: ({ pkgseerService }) => createListSymbolsTool(pkgseerService),
6980
+ symbol_callers: ({ pkgseerService }) => createSymbolCallersTool(pkgseerService),
6981
+ symbol_callees: ({ pkgseerService }) => createSymbolCalleesTool(pkgseerService),
6982
+ package_imports: ({ pkgseerService }) => createPackageImportsTool(pkgseerService),
6983
+ call_path: ({ pkgseerService }) => createCallPathTool(pkgseerService),
6984
+ trigger_indexing: ({ pkgseerService }) => createTriggerIndexingTool(pkgseerService)
5539
6985
  };
5540
6986
  var PUBLIC_READ_TOOLS = [
5541
6987
  "package_summary",
@@ -5547,7 +6993,15 @@ var PUBLIC_READ_TOOLS = [
5547
6993
  "fetch_package_doc",
5548
6994
  "search",
5549
6995
  "search_status",
5550
- "fetch_code_context"
6996
+ "fetch_code_context",
6997
+ "find_symbol",
6998
+ "search_symbols",
6999
+ "list_symbols",
7000
+ "symbol_callers",
7001
+ "symbol_callees",
7002
+ "package_imports",
7003
+ "call_path",
7004
+ "trigger_indexing"
5551
7005
  ];
5552
7006
  var PROJECT_READ_TOOLS = ["search_project_docs"];
5553
7007
  var ALL_TOOLS = [...PUBLIC_READ_TOOLS, ...PROJECT_READ_TOOLS];
@@ -6547,6 +8001,18 @@ Documentation commands:
6547
8001
  pkgseer docs get <pkg> <page> Fetch a doc page
6548
8002
  pkgseer docs search <query> Search docs only
6549
8003
 
8004
+ Code navigation commands:
8005
+ pkgseer code find <pkg> [name] Find symbols by name
8006
+ pkgseer code search <pkg> <q> Search in package code
8007
+ pkgseer code list <package> Browse package symbols
8008
+ pkgseer code callers <symbol> Find what calls a symbol
8009
+ pkgseer code callees <symbol> Find what a symbol calls
8010
+ pkgseer code imports <package> List package imports
8011
+ pkgseer code path <from> <to> Find call path between symbols
8012
+
8013
+ Indexing:
8014
+ pkgseer index <packages...> Trigger pre-indexing
8015
+
6550
8016
  Learn more at https://pkgseer.dev`);
6551
8017
  registerInitCommand(program);
6552
8018
  registerMcpCommand(program);
@@ -6568,6 +8034,15 @@ var docs = program.command("docs").description("Package documentation commands")
6568
8034
  registerDocsListCommand(docs);
6569
8035
  registerDocsGetCommand(docs);
6570
8036
  registerDocsSearchCommand(docs);
8037
+ var code = program.command("code").description("Code navigation commands");
8038
+ registerCodeFindCommand(code);
8039
+ registerCodeSearchCommand(code);
8040
+ registerCodeListCommand(code);
8041
+ registerCodeCallersCommand(code);
8042
+ registerCodeCalleesCommand(code);
8043
+ registerCodeImportsCommand(code);
8044
+ registerCodePathCommand(code);
8045
+ registerIndexCommand(program);
6571
8046
  var project = program.command("project").description("Project management commands");
6572
8047
  registerProjectInitCommand(project);
6573
8048
  registerProjectDetectCommand(project);