Skip to content

Commit a2376b9

Browse files
committed
feat(visualize): open the graph in the browser by default
Auto-open after generating so plain `openkb visualize` just shows the graph; pass --no-open for headless/CI use. The HTML is still written to output/visualize/graph.html every run (latest snapshot, shareable). If a browser can't be launched, print a hint instead of failing.
1 parent 4e4d1f3 commit a2376b9

2 files changed

Lines changed: 25 additions & 6 deletions

File tree

openkb/cli.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,8 +1495,8 @@ def lint(ctx, fix):
14951495

14961496

14971497
@cli.command()
1498-
@click.option("--open", "open_browser", is_flag=True, default=False,
1499-
help="Open the generated graph in your browser.")
1498+
@click.option("--open/--no-open", "open_browser", default=True,
1499+
help="Open the graph in your browser after generating (default: on; --no-open for headless).")
15001500
@click.pass_context
15011501
@_with_kb_lock(exclusive=False)
15021502
def visualize(ctx, open_browser):
@@ -1516,7 +1516,12 @@ def visualize(ctx, open_browser):
15161516
click.echo(f"Graph written to {out} ({len(graph['nodes'])} nodes, {len(graph['edges'])} edges)")
15171517
if open_browser:
15181518
import webbrowser
1519-
webbrowser.open(out.resolve().as_uri()) # resolve() so a relative --kb-dir still yields a valid file URI
1519+
try:
1520+
opened = webbrowser.open(out.resolve().as_uri()) # resolve() so a relative --kb-dir still yields a valid file URI
1521+
except Exception:
1522+
opened = False
1523+
if not opened:
1524+
click.echo("(couldn't launch a browser — open the file above manually, or use --no-open)")
15201525

15211526

15221527
def print_list(kb_dir: Path) -> None:

tests/test_visualize_cli.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,38 @@ def _kb(tmp_path: Path) -> Path:
1616
return tmp_path
1717

1818

19-
def test_visualize_writes_html(tmp_path):
19+
def test_visualize_writes_html_and_opens_by_default(tmp_path):
2020
kb = _kb(tmp_path)
21-
with patch("openkb.cli._find_kb_dir", return_value=kb):
21+
with patch("openkb.cli._find_kb_dir", return_value=kb), \
22+
patch("webbrowser.open") as wb:
2223
result = CliRunner().invoke(cli, ["visualize"])
2324
assert result.exit_code == 0, result.output
2425
out = kb / "output" / "visualize" / "graph.html"
2526
assert out.exists()
2627
html = out.read_text(encoding="utf-8")
2728
assert "<canvas" in html and '"concepts/a"' in html
29+
wb.assert_called_once() # auto-opens the browser by default
30+
31+
32+
def test_visualize_no_open_suppresses_browser(tmp_path):
33+
kb = _kb(tmp_path)
34+
with patch("openkb.cli._find_kb_dir", return_value=kb), \
35+
patch("webbrowser.open") as wb:
36+
result = CliRunner().invoke(cli, ["visualize", "--no-open"])
37+
assert result.exit_code == 0, result.output
38+
assert (kb / "output" / "visualize" / "graph.html").exists()
39+
wb.assert_not_called() # --no-open keeps it headless-friendly
2840

2941

3042
def test_visualize_empty_wiki(tmp_path):
3143
for sub in ("summaries", "concepts", "entities"):
3244
(tmp_path / "wiki" / sub).mkdir(parents=True)
3345
(tmp_path / ".openkb").mkdir()
3446
(tmp_path / ".openkb" / "config.yaml").write_text("model: gpt-4o-mini\n", encoding="utf-8")
35-
with patch("openkb.cli._find_kb_dir", return_value=tmp_path):
47+
with patch("openkb.cli._find_kb_dir", return_value=tmp_path), \
48+
patch("webbrowser.open") as wb:
3649
result = CliRunner().invoke(cli, ["visualize"])
3750
assert result.exit_code == 0
3851
assert "No wiki pages" in result.output
3952
assert not (tmp_path / "output" / "visualize" / "graph.html").exists()
53+
wb.assert_not_called() # nothing to show → no browser

0 commit comments

Comments
 (0)