code-aide 1.5.0__tar.gz → 1.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 (42) hide show
  1. {code_aide-1.5.0 → code_aide-1.6.0}/AGENTS.md +10 -5
  2. {code_aide-1.5.0 → code_aide-1.6.0}/PKG-INFO +16 -27
  3. {code_aide-1.5.0 → code_aide-1.6.0}/README.md +15 -26
  4. code_aide-1.6.0/specs/remove-bundled-version-baseline.md +77 -0
  5. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/__init__.py +1 -1
  6. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/commands_actions.py +2 -7
  7. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/config.py +4 -30
  8. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/data/tools.json +8 -24
  9. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/entry.py +0 -6
  10. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/install.py +12 -2
  11. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_commands_actions.py +0 -61
  12. {code_aide-1.5.0 → code_aide-1.6.0}/.github/workflows/ci.yml +0 -0
  13. {code_aide-1.5.0 → code_aide-1.6.0}/.github/workflows/publish.yml +0 -0
  14. {code_aide-1.5.0 → code_aide-1.6.0}/.gitignore +0 -0
  15. {code_aide-1.5.0 → code_aide-1.6.0}/.gitlab-ci.yml +0 -0
  16. {code_aide-1.5.0 → code_aide-1.6.0}/.pre-commit-config.yaml +0 -0
  17. {code_aide-1.5.0 → code_aide-1.6.0}/CLAUDE.md +0 -0
  18. {code_aide-1.5.0 → code_aide-1.6.0}/LICENSE +0 -0
  19. {code_aide-1.5.0 → code_aide-1.6.0}/TODO.md +0 -0
  20. {code_aide-1.5.0 → code_aide-1.6.0}/pyproject.toml +0 -0
  21. {code_aide-1.5.0 → code_aide-1.6.0}/specs/claude-native-installer-migration.md +0 -0
  22. {code_aide-1.5.0 → code_aide-1.6.0}/specs/missing-coding-llm-cli-tools.md +0 -0
  23. {code_aide-1.5.0 → code_aide-1.6.0}/specs/pre-commit-uv-setup.md +0 -0
  24. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/__main__.py +0 -0
  25. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/commands_tools.py +0 -0
  26. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/console.py +0 -0
  27. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/constants.py +0 -0
  28. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/detection.py +0 -0
  29. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/operations.py +0 -0
  30. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/prereqs.py +0 -0
  31. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/status.py +0 -0
  32. {code_aide-1.5.0 → code_aide-1.6.0}/src/code_aide/versions.py +0 -0
  33. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_commands_tools.py +0 -0
  34. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_config.py +0 -0
  35. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_console.py +0 -0
  36. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_constants.py +0 -0
  37. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_detection.py +0 -0
  38. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_install.py +0 -0
  39. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_operations.py +0 -0
  40. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_status.py +0 -0
  41. {code_aide-1.5.0 → code_aide-1.6.0}/tests/test_versions.py +0 -0
  42. {code_aide-1.5.0 → code_aide-1.6.0}/uv.lock +0 -0
@@ -3,15 +3,20 @@
3
3
  ## Key Design Decisions
4
4
 
5
5
  - No external dependencies - stdlib only
6
- - Three-layer version data: bundled definitions, bundled baseline versions,
6
+ - Two-layer version data: bundled definitions (with SHA256 checksums),
7
7
  user's local cache (~/.config/code-aide/versions.json)
8
8
  - All tests should pass before committing
9
- - pre-commit runs black and ruff on commit; run `pre-commit run --all-files` to
10
- check before committing
11
- - When changing pyproject.toml dependencies, run `uv lock` and commit uv.lock
9
+ - pre-commit runs black and ruff on commit; run `black` to format and then
10
+ `pre-commit run --all-files` to check before committing
11
+ - When changing pyproject.toml dependencies, run `uv lock` and commit
12
+ uv.lock
12
13
  - Write useful commit messages: start subjects with past-tense action verbs
