refactor: remove env var fallbacks
This commit is contained in:
@@ -87,9 +87,6 @@ def chunk_text(text: str, limit: int = DEFAULT_CHUNK_LEN) -> List[str]:
|
||||
class TelegramClient:
|
||||
"""
|
||||
Minimal Telegram Bot API client using standard library (no requests dependency).
|
||||
|
||||
Env:
|
||||
TELEGRAM_BOT_TOKEN
|
||||
"""
|
||||
|
||||
def __init__(self, token: str, timeout_s: int = 120) -> None:
|
||||
@@ -255,11 +252,11 @@ class RouteStore:
|
||||
self._conn.close()
|
||||
|
||||
|
||||
def parse_allowed_chat_ids(env_value: str) -> Optional[set[int]]:
|
||||
def parse_allowed_chat_ids(value: str) -> Optional[set[int]]:
|
||||
"""
|
||||
Parse ALLOWED_CHAT_IDS="123,456"
|
||||
Parse a comma-separated chat id string like "123,456".
|
||||
"""
|
||||
v = (env_value or "").strip()
|
||||
v = (value or "").strip()
|
||||
if not v:
|
||||
return None
|
||||
out: set[int] = set()
|
||||
@@ -291,3 +288,12 @@ def parse_chat_id_list(value: Any) -> Optional[set[int]]:
|
||||
out.add(int(item))
|
||||
return out or None
|
||||
return None
|
||||
|
||||
|
||||
def resolve_chat_ids(config: Dict[str, Any]) -> Optional[set[int]]:
|
||||
chat_ids = parse_chat_id_list(config_get(config, "chat_id"))
|
||||
if chat_ids is None:
|
||||
chat_ids = parse_chat_id_list(config_get(config, "allowed_chat_ids"))
|
||||
if chat_ids is None:
|
||||
chat_ids = parse_chat_id_list(config_get(config, "startup_chat_ids"))
|
||||
return chat_ids
|
||||
|
||||
@@ -14,8 +14,7 @@ from bridge_common import (
|
||||
RouteStore,
|
||||
config_get,
|
||||
load_telegram_config,
|
||||
parse_allowed_chat_ids,
|
||||
parse_chat_id_list,
|
||||
resolve_chat_ids,
|
||||
)
|
||||
|
||||
# -------------------- Codex runner --------------------
|
||||
@@ -146,27 +145,18 @@ class CodexExecRunner:
|
||||
|
||||
def main() -> None:
|
||||
config = load_telegram_config()
|
||||
token = os.environ.get("TELEGRAM_BOT_TOKEN") or config_get(config, "bot_token") or ""
|
||||
db_path = os.environ.get("BRIDGE_DB") or config_get(config, "bridge_db") or "./bridge_routes.sqlite3"
|
||||
allowed = parse_allowed_chat_ids(os.environ.get("ALLOWED_CHAT_IDS", ""))
|
||||
if allowed is None:
|
||||
allowed = parse_chat_id_list(config_get(config, "allowed_chat_ids"))
|
||||
startup_ids = parse_allowed_chat_ids(os.environ.get("STARTUP_CHAT_IDS", ""))
|
||||
if startup_ids is None:
|
||||
startup_ids = parse_chat_id_list(config_get(config, "startup_chat_ids"))
|
||||
if startup_ids is None:
|
||||
startup_ids = allowed
|
||||
startup_msg = os.environ.get("STARTUP_MESSAGE") or config_get(
|
||||
config, "startup_message"
|
||||
) or "✅ exec_bridge started (codex exec)."
|
||||
token = config_get(config, "bot_token") or ""
|
||||
db_path = config_get(config, "bridge_db") or "./bridge_routes.sqlite3"
|
||||
chat_ids = resolve_chat_ids(config)
|
||||
allowed = chat_ids
|
||||
startup_ids = chat_ids
|
||||
startup_msg = config_get(config, "startup_message") or "✅ exec_bridge started (codex exec)."
|
||||
startup_pwd = os.getcwd()
|
||||
startup_msg = f"{startup_msg}\nPWD: {startup_pwd}"
|
||||
|
||||
codex_cmd = os.environ.get("CODEX_CMD") or config_get(config, "codex_cmd") or "codex"
|
||||
workspace = os.environ.get("CODEX_WORKSPACE") or config_get(config, "codex_workspace")
|
||||
raw_exec_args = os.environ.get("CODEX_EXEC_ARGS")
|
||||
if raw_exec_args is None:
|
||||
raw_exec_args = config_get(config, "codex_exec_args") or ""
|
||||
codex_cmd = config_get(config, "codex_cmd") or "codex"
|
||||
workspace = config_get(config, "codex_workspace")
|
||||
raw_exec_args = config_get(config, "codex_exec_args") or ""
|
||||
if isinstance(raw_exec_args, list):
|
||||
extra_args = [str(v) for v in raw_exec_args]
|
||||
else:
|
||||
@@ -194,7 +184,12 @@ def main() -> None:
|
||||
store = RouteStore(db_path)
|
||||
runner = CodexExecRunner(codex_cmd=codex_cmd, workspace=workspace, extra_args=extra_args)
|
||||
|
||||
pool = ThreadPoolExecutor(max_workers=int(os.environ.get("MAX_WORKERS", "4")))
|
||||
max_workers = config_get(config, "max_workers")
|
||||
if isinstance(max_workers, str):
|
||||
max_workers = int(max_workers) if max_workers.strip() else None
|
||||
elif not isinstance(max_workers, int):
|
||||
max_workers = None
|
||||
pool = ThreadPoolExecutor(max_workers=max_workers or 4)
|
||||
offset: Optional[int] = None
|
||||
|
||||
log(f"[startup] pwd={startup_pwd}")
|
||||
@@ -207,7 +202,7 @@ def main() -> None:
|
||||
except Exception as e:
|
||||
log(f"[startup] failed to send startup message to chat_id={chat_id}: {e}")
|
||||
else:
|
||||
log("[startup] no STARTUP_CHAT_IDS or ALLOWED_CHAT_IDS set; skipping startup message")
|
||||
log("[startup] no chat_id configured; skipping startup message")
|
||||
|
||||
def handle(chat_id: int, user_msg_id: int, text: str, resume_session: Optional[str]) -> None:
|
||||
log(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import threading
|
||||
@@ -14,8 +13,7 @@ from bridge_common import (
|
||||
RouteStore,
|
||||
config_get,
|
||||
load_telegram_config,
|
||||
parse_allowed_chat_ids,
|
||||
parse_chat_id_list,
|
||||
resolve_chat_ids,
|
||||
)
|
||||
|
||||
MCP_PROTOCOL_VERSION = "2025-06-18"
|
||||
@@ -252,34 +250,22 @@ class MCPStdioClient:
|
||||
|
||||
def main() -> None:
|
||||
config = load_telegram_config()
|
||||
token = os.environ.get("TELEGRAM_BOT_TOKEN") or config_get(config, "bot_token") or ""
|
||||
db_path = os.environ.get("BRIDGE_DB") or config_get(config, "bridge_db") or "./bridge_routes.sqlite3"
|
||||
allowed = parse_allowed_chat_ids(os.environ.get("ALLOWED_CHAT_IDS", ""))
|
||||
if allowed is None:
|
||||
allowed = parse_chat_id_list(config_get(config, "allowed_chat_ids"))
|
||||
token = config_get(config, "bot_token") or ""
|
||||
db_path = config_get(config, "bridge_db") or "./bridge_routes.sqlite3"
|
||||
allowed = resolve_chat_ids(config)
|
||||
|
||||
# How to start Codex MCP server:
|
||||
# default: "codex mcp-server" (can also be "npx -y codex mcp-server")
|
||||
raw_mcp_cmd = os.environ.get("CODEX_MCP_CMD")
|
||||
if raw_mcp_cmd is None:
|
||||
raw_mcp_cmd = config_get(config, "codex_mcp_cmd") or "codex mcp-server"
|
||||
raw_mcp_cmd = config_get(config, "codex_mcp_cmd") or "codex mcp-server"
|
||||
if isinstance(raw_mcp_cmd, list):
|
||||
mcp_cmd = [str(v) for v in raw_mcp_cmd]
|
||||
else:
|
||||
mcp_cmd = shlex.split(str(raw_mcp_cmd))
|
||||
|
||||
# Optional defaults for tool args (you can override as you like)
|
||||
default_cwd = os.environ.get("CODEX_WORKSPACE") or config_get(config, "codex_workspace")
|
||||
default_sandbox = (
|
||||
os.environ.get("CODEX_SANDBOX")
|
||||
or config_get(config, "codex_sandbox")
|
||||
or "workspace-write"
|
||||
)
|
||||
default_approval = (
|
||||
os.environ.get("CODEX_APPROVAL_POLICY")
|
||||
or config_get(config, "codex_approval_policy")
|
||||
or "never"
|
||||
)
|
||||
default_cwd = config_get(config, "codex_workspace")
|
||||
default_sandbox = config_get(config, "codex_sandbox") or "workspace-write"
|
||||
default_approval = config_get(config, "codex_approval_policy") or "never"
|
||||
|
||||
bot = TelegramClient(token)
|
||||
store = RouteStore(db_path)
|
||||
|
||||
@@ -12,31 +12,29 @@ All options store a mapping from `(chat_id, bot_message_id)` to a route so repli
|
||||
|
||||
1. Ensure `uv` is installed.
|
||||
2. Use the scripts in this folder as-is (no extra dependencies).
|
||||
3. Set `TELEGRAM_BOT_TOKEN` and (optionally) `ALLOWED_CHAT_IDS`, or put them in `~/.codex/telegram.toml`.
|
||||
3. Put your Telegram credentials in `~/.codex/telegram.toml`.
|
||||
|
||||
Example `~/.codex/telegram.toml`:
|
||||
|
||||
```toml
|
||||
bot_token = "123:abc"
|
||||
allowed_chat_ids = [123456789]
|
||||
startup_chat_ids = [123456789]
|
||||
startup_message = "✅ exec_bridge started (codex exec)."
|
||||
chat_id = 123456789
|
||||
```
|
||||
|
||||
Environment variables always override the TOML file.
|
||||
For Python < 3.11, install `tomli` to read TOML. `chat_id` is used both for allowed messages
|
||||
and startup notifications.
|
||||
|
||||
Optional keys (by mode):
|
||||
|
||||
- common: `bridge_db`, `allowed_chat_ids`, `startup_chat_ids`
|
||||
- exec/resume: `startup_message`, `codex_cmd`, `codex_workspace`, `codex_exec_args`, `max_workers`
|
||||
- MCP server: `codex_mcp_cmd`, `codex_workspace`, `codex_sandbox`, `codex_approval_policy`
|
||||
|
||||
## Option 1: exec/resume
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
export TELEGRAM_BOT_TOKEN="123:abc"
|
||||
export BRIDGE_DB="./bridge_routes.sqlite3"
|
||||
export CODEX_CMD="codex"
|
||||
export CODEX_WORKSPACE="/path/to/repo"
|
||||
export CODEX_EXEC_ARGS="--full-auto"
|
||||
export STARTUP_CHAT_IDS="123456789" # optional; defaults to ALLOWED_CHAT_IDS if set
|
||||
export STARTUP_MESSAGE="✅ exec_bridge started (codex exec)." # optional; PWD is appended
|
||||
uv run exec_bridge.py
|
||||
```
|
||||
|
||||
@@ -45,12 +43,6 @@ uv run exec_bridge.py
|
||||
Run:
|
||||
|
||||
```bash
|
||||
export TELEGRAM_BOT_TOKEN="123:abc"
|
||||
export BRIDGE_DB="./bridge_routes.sqlite3"
|
||||
export CODEX_MCP_CMD="codex mcp-server"
|
||||
export CODEX_WORKSPACE="/path/to/repo"
|
||||
export CODEX_SANDBOX="workspace-write"
|
||||
export CODEX_APPROVAL_POLICY="never"
|
||||
uv run mcp_bridge.py
|
||||
```
|
||||
|
||||
@@ -59,18 +51,17 @@ uv run mcp_bridge.py
|
||||
Reply injector:
|
||||
|
||||
```bash
|
||||
export TELEGRAM_BOT_TOKEN="123:abc"
|
||||
export BRIDGE_DB="./bridge_routes.sqlite3"
|
||||
export ALLOWED_CHAT_IDS="123456789"
|
||||
uv run tmux_reply_bot.py
|
||||
```
|
||||
|
||||
Notifier (call from your existing hook):
|
||||
|
||||
```bash
|
||||
uv run tmux_notify.py --chat-id "$CHAT_ID" --tmux-target "codex1:0.0" --text "$TURN_TEXT"
|
||||
uv run tmux_notify.py --tmux-target "codex1:0.0" --text "$TURN_TEXT"
|
||||
```
|
||||
|
||||
Add `--chat-id` if `chat_id` is not set in `~/.codex/telegram.toml`.
|
||||
|
||||
## Files
|
||||
|
||||
- `bridge_common.py`: shared Telegram client, chunking, and routing store
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
@@ -22,13 +21,13 @@ def main() -> None:
|
||||
ap.add_argument(
|
||||
"--db",
|
||||
type=str,
|
||||
default=os.environ.get("BRIDGE_DB") or config_get(config, "bridge_db") or "./bridge_routes.sqlite3",
|
||||
default=config_get(config, "bridge_db") or "./bridge_routes.sqlite3",
|
||||
)
|
||||
ap.add_argument("--reply-to", type=int, default=None, help="Optional Telegram message_id to reply to")
|
||||
ap.add_argument("--text", type=str, default=None, help="Message text. If omitted, read stdin.")
|
||||
args = ap.parse_args()
|
||||
|
||||
token = os.environ.get("TELEGRAM_BOT_TOKEN") or config_get(config, "bot_token") or ""
|
||||
token = config_get(config, "bot_token") or ""
|
||||
bot = TelegramClient(token)
|
||||
store = RouteStore(args.db)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from typing import Optional
|
||||
@@ -10,8 +9,7 @@ from bridge_common import (
|
||||
RouteStore,
|
||||
config_get,
|
||||
load_telegram_config,
|
||||
parse_allowed_chat_ids,
|
||||
parse_chat_id_list,
|
||||
resolve_chat_ids,
|
||||
)
|
||||
|
||||
|
||||
@@ -29,11 +27,9 @@ def tmux_send_text(target: str, text: str, press_enter: bool = True) -> None:
|
||||
|
||||
def main() -> None:
|
||||
config = load_telegram_config()
|
||||
token = os.environ.get("TELEGRAM_BOT_TOKEN") or config_get(config, "bot_token") or ""
|
||||
db_path = os.environ.get("BRIDGE_DB") or config_get(config, "bridge_db") or "./bridge_routes.sqlite3"
|
||||
allowed = parse_allowed_chat_ids(os.environ.get("ALLOWED_CHAT_IDS", ""))
|
||||
if allowed is None:
|
||||
allowed = parse_chat_id_list(config_get(config, "allowed_chat_ids"))
|
||||
token = config_get(config, "bot_token") or ""
|
||||
db_path = config_get(config, "bridge_db") or "./bridge_routes.sqlite3"
|
||||
allowed = resolve_chat_ids(config)
|
||||
|
||||
bot = TelegramClient(token)
|
||||
store = RouteStore(db_path)
|
||||
|
||||
Reference in New Issue
Block a user