Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d8e09bee6 | ||
|
|
ebc0e7edce | ||
|
|
c22bc002bc | ||
|
|
17b2e32c8c |
No files matched your search
@@ -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
@@ -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"
|
||||
|
||||
|
||||
@@ -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": []
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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."""
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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}",
|
||||
|
||||
@@ -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(
|
||||
{
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)."""
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
|
||||
|
||||
@@ -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)."""
|
||||
|
||||
@@ -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, "
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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():
|
||||
|
||||
+5663
-2
File diff suppressed because it is too large.
Load diff
+312
-288
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
|
||||
Reference in new issue
Block a user