agent-cli 0.70.2__py3-none-any.whl → 0.72.1__py3-none-any.whl
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_cli/_extras.json +4 -3
- agent_cli/_requirements/memory.txt +14 -1
- agent_cli/_requirements/rag.txt +14 -1
- agent_cli/_requirements/vad.txt +1 -85
- agent_cli/_requirements/wyoming.txt +71 -0
- agent_cli/agents/assistant.py +24 -28
- agent_cli/agents/autocorrect.py +30 -4
- agent_cli/agents/chat.py +45 -15
- agent_cli/agents/memory/__init__.py +19 -1
- agent_cli/agents/memory/add.py +3 -3
- agent_cli/agents/memory/proxy.py +20 -11
- agent_cli/agents/rag_proxy.py +42 -10
- agent_cli/agents/speak.py +23 -3
- agent_cli/agents/transcribe.py +21 -3
- agent_cli/agents/transcribe_daemon.py +34 -22
- agent_cli/agents/voice_edit.py +18 -10
- agent_cli/cli.py +25 -2
- agent_cli/config_cmd.py +30 -11
- agent_cli/core/deps.py +6 -3
- agent_cli/core/transcription_logger.py +1 -1
- agent_cli/core/vad.py +6 -24
- agent_cli/dev/cli.py +295 -65
- agent_cli/docs_gen.py +18 -8
- agent_cli/install/extras.py +44 -13
- agent_cli/install/hotkeys.py +22 -11
- agent_cli/install/services.py +54 -14
- agent_cli/opts.py +43 -22
- agent_cli/server/cli.py +128 -62
- agent_cli/server/proxy/api.py +77 -19
- agent_cli/services/__init__.py +46 -5
- {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/METADATA +627 -246
- {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/RECORD +35 -34
- {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/WHEEL +0 -0
- {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/entry_points.txt +0 -0
- {agent_cli-0.70.2.dist-info → agent_cli-0.72.1.dist-info}/licenses/LICENSE +0 -0
agent_cli/dev/cli.py
CHANGED
|
@@ -114,7 +114,27 @@ if TYPE_CHECKING:
|
|
|
114
114
|
|
|
115
115
|
app = typer.Typer(
|
|
116
116
|
name="dev",
|
|
117
|
-
help="Parallel development environment manager using git worktrees.
|
|
117
|
+
help="""Parallel development environment manager using git worktrees.
|
|
118
|
+
|
|
119
|
+
Creates isolated working directories for each feature branch, allowing you to
|
|
120
|
+
work on multiple features simultaneously without stashing changes. Each worktree
|
|
121
|
+
has its own branch and working directory.
|
|
122
|
+
|
|
123
|
+
**Common workflows:**
|
|
124
|
+
|
|
125
|
+
- `dev new feature-x -a` — Create worktree + start AI agent in new terminal tab
|
|
126
|
+
- `dev new feature-x -e -a` — Create worktree + open editor + start agent
|
|
127
|
+
- `dev new -a -p "Fix the auth bug"` — Create worktree + start agent with prompt
|
|
128
|
+
- `dev status` — See all worktrees with uncommitted changes
|
|
129
|
+
- `dev clean --merged` — Remove worktrees whose PRs are merged
|
|
130
|
+
|
|
131
|
+
**Automatic features:**
|
|
132
|
+
|
|
133
|
+
- Project setup (npm install, poetry install, uv sync, etc.)
|
|
134
|
+
- Environment file copying (.env, .env.local)
|
|
135
|
+
- Direnv setup (.envrc generation)
|
|
136
|
+
- Git submodules and LFS initialization
|
|
137
|
+
""",
|
|
118
138
|
add_completion=True,
|
|
119
139
|
rich_markup_mode="markdown",
|
|
120
140
|
no_args_is_help=True,
|
|
@@ -130,7 +150,11 @@ def dev_callback(
|
|
|
130
150
|
typer.Option("--config", "-c", help="Path to config file"),
|
|
131
151
|
] = None,
|
|
132
152
|
) -> None:
|
|
133
|
-
"""Parallel development environment manager using git worktrees.
|
|
153
|
+
"""Parallel development environment manager using git worktrees.
|
|
154
|
+
|
|
155
|
+
Creates isolated working directories for each feature branch. Each worktree
|
|
156
|
+
has its own branch, allowing parallel development without stashing changes.
|
|
157
|
+
"""
|
|
134
158
|
set_config_defaults(ctx, config_file)
|
|
135
159
|
if ctx.invoked_subcommand is not None:
|
|
136
160
|
set_process_title(f"dev-{ctx.invoked_subcommand}")
|
|
@@ -478,27 +502,47 @@ def _launch_agent(
|
|
|
478
502
|
def new( # noqa: C901, PLR0912, PLR0915
|
|
479
503
|
branch: Annotated[
|
|
480
504
|
str | None,
|
|
481
|
-
typer.Argument(
|
|
505
|
+
typer.Argument(
|
|
506
|
+
help="Branch name for the worktree. If omitted, generates a random name like 'clever-fox'",
|
|
507
|
+
),
|
|
482
508
|
] = None,
|
|
483
509
|
from_ref: Annotated[
|
|
484
510
|
str | None,
|
|
485
|
-
typer.Option(
|
|
511
|
+
typer.Option(
|
|
512
|
+
"--from",
|
|
513
|
+
"-f",
|
|
514
|
+
help="Git ref (branch/tag/commit) to branch from. Defaults to origin/main or origin/master",
|
|
515
|
+
),
|
|
486
516
|
] = None,
|
|
487
517
|
editor: Annotated[
|
|
488
518
|
bool,
|
|
489
|
-
typer.Option(
|
|
519
|
+
typer.Option(
|
|
520
|
+
"--editor",
|
|
521
|
+
"-e",
|
|
522
|
+
help="Open the worktree in an editor. Uses --with-editor, config default, or auto-detects",
|
|
523
|
+
),
|
|
490
524
|
] = False,
|
|
491
525
|
agent: Annotated[
|
|
492
526
|
bool,
|
|
493
|
-
typer.Option(
|
|
527
|
+
typer.Option(
|
|
528
|
+
"--agent",
|
|
529
|
+
"-a",
|
|
530
|
+
help="Start an AI coding agent in a new terminal tab. Uses --with-agent, config default, or auto-detects. Implied by --prompt",
|
|
531
|
+
),
|
|
494
532
|
] = False,
|
|
495
533
|
agent_name: Annotated[
|
|
496
534
|
str | None,
|
|
497
|
-
typer.Option(
|
|
535
|
+
typer.Option(
|
|
536
|
+
"--with-agent",
|
|
537
|
+
help="Which AI agent to start: claude, codex, gemini, aider, copilot, cn (Continue), opencode, cursor-agent",
|
|
538
|
+
),
|
|
498
539
|
] = None,
|
|
499
540
|
editor_name: Annotated[
|
|
500
541
|
str | None,
|
|
501
|
-
typer.Option(
|
|
542
|
+
typer.Option(
|
|
543
|
+
"--with-editor",
|
|
544
|
+
help="Which editor to open: cursor, vscode, zed, nvim, vim, emacs, sublime, idea, pycharm, etc.",
|
|
545
|
+
),
|
|
502
546
|
] = None,
|
|
503
547
|
default_agent: Annotated[
|
|
504
548
|
str | None,
|
|
@@ -510,28 +554,37 @@ def new( # noqa: C901, PLR0912, PLR0915
|
|
|
510
554
|
] = None,
|
|
511
555
|
setup: Annotated[
|
|
512
556
|
bool,
|
|
513
|
-
typer.Option(
|
|
557
|
+
typer.Option(
|
|
558
|
+
"--setup/--no-setup",
|
|
559
|
+
help="Run project setup after creation: npm/pnpm/yarn install, poetry/uv sync, cargo build, etc. Auto-detects project type",
|
|
560
|
+
),
|
|
514
561
|
] = True,
|
|
515
562
|
copy_env: Annotated[
|
|
516
563
|
bool,
|
|
517
|
-
typer.Option(
|
|
564
|
+
typer.Option(
|
|
565
|
+
"--copy-env/--no-copy-env",
|
|
566
|
+
help="Copy .env, .env.local, .env.example from main repo to worktree",
|
|
567
|
+
),
|
|
518
568
|
] = True,
|
|
519
569
|
fetch: Annotated[
|
|
520
570
|
bool,
|
|
521
|
-
typer.Option(
|
|
571
|
+
typer.Option(
|
|
572
|
+
"--fetch/--no-fetch",
|
|
573
|
+
help="Run 'git fetch' before creating the worktree to ensure refs are up-to-date",
|
|
574
|
+
),
|
|
522
575
|
] = True,
|
|
523
576
|
direnv: Annotated[
|
|
524
577
|
bool | None,
|
|
525
578
|
typer.Option(
|
|
526
579
|
"--direnv/--no-direnv",
|
|
527
|
-
help="
|
|
580
|
+
help="Generate .envrc based on project type and run 'direnv allow'. Auto-enabled if direnv is installed",
|
|
528
581
|
),
|
|
529
582
|
] = None,
|
|
530
583
|
agent_args: Annotated[
|
|
531
584
|
list[str] | None,
|
|
532
585
|
typer.Option(
|
|
533
586
|
"--agent-args",
|
|
534
|
-
help="Extra
|
|
587
|
+
help="Extra CLI args for the agent. Can be repeated. Example: --agent-args='--dangerously-skip-permissions'",
|
|
535
588
|
),
|
|
536
589
|
] = None,
|
|
537
590
|
prompt: Annotated[
|
|
@@ -539,7 +592,7 @@ def new( # noqa: C901, PLR0912, PLR0915
|
|
|
539
592
|
typer.Option(
|
|
540
593
|
"--prompt",
|
|
541
594
|
"-p",
|
|
542
|
-
help="Initial
|
|
595
|
+
help="Initial task for the AI agent. Saved to .claude/TASK.md. Implies --agent. Example: --prompt='Fix the login bug'",
|
|
543
596
|
),
|
|
544
597
|
] = None,
|
|
545
598
|
prompt_file: Annotated[
|
|
@@ -547,17 +600,44 @@ def new( # noqa: C901, PLR0912, PLR0915
|
|
|
547
600
|
typer.Option(
|
|
548
601
|
"--prompt-file",
|
|
549
602
|
"-P",
|
|
550
|
-
help="Read
|
|
603
|
+
help="Read the agent prompt from a file. Useful for long prompts to avoid shell quoting. Implies --agent",
|
|
551
604
|
exists=True,
|
|
552
605
|
readable=True,
|
|
553
606
|
),
|
|
554
607
|
] = None,
|
|
555
608
|
verbose: Annotated[
|
|
556
609
|
bool,
|
|
557
|
-
typer.Option(
|
|
610
|
+
typer.Option(
|
|
611
|
+
"--verbose",
|
|
612
|
+
"-v",
|
|
613
|
+
help="Stream output from setup commands instead of hiding it",
|
|
614
|
+
),
|
|
558
615
|
] = False,
|
|
559
616
|
) -> None:
|
|
560
|
-
"""Create a new parallel development environment (git worktree).
|
|
617
|
+
"""Create a new parallel development environment (git worktree).
|
|
618
|
+
|
|
619
|
+
Creates an isolated git worktree with its own branch and working directory.
|
|
620
|
+
Optionally runs project setup, opens an editor, and/or starts an AI agent.
|
|
621
|
+
|
|
622
|
+
**What happens:**
|
|
623
|
+
|
|
624
|
+
1. Creates git worktree at `../REPO-worktrees/BRANCH/`
|
|
625
|
+
2. Copies .env files from main repo (--copy-env)
|
|
626
|
+
3. Runs project setup: npm install, uv sync, etc. (--setup)
|
|
627
|
+
4. Sets up direnv if installed (--direnv)
|
|
628
|
+
5. Opens editor if requested (-e/--editor)
|
|
629
|
+
6. Starts AI agent in new terminal tab if requested (-a/--agent or --prompt)
|
|
630
|
+
|
|
631
|
+
**Examples:**
|
|
632
|
+
|
|
633
|
+
- `dev new feature-x` — Create worktree, branching from origin/main (default)
|
|
634
|
+
- `dev new feature-x -a` — Create + start Claude/detected agent
|
|
635
|
+
- `dev new feature-x -e -a` — Create + open editor + start agent
|
|
636
|
+
- `dev new -a --prompt "Fix auth bug"` — Auto-named branch + agent with task
|
|
637
|
+
- `dev new hotfix --from v1.2.3` — Branch from a tag instead of main
|
|
638
|
+
- `dev new feature-x --from origin/develop` — Branch from develop instead
|
|
639
|
+
- `dev new feature-x --with-agent aider --with-editor cursor` — Specific tools
|
|
640
|
+
"""
|
|
561
641
|
# Handle prompt-file option (takes precedence over --prompt)
|
|
562
642
|
if prompt_file is not None:
|
|
563
643
|
prompt = prompt_file.read_text().strip()
|
|
@@ -676,10 +756,17 @@ def new( # noqa: C901, PLR0912, PLR0915
|
|
|
676
756
|
def list_envs(
|
|
677
757
|
json_output: Annotated[
|
|
678
758
|
bool,
|
|
679
|
-
typer.Option(
|
|
759
|
+
typer.Option(
|
|
760
|
+
"--json",
|
|
761
|
+
help="Output as JSON. Fields: name, path, branch, is_main, is_detached, is_locked, is_prunable",
|
|
762
|
+
),
|
|
680
763
|
] = False,
|
|
681
764
|
) -> None:
|
|
682
|
-
"""List all dev environments (worktrees) for the current repository.
|
|
765
|
+
"""List all dev environments (worktrees) for the current repository.
|
|
766
|
+
|
|
767
|
+
Shows each worktree's name, branch, path, and status (main, detached, locked, prunable).
|
|
768
|
+
Use `dev status` for more details including uncommitted changes and commit history.
|
|
769
|
+
"""
|
|
683
770
|
_ensure_git_repo()
|
|
684
771
|
|
|
685
772
|
worktrees = worktree.list_worktrees()
|
|
@@ -779,17 +866,28 @@ def _is_stale(status: worktree.WorktreeStatus, stale_days: int) -> bool:
|
|
|
779
866
|
def status_cmd( # noqa: PLR0915
|
|
780
867
|
stale_days: Annotated[
|
|
781
868
|
int,
|
|
782
|
-
typer.Option(
|
|
869
|
+
typer.Option(
|
|
870
|
+
"--stale-days",
|
|
871
|
+
"-s",
|
|
872
|
+
help="Mark worktrees as stale if inactive for N+ days (default: 7)",
|
|
873
|
+
),
|
|
783
874
|
] = 7,
|
|
784
875
|
json_output: Annotated[
|
|
785
876
|
bool,
|
|
786
|
-
typer.Option(
|
|
877
|
+
typer.Option(
|
|
878
|
+
"--json",
|
|
879
|
+
help="Output as JSON with fields: name, branch, modified, staged, untracked, ahead, behind, last_commit_timestamp, is_stale",
|
|
880
|
+
),
|
|
787
881
|
] = False,
|
|
788
882
|
) -> None:
|
|
789
|
-
"""Show status of all dev environments
|
|
883
|
+
"""Show detailed status of all dev environments with git information.
|
|
884
|
+
|
|
885
|
+
Displays for each worktree:
|
|
886
|
+
- **Changes**: Modified (M), Staged (S), Untracked (?) file counts
|
|
887
|
+
- **↑/↓**: Commits ahead (+N) or behind (-N) upstream
|
|
888
|
+
- **Last Commit**: Time since last commit, with ⚠️ for stale worktrees
|
|
790
889
|
|
|
791
|
-
|
|
792
|
-
upstream, and last commit time for each worktree.
|
|
890
|
+
Use this to find worktrees with uncommitted work or that need cleanup.
|
|
793
891
|
"""
|
|
794
892
|
_ensure_git_repo()
|
|
795
893
|
|
|
@@ -877,18 +975,39 @@ def status_cmd( # noqa: PLR0915
|
|
|
877
975
|
|
|
878
976
|
@app.command("rm")
|
|
879
977
|
def remove(
|
|
880
|
-
name: Annotated[
|
|
978
|
+
name: Annotated[
|
|
979
|
+
str,
|
|
980
|
+
typer.Argument(help="Worktree to remove. Can be branch name or directory name"),
|
|
981
|
+
],
|
|
881
982
|
force: Annotated[
|
|
882
983
|
bool,
|
|
883
|
-
typer.Option(
|
|
984
|
+
typer.Option(
|
|
985
|
+
"--force",
|
|
986
|
+
"-f",
|
|
987
|
+
help="Force removal even if worktree has uncommitted changes",
|
|
988
|
+
),
|
|
884
989
|
] = False,
|
|
885
990
|
delete_branch: Annotated[
|
|
886
991
|
bool,
|
|
887
|
-
typer.Option(
|
|
992
|
+
typer.Option(
|
|
993
|
+
"--delete-branch",
|
|
994
|
+
"-d",
|
|
995
|
+
help="Also delete the git branch (not just the worktree)",
|
|
996
|
+
),
|
|
997
|
+
] = False,
|
|
998
|
+
yes: Annotated[
|
|
999
|
+
bool,
|
|
1000
|
+
typer.Option("--yes", "-y", help="Skip confirmation prompt"),
|
|
888
1001
|
] = False,
|
|
889
|
-
yes: Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation")] = False,
|
|
890
1002
|
) -> None:
|
|
891
|
-
"""Remove a dev environment (worktree).
|
|
1003
|
+
"""Remove a dev environment (worktree) and optionally its branch.
|
|
1004
|
+
|
|
1005
|
+
By default, prompts for confirmation and refuses to remove worktrees with
|
|
1006
|
+
uncommitted changes. Use --force to override, --delete-branch to also
|
|
1007
|
+
delete the git branch.
|
|
1008
|
+
|
|
1009
|
+
Cannot remove the main worktree.
|
|
1010
|
+
"""
|
|
892
1011
|
repo_root = _ensure_git_repo()
|
|
893
1012
|
|
|
894
1013
|
wt = worktree.find_worktree_by_name(name, repo_root)
|
|
@@ -920,11 +1039,16 @@ def remove(
|
|
|
920
1039
|
|
|
921
1040
|
@app.command("path")
|
|
922
1041
|
def path_cmd(
|
|
923
|
-
name: Annotated[
|
|
1042
|
+
name: Annotated[
|
|
1043
|
+
str,
|
|
1044
|
+
typer.Argument(help="Worktree to get path for. Can be branch name or directory name"),
|
|
1045
|
+
],
|
|
924
1046
|
) -> None:
|
|
925
|
-
"""Print the path to a dev environment
|
|
1047
|
+
"""Print the absolute path to a dev environment.
|
|
1048
|
+
|
|
1049
|
+
Useful for shell integration and scripting.
|
|
926
1050
|
|
|
927
|
-
|
|
1051
|
+
**Example:** `cd "$(agent-cli dev path my-feature)"`
|
|
928
1052
|
"""
|
|
929
1053
|
repo_root = _ensure_git_repo()
|
|
930
1054
|
|
|
@@ -937,13 +1061,24 @@ def path_cmd(
|
|
|
937
1061
|
|
|
938
1062
|
@app.command("editor")
|
|
939
1063
|
def open_editor(
|
|
940
|
-
name: Annotated[
|
|
1064
|
+
name: Annotated[
|
|
1065
|
+
str,
|
|
1066
|
+
typer.Argument(help="Worktree to open. Can be branch name or directory name"),
|
|
1067
|
+
],
|
|
941
1068
|
editor_name: Annotated[
|
|
942
1069
|
str | None,
|
|
943
|
-
typer.Option(
|
|
1070
|
+
typer.Option(
|
|
1071
|
+
"--editor",
|
|
1072
|
+
"-e",
|
|
1073
|
+
help="Override auto-detection. Options: cursor, vscode, zed, nvim, vim, emacs, sublime, idea, pycharm, etc.",
|
|
1074
|
+
),
|
|
944
1075
|
] = None,
|
|
945
1076
|
) -> None:
|
|
946
|
-
"""Open a dev environment in an editor.
|
|
1077
|
+
"""Open a dev environment in an editor.
|
|
1078
|
+
|
|
1079
|
+
Without --editor, auto-detects based on current environment or uses
|
|
1080
|
+
the first available editor. Run `dev editors` to see what's available.
|
|
1081
|
+
"""
|
|
947
1082
|
repo_root = _ensure_git_repo()
|
|
948
1083
|
|
|
949
1084
|
wt = worktree.find_worktree_by_name(name, repo_root)
|
|
@@ -974,16 +1109,25 @@ def open_editor(
|
|
|
974
1109
|
|
|
975
1110
|
@app.command("agent")
|
|
976
1111
|
def start_agent(
|
|
977
|
-
name: Annotated[
|
|
1112
|
+
name: Annotated[
|
|
1113
|
+
str,
|
|
1114
|
+
typer.Argument(
|
|
1115
|
+
help="Worktree to start the agent in. Can be branch name or directory name",
|
|
1116
|
+
),
|
|
1117
|
+
],
|
|
978
1118
|
agent_name: Annotated[
|
|
979
1119
|
str | None,
|
|
980
|
-
typer.Option(
|
|
1120
|
+
typer.Option(
|
|
1121
|
+
"--agent",
|
|
1122
|
+
"-a",
|
|
1123
|
+
help="Which agent: claude, codex, gemini, aider, copilot, cn, opencode, cursor-agent. Auto-detects if omitted",
|
|
1124
|
+
),
|
|
981
1125
|
] = None,
|
|
982
1126
|
agent_args: Annotated[
|
|
983
1127
|
list[str] | None,
|
|
984
1128
|
typer.Option(
|
|
985
1129
|
"--agent-args",
|
|
986
|
-
help="Extra
|
|
1130
|
+
help="Extra CLI args for the agent. Example: --agent-args='--dangerously-skip-permissions'",
|
|
987
1131
|
),
|
|
988
1132
|
] = None,
|
|
989
1133
|
prompt: Annotated[
|
|
@@ -991,7 +1135,7 @@ def start_agent(
|
|
|
991
1135
|
typer.Option(
|
|
992
1136
|
"--prompt",
|
|
993
1137
|
"-p",
|
|
994
|
-
help="Initial
|
|
1138
|
+
help="Initial task for the agent. Saved to .claude/TASK.md. Example: --prompt='Add unit tests for auth'",
|
|
995
1139
|
),
|
|
996
1140
|
] = None,
|
|
997
1141
|
prompt_file: Annotated[
|
|
@@ -999,13 +1143,23 @@ def start_agent(
|
|
|
999
1143
|
typer.Option(
|
|
1000
1144
|
"--prompt-file",
|
|
1001
1145
|
"-P",
|
|
1002
|
-
help="Read
|
|
1146
|
+
help="Read the agent prompt from a file instead of command line",
|
|
1003
1147
|
exists=True,
|
|
1004
1148
|
readable=True,
|
|
1005
1149
|
),
|
|
1006
1150
|
] = None,
|
|
1007
1151
|
) -> None:
|
|
1008
|
-
"""Start an AI coding agent in
|
|
1152
|
+
"""Start an AI coding agent in an existing dev environment.
|
|
1153
|
+
|
|
1154
|
+
Launches the agent directly in your current terminal (not a new tab).
|
|
1155
|
+
Use this when the worktree already exists and you want to start/resume work.
|
|
1156
|
+
|
|
1157
|
+
**Examples:**
|
|
1158
|
+
|
|
1159
|
+
- `dev agent my-feature` — Start auto-detected agent in worktree
|
|
1160
|
+
- `dev agent my-feature -a claude` — Start Claude specifically
|
|
1161
|
+
- `dev agent my-feature -p "Continue the auth refactor"` — Start with a task
|
|
1162
|
+
"""
|
|
1009
1163
|
# Handle prompt-file option (takes precedence over --prompt)
|
|
1010
1164
|
if prompt_file is not None:
|
|
1011
1165
|
prompt = prompt_file.read_text().strip()
|
|
@@ -1057,10 +1211,20 @@ def start_agent(
|
|
|
1057
1211
|
def list_agents(
|
|
1058
1212
|
json_output: Annotated[
|
|
1059
1213
|
bool,
|
|
1060
|
-
typer.Option(
|
|
1214
|
+
typer.Option(
|
|
1215
|
+
"--json",
|
|
1216
|
+
help="Output as JSON with name, command, is_available, is_current, install_url",
|
|
1217
|
+
),
|
|
1061
1218
|
] = False,
|
|
1062
1219
|
) -> None:
|
|
1063
|
-
"""List available AI coding agents.
|
|
1220
|
+
"""List available AI coding agents and their installation status.
|
|
1221
|
+
|
|
1222
|
+
Shows all supported agents: claude, codex, gemini, aider, copilot,
|
|
1223
|
+
cn (Continue), opencode, cursor-agent.
|
|
1224
|
+
|
|
1225
|
+
✓ = installed, ✗ = not installed (shows install URL).
|
|
1226
|
+
Current agent (detected from parent process) is marked.
|
|
1227
|
+
"""
|
|
1064
1228
|
current = coding_agents.detect_current_agent()
|
|
1065
1229
|
|
|
1066
1230
|
if json_output:
|
|
@@ -1099,10 +1263,20 @@ def list_agents(
|
|
|
1099
1263
|
def list_editors_cmd(
|
|
1100
1264
|
json_output: Annotated[
|
|
1101
1265
|
bool,
|
|
1102
|
-
typer.Option(
|
|
1266
|
+
typer.Option(
|
|
1267
|
+
"--json",
|
|
1268
|
+
help="Output as JSON with name, command, is_available, is_current, install_url",
|
|
1269
|
+
),
|
|
1103
1270
|
] = False,
|
|
1104
1271
|
) -> None:
|
|
1105
|
-
"""List available editors.
|
|
1272
|
+
"""List available editors and their installation status.
|
|
1273
|
+
|
|
1274
|
+
Shows all supported editors: cursor, vscode, zed, nvim, vim, emacs,
|
|
1275
|
+
sublime, idea, pycharm, webstorm, goland, rustrover.
|
|
1276
|
+
|
|
1277
|
+
✓ = installed, ✗ = not installed.
|
|
1278
|
+
Current editor (if detectable) is marked.
|
|
1279
|
+
"""
|
|
1106
1280
|
current = editors.detect_current_editor()
|
|
1107
1281
|
|
|
1108
1282
|
if json_output:
|
|
@@ -1141,10 +1315,17 @@ def list_editors_cmd(
|
|
|
1141
1315
|
def list_terminals_cmd(
|
|
1142
1316
|
json_output: Annotated[
|
|
1143
1317
|
bool,
|
|
1144
|
-
typer.Option("--json", help="Output as JSON
|
|
1318
|
+
typer.Option("--json", help="Output as JSON with name, is_available, is_current"),
|
|
1145
1319
|
] = False,
|
|
1146
1320
|
) -> None:
|
|
1147
|
-
"""List available
|
|
1321
|
+
"""List available terminal multiplexers and their status.
|
|
1322
|
+
|
|
1323
|
+
Shows supported terminals: tmux, zellij, kitty, iTerm2, Terminal.app,
|
|
1324
|
+
Warp, GNOME Terminal.
|
|
1325
|
+
|
|
1326
|
+
These are used to open new tabs when launching AI agents with `dev new -a`.
|
|
1327
|
+
The current terminal (if detectable) is marked.
|
|
1328
|
+
"""
|
|
1148
1329
|
current = terminals.detect_current_terminal()
|
|
1149
1330
|
|
|
1150
1331
|
if json_output:
|
|
@@ -1207,12 +1388,25 @@ def _doctor_check_git() -> None:
|
|
|
1207
1388
|
|
|
1208
1389
|
@app.command("run")
|
|
1209
1390
|
def run_cmd(
|
|
1210
|
-
name: Annotated[
|
|
1211
|
-
|
|
1391
|
+
name: Annotated[
|
|
1392
|
+
str,
|
|
1393
|
+
typer.Argument(help="Worktree to run command in. Can be branch name or directory name"),
|
|
1394
|
+
],
|
|
1395
|
+
command: Annotated[
|
|
1396
|
+
list[str],
|
|
1397
|
+
typer.Argument(help="Command and arguments to run"),
|
|
1398
|
+
],
|
|
1212
1399
|
) -> None:
|
|
1213
|
-
"""Run a command in a dev environment.
|
|
1400
|
+
"""Run a command in a dev environment's directory.
|
|
1214
1401
|
|
|
1215
|
-
|
|
1402
|
+
Executes the command with the worktree as the current directory.
|
|
1403
|
+
Exit code is passed through from the command.
|
|
1404
|
+
|
|
1405
|
+
**Examples:**
|
|
1406
|
+
|
|
1407
|
+
- `dev run my-feature npm test` — Run tests
|
|
1408
|
+
- `dev run my-feature git status` — Check git status
|
|
1409
|
+
- `dev run my-feature bash -c "npm install && npm test"` — Multiple commands
|
|
1216
1410
|
"""
|
|
1217
1411
|
repo_root = _ensure_git_repo()
|
|
1218
1412
|
|
|
@@ -1380,26 +1574,47 @@ def _clean_no_commits_worktrees(
|
|
|
1380
1574
|
def clean(
|
|
1381
1575
|
merged: Annotated[
|
|
1382
1576
|
bool,
|
|
1383
|
-
typer.Option(
|
|
1577
|
+
typer.Option(
|
|
1578
|
+
"--merged",
|
|
1579
|
+
help="Also remove worktrees whose GitHub PRs are merged (requires gh CLI and auth)",
|
|
1580
|
+
),
|
|
1384
1581
|
] = False,
|
|
1385
1582
|
no_commits: Annotated[
|
|
1386
1583
|
bool,
|
|
1387
1584
|
typer.Option(
|
|
1388
1585
|
"--no-commits",
|
|
1389
|
-
help="
|
|
1586
|
+
help="Also remove worktrees with 0 commits ahead of default branch (abandoned branches)",
|
|
1390
1587
|
),
|
|
1391
1588
|
] = False,
|
|
1392
1589
|
dry_run: Annotated[
|
|
1393
1590
|
bool,
|
|
1394
|
-
typer.Option(
|
|
1591
|
+
typer.Option(
|
|
1592
|
+
"--dry-run",
|
|
1593
|
+
"-n",
|
|
1594
|
+
help="Preview what would be removed without actually removing",
|
|
1595
|
+
),
|
|
1596
|
+
] = False,
|
|
1597
|
+
yes: Annotated[
|
|
1598
|
+
bool,
|
|
1599
|
+
typer.Option("--yes", "-y", help="Skip confirmation prompts"),
|
|
1395
1600
|
] = False,
|
|
1396
|
-
yes: Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation")] = False,
|
|
1397
1601
|
) -> None:
|
|
1398
1602
|
"""Clean up stale worktrees and empty directories.
|
|
1399
1603
|
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1604
|
+
Always runs `git worktree prune` to remove stale administrative files,
|
|
1605
|
+
and removes empty directories in the worktrees folder.
|
|
1606
|
+
|
|
1607
|
+
**Modes:**
|
|
1608
|
+
|
|
1609
|
+
- Default: Just prune stale refs and empty directories
|
|
1610
|
+
- `--merged`: Also remove worktrees whose PRs are merged on GitHub
|
|
1611
|
+
- `--no-commits`: Also remove worktrees with no commits (abandoned branches)
|
|
1612
|
+
|
|
1613
|
+
**Examples:**
|
|
1614
|
+
|
|
1615
|
+
- `dev clean` — Basic cleanup
|
|
1616
|
+
- `dev clean --merged` — Remove worktrees with merged PRs
|
|
1617
|
+
- `dev clean --merged --dry-run` — Preview what would be removed
|
|
1403
1618
|
"""
|
|
1404
1619
|
repo_root = _ensure_git_repo()
|
|
1405
1620
|
|
|
@@ -1445,10 +1660,20 @@ def clean(
|
|
|
1445
1660
|
def doctor(
|
|
1446
1661
|
json_output: Annotated[
|
|
1447
1662
|
bool,
|
|
1448
|
-
typer.Option("--json", help="Output as JSON
|
|
1663
|
+
typer.Option("--json", help="Output as JSON with git, editors, agents, terminals status"),
|
|
1449
1664
|
] = False,
|
|
1450
1665
|
) -> None:
|
|
1451
|
-
"""Check system requirements and available integrations.
|
|
1666
|
+
"""Check system requirements and show available integrations.
|
|
1667
|
+
|
|
1668
|
+
Shows availability status for:
|
|
1669
|
+
- **Git**: Is git installed? Are we in a git repo?
|
|
1670
|
+
- **Editors**: Which editors are installed and which is current?
|
|
1671
|
+
- **Agents**: Which AI coding agents are installed?
|
|
1672
|
+
- **Terminals**: Which terminal multiplexers are detected?
|
|
1673
|
+
|
|
1674
|
+
Items marked with ✓ are available, ✗ are not installed.
|
|
1675
|
+
Current editor/agent/terminal is marked with (current).
|
|
1676
|
+
"""
|
|
1452
1677
|
current_editor = editors.detect_current_editor()
|
|
1453
1678
|
current_agent = coding_agents.detect_current_agent()
|
|
1454
1679
|
current_terminal = terminals.detect_current_terminal()
|
|
@@ -1537,17 +1762,22 @@ def _get_current_repo_root() -> Path | None:
|
|
|
1537
1762
|
def install_skill(
|
|
1538
1763
|
force: Annotated[
|
|
1539
1764
|
bool,
|
|
1540
|
-
typer.Option("--force", "-f", help="Overwrite existing skill files"),
|
|
1765
|
+
typer.Option("--force", "-f", help="Overwrite existing skill files if already installed"),
|
|
1541
1766
|
] = False,
|
|
1542
1767
|
) -> None:
|
|
1543
1768
|
"""Install Claude Code skill for parallel agent orchestration.
|
|
1544
1769
|
|
|
1545
|
-
Installs a skill that teaches Claude Code how to use
|
|
1770
|
+
Installs a skill that teaches Claude Code how to use `agent-cli dev` to
|
|
1546
1771
|
spawn parallel AI coding agents in isolated git worktrees.
|
|
1547
1772
|
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1773
|
+
**What it does:**
|
|
1774
|
+
|
|
1775
|
+
- Copies skill files to `.claude/skills/agent-cli-dev/` in current repo
|
|
1776
|
+
- Enables Claude Code to automatically spawn parallel agents
|
|
1777
|
+
- Works when you ask to "work on multiple features" or "parallelize tasks"
|
|
1778
|
+
|
|
1779
|
+
**Alternative:** Install globally via Claude Code plugin marketplace:
|
|
1780
|
+
`claude plugin marketplace add basnijholt/agent-cli`
|
|
1551
1781
|
"""
|
|
1552
1782
|
# Use current repo root (works in worktrees too)
|
|
1553
1783
|
repo_root = _get_current_repo_root()
|
agent_cli/docs_gen.py
CHANGED
|
@@ -80,16 +80,26 @@ def _extract_options_from_click(cmd: click.Command) -> list[dict[str, Any]]:
|
|
|
80
80
|
options = []
|
|
81
81
|
for param in cmd.params:
|
|
82
82
|
if isinstance(param, click.Option):
|
|
83
|
-
# Get
|
|
84
|
-
|
|
85
|
-
if not
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
# Get long and short option names
|
|
84
|
+
long_opts = [n for n in param.opts if n.startswith("--")]
|
|
85
|
+
short_opts = [n for n in param.opts if n.startswith("-") and not n.startswith("--")]
|
|
86
|
+
|
|
87
|
+
# Build display name: prefer long form, include short if available
|
|
88
|
+
if long_opts:
|
|
89
|
+
primary_name = max(long_opts, key=len)
|
|
90
|
+
# Include short flag if available (e.g., "--from", "-f" -> "--from, -f")
|
|
91
|
+
if short_opts:
|
|
92
|
+
primary_name = f"{primary_name}, {short_opts[0]}"
|
|
93
|
+
elif short_opts:
|
|
94
|
+
primary_name = short_opts[0]
|
|
95
|
+
else:
|
|
96
|
+
primary_name = f"--{param.name}"
|
|
97
|
+
|
|
98
|
+
# Handle boolean flags with --foo/--no-foo pattern
|
|
90
99
|
if param.is_flag and param.secondary_opts:
|
|
91
100
|
# e.g., --llm/--no-llm
|
|
92
|
-
|
|
101
|
+
base_opt = long_opts[0] if long_opts else param.opts[0]
|
|
102
|
+
primary_name = f"{base_opt}/{param.secondary_opts[0]}"
|
|
93
103
|
|
|
94
104
|
# Get panel from rich_help_panel or use default
|
|
95
105
|
panel = getattr(param, "rich_help_panel", None) or "Options"
|