13
14
  (`Added`, `Changed`, `Fixed`, `Removed`), keep them user-facing, and keep
14
15
  commits focused.
15
16
  - Python 3.11+ compatible
16
17
  - Keep files under 300 lines where practical
17
- - Run `format-markdown` on markdown files before commits (if it is available)
18
+ - Run `format-markdown` on markdown files before commits (if it is
19
+ available)
20
+ - When pushing tags, always push them explicitly with `git push <remote>
21
+ <tag>` rather than relying on `--follow-tags`, which silently skips tags
22
+ when the branch commits are already on the remote
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-aide
3
- Version: 1.5.0
3
+ Version: 1.6.0
4
4
  Summary: Manage AI coding CLI tools (Claude, Copilot, Cursor, Gemini, Amp, Codex)
5
5
  Project-URL: Homepage, https://github.com/dajobe/code-aide
6
6
  Project-URL: Repository, https://github.com/dajobe/code-aide
@@ -74,9 +74,6 @@ code-aide update-versions -n
74
74
 
75
75
  # Update version cache
76
76
  code-aide update-versions -y
77
-
78
- # Update bundled version baseline (developer use, before releases)
79
- code-aide update-versions -b -y
80
77
  ```
81
78
 
82
79
  ## Supported Tools
@@ -94,22 +91,18 @@ code-aide update-versions -b -y
94
91
 
95
92
  ## How Version Data Works
96
93
 
97
- code-aide uses a three-layer version data model:
98
-
99
- 1. **Tool definitions** (bundled with the package): Install methods, URLs,
100
- npm packages, version args. Updated by releasing new versions of
101
- code-aide.
94
+ code-aide uses a two-layer version data model:
102
95
 
103
- 2. **Bundled version baseline** (in `data/tools.json`): Latest versions and
104
- SHA256 hashes as known at release time. Acts as a fallback for fresh
105
- installs.
96
+ 1. **Bundled tool definitions** (in `data/tools.json`): Install methods,
97
+ URLs, npm packages, version args, and SHA256 checksums. Updated by
98
+ releasing new versions of code-aide.
106
99
 
107
- 3. **User's local version cache** (`~/.config/code-aide/versions.json`):
108
- Written by `code-aide update-versions`. Takes precedence over bundled
109
- data when present.
100
+ 2. **User's local version cache** (`~/.config/code-aide/versions.json`):
101
+ Written by `code-aide update-versions`. Provides latest versions, dates,
102
+ and updated SHA256 checksums.
110
103
 
111
- Run `code-aide update-versions` to get fresher version data without waiting
112
- for a new code-aide release.
104
+ Run `code-aide update-versions` to get the latest version data without
105
+ waiting for a new code-aide release.
113
106
 
114
107
  ## Features
115
108
 
@@ -147,29 +140,25 @@ uv run pytest tests/test_install.py::TestDetectOsArch -v
147
140
 
148
141
  `publish.yml` publishes to PyPI when a Git tag matching `v*` is pushed.
149
142
 
150
- 1. Update the bundled version baseline:
151
- - `code-aide update-versions -b -y`
152
- - `git add src/code_aide/data/tools.json`
153
- - `git commit -m "Updated bundled version data"`
154
- 2. Update the version string in `src/code_aide/__init__.py` (`__version__`).
143
+ 1. Update the version string in `src/code_aide/__init__.py` (`__version__`).
155
144
  `pyproject.toml` reads it automatically via Hatchling.
156
- 3. Run checks:
145
+ 2. Run checks:
157
146
  - `uv run pytest tests/ -v`
158
147
  - `uv build`
159
- 4. Commit the release version bump:
148
+ 3. Commit the release version bump:
160
149
  - `git add src/code_aide/__init__.py`
161
150
  - `git commit -m "Bumped version to X.Y.Z"`
162
- 5. Write useful commit messages before tagging:
151
+ 4. Write useful commit messages before tagging:
163
152
  - Start subject lines with an action verb in past tense (`Added`,
164
153
  `Changed`, `Fixed`, `Removed`).
165
154
  - Keep subjects user-facing so auto-generated release notes are
166
155
  meaningful.
167
156
  - Group related changes into focused commits instead of one broad commit.
168
157
  - Example: `Fixed timeout handling in status command`
169
- 6. Tag and push:
158
+ 5. Tag and push:
170
159
  - `git tag vX.Y.Z`
171
160
  - `git push origin main --follow-tags`
172
- 7. Confirm GitHub Actions:
161
+ 6. Confirm GitHub Actions:
173
162
  - CI should pass.
174
163
  - Publish workflow should upload to PyPI and create GitHub Release notes.
175
164
  - Release notes should include generated notes plus a commit summary from
@@ -48,9 +48,6 @@ code-aide update-versions -n
48
48
 
49
49
  # Update version cache
50
50
  code-aide update-versions -y
51
-
52
- # Update bundled version baseline (developer use, before releases)
53
- code-aide update-versions -b -y
54
51
  ```
