feat: add 19 fast commands (no-LLM) + incremental embeddings indexing
Fast commands for git, email, calendar, notes, search, reminders, and diagnostics — all execute instantly without Claude CLI. Incremental embeddings indexing in heartbeat (1h cooldown) + inline indexing after /note, /jurnal, /email save. Fix Ollama URL (localhost → 10.0.20.161), fix email_process.py KB path (kb/ → memory/kb/). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -222,6 +222,48 @@ def reindex() -> dict:
|
||||
return {"files": files_count, "chunks": chunks_count}
|
||||
|
||||
|
||||
def incremental_index() -> dict:
|
||||
"""Index only new or modified .md files. Returns {"indexed": N, "chunks": M}."""
|
||||
conn = get_db()
|
||||
try:
|
||||
# Get latest updated_at per file from DB
|
||||
rows = conn.execute(
|
||||
"SELECT file_path, MAX(updated_at) FROM chunks GROUP BY file_path"
|
||||
).fetchall()
|
||||
db_times = {}
|
||||
for rel_path, updated_at in rows:
|
||||
try:
|
||||
db_times[rel_path] = datetime.fromisoformat(updated_at)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
files_indexed = 0
|
||||
chunks_total = 0
|
||||
for md_file in sorted(MEMORY_DIR.rglob("*.md")):
|
||||
rel_path = str(md_file.relative_to(MEMORY_DIR))
|
||||
file_mtime = datetime.fromtimestamp(
|
||||
md_file.stat().st_mtime, tz=timezone.utc
|
||||
)
|
||||
db_time = db_times.get(rel_path)
|
||||
if db_time is not None:
|
||||
# Ensure both are offset-aware for comparison
|
||||
if db_time.tzinfo is None:
|
||||
db_time = db_time.replace(tzinfo=timezone.utc)
|
||||
if file_mtime <= db_time:
|
||||
continue
|
||||
try:
|
||||
n = index_file(md_file)
|
||||
files_indexed += 1
|
||||
chunks_total += n
|
||||
log.info("Incremental indexed %s (%d chunks)", md_file.name, n)
|
||||
except Exception as e:
|
||||
log.warning("Failed to index %s: %s", md_file, e)
|
||||
|
||||
return {"indexed": files_indexed, "chunks": chunks_total}
|
||||
|
||||
|
||||
def search(query: str, top_k: int = 5) -> list[dict]:
|
||||
"""Search for query. Returns list of {"file": str, "chunk": str, "score": float}."""
|
||||
query_embedding = get_embedding(query)
|
||||
|
||||
Reference in New Issue
Block a user