agent-toggle 0.16.1__tar.gz → 0.17.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.16.1 → agent_toggle-0.17.0}/PKG-INFO +20 -14
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/README.md +19 -13
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/__init__.py +1 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/backends/flag_json.py +1 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/backends/plugin_cli.py +1 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/cli.py +1 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/cost.py +1 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/doctor.py +2 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/harnesses.py +1 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/ui/config_menu.py +1 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/ui/picker.py +1 -1
- agent_toggle-0.17.0/agent_toggle/update_check.py +209 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/update_prompt.py +12 -9
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle.egg-info/PKG-INFO +20 -14
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle.egg-info/SOURCES.txt +1 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/pyproject.toml +5 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_backends.py +1 -1
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_cli.py +8 -8
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_cost.py +2 -1
- agent_toggle-0.17.0/tests/test_mod_version.py +20 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_picker.py +2 -2
- agent_toggle-0.17.0/tests/test_update_check.py +240 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_update_prompt.py +12 -0
- agent_toggle-0.16.1/agent_toggle/update_check.py +0 -361
- agent_toggle-0.16.1/tests/test_update_check.py +0 -423
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/LICENSE +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/__main__.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/backends/__init__.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/backends/mcp_json.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/backends/mcp_toml.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/companions.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/completions.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/config.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/fs.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/help.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/i18n.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/locales/__init__.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/locales/zh_tw_cli.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/locales/zh_tw_common.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/locales/zh_tw_config.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/locales/zh_tw_picker.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/mechanisms.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/ops.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/output.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/profiles.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/settings.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/shims/claude.md.tmpl +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/shims/generic.md.tmpl +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/spinner.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/store.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/toml_check.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/ui/__init__.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/ui/logo.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/ui/menu.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/ui/model.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/ui/theme.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle/undo.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle.egg-info/dependency_links.txt +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle.egg-info/entry_points.txt +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle.egg-info/requires.txt +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/agent_toggle.egg-info/top_level.txt +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/setup.cfg +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_alias.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_all_type.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_cli_surface.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_color.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_companions.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_completions.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_config.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_config_menu.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_conformance.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_containment.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_crash.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_doctor.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_encoding.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_fs.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_harnesses.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_help.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_i18n.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_install.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_logo.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_mechanisms.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_menu.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_mods.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_platform.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_profiles.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_project.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_safety.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_same_name.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_secret_audit.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_settings.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_store.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_theme.py +0 -0
- {agent_toggle-0.16.1 → agent_toggle-0.17.0}/tests/test_undo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-toggle
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.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
|
|
@@ -168,6 +168,9 @@ installs above, type this at the prompt of a Claude Code terminal session (2.1.2
|
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
Answer `y` to add the marketplace, pick a scope (user is the default), then run `/agent-toggle`.
|
|
171
|
+
The same mod is also listed in the `weskao-agent-plugins` marketplace
|
|
172
|
+
(`claude plugin marketplace add weskao/weskao-agent-plugins`, then
|
|
173
|
+
`claude plugin install agent-toggle@weskao-agent-plugins`); install it from one of the two, not both.
|
|
171
174
|
|
|
172
175
|
See [Claude Code pane mod](#claude-code-pane-mod).
|
|
173
176
|
|
|
@@ -260,7 +263,7 @@ Flags accepted by every command, before or after the subcommand:
|
|
|
260
263
|
|
|
261
264
|
Extra row fields: `list` rows carry `at`, `mechanism`, `companions`; `cost` rows
|
|
262
265
|
carry `enabled`, `tokens`, `would_save`, `chars`, and the final `total` row
|
|
263
|
-
carries `total_tokens`, `saved_tokens`, `formula`. Rows for a
|
|
266
|
+
carries `total_tokens`, `saved_tokens`, `formula`, `version`. Rows for a
|
|
264
267
|
directory shared with another harness (see below) carry `shared_with`, the other
|
|
265
268
|
harnesses that read it: `disable` / `enable` rows relative to the harness you
|
|
266
269
|
asked, plus `owner`, the harness whose park dir and state entry hold the item;
|
|
@@ -498,7 +501,7 @@ invalid value in either is ignored with one warning on stderr.
|
|
|
498
501
|
|
|
499
502
|
## Update check
|
|
500
503
|
|
|
501
|
-
On every invocation (unless disabled) agent-toggle checks
|
|
504
|
+
On every invocation (unless disabled) agent-toggle checks the repository's release tags for a newer release. It starts
|
|
502
505
|
before the command and is offered after it, on every exit path; it overlaps the command and waits at most 0.8 s afterwards.
|
|
503
506
|
`update` and `completion` skip it.
|
|
504
507
|
|
|
@@ -513,9 +516,9 @@ before the command and is offered after it, on every exit path; it overlaps the
|
|
|
513
516
|
then ` agent-toggle update`.
|
|
514
517
|
- It never changes the exit code or stdout, so `--json` output stays one document.
|
|
515
518
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
+
The lookup is update-kit's: one `git ls-remote --tags --refs` of the repository on a background
|
|
520
|
+
thread, cached for 10 minutes in `~/.update-kit/state.json`. Only the version you chose to skip is
|
|
521
|
+
kept in `~/.agent-toggle/update-check.json`. Nothing is sent beyond a normal git request. See `SECURITY.md`
|
|
519
522
|
for the hardening. To turn it off, set `AGENT_TOGGLE_UPDATE_CHECK=0` or the `update_check` setting
|
|
520
523
|
to off (the settings menu's "Check for updates").
|
|
521
524
|
|
|
@@ -527,9 +530,9 @@ tag (`git ls-remote --tags`) and always installs that tag with
|
|
|
527
530
|
`uv tool install --force --no-sources git+<repo>@<tag>` (`pipx install --force` for a pipx install).
|
|
528
531
|
A dev checkout, a branch or commit install, or an unmanaged install is replaced by the tag too
|
|
529
532
|
(with uv, else pipx); only an install made from exactly that tag is already up to date.
|
|
530
|
-
It then runs, with the new binary and in order: when the Claude Code plugin is installed
|
|
531
|
-
`claude plugin marketplace update
|
|
532
|
-
then `agent-toggle install-shims`. A failing step prints a warning and makes the exit code `1`.
|
|
533
|
+
It then runs, with the new binary and in order: when the Claude Code plugin is installed (from any
|
|
534
|
+
marketplace), `claude plugin marketplace update <marketplace>` and
|
|
535
|
+
`claude plugin update agent-toggle@<marketplace>`, then `agent-toggle install-shims`. A failing step prints a warning and makes the exit code `1`.
|
|
533
536
|
It never prompts and writes to stderr only.
|
|
534
537
|
|
|
535
538
|
| Exit | Meaning |
|
|
@@ -931,7 +934,7 @@ bookkeeping.
|
|
|
931
934
|
| `parked/<sha8>/` | items parked by `--project` (`<sha8>` = first 8 hex of the SHA-1 of the resolved project dir) |
|
|
932
935
|
| `profiles/` | `<name>.json` profiles (dir `0700`, files `0600`) |
|
|
933
936
|
| `config.json` | [settings](#settings--config-menu) and the Telegram chat id (mode `0600`, atomic write, unknown keys kept) |
|
|
934
|
-
| `update-check.json` | the [update check](#update-check)'s
|
|
937
|
+
| `update-check.json` | the [update check](#update-check)'s skipped version (mode `0600`, atomic write) |
|
|
935
938
|
|
|
936
939
|
A killed run loses at most the one item in flight. If that was a flag write or a
|
|
937
940
|
dir move (with its companions), its `pending` record (the full entry, a flag's
|
|
@@ -1011,8 +1014,9 @@ CLI (`cost --json`, `disable|enable --json`) and works for the claude harness on
|
|
|
1011
1014
|
`agent-toggle ui` stays the cross-harness UI.
|
|
1012
1015
|
|
|
1013
1016
|
Install it with `/plugin install agent-toggle --marketplace weskao/agent-toggle` (see
|
|
1014
|
-
[Install](#install));
|
|
1015
|
-
|
|
1017
|
+
[Install](#install)); `/agent-toggle update` picks up a new release: it runs `agent-toggle update`,
|
|
1018
|
+
which updates the CLI, this mod and the shims together (restart Claude Code to load the new mod).
|
|
1019
|
+
The mod and the CLI share one version. To run your own checkout instead (edits reload as you save):
|
|
1016
1020
|
|
|
1017
1021
|
```sh
|
|
1018
1022
|
claude --plugin-dir ./mod # then run /agent-toggle inside Claude
|
|
@@ -1144,8 +1148,10 @@ prints a `::notice::` and exits 0, so it never adds a second red X.
|
|
|
1144
1148
|
## Releasing
|
|
1145
1149
|
|
|
1146
1150
|
A release is a git tag `vX.Y.Z` (where `X.Y.Z` must match `agent_toggle.__version__`).
|
|
1147
|
-
|
|
1148
|
-
|
|
1151
|
+
`version` in `mod/.claude-plugin/plugin.json` must be the same value (the mod ships in lockstep;
|
|
1152
|
+
without the bump `claude plugin update` does not hand marketplace installs the new mod).
|
|
1153
|
+
`tests/test_mod_version.py` and the release workflow both fail on a mismatch.
|
|
1154
|
+
The `weskao-agent-plugins` marketplace lists the mod without a version, so it needs no bump there.
|
|
1149
1155
|
Pushing the tag triggers `.github/workflows/release.yml`:
|
|
1150
1156
|
|
|
1151
1157
|
1. **Build** job checks that the tag matches `__version__`, builds a wheel and
|
|
@@ -134,6 +134,9 @@ installs above, type this at the prompt of a Claude Code terminal session (2.1.2
|
|
|
134
134
|
```
|
|
135
135
|
|
|
136
136
|
Answer `y` to add the marketplace, pick a scope (user is the default), then run `/agent-toggle`.
|
|
137
|
+
The same mod is also listed in the `weskao-agent-plugins` marketplace
|
|
138
|
+
(`claude plugin marketplace add weskao/weskao-agent-plugins`, then
|
|
139
|
+
`claude plugin install agent-toggle@weskao-agent-plugins`); install it from one of the two, not both.
|
|
137
140
|
|
|
138
141
|
See [Claude Code pane mod](#claude-code-pane-mod).
|
|
139
142
|
|
|
@@ -226,7 +229,7 @@ Flags accepted by every command, before or after the subcommand:
|
|
|
226
229
|
|
|
227
230
|
Extra row fields: `list` rows carry `at`, `mechanism`, `companions`; `cost` rows
|
|
228
231
|
carry `enabled`, `tokens`, `would_save`, `chars`, and the final `total` row
|
|
229
|
-
carries `total_tokens`, `saved_tokens`, `formula`. Rows for a
|
|
232
|
+
carries `total_tokens`, `saved_tokens`, `formula`, `version`. Rows for a
|
|
230
233
|
directory shared with another harness (see below) carry `shared_with`, the other
|
|
231
234
|
harnesses that read it: `disable` / `enable` rows relative to the harness you
|
|
232
235
|
asked, plus `owner`, the harness whose park dir and state entry hold the item;
|
|
@@ -464,7 +467,7 @@ invalid value in either is ignored with one warning on stderr.
|
|
|
464
467
|
|
|
465
468
|
## Update check
|
|
466
469
|
|
|
467
|
-
On every invocation (unless disabled) agent-toggle checks
|
|
470
|
+
On every invocation (unless disabled) agent-toggle checks the repository's release tags for a newer release. It starts
|
|
468
471
|
before the command and is offered after it, on every exit path; it overlaps the command and waits at most 0.8 s afterwards.
|
|
469
472
|
`update` and `completion` skip it.
|
|
470
473
|
|
|
@@ -479,9 +482,9 @@ before the command and is offered after it, on every exit path; it overlaps the
|
|
|
479
482
|
then ` agent-toggle update`.
|
|
480
483
|
- It never changes the exit code or stdout, so `--json` output stays one document.
|
|
481
484
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
+
The lookup is update-kit's: one `git ls-remote --tags --refs` of the repository on a background
|
|
486
|
+
thread, cached for 10 minutes in `~/.update-kit/state.json`. Only the version you chose to skip is
|
|
487
|
+
kept in `~/.agent-toggle/update-check.json`. Nothing is sent beyond a normal git request. See `SECURITY.md`
|
|
485
488
|
for the hardening. To turn it off, set `AGENT_TOGGLE_UPDATE_CHECK=0` or the `update_check` setting
|
|
486
489
|
to off (the settings menu's "Check for updates").
|
|
487
490
|
|
|
@@ -493,9 +496,9 @@ tag (`git ls-remote --tags`) and always installs that tag with
|
|
|
493
496
|
`uv tool install --force --no-sources git+<repo>@<tag>` (`pipx install --force` for a pipx install).
|
|
494
497
|
A dev checkout, a branch or commit install, or an unmanaged install is replaced by the tag too
|
|
495
498
|
(with uv, else pipx); only an install made from exactly that tag is already up to date.
|
|
496
|
-
It then runs, with the new binary and in order: when the Claude Code plugin is installed
|
|
497
|
-
`claude plugin marketplace update
|
|
498
|
-
then `agent-toggle install-shims`. A failing step prints a warning and makes the exit code `1`.
|
|
499
|
+
It then runs, with the new binary and in order: when the Claude Code plugin is installed (from any
|
|
500
|
+
marketplace), `claude plugin marketplace update <marketplace>` and
|
|
501
|
+
`claude plugin update agent-toggle@<marketplace>`, then `agent-toggle install-shims`. A failing step prints a warning and makes the exit code `1`.
|
|
499
502
|
It never prompts and writes to stderr only.
|
|
500
503
|
|
|
501
504
|
| Exit | Meaning |
|
|
@@ -897,7 +900,7 @@ bookkeeping.
|
|
|
897
900
|
| `parked/<sha8>/` | items parked by `--project` (`<sha8>` = first 8 hex of the SHA-1 of the resolved project dir) |
|
|
898
901
|
| `profiles/` | `<name>.json` profiles (dir `0700`, files `0600`) |
|
|
899
902
|
| `config.json` | [settings](#settings--config-menu) and the Telegram chat id (mode `0600`, atomic write, unknown keys kept) |
|
|
900
|
-
| `update-check.json` | the [update check](#update-check)'s
|
|
903
|
+
| `update-check.json` | the [update check](#update-check)'s skipped version (mode `0600`, atomic write) |
|
|
901
904
|
|
|
902
905
|
A killed run loses at most the one item in flight. If that was a flag write or a
|
|
903
906
|
dir move (with its companions), its `pending` record (the full entry, a flag's
|
|
@@ -977,8 +980,9 @@ CLI (`cost --json`, `disable|enable --json`) and works for the claude harness on
|
|
|
977
980
|
`agent-toggle ui` stays the cross-harness UI.
|
|
978
981
|
|
|
979
982
|
Install it with `/plugin install agent-toggle --marketplace weskao/agent-toggle` (see
|
|
980
|
-
[Install](#install));
|
|
981
|
-
|
|
983
|
+
[Install](#install)); `/agent-toggle update` picks up a new release: it runs `agent-toggle update`,
|
|
984
|
+
which updates the CLI, this mod and the shims together (restart Claude Code to load the new mod).
|
|
985
|
+
The mod and the CLI share one version. To run your own checkout instead (edits reload as you save):
|
|
982
986
|
|
|
983
987
|
```sh
|
|
984
988
|
claude --plugin-dir ./mod # then run /agent-toggle inside Claude
|
|
@@ -1110,8 +1114,10 @@ prints a `::notice::` and exits 0, so it never adds a second red X.
|
|
|
1110
1114
|
## Releasing
|
|
1111
1115
|
|
|
1112
1116
|
A release is a git tag `vX.Y.Z` (where `X.Y.Z` must match `agent_toggle.__version__`).
|
|
1113
|
-
|
|
1114
|
-
|
|
1117
|
+
`version` in `mod/.claude-plugin/plugin.json` must be the same value (the mod ships in lockstep;
|
|
1118
|
+
without the bump `claude plugin update` does not hand marketplace installs the new mod).
|
|
1119
|
+
`tests/test_mod_version.py` and the release workflow both fail on a mismatch.
|
|
1120
|
+
The `weskao-agent-plugins` marketplace lists the mod without a version, so it needs no bump there.
|
|
1115
1121
|
Pushing the tag triggers `.github/workflows/release.yml`:
|
|
1116
1122
|
|
|
1117
1123
|
1. **Build** job checks that the tag matches `__version__`, builds a wheel and
|
|
@@ -298,7 +298,7 @@ def cmd_cost(state: dict, out: Result, harness: str | None = None,
|
|
|
298
298
|
if len(shown) > len(items):
|
|
299
299
|
_say_hidden(out, f"{len(shown) - len(items)} hidden by settings (agent-toggle config)")
|
|
300
300
|
out.row(harness, type_, None, "cost", "ok", "total", show=False, items=len(items),
|
|
301
|
-
total_tokens=live, saved_tokens=saved, formula=cost.FORMULA,
|
|
301
|
+
total_tokens=live, saved_tokens=saved, formula=cost.FORMULA, version=__version__,
|
|
302
302
|
**({"project": str(proj)} if proj else {}))
|
|
303
303
|
|
|
304
304
|
|
|
@@ -26,10 +26,10 @@ from __future__ import annotations
|
|
|
26
26
|
import json
|
|
27
27
|
import re
|
|
28
28
|
from collections import Counter
|
|
29
|
+
from collections.abc import Callable
|
|
29
30
|
from concurrent.futures import ThreadPoolExecutor
|
|
30
31
|
from dataclasses import dataclass
|
|
31
32
|
from pathlib import Path
|
|
32
|
-
from typing import Callable
|
|
33
33
|
|
|
34
34
|
from . import fs
|
|
35
35
|
from .backends.flag_json import jsonc_loads
|
|
@@ -15,8 +15,9 @@ import filecmp
|
|
|
15
15
|
import json
|
|
16
16
|
import os
|
|
17
17
|
import shutil
|
|
18
|
+
from collections.abc import Callable
|
|
18
19
|
from pathlib import Path
|
|
19
|
-
from typing import
|
|
20
|
+
from typing import NamedTuple
|
|
20
21
|
|
|
21
22
|
from . import fs, ops, store
|
|
22
23
|
from .backends.flag_json import jsonc_loads
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import os
|
|
5
|
+
from collections.abc import Mapping
|
|
5
6
|
from dataclasses import dataclass, field
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from types import MappingProxyType
|
|
8
|
-
from typing import Mapping
|
|
9
9
|
|
|
10
10
|
from . import fs
|
|
11
11
|
from .backends import flag_json
|
|
@@ -17,8 +17,8 @@ import contextlib
|
|
|
17
17
|
import io
|
|
18
18
|
import sys
|
|
19
19
|
import time
|
|
20
|
+
from collections.abc import Callable
|
|
20
21
|
from dataclasses import dataclass
|
|
21
|
-
from typing import Callable
|
|
22
22
|
|
|
23
23
|
from .. import __version__, config, doctor, fs, harnesses, i18n, settings, undo
|
|
24
24
|
from ..i18n import t
|
|
@@ -498,7 +498,7 @@ def ask_save(win, v: View, pal: theme.Palette, g: theme.Glyphs,
|
|
|
498
498
|
top = min(top, max(0, len(changed) - max(1, page)))
|
|
499
499
|
row_y = y0 + (2 if bh >= 7 else 1)
|
|
500
500
|
|
|
501
|
-
def put(y, segments):
|
|
501
|
+
def put(y, segments, x0=x0, inner=inner):
|
|
502
502
|
theme.draw_segments(win, y, x0, [(g.v, "accent"),
|
|
503
503
|
*clip(segments, inner, g.ellipsis), (g.v, "accent")], pal)
|
|
504
504
|
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""Update check on top of update-kit, plus the "skip this version" memory.
|
|
2
|
+
|
|
3
|
+
from agent_toggle.update_check import check
|
|
4
|
+
found = check("1.0.0", cache_path=Path.home() / ".agent-toggle" / "update-check.json")
|
|
5
|
+
if found:
|
|
6
|
+
print(f"{found.latest} is available (you have {found.current})")
|
|
7
|
+
|
|
8
|
+
The lookup itself -- ``git ls-remote`` of the release tags, the 10-minute cache in
|
|
9
|
+
``~/.update-kit/state.json``, the timeout -- is :func:`update_kit.check`; ``latest`` is
|
|
10
|
+
the tag as it returns it (``v1.2.0``). Only the skipped version lives in *cache_path*.
|
|
11
|
+
|
|
12
|
+
To overlap the lookup with the command's own work instead of paying for
|
|
13
|
+
it at exit, start it early and collect the result at the end:
|
|
14
|
+
|
|
15
|
+
started = start("1.0.0", cache_path=...)
|
|
16
|
+
... # the command's own work
|
|
17
|
+
found = collect(started)
|
|
18
|
+
|
|
19
|
+
To ask the user what to do instead of only hinting, hand :func:`offer` the
|
|
20
|
+
UI as a callback -- it owns what each answer does, the UI only picks one:
|
|
21
|
+
|
|
22
|
+
offer(started, ask, cache_path=..., upgrade=["uv", "tool", "upgrade", "agent-toggle"])
|
|
23
|
+
|
|
24
|
+
where ``ask(found)`` returns ``UPDATE_NOW``, ``SKIP`` or ``SKIP_VERSION``.
|
|
25
|
+
When the upgrade depends on the version or takes several steps, pass a
|
|
26
|
+
callable instead: ``upgrade=lambda found: [[...], [...]]`` runs each command
|
|
27
|
+
in order and stops at the first one that fails.
|
|
28
|
+
``SKIP_VERSION`` is remembered in *cache_path*; a newer release asks again.
|
|
29
|
+
|
|
30
|
+
Nothing here is allowed to raise to the caller: a missing cache, a bad
|
|
31
|
+
payload, or a dead network all become ``None``.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
import json
|
|
37
|
+
import os
|
|
38
|
+
import re
|
|
39
|
+
import subprocess
|
|
40
|
+
import threading
|
|
41
|
+
from collections.abc import Callable, Sequence
|
|
42
|
+
from dataclasses import dataclass, field
|
|
43
|
+
from pathlib import Path
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
"DEFAULT_TIMEOUT",
|
|
47
|
+
"REPO",
|
|
48
|
+
"SKIP",
|
|
49
|
+
"SKIP_VERSION",
|
|
50
|
+
"UPDATE_NOW",
|
|
51
|
+
"UPGRADE_FAILED",
|
|
52
|
+
"Started",
|
|
53
|
+
"UpdateAvailable",
|
|
54
|
+
"check",
|
|
55
|
+
"collect",
|
|
56
|
+
"offer",
|
|
57
|
+
"skip",
|
|
58
|
+
"start",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
REPO = "weskao/agent-toggle"
|
|
62
|
+
#: How long :func:`collect` waits for the background lookup before giving up on it.
|
|
63
|
+
DEFAULT_TIMEOUT = 0.8
|
|
64
|
+
|
|
65
|
+
#: Answers an ``ask`` callback returns to :func:`offer`.
|
|
66
|
+
UPDATE_NOW = "update-now"
|
|
67
|
+
SKIP = "skip"
|
|
68
|
+
SKIP_VERSION = "skip-version"
|
|
69
|
+
#: What :func:`offer` returns when UPDATE_NOW's command could not run or failed.
|
|
70
|
+
UPGRADE_FAILED = "upgrade-failed"
|
|
71
|
+
|
|
72
|
+
#: What a skipped version may look like before it is trusted: it is read from a file.
|
|
73
|
+
_VERSION_RE = re.compile(r"v?\d{1,6}(\.\d{1,6}){1,3}([a-zA-Z0-9.+-]{0,20})?")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass(frozen=True)
|
|
77
|
+
class UpdateAvailable:
|
|
78
|
+
current: str
|
|
79
|
+
latest: str
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def check(current: str, *, cache_path: Path) -> UpdateAvailable | None:
|
|
83
|
+
"""Return an update when the latest release is newer than *current* and not the
|
|
84
|
+
version skipped in *cache_path*, else None. Never raises."""
|
|
85
|
+
try:
|
|
86
|
+
import update_kit # lazy: a checkout run or a stale env lacks it
|
|
87
|
+
|
|
88
|
+
latest = update_kit.check(repo=REPO, current=current)
|
|
89
|
+
if not isinstance(latest, str) or _bare(latest) == _bare(_load_cache(cache_path).get("skipped")):
|
|
90
|
+
return None
|
|
91
|
+
return UpdateAvailable(current=current, latest=latest)
|
|
92
|
+
except Exception: # noqa: BLE001 - a hint must never fail the command
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass
|
|
97
|
+
class Started:
|
|
98
|
+
"""A background check in flight; pass to :func:`collect` to get its result."""
|
|
99
|
+
|
|
100
|
+
thread: threading.Thread
|
|
101
|
+
_result: list = field(default_factory=list)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def start(current: str, *, cache_path: Path) -> Started:
|
|
105
|
+
"""Run :func:`check` on a daemon thread so it overlaps the caller's own work."""
|
|
106
|
+
result: list = []
|
|
107
|
+
|
|
108
|
+
def run() -> None:
|
|
109
|
+
result.append(check(current, cache_path=cache_path))
|
|
110
|
+
|
|
111
|
+
thread = threading.Thread(target=run, name="agent-toggle-update-check", daemon=True)
|
|
112
|
+
thread.start()
|
|
113
|
+
return Started(thread=thread, _result=result)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def collect(started: Started | None, *, timeout: float = DEFAULT_TIMEOUT) -> UpdateAvailable | None:
|
|
117
|
+
"""Wait for a :func:`start`-ed check and return its result. Never raises."""
|
|
118
|
+
if started is None:
|
|
119
|
+
return None
|
|
120
|
+
try:
|
|
121
|
+
# Usually already done: it ran alongside the caller's own work.
|
|
122
|
+
started.thread.join(timeout)
|
|
123
|
+
return started._result[0] if started._result else None
|
|
124
|
+
except Exception: # noqa: BLE001 - a hint must never fail the command
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def skip(cache_path: Path, version: str) -> None:
|
|
129
|
+
"""Stop reporting *version*; a newer release is reported again. Never raises."""
|
|
130
|
+
data = _load_cache(cache_path)
|
|
131
|
+
data["skipped"] = version
|
|
132
|
+
_write_cache(cache_path, data)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def offer(
|
|
136
|
+
started: Started | None,
|
|
137
|
+
ask: Callable[[UpdateAvailable], str],
|
|
138
|
+
*,
|
|
139
|
+
cache_path: Path,
|
|
140
|
+
upgrade: Sequence[str] | Callable[[UpdateAvailable], Sequence[Sequence[str]]],
|
|
141
|
+
run: Callable[..., object] = subprocess.run,
|
|
142
|
+
) -> str | None:
|
|
143
|
+
"""Collect *started*, let *ask* pick an answer, then act on it.
|
|
144
|
+
|
|
145
|
+
*upgrade* is one command, or a callable building the commands from the
|
|
146
|
+
found release, run in order. Returns the answer acted on
|
|
147
|
+
(``UPGRADE_FAILED`` when a command is missing or exits nonzero — the
|
|
148
|
+
rest are then skipped), or None when there was nothing to offer. Ctrl+C
|
|
149
|
+
inside *ask* is ``SKIP``. Never raises.
|
|
150
|
+
"""
|
|
151
|
+
try:
|
|
152
|
+
found = collect(started)
|
|
153
|
+
if found is None:
|
|
154
|
+
return None
|
|
155
|
+
try:
|
|
156
|
+
answer = ask(found)
|
|
157
|
+
except KeyboardInterrupt:
|
|
158
|
+
return SKIP
|
|
159
|
+
if answer == SKIP_VERSION:
|
|
160
|
+
skip(cache_path, found.latest)
|
|
161
|
+
elif answer == UPDATE_NOW:
|
|
162
|
+
steps = upgrade(found) if callable(upgrade) else [upgrade]
|
|
163
|
+
for step in steps:
|
|
164
|
+
try:
|
|
165
|
+
done = run(list(step), check=False)
|
|
166
|
+
except OSError:
|
|
167
|
+
return UPGRADE_FAILED
|
|
168
|
+
if getattr(done, "returncode", 1) != 0:
|
|
169
|
+
return UPGRADE_FAILED
|
|
170
|
+
return answer
|
|
171
|
+
except Exception: # noqa: BLE001 - an update offer must never fail the command
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _bare(version: object) -> str | None:
|
|
176
|
+
"""*version* without a leading ``v`` (an old cache holds PyPI's ``0.10.0``, now tags)."""
|
|
177
|
+
return version.removeprefix("v") if isinstance(version, str) else None
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _load_cache(path: Path) -> dict:
|
|
181
|
+
try:
|
|
182
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
183
|
+
except (OSError, ValueError, RecursionError): # RecursionError: a deeply nested file
|
|
184
|
+
return {}
|
|
185
|
+
if not isinstance(data, dict):
|
|
186
|
+
return {}
|
|
187
|
+
# Only a valid skipped version survives: a hostile file can't smuggle anything
|
|
188
|
+
# (e.g. a 100k-deep dict that json.dumps can't write back), and old
|
|
189
|
+
# checked_at/latest keys are dropped on the next write.
|
|
190
|
+
skipped = data.get("skipped")
|
|
191
|
+
return {"skipped": skipped} if isinstance(skipped, str) and _VERSION_RE.fullmatch(skipped) else {}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _write_cache(path: Path, data: dict) -> None:
|
|
195
|
+
# tmp + os.replace never follows a symlink at *path*; 0600 from creation.
|
|
196
|
+
tmp = path.with_name(f".{path.name}.{os.getpid()}.tmp")
|
|
197
|
+
try:
|
|
198
|
+
path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
|
199
|
+
tmp.unlink(missing_ok=True)
|
|
200
|
+
fd = os.open(tmp, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600)
|
|
201
|
+
try:
|
|
202
|
+
with os.fdopen(fd, "w", encoding="utf-8") as fh:
|
|
203
|
+
fh.write(json.dumps(data) + "\n")
|
|
204
|
+
os.replace(tmp, path)
|
|
205
|
+
except BaseException:
|
|
206
|
+
tmp.unlink(missing_ok=True)
|
|
207
|
+
raise
|
|
208
|
+
except (OSError, RecursionError, ValueError):
|
|
209
|
+
return
|
|
@@ -28,8 +28,7 @@ from .output import use_color
|
|
|
28
28
|
from .ui import theme
|
|
29
29
|
|
|
30
30
|
DIST = "agent-toggle"
|
|
31
|
-
REPO =
|
|
32
|
-
PLUGIN = "agent-toggle@agent-toggle"
|
|
31
|
+
REPO = update_check.REPO
|
|
33
32
|
UPDATE = [DIST, "update"]
|
|
34
33
|
RELEASE_NOTES = "https://github.com/weskao/agent-toggle/releases/tag/v%s"
|
|
35
34
|
ANSWERS = (update_check.UPDATE_NOW, update_check.SKIP, update_check.SKIP_VERSION)
|
|
@@ -48,9 +47,13 @@ def after_steps() -> list[list[str]]:
|
|
|
48
47
|
installed, then the shims."""
|
|
49
48
|
steps: list[list[str]] = []
|
|
50
49
|
# bare "claude": what a person pastes; _run() resolves it, as claude is often off PATH
|
|
51
|
-
if plugin_cli.claude_bin()
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
if plugin_cli.claude_bin():
|
|
51
|
+
# any marketplace the mod came from; one id lists once per scope
|
|
52
|
+
installed = sorted({p["id"] for p in plugin_cli.list_plugins(lambda _msg: None)
|
|
53
|
+
if p["id"].partition("@")[0] == DIST})
|
|
54
|
+
for pid in installed:
|
|
55
|
+
steps += [["claude", "plugin", "marketplace", "update", pid.partition("@")[2]],
|
|
56
|
+
["claude", "plugin", "update", pid]]
|
|
54
57
|
return [*steps, [DIST, "install-shims"]]
|
|
55
58
|
|
|
56
59
|
|
|
@@ -93,12 +96,12 @@ def cache_path() -> Path:
|
|
|
93
96
|
|
|
94
97
|
|
|
95
98
|
def start() -> update_check.Started | None:
|
|
96
|
-
"""Kick off the
|
|
97
|
-
(env AGENT_TOGGLE_UPDATE_CHECK wins) is off. Never raises."""
|
|
99
|
+
"""Kick off the release check (update_kit) on a daemon thread, unless the `update_check`
|
|
100
|
+
setting (env AGENT_TOGGLE_UPDATE_CHECK wins) is off. Never raises."""
|
|
98
101
|
try:
|
|
99
102
|
if not settings.get("update_check"):
|
|
100
103
|
return None
|
|
101
|
-
return update_check.start(
|
|
104
|
+
return update_check.start(__version__, cache_path=cache_path())
|
|
102
105
|
except Exception: # noqa: BLE001 - a hint must never fail the command
|
|
103
106
|
return None
|
|
104
107
|
|
|
@@ -112,7 +115,7 @@ def is_interactive() -> bool:
|
|
|
112
115
|
|
|
113
116
|
def _available(found: update_check.UpdateAvailable) -> str:
|
|
114
117
|
return t("update.available", "agent-toggle %s is available (you have %s)",
|
|
115
|
-
_clean(found.latest), _clean(found.current))
|
|
118
|
+
_clean(found.latest).removeprefix("v"), _clean(found.current))
|
|
116
119
|
|
|
117
120
|
|
|
118
121
|
def hint(found: update_check.UpdateAvailable) -> str:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-toggle
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.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
|
|
@@ -168,6 +168,9 @@ installs above, type this at the prompt of a Claude Code terminal session (2.1.2
|
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
Answer `y` to add the marketplace, pick a scope (user is the default), then run `/agent-toggle`.
|
|
171
|
+
The same mod is also listed in the `weskao-agent-plugins` marketplace
|
|
172
|
+
(`claude plugin marketplace add weskao/weskao-agent-plugins`, then
|
|
173
|
+
`claude plugin install agent-toggle@weskao-agent-plugins`); install it from one of the two, not both.
|
|
171
174
|
|
|
172
175
|
See [Claude Code pane mod](#claude-code-pane-mod).
|
|
173
176
|
|
|
@@ -260,7 +263,7 @@ Flags accepted by every command, before or after the subcommand:
|
|
|
260
263
|
|
|
261
264
|
Extra row fields: `list` rows carry `at`, `mechanism`, `companions`; `cost` rows
|
|
262
265
|
carry `enabled`, `tokens`, `would_save`, `chars`, and the final `total` row
|
|
263
|
-
carries `total_tokens`, `saved_tokens`, `formula`. Rows for a
|
|
266
|
+
carries `total_tokens`, `saved_tokens`, `formula`, `version`. Rows for a
|
|
264
267
|
directory shared with another harness (see below) carry `shared_with`, the other
|
|
265
268
|
harnesses that read it: `disable` / `enable` rows relative to the harness you
|
|
266
269
|
asked, plus `owner`, the harness whose park dir and state entry hold the item;
|
|
@@ -498,7 +501,7 @@ invalid value in either is ignored with one warning on stderr.
|
|
|
498
501
|
|
|
499
502
|
## Update check
|
|
500
503
|
|
|
501
|
-
On every invocation (unless disabled) agent-toggle checks
|
|
504
|
+
On every invocation (unless disabled) agent-toggle checks the repository's release tags for a newer release. It starts
|
|
502
505
|
before the command and is offered after it, on every exit path; it overlaps the command and waits at most 0.8 s afterwards.
|
|
503
506
|
`update` and `completion` skip it.
|
|
504
507
|
|
|
@@ -513,9 +516,9 @@ before the command and is offered after it, on every exit path; it overlaps the
|
|
|
513
516
|
then ` agent-toggle update`.
|
|
514
517
|
- It never changes the exit code or stdout, so `--json` output stays one document.
|
|
515
518
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
+
The lookup is update-kit's: one `git ls-remote --tags --refs` of the repository on a background
|
|
520
|
+
thread, cached for 10 minutes in `~/.update-kit/state.json`. Only the version you chose to skip is
|
|
521
|
+
kept in `~/.agent-toggle/update-check.json`. Nothing is sent beyond a normal git request. See `SECURITY.md`
|
|
519
522
|
for the hardening. To turn it off, set `AGENT_TOGGLE_UPDATE_CHECK=0` or the `update_check` setting
|
|
520
523
|
to off (the settings menu's "Check for updates").
|
|
521
524
|
|
|
@@ -527,9 +530,9 @@ tag (`git ls-remote --tags`) and always installs that tag with
|
|
|
527
530
|
`uv tool install --force --no-sources git+<repo>@<tag>` (`pipx install --force` for a pipx install).
|
|
528
531
|
A dev checkout, a branch or commit install, or an unmanaged install is replaced by the tag too
|
|
529
532
|
(with uv, else pipx); only an install made from exactly that tag is already up to date.
|
|
530
|
-
It then runs, with the new binary and in order: when the Claude Code plugin is installed
|
|
531
|
-
`claude plugin marketplace update
|
|
532
|
-
then `agent-toggle install-shims`. A failing step prints a warning and makes the exit code `1`.
|
|
533
|
+
It then runs, with the new binary and in order: when the Claude Code plugin is installed (from any
|
|
534
|
+
marketplace), `claude plugin marketplace update <marketplace>` and
|
|
535
|
+
`claude plugin update agent-toggle@<marketplace>`, then `agent-toggle install-shims`. A failing step prints a warning and makes the exit code `1`.
|
|
533
536
|
It never prompts and writes to stderr only.
|
|
534
537
|
|
|
535
538
|
| Exit | Meaning |
|
|
@@ -931,7 +934,7 @@ bookkeeping.
|
|
|
931
934
|
| `parked/<sha8>/` | items parked by `--project` (`<sha8>` = first 8 hex of the SHA-1 of the resolved project dir) |
|
|
932
935
|
| `profiles/` | `<name>.json` profiles (dir `0700`, files `0600`) |
|
|
933
936
|
| `config.json` | [settings](#settings--config-menu) and the Telegram chat id (mode `0600`, atomic write, unknown keys kept) |
|
|
934
|
-
| `update-check.json` | the [update check](#update-check)'s
|
|
937
|
+
| `update-check.json` | the [update check](#update-check)'s skipped version (mode `0600`, atomic write) |
|
|
935
938
|
|
|
936
939
|
A killed run loses at most the one item in flight. If that was a flag write or a
|
|
937
940
|
dir move (with its companions), its `pending` record (the full entry, a flag's
|
|
@@ -1011,8 +1014,9 @@ CLI (`cost --json`, `disable|enable --json`) and works for the claude harness on
|
|
|
1011
1014
|
`agent-toggle ui` stays the cross-harness UI.
|
|
1012
1015
|
|
|
1013
1016
|
Install it with `/plugin install agent-toggle --marketplace weskao/agent-toggle` (see
|
|
1014
|
-
[Install](#install));
|
|
1015
|
-
|
|
1017
|
+
[Install](#install)); `/agent-toggle update` picks up a new release: it runs `agent-toggle update`,
|
|
1018
|
+
which updates the CLI, this mod and the shims together (restart Claude Code to load the new mod).
|
|
1019
|
+
The mod and the CLI share one version. To run your own checkout instead (edits reload as you save):
|
|
1016
1020
|
|
|
1017
1021
|
```sh
|
|
1018
1022
|
claude --plugin-dir ./mod # then run /agent-toggle inside Claude
|
|
@@ -1144,8 +1148,10 @@ prints a `::notice::` and exits 0, so it never adds a second red X.
|
|
|
1144
1148
|
## Releasing
|
|
1145
1149
|
|
|
1146
1150
|
A release is a git tag `vX.Y.Z` (where `X.Y.Z` must match `agent_toggle.__version__`).
|
|
1147
|
-
|
|
1148
|
-
|
|
1151
|
+
`version` in `mod/.claude-plugin/plugin.json` must be the same value (the mod ships in lockstep;
|
|
1152
|
+
without the bump `claude plugin update` does not hand marketplace installs the new mod).
|
|
1153
|
+
`tests/test_mod_version.py` and the release workflow both fail on a mismatch.
|
|
1154
|
+
The `weskao-agent-plugins` marketplace lists the mod without a version, so it needs no bump there.
|
|
1149
1155
|
Pushing the tag triggers `.github/workflows/release.yml`:
|
|
1150
1156
|
|
|
1151
1157
|
1. **Build** job checks that the tag matches `__version__`, builds a wheel and
|