code-aide 1.5.0__tar.gz → 1.7.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 (46) hide show
  1. {code_aide-1.5.0 → code_aide-1.7.0}/AGENTS.md +10 -5
  2. {code_aide-1.5.0 → code_aide-1.7.0}/PKG-INFO +18 -28
  3. {code_aide-1.5.0 → code_aide-1.7.0}/README.md +17 -27
  4. {code_aide-1.5.0 → code_aide-1.7.0}/TODO.md +19 -18
  5. code_aide-1.7.0/specs/auto-migrate-deprecated-installs.md +128 -0
  6. code_aide-1.7.0/specs/remove-bundled-version-baseline.md +77 -0
  7. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/__init__.py +1 -1
  8. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/commands_actions.py +7 -7
  9. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/commands_tools.py +14 -0
  10. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/config.py +4 -30
  11. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/data/tools.json +8 -24
  12. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/detection.py +60 -0
  13. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/entry.py +0 -6
  14. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/install.py +12 -2
  15. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/operations.py +41 -2
  16. {code_aide-1.5.0 → code_aide-1.7.0}/tests/test_commands_actions.py +0 -61
  17. code_aide-1.7.0/tests/test_commands_tools.py +163 -0
  18. code_aide-1.7.0/tests/test_detection.py +286 -0
  19. code_aide-1.7.0/tests/test_operations.py +309 -0
  20. code_aide-1.5.0/tests/test_commands_tools.py +0 -78
  21. code_aide-1.5.0/tests/test_detection.py +0 -116
  22. code_aide-1.5.0/tests/test_operations.py +0 -159
  23. {code_aide-1.5.0 → code_aide-1.7.0}/.github/workflows/ci.yml +0 -0
  24. {code_aide-1.5.0 → code_aide-1.7.0}/.github/workflows/publish.yml +0 -0
  25. {code_aide-1.5.0 → code_aide-1.7.0}/.gitignore +0 -0
  26. {code_aide-1.5.0 → code_aide-1.7.0}/.gitlab-ci.yml +0 -0
  27. {code_aide-1.5.0 → code_aide-1.7.0}/.pre-commit-config.yaml +0 -0
  28. {code_aide-1.5.0 → code_aide-1.7.0}/CLAUDE.md +0 -0
  29. {code_aide-1.5.0 → code_aide-1.7.0}/LICENSE +0 -0
  30. {code_aide-1.5.0 → code_aide-1.7.0}/pyproject.toml +0 -0
  31. {code_aide-1.5.0 → code_aide-1.7.0}/specs/claude-native-installer-migration.md +0 -0
  32. {code_aide-1.5.0 → code_aide-1.7.0}/specs/missing-coding-llm-cli-tools.md +0 -0
  33. {code_aide-1.5.0 → code_aide-1.7.0}/specs/pre-commit-uv-setup.md +0 -0
  34. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/__main__.py +0 -0
  35. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/console.py +0 -0
  36. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/constants.py +0 -0
  37. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/prereqs.py +0 -0
  38. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/status.py +0 -0
  39. {code_aide-1.5.0 → code_aide-1.7.0}/src/code_aide/versions.py +0 -0
  40. {code_aide-1.5.0 → code_aide-1.7.0}/tests/test_config.py +0 -0
  41. {code_aide-1.5.0 → code_aide-1.7.0}/tests/test_console.py +0 -0
  42. {code_aide-1.5.0 → code_aide-1.7.0}/tests/test_constants.py +0 -0
  43. {code_aide-1.5.0 → code_aide-1.7.0}/tests/test_install.py +0 -0
  44. {code_aide-1.5.0 → code_aide-1.7.0}/tests/test_status.py +0 -0
  45. {code_aide-1.5.0 → code_aide-1.7.0}/tests/test_versions.py +0 -0
  46. {code_aide-1.5.0 → code_aide-1.7.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.7.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,26 @@ 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
- - `git push origin main --follow-tags`
172
- 7. Confirm GitHub Actions:
160
+ - `git push origin main`
161
+ - `git push origin vX.Y.Z`
162
+ 6. Confirm GitHub Actions:
173
163
  - CI should pass.
174
164
  - Publish workflow should upload to PyPI and create GitHub Release notes.
175
165
  - 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,26 @@ 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
- - `git push origin main --follow-tags`
146
- 7. Confirm GitHub Actions:
134
+ - `git push origin main`
135
+ - `git push origin vX.Y.Z`
136
+ 6. Confirm GitHub Actions:
147
137
  - CI should pass.
148
138
  - Publish workflow should upload to PyPI and create GitHub Release notes.
149
139
  - Release notes should include generated notes plus a commit summary from
@@ -7,8 +7,8 @@ remove, status, and version metadata).
7
7
 
