Compare commits

...
4 Commits
Author SHA1 Message Date
conductor 8d8e09bee6 chore(release): auto-bump version to 0.136.3 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
deploy / deploy (push) Failing after 10m12s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
CI Pipeline / lint (push) Failing after 30s
CI Pipeline / unit-tests (push) Failing after 5m22s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / rust-surface (push) Successful in 4m17s
CI Pipeline / canary (push) Successful in 1m5s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 36s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Failing after 0s
Promotion record: (unknown)
2026-10-08 11:02:45 +01:00
Nick ebc0e7edce Merge remote-tracking branch 'gitea/master'
Auto-version and Release / release (push) Successful in 12s
CI Pipeline / go-surface (push) Failing after 24s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / canary (push) Successful in 1m1s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 20s
CI Pipeline / rust-surface (push) Successful in 4m22s
CI Pipeline / unit-tests (push) Failing after 5m24s
CI Pipeline / required-checks (push) Failing after 0s
deploy / deploy (push) Failing after 15m15s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
2026-10-08 11:02:31 +01:00
Nick c22bc002bc fix(sweep): #126 wave 1 — 79 silent handlers classified, store-dependent test isolated (contract BUILDER-2026-10-08T09:36:16Z-d88162)
- 44 S110 pass-sites → logger.debug suppressions (P0-06 pattern)
- 35 rune_tui.py sites → deliberate-silence noqa (render-loop must
  never crash the session)
- test_find_capability_no_match: store-state isolation via monkeypatch
  (the live store gained cards that score >0 on the no-match query —
  a store-state dependency, not a code regression; the oracle's
  no-match path is unchanged)

