@ncukondo/search-hub 0.1.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/LICENSE +21 -0
- package/README.md +93 -0
- package/dist/_virtual/___vite-browser-external.js +7 -0
- package/dist/_virtual/___vite-browser-external.js.map +1 -0
- package/dist/_virtual/__vite-browser-external.js +5 -0
- package/dist/_virtual/__vite-browser-external.js.map +1 -0
- package/dist/_virtual/_commonjsHelpers.js +28 -0
- package/dist/_virtual/_commonjsHelpers.js.map +1 -0
- package/dist/_virtual/cli-progress.js +6 -0
- package/dist/_virtual/cli-progress.js.map +1 -0
- package/dist/_virtual/index.js +5 -0
- package/dist/_virtual/index.js.map +1 -0
- package/dist/_virtual/index2.js +5 -0
- package/dist/_virtual/index2.js.map +1 -0
- package/dist/cli/commands/config.d.ts +37 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +117 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/export.d.ts +26 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +86 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/init.d.ts +45 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +134 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/query/translate.d.ts +32 -0
- package/dist/cli/commands/query/translate.d.ts.map +1 -0
- package/dist/cli/commands/query/translate.js +76 -0
- package/dist/cli/commands/query/translate.js.map +1 -0
- package/dist/cli/commands/query/validate.d.ts +25 -0
- package/dist/cli/commands/query/validate.d.ts.map +1 -0
- package/dist/cli/commands/query/validate.js +68 -0
- package/dist/cli/commands/query/validate.js.map +1 -0
- package/dist/cli/commands/register.d.ts +39 -0
- package/dist/cli/commands/register.d.ts.map +1 -0
- package/dist/cli/commands/register.js +78 -0
- package/dist/cli/commands/register.js.map +1 -0
- package/dist/cli/commands/resume-executor.d.ts +19 -0
- package/dist/cli/commands/resume-executor.d.ts.map +1 -0
- package/dist/cli/commands/resume-executor.js +170 -0
- package/dist/cli/commands/resume-executor.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +26 -0
- package/dist/cli/commands/resume.d.ts.map +1 -0
- package/dist/cli/commands/resume.js +51 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/search-executor.d.ts +26 -0
- package/dist/cli/commands/search-executor.d.ts.map +1 -0
- package/dist/cli/commands/search-executor.js +315 -0
- package/dist/cli/commands/search-executor.js.map +1 -0
- package/dist/cli/commands/search.d.ts +30 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/search.js +67 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/status.d.ts +41 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +123 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/e2e-helpers.d.ts +165 -0
- package/dist/cli/e2e-helpers.d.ts.map +1 -0
- package/dist/cli/exit-codes.d.ts +25 -0
- package/dist/cli/exit-codes.d.ts.map +1 -0
- package/dist/cli/exit-codes.js +18 -0
- package/dist/cli/exit-codes.js.map +1 -0
- package/dist/cli/index.d.ts +25 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +638 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/progress.d.ts +24 -0
- package/dist/cli/utils/progress.d.ts.map +1 -0
- package/dist/cli/utils/progress.js +128 -0
- package/dist/cli/utils/progress.js.map +1 -0
- package/dist/cli/utils/sessions-dir.d.ts +14 -0
- package/dist/cli/utils/sessions-dir.d.ts.map +1 -0
- package/dist/cli/utils/sessions-dir.js +21 -0
- package/dist/cli/utils/sessions-dir.js.map +1 -0
- package/dist/cli/utils/validation.d.ts +18 -0
- package/dist/cli/utils/validation.d.ts.map +1 -0
- package/dist/cli/utils/validation.js +24 -0
- package/dist/cli/utils/validation.js.map +1 -0
- package/dist/config/defaults.d.ts +12 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +10 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/env.d.ts +12 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +36 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/loader.d.ts +49 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +72 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/paths.d.ts +23 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +22 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/schema.d.ts +109 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +74 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/integration/ref-cli.d.ts +41 -0
- package/dist/integration/ref-cli.d.ts.map +1 -0
- package/dist/integration/ref-cli.js +132 -0
- package/dist/integration/ref-cli.js.map +1 -0
- package/dist/integration/register.d.ts +27 -0
- package/dist/integration/register.d.ts.map +1 -0
- package/dist/integration/register.js +108 -0
- package/dist/integration/register.js.map +1 -0
- package/dist/integration/types.d.ts +61 -0
- package/dist/integration/types.d.ts.map +1 -0
- package/dist/integration/types.js +61 -0
- package/dist/integration/types.js.map +1 -0
- package/dist/node_modules/cli-progress/cli-progress.js +37 -0
- package/dist/node_modules/cli-progress/cli-progress.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/eta.js +52 -0
- package/dist/node_modules/cli-progress/lib/eta.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/format-bar.js +16 -0
- package/dist/node_modules/cli-progress/lib/format-bar.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/format-time.js +32 -0
- package/dist/node_modules/cli-progress/lib/format-time.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/format-value.js +25 -0
- package/dist/node_modules/cli-progress/lib/format-value.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/formatter.js +57 -0
- package/dist/node_modules/cli-progress/lib/formatter.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/generic-bar.js +137 -0
- package/dist/node_modules/cli-progress/lib/generic-bar.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/multi-bar.js +147 -0
- package/dist/node_modules/cli-progress/lib/multi-bar.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/options.js +59 -0
- package/dist/node_modules/cli-progress/lib/options.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/single-bar.js +95 -0
- package/dist/node_modules/cli-progress/lib/single-bar.js.map +1 -0
- package/dist/node_modules/cli-progress/lib/terminal.js +125 -0
- package/dist/node_modules/cli-progress/lib/terminal.js.map +1 -0
- package/dist/node_modules/cli-progress/node_modules/ansi-regex/index.js +18 -0
- package/dist/node_modules/cli-progress/node_modules/ansi-regex/index.js.map +1 -0
- package/dist/node_modules/cli-progress/node_modules/emoji-regex/index.js +14 -0
- package/dist/node_modules/cli-progress/node_modules/emoji-regex/index.js.map +1 -0
- package/dist/node_modules/cli-progress/node_modules/string-width/index.js +44 -0
- package/dist/node_modules/cli-progress/node_modules/string-width/index.js.map +1 -0
- package/dist/node_modules/cli-progress/node_modules/strip-ansi/index.js +14 -0
- package/dist/node_modules/cli-progress/node_modules/strip-ansi/index.js.map +1 -0
- package/dist/node_modules/cli-progress/presets/index.js +25 -0
- package/dist/node_modules/cli-progress/presets/index.js.map +1 -0
- package/dist/node_modules/cli-progress/presets/legacy.js +16 -0
- package/dist/node_modules/cli-progress/presets/legacy.js.map +1 -0
- package/dist/node_modules/cli-progress/presets/rect.js +16 -0
- package/dist/node_modules/cli-progress/presets/rect.js.map +1 -0
- package/dist/node_modules/cli-progress/presets/shades-classic.js +16 -0
- package/dist/node_modules/cli-progress/presets/shades-classic.js.map +1 -0
- package/dist/node_modules/cli-progress/presets/shades-grey.js +16 -0
- package/dist/node_modules/cli-progress/presets/shades-grey.js.map +1 -0
- package/dist/node_modules/env-paths/index.js +58 -0
- package/dist/node_modules/env-paths/index.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/ignoreAttributes.js +22 -0
- package/dist/node_modules/fast-xml-parser/src/ignoreAttributes.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/util.js +33 -0
- package/dist/node_modules/fast-xml-parser/src/util.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/validator.js +309 -0
- package/dist/node_modules/fast-xml-parser/src/validator.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js +265 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js +53 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js +515 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js +68 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/node2json.js +88 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/node2json.js.map +1 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js +36 -0
- package/dist/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js.map +1 -0
- package/dist/node_modules/is-fullwidth-code-point/index.js +37 -0
- package/dist/node_modules/is-fullwidth-code-point/index.js.map +1 -0
- package/dist/node_modules/strnum/strnum.js +100 -0
- package/dist/node_modules/strnum/strnum.js.map +1 -0
- package/dist/providers/arxiv/client.d.ts +54 -0
- package/dist/providers/arxiv/client.d.ts.map +1 -0
- package/dist/providers/arxiv/client.js +105 -0
- package/dist/providers/arxiv/client.js.map +1 -0
- package/dist/providers/arxiv/index.d.ts +14 -0
- package/dist/providers/arxiv/index.d.ts.map +1 -0
- package/dist/providers/arxiv/parser.d.ts +16 -0
- package/dist/providers/arxiv/parser.d.ts.map +1 -0
- package/dist/providers/arxiv/parser.js +144 -0
- package/dist/providers/arxiv/parser.js.map +1 -0
- package/dist/providers/arxiv/provider.d.ts +39 -0
- package/dist/providers/arxiv/provider.d.ts.map +1 -0
- package/dist/providers/arxiv/provider.js +153 -0
- package/dist/providers/arxiv/provider.js.map +1 -0
- package/dist/providers/arxiv/translator.d.ts +17 -0
- package/dist/providers/arxiv/translator.d.ts.map +1 -0
- package/dist/providers/arxiv/translator.js +112 -0
- package/dist/providers/arxiv/translator.js.map +1 -0
- package/dist/providers/arxiv/types.d.ts +71 -0
- package/dist/providers/arxiv/types.d.ts.map +1 -0
- package/dist/providers/arxiv/types.js +17 -0
- package/dist/providers/arxiv/types.js.map +1 -0
- package/dist/providers/base/index.d.ts +16 -0
- package/dist/providers/base/index.d.ts.map +1 -0
- package/dist/providers/base/mock-provider.d.ts +76 -0
- package/dist/providers/base/mock-provider.d.ts.map +1 -0
- package/dist/providers/base/mock-provider.js +159 -0
- package/dist/providers/base/mock-provider.js.map +1 -0
- package/dist/providers/base/provider.d.ts +95 -0
- package/dist/providers/base/provider.d.ts.map +1 -0
- package/dist/providers/base/provider.js +117 -0
- package/dist/providers/base/provider.js.map +1 -0
- package/dist/providers/base/rate-limiter.d.ts +70 -0
- package/dist/providers/base/rate-limiter.d.ts.map +1 -0
- package/dist/providers/base/rate-limiter.js +111 -0
- package/dist/providers/base/rate-limiter.js.map +1 -0
- package/dist/providers/base/registry.d.ts +52 -0
- package/dist/providers/base/registry.d.ts.map +1 -0
- package/dist/providers/base/registry.js +55 -0
- package/dist/providers/base/registry.js.map +1 -0
- package/dist/providers/base/types.d.ts +163 -0
- package/dist/providers/base/types.d.ts.map +1 -0
- package/dist/providers/base/types.js +29 -0
- package/dist/providers/base/types.js.map +1 -0
- package/dist/providers/eric/client.d.ts +40 -0
- package/dist/providers/eric/client.d.ts.map +1 -0
- package/dist/providers/eric/client.js +93 -0
- package/dist/providers/eric/client.js.map +1 -0
- package/dist/providers/eric/index.d.ts +14 -0
- package/dist/providers/eric/index.d.ts.map +1 -0
- package/dist/providers/eric/parser.d.ts +21 -0
- package/dist/providers/eric/parser.d.ts.map +1 -0
- package/dist/providers/eric/parser.js +86 -0
- package/dist/providers/eric/parser.js.map +1 -0
- package/dist/providers/eric/provider.d.ts +59 -0
- package/dist/providers/eric/provider.d.ts.map +1 -0
- package/dist/providers/eric/provider.js +166 -0
- package/dist/providers/eric/provider.js.map +1 -0
- package/dist/providers/eric/translator.d.ts +12 -0
- package/dist/providers/eric/translator.d.ts.map +1 -0
- package/dist/providers/eric/translator.js +81 -0
- package/dist/providers/eric/translator.js.map +1 -0
- package/dist/providers/eric/types.d.ts +84 -0
- package/dist/providers/eric/types.d.ts.map +1 -0
- package/dist/providers/pubmed/client.d.ts +54 -0
- package/dist/providers/pubmed/client.d.ts.map +1 -0
- package/dist/providers/pubmed/client.js +141 -0
- package/dist/providers/pubmed/client.js.map +1 -0
- package/dist/providers/pubmed/index.d.ts +27 -0
- package/dist/providers/pubmed/index.d.ts.map +1 -0
- package/dist/providers/pubmed/parser.d.ts +22 -0
- package/dist/providers/pubmed/parser.d.ts.map +1 -0
- package/dist/providers/pubmed/parser.js +174 -0
- package/dist/providers/pubmed/parser.js.map +1 -0
- package/dist/providers/pubmed/provider.d.ts +44 -0
- package/dist/providers/pubmed/provider.d.ts.map +1 -0
- package/dist/providers/pubmed/provider.js +224 -0
- package/dist/providers/pubmed/provider.js.map +1 -0
- package/dist/providers/pubmed/translator.d.ts +7 -0
- package/dist/providers/pubmed/translator.d.ts.map +1 -0
- package/dist/providers/pubmed/translator.js +143 -0
- package/dist/providers/pubmed/translator.js.map +1 -0
- package/dist/providers/pubmed/types.d.ts +72 -0
- package/dist/providers/pubmed/types.d.ts.map +1 -0
- package/dist/providers/scopus/client.d.ts +64 -0
- package/dist/providers/scopus/client.d.ts.map +1 -0
- package/dist/providers/scopus/client.js +155 -0
- package/dist/providers/scopus/client.js.map +1 -0
- package/dist/providers/scopus/index.d.ts +21 -0
- package/dist/providers/scopus/index.d.ts.map +1 -0
- package/dist/providers/scopus/parser.d.ts +11 -0
- package/dist/providers/scopus/parser.d.ts.map +1 -0
- package/dist/providers/scopus/parser.js +128 -0
- package/dist/providers/scopus/parser.js.map +1 -0
- package/dist/providers/scopus/provider.d.ts +39 -0
- package/dist/providers/scopus/provider.d.ts.map +1 -0
- package/dist/providers/scopus/provider.js +175 -0
- package/dist/providers/scopus/provider.js.map +1 -0
- package/dist/providers/scopus/translator.d.ts +7 -0
- package/dist/providers/scopus/translator.d.ts.map +1 -0
- package/dist/providers/scopus/translator.js +83 -0
- package/dist/providers/scopus/translator.js.map +1 -0
- package/dist/providers/scopus/types.d.ts +86 -0
- package/dist/providers/scopus/types.d.ts.map +1 -0
- package/dist/query/index.d.ts +12 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/parser.d.ts +18 -0
- package/dist/query/parser.d.ts.map +1 -0
- package/dist/query/parser.js +16 -0
- package/dist/query/parser.js.map +1 -0
- package/dist/query/types.d.ts +85 -0
- package/dist/query/types.d.ts.map +1 -0
- package/dist/query/validator.d.ts +635 -0
- package/dist/query/validator.d.ts.map +1 -0
- package/dist/query/validator.js +117 -0
- package/dist/query/validator.js.map +1 -0
- package/dist/session/index.d.ts +14 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/logger.d.ts +15 -0
- package/dist/session/logger.d.ts.map +1 -0
- package/dist/session/logger.js +18 -0
- package/dist/session/logger.js.map +1 -0
- package/dist/session/manager.d.ts +63 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +193 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/types.d.ts +182 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/utils/deep-merge.d.ts +17 -0
- package/dist/utils/deep-merge.d.ts.map +1 -0
- package/dist/utils/deep-merge.js +23 -0
- package/dist/utils/deep-merge.js.map +1 -0
- package/dist/utils/path.d.ts +9 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +15 -0
- package/dist/utils/path.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { readFile, appendFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { loadSession, getResumableProviders, updateDatabaseStatus, updateSessionStatus } from "../../session/manager.js";
|
|
4
|
+
import { MultiProviderProgress } from "../utils/progress.js";
|
|
5
|
+
import { createProviderInstance } from "./search-executor.js";
|
|
6
|
+
function isResumable(provider) {
|
|
7
|
+
return "resumeSearch" in provider && typeof provider.resumeSearch === "function";
|
|
8
|
+
}
|
|
9
|
+
async function executeResume(options, sessionsDir, config, showProgress = true) {
|
|
10
|
+
let session;
|
|
11
|
+
try {
|
|
12
|
+
session = await loadSession(options.sessionId, sessionsDir);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
return {
|
|
15
|
+
success: false,
|
|
16
|
+
resumed: 0,
|
|
17
|
+
error: `Failed to load session: ${error instanceof Error ? error.message : error}`
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
let resumableProviders = getResumableProviders(session);
|
|
21
|
+
if (options.providers && options.providers.length > 0) {
|
|
22
|
+
resumableProviders = resumableProviders.filter(
|
|
23
|
+
(r) => options.providers.includes(r.provider)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
if (options.retryFailed) {
|
|
27
|
+
resumableProviders = resumableProviders.filter((r) => r.strategy === "retry");
|
|
28
|
+
}
|
|
29
|
+
if (resumableProviders.length === 0) {
|
|
30
|
+
return {
|
|
31
|
+
success: true,
|
|
32
|
+
resumed: 0,
|
|
33
|
+
error: "No providers to resume"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const results = {};
|
|
37
|
+
let progress;
|
|
38
|
+
if (showProgress && process.stdout.isTTY) {
|
|
39
|
+
progress = new MultiProviderProgress(resumableProviders.map((p) => p.provider));
|
|
40
|
+
}
|
|
41
|
+
let successCount = 0;
|
|
42
|
+
for (const resumable of resumableProviders) {
|
|
43
|
+
const providerName = resumable.provider;
|
|
44
|
+
const dbStatus = session.databases[providerName];
|
|
45
|
+
if (!dbStatus) continue;
|
|
46
|
+
try {
|
|
47
|
+
const provider = createProviderInstance(providerName, config);
|
|
48
|
+
const queryPath = join(sessionsDir, options.sessionId, dbStatus.files.query);
|
|
49
|
+
let nativeQuery;
|
|
50
|
+
try {
|
|
51
|
+
nativeQuery = await readFile(queryPath, "utf-8");
|
|
52
|
+
} catch {
|
|
53
|
+
progress?.fail(providerName, "Query file not found");
|
|
54
|
+
results[providerName] = { hits: 0, retrieved: 0 };
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const translatedQuery = {
|
|
58
|
+
native: nativeQuery.trim(),
|
|
59
|
+
provider: providerName
|
|
60
|
+
};
|
|
61
|
+
await updateDatabaseStatus(
|
|
62
|
+
options.sessionId,
|
|
63
|
+
providerName,
|
|
64
|
+
{
|
|
65
|
+
status: "in_progress",
|
|
66
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
67
|
+
},
|
|
68
|
+
sessionsDir
|
|
69
|
+
);
|
|
70
|
+
const resultsPath = join(sessionsDir, options.sessionId, dbStatus.files.results);
|
|
71
|
+
let retrievedCount = dbStatus.retrievedCount ?? 0;
|
|
72
|
+
const totalHits = dbStatus.totalHits ?? 0;
|
|
73
|
+
progress?.update(providerName, retrievedCount, totalHits || 100, "in_progress");
|
|
74
|
+
if (resumable.strategy === "continue" && isResumable(provider)) {
|
|
75
|
+
const searchState = {
|
|
76
|
+
provider: providerName,
|
|
77
|
+
query: translatedQuery,
|
|
78
|
+
totalResults: totalHits,
|
|
79
|
+
retrievedCount,
|
|
80
|
+
lastUpdated: /* @__PURE__ */ new Date(),
|
|
81
|
+
providerState: dbStatus.pagination ? {
|
|
82
|
+
cursor: dbStatus.pagination.cursor,
|
|
83
|
+
pageNumber: dbStatus.pagination.pageNumber
|
|
84
|
+
} : void 0
|
|
85
|
+
};
|
|
86
|
+
for await (const article of provider.resumeSearch(searchState)) {
|
|
87
|
+
retrievedCount++;
|
|
88
|
+
await appendFile(resultsPath, JSON.stringify(article) + "\n", "utf-8");
|
|
89
|
+
progress?.update(providerName, retrievedCount, totalHits || retrievedCount, "in_progress");
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
const searchOptions = {
|
|
93
|
+
maxResults: config.providers[providerName].max_results
|
|
94
|
+
};
|
|
95
|
+
for await (const article of provider.search(translatedQuery, searchOptions)) {
|
|
96
|
+
retrievedCount++;
|
|
97
|
+
await appendFile(resultsPath, JSON.stringify(article) + "\n", "utf-8");
|
|
98
|
+
progress?.update(providerName, retrievedCount, totalHits || retrievedCount * 2, "in_progress");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
progress?.complete(providerName);
|
|
102
|
+
await updateDatabaseStatus(
|
|
103
|
+
options.sessionId,
|
|
104
|
+
providerName,
|
|
105
|
+
{
|
|
106
|
+
status: "completed",
|
|
107
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
108
|
+
totalHits: totalHits || retrievedCount,
|
|
109
|
+
retrievedCount
|
|
110
|
+
},
|
|
111
|
+
sessionsDir
|
|
112
|
+
);
|
|
113
|
+
results[providerName] = { hits: totalHits || retrievedCount, retrieved: retrievedCount };
|
|
114
|
+
successCount++;
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
117
|
+
progress?.fail(providerName, errorMessage);
|
|
118
|
+
await updateDatabaseStatus(
|
|
119
|
+
options.sessionId,
|
|
120
|
+
providerName,
|
|
121
|
+
{
|
|
122
|
+
status: "failed",
|
|
123
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
124
|
+
error: {
|
|
125
|
+
code: "RESUME_ERROR",
|
|
126
|
+
message: errorMessage,
|
|
127
|
+
retryable: true
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
sessionsDir
|
|
131
|
+
);
|
|
132
|
+
results[providerName] = { hits: 0, retrieved: 0 };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
progress?.stop();
|
|
136
|
+
const anyFailed = resumableProviders.some((p) => {
|
|
137
|
+
const r = results[p.provider];
|
|
138
|
+
return r && r.retrieved === 0 && r.hits === 0;
|
|
139
|
+
});
|
|
140
|
+
const anySucceeded = resumableProviders.some((p) => {
|
|
141
|
+
const r = results[p.provider];
|
|
142
|
+
return r && r.retrieved > 0;
|
|
143
|
+
});
|
|
144
|
+
let sessionStatus;
|
|
145
|
+
if (!anyFailed) {
|
|
146
|
+
sessionStatus = "completed";
|
|
147
|
+
} else if (anySucceeded) {
|
|
148
|
+
sessionStatus = "partial";
|
|
149
|
+
} else {
|
|
150
|
+
sessionStatus = "failed";
|
|
151
|
+
}
|
|
152
|
+
await updateSessionStatus(options.sessionId, sessionStatus, sessionsDir);
|
|
153
|
+
if (sessionStatus === "failed") {
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
resumed: successCount,
|
|
157
|
+
results,
|
|
158
|
+
error: "All providers failed"
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
resumed: successCount,
|
|
164
|
+
results
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export {
|
|
168
|
+
executeResume
|
|
169
|
+
};
|
|
170
|
+
//# sourceMappingURL=resume-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume-executor.js","sources":["../../../src/cli/commands/resume-executor.ts"],"sourcesContent":["/**\n * Resume executor for CLI resume command.\n *\n * Handles resuming interrupted search sessions by continuing\n * from where providers left off or retrying failed providers.\n */\nimport { readFile, appendFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { ResumeCommandOptions } from './resume.js';\nimport type { Config } from '../../config/index.js';\nimport type {\n Provider,\n TranslatedQuery,\n SearchState,\n} from '../../providers/base/types.js';\nimport {\n loadSession,\n updateDatabaseStatus,\n updateSessionStatus,\n getResumableProviders,\n} from '../../session/manager.js';\nimport { MultiProviderProgress } from '../utils/progress.js';\nimport { createProviderInstance } from './search-executor.js';\n\n/**\n * Result of a resume execution.\n */\nexport interface ResumeExecutionResult {\n success: boolean;\n resumed: number;\n results?: Record<string, { hits: number; retrieved: number }>;\n error?: string;\n}\n\n/**\n * Interface for providers that support resuming.\n */\ninterface ResumableProviderInstance extends Provider {\n resumeSearch(state: SearchState): AsyncIterable<import('../../providers/base/types.js').Article>;\n}\n\n/**\n * Check if a provider instance supports resuming.\n */\nfunction isResumable(provider: Provider): provider is ResumableProviderInstance {\n return 'resumeSearch' in provider && typeof (provider as any).resumeSearch === 'function';\n}\n\n/**\n * Execute resume for interrupted sessions.\n */\nexport async function executeResume(\n options: ResumeCommandOptions,\n sessionsDir: string,\n config: Config,\n showProgress = true\n): Promise<ResumeExecutionResult> {\n // Load session\n let session;\n try {\n session = await loadSession(options.sessionId, sessionsDir);\n } catch (error) {\n return {\n success: false,\n resumed: 0,\n error: `Failed to load session: ${error instanceof Error ? error.message : error}`,\n };\n }\n\n // Get resumable providers\n let resumableProviders = getResumableProviders(session);\n\n // Filter by specific providers if requested\n if (options.providers && options.providers.length > 0) {\n resumableProviders = resumableProviders.filter((r) =>\n options.providers!.includes(r.provider)\n );\n }\n\n // Filter to only retry strategies if retryFailed is true\n if (options.retryFailed) {\n resumableProviders = resumableProviders.filter((r) => r.strategy === 'retry');\n }\n\n if (resumableProviders.length === 0) {\n return {\n success: true,\n resumed: 0,\n error: 'No providers to resume',\n };\n }\n\n const results: Record<string, { hits: number; retrieved: number }> = {};\n\n // Create progress display if enabled\n let progress: MultiProviderProgress | undefined;\n if (showProgress && process.stdout.isTTY) {\n progress = new MultiProviderProgress(resumableProviders.map((p) => p.provider));\n }\n\n let successCount = 0;\n\n // Resume each provider\n for (const resumable of resumableProviders) {\n const providerName = resumable.provider;\n const dbStatus = session.databases[providerName];\n\n if (!dbStatus) continue;\n\n try {\n // Create provider instance\n const provider = createProviderInstance(providerName, config);\n\n // Build the translated query from stored query file\n const queryPath = join(sessionsDir, options.sessionId, dbStatus.files.query);\n let nativeQuery: string;\n try {\n nativeQuery = await readFile(queryPath, 'utf-8');\n } catch {\n // If query file doesn't exist, skip this provider\n progress?.fail(providerName, 'Query file not found');\n results[providerName] = { hits: 0, retrieved: 0 };\n continue;\n }\n\n const translatedQuery: TranslatedQuery = {\n native: nativeQuery.trim(),\n provider: providerName,\n };\n\n // Update database status to in_progress\n await updateDatabaseStatus(\n options.sessionId,\n providerName,\n {\n status: 'in_progress',\n startedAt: new Date().toISOString(),\n },\n sessionsDir\n );\n\n // Prepare results file path\n const resultsPath = join(sessionsDir, options.sessionId, dbStatus.files.results);\n\n let retrievedCount = dbStatus.retrievedCount ?? 0;\n const totalHits = dbStatus.totalHits ?? 0;\n\n progress?.update(providerName, retrievedCount, totalHits || 100, 'in_progress');\n\n // Determine how to resume\n if (resumable.strategy === 'continue' && isResumable(provider)) {\n // Build SearchState for continuing\n const searchState: SearchState = {\n provider: providerName,\n query: translatedQuery,\n totalResults: totalHits,\n retrievedCount,\n lastUpdated: new Date(),\n providerState: dbStatus.pagination\n ? {\n cursor: dbStatus.pagination.cursor,\n pageNumber: dbStatus.pagination.pageNumber,\n }\n : undefined,\n };\n\n // Resume search\n for await (const article of provider.resumeSearch(searchState)) {\n retrievedCount++;\n\n // Write article to JSONL file\n await appendFile(resultsPath, JSON.stringify(article) + '\\n', 'utf-8');\n\n progress?.update(providerName, retrievedCount, totalHits || retrievedCount, 'in_progress');\n }\n } else {\n // Fresh start or retry - use regular search\n const searchOptions = {\n maxResults: config.providers[providerName].max_results,\n };\n\n for await (const article of provider.search(translatedQuery, searchOptions)) {\n retrievedCount++;\n\n // Write article to JSONL file\n await appendFile(resultsPath, JSON.stringify(article) + '\\n', 'utf-8');\n\n progress?.update(providerName, retrievedCount, totalHits || retrievedCount * 2, 'in_progress');\n }\n }\n\n // Mark as completed\n progress?.complete(providerName);\n\n // Update database status\n await updateDatabaseStatus(\n options.sessionId,\n providerName,\n {\n status: 'completed',\n completedAt: new Date().toISOString(),\n totalHits: totalHits || retrievedCount,\n retrievedCount,\n },\n sessionsDir\n );\n\n results[providerName] = { hits: totalHits || retrievedCount, retrieved: retrievedCount };\n successCount++;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n progress?.fail(providerName, errorMessage);\n\n // Update database status with error\n await updateDatabaseStatus(\n options.sessionId,\n providerName,\n {\n status: 'failed',\n completedAt: new Date().toISOString(),\n error: {\n code: 'RESUME_ERROR',\n message: errorMessage,\n retryable: true,\n },\n },\n sessionsDir\n );\n\n results[providerName] = { hits: 0, retrieved: 0 };\n }\n }\n\n // Stop progress display\n progress?.stop();\n\n // Determine overall session status\n const anyFailed = resumableProviders.some((p) => {\n const r = results[p.provider];\n return r && r.retrieved === 0 && r.hits === 0;\n });\n const anySucceeded = resumableProviders.some((p) => {\n const r = results[p.provider];\n return r && r.retrieved > 0;\n });\n\n let sessionStatus: 'completed' | 'partial' | 'failed';\n if (!anyFailed) {\n sessionStatus = 'completed';\n } else if (anySucceeded) {\n sessionStatus = 'partial';\n } else {\n sessionStatus = 'failed';\n }\n\n // Update session status\n await updateSessionStatus(options.sessionId, sessionStatus, sessionsDir);\n\n if (sessionStatus === 'failed') {\n return {\n success: false,\n resumed: successCount,\n results,\n error: 'All providers failed',\n };\n }\n\n return {\n success: true,\n resumed: successCount,\n results,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ProviderName, ResumableProvider } from '../../session/types.js';
|
|
2
|
+
export interface ResumeCommandOptions {
|
|
3
|
+
sessionId: string;
|
|
4
|
+
providers?: ProviderName[];
|
|
5
|
+
retryFailed?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface CommandLineOptions {
|
|
8
|
+
db?: string | undefined;
|
|
9
|
+
retryFailed?: boolean | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface ValidationResult {
|
|
12
|
+
valid: boolean;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ResumeResult {
|
|
16
|
+
success: boolean;
|
|
17
|
+
providers?: ResumableProvider[];
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function parseResumeOptions(sessionId: string, options: CommandLineOptions): ResumeCommandOptions;
|
|
21
|
+
export declare function validateResumeInput(options: ResumeCommandOptions): ValidationResult;
|
|
22
|
+
export declare function getResumableProvidersForCommand(sessionId: string, sessionsDir: string, options: {
|
|
23
|
+
providers?: ProviderName[] | undefined;
|
|
24
|
+
retryFailed?: boolean | undefined;
|
|
25
|
+
}): Promise<ResumeResult>;
|
|
26
|
+
//# sourceMappingURL=resume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/resume.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG9E,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kBAAkB,GAC1B,oBAAoB,CActB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,gBAAgB,CASnF;AAED,wBAAsB,+BAA+B,CACnD,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,GACrF,OAAO,CAAC,YAAY,CAAC,CA0BvB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { loadSession, getResumableProviders } from "../../session/manager.js";
|
|
2
|
+
import { parseProviderNames } from "../utils/validation.js";
|
|
3
|
+
function parseResumeOptions(sessionId, options) {
|
|
4
|
+
const result = {
|
|
5
|
+
sessionId
|
|
6
|
+
};
|
|
7
|
+
if (options.db) {
|
|
8
|
+
result.providers = parseProviderNames(options.db);
|
|
9
|
+
}
|
|
10
|
+
if (options.retryFailed) {
|
|
11
|
+
result.retryFailed = true;
|
|
12
|
+
}
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
function validateResumeInput(options) {
|
|
16
|
+
if (!options.sessionId || options.sessionId.trim() === "") {
|
|
17
|
+
return {
|
|
18
|
+
valid: false,
|
|
19
|
+
error: "A session ID is required"
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return { valid: true };
|
|
23
|
+
}
|
|
24
|
+
async function getResumableProvidersForCommand(sessionId, sessionsDir, options) {
|
|
25
|
+
try {
|
|
26
|
+
const session = await loadSession(sessionId, sessionsDir);
|
|
27
|
+
let resumable = getResumableProviders(session);
|
|
28
|
+
if (options.providers && options.providers.length > 0) {
|
|
29
|
+
resumable = resumable.filter((r) => options.providers.includes(r.provider));
|
|
30
|
+
}
|
|
31
|
+
if (options.retryFailed) {
|
|
32
|
+
resumable = resumable.filter((r) => r.strategy === "retry");
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
success: true,
|
|
36
|
+
providers: resumable
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
error: message
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
getResumableProvidersForCommand,
|
|
48
|
+
parseResumeOptions,
|
|
49
|
+
validateResumeInput
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.js","sources":["../../../src/cli/commands/resume.ts"],"sourcesContent":["import { loadSession, getResumableProviders } from '../../session/manager.js';\nimport type { ProviderName, ResumableProvider } from '../../session/types.js';\nimport { parseProviderNames } from '../utils/validation.js';\n\nexport interface ResumeCommandOptions {\n sessionId: string;\n providers?: ProviderName[];\n retryFailed?: boolean;\n}\n\nexport interface CommandLineOptions {\n db?: string | undefined;\n retryFailed?: boolean | undefined;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n error?: string;\n}\n\nexport interface ResumeResult {\n success: boolean;\n providers?: ResumableProvider[];\n error?: string;\n}\n\nexport function parseResumeOptions(\n sessionId: string,\n options: CommandLineOptions\n): ResumeCommandOptions {\n const result: ResumeCommandOptions = {\n sessionId,\n };\n\n if (options.db) {\n result.providers = parseProviderNames(options.db);\n }\n\n if (options.retryFailed) {\n result.retryFailed = true;\n }\n\n return result;\n}\n\nexport function validateResumeInput(options: ResumeCommandOptions): ValidationResult {\n if (!options.sessionId || options.sessionId.trim() === '') {\n return {\n valid: false,\n error: 'A session ID is required',\n };\n }\n\n return { valid: true };\n}\n\nexport async function getResumableProvidersForCommand(\n sessionId: string,\n sessionsDir: string,\n options: { providers?: ProviderName[] | undefined; retryFailed?: boolean | undefined }\n): Promise<ResumeResult> {\n try {\n const session = await loadSession(sessionId, sessionsDir);\n let resumable = getResumableProviders(session);\n\n // Filter by specific providers if requested\n if (options.providers && options.providers.length > 0) {\n resumable = resumable.filter((r) => options.providers!.includes(r.provider));\n }\n\n // Filter to only retry strategies if retryFailed is true\n if (options.retryFailed) {\n resumable = resumable.filter((r) => r.strategy === 'retry');\n }\n\n return {\n success: true,\n providers: resumable,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return {\n success: false,\n error: message,\n };\n }\n}\n"],"names":[],"mappings":";;AA0BO,SAAS,mBACd,WACA,SACsB;AACtB,QAAM,SAA+B;AAAA,IACnC;AAAA,EAAA;AAGF,MAAI,QAAQ,IAAI;AACd,WAAO,YAAY,mBAAmB,QAAQ,EAAE;AAAA,EAClD;AAEA,MAAI,QAAQ,aAAa;AACvB,WAAO,cAAc;AAAA,EACvB;AAEA,SAAO;AACT;AAEO,SAAS,oBAAoB,SAAiD;AACnF,MAAI,CAAC,QAAQ,aAAa,QAAQ,UAAU,KAAA,MAAW,IAAI;AACzD,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,SAAO,EAAE,OAAO,KAAA;AAClB;AAEA,eAAsB,gCACpB,WACA,aACA,SACuB;AACvB,MAAI;AACF,UAAM,UAAU,MAAM,YAAY,WAAW,WAAW;AACxD,QAAI,YAAY,sBAAsB,OAAO;AAG7C,QAAI,QAAQ,aAAa,QAAQ,UAAU,SAAS,GAAG;AACrD,kBAAY,UAAU,OAAO,CAAC,MAAM,QAAQ,UAAW,SAAS,EAAE,QAAQ,CAAC;AAAA,IAC7E;AAGA,QAAI,QAAQ,aAAa;AACvB,kBAAY,UAAU,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO;AAAA,IAC5D;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,WAAW;AAAA,IAAA;AAAA,EAEf,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IAAA;AAAA,EAEX;AACF;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SearchCommandOptions } from './search.js';
|
|
2
|
+
import { Config } from '../../config/index.js';
|
|
3
|
+
import { Provider, ProviderName } from '../../providers/base/types.js';
|
|
4
|
+
import { RegistrationRecord } from '../../integration/types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Result of a search execution.
|
|
7
|
+
*/
|
|
8
|
+
export interface SearchExecutionResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
sessionId?: string;
|
|
11
|
+
results?: Record<string, {
|
|
12
|
+
hits: number;
|
|
13
|
+
retrieved: number;
|
|
14
|
+
}>;
|
|
15
|
+
error?: string;
|
|
16
|
+
autoRegisterResult?: RegistrationRecord;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a provider instance for the given provider name.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createProviderInstance(name: ProviderName, config: Config): Provider;
|
|
22
|
+
/**
|
|
23
|
+
* Execute a search across multiple providers.
|
|
24
|
+
*/
|
|
25
|
+
export declare function executeSearch(options: SearchCommandOptions, sessionsDir: string, config: Config, showProgress?: boolean): Promise<SearchExecutionResult>;
|
|
26
|
+
//# sourceMappingURL=search-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-executor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/search-executor.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAEV,QAAQ,EACR,YAAY,EAEb,MAAM,+BAA+B,CAAC;AAqBvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGrE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAOD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,MAAM,GACb,QAAQ,CAgDV;AAyCD;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,EAC7B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,YAAY,UAAO,GAClB,OAAO,CAAC,qBAAqB,CAAC,CA8QhC"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { readFile, writeFile, appendFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { parseQueryString } from "../../query/parser.js";
|
|
5
|
+
import "../../query/validator.js";
|
|
6
|
+
import { createSession, updateDatabaseStatus, updateSessionStatus } from "../../session/manager.js";
|
|
7
|
+
import { MultiProviderProgress } from "../utils/progress.js";
|
|
8
|
+
import { PubMedProvider } from "../../providers/pubmed/provider.js";
|
|
9
|
+
import { ERICProvider } from "../../providers/eric/provider.js";
|
|
10
|
+
import { ArxivProvider } from "../../providers/arxiv/provider.js";
|
|
11
|
+
import { ScopusProvider } from "../../providers/scopus/provider.js";
|
|
12
|
+
import { translateQuery as translateQuery$3 } from "../../providers/pubmed/translator.js";
|
|
13
|
+
import { translateQuery as translateQuery$2 } from "../../providers/eric/translator.js";
|
|
14
|
+
import { translateQuery as translateQuery$1 } from "../../providers/arxiv/translator.js";
|
|
15
|
+
import { translateQuery } from "../../providers/scopus/translator.js";
|
|
16
|
+
import { stringify } from "yaml";
|
|
17
|
+
import { registerArticles, saveRegistrationRecord } from "../../integration/register.js";
|
|
18
|
+
import { checkRefAvailable } from "../../integration/ref-cli.js";
|
|
19
|
+
const IMPLEMENTED_PROVIDERS = ["pubmed", "eric", "arxiv", "scopus"];
|
|
20
|
+
function createProviderInstance(name, config) {
|
|
21
|
+
const providerConfig = config.providers[name];
|
|
22
|
+
switch (name) {
|
|
23
|
+
case "pubmed": {
|
|
24
|
+
if (!providerConfig.email) {
|
|
25
|
+
console.warn(
|
|
26
|
+
"Warning: No email configured for PubMed. Set providers.pubmed.email in config."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const pubmedOpts = {
|
|
30
|
+
email: providerConfig.email ?? "search-hub@example.com",
|
|
31
|
+
rateLimit: providerConfig.rate_limit,
|
|
32
|
+
timeout: providerConfig.timeout,
|
|
33
|
+
retries: providerConfig.retries
|
|
34
|
+
};
|
|
35
|
+
if (providerConfig.api_key) {
|
|
36
|
+
pubmedOpts.apiKey = providerConfig.api_key;
|
|
37
|
+
}
|
|
38
|
+
return new PubMedProvider(pubmedOpts);
|
|
39
|
+
}
|
|
40
|
+
case "eric":
|
|
41
|
+
return new ERICProvider({
|
|
42
|
+
rateLimit: providerConfig.rate_limit,
|
|
43
|
+
timeout: providerConfig.timeout,
|
|
44
|
+
retries: providerConfig.retries
|
|
45
|
+
});
|
|
46
|
+
case "arxiv":
|
|
47
|
+
return new ArxivProvider({
|
|
48
|
+
rateLimit: providerConfig.rate_limit,
|
|
49
|
+
timeout: providerConfig.timeout,
|
|
50
|
+
retries: providerConfig.retries
|
|
51
|
+
});
|
|
52
|
+
case "scopus": {
|
|
53
|
+
const scopusOpts = {
|
|
54
|
+
apiKey: providerConfig.api_key ?? "",
|
|
55
|
+
rateLimit: providerConfig.rate_limit,
|
|
56
|
+
timeout: providerConfig.timeout,
|
|
57
|
+
retries: providerConfig.retries
|
|
58
|
+
};
|
|
59
|
+
if (providerConfig.inst_token) {
|
|
60
|
+
scopusOpts.instToken = providerConfig.inst_token;
|
|
61
|
+
}
|
|
62
|
+
return new ScopusProvider(scopusOpts);
|
|
63
|
+
}
|
|
64
|
+
default:
|
|
65
|
+
throw new Error(`Provider '${name}' is not implemented`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function translateQueryForProvider(ast, provider) {
|
|
69
|
+
switch (provider) {
|
|
70
|
+
case "pubmed":
|
|
71
|
+
return translateQuery$3(ast);
|
|
72
|
+
case "eric":
|
|
73
|
+
return translateQuery$2(ast);
|
|
74
|
+
case "arxiv":
|
|
75
|
+
return translateQuery$1(ast);
|
|
76
|
+
case "scopus":
|
|
77
|
+
return translateQuery(ast);
|
|
78
|
+
default:
|
|
79
|
+
throw new Error(`No translator for provider '${provider}'`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function getEnabledProviders(config, requestedProviders) {
|
|
83
|
+
const enabledInConfig = IMPLEMENTED_PROVIDERS.filter(
|
|
84
|
+
(name) => config.providers[name].enabled
|
|
85
|
+
);
|
|
86
|
+
if (requestedProviders && requestedProviders.length > 0) {
|
|
87
|
+
return requestedProviders.filter((p) => enabledInConfig.includes(p));
|
|
88
|
+
}
|
|
89
|
+
return enabledInConfig;
|
|
90
|
+
}
|
|
91
|
+
async function executeSearch(options, sessionsDir, config, showProgress = true) {
|
|
92
|
+
let ast;
|
|
93
|
+
let queryContent;
|
|
94
|
+
let queryFile;
|
|
95
|
+
if (options.directQuery && options.providers && options.providers.length === 1) {
|
|
96
|
+
queryFile = "direct-query";
|
|
97
|
+
ast = {
|
|
98
|
+
name: options.sessionName ?? "direct-query",
|
|
99
|
+
blocks: [
|
|
100
|
+
{
|
|
101
|
+
field: "all",
|
|
102
|
+
terms: { keywords: [options.directQuery] },
|
|
103
|
+
operator: "AND"
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
filters: {},
|
|
107
|
+
overrides: {}
|
|
108
|
+
};
|
|
109
|
+
queryContent = stringify({
|
|
110
|
+
name: ast.name,
|
|
111
|
+
blocks: ast.blocks,
|
|
112
|
+
filters: ast.filters
|
|
113
|
+
});
|
|
114
|
+
} else if (options.queryFile) {
|
|
115
|
+
try {
|
|
116
|
+
queryContent = await readFile(options.queryFile, "utf-8");
|
|
117
|
+
ast = parseQueryString(queryContent);
|
|
118
|
+
queryFile = options.queryFile;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
return {
|
|
121
|
+
success: false,
|
|
122
|
+
error: `Failed to parse query file: ${error instanceof Error ? error.message : error}`
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
return {
|
|
127
|
+
success: false,
|
|
128
|
+
error: "Either queryFile or directQuery with provider is required"
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const providers = getEnabledProviders(config, options.providers);
|
|
132
|
+
if (providers.length === 0) {
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
error: "No providers enabled or selected"
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const queryHash = createHash("sha256").update(queryContent).digest("hex").slice(0, 8);
|
|
139
|
+
let session;
|
|
140
|
+
try {
|
|
141
|
+
const sessionOpts = {
|
|
142
|
+
name: options.sessionName ?? ast.name,
|
|
143
|
+
queryFile,
|
|
144
|
+
queryContent,
|
|
145
|
+
queryHash,
|
|
146
|
+
targets: providers,
|
|
147
|
+
sessionsDir
|
|
148
|
+
};
|
|
149
|
+
if (ast.description) {
|
|
150
|
+
sessionOpts.description = ast.description;
|
|
151
|
+
}
|
|
152
|
+
session = await createSession(sessionOpts);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
error: `Failed to create session: ${error instanceof Error ? error.message : error}`
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const sessionId = session.id;
|
|
160
|
+
const results = {};
|
|
161
|
+
let progress;
|
|
162
|
+
if (showProgress && process.stdout.isTTY) {
|
|
163
|
+
progress = new MultiProviderProgress(providers);
|
|
164
|
+
}
|
|
165
|
+
for (const providerName of providers) {
|
|
166
|
+
try {
|
|
167
|
+
const provider = createProviderInstance(providerName, config);
|
|
168
|
+
let translatedQuery;
|
|
169
|
+
if (options.directQuery && options.providers?.length === 1) {
|
|
170
|
+
translatedQuery = {
|
|
171
|
+
native: options.directQuery,
|
|
172
|
+
provider: providerName
|
|
173
|
+
};
|
|
174
|
+
} else {
|
|
175
|
+
translatedQuery = translateQueryForProvider(ast, providerName);
|
|
176
|
+
}
|
|
177
|
+
const queryPath = join(sessionsDir, sessionId, `${providerName}_query.txt`);
|
|
178
|
+
await writeFile(queryPath, translatedQuery.native, "utf-8");
|
|
179
|
+
await updateDatabaseStatus(
|
|
180
|
+
sessionId,
|
|
181
|
+
providerName,
|
|
182
|
+
{
|
|
183
|
+
status: "in_progress",
|
|
184
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
185
|
+
},
|
|
186
|
+
sessionsDir
|
|
187
|
+
);
|
|
188
|
+
const resultsPath = join(sessionsDir, sessionId, `${providerName}_results.jsonl`);
|
|
189
|
+
let retrievedCount = 0;
|
|
190
|
+
let totalHits = 0;
|
|
191
|
+
progress?.update(providerName, 0, 0, "in_progress");
|
|
192
|
+
const searchOptions = {
|
|
193
|
+
maxResults: options.maxResults ?? config.providers[providerName].max_results
|
|
194
|
+
};
|
|
195
|
+
for await (const article of provider.search(translatedQuery, searchOptions)) {
|
|
196
|
+
retrievedCount++;
|
|
197
|
+
await appendFile(resultsPath, JSON.stringify(article) + "\n", "utf-8");
|
|
198
|
+
if (totalHits === 0) {
|
|
199
|
+
totalHits = Math.max(retrievedCount * 10, 100);
|
|
200
|
+
}
|
|
201
|
+
progress?.update(providerName, retrievedCount, totalHits, "in_progress");
|
|
202
|
+
}
|
|
203
|
+
totalHits = retrievedCount;
|
|
204
|
+
progress?.complete(providerName);
|
|
205
|
+
await updateDatabaseStatus(
|
|
206
|
+
sessionId,
|
|
207
|
+
providerName,
|
|
208
|
+
{
|
|
209
|
+
status: "completed",
|
|
210
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
211
|
+
totalHits,
|
|
212
|
+
retrievedCount,
|
|
213
|
+
files: {
|
|
214
|
+
query: `${providerName}_query.txt`,
|
|
215
|
+
results: `${providerName}_results.jsonl`
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
sessionsDir
|
|
219
|
+
);
|
|
220
|
+
results[providerName] = { hits: totalHits, retrieved: retrievedCount };
|
|
221
|
+
} catch (error) {
|
|
222
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
223
|
+
progress?.fail(providerName, errorMessage);
|
|
224
|
+
await updateDatabaseStatus(
|
|
225
|
+
sessionId,
|
|
226
|
+
providerName,
|
|
227
|
+
{
|
|
228
|
+
status: "failed",
|
|
229
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
230
|
+
error: {
|
|
231
|
+
code: "SEARCH_ERROR",
|
|
232
|
+
message: errorMessage,
|
|
233
|
+
retryable: true
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
sessionsDir
|
|
237
|
+
);
|
|
238
|
+
results[providerName] = { hits: 0, retrieved: 0 };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
progress?.stop();
|
|
242
|
+
const anyFailed = providers.some((p) => {
|
|
243
|
+
const r = results[p];
|
|
244
|
+
return r && r.retrieved === 0 && r.hits === 0;
|
|
245
|
+
});
|
|
246
|
+
const anySucceeded = providers.some((p) => {
|
|
247
|
+
const r = results[p];
|
|
248
|
+
return r && r.retrieved > 0;
|
|
249
|
+
});
|
|
250
|
+
let sessionStatus;
|
|
251
|
+
if (!anyFailed) {
|
|
252
|
+
sessionStatus = "completed";
|
|
253
|
+
} else if (anySucceeded) {
|
|
254
|
+
sessionStatus = "partial";
|
|
255
|
+
} else {
|
|
256
|
+
sessionStatus = "failed";
|
|
257
|
+
}
|
|
258
|
+
await updateSessionStatus(sessionId, sessionStatus, sessionsDir);
|
|
259
|
+
if (sessionStatus === "failed") {
|
|
260
|
+
return {
|
|
261
|
+
success: false,
|
|
262
|
+
sessionId,
|
|
263
|
+
results,
|
|
264
|
+
error: "All providers failed"
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
let autoRegisterResult;
|
|
268
|
+
if (config.integration.reference_manager.enabled && config.integration.reference_manager.auto_register) {
|
|
269
|
+
const refAvailable = await checkRefAvailable();
|
|
270
|
+
if (refAvailable) {
|
|
271
|
+
const allArticles = await loadArticlesFromSession(sessionsDir, sessionId, providers);
|
|
272
|
+
if (allArticles.length > 0) {
|
|
273
|
+
autoRegisterResult = await registerArticles(allArticles, {
|
|
274
|
+
sessionId,
|
|
275
|
+
sessionDir: join(sessionsDir, sessionId),
|
|
276
|
+
withAbstracts: config.integration.reference_manager.with_abstracts
|
|
277
|
+
});
|
|
278
|
+
await saveRegistrationRecord(join(sessionsDir, sessionId), autoRegisterResult);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const result = {
|
|
283
|
+
success: true,
|
|
284
|
+
sessionId,
|
|
285
|
+
results
|
|
286
|
+
};
|
|
287
|
+
if (autoRegisterResult) {
|
|
288
|
+
result.autoRegisterResult = autoRegisterResult;
|
|
289
|
+
}
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
292
|
+
async function loadArticlesFromSession(sessionsDir, sessionId, providers) {
|
|
293
|
+
const articles = [];
|
|
294
|
+
for (const provider of providers) {
|
|
295
|
+
const resultsPath = join(sessionsDir, sessionId, `${provider}_results.jsonl`);
|
|
296
|
+
try {
|
|
297
|
+
const content = await readFile(resultsPath, "utf-8");
|
|
298
|
+
const lines = content.trim().split("\n").filter((line) => line.length > 0);
|
|
299
|
+
for (const line of lines) {
|
|
300
|
+
try {
|
|
301
|
+
const article = JSON.parse(line);
|
|
302
|
+
articles.push(article);
|
|
303
|
+
} catch {
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
} catch {
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return articles;
|
|
310
|
+
}
|
|
311
|
+
export {
|
|
312
|
+
createProviderInstance,
|
|
313
|
+
executeSearch
|
|
314
|
+
};
|
|
315
|
+
//# sourceMappingURL=search-executor.js.map
|