Clean up lint/LSP across gateway, Android, and desktop (alpha -> stable)
Gateway (gateway-plugin/): - Fix interactive_setup broken imports: print helpers were imported from the wrong hermes module (hermes_cli.config instead of hermes_cli.cli_output) plus a non-existent print_code; the try/except swallowed the ImportError so `hermes gateway setup` for android always bailed out early. - Fix release_scoped_lock type error (str | None passed where str required). - Rewrite empty `except: pass` blocks as contextlib.suppress with rationale. - Restructure two ambiguous ws_server try blocks (hello-auth, frame loop). - Ruff cleanup: type annotations, import sorting, line wrapping, magic values -> named constants, `raise ... from e`, complexity. Add gateway-plugin/ruff.toml. - Add pyrightconfig.json so the Python LSP resolves hermes-runtime imports. - Suppress verified false positives inline (parameterized SQL, column-name "secrets", hermes-generated media path). Android (app/androidApp + app/shared): - Consolidate launcher icons into a single mipmap-anydpi (minSdk 29 >= 26) with the monochrome layer; clears ObsoleteSdkInt + MonochromeLauncherIcon. - Bump core-splashscreen 1.0.1 -> 1.2.0; pin targetSdk 34 (deliberate). - Suppress verified findings inline (LAN ws:// default, correct GCM IV usage). Desktop (app/desktopApp): - Move the desktop to a Java 21 runtime (org.gradle.java.home) and set the desktop jvmTarget to 21 (Android stays JVM 17 / minSdk 29). Fixes the startup UnsupportedClassVersionError and restores Markdown renderer 0.44.0. Tooling/config: - .pi-lens.json: disable verified-noisy heuristics (documented in docs). - .gitleaks.toml: allowlist git-ignored false-positive paths. - docs/18-code-review.md: full findings + verification. Verified: ruff clean, pyright 0 errors, 64/64 gateway tests, all Kotlin tests, Android lint 0 issues, Android installed+launched on device, desktop launches on JDK 21.
This commit is contained in:
1 parent
9f3f9842c8
commit
678c0344c8
27 files changed
+928
-454
No files matched your search
+26
-35
@@ -15,13 +15,14 @@ Storage: ``get_hermes_home()/"android"/outbox.db``.
|
||||
Milestone M3 (built), extended in M5 (push integration).
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import json
|
||||
import logging
|
||||
import sqlite3
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -69,9 +70,7 @@ class Outbox:
|
||||
)
|
||||
"""
|
||||
)
|
||||
self._conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_outbox_created ON outbox (created)"
|
||||
)
|
||||
self._conn.execute("CREATE INDEX IF NOT EXISTS idx_outbox_created ON outbox (created)")
|
||||
self._conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS counters (
|
||||
@@ -84,7 +83,7 @@ class Outbox:
|
||||
|
||||
# ── append / cursor ───────────────────────────────────────────────────
|
||||
|
||||
def append(self, chat_id: Optional[str], frame_json: str) -> int:
|
||||
def append(self, chat_id: str | None, frame_json: str) -> int:
|
||||
"""Append a frame; returns the (monotonic) cursor assigned to it."""
|
||||
now = time.time()
|
||||
with self._lock:
|
||||
@@ -92,13 +91,10 @@ class Outbox:
|
||||
"INSERT INTO counters (name, value) VALUES ('cursor', 1) "
|
||||
"ON CONFLICT(name) DO UPDATE SET value = value + 1"
|
||||
)
|
||||
row = self._conn.execute(
|
||||
"SELECT value FROM counters WHERE name = 'cursor'"
|
||||
).fetchone()
|
||||
row = self._conn.execute("SELECT value FROM counters WHERE name = 'cursor'").fetchone()
|
||||
cursor = int(row["value"]) if row else 1
|
||||
self._conn.execute(
|
||||
"INSERT INTO outbox (cursor, chat_id, frame, created) "
|
||||
"VALUES (?, ?, ?, ?)",
|
||||
"INSERT INTO outbox (cursor, chat_id, frame, created) VALUES (?, ?, ?, ?)",
|
||||
(cursor, chat_id, frame_json, now),
|
||||
)
|
||||
self._enforce_row_cap()
|
||||
@@ -135,14 +131,12 @@ class Outbox:
|
||||
def latest_cursor(self) -> int:
|
||||
"""The high-water cursor (0 when nothing has been appended)."""
|
||||
with self._lock:
|
||||
row = self._conn.execute(
|
||||
"SELECT value FROM counters WHERE name = 'cursor'"
|
||||
).fetchone()
|
||||
row = self._conn.execute("SELECT value FROM counters WHERE name = 'cursor'").fetchone()
|
||||
return int(row["value"]) if row else 0
|
||||
|
||||
# ── replay ────────────────────────────────────────────────────────────
|
||||
|
||||
def replay(self, cursor: int, limit: int = _REPLAY_LIMIT) -> List[Dict[str, Any]]:
|
||||
def replay(self, cursor: int, limit: int = _REPLAY_LIMIT) -> list[dict[str, Any]]:
|
||||
"""Frames with ``cursor > `cursor```, oldest first.
|
||||
|
||||
Each entry: ``{cursor, chat_id, frame}`` where ``frame`` is the parsed
|
||||
@@ -156,7 +150,7 @@ class Outbox:
|
||||
"WHERE cursor > ? ORDER BY cursor ASC LIMIT ?",
|
||||
(cursor, limit),
|
||||
).fetchall()
|
||||
out: List[Dict[str, Any]] = []
|
||||
out: list[dict[str, Any]] = []
|
||||
for r in rows:
|
||||
try:
|
||||
frame = json.loads(r["frame"])
|
||||
@@ -164,9 +158,7 @@ class Outbox:
|
||||
continue
|
||||
if not isinstance(frame, dict):
|
||||
continue
|
||||
out.append(
|
||||
{"cursor": int(r["cursor"]), "chat_id": r["chat_id"], "frame": frame}
|
||||
)
|
||||
out.append({"cursor": int(r["cursor"]), "chat_id": r["chat_id"], "frame": frame})
|
||||
return out
|
||||
|
||||
# ── history (full message history for a chat/thread) ──────────────────
|
||||
@@ -174,10 +166,10 @@ class Outbox:
|
||||
def history(
|
||||
self,
|
||||
chat_id: str,
|
||||
thread_id: Optional[str] = None,
|
||||
before_message_id: Optional[str] = None,
|
||||
thread_id: str | None = None,
|
||||
before_message_id: str | None = None,
|
||||
limit: int = 50,
|
||||
) -> Dict[str, Any]:
|
||||
) -> dict[str, Any]:
|
||||
"""Final messages for a chat/thread, for the ``history`` frame.
|
||||
|
||||
Reconstructs the message list from the outbox log: a final message is
|
||||
@@ -194,11 +186,10 @@ class Outbox:
|
||||
limit = max(1, min(int(limit or 50), 200))
|
||||
with self._lock:
|
||||
rows = self._conn.execute(
|
||||
"SELECT cursor, frame FROM outbox WHERE chat_id = ? "
|
||||
"ORDER BY cursor ASC",
|
||||
"SELECT cursor, frame FROM outbox WHERE chat_id = ? ORDER BY cursor ASC",
|
||||
(chat_id,),
|
||||
).fetchall()
|
||||
final: List[Dict[str, Any]] = []
|
||||
final: list[dict[str, Any]] = []
|
||||
for r in rows:
|
||||
try:
|
||||
frame = json.loads(r["frame"])
|
||||
@@ -244,7 +235,7 @@ class Outbox:
|
||||
}
|
||||
)
|
||||
# Deduplicate by message_id (keep the latest occurrence), keep order.
|
||||
by_id: Dict[str, Dict[str, Any]] = {}
|
||||
by_id: dict[str, dict[str, Any]] = {}
|
||||
for m in final:
|
||||
mid = m.get("message_id")
|
||||
if mid:
|
||||
@@ -283,7 +274,7 @@ class Outbox:
|
||||
self,
|
||||
chat_id: str,
|
||||
message_id: str,
|
||||
thread_id: Optional[str] = None,
|
||||
thread_id: str | None = None,
|
||||
) -> int:
|
||||
"""Remove every outbox frame belonging to *message_id* in *chat_id*.
|
||||
|
||||
@@ -304,7 +295,7 @@ class Outbox:
|
||||
rows = self._conn.execute(
|
||||
"SELECT cursor, frame FROM outbox WHERE chat_id = ?", (chat_id,)
|
||||
).fetchall()
|
||||
cursors: List[int] = []
|
||||
cursors: list[int] = []
|
||||
for r in rows:
|
||||
try:
|
||||
frame = json.loads(r["frame"])
|
||||
@@ -320,9 +311,11 @@ class Outbox:
|
||||
if not cursors:
|
||||
return 0
|
||||
placeholders = ",".join("?" * len(cursors))
|
||||
self._conn.execute(
|
||||
f"DELETE FROM outbox WHERE cursor IN ({placeholders})", cursors
|
||||
)
|
||||
sql = f"DELETE FROM outbox WHERE cursor IN ({placeholders})"
|
||||
# Safe: ``placeholders`` is only ``?`` markers; every cursor value is
|
||||
# bound as a parameter (no user data in the SQL text).
|
||||
# pi-lens-ignore: python-sql-injection
|
||||
self._conn.execute(sql, cursors)
|
||||
self._conn.commit()
|
||||
return len(cursors)
|
||||
|
||||
@@ -347,8 +340,6 @@ class Outbox:
|
||||
self._maybe_prune()
|
||||
|
||||
def close(self) -> None:
|
||||
with self._lock:
|
||||
try:
|
||||
self._conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
with self._lock, contextlib.suppress(Exception):
|
||||
# Best-effort: a close failure on shutdown is not actionable.
|
||||
self._conn.close()
|
||||
Reference in new issue
Block a user