tony-cli 0.4.2__tar.gz → 0.6.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 (35) hide show
  1. {tony_cli-0.4.2 → tony_cli-0.6.0}/LICENSE +2 -2
  2. {tony_cli-0.4.2/src/tony_cli.egg-info → tony_cli-0.6.0}/PKG-INFO +47 -68
  3. tony_cli-0.6.0/README.md +120 -0
  4. {tony_cli-0.4.2 → tony_cli-0.6.0}/pyproject.toml +2 -6
  5. tony_cli-0.6.0/src/tony_cli/agent.py +108 -0
  6. tony_cli-0.6.0/src/tony_cli/anchors.py +374 -0
  7. tony_cli-0.6.0/src/tony_cli/hosted.py +550 -0
  8. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli/install.py +118 -1
  9. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli/layout.py +37 -24
  10. tony_cli-0.6.0/src/tony_cli/mcp_config.py +190 -0
  11. tony_cli-0.6.0/src/tony_cli/mcp_server.py +790 -0
  12. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli/payload.py +18 -7
  13. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli/source/local.py +88 -87
  14. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli/uninstall.py +9 -8
  15. {tony_cli-0.4.2 → tony_cli-0.6.0/src/tony_cli.egg-info}/PKG-INFO +47 -68
  16. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli.egg-info/SOURCES.txt +3 -9
  17. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli.egg-info/requires.txt +1 -2
  18. tony_cli-0.4.2/README.md +0 -140
  19. tony_cli-0.4.2/src/tony_cli/agent.py +0 -766
  20. tony_cli-0.4.2/src/tony_cli/assets/fonts/Favorit-Bold.woff2 +0 -0
  21. tony_cli-0.4.2/src/tony_cli/assets/fonts/Favorit-Book.woff2 +0 -0
  22. tony_cli-0.4.2/src/tony_cli/assets/fonts/Favorit-Regular.woff2 +0 -0
  23. tony_cli-0.4.2/src/tony_cli/assets/fonts/FavoritMono-Medium.woff2 +0 -0
  24. tony_cli-0.4.2/src/tony_cli/assets/fonts/FavoritMono-Regular.woff2 +0 -0
  25. tony_cli-0.4.2/src/tony_cli/assets/viewer.css +0 -281
  26. tony_cli-0.4.2/src/tony_cli/assets/viewer.js +0 -98
  27. tony_cli-0.4.2/src/tony_cli/fonts.py +0 -38
  28. tony_cli-0.4.2/src/tony_cli/hosted.py +0 -324
  29. tony_cli-0.4.2/src/tony_cli/page.py +0 -54
  30. {tony_cli-0.4.2 → tony_cli-0.6.0}/setup.cfg +0 -0
  31. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli/__init__.py +0 -0
  32. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli/source/__init__.py +0 -0
  33. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli.egg-info/dependency_links.txt +0 -0
  34. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli.egg-info/entry_points.txt +0 -0
  35. {tony_cli-0.4.2 → tony_cli-0.6.0}/src/tony_cli.egg-info/top_level.txt +0 -0
@@ -12,8 +12,8 @@ furnished to do so, subject to the following conditions:
12
12
  The above copyright notice and this permission notice shall be included in all
13
13
  copies or substantial portions of the Software.
14
14
 
15
- The ABC Favorit and ABC Favorit Mono font files under src/tony_cli/assets/fonts
16
- are commercial typefaces by Dinamo and are NOT covered by this license.
15
+ The ABC Favorit and ABC Favorit Mono font files under web/public/fonts are
16
+ commercial typefaces by Dinamo and are NOT covered by this license.
17
17
 
18
18
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
19
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tony-cli
3
- Version: 0.4.2
3
+ Version: 0.6.0
4
4
  Summary: Explains a git diff to whoever now owns it — annotated changes, blast radius, and steppable runtime walkthroughs.
5
5
  Author: Fawwaz Abayomi
6
6
  License: MIT License
@@ -17,8 +17,8 @@ License: MIT License
17
17
  The above copyright notice and this permission notice shall be included in all
18
18
  copies or substantial portions of the Software.
19
19
 
