@pkgseer/cli 0.3.0 → 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/README.md +6 -0
- package/dist/cli.js +1929 -152
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-9yar14cw.js → chunk-c1e7ntb6.js} +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
version
|
|
4
|
-
} from "./shared/chunk-
|
|
4
|
+
} from "./shared/chunk-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
|
|
@@ -261,6 +264,56 @@ var CombinedSearchDocument = gql`
|
|
|
261
264
|
}
|
|
262
265
|
}
|
|
263
266
|
`;
|
|
267
|
+
var SearchProgressDocument = gql`
|
|
268
|
+
query SearchProgress($searchRef: String!, $includeResults: Boolean) {
|
|
269
|
+
searchProgress(searchRef: $searchRef, includeResults: $includeResults) {
|
|
270
|
+
searchRef
|
|
271
|
+
status
|
|
272
|
+
packagesTotal
|
|
273
|
+
packagesReady
|
|
274
|
+
elapsedMs
|
|
275
|
+
query
|
|
276
|
+
mode
|
|
277
|
+
expiresAt
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
`;
|
|
281
|
+
var SearchResultsDocument = gql`
|
|
282
|
+
query SearchResults($searchRef: String!) {
|
|
283
|
+
searchResults(searchRef: $searchRef) {
|
|
284
|
+
query
|
|
285
|
+
mode
|
|
286
|
+
totalResults
|
|
287
|
+
entries {
|
|
288
|
+
id
|
|
289
|
+
type
|
|
290
|
+
title
|
|
291
|
+
subtitle
|
|
292
|
+
packageName
|
|
293
|
+
registry
|
|
294
|
+
score
|
|
295
|
+
snippet
|
|
296
|
+
matchLine
|
|
297
|
+
filePath
|
|
298
|
+
startLine
|
|
299
|
+
endLine
|
|
300
|
+
language
|
|
301
|
+
chunkType
|
|
302
|
+
repoUrl
|
|
303
|
+
gitRef
|
|
304
|
+
pageId
|
|
305
|
+
sourceUrl
|
|
306
|
+
}
|
|
307
|
+
indexingStatus {
|
|
308
|
+
registry
|
|
309
|
+
packageName
|
|
310
|
+
version
|
|
311
|
+
codeStatus
|
|
312
|
+
docsStatus
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
`;
|
|
264
317
|
var FetchCodeContextDocument = gql`
|
|
265
318
|
query FetchCodeContext($repoUrl: String!, $gitRef: String!, $filePath: String!, $startLine: Int, $endLine: Int) {
|
|
266
319
|
fetchCodeContext(
|
|
@@ -297,6 +350,14 @@ var CliDocsGetDocument = gql`
|
|
|
297
350
|
}
|
|
298
351
|
}
|
|
299
352
|
`;
|
|
353
|
+
var TriggerIndexingDocument = gql`
|
|
354
|
+
mutation TriggerIndexing($input: TriggerIndexingInput!) {
|
|
355
|
+
triggerIndexing(input: $input) {
|
|
356
|
+
accepted
|
|
357
|
+
skipped
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
`;
|
|
300
361
|
var CreateProjectDocument = gql`
|
|
301
362
|
mutation CreateProject($input: CreateProjectInput!) {
|
|
302
363
|
createProject(input: $input) {
|
|
@@ -326,6 +387,7 @@ var PackageSummaryDocument = gql`
|
|
|
326
387
|
repositoryUrl
|
|
327
388
|
license
|
|
328
389
|
downloadsLastMonth
|
|
390
|
+
downloadsTotal
|
|
329
391
|
downloadsRefreshedAt
|
|
330
392
|
}
|
|
331
393
|
security {
|
|
@@ -468,6 +530,7 @@ var ComparePackagesDocument = gql`
|
|
|
468
530
|
latestVersion
|
|
469
531
|
license
|
|
470
532
|
downloadsLastMonth
|
|
533
|
+
downloadsTotal
|
|
471
534
|
vulnerabilityCount
|
|
472
535
|
quality {
|
|
473
536
|
score
|
|
@@ -591,6 +654,237 @@ var SearchPackageDocsDocument = gql`
|
|
|
591
654
|
}
|
|
592
655
|
}
|
|
593
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
|
+
`;
|
|
594
888
|
var SearchProjectDocsDocument = gql`
|
|
595
889
|
query SearchProjectDocs($project: String!, $keywords: [String!], $matchMode: MatchMode, $includeSnippets: Boolean, $limit: Int) {
|
|
596
890
|
searchProjectDocs(
|
|
@@ -629,8 +923,11 @@ var CliDocsSearchDocumentString = print(CliDocsSearchDocument);
|
|
|
629
923
|
var CliProjectDocsSearchDocumentString = print(CliProjectDocsSearchDocument);
|
|
630
924
|
var CliDocsListDocumentString = print(CliDocsListDocument);
|
|
631
925
|
var CombinedSearchDocumentString = print(CombinedSearchDocument);
|
|
926
|
+
var SearchProgressDocumentString = print(SearchProgressDocument);
|
|
927
|
+
var SearchResultsDocumentString = print(SearchResultsDocument);
|
|
632
928
|
var FetchCodeContextDocumentString = print(FetchCodeContextDocument);
|
|
633
929
|
var CliDocsGetDocumentString = print(CliDocsGetDocument);
|
|
930
|
+
var TriggerIndexingDocumentString = print(TriggerIndexingDocument);
|
|
634
931
|
var CreateProjectDocumentString = print(CreateProjectDocument);
|
|
635
932
|
var PackageSummaryDocumentString = print(PackageSummaryDocument);
|
|
636
933
|
var PackageVulnerabilitiesDocumentString = print(PackageVulnerabilitiesDocument);
|
|
@@ -641,6 +938,13 @@ var ListPackageDocsDocumentString = print(ListPackageDocsDocument);
|
|
|
641
938
|
var FetchPackageDocDocumentString = print(FetchPackageDocDocument);
|
|
642
939
|
var GetDocPageDocumentString = print(GetDocPageDocument);
|
|
643
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);
|
|
644
948
|
var SearchProjectDocsDocumentString = print(SearchProjectDocsDocument);
|
|
645
949
|
function getSdk(client, withWrapper = defaultWrapper) {
|
|
646
950
|
return {
|
|
@@ -671,12 +975,21 @@ function getSdk(client, withWrapper = defaultWrapper) {
|
|
|
671
975
|
CombinedSearch(variables, requestHeaders) {
|
|
672
976
|
return withWrapper((wrappedRequestHeaders) => client.rawRequest(CombinedSearchDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CombinedSearch", "query", variables);
|
|
673
977
|
},
|
|
978
|
+
SearchProgress(variables, requestHeaders) {
|
|
979
|
+
return withWrapper((wrappedRequestHeaders) => client.rawRequest(SearchProgressDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SearchProgress", "query", variables);
|
|
980
|
+
},
|
|
981
|
+
SearchResults(variables, requestHeaders) {
|
|
982
|
+
return withWrapper((wrappedRequestHeaders) => client.rawRequest(SearchResultsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SearchResults", "query", variables);
|
|
983
|
+
},
|
|
674
984
|
FetchCodeContext(variables, requestHeaders) {
|
|
675
985
|
return withWrapper((wrappedRequestHeaders) => client.rawRequest(FetchCodeContextDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "FetchCodeContext", "query", variables);
|
|
676
986
|
},
|
|
677
987
|
CliDocsGet(variables, requestHeaders) {
|
|
678
988
|
return withWrapper((wrappedRequestHeaders) => client.rawRequest(CliDocsGetDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CliDocsGet", "query", variables);
|
|
679
989
|
},
|
|
990
|
+
TriggerIndexing(variables, requestHeaders) {
|
|
991
|
+
return withWrapper((wrappedRequestHeaders) => client.rawRequest(TriggerIndexingDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "TriggerIndexing", "mutation", variables);
|
|
992
|
+
},
|
|
680
993
|
CreateProject(variables, requestHeaders) {
|
|
681
994
|
return withWrapper((wrappedRequestHeaders) => client.rawRequest(CreateProjectDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CreateProject", "mutation", variables);
|
|
682
995
|
},
|
|
@@ -707,6 +1020,27 @@ function getSdk(client, withWrapper = defaultWrapper) {
|
|
|
707
1020
|
SearchPackageDocs(variables, requestHeaders) {
|
|
708
1021
|
return withWrapper((wrappedRequestHeaders) => client.rawRequest(SearchPackageDocsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SearchPackageDocs", "query", variables);
|
|
709
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
|
+
},
|
|
710
1044
|
SearchProjectDocs(variables, requestHeaders) {
|
|
711
1045
|
return withWrapper((wrappedRequestHeaders) => client.rawRequest(SearchProjectDocsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SearchProjectDocs", "query", variables);
|
|
712
1046
|
}
|
|
@@ -1037,8 +1371,17 @@ var TOOL_NAMES = [
|
|
|
1037
1371
|
"list_package_docs",
|
|
1038
1372
|
"fetch_package_doc",
|
|
1039
1373
|
"search",
|
|
1374
|
+
"search_status",
|
|
1040
1375
|
"fetch_code_context",
|
|
1041
|
-
"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"
|
|
1042
1385
|
];
|
|
1043
1386
|
var ToolNameSchema = z.enum(TOOL_NAMES);
|
|
1044
1387
|
var SharedConfigFields = {
|
|
@@ -1440,6 +1783,17 @@ class PkgseerServiceImpl {
|
|
|
1440
1783
|
});
|
|
1441
1784
|
return { data: result.data, errors: result.errors };
|
|
1442
1785
|
}
|
|
1786
|
+
async getSearchProgress(searchRef, options) {
|
|
1787
|
+
const result = await this.client.SearchProgress({
|
|
1788
|
+
searchRef,
|
|
1789
|
+
includeResults: options?.includeResults
|
|
1790
|
+
});
|
|
1791
|
+
return { data: result.data, errors: result.errors };
|
|
1792
|
+
}
|
|
1793
|
+
async getSearchResults(searchRef) {
|
|
1794
|
+
const result = await this.client.SearchResults({ searchRef });
|
|
1795
|
+
return { data: result.data, errors: result.errors };
|
|
1796
|
+
}
|
|
1443
1797
|
async fetchCodeContext(repoUrl, gitRef, filePath, options) {
|
|
1444
1798
|
const result = await this.client.FetchCodeContext({
|
|
1445
1799
|
repoUrl,
|
|
@@ -1450,6 +1804,100 @@ class PkgseerServiceImpl {
|
|
|
1450
1804
|
});
|
|
1451
1805
|
return { data: result.data, errors: result.errors };
|
|
1452
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
|
+
}
|
|
1453
1901
|
}
|
|
1454
1902
|
// src/services/project-service.ts
|
|
1455
1903
|
var PROJECT_NAME_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
@@ -1747,58 +2195,6 @@ function registerAuthStatusCommand(program) {
|
|
|
1747
2195
|
});
|
|
1748
2196
|
}
|
|
1749
2197
|
|
|
1750
|
-
// src/commands/config-show.ts
|
|
1751
|
-
async function configShowAction(deps) {
|
|
1752
|
-
const { configService } = deps;
|
|
1753
|
-
const { config, globalPath, projectPath } = await configService.loadMergedConfig();
|
|
1754
|
-
if (!globalPath && !projectPath) {
|
|
1755
|
-
console.log(`No configuration found.
|
|
1756
|
-
`);
|
|
1757
|
-
console.log(" Global config: ~/.pkgseer/config.yml");
|
|
1758
|
-
console.log(` Project config: pkgseer.yml
|
|
1759
|
-
`);
|
|
1760
|
-
console.log("Create a config file to customize pkgseer behavior.");
|
|
1761
|
-
return;
|
|
1762
|
-
}
|
|
1763
|
-
console.log(`Configuration sources:
|
|
1764
|
-
`);
|
|
1765
|
-
if (globalPath) {
|
|
1766
|
-
console.log(` Global: ${globalPath}`);
|
|
1767
|
-
}
|
|
1768
|
-
if (projectPath) {
|
|
1769
|
-
console.log(` Project: ${projectPath}`);
|
|
1770
|
-
}
|
|
1771
|
-
console.log(`
|
|
1772
|
-
Merged configuration:
|
|
1773
|
-
`);
|
|
1774
|
-
if (config.enabled_tools !== undefined) {
|
|
1775
|
-
if (config.enabled_tools.length > 0) {
|
|
1776
|
-
console.log(" enabled_tools:");
|
|
1777
|
-
for (const tool of config.enabled_tools) {
|
|
1778
|
-
console.log(` - ${tool}`);
|
|
1779
|
-
}
|
|
1780
|
-
} else {
|
|
1781
|
-
console.log(" enabled_tools: [] (no tools enabled)");
|
|
1782
|
-
}
|
|
1783
|
-
} else {
|
|
1784
|
-
console.log(" enabled_tools: (all tools enabled by default)");
|
|
1785
|
-
}
|
|
1786
|
-
if (config.project) {
|
|
1787
|
-
console.log(` project: ${config.project}`);
|
|
1788
|
-
}
|
|
1789
|
-
}
|
|
1790
|
-
var SHOW_DESCRIPTION = `Display current configuration.
|
|
1791
|
-
|
|
1792
|
-
Shows the merged configuration from global (~/.pkgseer/config.yml) and
|
|
1793
|
-
project (pkgseer.yml) config files. Project config takes precedence
|
|
1794
|
-
over global config for overlapping settings.`;
|
|
1795
|
-
function registerConfigShowCommand(program) {
|
|
1796
|
-
program.command("show").summary("Display current configuration").description(SHOW_DESCRIPTION).action(async () => {
|
|
1797
|
-
const deps = await createContainer();
|
|
1798
|
-
await configShowAction(deps);
|
|
1799
|
-
});
|
|
1800
|
-
}
|
|
1801
|
-
|
|
1802
2198
|
// src/commands/shared.ts
|
|
1803
2199
|
function parsePackageSpec(spec) {
|
|
1804
2200
|
let registry = "npm";
|
|
@@ -1806,7 +2202,16 @@ function parsePackageSpec(spec) {
|
|
|
1806
2202
|
if (spec.includes(":")) {
|
|
1807
2203
|
const colonIndex = spec.indexOf(":");
|
|
1808
2204
|
const potentialRegistry = spec.slice(0, colonIndex).toLowerCase();
|
|
1809
|
-
if ([
|
|
2205
|
+
if ([
|
|
2206
|
+
"npm",
|
|
2207
|
+
"pypi",
|
|
2208
|
+
"hex",
|
|
2209
|
+
"crates",
|
|
2210
|
+
"nuget",
|
|
2211
|
+
"maven",
|
|
2212
|
+
"zig",
|
|
2213
|
+
"vcpkg"
|
|
2214
|
+
].includes(potentialRegistry)) {
|
|
1810
2215
|
registry = potentialRegistry;
|
|
1811
2216
|
rest = spec.slice(colonIndex + 1);
|
|
1812
2217
|
}
|
|
@@ -1826,7 +2231,11 @@ function toGraphQLRegistry(registry) {
|
|
|
1826
2231
|
npm: "NPM",
|
|
1827
2232
|
pypi: "PYPI",
|
|
1828
2233
|
hex: "HEX",
|
|
1829
|
-
crates: "CRATES"
|
|
2234
|
+
crates: "CRATES",
|
|
2235
|
+
nuget: "NUGET",
|
|
2236
|
+
maven: "MAVEN",
|
|
2237
|
+
zig: "ZIG",
|
|
2238
|
+
vcpkg: "VCPKG"
|
|
1830
2239
|
};
|
|
1831
2240
|
return map[registry.toLowerCase()] || "NPM";
|
|
1832
2241
|
}
|
|
@@ -1872,6 +2281,11 @@ function formatNumber(num) {
|
|
|
1872
2281
|
return "N/A";
|
|
1873
2282
|
return num.toLocaleString();
|
|
1874
2283
|
}
|
|
2284
|
+
function truncate(text, maxLength) {
|
|
2285
|
+
if (text.length <= maxLength)
|
|
2286
|
+
return text;
|
|
2287
|
+
return `${text.slice(0, maxLength - 3)}...`;
|
|
2288
|
+
}
|
|
1875
2289
|
function keyValueTable(pairs) {
|
|
1876
2290
|
const maxKeyLen = Math.max(...pairs.map(([k]) => k.length));
|
|
1877
2291
|
return pairs.map(([key, value]) => ` ${key.padEnd(maxKeyLen)} ${value ?? "N/A"}`).join(`
|
|
@@ -1970,24 +2384,630 @@ function formatScore(score) {
|
|
|
1970
2384
|
return `${bar} ${percentage}%`;
|
|
1971
2385
|
}
|
|
1972
2386
|
|
|
1973
|
-
// src/commands/
|
|
1974
|
-
function
|
|
1975
|
-
|
|
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);
|
|
1976
2394
|
return {
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2395
|
+
registry: toGraphQLRegistry(parsed2.registry),
|
|
2396
|
+
packageName: parsed2.name,
|
|
2397
|
+
symbolName: symbolName || undefined
|
|
1980
2398
|
};
|
|
1981
2399
|
}
|
|
1982
|
-
const
|
|
1983
|
-
|
|
1984
|
-
|
|
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) };
|
|
1985
2409
|
}
|
|
1986
|
-
if (
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
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}`);
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
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
|
+
});
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
// src/commands/docs/get.ts
|
|
2994
|
+
function parsePackageRef(ref) {
|
|
2995
|
+
if (!ref.includes("/")) {
|
|
2996
|
+
return {
|
|
2997
|
+
pageId: ref,
|
|
2998
|
+
originalRef: ref,
|
|
2999
|
+
isGlobalId: true
|
|
3000
|
+
};
|
|
3001
|
+
}
|
|
3002
|
+
const parts = ref.split("/");
|
|
3003
|
+
if (parts.length < 2) {
|
|
3004
|
+
throw new Error(`Invalid format: "${ref}". Expected at least 2 parts separated by "/"`);
|
|
3005
|
+
}
|
|
3006
|
+
if (parts.length >= 4) {
|
|
3007
|
+
const registry = parts[0];
|
|
3008
|
+
const packageName2 = parts[1];
|
|
3009
|
+
const version2 = parts[2];
|
|
3010
|
+
const pageId2 = parts.slice(3).join("/");
|
|
1991
3011
|
if (!registry || !packageName2 || !version2 || !pageId2) {
|
|
1992
3012
|
throw new Error(`Invalid full form: "${ref}". All components (registry/package/version/document) are required.`);
|
|
1993
3013
|
}
|
|
@@ -2338,7 +3358,7 @@ async function docsListAction(packageArg, options, deps) {
|
|
|
2338
3358
|
console.log(formatDocsList(result.data.listPackageDocs));
|
|
2339
3359
|
}
|
|
2340
3360
|
}
|
|
2341
|
-
var
|
|
3361
|
+
var LIST_DESCRIPTION2 = `List available documentation pages for a package.
|
|
2342
3362
|
|
|
2343
3363
|
Shows all documentation pages with titles, globally unique page IDs,
|
|
2344
3364
|
word counts, and descriptions. Use the page ID with 'docs get'
|
|
@@ -2351,15 +3371,66 @@ Examples:
|
|
|
2351
3371
|
pkgseer docs list pypi:requests
|
|
2352
3372
|
pkgseer docs list hex:phoenix@1.7.0 --json`;
|
|
2353
3373
|
function registerDocsListCommand(program) {
|
|
2354
|
-
program.command("list <package>").summary("List documentation pages").description(
|
|
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) => {
|
|
2355
3375
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
2356
3376
|
const deps = await createContainer();
|
|
2357
3377
|
await docsListAction(packageName, options, deps);
|
|
2358
3378
|
});
|
|
2359
3379
|
});
|
|
2360
3380
|
}
|
|
3381
|
+
// src/lib/polling.ts
|
|
3382
|
+
var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3383
|
+
async function pollUntilDone(config) {
|
|
3384
|
+
const {
|
|
3385
|
+
fetch: fetch2,
|
|
3386
|
+
isDone,
|
|
3387
|
+
onUpdate,
|
|
3388
|
+
intervalMs,
|
|
3389
|
+
maxWaitMs,
|
|
3390
|
+
sleep = defaultSleep,
|
|
3391
|
+
now = Date.now
|
|
3392
|
+
} = config;
|
|
3393
|
+
const startTime = now();
|
|
3394
|
+
let lastData;
|
|
3395
|
+
while (true) {
|
|
3396
|
+
try {
|
|
3397
|
+
const data = await fetch2();
|
|
3398
|
+
lastData = data;
|
|
3399
|
+
if (onUpdate) {
|
|
3400
|
+
onUpdate(data);
|
|
3401
|
+
}
|
|
3402
|
+
if (isDone(data)) {
|
|
3403
|
+
return { success: true, data };
|
|
3404
|
+
}
|
|
3405
|
+
const elapsed = now() - startTime;
|
|
3406
|
+
if (elapsed >= maxWaitMs) {
|
|
3407
|
+
return {
|
|
3408
|
+
success: false,
|
|
3409
|
+
error: `Client polling timeout after ${elapsed}ms`,
|
|
3410
|
+
lastData
|
|
3411
|
+
};
|
|
3412
|
+
}
|
|
3413
|
+
await sleep(intervalMs);
|
|
3414
|
+
} catch (error) {
|
|
3415
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3416
|
+
return {
|
|
3417
|
+
success: false,
|
|
3418
|
+
error: `Poll failed: ${message}`,
|
|
3419
|
+
lastData
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
|
|
2361
3425
|
// src/commands/search.ts
|
|
2362
3426
|
var DEFAULT_WAIT_TIMEOUT_MS = 30000;
|
|
3427
|
+
var DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
3428
|
+
var DEFAULT_MAX_POLL_TIME_MS = 120000;
|
|
3429
|
+
var TERMINAL_STATUSES = [
|
|
3430
|
+
"COMPLETED",
|
|
3431
|
+
"TIMEOUT",
|
|
3432
|
+
"FAILED"
|
|
3433
|
+
];
|
|
2363
3434
|
var colors = {
|
|
2364
3435
|
reset: "\x1B[0m",
|
|
2365
3436
|
bold: "\x1B[1m",
|
|
@@ -2575,7 +3646,7 @@ function abbrevLang(lang) {
|
|
|
2575
3646
|
const lower = lang.toLowerCase();
|
|
2576
3647
|
return LANG_ABBREV[lower] ?? lower;
|
|
2577
3648
|
}
|
|
2578
|
-
function
|
|
3649
|
+
function truncate2(text, maxLen) {
|
|
2579
3650
|
if (text.length <= maxLen)
|
|
2580
3651
|
return text;
|
|
2581
3652
|
return `${text.slice(0, maxLen - 3)}...`;
|
|
@@ -2629,9 +3700,9 @@ function formatEntryCompact(entry, useColors) {
|
|
|
2629
3700
|
if (entry.snippet) {
|
|
2630
3701
|
const bestLine = findBestSnippetLine(entry.snippet);
|
|
2631
3702
|
if (bestLine) {
|
|
2632
|
-
snippet = ` ${
|
|
3703
|
+
snippet = ` ${truncate2(bestLine, 80)}`;
|
|
2633
3704
|
if (useColors) {
|
|
2634
|
-
snippet = ` ${colors.dim}${
|
|
3705
|
+
snippet = ` ${colors.dim}${truncate2(bestLine, 80)}${colors.reset}`;
|
|
2635
3706
|
}
|
|
2636
3707
|
}
|
|
2637
3708
|
}
|
|
@@ -2737,24 +3808,138 @@ function formatSearchProgress(progress, searchRef, useColors) {
|
|
|
2737
3808
|
lines.push(`Search ref: ${searchRef}`);
|
|
2738
3809
|
}
|
|
2739
3810
|
}
|
|
2740
|
-
return lines.join(`
|
|
2741
|
-
`);
|
|
2742
|
-
}
|
|
2743
|
-
function getWaitTimeoutMs(options) {
|
|
2744
|
-
if (options.noWait) {
|
|
2745
|
-
return 0;
|
|
3811
|
+
return lines.join(`
|
|
3812
|
+
`);
|
|
3813
|
+
}
|
|
3814
|
+
function getWaitTimeoutMs(options) {
|
|
3815
|
+
if (options.noWait) {
|
|
3816
|
+
return 0;
|
|
3817
|
+
}
|
|
3818
|
+
if (options.wait) {
|
|
3819
|
+
const parsed = Number.parseInt(options.wait, 10);
|
|
3820
|
+
if (!Number.isNaN(parsed) && parsed >= 0) {
|
|
3821
|
+
return parsed;
|
|
3822
|
+
}
|
|
3823
|
+
console.warn(`Warning: Invalid --wait value "${options.wait}". Using default (${DEFAULT_WAIT_TIMEOUT_MS}ms).`);
|
|
3824
|
+
}
|
|
3825
|
+
return DEFAULT_WAIT_TIMEOUT_MS;
|
|
3826
|
+
}
|
|
3827
|
+
function shouldPoll(options) {
|
|
3828
|
+
if (options.noPoll) {
|
|
3829
|
+
return false;
|
|
3830
|
+
}
|
|
3831
|
+
return process.stdout.isTTY ?? false;
|
|
3832
|
+
}
|
|
3833
|
+
async function pollSearchProgress(searchRef, pkgseerService, useColors) {
|
|
3834
|
+
const result = await pollUntilDone({
|
|
3835
|
+
fetch: async () => {
|
|
3836
|
+
const res = await pkgseerService.getSearchProgress(searchRef);
|
|
3837
|
+
return res.data.searchProgress ?? null;
|
|
3838
|
+
},
|
|
3839
|
+
isDone: (progress) => {
|
|
3840
|
+
if (!progress)
|
|
3841
|
+
return true;
|
|
3842
|
+
return TERMINAL_STATUSES.includes(progress.status);
|
|
3843
|
+
},
|
|
3844
|
+
onUpdate: (progress) => {
|
|
3845
|
+
if (progress) {
|
|
3846
|
+
const statusText = progress.status?.toLowerCase() ?? "unknown";
|
|
3847
|
+
const ready = progress.packagesReady ?? 0;
|
|
3848
|
+
const total = progress.packagesTotal ?? 0;
|
|
3849
|
+
const elapsed = ((progress.elapsedMs ?? 0) / 1000).toFixed(1);
|
|
3850
|
+
console.log(` ${statusText} (${ready}/${total} ready) - ${elapsed}s`);
|
|
3851
|
+
}
|
|
3852
|
+
},
|
|
3853
|
+
intervalMs: DEFAULT_POLL_INTERVAL_MS,
|
|
3854
|
+
maxWaitMs: DEFAULT_MAX_POLL_TIME_MS
|
|
3855
|
+
});
|
|
3856
|
+
if (!result.success) {
|
|
3857
|
+
return { success: false, error: result.error };
|
|
3858
|
+
}
|
|
3859
|
+
if (!result.data) {
|
|
3860
|
+
return { success: false, error: "Search session not found" };
|
|
3861
|
+
}
|
|
3862
|
+
return { success: true, status: result.data.status };
|
|
3863
|
+
}
|
|
3864
|
+
async function handleResume(searchRef, pkgseerService, options, useColors) {
|
|
3865
|
+
const progressResult = await pkgseerService.getSearchProgress(searchRef);
|
|
3866
|
+
if (progressResult.errors?.length) {
|
|
3867
|
+
handleErrors(progressResult.errors, options.json ?? false);
|
|
3868
|
+
return true;
|
|
3869
|
+
}
|
|
3870
|
+
const progress = progressResult.data.searchProgress;
|
|
3871
|
+
if (!progress) {
|
|
3872
|
+
outputError("Search session not found. It may have expired (sessions last 1 hour).", options.json ?? false);
|
|
3873
|
+
return true;
|
|
3874
|
+
}
|
|
3875
|
+
if (progress.status === "COMPLETED") {
|
|
3876
|
+
const resultsResponse = await pkgseerService.getSearchResults(searchRef);
|
|
3877
|
+
if (resultsResponse.errors?.length) {
|
|
3878
|
+
handleErrors(resultsResponse.errors, options.json ?? false);
|
|
3879
|
+
return true;
|
|
3880
|
+
}
|
|
3881
|
+
const searchResults = resultsResponse.data.searchResults;
|
|
3882
|
+
if (!searchResults) {
|
|
3883
|
+
outputError("Search completed but no results returned.", options.json ?? false);
|
|
3884
|
+
return true;
|
|
3885
|
+
}
|
|
3886
|
+
outputResults(searchResults, options, useColors);
|
|
3887
|
+
return true;
|
|
3888
|
+
}
|
|
3889
|
+
if (progress.status === "FAILED") {
|
|
3890
|
+
outputError(`Search failed. Ref: ${searchRef}`, options.json ?? false);
|
|
3891
|
+
return true;
|
|
3892
|
+
}
|
|
3893
|
+
if (progress.status === "TIMEOUT") {
|
|
3894
|
+
outputError(`Search timed out. Try again or use --wait with a higher value.
|
|
3895
|
+
Ref: ${searchRef}`, options.json ?? false);
|
|
3896
|
+
return true;
|
|
2746
3897
|
}
|
|
2747
|
-
if (options.
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
3898
|
+
if (options.json) {
|
|
3899
|
+
output({
|
|
3900
|
+
completed: false,
|
|
3901
|
+
searchRef,
|
|
3902
|
+
progress: {
|
|
3903
|
+
status: progress.status,
|
|
3904
|
+
packagesTotal: progress.packagesTotal,
|
|
3905
|
+
packagesReady: progress.packagesReady,
|
|
3906
|
+
elapsedMs: progress.elapsedMs
|
|
3907
|
+
},
|
|
3908
|
+
message: "Search is still in progress."
|
|
3909
|
+
}, true);
|
|
3910
|
+
return true;
|
|
3911
|
+
}
|
|
3912
|
+
console.log("Checking search status...");
|
|
3913
|
+
console.log(`Status: ${progress.status?.toLowerCase() ?? "unknown"}`);
|
|
3914
|
+
if (shouldPoll(options)) {
|
|
3915
|
+
console.log("Polling for completion...");
|
|
3916
|
+
const pollResult = await pollSearchProgress(searchRef, pkgseerService, useColors);
|
|
3917
|
+
if (!pollResult.success) {
|
|
3918
|
+
outputError(pollResult.error, false);
|
|
3919
|
+
console.log(`Resume with: pkgseer search --resume ${searchRef}`);
|
|
3920
|
+
return true;
|
|
2751
3921
|
}
|
|
2752
|
-
|
|
3922
|
+
if (pollResult.status === "COMPLETED") {
|
|
3923
|
+
const resultsResponse = await pkgseerService.getSearchResults(searchRef);
|
|
3924
|
+
if (resultsResponse.data.searchResults) {
|
|
3925
|
+
outputResults(resultsResponse.data.searchResults, options, useColors);
|
|
3926
|
+
}
|
|
3927
|
+
} else {
|
|
3928
|
+
console.log(`Search ended with status: ${pollResult.status.toLowerCase()}`);
|
|
3929
|
+
}
|
|
3930
|
+
} else {
|
|
3931
|
+
console.log(`
|
|
3932
|
+
Resume with: pkgseer search --resume ${searchRef}`);
|
|
2753
3933
|
}
|
|
2754
|
-
return
|
|
3934
|
+
return true;
|
|
2755
3935
|
}
|
|
2756
3936
|
async function searchAction(queryArg, options, deps, defaultMode = "ALL") {
|
|
2757
3937
|
const { pkgseerService } = deps;
|
|
3938
|
+
const useColors = shouldUseColors(options.noColor);
|
|
3939
|
+
if (options.resume?.trim()) {
|
|
3940
|
+
await handleResume(options.resume.trim(), pkgseerService, options, useColors);
|
|
3941
|
+
return;
|
|
3942
|
+
}
|
|
2758
3943
|
const query = Array.isArray(queryArg) ? queryArg.join(" ") : queryArg ?? "";
|
|
2759
3944
|
if (!query.trim()) {
|
|
2760
3945
|
outputError("Search query required. Provide query as argument.", options.json ?? false);
|
|
@@ -2771,7 +3956,6 @@ async function searchAction(queryArg, options, deps, defaultMode = "ALL") {
|
|
|
2771
3956
|
const packages = parsePackageList(options.packages);
|
|
2772
3957
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : 25;
|
|
2773
3958
|
const mode = options.mode ? toSearchMode(options.mode) : defaultMode;
|
|
2774
|
-
const useColors = shouldUseColors(options.noColor);
|
|
2775
3959
|
const waitTimeoutMs = getWaitTimeoutMs(options);
|
|
2776
3960
|
const result = await pkgseerService.combinedSearch(packages, query, {
|
|
2777
3961
|
mode,
|
|
@@ -2785,16 +3969,40 @@ async function searchAction(queryArg, options, deps, defaultMode = "ALL") {
|
|
|
2785
3969
|
return;
|
|
2786
3970
|
}
|
|
2787
3971
|
if (!asyncResult.completed) {
|
|
3972
|
+
const searchRef = asyncResult.searchRef;
|
|
2788
3973
|
if (options.json) {
|
|
2789
3974
|
output({
|
|
2790
3975
|
completed: false,
|
|
2791
|
-
searchRef
|
|
3976
|
+
searchRef,
|
|
2792
3977
|
progress: asyncResult.progress,
|
|
2793
3978
|
message: "Search is still indexing. Retry for complete results."
|
|
2794
3979
|
}, true);
|
|
2795
|
-
|
|
2796
|
-
|
|
3980
|
+
return;
|
|
3981
|
+
}
|
|
3982
|
+
if (shouldPoll(options) && searchRef) {
|
|
3983
|
+
console.log("Search in progress, polling for completion...");
|
|
3984
|
+
const pollResult = await pollSearchProgress(searchRef, pkgseerService, useColors);
|
|
3985
|
+
if (pollResult.success && pollResult.status === "COMPLETED") {
|
|
3986
|
+
const resultsResponse = await pkgseerService.getSearchResults(searchRef);
|
|
3987
|
+
if (resultsResponse.data.searchResults) {
|
|
3988
|
+
console.log("");
|
|
3989
|
+
outputResults(resultsResponse.data.searchResults, options, useColors);
|
|
3990
|
+
return;
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
if (!pollResult.success) {
|
|
3994
|
+
console.log(`
|
|
3995
|
+
${pollResult.error}`);
|
|
3996
|
+
} else if (pollResult.status !== "COMPLETED") {
|
|
3997
|
+
console.log(`
|
|
3998
|
+
Search ended with status: ${pollResult.status.toLowerCase()}`);
|
|
3999
|
+
}
|
|
4000
|
+
if (searchRef) {
|
|
4001
|
+
console.log(`Resume with: pkgseer search --resume ${searchRef}`);
|
|
4002
|
+
}
|
|
4003
|
+
return;
|
|
2797
4004
|
}
|
|
4005
|
+
console.log(formatSearchProgress(asyncResult.progress, searchRef, useColors));
|
|
2798
4006
|
return;
|
|
2799
4007
|
}
|
|
2800
4008
|
const searchResults = asyncResult.result;
|
|
@@ -2820,7 +4028,7 @@ function outputResults(results, options, useColors) {
|
|
|
2820
4028
|
console.log(formatSearchResultsCompact(results, useColors));
|
|
2821
4029
|
}
|
|
2822
4030
|
}
|
|
2823
|
-
var
|
|
4031
|
+
var SEARCH_DESCRIPTION2 = `Search code and documentation across packages.
|
|
2824
4032
|
|
|
2825
4033
|
Searches both code (functions, classes) and documentation pages
|
|
2826
4034
|
using the combined search endpoint. Returns results with snippets
|
|
@@ -2853,10 +4061,10 @@ Examples:
|
|
|
2853
4061
|
# JSON output
|
|
2854
4062
|
pkgseer search "error" -P express --json`;
|
|
2855
4063
|
function addSearchOptions(cmd) {
|
|
2856
|
-
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");
|
|
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");
|
|
2857
4065
|
}
|
|
2858
4066
|
function registerSearchCommand(program) {
|
|
2859
|
-
const cmd = program.command("search [query...]").summary("Search code and documentation across packages").description(
|
|
4067
|
+
const cmd = program.command("search [query...]").summary("Search code and documentation across packages").description(SEARCH_DESCRIPTION2);
|
|
2860
4068
|
addSearchOptions(cmd).action(async (query, options) => {
|
|
2861
4069
|
await withCliErrorHandling(options.json ?? false, async () => {
|
|
2862
4070
|
const deps = await createContainer();
|
|
@@ -2905,6 +4113,70 @@ function registerDocsSearchCommand(program) {
|
|
|
2905
4113
|
});
|
|
2906
4114
|
});
|
|
2907
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
|
+
|
|
2908
4180
|
// src/commands/shared-colors.ts
|
|
2909
4181
|
var colors2 = {
|
|
2910
4182
|
reset: "\x1B[0m",
|
|
@@ -4676,7 +5948,7 @@ function registerLogoutCommand(program) {
|
|
|
4676
5948
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4677
5949
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4678
5950
|
|
|
4679
|
-
// src/tools/
|
|
5951
|
+
// src/tools/call-path.ts
|
|
4680
5952
|
import { z as z3 } from "zod";
|
|
4681
5953
|
|
|
4682
5954
|
// src/tools/shared.ts
|
|
@@ -4701,15 +5973,68 @@ function toGraphQLRegistry2(registry) {
|
|
|
4701
5973
|
npm: "NPM",
|
|
4702
5974
|
pypi: "PYPI",
|
|
4703
5975
|
hex: "HEX",
|
|
4704
|
-
crates: "CRATES"
|
|
5976
|
+
crates: "CRATES",
|
|
5977
|
+
nuget: "NUGET",
|
|
5978
|
+
maven: "MAVEN",
|
|
5979
|
+
zig: "ZIG",
|
|
5980
|
+
vcpkg: "VCPKG"
|
|
4705
5981
|
};
|
|
4706
5982
|
return map[registry.toLowerCase()] || "NPM";
|
|
4707
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
|
+
}
|
|
4708
6017
|
var schemas = {
|
|
4709
|
-
registry: z2.enum(["npm", "pypi", "hex", "crates"]).describe("Package registry (npm, pypi, hex, or
|
|
6018
|
+
registry: z2.enum(["npm", "pypi", "hex", "crates", "nuget", "maven", "zig", "vcpkg"]).describe("Package registry (npm, pypi, hex, crates, nuget, maven, zig, or vcpkg)"),
|
|
4710
6019
|
packageName: z2.string().max(255).describe("Name of the package"),
|
|
4711
|
-
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
|
+
})
|
|
4712
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
|
+
}
|
|
4713
6038
|
function buildHintedMessage(operation, message) {
|
|
4714
6039
|
const lower = message.toLowerCase();
|
|
4715
6040
|
const isTimeout = lower.includes("-32001") || lower.includes("timeout") || lower.includes("timed out");
|
|
@@ -4747,20 +6072,60 @@ function notFoundError(packageName, registry) {
|
|
|
4747
6072
|
return errorResult(`Package not found: ${packageName} in ${registry}`);
|
|
4748
6073
|
}
|
|
4749
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
|
+
}
|
|
4750
6114
|
// src/tools/compare-packages.ts
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
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()
|
|
4755
6120
|
});
|
|
4756
|
-
var
|
|
4757
|
-
packages:
|
|
6121
|
+
var argsSchema2 = {
|
|
6122
|
+
packages: z4.array(packageInputSchema).min(2).max(10).describe("List of packages to compare (2-10 packages)")
|
|
4758
6123
|
};
|
|
4759
6124
|
function createComparePackagesTool(pkgseerService) {
|
|
4760
6125
|
return {
|
|
4761
6126
|
name: "compare_packages",
|
|
4762
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"}]',
|
|
4763
|
-
schema:
|
|
6128
|
+
schema: argsSchema2,
|
|
4764
6129
|
handler: async ({ packages }, _extra) => {
|
|
4765
6130
|
return withErrorHandling("compare packages", async () => {
|
|
4766
6131
|
const input2 = packages.map((pkg) => ({
|
|
@@ -4781,19 +6146,19 @@ function createComparePackagesTool(pkgseerService) {
|
|
|
4781
6146
|
};
|
|
4782
6147
|
}
|
|
4783
6148
|
// src/tools/fetch-code-context.ts
|
|
4784
|
-
import { z as
|
|
4785
|
-
var
|
|
4786
|
-
repo_url:
|
|
4787
|
-
git_ref:
|
|
4788
|
-
file_path:
|
|
4789
|
-
start_line:
|
|
4790
|
-
end_line:
|
|
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.")
|
|
4791
6156
|
};
|
|
4792
6157
|
function createFetchCodeContextTool(pkgseerService) {
|
|
4793
6158
|
return {
|
|
4794
6159
|
name: "fetch_code_context",
|
|
4795
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.",
|
|
4796
|
-
schema:
|
|
6161
|
+
schema: argsSchema3,
|
|
4797
6162
|
handler: async ({ repo_url, git_ref, file_path, start_line, end_line }, _extra) => {
|
|
4798
6163
|
return withErrorHandling("fetch code context", async () => {
|
|
4799
6164
|
const result = await pkgseerService.fetchCodeContext(repo_url, git_ref, file_path, {
|
|
@@ -4812,15 +6177,15 @@ function createFetchCodeContextTool(pkgseerService) {
|
|
|
4812
6177
|
};
|
|
4813
6178
|
}
|
|
4814
6179
|
// src/tools/fetch-package-doc.ts
|
|
4815
|
-
import { z as
|
|
4816
|
-
var
|
|
4817
|
-
page_id:
|
|
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)")
|
|
4818
6183
|
};
|
|
4819
6184
|
function createFetchPackageDocTool(pkgseerService) {
|
|
4820
6185
|
return {
|
|
4821
6186
|
name: "fetch_package_doc",
|
|
4822
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.",
|
|
4823
|
-
schema:
|
|
6188
|
+
schema: argsSchema4,
|
|
4824
6189
|
handler: async ({ page_id }, _extra) => {
|
|
4825
6190
|
return withErrorHandling("fetch documentation page", async () => {
|
|
4826
6191
|
const result = await pkgseerService.getDocPage(page_id);
|
|
@@ -4835,8 +6200,60 @@ function createFetchPackageDocTool(pkgseerService) {
|
|
|
4835
6200
|
}
|
|
4836
6201
|
};
|
|
4837
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
|
+
}
|
|
4838
6255
|
// src/tools/list-package-docs.ts
|
|
4839
|
-
var
|
|
6256
|
+
var argsSchema6 = {
|
|
4840
6257
|
registry: schemas.registry,
|
|
4841
6258
|
package_name: schemas.packageName.describe("Name of the package to list documentation for"),
|
|
4842
6259
|
version: schemas.version
|
|
@@ -4845,7 +6262,7 @@ function createListPackageDocsTool(pkgseerService) {
|
|
|
4845
6262
|
return {
|
|
4846
6263
|
name: "list_package_docs",
|
|
4847
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.",
|
|
4848
|
-
schema:
|
|
6265
|
+
schema: argsSchema6,
|
|
4849
6266
|
handler: async ({ registry, package_name, version: version2 }, _extra) => {
|
|
4850
6267
|
return withErrorHandling("list package documentation", async () => {
|
|
4851
6268
|
const result = await pkgseerService.listPackageDocs(toGraphQLRegistry2(registry), package_name, version2);
|
|
@@ -4860,14 +6277,69 @@ function createListPackageDocsTool(pkgseerService) {
|
|
|
4860
6277
|
}
|
|
4861
6278
|
};
|
|
4862
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
|
+
}
|
|
4863
6335
|
// src/tools/package-dependencies.ts
|
|
4864
|
-
import { z as
|
|
4865
|
-
var
|
|
6336
|
+
import { z as z9 } from "zod";
|
|
6337
|
+
var argsSchema8 = {
|
|
4866
6338
|
registry: schemas.registry,
|
|
4867
6339
|
package_name: schemas.packageName.describe("Name of the package to retrieve dependencies for"),
|
|
4868
6340
|
version: schemas.version,
|
|
4869
|
-
include_transitive:
|
|
4870
|
-
max_depth:
|
|
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)")
|
|
4871
6343
|
};
|
|
4872
6344
|
function decodeDag(rawDag) {
|
|
4873
6345
|
if (!rawDag || typeof rawDag !== "object")
|
|
@@ -4945,7 +6417,7 @@ function createPackageDependenciesTool(pkgseerService) {
|
|
|
4945
6417
|
return {
|
|
4946
6418
|
name: "package_dependencies",
|
|
4947
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.",
|
|
4948
|
-
schema:
|
|
6420
|
+
schema: argsSchema8,
|
|
4949
6421
|
handler: async ({ registry, package_name, version: version2, include_transitive, max_depth }, _extra) => {
|
|
4950
6422
|
return withErrorHandling("fetch package dependencies", async () => {
|
|
4951
6423
|
const result = await pkgseerService.getPackageDependencies(toGraphQLRegistry2(registry), package_name, version2, include_transitive, max_depth);
|
|
@@ -4982,8 +6454,46 @@ function createPackageDependenciesTool(pkgseerService) {
|
|
|
4982
6454
|
}
|
|
4983
6455
|
};
|
|
4984
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
|
+
}
|
|
4985
6495
|
// src/tools/package-quality.ts
|
|
4986
|
-
var
|
|
6496
|
+
var argsSchema10 = {
|
|
4987
6497
|
registry: schemas.registry,
|
|
4988
6498
|
package_name: schemas.packageName.describe("Name of the package to analyze"),
|
|
4989
6499
|
version: schemas.version
|
|
@@ -4992,7 +6502,7 @@ function createPackageQualityTool(pkgseerService) {
|
|
|
4992
6502
|
return {
|
|
4993
6503
|
name: "package_quality",
|
|
4994
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.",
|
|
4995
|
-
schema:
|
|
6505
|
+
schema: argsSchema10,
|
|
4996
6506
|
handler: async ({ registry, package_name, version: version2 }, _extra) => {
|
|
4997
6507
|
return withErrorHandling("fetch package quality", async () => {
|
|
4998
6508
|
const result = await pkgseerService.getPackageQuality(toGraphQLRegistry2(registry), package_name, version2);
|
|
@@ -5008,7 +6518,7 @@ function createPackageQualityTool(pkgseerService) {
|
|
|
5008
6518
|
};
|
|
5009
6519
|
}
|
|
5010
6520
|
// src/tools/package-summary.ts
|
|
5011
|
-
var
|
|
6521
|
+
var argsSchema11 = {
|
|
5012
6522
|
registry: schemas.registry,
|
|
5013
6523
|
package_name: schemas.packageName.describe("Name of the package to retrieve summary for")
|
|
5014
6524
|
};
|
|
@@ -5016,7 +6526,7 @@ function createPackageSummaryTool(pkgseerService) {
|
|
|
5016
6526
|
return {
|
|
5017
6527
|
name: "package_summary",
|
|
5018
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).",
|
|
5019
|
-
schema:
|
|
6529
|
+
schema: argsSchema11,
|
|
5020
6530
|
handler: async ({ registry, package_name }, _extra) => {
|
|
5021
6531
|
return withErrorHandling("fetch package summary", async () => {
|
|
5022
6532
|
const result = await pkgseerService.getPackageSummary(toGraphQLRegistry2(registry), package_name);
|
|
@@ -5032,7 +6542,7 @@ function createPackageSummaryTool(pkgseerService) {
|
|
|
5032
6542
|
};
|
|
5033
6543
|
}
|
|
5034
6544
|
// src/tools/package-vulnerabilities.ts
|
|
5035
|
-
var
|
|
6545
|
+
var argsSchema12 = {
|
|
5036
6546
|
registry: schemas.registry,
|
|
5037
6547
|
package_name: schemas.packageName.describe("Name of the package to inspect for vulnerabilities"),
|
|
5038
6548
|
version: schemas.version
|
|
@@ -5041,7 +6551,7 @@ function createPackageVulnerabilitiesTool(pkgseerService) {
|
|
|
5041
6551
|
return {
|
|
5042
6552
|
name: "package_vulnerabilities",
|
|
5043
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.",
|
|
5044
|
-
schema:
|
|
6554
|
+
schema: argsSchema12,
|
|
5045
6555
|
handler: async ({ registry, package_name, version: version2 }, _extra) => {
|
|
5046
6556
|
return withErrorHandling("fetch package vulnerabilities", async () => {
|
|
5047
6557
|
const result = await pkgseerService.getPackageVulnerabilities(toGraphQLRegistry2(registry), package_name, version2);
|
|
@@ -5057,19 +6567,19 @@ function createPackageVulnerabilitiesTool(pkgseerService) {
|
|
|
5057
6567
|
};
|
|
5058
6568
|
}
|
|
5059
6569
|
// src/tools/search.ts
|
|
5060
|
-
import { z as
|
|
5061
|
-
var packageInputSchema2 =
|
|
6570
|
+
import { z as z11 } from "zod";
|
|
6571
|
+
var packageInputSchema2 = z11.object({
|
|
5062
6572
|
registry: schemas.registry,
|
|
5063
|
-
name:
|
|
5064
|
-
version:
|
|
6573
|
+
name: z11.string().min(1).describe("Package name"),
|
|
6574
|
+
version: z11.string().optional().describe("Specific version (defaults to latest)")
|
|
5065
6575
|
});
|
|
5066
6576
|
var DEFAULT_AGENT_WAIT_TIMEOUT_MS = 1e4;
|
|
5067
|
-
var
|
|
5068
|
-
packages:
|
|
5069
|
-
query:
|
|
5070
|
-
mode:
|
|
5071
|
-
limit:
|
|
5072
|
-
waitTimeoutMs:
|
|
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)")
|
|
5073
6583
|
};
|
|
5074
6584
|
function toSearchMode2(mode) {
|
|
5075
6585
|
if (!mode)
|
|
@@ -5108,7 +6618,7 @@ function createSearchTool(pkgseerService) {
|
|
|
5108
6618
|
return {
|
|
5109
6619
|
name: "search",
|
|
5110
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.",
|
|
5111
|
-
schema:
|
|
6621
|
+
schema: argsSchema13,
|
|
5112
6622
|
handler: async ({ packages, query, mode, limit, waitTimeoutMs }, _extra) => {
|
|
5113
6623
|
return withErrorHandling("search packages", async () => {
|
|
5114
6624
|
const normalizedQuery = query.trim();
|
|
@@ -5160,21 +6670,21 @@ function createSearchTool(pkgseerService) {
|
|
|
5160
6670
|
};
|
|
5161
6671
|
}
|
|
5162
6672
|
// src/tools/search-project-docs.ts
|
|
5163
|
-
import { z as
|
|
5164
|
-
var
|
|
5165
|
-
project_directory:
|
|
5166
|
-
project:
|
|
5167
|
-
terms:
|
|
5168
|
-
match_mode:
|
|
5169
|
-
include_snippets:
|
|
5170
|
-
limit:
|
|
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")
|
|
5171
6681
|
};
|
|
5172
6682
|
function createSearchProjectDocsTool(deps) {
|
|
5173
6683
|
const { pkgseerService, configService, defaultProjectDir } = deps;
|
|
5174
6684
|
return {
|
|
5175
6685
|
name: "search_project_docs",
|
|
5176
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.",
|
|
5177
|
-
schema:
|
|
6687
|
+
schema: argsSchema14,
|
|
5178
6688
|
handler: async ({
|
|
5179
6689
|
project_directory,
|
|
5180
6690
|
project,
|
|
@@ -5219,6 +6729,234 @@ function createSearchProjectDocsTool(deps) {
|
|
|
5219
6729
|
}
|
|
5220
6730
|
};
|
|
5221
6731
|
}
|
|
6732
|
+
// src/tools/search-status.ts
|
|
6733
|
+
import { z as z13 } from "zod";
|
|
6734
|
+
var argsSchema15 = {
|
|
6735
|
+
searchRef: z13.string().min(1).describe("Search reference from a previous incomplete search")
|
|
6736
|
+
};
|
|
6737
|
+
function createSearchStatusTool(pkgseerService) {
|
|
6738
|
+
return {
|
|
6739
|
+
name: "search_status",
|
|
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.",
|
|
6741
|
+
schema: argsSchema15,
|
|
6742
|
+
handler: async ({ searchRef }, _extra) => {
|
|
6743
|
+
return withErrorHandling("check search status", async () => {
|
|
6744
|
+
const progressResult = await pkgseerService.getSearchProgress(searchRef);
|
|
6745
|
+
const graphqlError = handleGraphQLErrors(progressResult.errors);
|
|
6746
|
+
if (graphqlError)
|
|
6747
|
+
return graphqlError;
|
|
6748
|
+
const progress = progressResult.data.searchProgress;
|
|
6749
|
+
if (!progress) {
|
|
6750
|
+
return errorResult("Search session not found. It may have expired (sessions last 1 hour).");
|
|
6751
|
+
}
|
|
6752
|
+
if (progress.status === "COMPLETED") {
|
|
6753
|
+
const resultsResponse = await pkgseerService.getSearchResults(searchRef);
|
|
6754
|
+
const resultsError = handleGraphQLErrors(resultsResponse.errors);
|
|
6755
|
+
if (resultsError)
|
|
6756
|
+
return resultsError;
|
|
6757
|
+
const searchResults = resultsResponse.data.searchResults;
|
|
6758
|
+
if (!searchResults) {
|
|
6759
|
+
return errorResult("Search completed but results are no longer available. " + "The session may have expired (sessions last 1 hour).");
|
|
6760
|
+
}
|
|
6761
|
+
return textResult(JSON.stringify({
|
|
6762
|
+
status: progress.status,
|
|
6763
|
+
searchRef: progress.searchRef,
|
|
6764
|
+
result: searchResults
|
|
6765
|
+
}, null, 2));
|
|
6766
|
+
}
|
|
6767
|
+
return textResult(JSON.stringify({
|
|
6768
|
+
status: progress.status,
|
|
6769
|
+
searchRef: progress.searchRef,
|
|
6770
|
+
progress: {
|
|
6771
|
+
packagesTotal: progress.packagesTotal,
|
|
6772
|
+
packagesReady: progress.packagesReady,
|
|
6773
|
+
elapsedMs: progress.elapsedMs
|
|
6774
|
+
},
|
|
6775
|
+
message: progress.status === "FAILED" ? "Search failed." : progress.status === "TIMEOUT" ? "Search timed out before completion." : "Search is still in progress. Poll again to check status."
|
|
6776
|
+
}, null, 2));
|
|
6777
|
+
});
|
|
6778
|
+
}
|
|
6779
|
+
};
|
|
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
|
+
}
|
|
5222
6960
|
// src/commands/mcp.ts
|
|
5223
6961
|
var TOOL_FACTORIES = {
|
|
5224
6962
|
package_summary: ({ pkgseerService }) => createPackageSummaryTool(pkgseerService),
|
|
@@ -5229,12 +6967,21 @@ var TOOL_FACTORIES = {
|
|
|
5229
6967
|
list_package_docs: ({ pkgseerService }) => createListPackageDocsTool(pkgseerService),
|
|
5230
6968
|
fetch_package_doc: ({ pkgseerService }) => createFetchPackageDocTool(pkgseerService),
|
|
5231
6969
|
search: ({ pkgseerService }) => createSearchTool(pkgseerService),
|
|
6970
|
+
search_status: ({ pkgseerService }) => createSearchStatusTool(pkgseerService),
|
|
5232
6971
|
fetch_code_context: ({ pkgseerService }) => createFetchCodeContextTool(pkgseerService),
|
|
5233
6972
|
search_project_docs: ({ pkgseerService, configService, defaultProjectDir }) => createSearchProjectDocsTool({
|
|
5234
6973
|
pkgseerService,
|
|
5235
6974
|
configService,
|
|
5236
6975
|
defaultProjectDir
|
|
5237
|
-
})
|
|
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)
|
|
5238
6985
|
};
|
|
5239
6986
|
var PUBLIC_READ_TOOLS = [
|
|
5240
6987
|
"package_summary",
|
|
@@ -5245,7 +6992,16 @@ var PUBLIC_READ_TOOLS = [
|
|
|
5245
6992
|
"list_package_docs",
|
|
5246
6993
|
"fetch_package_doc",
|
|
5247
6994
|
"search",
|
|
5248
|
-
"
|
|
6995
|
+
"search_status",
|
|
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"
|
|
5249
7005
|
];
|
|
5250
7006
|
var PROJECT_READ_TOOLS = ["search_project_docs"];
|
|
5251
7007
|
var ALL_TOOLS = [...PUBLIC_READ_TOOLS, ...PROJECT_READ_TOOLS];
|
|
@@ -6245,6 +8001,18 @@ Documentation commands:
|
|
|
6245
8001
|
pkgseer docs get <pkg> <page> Fetch a doc page
|
|
6246
8002
|
pkgseer docs search <query> Search docs only
|
|
6247
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
|
+
|
|
6248
8016
|
Learn more at https://pkgseer.dev`);
|
|
6249
8017
|
registerInitCommand(program);
|
|
6250
8018
|
registerMcpCommand(program);
|
|
@@ -6266,6 +8034,15 @@ var docs = program.command("docs").description("Package documentation commands")
|
|
|
6266
8034
|
registerDocsListCommand(docs);
|
|
6267
8035
|
registerDocsGetCommand(docs);
|
|
6268
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);
|
|
6269
8046
|
var project = program.command("project").description("Project management commands");
|
|
6270
8047
|
registerProjectInitCommand(project);
|
|
6271
8048
|
registerProjectDetectCommand(project);
|