55
52
 
56
53
  ## Supported Tools
@@ -68,22 +65,18 @@ code-aide update-versions -b -y
68
65
 
69
66
  ## How Version Data Works
70
67
 
71
- code-aide uses a three-layer version data model:
72
-
73
- 1. **Tool definitions** (bundled with the package): Install methods, URLs,
74
- npm packages, version args. Updated by releasing new versions of
75
- code-aide.
68
+ code-aide uses a two-layer version data model:
76
69
 
77
- 2. **Bundled version baseline** (in `data/tools.json`): Latest versions and
78
- SHA256 hashes as known at release time. Acts as a fallback for fresh
79
- installs.
70
+ 1. **Bundled tool definitions** (in `data/tools.json`): Install methods,
71
+ URLs, npm packages, version args, and SHA256 checksums. Updated by
72
+ releasing new versions of code-aide.
80
73
 
81
- 3. **User's local version cache** (`~/.config/code-aide/versions.json`):
82
- Written by `code-aide update-versions`. Takes precedence over bundled
83
- data when present.
74
+ 2. **User's local version cache** (`~/.config/code-aide/versions.json`):
75
+ Written by `code-aide update-versions`. Provides latest versions, dates,
76
+ and updated SHA256 checksums.
84
77
 
85
- Run `code-aide update-versions` to get fresher version data without waiting
86
- for a new code-aide release.
78
+ Run `code-aide update-versions` to get the latest version data without
79
+ waiting for a new code-aide release.
87
80
 
88
81
  ## Features
89
82
 
@@ -121,29 +114,25 @@ uv run pytest tests/test_install.py::TestDetectOsArch -v
121
114
 
122
115
  `publish.yml` publishes to PyPI when a Git tag matching `v*` is pushed.
123
116
 
124
- 1. Update the bundled version baseline:
125
- - `code-aide update-versions -b -y`
126
- - `git add src/code_aide/data/tools.json`
127
- - `git commit -m "Updated bundled version data"`
128
- 2. Update the version string in `src/code_aide/__init__.py` (`__version__`).
117
+ 1. Update the version string in `src/code_aide/__init__.py` (`__version__`).
129
118
  `pyproject.toml` reads it automatically via Hatchling.
130
- 3. Run checks:
119
+ 2. Run checks:
131
120
  - `uv run pytest tests/ -v`
132
121
  - `uv build`
133
- 4. Commit the release version bump:
122
+ 3. Commit the release version bump:
134
123
  - `git add src/code_aide/__init__.py`
135
124
  - `git commit -m "Bumped version to X.Y.Z"`
136
- 5. Write useful commit messages before tagging:
125
+ 4. Write useful commit messages before tagging:
137
126
  - Start subject lines with an action verb in past tense (`Added`,
138
127
  `Changed`, `Fixed`, `Removed`).
