Package not found. Please check the package name and try again.
@ncukondo/search-hub 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_commonjsHelpers.js +30 -0
- package/dist/_virtual/_commonjsHelpers.js.map +1 -0
- package/dist/_virtual/aliases.js +5 -0
- package/dist/_virtual/aliases.js.map +1 -0
- package/dist/_virtual/attributes.js +5 -0
- package/dist/_virtual/attributes.js.map +1 -0
- package/dist/_virtual/back.js +5 -0
- package/dist/_virtual/back.js.map +1 -0
- package/dist/_virtual/comment.js +5 -0
- package/dist/_virtual/comment.js.map +1 -0
- package/dist/_virtual/compile.js +5 -0
- package/dist/_virtual/compile.js.map +1 -0
- package/dist/_virtual/compile2.js +5 -0
- package/dist/_virtual/compile2.js.map +1 -0
- package/dist/_virtual/decode-data-html.js +5 -0
- package/dist/_virtual/decode-data-html.js.map +1 -0
- package/dist/_virtual/decode-data-xml.js +5 -0
- package/dist/_virtual/decode-data-xml.js.map +1 -0
- package/dist/_virtual/decode.js +5 -0
- package/dist/_virtual/decode.js.map +1 -0
- package/dist/_virtual/decode_codepoint.js +5 -0
- package/dist/_virtual/decode_codepoint.js.map +1 -0
- package/dist/_virtual/encode-html.js +5 -0
- package/dist/_virtual/encode-html.js.map +1 -0
- package/dist/_virtual/encode.js +5 -0
- package/dist/_virtual/encode.js.map +1 -0
- package/dist/_virtual/escape.js +5 -0
- package/dist/_virtual/escape.js.map +1 -0
- package/dist/_virtual/feeds.js +5 -0
- package/dist/_virtual/feeds.js.map +1 -0
- package/dist/_virtual/filters.js +5 -0
- package/dist/_virtual/filters.js.map +1 -0
- package/dist/_virtual/foreignNames.js +5 -0
- package/dist/_virtual/foreignNames.js.map +1 -0
- package/dist/_virtual/general.js +5 -0
- package/dist/_virtual/general.js.map +1 -0
- package/dist/_virtual/he.js +5 -0
- package/dist/_virtual/he.js.map +1 -0
- package/dist/_virtual/helpers.js +5 -0
- package/dist/_virtual/helpers.js.map +1 -0
- package/dist/_virtual/html.js +5 -0
- package/dist/_virtual/html.js.map +1 -0
- package/dist/_virtual/index.js +6 -0
- package/dist/_virtual/index.js.map +1 -0
- package/dist/_virtual/index10.js +5 -0
- package/dist/_virtual/index10.js.map +1 -0
- package/dist/_virtual/index11.js +5 -0
- package/dist/_virtual/index11.js.map +1 -0
- package/dist/_virtual/index2.js +5 -0
- package/dist/_virtual/index2.js.map +1 -0
- package/dist/_virtual/index3.js +5 -0
- package/dist/_virtual/index3.js.map +1 -0
- package/dist/_virtual/index4.js +5 -0
- package/dist/_virtual/index4.js.map +1 -0
- package/dist/_virtual/index5.js +7 -0
- package/dist/_virtual/index5.js.map +1 -0
- package/dist/_virtual/index6.js +5 -0
- package/dist/_virtual/index6.js.map +1 -0
- package/dist/_virtual/index7.js +5 -0
- package/dist/_virtual/index7.js.map +1 -0
- package/dist/_virtual/index8.js +5 -0
- package/dist/_virtual/index8.js.map +1 -0
- package/dist/_virtual/index9.js +5 -0
- package/dist/_virtual/index9.js.map +1 -0
- package/dist/_virtual/legacy.js +5 -0
- package/dist/_virtual/legacy.js.map +1 -0
- package/dist/_virtual/manipulation.js +5 -0
- package/dist/_virtual/manipulation.js.map +1 -0
- package/dist/_virtual/matcher.js +5 -0
- package/dist/_virtual/matcher.js.map +1 -0
- package/dist/_virtual/node.js +5 -0
- package/dist/_virtual/node.js.map +1 -0
- package/dist/_virtual/node2.js +5 -0
- package/dist/_virtual/node2.js.map +1 -0
- package/dist/_virtual/parse.js +5 -0
- package/dist/_virtual/parse.js.map +1 -0
- package/dist/_virtual/parse2.js +5 -0
- package/dist/_virtual/parse2.js.map +1 -0
- package/dist/_virtual/pseudos.js +5 -0
- package/dist/_virtual/pseudos.js.map +1 -0
- package/dist/_virtual/querying.js +5 -0
- package/dist/_virtual/querying.js.map +1 -0
- package/dist/_virtual/sort.js +5 -0
- package/dist/_virtual/sort.js.map +1 -0
- package/dist/_virtual/stringify.js +5 -0
- package/dist/_virtual/stringify.js.map +1 -0
- package/dist/_virtual/subselects.js +5 -0
- package/dist/_virtual/subselects.js.map +1 -0
- package/dist/_virtual/text.js +5 -0
- package/dist/_virtual/text.js.map +1 -0
- package/dist/_virtual/traversal.js +5 -0
- package/dist/_virtual/traversal.js.map +1 -0
- package/dist/_virtual/type.js +5 -0
- package/dist/_virtual/type.js.map +1 -0
- package/dist/_virtual/valid.js +5 -0
- package/dist/_virtual/valid.js.map +1 -0
- package/dist/_virtual/void-tag.js +5 -0
- package/dist/_virtual/void-tag.js.map +1 -0
- package/dist/cli/commands/diff.js +2 -2
- package/dist/cli/commands/diff.js.map +1 -1
- package/dist/cli/commands/fulltext/attach.js +1 -1
- package/dist/cli/commands/fulltext/attach.js.map +1 -1
- package/dist/cli/commands/fulltext/check.d.ts +1 -2
- package/dist/cli/commands/fulltext/check.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/check.js +4 -2
- package/dist/cli/commands/fulltext/check.js.map +1 -1
- package/dist/cli/commands/fulltext/convert.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/convert.js +8 -8
- package/dist/cli/commands/fulltext/convert.js.map +1 -1
- package/dist/cli/commands/fulltext/fetch.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/fetch.js +10 -6
- package/dist/cli/commands/fulltext/fetch.js.map +1 -1
- package/dist/cli/commands/fulltext/index.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/index.js +2 -0
- package/dist/cli/commands/fulltext/index.js.map +1 -1
- package/dist/cli/commands/fulltext/init.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/init.js +6 -5
- package/dist/cli/commands/fulltext/init.js.map +1 -1
- package/dist/cli/commands/fulltext/pending.d.ts +1 -1
- package/dist/cli/commands/fulltext/pending.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/pending.js +4 -2
- package/dist/cli/commands/fulltext/pending.js.map +1 -1
- package/dist/cli/commands/fulltext/status.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/status.js +4 -2
- package/dist/cli/commands/fulltext/status.js.map +1 -1
- package/dist/cli/commands/fulltext/sync.d.ts.map +1 -1
- package/dist/cli/commands/fulltext/sync.js +6 -2
- package/dist/cli/commands/fulltext/sync.js.map +1 -1
- package/dist/cli/commands/query/init.d.ts +5 -0
- package/dist/cli/commands/query/init.d.ts.map +1 -1
- package/dist/cli/commands/query/init.js +9 -1
- package/dist/cli/commands/query/init.js.map +1 -1
- package/dist/cli/commands/query/translate.d.ts.map +1 -1
- package/dist/cli/commands/query/translate.js +5 -0
- package/dist/cli/commands/query/translate.js.map +1 -1
- package/dist/cli/commands/query/validate.d.ts +22 -1
- package/dist/cli/commands/query/validate.d.ts.map +1 -1
- package/dist/cli/commands/query/validate.js +65 -22
- package/dist/cli/commands/query/validate.js.map +1 -1
- package/dist/cli/commands/review/extract.d.ts.map +1 -1
- package/dist/cli/commands/review/extract.js +1 -2
- package/dist/cli/commands/review/extract.js.map +1 -1
- package/dist/cli/commands/review/finalize.d.ts.map +1 -1
- package/dist/cli/commands/review/finalize.js +1 -2
- package/dist/cli/commands/review/finalize.js.map +1 -1
- package/dist/cli/commands/review/init.d.ts.map +1 -1
- package/dist/cli/commands/review/init.js +2 -5
- package/dist/cli/commands/review/init.js.map +1 -1
- package/dist/cli/commands/review/merge.d.ts.map +1 -1
- package/dist/cli/commands/review/merge.js +1 -2
- package/dist/cli/commands/review/merge.js.map +1 -1
- package/dist/cli/commands/review/types.d.ts +1 -1
- package/dist/cli/commands/review/types.d.ts.map +1 -1
- package/dist/cli/commands/review/types.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +81 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/suggestions/index.d.ts.map +1 -1
- package/dist/cli/suggestions/index.js +10 -0
- package/dist/cli/suggestions/index.js.map +1 -1
- package/dist/cli/suggestions/rules.d.ts.map +1 -1
- package/dist/cli/suggestions/rules.js +21 -8
- package/dist/cli/suggestions/rules.js.map +1 -1
- package/dist/cli/suggestions/types.d.ts +11 -0
- package/dist/cli/suggestions/types.d.ts.map +1 -1
- package/dist/config/schema.d.ts +2 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +6 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/{fulltext → integration}/attach-shared.d.ts +2 -2
- package/dist/integration/attach-shared.d.ts.map +1 -0
- package/dist/integration/attach-shared.js.map +1 -0
- package/dist/integration/fulltext-attach.js +1 -1
- package/dist/integration/fulltext-attach.js.map +1 -1
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/citation-key.js +1 -1
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/citation-key.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/arxiv-html-parser.js +434 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/arxiv-html-parser.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/index.js +93 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/index.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js +1060 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/jats-parser.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/convert/markdown-writer.js +146 -117
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/convert/markdown-writer.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/arxiv.js +8 -1
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/arxiv.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/core.js +6 -3
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/core.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/index.js +139 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/index.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/ncbi-id-converter.js +46 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/ncbi-id-converter.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/pmc.js +8 -4
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/pmc.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/discovery/unpaywall.js +43 -9
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/discovery/unpaywall.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/arxiv-html.js +48 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/arxiv-html.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/downloader.js +64 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/downloader.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/orchestrator.js +236 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/orchestrator.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/download/pmc-xml.js +2 -1
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/download/pmc-xml.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/meta.js +15 -10
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/meta.js.map +1 -0
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/paths.js.map +1 -0
- package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/readme.js +8 -4
- package/dist/node_modules/@ncukondo/academic-fulltext/dist/readme.js.map +1 -0
- package/dist/node_modules/boolbase/index.js +19 -0
- package/dist/node_modules/boolbase/index.js.map +1 -0
- package/dist/node_modules/css-select/lib/attributes.js +203 -0
- package/dist/node_modules/css-select/lib/attributes.js.map +1 -0
- package/dist/node_modules/css-select/lib/compile.js +141 -0
- package/dist/node_modules/css-select/lib/compile.js.map +1 -0
- package/dist/node_modules/css-select/lib/general.js +154 -0
- package/dist/node_modules/css-select/lib/general.js.map +1 -0
- package/dist/node_modules/css-select/lib/index.js +128 -0
- package/dist/node_modules/css-select/lib/index.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/aliases.js +40 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/aliases.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/filters.js +163 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/filters.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/index.js +71 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/index.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/pseudos.js +93 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/pseudos.js.map +1 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/subselects.js +111 -0
- package/dist/node_modules/css-select/lib/pseudo-selectors/subselects.js.map +1 -0
- package/dist/node_modules/css-select/lib/sort.js +78 -0
- package/dist/node_modules/css-select/lib/sort.js.map +1 -0
- package/dist/node_modules/css-what/lib/es/index.js +12 -0
- package/dist/node_modules/css-what/lib/es/index.js.map +1 -0
- package/dist/node_modules/css-what/lib/es/parse.js +349 -0
- package/dist/node_modules/css-what/lib/es/parse.js.map +1 -0
- package/dist/node_modules/css-what/lib/es/stringify.js +102 -0
- package/dist/node_modules/css-what/lib/es/stringify.js.map +1 -0
- package/dist/node_modules/css-what/lib/es/types.js +37 -0
- package/dist/node_modules/css-what/lib/es/types.js.map +1 -0
- package/dist/node_modules/dom-serializer/lib/foreignNames.js +117 -0
- package/dist/node_modules/dom-serializer/lib/foreignNames.js.map +1 -0
- package/dist/node_modules/dom-serializer/lib/index.js +207 -0
- package/dist/node_modules/dom-serializer/lib/index.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode.js +368 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode_codepoint.js +70 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/decode_codepoint.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/encode.js +61 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/encode.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/escape.js +79 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/escape.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-html.js +18 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-html.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-xml.js +18 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/decode-data-xml.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/encode-html.js +19 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/generated/encode-html.js.map +1 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/index.js +139 -0
- package/dist/node_modules/dom-serializer/node_modules/entities/lib/index.js.map +1 -0
- package/dist/node_modules/domelementtype/lib/index.js +40 -0
- package/dist/node_modules/domelementtype/lib/index.js.map +1 -0
- package/dist/node_modules/domhandler/lib/index.js +167 -0
- package/dist/node_modules/domhandler/lib/index.js.map +1 -0
- package/dist/node_modules/domhandler/lib/node.js +439 -0
- package/dist/node_modules/domhandler/lib/node.js.map +1 -0
- package/dist/node_modules/domutils/lib/feeds.js +146 -0
- package/dist/node_modules/domutils/lib/feeds.js.map +1 -0
- package/dist/node_modules/domutils/lib/helpers.js +97 -0
- package/dist/node_modules/domutils/lib/helpers.js.map +1 -0
- package/dist/node_modules/domutils/lib/index.js +65 -0
- package/dist/node_modules/domutils/lib/index.js.map +1 -0
- package/dist/node_modules/domutils/lib/legacy.js +124 -0
- package/dist/node_modules/domutils/lib/legacy.js.map +1 -0
- package/dist/node_modules/domutils/lib/manipulation.js +107 -0
- package/dist/node_modules/domutils/lib/manipulation.js.map +1 -0
- package/dist/node_modules/domutils/lib/querying.js +102 -0
- package/dist/node_modules/domutils/lib/querying.js.map +1 -0
- package/dist/node_modules/domutils/lib/stringify.js +65 -0
- package/dist/node_modules/domutils/lib/stringify.js.map +1 -0
- package/dist/node_modules/domutils/lib/traversal.js +69 -0
- package/dist/node_modules/domutils/lib/traversal.js.map +1 -0
- package/dist/node_modules/he/he.js +256 -0
- package/dist/node_modules/he/he.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/back.js +16 -0
- package/dist/node_modules/node-html-parser/dist/back.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/index.js +48 -0
- package/dist/node_modules/node-html-parser/dist/index.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/matcher.js +112 -0
- package/dist/node_modules/node-html-parser/dist/matcher.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/comment.js +41 -0
- package/dist/node_modules/node-html-parser/dist/nodes/comment.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/html.js +1048 -0
- package/dist/node_modules/node-html-parser/dist/nodes/html.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/node.js +49 -0
- package/dist/node_modules/node-html-parser/dist/nodes/node.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/text.js +106 -0
- package/dist/node_modules/node-html-parser/dist/nodes/text.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/nodes/type.js +19 -0
- package/dist/node_modules/node-html-parser/dist/nodes/type.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/parse.js +20 -0
- package/dist/node_modules/node-html-parser/dist/parse.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/valid.js +19 -0
- package/dist/node_modules/node-html-parser/dist/valid.js.map +1 -0
- package/dist/node_modules/node-html-parser/dist/void-tag.js +36 -0
- package/dist/node_modules/node-html-parser/dist/void-tag.js.map +1 -0
- package/dist/node_modules/nth-check/lib/compile.js +76 -0
- package/dist/node_modules/nth-check/lib/compile.js.map +1 -0
- package/dist/node_modules/nth-check/lib/index.js +36 -0
- package/dist/node_modules/nth-check/lib/index.js.map +1 -0
- package/dist/node_modules/nth-check/lib/parse.js +69 -0
- package/dist/node_modules/nth-check/lib/parse.js.map +1 -0
- package/dist/providers/arxiv/translator.d.ts.map +1 -1
- package/dist/providers/arxiv/translator.js +5 -2
- package/dist/providers/arxiv/translator.js.map +1 -1
- package/dist/providers/base/types.d.ts +2 -0
- package/dist/providers/base/types.d.ts.map +1 -1
- package/dist/providers/base/types.js.map +1 -1
- package/dist/providers/base/warnings.d.ts +14 -0
- package/dist/providers/base/warnings.d.ts.map +1 -0
- package/dist/providers/base/warnings.js +33 -0
- package/dist/providers/base/warnings.js.map +1 -0
- package/dist/providers/eric/translator.d.ts.map +1 -1
- package/dist/providers/eric/translator.js +5 -2
- package/dist/providers/eric/translator.js.map +1 -1
- package/dist/providers/pubmed/translator.d.ts.map +1 -1
- package/dist/providers/pubmed/translator.js +5 -2
- package/dist/providers/pubmed/translator.js.map +1 -1
- package/dist/providers/scopus/translator.d.ts.map +1 -1
- package/dist/providers/scopus/translator.js +22 -5
- package/dist/providers/scopus/translator.js.map +1 -1
- package/dist/query/__test-helpers__/mock-mesh-client.d.ts +12 -0
- package/dist/query/__test-helpers__/mock-mesh-client.d.ts.map +1 -0
- package/dist/query/index.d.ts +4 -0
- package/dist/query/index.d.ts.map +1 -1
- package/dist/query/json-schema.d.ts +3 -0
- package/dist/query/json-schema.d.ts.map +1 -0
- package/dist/query/json-schema.js +48 -0
- package/dist/query/json-schema.js.map +1 -0
- package/dist/query/mesh-lookup.d.ts +47 -0
- package/dist/query/mesh-lookup.d.ts.map +1 -0
- package/dist/query/mesh-lookup.js +151 -0
- package/dist/query/mesh-lookup.js.map +1 -0
- package/dist/query/parser.js +1 -1
- package/dist/query/parser.js.map +1 -1
- package/dist/query/types.d.ts +2 -2
- package/dist/query/types.d.ts.map +1 -1
- package/dist/query/validator.d.ts +5 -5
- package/dist/query/validator.d.ts.map +1 -1
- package/dist/query/validator.js +5 -2
- package/dist/query/validator.js.map +1 -1
- package/dist/query/vocab-cache.d.ts +15 -0
- package/dist/query/vocab-cache.d.ts.map +1 -0
- package/dist/query/vocab-cache.js +44 -0
- package/dist/query/vocab-cache.js.map +1 -0
- package/dist/query/vocab-validator.d.ts +71 -0
- package/dist/query/vocab-validator.d.ts.map +1 -0
- package/dist/query/vocab-validator.js +153 -0
- package/dist/query/vocab-validator.js.map +1 -0
- package/dist/utils/levenshtein.d.ts +6 -0
- package/dist/utils/levenshtein.d.ts.map +1 -0
- package/dist/utils/levenshtein.js +21 -0
- package/dist/utils/levenshtein.js.map +1 -0
- package/package.json +2 -2
- package/dist/fulltext/attach-shared.d.ts.map +0 -1
- package/dist/fulltext/attach-shared.js.map +0 -1
- package/dist/fulltext/citation-key.d.ts +0 -15
- package/dist/fulltext/citation-key.d.ts.map +0 -1
- package/dist/fulltext/citation-key.js.map +0 -1
- package/dist/fulltext/convert/index.d.ts +0 -20
- package/dist/fulltext/convert/index.d.ts.map +0 -1
- package/dist/fulltext/convert/index.js +0 -50
- package/dist/fulltext/convert/index.js.map +0 -1
- package/dist/fulltext/convert/jats-parser.d.ts +0 -36
- package/dist/fulltext/convert/jats-parser.d.ts.map +0 -1
- package/dist/fulltext/convert/jats-parser.js +0 -887
- package/dist/fulltext/convert/jats-parser.js.map +0 -1
- package/dist/fulltext/convert/markdown-writer.d.ts +0 -6
- package/dist/fulltext/convert/markdown-writer.d.ts.map +0 -1
- package/dist/fulltext/convert/markdown-writer.js.map +0 -1
- package/dist/fulltext/convert/types.d.ts +0 -141
- package/dist/fulltext/convert/types.d.ts.map +0 -1
- package/dist/fulltext/discovery/arxiv.d.ts +0 -11
- package/dist/fulltext/discovery/arxiv.d.ts.map +0 -1
- package/dist/fulltext/discovery/arxiv.js.map +0 -1
- package/dist/fulltext/discovery/core.d.ts +0 -11
- package/dist/fulltext/discovery/core.d.ts.map +0 -1
- package/dist/fulltext/discovery/core.js.map +0 -1
- package/dist/fulltext/discovery/index.d.ts +0 -28
- package/dist/fulltext/discovery/index.d.ts.map +0 -1
- package/dist/fulltext/discovery/index.js +0 -75
- package/dist/fulltext/discovery/index.js.map +0 -1
- package/dist/fulltext/discovery/pmc.d.ts +0 -19
- package/dist/fulltext/discovery/pmc.d.ts.map +0 -1
- package/dist/fulltext/discovery/pmc.js.map +0 -1
- package/dist/fulltext/discovery/unpaywall.d.ts +0 -11
- package/dist/fulltext/discovery/unpaywall.d.ts.map +0 -1
- package/dist/fulltext/discovery/unpaywall.js.map +0 -1
- package/dist/fulltext/download/downloader.d.ts +0 -21
- package/dist/fulltext/download/downloader.d.ts.map +0 -1
- package/dist/fulltext/download/downloader.js +0 -59
- package/dist/fulltext/download/downloader.js.map +0 -1
- package/dist/fulltext/download/orchestrator.d.ts +0 -33
- package/dist/fulltext/download/orchestrator.d.ts.map +0 -1
- package/dist/fulltext/download/orchestrator.js +0 -125
- package/dist/fulltext/download/orchestrator.js.map +0 -1
- package/dist/fulltext/download/pmc-xml.d.ts +0 -13
- package/dist/fulltext/download/pmc-xml.d.ts.map +0 -1
- package/dist/fulltext/download/pmc-xml.js.map +0 -1
- package/dist/fulltext/meta.d.ts +0 -25
- package/dist/fulltext/meta.d.ts.map +0 -1
- package/dist/fulltext/meta.js.map +0 -1
- package/dist/fulltext/paths.d.ts +0 -12
- package/dist/fulltext/paths.d.ts.map +0 -1
- package/dist/fulltext/paths.js.map +0 -1
- package/dist/fulltext/readme.d.ts +0 -4
- package/dist/fulltext/readme.d.ts.map +0 -1
- package/dist/fulltext/readme.js.map +0 -1
- package/dist/fulltext/types.d.ts +0 -90
- package/dist/fulltext/types.d.ts.map +0 -1
- /package/dist/{fulltext → integration}/attach-shared.js +0 -0
- /package/dist/{fulltext → node_modules/@ncukondo/academic-fulltext/dist}/paths.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/suggestions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE/D,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAoBpE;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/suggestions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE/D,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAoBpE;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,MAAM,CA2BxE"}
|
|
@@ -12,8 +12,18 @@ ${lines.join("\n")}`;
|
|
|
12
12
|
function formatSuggestion(result) {
|
|
13
13
|
if (result === null) return "";
|
|
14
14
|
const sections = [];
|
|
15
|
+
if (result.tip) {
|
|
16
|
+
sections.push(result.tip);
|
|
17
|
+
}
|
|
15
18
|
const nextSection = formatSection("Next", result.next);
|
|
16
19
|
if (nextSection) sections.push(nextSection);
|
|
20
|
+
if (result.or && result.or.items.length > 0) {
|
|
21
|
+
const lines = result.or.items.map(
|
|
22
|
+
(s) => s.description ? ` ${s.command} # ${s.description}` : ` ${s.command}`
|
|
23
|
+
);
|
|
24
|
+
sections.push(`${result.or.label}:
|
|
25
|
+
${lines.join("\n")}`);
|
|
26
|
+
}
|
|
17
27
|
const seeAlsoSection = formatSection("See also", result.seeAlso);
|
|
18
28
|
if (seeAlsoSection) sections.push(seeAlsoSection);
|
|
19
29
|
if (sections.length === 0) return "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/cli/suggestions/index.ts"],"sourcesContent":["import type { Suggestion, SuggestionResult } from './types.js';\n\nexport type { Suggestion, SuggestionResult } from './types.js';\nexport type { SuggestionContext, SuggestionRule } from './types.js';\n\n/**\n * Format a section (Next or See also) with aligned inline comments.\n */\nfunction formatSection(label: string, items: Suggestion[]): string {\n if (items.length === 0) return '';\n\n // Find the longest command to align comments\n const maxCommandLen = Math.max(...items.map((s) => s.command.length));\n const padding = 4; // spaces between command and comment\n\n const lines = items.map((s) => {\n const spaces = ' '.repeat(maxCommandLen - s.command.length + padding);\n return ` ${s.command}${spaces}# ${s.description}`;\n });\n\n return `${label}:\\n${lines.join('\\n')}`;\n}\n\n/**\n * Format suggestion result into a human-readable string.\n *\n * Output format:\n * ```\n * Next:\n * search-hub results <session-id> # 結果を確認\n *\n * See also:\n * search-hub diff <other> <session-id> # 別バージョンと比較\n * ```\n */\nexport function formatSuggestion(result: SuggestionResult | null): string {\n if (result === null) return '';\n\n const sections: string[] = [];\n\n const nextSection = formatSection('Next', result.next);\n if (nextSection) sections.push(nextSection);\n\n const seeAlsoSection = formatSection('See also', result.seeAlso);\n if (seeAlsoSection) sections.push(seeAlsoSection);\n\n if (sections.length === 0) return '';\n\n return '\\n' + sections.join('\\n\\n');\n}\n"],"names":[],"mappings":"AAQA,SAAS,cAAc,OAAe,OAA6B;AACjE,MAAI,MAAM,WAAW,EAAG,QAAO;AAG/B,QAAM,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ,MAAM,CAAC;AACpE,QAAM,UAAU;AAEhB,QAAM,QAAQ,MAAM,IAAI,CAAC,MAAM;AAC7B,UAAM,SAAS,IAAI,OAAO,gBAAgB,EAAE,QAAQ,SAAS,OAAO;AACpE,WAAO,KAAK,EAAE,OAAO,GAAG,MAAM,KAAK,EAAE,WAAW;AAAA,EAClD,CAAC;AAED,SAAO,GAAG,KAAK;AAAA,EAAM,MAAM,KAAK,IAAI,CAAC;AACvC;AAcO,SAAS,iBAAiB,QAAyC;AACxE,MAAI,WAAW,KAAM,QAAO;AAE5B,QAAM,WAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/cli/suggestions/index.ts"],"sourcesContent":["import type { Suggestion, SuggestionResult } from './types.js';\n\nexport type { Suggestion, SuggestionResult } from './types.js';\nexport type { SuggestionContext, SuggestionRule } from './types.js';\n\n/**\n * Format a section (Next or See also) with aligned inline comments.\n */\nfunction formatSection(label: string, items: Suggestion[]): string {\n if (items.length === 0) return '';\n\n // Find the longest command to align comments\n const maxCommandLen = Math.max(...items.map((s) => s.command.length));\n const padding = 4; // spaces between command and comment\n\n const lines = items.map((s) => {\n const spaces = ' '.repeat(maxCommandLen - s.command.length + padding);\n return ` ${s.command}${spaces}# ${s.description}`;\n });\n\n return `${label}:\\n${lines.join('\\n')}`;\n}\n\n/**\n * Format suggestion result into a human-readable string.\n *\n * Output format:\n * ```\n * Next:\n * search-hub results <session-id> # 結果を確認\n *\n * See also:\n * search-hub diff <other> <session-id> # 別バージョンと比較\n * ```\n */\nexport function formatSuggestion(result: SuggestionResult | null): string {\n if (result === null) return '';\n\n const sections: string[] = [];\n\n // Tip (before Next)\n if (result.tip) {\n sections.push(result.tip);\n }\n\n const nextSection = formatSection('Next', result.next);\n if (nextSection) sections.push(nextSection);\n\n // Or section (after Next, before See also)\n if (result.or && result.or.items.length > 0) {\n const lines = result.or.items.map((s) =>\n s.description ? ` ${s.command} # ${s.description}` : ` ${s.command}`\n );\n sections.push(`${result.or.label}:\\n${lines.join('\\n')}`);\n }\n\n const seeAlsoSection = formatSection('See also', result.seeAlso);\n if (seeAlsoSection) sections.push(seeAlsoSection);\n\n if (sections.length === 0) return '';\n\n return '\\n' + sections.join('\\n\\n');\n}\n"],"names":[],"mappings":"AAQA,SAAS,cAAc,OAAe,OAA6B;AACjE,MAAI,MAAM,WAAW,EAAG,QAAO;AAG/B,QAAM,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ,MAAM,CAAC;AACpE,QAAM,UAAU;AAEhB,QAAM,QAAQ,MAAM,IAAI,CAAC,MAAM;AAC7B,UAAM,SAAS,IAAI,OAAO,gBAAgB,EAAE,QAAQ,SAAS,OAAO;AACpE,WAAO,KAAK,EAAE,OAAO,GAAG,MAAM,KAAK,EAAE,WAAW;AAAA,EAClD,CAAC;AAED,SAAO,GAAG,KAAK;AAAA,EAAM,MAAM,KAAK,IAAI,CAAC;AACvC;AAcO,SAAS,iBAAiB,QAAyC;AACxE,MAAI,WAAW,KAAM,QAAO;AAE5B,QAAM,WAAqB,CAAA;AAG3B,MAAI,OAAO,KAAK;AACd,aAAS,KAAK,OAAO,GAAG;AAAA,EAC1B;AAEA,QAAM,cAAc,cAAc,QAAQ,OAAO,IAAI;AACrD,MAAI,YAAa,UAAS,KAAK,WAAW;AAG1C,MAAI,OAAO,MAAM,OAAO,GAAG,MAAM,SAAS,GAAG;AAC3C,UAAM,QAAQ,OAAO,GAAG,MAAM;AAAA,MAAI,CAAC,MACjC,EAAE,cAAc,KAAK,EAAE,OAAO,SAAS,EAAE,WAAW,KAAK,KAAK,EAAE,OAAO;AAAA,IAAA;AAEzE,aAAS,KAAK,GAAG,OAAO,GAAG,KAAK;AAAA,EAAM,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,EAC1D;AAEA,QAAM,iBAAiB,cAAc,YAAY,OAAO,OAAO;AAC/D,MAAI,eAAgB,UAAS,KAAK,cAAc;AAEhD,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,SAAO,OAAO,SAAS,KAAK,MAAM;AACpC;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/cli/suggestions/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/cli/suggestions/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC;AAgctF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,CAM7E"}
|
|
@@ -11,18 +11,31 @@ const queryValidateRule = (ctx) => {
|
|
|
11
11
|
if (ctx.command !== "query validate") return null;
|
|
12
12
|
const file = ctx.queryFile ?? "<query-file>";
|
|
13
13
|
if (ctx.validationSuccess === false) {
|
|
14
|
+
const next2 = [{ command: `$EDITOR ${file}`, description: "Fix errors and re-validate" }];
|
|
15
|
+
if (ctx.hasSchemaLink === false) {
|
|
16
|
+
return {
|
|
17
|
+
next: next2,
|
|
18
|
+
or: {
|
|
19
|
+
label: "Or create a new query from the template",
|
|
20
|
+
items: [{ command: "search-hub query init -o query.yaml", description: "" }]
|
|
21
|
+
},
|
|
22
|
+
seeAlso: []
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return { next: next2, seeAlso: [] };
|
|
26
|
+
}
|
|
27
|
+
const next = [
|
|
28
|
+
{ command: `search-hub search ${file} --dry-run`, description: "Check DB translations" },
|
|
29
|
+
{ command: `search-hub search ${file} --preview`, description: "Preview hit counts + sample titles" }
|
|
30
|
+
];
|
|
31
|
+
if (ctx.hasSchemaLink === false) {
|
|
14
32
|
return {
|
|
15
|
-
|
|
33
|
+
tip: "Tip: Start from a template to get $schema support and usage examples:\n search-hub query init -o query.yaml",
|
|
34
|
+
next,
|
|
16
35
|
seeAlso: []
|
|
17
36
|
};
|
|
18
37
|
}
|
|
19
|
-
return {
|
|
20
|
-
next: [
|
|
21
|
-
{ command: `search-hub search ${file} --dry-run`, description: "Check DB translations" },
|
|
22
|
-
{ command: `search-hub search ${file} --preview`, description: "Preview hit counts + sample titles" }
|
|
23
|
-
],
|
|
24
|
-
seeAlso: []
|
|
25
|
-
};
|
|
38
|
+
return { next, seeAlso: [] };
|
|
26
39
|
};
|
|
27
40
|
const queryTranslateRule = (ctx) => {
|
|
28
41
|
if (ctx.command !== "query translate") return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","sources":["../../../src/cli/suggestions/rules.ts"],"sourcesContent":["import type { SuggestionContext, SuggestionResult, SuggestionRule } from './types.js';\nimport { computeBatchContinuation, generateReviewNextSteps } from '../commands/review/next-steps.js';\n\n// Phase 1: Query Preparation rules\n\nconst queryInitRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'query init') return null;\n const file = ctx.outputFile ?? 'query.yaml';\n return {\n next: [{ command: `$EDITOR ${file}`, description: 'Edit your query' }],\n seeAlso: [],\n };\n};\n\nconst queryValidateRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'query validate') return null;\n const file = ctx.queryFile ?? '<query-file>';\n\n if (ctx.validationSuccess === false) {\n return {\n next: [{ command: `$EDITOR ${file}`, description: 'Fix errors and re-validate' }],\n seeAlso: [],\n };\n }\n\n return {\n next: [\n { command: `search-hub search ${file} --dry-run`, description: 'Check DB translations' },\n { command: `search-hub search ${file} --preview`, description: 'Preview hit counts + sample titles' },\n ],\n seeAlso: [],\n };\n};\n\nconst queryTranslateRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'query translate') return null;\n const file = ctx.queryFile ?? '<query-file>';\n return {\n next: [\n { command: `search-hub search ${file} --preview`, description: 'Preview hit counts + sample titles' },\n { command: `search-hub search ${file}`, description: 'Execute search' },\n ],\n seeAlso: [],\n };\n};\n\n// Phase 2: Search Execution rules\n\n/**\n * Build search completion suggestions based on session status.\n * Shared by search, search --query, and resume commands.\n */\nfunction searchCompletionSuggestion(ctx: SuggestionContext): SuggestionResult | null {\n const sid = ctx.sessionId ?? '<session-id>';\n\n switch (ctx.sessionStatus) {\n case 'completed': {\n const seeAlso: SuggestionResult['seeAlso'] = [];\n if (ctx.sessionCount !== undefined && ctx.sessionCount > 1) {\n seeAlso.push({\n command: `search-hub diff <other-session> ${sid}`,\n description: 'Compare with another query version',\n });\n }\n return {\n next: [{ command: `search-hub results ${sid}`, description: 'View results' }],\n seeAlso,\n };\n }\n case 'partial':\n return {\n next: [{ command: `search-hub resume ${sid}`, description: 'Retry failed databases' }],\n seeAlso: [],\n };\n case 'failed':\n return {\n next: [\n { command: `search-hub resume ${sid} --retry-failed`, description: 'Retry all databases' },\n { command: `search-hub status ${sid}`, description: 'View error details' },\n ],\n seeAlso: [],\n };\n default:\n return null;\n }\n}\n\nconst searchDryRunRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search --dry-run') return null;\n const file = ctx.queryFile ?? '<query-file>';\n return {\n next: [\n { command: `search-hub search ${file} --preview`, description: 'Preview hit counts + sample titles' },\n { command: `search-hub search ${file}`, description: 'Execute search' },\n ],\n seeAlso: [],\n };\n};\n\nconst searchPreviewRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search --preview') return null;\n const file = ctx.queryFile ?? '<query-file>';\n return {\n next: [{ command: `search-hub search ${file}`, description: 'Execute full search' }],\n seeAlso: [],\n };\n};\n\nconst searchCountOnlyRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search --count-only') return null;\n const file = ctx.queryFile ?? '<query-file>';\n return {\n next: [{ command: `search-hub search ${file}`, description: 'Execute full search' }],\n seeAlso: [],\n };\n};\n\nconst searchDirectQueryRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search --query') return null;\n const base = searchCompletionSuggestion(ctx);\n if (base === null) return null;\n return {\n next: base.next,\n seeAlso: [\n ...base.seeAlso,\n { command: 'search-hub query init -o my-search.yaml', description: 'Save as YAML for reproducibility' },\n ],\n };\n};\n\nconst searchRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search') return null;\n return searchCompletionSuggestion(ctx);\n};\n\nconst resumeRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'resume') return null;\n return searchCompletionSuggestion(ctx);\n};\n\n// Phase 3: Result Analysis rules\n\nconst statusRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'status') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n\n switch (ctx.sessionStatus) {\n case 'completed':\n return {\n next: [{ command: `search-hub results ${sid}`, description: 'View results' }],\n seeAlso: [],\n };\n case 'partial':\n return {\n next: [{ command: `search-hub resume ${sid}`, description: 'Resume search' }],\n seeAlso: [],\n };\n case 'failed':\n return {\n next: [{ command: `search-hub resume ${sid} --retry-failed`, description: 'Retry all databases' }],\n seeAlso: [],\n };\n default:\n return null;\n }\n};\n\n/**\n * Suggestion for results/summary commands - conditional based on reviews.yaml existence.\n */\nfunction resultReviewSuggestion(ctx: SuggestionContext): SuggestionResult {\n const sid = ctx.sessionId ?? '<session-id>';\n if (ctx.hasReviews === true) {\n return {\n next: [{ command: `search-hub review status --session ${sid}`, description: 'Check review progress' }],\n seeAlso: [],\n };\n }\n return {\n next: [{ command: `search-hub review init --session ${sid}`, description: 'Start systematic review' }],\n seeAlso: [],\n };\n}\n\nconst resultsRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'results') return null;\n return resultReviewSuggestion(ctx);\n};\n\nconst summaryRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'summary') return null;\n return resultReviewSuggestion(ctx);\n};\n\nconst diffRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'diff') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n const seeAlso: SuggestionResult['seeAlso'] = [];\n\n // Suggest merge when both sessions have unique articles\n if (ctx.diffAddedCount !== undefined && ctx.diffAddedCount > 0 &&\n ctx.diffRemovedCount !== undefined && ctx.diffRemovedCount > 0) {\n const sid1 = ctx.diffSession1Id ?? '<session-id-1>';\n seeAlso.push({\n command: `search-hub merge ${sid1} ${sid}`,\n description: 'Combine results from both sessions',\n });\n }\n\n seeAlso.push({ command: `search-hub results ${sid}`, description: 'View detailed results' });\n\n return { next: [], seeAlso };\n};\n\nconst mergeRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'merge') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [\n { command: `search-hub results ${sid}`, description: 'View merged results' },\n { command: `search-hub summary ${sid}`, description: 'View merge statistics' },\n ],\n seeAlso: [],\n };\n};\n\n// Phase 4: Review Workflow rules\n\nconst reviewInitRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review init') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [\n {\n command: `search-hub review extract --session ${sid} --basis title --name title-screening`,\n description: 'Start title screening',\n },\n ],\n seeAlso: [],\n };\n};\n\nconst reviewStatusRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review status') return null;\n const rs = ctx.reviewStatus;\n if (!rs) return null;\n\n return generateReviewNextSteps({\n sessionId: ctx.sessionId ?? '<session-id>',\n statusResult: rs,\n });\n};\n\nconst reviewListRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review list') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [],\n seeAlso: [\n {\n command: `search-hub review extract --session ${sid} --name <name>`,\n description: 'Extract subset for review',\n },\n ],\n };\n};\n\nconst reviewExtractRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review extract') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n const name = ctx.extractName ?? '<name>';\n const result: SuggestionResult = {\n next: [\n {\n command: `search-hub review merge --session ${sid} --name ${name}`,\n description: 'Merge review results',\n },\n ],\n seeAlso: [],\n };\n\n // Batch continuation: suggest next batch if --limit was used with remaining articles\n if (\n ctx.extractLimit !== undefined &&\n ctx.extractedCount !== undefined &&\n ctx.totalMatching !== undefined\n ) {\n const batch = computeBatchContinuation({\n sessionId: sid,\n extractName: name !== '<name>' ? name : undefined,\n extractedCount: ctx.extractedCount,\n totalMatching: ctx.totalMatching,\n limit: ctx.extractLimit,\n offset: ctx.extractOffset,\n });\n if (batch) result.seeAlso.push(batch);\n }\n\n return result;\n};\n\nconst reviewMergeRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review merge') return null;\n const rs = ctx.reviewStatus;\n if (!rs) {\n // Fallback: suggest status check when reviewStatus not available\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [\n {\n command: `search-hub review status --session ${sid}`,\n description: 'Check progress',\n },\n ],\n seeAlso: [],\n };\n }\n\n return generateReviewNextSteps({\n sessionId: ctx.sessionId ?? '<session-id>',\n statusResult: rs,\n });\n};\n\nconst reviewFinalizeRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review finalize') return null;\n const rs = ctx.reviewStatus;\n if (!rs) return null;\n\n return generateReviewNextSteps({\n sessionId: ctx.sessionId ?? '<session-id>',\n statusResult: rs,\n });\n};\n\nconst reviewExportRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review export') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [],\n seeAlso: [\n {\n command: `search-hub register ${sid} --reviewed`,\n description: 'Register with reference-manager',\n },\n ],\n };\n};\n\n// Phase 5: Registration & Export rules\n\nconst exportRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'export') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n if (ctx.hasReviews === false) {\n return {\n next: [],\n seeAlso: [\n {\n command: `search-hub review init --session ${sid}`,\n description: 'Start review workflow',\n },\n ],\n };\n }\n return { next: [], seeAlso: [] };\n};\n\nconst registerRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'register') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n if (ctx.hasReviews === false) {\n return {\n next: [],\n seeAlso: [\n {\n command: `search-hub review init --session ${sid}`,\n description: 'Start systematic review',\n },\n ],\n };\n }\n // Terminal state: no suggestions\n return null;\n};\n\nconst notesRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'notes add' && ctx.command !== 'notes assess') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [],\n seeAlso: [{ command: `search-hub notes list ${sid}`, description: 'View notes' }],\n };\n};\n\n/**\n * All suggestion rules in evaluation order.\n */\nconst rules: SuggestionRule[] = [\n // Phase 1\n queryInitRule,\n queryValidateRule,\n queryTranslateRule,\n // Phase 2\n searchDryRunRule,\n searchPreviewRule,\n searchCountOnlyRule,\n searchDirectQueryRule,\n searchRule,\n resumeRule,\n // Phase 3\n statusRule,\n resultsRule,\n summaryRule,\n diffRule,\n mergeRule,\n // Phase 4\n reviewInitRule,\n reviewStatusRule,\n reviewListRule,\n reviewExtractRule,\n reviewMergeRule,\n reviewFinalizeRule,\n reviewExportRule,\n // Phase 5\n exportRule,\n registerRule,\n notesRule,\n];\n\n/**\n * Evaluate suggestion rules for the given context.\n * Returns the first matching rule's result, or null if no rules match.\n */\nexport function getSuggestion(ctx: SuggestionContext): SuggestionResult | null {\n for (const rule of rules) {\n const result = rule(ctx);\n if (result !== null) return result;\n }\n return null;\n}\n"],"names":[],"mappings":";AAKA,MAAM,gBAAgC,CAAC,QAAQ;AAC7C,MAAI,IAAI,YAAY,aAAc,QAAO;AACzC,QAAM,OAAO,IAAI,cAAc;AAC/B,SAAO;AAAA,IACL,MAAM,CAAC,EAAE,SAAS,WAAW,IAAI,IAAI,aAAa,mBAAmB;AAAA,IACrE,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,oBAAoC,CAAC,QAAQ;AACjD,MAAI,IAAI,YAAY,iBAAkB,QAAO;AAC7C,QAAM,OAAO,IAAI,aAAa;AAE9B,MAAI,IAAI,sBAAsB,OAAO;AACnC,WAAO;AAAA,MACL,MAAM,CAAC,EAAE,SAAS,WAAW,IAAI,IAAI,aAAa,8BAA8B;AAAA,MAChF,SAAS,CAAA;AAAA,IAAC;AAAA,EAEd;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,EAAE,SAAS,qBAAqB,IAAI,cAAc,aAAa,wBAAA;AAAA,MAC/D,EAAE,SAAS,qBAAqB,IAAI,cAAc,aAAa,qCAAA;AAAA,IAAqC;AAAA,IAEtG,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,qBAAqC,CAAC,QAAQ;AAClD,MAAI,IAAI,YAAY,kBAAmB,QAAO;AAC9C,QAAM,OAAO,IAAI,aAAa;AAC9B,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,EAAE,SAAS,qBAAqB,IAAI,cAAc,aAAa,qCAAA;AAAA,MAC/D,EAAE,SAAS,qBAAqB,IAAI,IAAI,aAAa,iBAAA;AAAA,IAAiB;AAAA,IAExE,SAAS,CAAA;AAAA,EAAC;AAEd;AAQA,SAAS,2BAA2B,KAAiD;AACnF,QAAM,MAAM,IAAI,aAAa;AAE7B,UAAQ,IAAI,eAAA;AAAA,IACV,KAAK,aAAa;AAChB,YAAM,UAAuC,CAAA;AAC7C,UAAI,IAAI,iBAAiB,UAAa,IAAI,eAAe,GAAG;AAC1D,gBAAQ,KAAK;AAAA,UACX,SAAS,mCAAmC,GAAG;AAAA,UAC/C,aAAa;AAAA,QAAA,CACd;AAAA,MACH;AACA,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,gBAAgB;AAAA,QAC5E;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,GAAG,IAAI,aAAa,0BAA0B;AAAA,QACrF,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,UACJ,EAAE,SAAS,qBAAqB,GAAG,mBAAmB,aAAa,sBAAA;AAAA,UACnE,EAAE,SAAS,qBAAqB,GAAG,IAAI,aAAa,qBAAA;AAAA,QAAqB;AAAA,QAE3E,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd;AACE,aAAO;AAAA,EAAA;AAEb;AAEA,MAAM,mBAAmC,CAAC,QAAQ;AAChD,MAAI,IAAI,YAAY,mBAAoB,QAAO;AAC/C,QAAM,OAAO,IAAI,aAAa;AAC9B,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,EAAE,SAAS,qBAAqB,IAAI,cAAc,aAAa,qCAAA;AAAA,MAC/D,EAAE,SAAS,qBAAqB,IAAI,IAAI,aAAa,iBAAA;AAAA,IAAiB;AAAA,IAExE,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,oBAAoC,CAAC,QAAQ;AACjD,MAAI,IAAI,YAAY,mBAAoB,QAAO;AAC/C,QAAM,OAAO,IAAI,aAAa;AAC9B,SAAO;AAAA,IACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,IAAI,IAAI,aAAa,uBAAuB;AAAA,IACnF,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,sBAAsC,CAAC,QAAQ;AACnD,MAAI,IAAI,YAAY,sBAAuB,QAAO;AAClD,QAAM,OAAO,IAAI,aAAa;AAC9B,SAAO;AAAA,IACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,IAAI,IAAI,aAAa,uBAAuB;AAAA,IACnF,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,wBAAwC,CAAC,QAAQ;AACrD,MAAI,IAAI,YAAY,iBAAkB,QAAO;AAC7C,QAAM,OAAO,2BAA2B,GAAG;AAC3C,MAAI,SAAS,KAAM,QAAO;AAC1B,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,SAAS;AAAA,MACP,GAAG,KAAK;AAAA,MACR,EAAE,SAAS,2CAA2C,aAAa,mCAAA;AAAA,IAAmC;AAAA,EACxG;AAEJ;AAEA,MAAM,aAA6B,CAAC,QAAQ;AAC1C,MAAI,IAAI,YAAY,SAAU,QAAO;AACrC,SAAO,2BAA2B,GAAG;AACvC;AAEA,MAAM,aAA6B,CAAC,QAAQ;AAC1C,MAAI,IAAI,YAAY,SAAU,QAAO;AACrC,SAAO,2BAA2B,GAAG;AACvC;AAIA,MAAM,aAA6B,CAAC,QAAQ;AAC1C,MAAI,IAAI,YAAY,SAAU,QAAO;AACrC,QAAM,MAAM,IAAI,aAAa;AAE7B,UAAQ,IAAI,eAAA;AAAA,IACV,KAAK;AACH,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,gBAAgB;AAAA,QAC5E,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd,KAAK;AACH,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,GAAG,IAAI,aAAa,iBAAiB;AAAA,QAC5E,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd,KAAK;AACH,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,GAAG,mBAAmB,aAAa,uBAAuB;AAAA,QACjG,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd;AACE,aAAO;AAAA,EAAA;AAEb;AAKA,SAAS,uBAAuB,KAA0C;AACxE,QAAM,MAAM,IAAI,aAAa;AAC7B,MAAI,IAAI,eAAe,MAAM;AAC3B,WAAO;AAAA,MACL,MAAM,CAAC,EAAE,SAAS,sCAAsC,GAAG,IAAI,aAAa,yBAAyB;AAAA,MACrG,SAAS,CAAA;AAAA,IAAC;AAAA,EAEd;AACA,SAAO;AAAA,IACL,MAAM,CAAC,EAAE,SAAS,oCAAoC,GAAG,IAAI,aAAa,2BAA2B;AAAA,IACrG,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,cAA8B,CAAC,QAAQ;AAC3C,MAAI,IAAI,YAAY,UAAW,QAAO;AACtC,SAAO,uBAAuB,GAAG;AACnC;AAEA,MAAM,cAA8B,CAAC,QAAQ;AAC3C,MAAI,IAAI,YAAY,UAAW,QAAO;AACtC,SAAO,uBAAuB,GAAG;AACnC;AAEA,MAAM,WAA2B,CAAC,QAAQ;AACxC,MAAI,IAAI,YAAY,OAAQ,QAAO;AACnC,QAAM,MAAM,IAAI,aAAa;AAC7B,QAAM,UAAuC,CAAA;AAG7C,MAAI,IAAI,mBAAmB,UAAa,IAAI,iBAAiB,KACzD,IAAI,qBAAqB,UAAa,IAAI,mBAAmB,GAAG;AAClE,UAAM,OAAO,IAAI,kBAAkB;AACnC,YAAQ,KAAK;AAAA,MACX,SAAS,oBAAoB,IAAI,IAAI,GAAG;AAAA,MACxC,aAAa;AAAA,IAAA,CACd;AAAA,EACH;AAEA,UAAQ,KAAK,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,yBAAyB;AAE3F,SAAO,EAAE,MAAM,CAAA,GAAI,QAAA;AACrB;AAEA,MAAM,YAA4B,CAAC,QAAQ;AACzC,MAAI,IAAI,YAAY,QAAS,QAAO;AACpC,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,sBAAA;AAAA,MACrD,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,wBAAA;AAAA,IAAwB;AAAA,IAE/E,SAAS,CAAA;AAAA,EAAC;AAEd;AAIA,MAAM,iBAAiC,CAAC,QAAQ;AAC9C,MAAI,IAAI,YAAY,cAAe,QAAO;AAC1C,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM;AAAA,MACJ;AAAA,QACE,SAAS,uCAAuC,GAAG;AAAA,QACnD,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,IAEF,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,mBAAmC,CAAC,QAAQ;AAChD,MAAI,IAAI,YAAY,gBAAiB,QAAO;AAC5C,QAAM,KAAK,IAAI;AACf,MAAI,CAAC,GAAI,QAAO;AAEhB,SAAO,wBAAwB;AAAA,IAC7B,WAAW,IAAI,aAAa;AAAA,IAC5B,cAAc;AAAA,EAAA,CACf;AACH;AAEA,MAAM,iBAAiC,CAAC,QAAQ;AAC9C,MAAI,IAAI,YAAY,cAAe,QAAO;AAC1C,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM,CAAA;AAAA,IACN,SAAS;AAAA,MACP;AAAA,QACE,SAAS,uCAAuC,GAAG;AAAA,QACnD,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,EACF;AAEJ;AAEA,MAAM,oBAAoC,CAAC,QAAQ;AACjD,MAAI,IAAI,YAAY,iBAAkB,QAAO;AAC7C,QAAM,MAAM,IAAI,aAAa;AAC7B,QAAM,OAAO,IAAI,eAAe;AAChC,QAAM,SAA2B;AAAA,IAC/B,MAAM;AAAA,MACJ;AAAA,QACE,SAAS,qCAAqC,GAAG,WAAW,IAAI;AAAA,QAChE,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,IAEF,SAAS,CAAA;AAAA,EAAC;AAIZ,MACE,IAAI,iBAAiB,UACrB,IAAI,mBAAmB,UACvB,IAAI,kBAAkB,QACtB;AACA,UAAM,QAAQ,yBAAyB;AAAA,MACrC,WAAW;AAAA,MACX,aAAa,SAAS,WAAW,OAAO;AAAA,MACxC,gBAAgB,IAAI;AAAA,MACpB,eAAe,IAAI;AAAA,MACnB,OAAO,IAAI;AAAA,MACX,QAAQ,IAAI;AAAA,IAAA,CACb;AACD,QAAI,MAAO,QAAO,QAAQ,KAAK,KAAK;AAAA,EACtC;AAEA,SAAO;AACT;AAEA,MAAM,kBAAkC,CAAC,QAAQ;AAC/C,MAAI,IAAI,YAAY,eAAgB,QAAO;AAC3C,QAAM,KAAK,IAAI;AACf,MAAI,CAAC,IAAI;AAEP,UAAM,MAAM,IAAI,aAAa;AAC7B,WAAO;AAAA,MACL,MAAM;AAAA,QACJ;AAAA,UACE,SAAS,sCAAsC,GAAG;AAAA,UAClD,aAAa;AAAA,QAAA;AAAA,MACf;AAAA,MAEF,SAAS,CAAA;AAAA,IAAC;AAAA,EAEd;AAEA,SAAO,wBAAwB;AAAA,IAC7B,WAAW,IAAI,aAAa;AAAA,IAC5B,cAAc;AAAA,EAAA,CACf;AACH;AAEA,MAAM,qBAAqC,CAAC,QAAQ;AAClD,MAAI,IAAI,YAAY,kBAAmB,QAAO;AAC9C,QAAM,KAAK,IAAI;AACf,MAAI,CAAC,GAAI,QAAO;AAEhB,SAAO,wBAAwB;AAAA,IAC7B,WAAW,IAAI,aAAa;AAAA,IAC5B,cAAc;AAAA,EAAA,CACf;AACH;AAEA,MAAM,mBAAmC,CAAC,QAAQ;AAChD,MAAI,IAAI,YAAY,gBAAiB,QAAO;AAC5C,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM,CAAA;AAAA,IACN,SAAS;AAAA,MACP;AAAA,QACE,SAAS,uBAAuB,GAAG;AAAA,QACnC,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,EACF;AAEJ;AAIA,MAAM,aAA6B,CAAC,QAAQ;AAC1C,MAAI,IAAI,YAAY,SAAU,QAAO;AACrC,QAAM,MAAM,IAAI,aAAa;AAC7B,MAAI,IAAI,eAAe,OAAO;AAC5B,WAAO;AAAA,MACL,MAAM,CAAA;AAAA,MACN,SAAS;AAAA,QACP;AAAA,UACE,SAAS,oCAAoC,GAAG;AAAA,UAChD,aAAa;AAAA,QAAA;AAAA,MACf;AAAA,IACF;AAAA,EAEJ;AACA,SAAO,EAAE,MAAM,IAAI,SAAS,CAAA,EAAC;AAC/B;AAEA,MAAM,eAA+B,CAAC,QAAQ;AAC5C,MAAI,IAAI,YAAY,WAAY,QAAO;AACvC,QAAM,MAAM,IAAI,aAAa;AAC7B,MAAI,IAAI,eAAe,OAAO;AAC5B,WAAO;AAAA,MACL,MAAM,CAAA;AAAA,MACN,SAAS;AAAA,QACP;AAAA,UACE,SAAS,oCAAoC,GAAG;AAAA,UAChD,aAAa;AAAA,QAAA;AAAA,MACf;AAAA,IACF;AAAA,EAEJ;AAEA,SAAO;AACT;AAEA,MAAM,YAA4B,CAAC,QAAQ;AACzC,MAAI,IAAI,YAAY,eAAe,IAAI,YAAY,eAAgB,QAAO;AAC1E,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM,CAAA;AAAA,IACN,SAAS,CAAC,EAAE,SAAS,yBAAyB,GAAG,IAAI,aAAa,aAAA,CAAc;AAAA,EAAA;AAEpF;AAKA,MAAM,QAA0B;AAAA;AAAA,EAE9B;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AACF;AAMO,SAAS,cAAc,KAAiD;AAC7E,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,KAAK,GAAG;AACvB,QAAI,WAAW,KAAM,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;"}
|
|
1
|
+
{"version":3,"file":"rules.js","sources":["../../../src/cli/suggestions/rules.ts"],"sourcesContent":["import type { SuggestionContext, SuggestionResult, SuggestionRule } from './types.js';\nimport { computeBatchContinuation, generateReviewNextSteps } from '../commands/review/next-steps.js';\n\n// Phase 1: Query Preparation rules\n\nconst queryInitRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'query init') return null;\n const file = ctx.outputFile ?? 'query.yaml';\n return {\n next: [{ command: `$EDITOR ${file}`, description: 'Edit your query' }],\n seeAlso: [],\n };\n};\n\nconst queryValidateRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'query validate') return null;\n const file = ctx.queryFile ?? '<query-file>';\n\n if (ctx.validationSuccess === false) {\n const next = [{ command: `$EDITOR ${file}`, description: 'Fix errors and re-validate' }];\n\n if (ctx.hasSchemaLink === false) {\n return {\n next,\n or: {\n label: 'Or create a new query from the template',\n items: [{ command: 'search-hub query init -o query.yaml', description: '' }],\n },\n seeAlso: [],\n };\n }\n\n return { next, seeAlso: [] };\n }\n\n const next = [\n { command: `search-hub search ${file} --dry-run`, description: 'Check DB translations' },\n { command: `search-hub search ${file} --preview`, description: 'Preview hit counts + sample titles' },\n ];\n\n if (ctx.hasSchemaLink === false) {\n return {\n tip: 'Tip: Start from a template to get $schema support and usage examples:\\n'\n + ' search-hub query init -o query.yaml',\n next,\n seeAlso: [],\n };\n }\n\n return { next, seeAlso: [] };\n};\n\nconst queryTranslateRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'query translate') return null;\n const file = ctx.queryFile ?? '<query-file>';\n return {\n next: [\n { command: `search-hub search ${file} --preview`, description: 'Preview hit counts + sample titles' },\n { command: `search-hub search ${file}`, description: 'Execute search' },\n ],\n seeAlso: [],\n };\n};\n\n// Phase 2: Search Execution rules\n\n/**\n * Build search completion suggestions based on session status.\n * Shared by search, search --query, and resume commands.\n */\nfunction searchCompletionSuggestion(ctx: SuggestionContext): SuggestionResult | null {\n const sid = ctx.sessionId ?? '<session-id>';\n\n switch (ctx.sessionStatus) {\n case 'completed': {\n const seeAlso: SuggestionResult['seeAlso'] = [];\n if (ctx.sessionCount !== undefined && ctx.sessionCount > 1) {\n seeAlso.push({\n command: `search-hub diff <other-session> ${sid}`,\n description: 'Compare with another query version',\n });\n }\n return {\n next: [{ command: `search-hub results ${sid}`, description: 'View results' }],\n seeAlso,\n };\n }\n case 'partial':\n return {\n next: [{ command: `search-hub resume ${sid}`, description: 'Retry failed databases' }],\n seeAlso: [],\n };\n case 'failed':\n return {\n next: [\n { command: `search-hub resume ${sid} --retry-failed`, description: 'Retry all databases' },\n { command: `search-hub status ${sid}`, description: 'View error details' },\n ],\n seeAlso: [],\n };\n default:\n return null;\n }\n}\n\nconst searchDryRunRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search --dry-run') return null;\n const file = ctx.queryFile ?? '<query-file>';\n return {\n next: [\n { command: `search-hub search ${file} --preview`, description: 'Preview hit counts + sample titles' },\n { command: `search-hub search ${file}`, description: 'Execute search' },\n ],\n seeAlso: [],\n };\n};\n\nconst searchPreviewRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search --preview') return null;\n const file = ctx.queryFile ?? '<query-file>';\n return {\n next: [{ command: `search-hub search ${file}`, description: 'Execute full search' }],\n seeAlso: [],\n };\n};\n\nconst searchCountOnlyRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search --count-only') return null;\n const file = ctx.queryFile ?? '<query-file>';\n return {\n next: [{ command: `search-hub search ${file}`, description: 'Execute full search' }],\n seeAlso: [],\n };\n};\n\nconst searchDirectQueryRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search --query') return null;\n const base = searchCompletionSuggestion(ctx);\n if (base === null) return null;\n return {\n next: base.next,\n seeAlso: [\n ...base.seeAlso,\n { command: 'search-hub query init -o my-search.yaml', description: 'Save as YAML for reproducibility' },\n ],\n };\n};\n\nconst searchRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'search') return null;\n return searchCompletionSuggestion(ctx);\n};\n\nconst resumeRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'resume') return null;\n return searchCompletionSuggestion(ctx);\n};\n\n// Phase 3: Result Analysis rules\n\nconst statusRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'status') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n\n switch (ctx.sessionStatus) {\n case 'completed':\n return {\n next: [{ command: `search-hub results ${sid}`, description: 'View results' }],\n seeAlso: [],\n };\n case 'partial':\n return {\n next: [{ command: `search-hub resume ${sid}`, description: 'Resume search' }],\n seeAlso: [],\n };\n case 'failed':\n return {\n next: [{ command: `search-hub resume ${sid} --retry-failed`, description: 'Retry all databases' }],\n seeAlso: [],\n };\n default:\n return null;\n }\n};\n\n/**\n * Suggestion for results/summary commands - conditional based on reviews.yaml existence.\n */\nfunction resultReviewSuggestion(ctx: SuggestionContext): SuggestionResult {\n const sid = ctx.sessionId ?? '<session-id>';\n if (ctx.hasReviews === true) {\n return {\n next: [{ command: `search-hub review status --session ${sid}`, description: 'Check review progress' }],\n seeAlso: [],\n };\n }\n return {\n next: [{ command: `search-hub review init --session ${sid}`, description: 'Start systematic review' }],\n seeAlso: [],\n };\n}\n\nconst resultsRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'results') return null;\n return resultReviewSuggestion(ctx);\n};\n\nconst summaryRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'summary') return null;\n return resultReviewSuggestion(ctx);\n};\n\nconst diffRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'diff') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n const seeAlso: SuggestionResult['seeAlso'] = [];\n\n // Suggest merge when both sessions have unique articles\n if (ctx.diffAddedCount !== undefined && ctx.diffAddedCount > 0 &&\n ctx.diffRemovedCount !== undefined && ctx.diffRemovedCount > 0) {\n const sid1 = ctx.diffSession1Id ?? '<session-id-1>';\n seeAlso.push({\n command: `search-hub merge ${sid1} ${sid}`,\n description: 'Combine results from both sessions',\n });\n }\n\n seeAlso.push({ command: `search-hub results ${sid}`, description: 'View detailed results' });\n\n return { next: [], seeAlso };\n};\n\nconst mergeRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'merge') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [\n { command: `search-hub results ${sid}`, description: 'View merged results' },\n { command: `search-hub summary ${sid}`, description: 'View merge statistics' },\n ],\n seeAlso: [],\n };\n};\n\n// Phase 4: Review Workflow rules\n\nconst reviewInitRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review init') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [\n {\n command: `search-hub review extract --session ${sid} --basis title --name title-screening`,\n description: 'Start title screening',\n },\n ],\n seeAlso: [],\n };\n};\n\nconst reviewStatusRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review status') return null;\n const rs = ctx.reviewStatus;\n if (!rs) return null;\n\n return generateReviewNextSteps({\n sessionId: ctx.sessionId ?? '<session-id>',\n statusResult: rs,\n });\n};\n\nconst reviewListRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review list') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [],\n seeAlso: [\n {\n command: `search-hub review extract --session ${sid} --name <name>`,\n description: 'Extract subset for review',\n },\n ],\n };\n};\n\nconst reviewExtractRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review extract') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n const name = ctx.extractName ?? '<name>';\n const result: SuggestionResult = {\n next: [\n {\n command: `search-hub review merge --session ${sid} --name ${name}`,\n description: 'Merge review results',\n },\n ],\n seeAlso: [],\n };\n\n // Batch continuation: suggest next batch if --limit was used with remaining articles\n if (\n ctx.extractLimit !== undefined &&\n ctx.extractedCount !== undefined &&\n ctx.totalMatching !== undefined\n ) {\n const batch = computeBatchContinuation({\n sessionId: sid,\n extractName: name !== '<name>' ? name : undefined,\n extractedCount: ctx.extractedCount,\n totalMatching: ctx.totalMatching,\n limit: ctx.extractLimit,\n offset: ctx.extractOffset,\n });\n if (batch) result.seeAlso.push(batch);\n }\n\n return result;\n};\n\nconst reviewMergeRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review merge') return null;\n const rs = ctx.reviewStatus;\n if (!rs) {\n // Fallback: suggest status check when reviewStatus not available\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [\n {\n command: `search-hub review status --session ${sid}`,\n description: 'Check progress',\n },\n ],\n seeAlso: [],\n };\n }\n\n return generateReviewNextSteps({\n sessionId: ctx.sessionId ?? '<session-id>',\n statusResult: rs,\n });\n};\n\nconst reviewFinalizeRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review finalize') return null;\n const rs = ctx.reviewStatus;\n if (!rs) return null;\n\n return generateReviewNextSteps({\n sessionId: ctx.sessionId ?? '<session-id>',\n statusResult: rs,\n });\n};\n\nconst reviewExportRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'review export') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [],\n seeAlso: [\n {\n command: `search-hub register ${sid} --reviewed`,\n description: 'Register with reference-manager',\n },\n ],\n };\n};\n\n// Phase 5: Registration & Export rules\n\nconst exportRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'export') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n if (ctx.hasReviews === false) {\n return {\n next: [],\n seeAlso: [\n {\n command: `search-hub review init --session ${sid}`,\n description: 'Start review workflow',\n },\n ],\n };\n }\n return { next: [], seeAlso: [] };\n};\n\nconst registerRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'register') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n if (ctx.hasReviews === false) {\n return {\n next: [],\n seeAlso: [\n {\n command: `search-hub review init --session ${sid}`,\n description: 'Start systematic review',\n },\n ],\n };\n }\n // Terminal state: no suggestions\n return null;\n};\n\nconst notesRule: SuggestionRule = (ctx) => {\n if (ctx.command !== 'notes add' && ctx.command !== 'notes assess') return null;\n const sid = ctx.sessionId ?? '<session-id>';\n return {\n next: [],\n seeAlso: [{ command: `search-hub notes list ${sid}`, description: 'View notes' }],\n };\n};\n\n/**\n * All suggestion rules in evaluation order.\n */\nconst rules: SuggestionRule[] = [\n // Phase 1\n queryInitRule,\n queryValidateRule,\n queryTranslateRule,\n // Phase 2\n searchDryRunRule,\n searchPreviewRule,\n searchCountOnlyRule,\n searchDirectQueryRule,\n searchRule,\n resumeRule,\n // Phase 3\n statusRule,\n resultsRule,\n summaryRule,\n diffRule,\n mergeRule,\n // Phase 4\n reviewInitRule,\n reviewStatusRule,\n reviewListRule,\n reviewExtractRule,\n reviewMergeRule,\n reviewFinalizeRule,\n reviewExportRule,\n // Phase 5\n exportRule,\n registerRule,\n notesRule,\n];\n\n/**\n * Evaluate suggestion rules for the given context.\n * Returns the first matching rule's result, or null if no rules match.\n */\nexport function getSuggestion(ctx: SuggestionContext): SuggestionResult | null {\n for (const rule of rules) {\n const result = rule(ctx);\n if (result !== null) return result;\n }\n return null;\n}\n"],"names":["next"],"mappings":";AAKA,MAAM,gBAAgC,CAAC,QAAQ;AAC7C,MAAI,IAAI,YAAY,aAAc,QAAO;AACzC,QAAM,OAAO,IAAI,cAAc;AAC/B,SAAO;AAAA,IACL,MAAM,CAAC,EAAE,SAAS,WAAW,IAAI,IAAI,aAAa,mBAAmB;AAAA,IACrE,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,oBAAoC,CAAC,QAAQ;AACjD,MAAI,IAAI,YAAY,iBAAkB,QAAO;AAC7C,QAAM,OAAO,IAAI,aAAa;AAE9B,MAAI,IAAI,sBAAsB,OAAO;AACnC,UAAMA,QAAO,CAAC,EAAE,SAAS,WAAW,IAAI,IAAI,aAAa,8BAA8B;AAEvF,QAAI,IAAI,kBAAkB,OAAO;AAC/B,aAAO;AAAA,QACL,MAAAA;AAAAA,QACA,IAAI;AAAA,UACF,OAAO;AAAA,UACP,OAAO,CAAC,EAAE,SAAS,uCAAuC,aAAa,IAAI;AAAA,QAAA;AAAA,QAE7E,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd;AAEA,WAAO,EAAE,MAAAA,OAAM,SAAS,CAAA,EAAC;AAAA,EAC3B;AAEA,QAAM,OAAO;AAAA,IACX,EAAE,SAAS,qBAAqB,IAAI,cAAc,aAAa,wBAAA;AAAA,IAC/D,EAAE,SAAS,qBAAqB,IAAI,cAAc,aAAa,qCAAA;AAAA,EAAqC;AAGtG,MAAI,IAAI,kBAAkB,OAAO;AAC/B,WAAO;AAAA,MACL,KAAK;AAAA,MAEL;AAAA,MACA,SAAS,CAAA;AAAA,IAAC;AAAA,EAEd;AAEA,SAAO,EAAE,MAAM,SAAS,GAAC;AAC3B;AAEA,MAAM,qBAAqC,CAAC,QAAQ;AAClD,MAAI,IAAI,YAAY,kBAAmB,QAAO;AAC9C,QAAM,OAAO,IAAI,aAAa;AAC9B,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,EAAE,SAAS,qBAAqB,IAAI,cAAc,aAAa,qCAAA;AAAA,MAC/D,EAAE,SAAS,qBAAqB,IAAI,IAAI,aAAa,iBAAA;AAAA,IAAiB;AAAA,IAExE,SAAS,CAAA;AAAA,EAAC;AAEd;AAQA,SAAS,2BAA2B,KAAiD;AACnF,QAAM,MAAM,IAAI,aAAa;AAE7B,UAAQ,IAAI,eAAA;AAAA,IACV,KAAK,aAAa;AAChB,YAAM,UAAuC,CAAA;AAC7C,UAAI,IAAI,iBAAiB,UAAa,IAAI,eAAe,GAAG;AAC1D,gBAAQ,KAAK;AAAA,UACX,SAAS,mCAAmC,GAAG;AAAA,UAC/C,aAAa;AAAA,QAAA,CACd;AAAA,MACH;AACA,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,gBAAgB;AAAA,QAC5E;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,GAAG,IAAI,aAAa,0BAA0B;AAAA,QACrF,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,UACJ,EAAE,SAAS,qBAAqB,GAAG,mBAAmB,aAAa,sBAAA;AAAA,UACnE,EAAE,SAAS,qBAAqB,GAAG,IAAI,aAAa,qBAAA;AAAA,QAAqB;AAAA,QAE3E,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd;AACE,aAAO;AAAA,EAAA;AAEb;AAEA,MAAM,mBAAmC,CAAC,QAAQ;AAChD,MAAI,IAAI,YAAY,mBAAoB,QAAO;AAC/C,QAAM,OAAO,IAAI,aAAa;AAC9B,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,EAAE,SAAS,qBAAqB,IAAI,cAAc,aAAa,qCAAA;AAAA,MAC/D,EAAE,SAAS,qBAAqB,IAAI,IAAI,aAAa,iBAAA;AAAA,IAAiB;AAAA,IAExE,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,oBAAoC,CAAC,QAAQ;AACjD,MAAI,IAAI,YAAY,mBAAoB,QAAO;AAC/C,QAAM,OAAO,IAAI,aAAa;AAC9B,SAAO;AAAA,IACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,IAAI,IAAI,aAAa,uBAAuB;AAAA,IACnF,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,sBAAsC,CAAC,QAAQ;AACnD,MAAI,IAAI,YAAY,sBAAuB,QAAO;AAClD,QAAM,OAAO,IAAI,aAAa;AAC9B,SAAO;AAAA,IACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,IAAI,IAAI,aAAa,uBAAuB;AAAA,IACnF,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,wBAAwC,CAAC,QAAQ;AACrD,MAAI,IAAI,YAAY,iBAAkB,QAAO;AAC7C,QAAM,OAAO,2BAA2B,GAAG;AAC3C,MAAI,SAAS,KAAM,QAAO;AAC1B,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,SAAS;AAAA,MACP,GAAG,KAAK;AAAA,MACR,EAAE,SAAS,2CAA2C,aAAa,mCAAA;AAAA,IAAmC;AAAA,EACxG;AAEJ;AAEA,MAAM,aAA6B,CAAC,QAAQ;AAC1C,MAAI,IAAI,YAAY,SAAU,QAAO;AACrC,SAAO,2BAA2B,GAAG;AACvC;AAEA,MAAM,aAA6B,CAAC,QAAQ;AAC1C,MAAI,IAAI,YAAY,SAAU,QAAO;AACrC,SAAO,2BAA2B,GAAG;AACvC;AAIA,MAAM,aAA6B,CAAC,QAAQ;AAC1C,MAAI,IAAI,YAAY,SAAU,QAAO;AACrC,QAAM,MAAM,IAAI,aAAa;AAE7B,UAAQ,IAAI,eAAA;AAAA,IACV,KAAK;AACH,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,gBAAgB;AAAA,QAC5E,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd,KAAK;AACH,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,GAAG,IAAI,aAAa,iBAAiB;AAAA,QAC5E,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd,KAAK;AACH,aAAO;AAAA,QACL,MAAM,CAAC,EAAE,SAAS,qBAAqB,GAAG,mBAAmB,aAAa,uBAAuB;AAAA,QACjG,SAAS,CAAA;AAAA,MAAC;AAAA,IAEd;AACE,aAAO;AAAA,EAAA;AAEb;AAKA,SAAS,uBAAuB,KAA0C;AACxE,QAAM,MAAM,IAAI,aAAa;AAC7B,MAAI,IAAI,eAAe,MAAM;AAC3B,WAAO;AAAA,MACL,MAAM,CAAC,EAAE,SAAS,sCAAsC,GAAG,IAAI,aAAa,yBAAyB;AAAA,MACrG,SAAS,CAAA;AAAA,IAAC;AAAA,EAEd;AACA,SAAO;AAAA,IACL,MAAM,CAAC,EAAE,SAAS,oCAAoC,GAAG,IAAI,aAAa,2BAA2B;AAAA,IACrG,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,cAA8B,CAAC,QAAQ;AAC3C,MAAI,IAAI,YAAY,UAAW,QAAO;AACtC,SAAO,uBAAuB,GAAG;AACnC;AAEA,MAAM,cAA8B,CAAC,QAAQ;AAC3C,MAAI,IAAI,YAAY,UAAW,QAAO;AACtC,SAAO,uBAAuB,GAAG;AACnC;AAEA,MAAM,WAA2B,CAAC,QAAQ;AACxC,MAAI,IAAI,YAAY,OAAQ,QAAO;AACnC,QAAM,MAAM,IAAI,aAAa;AAC7B,QAAM,UAAuC,CAAA;AAG7C,MAAI,IAAI,mBAAmB,UAAa,IAAI,iBAAiB,KACzD,IAAI,qBAAqB,UAAa,IAAI,mBAAmB,GAAG;AAClE,UAAM,OAAO,IAAI,kBAAkB;AACnC,YAAQ,KAAK;AAAA,MACX,SAAS,oBAAoB,IAAI,IAAI,GAAG;AAAA,MACxC,aAAa;AAAA,IAAA,CACd;AAAA,EACH;AAEA,UAAQ,KAAK,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,yBAAyB;AAE3F,SAAO,EAAE,MAAM,CAAA,GAAI,QAAA;AACrB;AAEA,MAAM,YAA4B,CAAC,QAAQ;AACzC,MAAI,IAAI,YAAY,QAAS,QAAO;AACpC,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,sBAAA;AAAA,MACrD,EAAE,SAAS,sBAAsB,GAAG,IAAI,aAAa,wBAAA;AAAA,IAAwB;AAAA,IAE/E,SAAS,CAAA;AAAA,EAAC;AAEd;AAIA,MAAM,iBAAiC,CAAC,QAAQ;AAC9C,MAAI,IAAI,YAAY,cAAe,QAAO;AAC1C,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM;AAAA,MACJ;AAAA,QACE,SAAS,uCAAuC,GAAG;AAAA,QACnD,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,IAEF,SAAS,CAAA;AAAA,EAAC;AAEd;AAEA,MAAM,mBAAmC,CAAC,QAAQ;AAChD,MAAI,IAAI,YAAY,gBAAiB,QAAO;AAC5C,QAAM,KAAK,IAAI;AACf,MAAI,CAAC,GAAI,QAAO;AAEhB,SAAO,wBAAwB;AAAA,IAC7B,WAAW,IAAI,aAAa;AAAA,IAC5B,cAAc;AAAA,EAAA,CACf;AACH;AAEA,MAAM,iBAAiC,CAAC,QAAQ;AAC9C,MAAI,IAAI,YAAY,cAAe,QAAO;AAC1C,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM,CAAA;AAAA,IACN,SAAS;AAAA,MACP;AAAA,QACE,SAAS,uCAAuC,GAAG;AAAA,QACnD,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,EACF;AAEJ;AAEA,MAAM,oBAAoC,CAAC,QAAQ;AACjD,MAAI,IAAI,YAAY,iBAAkB,QAAO;AAC7C,QAAM,MAAM,IAAI,aAAa;AAC7B,QAAM,OAAO,IAAI,eAAe;AAChC,QAAM,SAA2B;AAAA,IAC/B,MAAM;AAAA,MACJ;AAAA,QACE,SAAS,qCAAqC,GAAG,WAAW,IAAI;AAAA,QAChE,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,IAEF,SAAS,CAAA;AAAA,EAAC;AAIZ,MACE,IAAI,iBAAiB,UACrB,IAAI,mBAAmB,UACvB,IAAI,kBAAkB,QACtB;AACA,UAAM,QAAQ,yBAAyB;AAAA,MACrC,WAAW;AAAA,MACX,aAAa,SAAS,WAAW,OAAO;AAAA,MACxC,gBAAgB,IAAI;AAAA,MACpB,eAAe,IAAI;AAAA,MACnB,OAAO,IAAI;AAAA,MACX,QAAQ,IAAI;AAAA,IAAA,CACb;AACD,QAAI,MAAO,QAAO,QAAQ,KAAK,KAAK;AAAA,EACtC;AAEA,SAAO;AACT;AAEA,MAAM,kBAAkC,CAAC,QAAQ;AAC/C,MAAI,IAAI,YAAY,eAAgB,QAAO;AAC3C,QAAM,KAAK,IAAI;AACf,MAAI,CAAC,IAAI;AAEP,UAAM,MAAM,IAAI,aAAa;AAC7B,WAAO;AAAA,MACL,MAAM;AAAA,QACJ;AAAA,UACE,SAAS,sCAAsC,GAAG;AAAA,UAClD,aAAa;AAAA,QAAA;AAAA,MACf;AAAA,MAEF,SAAS,CAAA;AAAA,IAAC;AAAA,EAEd;AAEA,SAAO,wBAAwB;AAAA,IAC7B,WAAW,IAAI,aAAa;AAAA,IAC5B,cAAc;AAAA,EAAA,CACf;AACH;AAEA,MAAM,qBAAqC,CAAC,QAAQ;AAClD,MAAI,IAAI,YAAY,kBAAmB,QAAO;AAC9C,QAAM,KAAK,IAAI;AACf,MAAI,CAAC,GAAI,QAAO;AAEhB,SAAO,wBAAwB;AAAA,IAC7B,WAAW,IAAI,aAAa;AAAA,IAC5B,cAAc;AAAA,EAAA,CACf;AACH;AAEA,MAAM,mBAAmC,CAAC,QAAQ;AAChD,MAAI,IAAI,YAAY,gBAAiB,QAAO;AAC5C,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM,CAAA;AAAA,IACN,SAAS;AAAA,MACP;AAAA,QACE,SAAS,uBAAuB,GAAG;AAAA,QACnC,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,EACF;AAEJ;AAIA,MAAM,aAA6B,CAAC,QAAQ;AAC1C,MAAI,IAAI,YAAY,SAAU,QAAO;AACrC,QAAM,MAAM,IAAI,aAAa;AAC7B,MAAI,IAAI,eAAe,OAAO;AAC5B,WAAO;AAAA,MACL,MAAM,CAAA;AAAA,MACN,SAAS;AAAA,QACP;AAAA,UACE,SAAS,oCAAoC,GAAG;AAAA,UAChD,aAAa;AAAA,QAAA;AAAA,MACf;AAAA,IACF;AAAA,EAEJ;AACA,SAAO,EAAE,MAAM,IAAI,SAAS,CAAA,EAAC;AAC/B;AAEA,MAAM,eAA+B,CAAC,QAAQ;AAC5C,MAAI,IAAI,YAAY,WAAY,QAAO;AACvC,QAAM,MAAM,IAAI,aAAa;AAC7B,MAAI,IAAI,eAAe,OAAO;AAC5B,WAAO;AAAA,MACL,MAAM,CAAA;AAAA,MACN,SAAS;AAAA,QACP;AAAA,UACE,SAAS,oCAAoC,GAAG;AAAA,UAChD,aAAa;AAAA,QAAA;AAAA,MACf;AAAA,IACF;AAAA,EAEJ;AAEA,SAAO;AACT;AAEA,MAAM,YAA4B,CAAC,QAAQ;AACzC,MAAI,IAAI,YAAY,eAAe,IAAI,YAAY,eAAgB,QAAO;AAC1E,QAAM,MAAM,IAAI,aAAa;AAC7B,SAAO;AAAA,IACL,MAAM,CAAA;AAAA,IACN,SAAS,CAAC,EAAE,SAAS,yBAAyB,GAAG,IAAI,aAAa,aAAA,CAAc;AAAA,EAAA;AAEpF;AAKA,MAAM,QAA0B;AAAA;AAAA,EAE9B;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AACF;AAMO,SAAS,cAAc,KAAiD;AAC7E,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,KAAK,GAAG;AACvB,QAAI,WAAW,KAAM,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;"}
|
|
@@ -17,6 +17,15 @@ export interface SuggestionResult {
|
|
|
17
17
|
next: Suggestion[];
|
|
18
18
|
/** Alternative paths (0-2 items) */
|
|
19
19
|
seeAlso: Suggestion[];
|
|
20
|
+
/** Tip displayed before Next (plain text) */
|
|
21
|
+
tip?: string;
|
|
22
|
+
/** Alternative section displayed after Next, before See also */
|
|
23
|
+
or?: {
|
|
24
|
+
/** Section label (e.g. "Or create a new query from the template") */
|
|
25
|
+
label: string;
|
|
26
|
+
/** Command items */
|
|
27
|
+
items: Suggestion[];
|
|
28
|
+
};
|
|
20
29
|
}
|
|
21
30
|
/**
|
|
22
31
|
* Context passed to suggestion rules for evaluation.
|
|
@@ -50,6 +59,8 @@ export interface SuggestionContext {
|
|
|
50
59
|
outputFile?: string | undefined;
|
|
51
60
|
/** Whether validation succeeded (for query validate) */
|
|
52
61
|
validationSuccess?: boolean | undefined;
|
|
62
|
+
/** Whether the query file has a $schema link */
|
|
63
|
+
hasSchemaLink?: boolean | undefined;
|
|
53
64
|
/** Number of added articles in diff result */
|
|
54
65
|
diffAddedCount?: number | undefined;
|
|
55
66
|
/** Number of removed articles in diff result */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cli/suggestions/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,oCAAoC;IACpC,OAAO,EAAE,UAAU,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cli/suggestions/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,oCAAoC;IACpC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,6CAA6C;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,EAAE,CAAC,EAAE;QACH,qEAAqE;QACrE,KAAK,EAAE,MAAM,CAAC;QACd,oBAAoB;QACpB,KAAK,EAAE,UAAU,EAAE,CAAC;KACrB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,qBAAqB;IACrB,aAAa,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC1C,iDAAiD;IACjD,YAAY,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC9C,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,kCAAkC;IAClC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,yCAAyC;IACzC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,4BAA4B;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,6BAA6B;IAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,gDAAgD;IAChD,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,oCAAoC;IACpC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,iBAAiB,KAAK,gBAAgB,GAAG,IAAI,CAAC"}
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -103,6 +103,8 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
103
103
|
sources: z.ZodDefault<z.ZodObject<{
|
|
104
104
|
unpaywall_email: z.ZodDefault<z.ZodString>;
|
|
105
105
|
core_api_key: z.ZodDefault<z.ZodString>;
|
|
106
|
+
ncbi_email: z.ZodDefault<z.ZodString>;
|
|
107
|
+
ncbi_tool: z.ZodDefault<z.ZodString>;
|
|
106
108
|
prefer_sources: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
107
109
|
}, z.core.$strip>>;
|
|
108
110
|
download: z.ZodDefault<z.ZodObject<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;iBAc/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AASlE;;;GAGG;AACH,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;iBAc/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AASlE;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8GvB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
|
package/dist/config/schema.js
CHANGED
|
@@ -55,10 +55,14 @@ const ConfigSchema = z.object({
|
|
|
55
55
|
sources: z.object({
|
|
56
56
|
unpaywall_email: z.string().default(""),
|
|
57
57
|
core_api_key: z.string().default(""),
|
|
58
|
+
ncbi_email: z.string().default(""),
|
|
59
|
+
ncbi_tool: z.string().default("search-hub"),
|
|
58
60
|
prefer_sources: z.array(z.string()).default(["pmc", "arxiv", "unpaywall", "core"])
|
|
59
61
|
}).default(() => ({
|
|
60
62
|
unpaywall_email: "",
|
|
61
63
|
core_api_key: "",
|
|
64
|
+
ncbi_email: "",
|
|
65
|
+
ncbi_tool: "search-hub",
|
|
62
66
|
prefer_sources: ["pmc", "arxiv", "unpaywall", "core"]
|
|
63
67
|
})),
|
|
64
68
|
download: z.object({
|
|
@@ -75,6 +79,8 @@ const ConfigSchema = z.object({
|
|
|
75
79
|
sources: {
|
|
76
80
|
unpaywall_email: "",
|
|
77
81
|
core_api_key: "",
|
|
82
|
+
ncbi_email: "",
|
|
83
|
+
ncbi_tool: "search-hub",
|
|
78
84
|
prefer_sources: ["pmc", "arxiv", "unpaywall", "core"]
|
|
79
85
|
},
|
|
80
86
|
download: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sources":["../../src/config/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Default values for provider configuration.\n */\nconst PROVIDER_DEFAULTS = {\n enabled: true,\n rate_limit: 3,\n timeout: 30000,\n retries: 3,\n max_results: 10000,\n} as const;\n\n/**\n * Schema for individual provider configuration.\n * Each provider (PubMed, Scopus, etc.) has similar config options.\n */\nexport const ProviderConfigSchema = z.object({\n enabled: z.boolean().default(PROVIDER_DEFAULTS.enabled),\n api_key: z.string().default(''),\n email: z\n .string()\n .refine((val) => val === '' || /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(val), {\n message: 'Invalid email',\n })\n .default(''),\n rate_limit: z.number().positive().default(PROVIDER_DEFAULTS.rate_limit),\n timeout: z.number().positive().default(PROVIDER_DEFAULTS.timeout),\n retries: z.number().int().min(0).default(PROVIDER_DEFAULTS.retries),\n max_results: z.number().int().positive().default(PROVIDER_DEFAULTS.max_results),\n inst_token: z.string().default(''),\n});\n\nexport type ProviderConfig = z.infer<typeof ProviderConfigSchema>;\n\n/**\n * Get default provider config object.\n */\nfunction getDefaultProviderConfig(): ProviderConfig {\n return ProviderConfigSchema.parse({});\n}\n\n/**\n * Main configuration schema for search-hub.\n * All fields have defaults, so an empty object is valid input.\n */\nexport const ConfigSchema = z.object({\n session: z\n .object({\n // Empty string means use platform default (resolved in loader.ts)\n directory: z.string().default(''),\n })\n .default(() => ({ directory: '' })),\n\n log: z\n .object({\n level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n })\n .default(() => ({ level: 'info' as const })),\n\n output: z\n .object({\n color: z.boolean().default(true),\n progress_bar: z.boolean().default(true),\n })\n .default(() => ({ color: true, progress_bar: true })),\n\n providers: z\n .object({\n pubmed: ProviderConfigSchema.default(getDefaultProviderConfig),\n eric: ProviderConfigSchema.default(getDefaultProviderConfig),\n arxiv: ProviderConfigSchema.default(getDefaultProviderConfig),\n scopus: ProviderConfigSchema.default(getDefaultProviderConfig),\n wos: ProviderConfigSchema.default(getDefaultProviderConfig),\n embase: ProviderConfigSchema.default(getDefaultProviderConfig),\n })\n .default(() => ({\n pubmed: getDefaultProviderConfig(),\n eric: getDefaultProviderConfig(),\n arxiv: getDefaultProviderConfig(),\n scopus: getDefaultProviderConfig(),\n wos: getDefaultProviderConfig(),\n embase: getDefaultProviderConfig(),\n })),\n\n fulltext: z\n .object({\n enabled: z.boolean().default(true),\n auto_convert_markdown: z.boolean().default(true),\n auto_attach_on_register: z.boolean().default(true),\n sources: z\n .object({\n unpaywall_email: z.string().default(''),\n core_api_key: z.string().default(''),\n prefer_sources: z.array(z.string()).default(['pmc', 'arxiv', 'unpaywall', 'core']),\n })\n .default(() => ({\n unpaywall_email: '',\n core_api_key: '',\n prefer_sources: ['pmc', 'arxiv', 'unpaywall', 'core'],\n })),\n download: z\n .object({\n concurrent_downloads: z.number().int().positive().default(3),\n retry_attempts: z.number().int().min(0).default(3),\n })\n .default(() => ({\n concurrent_downloads: 3,\n retry_attempts: 3,\n })),\n })\n .default(() => ({\n enabled: true,\n auto_convert_markdown: true,\n auto_attach_on_register: true,\n sources: {\n unpaywall_email: '',\n core_api_key: '',\n prefer_sources: ['pmc', 'arxiv', 'unpaywall', 'core'],\n },\n download: {\n concurrent_downloads: 3,\n retry_attempts: 3,\n },\n })),\n\n integration: z\n .object({\n reference_manager: z\n .object({\n enabled: z.boolean().default(true),\n command: z.string().default('ref'),\n auto_register: z.boolean().default(false),\n with_abstracts: z.boolean().default(false),\n })\n .default(() => ({\n enabled: true,\n command: 'ref',\n auto_register: false,\n with_abstracts: false,\n })),\n })\n .default(() => ({\n reference_manager: {\n enabled: true,\n command: 'ref',\n auto_register: false,\n with_abstracts: false,\n },\n })),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.js","sources":["../../src/config/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Default values for provider configuration.\n */\nconst PROVIDER_DEFAULTS = {\n enabled: true,\n rate_limit: 3,\n timeout: 30000,\n retries: 3,\n max_results: 10000,\n} as const;\n\n/**\n * Schema for individual provider configuration.\n * Each provider (PubMed, Scopus, etc.) has similar config options.\n */\nexport const ProviderConfigSchema = z.object({\n enabled: z.boolean().default(PROVIDER_DEFAULTS.enabled),\n api_key: z.string().default(''),\n email: z\n .string()\n .refine((val) => val === '' || /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(val), {\n message: 'Invalid email',\n })\n .default(''),\n rate_limit: z.number().positive().default(PROVIDER_DEFAULTS.rate_limit),\n timeout: z.number().positive().default(PROVIDER_DEFAULTS.timeout),\n retries: z.number().int().min(0).default(PROVIDER_DEFAULTS.retries),\n max_results: z.number().int().positive().default(PROVIDER_DEFAULTS.max_results),\n inst_token: z.string().default(''),\n});\n\nexport type ProviderConfig = z.infer<typeof ProviderConfigSchema>;\n\n/**\n * Get default provider config object.\n */\nfunction getDefaultProviderConfig(): ProviderConfig {\n return ProviderConfigSchema.parse({});\n}\n\n/**\n * Main configuration schema for search-hub.\n * All fields have defaults, so an empty object is valid input.\n */\nexport const ConfigSchema = z.object({\n session: z\n .object({\n // Empty string means use platform default (resolved in loader.ts)\n directory: z.string().default(''),\n })\n .default(() => ({ directory: '' })),\n\n log: z\n .object({\n level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n })\n .default(() => ({ level: 'info' as const })),\n\n output: z\n .object({\n color: z.boolean().default(true),\n progress_bar: z.boolean().default(true),\n })\n .default(() => ({ color: true, progress_bar: true })),\n\n providers: z\n .object({\n pubmed: ProviderConfigSchema.default(getDefaultProviderConfig),\n eric: ProviderConfigSchema.default(getDefaultProviderConfig),\n arxiv: ProviderConfigSchema.default(getDefaultProviderConfig),\n scopus: ProviderConfigSchema.default(getDefaultProviderConfig),\n wos: ProviderConfigSchema.default(getDefaultProviderConfig),\n embase: ProviderConfigSchema.default(getDefaultProviderConfig),\n })\n .default(() => ({\n pubmed: getDefaultProviderConfig(),\n eric: getDefaultProviderConfig(),\n arxiv: getDefaultProviderConfig(),\n scopus: getDefaultProviderConfig(),\n wos: getDefaultProviderConfig(),\n embase: getDefaultProviderConfig(),\n })),\n\n fulltext: z\n .object({\n enabled: z.boolean().default(true),\n auto_convert_markdown: z.boolean().default(true),\n auto_attach_on_register: z.boolean().default(true),\n sources: z\n .object({\n unpaywall_email: z.string().default(''),\n core_api_key: z.string().default(''),\n ncbi_email: z.string().default(''),\n ncbi_tool: z.string().default('search-hub'),\n prefer_sources: z.array(z.string()).default(['pmc', 'arxiv', 'unpaywall', 'core']),\n })\n .default(() => ({\n unpaywall_email: '',\n core_api_key: '',\n ncbi_email: '',\n ncbi_tool: 'search-hub',\n prefer_sources: ['pmc', 'arxiv', 'unpaywall', 'core'],\n })),\n download: z\n .object({\n concurrent_downloads: z.number().int().positive().default(3),\n retry_attempts: z.number().int().min(0).default(3),\n })\n .default(() => ({\n concurrent_downloads: 3,\n retry_attempts: 3,\n })),\n })\n .default(() => ({\n enabled: true,\n auto_convert_markdown: true,\n auto_attach_on_register: true,\n sources: {\n unpaywall_email: '',\n core_api_key: '',\n ncbi_email: '',\n ncbi_tool: 'search-hub',\n prefer_sources: ['pmc', 'arxiv', 'unpaywall', 'core'],\n },\n download: {\n concurrent_downloads: 3,\n retry_attempts: 3,\n },\n })),\n\n integration: z\n .object({\n reference_manager: z\n .object({\n enabled: z.boolean().default(true),\n command: z.string().default('ref'),\n auto_register: z.boolean().default(false),\n with_abstracts: z.boolean().default(false),\n })\n .default(() => ({\n enabled: true,\n command: 'ref',\n auto_register: false,\n with_abstracts: false,\n })),\n })\n .default(() => ({\n reference_manager: {\n enabled: true,\n command: 'ref',\n auto_register: false,\n with_abstracts: false,\n },\n })),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { parseQueryFile, parseQueryString } from "./query/parser.js";
|
|
2
2
|
import { ValidationError, fieldTypeSchema, filtersSchema, formatValidationErrors, overrideBlockSchema, queryBlockSchema, queryFileSchema, termBlockSchema, validateQueryFile } from "./query/validator.js";
|
|
3
|
+
import { MeSHLookupClient } from "./query/mesh-lookup.js";
|
|
4
|
+
import { extractControlledVocabTerms, validateControlledVocab } from "./query/vocab-validator.js";
|
|
3
5
|
import { loadConfig, saveConfig } from "./config/loader.js";
|
|
4
6
|
import { ConfigSchema } from "./config/schema.js";
|
|
5
7
|
import { DEFAULT_CONFIG, getDefaultConfig } from "./config/defaults.js";
|
|
@@ -14,6 +16,7 @@ export {
|
|
|
14
16
|
BaseProvider,
|
|
15
17
|
ConfigSchema,
|
|
16
18
|
DEFAULT_CONFIG,
|
|
19
|
+
MeSHLookupClient,
|
|
17
20
|
MockProvider,
|
|
18
21
|
ProviderRegistry,
|
|
19
22
|
RateLimiter,
|
|
@@ -23,6 +26,7 @@ export {
|
|
|
23
26
|
createProviderRegistry,
|
|
24
27
|
createSession,
|
|
25
28
|
deserializeState,
|
|
29
|
+
extractControlledVocabTerms,
|
|
26
30
|
fieldTypeSchema,
|
|
27
31
|
filtersSchema,
|
|
28
32
|
formatValidationErrors,
|
|
@@ -49,6 +53,7 @@ export {
|
|
|
49
53
|
termBlockSchema,
|
|
50
54
|
updateDatabaseStatus,
|
|
51
55
|
updateSessionStatus,
|
|
56
|
+
validateControlledVocab,
|
|
52
57
|
validateQueryFile
|
|
53
58
|
};
|
|
54
59
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FulltextMeta } from '
|
|
2
|
-
import { FulltextAttachResult } from '
|
|
1
|
+
import { FulltextMeta } from '@ncukondo/academic-fulltext';
|
|
2
|
+
import { FulltextAttachResult } from './types.js';
|
|
3
3
|
/** Files we try to attach, in priority order. */
|
|
4
4
|
export declare const ATTACHABLE_FILES: readonly ["fulltext.pdf", "fulltext.md"];
|
|
5
5
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach-shared.d.ts","sourceRoot":"","sources":["../../src/integration/attach-shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,iDAAiD;AACjD,eAAO,MAAM,gBAAgB,0CAA2C,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,SAAS,CAUhG;AAED,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAwBtF;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAcnB;AAED,0CAA0C;AAC1C,MAAM,WAAW,6BAA6B;IAC5C,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,sDAAsD;IACtD,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wBAAwB;IACxB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,oBAAoB,CAAC,CAsE/B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach-shared.js","sources":["../../src/integration/attach-shared.ts"],"sourcesContent":["/**\n * Shared fulltext attach utilities.\n * Used by both the integration attach (register flow) and standalone attach command.\n */\n\nimport { readdir, readFile, access } from 'node:fs/promises';\nimport { constants } from 'node:fs';\nimport { join } from 'node:path';\nimport type { FulltextMeta } from '@ncukondo/academic-fulltext';\nimport type { FulltextAttachResult } from './types.js';\n\n/** Files we try to attach, in priority order. */\nexport const ATTACHABLE_FILES = ['fulltext.pdf', 'fulltext.md'] as const;\n\n/**\n * Find the ref ID matching a fulltext meta entry.\n * Tries DOI first, then PMID.\n */\nexport function findRefId(meta: FulltextMeta, refLookup: Map<string, string>): string | undefined {\n if (meta.doi) {\n const byDoi = refLookup.get(`doi:${meta.doi}`);\n if (byDoi) return byDoi;\n }\n if (meta.pmid) {\n const byPmid = refLookup.get(`pmid:${meta.pmid}`);\n if (byPmid) return byPmid;\n }\n return undefined;\n}\n\n/** A single article directory entry with its loaded metadata. */\nexport interface ArticleEntry {\n dirName: string;\n articleDir: string;\n meta: FulltextMeta | null;\n}\n\n/**\n * Scan a fulltext directory and load metadata for all article subdirectories.\n * Returns an empty array if the directory doesn't exist.\n */\nexport async function loadFulltextEntries(fulltextDir: string): Promise<ArticleEntry[]> {\n let dirNames: string[];\n try {\n const dirEntries = await readdir(fulltextDir, { withFileTypes: true });\n dirNames = dirEntries\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n } catch {\n return [];\n }\n\n const entries: ArticleEntry[] = [];\n for (const dirName of dirNames) {\n const articleDir = join(fulltextDir, dirName);\n try {\n const raw = await readFile(join(articleDir, 'meta.json'), 'utf-8');\n const meta = JSON.parse(raw) as FulltextMeta;\n entries.push({ dirName, articleDir, meta });\n } catch {\n // Will be handled as a failed entry by the caller\n entries.push({ dirName, articleDir, meta: null });\n }\n }\n return entries;\n}\n\n/**\n * Determine which attachable files exist for an article, verifying on disk.\n */\nexport async function resolveAttachableFiles(\n articleDir: string,\n meta: FulltextMeta,\n): Promise<string[]> {\n const filesToAttach: string[] = [];\n for (const filename of ATTACHABLE_FILES) {\n const fileKey = filename === 'fulltext.pdf' ? 'pdf' : 'markdown';\n if (meta.files[fileKey]) {\n try {\n await access(join(articleDir, filename), constants.R_OK);\n filesToAttach.push(filename);\n } catch {\n // File recorded in meta but not on disk — skip\n }\n }\n }\n return filesToAttach;\n}\n\n/** Options for processFulltextEntries. */\nexport interface ProcessFulltextEntriesOptions {\n /** Path to the fulltext directory (sessionDir/fulltext) */\n fulltextDir: string;\n /** Lookup map from identifiers to ref IDs */\n refLookup: Map<string, string>;\n /** Function to attach a single file to a ref entry */\n attachFile: (refId: string, filePath: string) => Promise<void>;\n /** If true, skip actual attach calls and just record what would be attached */\n dryRun?: boolean;\n /** Progress callback */\n onProgress?: (current: number, total: number) => void;\n}\n\n/**\n * Shared attach loop: scan fulltext entries, match to refs, and attach files.\n * Both the standalone and integrated attach commands delegate to this function.\n */\nexport async function processFulltextEntries(\n options: ProcessFulltextEntriesOptions,\n): Promise<FulltextAttachResult> {\n const { fulltextDir, refLookup, attachFile, dryRun = false, onProgress } = options;\n\n const result: FulltextAttachResult = {\n summary: { total: 0, attached: 0, skipped: 0, failed: 0 },\n attached: [],\n skipped: [],\n failed: [],\n };\n\n const entries = await loadFulltextEntries(fulltextDir);\n result.summary.total = entries.length;\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i]!;\n const { dirName, articleDir, meta } = entry;\n\n if (onProgress) {\n onProgress(i + 1, entries.length);\n }\n\n if (!meta) {\n result.summary.failed++;\n result.failed.push({\n dirName,\n reason: 'meta_read_error',\n error: 'Failed to read meta.json',\n });\n continue;\n }\n\n const refId = findRefId(meta, refLookup);\n if (!refId) {\n result.summary.skipped++;\n result.skipped.push({ dirName, reason: 'not_in_ref' });\n continue;\n }\n\n const filesToAttach = await resolveAttachableFiles(articleDir, meta);\n\n if (filesToAttach.length === 0) {\n result.summary.skipped++;\n result.skipped.push({ dirName, reason: 'no_files' });\n continue;\n }\n\n if (dryRun) {\n result.summary.attached++;\n result.attached.push({ refId, files: filesToAttach });\n continue;\n }\n\n try {\n for (const filename of filesToAttach) {\n const filePath = join(articleDir, filename);\n await attachFile(refId, filePath);\n }\n result.summary.attached++;\n result.attached.push({ refId, files: filesToAttach });\n } catch (error) {\n result.summary.failed++;\n result.failed.push({\n dirName,\n reason: 'attach_error',\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n\n return result;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { refFulltextAttach } from "./ref-cli.js";
|
|
3
|
-
import { processFulltextEntries } from "
|
|
3
|
+
import { processFulltextEntries } from "./attach-shared.js";
|
|
4
4
|
function extractDoi(source) {
|
|
5
5
|
if (source.startsWith("10.")) return source;
|
|
6
6
|
if (source.startsWith("doi:")) return source.slice(4);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fulltext-attach.js","sources":["../../src/integration/fulltext-attach.ts"],"sourcesContent":["/**\n * Fulltext attach logic for reference-manager integration.\n * Attaches fulltext files (PDF, Markdown) from session fulltext directories\n * to corresponding entries in the reference-manager library.\n */\n\nimport { join } from 'node:path';\nimport type { FulltextAttachResult } from './types.js';\nimport { refFulltextAttach, type RefCliOptions } from './ref-cli.js';\nimport { processFulltextEntries } from '
|
|
1
|
+
{"version":3,"file":"fulltext-attach.js","sources":["../../src/integration/fulltext-attach.ts"],"sourcesContent":["/**\n * Fulltext attach logic for reference-manager integration.\n * Attaches fulltext files (PDF, Markdown) from session fulltext directories\n * to corresponding entries in the reference-manager library.\n */\n\nimport { join } from 'node:path';\nimport type { FulltextAttachResult } from './types.js';\nimport { refFulltextAttach, type RefCliOptions } from './ref-cli.js';\nimport { processFulltextEntries } from './attach-shared.js';\n\n/**\n * Options for attachFulltexts function.\n */\nexport interface AttachFulltextsOptions {\n /** Path to the session directory */\n sessionDir: string;\n /** Path to the reference library file */\n libraryPath: string;\n /** List of refs that were added/exist in the library, with source identifiers */\n addedRefs: Array<{ id: string; source: string }>;\n /** Progress callback */\n onProgress?: (current: number, total: number) => void;\n}\n\n/**\n * Extract DOI from a source string.\n * Sources look like \"10.1234/test\" (bare DOI) or \"doi:10.1234/test\".\n */\nfunction extractDoi(source: string): string | undefined {\n if (source.startsWith('10.')) return source;\n if (source.startsWith('doi:')) return source.slice(4);\n return undefined;\n}\n\n/**\n * Extract PMID from a source string.\n * Sources look like \"pmid:12345678\".\n */\nfunction extractPmid(source: string): string | undefined {\n if (source.startsWith('pmid:')) return source.slice(5);\n return undefined;\n}\n\n/**\n * Build a lookup map from identifiers to ref IDs.\n * Keys are normalized: \"doi:10.1234/test\" and \"pmid:12345678\".\n */\nfunction buildRefLookup(addedRefs: Array<{ id: string; source: string }>): Map<string, string> {\n const lookup = new Map<string, string>();\n for (const ref of addedRefs) {\n const doi = extractDoi(ref.source);\n if (doi) {\n lookup.set(`doi:${doi}`, ref.id);\n }\n const pmid = extractPmid(ref.source);\n if (pmid) {\n lookup.set(`pmid:${pmid}`, ref.id);\n }\n }\n return lookup;\n}\n\n/**\n * Attach fulltext files from session fulltext directories to reference-manager entries.\n *\n * For each article directory in sessionDir/fulltext/:\n * 1. Load meta.json to get identifiers\n * 2. Match to a ref entry by DOI or PMID\n * 3. Attach available fulltext files (PDF, Markdown)\n * 4. Record results\n */\nexport async function attachFulltexts(\n options: AttachFulltextsOptions,\n): Promise<FulltextAttachResult> {\n const { sessionDir, libraryPath, addedRefs, onProgress } = options;\n const fulltextDir = join(sessionDir, 'fulltext');\n const refCliOptions: RefCliOptions = { libraryPath };\n const refLookup = buildRefLookup(addedRefs);\n\n return processFulltextEntries({\n fulltextDir,\n refLookup,\n attachFile: (refId, filePath) => refFulltextAttach(refId, filePath, refCliOptions),\n ...(onProgress ? { onProgress } : {}),\n });\n}\n"],"names":[],"mappings":";;;AA6BA,SAAS,WAAW,QAAoC;AACtD,MAAI,OAAO,WAAW,KAAK,EAAG,QAAO;AACrC,MAAI,OAAO,WAAW,MAAM,EAAG,QAAO,OAAO,MAAM,CAAC;AACpD,SAAO;AACT;AAMA,SAAS,YAAY,QAAoC;AACvD,MAAI,OAAO,WAAW,OAAO,EAAG,QAAO,OAAO,MAAM,CAAC;AACrD,SAAO;AACT;AAMA,SAAS,eAAe,WAAuE;AAC7F,QAAM,6BAAa,IAAA;AACnB,aAAW,OAAO,WAAW;AAC3B,UAAM,MAAM,WAAW,IAAI,MAAM;AACjC,QAAI,KAAK;AACP,aAAO,IAAI,OAAO,GAAG,IAAI,IAAI,EAAE;AAAA,IACjC;AACA,UAAM,OAAO,YAAY,IAAI,MAAM;AACnC,QAAI,MAAM;AACR,aAAO,IAAI,QAAQ,IAAI,IAAI,IAAI,EAAE;AAAA,IACnC;AAAA,EACF;AACA,SAAO;AACT;AAWA,eAAsB,gBACpB,SAC+B;AAC/B,QAAM,EAAE,YAAY,aAAa,WAAW,eAAe;AAC3D,QAAM,cAAc,KAAK,YAAY,UAAU;AAC/C,QAAM,gBAA+B,EAAE,YAAA;AACvC,QAAM,YAAY,eAAe,SAAS;AAE1C,SAAO,uBAAuB;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,YAAY,CAAC,OAAO,aAAa,kBAAkB,OAAO,UAAU,aAAa;AAAA,IACjF,GAAI,aAAa,EAAE,eAAe,CAAA;AAAA,EAAC,CACpC;AACH;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citation-key.js","sources":["../../../../../node_modules/@ncukondo/academic-fulltext/dist/citation-key.js"],"sourcesContent":["/**\n * Citation key generation for fulltext directories.\n */\nimport { randomUUID } from \"node:crypto\";\nimport anyAscii from \"any-ascii\";\n/**\n * Generate a collision suffix: a, b, ..., z, aa, ab, ...\n */\nfunction collisionSuffix(index) {\n let result = \"\";\n let n = index;\n do {\n result = String.fromCodePoint(97 + (n % 26)) + result;\n n = Math.floor(n / 26) - 1;\n } while (n >= 0);\n return result;\n}\n/** CJK Unified Ideographs range: U+4E00–U+9FFF */\nconst CJK_REGEX = /[\\u4e00-\\u9fff]/;\n/**\n * Extract the family name portion from an author string.\n * Handles formats like \"Smith, J.\" → \"Smith\", \"Smith\" → \"Smith\".\n */\nfunction extractFamilyName(author) {\n const commaIndex = author.indexOf(\",\");\n if (commaIndex >= 0) {\n return author.slice(0, commaIndex).trim();\n }\n return author.trim();\n}\n/**\n * Generate a citation key from author and year.\n * Format: {family-name-lowercase}{year}\n * With collision handling via letter suffixes (a, b, c, ...).\n */\nexport function generateCitationKey(author, year, existingKeys) {\n // Extract and normalize author\n const rawFamily = author?.trim() ? extractFamilyName(author) : \"unknown\";\n // CJK characters cannot be accurately transliterated to the correct reading\n // (any-ascii maps them to Chinese pinyin, not Japanese romaji etc.)\n // Fall back to 'unknown' for names containing CJK ideographs.\n const normalizedFamily = CJK_REGEX.test(rawFamily)\n ? \"unknown\"\n : anyAscii(rawFamily)\n .toLowerCase()\n .replace(/[^a-z]/g, \"\") || \"unknown\";\n // Normalize year\n const normalizedYear = year?.trim() || \"0000\";\n const baseKey = `${normalizedFamily}${normalizedYear}`;\n // Handle collisions\n if (!existingKeys || !existingKeys.includes(baseKey)) {\n return baseKey;\n }\n // Find the first available suffix\n for (let i = 0;; i++) {\n const candidateKey = `${baseKey}${collisionSuffix(i)}`;\n if (!existingKeys.includes(candidateKey)) {\n return candidateKey;\n }\n }\n}\n/**\n * Generate a directory name from a citation key.\n * Format: {citationKey}-{uuid8}\n */\nexport function generateDirName(citationKey, uuid) {\n const id = uuid ?? randomUUID();\n const uuid8 = id.slice(0, 8);\n return `${citationKey}-${uuid8}`;\n}\n//# sourceMappingURL=citation-key.js.map"],"names":[],"mappings":";;AAQA,SAAS,gBAAgB,OAAO;AAC5B,MAAI,SAAS;AACb,MAAI,IAAI;AACR,KAAG;AACC,aAAS,OAAO,cAAc,KAAM,IAAI,EAAG,IAAI;AAC/C,QAAI,KAAK,MAAM,IAAI,EAAE,IAAI;AAAA,EAC7B,SAAS,KAAK;AACd,SAAO;AACX;AAEA,MAAM,YAAY;AAKlB,SAAS,kBAAkB,QAAQ;AAC/B,QAAM,aAAa,OAAO,QAAQ,GAAG;AACrC,MAAI,cAAc,GAAG;AACjB,WAAO,OAAO,MAAM,GAAG,UAAU,EAAE,KAAI;AAAA,EAC3C;AACA,SAAO,OAAO,KAAI;AACtB;AAMO,SAAS,oBAAoB,QAAQ,MAAM,cAAc;AAE5D,QAAM,YAAY,QAAQ,KAAI,IAAK,kBAAkB,MAAM,IAAI;AAI/D,QAAM,mBAAmB,UAAU,KAAK,SAAS,IAC3C,YACA,SAAS,SAAS,EACf,YAAW,EACX,QAAQ,WAAW,EAAE,KAAK;AAEnC,QAAM,iBAAiB,MAAM,KAAI,KAAM;AACvC,QAAM,UAAU,GAAG,gBAAgB,GAAG,cAAc;AAEpD,MAAI,CAAC,gBAAgB,CAAC,aAAa,SAAS,OAAO,GAAG;AAClD,WAAO;AAAA,EACX;AAEA,WAAS,IAAI,KAAI,KAAK;AAClB,UAAM,eAAe,GAAG,OAAO,GAAG,gBAAgB,CAAC,CAAC;AACpD,QAAI,CAAC,aAAa,SAAS,YAAY,GAAG;AACtC,aAAO;AAAA,IACX;AAAA,EACJ;AACJ;AAKO,SAAS,gBAAgB,aAAa,MAAM;AAC/C,QAAM,KAAK,QAAQ,WAAU;AAC7B,QAAM,QAAQ,GAAG,MAAM,GAAG,CAAC;AAC3B,SAAO,GAAG,WAAW,IAAI,KAAK;AAClC;","x_google_ignoreList":[0]}
|