agent-toggle 0.13.0__tar.gz → 0.14.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.
Files changed (91) hide show
  1. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/PKG-INFO +61 -29
  2. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/README.md +60 -28
  3. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/__init__.py +1 -1
  4. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/backends/mcp_json.py +6 -4
  5. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/backends/plugin_cli.py +33 -3
  6. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/locales/zh_tw_picker.py +12 -7
  7. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/mechanisms.py +58 -11
  8. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/ui/menu.py +17 -1
  9. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/ui/picker.py +240 -54
  10. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/ui/theme.py +4 -3
  11. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle.egg-info/PKG-INFO +61 -29
  12. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_backends.py +24 -0
  13. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_crash.py +14 -0
  14. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_mechanisms.py +94 -0
  15. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_menu.py +9 -0
  16. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_mods.py +28 -17
  17. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_picker.py +294 -76
  18. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_project.py +17 -0
  19. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_same_name.py +2 -2
  20. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_theme.py +2 -2
  21. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/LICENSE +0 -0
  22. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/__main__.py +0 -0
  23. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/backends/__init__.py +0 -0
  24. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/backends/flag_json.py +0 -0
  25. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/backends/mcp_toml.py +0 -0
  26. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/cli.py +0 -0
  27. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/companions.py +0 -0
  28. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/completions.py +0 -0
  29. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/config.py +0 -0
  30. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/cost.py +0 -0
  31. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/doctor.py +0 -0
  32. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/fs.py +0 -0
  33. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/harnesses.py +0 -0
  34. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/help.py +0 -0
  35. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/i18n.py +0 -0
  36. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/locales/__init__.py +0 -0
  37. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/locales/zh_tw_cli.py +0 -0
  38. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/locales/zh_tw_common.py +0 -0
  39. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/locales/zh_tw_config.py +0 -0
  40. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/ops.py +0 -0
  41. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/output.py +0 -0
  42. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/profiles.py +0 -0
  43. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/settings.py +0 -0
  44. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/shims/claude.md.tmpl +0 -0
  45. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/shims/generic.md.tmpl +0 -0
  46. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/spinner.py +0 -0
  47. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/store.py +0 -0
  48. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/toml_check.py +0 -0
  49. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/ui/__init__.py +0 -0
  50. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/ui/config_menu.py +0 -0
  51. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/ui/logo.py +0 -0
  52. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/ui/model.py +0 -0
  53. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/undo.py +0 -0
  54. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/update_check.py +0 -0
  55. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle/update_prompt.py +0 -0
  56. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle.egg-info/SOURCES.txt +0 -0
  57. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle.egg-info/dependency_links.txt +0 -0
  58. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle.egg-info/entry_points.txt +0 -0
  59. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle.egg-info/requires.txt +0 -0
  60. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/agent_toggle.egg-info/top_level.txt +0 -0
  61. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/pyproject.toml +0 -0
  62. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/setup.cfg +0 -0
  63. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_alias.py +0 -0
  64. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_all_type.py +0 -0
  65. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_cli.py +0 -0
  66. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_cli_surface.py +0 -0
  67. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_color.py +0 -0
  68. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_companions.py +0 -0
  69. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_completions.py +0 -0
  70. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_config.py +0 -0
  71. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_config_menu.py +0 -0
  72. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_conformance.py +0 -0
  73. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_containment.py +0 -0
  74. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_cost.py +0 -0
  75. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_doctor.py +0 -0
  76. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_encoding.py +0 -0
  77. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_fs.py +0 -0
  78. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_harnesses.py +0 -0
  79. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_help.py +0 -0
  80. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_i18n.py +0 -0
  81. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_install.py +0 -0
  82. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_logo.py +0 -0
  83. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_platform.py +0 -0
  84. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_profiles.py +0 -0
  85. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_safety.py +0 -0
  86. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_secret_audit.py +0 -0
  87. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_settings.py +0 -0
  88. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_store.py +0 -0
  89. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_undo.py +0 -0
  90. {agent_toggle-0.13.0 → agent_toggle-0.14.0}/tests/test_update_check.py +0 -0
  91. {agent_toggle-0.13.0 → agent_toggle-0.14.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.13.0
3
+ Version: 0.14.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
@@ -69,7 +69,7 @@ queues the matching reload ([Claude Code pane mod](#claude-code-pane-mod)).
69
69
 
70
70
  | target | native mechanism | the gap |
71
71
  |---|---|---|
72
- | plugin | `claude plugin disable/enable` | fine — this tool just batches it |
72
+ | plugin | `claude plugin disable/enable` | without `-s` the scope follows the current dir, so a project plugin enabled from elsewhere stays off; this tool pins the install's scope and project |
73
73
  | skill | none | moving files by hand hits the rename trap below |
74
74
  | agent | none | same |
75
75
  | command | none | same, plus nested `group/name.md` paths get flattened |
@@ -316,7 +316,7 @@ agent-toggle # same, on a terminal; elsewhere prints help and exits
316
316
  ● delta codex 10 ▏ │ cost 0 now; ~300 tok if restored
317
317
  │ since 2026-09-19 10:00:00
318
318
  5 of 5 shown · 2/5
319
- Space toggle Enter apply Esc cancel ? help / search ←→ harness t type s sort p profile a all
319
+ Tab toggle Enter apply Esc cancel ? help / search ←→ harness t type s sort p profile a all
320
320
  ```
321
321
 
322
322
  What is on screen:
@@ -344,38 +344,54 @@ What is on screen:
344
344
 
345
345
  | key | action |
346
346
  |---|---|
347
- | `Space` | toggle the highlighted row (live / parked) and stay on it (while searching, the first `Space` separates search terms and a second one toggles) |
348
- | `Tab` | toggle the highlighted row and advance to the next |
347
+ | `Tab` | toggle the highlighted row (live / parked) and stay on it, including while searching |
348
+ | `Space` | enter a space in the search (separates search terms) |
349
349
  | `Enter` | apply every staged change (with `--dry-run`: show the plan) |
350
- | `Esc` / `Ctrl-C` | cancel; nothing is applied |
350
+ | `Esc` | leave; if changes are staged, review them in a centered Save changes? dialog |
351
+ | `Ctrl-C` | discard staged changes and leave |
351
352
  | `↑` `↓` `PgUp` `PgDn` `Home` `End`, `Ctrl-P` / `Ctrl-N` | move |
352
- | `/` | start a search; any other non-command letter starts one too. Terms are ANDed, case-insensitive, and match the harness/type/name, the group (`mod` or `mods` finds every mod) and the path; when nothing matches, letters-in-order (fuzzy) is tried: `ctxmd` finds `context-md`, and the bar says `≈ fuzzy match` |
353
+ | `/` | start a search; any letter or digit starts one too. Terms are ANDed, case-insensitive, and match the harness/type/name, the group (`mod` or `mods` finds every mod) and the path; when nothing matches, letters-in-order (fuzzy) is tried: `ctxmd` finds `context-md`, and the bar says `≈ fuzzy match` |
353
354
  | `Backspace` / `Ctrl-U` | delete one character / clear the filter |
354
- | `←` `→` | switch harness tab (also while typing a filter); `0` = All, `1`-`9` = that tab, `h` = next tab |
355
- | `t` | cycle the type filter |
356
- | `s` | cycle sort: name, cost (biggest first); applies within each type group |
357
- | `p` | profiles: stage a saved one, or save the live state (see below) |
355
+ | `←` `→` | switch harness tab (also while typing a filter) |
356
+ | `Ctrl-T` | cycle the type filter |
357
+ | `Ctrl-S` | cycle sort: name, cost (biggest first); applies within each type group |
358
+ | `Ctrl-O` | profiles: stage a saved one, or save the live state (see below) |
358
359
  | `?` | show the key list |
359
- | `a` / `Ctrl-A` | toggle every visible row |
360
- | `n` | toggle every row on this row's harness with the same name, of any type (skill, command, MCP, ...), shown or filtered out; like `disable all <name>` |
360
+ | `Ctrl-A` | toggle every visible row |
361
+ | `Ctrl-E` | toggle every row on this row's harness with the same name, of any type (skill, command, MCP, ...), shown or filtered out; like `disable all <name>` |
361
362
 
362
- The command keys (`t`, `s`, `p`, `h`, `a`, `n`, `0`-`9`, `?`) act only while no filter is active.
363
- Press `/` first to type a filter that begins with one of them; once the filter is non-empty,
364
- every letter just types.
363
+ Commands are `Ctrl` chords, so every letter and digit types into the search, and the chords
364
+ work while a filter is active too. `?` and `/` act only while no filter is active. The picker
365
+ reads keys in raw mode, so `Ctrl-S`, `Ctrl-T` and `Ctrl-O` reach it instead of the terminal
366
+ (flow control, `SIGINFO`, discard).
365
367
 
366
368
  The start view (sort, harness tab, type filter) comes from the `picker_sort`, `picker_harness`
367
369
  and `picker_type` [settings](#settings--config-menu). A profile skips harnesses that are hidden
368
370
  and counts those items as `hidden by settings`; `ui --harness <name>` shows that harness even
369
371
  when it is switched off.
370
372
 
371
- `p` opens a prompt over the list of saved profiles: type a number or name (or
373
+ `Ctrl-O` opens a prompt over the list of saved profiles: type a number or name (or
372
374
  `apply <name>`) and Enter to **stage** that profile's changes (only the items it
373
375
  mentions; ones this machine lacks are skipped), then Enter in the picker applies
374
376
  them like any other change, so `ui --dry-run` previews a profile and a stray
375
- `p` changes nothing. `save <name>` writes the live state (not your staged changes) as
377
+ `Ctrl-O` changes nothing. `save <name>` writes the live state (not your staged changes) as
376
378
  a profile, with the same name rules and project scope as `profile save`; it is
377
379
  off under `--dry-run`. Esc closes the prompt.
378
380
 
381
+ The exit dialog lists all staged changes, including rows hidden by a filter. Choose
382
+ **Yes** to apply and leave, or **No** to discard and leave. Use Left/Right
383
+ to select, Enter to confirm, Y/N shortcuts, or click either button (hovering selects it and underlines it). Esc in the
384
+ dialog returns to editing. Up/Down, PgUp/PgDn, Home/End and the mouse wheel scroll
385
+ a long change list. Its height is capped at 80% of the terminal (up to 24 lines,
386
+ with a compact layout on tiny terminals); the confirmation buttons stay visible.
387
+ Up/Down and the mouse wheel move the selected row, just like the main picker;
388
+ the list scrolls when the selection reaches its edge. Tab or a click toggles the
389
+ row's staged enabled/disabled state. The picker stays visible behind the opaque
390
+ dialog; both are painted together in one refresh to prevent background flashes.
391
+ Reverted rows stay in the review so they can be toggled again; Yes applies only
392
+ the remaining changes. The dialog follows the selected language and color mode;
393
+ with `--dry-run`, Yes only shows the plan.
394
+
379
395
  Nothing happens while the picker is open. Changes are staged, the screen is
380
396
  torn down, and only then do the real operations run, so their output (which
381
397
  companion files moved, which were kept because they are shared) is readable
@@ -390,7 +406,8 @@ numbers (`1 3 5-7`) to tick or untick, `n <number>` to toggle every type with th
390
406
  row's name, `/text` to filter (`/` alone clears it),
391
407
  `s` / `h` / `t` to sort and cycle the harness and type filters, `p` to list profiles,
392
408
  `p <number|name>` to stage one and `p save <name>` to save the live state, `a` to
393
- apply, `q` (or end of input) to cancel.
409
+ apply, `q` to review staged changes with a `y/n` save prompt (no changes: exit
410
+ immediately). End of input discards changes.
394
411
 
395
412
  ### Mods
396
413
 
@@ -408,7 +425,7 @@ plugin: it ships skills, commands, agents, MCP servers or hooks and draws nothin
408
425
  grep -l modules ~/.claude/plugins/cache/*/*/*/hooks/hooks.json
409
426
  ```
410
427
 
411
- - The picker lists mods under **Mods**, right after Plugins. `t` cycles to it, the
428
+ - The picker lists mods under **Mods**, right after Plugins. `Ctrl-T` cycles to it, the
412
429
  `picker_type` setting can open on it, and a search for `mod` or `mods` finds every mod.
413
430
  The detail pane shows its type as `mod (plugin)`.
414
431
  - A mod is still a plugin everywhere else: it toggles through `claude plugin
@@ -534,7 +551,9 @@ logo, centred, when the window is tall enough to fit the whole menu beside it; t
534
551
  | agy | `~/.gemini/config` | ✓ | — | — | — | — | ✓ `mcp_config.json` |
535
552
 
536
553
  Per-harness locations, mechanisms and the harness versions this was checked
537
- against are in [docs/harnesses.md](docs/harnesses.md).
554
+ against are in [docs/harnesses.md](docs/harnesses.md). What `disable` and `enable`
555
+ change on disk for each type, with example live, parked and backup paths, is in
556
+ [docs/toggle-paths.md](docs/toggle-paths.md).
538
557
 
539
558
  **Homes per OS.** Every `~` above is Python's `Path.home()`: `$HOME` on macOS and
540
559
  Linux, `%USERPROFILE%` on Windows (so `~/.claude` is `C:\Users\<you>\.claude`).
@@ -551,8 +570,13 @@ Plugin ids are passed to `claude plugin ...`, which on Windows runs through
551
570
 
552
571
  Copilot's `config.json` is machine-managed and never edited by this tool; Copilot
553
572
  plugins are not yet supported. `claude` plugins are toggled through `claude
554
- plugin enable/disable`; `openclaw` plugins through a config flag (see [Assumed
555
- formats](#assumed-formats)). Codex has no plugin CLI this tool can drive: `disable
573
+ plugin enable/disable -s <scope>`. The scope comes from the plugin's one install in
574
+ `~/.claude/plugins/installed_plugins.json`, and a project or local install runs in its
575
+ project dir, so a disable and an enable from different directories still hit the same
576
+ setting. With several installs of one id, the CLI picks the scope from the current dir;
577
+ `enable` then runs in the dir the disable ran in. Details are in
578
+ [docs/toggle-paths.md](docs/toggle-paths.md#plugins). `openclaw` plugins are toggled
579
+ through a config flag (see [Assumed formats](#assumed-formats)). Codex has no plugin CLI this tool can drive: `disable
556
580
  plugin x --harness codex` exits `4`, which is why the matrix leaves it unchecked.
557
581
 
558
582
  Flag items (openclaw plugins and flagged skills, opencode mcp) are toggled with
@@ -623,6 +647,11 @@ visible rather than silent.
623
647
  MCP changes need a **new session** to take effect, except in a Claude Code session running the
624
648
  agent-toggle mod, which runs `/mcp disable|enable <name>` for you (see the mod section).
625
649
 
650
+ `/mcp disable <name>` also lists the server in that project's `disabledMcpServers` in
651
+ `~/.claude.json`. Left there, a restored server would stay off in that project, so `enable`
652
+ removes the name again: from every project for a user- or local-scope server, and only from
653
+ that repo and the dirs inside it for a `--project` `.mcp.json` server.
654
+
626
655
  ### Claude MCP scopes
627
656
 
628
657
  Both scopes stored in `~/.claude.json` are togglable, and the scope round-trips:
@@ -977,20 +1006,20 @@ claude --plugin-dir ./mod # then run /agent-toggle inside Claude
977
1006
  and the first and last list lines count the rows out of view (`↑ 4`, `↓ 12`).
978
1007
  - The mouse wheel over the list moves the cursor, as in the terminal picker; no click needed.
979
1008
  - Click the list once so it takes keys (Esc hands the keyboard back to the prompt). Then `↑` `↓`
980
- `PgUp` `PgDn` `Home` `End` (also `Ctrl-P` / `Ctrl-N`) move; `Space` or `Enter` toggles the row,
981
- `Tab` toggles and moves on; `/` or any other letter starts a search (terms ANDed over
982
- `type/name` and the group, letters-in-order if nothing matches; a second `Space` toggles);
983
- `s` sorts by name or cost; `n` toggles every type with this row's name (skill, command, MCP,
1009
+ `PgUp` `PgDn` `Home` `End` (also `Ctrl-P` / `Ctrl-N`) move; `Tab` toggles the row
1010
+ and stays on it, including while searching; `/` or any letter starts a search (terms ANDed over
1011
+ `type/name` and the group, letters-in-order if nothing matches; `Space` separates terms);
1012
+ `Ctrl-S` sorts by name or cost; `Ctrl-E` toggles every type with this row's name (skill, command, MCP,
984
1013
  ...), like `disable all <name>`; `Ctrl-U` clears the search. A click moves the cursor.
985
1014
  - A toggle applies at once (no staging, no Enter to apply); the toast names the target and the state
986
1015
  with an emoji and a bracketed tag (no colour codes, so nothing garbles; on the Linux console and the
987
1016
  legacy Windows console, where emoji draw as boxes, the tag alone): `✅ [ENABLED] skill: foo`, `⛔ [DISABLED] mod: bar (/reload-plugins)`,
988
- `⛔ [DISABLED] rule: baz (takes effect in a new session)`, `⛔ [DISABLED] all: foo` after `n`, or `❌ [FAILED] disable skill: foo - <error>`.
1017
+ `⛔ [DISABLED] rule: baz (takes effect in a new session)`, `⛔ [DISABLED] all: foo` after `Ctrl-E`, or `❌ [FAILED] disable skill: foo - <error>`.
989
1018
  The row flips the moment you press (and flips back
990
1019
  if the CLI fails); the list reloads in the background. While a toggle runs, further keys are ignored.
991
1020
  - Opening the pane shows the same braille spinner and `Loading resources…` as `agent-toggle ui`
992
1021
  until the list arrives, and a spinner beside `working…` while a toggle runs.
993
- - Not in the pane: harness tabs (claude only), and the `t` `p` `a` keys. Where Claude draws no
1022
+ - Not in the pane: harness tabs (claude only), and the `Ctrl-T` `Ctrl-O` `Ctrl-A` keys. Where Claude draws no
994
1023
  such pane (the mobile app, VS Code) it is a plain list of buttons instead.
995
1024
  - `/agent-toggle <command> ...` with `disable`, `enable`,
996
1025
  `undo`, `list`, `status`, `cost` or `doctor` runs the CLI instead of opening the pane and prints
@@ -1001,6 +1030,9 @@ claude --plugin-dir ./mod # then run /agent-toggle inside Claude
1001
1030
  `/reload-plugins`, an MCP server `/mcp disable|enable <name>`. The toast names it, e.g.
1002
1031
  `⛔ [DISABLED] skill: foo (/reload-skills)`. Agents and rules have no reload and still say
1003
1032
  `takes effect in a new session`. If Claude refuses a queued command, a toast says so.
1033
+ `/reload-skills` and `/reload-plugins` only re-read what is on disk. `/mcp disable` also
1034
+ leaves the per-project mark that `enable` clears (see
1035
+ [MCP backups are verbatim](#mcp-backups-are-verbatim)).
1004
1036
  - `agent-toggle ui` in another terminal applies on Enter and writes the Claude rows it changed to
1005
1037
  `~/.agent-toggle/reload.json`. Every open session running the mod checks that file's mtime every
1006
1038
  5 s (one `stat`) and queues the same reloads, toasting `agent-toggle ui: /reload-skills`. A file
@@ -36,7 +36,7 @@ queues the matching reload ([Claude Code pane mod](#claude-code-pane-mod)).
36
36
 
37
37
  | target | native mechanism | the gap |
38
38
  |---|---|---|
39
- | plugin | `claude plugin disable/enable` | fine — this tool just batches it |
39
+ | plugin | `claude plugin disable/enable` | without `-s` the scope follows the current dir, so a project plugin enabled from elsewhere stays off; this tool pins the install's scope and project |
40
40
  | skill | none | moving files by hand hits the rename trap below |
41
41
  | agent | none | same |
42
42
  | command | none | same, plus nested `group/name.md` paths get flattened |
@@ -283,7 +283,7 @@ agent-toggle # same, on a terminal; elsewhere prints help and exits
283
283
  ● delta codex 10 ▏ │ cost 0 now; ~300 tok if restored
284
284
  │ since 2026-09-19 10:00:00
285
285
  5 of 5 shown · 2/5
286
- Space toggle Enter apply Esc cancel ? help / search ←→ harness t type s sort p profile a all
286
+ Tab toggle Enter apply Esc cancel ? help / search ←→ harness t type s sort p profile a all
287
287
  ```
288
288
 
289
289
  What is on screen:
@@ -311,38 +311,54 @@ What is on screen:
311
311
 
312
312
  | key | action |
313
313
  |---|---|
314
- | `Space` | toggle the highlighted row (live / parked) and stay on it (while searching, the first `Space` separates search terms and a second one toggles) |
315
- | `Tab` | toggle the highlighted row and advance to the next |
314
+ | `Tab` | toggle the highlighted row (live / parked) and stay on it, including while searching |
315
+ | `Space` | enter a space in the search (separates search terms) |
316
316
  | `Enter` | apply every staged change (with `--dry-run`: show the plan) |
317
- | `Esc` / `Ctrl-C` | cancel; nothing is applied |
317
+ | `Esc` | leave; if changes are staged, review them in a centered Save changes? dialog |
318
+ | `Ctrl-C` | discard staged changes and leave |
318
319
  | `↑` `↓` `PgUp` `PgDn` `Home` `End`, `Ctrl-P` / `Ctrl-N` | move |
319
- | `/` | start a search; any other non-command letter starts one too. Terms are ANDed, case-insensitive, and match the harness/type/name, the group (`mod` or `mods` finds every mod) and the path; when nothing matches, letters-in-order (fuzzy) is tried: `ctxmd` finds `context-md`, and the bar says `≈ fuzzy match` |
320
+ | `/` | start a search; any letter or digit starts one too. Terms are ANDed, case-insensitive, and match the harness/type/name, the group (`mod` or `mods` finds every mod) and the path; when nothing matches, letters-in-order (fuzzy) is tried: `ctxmd` finds `context-md`, and the bar says `≈ fuzzy match` |
320
321
  | `Backspace` / `Ctrl-U` | delete one character / clear the filter |
321
- | `←` `→` | switch harness tab (also while typing a filter); `0` = All, `1`-`9` = that tab, `h` = next tab |
322
- | `t` | cycle the type filter |
323
- | `s` | cycle sort: name, cost (biggest first); applies within each type group |
324
- | `p` | profiles: stage a saved one, or save the live state (see below) |
322
+ | `←` `→` | switch harness tab (also while typing a filter) |
323
+ | `Ctrl-T` | cycle the type filter |
324
+ | `Ctrl-S` | cycle sort: name, cost (biggest first); applies within each type group |
325
+ | `Ctrl-O` | profiles: stage a saved one, or save the live state (see below) |
325
326
  | `?` | show the key list |
326
- | `a` / `Ctrl-A` | toggle every visible row |
327
- | `n` | toggle every row on this row's harness with the same name, of any type (skill, command, MCP, ...), shown or filtered out; like `disable all <name>` |
327
+ | `Ctrl-A` | toggle every visible row |
328
+ | `Ctrl-E` | toggle every row on this row's harness with the same name, of any type (skill, command, MCP, ...), shown or filtered out; like `disable all <name>` |
328
329
 
329
- The command keys (`t`, `s`, `p`, `h`, `a`, `n`, `0`-`9`, `?`) act only while no filter is active.
330
- Press `/` first to type a filter that begins with one of them; once the filter is non-empty,
331
- every letter just types.
330
+ Commands are `Ctrl` chords, so every letter and digit types into the search, and the chords
331
+ work while a filter is active too. `?` and `/` act only while no filter is active. The picker
332
+ reads keys in raw mode, so `Ctrl-S`, `Ctrl-T` and `Ctrl-O` reach it instead of the terminal
333
+ (flow control, `SIGINFO`, discard).
332
334
 
333
335
  The start view (sort, harness tab, type filter) comes from the `picker_sort`, `picker_harness`
334
336
  and `picker_type` [settings](#settings--config-menu). A profile skips harnesses that are hidden
335
337
  and counts those items as `hidden by settings`; `ui --harness <name>` shows that harness even
336
338
  when it is switched off.
337
339
 
338
- `p` opens a prompt over the list of saved profiles: type a number or name (or
340
+ `Ctrl-O` opens a prompt over the list of saved profiles: type a number or name (or
339
341
  `apply <name>`) and Enter to **stage** that profile's changes (only the items it
340
342
  mentions; ones this machine lacks are skipped), then Enter in the picker applies
341
343
  them like any other change, so `ui --dry-run` previews a profile and a stray
342
- `p` changes nothing. `save <name>` writes the live state (not your staged changes) as
344
+ `Ctrl-O` changes nothing. `save <name>` writes the live state (not your staged changes) as
343
345
  a profile, with the same name rules and project scope as `profile save`; it is
344
346
  off under `--dry-run`. Esc closes the prompt.
345
347
 
348
+ The exit dialog lists all staged changes, including rows hidden by a filter. Choose
349
+ **Yes** to apply and leave, or **No** to discard and leave. Use Left/Right
350
+ to select, Enter to confirm, Y/N shortcuts, or click either button (hovering selects it and underlines it). Esc in the
351
+ dialog returns to editing. Up/Down, PgUp/PgDn, Home/End and the mouse wheel scroll
352
+ a long change list. Its height is capped at 80% of the terminal (up to 24 lines,
353
+ with a compact layout on tiny terminals); the confirmation buttons stay visible.
354
+ Up/Down and the mouse wheel move the selected row, just like the main picker;
355
+ the list scrolls when the selection reaches its edge. Tab or a click toggles the
356
+ row's staged enabled/disabled state. The picker stays visible behind the opaque
357
+ dialog; both are painted together in one refresh to prevent background flashes.
358
+ Reverted rows stay in the review so they can be toggled again; Yes applies only
359
+ the remaining changes. The dialog follows the selected language and color mode;
360
+ with `--dry-run`, Yes only shows the plan.
361
+
346
362
  Nothing happens while the picker is open. Changes are staged, the screen is
347
363
  torn down, and only then do the real operations run, so their output (which
348
364
  companion files moved, which were kept because they are shared) is readable
@@ -357,7 +373,8 @@ numbers (`1 3 5-7`) to tick or untick, `n <number>` to toggle every type with th
357
373
  row's name, `/text` to filter (`/` alone clears it),
358
374
  `s` / `h` / `t` to sort and cycle the harness and type filters, `p` to list profiles,
359
375
  `p <number|name>` to stage one and `p save <name>` to save the live state, `a` to
360
- apply, `q` (or end of input) to cancel.
376
+ apply, `q` to review staged changes with a `y/n` save prompt (no changes: exit
377
+ immediately). End of input discards changes.
361
378
 
362
379
  ### Mods
363
380
 
@@ -375,7 +392,7 @@ plugin: it ships skills, commands, agents, MCP servers or hooks and draws nothin
375
392
  grep -l modules ~/.claude/plugins/cache/*/*/*/hooks/hooks.json
376
393
  ```
377
394
 
378
- - The picker lists mods under **Mods**, right after Plugins. `t` cycles to it, the
395
+ - The picker lists mods under **Mods**, right after Plugins. `Ctrl-T` cycles to it, the
379
396
  `picker_type` setting can open on it, and a search for `mod` or `mods` finds every mod.
380
397
  The detail pane shows its type as `mod (plugin)`.
381
398
  - A mod is still a plugin everywhere else: it toggles through `claude plugin
@@ -501,7 +518,9 @@ logo, centred, when the window is tall enough to fit the whole menu beside it; t
501
518
  | agy | `~/.gemini/config` | ✓ | — | — | — | — | ✓ `mcp_config.json` |
502
519
 
503
520
  Per-harness locations, mechanisms and the harness versions this was checked
504
- against are in [docs/harnesses.md](docs/harnesses.md).
521
+ against are in [docs/harnesses.md](docs/harnesses.md). What `disable` and `enable`
522
+ change on disk for each type, with example live, parked and backup paths, is in
523
+ [docs/toggle-paths.md](docs/toggle-paths.md).
505
524
 
506
525
  **Homes per OS.** Every `~` above is Python's `Path.home()`: `$HOME` on macOS and
507
526
  Linux, `%USERPROFILE%` on Windows (so `~/.claude` is `C:\Users\<you>\.claude`).
@@ -518,8 +537,13 @@ Plugin ids are passed to `claude plugin ...`, which on Windows runs through
518
537
 
519
538
  Copilot's `config.json` is machine-managed and never edited by this tool; Copilot
520
539
  plugins are not yet supported. `claude` plugins are toggled through `claude
521
- plugin enable/disable`; `openclaw` plugins through a config flag (see [Assumed
522
- formats](#assumed-formats)). Codex has no plugin CLI this tool can drive: `disable
540
+ plugin enable/disable -s <scope>`. The scope comes from the plugin's one install in
541
+ `~/.claude/plugins/installed_plugins.json`, and a project or local install runs in its
542
+ project dir, so a disable and an enable from different directories still hit the same
543
+ setting. With several installs of one id, the CLI picks the scope from the current dir;
544
+ `enable` then runs in the dir the disable ran in. Details are in
545
+ [docs/toggle-paths.md](docs/toggle-paths.md#plugins). `openclaw` plugins are toggled
546
+ through a config flag (see [Assumed formats](#assumed-formats)). Codex has no plugin CLI this tool can drive: `disable
523
547
  plugin x --harness codex` exits `4`, which is why the matrix leaves it unchecked.
524
548
 
525
549
  Flag items (openclaw plugins and flagged skills, opencode mcp) are toggled with
@@ -590,6 +614,11 @@ visible rather than silent.
590
614
  MCP changes need a **new session** to take effect, except in a Claude Code session running the
591
615
  agent-toggle mod, which runs `/mcp disable|enable <name>` for you (see the mod section).
592
616
 
617
+ `/mcp disable <name>` also lists the server in that project's `disabledMcpServers` in
618
+ `~/.claude.json`. Left there, a restored server would stay off in that project, so `enable`
619
+ removes the name again: from every project for a user- or local-scope server, and only from
620
+ that repo and the dirs inside it for a `--project` `.mcp.json` server.
621
+
593
622
  ### Claude MCP scopes
594
623
 
595
624
  Both scopes stored in `~/.claude.json` are togglable, and the scope round-trips:
@@ -944,20 +973,20 @@ claude --plugin-dir ./mod # then run /agent-toggle inside Claude
944
973
  and the first and last list lines count the rows out of view (`↑ 4`, `↓ 12`).
945
974
  - The mouse wheel over the list moves the cursor, as in the terminal picker; no click needed.
946
975
  - Click the list once so it takes keys (Esc hands the keyboard back to the prompt). Then `↑` `↓`
947
- `PgUp` `PgDn` `Home` `End` (also `Ctrl-P` / `Ctrl-N`) move; `Space` or `Enter` toggles the row,
948
- `Tab` toggles and moves on; `/` or any other letter starts a search (terms ANDed over
949
- `type/name` and the group, letters-in-order if nothing matches; a second `Space` toggles);
950
- `s` sorts by name or cost; `n` toggles every type with this row's name (skill, command, MCP,
976
+ `PgUp` `PgDn` `Home` `End` (also `Ctrl-P` / `Ctrl-N`) move; `Tab` toggles the row
977
+ and stays on it, including while searching; `/` or any letter starts a search (terms ANDed over
978
+ `type/name` and the group, letters-in-order if nothing matches; `Space` separates terms);
979
+ `Ctrl-S` sorts by name or cost; `Ctrl-E` toggles every type with this row's name (skill, command, MCP,
951
980
  ...), like `disable all <name>`; `Ctrl-U` clears the search. A click moves the cursor.
952
981
  - A toggle applies at once (no staging, no Enter to apply); the toast names the target and the state
953
982
  with an emoji and a bracketed tag (no colour codes, so nothing garbles; on the Linux console and the
954
983
  legacy Windows console, where emoji draw as boxes, the tag alone): `✅ [ENABLED] skill: foo`, `⛔ [DISABLED] mod: bar (/reload-plugins)`,
955
- `⛔ [DISABLED] rule: baz (takes effect in a new session)`, `⛔ [DISABLED] all: foo` after `n`, or `❌ [FAILED] disable skill: foo - <error>`.
984
+ `⛔ [DISABLED] rule: baz (takes effect in a new session)`, `⛔ [DISABLED] all: foo` after `Ctrl-E`, or `❌ [FAILED] disable skill: foo - <error>`.
956
985
  The row flips the moment you press (and flips back
957
986
  if the CLI fails); the list reloads in the background. While a toggle runs, further keys are ignored.
958
987
  - Opening the pane shows the same braille spinner and `Loading resources…` as `agent-toggle ui`
959
988
  until the list arrives, and a spinner beside `working…` while a toggle runs.
960
- - Not in the pane: harness tabs (claude only), and the `t` `p` `a` keys. Where Claude draws no
989
+ - Not in the pane: harness tabs (claude only), and the `Ctrl-T` `Ctrl-O` `Ctrl-A` keys. Where Claude draws no
961
990
  such pane (the mobile app, VS Code) it is a plain list of buttons instead.
962
991
  - `/agent-toggle <command> ...` with `disable`, `enable`,
963
992
  `undo`, `list`, `status`, `cost` or `doctor` runs the CLI instead of opening the pane and prints
@@ -968,6 +997,9 @@ claude --plugin-dir ./mod # then run /agent-toggle inside Claude
968
997
  `/reload-plugins`, an MCP server `/mcp disable|enable <name>`. The toast names it, e.g.
969
998
  `⛔ [DISABLED] skill: foo (/reload-skills)`. Agents and rules have no reload and still say
970
999
  `takes effect in a new session`. If Claude refuses a queued command, a toast says so.
1000
+ `/reload-skills` and `/reload-plugins` only re-read what is on disk. `/mcp disable` also
1001
+ leaves the per-project mark that `enable` clears (see
1002
+ [MCP backups are verbatim](#mcp-backups-are-verbatim)).
971
1003
  - `agent-toggle ui` in another terminal applies on Enter and writes the Claude rows it changed to
972
1004
  `~/.agent-toggle/reload.json`. Every open session running the mod checks that file's mtime every
973
1005
  5 s (one `stat`) and queues the same reloads, toasting `agent-toggle ui: /reload-skills`. A file
@@ -1,3 +1,3 @@
1
1
  """agent-toggle: temporarily disable / re-enable AI-agent resources."""
2
2
 
3
- __version__ = "0.13.0"
3
+ __version__ = "0.14.0"
@@ -58,11 +58,12 @@ def claudeai_connector_names() -> set[str]:
58
58
  return set(cfg.get("claudeAiMcpEverConnected", []) or [])
59
59
 
60
60
 
61
- def toggle_claudeai_connector(action: str, name: str,
62
- dry_run: bool = False) -> tuple[bool, list | str]:
61
+ def toggle_claudeai_connector(action: str, name: str, dry_run: bool = False,
62
+ under: Path | None = None) -> tuple[bool, list | str]:
63
63
  """Fan a claude.ai connector on/off across every EXISTING project entry
64
64
  in ~/.claude.json's disabledMcpServers list -- the only place /mcp writes
65
- that state; no `claude mcp` CLI verb reaches it.
65
+ that state; no `claude mcp` CLI verb reaches it. `under`: only the project
66
+ entries that are that dir or inside it.
66
67
 
67
68
  ponytail: covers projects that exist now; a project dir opened for the
68
69
  first time later starts without the entry until this is re-run for it.
@@ -75,7 +76,8 @@ def toggle_claudeai_connector(action: str, name: str,
75
76
 
76
77
  touched = []
77
78
  for proj, pdata in cfg.get("projects", {}).items():
78
- if not isinstance(pdata, dict):
79
+ if not isinstance(pdata, dict) or (
80
+ under is not None and under != Path(proj) and under not in Path(proj).parents):
79
81
  continue
80
82
  cur = pdata.get("disabledMcpServers") or []
81
83
  has = name in cur
@@ -10,6 +10,7 @@ import os
10
10
  import shutil
11
11
  import subprocess
12
12
  import sys
13
+ from pathlib import Path
13
14
  from typing import Callable
14
15
 
15
16
  from .. import fs
@@ -17,6 +18,8 @@ from .. import fs
17
18
  which = shutil.which
18
19
  runner = subprocess.run
19
20
 
21
+ PLUGIN_SCOPES = ("user", "project", "local") # `claude plugin enable|disable -s`
22
+
20
23
  TIMEOUT_ENV = "AGENT_TOGGLE_CLI_TIMEOUT"
21
24
  MUTATE_TIMEOUT = 120 # enable / disable / install / mcp add|remove: may fetch from a marketplace
22
25
  READ_TIMEOUT = 30 # read-only `plugin list`
@@ -68,12 +71,39 @@ def run_cli(binary: str | None, args: list[str], cwd: str | None = None,
68
71
  return p.returncode == 0, (p.stdout + p.stderr).strip()
69
72
 
70
73
 
71
- def list_plugins(warn: Callable[[str], None]) -> list[dict]:
72
- """`claude plugin list --json` through the injectable runner; [] when unavailable."""
74
+ def plugin_where(name: str, claude_home: Path) -> tuple[str | None, str | None]:
75
+ """(scope, cwd) of plugin `name`'s one install, from Claude Code's install registry
76
+ (`<claude_home>/plugins/installed_plugins.json`; a bare name: its one `name@mkt` id).
77
+
78
+ Without `-s` the CLI picks the scope from its cwd, so a project-scope plugin toggled
79
+ from another dir lands in user scope. (None, None) when the registry cannot say --
80
+ absent, another shape, several installs, a project dir that is gone: the caller
81
+ then lets the CLI auto-detect, as before. A file read, not `claude plugin list`
82
+ (~0.8 s per call, paid on every pane toggle)."""
83
+ try:
84
+ reg = json.loads((claude_home / "plugins" / "installed_plugins.json")
85
+ .read_text(encoding="utf-8"))
86
+ rows = [r for k, v in reg["plugins"].items()
87
+ if k == name or ("@" not in name and k.partition("@")[0] == name) for r in v]
88
+ except (OSError, ValueError, KeyError, TypeError, AttributeError):
89
+ return None, None
90
+ if len(rows) != 1 or not isinstance(rows[0], dict) or rows[0].get("scope") not in PLUGIN_SCOPES:
91
+ return None, None
92
+ scope, proj = rows[0]["scope"], rows[0].get("projectPath")
93
+ if scope == "user":
94
+ return scope, None
95
+ if isinstance(proj, str) and os.path.isabs(proj) and os.path.isdir(proj):
96
+ return scope, proj
97
+ return None, None
98
+
99
+
100
+ def list_plugins(warn: Callable[[str], None], cwd: str | None = None) -> list[dict]:
101
+ """`claude plugin list --json` through the injectable runner; [] when unavailable.
102
+ `cwd`: its `enabled` is the plugin's state as seen from there."""
73
103
  exe = claude_bin()
74
104
  if not exe:
75
105
  return []
76
- ok, text = run_cli(exe, ["plugin", "list", "--json"], timeout=READ_TIMEOUT)
106
+ ok, text = run_cli(exe, ["plugin", "list", "--json"], cwd=cwd, timeout=READ_TIMEOUT)
77
107
  try: # run_cli merges stderr into the text: skip any notice before the array
78
108
  data = json.JSONDecoder().raw_decode(text, max(text.find("["), 0))[0] if ok else None
79
109
  except ValueError:
@@ -25,10 +25,10 @@ CATALOG: dict[str, str] = {
25
25
  "picker.loading": "載入資源中…",
26
26
  "picker.filter.type": "類型:",
27
27
  "picker.filter.sort": "排序:",
28
- "picker.empty": "沒有符合的項目 -- Ctrl-U 清除篩選,Left/Right 換 harness,t 換類型",
28
+ "picker.empty": "沒有符合的項目 -- Ctrl-U 清除篩選,Left/Right 換 harness,Ctrl-T 換類型",
29
29
  "picker.status.shown": "顯示 %s / %s",
30
30
  "picker.status.dry_run": "試跑:Enter 只顯示計畫",
31
- "picker.status.leave": "Ctrl+C 離開 · 自動儲存",
31
+ "picker.chip.leave": "離開/檢視變更",
32
32
  "picker.badge.shared": "+共用",
33
33
  # detail pane
34
34
  "picker.state.live": "啟用",
@@ -49,7 +49,7 @@ CATALOG: dict[str, str] = {
49
49
  # key chips
50
50
  "picker.chip.toggle": "切換",
51
51
  "picker.chip.apply": "套用",
52
- "picker.chip.cancel": "取消",
52
+ "picker.chip.cancel": "放棄",
53
53
  "picker.chip.help": "說明",
54
54
  "picker.chip.filter": "搜尋",
55
55
  "picker.chip.harness": "harness",
@@ -64,12 +64,17 @@ CATALOG: dict[str, str] = {
64
64
  "picker.help.title": "按鍵",
65
65
  "picker.help.move": "移動(也可用 Ctrl-P / Ctrl-N)",
66
66
  "picker.help.toggle": "切換此列(啟用 <-> 停用),停留在該列",
67
- "picker.help.toggle_next": "切換此列,然後移到下一列",
68
67
  "picker.help.apply": "套用暫存的變更(--dry-run:只看計畫)",
69
- "picker.help.cancel": "取消;不做任何變更",
70
- "picker.help.filter": "搜尋名稱 / harness / 路徑(可模糊);直接打其他字母也會開始搜尋",
68
+ "picker.help.cancel": "離開;有暫存變更時先詢問是否儲存",
69
+ "picker.help.discard": "放棄變更並離開",
70
+ "picker.save.title": "儲存變更?",
71
+ "picker.save.count": "%s 項變更",
72
+ "picker.save.yes": "是",
73
+ "picker.save.no": "否",
74
+ "picker.save.keys": "Tab/點擊 切換 · 上下 移動 · Enter 確認 · Esc 返回",
75
+ "picker.help.filter": "搜尋名稱 / harness / 路徑(可模糊);直接打任何字母或數字也會開始搜尋",
71
76
  "picker.help.edit": "編輯 / 清除篩選",
72
- "picker.help.harness": "harness 分頁(0 = 全部)",
77
+ "picker.help.harness": "harness 分頁",
73
78
  "picker.help.type": "循環切換類型篩選",
74
79
  "picker.help.sort": "循環切換排序:名稱 / 成本(由大到小)",
75
80
  "picker.help.profile": "設定檔:暫存一個,或儲存目前啟用的狀態",