139
128
  - Keep subjects user-facing so auto-generated release notes are
140
129
  meaningful.
141
130
  - Group related changes into focused commits instead of one broad commit.
142
131
  - Example: `Fixed timeout handling in status command`
143
- 6. Tag and push:
132
+ 5. Tag and push:
144
133
  - `git tag vX.Y.Z`
145
134
  - `git push origin main --follow-tags`
146
- 7. Confirm GitHub Actions:
135
+ 6. Confirm GitHub Actions:
147
136
  - CI should pass.
148
137
  - Publish workflow should upload to PyPI and create GitHub Release notes.
149
138
  - Release notes should include generated notes plus a commit summary from
@@ -0,0 +1,77 @@
1
+ # Remove bundled version baseline
2
+
3
+ ## Context
4
+
5
+ code-aide has a three-layer version data model where `latest_version` and
6
+ `latest_date` are bundled in `tools.json` as a baseline. These go stale
7
+ between releases and require a manual release step (`update-versions -b
8
+ -y`). The `install_sha256` field protects against tampered install scripts
9
+ and must remain bundled.
10
+
11
+ ## Approach
12
+
13
+ Remove `latest_version` and `latest_date` from bundled data and the
14
+ `-b`/`--bundled` flag from `update-versions`, simplifying to two layers:
15
+ bundled definitions (with SHA256) + user cache (with versions). The
16
+ `install_direct_download()` function needs an on-demand fetch when
17
+ `latest_version` is missing (fresh install with no cache).
18
+
19
+ ## Changes
20
+
21
+ ### 1. `src/code_aide/data/tools.json` -- remove version fields
22
+
23
+ Remove `latest_version` and `latest_date` from all 8 tool entries. Keep
24
+ `install_sha256`.
25
+
26
+ ### 2. `src/code_aide/config.py` -- remove bundled save function
27
+
28
+ - Remove `save_bundled_versions()` function.
29
+ - Update `load_tools_config()` docstring to describe two-layer model.
30
+ - `DYNAMIC_FIELDS` stays the same (user cache still stores all three).
31
+
32
+ ### 3. `src/code_aide/entry.py` -- remove --bundled flag
33
+
34
+ Remove `-b`/`--bundled` argument from the update-versions subparser.
35
+
36
+ ### 4. `src/code_aide/commands_actions.py` -- simplify update-versions
37
+
38
+ - Remove `save_bundled_versions` from imports.
39
+ - Remove `if not args.bundled:` guard around `merge_cached_versions` --
40
+ always merge.
41
+ - Remove bundled branch in `_save()` -- always save to user cache.
42
+ - Remove `args.bundled` reference.
43
+
44
+ ### 5. `src/code_aide/install.py` -- handle missing latest_version
45
+
46
+ In `install_direct_download()`, `tool_config["latest_version"]` will
47
+ KeyError on fresh installs with no cache. Add on-demand fetch: if
48
+ `latest_version` is missing, call `check_script_tool()` to get it before
49
+ proceeding with the download.
50
+
51
+ ### 6. `README.md` -- update documentation
52
+
53
+ - Rewrite "How Version Data Works" to describe two-layer model.
54
+ - Remove release step 1 (`update-versions -b -y` step).
55
+ - Remove usage example for `update-versions -b -y`.
56
+
57
+ ### 7. `AGENTS.md` -- update layer description
58
+
59
+ Change "Three-layer version data" to "Two-layer version data" and update
60
+ description.
61
+
62
+ ### 8. Tests
63
+
64
+ - `tests/test_commands_actions.py`: Remove
65
+ `test_bundled_flag_skips_cache_and_saves_to_bundled`. Update remaining
66
+ tests that set `"bundled": False` in args.
67
+
68
+ ## Verification
69
+
70
+ 1. `pre-commit run --all-files` -- formatting passes
71
+ 2. `uv run pytest tests/ -v` -- all tests pass
72
+ 3. `uv run python -m code_aide status` -- shows versions from cache, or
73
+ plain version without comparison if no cache
74
+ 4. `uv run python -m code_aide update-versions -n` -- fetches latest
75
+ versions
76
+ 5. `uv run python -m code_aide update-versions -y` -- saves to user cache
77
+ 6. `uv run python -m code_aide update-versions -b` -- errors (flag removed)
@@ -1,3 +1,3 @@
1
1
  """code-aide - Manage AI coding CLI tools."""
