overcode 0.3.1__tar.gz → 0.3.3__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.
- {overcode-0.3.1/src/overcode.egg-info → overcode-0.3.3}/PKG-INFO +1 -1
- {overcode-0.3.1 → overcode-0.3.3}/pyproject.toml +1 -1
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/claude_config.py +17 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/agent.py +2 -1
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/split.py +47 -28
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/history_reader.py +31 -1
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/hook_handler.py +3 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/hook_status_detector.py +104 -91
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/job_launcher.py +18 -3
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/monitor_daemon.py +46 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/settings.py +33 -1
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/status_detector.py +31 -4
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/status_detector_factory.py +26 -16
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/summary_columns.py +13 -4
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/supervisor_layout.sh +10 -5
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tmux_manager.py +1 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tmux_utils.py +22 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui.py +50 -18
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui.tcss +1 -1
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_actions/session.py +26 -39
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_actions/view.py +1 -1
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/daemon_panel.py +41 -32
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/help_overlay.py +2 -2
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/session_summary.py +1 -1
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/usage_monitor.py +2 -2
- {overcode-0.3.1 → overcode-0.3.3/src/overcode.egg-info}/PKG-INFO +1 -1
- {overcode-0.3.1 → overcode-0.3.3}/LICENSE +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/MANIFEST.in +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/README.md +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/setup.cfg +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/__init__.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/agent_scanner.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/bundled_skills.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/claude_pid.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/__init__.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/__main__.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/_shared.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/budget.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/config.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/daemon.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/hooks.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/jobs.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/monitoring.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/perms.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/sister.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/cli/skills.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/config.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/daemon_claude_skill.md +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/daemon_logging.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/daemon_utils.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/data_export.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/dependency_check.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/duration.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/exceptions.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/follow_mode.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/implementations.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/interfaces.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/job_manager.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/launcher.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/logging_config.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/mocks.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/monitor_daemon_core.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/monitor_daemon_state.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/notifier.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/pid_utils.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/presence_logger.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/protocols.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/session_manager.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/sister_controller.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/sister_poller.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/standing_instructions.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/status_constants.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/status_history.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/status_patterns.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/summarizer_client.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/summarizer_component.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/summary_groups.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/supervisor_daemon.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/supervisor_daemon_core.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/testing/__init__.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/testing/renderer.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/testing/tmux_driver.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/testing/tui_eye.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/testing/tui_eye_skill.md +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/time_context.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_actions/__init__.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_actions/daemon.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_actions/input.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_actions/navigation.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_helpers.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_logic.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_render.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/__init__.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/agent_select_modal.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/command_bar.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/daemon_status_bar.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/fullscreen_preview.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/instruction_history_modal.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/job_summary.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/new_agent_defaults_modal.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/preview_pane.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/sister_selection_modal.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/status_timeline.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/tui_widgets/summary_config_modal.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web/__init__.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web/templates/analytics.html +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web/templates/dashboard.html +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web_api.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web_chartjs.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web_control_api.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web_server.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web_server_runner.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode/web_templates.py +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode.egg-info/SOURCES.txt +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode.egg-info/dependency_links.txt +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode.egg-info/entry_points.txt +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode.egg-info/requires.txt +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/src/overcode.egg-info/top_level.txt +0 -0
- {overcode-0.3.1 → overcode-0.3.3}/tests/test_e2e_multi_agent_jokes.py +0 -0
|
@@ -137,6 +137,23 @@ class ClaudeConfigEditor:
|
|
|
137
137
|
results.append((event, cmd))
|
|
138
138
|
return results
|
|
139
139
|
|
|
140
|
+
# ----- Hook detection -----
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def are_overcode_hooks_installed() -> bool:
|
|
144
|
+
"""Check if core overcode hooks are installed at user level.
|
|
145
|
+
|
|
146
|
+
Requires at least UserPromptSubmit, Stop, and PostToolUse hooks
|
|
147
|
+
to consider hooks mode viable.
|
|
148
|
+
"""
|
|
149
|
+
editor = ClaudeConfigEditor.user_level()
|
|
150
|
+
try:
|
|
151
|
+
editor.load()
|
|
152
|
+
except (ValueError, FileNotFoundError):
|
|
153
|
+
return False
|
|
154
|
+
core_events = ("UserPromptSubmit", "Stop", "PostToolUse")
|
|
155
|
+
return all(editor.has_hook(event, "overcode hook-handler") for event in core_events)
|
|
156
|
+
|
|
140
157
|
# ----- Permission management -----
|
|
141
158
|
|
|
142
159
|
def add_permission(self, tool_pattern: str) -> bool:
|
|
@@ -970,9 +970,10 @@ def show(
|
|
|
970
970
|
else:
|
|
971
971
|
# Daemon not running — fall back to direct detection
|
|
972
972
|
from ..status_detector_factory import create_status_detector
|
|
973
|
+
from ..settings import resolve_detection_mode
|
|
973
974
|
detector = create_status_detector(
|
|
974
975
|
session,
|
|
975
|
-
strategy=
|
|
976
|
+
strategy=resolve_detection_mode(session),
|
|
976
977
|
)
|
|
977
978
|
status, activity, pane_content_raw = detector.detect_status(sess)
|
|
978
979
|
|
|
@@ -34,6 +34,7 @@ from typing import Annotated
|
|
|
34
34
|
import typer
|
|
35
35
|
|
|
36
36
|
from ._shared import app, SessionOption
|
|
37
|
+
from ..tmux_utils import get_pane_base_index
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
def _acquire_setup_lock() -> bool:
|
|
@@ -179,11 +180,13 @@ def _setup_linked_session(agents_session: str) -> str:
|
|
|
179
180
|
|
|
180
181
|
def _are_keybindings_installed() -> bool:
|
|
181
182
|
"""Check if overcode keybindings are already installed."""
|
|
182
|
-
# Check for our
|
|
183
|
+
# Check for our M-j binding as a sentinel — look for the exact
|
|
184
|
+
# send-keys target rather than a substring match on the window name,
|
|
185
|
+
# to avoid false positives from unrelated bindings (#384).
|
|
183
186
|
result = _tmux("list-keys", "-T", "root")
|
|
184
187
|
if result.returncode != 0:
|
|
185
188
|
return False
|
|
186
|
-
return SPLIT_WINDOW_NAME in result.stdout
|
|
189
|
+
return f"send-keys -t overcode:{SPLIT_WINDOW_NAME}." in result.stdout
|
|
187
190
|
|
|
188
191
|
|
|
189
192
|
def _remove_keybindings() -> None:
|
|
@@ -232,27 +235,28 @@ def _setup_keybindings(linked_session: str = "", toggle_key: str = "") -> None:
|
|
|
232
235
|
# --- Agent navigation from the bottom (terminal) pane ---
|
|
233
236
|
# Option+J / Option+K (Meta+j/k) cycle agents by sending j/k
|
|
234
237
|
# to the monitor pane, which navigates and syncs the terminal.
|
|
238
|
+
_base = get_pane_base_index()
|
|
235
239
|
_in_bottom = (
|
|
236
240
|
f"#{{&&:#{{==:#{{window_name}},{SPLIT_WINDOW_NAME}}},"
|
|
237
|
-
f"#{{!=:#{{pane_index}},
|
|
241
|
+
f"#{{!=:#{{pane_index}},{_base}}}}}"
|
|
238
242
|
)
|
|
239
243
|
_tmux(
|
|
240
244
|
"bind-key", "-n", "M-j",
|
|
241
245
|
"if-shell", "-F", _in_bottom,
|
|
242
|
-
f"send-keys -t overcode:{SPLIT_WINDOW_NAME}.
|
|
246
|
+
f"send-keys -t overcode:{SPLIT_WINDOW_NAME}.{_base} j",
|
|
243
247
|
"send-keys M-j",
|
|
244
248
|
)
|
|
245
249
|
_tmux(
|
|
246
250
|
"bind-key", "-n", "M-k",
|
|
247
251
|
"if-shell", "-F", _in_bottom,
|
|
248
|
-
f"send-keys -t overcode:{SPLIT_WINDOW_NAME}.
|
|
252
|
+
f"send-keys -t overcode:{SPLIT_WINDOW_NAME}.{_base} k",
|
|
249
253
|
"send-keys M-k",
|
|
250
254
|
)
|
|
251
255
|
# Option+B: navigate to bell (next agent needing attention)
|
|
252
256
|
_tmux(
|
|
253
257
|
"bind-key", "-n", "M-b",
|
|
254
258
|
"if-shell", "-F", _in_bottom,
|
|
255
|
-
f"send-keys -t overcode:{SPLIT_WINDOW_NAME}.
|
|
259
|
+
f"send-keys -t overcode:{SPLIT_WINDOW_NAME}.{_base} b",
|
|
256
260
|
"send-keys M-b",
|
|
257
261
|
)
|
|
258
262
|
|
|
@@ -263,12 +267,12 @@ def _setup_keybindings(linked_session: str = "", toggle_key: str = "") -> None:
|
|
|
263
267
|
# copy mode in the inner session via the tmux API.
|
|
264
268
|
if linked_session:
|
|
265
269
|
# PageUp: enter copy mode + scroll up, but only when in the
|
|
266
|
-
# bottom pane (pane_index !=
|
|
270
|
+
# bottom pane (pane_index != base) of the split window.
|
|
267
271
|
# Top pane (Textual TUI) and other windows get normal PageUp.
|
|
268
272
|
_tmux(
|
|
269
273
|
"bind-key", "-n", "PPage",
|
|
270
274
|
"if-shell", "-F",
|
|
271
|
-
f"#{{&&:#{{==:#{{window_name}},{SPLIT_WINDOW_NAME}}},#{{!=:#{{pane_index}},
|
|
275
|
+
f"#{{&&:#{{==:#{{window_name}},{SPLIT_WINDOW_NAME}}},#{{!=:#{{pane_index}},{_base}}}}}",
|
|
272
276
|
f"copy-mode -t {linked_session} -u",
|
|
273
277
|
"send-keys PPage",
|
|
274
278
|
)
|
|
@@ -276,7 +280,7 @@ def _setup_keybindings(linked_session: str = "", toggle_key: str = "") -> None:
|
|
|
276
280
|
_tmux(
|
|
277
281
|
"bind-key", "-n", "NPage",
|
|
278
282
|
"if-shell", "-F",
|
|
279
|
-
f"#{{&&:#{{==:#{{window_name}},{SPLIT_WINDOW_NAME}}},#{{!=:#{{pane_index}},
|
|
283
|
+
f"#{{&&:#{{==:#{{window_name}},{SPLIT_WINDOW_NAME}}},#{{!=:#{{pane_index}},{_base}}}}}",
|
|
280
284
|
f"send-keys -t {linked_session} NPage",
|
|
281
285
|
"send-keys NPage",
|
|
282
286
|
)
|
|
@@ -288,7 +292,7 @@ def _setup_keybindings(linked_session: str = "", toggle_key: str = "") -> None:
|
|
|
288
292
|
# already active), then send scroll-up/down commands to it.
|
|
289
293
|
_in_bottom = (
|
|
290
294
|
f"#{{&&:#{{==:#{{window_name}},{SPLIT_WINDOW_NAME}}},"
|
|
291
|
-
f"#{{!=:#{{pane_index}},
|
|
295
|
+
f"#{{!=:#{{pane_index}},{_base}}}}}"
|
|
292
296
|
)
|
|
293
297
|
_tmux(
|
|
294
298
|
"bind-key", "-n", "WheelUpPane",
|
|
@@ -410,7 +414,7 @@ def tmux_resize():
|
|
|
410
414
|
|
|
411
415
|
# Apply the new ratio
|
|
412
416
|
new_height = max(int(int(info.split(":")[1]) * next_ratio / 100), 5)
|
|
413
|
-
_tmux("resize-pane", "-t", f"{target}.
|
|
417
|
+
_tmux("resize-pane", "-t", f"{target}.{get_pane_base_index()}", "-y", str(new_height))
|
|
414
418
|
|
|
415
419
|
|
|
416
420
|
@app.command("tmux")
|
|
@@ -487,11 +491,10 @@ def tmux_layout(
|
|
|
487
491
|
rprint(" tmux set -g terminal-features ''")
|
|
488
492
|
return
|
|
489
493
|
|
|
490
|
-
#
|
|
494
|
+
# Create agents session if it doesn't exist (#397)
|
|
491
495
|
if not _tmux_check("has-session", "-t", session):
|
|
492
|
-
rprint(f"[
|
|
493
|
-
|
|
494
|
-
raise typer.Exit(1)
|
|
496
|
+
rprint(f"[dim]Creating tmux session '{session}'...[/dim]")
|
|
497
|
+
_tmux("new-session", "-d", "-s", session)
|
|
495
498
|
|
|
496
499
|
# --- Toggle key selection (runs if not yet configured) ---
|
|
497
500
|
from ..config import get_tmux_toggle_key, set_tmux_toggle_key
|
|
@@ -601,20 +604,30 @@ def _tmux_layout_locked(session: str, ratio: int, rprint) -> None:
|
|
|
601
604
|
if existing:
|
|
602
605
|
if _is_split_window_healthy(existing):
|
|
603
606
|
if in_tmux:
|
|
604
|
-
# Check if a real (non-
|
|
607
|
+
# Check if a real (non-nested) client is already on overcode.
|
|
605
608
|
# If so, no switch needed — the user is already there or
|
|
606
609
|
# another terminal has it open. Switching blindly can
|
|
607
610
|
# accidentally move the bottom pane's nested client from
|
|
608
611
|
# oc-view-agents to overcode, creating a recursive display
|
|
609
612
|
# that collapses the window.
|
|
613
|
+
#
|
|
614
|
+
# Detect nested clients by comparing client TTYs against
|
|
615
|
+
# pane TTYs in the split window (#387). A nested tmux
|
|
616
|
+
# client's TTY matches one of the pane TTYs.
|
|
617
|
+
pane_ttys = set(
|
|
618
|
+
_tmux_output(
|
|
619
|
+
"list-panes", "-t", f"{oc_session}:{SPLIT_WINDOW_NAME}",
|
|
620
|
+
"-F", "#{pane_tty}",
|
|
621
|
+
).splitlines()
|
|
622
|
+
)
|
|
610
623
|
oc_clients = _tmux_output(
|
|
611
624
|
"list-clients", "-t", oc_session,
|
|
612
|
-
"-F", "#{
|
|
625
|
+
"-F", "#{client_tty}",
|
|
613
626
|
)
|
|
614
627
|
has_real_client = any(
|
|
615
|
-
|
|
616
|
-
for
|
|
617
|
-
if
|
|
628
|
+
tty.strip() not in pane_ttys
|
|
629
|
+
for tty in oc_clients.splitlines()
|
|
630
|
+
if tty.strip()
|
|
618
631
|
)
|
|
619
632
|
if not has_real_client:
|
|
620
633
|
# No real client on overcode yet — switch the caller's
|
|
@@ -632,14 +645,14 @@ def _tmux_layout_locked(session: str, ratio: int, rprint) -> None:
|
|
|
632
645
|
else:
|
|
633
646
|
# Respawn before attach — execlp replaces this process
|
|
634
647
|
_tmux("respawn-pane", "-k",
|
|
635
|
-
"-t", f"{oc_session}:{SPLIT_WINDOW_NAME}.
|
|
648
|
+
"-t", f"{oc_session}:{SPLIT_WINDOW_NAME}.{get_pane_base_index()}",
|
|
636
649
|
monitor_cmd)
|
|
637
650
|
rprint(f"[green]Attaching to existing {SPLIT_WINDOW_NAME} window (monitor restarted)...[/green]")
|
|
638
651
|
time.sleep(0.2)
|
|
639
652
|
os.execlp("tmux", "tmux", "attach-session", "-t", oc_session)
|
|
640
653
|
# Always restart the monitor so code changes take effect
|
|
641
654
|
_tmux("respawn-pane", "-k",
|
|
642
|
-
"-t", f"{oc_session}:{SPLIT_WINDOW_NAME}.
|
|
655
|
+
"-t", f"{oc_session}:{SPLIT_WINDOW_NAME}.{get_pane_base_index()}",
|
|
643
656
|
monitor_cmd)
|
|
644
657
|
rprint(f"[green]Switched to existing {SPLIT_WINDOW_NAME} window (monitor restarted)[/green]")
|
|
645
658
|
return
|
|
@@ -668,7 +681,7 @@ def _tmux_layout_locked(session: str, ratio: int, rprint) -> None:
|
|
|
668
681
|
|
|
669
682
|
# The bottom pane runs a nested tmux attach. We must unset $TMUX
|
|
670
683
|
# because tmux refuses to attach from inside an existing session.
|
|
671
|
-
attach_cmd = f"unset TMUX; tmux attach-session -t {linked}"
|
|
684
|
+
attach_cmd = f"sh -c 'unset TMUX; exec tmux attach-session -t {linked}'"
|
|
672
685
|
|
|
673
686
|
# If an "overcode" session exists but has no split window, it might be:
|
|
674
687
|
# (a) a stale session from a previous overcode run, or
|
|
@@ -749,7 +762,7 @@ def _tmux_layout_locked(session: str, ratio: int, rprint) -> None:
|
|
|
749
762
|
result = _tmux(
|
|
750
763
|
"split-window", "-v",
|
|
751
764
|
"-t", f"{oc_session}:{SPLIT_WINDOW_NAME}",
|
|
752
|
-
"-
|
|
765
|
+
"-l", f"{100 - ratio}%",
|
|
753
766
|
attach_cmd,
|
|
754
767
|
)
|
|
755
768
|
if result.returncode != 0:
|
|
@@ -757,17 +770,23 @@ def _tmux_layout_locked(session: str, ratio: int, rprint) -> None:
|
|
|
757
770
|
raise typer.Exit(1)
|
|
758
771
|
|
|
759
772
|
# Focus top pane
|
|
760
|
-
_tmux("select-pane", "-t", f"{oc_session}:{SPLIT_WINDOW_NAME}.
|
|
773
|
+
_tmux("select-pane", "-t", f"{oc_session}:{SPLIT_WINDOW_NAME}.{get_pane_base_index()}")
|
|
761
774
|
|
|
762
775
|
rprint(f"[green]Split layout ready.[/green] Tab toggles panes.")
|
|
763
776
|
|
|
764
777
|
else:
|
|
765
778
|
# --- Outside tmux: create detached, split, then attach ---
|
|
766
779
|
if need_new_session:
|
|
780
|
+
# Use actual terminal size (fall back to 200x50 if unavailable)
|
|
781
|
+
try:
|
|
782
|
+
term_size = os.get_terminal_size()
|
|
783
|
+
term_x, term_y = str(term_size.columns), str(term_size.lines)
|
|
784
|
+
except OSError:
|
|
785
|
+
term_x, term_y = "200", "50"
|
|
767
786
|
result = _tmux(
|
|
768
787
|
"new-session", "-d", "-s", oc_session,
|
|
769
788
|
"-n", SPLIT_WINDOW_NAME,
|
|
770
|
-
"-x",
|
|
789
|
+
"-x", term_x, "-y", term_y,
|
|
771
790
|
monitor_cmd,
|
|
772
791
|
)
|
|
773
792
|
if result.returncode != 0:
|
|
@@ -792,12 +811,12 @@ def _tmux_layout_locked(session: str, ratio: int, rprint) -> None:
|
|
|
792
811
|
_tmux(
|
|
793
812
|
"split-window", "-v",
|
|
794
813
|
"-t", f"{oc_session}:{SPLIT_WINDOW_NAME}",
|
|
795
|
-
"-
|
|
814
|
+
"-l", f"{100 - ratio}%",
|
|
796
815
|
attach_cmd,
|
|
797
816
|
)
|
|
798
817
|
|
|
799
818
|
# Focus top pane
|
|
800
|
-
_tmux("select-pane", "-t", f"{oc_session}:{SPLIT_WINDOW_NAME}.
|
|
819
|
+
_tmux("select-pane", "-t", f"{oc_session}:{SPLIT_WINDOW_NAME}.{get_pane_base_index()}")
|
|
801
820
|
|
|
802
821
|
# Attach to the session (replaces this process)
|
|
803
822
|
rprint(f"[green]Attaching to split layout...[/green]")
|
|
@@ -33,8 +33,12 @@ CLAUDE_PROJECTS_PATH = Path.home() / ".claude" / "projects"
|
|
|
33
33
|
|
|
34
34
|
# Model name → context window size in tokens.
|
|
35
35
|
# Default 200K for unknown models. Update as new models ship.
|
|
36
|
+
# Claude Code with 1M context reports the same model ID — we detect
|
|
37
|
+
# the actual context size from token counts at runtime and update here
|
|
38
|
+
# for the models known to support extended context.
|
|
36
39
|
MODEL_CONTEXT_WINDOWS: Dict[str, int] = {
|
|
37
|
-
"claude-opus-4-6":
|
|
40
|
+
"claude-opus-4-6": 1_000_000,
|
|
41
|
+
"claude-sonnet-4-6": 1_000_000,
|
|
38
42
|
"claude-sonnet-4-5-20250929": 200_000,
|
|
39
43
|
"claude-haiku-4-5-20251001": 200_000,
|
|
40
44
|
"claude-3-5-sonnet-20241022": 200_000,
|
|
@@ -45,6 +49,32 @@ MODEL_CONTEXT_WINDOWS: Dict[str, int] = {
|
|
|
45
49
|
}
|
|
46
50
|
DEFAULT_CONTEXT_WINDOW = 200_000
|
|
47
51
|
|
|
52
|
+
# Model ID → human-readable short name for display
|
|
53
|
+
MODEL_SHORT_NAMES: Dict[str, str] = {
|
|
54
|
+
"claude-opus-4-6": "Op4.6",
|
|
55
|
+
"claude-sonnet-4-6": "Sn4.6",
|
|
56
|
+
"claude-sonnet-4-5-20250929": "Sn4.5",
|
|
57
|
+
"claude-haiku-4-5-20251001": "Hk4.5",
|
|
58
|
+
"claude-3-5-sonnet-20241022": "Sn3.5",
|
|
59
|
+
"claude-3-5-haiku-20241022": "Hk3.5",
|
|
60
|
+
"claude-3-opus-20240229": "Op3",
|
|
61
|
+
"claude-3-sonnet-20240229": "Sn3",
|
|
62
|
+
"claude-3-haiku-20240307": "Hk3",
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def model_short_name(model: Optional[str]) -> str:
|
|
67
|
+
"""Return a short display name for a model ID.
|
|
68
|
+
|
|
69
|
+
Examples:
|
|
70
|
+
"claude-opus-4-6" → "Op4.6"
|
|
71
|
+
"claude-haiku-4-5-20251001" → "Hk4.5"
|
|
72
|
+
"unknown-model" → "unknown-model"
|
|
73
|
+
"""
|
|
74
|
+
if not model:
|
|
75
|
+
return ""
|
|
76
|
+
return MODEL_SHORT_NAMES.get(model, model)
|
|
77
|
+
|
|
48
78
|
|
|
49
79
|
def model_context_window(model: Optional[str]) -> int:
|
|
50
80
|
"""Return the context window size for a given model name.
|
|
@@ -25,8 +25,11 @@ logger = logging.getLogger(__name__)
|
|
|
25
25
|
# All hooks that overcode installs
|
|
26
26
|
OVERCODE_HOOKS: list[tuple[str, str]] = [
|
|
27
27
|
("UserPromptSubmit", "overcode hook-handler"),
|
|
28
|
+
("PreToolUse", "overcode hook-handler"),
|
|
28
29
|
("PostToolUse", "overcode hook-handler"),
|
|
30
|
+
("PostToolUseFailure", "overcode hook-handler"),
|
|
29
31
|
("Stop", "overcode hook-handler"),
|
|
32
|
+
("StopFailure", "overcode hook-handler"),
|
|
30
33
|
("PermissionRequest", "overcode hook-handler"),
|
|
31
34
|
("SessionEnd", "overcode hook-handler"),
|
|
32
35
|
]
|