@ncukondo/search-hub 0.20.1 → 0.22.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 +44 -22
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +2 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/query/init.d.ts +20 -9
- package/dist/cli/commands/query/init.d.ts.map +1 -1
- package/dist/cli/commands/query/init.js +25 -10
- package/dist/cli/commands/query/init.js.map +1 -1
- package/dist/cli/commands/query/resolve.d.ts +5 -0
- package/dist/cli/commands/query/resolve.d.ts.map +1 -0
- package/dist/cli/commands/query/resolve.js +59 -0
- package/dist/cli/commands/query/resolve.js.map +1 -0
- package/dist/cli/entry-bun.d.ts +2 -0
- package/dist/cli/entry-bun.d.ts.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +58 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/suggestions/rules.d.ts.map +1 -1
- package/dist/cli/suggestions/rules.js +21 -9
- package/dist/cli/suggestions/rules.js.map +1 -1
- package/dist/cli/suggestions/types.d.ts +2 -0
- package/dist/cli/suggestions/types.d.ts.map +1 -1
- package/dist/node_modules/dom-serializer/lib/index.js +1 -1
- package/dist/node_modules/domelementtype/lib/index.js +1 -1
- package/dist/node_modules/nth-check/lib/index.js +1 -1
- package/dist/package.json.js +9 -0
- package/dist/package.json.js.map +1 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -3
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -17,7 +17,8 @@ import { createEricCountValidator, createEmtreeCountValidator } from "../query/v
|
|
|
17
17
|
import { createProviderInstance, executePreview, executeCountOnly, executeSearch } from "./commands/search-executor.js";
|
|
18
18
|
import { translateQueryCommand, formatTranslateResult } from "./commands/query/translate.js";
|
|
19
19
|
import { inspectQueryCommand, formatInspectOutput } from "./commands/query/inspect.js";
|
|
20
|
-
import { writeQueryTemplate
|
|
20
|
+
import { writeQueryTemplate } from "./commands/query/init.js";
|
|
21
|
+
import { resolveQueryFile } from "./commands/query/resolve.js";
|
|
21
22
|
import { getSessionDetails, computeDeduplicationStats, formatSessionDetails, listSessionsForDisplay, formatSessionList } from "./commands/status.js";
|
|
22
23
|
import { parseSearchOptions, validateSearchInput, formatShortKeywordWarning, formatDryRunOutput, formatPreviewOutput, formatCountOnlyOutput } from "./commands/search.js";
|
|
23
24
|
import { parseResumeOptions, validateResumeInput, getResumableProvidersForCommand } from "./commands/resume.js";
|
|
@@ -77,10 +78,10 @@ Workflow:
|
|
|
77
78
|
Iterate: search → results -q → check → diff Query refinement
|
|
78
79
|
|
|
79
80
|
Quick Start:
|
|
80
|
-
$ search-hub query init
|
|
81
|
-
$ search-hub search search
|
|
82
|
-
$ search-hub search search
|
|
83
|
-
$ search-hub results <session>
|
|
81
|
+
$ search-hub query init "my search" # Create query template
|
|
82
|
+
$ search-hub search my-search --count-only # Check hit counts
|
|
83
|
+
$ search-hub search my-search # Execute search
|
|
84
|
+
$ search-hub results <session> # Review titles`);
|
|
84
85
|
program.command("init").description("Initialize configuration directory").option("-f, --force", "overwrite existing configuration", false).addHelpText("after", `
|
|
85
86
|
Examples:
|
|
86
87
|
$ search-hub init # Initialize with default settings
|
|
@@ -190,9 +191,10 @@ Use "search-hub query init" to generate a template.`);
|
|
|
190
191
|
Examples:
|
|
191
192
|
$ search-hub query validate ./diabetes-ai.yaml
|
|
192
193
|
$ search-hub query validate ./diabetes-ai.yaml --no-vocab # Skip MeSH check
|
|
193
|
-
$ search-hub query validate ./diabetes-ai.yaml --no-cache # Ignore cache`).action(async (
|
|
194
|
+
$ search-hub query validate ./diabetes-ai.yaml --no-cache # Ignore cache`).action(async (fileArg, opts) => {
|
|
194
195
|
const globalOpts = program.opts();
|
|
195
196
|
try {
|
|
197
|
+
const file = await resolveQueryFile(fileArg);
|
|
196
198
|
const noVocab = opts.vocab === false;
|
|
197
199
|
const noCache = opts.cache === false;
|
|
198
200
|
let cache;
|
|
@@ -279,9 +281,10 @@ Examples:
|
|
|
279
281
|
queryCommand.command("translate").description("Show translated queries for each database").argument("<file>", "path to query YAML file").option("--db <provider>", "show translation for specific provider only").addHelpText("after", `
|
|
280
282
|
Examples:
|
|
281
283
|
$ search-hub query translate ./diabetes-ai.yaml # All databases
|
|
282
|
-
$ search-hub query translate ./diabetes-ai.yaml --db pubmed # PubMed only`).action(async (
|
|
284
|
+
$ search-hub query translate ./diabetes-ai.yaml --db pubmed # PubMed only`).action(async (fileArg, options) => {
|
|
283
285
|
const globalOpts = program.opts();
|
|
284
286
|
try {
|
|
287
|
+
const file = await resolveQueryFile(fileArg);
|
|
285
288
|
const translateOptions = options.db ? { providers: [options.db] } : {};
|
|
286
289
|
const result = await translateQueryCommand(file, translateOptions);
|
|
287
290
|
if (!globalOpts.quiet) {
|
|
@@ -301,9 +304,10 @@ Examples:
|
|
|
301
304
|
queryCommand.command("inspect").description("Show how a query resolves per provider (block replacements and added filters)").argument("<file>", "path to query YAML file").option("--db <provider>", "show resolution for specific provider only").addHelpText("after", `
|
|
302
305
|
Examples:
|
|
303
306
|
$ search-hub query inspect ./diabetes-ai.yaml # All databases
|
|
304
|
-
$ search-hub query inspect ./diabetes-ai.yaml --db pubmed # PubMed only`).action(async (
|
|
307
|
+
$ search-hub query inspect ./diabetes-ai.yaml --db pubmed # PubMed only`).action(async (fileArg, options) => {
|
|
305
308
|
const globalOpts = program.opts();
|
|
306
309
|
try {
|
|
310
|
+
const file = await resolveQueryFile(fileArg);
|
|
307
311
|
const inspectOptions = options.db ? { providers: [options.db] } : {};
|
|
308
312
|
const result = await inspectQueryCommand(file, inspectOptions);
|
|
309
313
|
if (!result.success) {
|
|
@@ -328,24 +332,35 @@ Examples:
|
|
|
328
332
|
process.exitCode = EXIT_CODES.QUERY_ERROR;
|
|
329
333
|
}
|
|
330
334
|
});
|
|
331
|
-
queryCommand.command("init").description("Generate a template query YAML file").option("-o, --output <path>", "write to file (
|
|
335
|
+
queryCommand.command("init").description("Generate a template query YAML file").argument("<title>", "query title (used for name field and filename)").option("-o, --output <path>", "write to specific file path").option("--stdout", "output to stdout instead of file").option("--force", "overwrite existing file", false).addHelpText("after", `
|
|
336
|
+
Examples:
|
|
337
|
+
$ search-hub query init "WBA pain mechanisms" # → queries/wba-pain-mechanisms.yaml
|
|
338
|
+
$ search-hub query init "WBA pain" -o ./custom-path.yaml # Custom output path
|
|
339
|
+
$ search-hub query init "WBA pain" --stdout # Print to stdout`).action(async (title, options) => {
|
|
332
340
|
const globalOpts = program.opts();
|
|
333
341
|
try {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
342
|
+
const result = await writeQueryTemplate({
|
|
343
|
+
title,
|
|
344
|
+
output: options.output,
|
|
345
|
+
stdout: options.stdout,
|
|
346
|
+
force: options.force
|
|
347
|
+
});
|
|
348
|
+
if (!globalOpts.quiet) {
|
|
349
|
+
if (result.success) {
|
|
350
|
+
console.log(result.message);
|
|
351
|
+
if (result.outputPath) {
|
|
352
|
+
const suggestion = formatSuggestion(getSuggestion({
|
|
353
|
+
command: "query init",
|
|
354
|
+
outputFile: result.outputPath
|
|
355
|
+
}));
|
|
356
|
+
if (suggestion) console.log("\n" + suggestion);
|
|
357
|
+
console.log("\nIterate: edit the same file and re-run step 3. Counts are logged automatically.");
|
|
341
358
|
}
|
|
359
|
+
} else {
|
|
360
|
+
console.error(result.message);
|
|
342
361
|
}
|
|
343
|
-
process.exitCode = result.success ? EXIT_CODES.SUCCESS : EXIT_CODES.GENERAL_ERROR;
|
|
344
|
-
} else {
|
|
345
|
-
const template = generateQueryTemplate();
|
|
346
|
-
console.log(template);
|
|
347
|
-
process.exitCode = EXIT_CODES.SUCCESS;
|
|
348
362
|
}
|
|
363
|
+
process.exitCode = result.success ? EXIT_CODES.SUCCESS : EXIT_CODES.GENERAL_ERROR;
|
|
349
364
|
} catch (error) {
|
|
350
365
|
if (!globalOpts.quiet) {
|
|
351
366
|
console.error("Error:", error instanceof Error ? error.message : error);
|
|
@@ -356,9 +371,10 @@ Examples:
|
|
|
356
371
|
queryCommand.command("assess").description("Record an assessment of the current query iteration").argument("<file>", "path to query YAML file").option("--verdict <verdict>", "assessment verdict (e.g., reject, good, refine)").option("--precision <precision>", "estimated precision (e.g., ~60%)").option("--comment <comment>", "free-text comment").addHelpText("after", `
|
|
357
372
|
Examples:
|
|
358
373
|
$ search-hub query assess query.yaml --verdict reject --comment "Too broad"
|
|
359
|
-
$ search-hub query assess query.yaml --verdict good --precision "~60%"`).action(async (
|
|
374
|
+
$ search-hub query assess query.yaml --verdict good --precision "~60%"`).action(async (fileArg, options) => {
|
|
360
375
|
const globalOpts = program.opts();
|
|
361
376
|
try {
|
|
377
|
+
const file = await resolveQueryFile(fileArg);
|
|
362
378
|
const result = await executeQueryAssess(file, options);
|
|
363
379
|
if (result.success) {
|
|
364
380
|
if (!globalOpts.quiet) {
|
|
@@ -386,9 +402,10 @@ Examples:
|
|
|
386
402
|
queryCommand.command("log").description("View the query iteration history").argument("<file>", "path to query YAML file").option("--json", "output as JSON").addHelpText("after", `
|
|
387
403
|
Examples:
|
|
388
404
|
$ search-hub query log query.yaml
|
|
389
|
-
$ search-hub query log query.yaml --json`).action(async (
|
|
405
|
+
$ search-hub query log query.yaml --json`).action(async (fileArg, options) => {
|
|
390
406
|
const globalOpts = program.opts();
|
|
391
407
|
try {
|
|
408
|
+
const file = await resolveQueryFile(fileArg);
|
|
392
409
|
const entries = await readLogEntries(file);
|
|
393
410
|
if (!globalOpts.quiet) {
|
|
394
411
|
console.log(formatLogOutput(entries, { json: options?.json }));
|
|
@@ -468,7 +485,8 @@ Query features (use "query init" to see full template):
|
|
|
468
485
|
async (queryFile, options) => {
|
|
469
486
|
const globalOpts = program.opts();
|
|
470
487
|
try {
|
|
471
|
-
const
|
|
488
|
+
const resolvedQueryFile = queryFile ? await resolveQueryFile(queryFile) : void 0;
|
|
489
|
+
const searchOpts = parseSearchOptions(resolvedQueryFile, {
|
|
472
490
|
db: options?.db,
|
|
473
491
|
query: options?.query,
|
|
474
492
|
name: options?.name,
|
|
@@ -683,11 +701,14 @@ Warning: Some providers failed:
|
|
|
683
701
|
if (result.sessionId) {
|
|
684
702
|
const sessions = await listSessions(sessionsDir);
|
|
685
703
|
const suggestionCmd = searchOpts.directQuery ? "search --query" : "search";
|
|
704
|
+
const currentSession = sessions.find((s) => s.id === result.sessionId);
|
|
705
|
+
const previousSession = currentSession ? sessions.filter((s) => s.name === currentSession.name && s.id !== result.sessionId).sort((a, b) => b.createdAt.localeCompare(a.createdAt))[0] : void 0;
|
|
686
706
|
const suggestion = formatSuggestion(getSuggestion({
|
|
687
707
|
command: suggestionCmd,
|
|
688
708
|
sessionId: result.sessionId,
|
|
689
709
|
sessionStatus: result.sessionStatus,
|
|
690
|
-
sessionCount: sessions.length
|
|
710
|
+
sessionCount: sessions.length,
|
|
711
|
+
previousSessionId: previousSession?.id
|
|
691
712
|
}));
|
|
692
713
|
if (suggestion) console.log(suggestion);
|
|
693
714
|
}
|
|
@@ -2183,11 +2204,18 @@ async function main() {
|
|
|
2183
2204
|
const currentFile = fileURLToPath(import.meta.url);
|
|
2184
2205
|
const executedFile = process.argv[1];
|
|
2185
2206
|
if (executedFile) {
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2207
|
+
try {
|
|
2208
|
+
if (realpathSync(executedFile) === realpathSync(currentFile)) {
|
|
2209
|
+
main().catch((error) => {
|
|
2210
|
+
console.error("Fatal error:", error);
|
|
2211
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
} catch (e) {
|
|
2215
|
+
const code = e instanceof Error ? e.code : void 0;
|
|
2216
|
+
if (code !== "ENOENT" && code !== "ERR_INVALID_ARG_TYPE") {
|
|
2217
|
+
console.error("[debug] Unexpected error resolving entry path:", e);
|
|
2218
|
+
}
|
|
2191
2219
|
}
|
|
2192
2220
|
}
|
|
2193
2221
|
export {
|