2
2
 
3
- __version__ = "1.5.0"
3
+ __version__ = "1.6.0"
@@ -26,7 +26,6 @@ from code_aide.config import (
26
26
  load_bundled_tools,
27
27
  load_versions_cache,
28
28
  merge_cached_versions,
29
- save_bundled_versions,
30
29
  save_updated_versions,
31
30
  )
32
31
 
@@ -234,8 +233,7 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
234
233
  """Handle update-versions command: check upstream for latest tool versions."""
235
234
  bundled = load_bundled_tools()
236
235
  tools = bundled.get("tools", {})
237
- if not args.bundled:
238
- merge_cached_versions(tools, load_versions_cache())
236
+ merge_cached_versions(tools, load_versions_cache())
239
237
 
240
238
  config: Dict[str, Any] = {"tools": tools}
241
239
 
@@ -293,10 +291,7 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
293
291
  version_info_changed = True
294
292
 
295
293
  def _save(tools: dict) -> str:
296
- """Save versions to bundled or user cache. Returns description."""
297
- if args.bundled:
298
- path = save_bundled_versions(tools)
299
- return path
294
+ """Save versions to user cache. Returns description."""
300
295
  save_updated_versions(tools)
301
296
  return "~/.config/code-aide/versions.json"
302
297
 
@@ -76,10 +76,10 @@ def merge_cached_versions(tools: dict, cache: dict) -> None:
76
76
  def load_tools_config() -> dict:
77
77
  """Load tool config: bundled definitions merged with cached versions.
78
78
 
79
- The bundled tools.json provides all tool definitions plus a baseline
80
- for latest_version, latest_date, and install_sha256. The user's
81
- version cache (from update-versions) overrides these dynamic fields
82
- when present.
79
+ Two-layer model: the bundled tools.json provides tool definitions and
80
+ install_sha256 checksums. The user's version cache (from
81
+ update-versions) provides latest_version, latest_date, and updated
82
+ install_sha256 values when present.
83
83
  """
84
84
  bundled = load_bundled_tools()
85
85
  cache = load_versions_cache()
@@ -103,29 +103,3 @@ def save_updated_versions(tools: dict) -> None:
103
103
  if entry:
104
104
  cache_data["tools"][tool_key] = entry
105
105
  save_versions_cache(cache_data)
106
-
107
-
108
- def save_bundled_versions(tools: dict) -> str:
109
- """Update dynamic fields in the bundled data/tools.json.
110
-
111
- Loads the existing bundled file to preserve static fields, then
112
- overwrites only the dynamic version fields from the provided tools
113
- dict. Returns the file path written.
114
- """
115
- ref = importlib.resources.files("code_aide").joinpath("data/tools.json")
116
- path = str(ref)
117
-
118
- with open(path, encoding="utf-8") as f:
119
- bundled = json.load(f)
120
-
121
- for tool_key, tool_data in tools.items():
122
- if tool_key in bundled.get("tools", {}):
123
- for field in DYNAMIC_FIELDS:
124
- if field in tool_data:
125
- bundled["tools"][tool_key][field] = tool_data[field]
126
-
127
- with open(path, "w", encoding="utf-8") as f:
128
- json.dump(bundled, f, indent=2)
129
- f.write("\n")
130
-
131
- return path
@@ -21,9 +21,7 @@
21
21
  "--version"
