diff --git a/apps/activities/routes.py b/apps/activities/routes.py index 315cff20c..795ade8d1 100644 --- a/apps/activities/routes.py +++ b/apps/activities/routes.py @@ -102,7 +102,7 @@ def activities_stats(month: str) -> Any: JSON dict mapping day (YYYYMMDD) to facet counts dict. Frontend handles filtering by selected facet or summing for all-facet mode. """ - from think.events import get_month_event_counts + from think.event_formatter import get_month_event_counts # Validate month format (YYYYMM) if not re.fullmatch(r"\d{6}", month): diff --git a/tests/test_call.py b/tests/test_call.py index 444a6d675..d9854a994 100644 --- a/tests/test_call.py +++ b/tests/test_call.py @@ -148,34 +148,12 @@ class TestDiscovery: class TestJournal: """Tests for 'sol call journal' commands.""" - def test_journal_app_discovered(self): - """Journal sub-app is registered and shows help.""" - result = runner.invoke(call_app, ["journal", "--help"]) - assert result.exit_code == 0 - for cmd in ("search", "events", "facet", "facets", "news", "agents", "read"): - assert cmd in result.output - def test_journal_search(self): """Search command runs without error.""" result = runner.invoke(call_app, ["journal", "search", "test", "--limit", "5"]) assert result.exit_code == 0 assert "results" in result.output - def test_journal_events(self): - """Events command returns fixture data.""" - result = runner.invoke(call_app, ["journal", "events", "20240101"]) - assert result.exit_code == 0 - # Fixture has work + personal events for this day - assert "Team standup" in result.output - - def test_journal_events_with_facet(self): - """Events command filters by facet.""" - result = runner.invoke( - call_app, ["journal", "events", "20240101", "--facet", "work"] - ) - assert result.exit_code == 0 - assert "Team standup" in result.output - def test_journal_facet(self): """Facet command shows summary for test-facet.""" result = runner.invoke(call_app, ["journal", "facet", "show", "test-facet"]) @@ -200,14 +178,6 @@ class TestJournal: if "0 results" not in output: assert "Facets:" in output or "Agents:" in output - def test_journal_events_shows_details(self): - """Events output includes participants and details.""" - result = runner.invoke(call_app, ["journal", "events", "20240101"]) - assert result.exit_code == 0 - assert "Participants:" in result.output - assert "Alice" in result.output - assert "Details:" in result.output - def test_journal_facets(self): """Facets command lists available facets.""" result = runner.invoke(call_app, ["journal", "facets"]) @@ -915,26 +885,6 @@ class TestResolveHelpers: class TestJournalSolEnv: """Tests for journal commands resolving SOL_* env vars.""" - def test_events_from_sol_day(self, monkeypatch): - """events with SOL_DAY env and no arg works.""" - monkeypatch.setenv("SOL_DAY", "20240101") - result = runner.invoke(call_app, ["journal", "events"]) - assert result.exit_code == 0 - assert "Team standup" in result.output - - def test_events_arg_overrides_env(self, monkeypatch): - """events with both env and arg — arg wins.""" - monkeypatch.setenv("SOL_DAY", "19990101") - result = runner.invoke(call_app, ["journal", "events", "20240101"]) - assert result.exit_code == 0 - assert "Team standup" in result.output - - def test_events_no_day_exits(self, monkeypatch): - """events with neither arg nor env exits with error.""" - monkeypatch.delenv("SOL_DAY", raising=False) - result = runner.invoke(call_app, ["journal", "events"]) - assert result.exit_code != 0 - def test_agents_from_sol_day(self, monkeypatch): """agents with SOL_DAY env and no arg works.""" monkeypatch.setenv("SOL_DAY", "20240101") diff --git a/tests/test_events.py b/tests/test_events.py index 082ae82b7..f9381eafc 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -6,7 +6,7 @@ import json def test_get_month_event_counts(tmp_path, monkeypatch): """Test get_month_event_counts scans event files correctly.""" - from think.events import get_month_event_counts + from think.event_formatter import get_month_event_counts journal = tmp_path @@ -46,7 +46,7 @@ def test_get_month_event_counts(tmp_path, monkeypatch): def test_get_month_event_counts_future_dates(tmp_path, monkeypatch): """Test that future dates without day directories are included.""" - from think.events import get_month_event_counts + from think.event_formatter import get_month_event_counts journal = tmp_path @@ -78,7 +78,7 @@ def test_get_month_event_counts_future_dates(tmp_path, monkeypatch): def test_get_month_event_counts_skips_entries_without_title(tmp_path, monkeypatch): """Test that entries without title are not counted.""" - from think.events import get_month_event_counts + from think.event_formatter import get_month_event_counts journal = tmp_path @@ -106,7 +106,7 @@ def test_get_month_event_counts_skips_entries_without_title(tmp_path, monkeypatc def test_get_month_event_counts_empty_month(tmp_path, monkeypatch): """Test that empty month returns empty dict.""" - from think.events import get_month_event_counts + from think.event_formatter import get_month_event_counts journal = tmp_path @@ -123,7 +123,7 @@ def test_get_month_event_counts_empty_month(tmp_path, monkeypatch): def test_get_month_event_counts_empty_journal(tmp_path, monkeypatch): """Test that empty journal directory returns empty dict.""" - from think.events import get_month_event_counts + from think.event_formatter import get_month_event_counts monkeypatch.setenv("_SOLSTONE_JOURNAL_OVERRIDE", str(tmp_path)) diff --git a/tests/test_formatters.py b/tests/test_formatters.py index c8869e62d..d03d82584 100644 --- a/tests/test_formatters.py +++ b/tests/test_formatters.py @@ -976,7 +976,7 @@ class TestFormatEvents: def test_format_events_direct(self): """Test format_events function directly.""" - from think.events import format_events + from think.event_formatter import format_events entries = [ { @@ -1008,7 +1008,7 @@ class TestFormatEvents: def test_format_events_planned_labels(self): """Test that planned future events use 'Planned', 'Scheduled', 'Expected' labels.""" - from think.events import format_events + from think.event_formatter import format_events entries = [ { @@ -1031,7 +1031,7 @@ class TestFormatEvents: def test_format_events_occurrence_no_created_on(self): """Test that occurrences do NOT show 'Created on' or 'Planned' prefix.""" - from think.events import format_events + from think.event_formatter import format_events entries = [ { @@ -1055,7 +1055,7 @@ class TestFormatEvents: def test_format_events_header_facet_from_path(self): """Test that facet name and day are extracted from file path.""" - from think.events import format_events + from think.event_formatter import format_events entries = [{"type": "task", "title": "Test", "occurred": True}] context = {"file_path": "/journal/facets/personal/events/20251215.jsonl"} @@ -1066,7 +1066,7 @@ class TestFormatEvents: def test_format_events_timestamp_calculation(self): """Test that timestamp is calculated from day + start time.""" - from think.events import format_events + from think.event_formatter import format_events entries = [ { @@ -1091,7 +1091,7 @@ class TestFormatEvents: def test_format_events_skipped_entries_error(self): """Test that entries without 'title' field are skipped and reported.""" - from think.events import format_events + from think.event_formatter import format_events entries = [ {"type": "meeting", "title": "Valid", "occurred": True}, @@ -1108,7 +1108,7 @@ class TestFormatEvents: def test_format_events_mixed_occurred_anticipated(self): """Test header counts for mixed occurred/anticipated events.""" - from think.events import format_events + from think.event_formatter import format_events entries = [ {"type": "meeting", "title": "Past event", "occurred": True}, @@ -1123,7 +1123,7 @@ class TestFormatEvents: def test_format_events_time_display_24h(self): """Test that times are displayed in 24-hour format without seconds.""" - from think.events import format_events + from think.event_formatter import format_events entries = [ { @@ -1143,7 +1143,7 @@ class TestFormatEvents: def test_format_events_with_details(self): """Test that details field is included in output.""" - from think.events import format_events + from think.event_formatter import format_events entries = [ { @@ -1515,7 +1515,7 @@ class TestFormatterIndexerMetadata: def test_format_events_returns_indexer(self): """Test format_events returns indexer with agent.""" - from think.events import format_events + from think.event_formatter import format_events entries = [{"type": "meeting", "title": "Test", "occurred": True}] chunks, meta = format_events(entries) @@ -1621,7 +1621,7 @@ class TestFormatterSourceKey: def test_format_events_returns_source(self): """Test format_events returns source with original event.""" - from think.events import format_events + from think.event_formatter import format_events event = {"type": "meeting", "title": "Test", "occurred": True, "custom": "data"} entries = [event] diff --git a/think/events.py b/think/event_formatter.py similarity index 100% rename from think/events.py rename to think/event_formatter.py diff --git a/think/formatters.py b/think/formatters.py index a2b24fdaa..cd8362d0b 100644 --- a/think/formatters.py +++ b/think/formatters.py @@ -139,7 +139,7 @@ FORMATTERS: dict[str, tuple[str, str, bool]] = { "format_entity_identity", False, # Indexed via _index_entity_search_chunks (enriched with relationship data) ), - "facets/*/events/*.jsonl": ("think.events", "format_events", True), + "facets/*/events/*.jsonl": ("think.event_formatter", "format_events", True), "facets/*/activities/*.jsonl": ("think.activities", "format_activities", True), "facets/*/todos/*.jsonl": ("apps.todos.todo", "format_todos", True), "facets/*/logs/*.jsonl": ("think.facets", "format_logs", True), diff --git a/think/indexer/__init__.py b/think/indexer/__init__.py index 14b755a08..5a278aa92 100644 --- a/think/indexer/__init__.py +++ b/think/indexer/__init__.py @@ -13,7 +13,6 @@ from .cli import main from .journal import ( get_entity_intelligence, get_entity_strength, - get_events, get_journal_index, index_file, reset_journal_index, @@ -27,7 +26,6 @@ from .journal import ( # All public functions and constants __all__ = [ # Journal (unified index) - "get_events", "get_entity_intelligence", "get_entity_strength", "get_journal_index", diff --git a/think/tools/call.py b/think/tools/call.py index a02562749..d8259d238 100644 --- a/think/tools/call.py +++ b/think/tools/call.py @@ -37,7 +37,6 @@ from think.importers.utils import ( get_import_details, list_import_timestamps, ) -from think.indexer.journal import get_events as get_events_impl from think.indexer.journal import search_counts as search_counts_impl from think.indexer.journal import search_journal as search_journal_impl from think.utils import ( @@ -130,37 +129,6 @@ def search( typer.echo(r["text"].strip()) -@app.command() -def events( - day: str | None = typer.Argument( - default=None, help="Day YYYYMMDD (default: SOL_DAY env)." - ), - facet: str | None = typer.Option(None, "--facet", "-f", help="Filter by facet."), -) -> None: - """List events for a day.""" - day = resolve_sol_day(day) - items = get_events_impl(day, facet) - if not items: - typer.echo("No events found.") - return - for ev in items: - time_range = "" - if ev.get("start"): - time_range = ev["start"] - if ev.get("end"): - time_range += f"-{ev['end']}" - time_range = f" ({time_range})" - facet_tag = f" [{ev.get('facet', '')}]" if ev.get("facet") else "" - typer.echo(f"- {ev.get('title', 'Untitled')}{time_range}{facet_tag}") - if ev.get("summary"): - typer.echo(f" {ev['summary']}") - participants = ev.get("participants", []) - if participants: - typer.echo(f" Participants: {', '.join(participants)}") - if ev.get("details"): - typer.echo(f" Details: {ev['details']}") - - @facet_app.command() def show( name: str | None = typer.Argument( diff --git a/think/tools/search.py b/think/tools/search.py index c27f0f2dd..7c2305058 100644 --- a/think/tools/search.py +++ b/think/tools/search.py @@ -10,7 +10,6 @@ tests, or other internal modules. from datetime import datetime, timedelta from typing import Any -from think.indexer.journal import get_events as get_events_impl from think.indexer.journal import search_counts as search_counts_impl from think.indexer.journal import search_journal as search_journal_impl @@ -200,41 +199,3 @@ def search_journal( "error": f"Failed to search journal: {exc}", "suggestion": "try adjusting the query or ensure the index exists (run sol indexer --rescan)", } - - -def get_events( - day: str, - facet: str | None = None, -) -> dict[str, Any]: - """Get structured events for a specific day. - - This tool retrieves full event data including titles, summaries, - start/end times, and participants. Use this when you need complete - event information rather than text search results. - - Args: - day: Day in ``YYYYMMDD`` format - facet: Optional facet name to filter by - - Returns: - Dictionary containing: - - day: The requested day - - facet: The facet filter (if any) - - events: List of event objects with full structured data - - Examples: - - get_events("20240101") - - get_events("20240101", facet="work") - """ - try: - events = get_events_impl(day, facet) - return { - "day": day, - "facet": facet or "", - "events": events, - } - except Exception as exc: - return { - "error": f"Failed to get events: {exc}", - "suggestion": "verify the day parameter is valid", - }