@pkgseer/cli 0.2.5 → 0.3.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 +175 -47
- package/dist/index.js +1 -1
- package/dist/shared/{chunk-drz16bhv.js → chunk-9yar14cw.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,8 +96,14 @@ pkgseer search "json parsing" -P hex:jason,hex:poison
|
|
|
96
96
|
# Search modes
|
|
97
97
|
pkgseer search "auth" -P lodash --mode code # Code only
|
|
98
98
|
pkgseer search "auth" -P lodash --mode docs # Docs only
|
|
99
|
+
|
|
100
|
+
# Wait options (for packages that need indexing)
|
|
101
|
+
pkgseer search "api" -P new-package --wait 60000 # Wait up to 60s
|
|
102
|
+
pkgseer search "api" -P new-package --no-wait # Return immediately
|
|
99
103
|
```
|
|
100
104
|
|
|
105
|
+
If packages haven't been indexed yet, the search will wait up to 30 seconds by default. Use `--wait <ms>` to customize or `--no-wait` to return immediately with progress info.
|
|
106
|
+
|
|
101
107
|
### Package Commands
|
|
102
108
|
|
|
103
109
|
```bash
|
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-9yar14cw.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -211,36 +211,52 @@ var CliDocsListDocument = gql`
|
|
|
211
211
|
}
|
|
212
212
|
`;
|
|
213
213
|
var CombinedSearchDocument = gql`
|
|
214
|
-
query CombinedSearch($packages: [SearchPackageInput!]!, $query: String!, $mode: SearchMode, $limit: Int) {
|
|
215
|
-
combinedSearch(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
214
|
+
query CombinedSearch($packages: [SearchPackageInput!]!, $query: String!, $mode: SearchMode, $limit: Int, $waitTimeoutMs: Int) {
|
|
215
|
+
combinedSearch(
|
|
216
|
+
packages: $packages
|
|
217
|
+
query: $query
|
|
218
|
+
mode: $mode
|
|
219
|
+
limit: $limit
|
|
220
|
+
waitTimeoutMs: $waitTimeoutMs
|
|
221
|
+
) {
|
|
222
|
+
completed
|
|
223
|
+
searchRef
|
|
224
|
+
result {
|
|
225
|
+
query
|
|
226
|
+
mode
|
|
227
|
+
totalResults
|
|
228
|
+
entries {
|
|
229
|
+
id
|
|
230
|
+
type
|
|
231
|
+
title
|
|
232
|
+
subtitle
|
|
233
|
+
packageName
|
|
234
|
+
registry
|
|
235
|
+
score
|
|
236
|
+
snippet
|
|
237
|
+
filePath
|
|
238
|
+
startLine
|
|
239
|
+
endLine
|
|
240
|
+
language
|
|
241
|
+
chunkType
|
|
242
|
+
repoUrl
|
|
243
|
+
gitRef
|
|
244
|
+
pageId
|
|
245
|
+
sourceUrl
|
|
246
|
+
}
|
|
247
|
+
indexingStatus {
|
|
248
|
+
registry
|
|
249
|
+
packageName
|
|
250
|
+
version
|
|
251
|
+
codeStatus
|
|
252
|
+
docsStatus
|
|
253
|
+
}
|
|
237
254
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
docsStatus
|
|
255
|
+
progress {
|
|
256
|
+
status
|
|
257
|
+
packagesTotal
|
|
258
|
+
packagesReady
|
|
259
|
+
elapsedMs
|
|
244
260
|
}
|
|
245
261
|
}
|
|
246
262
|
}
|
|
@@ -1419,7 +1435,8 @@ class PkgseerServiceImpl {
|
|
|
1419
1435
|
packages,
|
|
1420
1436
|
query,
|
|
1421
1437
|
mode: options?.mode,
|
|
1422
|
-
limit: options?.limit
|
|
1438
|
+
limit: options?.limit,
|
|
1439
|
+
waitTimeoutMs: options?.waitTimeoutMs
|
|
1423
1440
|
});
|
|
1424
1441
|
return { data: result.data, errors: result.errors };
|
|
1425
1442
|
}
|
|
@@ -2342,6 +2359,7 @@ function registerDocsListCommand(program) {
|
|
|
2342
2359
|
});
|
|
2343
2360
|
}
|
|
2344
2361
|
// src/commands/search.ts
|
|
2362
|
+
var DEFAULT_WAIT_TIMEOUT_MS = 30000;
|
|
2345
2363
|
var colors = {
|
|
2346
2364
|
reset: "\x1B[0m",
|
|
2347
2365
|
bold: "\x1B[1m",
|
|
@@ -2562,6 +2580,36 @@ function truncate(text, maxLen) {
|
|
|
2562
2580
|
return text;
|
|
2563
2581
|
return `${text.slice(0, maxLen - 3)}...`;
|
|
2564
2582
|
}
|
|
2583
|
+
function isSubstantiveLine(line) {
|
|
2584
|
+
const trimmed = line.trim();
|
|
2585
|
+
if (trimmed.length === 0)
|
|
2586
|
+
return false;
|
|
2587
|
+
if (/^[(){}[\];,]+$/.test(trimmed))
|
|
2588
|
+
return false;
|
|
2589
|
+
if (trimmed.length <= 3 && /^[^a-zA-Z0-9]*$/.test(trimmed))
|
|
2590
|
+
return false;
|
|
2591
|
+
return true;
|
|
2592
|
+
}
|
|
2593
|
+
function findBestSnippetLine(snippet) {
|
|
2594
|
+
const lines = snippet.split(`
|
|
2595
|
+
`).map((l) => l.trim());
|
|
2596
|
+
if (lines.length === 0)
|
|
2597
|
+
return null;
|
|
2598
|
+
const middleIndex = Math.floor((lines.length - 1) / 2);
|
|
2599
|
+
for (let offset = 0;offset <= lines.length; offset++) {
|
|
2600
|
+
const beforeIdx = middleIndex - offset;
|
|
2601
|
+
if (beforeIdx >= 0 && isSubstantiveLine(lines[beforeIdx])) {
|
|
2602
|
+
return lines[beforeIdx];
|
|
2603
|
+
}
|
|
2604
|
+
if (offset > 0) {
|
|
2605
|
+
const afterIdx = middleIndex + offset;
|
|
2606
|
+
if (afterIdx < lines.length && isSubstantiveLine(lines[afterIdx])) {
|
|
2607
|
+
return lines[afterIdx];
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
return null;
|
|
2612
|
+
}
|
|
2565
2613
|
function formatEntryCompact(entry, useColors) {
|
|
2566
2614
|
if (!entry)
|
|
2567
2615
|
return "";
|
|
@@ -2579,12 +2627,11 @@ function formatEntryCompact(entry, useColors) {
|
|
|
2579
2627
|
}
|
|
2580
2628
|
let snippet = "";
|
|
2581
2629
|
if (entry.snippet) {
|
|
2582
|
-
const
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
snippet = ` ${truncate(firstLine, 80)}`;
|
|
2630
|
+
const bestLine = findBestSnippetLine(entry.snippet);
|
|
2631
|
+
if (bestLine) {
|
|
2632
|
+
snippet = ` ${truncate(bestLine, 80)}`;
|
|
2586
2633
|
if (useColors) {
|
|
2587
|
-
snippet = ` ${colors.dim}${truncate(
|
|
2634
|
+
snippet = ` ${colors.dim}${truncate(bestLine, 80)}${colors.reset}`;
|
|
2588
2635
|
}
|
|
2589
2636
|
}
|
|
2590
2637
|
}
|
|
@@ -2662,6 +2709,50 @@ function summarizeSearchResults(results) {
|
|
|
2662
2709
|
return lines.join(`
|
|
2663
2710
|
`);
|
|
2664
2711
|
}
|
|
2712
|
+
function formatSearchProgress(progress, searchRef, useColors) {
|
|
2713
|
+
const lines = [];
|
|
2714
|
+
if (useColors) {
|
|
2715
|
+
lines.push(`${colors.yellow}Search in progress...${colors.reset}`);
|
|
2716
|
+
} else {
|
|
2717
|
+
lines.push("Search in progress...");
|
|
2718
|
+
}
|
|
2719
|
+
if (progress) {
|
|
2720
|
+
const statusText = progress.status?.toLowerCase() ?? "unknown";
|
|
2721
|
+
lines.push(`Status: ${statusText}`);
|
|
2722
|
+
if (progress.packagesTotal != null && progress.packagesReady != null) {
|
|
2723
|
+
lines.push(`Packages: ${progress.packagesReady}/${progress.packagesTotal} ready`);
|
|
2724
|
+
}
|
|
2725
|
+
if (progress.elapsedMs != null) {
|
|
2726
|
+
lines.push(`Elapsed: ${(progress.elapsedMs / 1000).toFixed(1)}s`);
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
lines.push("");
|
|
2730
|
+
lines.push("Some packages may still be indexing.");
|
|
2731
|
+
lines.push("Run again in a moment for complete results.");
|
|
2732
|
+
if (searchRef) {
|
|
2733
|
+
lines.push("");
|
|
2734
|
+
if (useColors) {
|
|
2735
|
+
lines.push(`${colors.dim}Search ref: ${searchRef}${colors.reset}`);
|
|
2736
|
+
} else {
|
|
2737
|
+
lines.push(`Search ref: ${searchRef}`);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
return lines.join(`
|
|
2741
|
+
`);
|
|
2742
|
+
}
|
|
2743
|
+
function getWaitTimeoutMs(options) {
|
|
2744
|
+
if (options.noWait) {
|
|
2745
|
+
return 0;
|
|
2746
|
+
}
|
|
2747
|
+
if (options.wait) {
|
|
2748
|
+
const parsed = Number.parseInt(options.wait, 10);
|
|
2749
|
+
if (!Number.isNaN(parsed) && parsed >= 0) {
|
|
2750
|
+
return parsed;
|
|
2751
|
+
}
|
|
2752
|
+
console.warn(`Warning: Invalid --wait value "${options.wait}". Using default (${DEFAULT_WAIT_TIMEOUT_MS}ms).`);
|
|
2753
|
+
}
|
|
2754
|
+
return DEFAULT_WAIT_TIMEOUT_MS;
|
|
2755
|
+
}
|
|
2665
2756
|
async function searchAction(queryArg, options, deps, defaultMode = "ALL") {
|
|
2666
2757
|
const { pkgseerService } = deps;
|
|
2667
2758
|
const query = Array.isArray(queryArg) ? queryArg.join(" ") : queryArg ?? "";
|
|
@@ -2681,16 +2772,37 @@ async function searchAction(queryArg, options, deps, defaultMode = "ALL") {
|
|
|
2681
2772
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : 25;
|
|
2682
2773
|
const mode = options.mode ? toSearchMode(options.mode) : defaultMode;
|
|
2683
2774
|
const useColors = shouldUseColors(options.noColor);
|
|
2775
|
+
const waitTimeoutMs = getWaitTimeoutMs(options);
|
|
2684
2776
|
const result = await pkgseerService.combinedSearch(packages, query, {
|
|
2685
2777
|
mode,
|
|
2686
|
-
limit
|
|
2778
|
+
limit,
|
|
2779
|
+
waitTimeoutMs
|
|
2687
2780
|
});
|
|
2688
2781
|
handleErrors(result.errors, options.json ?? false);
|
|
2689
|
-
|
|
2782
|
+
const asyncResult = result.data.combinedSearch;
|
|
2783
|
+
if (!asyncResult) {
|
|
2690
2784
|
outputError("No results returned. Check package names and registries.", options.json ?? false);
|
|
2691
2785
|
return;
|
|
2692
2786
|
}
|
|
2693
|
-
|
|
2787
|
+
if (!asyncResult.completed) {
|
|
2788
|
+
if (options.json) {
|
|
2789
|
+
output({
|
|
2790
|
+
completed: false,
|
|
2791
|
+
searchRef: asyncResult.searchRef,
|
|
2792
|
+
progress: asyncResult.progress,
|
|
2793
|
+
message: "Search is still indexing. Retry for complete results."
|
|
2794
|
+
}, true);
|
|
2795
|
+
} else {
|
|
2796
|
+
console.log(formatSearchProgress(asyncResult.progress, asyncResult.searchRef, useColors));
|
|
2797
|
+
}
|
|
2798
|
+
return;
|
|
2799
|
+
}
|
|
2800
|
+
const searchResults = asyncResult.result;
|
|
2801
|
+
if (!searchResults) {
|
|
2802
|
+
outputError("Search completed but no results returned.", options.json ?? false);
|
|
2803
|
+
return;
|
|
2804
|
+
}
|
|
2805
|
+
outputResults(searchResults, options, useColors);
|
|
2694
2806
|
}
|
|
2695
2807
|
function outputResults(results, options, useColors) {
|
|
2696
2808
|
const format = options.json ? "json" : options.format ?? "human";
|
|
@@ -2741,7 +2853,7 @@ Examples:
|
|
|
2741
2853
|
# JSON output
|
|
2742
2854
|
pkgseer search "error" -P express --json`;
|
|
2743
2855
|
function addSearchOptions(cmd) {
|
|
2744
|
-
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");
|
|
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");
|
|
2745
2857
|
}
|
|
2746
2858
|
function registerSearchCommand(program) {
|
|
2747
2859
|
const cmd = program.command("search [query...]").summary("Search code and documentation across packages").description(SEARCH_DESCRIPTION);
|
|
@@ -2782,7 +2894,7 @@ Examples:
|
|
|
2782
2894
|
|
|
2783
2895
|
Note: For code search, use 'pkgseer search --mode code' instead.`;
|
|
2784
2896
|
function addDocsSearchOptions(cmd) {
|
|
2785
|
-
return cmd.option("-P, --packages <packages>", "Packages to search (comma-separated). Format: [registry:]name[@version]. Examples: express | express,lodash | pypi:django@4.2").option("-l, --limit <n>", "Max results (default: 25)").option("-v, --verbose", "Expanded output with more details").option("--refs-only", "Output only references (for piping)").option("--count", "Output result counts by package").option("--format <format>", "Output format: human|summary|json", "human").option("--no-color", "Disable colored output").option("--json", "Output as JSON");
|
|
2897
|
+
return cmd.option("-P, --packages <packages>", "Packages to search (comma-separated). Format: [registry:]name[@version]. Examples: express | express,lodash | pypi:django@4.2").option("-l, --limit <n>", "Max results (default: 25)").option("-v, --verbose", "Expanded output with more details").option("--refs-only", "Output only references (for piping)").option("--count", "Output result counts by package").option("--format <format>", "Output format: human|summary|json", "human").option("--no-color", "Disable colored output").option("--json", "Output as JSON").option("--wait <ms>", "Max milliseconds to wait for indexing (default: 30000)").option("--no-wait", "Return immediately without waiting for indexing");
|
|
2786
2898
|
}
|
|
2787
2899
|
function registerDocsSearchCommand(program) {
|
|
2788
2900
|
const cmd = program.command("search [query...]").summary("Search documentation").description(DOCS_SEARCH_DESCRIPTION);
|
|
@@ -4951,11 +5063,13 @@ var packageInputSchema2 = z7.object({
|
|
|
4951
5063
|
name: z7.string().min(1).describe("Package name"),
|
|
4952
5064
|
version: z7.string().optional().describe("Specific version (defaults to latest)")
|
|
4953
5065
|
});
|
|
5066
|
+
var DEFAULT_AGENT_WAIT_TIMEOUT_MS = 1e4;
|
|
4954
5067
|
var argsSchema9 = {
|
|
4955
5068
|
packages: z7.array(packageInputSchema2).min(1).max(20).describe("Packages to search (1-20). Each package needs registry and name."),
|
|
4956
5069
|
query: z7.string().min(1).describe("Search query - natural language or keywords"),
|
|
4957
5070
|
mode: z7.enum(["all", "code", "docs"]).optional().describe('Search mode: "all" (default), "code" only, or "docs" only'),
|
|
4958
|
-
limit: z7.number().int().min(1).max(100).optional().describe("Maximum results (default: 20)")
|
|
5071
|
+
limit: z7.number().int().min(1).max(100).optional().describe("Maximum results (default: 20)"),
|
|
5072
|
+
waitTimeoutMs: z7.number().int().min(0).max(60000).optional().describe("Max milliseconds to wait for indexing (default: 10000, 0=immediate)")
|
|
4959
5073
|
};
|
|
4960
5074
|
function toSearchMode2(mode) {
|
|
4961
5075
|
if (!mode)
|
|
@@ -4993,9 +5107,9 @@ Results may be incomplete. Retry later for more complete results.`;
|
|
|
4993
5107
|
function createSearchTool(pkgseerService) {
|
|
4994
5108
|
return {
|
|
4995
5109
|
name: "search",
|
|
4996
|
-
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.",
|
|
5110
|
+
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.",
|
|
4997
5111
|
schema: argsSchema9,
|
|
4998
|
-
handler: async ({ packages, query, mode, limit }, _extra) => {
|
|
5112
|
+
handler: async ({ packages, query, mode, limit, waitTimeoutMs }, _extra) => {
|
|
4999
5113
|
return withErrorHandling("search packages", async () => {
|
|
5000
5114
|
const normalizedQuery = query.trim();
|
|
5001
5115
|
if (normalizedQuery.length === 0) {
|
|
@@ -5008,15 +5122,29 @@ function createSearchTool(pkgseerService) {
|
|
|
5008
5122
|
}));
|
|
5009
5123
|
const result = await pkgseerService.combinedSearch(graphqlPackages, normalizedQuery, {
|
|
5010
5124
|
mode: toSearchMode2(mode),
|
|
5011
|
-
limit
|
|
5125
|
+
limit,
|
|
5126
|
+
waitTimeoutMs: waitTimeoutMs ?? DEFAULT_AGENT_WAIT_TIMEOUT_MS
|
|
5012
5127
|
});
|
|
5013
5128
|
const graphqlError = handleGraphQLErrors(result.errors);
|
|
5014
5129
|
if (graphqlError)
|
|
5015
5130
|
return graphqlError;
|
|
5016
|
-
|
|
5131
|
+
const asyncResult = result.data.combinedSearch;
|
|
5132
|
+
if (!asyncResult) {
|
|
5017
5133
|
return errorResult("No search results returned. Check package names and registries.");
|
|
5018
5134
|
}
|
|
5019
|
-
|
|
5135
|
+
if (!asyncResult.completed) {
|
|
5136
|
+
const progressInfo = {
|
|
5137
|
+
completed: false,
|
|
5138
|
+
searchRef: asyncResult.searchRef,
|
|
5139
|
+
progress: asyncResult.progress,
|
|
5140
|
+
message: "Search is still indexing. Retry with same query for results, " + "or increase waitTimeoutMs to wait longer."
|
|
5141
|
+
};
|
|
5142
|
+
return textResult(JSON.stringify(progressInfo, null, 2));
|
|
5143
|
+
}
|
|
5144
|
+
const searchResult = asyncResult.result;
|
|
5145
|
+
if (!searchResult) {
|
|
5146
|
+
return errorResult("Search completed but no results returned.");
|
|
5147
|
+
}
|
|
5020
5148
|
const entries = searchResult.entries ?? [];
|
|
5021
5149
|
if (entries.length === 0) {
|
|
5022
5150
|
return errorResult(`No results found for "${normalizedQuery}". ` + "Try broader terms or different packages.");
|
package/dist/index.js
CHANGED