fix: guard against closed streams in promo and missing vector tables (#579, #607)

- Wrap isatty() in _is_interactive_session() with try/except ValueError
  so MCP stdio transport shutdown no longer produces noisy tracebacks
- Check both search_vector_chunks AND search_vector_embeddings exist
  before running JOIN queries in get_embedding_status(), fixing
  OperationalError when only the chunks table is present
- Add test for closed-stream scenario

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
phernandez
2026-02-25 18:01:59 -06:00
parent 74e6afdc0f
commit e46555bf2c
3 changed files with 27 additions and 4 deletions
+15
View File
@@ -8,6 +8,7 @@ from typer.testing import CliRunner
from basic_memory.cli.app import app
import basic_memory
from basic_memory.cli.promo import (
_is_interactive_session,
maybe_show_cloud_promo,
maybe_show_init_line,
)
@@ -294,3 +295,17 @@ def test_cloud_promo_command_on_clears_opt_out(monkeypatch):
assert "Cloud promo messages enabled" in result.stdout
assert len(instances) == 1
assert instances[0].saved_config.cloud_promo_opt_out is False
# --- _is_interactive_session tests ---
def test_is_interactive_session_returns_false_when_streams_closed(monkeypatch):
"""isatty() raises ValueError on closed file descriptors (e.g., MCP shutdown)."""
class ClosedStream:
def isatty(self):
raise ValueError("I/O operation on closed file")
monkeypatch.setattr("sys.stdin", ClosedStream())
assert _is_interactive_session() is False