agent-toggle 0.11.4__tar.gz → 0.12.0__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.
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/PKG-INFO +15 -15
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/README.md +13 -14
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/__init__.py +1 -1
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/cli.py +1 -1
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/config.py +4 -4
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/cost.py +1 -1
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/harnesses.py +8 -3
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/locales/zh_tw_config.py +1 -1
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/mechanisms.py +5 -4
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/ui/config_menu.py +2 -2
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle.egg-info/PKG-INFO +15 -15
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle.egg-info/requires.txt +1 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/pyproject.toml +3 -1
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_config.py +2 -2
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_config_menu.py +3 -3
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_cost.py +10 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_harnesses.py +6 -1
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/LICENSE +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/__main__.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/backends/__init__.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/backends/flag_json.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/backends/mcp_json.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/backends/mcp_toml.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/backends/plugin_cli.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/companions.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/doctor.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/fs.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/help.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/i18n.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/locales/__init__.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/locales/zh_tw_cli.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/locales/zh_tw_common.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/locales/zh_tw_picker.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/ops.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/output.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/profiles.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/settings.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/shims/claude.md.tmpl +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/shims/generic.md.tmpl +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/spinner.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/store.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/toml_check.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/ui/__init__.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/ui/logo.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/ui/menu.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/ui/model.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/ui/picker.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/ui/theme.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/undo.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/update_check.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle/update_prompt.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle.egg-info/SOURCES.txt +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle.egg-info/dependency_links.txt +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle.egg-info/entry_points.txt +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/agent_toggle.egg-info/top_level.txt +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/setup.cfg +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_alias.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_all_type.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_backends.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_cli.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_cli_surface.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_color.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_companions.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_completions.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_conformance.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_containment.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_crash.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_doctor.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_encoding.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_fs.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_help.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_i18n.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_install.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_logo.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_mechanisms.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_menu.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_mods.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_picker.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_platform.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_profiles.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_project.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_safety.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_same_name.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_secret_audit.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_settings.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_store.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_theme.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_undo.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_update_check.py +0 -0
- {agent_toggle-0.11.4 → agent_toggle-0.12.0}/tests/test_update_prompt.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-toggle
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Temporarily disable / re-enable AI-agent skills, agents, commands, rules, plugins and MCP servers across harnesses (Claude Code, Codex, Grok, OpenCode, OpenClaw, Copilot, Vibe, Devin, Antigravity)
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/weskao/agent-toggle
|
|
@@ -24,6 +24,7 @@ Classifier: Topic :: Utilities
|
|
|
24
24
|
Requires-Python: >=3.10
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
|
+
Requires-Dist: telegram-kit<0.3,>=0.2.2
|
|
27
28
|
Provides-Extra: windows
|
|
28
29
|
Requires-Dist: windows-curses; sys_platform == "win32" and extra == "windows"
|
|
29
30
|
Provides-Extra: telegram
|
|
@@ -142,21 +143,20 @@ exits `1`. A shim written by a version before the marker counts as foreign;
|
|
|
142
143
|
delete it and re-run. `--dry-run` shows the same plan, refusals included. The
|
|
143
144
|
tool itself stays in one place.
|
|
144
145
|
|
|
145
|
-
**Optional: Telegram alerts for CI** (for maintainers of a fork or clone).
|
|
146
|
-
|
|
147
|
-
(itself stdlib-only),
|
|
146
|
+
**Optional: Telegram alerts for CI** (for maintainers of a fork or clone). The
|
|
147
|
+
Telegram support comes from [telegram-kit](https://pypi.org/project/telegram-kit/)
|
|
148
|
+
(itself stdlib-only), which every install includes, so a reinstall or upgrade keeps
|
|
149
|
+
your settings. Run the setup once; see [CI notifications](#ci-notifications):
|
|
148
150
|
|
|
149
151
|
```sh
|
|
150
|
-
uv tool install "agent-toggle[telegram]" # or: pipx install "agent-toggle[telegram]"
|
|
151
|
-
pip install -e ".[telegram]" # from a checkout
|
|
152
152
|
agent-toggle config # settings menu: bot token + chat id live under Notifications
|
|
153
153
|
agent-toggle config sync-ci # set the two GitHub repository secrets
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
The old `agent-toggle[telegram]` extra still resolves and is now a no-op. If
|
|
157
|
+
telegram-kit is missing from a broken install, `config test` and `config sync-ci`
|
|
158
|
+
exit `4`, bare `config` still opens, and the Telegram rows read
|
|
159
|
+
`telegram-kit missing: reinstall agent-toggle`.
|
|
160
160
|
|
|
161
161
|
**Optional: the Claude Code pane mod** (the picker as a pane inside Claude Code, claude harness
|
|
162
162
|
only). It is not part of the PyPI package; with `agent-toggle` already on `PATH` from one of the
|
|
@@ -204,7 +204,7 @@ agent-toggle <command> [args] # or: python3 agent_toggle.py <command> [
|
|
|
204
204
|
| `undo` | reverse the last logged batch (`--dry-run` shows the plan) |
|
|
205
205
|
| `profile save\|apply\|diff\|list\|delete\|rename` | named sets of live items; see [Profiles](#profiles) |
|
|
206
206
|
| `config` | settings menu (curses, else a numbered list); `config --json` lists every setting and the package version; see [Settings & config menu](#settings--config-menu) |
|
|
207
|
-
| `config test\|sync-ci` | send one Telegram test message / set the GitHub CI secrets;
|
|
207
|
+
| `config test\|sync-ci` | send one Telegram test message / set the GitHub CI secrets; see [CI notifications](#ci-notifications) |
|
|
208
208
|
| `help [command]` | styled help; `help ui` = `--help ui` = `ui --help`; see [Help](#help) |
|
|
209
209
|
| `doctor` | check each harness layout and `state.json` against disk; exit `1` only on an `error` row; on a terminal, asks y/n per fix it can run itself |
|
|
210
210
|
| `migrate` | import an older `~/.claude-toggle/` state, and move legacy `<home>/<dir>-disabled/` park dirs into `~/.agent-toggle/parked/user/` (see [Upgrading the park layout](#upgrading-the-park-layout)); safe to re-run |
|
|
@@ -463,8 +463,8 @@ invalid value in either is ignored with one warning on stderr.
|
|
|
463
463
|
harness is switched off (with one warning on stderr);
|
|
464
464
|
`disable` / `enable --project` without `--harness` still default to `claude`.
|
|
465
465
|
- `language` translates the config menu, help, update prompt and picker chrome; command output stays English.
|
|
466
|
-
-
|
|
467
|
-
|
|
466
|
+
- telegram-kit is a regular dependency now, so reinstalling keeps the Telegram settings working;
|
|
467
|
+
`agent-toggle[telegram]` still resolves.
|
|
468
468
|
|
|
469
469
|
## Update check
|
|
470
470
|
|
|
@@ -523,7 +523,7 @@ logo, centred, when the window is tall enough to fit the whole menu beside it; t
|
|
|
523
523
|
| copilot | `~/.copilot` | ✓ | ✓ | — | — | — | ✓ `mcp-config.json` |
|
|
524
524
|
| vibe | `~/.vibe` | ✓ | — | — | — | — | — |
|
|
525
525
|
| devin | `~/.devin` | — | — | — | — | — | — |
|
|
526
|
-
| agy | `~/.
|
|
526
|
+
| agy | `~/.gemini/config` | ✓ | — | — | — | — | ✓ `mcp_config.json` |
|
|
527
527
|
|
|
528
528
|
Per-harness locations, mechanisms and the harness versions this was checked
|
|
529
529
|
against are in [docs/harnesses.md](docs/harnesses.md).
|
|
@@ -1041,7 +1041,7 @@ agent-toggle config sync-ci # set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID on
|
|
|
1041
1041
|
|
|
1042
1042
|
In the [settings menu](#settings--config-menu) an inline field commits on `Enter`, cancels on
|
|
1043
1043
|
`Esc`, and clears on `-` then `Enter`; the Tools group also has Send test message and Sync CI
|
|
1044
|
-
secrets (the same as `config test` / `config sync-ci
|
|
1044
|
+
secrets (the same as `config test` / `config sync-ci`). The bot token
|
|
1045
1045
|
is kept only in the OS credential store (macOS Keychain, Linux Secret Service, Windows DPAPI)
|
|
1046
1046
|
through telegram-kit, never in a file or on a command line, and is shown masked. With no
|
|
1047
1047
|
credential store it refuses to store the token; set `TG_BOT_TOKEN` in the environment instead
|
|
@@ -110,21 +110,20 @@ exits `1`. A shim written by a version before the marker counts as foreign;
|
|
|
110
110
|
delete it and re-run. `--dry-run` shows the same plan, refusals included. The
|
|
111
111
|
tool itself stays in one place.
|
|
112
112
|
|
|
113
|
-
**Optional: Telegram alerts for CI** (for maintainers of a fork or clone).
|
|
114
|
-
|
|
115
|
-
(itself stdlib-only),
|
|
113
|
+
**Optional: Telegram alerts for CI** (for maintainers of a fork or clone). The
|
|
114
|
+
Telegram support comes from [telegram-kit](https://pypi.org/project/telegram-kit/)
|
|
115
|
+
(itself stdlib-only), which every install includes, so a reinstall or upgrade keeps
|
|
116
|
+
your settings. Run the setup once; see [CI notifications](#ci-notifications):
|
|
116
117
|
|
|
117
118
|
```sh
|
|
118
|
-
uv tool install "agent-toggle[telegram]" # or: pipx install "agent-toggle[telegram]"
|
|
119
|
-
pip install -e ".[telegram]" # from a checkout
|
|
120
119
|
agent-toggle config # settings menu: bot token + chat id live under Notifications
|
|
121
120
|
agent-toggle config sync-ci # set the two GitHub repository secrets
|
|
122
121
|
```
|
|
123
122
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
The old `agent-toggle[telegram]` extra still resolves and is now a no-op. If
|
|
124
|
+
telegram-kit is missing from a broken install, `config test` and `config sync-ci`
|
|
125
|
+
exit `4`, bare `config` still opens, and the Telegram rows read
|
|
126
|
+
`telegram-kit missing: reinstall agent-toggle`.
|
|
128
127
|
|
|
129
128
|
**Optional: the Claude Code pane mod** (the picker as a pane inside Claude Code, claude harness
|
|
130
129
|
only). It is not part of the PyPI package; with `agent-toggle` already on `PATH` from one of the
|
|
@@ -172,7 +171,7 @@ agent-toggle <command> [args] # or: python3 agent_toggle.py <command> [
|
|
|
172
171
|
| `undo` | reverse the last logged batch (`--dry-run` shows the plan) |
|
|
173
172
|
| `profile save\|apply\|diff\|list\|delete\|rename` | named sets of live items; see [Profiles](#profiles) |
|
|
174
173
|
| `config` | settings menu (curses, else a numbered list); `config --json` lists every setting and the package version; see [Settings & config menu](#settings--config-menu) |
|
|
175
|
-
| `config test\|sync-ci` | send one Telegram test message / set the GitHub CI secrets;
|
|
174
|
+
| `config test\|sync-ci` | send one Telegram test message / set the GitHub CI secrets; see [CI notifications](#ci-notifications) |
|
|
176
175
|
| `help [command]` | styled help; `help ui` = `--help ui` = `ui --help`; see [Help](#help) |
|
|
177
176
|
| `doctor` | check each harness layout and `state.json` against disk; exit `1` only on an `error` row; on a terminal, asks y/n per fix it can run itself |
|
|
178
177
|
| `migrate` | import an older `~/.claude-toggle/` state, and move legacy `<home>/<dir>-disabled/` park dirs into `~/.agent-toggle/parked/user/` (see [Upgrading the park layout](#upgrading-the-park-layout)); safe to re-run |
|
|
@@ -431,8 +430,8 @@ invalid value in either is ignored with one warning on stderr.
|
|
|
431
430
|
harness is switched off (with one warning on stderr);
|
|
432
431
|
`disable` / `enable --project` without `--harness` still default to `claude`.
|
|
433
432
|
- `language` translates the config menu, help, update prompt and picker chrome; command output stays English.
|
|
434
|
-
-
|
|
435
|
-
|
|
433
|
+
- telegram-kit is a regular dependency now, so reinstalling keeps the Telegram settings working;
|
|
434
|
+
`agent-toggle[telegram]` still resolves.
|
|
436
435
|
|
|
437
436
|
## Update check
|
|
438
437
|
|
|
@@ -491,7 +490,7 @@ logo, centred, when the window is tall enough to fit the whole menu beside it; t
|
|
|
491
490
|
| copilot | `~/.copilot` | ✓ | ✓ | — | — | — | ✓ `mcp-config.json` |
|
|
492
491
|
| vibe | `~/.vibe` | ✓ | — | — | — | — | — |
|
|
493
492
|
| devin | `~/.devin` | — | — | — | — | — | — |
|
|
494
|
-
| agy | `~/.
|
|
493
|
+
| agy | `~/.gemini/config` | ✓ | — | — | — | — | ✓ `mcp_config.json` |
|
|
495
494
|
|
|
496
495
|
Per-harness locations, mechanisms and the harness versions this was checked
|
|
497
496
|
against are in [docs/harnesses.md](docs/harnesses.md).
|
|
@@ -1009,7 +1008,7 @@ agent-toggle config sync-ci # set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID on
|
|
|
1009
1008
|
|
|
1010
1009
|
In the [settings menu](#settings--config-menu) an inline field commits on `Enter`, cancels on
|
|
1011
1010
|
`Esc`, and clears on `-` then `Enter`; the Tools group also has Send test message and Sync CI
|
|
1012
|
-
secrets (the same as `config test` / `config sync-ci
|
|
1011
|
+
secrets (the same as `config test` / `config sync-ci`). The bot token
|
|
1013
1012
|
is kept only in the OS credential store (macOS Keychain, Linux Secret Service, Windows DPAPI)
|
|
1014
1013
|
through telegram-kit, never in a file or on a command line, and is shown masked. With no
|
|
1015
1014
|
credential store it refuses to store the token; set `TG_BOT_TOKEN` in the environment instead
|
|
@@ -696,7 +696,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
696
696
|
sub.add_parser("update", parents=[common],
|
|
697
697
|
help="check for a newer release; show the commands that update everything")
|
|
698
698
|
cf = sub.add_parser("config", parents=[common],
|
|
699
|
-
help="Telegram settings for the CI failure alerts
|
|
699
|
+
help="Telegram settings for the CI failure alerts")
|
|
700
700
|
cf.add_argument("action", nargs="?", choices=("test", "sync-ci"),
|
|
701
701
|
help="test: send one message | sync-ci: set the GitHub repo secrets")
|
|
702
702
|
cf.add_argument("--repo", metavar="OWNER/REPO", help="sync-ci: repository (default: this one)")
|
|
@@ -5,8 +5,8 @@ numbered list otherwise; `--json` prints every setting). Same shape as aicp's `-
|
|
|
5
5
|
the bot token lives only in the OS credential store (Keychain / Secret Service / DPAPI,
|
|
6
6
|
through telegram-kit, never in a file or an argument vector); the chat id and every other
|
|
7
7
|
setting are ordinary configuration in ~/.agent-toggle/config.json (`settings`).
|
|
8
|
-
telegram-kit is
|
|
9
|
-
|
|
8
|
+
telegram-kit is a dependency, imported only here: `test` and `sync-ci` need it, and the menu
|
|
9
|
+
still works if a broken install lacks it (its Telegram rows say so).
|
|
10
10
|
"""
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
@@ -20,7 +20,7 @@ SERVICE = "agent-toggle"
|
|
|
20
20
|
CHAT_KEY = "telegram_chat_id"
|
|
21
21
|
SECRETS = ("TELEGRAM_BOT_TOKEN", "TELEGRAM_CHAT_ID")
|
|
22
22
|
CHAT_ID_RE = settings.CHAT_ID_RE
|
|
23
|
-
INSTALL_HINT = "
|
|
23
|
+
INSTALL_HINT = "reinstall agent-toggle: uv tool install --reinstall agent-toggle"
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
config_file = settings.config_file
|
|
@@ -43,7 +43,7 @@ def kit():
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
def optional_kit():
|
|
46
|
-
"""telegram-kit, or None
|
|
46
|
+
"""telegram-kit, or None when it is missing (the menu degrades instead of exiting 4)."""
|
|
47
47
|
try:
|
|
48
48
|
return kit()
|
|
49
49
|
except CliError:
|
|
@@ -312,7 +312,7 @@ def inventory(state: dict, table: dict, warn: Callable[[str], None] = lambda m:
|
|
|
312
312
|
else (0, None, "flag entry; size unknown"))
|
|
313
313
|
elif type_ == "mcp":
|
|
314
314
|
counts = mcp_tool_counts(h)
|
|
315
|
-
for name in live_mcp(h.home, h.backend):
|
|
315
|
+
for name in live_mcp(h.home, h.backend, h.mcp and h.mcp.file):
|
|
316
316
|
add(hname, type_, name, True, mcp_estimate(hname, counts.get(name)))
|
|
317
317
|
|
|
318
318
|
listed: list[str] = [] # canonical `name@marketplace` ids, for the parked rows
|
|
@@ -173,9 +173,14 @@ def build(home: Path) -> dict[str, Harness]:
|
|
|
173
173
|
# explicit not-applicable row: no dirs, no mechanisms, so every type
|
|
174
174
|
# exits 4 through the ops dispatch.
|
|
175
175
|
Harness("devin", home / ".devin", dirs={}, mechanisms={}),
|
|
176
|
-
# DESIGN s11 q1
|
|
177
|
-
#
|
|
178
|
-
Harness("agy", home / ".
|
|
176
|
+
# DESIGN s11 q1 (answered on 1.3.3): global root `~/.gemini/config/` holds
|
|
177
|
+
# `skills/<name>/SKILL.md` and strict-JSON `mcp_config.json -> mcpServers`.
|
|
178
|
+
Harness("agy", home / ".gemini" / "config",
|
|
179
|
+
dirs={"skill": ("skills",)},
|
|
180
|
+
mechanisms={"skill": "move", "mcp": "remove_backup"},
|
|
181
|
+
mcp=McpSpec("json", home / ".gemini" / "config" / "mcp_config.json",
|
|
182
|
+
("mcpServers",)),
|
|
183
|
+
editable=frozenset({"mcp_config.json"}), verified="1.3.3"),
|
|
179
184
|
)}
|
|
180
185
|
|
|
181
186
|
|
|
@@ -54,7 +54,7 @@ CATALOG: dict[str, str] = {
|
|
|
54
54
|
"config.language": "語言 / Language",
|
|
55
55
|
"config.logo": "標誌",
|
|
56
56
|
"config.more": "還有 %s 項",
|
|
57
|
-
"config.needs_extra": "
|
|
57
|
+
"config.needs_extra": "缺少 telegram-kit:請重新安裝 agent-toggle",
|
|
58
58
|
"config.no_hidden": "此終端機無法隱藏輸入;請改在環境變數設定 TG_BOT_TOKEN",
|
|
59
59
|
"config.no_output": "(沒有輸出)",
|
|
60
60
|
"config.no_store": "這裡沒有作業系統憑證儲存區,權杖未儲存;請改設定 TG_BOT_TOKEN",
|
|
@@ -240,8 +240,9 @@ def live_names(base: Path, type_: str) -> list[str]:
|
|
|
240
240
|
return sorted(set(names))
|
|
241
241
|
|
|
242
242
|
|
|
243
|
-
def live_mcp(home: Path, backend: str | None) -> list[str]:
|
|
244
|
-
"""Names of the MCP servers currently configured for one harness
|
|
243
|
+
def live_mcp(home: Path, backend: str | None, file: Path | None = None) -> list[str]:
|
|
244
|
+
"""Names of the MCP servers currently configured for one harness (`file`: the
|
|
245
|
+
table's McpSpec.file, which the `json` backend reads)."""
|
|
245
246
|
if backend == "claude-json":
|
|
246
247
|
try:
|
|
247
248
|
cfg = json.loads(fs.claude_json().read_text(encoding="utf-8"))
|
|
@@ -260,9 +261,9 @@ def live_mcp(home: Path, backend: str | None) -> list[str]:
|
|
|
260
261
|
except ProjectMcpError:
|
|
261
262
|
return []
|
|
262
263
|
return sorted(n for n in names if n.isprintable() and _valid_name(n))
|
|
263
|
-
if backend == "json":
|
|
264
|
+
if backend == "json" and file: # user-edited text, so filter names
|
|
264
265
|
try:
|
|
265
|
-
names = read_project_mcp(
|
|
266
|
+
names = read_project_mcp(file)[1]["mcpServers"]
|
|
266
267
|
except ProjectMcpError:
|
|
267
268
|
return []
|
|
268
269
|
return sorted(n for n in names if n.isprintable() and _valid_name(n))
|
|
@@ -38,7 +38,7 @@ class Row:
|
|
|
38
38
|
key: str = "" # the settings key (bool / choice / text)
|
|
39
39
|
run: Callable[[Ctx, Result], None] | None = None # action rows
|
|
40
40
|
confirm: Callable[[], str] | None = None # y/n question asked before the action runs
|
|
41
|
-
telegram: bool = False # inert
|
|
41
|
+
telegram: bool = False # inert when telegram-kit is missing
|
|
42
42
|
harness: str = "" # harness rows: the name, for the detected note
|
|
43
43
|
role: str = "title" # headings: each group in its own colour
|
|
44
44
|
|
|
@@ -265,7 +265,7 @@ def capture(fn: Callable[[Result], None]) -> list[Segment]:
|
|
|
265
265
|
|
|
266
266
|
|
|
267
267
|
def needs_extra() -> str:
|
|
268
|
-
return t("config.needs_extra", "
|
|
268
|
+
return t("config.needs_extra", "telegram-kit missing: reinstall agent-toggle")
|
|
269
269
|
|
|
270
270
|
|
|
271
271
|
def value_segments(ctx: Ctx, row: Row, g: theme.Glyphs) -> list[Segment]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-toggle
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Temporarily disable / re-enable AI-agent skills, agents, commands, rules, plugins and MCP servers across harnesses (Claude Code, Codex, Grok, OpenCode, OpenClaw, Copilot, Vibe, Devin, Antigravity)
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/weskao/agent-toggle
|
|
@@ -24,6 +24,7 @@ Classifier: Topic :: Utilities
|
|
|
24
24
|
Requires-Python: >=3.10
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
|
+
Requires-Dist: telegram-kit<0.3,>=0.2.2
|
|
27
28
|
Provides-Extra: windows
|
|
28
29
|
Requires-Dist: windows-curses; sys_platform == "win32" and extra == "windows"
|
|
29
30
|
Provides-Extra: telegram
|
|
@@ -142,21 +143,20 @@ exits `1`. A shim written by a version before the marker counts as foreign;
|
|
|
142
143
|
delete it and re-run. `--dry-run` shows the same plan, refusals included. The
|
|
143
144
|
tool itself stays in one place.
|
|
144
145
|
|
|
145
|
-
**Optional: Telegram alerts for CI** (for maintainers of a fork or clone).
|
|
146
|
-
|
|
147
|
-
(itself stdlib-only),
|
|
146
|
+
**Optional: Telegram alerts for CI** (for maintainers of a fork or clone). The
|
|
147
|
+
Telegram support comes from [telegram-kit](https://pypi.org/project/telegram-kit/)
|
|
148
|
+
(itself stdlib-only), which every install includes, so a reinstall or upgrade keeps
|
|
149
|
+
your settings. Run the setup once; see [CI notifications](#ci-notifications):
|
|
148
150
|
|
|
149
151
|
```sh
|
|
150
|
-
uv tool install "agent-toggle[telegram]" # or: pipx install "agent-toggle[telegram]"
|
|
151
|
-
pip install -e ".[telegram]" # from a checkout
|
|
152
152
|
agent-toggle config # settings menu: bot token + chat id live under Notifications
|
|
153
153
|
agent-toggle config sync-ci # set the two GitHub repository secrets
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
The old `agent-toggle[telegram]` extra still resolves and is now a no-op. If
|
|
157
|
+
telegram-kit is missing from a broken install, `config test` and `config sync-ci`
|
|
158
|
+
exit `4`, bare `config` still opens, and the Telegram rows read
|
|
159
|
+
`telegram-kit missing: reinstall agent-toggle`.
|
|
160
160
|
|
|
161
161
|
**Optional: the Claude Code pane mod** (the picker as a pane inside Claude Code, claude harness
|
|
162
162
|
only). It is not part of the PyPI package; with `agent-toggle` already on `PATH` from one of the
|
|
@@ -204,7 +204,7 @@ agent-toggle <command> [args] # or: python3 agent_toggle.py <command> [
|
|
|
204
204
|
| `undo` | reverse the last logged batch (`--dry-run` shows the plan) |
|
|
205
205
|
| `profile save\|apply\|diff\|list\|delete\|rename` | named sets of live items; see [Profiles](#profiles) |
|
|
206
206
|
| `config` | settings menu (curses, else a numbered list); `config --json` lists every setting and the package version; see [Settings & config menu](#settings--config-menu) |
|
|
207
|
-
| `config test\|sync-ci` | send one Telegram test message / set the GitHub CI secrets;
|
|
207
|
+
| `config test\|sync-ci` | send one Telegram test message / set the GitHub CI secrets; see [CI notifications](#ci-notifications) |
|
|
208
208
|
| `help [command]` | styled help; `help ui` = `--help ui` = `ui --help`; see [Help](#help) |
|
|
209
209
|
| `doctor` | check each harness layout and `state.json` against disk; exit `1` only on an `error` row; on a terminal, asks y/n per fix it can run itself |
|
|
210
210
|
| `migrate` | import an older `~/.claude-toggle/` state, and move legacy `<home>/<dir>-disabled/` park dirs into `~/.agent-toggle/parked/user/` (see [Upgrading the park layout](#upgrading-the-park-layout)); safe to re-run |
|
|
@@ -463,8 +463,8 @@ invalid value in either is ignored with one warning on stderr.
|
|
|
463
463
|
harness is switched off (with one warning on stderr);
|
|
464
464
|
`disable` / `enable --project` without `--harness` still default to `claude`.
|
|
465
465
|
- `language` translates the config menu, help, update prompt and picker chrome; command output stays English.
|
|
466
|
-
-
|
|
467
|
-
|
|
466
|
+
- telegram-kit is a regular dependency now, so reinstalling keeps the Telegram settings working;
|
|
467
|
+
`agent-toggle[telegram]` still resolves.
|
|
468
468
|
|
|
469
469
|
## Update check
|
|
470
470
|
|
|
@@ -523,7 +523,7 @@ logo, centred, when the window is tall enough to fit the whole menu beside it; t
|
|
|
523
523
|
| copilot | `~/.copilot` | ✓ | ✓ | — | — | — | ✓ `mcp-config.json` |
|
|
524
524
|
| vibe | `~/.vibe` | ✓ | — | — | — | — | — |
|
|
525
525
|
| devin | `~/.devin` | — | — | — | — | — | — |
|
|
526
|
-
| agy | `~/.
|
|
526
|
+
| agy | `~/.gemini/config` | ✓ | — | — | — | — | ✓ `mcp_config.json` |
|
|
527
527
|
|
|
528
528
|
Per-harness locations, mechanisms and the harness versions this was checked
|
|
529
529
|
against are in [docs/harnesses.md](docs/harnesses.md).
|
|
@@ -1041,7 +1041,7 @@ agent-toggle config sync-ci # set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID on
|
|
|
1041
1041
|
|
|
1042
1042
|
In the [settings menu](#settings--config-menu) an inline field commits on `Enter`, cancels on
|
|
1043
1043
|
`Esc`, and clears on `-` then `Enter`; the Tools group also has Send test message and Sync CI
|
|
1044
|
-
secrets (the same as `config test` / `config sync-ci
|
|
1044
|
+
secrets (the same as `config test` / `config sync-ci`). The bot token
|
|
1045
1045
|
is kept only in the OS credential store (macOS Keychain, Linux Secret Service, Windows DPAPI)
|
|
1046
1046
|
through telegram-kit, never in a file or on a command line, and is shown masked. With no
|
|
1047
1047
|
credential store it refuses to store the token; set `TG_BOT_TOKEN` in the environment instead
|
|
@@ -26,7 +26,8 @@ classifiers = [
|
|
|
26
26
|
"Topic :: Utilities",
|
|
27
27
|
]
|
|
28
28
|
requires-python = ">=3.10"
|
|
29
|
-
|
|
29
|
+
# telegram-kit is core (stdlib-only) so a plain reinstall can't drop the Telegram settings
|
|
30
|
+
dependencies = ["telegram-kit>=0.2.2,<0.3"]
|
|
30
31
|
|
|
31
32
|
[project.urls]
|
|
32
33
|
Homepage = "https://github.com/weskao/agent-toggle"
|
|
@@ -36,6 +37,7 @@ Changelog = "https://github.com/weskao/agent-toggle/blob/main/CHANGELOG.md"
|
|
|
36
37
|
|
|
37
38
|
[project.optional-dependencies]
|
|
38
39
|
windows = ["windows-curses; sys_platform == 'win32'"]
|
|
40
|
+
# kept so existing `agent-toggle[telegram]` install commands resolve without a warning
|
|
39
41
|
telegram = ["telegram-kit>=0.2.2,<0.3"]
|
|
40
42
|
|
|
41
43
|
[project.scripts]
|
|
@@ -163,13 +163,13 @@ class ConfigTest(CliCase):
|
|
|
163
163
|
self.assertEqual(self.run_cli("config", "sync-ci", "--dry-run", "--repo", "o/r")[0], 0)
|
|
164
164
|
self.assertEqual(self.gh_calls, [])
|
|
165
165
|
|
|
166
|
-
def
|
|
166
|
+
def test_missing_kit_is_a_clear_exit_4_for_test_and_sync_ci_only(self) -> None:
|
|
167
167
|
mock.patch.stopall()
|
|
168
168
|
with mock.patch.dict(sys.modules, {"telegram_kit": None}):
|
|
169
169
|
for action in ("test", "sync-ci"):
|
|
170
170
|
rc, _, err = self.run_cli("config", action)
|
|
171
171
|
self.assertEqual(rc, 4)
|
|
172
|
-
self.assertIn("agent-toggle
|
|
172
|
+
self.assertIn("reinstall agent-toggle", err)
|
|
173
173
|
with mock.patch.object(sys, "stdin", io.StringIO("")): # never the real TTY
|
|
174
174
|
self.assertEqual(self.run_cli("config")[0], 0) # the menu degrades instead
|
|
175
175
|
|
|
@@ -260,7 +260,7 @@ class CursesMenuTest(MenuCase):
|
|
|
260
260
|
def test_without_telegram_kit_the_rows_are_inert(self) -> None:
|
|
261
261
|
win, rc = self.menu([*to("Telegram chat"), "\n", "r", "q"], telegram=False)
|
|
262
262
|
self.assertEqual(rc, 0)
|
|
263
|
-
self.assertIn("
|
|
263
|
+
self.assertIn("reinstall agent-toggle", win.text())
|
|
264
264
|
self.assertFalse(settings.config_file().exists())
|
|
265
265
|
|
|
266
266
|
def test_tools_run_with_a_fresh_result_in_a_pager(self) -> None:
|
|
@@ -394,7 +394,7 @@ class NumberedTest(MenuCase):
|
|
|
394
394
|
def test_without_telegram_kit_rows_are_degraded(self) -> None:
|
|
395
395
|
rc, out = self.run_numbered(f"{number('Telegram chat')}\nq\n", telegram=False)
|
|
396
396
|
self.assertEqual(rc, 0)
|
|
397
|
-
self.assertIn("
|
|
397
|
+
self.assertIn("reinstall agent-toggle", out)
|
|
398
398
|
self.assertFalse(settings.config_file().exists())
|
|
399
399
|
|
|
400
400
|
def test_actions_confirm_and_print_their_output(self) -> None:
|
|
@@ -431,7 +431,7 @@ class CliConfigMenuTest(CliCase):
|
|
|
431
431
|
mock.patch.object(sys, "stdin", io.StringIO("1\n")):
|
|
432
432
|
rc, out, err = self.run_cli("config")
|
|
433
433
|
self.assertEqual(rc, 0, err)
|
|
434
|
-
self.assertIn("
|
|
434
|
+
self.assertIn("reinstall agent-toggle", out)
|
|
435
435
|
self.assertIs(settings.get("update_check"), False)
|
|
436
436
|
with mock.patch.dict(sys.modules, {"telegram_kit": None}):
|
|
437
437
|
rc, env = self.run_json("config")
|
|
@@ -189,6 +189,16 @@ class CostCommandTest(CliCase):
|
|
|
189
189
|
self.assertTrue(any("plugin list" in w for w in env["warnings"]))
|
|
190
190
|
|
|
191
191
|
|
|
192
|
+
class AgyCostTest(CliCase):
|
|
193
|
+
def test_live_skill_and_mcp_servers_are_listed(self) -> None:
|
|
194
|
+
shutil.copytree(FIXTURES / "agy", self.tmp, dirs_exist_ok=True)
|
|
195
|
+
rc, env = self.run_json("cost", "--harness", "agy")
|
|
196
|
+
self.assertEqual(rc, 0, env)
|
|
197
|
+
live = {(r["type"], r["name"]) for r in env["results"] if r["name"] and r["enabled"]}
|
|
198
|
+
self.assertEqual(live, {("skill", "demo-skill"), ("mcp", "example-mcp"),
|
|
199
|
+
("mcp", "other-mcp")})
|
|
200
|
+
|
|
201
|
+
|
|
192
202
|
class FlagCostTest(CliCase):
|
|
193
203
|
def setUp(self) -> None:
|
|
194
204
|
super().setUp()
|
|
@@ -17,7 +17,8 @@ TODAY = {
|
|
|
17
17
|
} | {("opencode", "skill"), ("opencode", "command"),
|
|
18
18
|
("grok", "skill"), ("grok", "mcp"), ("openclaw", "skill"), ("openclaw", "agent"),
|
|
19
19
|
("openclaw", "plugin"), ("opencode", "mcp"), ("vibe", "skill"),
|
|
20
|
-
("copilot", "skill"), ("copilot", "agent"), ("copilot", "mcp")
|
|
20
|
+
("copilot", "skill"), ("copilot", "agent"), ("copilot", "mcp"),
|
|
21
|
+
("agy", "skill"), ("agy", "mcp")}
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class HarnessTableTest(SandboxCase):
|
|
@@ -62,6 +63,10 @@ class HarnessTableTest(SandboxCase):
|
|
|
62
63
|
self.assertEqual(t["copilot"].backend, "json")
|
|
63
64
|
self.assertEqual(t["copilot"].mcp.file, self.tmp / ".copilot" / "mcp-config.json")
|
|
64
65
|
self.assertEqual(t["copilot"].editable, {"mcp-config.json"})
|
|
66
|
+
self.assertEqual(t["agy"].home, self.tmp / ".gemini" / "config")
|
|
67
|
+
self.assertEqual(t["agy"].backend, "json")
|
|
68
|
+
self.assertEqual(t["agy"].mcp.file, self.tmp / ".gemini" / "config" / "mcp_config.json")
|
|
69
|
+
self.assertEqual(t["agy"].editable, {"mcp_config.json"})
|
|
65
70
|
|
|
66
71
|
def test_flag_pairs_are_declared_and_editable(self) -> None:
|
|
67
72
|
for n, h in build(self.tmp).items():
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|