Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions api/composers.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ def list_composers():
try:
local = WorkspaceLocalComposer.from_dict(c)
except SchemaError as e:
print(f"Schema drift in {db_path}: {e}")
_logger.warning(
"Schema drift in %s: %s (%s)",
db_path,
e,
type(e).__name__,
)
continue
# Use the typed view downstream so the dataclass is
# load-bearing, not just a filter (Brad's review): the
Expand All @@ -91,9 +96,20 @@ def list_composers():
c["workspaceFolder"] = workspace_folder
composers.append((local, c))
except SchemaError as e:
print(f"Schema drift in {db_path}: {e}")
_logger.warning(
"Schema drift in %s: %s (%s)",
db_path,
e,
type(e).__name__,
)
except Exception as e:
print(f"Failed reading composers from {db_path}: {e}")
_logger.error(
"Failed reading composers from %s: %s (%s)",
db_path,
e,
type(e).__name__,
exc_info=True,
)

composers.sort(key=lambda pair: to_epoch_ms(pair[0].last_updated_at), reverse=True)
return jsonify([c for _, c in composers])
Expand Down Expand Up @@ -152,7 +168,12 @@ def get_composer(composer_id):
# Same drift list_composers() logs and skips at line ~78,
# so a single-composer fetch can't silently return malformed
# JSON the list endpoint hid.
print(f"Schema drift in workspace-local composer {composer_id}: {e}")
_logger.warning(
"Schema drift in workspace-local composer %s: %s (%s)",
composer_id,
e,
type(e).__name__,
)
continue
# Match list_composers() at line 89 and the global
# fallback below: `conversation` is normalised to []
Expand All @@ -163,7 +184,12 @@ def get_composer(composer_id):
payload["conversation"] = payload.get("conversation") or []
return jsonify(payload)
except SchemaError as e:
print(f"Schema drift in {db_path}: {e}")
_logger.warning(
"Schema drift in %s: %s (%s)",
db_path,
e,
type(e).__name__,
)
except (OSError, sqlite3.Error, json.JSONDecodeError, ValueError):
pass

Expand All @@ -186,7 +212,12 @@ def get_composer(composer_id):
# Don't return malformed JSON to the client — surface the drift
# as a 404 + log, matching the silent-skip behaviour of the
# list endpoints for the same row.
print(f"Schema drift in composer {composer_id}: {e}")
_logger.warning(
"Schema drift in composer %s: %s (%s)",
composer_id,
e,
type(e).__name__,
)
return jsonify({"error": "Composer schema drift"}), 404
payload = dict(composer.raw)
payload["conversation"] = payload.get("conversation") or []
Expand Down
23 changes: 20 additions & 3 deletions api/config_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
src/app/api/get-username/route.ts GET /api/get-username
"""

import logging
import os
import subprocess
import sys
Expand All @@ -16,6 +17,7 @@
from utils.workspace_path import set_workspace_path_override

bp = Blueprint("config_api", __name__)
_logger = logging.getLogger(__name__)


@bp.route("/api/detect-environment")
Expand Down Expand Up @@ -44,7 +46,12 @@ def detect_environment():
})

except Exception as e:
print(f"Failed to detect environment: {e}")
_logger.warning(
"Failed to detect environment: %s (%s)",
e,
type(e).__name__,
exc_info=True,
)
return jsonify({"os": "unknown", "isWSL": False, "isRemote": False})


Expand Down Expand Up @@ -80,7 +87,12 @@ def validate_path():
)

except Exception as e:
print(f"Validation error: {e}")
_logger.error(
"Validation error: %s (%s)",
e,
type(e).__name__,
exc_info=True,
)
return jsonify({"valid": False, "error": "Failed to validate path"}), 500


Expand Down Expand Up @@ -135,5 +147,10 @@ def get_username():
return jsonify({"username": username})

except Exception as e:
print(f"Failed to get username: {e}")
_logger.warning(
"Failed to get username: %s (%s)",
e,
type(e).__name__,
exc_info=True,
)
return jsonify({"username": "YOUR_USERNAME"})
19 changes: 15 additions & 4 deletions api/export_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import io
import json
import logging
import os
import sqlite3
import zipfile
Expand All @@ -32,6 +33,7 @@
)

bp = Blueprint("export_api", __name__)
_logger = logging.getLogger(__name__)


def _get_state_dir() -> str:
Expand Down Expand Up @@ -181,7 +183,13 @@ def export_chats():
exported.append({"path": rel_path, "content": md, "updatedAt": updated_at_ms})

except Exception as e:
print(f"Error processing composer {composer_id} for export: {e}")
_logger.error(
"Error processing composer %s for export: %s (%s)",
composer_id,
e,
type(e).__name__,
exc_info=True,
)

count = len(exported)
if count == 0:
Expand All @@ -208,7 +216,10 @@ def export_chats():
)

except Exception as e:
print(f"Export error: {e}")
import traceback
traceback.print_exc()
_logger.error(
"Export failed: %s (%s)",
e,
type(e).__name__,
exc_info=True,
)
return jsonify({"error": f"Export failed: {str(e)}"}), 500
30 changes: 21 additions & 9 deletions api/logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from flask import Blueprint, jsonify

from utils.workspace_path import resolve_workspace_path
from utils.path_helpers import to_epoch_ms
from utils.path_helpers import to_epoch_ms, warn_workspace_json_read

bp = Blueprint("logs", __name__)
_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -48,8 +48,12 @@ def get_logs():
try:
bubble = json.loads(row["value"])
chat_map.setdefault(chat_id, []).append(bubble)
except Exception:
pass
except Exception as e:
_logger.warning(
"Failed to decode bubble row %s: %s",
row["key"],
e,
)

for chat_id, bubbles in chat_map.items():
bubbles = [b for b in bubbles if isinstance(b, dict)]
Expand Down Expand Up @@ -90,8 +94,8 @@ def get_logs():
with open(wj_path, "r", encoding="utf-8") as f:
wd = json.load(f)
workspace_folder = wd.get("folder")
except Exception:
pass
except Exception as e:
warn_workspace_json_read(_logger, name, e)

try:
# closing() guarantees .close() on scope exit (issue #17).
Expand Down Expand Up @@ -130,10 +134,18 @@ def get_logs():
"type": "composer",
"messageCount": len(c.get("conversation") or []),
})
except Exception:
pass
except Exception:
pass
except Exception as e:
_logger.warning(
"Failed to read logs from workspace %s: %s",
name,
e,
)
except Exception as e:
_logger.warning(
"Failed to iterate workspaces under %s: %s",
workspace_path,
e,
)

logs.sort(key=lambda log: log.get("timestamp") or 0, reverse=True)
return jsonify({"logs": logs})
Expand Down
11 changes: 8 additions & 3 deletions api/pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
"""

import io
import logging
import re

from flask import Blueprint, Response, jsonify, request

bp = Blueprint("pdf", __name__)
_logger = logging.getLogger(__name__)


def _safe_text(text: str) -> str:
Expand Down Expand Up @@ -168,9 +170,12 @@ def footer(self):
)

except Exception as e:
print(f"Failed to generate PDF: {e}")
import traceback
traceback.print_exc()
_logger.error(
"Failed to generate PDF: %s (%s)",
e,
type(e).__name__,
exc_info=True,
)
return jsonify({"error": f"Failed to generate PDF: {str(e)}"}), 500


Expand Down
Loading
Loading