test#1
Closed
Jack-261108 wants to merge 50 commits into
Closed
Conversation
added 30 commits
May 21, 2026 22:37
…de sessions Implement full external session discovery, binding, and management: - SessionOwnershipResolver: first gate in hook pipeline with strict priority (tmux-owned → external-bound → unbound). No workdir auto-match. - ExternalSessionDiscoveryService: tracks unbound sessions from hook events - ExternalBindingStore: persists bindings as JSON for restart survival - ExternalSessionBinder: bind/unbind with immediate JSONL path resolution - UnboundPermissionHandler: broadcasts to all allowed users, first-responder wins, auto-deny on TTL expiry - ExternalSessionPushNotifier: independent Telegram push for bound sessions - Telegram bot commands: /external list|bind|unbind|status - Hook pipeline restructured to use ownership resolver as first gate 16 property-based tests (Hypothesis) + 4 integration tests + 8 unit tests. 550 tests pass.
Users can now type partial session IDs (e.g. '90fcaa30-564') and the system will auto-resolve to the full session_id if unambiguous.
These were implemented but never instantiated in bootstrap, so bound external session permission requests were silently not forwarded.
- Push notifier sends InlineKeyboardMarkup with Approve/Deny buttons
- UnboundPermissionHandler also uses inline buttons
- New callback handler routes ext_perm:{tool_use_id}:{decision} callbacks
- Edits original message to show decision result
- Prevents text-based permission responses being eaten by claude chat
Claude Code hook protocol expects 'allow'/'deny' in the decision field, not 'approve'/'deny'. This was causing the terminal to not respond after the user clicked Approve in Telegram.
AskUserQuestion is a special PermissionRequest where Claude just needs permission to display a question. The user answers directly in the terminal. Auto-allow these instead of showing Approve/Deny buttons. For bound sessions: auto-allow + send info push '❓ 等待用户输入' For unbound sessions: auto-allow (no broadcast needed)
When an external session receives an AskUserQuestion, display the question text and numbered options in Telegram so the user knows what to select in their terminal. Auto-allow is preserved — user still answers directly in the terminal.
When an external Claude session asks a user question and is running inside tmux, show option buttons in Telegram. When the user clicks: 1. Find the tmux pane containing Claude via PID process tree walk 2. Inject keystrokes (Down arrows + Enter) via tmux send-keys 3. Respond to the hook permission with 'allow' Falls back to read-only notification if no tmux pane found. New components: - pty_injector: finds tmux panes and injects keystrokes - ExternalUserQuestionState: tracks pending questions for callback routing - ext_uq callback handler: processes button clicks and triggers injection
…auto-approve - Register 11 bot commands via set_my_commands on startup - /list shows external sessions with inline buttons (bind/unbind) - Add PID liveness check to prune dead external sessions - Add auto-approve button to all permission flows - Auto-approve intercepts hook events before user notification - Sends silent notification on auto-approved permissions - /deny disables auto-approve for current session - SessionEnd and health check cleanup auto-approve state
- Discover built-in commands (/compact, /clear, /resume, etc.) - Scan ~/.claude/skills/ for user-level skills - Scan <workdir>/.claude/commands/ and .claude/skills/ for project-level - Display as categorized inline keyboard (builtin/user/skill/project) - Clicking a button sends the slash command to the active Claude session - Register /cmds in Telegram bot menu
/resume: - SessionScanner scans ~/.claude/projects/<workdir>/ for past JSONL sessions - Displays recent sessions as inline keyboard (date + first prompt summary) - Clicking resumes via claude --resume <session-id> in tmux - TmuxCommands extended with _build_interactive_claude_resume_command - TerminalSessionService.open_claude_resume_session handles full lifecycle /cmds: - Discovers built-in Claude commands (/compact, /clear, /model) - Scans ~/.claude/skills/ for user-level skills - Scans <workdir>/.claude/commands/ and .claude/skills/ for project-level - Renders as categorized inline keyboard, clicking sends to Claude session Both registered in Telegram bot menu (now 13 commands total).
…ives - FileSenderService detects PostToolUse Write events via hook pipeline - Classifies files by extension (image → send_photo, document → send_document) - Respects Telegram size limits (10MB photos, 50MB documents) - Fire-and-forget via asyncio.create_task (non-blocking) - Works for both owned (tmux) and bound (external) sessions - Configurable via AUTO_FILE_SEND_ENABLED and AUTO_FILE_SEND_EXTENSIONS env vars - Default extensions: png,jpg,jpeg,gif,webp,svg,pdf,docx,xlsx,csv,html,zip,tar.gz
Add configurable TTL and cleanup limits for task storage, rate-limit buckets, and async lock registries so long-running processes can shed stale in-memory state.
added 20 commits
May 26, 2026 16:34
…r automatic cleanup TmuxRunner._session_locks was a plain dict[str, asyncio.Lock] that grew without bound. Replace it with RefCountedLockRegistry so expired locks are cleaned up after TTL. Pass lock settings from bootstrap.
- Add _clear_seen_mtimes_for_session for prefix-based mtime cleanup - Add _cleanup_finished_session to properly clean tasks, mtime keys, and locks - Fix forget() to clear all mtime keys for a session, not just exact match - Fix forget() to defer lock cleanup for still-running watcher tasks - Fix stop_all() to clear _session_locks after awaiting all tasks - Fix _watch_session finally block to use _cleanup_finished_session
The test_run_prompt_and_stream_interactive_reports_pending_permission_once test was using the old tool_use_id-based callback format. Updated to use PermissionCallbackRegistry short tokens and verify token resolution.
- Bounded upload queue with per-user limits and pre-download rejection - Permission callback short tokens (PermissionCallbackRegistry) - Delayed queued upload processing after task completion - Unbound permission pending cleanup with lock - Tmux session lock cleanup via RefCountedLockRegistry - AgentFileWatcher state cleanup (prefix mtime, deferred lock release)
Add TTL cleanup for queued uploads and tighten reattach/permission state handling so stale sessions do not block later runs.
Update stale queue, permission, and watcher expectations so the regression suite reflects the current cleanup flow.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.