22
22
  ],
23
23
  "docs_url": "https://docs.cursor.com/",
24
- "default_install": true,
25
- "latest_version": "2026.02.27-e7d2ef6",
26
- "latest_date": "2026-02-27"
24
+ "default_install": true
27
25
  },
28
26
  "claude": {
29
27
  "name": "Claude CLI (Claude Code)",
@@ -38,9 +36,7 @@
38
36
  "--version"
39
37
  ],
40
38
  "docs_url": "https://code.claude.com/docs/en/setup",
41
- "default_install": true,
42
- "latest_version": "2.1.63",
43
- "latest_date": "2026-02-28"
39
+ "default_install": true
44
40
  },
45
41
  "gemini": {
46
42
  "name": "Gemini CLI",
@@ -56,9 +52,7 @@
56
52
  "--version"
57
53
  ],
58
54
  "docs_url": "https://github.com/google-gemini/gemini-cli",
59
- "default_install": true,
60
- "latest_version": "0.31.0",
61
- "latest_date": "2026-02-27"
55
+ "default_install": true
62
56
  },
63
57
  "amp": {
64
58
  "name": "Amp (Sourcegraph)",
@@ -74,9 +68,7 @@
74
68
  "--version"
75
69
  ],
76
70
  "docs_url": "https://ampcode.com/manual",
77
- "default_install": false,
78
- "latest_version": "0.0.1772339780-g24a24e",
79
- "latest_date": "2026-03-01"
71
+ "default_install": false
80
72
  },
81
73
  "codex": {
82
74
  "name": "Codex CLI",
@@ -92,9 +84,7 @@
92
84
  "--version"
93
85
  ],
94
86
  "docs_url": "https://github.com/openai/codex",
95
- "default_install": false,
96
- "latest_version": "0.106.0",
97
- "latest_date": "2026-02-26"
87
+ "default_install": false
98
88
  },
99
89
  "copilot": {
100
90
  "name": "Copilot CLI",
@@ -110,9 +100,7 @@
110
100
  "--version"
111
101
  ],
112
102
  "docs_url": "https://github.com/github/copilot-cli",
113
- "default_install": false,
114
- "latest_version": "0.0.420",
115
- "latest_date": "2026-02-27"
103
+ "default_install": false
116
104
  },
117
105
  "opencode": {
118
106
  "name": "OpenCode",
@@ -128,9 +116,7 @@
128
116
  "--version"
129
117
  ],
130
118
  "docs_url": "https://opencode.ai/docs/cli",
131
- "default_install": false,
132
- "latest_version": "1.2.15",
133
- "latest_date": "2026-02-26"
119
+ "default_install": false
134
120
  },
135
121
  "kilo": {
136
122
  "name": "Kilo CLI",
@@ -146,9 +132,7 @@
146
132
  "--version"
147
133
  ],
148
134
  "docs_url": "https://kilo.ai/docs/cli",
149
- "default_install": false,
150
- "latest_version": "7.0.33",
151
- "latest_date": "2026-02-27"
135
+ "default_install": false
152
136
  }
153
137
  }
154
138
  }
@@ -100,12 +100,6 @@ def main() -> None:
100
100
  action="store_true",
101
101
  help="Show full SHA256 hashes",
102
102
  )
103
- update_versions_parser.add_argument(
104
- "-b",
105
- "--bundled",
106
- action="store_true",
107
- help="Update bundled data/tools.json instead of user cache (developer use)",
108
- )
109
103
  update_versions_parser.set_defaults(func=cmd_update_versions)
110
104
 
111
105
  args = parser.parse_args()
@@ -12,7 +12,7 @@ from typing import Any, Dict, Optional
12
12
 
13
13
  from code_aide.constants import TOOLS
14
14
  from code_aide.console import command_exists, error, info, run_command, success, warning