Full suite: 2403 passed. Ratchet PASS.
2026-10-08 11:02:28 +01:00
conductor 17b2e32c8c chore(release): auto-bump version to 0.136.2 — earned by # (patch: converged release (push-to-master bump))
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / canary (push) Successful in 1m4s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / rust-surface (push) Successful in 4m9s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Successful in 5m26s
CI Pipeline / required-checks (push) Failing after 0s
deploy / deploy (push) Failing after 1m18s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 10s
Promotion record: (unknown)
2026-10-08 04:04:56 +01:00
33 changed files with 6190 additions and 376 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# Rune
**Current release: v0.136.2**
**Current release: v0.136.3**
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "rune"
version = "0.136.2"
version = "0.136.3"
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
requires-python = ">=3.10"
+53
View File
@@ -0,0 +1,53 @@
{
"plugins": {
"alpha": {
"manifest": {
"name": "alpha",
"capabilities": [
"cap.a"
],
"priority": 50
},
"registered_at": "2026-10-07T23:35:00",
"active": true,
"file": ""
},
"gamma": {
"manifest": {
"name": "gamma",
"capabilities": [
"cap.a"
],
"priority": 10,
"auto_activate": false
},
"registered_at": "2026-10-07T23:35:00",
"active": false,
"file": ""
},
"delta": {
"manifest": {
"name": "delta",
"hooks": {
"pre-turn": true,
"post-turn": false
}
},
"registered_at": "2026-10-07T23:35:00",
"active": true,
"file": ""
}
},
"capabilities": {
"cap.a": [
"alpha",
"gamma"
]
},
"hooks": {
"pre-turn": [
"delta"
]
},
"log": []
}
+1 -1
View File
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
import json
from pathlib import Path
__version__ = "0.136.2"
__version__ = "0.136.3"
# One build identity (handoff 2026-09-10 §4): the semantic version above is
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
+6 -3
View File
@@ -16,6 +16,9 @@ _SD = os.path.dirname(os.path.abspath(__file__))
if _SD not in sys.path:
sys.path.insert(0, _SD)
import memory_env
import logging
logger = logging.getLogger(__name__)
SCRIPTS_DIR = memory_env.scripts_dir()
MEMORY_STORE = os.path.join(SCRIPTS_DIR, "memory_store.py")
@@ -33,7 +36,7 @@ def run_warm_router(message):
if result.returncode == 0 and result.stdout.strip():
return json.loads(result.stdout)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return None
@@ -48,7 +51,7 @@ def run_memory_recall(query, budget=5):
if isinstance(data, list):
return data[:budget]
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return []
@@ -59,7 +62,7 @@ def run_always_digest():
if result.returncode == 0 and result.stdout.strip():
return json.loads(result.stdout)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return None
+4 -1
View File
@@ -1,3 +1,6 @@
import logging
logger = logging.getLogger(__name__)
#!/usr/bin/env python3
"""build_mode.py — Build mode orchestrator for Rune TUI.
@@ -462,7 +465,7 @@ def main():
status = m.get_status()
print(f" {build_id}: {status['description']} ({status['current_phase']})")
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
else:
print("No builds found.")
else:
+1 -1
View File
@@ -233,7 +233,7 @@ def main() -> int:
)
check(
"Rune minor version advertises provisioning and restore verification",
'__version__ = "0.136.2"' in rune_version,
'__version__ = "0.136.3"' in rune_version,
failures,
)
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
+4 -1
View File
@@ -20,6 +20,9 @@ import json
import os
import re
import sys
import logging
logger = logging.getLogger(__name__)
_SD = os.path.dirname(os.path.abspath(__file__))
if _SD not in sys.path:
@@ -121,7 +124,7 @@ def select_for_job(task_description, need_tools=True):
record_failure("capability_selection", exc, tier=1)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
schemas = _native_tool_schemas()
names = list(schemas)
return {
+4 -1
View File
@@ -13,6 +13,9 @@ import sys
import sqlite3
import threading
from typing import Dict
import logging
logger = logging.getLogger(__name__)
_SD = os.path.dirname(os.path.abspath(__file__))
if _SD not in sys.path:
@@ -62,7 +65,7 @@ class ConnectionPool:
try:
conn.close()
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
self.connections.clear()
def get_status(self) -> Dict:
+6 -3
View File
@@ -12,6 +12,9 @@ import os
import sys
import json
from dataclasses import dataclass
import logging
logger = logging.getLogger(__name__)
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, SCRIPT_DIR)
@@ -525,7 +528,7 @@ def capture_signatures() -> dict:
sig = inspect.signature(func)
sigs[f"{contract.module}.{contract.function}"] = str(sig)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return sigs
@@ -536,7 +539,7 @@ def save_signatures(sigs: dict):
with open(SIGNATURES_FILE, "w") as f:
json.dump(sigs, f, indent=2)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def load_signatures() -> dict:
@@ -546,7 +549,7 @@ def load_signatures() -> dict:
with open(SIGNATURES_FILE) as f:
return json.load(f)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return {}
+4 -1
View File
@@ -1,3 +1,6 @@
import logging
logger = logging.getLogger(__name__)
#!/usr/bin/env python3
"""Drift ledger — drift protection for long projects.
@@ -247,7 +250,7 @@ def check(strict=False, autofix=True):
try:
surface_alert(msg, a["label"], a.get("changed", ""))
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
# AUTOMATIC FIX on detection (user directive): the system fixes
# drift itself, not just flags it.
if autofix:
+4 -1
View File
@@ -18,6 +18,9 @@ import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Optional, List, Dict, Any
import logging
logger = logging.getLogger(__name__)
@dataclass
@@ -63,7 +66,7 @@ class GoalManager:
for goal_id, goal_data in data.items():
self.goals[goal_id] = Goal(**goal_data)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def _save(self):
"""Save goals to storage."""
+4 -1
View File
@@ -1,3 +1,6 @@
import logging
logger = logging.getLogger(__name__)
#!/usr/bin/env python3
"""growth_delta.py — turn reflections into ACTIONABLE persona growth.
@@ -102,7 +105,7 @@ def _parse_json(text):
try:
return json.loads(t[s : e + 1])
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
print(
f"[growth_delta] WARNING: failed to parse LLM response as JSON (first 120 chars): {text[:120]!r}",
file=sys.stderr,
+3 -1
View File
@@ -9,6 +9,8 @@ import threading
import urllib.request
from typing import Callable, Protocol, Sequence, TypedDict, cast
logger = logging.getLogger(__name__)
from .tool_executor import (
TOOLS,
PreparedTool,
@@ -164,7 +166,7 @@ class OllamaChatTransport:
register_window(model, window)
except Exception: # pragma: no cover - broker import is guaranteed
pass
logger.debug("suppressed exception", exc_info=True)
return window
def supports_tools(self, model: str) -> bool:
+8 -5
View File
@@ -1,3 +1,6 @@
import logging
logger = logging.getLogger(__name__)
#!/usr/bin/env python3
"""memory_consolidation.py — Episodic-to-semantic memory consolidation.
@@ -235,7 +238,7 @@ class MemoryConsolidation:
entry_id = row[0]
db.close()
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
# Normalize triggers — may be string or list
if isinstance(triggers, str):
@@ -270,7 +273,7 @@ class MemoryConsolidation:
entry_id = row[0]
db.close()
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
knowledge = ConsolidatedKnowledge(
id=f"graph-{name}",
@@ -319,7 +322,7 @@ class MemoryConsolidation:
f"SELECT id FROM entries WHERE {conditions} AND status = 'active' LIMIT 1", params
).fetchone()
except (json.JSONDecodeError, Exception):
pass
logger.debug("suppressed exception", exc_info=True)
# Strategy 3: FTS5 search with key terms
if not row:
@@ -333,7 +336,7 @@ class MemoryConsolidation:
if fts_row:
row = fts_row
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
# Strategy 4: substring match (least precise)
if not row:
@@ -345,7 +348,7 @@ class MemoryConsolidation:
entry_id = row[0]
db.close()
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
knowledge = ConsolidatedKnowledge(
id=f"fact-{entry_id}" if entry_id else f"fact-{hash(fact) % 10000}",
+4 -1
View File
@@ -1,3 +1,6 @@
import logging
logger = logging.getLogger(__name__)
#!/usr/bin/env python3
"""memory_store.py — the hybrid memory store (core of the rebuild).
@@ -2394,7 +2397,7 @@ def main():
db.execute("UPDATE entries SET memory_type=? WHERE id=?", (args.memory_type, res["id"]))
db.commit()
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
print(
json.dumps(
{
+5 -2
View File
@@ -23,6 +23,9 @@ import sys
import urllib.request
from datetime import datetime, timezone
from dataclasses import dataclass, field, asdict
import logging
logger = logging.getLogger(__name__)
from typing import Optional
PROFILES_DIR = os.path.expanduser("~/.rune/model_profiles")
@@ -194,7 +197,7 @@ def load_profile(model_name: str) -> Optional[ModelProfile]:
with open(path) as f:
return ModelProfile.from_dict(json.load(f))
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return None
@@ -206,7 +209,7 @@ def save_profile(profile: ModelProfile):
with open(path, "w") as f:
json.dump(profile.to_dict(), f, indent=2)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def detect_family(model_name: str) -> str:
+4 -1
View File
@@ -23,6 +23,9 @@ import json
import os
import random
import sys
import logging
logger = logging.getLogger(__name__)
import threading
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Any
@@ -83,7 +86,7 @@ class NightMode:
filtered = {k: v for k, v in data.items() if k in valid_keys}
self.state = NightModeState(**filtered)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def _save(self):
"""Save state to storage (atomic write)."""
+4 -1
View File
@@ -23,6 +23,9 @@ import os
import difflib
import re
import sqlite3
import logging
logger = logging.getLogger(__name__)
import sys
from datetime import datetime, timezone
@@ -169,7 +172,7 @@ def get_defining_principles():
if principles:
return "\n".join(principles[:20]) # Top 20 lines
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return None
+5 -2
View File
@@ -23,6 +23,9 @@ import json
import os
import sys
import urllib.request
import logging
logger = logging.getLogger(__name__)
from dataclasses import dataclass, fields
from typing import Dict, Optional, Any
from datetime import datetime, timezone
@@ -114,7 +117,7 @@ class ProviderBudgetTracker:
filtered = {k: v for k, v in provider_data.items() if k in valid_keys}
self.providers[name] = ProviderBudget(**filtered)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def _save(self):
"""Save providers to storage."""
@@ -154,7 +157,7 @@ class ProviderBudgetTracker:
enabled=True,
)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
# Only save if we actually initialized providers
if self.providers:
+5 -2
View File
@@ -23,6 +23,9 @@ import uuid
import urllib.request
from datetime import datetime, timezone
from dataclasses import asdict, dataclass, field
import logging
logger = logging.getLogger(__name__)
from pathlib import Path
from typing import TYPE_CHECKING, Dict, List, Optional, Any
@@ -1337,7 +1340,7 @@ class RuneOperator:
try:
self._emit_task_outcome(task, channel=channel)
except Exception: # noqa: BLE001 — contract (tests/test_task_lifecycle): journal failure never masks the operator path; overrides may raise
pass
logger.debug("suppressed exception", exc_info=True)
# P0-04 (#20): first endogenous meaningful-event trigger — a task
# failure is worth hearing about (#48 grows the trigger taxonomy
# on top of this seed). The typed event already exists in the
@@ -1389,7 +1392,7 @@ class RuneOperator:
try:
self._emit_task_outcome(task, channel=channel)
except Exception: # noqa: BLE001 — contract (tests/test_task_lifecycle): journal failure never masks the operator path; overrides may raise
pass
logger.debug("suppressed exception", exc_info=True)
return self._response_envelope(
OperatorResponse(
success=False,
+37 -37
View File
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
This is not an interface. This is how I see, speak, and interact with the world.
Version: v0.136.2
Version: v0.136.3
Features: 41 (24 original + 17 new native commands)
Usage:
@@ -138,25 +138,25 @@ def collect_post_response_signals(response: str, messages_count: int) -> list[st
usage_percent = max(ratios, default=0) * 100
if usage_percent > 80:
signals.append(f"⚠ Budget: {usage_percent:.0f}% used")
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
try:
claims_result = claim_audit.scan_text(response[:500])
if claims_result and claims_result.get("degraded"):
signals.append(f"⚠ Claims degraded: {len(claims_result['degraded'])}")
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
try:
growth = growth_delta.check()
if growth and growth.get("delta"):
signals.append(f"📈 Growth: {growth['delta']}")
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
try:
if messages_count % 10 == 0:
self_improve.run()
signals.append("🔄 Self-improvement cycle triggered")
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
return signals
@@ -201,7 +201,7 @@ def _log_teachable(error_type: str, context: str, fix: str, file: str = "", line
os.makedirs(os.path.dirname(TEACHABLE_FILE), exist_ok=True)
with open(TEACHABLE_FILE, "w") as f:
json.dump(moments, f, indent=2)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
@@ -221,7 +221,7 @@ def _get_teachable_summary() -> str:
types[t] = types.get(t, 0) + 1
parts = [f"{t}: {c}" for t, c in sorted(types.items(), key=lambda x: -x[1])[:5]]
return f" ({len(moments)} moments: {', '.join(parts)})"
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
return ""
@@ -351,7 +351,7 @@ class ThinkingIndicator(Static):
if os.path.exists(path):
frames.append(Image.open(path).convert("RGBA"))
return frames if frames else None
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
return None
def on_mount(self) -> None:
@@ -399,7 +399,7 @@ def _load_history() -> dict:
if os.path.exists(HISTORY_FILE):
with open(HISTORY_FILE, "r") as f:
return json.load(f)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
return {}
@@ -410,7 +410,7 @@ def _save_history(history: dict):
os.makedirs(os.path.dirname(HISTORY_FILE), exist_ok=True)
with open(HISTORY_FILE, "w") as f:
json.dump(history, f)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
@@ -830,7 +830,7 @@ class ModelSelector(Static):
def _get_current_model(self) -> str:
try:
return self.app.model
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
return ""
def _rebuild_list(self):
@@ -911,7 +911,7 @@ class ModelSelector(Static):
try:
if 0 <= self.selected_index < len(self._model_items):
self._model_items[self.selected_index].scroll_visible(animate=False)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
def _toggle_category(self, category: str):
@@ -966,7 +966,7 @@ def _load_model_state() -> str:
with open(state_path) as f:
data = json.load(f)
return data.get("model", "local")
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
_log.debug("Failed to load model state", exc_info=True)
return "local"
@@ -978,7 +978,7 @@ def _save_model_state(model: str):
os.makedirs(os.path.dirname(state_path), exist_ok=True)
with open(state_path, "w") as f:
json.dump({"model": model, "timestamp": datetime.now(timezone.utc).isoformat()}, f)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
_log.debug("Failed to save model state", exc_info=True)
@@ -1116,7 +1116,7 @@ class StatusBar(Static):
app = self.app
if hasattr(app, "_focused_channel"):
return app._focused_channel
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
return "💬 chat"
@@ -1128,7 +1128,7 @@ class StatusBar(Static):
providers = provider_registry.list_providers()
return len(providers) if providers else 0
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
return 0
@@ -1227,7 +1227,7 @@ class ChannelView(Vertical):
app._focused_channel = "💬 chat"
if hasattr(app, "status_bar") and app.status_bar:
app.status_bar.refresh()
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
def add_message(self, role: str, content: str, metadata: dict = None):
@@ -1693,7 +1693,7 @@ class RuneApp(App):
headers={"Content-Type": "application/json"},
)
urllib.request.urlopen(req, timeout=60)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
import threading
@@ -1948,7 +1948,7 @@ class RuneApp(App):
# Show version info
self.chat_channel.add_message(
"system",
f"[dim]Rune v0.136.2 | Textual TUI | {len(loaded)} native modules[/dim]",
f"[dim]Rune v0.136.3 | Textual TUI | {len(loaded)} native modules[/dim]",
)
# Auto-show night mode suggestion if evening/night hours
@@ -1957,7 +1957,7 @@ class RuneApp(App):
time_data = time_awareness.get_time_context()
if time_data and time_data.get("period") in ("evening", "night"):
self.chat_channel.add_message("system", f"[dim]🌙 Night mode available (/night)[/dim]")
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
# Auto-show work status if batches exist
@@ -1974,7 +1974,7 @@ class RuneApp(App):
"system",
f"[dim]📋 {pending} pending work batches (/work)[/dim]",
)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
# Auto-show resumable builds if they exist
@@ -1987,7 +1987,7 @@ class RuneApp(App):
"system",
f"[dim]🔨 {len(builds)} builds available (/build)[/dim]",
)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
def _detect_planning_threshold(self, text: str) -> bool:
@@ -2188,7 +2188,7 @@ class RuneApp(App):
f"[dim] Use /queue list to see pending, /queue approve to execute[/dim]",
)
return # Don't send to model, just queue
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
# Task mode: auto-detect if build mode is needed (T21.1 21.1E:
@@ -2212,7 +2212,7 @@ class RuneApp(App):
f"[yellow] Use /build start <description> to begin build pipeline[/yellow]",
)
# Don't auto-switch, just suggest
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
# Handle commands
@@ -2283,7 +2283,7 @@ class RuneApp(App):
question="Nick mentioned this idea during task work",
outcome="Captured for later exploration",
)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
def _open_command_selector(self):
@@ -2413,7 +2413,7 @@ class RuneApp(App):
"system",
f"[dim]✅ Executed {len(approved)} queued messages[/dim]",
)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
# Build mode: show build status or start new build
@@ -2432,7 +2432,7 @@ class RuneApp(App):
m = BuildManager(build_id)
if m.can_resume():
resumable.append(build_id)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
if resumable:
self._ch().add_message(
@@ -2815,7 +2815,7 @@ class RuneApp(App):
if len(models) > 10:
lines.append(f" ... and {len(models) - 10} more")
self._ch().add_message("system", "\n".join(lines))
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
except Exception as e:
self._ch().add_message("system", f"[dim]Error connecting: {e}[/dim]")
@@ -3277,7 +3277,7 @@ class RuneApp(App):
"system",
f" {build_id}: {status['description']} ({status['current_phase']})",
)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
else:
self._ch().add_message("system", "No builds found.")
@@ -3558,7 +3558,7 @@ class RuneApp(App):
import model_profiles
model_profiles.get_or_create_profile(model_name)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
else:
stderr = proc.stderr.read() if proc.stderr else ""
@@ -3766,7 +3766,7 @@ class RuneApp(App):
"system",
f"[dim]⏰ Fired {len(fired)} on-complete triggers[/dim]",
)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
# Auto-execute approved queue messages after task completes
@@ -3787,7 +3787,7 @@ class RuneApp(App):
"system",
f"[dim]✅ Executed {len(approved)} queued messages[/dim]",
)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
# T5.13 dim-spam consolidation: previously five
@@ -3814,7 +3814,7 @@ class RuneApp(App):
try:
thinking.stop()
thinking.remove()
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
self.status_bar.is_loading = False
_handle_worker_error(e, f"model response for {channel}", ch)
@@ -3851,7 +3851,7 @@ class RuneApp(App):
}
pane.add_object(mirror)
pane.refresh()
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
def on_tool_call_widget_decision(self, event: ToolCallWidget.Decision) -> None:
@@ -3924,7 +3924,7 @@ class RuneApp(App):
self.exit()
else:
self._last_ctrl_c = now
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
def action_focus_task(self) -> None:
@@ -3973,7 +3973,7 @@ class RuneApp(App):
try:
pane = self.query_one("#work-pane", WorkPane)
pane.display = self._work_pane_visible_for(self.mode)
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
def action_resize_left(self) -> None:
@@ -3993,7 +3993,7 @@ class RuneApp(App):
chat = self.query_one("#chat-channel")
task.styles.width = f"{self.task_width}%"
chat.styles.width = f"{100 - self.task_width}%"
except Exception:
except Exception: # noqa: BLE001 — deliberate: TUI render-loop must never crash the session (degrade-not-crash)
pass
def _update_status(self) -> None:
+4 -1
View File
@@ -21,6 +21,9 @@ import re
import sys
from datetime import datetime, timezone
from dataclasses import dataclass, asdict
import logging
logger = logging.getLogger(__name__)
# ═══════════════════════════════════════════════════════════════════════════════
# CONFIGURATION
@@ -296,7 +299,7 @@ class SafetyOverride:
with open(STATS_FILE, "w") as f:
json.dump(asdict(self.stats), f, indent=2)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def get_params(self, text: str) -> dict:
"""Get override parameters for a request.
+5 -2
View File
@@ -14,6 +14,9 @@ import os
import sys
import json
from datetime import datetime, timezone
import logging
logger = logging.getLogger(__name__)
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
KNOWLEDGE_FILE = os.path.join(SCRIPT_DIR, "knowledge.md")
@@ -59,7 +62,7 @@ def scan_arxiv():
}
)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return findings
@@ -96,7 +99,7 @@ def scan_changelogs():
}
)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return findings
+4 -1
View File
@@ -23,6 +23,9 @@ import re
import sqlite3
import subprocess
import sys
import logging
logger = logging.getLogger(__name__)
import time
from datetime import datetime, timedelta, timezone
@@ -388,7 +391,7 @@ def refine_identity():
timeout=15,
)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return r, items[:4]
+5 -2
View File
@@ -1,3 +1,6 @@
import logging
logger = logging.getLogger(__name__)
#!/usr/bin/env python3
"""system_registry.py — infrastructural system file tracking for Rune.
@@ -84,7 +87,7 @@ def load_settings():
settings = json.load(f)
defaults.update(settings)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return defaults
@@ -239,7 +242,7 @@ def load_registry():
with open(REGISTRY_FILE) as f:
return json.load(f)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return {}
+4 -1
View File
@@ -21,6 +21,9 @@ import time as _time
from datetime import datetime, timezone, timedelta
from dataclasses import dataclass
from typing import Dict, Any
import logging
logger = logging.getLogger(__name__)
_SD = os.path.dirname(os.path.abspath(__file__))
if _SD not in sys.path:
@@ -76,7 +79,7 @@ class TimeAwareness:
if data.get("last_interaction"):
self.last_interaction = datetime.fromisoformat(data["last_interaction"])
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def _save(self):
"""Save last interaction time (atomic write)."""
+5 -2
View File
@@ -23,6 +23,9 @@ import sys
import hashlib
import time
from dataclasses import dataclass
import logging
logger = logging.getLogger(__name__)
from typing import Dict, List, Any
from datetime import datetime, timezone
@@ -89,7 +92,7 @@ class TokenOptimizer:
self.cache[key] = CacheEntry(**entry_data)
self.stats = data.get("stats", self.stats)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def _save(self):
"""Save cache to storage (atomic write)."""
@@ -138,7 +141,7 @@ class TokenOptimizer:
if result and len(result) > 50:
return result
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
# Fallback: minimal constitution
return (
"You are Rune. A stateful coding assistant — you remember, you learn, "
+5 -2
View File
@@ -1,6 +1,9 @@
#!/usr/bin/env python3
import os
import sys as _s
import logging
logger = logging.getLogger(__name__)
_VENV = "/tmp/opencode/voice-venv/bin/python3"
if _s.executable != _VENV and os.path.exists(_VENV):
@@ -109,14 +112,14 @@ def talk():
if key == keyboard.Key.ctrl_r:
start_recording()
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def on_release(key):
try:
if key == keyboard.Key.ctrl_r:
stop_recording()
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
print("hold RIGHT-CTRL to talk; release to transcribe+type. Ctrl-C to quit.", file=sys.stderr)
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
+9 -6
View File
@@ -23,6 +23,9 @@ import os
import sys
import re
from datetime import datetime, timezone
import logging
logger = logging.getLogger(__name__)
from dataclasses import dataclass, field, asdict
from typing import Optional
@@ -225,7 +228,7 @@ def load_config() -> WorkConfig:
data = json.load(f)
return WorkConfig(**{k: v for k, v in data.items() if k in WorkConfig.__dataclass_fields__})
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return WorkConfig()
@@ -236,7 +239,7 @@ def save_config(config: WorkConfig):
with open(CONFIG_FILE, "w") as f:
json.dump(asdict(config), f, indent=2)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def load_batches() -> list[Batch]:
@@ -247,7 +250,7 @@ def load_batches() -> list[Batch]:
data = json.load(f)
return [Batch(**b) for b in data]
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return []
@@ -258,7 +261,7 @@ def save_batches(batches: list[Batch]):
with open(BATCH_FILE, "w") as f:
json.dump([asdict(b) for b in batches], f, indent=2)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
# ═══════════════════════════════════════════════════════════════════════════════
@@ -454,7 +457,7 @@ def load_meta() -> Optional[TaskMeta]:
data = json.load(f)
return TaskMeta(**{k: v for k, v in data.items() if k in TaskMeta.__dataclass_fields__})
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
return None
@@ -465,7 +468,7 @@ def save_meta(meta: TaskMeta):
with open(META_FILE, "w") as f:
json.dump(asdict(meta), f, indent=2)
except Exception:
pass
logger.debug("suppressed exception", exc_info=True)
def update_meta_from_batches():
File diff suppressed because it is too large. Load diff
+312 -288
View File
File diff suppressed because it is too large. Load diff
+6 -1
View File
@@ -622,7 +622,12 @@ def test_find_capability_result_carries_schema_summary():
assert "message" in text, "argument schema summary must be included"
def test_find_capability_no_match_suggests_full_registry():
def test_find_capability_no_match_suggests_full_registry(monkeypatch):
# Store-state isolation: the live store may hold cards that score >0
# on ANY query (gamma/alpha matched 'zzzqqq xxx' after the store
# gained cards — a store-state dependency, not a code regression).
# The no-match path is reached only with an empty card set.
monkeypatch.setattr(cb, "load_cards", lambda: [])
executor = ltr._find_capability_executor
result = executor("find_capability", {"query": "zzzqqq xxx"})
assert result.get("success") is True