claude-code-tools 1.29.1__tar.gz → 1.29.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/PKG-INFO +1 -1
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/__init__.py +1 -1
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/config.py +8 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/mattermost_bot.py +100 -11
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/agent-tunnel-spec.md +8 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/pyproject.toml +2 -2
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/.gitignore +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/LICENSE +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/README.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/action_rpc.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/__init__.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/backends.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/cli.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/convert.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/discord_bot.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/http_frontend.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/locking.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/paths.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/readonly.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/registry.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/relay.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/serve.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/store.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/tmux.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/trust.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/turn_log.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/aichat.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/__init__.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/__main__.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/activity.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/cache.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/cli.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/detect.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/filters.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/model.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/render.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/amux/scan.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/claude_continue.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/cli_passthrough.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_app_server_rpc.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_continue.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_callback.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_cli.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_fingerprint.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_generation.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_legacy.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_models.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_process.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_reservation.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_resume.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_retry.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_reuse.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_state.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_supervisor.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_wait.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_worker.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/config.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/csv2gsheet.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/delete_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/dotenv_vault.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/env_safe.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/export_all.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/export_claude_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/export_codex_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/export_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_claude_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_codex_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_original_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_trimmed_sessions.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/fix_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/gdoc2docx.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/gdoc2md.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/github_wake.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/github_watch_daemon.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/github_watch_store.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/gsheet2csv.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/helper_sessions.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/issue_reply_delivery.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/legacy_session_wrappers.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/md2gdoc.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/move_account.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/__init__.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/cli.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/hooks.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/migrations.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/models.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/prompt_detect.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/store.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/watcher.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/node_menu_ui.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_claude_noise.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_claude_to_codex.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_codex_flatten.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_codex_to_claude.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_render.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_service.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/resolve_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/resolve_session_names.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/resolve_session_render.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/search_index.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_cli_resolution.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_lineage.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_menu.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_menu_cli.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_resolution.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_selection.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_utils.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/smart_trim.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/smart_trim_core.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/tmux_cli_controller.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/tmux_execution_helpers.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/tmux_remote_controller.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/trim_in_place.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/trim_session.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/trim_session_claude.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/trim_session_codex.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_contract.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_formatting.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_identity_policy.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_manifest.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_projection.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_rendering.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_snapshots.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_store_backends.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_processes.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_runs.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_store_io.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_validation.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/claude-code-tmux-tutorials.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/dot-zshrc.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/find-claude-session.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/intercom-spec.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/lmsh.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/local-llm-setup.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/tmux-cli-instructions.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/docs/vault-documentation.md +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/hatch_build.py +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/node_ui/action_config.js +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/node_ui/menu.js +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/node_ui/package-lock.json +0 -0
- {claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/node_ui/package.json +0 -0
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/config.py
RENAMED
|
@@ -104,6 +104,10 @@ class MattermostConfig:
|
|
|
104
104
|
allowed_user_ids: list[str] = field(default_factory=list)
|
|
105
105
|
# false only for a self-signed test server.
|
|
106
106
|
verify_tls: bool = True
|
|
107
|
+
# Handle answered when a teammate just @-mentions the bot without naming
|
|
108
|
+
# a handle ("@bot how does X work?"). Empty = use the only shared session
|
|
109
|
+
# when exactly one is live, else ask which.
|
|
110
|
+
default_handle: str = ""
|
|
107
111
|
|
|
108
112
|
|
|
109
113
|
@dataclass
|
|
@@ -385,6 +389,10 @@ respond_to_dms = false
|
|
|
385
389
|
# channel_ids = [] # 26-char channel ids
|
|
386
390
|
# allowed_user_ids = [] # empty = anyone in the watched channels
|
|
387
391
|
# verify_tls = true
|
|
392
|
+
# Handle answered when someone just @-mentions the bot without naming one
|
|
393
|
+
# ("@bot how does X work?"). Unset = the only shared session when exactly
|
|
394
|
+
# one is live, else the bot asks which.
|
|
395
|
+
# default_handle = ""
|
|
388
396
|
|
|
389
397
|
[claude]
|
|
390
398
|
binary = "claude"
|
|
@@ -141,11 +141,23 @@ def parse_posted(event: dict[str, Any]) -> Optional[MMPost]:
|
|
|
141
141
|
)
|
|
142
142
|
|
|
143
143
|
|
|
144
|
+
def resolve_default_handle(cfg: TunnelConfig, live: Sequence[str]) -> str:
|
|
145
|
+
"""Handle to answer for a bare ``@bot`` mention.
|
|
146
|
+
|
|
147
|
+
The configured ``default_handle`` wins. With none set, a single shared
|
|
148
|
+
session is unambiguous; with several, the bot asks which one.
|
|
149
|
+
"""
|
|
150
|
+
if cfg.mattermost.default_handle:
|
|
151
|
+
return cfg.mattermost.default_handle
|
|
152
|
+
return live[0] if len(live) == 1 else ""
|
|
153
|
+
|
|
154
|
+
|
|
144
155
|
@dataclass
|
|
145
156
|
class Route:
|
|
146
157
|
"""What the bot should do with one post."""
|
|
147
158
|
|
|
148
|
-
|
|
159
|
+
# ignore | list | open | unknown_handle | which_handle | followup | close
|
|
160
|
+
action: str
|
|
149
161
|
thread_key: str = ""
|
|
150
162
|
root_id: str = ""
|
|
151
163
|
handle: str = ""
|
|
@@ -161,6 +173,7 @@ def route_post(
|
|
|
161
173
|
allowed_user_ids: Sequence[str],
|
|
162
174
|
is_bound: Callable[[str], bool],
|
|
163
175
|
handle_live: Callable[[str], bool],
|
|
176
|
+
default_handle: str = "",
|
|
164
177
|
) -> Route:
|
|
165
178
|
"""Decide what to do with a post (pure; no I/O).
|
|
166
179
|
|
|
@@ -172,6 +185,8 @@ def route_post(
|
|
|
172
185
|
allowed_user_ids: If non-empty, only these users are answered.
|
|
173
186
|
is_bound: Whether a thread key is bound to a session.
|
|
174
187
|
handle_live: Whether a handle is currently shared.
|
|
188
|
+
default_handle: Handle to use when the bot is @-mentioned without
|
|
189
|
+
one (see ``resolve_default_handle``); "" = ask which.
|
|
175
190
|
|
|
176
191
|
Returns:
|
|
177
192
|
The routing decision.
|
|
@@ -194,7 +209,18 @@ def route_post(
|
|
|
194
209
|
if post.root_id:
|
|
195
210
|
key = f"mm:{post.root_id}"
|
|
196
211
|
if not is_bound(key):
|
|
197
|
-
|
|
212
|
+
# Not our thread yet. Teammates still address the bot inside one
|
|
213
|
+
# (e.g. answering its "which session?" question), so an explicit
|
|
214
|
+
# handle or @bot mention opens a binding on that root; anything
|
|
215
|
+
# else stays ignored.
|
|
216
|
+
return _open_route(
|
|
217
|
+
text,
|
|
218
|
+
post_id=post.root_id,
|
|
219
|
+
bot_username=bot_username,
|
|
220
|
+
handle_live=handle_live,
|
|
221
|
+
default_handle=default_handle,
|
|
222
|
+
complain_unknown=False,
|
|
223
|
+
)
|
|
198
224
|
# A reply that opens with @someone-else (or @all/@channel/@here) is
|
|
199
225
|
# teammates talking among themselves. A leading @bot is stripped.
|
|
200
226
|
who = leading_mention(text)
|
|
@@ -208,21 +234,74 @@ def route_post(
|
|
|
208
234
|
return Route("close", thread_key=key, root_id=post.root_id)
|
|
209
235
|
return Route("followup", thread_key=key, root_id=post.root_id, text=text)
|
|
210
236
|
|
|
237
|
+
return _open_route(
|
|
238
|
+
text,
|
|
239
|
+
post_id=post.id,
|
|
240
|
+
bot_username=bot_username,
|
|
241
|
+
handle_live=handle_live,
|
|
242
|
+
default_handle=default_handle,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _open_route(
|
|
247
|
+
text: str,
|
|
248
|
+
*,
|
|
249
|
+
post_id: str,
|
|
250
|
+
bot_username: str,
|
|
251
|
+
handle_live: Callable[[str], bool],
|
|
252
|
+
default_handle: str,
|
|
253
|
+
complain_unknown: bool = True,
|
|
254
|
+
) -> Route:
|
|
255
|
+
"""Route a message that may open a thread on ``post_id`` (pure).
|
|
256
|
+
|
|
257
|
+
Used for a root post and for a message inside a thread the bot has not
|
|
258
|
+
bound yet: both are "someone addressing the bot in the channel".
|
|
259
|
+
``complain_unknown`` is off in the latter case, so ordinary chatter
|
|
260
|
+
there stays unanswered.
|
|
261
|
+
"""
|
|
262
|
+
ignore = Route("ignore")
|
|
263
|
+
# An @bot mention is how a teammate naturally addresses the bot. Strip
|
|
264
|
+
# it; whatever follows is the question (a handle may still lead it).
|
|
265
|
+
mentioned = False
|
|
266
|
+
who = leading_mention(text)
|
|
267
|
+
if who is not None:
|
|
268
|
+
if who in BROADCAST_MENTIONS or who != bot_username.lower():
|
|
269
|
+
return ignore # teammates talking to each other
|
|
270
|
+
mentioned = True
|
|
271
|
+
text = _MENTION_RE.sub("", text.lstrip(), count=1).strip()
|
|
272
|
+
|
|
211
273
|
if is_list_command(text):
|
|
212
|
-
return Route("list", root_id=
|
|
213
|
-
|
|
214
|
-
handle
|
|
274
|
+
return Route("list", root_id=post_id)
|
|
275
|
+
# Split on ANY whitespace: a handle followed by a newline is still a
|
|
276
|
+
# handle, and must not fall through to the default.
|
|
277
|
+
parts = text.split(None, 1)
|
|
278
|
+
handle = parts[0].strip().lower() if parts else ""
|
|
279
|
+
remainder = parts[1].strip() if len(parts) > 1 else ""
|
|
215
280
|
if handle_live(handle):
|
|
216
281
|
return Route(
|
|
217
282
|
"open",
|
|
218
|
-
thread_key=f"mm:{
|
|
219
|
-
root_id=
|
|
283
|
+
thread_key=f"mm:{post_id}",
|
|
284
|
+
root_id=post_id,
|
|
220
285
|
handle=handle,
|
|
221
|
-
text=remainder
|
|
286
|
+
text=remainder,
|
|
222
287
|
)
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
288
|
+
if mentioned:
|
|
289
|
+
# Addressed to the bot but no handle named: answer the default one,
|
|
290
|
+
# but only while it is actually shared.
|
|
291
|
+
if not default_handle or not handle_live(default_handle):
|
|
292
|
+
return Route("which_handle", root_id=post_id)
|
|
293
|
+
return Route(
|
|
294
|
+
"open",
|
|
295
|
+
thread_key=f"mm:{post_id}",
|
|
296
|
+
root_id=post_id,
|
|
297
|
+
handle=default_handle,
|
|
298
|
+
text=text,
|
|
299
|
+
)
|
|
300
|
+
# Only complain if it clearly looks like a handle attempt — and never
|
|
301
|
+
# inside someone else's thread, where a one-word reply ("thanks") would
|
|
302
|
+
# otherwise draw a "no live session" answer.
|
|
303
|
+
if complain_unknown and HANDLE_RE.match(handle) and not remainder:
|
|
304
|
+
return Route("unknown_handle", root_id=post_id, handle=handle)
|
|
226
305
|
return ignore
|
|
227
306
|
|
|
228
307
|
|
|
@@ -553,6 +632,9 @@ class _Router:
|
|
|
553
632
|
allowed_user_ids=self.cfg.mattermost.allowed_user_ids,
|
|
554
633
|
is_bound=lambda key: relay.store.get(key) is not None,
|
|
555
634
|
handle_live=lambda h: self.registry.get(h) is not None,
|
|
635
|
+
default_handle=resolve_default_handle(
|
|
636
|
+
self.cfg, [r.handle for r in self.registry.active()]
|
|
637
|
+
),
|
|
556
638
|
)
|
|
557
639
|
if route.action == "ignore":
|
|
558
640
|
return
|
|
@@ -560,6 +642,13 @@ class _Router:
|
|
|
560
642
|
sender = post.sender or "A teammate"
|
|
561
643
|
if route.action == "list":
|
|
562
644
|
await dest.send(relay.handles_text())
|
|
645
|
+
elif route.action == "which_handle":
|
|
646
|
+
live = self.registry.active()
|
|
647
|
+
example = live[0].handle if live else "handle"
|
|
648
|
+
await dest.send(
|
|
649
|
+
"Which session should I ask? Put its handle first, e.g. "
|
|
650
|
+
f"`{example} your question`.\n\n" + relay.handles_text()
|
|
651
|
+
)
|
|
563
652
|
elif route.action == "unknown_handle":
|
|
564
653
|
await dest.send(
|
|
565
654
|
f"No live session for handle `{route.handle}`. "
|
|
@@ -236,6 +236,14 @@ Daemon + core — `claude_code_tools/agent_tunnel/`:
|
|
|
236
236
|
Mattermost routes the same way, with Mattermost's thread model: a root post
|
|
237
237
|
`\<handle\> [question]` in a watched channel (26-char `channel_ids`) opens a
|
|
238
238
|
thread keyed `mm:<root post id>`, and the bot answers as replies under it.
|
|
239
|
+
A root post that simply **@-mentions the bot** works too — the mention is
|
|
240
|
+
stripped and what follows is the question, answered against
|
|
241
|
+
`[mattermost] default_handle` (unset: the only shared session when exactly
|
|
242
|
+
one is live, else the bot replies asking which handle to use). A handle may
|
|
243
|
+
still lead the question after the mention.
|
|
244
|
+
A message inside a thread the bot has NOT bound is routed the same way as a
|
|
245
|
+
root post (so a teammate can answer the bot's "which session?" question
|
|
246
|
+
in place); anything else there is left alone.
|
|
239
247
|
Replies in a bound thread are follow-ups; a reply opening with
|
|
240
248
|
`@someone-else`, `@all`, `@channel` or `@here` is side-chat and ignored, and
|
|
241
249
|
a leading `@bot` is stripped. `!list`/`!handles` and `!done`/`!close`/`!end`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "claude-code-tools"
|
|
3
|
-
version = "1.29.
|
|
3
|
+
version = "1.29.2"
|
|
4
4
|
description = "Collection of tools for working with Claude Code"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -113,7 +113,7 @@ markers = [
|
|
|
113
113
|
|
|
114
114
|
[tool.commitizen]
|
|
115
115
|
name = "cz_conventional_commits"
|
|
116
|
-
version = "1.29.
|
|
116
|
+
version = "1.29.2"
|
|
117
117
|
tag_format = "v$version"
|
|
118
118
|
version_files = [
|
|
119
119
|
"pyproject.toml:version",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/__init__.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/backends.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/convert.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/discord_bot.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/locking.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/paths.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/readonly.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/registry.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/relay.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/serve.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/store.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/tmux.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/trust.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/agent_tunnel/turn_log.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_app_server_rpc.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_callback.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_fingerprint.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_generation.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_legacy.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_models.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_process.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_reservation.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_resume.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_retry.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_reuse.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_state.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_supervisor.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_wait.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/codex_server_worker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/export_claude_session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/export_codex_session.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_claude_session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_codex_session.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_original_session.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/find_trimmed_sessions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/github_watch_daemon.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/github_watch_store.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/issue_reply_delivery.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/legacy_session_wrappers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/msg/prompt_detect.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_claude_noise.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_claude_to_codex.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_codex_flatten.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/port_codex_to_claude.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/resolve_session_names.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/resolve_session_render.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_cli_resolution.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_resolution.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/session_selection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/tmux_cli_controller.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/tmux_execution_helpers.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/tmux_remote_controller.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/trim_session_claude.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/trim_session_codex.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_contract.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_formatting.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_manifest.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_projection.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_rendering.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_cli_snapshots.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_processes.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_store_io.py
RENAMED
|
File without changes
|
{claude_code_tools-1.29.1 → claude_code_tools-1.29.2}/claude_code_tools/workflow_validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|