15
- from code_aide.versions import fetch_url
15
+ from code_aide.versions import check_script_tool, fetch_url
16
16
 
17
17
 
18
18
  def run_install_script(
@@ -117,7 +117,17 @@ def install_direct_download(
117
117
  ) -> bool:
118
118
  """Download, extract, and install a tool via direct tarball download."""
119
119
  try:
120
- version = tool_config["latest_version"]
120
+ version = tool_config.get("latest_version")
121
+ if not version:
122
+ info("No cached version found, fetching latest version...")
123
+ result = check_script_tool(tool_name, tool_config)
124
+ version = result.get("version")
125
+ if not version or version == "-":
126
+ error(
127
+ f"Could not determine latest version for {tool_name}. "
128
+ "Run 'code-aide update-versions -y' first."
129
+ )
130
+ return False
121
131
  install_url = tool_config["install_url"]
122
132
  expected_sha256 = tool_config.get("install_sha256")
123
133
 
@@ -62,7 +62,6 @@ class TestCmdUpdateVersions(unittest.TestCase):
62
62
  "dryrun": False,
63
63
  "yes": False,
64
64
  "verbose": False,
65
- "bundled": False,
66
65
  },
67
66
  )()
68
67
  with mock.patch.object(
@@ -84,7 +83,6 @@ class TestCmdUpdateVersions(unittest.TestCase):
84
83
  "dryrun": True,
85
84
  "yes": False,
86
85
  "verbose": False,
87
- "bundled": False,
88
86
  },
89
87
  )()
90
88
  with (
@@ -124,65 +122,6 @@ class TestCmdUpdateVersions(unittest.TestCase):
124
122
  self.assertIn("No upstream config changes detected.", buf.getvalue())
125
123
  mock_save.assert_not_called()
126
124
 
127
- def test_bundled_flag_skips_cache_and_saves_to_bundled(self):
128
- args = type(
129
- "Args",
130
- (),
131
- {
132
- "tools": [],
133
- "dryrun": False,
134
- "yes": True,
135
- "verbose": False,
136
- "bundled": True,
137
- },
138
- )()
139
- bundled_tools = {
140
- "tools": {
141
- "ok": {
142
- "install_type": "npm",
143
- "npm_package": "pkg",
144
- "latest_version": "1.0.0",
145
- "latest_date": "2026-01-01",
146
- }
147
- }
148
- }
149
- with (
150
- mock.patch.object(
151
- commands_actions,
152
- "load_bundled_tools",
153
- return_value=bundled_tools,
154
- ),
155
- mock.patch.object(
156
- commands_actions, "load_versions_cache", return_value={}
157
- ) as mock_cache,
158
- mock.patch.object(commands_actions, "merge_cached_versions") as mock_merge,
159
- mock.patch.object(
160
- commands_actions,
161
- "check_npm_tool",
162
- return_value={
163
- "tool": "ok",
164
- "type": "npm",
165
- "version": "2.0.0",
166
- "date": "2026-02-01",
167
- "status": "ok",
168
- "update": None,
169
- },
170
- ),
171
- mock.patch.object(commands_actions, "print_check_results_table"),
172
- mock.patch.object(commands_actions, "save_updated_versions") as mock_save,
173
- mock.patch.object(
174
- commands_actions, "save_bundled_versions", return_value="/fake/path"
175
- ) as mock_bundled,
176
- ):
177
- buf = io.StringIO()
178
- with contextlib.redirect_stdout(buf):
179
- commands_actions.cmd_update_versions(args)
180
-
181
- mock_cache.assert_not_called()
182
- mock_merge.assert_not_called()
183
- mock_save.assert_not_called()
184
- mock_bundled.assert_called_once()
185
-
186
125
 
187
126
  class TestUpgradeNoArgsParsing(unittest.TestCase):
188
127
  """Test that 'code-aide upgrade' with no arguments parses successfully."""
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes