Skip to content

Commit cc62097

Browse files
committed
feat(cli): add --from-pageindex-cloud flag to add command
1 parent 188badd commit cc62097

2 files changed

Lines changed: 51 additions & 2 deletions

File tree

openkb/cli.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -689,23 +689,44 @@ def init(model, language):
689689

690690

691691
@cli.command()
692-
@click.argument("path")
692+
@click.argument("path", required=False)
693+
@click.option(
694+
"--from-pageindex-cloud", "from_pageindex_cloud", default=None, metavar="DOC_ID",
695+
help="Import an already-indexed PageIndex Cloud document by its doc-id "
696+
"(no local file). Mutually exclusive with PATH.",
697+
)
693698
@click.pass_context
694699
@_with_kb_lock(exclusive=True)
695-
def add(ctx, path):
700+
def add(ctx, path, from_pageindex_cloud):
696701
"""Add a document or directory of documents at PATH to the knowledge base.
697702
698703
PATH may be a local file, a local directory (which is walked
699704
recursively for supported extensions), or an http(s) URL. URLs are
700705
fetched into ``raw/`` first: PDF responses (by Content-Type and
701706
magic-byte sniff) are saved as ``.pdf``; HTML responses are run
702707
through trafilatura's main-content extractor and saved as ``.md``.
708+
709+
Alternatively, pass --from-pageindex-cloud <DOC_ID> to import a document
710+
that is already indexed in PageIndex Cloud, with no local file. Requires
711+
the PAGEINDEX_API_KEY environment variable.
703712
"""
704713
kb_dir = _find_kb_dir(ctx.obj.get("kb_dir_override"))
705714
if kb_dir is None:
706715
click.echo("No knowledge base found. Run `openkb init` first.")
707716
return
708717

718+
# Cloud import path — mutually exclusive with a local/URL PATH.
719+
if from_pageindex_cloud is not None:
720+
if path is not None:
721+
click.echo("Provide either PATH or --from-pageindex-cloud, not both.")
722+
return
723+
import_from_pageindex_cloud(from_pageindex_cloud, kb_dir)
724+
return
725+
726+
if path is None:
727+
click.echo("Provide a PATH or use --from-pageindex-cloud <DOC_ID>.")
728+
return
729+
709730
# URL ingest: download into raw/ first, then call add_single_file
710731
# explicitly so we can clean up the just-downloaded file if it
711732
# turns out to be a duplicate (registry already has its hash).

tests/test_add_command.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,34 @@ def test_add_oldest_legacy_entry_converges_to_single_entry(self, tmp_path):
204204
assert len(new_entries) == 1 # …exactly one entry survives
205205
assert new_entries[0]["path"] # with path identity persisted
206206

207+
def test_add_from_pageindex_cloud_dispatches(self, tmp_path):
208+
kb_dir = self._setup_kb(tmp_path)
209+
runner = CliRunner()
210+
with patch("openkb.cli.import_from_pageindex_cloud", return_value="added") as mock_imp, \
211+
patch("openkb.cli._find_kb_dir", return_value=kb_dir):
212+
runner.invoke(cli, ["add", "--from-pageindex-cloud", "doc-123"])
213+
mock_imp.assert_called_once_with("doc-123", kb_dir)
214+
215+
def test_add_rejects_path_and_cloud_together(self, tmp_path):
216+
kb_dir = self._setup_kb(tmp_path)
217+
doc = tmp_path / "test.md"
218+
doc.write_text("# Hi")
219+
runner = CliRunner()
220+
with patch("openkb.cli.import_from_pageindex_cloud") as mock_imp, \
221+
patch("openkb.cli.add_single_file") as mock_add, \
222+
patch("openkb.cli._find_kb_dir", return_value=kb_dir):
223+
result = runner.invoke(cli, ["add", str(doc), "--from-pageindex-cloud", "doc-1"])
224+
assert "not both" in result.output
225+
mock_imp.assert_not_called()
226+
mock_add.assert_not_called()
227+
228+
def test_add_requires_path_or_cloud(self, tmp_path):
229+
kb_dir = self._setup_kb(tmp_path)
230+
runner = CliRunner()
231+
with patch("openkb.cli._find_kb_dir", return_value=kb_dir):
232+
result = runner.invoke(cli, ["add"])
233+
assert "Provide a PATH" in result.output
234+
207235

208236
class TestImportFromPageindexCloud:
209237
def _setup_kb(self, tmp_path):

0 commit comments

Comments
 (0)