8
8
  - [x] Standardize `--dryrun` flag: `update-versions` uses `--dry-run` but
9
9
  `install` uses `--dryrun`. Change `update-versions` to `--dryrun`.
10
- - [x] Add missing `success()` message for direct-download installs in non-dryrun
11
- mode (`install.py`, `install_tool()`).
10
+ - [x] Add missing `success()` message for direct-download installs in
11
+ non-dryrun mode (`install.py`, `install_tool()`).
12
12
  - [x] Replace PID-based temp directory naming with `tempfile.mkdtemp()` in
13
13
  `install.py` `install_direct_download()`.
14
14
  - [x] Guard `package.split("/", 1)` in `detection.py`
@@ -18,21 +18,21 @@ remove, status, and version metadata).
18
18
 
19
19
  - [ ] Handle missing `node` cleanly during prerequisite checks
20
20
  (`FileNotFoundError` path in Node version probing).
21
- - [ ] Read tool version output from both stdout and stderr so status does not
22
- miss installed versions.
21
+ - [ ] Read tool version output from both stdout and stderr so status does
22
+ not miss installed versions.
23
23
  - [ ] Make version cache writes atomic (write temp file + rename) to avoid
24
- partial/corrupted `versions.json`. Apply to `save_bundled_versions()` too.
25
- - [ ] Warn when `versions.json` cache contains invalid JSON instead of silently
26
- returning empty data.
24
+ partial/corrupted `versions.json`.
25
+ - [ ] Warn when `versions.json` cache contains invalid JSON instead of
26
+ silently returning empty data.
27
27
  - [ ] Use `os.pathsep` instead of hardcoded `":"` in `prereqs.py`
28
28
  `check_path_directories()`.
29
29
 
30
30
  ## Security and Integrity
31
31
 
32
- - [ ] Add integrity verification for direct-download tarballs (not only install
33
- script SHA256).
34
- - [ ] Extend tool metadata to support tarball checksum/signature fields where
35
- applicable.
32
+ - [ ] Add integrity verification for direct-download tarballs (not only
33
+ install script SHA256).
34
+ - [ ] Extend tool metadata to support tarball checksum/signature fields
35
+ where applicable.
36
36
 
37
37
  ## CLI and Automation UX
38
38
 
@@ -40,21 +40,23 @@ remove, status, and version metadata).
40
40
  - [ ] Add a focused `doctor` command for environment checks (PATH,
41
41
  prerequisites, command health).
42
42
  - [ ] Consider `install --force` for reinstall/repair flows.
43
- - [ ] Add cleanup support for stale direct-download versions no longer in use.
44
- - [ ] Expand `upgrade` help text to mention the default "only out-of-date tools"
45
- behavior.
43
+ - [ ] Add cleanup support for stale direct-download versions no longer in
44
+ use.
45
+ - [ ] Expand `upgrade` help text to mention the default "only out-of-date
46
+ tools" behavior.
46
47
 
47
48
  ## Documentation
48
49
 
49
- - [ ] Document that running `code-aide` with no subcommand defaults to `status`.
50
+ - [ ] Document that running `code-aide` with no subcommand defaults to
51
+ `status`.
50
52
  - [ ] Add `install --dryrun` to the README usage examples.
51
53
  - [ ] Document environment variables and config file paths
52
54
  (`~/.config/code-aide/versions.json`).
53
55
 
54
56
  ## Platform and Package Detection
55
57
 
56
- - [ ] Broaden system package metadata detection beyond Gentoo-specific tooling
57
- where practical.
58
+ - [ ] Broaden system package metadata detection beyond Gentoo-specific
59
+ tooling where practical.
58
60
 
59
61
  ## Maintainability and Tests
60
62
 
@@ -65,6 +67,5 @@ remove, status, and version metadata).
65
67
  - `cmd_remove()` (completely untested)
66
68
  - `fetch_url()` (completely untested)
67
69
  - `check_prerequisites()` / `install_nodejs_npm()` (completely untested)
68
- - `save_bundled_versions()` (untested)
69
70
  - `get_system_package_info()` (completely untested)
70
71
  - [ ] Add tests for prerequisite edge cases and cache write behavior.
