refactor: rename package fabledassistant -> scribe (code-only)
Renames src/fabledassistant -> src/scribe and all imports, plus the default DB name and DB user/password (fabled -> scribe) in config + compose. 952 refs / 154 files. Reverses the old 'internal name stays fabledassistant' convention. Code-only: live databases are still physically named 'fabledassistant'. Deployed environments must set POSTGRES_DB / POSTGRES_USER (or rename the DB) since the defaults now resolve to 'scribe'. Repo (FabledScribe), git host (fabledsword), MCP (fabled-git) and the image name (fabledscribe) are intentionally unchanged. ruff check src/ clean locally; CI (typecheck + pytest) is the gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""get_recent — cross-type recent-activity tool.
|
||||
|
||||
Returns the most-recently-touched notes, tasks, projects, and events for the
|
||||
user, ordered by updated_at descending. Useful for Claude to bootstrap context
|
||||
at the start of a conversation ("what was I working on?").
|
||||
|
||||
Aggregation is Python-side after three small per-table queries — simpler than
|
||||
a UNION ALL with type-discriminating columns, and fine for personal-scale data.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
from scribe.mcp._context import current_user_id
|
||||
from scribe.models import async_session
|
||||
from scribe.models.event import Event
|
||||
from scribe.models.note import Note
|
||||
from scribe.models.project import Project
|
||||
|
||||
|
||||
async def get_recent(days: int = 7, limit: int = 25) -> dict:
|
||||
"""Return recently-touched items across notes, tasks, projects, events.
|
||||
|
||||
Args:
|
||||
days: Look-back window in days (1-90).
|
||||
limit: Maximum number of items returned (1-100).
|
||||
|
||||
Returns:
|
||||
{"items": [{"id", "type", "title", "updated_at"}], "total": int}
|
||||
Sorted by updated_at descending.
|
||||
"""
|
||||
uid = current_user_id()
|
||||
days = max(1, min(days, 90))
|
||||
limit = max(1, min(limit, 100))
|
||||
since = datetime.now(timezone.utc) - timedelta(days=days)
|
||||
items: list[dict] = []
|
||||
async with async_session() as session:
|
||||
notes = (await session.execute(
|
||||
select(Note).where(Note.user_id == uid, Note.updated_at >= since,
|
||||
Note.deleted_at.is_(None))
|
||||
.order_by(Note.updated_at.desc()).limit(limit)
|
||||
)).scalars().all()
|
||||
for n in notes:
|
||||
items.append({
|
||||
"id": n.id,
|
||||
"type": "task" if n.is_task else "note",
|
||||
"title": n.title,
|
||||
"updated_at": n.updated_at.isoformat(),
|
||||
})
|
||||
projects = (await session.execute(
|
||||
select(Project).where(Project.user_id == uid,
|
||||
Project.updated_at >= since,
|
||||
Project.deleted_at.is_(None))
|
||||
.order_by(Project.updated_at.desc()).limit(limit)
|
||||
)).scalars().all()
|
||||
for p in projects:
|
||||
items.append({
|
||||
"id": p.id,
|
||||
"type": "project",
|
||||
"title": p.title,
|
||||
"updated_at": p.updated_at.isoformat(),
|
||||
})
|
||||
events = (await session.execute(
|
||||
select(Event).where(Event.user_id == uid,
|
||||
Event.updated_at >= since,
|
||||
Event.deleted_at.is_(None))
|
||||
.order_by(Event.updated_at.desc()).limit(limit)
|
||||
)).scalars().all()
|
||||
for e in events:
|
||||
items.append({
|
||||
"id": e.id,
|
||||
"type": "event",
|
||||
"title": e.title,
|
||||
"updated_at": e.updated_at.isoformat(),
|
||||
})
|
||||
items.sort(key=lambda r: r["updated_at"], reverse=True)
|
||||
items = items[:limit]
|
||||
return {"items": items, "total": len(items)}
|
||||
|
||||
|
||||
def register(mcp) -> None:
|
||||
mcp.tool(name="get_recent")(get_recent)
|
||||
Reference in New Issue
Block a user