20
- The ABC Favorit and ABC Favorit Mono font files under src/tony_cli/assets/fonts
21
- are commercial typefaces by Dinamo and are NOT covered by this license.
20
+ The ABC Favorit and ABC Favorit Mono font files under web/public/fonts are
21
+ commercial typefaces by Dinamo and are NOT covered by this license.
22
22
 
23
23
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
24
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -44,10 +44,9 @@ Classifier: Topic :: Software Development :: Version Control :: Git
44
44
  Requires-Python: >=3.10
45
45
  Description-Content-Type: text/markdown
46
46
  License-File: LICENSE
47
- Requires-Dist: anthropic>=0.40
48
- Requires-Dist: python-dotenv>=1.0
49
47
  Requires-Dist: httpx>=0.27
50
48
  Requires-Dist: cryptography>=42
49
+ Requires-Dist: mcp>=1.9
51
50
  Provides-Extra: dev
52
51
  Requires-Dist: pytest>=8; extra == "dev"
53
52
  Dynamic: license-file
@@ -56,9 +55,14 @@ Dynamic: license-file
56
55
 
57
56
  **Your AI wrote the code. tony explains what now exists.**
58
57
 
59
- tony is a CLI that turns a git diff into a review page for the person who now
60
- owns the code — often someone who didn't type a line of it. Not a linter, not a
61
- code-review gate: it builds your mental model of the change, fast.
58
+ tony turns a git diff into a review page for the person who now owns the code —
59
+ often someone who didn't type a line of it. Not a linter, not a code-review
60
+ gate: it builds your mental model of the change, fast.
61
+
62
+ tony does not call a model. It runs inside the coding agent you already pay for:
63
+ you ask the agent to review a branch, it calls tony over MCP, tony hands it the
64
+ diff and the standard the review has to meet, checks the answer against the
65
+ diff, and publishes the page.
62
66
 
63
67
  Every review page has three tabs:
64
68
 
@@ -87,63 +91,46 @@ uv tool install tony-cli # or: pipx install tony-cli
87
91
 
88
92
  Either way you get a `tony` command on your PATH.
89
93
 
90
- ## Use
94
+ ## Set up
95
+
96
+ Two commands, once per machine:
91
97
 
92
98
  ```sh
93
- cd your-repo
94
- tony main...my-branch # review a branch against main
95
- tony # review the default branch...HEAD
99
+ tony connect # register tony with Claude Code, Codex, Cursor, Amp
100
+ tony login # sign in, so reviews have somewhere to publish
96
101
  ```
97
102
 
