dev-autopilot 0.4.0__tar.gz → 0.5.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.
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/PKG-INFO +31 -19
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/README.md +30 -18
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/__init__.py +1 -1
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/backends/__init__.py +5 -1
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/backends/command.py +38 -8
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/cli.py +76 -23
- dev_autopilot-0.5.0/autopilot/commands/precheck.py +216 -0
- dev_autopilot-0.5.0/autopilot/commands/setup.py +265 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/config.py +8 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/doctor.py +166 -48
- dev_autopilot-0.5.0/autopilot/install_errors.py +195 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/__pycache__/cloudflare_apply.cpython-313.pyc +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/agent/project.yaml +1 -1
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/upgrade.py +69 -3
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/dev_autopilot.egg-info/PKG-INFO +31 -19
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/dev_autopilot.egg-info/SOURCES.txt +7 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/pyproject.toml +1 -1
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_doctor.py +3 -0
- dev_autopilot-0.5.0/tests/test_install_errors.py +104 -0
- dev_autopilot-0.5.0/tests/test_install_scripts.py +151 -0
- dev_autopilot-0.5.0/tests/test_precheck.py +120 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_presets.py +75 -2
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_quickstart.py +9 -7
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_runner_detect.py +146 -12
- dev_autopilot-0.5.0/tests/test_setup.py +238 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_simple_view.py +2 -2
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_upgrade.py +67 -2
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_version.py +32 -4
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/LICENSE +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/__main__.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/backends/claude_cli.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/commands/__init__.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/commands/preflight.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/context.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/dash_term.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/dash_web.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/dashboard.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/decisions.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/deploy.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/docs.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/gate.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/github_util.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/gitops.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/growth.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/handoff.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/layers.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/log_scrub.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/mcp.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/notify.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/orchestrator.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/plain.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/plan.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/proc.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/auditor.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/decide.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/docs.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/fixer.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/onboard.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/plan_writer.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/replanner.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/research.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/resume.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/retry.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/review.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/system.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/task.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/triage.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/unstick.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/prompts/verify.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/repomap.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/report.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/rights.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/schemas.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/state.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/agent/BRAIN.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/agent/CLAUDE.md.snippet +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/agent/DECISIONS.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/agent/HANDOFF.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/agent/gitignore +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/agent/ide_rules.md +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/agent/plan.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/cloudflare_apply.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/deploy.sh +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/email_verify.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/infra/cloudflare.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/presets/docker.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/presets/generic.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/presets/go.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/presets/java.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/presets/node.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/presets/python.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/presets/rust.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/autopilot/templates/presets/static.yaml +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/dev_autopilot.egg-info/dependency_links.txt +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/dev_autopilot.egg-info/entry_points.txt +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/dev_autopilot.egg-info/requires.txt +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/dev_autopilot.egg-info/top_level.txt +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/setup.cfg +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_adopt.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_autofix.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_autopilot.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_backend.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_cache.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_chat.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_conflicts.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_consolidate.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_dash_term.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_dash_web.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_dashboard.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_dashboard_rows.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_dashboard_time.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_decide.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_deploy.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_deps.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_docs_session.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_functional.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_gate.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_github_identity.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_handoff.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_heal.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_ide_rules.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_infra_templates.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_intake.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_killed_usage.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_layers.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_lean.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_lifecycle.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_mcp.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_needs_you.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_new_file_gate.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_opening.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_orchestrator.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_parallel.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_plan_source.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_preflight.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_proc.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_prompt_contract_task.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_quality.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_reliability.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_repomap.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_research.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_review.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_rights.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_roadmap.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_routing.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_sandbox.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_stats.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_status_line.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_status_page.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_sync.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_three_actions.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_usage.py +0 -0
- {dev_autopilot-0.4.0 → dev_autopilot-0.5.0}/tests/test_window.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dev-autopilot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Autopilot builds your software project while you are away. You write what you want in plain words and start it once. You get working software, tested, with a record of every step.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/manishjnv/AutoPilot
|
|
@@ -46,8 +46,7 @@ It is for one developer, or for a person with an idea and a developer friend.
|
|
|
46
46
|
| Questions | The chat waits for you. | That task waits. Other tasks continue. |
|
|
47
47
|
| Status | You scroll the chat. | `ap watch` shows tasks, output, progress and usage. |
|
|
48
48
|
|
|
49
|
-
The [full comparison](ARCHITECTURE.md#13-claude-code-alone-and-with-autopilot) has ten rows.
|
|
50
|
-
for a small change, a question, or an open design.
|
|
49
|
+
The [full comparison](ARCHITECTURE.md#13-claude-code-alone-and-with-autopilot) has ten rows.
|
|
51
50
|
|
|
52
51
|
## How it works
|
|
53
52
|
|
|
@@ -95,28 +94,41 @@ Two real projects built from a plan:
|
|
|
95
94
|
| Agent time | 2.2 hours, 38 sessions | 1.4 hours, 42 sessions |
|
|
96
95
|
| Cost at API prices | $17.13 | $19.01 |
|
|
97
96
|
|
|
98
|
-
Both runs used a subscription. The envguard audits found 8 real bugs; Autopilot fixed all. envguard is private; numbers come from the run log.
|
|
97
|
+
Both runs used a subscription. The envguard audits found 8 real bugs; Autopilot fixed all. envguard is private; numbers come from the run log.
|
|
99
98
|
|
|
100
99
|
## Install
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
Windows (PowerShell):
|
|
101
|
+
Three steps, no administrator prompt.
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
irm https://raw.githubusercontent.com/manishjnv/AutoPilot/main/install.ps1 | iex
|
|
107
|
-
```
|
|
103
|
+
1. Run one line in your shell.
|
|
108
104
|
|
|
109
|
-
|
|
105
|
+
Windows (PowerShell):
|
|
110
106
|
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
```
|
|
107
|
+
```powershell
|
|
108
|
+
irm https://raw.githubusercontent.com/manishjnv/AutoPilot/main/install.ps1 | iex
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
macOS, Linux, WSL or Git Bash:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
curl -fsSL https://raw.githubusercontent.com/manishjnv/AutoPilot/main/install.sh | bash
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Windows (CMD):
|
|
118
|
+
|
|
119
|
+
```bat
|
|
120
|
+
curl -o %TEMP%\install.cmd https://raw.githubusercontent.com/manishjnv/AutoPilot/main/install.cmd && %TEMP%\install.cmd
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Have Python 3.10 or newer? `pip install dev-autopilot && ap setup`.
|
|
124
|
+
|
|
125
|
+
2. Answer one question: which AI do you pay for (Claude, GitHub Copilot, Codex, Cursor or Kiro)? The script
|
|
126
|
+
installs that one CLI and prints its login command. Copilot in VS Code is not a command-line tool. Autopilot
|
|
127
|
+
needs the Copilot CLI, which uses the same subscription.
|
|
128
|
+
3. Open a project folder and type `ap`.
|
|
114
129
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
Open a project folder and type `ap`. The first run logs you in to Claude (a paid plan, Pro or Max), then starts.
|
|
118
|
-
See [What `ap` does](HOWTO.md#what-ap-does-in-a-folder). After a release, run `ap upgrade`. For a repair or a
|
|
119
|
-
second machine, run `ap install`. Checksums and each step: [Install with one script](HOWTO.md#install-with-one-script).
|
|
130
|
+
See [What `ap` does](HOWTO.md#what-ap-does-in-a-folder). Autopilot updates itself once a day; `ap uninstall --all`
|
|
131
|
+
removes it. Checksums and each step: [Install with one script](HOWTO.md#install-with-one-script).
|
|
120
132
|
|
|
121
133
|
## Example output
|
|
122
134
|
|
|
@@ -144,5 +156,5 @@ audit: completion audit: 92% complete, 8 corrective tasks (FIX001)
|
|
|
144
156
|
> Use a sandbox on a server: sessions run without permission prompts. See
|
|
145
157
|
> [Run Autopilot on a server](HOWTO.md#run-autopilot-on-a-server).
|
|
146
158
|
|
|
147
|
-
- Version 0.
|
|
159
|
+
- Version 0.4.0, an early release. [MIT license](LICENSE).
|
|
148
160
|
- One CLI agent per session. See [limits and runners](HOWTO.md#limits-and-supported-agent-clis).
|
|
@@ -19,8 +19,7 @@ It is for one developer, or for a person with an idea and a developer friend.
|
|
|
19
19
|
| Questions | The chat waits for you. | That task waits. Other tasks continue. |
|
|
20
20
|
| Status | You scroll the chat. | `ap watch` shows tasks, output, progress and usage. |
|
|
21
21
|
|
|
22
|
-
The [full comparison](ARCHITECTURE.md#13-claude-code-alone-and-with-autopilot) has ten rows.
|
|
23
|
-
for a small change, a question, or an open design.
|
|
22
|
+
The [full comparison](ARCHITECTURE.md#13-claude-code-alone-and-with-autopilot) has ten rows.
|
|
24
23
|
|
|
25
24
|
## How it works
|
|
26
25
|
|
|
@@ -68,28 +67,41 @@ Two real projects built from a plan:
|
|
|
68
67
|
| Agent time | 2.2 hours, 38 sessions | 1.4 hours, 42 sessions |
|
|
69
68
|
| Cost at API prices | $17.13 | $19.01 |
|
|
70
69
|
|
|
71
|
-
Both runs used a subscription. The envguard audits found 8 real bugs; Autopilot fixed all. envguard is private; numbers come from the run log.
|
|
70
|
+
Both runs used a subscription. The envguard audits found 8 real bugs; Autopilot fixed all. envguard is private; numbers come from the run log.
|
|
72
71
|
|
|
73
72
|
## Install
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
Windows (PowerShell):
|
|
74
|
+
Three steps, no administrator prompt.
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
irm https://raw.githubusercontent.com/manishjnv/AutoPilot/main/install.ps1 | iex
|
|
80
|
-
```
|
|
76
|
+
1. Run one line in your shell.
|
|
81
77
|
|
|
82
|
-
|
|
78
|
+
Windows (PowerShell):
|
|
83
79
|
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
```
|
|
80
|
+
```powershell
|
|
81
|
+
irm https://raw.githubusercontent.com/manishjnv/AutoPilot/main/install.ps1 | iex
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
macOS, Linux, WSL or Git Bash:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
curl -fsSL https://raw.githubusercontent.com/manishjnv/AutoPilot/main/install.sh | bash
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Windows (CMD):
|
|
91
|
+
|
|
92
|
+
```bat
|
|
93
|
+
curl -o %TEMP%\install.cmd https://raw.githubusercontent.com/manishjnv/AutoPilot/main/install.cmd && %TEMP%\install.cmd
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Have Python 3.10 or newer? `pip install dev-autopilot && ap setup`.
|
|
97
|
+
|
|
98
|
+
2. Answer one question: which AI do you pay for (Claude, GitHub Copilot, Codex, Cursor or Kiro)? The script
|
|
99
|
+
installs that one CLI and prints its login command. Copilot in VS Code is not a command-line tool. Autopilot
|
|
100
|
+
needs the Copilot CLI, which uses the same subscription.
|
|
101
|
+
3. Open a project folder and type `ap`.
|
|
87
102
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
Open a project folder and type `ap`. The first run logs you in to Claude (a paid plan, Pro or Max), then starts.
|
|
91
|
-
See [What `ap` does](HOWTO.md#what-ap-does-in-a-folder). After a release, run `ap upgrade`. For a repair or a
|
|
92
|
-
second machine, run `ap install`. Checksums and each step: [Install with one script](HOWTO.md#install-with-one-script).
|
|
103
|
+
See [What `ap` does](HOWTO.md#what-ap-does-in-a-folder). Autopilot updates itself once a day; `ap uninstall --all`
|
|
104
|
+
removes it. Checksums and each step: [Install with one script](HOWTO.md#install-with-one-script).
|
|
93
105
|
|
|
94
106
|
## Example output
|
|
95
107
|
|
|
@@ -117,5 +129,5 @@ audit: completion audit: 92% complete, 8 corrective tasks (FIX001)
|
|
|
117
129
|
> Use a sandbox on a server: sessions run without permission prompts. See
|
|
118
130
|
> [Run Autopilot on a server](HOWTO.md#run-autopilot-on-a-server).
|
|
119
131
|
|
|
120
|
-
- Version 0.
|
|
132
|
+
- Version 0.4.0, an early release. [MIT license](LICENSE).
|
|
121
133
|
- One CLI agent per session. See [limits and runners](HOWTO.md#limits-and-supported-agent-clis).
|
|
@@ -10,6 +10,10 @@ from datetime import datetime, timedelta
|
|
|
10
10
|
LIMIT_RX = re.compile(r"^\s*(?:you've|you have) hit your (?:[\w-]+ ){0,3}limit"
|
|
11
11
|
r"(?:\s*[·•|\-–—,.]*\s*resets?\s+(?P<reset>[^\n]+))?", re.I | re.M)
|
|
12
12
|
API_LIMIT_RX = re.compile(r"^\s*API Error: (?:429|529)\b|^\s*API Error:.*(?:rate_limit_error|overloaded_error)", re.I | re.M)
|
|
13
|
+
# Q2 copilot: the premium-request quota message. Docs checked 2026-10-12, not run live: the exact wording and the exit
|
|
14
|
+
# code are recorded in Q9; until then any line that names premium requests with a limit word counts.
|
|
15
|
+
COPILOT_LIMIT_RX = re.compile(r"^\s*.{0,60}\b(?:premium requests? (?:limit|quota)|(?:limit|quota) (?:of|for|on) premium requests?"
|
|
16
|
+
r"|premium requests? .{0,20}\b(?:exhausted|exceeded|used up))", re.I | re.M)
|
|
13
17
|
_RESET_RX = re.compile(r"^(?:(?P<mon>[a-z]{3,9})\.?\s+(?P<day>\d{1,2})\s*(?:,|at)?\s*)?(?P<h>\d{1,2})(?::(?P<m>\d{2}))?"
|
|
14
18
|
r"\s*(?P<ap>am|pm)?\s*(?:\((?P<tz>[^)]+)\))?$", re.I)
|
|
15
19
|
_MONTHS = {m: i + 1 for i, m in enumerate("jan feb mar apr may jun jul aug sep oct nov dec".split())}
|
|
@@ -57,7 +61,7 @@ def detect_limit(text: str, now: datetime | None = None) -> tuple[bool, float |
|
|
|
57
61
|
m = LIMIT_RX.search(text)
|
|
58
62
|
if m:
|
|
59
63
|
return True, (parse_reset(m["reset"], now or datetime.now().astimezone()) if m["reset"] else None)
|
|
60
|
-
return bool(API_LIMIT_RX.search(text)), None
|
|
64
|
+
return bool(API_LIMIT_RX.search(text) or COPILOT_LIMIT_RX.search(text)), None
|
|
61
65
|
|
|
62
66
|
|
|
63
67
|
# Failures of the machinery, not of the work: retried by the orchestrator, never counted as a task attempt.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Generic backend: any CLI agent (Aider, Codex, a LiteLLM wrapper...). Prompt on stdin, report in stdout."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
+
import os
|
|
4
5
|
import re
|
|
5
6
|
import shlex
|
|
7
|
+
import shutil
|
|
6
8
|
import tempfile
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
|
|
@@ -21,30 +23,58 @@ PRESETS = {
|
|
|
21
23
|
# https://cursor.com/docs/cli/headless , https://cursor.com/docs/cli/reference/parameters ,
|
|
22
24
|
# https://aider.chat/docs/config/options.html , https://aider.chat/docs/scripting.html
|
|
23
25
|
# kiro: no _ASK, because a positional argument stops kiro-cli from reading the prompt on stdin.
|
|
24
|
-
# cursor: stdin is not documented (the Chief project, PR #48, uses it), so the short _ASK argument stays.
|
|
26
|
+
# cursor: stdin is not documented (the Chief project, PR #48, uses it), so the short _ASK argument stays. The binary
|
|
27
|
+
# is `agent` since the rename (docs checked 2026-10-12); `command_template` falls back to an installed `cursor-agent`.
|
|
25
28
|
# aider: no stdin prompt, so it reads {prompt_file} (a temp file outside the worktree); git stays with the orchestrator.
|
|
26
29
|
# --trust-all-tools (kiro) and --force (cursor) approve every tool, not only the workspace (like gemini yolo).
|
|
27
30
|
"kiro": "kiro-cli chat --no-interactive --trust-all-tools{model_flag}",
|
|
28
|
-
"cursor": "
|
|
31
|
+
"cursor": "agent -p --force --trust{model_flag} " + _ASK,
|
|
29
32
|
"aider": "aider --message-file {prompt_file} --yes-always --no-auto-commits --no-dirty-commits --no-gitignore"
|
|
30
33
|
" --no-check-update --no-analytics --no-pretty --no-stream{model_flag}",
|
|
34
|
+
# Q2 copilot: docs checked 2026-10-12, not run live (the live task is Q9). Sources: https://docs.github.com/en/copilot
|
|
35
|
+
# /how-tos/use-copilot-agents/use-copilot-cli . `-p` takes the prompt as an argument (stdin is not documented), so the
|
|
36
|
+
# prompt goes to a temp file outside the worktree (the aider pattern) and `--add-dir` lets copilot read that folder.
|
|
37
|
+
# --allow-all-tools and --no-ask-user approve every tool and never wait for a person; -s is the silent output.
|
|
38
|
+
"copilot": 'copilot -p "Your full instructions are in the file {prompt_path}. Read it, follow it, end with the '
|
|
39
|
+
'requested JSON report." --allow-all-tools --no-ask-user -s --add-dir {prompt_dir}{model_flag}',
|
|
31
40
|
}
|
|
32
|
-
_MODEL_OPT = {"kiro": "--model", "cursor": "--model", "aider": "--model"} #
|
|
41
|
+
_MODEL_OPT = {"kiro": "--model", "cursor": "--model", "aider": "--model", "copilot": "--model"} # aider -m = --message
|
|
33
42
|
CLAUDE_ALIASES = ("haiku", "sonnet", "opus")
|
|
43
|
+
# Q2: a preset's own names for the ladder aliases, used when agent.model_map does not map them. Copilot accepts Claude
|
|
44
|
+
# model names (docs checked 2026-10-12, not run live: only `claude-haiku-4.5` is named in the docs; sonnet and opus stay
|
|
45
|
+
# unmapped = Copilot's default model until Q9 records the exact names).
|
|
46
|
+
DEFAULT_MODEL_MAP = {"copilot": {"haiku": "claude-haiku-4.5"}}
|
|
47
|
+
_FILE_KEYS = ("{prompt_file}", "{prompt_path}", "{prompt_dir}")
|
|
34
48
|
SAFE_MODEL = re.compile(r"[A-Za-z0-9][A-Za-z0-9._:/@-]{0,127}")
|
|
35
49
|
|
|
36
50
|
|
|
37
51
|
def command_template(cfg) -> str:
|
|
38
|
-
|
|
52
|
+
"""The shell template: `agent.command`, or the preset. When the preset's binary is not on PATH but an older name
|
|
53
|
+
of it is (the doctor table's aliases, for example `cursor-agent`), that name is used."""
|
|
54
|
+
own = cfg.get("agent.command")
|
|
55
|
+
if own:
|
|
56
|
+
return own
|
|
57
|
+
preset = str(cfg.get("agent.preset") or "")
|
|
58
|
+
tpl = PRESETS.get(preset, "")
|
|
59
|
+
if tpl:
|
|
60
|
+
from ..doctor import runner
|
|
61
|
+
row = runner(preset)
|
|
62
|
+
if row is not None and not shutil.which(row.binary):
|
|
63
|
+
alias = next((a for a in row.aliases if shutil.which(a)), "")
|
|
64
|
+
if alias:
|
|
65
|
+
tpl = alias + tpl[len(row.binary):]
|
|
66
|
+
return tpl
|
|
39
67
|
|
|
40
68
|
|
|
41
69
|
def model_flag(cfg, model: str) -> str:
|
|
42
70
|
"""` -m <model>` (` --model <model>` for kiro, cursor, aider) after `agent.model_map` (ladder names → this CLI's
|
|
43
71
|
models); an unmapped Claude alias gets no flag, so the CLI uses its own default model."""
|
|
44
|
-
|
|
72
|
+
preset = str(cfg.get("agent.preset") or "")
|
|
73
|
+
own = (cfg.get("agent.model_map", {}) or {})
|
|
74
|
+
m = str(own.get(model, DEFAULT_MODEL_MAP.get(preset, {}).get(model, model)))
|
|
45
75
|
if not SAFE_MODEL.fullmatch(m): # the command runs through a shell (sh or cmd.exe): no quoting tricks needed
|
|
46
76
|
raise ValueError(f"unsafe model name for agent.preset: {m!r}")
|
|
47
|
-
opt = _MODEL_OPT.get(
|
|
77
|
+
opt = _MODEL_OPT.get(preset, "-m")
|
|
48
78
|
return "" if m in CLAUDE_ALIASES else f" {opt} {m}"
|
|
49
79
|
|
|
50
80
|
|
|
@@ -57,7 +87,7 @@ class CommandBackend:
|
|
|
57
87
|
# the project context lives in system_append (U7); a generic CLI has no system prompt, so it leads the prompt
|
|
58
88
|
prompt = f"{req.system_append}\n\n---\n\n{req.prompt}" if req.system_append else req.prompt
|
|
59
89
|
pf = ""
|
|
60
|
-
if
|
|
90
|
+
if any(k in self.template for k in _FILE_KEYS): # P03-T01: CLIs without a stdin prompt (aider, copilot); outside the worktree
|
|
61
91
|
with tempfile.NamedTemporaryFile("w", encoding="utf-8", prefix="autopilot-prompt-", suffix=".md",
|
|
62
92
|
delete=False) as f:
|
|
63
93
|
f.write(prompt)
|
|
@@ -70,7 +100,7 @@ class CommandBackend:
|
|
|
70
100
|
def _run(self, req: SessionRequest, prompt: str, pf: str) -> SessionResult:
|
|
71
101
|
cmd = self.template.format(model=shlex.quote(req.model), budget=req.budget_usd or 0,
|
|
72
102
|
read_only=int(req.read_only), model_flag=model_flag(self.cfg, req.model),
|
|
73
|
-
prompt_file=f'"{pf}"')
|
|
103
|
+
prompt_file=f'"{pf}"', prompt_path=pf, prompt_dir=f'"{os.path.dirname(pf)}"')
|
|
74
104
|
env = {**agent_env(self.cfg), "AUTOPILOT_MODEL": req.model, "AUTOPILOT_READ_ONLY": str(int(req.read_only)),
|
|
75
105
|
"AUTOPILOT_SYSTEM_APPEND": req.system_append}
|
|
76
106
|
env.update({"AUTODEV_" + k[10:]: v for k, v in list(env.items()) if k.startswith("AUTOPILOT_")})
|
|
@@ -383,36 +383,49 @@ def remember_setup(proj_path: Path, cmds: list[str]) -> None:
|
|
|
383
383
|
|
|
384
384
|
|
|
385
385
|
def runner_set(root: Path) -> bool:
|
|
386
|
-
"""N3: does the project's own project.yaml choose the agent CLI?
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
try:
|
|
390
|
-
agent = (load_yaml(path) if path.exists() else {}).get("agent") or {}
|
|
391
|
-
except (yaml.YAMLError, AttributeError):
|
|
392
|
-
return True # a file preflight cannot read is never edited; validate reports it
|
|
393
|
-
return not isinstance(agent, dict) or any(agent.get(k) for k in ("backend", "command", "preset"))
|
|
386
|
+
"""N3: does the project's own project.yaml choose the agent CLI? One reader: `doctor.runner_chosen`."""
|
|
387
|
+
from .doctor import runner_chosen
|
|
388
|
+
return runner_chosen(root)
|
|
394
389
|
|
|
395
390
|
|
|
396
391
|
def pick_runner(root: Path) -> bool:
|
|
397
|
-
"""N3: no runner set -> write the first installed, logged-in agent CLI on PATH. False = none
|
|
398
|
-
|
|
392
|
+
"""N3: no runner set -> write the first installed, logged-in agent CLI on PATH. False = none: the neutral list of
|
|
393
|
+
every runner with its install command (Q1), never 'Install Claude Code' first. A claude that is installed but
|
|
394
|
+
logged out stays the default with no write, so the H2 login offer still runs. The runner `ap setup` chose on this
|
|
395
|
+
PC (Q3, `~/.autopilot/runner`) is written when it is installed and nothing else is logged in."""
|
|
399
396
|
from .backends.claude_cli import ClaudeCLIBackend
|
|
400
|
-
from .doctor import
|
|
397
|
+
from .doctor import detect_runner, installed_runners, no_runner_text, runner
|
|
401
398
|
if os.environ.get("AUTOPILOT_CLAUDE_BIN") or os.environ.get("AUTODEV_CLAUDE_BIN"):
|
|
402
399
|
return True # an explicit claude binary is a choice: keep the claude_cli default
|
|
403
400
|
choice = detect_runner()
|
|
401
|
+
if not choice:
|
|
402
|
+
row = runner(setup_choice())
|
|
403
|
+
if row is not None and row.which():
|
|
404
|
+
choice = row.key
|
|
404
405
|
if choice:
|
|
405
406
|
if not remember_runner(Path(root) / AGENT_DIR / "project.yaml", choice):
|
|
406
407
|
return False
|
|
407
|
-
print(f"runner: {
|
|
408
|
+
print(f"runner: {runner(choice).binary} (found on PATH)")
|
|
408
409
|
return True
|
|
409
410
|
if shutil.which(ClaudeCLIBackend.resolve_binary()):
|
|
410
411
|
return True
|
|
411
|
-
|
|
412
|
-
|
|
412
|
+
found = installed_runners()
|
|
413
|
+
if found: # installed, logged out: say which login is missing, nothing else
|
|
414
|
+
row = found[0][0]
|
|
415
|
+
print(f"FAIL {row.binary} is installed but not logged in: run `{row.login}`, then start again")
|
|
416
|
+
return False
|
|
417
|
+
print(f"FAIL {no_runner_text()}")
|
|
413
418
|
return False
|
|
414
419
|
|
|
415
420
|
|
|
421
|
+
def setup_choice() -> str:
|
|
422
|
+
"""Q3: the runner `ap setup` chose on this PC (one word in `~/.autopilot/runner`), '' when none."""
|
|
423
|
+
try:
|
|
424
|
+
return (_recent_file().with_name("runner").read_text(encoding="utf-8").strip())
|
|
425
|
+
except OSError:
|
|
426
|
+
return ""
|
|
427
|
+
|
|
428
|
+
|
|
416
429
|
def remember_runner(proj_path: Path, choice: str) -> bool:
|
|
417
430
|
"""N3: write agent.backend (and agent.preset) as a text edit after the `agent:` line, so comments stay. The new
|
|
418
431
|
text is parsed first: when it would not give exactly the wanted values, nothing is written."""
|
|
@@ -1379,12 +1392,37 @@ def cmd_approve(args):
|
|
|
1379
1392
|
return 0
|
|
1380
1393
|
|
|
1381
1394
|
|
|
1382
|
-
def cmd_uninstall(args):
|
|
1383
|
-
"""N8: `ap uninstall --rights` removes the scheduled task / the sudoers file the installer created.
|
|
1384
|
-
|
|
1395
|
+
def cmd_uninstall(args, spawn=None):
|
|
1396
|
+
"""N8: `ap uninstall --rights` removes the scheduled task / the sudoers file the installer created.
|
|
1397
|
+
T3: `ap uninstall --all` removes the rights, `~/.autopilot`, and the package itself (last, after this process has
|
|
1398
|
+
exited: `ap.exe` is locked while it runs). `--dry-run` lists the steps. Projects' `.agent/` folders and the AI CLIs stay."""
|
|
1399
|
+
from .rights import have_rights, remove_rights
|
|
1400
|
+
from .upgrade import detect_install, spawn_after_exit
|
|
1401
|
+
dry = getattr(args, "dry_run", False)
|
|
1402
|
+
if getattr(args, "all", False):
|
|
1403
|
+
say = (lambda s: print(("would " if dry else "") + s))
|
|
1404
|
+
if have_rights():
|
|
1405
|
+
say("remove the rights the installer took (scheduled task / sudoers file)")
|
|
1406
|
+
if not dry:
|
|
1407
|
+
for line in remove_rights():
|
|
1408
|
+
print(line)
|
|
1409
|
+
home = _recent_file().parent
|
|
1410
|
+
say(f"delete {home} (recent projects, the install log, the runner choice)")
|
|
1411
|
+
if not dry and home.is_dir():
|
|
1412
|
+
shutil.rmtree(home, ignore_errors=True)
|
|
1413
|
+
kind = detect_install()
|
|
1414
|
+
cmd = {"uv": ["uv", "tool", "uninstall", "dev-autopilot"], "pip": [sys.executable, "-m", "pip", "uninstall", "-y", "dev-autopilot"]}.get(kind)
|
|
1415
|
+
if cmd is None:
|
|
1416
|
+
say("remove the package: this is a git checkout; run `pip uninstall dev-autopilot`, then delete the folder")
|
|
1417
|
+
else:
|
|
1418
|
+
say(f"remove the package ({kind}), after this command has exited: {' '.join(cmd)}")
|
|
1419
|
+
if not dry:
|
|
1420
|
+
(spawn or spawn_after_exit)(cmd)
|
|
1421
|
+
print("Kept: uv, Python, git, your AI CLI and its login, and each project's .agent/ folder (delete it to start clean).")
|
|
1422
|
+
return 0
|
|
1385
1423
|
if not getattr(args, "rights", False):
|
|
1386
1424
|
print("ap uninstall --rights removes the rights the installer took (scheduled task / sudoers file)\n"
|
|
1387
|
-
"
|
|
1425
|
+
"ap uninstall --all removes the rights, ~/.autopilot and Autopilot itself (--dry-run lists the steps)")
|
|
1388
1426
|
return 0
|
|
1389
1427
|
for line in remove_rights():
|
|
1390
1428
|
print(line)
|
|
@@ -1479,7 +1517,7 @@ def pick_project() -> str | None:
|
|
|
1479
1517
|
print("This folder is no Autopilot project, and no other project is known on this PC.\n"
|
|
1480
1518
|
"Go to the project folder, or name it with -C <folder>. To start a new one: autopilot quickstart")
|
|
1481
1519
|
return None
|
|
1482
|
-
print(f"project: {chosen}")
|
|
1520
|
+
print(f"this folder is no project, using the last one used: {chosen}") # Q10: say why, not only which
|
|
1483
1521
|
return str(chosen)
|
|
1484
1522
|
|
|
1485
1523
|
|
|
@@ -1499,6 +1537,8 @@ def main(argv=None):
|
|
|
1499
1537
|
if hasattr(s, "reconfigure"):
|
|
1500
1538
|
s.reconfigure(encoding="utf-8", errors="replace")
|
|
1501
1539
|
called = Path(sys.argv[0]).stem.lower() if argv is None else ""
|
|
1540
|
+
if called not in ("ap", "autopilot"): # `python -m autopilot` arrives as `__main__`: never a name a user reads
|
|
1541
|
+
called = ""
|
|
1502
1542
|
argv = list(sys.argv[1:] if argv is None else argv)
|
|
1503
1543
|
if argv[:1] == ["start"]: # J2: one plain word to start or continue the build in the background
|
|
1504
1544
|
argv[:1] = ["run", "--clear-stop", "--detach"]
|
|
@@ -1567,13 +1607,20 @@ def main(argv=None):
|
|
|
1567
1607
|
p = add("skip", cmd_skip, "skip task(s)"); p.add_argument("task_ids", nargs="+")
|
|
1568
1608
|
p = add("approve", cmd_approve, "deploy an approved phase to prod"); p.add_argument("phase")
|
|
1569
1609
|
add("mcp", cmd_mcp, "MCP server on stdin/stdout for IDE chats: ap_status, ap_next, ap_start, ap_stop, ap_answer")
|
|
1570
|
-
p = add("uninstall", cmd_uninstall, "--rights: remove the
|
|
1571
|
-
p.add_argument("--rights", action="store_true")
|
|
1610
|
+
p = add("uninstall", cmd_uninstall, "--rights: remove the rights the installer took; --all: remove Autopilot from this PC")
|
|
1611
|
+
p.add_argument("--rights", action="store_true"); p.add_argument("--all", action="store_true")
|
|
1612
|
+
p.add_argument("--dry-run", action="store_true", help="list the steps, change nothing")
|
|
1572
1613
|
from .upgrade import cmd_install, cmd_upgrade
|
|
1573
1614
|
p = add("upgrade", cmd_upgrade, "get the newest Autopilot; --check only prints")
|
|
1574
1615
|
p.add_argument("--check", action="store_true"); p.add_argument("--ref"); p.add_argument("--daily", action="store_true", help=argparse.SUPPRESS)
|
|
1575
1616
|
p = add("install", cmd_install, "install or repair Autopilot for this user; --rights = the one rights step")
|
|
1576
1617
|
p.add_argument("--rights", action="store_true")
|
|
1618
|
+
from .commands.setup import cmd_setup
|
|
1619
|
+
p = add("setup", cmd_setup, "find the AI you pay for, install its CLI, check the login, write the choice (one question at most)")
|
|
1620
|
+
p.add_argument("--dry-run", action="store_true", help="scan and print the plan; install and write nothing")
|
|
1621
|
+
p.add_argument("--runner", help="answer the question in advance: claude, copilot, codex, cursor or kiro")
|
|
1622
|
+
p.add_argument("--yes", action="store_true", help="take the default answer")
|
|
1623
|
+
p.add_argument("--skip-login", action="store_true", help="do not check or start a login")
|
|
1577
1624
|
add("stop", cmd_stop, "graceful stop before the next session")
|
|
1578
1625
|
add("resume", cmd_resume, "clear the stop flag")
|
|
1579
1626
|
p = add("report", cmd_report, "the run report; --tokens = tokens and cost per step type")
|
|
@@ -1597,7 +1644,7 @@ def main(argv=None):
|
|
|
1597
1644
|
print(f"autopilot {__version__}: {DESCRIPTION.split('. ')[0]}.")
|
|
1598
1645
|
print(next_steps_text(Path.cwd()))
|
|
1599
1646
|
return 0
|
|
1600
|
-
if args.cmd in ("upgrade", "install"): # no project: nothing to find or remember
|
|
1647
|
+
if args.cmd in ("upgrade", "install", "setup", "uninstall"): # no project needed: nothing to find or remember
|
|
1601
1648
|
return args.fn(args) or 0
|
|
1602
1649
|
if args.path is None: # J2: no -C
|
|
1603
1650
|
found = "." if args.cmd in NEW_PROJECT or (Path.cwd() / AGENT_DIR / "project.yaml").exists() else pick_project()
|
|
@@ -1607,7 +1654,13 @@ def main(argv=None):
|
|
|
1607
1654
|
remember(Path(args.path).resolve())
|
|
1608
1655
|
if getattr(args, "detach", False):
|
|
1609
1656
|
return start_detached(Path(args.path).resolve(), [a for a in (argv or sys.argv[1:]) if a != "--detach"])
|
|
1610
|
-
|
|
1657
|
+
rc = args.fn(args) or 0
|
|
1658
|
+
from .upgrade import auto_update # T2: after the command, once a day, never during a run
|
|
1659
|
+
|
|
1660
|
+
line = auto_update(args.cmd, Path(args.path).resolve())
|
|
1661
|
+
if line:
|
|
1662
|
+
print(line)
|
|
1663
|
+
return rc
|
|
1611
1664
|
|
|
1612
1665
|
|
|
1613
1666
|
if __name__ == "__main__":
|