@@ -0,0 +1,128 @@
1
+ # Auto-migrate deprecated install methods
2
+
3
+ ## Context
4
+
5
+ Claude Code switched from npm to a native installer. Users who installed
6
+ Claude via npm are stuck: `code-aide upgrade` runs `npm install -g @latest`
7
+ (the detected method) instead of the native script installer (the configured
8
+ method). `code-aide install` exits early because the command already exists.
9
+ There is no migration path. code-aide should detect this and fix it
10
+ automatically.
11
+
12
+ This is a general pattern -- any tool could change install methods in the
13
+ future. The solution should not be Claude-specific.
14
+
15
+ ## Approach
16
+
17
+ A detected install method is "deprecated" when:
18
+
19
+ - Detected method is `npm` or `brew_npm` AND config `install_type` is
20
+ `script` or `direct_download`
21
+
22
+ Methods that are never considered deprecated (user-managed choices):
23
+
24
+ - `brew_formula`, `brew_cask` -- user explicitly chose Homebrew
25
+ - `system` -- managed by system package manager
26
+
27
+ Migration flow: remove old (npm), install new (configured method), with
28
+ clear messaging. If the new install fails after removal, provide recovery
29
+ instructions.
30
+
31
+ ## Changes
32
+
33
+ ### 1. `src/code_aide/data/tools.json` -- add deprecated_npm_package
34
+
35
+ Add a `deprecated_npm_package` field to Claude's entry:
36
+
37
+ ```json
38
+ "claude": {
39
+ "name": "Claude CLI (Claude Code)",
40
+ "install_type": "script",
41
+ "deprecated_npm_package": "@anthropic-ai/claude-code",
42
+ ...
43
+ }
44
+ ```
45
+
46
+ This records the old npm package name explicitly so the migration removal
47
+ step does not rely solely on extracting the package name from the binary
48
+ path.
49
+
50
+ ### 2. `src/code_aide/detection.py` -- add deprecation detection
51
+
52
+ Add two functions:
53
+
54
+ - `is_deprecated_install(tool_name)` -- returns True when the detected
55
+ install method is `npm` or `brew_npm` but the configured `install_type` is
56
+ something else (script, direct_download). Also returns True when
57
+ `deprecated_npm_package` is set and the detected method is npm. Brew
58
+ formula/cask and system installs are never deprecated (user-managed).
59
+ - `format_migration_warning(tool_name)` -- returns a human-readable warning
60
+ string, or None if not deprecated. Uses existing `format_install_method()`
61
+ for labels.
62
+
63
+ ### 3. `src/code_aide/operations.py` -- auto-migrate in upgrade
64
+
65
+ Add `_migrate_install_method()` private function that:
66
+
67
+ 1. Warns about the deprecated method
68
+ 2. Calls `remove_tool()` to remove the old npm install
69
+ 3. Calls `install_tool()` to install via the configured method
70
+ 4. If install fails after remove, prints recovery instructions (`code-aide
71
+ install <tool>` and manual curl command for script types)
72
+
73
+ Modify `upgrade_tool()`: after `detect_install_method()`, check
74
+ `is_deprecated_install()`. If True, call `_migrate_install_method()` instead
75
+ of the normal upgrade branch.
76
+
77
+ Modify `remove_tool()` npm branch: fall back to
78
+ `tool_config.get("deprecated_npm_package")` when looking up the npm package
79
+ name. Current code: `npm_package = detail or
80
+ tool_config.get("npm_package")`. Change to also check
81
+ `deprecated_npm_package`.
82
+
83
+ New imports needed: `is_deprecated_install`, `format_install_method` from
84
+ detection, `install_tool` from install.
85
+
86
+ Note: after `remove_tool()` succeeds, `command_exists()` returns False so
87
+ `install_tool()` proceeds normally with the configured `install_type`.
88
+
89
+ ### 4. `src/code_aide/commands_actions.py` -- include deprecated in auto-upgrade
90
+
91
+ Modify `cmd_upgrade()` no-args path: after building the version-outdated
92
+ list, also add any installed tools with deprecated install methods. Without
93
+ this, a tool whose version is current but install method is deprecated would
94
+ be silently skipped by `code-aide upgrade`.
95
+
96
+ New import: `is_deprecated_install` from detection.
97
+
98
+ ### 5. `src/code_aide/commands_tools.py` -- show warnings in status/list
99
+
100
+ In both `cmd_list()` and `cmd_status()`, after displaying "Installed via:",
101
+ call `format_migration_warning()` and display the warning if present.
102
+
103
+ At the end of `cmd_status()`, add a summary line counting tools that need
104
+ migration.
105
+
106
+ New imports: `format_migration_warning`, `is_deprecated_install` from
107
+ detection.
108
+
109
+ ### 6. Tests
110
+
111
+ - `tests/test_detection.py`: Tests for `is_deprecated_install()` covering
112
+ npm to script (deprecated), npm to npm (not deprecated), brew_formula
113
+ (never deprecated), system (never deprecated), not installed, unknown
114
+ tool, npm to direct_download. Tests for `format_migration_warning()`.
115
+ - `tests/test_operations.py`: Tests for migration in `upgrade_tool()`:
116
+ triggers migration, normal upgrade when not deprecated, migration fails on
117
+ remove, migration fails on install with recovery message.
118
+ - `tests/test_commands_tools.py`: Test that status/list show migration
119
+ warnings for deprecated installs.
120
+
121
+ ## Verification
122
+
123
+ 1. `pre-commit run --all-files` -- formatting passes
124
+ 2. `uv run pytest tests/ -v` -- all tests pass
125
+ 3. `uv run python -m code_aide status` -- shows migration warning for
126
+ npm-installed Claude (if applicable)
127
+ 4. `uv run python -m code_aide upgrade claude` -- performs migration (remove
128
+ npm, install via script)
@@ -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.7.0"
@@ -5,6 +5,7 @@ import sys
5
5
  from typing import Any, Dict, List
