overcode 0.3.6__tar.gz → 0.4.1__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.6/src/overcode.egg-info → overcode-0.4.1}/PKG-INFO +11 -1
- {overcode-0.3.6 → overcode-0.4.1}/README.md +10 -0
- {overcode-0.3.6 → overcode-0.4.1}/pyproject.toml +1 -1
- overcode-0.4.1/src/overcode/__init__.py +40 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/__init__.py +2 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/_shared.py +8 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/agent.py +49 -35
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/config.py +25 -0
- overcode-0.4.1/src/overcode/cli/doctor.py +189 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/hooks.py +16 -38
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/perms.py +16 -41
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/sister.py +69 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/split.py +65 -25
- overcode-0.4.1/src/overcode/cli/wrappers.py +111 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/config.py +43 -3
- overcode-0.4.1/src/overcode/doctor.py +475 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/history_reader.py +202 -76
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/hook_handler.py +98 -1
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/hook_status_detector.py +140 -12
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/launcher.py +297 -70
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/monitor_daemon.py +133 -4
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/monitor_daemon_core.py +5 -3
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/monitor_daemon_state.py +7 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/presence_logger.py +26 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/session_manager.py +18 -2
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/settings.py +27 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/sister_controller.py +3 -1
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/sister_poller.py +14 -6
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/standing_instructions.py +21 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/status_constants.py +3 -3
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/status_patterns.py +33 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/summarizer_component.py +29 -31
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/summary_columns.py +58 -26
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/summary_groups.py +1 -1
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tmux_utils.py +6 -10
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui.py +252 -232
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui.tcss +49 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_actions/session.py +39 -59
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_actions/view.py +64 -26
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_helpers.py +14 -1
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/__init__.py +7 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/agent_select_modal.py +9 -50
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/command_bar.py +6 -338
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/daemon_status_bar.py +7 -1
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/help_overlay.py +5 -1
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/instruction_history_modal.py +12 -46
- overcode-0.4.1/src/overcode/tui_widgets/modal_base.py +78 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/new_agent_defaults_modal.py +8 -44
- overcode-0.4.1/src/overcode/tui_widgets/new_agent_modal.py +443 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/session_summary.py +59 -12
- overcode-0.4.1/src/overcode/tui_widgets/sister_selection_modal.py +174 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/status_timeline.py +6 -1
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/summary_config_modal.py +117 -81
- overcode-0.4.1/src/overcode/tui_widgets/tmux_config_modal.py +111 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web_api.py +36 -4
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web_control_api.py +22 -27
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web_server.py +1 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web_server_runner.py +3 -2
- overcode-0.4.1/src/overcode/wrapper.py +392 -0
- {overcode-0.3.6 → overcode-0.4.1/src/overcode.egg-info}/PKG-INFO +11 -1
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode.egg-info/SOURCES.txt +7 -0
- overcode-0.3.6/src/overcode/__init__.py +0 -14
- overcode-0.3.6/src/overcode/tui_widgets/sister_selection_modal.py +0 -157
- {overcode-0.3.6 → overcode-0.4.1}/LICENSE +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/MANIFEST.in +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/setup.cfg +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/agent_scanner.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/bundled_skills.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/claude_config.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/claude_pid.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/__main__.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/budget.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/daemon.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/jobs.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/monitoring.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/cli/skills.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/daemon_claude_skill.md +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/daemon_logging.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/daemon_utils.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/data_export.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/dependency_check.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/duration.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/exceptions.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/follow_mode.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/implementations.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/interfaces.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/job_launcher.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/job_manager.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/logging_config.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/mocks.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/notifier.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/pid_utils.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/pricing.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/protocols.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/ssh_provisioner.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/status_detector.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/status_detector_factory.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/status_history.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/summarizer_client.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/supervisor_daemon.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/supervisor_daemon_core.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/supervisor_layout.sh +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/testing/__init__.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/testing/renderer.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/testing/tmux_driver.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/testing/tui_eye.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/testing/tui_eye_skill.md +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/time_context.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tmux_manager.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_actions/__init__.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_actions/daemon.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_actions/input.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_actions/navigation.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_logic.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_render.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/daemon_panel.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/fullscreen_preview.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/job_summary.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/preview_pane.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/tui_widgets/tui_log_panel.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/usage_monitor.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web/__init__.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web/templates/analytics.html +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web/templates/dashboard.html +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web_chartjs.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode/web_templates.py +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode.egg-info/dependency_links.txt +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode.egg-info/entry_points.txt +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode.egg-info/requires.txt +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/src/overcode.egg-info/top_level.txt +0 -0
- {overcode-0.3.6 → overcode-0.4.1}/tests/test_e2e_multi_agent_jokes.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: overcode
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: A supervisor for managing multiple Claude Code instances in tmux
|
|
5
5
|
Author: Mike Bond
|
|
6
6
|
Project-URL: Homepage, https://github.com/mkb23/overcode
|
|
@@ -119,6 +119,15 @@ An optional Claude-powered orchestrator that:
|
|
|
119
119
|
- Follows per-agent standing orders
|
|
120
120
|
- Tracks interventions and steering decisions
|
|
121
121
|
|
|
122
|
+
### Wrappers
|
|
123
|
+
Run agents in custom environments — containers, VMs, or any setup your project needs:
|
|
124
|
+
- **Devcontainer wrapper** - Launch agents inside Docker containers with a single flag
|
|
125
|
+
- **Auto-install** - Bundled wrappers install themselves on first use
|
|
126
|
+
- **Customisable** - Write your own wrapper script or modify the bundled ones
|
|
127
|
+
- Set per-agent (`--wrapper devcontainer`) or as default in config
|
|
128
|
+
|
|
129
|
+
See the [Wrappers Guide](docs/wrappers.md) for setup and customisation.
|
|
130
|
+
|
|
122
131
|
### Sister Integration
|
|
123
132
|
Aggregate agents from multiple machines into one dashboard:
|
|
124
133
|
- Configure sister machines in `~/.overcode/config.yaml`
|
|
@@ -153,6 +162,7 @@ See the [TUI Guide](docs/tui-guide.md) for all keyboard shortcuts.
|
|
|
153
162
|
- [CLI Reference](docs/cli-reference.md) - All commands and options
|
|
154
163
|
- [TUI Guide](docs/tui-guide.md) - Keyboard shortcuts and display modes
|
|
155
164
|
- [Configuration](docs/configuration.md) - Config file and environment variables
|
|
165
|
+
- [Wrappers](docs/wrappers.md) - Run agents in containers and custom environments
|
|
156
166
|
- [Advanced Features](docs/advanced-features.md) - Sleep mode, handover, remote monitoring
|
|
157
167
|
|
|
158
168
|
## License
|
|
@@ -77,6 +77,15 @@ An optional Claude-powered orchestrator that:
|
|
|
77
77
|
- Follows per-agent standing orders
|
|
78
78
|
- Tracks interventions and steering decisions
|
|
79
79
|
|
|
80
|
+
### Wrappers
|
|
81
|
+
Run agents in custom environments — containers, VMs, or any setup your project needs:
|
|
82
|
+
- **Devcontainer wrapper** - Launch agents inside Docker containers with a single flag
|
|
83
|
+
- **Auto-install** - Bundled wrappers install themselves on first use
|
|
84
|
+
- **Customisable** - Write your own wrapper script or modify the bundled ones
|
|
85
|
+
- Set per-agent (`--wrapper devcontainer`) or as default in config
|
|
86
|
+
|
|
87
|
+
See the [Wrappers Guide](docs/wrappers.md) for setup and customisation.
|
|
88
|
+
|
|
80
89
|
### Sister Integration
|
|
81
90
|
Aggregate agents from multiple machines into one dashboard:
|
|
82
91
|
- Configure sister machines in `~/.overcode/config.yaml`
|
|
@@ -111,6 +120,7 @@ See the [TUI Guide](docs/tui-guide.md) for all keyboard shortcuts.
|
|
|
111
120
|
- [CLI Reference](docs/cli-reference.md) - All commands and options
|
|
112
121
|
- [TUI Guide](docs/tui-guide.md) - Keyboard shortcuts and display modes
|
|
113
122
|
- [Configuration](docs/configuration.md) - Config file and environment variables
|
|
123
|
+
- [Wrappers](docs/wrappers.md) - Run agents in containers and custom environments
|
|
114
124
|
- [Advanced Features](docs/advanced-features.md) - Sleep mode, handover, remote monitoring
|
|
115
125
|
|
|
116
126
|
## License
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Overcode - A supervisor for managing multiple Claude Code instances.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
_toml = Path(__file__).resolve().parent.parent.parent / "pyproject.toml"
|
|
8
|
+
if _toml.is_file():
|
|
9
|
+
import tomllib
|
|
10
|
+
with open(_toml, "rb") as _f:
|
|
11
|
+
__version__ = tomllib.load(_f)["project"]["version"]
|
|
12
|
+
else:
|
|
13
|
+
from importlib.metadata import version as _version
|
|
14
|
+
__version__ = _version("overcode")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_dev_version_suffix() -> str:
|
|
18
|
+
"""Get ` (git-describe)` if running from an editable git install, else ''."""
|
|
19
|
+
try:
|
|
20
|
+
import subprocess
|
|
21
|
+
pkg_dir = Path(__file__).resolve().parent
|
|
22
|
+
result = subprocess.run(
|
|
23
|
+
["git", "describe", "--always", "--dirty"],
|
|
24
|
+
capture_output=True, text=True, cwd=pkg_dir, timeout=2,
|
|
25
|
+
)
|
|
26
|
+
if result.returncode == 0:
|
|
27
|
+
return f" ({result.stdout.strip()})"
|
|
28
|
+
except Exception:
|
|
29
|
+
pass
|
|
30
|
+
return ""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_full_version() -> str:
|
|
34
|
+
"""Full version string used at launch: `<version>[ (git-describe)]`.
|
|
35
|
+
|
|
36
|
+
Recorded on each Session so we can see which overcode build spawned
|
|
37
|
+
each agent — useful for diagnosing feature-regression questions like
|
|
38
|
+
"was this agent launched before the --settings hook injection landed?"
|
|
39
|
+
"""
|
|
40
|
+
return f"{__version__}{get_dev_version_suffix()}"
|
|
@@ -51,6 +51,14 @@ skills_app = typer.Typer(
|
|
|
51
51
|
)
|
|
52
52
|
app.add_typer(skills_app, name="skills")
|
|
53
53
|
|
|
54
|
+
# Wrappers subcommand group
|
|
55
|
+
wrappers_app = typer.Typer(
|
|
56
|
+
name="wrappers",
|
|
57
|
+
help="Manage agent launch wrapper scripts.",
|
|
58
|
+
no_args_is_help=True,
|
|
59
|
+
)
|
|
60
|
+
app.add_typer(wrappers_app, name="wrappers")
|
|
61
|
+
|
|
54
62
|
# Perms subcommand group
|
|
55
63
|
perms_app = typer.Typer(
|
|
56
64
|
name="perms",
|
|
@@ -216,6 +216,10 @@ def launch(
|
|
|
216
216
|
Optional[str],
|
|
217
217
|
typer.Option("--provider", "-P", help="API provider: 'web' (Claude.ai OAuth) or 'bedrock' (AWS Bedrock)"),
|
|
218
218
|
] = None,
|
|
219
|
+
wrapper: Annotated[
|
|
220
|
+
Optional[str],
|
|
221
|
+
typer.Option("--wrapper", "-w", help="Wrapper script (path or name from ~/.overcode/wrappers/)"),
|
|
222
|
+
] = None,
|
|
219
223
|
sister: Annotated[
|
|
220
224
|
Optional[str],
|
|
221
225
|
typer.Option("--sister", "-S", help="Launch on a remote sister machine (by name from config)"),
|
|
@@ -275,14 +279,21 @@ def launch(
|
|
|
275
279
|
oversight_policy, oversight_timeout_seconds = _parse_oversight_policy(on_stuck, oversight_timeout)
|
|
276
280
|
|
|
277
281
|
# Resolve provider: CLI flag > config default > "web"
|
|
282
|
+
from ..config import get_new_agent_defaults
|
|
283
|
+
agent_defaults = get_new_agent_defaults()
|
|
284
|
+
|
|
278
285
|
resolved_provider = provider
|
|
279
286
|
if resolved_provider is None:
|
|
280
|
-
|
|
281
|
-
resolved_provider = get_new_agent_defaults().get("provider", "web")
|
|
287
|
+
resolved_provider = agent_defaults.get("provider", "web")
|
|
282
288
|
if resolved_provider not in ("web", "bedrock"):
|
|
283
289
|
rprint(f"[red]Error: Invalid provider '{resolved_provider}'. Use: web, bedrock[/red]")
|
|
284
290
|
raise typer.Exit(code=1)
|
|
285
291
|
|
|
292
|
+
# Resolve wrapper: CLI flag > config default > None
|
|
293
|
+
resolved_wrapper = wrapper
|
|
294
|
+
if resolved_wrapper is None:
|
|
295
|
+
resolved_wrapper = agent_defaults.get("wrapper") or None
|
|
296
|
+
|
|
286
297
|
# Default to current directory if not specified
|
|
287
298
|
working_dir = directory if directory else os.getcwd()
|
|
288
299
|
|
|
@@ -302,6 +313,7 @@ def launch(
|
|
|
302
313
|
claude_agent=agent,
|
|
303
314
|
model=model,
|
|
304
315
|
provider=resolved_provider,
|
|
316
|
+
wrapper=resolved_wrapper,
|
|
305
317
|
)
|
|
306
318
|
|
|
307
319
|
if result:
|
|
@@ -318,6 +330,8 @@ def launch(
|
|
|
318
330
|
rprint(f" Agent: {agent}")
|
|
319
331
|
if teams:
|
|
320
332
|
rprint(" Agent teams: enabled")
|
|
333
|
+
if resolved_wrapper:
|
|
334
|
+
rprint(f" Wrapper: {resolved_wrapper}")
|
|
321
335
|
if resolved_provider != "web":
|
|
322
336
|
rprint(f" Provider: {resolved_provider}")
|
|
323
337
|
if budget is not None and budget > 0:
|
|
@@ -440,7 +454,7 @@ def list_agents(
|
|
|
440
454
|
get_status_symbol, get_git_diff_stats,
|
|
441
455
|
)
|
|
442
456
|
from ..monitor_daemon_state import get_monitor_daemon_state
|
|
443
|
-
from ..summary_columns import build_cli_context, render_summary_cells,
|
|
457
|
+
from ..summary_columns import build_cli_context, render_summary_cells, compute_column_widths, pad_and_join_cells, render_header_cells
|
|
444
458
|
from ..tui_logic import compute_tree_metadata, sort_sessions
|
|
445
459
|
from rich.console import Console
|
|
446
460
|
|
|
@@ -630,7 +644,12 @@ def list_agents(
|
|
|
630
644
|
activities.append(activity)
|
|
631
645
|
|
|
632
646
|
# Auto-align columns across all rows, then append activity
|
|
633
|
-
|
|
647
|
+
widths = compute_column_widths(all_cells)
|
|
648
|
+
col_filter = lambda col: detail in col.detail_levels
|
|
649
|
+
header = render_header_cells(column_filter=col_filter, column_widths=widths)
|
|
650
|
+
header.truncate(console.width, pad=False)
|
|
651
|
+
console.print(header, no_wrap=True)
|
|
652
|
+
aligned_lines = [pad_and_join_cells(row, widths) for row in all_cells]
|
|
634
653
|
for line, activity in zip(aligned_lines, activities):
|
|
635
654
|
line.append(" │ ", style="dim")
|
|
636
655
|
line.append(activity)
|
|
@@ -696,51 +715,42 @@ def kill(
|
|
|
696
715
|
@app.command()
|
|
697
716
|
def restart(
|
|
698
717
|
name: Annotated[str, typer.Argument(help="Name of agent to restart")],
|
|
718
|
+
fresh: Annotated[
|
|
719
|
+
bool,
|
|
720
|
+
typer.Option(
|
|
721
|
+
"--fresh",
|
|
722
|
+
help="Start a brand-new Claude session instead of resuming the prior conversation.",
|
|
723
|
+
),
|
|
724
|
+
] = False,
|
|
699
725
|
session: SessionOption = "agents",
|
|
700
726
|
):
|
|
701
727
|
"""Restart a running agent with the same configuration.
|
|
702
728
|
|
|
703
|
-
Gracefully exits Claude (Ctrl-C + /exit), then relaunches with the
|
|
704
|
-
|
|
729
|
+
Gracefully exits Claude (Ctrl-C + /exit), then relaunches with the same
|
|
730
|
+
full launch environment as a fresh `overcode launch` — hooks/permissions
|
|
731
|
+
via --settings, wrapper script, env prefix, model, persona, allowed tools,
|
|
732
|
+
and extra CLI args.
|
|
733
|
+
|
|
734
|
+
By default, resumes the agent's prior Claude session so conversation
|
|
735
|
+
history is preserved. Pass --fresh to start a brand-new session (useful
|
|
736
|
+
when the old session is stuck or MCP configs have changed).
|
|
705
737
|
"""
|
|
706
|
-
import
|
|
707
|
-
import time
|
|
708
|
-
from ..session_manager import SessionManager
|
|
709
|
-
from ..tmux_manager import TmuxManager
|
|
710
|
-
from ..tmux_utils import tmux_window_target, _build_tmux_cmd
|
|
738
|
+
from ..launcher import ClaudeLauncher
|
|
711
739
|
|
|
712
|
-
|
|
713
|
-
sess =
|
|
740
|
+
launcher = ClaudeLauncher(session)
|
|
741
|
+
sess = launcher.sessions.get_session_by_name(name)
|
|
714
742
|
if not sess:
|
|
715
743
|
rprint(f"[red]Error: Agent '{name}' not found[/red]")
|
|
716
744
|
raise typer.Exit(code=1)
|
|
717
745
|
|
|
718
|
-
|
|
719
|
-
if not tmux.window_exists(sess.tmux_window):
|
|
746
|
+
if not launcher.tmux.window_exists(sess.tmux_window):
|
|
720
747
|
rprint(f"[red]Error: Tmux window for '{name}' no longer exists[/red]")
|
|
721
748
|
raise typer.Exit(code=1)
|
|
722
749
|
|
|
723
|
-
# Build the claude command based on permissiveness mode
|
|
724
|
-
claude_command = os.environ.get("CLAUDE_COMMAND", "claude")
|
|
725
|
-
cmd_parts = [claude_command]
|
|
726
|
-
if sess.permissiveness_mode == "bypass":
|
|
727
|
-
cmd_parts.append("--dangerously-skip-permissions")
|
|
728
|
-
elif sess.permissiveness_mode == "permissive":
|
|
729
|
-
cmd_parts.extend(["--permission-mode", "dontAsk"])
|
|
730
|
-
cmd_str = " ".join(cmd_parts)
|
|
731
|
-
|
|
732
|
-
# Gracefully exit Claude: Ctrl-C + /exit
|
|
733
750
|
rprint(f"[dim]Stopping '{name}'...[/dim]")
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
time.sleep(3.0)
|
|
738
|
-
|
|
739
|
-
# Relaunch
|
|
740
|
-
if tmux.send_keys(sess.tmux_window, cmd_str, enter=True):
|
|
741
|
-
sm.update_stats(sess.id, current_task="Restarting...")
|
|
742
|
-
sm.update_session(sess.id, claude_session_ids=[])
|
|
743
|
-
rprint(f"[green]Restarted agent: {name}[/green]")
|
|
751
|
+
if launcher.restart(sess, fresh=fresh):
|
|
752
|
+
mode = "fresh" if fresh else "resumed"
|
|
753
|
+
rprint(f"[green]Restarted agent: {name} ({mode})[/green]")
|
|
744
754
|
else:
|
|
745
755
|
rprint(f"[red]Failed to restart agent: {name}[/red]")
|
|
746
756
|
raise typer.Exit(code=1)
|
|
@@ -1121,6 +1131,10 @@ def show(
|
|
|
1121
1131
|
print(f"{'Agent:':<{label_width + 1}} {sess.claude_agent}")
|
|
1122
1132
|
if sess.agent_teams:
|
|
1123
1133
|
print(f"{'Teams:':<{label_width + 1}} enabled")
|
|
1134
|
+
if sess.wrapper:
|
|
1135
|
+
print(f"{'Wrapper:':<{label_width + 1}} {sess.wrapper}")
|
|
1136
|
+
if sess.launcher_version:
|
|
1137
|
+
print(f"{'Launcher:':<{label_width + 1}} {sess.launcher_version}")
|
|
1124
1138
|
|
|
1125
1139
|
print()
|
|
1126
1140
|
|
|
@@ -57,6 +57,15 @@ CONFIG_TEMPLATE = """\
|
|
|
57
57
|
# - name: "desktop"
|
|
58
58
|
# url: "http://192.168.1.10:5337"
|
|
59
59
|
# api_key: "shared-secret"
|
|
60
|
+
|
|
61
|
+
# Custom emoticons for skills (overrides built-in defaults)
|
|
62
|
+
# skill_emoji:
|
|
63
|
+
# overcode: 🐙 # Default: 🐙
|
|
64
|
+
# delegating-to-agents: 👥 # Default: 👥
|
|
65
|
+
# claude-api: 🔌 # Default: 🔌
|
|
66
|
+
# simplify: ✨ # Default: ✨
|
|
67
|
+
# shirka: 🔬 # Example: research project organization
|
|
68
|
+
# # Add your custom skills here with any emoji
|
|
60
69
|
"""
|
|
61
70
|
|
|
62
71
|
|
|
@@ -159,3 +168,19 @@ def config_path():
|
|
|
159
168
|
"""Show the config file path."""
|
|
160
169
|
from ..config import CONFIG_PATH
|
|
161
170
|
print(CONFIG_PATH)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@config_app.command("tmux")
|
|
174
|
+
def config_tmux():
|
|
175
|
+
"""Change the tmux pane-toggle key.
|
|
176
|
+
|
|
177
|
+
Re-runs the toggle-key picker and (if overcode-tmux keybindings are
|
|
178
|
+
already installed) reinstalls them with the new key.
|
|
179
|
+
"""
|
|
180
|
+
from ..config import get_tmux_toggle_key
|
|
181
|
+
from .split import run_toggle_key_picker
|
|
182
|
+
|
|
183
|
+
current = get_tmux_toggle_key()
|
|
184
|
+
if current:
|
|
185
|
+
rprint(f"[dim]Current toggle key: [cyan]{current}[/cyan][/dim]")
|
|
186
|
+
run_toggle_key_picker(current_key=current)
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`overcode doctor` — diagnose agents with broken hook configuration (#435).
|
|
3
|
+
|
|
4
|
+
Identifies agents whose claude process was started without the --settings
|
|
5
|
+
injection (most commonly because the user manually relaunched claude inside
|
|
6
|
+
the tmux window, bypassing `overcode restart`). Optionally auto-relaunches
|
|
7
|
+
broken agents to reinject hooks.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Annotated
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
from rich import print as rprint
|
|
14
|
+
from rich.table import Table
|
|
15
|
+
|
|
16
|
+
from ._shared import app, SessionOption
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@app.command()
|
|
20
|
+
def doctor(
|
|
21
|
+
session: SessionOption = "agents",
|
|
22
|
+
fix: Annotated[
|
|
23
|
+
bool,
|
|
24
|
+
typer.Option("--fix", help="Restart agents whose claude process is missing --settings"),
|
|
25
|
+
] = False,
|
|
26
|
+
verbose: Annotated[
|
|
27
|
+
bool,
|
|
28
|
+
typer.Option("--verbose", "-v", help="Show full claude argv for each agent"),
|
|
29
|
+
] = False,
|
|
30
|
+
):
|
|
31
|
+
"""Diagnose which agents have broken hook configuration.
|
|
32
|
+
|
|
33
|
+
An agent only emits hook-based state changes (PostToolUse, Stop, etc.)
|
|
34
|
+
if its claude process was launched with `--settings`. This command
|
|
35
|
+
inspects each live agent's claude process and flags ones that are
|
|
36
|
+
missing the injection — typically because they were relaunched
|
|
37
|
+
manually in the tmux pane.
|
|
38
|
+
|
|
39
|
+
Use --fix to `overcode restart` broken agents, which re-injects --settings.
|
|
40
|
+
"""
|
|
41
|
+
from ..launcher import ClaudeLauncher
|
|
42
|
+
from ..doctor import (
|
|
43
|
+
inspect_agent,
|
|
44
|
+
snapshot_process_table,
|
|
45
|
+
SEVERITY_ERROR,
|
|
46
|
+
SEVERITY_WARNING,
|
|
47
|
+
VERDICT_OK,
|
|
48
|
+
VERDICT_MISSING_SETTINGS,
|
|
49
|
+
VERDICT_NO_CLAUDE,
|
|
50
|
+
VERDICT_WINDOW_GONE,
|
|
51
|
+
VERDICT_REMOTE,
|
|
52
|
+
)
|
|
53
|
+
from ..history_reader import get_session_stats
|
|
54
|
+
from ..monitor_daemon import is_monitor_daemon_running
|
|
55
|
+
|
|
56
|
+
launcher = ClaudeLauncher(session)
|
|
57
|
+
# detect_terminated=False — doctor inspects running state, doesn't mutate
|
|
58
|
+
sessions = [s for s in launcher.list_sessions(detect_terminated=False)
|
|
59
|
+
if s.status != "terminated"]
|
|
60
|
+
|
|
61
|
+
if not sessions:
|
|
62
|
+
rprint("[dim]No running agents in session '[bold]{}[/bold]'[/dim]".format(session))
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
# Single ps snapshot shared across all agents.
|
|
66
|
+
children, argv_by_pid = snapshot_process_table()
|
|
67
|
+
daemon_running = is_monitor_daemon_running(session)
|
|
68
|
+
|
|
69
|
+
results = []
|
|
70
|
+
for sess in sessions:
|
|
71
|
+
pane_pid = None
|
|
72
|
+
live_stats = None
|
|
73
|
+
if not getattr(sess, "is_remote", False):
|
|
74
|
+
pane_pid = launcher.tmux.get_pane_pid(sess.tmux_window)
|
|
75
|
+
try:
|
|
76
|
+
live_stats = get_session_stats(sess)
|
|
77
|
+
except Exception:
|
|
78
|
+
live_stats = None
|
|
79
|
+
results.append(inspect_agent(
|
|
80
|
+
sess, pane_pid, children, argv_by_pid,
|
|
81
|
+
live_stats=live_stats,
|
|
82
|
+
daemon_running=daemon_running,
|
|
83
|
+
))
|
|
84
|
+
|
|
85
|
+
# Print table
|
|
86
|
+
table = Table(title=f"Agent hook health — session '{session}'")
|
|
87
|
+
table.add_column("Agent", style="bold")
|
|
88
|
+
table.add_column("Verdict")
|
|
89
|
+
table.add_column("Launcher")
|
|
90
|
+
table.add_column("PID")
|
|
91
|
+
table.add_column("Issues")
|
|
92
|
+
table.add_column("Details")
|
|
93
|
+
|
|
94
|
+
verdict_style = {
|
|
95
|
+
VERDICT_OK: "[green]✓ ok[/green]",
|
|
96
|
+
VERDICT_MISSING_SETTINGS: "[red]✗ no --settings[/red]",
|
|
97
|
+
VERDICT_NO_CLAUDE: "[yellow]? no claude[/yellow]",
|
|
98
|
+
VERDICT_WINDOW_GONE: "[dim]window gone[/dim]",
|
|
99
|
+
VERDICT_REMOTE: "[dim]remote[/dim]",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def _issues_cell(findings):
|
|
103
|
+
if not findings:
|
|
104
|
+
return "[dim]—[/dim]"
|
|
105
|
+
errors = sum(1 for f in findings if f.severity == SEVERITY_ERROR)
|
|
106
|
+
warnings = sum(1 for f in findings if f.severity == SEVERITY_WARNING)
|
|
107
|
+
parts = []
|
|
108
|
+
if errors:
|
|
109
|
+
parts.append(f"[red]{errors}✗[/red]")
|
|
110
|
+
if warnings:
|
|
111
|
+
parts.append(f"[yellow]{warnings}⚠[/yellow]")
|
|
112
|
+
return " ".join(parts)
|
|
113
|
+
|
|
114
|
+
for r in results:
|
|
115
|
+
table.add_row(
|
|
116
|
+
r.name,
|
|
117
|
+
verdict_style.get(r.verdict, r.verdict),
|
|
118
|
+
r.launcher_version or "[dim]—[/dim]",
|
|
119
|
+
str(r.claude_pid) if r.claude_pid else "[dim]—[/dim]",
|
|
120
|
+
_issues_cell(r.data_findings),
|
|
121
|
+
r.details,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
rprint(table)
|
|
125
|
+
|
|
126
|
+
# Detail findings below the table
|
|
127
|
+
flagged = [r for r in results if r.data_findings]
|
|
128
|
+
if flagged:
|
|
129
|
+
rprint()
|
|
130
|
+
rprint("[bold]Data-quality findings:[/bold]")
|
|
131
|
+
for r in flagged:
|
|
132
|
+
rprint(f" [bold]{r.name}[/bold]")
|
|
133
|
+
for f in r.data_findings:
|
|
134
|
+
badge = "[red]✗[/red]" if f.severity == SEVERITY_ERROR else "[yellow]⚠[/yellow]"
|
|
135
|
+
rprint(f" {badge} [dim]{f.code}[/dim]: {f.message}")
|
|
136
|
+
|
|
137
|
+
if verbose:
|
|
138
|
+
rprint()
|
|
139
|
+
for r in results:
|
|
140
|
+
if r.claude_argv:
|
|
141
|
+
rprint(f"[bold]{r.name}[/bold] argv:")
|
|
142
|
+
rprint(f" [dim]{r.claude_argv}[/dim]")
|
|
143
|
+
|
|
144
|
+
broken = [r for r in results if r.verdict == VERDICT_MISSING_SETTINGS]
|
|
145
|
+
ok_count = sum(1 for r in results if r.verdict == VERDICT_OK)
|
|
146
|
+
findings_count = sum(len(r.data_findings) for r in results)
|
|
147
|
+
|
|
148
|
+
rprint()
|
|
149
|
+
if broken:
|
|
150
|
+
rprint(f"[red]✗[/red] {len(broken)} broken, [green]{ok_count}[/green] ok, "
|
|
151
|
+
f"{len(results) - len(broken) - ok_count} other")
|
|
152
|
+
if not fix:
|
|
153
|
+
names = " ".join(r.name for r in broken)
|
|
154
|
+
rprint(f"[dim]Fix with: overcode restart {names}[/dim]")
|
|
155
|
+
rprint("[dim]Or: overcode doctor --fix[/dim]")
|
|
156
|
+
else:
|
|
157
|
+
rprint(f"[green]✓[/green] all {ok_count} agents have hooks injected")
|
|
158
|
+
|
|
159
|
+
if findings_count:
|
|
160
|
+
rprint(f"[yellow]⚠[/yellow] {findings_count} data-quality "
|
|
161
|
+
f"finding{'s' if findings_count != 1 else ''} across "
|
|
162
|
+
f"{len(flagged)} agent{'s' if len(flagged) != 1 else ''}")
|
|
163
|
+
|
|
164
|
+
# Global (not per-agent): bundled skills drifted from what's installed.
|
|
165
|
+
# Affects every agent, so it's surfaced once rather than duplicated per row.
|
|
166
|
+
try:
|
|
167
|
+
from ..bundled_skills import any_skills_stale
|
|
168
|
+
if any_skills_stale():
|
|
169
|
+
rprint("[yellow]⚠[/yellow] installed skills differ from bundled "
|
|
170
|
+
"versions — run [bold]overcode skills install[/bold]")
|
|
171
|
+
except Exception:
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
if fix and broken:
|
|
175
|
+
rprint()
|
|
176
|
+
rprint("[bold]Restarting broken agents...[/bold]")
|
|
177
|
+
from ..session_manager import SessionManager
|
|
178
|
+
sm = SessionManager()
|
|
179
|
+
for r in broken:
|
|
180
|
+
sess = sm.get_session_by_name(r.name)
|
|
181
|
+
if sess is None:
|
|
182
|
+
rprint(f" [yellow]skip {r.name} — session vanished[/yellow]")
|
|
183
|
+
continue
|
|
184
|
+
# fresh=False → resume the existing Claude session so history is preserved;
|
|
185
|
+
# the new shell line rebuilt by the launcher will include --settings.
|
|
186
|
+
if launcher.restart(sess, fresh=False):
|
|
187
|
+
rprint(f" [green]✓[/green] restarted {r.name}")
|
|
188
|
+
else:
|
|
189
|
+
rprint(f" [red]✗[/red] failed to restart {r.name}")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Hooks commands: install, uninstall, status.
|
|
2
|
+
Hooks commands: install (deprecated), uninstall, status.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from typing import Annotated
|
|
@@ -10,51 +10,27 @@ from rich import print as rprint
|
|
|
10
10
|
from ._shared import hooks_app
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
DEPRECATION_NOTE = (
|
|
14
|
+
"[yellow]Note:[/yellow] Manual hook installation is deprecated.\n"
|
|
15
|
+
" Hooks are now injected automatically when agents are launched via 'overcode launch'.\n"
|
|
16
|
+
" Use 'overcode hooks uninstall' to remove legacy hooks from your settings."
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@hooks_app.command("install", deprecated=True)
|
|
14
21
|
def hooks_install(
|
|
15
22
|
project: Annotated[
|
|
16
23
|
bool,
|
|
17
24
|
typer.Option("--project", "-p", help="Install to project-level .claude/settings.json instead of user-level"),
|
|
18
25
|
] = False,
|
|
19
26
|
):
|
|
20
|
-
"""Install
|
|
27
|
+
"""[Deprecated] Install overcode hooks into Claude Code settings.
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
Hooks are now injected automatically at launch time via --settings.
|
|
30
|
+
This command is no longer needed for overcode-launched agents.
|
|
24
31
|
"""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if project:
|
|
29
|
-
editor = ClaudeConfigEditor.project_level()
|
|
30
|
-
level = "project"
|
|
31
|
-
else:
|
|
32
|
-
editor = ClaudeConfigEditor.user_level()
|
|
33
|
-
level = "user"
|
|
34
|
-
|
|
35
|
-
try:
|
|
36
|
-
editor.load()
|
|
37
|
-
except ValueError as e:
|
|
38
|
-
rprint(f"[red]Error:[/red] {e}")
|
|
39
|
-
raise typer.Exit(1)
|
|
40
|
-
|
|
41
|
-
# Install all overcode hooks (idempotent)
|
|
42
|
-
installed = 0
|
|
43
|
-
already = 0
|
|
44
|
-
for event, command in OVERCODE_HOOKS:
|
|
45
|
-
if editor.add_hook(event, command):
|
|
46
|
-
installed += 1
|
|
47
|
-
else:
|
|
48
|
-
already += 1
|
|
49
|
-
|
|
50
|
-
if installed > 0:
|
|
51
|
-
events = ", ".join(event for event, _ in OVERCODE_HOOKS)
|
|
52
|
-
rprint(f"[green]\u2713[/green] Installed {installed} hook(s) in {level} settings")
|
|
53
|
-
rprint(f" [dim]{editor.path}[/dim]")
|
|
54
|
-
rprint(f"\n Events: {events}")
|
|
55
|
-
rprint(" All hooks run 'overcode hook-handler' (reads event from stdin).")
|
|
56
|
-
elif already == len(OVERCODE_HOOKS):
|
|
57
|
-
rprint(f"[green]\u2713[/green] All {already} hooks already installed in {level} settings")
|
|
32
|
+
rprint(DEPRECATION_NOTE)
|
|
33
|
+
raise typer.Exit(0)
|
|
58
34
|
|
|
59
35
|
|
|
60
36
|
@hooks_app.command("uninstall")
|
|
@@ -98,6 +74,8 @@ def hooks_status():
|
|
|
98
74
|
from ..claude_config import ClaudeConfigEditor
|
|
99
75
|
from ..hook_handler import OVERCODE_HOOKS
|
|
100
76
|
|
|
77
|
+
rprint(f"\n{DEPRECATION_NOTE}\n")
|
|
78
|
+
|
|
101
79
|
for level_name, editor in [
|
|
102
80
|
("User-level", ClaudeConfigEditor.user_level()),
|
|
103
81
|
("Project-level", ClaudeConfigEditor.project_level()),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Permissions commands: install, uninstall, status.
|
|
2
|
+
Permissions commands: install (deprecated), uninstall, status.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from typing import Annotated
|
|
@@ -25,7 +25,14 @@ OVERCODE_PUNCHY_PERMS = [
|
|
|
25
25
|
]
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
DEPRECATION_NOTE = (
|
|
29
|
+
"[yellow]Note:[/yellow] Manual permission installation is deprecated.\n"
|
|
30
|
+
" Permissions are now injected automatically when agents are launched via 'overcode launch'.\n"
|
|
31
|
+
" Use 'overcode perms uninstall' to remove legacy permissions from your settings."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@perms_app.command("install", deprecated=True)
|
|
29
36
|
def perms_install(
|
|
30
37
|
project: Annotated[
|
|
31
38
|
bool,
|
|
@@ -36,47 +43,13 @@ def perms_install(
|
|
|
36
43
|
typer.Option("--all", help="Include punchy permissions (launch, send, instruct)"),
|
|
37
44
|
] = False,
|
|
38
45
|
):
|
|
39
|
-
"""Install overcode
|
|
40
|
-
|
|
41
|
-
By default installs safe (read-only) permissions. Use --all to also
|
|
42
|
-
include punchy permissions that can spawn or control agents.
|
|
46
|
+
"""[Deprecated] Install overcode permissions into Claude Code settings.
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
Permissions are now injected automatically at launch time via --settings.
|
|
49
|
+
This command is no longer needed for overcode-launched agents.
|
|
46
50
|
"""
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if project:
|
|
50
|
-
editor = ClaudeConfigEditor.project_level()
|
|
51
|
-
level = "project"
|
|
52
|
-
else:
|
|
53
|
-
editor = ClaudeConfigEditor.user_level()
|
|
54
|
-
level = "user"
|
|
55
|
-
|
|
56
|
-
try:
|
|
57
|
-
editor.load()
|
|
58
|
-
except ValueError as e:
|
|
59
|
-
rprint(f"[red]Error:[/red] {e}")
|
|
60
|
-
raise typer.Exit(1)
|
|
61
|
-
|
|
62
|
-
perms = OVERCODE_SAFE_PERMS + (OVERCODE_PUNCHY_PERMS if all_perms else [])
|
|
63
|
-
|
|
64
|
-
installed = 0
|
|
65
|
-
already = 0
|
|
66
|
-
for perm in perms:
|
|
67
|
-
if editor.add_permission(perm):
|
|
68
|
-
installed += 1
|
|
69
|
-
else:
|
|
70
|
-
already += 1
|
|
71
|
-
|
|
72
|
-
if installed > 0:
|
|
73
|
-
tier = "safe + punchy" if all_perms else "safe"
|
|
74
|
-
rprint(f"[green]\u2713[/green] Installed {installed} permission(s) in {level} settings ({tier})")
|
|
75
|
-
rprint(f" [dim]{editor.path}[/dim]")
|
|
76
|
-
for perm in perms:
|
|
77
|
-
rprint(f" {perm}")
|
|
78
|
-
elif already == len(perms):
|
|
79
|
-
rprint(f"[green]\u2713[/green] All {already} permissions already installed in {level} settings")
|
|
51
|
+
rprint(DEPRECATION_NOTE)
|
|
52
|
+
raise typer.Exit(0)
|
|
80
53
|
|
|
81
54
|
|
|
82
55
|
@perms_app.command("uninstall")
|
|
@@ -119,6 +92,8 @@ def perms_status():
|
|
|
119
92
|
"""Show which overcode permissions are installed."""
|
|
120
93
|
from ..claude_config import ClaudeConfigEditor
|
|
121
94
|
|
|
95
|
+
rprint(f"\n{DEPRECATION_NOTE}\n")
|
|
96
|
+
|
|
122
97
|
all_perms = OVERCODE_SAFE_PERMS + OVERCODE_PUNCHY_PERMS
|
|
123
98
|
|
|
124
99
|
for level_name, editor in [
|