98
- Reviews stay on your machine. The page is written to `.tony/` inside the repo
99
- (gitignored automatically) and opens in your browser — one self-contained HTML
100
- file, fonts and styles and data inlined, so it works offline and forever.
101
- Nothing is uploaded; the only thing that leaves your machine is the diff tony
102
- sends to Anthropic to write the review.
103
-
104
- tony needs an Anthropic API key (`ANTHROPIC_API_KEY`, or `~/.tony/.env`). The
105
- first run tells you exactly where to get one and where to put it. tony reviews
106
- **committed** work: it shows code straight from disk, so the working tree must
107
- match the revision under review.
108
-
109
- Every command and flag is listed under [Commands](#commands).
103
+ Then restart your agent and ask it, in words:
110
104
 
111
- ## Commands
112
-
113
- `tony --help` prints this list. Everything below works from anywhere inside a
114
- git repo unless noted.
105
+ > review this branch with tony
115
106
 
116
- ### Reviewing
107
+ The agent calls `tony_start`, reads the diff and whatever files it needs,
108
+ writes the review, and calls `tony_publish`. What comes back is a URL. Reviews
109
+ are published to your account; the page is the deliverable, so the agent hands
110
+ you the link rather than pasting the review into the chat.
117
111
 
118
- ```sh
119
- tony # default branch...HEAD, in the current repo
120
- tony main...my-branch # an explicit range
121
- tony my-branch # shorthand for my-branch...HEAD
122
- tony ../other-repo main...x # any path inside another repo
123
- ```
112
+ tony reviews **committed** work: the page shows code straight from disk, so the
113
+ working tree has to match the revision under review.
124
114
 
125
- The range is git's own `BASE...HEAD` syntax. With no range, tony diffs against
126
- `origin/HEAD` — what the remote calls its default branch — falling back to
127
- `main`, then `master`.
128
-
129
- | Flag | What it does |
130
- |---|---|
131
- | `--json` | Print the raw review JSON to stdout and exit. Writes no page instead. |
132
- | `--no-open` | Write the page but don't open a browser. For CI, or over SSH. |
133
- | `--stale` | Review a revision that isn't checked out, or with a dirty tree. Code is read from disk, so line numbers may not match the diff — tony refuses by default for that reason. |
134
- | `--replay` | Rebuild the page from the last saved review for this range, without calling the API. Free; use it after a tony upgrade to re-render an old review. |
135
- | `-v`, `--verbose` | Log every tool call to stderr, so you can see which files the review actually read before it drew conclusions. |
136
- | `-m`, `--model` | Model to review with. Defaults to `claude-opus-5`. |
137
- | `--max-tokens` | Response ceiling, default `64000`. Raise it if a review comes back cut off. |
115
+ ## Commands
138
116
 
139
- ### Managing tony
117
+ `tony --help` prints this list.
140
118
 
141
119
  | Command | What it does |
142
120
  |---|---|
121
+ | `tony connect [host ...]` | Write the MCP config for Claude Code, Codex, Cursor, or Amp. Named hosts only, or all four it finds. |
122
+ | `tony login` / `tony logout` | Your account on the tony site. Publishing needs it; nothing else does. |
123
+ | `tony mcp` | Run the MCP server on stdio. Your agent runs this, not you. |
143
124
  | `tony update` | Upgrade to the latest release, using whichever of uv, pipx or pip installed tony. Checks PyPI first and tells you if you're already current. |
125
+
126
+ Every command asks PyPI whether there is a newer release and says so on the way
127
+ out; the request runs alongside the command, so nothing waits on it, and a
128
+ review started through the MCP server tells the agent instead of a terminal
129
+ nobody is watching. It never installs anything by itself.
130
+
144
131
  | `tony uninstall` | Delete tony and everything it wrote — see [Uninstall](#uninstall). |
145
132
  | `tony --version` | The installed version. |
146
- | `tony --help` | Every command and flag. |
133
+ | `tony --help` | This list. |
147
134
 
148
135
  `tony uninstall` takes `--yes` (`-y`) to skip the confirmation and `--no-scan` to
149
136
  limit it to the current repo instead of searching your home directory.
@@ -157,11 +144,12 @@ pointed at an internal mirror can't decide what `tony-cli` is.
157
144
  tony uninstall
158
145
  ```
159
146
 
160
- Removing the package by itself would leave the parts worth removing: your
161
- `ANTHROPIC_API_KEY` in `~/.tony`, and a `.tony/` directory of past reviews
162
- inside every repository you ran tony in — those hold source code. `tony
163
- uninstall` lists everything it found, waits for you to type `yes`, deletes it,
164
- then removes the package with whichever of uv, pipx, or pip installed it.
147
+ Removing the package by itself would leave the parts worth removing: your login
148
+ token in `~/.tony`, and — from versions before tony went agent-native — an API
149
+ key beside it and a `.tony/` directory of past reviews inside every repository
150
+ you ran tony in, which hold source code. `tony uninstall` lists everything it
151
+ found, waits for you to type `yes`, deletes it, then removes the package with
152
+ whichever of uv, pipx, or pip installed it.
165
153
 
166
154
  It searches your home directory for stray review directories; `--no-scan`
167
155
  limits it to the current repository, and `--yes` skips the prompt.
@@ -172,22 +160,13 @@ limits it to the current repository, and `--yes` skips the prompt.
172
160
  pip install -e ".[dev]" # the CLI, with pytest
173
161
  python -m pytest # the deterministic layer's tests
174
162
  cd web && npm install
175
- npm run build:viewer # rebuild the renderer bundle the CLI embeds
176
163
  npm run dev # the site; /dev renders src/fixtures/review.json
177
164
  ```
178
165
 
179
- Two flags exist only for this loop, and only work from a source checkout:
180
-
181
- | Flag | What it does |
182
- |---|---|
183
- | `--viewer` | Write the payload straight into the local Astro viewer and reload it there, so you can iterate on the renderer against a real review. |
184
- | `--payload [PATH]` | Write the upload payload — windowed source, no absolute paths — next to the page, or to `PATH`. |
185
-
186
- There is exactly one renderer — `web/src/renderer/render.ts` — used by both
187
- the local page and the hosted site. The Python side decides all layout facts
188
- (line numbers, spans, added/changed tags) in `src/tony_cli/layout.py` and ships
189
- them in the payload; the renderer never re-derives them. `DESIGN.md` is the
190
- visual contract.
166
+ The renderer is `web/src/renderer/render.ts`, and the site is the only thing
167
+ that runs it. The Python side decides all layout facts (line numbers, spans,
168
+ added/changed tags) in `src/tony_cli/layout.py` and ships them in the payload;
169
+ the renderer never re-derives them. `DESIGN.md` is the visual contract.
191
170
 
192
171
  The site deploys to Vercel and needs `DATABASE_URL` (Neon Postgres),
193
172
  `BLOB_READ_WRITE_TOKEN` (Vercel Blob), and `GITHUB_CLIENT_ID` (an OAuth app
@@ -0,0 +1,120 @@
1
+ # tony
2
+
3
+ **Your AI wrote the code. tony explains what now exists.**
4
+
5
+ tony turns a git diff into a review page for the person who now owns the code —
6
+ often someone who didn't type a line of it. Not a linter, not a code-review
7
+ gate: it builds your mental model of the change, fast.
8
+
9
+ tony does not call a model. It runs inside the coding agent you already pay for:
10
+ you ask the agent to review a branch, it calls tony over MCP, tony hands it the
11
+ diff and the standard the review has to meet, checks the answer against the
12
+ diff, and publishes the page.
13
+
14
+ Every review page has three tabs:
15
+
16
+ 1. **File changes** — the diff per file, with plain-language annotations sitting
17
+ inline above the lines they explain. Modified code gets Prev / New / Changes
18
+ panes; line numbers are computed from the diff, never trusted to the model.
19
+ 2. **Blast radius** — files the change reaches that are *not* in the diff, each
20
+ consumer classified breaks / behavior-change / compatible, shown at the
21
+ affected lines.
22
+ 3. **How it works** — steppable runtime walkthroughs. One concrete scenario
23
+ ("you run `export --resume` after a crash") traced step by step, showing the
24
+ real source lines read from your disk, a small state table, and one plain
25
+ sentence per step.
26
+
27
+ ## Install
28
+
29
+ ```sh
30
+ curl -fsSL https://tony-cli.com/install.sh | sh
31
+ ```
32
+
33
+ or, if you already use uv or pipx:
34
+
35
+ ```sh
36
+ uv tool install tony-cli # or: pipx install tony-cli
37
+ ```
38
+
39
+ Either way you get a `tony` command on your PATH.
40
+
41
+ ## Set up
42
+
43
+ Two commands, once per machine:
44
+
45
+ ```sh
46
+ tony connect # register tony with Claude Code, Codex, Cursor, Amp
47
+ tony login # sign in, so reviews have somewhere to publish
48
+ ```
49
+
50
+ Then restart your agent and ask it, in words:
51
+
52
+ > review this branch with tony
53
+
54
+ The agent calls `tony_start`, reads the diff and whatever files it needs,
55
+ writes the review, and calls `tony_publish`. What comes back is a URL. Reviews
56
+ are published to your account; the page is the deliverable, so the agent hands
57
+ you the link rather than pasting the review into the chat.
58
+
59
+ tony reviews **committed** work: the page shows code straight from disk, so the
60
+ working tree has to match the revision under review.
61
+
62
+ ## Commands
63
+
64
+ `tony --help` prints this list.
65
+
66
+ | Command | What it does |
67
+ |---|---|
68
+ | `tony connect [host ...]` | Write the MCP config for Claude Code, Codex, Cursor, or Amp. Named hosts only, or all four it finds. |
69
+ | `tony login` / `tony logout` | Your account on the tony site. Publishing needs it; nothing else does. |
70
+ | `tony mcp` | Run the MCP server on stdio. Your agent runs this, not you. |
71
+ | `tony update` | Upgrade to the latest release, using whichever of uv, pipx or pip installed tony. Checks PyPI first and tells you if you're already current. |
72
+
73
+ Every command asks PyPI whether there is a newer release and says so on the way
74
+ out; the request runs alongside the command, so nothing waits on it, and a
75
+ review started through the MCP server tells the agent instead of a terminal
76
+ nobody is watching. It never installs anything by itself.
77
+
78
+ | `tony uninstall` | Delete tony and everything it wrote — see [Uninstall](#uninstall). |
79
+ | `tony --version` | The installed version. |
80
+ | `tony --help` | This list. |
81
+
82
+ `tony uninstall` takes `--yes` (`-y`) to skip the confirmation and `--no-scan` to
83
+ limit it to the current repo instead of searching your home directory.
84
+
85
+ Both `tony update` and the installer resolve from PyPI explicitly, so a machine
86
+ pointed at an internal mirror can't decide what `tony-cli` is.
87
+
88
+ ## Uninstall
89
+
90
+ ```sh
91
+ tony uninstall
92
+ ```
93
+
94
+ Removing the package by itself would leave the parts worth removing: your login
95
+ token in `~/.tony`, and — from versions before tony went agent-native — an API
96
+ key beside it and a `.tony/` directory of past reviews inside every repository
97
+ you ran tony in, which hold source code. `tony uninstall` lists everything it
98
+ found, waits for you to type `yes`, deletes it, then removes the package with
99
+ whichever of uv, pipx, or pip installed it.
100
+
101
+ It searches your home directory for stray review directories; `--no-scan`
102
+ limits it to the current repository, and `--yes` skips the prompt.
103
+
104
+ ## Development
105
+
106
+ ```sh
107
+ pip install -e ".[dev]" # the CLI, with pytest
108
+ python -m pytest # the deterministic layer's tests
109
+ cd web && npm install
110
+ npm run dev # the site; /dev renders src/fixtures/review.json
111
+ ```
112
+
113
+ The renderer is `web/src/renderer/render.ts`, and the site is the only thing
114
+ that runs it. The Python side decides all layout facts (line numbers, spans,
115
+ added/changed tags) in `src/tony_cli/layout.py` and ships them in the payload;
116
+ the renderer never re-derives them. `DESIGN.md` is the visual contract.
117
+
118
+ The site deploys to Vercel and needs `DATABASE_URL` (Neon Postgres),
119
+ `BLOB_READ_WRITE_TOKEN` (Vercel Blob), and `GITHUB_CLIENT_ID` (an OAuth app
120
+ with device flow enabled).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tony-cli"
3
- version = "0.4.2"
3
+ version = "0.6.0"
4
4
  description = "Explains a git diff to whoever now owns it — annotated changes, blast radius, and steppable runtime walkthroughs."
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -20,10 +20,9 @@ classifiers = [
20
20
  "Topic :: Software Development :: Version Control :: Git",
21
21
  ]
22
22
  dependencies = [
23
- "anthropic>=0.40",
24
- "python-dotenv>=1.0",
25
23
  "httpx>=0.27",
26
24
  "cryptography>=42",
25
+ "mcp>=1.9",
27
26
  ]
28
27
 
29
28
  [project.optional-dependencies]
@@ -44,8 +43,5 @@ build-backend = "setuptools.build_meta"
44
43
  where = ["src"]
45
44
  include = ["tony_cli*"]
46
45
 
47
- [tool.setuptools.package-data]
48
- tony_cli = ["assets/fonts/*.woff2", "assets/viewer.js", "assets/viewer.css"]
49
-
50
46
  [tool.pytest.ini_options]
51
47
  testpaths = ["src/tests"]
@@ -0,0 +1,108 @@
1
+ """The `tony` command.
2
+
3
+ tony does not review anything itself. The reviewing happens inside whatever
4
+ coding agent the developer already pays for, over the MCP server in
5
+ `mcp_server.py` — the agent reads the diff, writes the review, and hands it
6
+ back to be validated and published. So this module is a dispatcher: accounts,
7
+ agent wiring, and the installer. Everything a person types.
8
+
9
+ The old path — tony owning an Anthropic key and driving its own tool loop —
10
+ is gone. See `mcp_server.py` for what replaced it.
11
+ """
12
+
13
+ import sys
14
+
15
+ from tony_cli import hosted, install
16
+
17
+ USAGE = """\
18
+ tony — explains a git diff to whoever now owns it.
19
+
20
+ tony connect [host ...] connect tony to your coding agent
21
+ tony login sign in, so reviews have somewhere to publish
22
+ tony logout sign out on this machine
23
+ tony mcp run the MCP server on stdio (agents call this)
24
+ tony update update to the latest release
25
+ tony uninstall delete tony, its login, and every saved review
26
+ tony --version what is installed
27
+
28
+ To review something, ask your agent: "review this branch with tony".
29
+
30
+ https://tony-cli.com
31
+ """
32
+
33
+
34
+ # Commands that must not carry the notice. `update` and `uninstall` are about
35
+ # the installed version already and would be talking over themselves; `mcp`
36
+ # speaks a protocol on stdio and has no terminal to say anything to — it tells
37
+ # the agent instead, in `mcp_server.startReview`.
38
+ NO_NOTICE = ("update", "uninstall", "mcp")
39
+
40
+
41
+ def main(argv=None):
42
+ argv = sys.argv[1:] if argv is None else argv
43
+ command = argv[0] if argv else None
44
+
45
+ # Started before the command, collected after it: the round trip to PyPI
46
+ # overlaps whatever the command was going to do anyway, so the only run
47
+ # that ever waits on it is one that finishes in under half a second.
48
+ check = None if command in NO_NOTICE else install.startUpdateCheck()
49
+ code = dispatch(argv, command)
50
+ if check:
51
+ notice = install.updateNotice(check)
52
+ if notice:
53
+ # stderr, so it never lands in the middle of output being piped
54
+ # somewhere that expected only the command's own.
55
+ print(notice, file=sys.stderr)
56
+ return code
57
+
58
+
59
+ def dispatch(argv, command):
60
+ """Run one command and return its exit code. Everything a person types."""
61
+ if command in (None, "help", "-h", "--help"):
62
+ # No arguments is not an error: it is someone who just installed tony
63
+ # and wants to know what to type next. That is `tony connect`.
64
+ print(USAGE)
65
+ return 0
66
+
67
+ if command in ("--version", "-V", "version"):
68
+ print(f"tony {install.installedVersion() or 'unknown'}")
69
+ return 0
70
+
71
+ if command == "login":
72
+ return hosted.login(argv[1:])
73
+ if command == "logout":
74
+ return hosted.logout()
75
+
76
+ # Imported here, not at the top: it pulls in the MCP SDK, and `tony` as a
77
+ # CLI should not pay that import on every run to serve one subcommand.
78
+ if command == "mcp":
79
+ from tony_cli.mcp_server import serve
80
+ return serve(argv[1:])
81
+ if command == "connect":
82
+ from tony_cli import mcp_config
83
+ return mcp_config.connect(argv[1:])
84
+
85
+ # The obvious wrong guess, and one worth answering.
86
+ if command == "install":
87
+ print("tony: tony is already installed — you want `tony connect`, which\n"
88
+ " registers it with your coding agent.", file=sys.stderr)
89
+ return 2
90
+ if command == "update":
91
+ return install.update(argv[1:])
92
+ if command == "uninstall":
93
+ from tony_cli.uninstall import uninstall
94
+ return uninstall(argv[1:])
95
+
96
+ # A range or a repository path — what tony used to take directly. Someone
97
+ # typing it has an older tony's habits, so say where the reviewing went.
98
+ print(
99
+ f"tony: unknown command {command!r}.\n\n"
100
+ " tony no longer reviews on its own. Run `tony connect` once, then ask\n"
101
+ " your coding agent to review the branch and it will call tony for you.\n",
102
+ file=sys.stderr,
103
+ )
104
+ return 2
105
+
106
+
107
+ if __name__ == "__main__":
108
+ sys.exit(main())