6
6
 
7
7
  from code_aide.constants import TOOLS
8
+ from code_aide.detection import is_deprecated_install
8
9
  from code_aide.install import install_tool
9
10
  from code_aide.console import error, info, success, warning
10
11
  from code_aide.operations import remove_tool, upgrade_tool, validate_tools
@@ -26,7 +27,6 @@ from code_aide.config import (
26
27
  load_bundled_tools,
27
28
  load_versions_cache,
28
29
  merge_cached_versions,
29
- save_bundled_versions,
30
30
  save_updated_versions,
31
31
  )
32
32
 
@@ -124,6 +124,10 @@ def cmd_upgrade(args: argparse.Namespace) -> None:
124
124
  for name, config in TOOLS.items():
125
125
  if not is_tool_installed(name):
126
126
  continue
127
+ if is_deprecated_install(name):
128
+ if name not in tools_to_upgrade:
129
+ tools_to_upgrade.append(name)
130
+ continue
127
131
  latest = config.get("latest_version")
128
132
  if not latest:
129
133
  continue
@@ -234,8 +238,7 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
234
238
  """Handle update-versions command: check upstream for latest tool versions."""
235
239
  bundled = load_bundled_tools()
236
240
  tools = bundled.get("tools", {})
237
- if not args.bundled:
238
- merge_cached_versions(tools, load_versions_cache())
241
+ merge_cached_versions(tools, load_versions_cache())
239
242
 
240
243
  config: Dict[str, Any] = {"tools": tools}
241
244
 
@@ -293,10 +296,7 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
293
296
  version_info_changed = True
294
297
 
295
298
  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
299
+ """Save versions to user cache. Returns description."""
300
300
  save_updated_versions(tools)
301
301
  return "~/.config/code-aide/versions.json"
302
302
 
@@ -8,6 +8,7 @@ from typing import List
8
8
  from code_aide.constants import Colors, PACKAGE_MANAGERS, TOOLS
9
9
  from code_aide.detection import (
10
10
  format_install_method,
11
+ format_migration_warning,
11
12
  get_system_package_info,
12
13
  detect_install_method,
13
14
  )
@@ -48,6 +49,9 @@ def cmd_list(args: argparse.Namespace) -> None:
48
49
  " Installed via: "
49
50
  f"{format_install_method(install_info['method'], install_info['detail'])}"
50
51
  )
52
+ migration_msg = format_migration_warning(tool_name)
53
+ if migration_msg:
54
+ warning(f" {migration_msg}")
51
55
 
52
56
  if tool_config.get("min_node_version"):
53
57
  print(f" Requires: Node.js v{tool_config['min_node_version']}+")
@@ -99,6 +103,7 @@ def cmd_status(args: argparse.Namespace) -> None:
99
103
  print()
100
104
 
101
105
  outdated_count = 0
106
+ migration_count = 0
102
107
  config_outdated: List[str] = []
103
108
 
104
109
  for tool_name, tool_config in TOOLS.items():
@@ -156,6 +161,10 @@ def cmd_status(args: argparse.Namespace) -> None:
156
161
  " Installed via: "
157
162
  f"{format_install_method(install_info['method'], install_info['detail'])}"
158
163
  )
164
+ migration_msg = format_migration_warning(tool_name)
165
+ if migration_msg:
166
+ warning(f" {migration_msg}")
167
+ migration_count += 1
159
168
 
160
169
  if status["user"]:
161
170
  print(f" User: {status['user']}")
@@ -181,3 +190,8 @@ def cmd_status(args: argparse.Namespace) -> None:
181
190
  f"{Colors.YELLOW}{outdated_count} tool(s) can be upgraded with "
182
191
  f"'code-aide upgrade'.{Colors.NC}"
183
192
  )
193
+ if migration_count > 0:
194
+ print(
195
+ f"{Colors.YELLOW}{migration_count} tool(s) need migration to a "
196
+ f"new install method. Run 'code-aide upgrade' to migrate.{Colors.NC}"
197
+ )
@@ -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