code-aide 1.16.2__tar.gz → 1.17.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.
- {code_aide-1.16.2 → code_aide-1.17.0}/.github/workflows/ci.yml +2 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/.gitlab-ci.yml +1 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/.pre-commit-config.yaml +8 -0
- code_aide-1.17.0/Makefile +29 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/PKG-INFO +38 -30
- {code_aide-1.16.2 → code_aide-1.17.0}/README.md +37 -29
- code_aide-1.17.0/TODO.md +77 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/pyproject.toml +0 -3
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/__init__.py +1 -1
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/commands_actions.py +74 -4
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/commands_tools.py +49 -74
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/config.py +38 -12
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/console.py +10 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/constants.py +33 -16
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/data/tools.json +2 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/entry.py +13 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/install.py +66 -7
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/operation_handlers.py +10 -2
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/operations.py +15 -3
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/package_managers.py +1 -1
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/prereqs.py +4 -5
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/versions.py +18 -9
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_commands_actions.py +237 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_config.py +54 -2
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_console.py +16 -0
- code_aide-1.17.0/tests/test_constants.py +45 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_install.py +96 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_prereqs.py +29 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_versions.py +31 -3
- code_aide-1.16.2/TODO.md +0 -78
- code_aide-1.16.2/tests/test_constants.py +0 -21
- {code_aide-1.16.2 → code_aide-1.17.0}/.github/workflows/publish.yml +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/.gitignore +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/AGENTS.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/CLAUDE.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/LICENSE +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/script-archive/README.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/script-archive/amp-install.sh +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/script-archive/antigravity-install.sh +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/script-archive/claude-install.sh +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/script-archive/cursor-install.sh +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/2026-05-03-qwen3.6-code-quality-analysis-original.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/2026-05-03-qwen3.6-code-quality-analysis.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/antigravity-cli-integration.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/auto-migrate-deprecated-installs.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/claude-native-installer-migration.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/missing-coding-llm-cli-tools.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/pre-commit-uv-setup.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/remove-bundled-version-baseline.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/specs/unify-upgrade-eligibility-with-shared-evaluator.md +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/__main__.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/detection.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/detection_types.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/install_types.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/package_info.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/status.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/src/code_aide/status_print.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_commands_tools.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_detection.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_entry.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_error_paths.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_install_types.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_operations.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_package_managers.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/tests/test_status.py +0 -0
- {code_aide-1.16.2 → code_aide-1.17.0}/uv.lock +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# code-aide quality checks (uv-based)
|
|
2
|
+
|
|
3
|
+
.PHONY: build install test lint format format-check typecheck hooks check
|
|
4
|
+
|
|
5
|
+
build:
|
|
6
|
+
uv build
|
|
7
|
+
|
|
8
|
+
install:
|
|
9
|
+
uv sync
|
|
10
|
+
|
|
11
|
+
test:
|
|
12
|
+
uv run pytest -n4 -q
|
|
13
|
+
|
|
14
|
+
lint:
|
|
15
|
+
uv run ruff check .
|
|
16
|
+
|
|
17
|
+
format:
|
|
18
|
+
uv run black .
|
|
19
|
+
|
|
20
|
+
format-check:
|
|
21
|
+
uv run black --check .
|
|
22
|
+
|
|
23
|
+
typecheck:
|
|
24
|
+
uv run mypy
|
|
25
|
+
|
|
26
|
+
hooks:
|
|
27
|
+
pre-commit install
|
|
28
|
+
|
|
29
|
+
check: lint format-check typecheck
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: code-aide
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.17.0
|
|
4
4
|
Summary: Manage AI coding CLI tools (Claude, Antigravity, 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
|
|
@@ -70,9 +70,15 @@ code-aide install -p
|
|
|
70
70
|
# Upgrade installed tools (no args = only out-of-date tools)
|
|
71
71
|
code-aide upgrade [NAMES]
|
|
72
72
|
|
|
73
|
-
# Remove tools
|
|
73
|
+
# Remove tools (prompts before removing all managed tools)
|
|
74
74
|
code-aide remove [NAMES]
|
|
75
75
|
|
|
76
|
+
# Preview a removal without changing anything
|
|
77
|
+
code-aide remove -n
|
|
78
|
+
|
|
79
|
+
# Remove all managed tools without prompting
|
|
80
|
+
code-aide remove -y
|
|
81
|
+
|
|
76
82
|
# Check upstream for latest versions (dry-run)
|
|
77
83
|
code-aide update-versions -n
|
|
78
84
|
|
|
@@ -106,8 +112,8 @@ code-aide uses a two-layer version data model:
|
|
|
106
112
|
versions of code-aide.
|
|
107
113
|
|
|
108
114
|
2. **User's local version cache** (`~/.config/code-aide/versions.json`): Written
|
|
109
|
-
by `code-aide update-versions`. Provides latest versions, dates,
|
|
110
|
-
SHA256 checksums.
|
|
115
|
+
by `code-aide update-versions`. Provides latest versions, dates, updated
|
|
116
|
+
SHA256 checksums, and recorded tarball checksums for direct_download tools.
|
|
111
117
|
|
|
112
118
|
Run `code-aide update-versions` to get the latest version data without waiting
|
|
113
119
|
for a new code-aide release.
|
|
@@ -118,32 +124,34 @@ Each entry in `tools.json` describes one managed tool. Required fields are
|
|
|
118
124
|
`name`, `command`, and `install_type`; the others are optional and only
|
|
119
125
|
consulted when the relevant install method or platform applies.
|
|
120
126
|
|
|
121
|
-
| Field | Required | Notes
|
|
122
|
-
|
|
123
|
-
| `name` | Yes | Display name for status output
|
|
124
|
-
| `command` | Yes | Binary name (looked up in `PATH`)
|
|
125
|
-
| `aliases` | No | Alternate names accepted by commands and resolved to the canonical tool key
|
|
126
|
-
| `install_type` | Yes | One of `npm`, `script`, `direct_download`, `pkg`
|
|
127
|
-
| `version_args` | No | List of arguments passed to the binary to print its version (default: `["--version"]`)
|
|
128
|
-
| `version_url` | No | URL queried by `update-versions` to discover the latest upstream version
|
|
129
|
-
| `version_manifest_url_template` | No | JSON manifest URL template with `{platform}`; reads its `version` field
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
127
|
+
| Field | Required | Notes |
|
|
128
|
+
|:--------------------------------|:---------|:----------------------------------------------------------------------------------------------------------------|
|
|
129
|
+
| `name` | Yes | Display name for status output |
|
|
130
|
+
| `command` | Yes | Binary name (looked up in `PATH`) |
|
|
131
|
+
| `aliases` | No | Alternate names accepted by commands and resolved to the canonical tool key |
|
|
132
|
+
| `install_type` | Yes | One of `npm`, `script`, `direct_download`, `pkg` |
|
|
133
|
+
| `version_args` | No | List of arguments passed to the binary to print its version (default: `["--version"]`) |
|
|
134
|
+
| `version_url` | No | URL queried by `update-versions` to discover the latest upstream version |
|
|
135
|
+
| `version_manifest_url_template` | No | JSON manifest URL template with `{platform}`; reads its `version` field |
|
|
136
|
+
| `version_extract_pattern` | No | Regex applied to the install script to extract the version before generic heuristics |
|
|
137
|
+
| `latest_version` | Cache | Last known upstream version (filled by `update-versions`) |
|
|
138
|
+
| `latest_date` | Cache | Release date for `latest_version` |
|
|
139
|
+
| `prerequisites` | No | List of required external commands (e.g. `["npm"]`) |
|
|
140
|
+
| `min_node_version` | No | Minimum major Node.js version required |
|
|
141
|
+
| `npm_package` | npm | npm package name (e.g. `@anthropic-ai/claude-code`) |
|
|
142
|
+
| `install_url` | script | URL of the install script that will be downloaded and piped to `bash` |
|
|
143
|
+
| `install_sha256` | script | SHA-256 of the install script body — required for verified installs |
|
|
144
|
+
| `download_sha256` | Cache | SHA-256 of the downloaded tarball for direct_download tools; recorded by `update-versions`, verified on install |
|
|
145
|
+
| `install_script_path_prepend` | script | Extra directories prepended to `PATH` when the install script runs (e.g. `["~/.local/bin"]`) |
|
|
146
|
+
| `download_url_template` | direct | URL template with `{version}`, `{os}`, `{arch}` placeholders |
|
|
147
|
+
| `install_dir` | direct | Directory to extract into; supports `{version}` |
|
|
148
|
+
| `bin_dir` | direct | Directory where symlinks for `command` are created (e.g. `~/.local/bin`) |
|
|
149
|
+
| `symlinks` | direct | Map of `link_name` → relative path inside `install_dir` to symlink into `bin_dir` |
|
|
150
|
+
| `freebsd_port` | FreeBSD | FreeBSD ports/pkg name (used when running on FreeBSD) |
|
|
151
|
+
| `freebsd_pkg_repo` | FreeBSD | Optional non-default pkg repository name (passed via `pkg install -r <repo>`) |
|
|
152
|
+
| `next_steps` | No | Free-form text printed after a successful install |
|
|
153
|
+
| `docs_url` | No | Documentation URL printed after install |
|
|
154
|
+
| `self_updates` | No | Tool updates itself when run; excludes it from managed upgrade actions |
|
|
147
155
|
|
|
148
156
|
## Features
|
|
149
157
|
|
|
@@ -43,9 +43,15 @@ code-aide install -p
|
|
|
43
43
|
# Upgrade installed tools (no args = only out-of-date tools)
|
|
44
44
|
code-aide upgrade [NAMES]
|
|
45
45
|
|
|
46
|
-
# Remove tools
|
|
46
|
+
# Remove tools (prompts before removing all managed tools)
|
|
47
47
|
code-aide remove [NAMES]
|
|
48
48
|
|
|
49
|
+
# Preview a removal without changing anything
|
|
50
|
+
code-aide remove -n
|
|
51
|
+
|
|
52
|
+
# Remove all managed tools without prompting
|
|
53
|
+
code-aide remove -y
|
|
54
|
+
|
|
49
55
|
# Check upstream for latest versions (dry-run)
|
|
50
56
|
code-aide update-versions -n
|
|
51
57
|
|
|
@@ -79,8 +85,8 @@ code-aide uses a two-layer version data model:
|
|
|
79
85
|
versions of code-aide.
|
|
80
86
|
|
|
81
87
|
2. **User's local version cache** (`~/.config/code-aide/versions.json`): Written
|
|
82
|
-
by `code-aide update-versions`. Provides latest versions, dates,
|
|
83
|
-
SHA256 checksums.
|
|
88
|
+
by `code-aide update-versions`. Provides latest versions, dates, updated
|
|
89
|
+
SHA256 checksums, and recorded tarball checksums for direct_download tools.
|
|
84
90
|
|
|
85
91
|
Run `code-aide update-versions` to get the latest version data without waiting
|
|
86
92
|
for a new code-aide release.
|
|
@@ -91,32 +97,34 @@ Each entry in `tools.json` describes one managed tool. Required fields are
|
|
|
91
97
|
`name`, `command`, and `install_type`; the others are optional and only
|
|
92
98
|
consulted when the relevant install method or platform applies.
|
|
93
99
|
|
|
94
|
-
| Field | Required | Notes
|
|
95
|
-
|
|
96
|
-
| `name` | Yes | Display name for status output
|
|
97
|
-
| `command` | Yes | Binary name (looked up in `PATH`)
|
|
98
|
-
| `aliases` | No | Alternate names accepted by commands and resolved to the canonical tool key
|
|
99
|
-
| `install_type` | Yes | One of `npm`, `script`, `direct_download`, `pkg`
|
|
100
|
-
| `version_args` | No | List of arguments passed to the binary to print its version (default: `["--version"]`)
|
|
101
|
-
| `version_url` | No | URL queried by `update-versions` to discover the latest upstream version
|
|
102
|
-
| `version_manifest_url_template` | No | JSON manifest URL template with `{platform}`; reads its `version` field
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
119
|
-
| `
|
|
100
|
+
| Field | Required | Notes |
|
|
101
|
+
|:--------------------------------|:---------|:----------------------------------------------------------------------------------------------------------------|
|
|
102
|
+
| `name` | Yes | Display name for status output |
|
|
103
|
+
| `command` | Yes | Binary name (looked up in `PATH`) |
|
|
104
|
+
| `aliases` | No | Alternate names accepted by commands and resolved to the canonical tool key |
|
|
105
|
+
| `install_type` | Yes | One of `npm`, `script`, `direct_download`, `pkg` |
|
|
106
|
+
| `version_args` | No | List of arguments passed to the binary to print its version (default: `["--version"]`) |
|
|
107
|
+
| `version_url` | No | URL queried by `update-versions` to discover the latest upstream version |
|
|
108
|
+
| `version_manifest_url_template` | No | JSON manifest URL template with `{platform}`; reads its `version` field |
|
|
109
|
+
| `version_extract_pattern` | No | Regex applied to the install script to extract the version before generic heuristics |
|
|
110
|
+
| `latest_version` | Cache | Last known upstream version (filled by `update-versions`) |
|
|
111
|
+
| `latest_date` | Cache | Release date for `latest_version` |
|
|
112
|
+
| `prerequisites` | No | List of required external commands (e.g. `["npm"]`) |
|
|
113
|
+
| `min_node_version` | No | Minimum major Node.js version required |
|
|
114
|
+
| `npm_package` | npm | npm package name (e.g. `@anthropic-ai/claude-code`) |
|
|
115
|
+
| `install_url` | script | URL of the install script that will be downloaded and piped to `bash` |
|
|
116
|
+
| `install_sha256` | script | SHA-256 of the install script body — required for verified installs |
|
|
117
|
+
| `download_sha256` | Cache | SHA-256 of the downloaded tarball for direct_download tools; recorded by `update-versions`, verified on install |
|
|
118
|
+
| `install_script_path_prepend` | script | Extra directories prepended to `PATH` when the install script runs (e.g. `["~/.local/bin"]`) |
|
|
119
|
+
| `download_url_template` | direct | URL template with `{version}`, `{os}`, `{arch}` placeholders |
|
|
120
|
+
| `install_dir` | direct | Directory to extract into; supports `{version}` |
|
|
121
|
+
| `bin_dir` | direct | Directory where symlinks for `command` are created (e.g. `~/.local/bin`) |
|
|
122
|
+
| `symlinks` | direct | Map of `link_name` → relative path inside `install_dir` to symlink into `bin_dir` |
|
|
123
|
+
| `freebsd_port` | FreeBSD | FreeBSD ports/pkg name (used when running on FreeBSD) |
|
|
124
|
+
| `freebsd_pkg_repo` | FreeBSD | Optional non-default pkg repository name (passed via `pkg install -r <repo>`) |
|
|
125
|
+
| `next_steps` | No | Free-form text printed after a successful install |
|
|
126
|
+
| `docs_url` | No | Documentation URL printed after install |
|
|
127
|
+
| `self_updates` | No | Tool updates itself when run; excludes it from managed upgrade actions |
|
|
120
128
|
|
|
121
129
|
## Features
|
|
122
130
|
|
code_aide-1.17.0/TODO.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
Keep the project focused on managing AI coding CLI tools (install, upgrade,
|
|
4
|
+
remove, status, and version metadata).
|
|
5
|
+
|
|
6
|
+
## Summary
|
|
7
|
+
|
|
8
|
+
| # | Item | Risk | Effort | Notes |
|
|
9
|
+
|:---|:--------------------------------------------|:---------|:--------|:-------------------------------------------------------------------|
|
|
10
|
+
| 1 | ~~Handle missing `node` cleanly~~ (done) | - | - | Fixed in `prereqs.py` `check_prerequisites()` |
|
|
11
|
+
| 2 | Read version from stdout+stderr | Med | Low | Some tools write version to stderr; shown as not installed |
|
|
12
|
+
| 3 | ~~Atomic version cache writes~~ (done) | - | - | Fixed in `config.py` `save_versions_cache()` |
|
|
13
|
+
| 4 | ~~Warn on invalid cache JSON~~ (done) | - | - | `config.py` `load_versions_cache()` logs a warning |
|
|
14
|
+
| 5 | ~~Use `os.pathsep` not `":"`~~ (done) | - | - | Fixed in `prereqs.py` `check_path_directories()` |
|
|
15
|
+
| 6 | ~~Verify direct-download tarballs~~ (done) | - | - | `download_sha256` recorded by update-versions, verified on install |
|
|
16
|
+
| 7 | ~~Tarball checksum metadata fields~~ (done) | - | - | `download_sha256` field in tools schema and versions cache |
|
|
17
|
+
| 8 | `--json` output mode | Low | Med | Needed for CI/automation consumers |
|
|
18
|
+
| 9 | `doctor` command | Low | Med | Health checks exist but are scattered |
|
|
19
|
+
| 10 | `install --force` | Low | Trivial | Internal `force` param exists; not exposed in CLI |
|
|
20
|
+
| 11 | Cleanup stale direct-download versions | Low | Med | Old version dirs accumulate on disk |
|
|
21
|
+
| 12 | Document default subcommand | Very Low | Trivial | One line in README |
|
|
22
|
+
| 13 | Document `install --dryrun` | Very Low | Trivial | One line in README |
|
|
23
|
+
| 14 | Document env vars and config paths | Low | Low | `XDG_CONFIG_HOME` undocumented |
|
|
24
|
+
| 15 | Cross-distro package detection | Med | High | Only Gentoo supported; other Linux distros get nothing |
|
|
25
|
+
| 16 | Split large modules | Low | High | Refactoring only; no behavior change |
|
|
26
|
+
| 17 | Tests for untested functions | Med | High | `fetch_url`, `get_system_package_info` |
|
|
27
|
+
| 18 | Tests for edge cases | Med | Med | PATH oddities, more version parsing corners |
|
|
28
|
+
|
|
29
|
+
## Reliability and Correctness
|
|
30
|
+
|
|
31
|
+
- [x] Handle missing `node` cleanly during prerequisite checks (`OSError` path
|
|
32
|
+
in Node version probing).
|
|
33
|
+
- [ ] Read tool version output from both stdout and stderr so status does not
|
|
34
|
+
miss installed versions.
|
|
35
|
+
- [x] Make version cache writes atomic (temp file + rename) to avoid
|
|
36
|
+
partial/corrupted `versions.json`.
|
|
37
|
+
- [x] Warn when `versions.json` cache contains invalid JSON instead of silently
|
|
38
|
+
returning empty data.
|
|
39
|
+
- [x] Use `os.pathsep` instead of hardcoded `":"` in `prereqs.py`
|
|
40
|
+
`check_path_directories()`.
|
|
41
|
+
|
|
42
|
+
## Security and Integrity
|
|
43
|
+
|
|
44
|
+
- [x] Verify direct-download tarballs against a checksum recorded by
|
|
45
|
+
`update-versions` (warn when no checksum has been recorded yet).
|
|
46
|
+
- [x] Extend tool metadata with a `download_sha256` field for tarball checksums.
|
|
47
|
+
- [ ] Consider signature verification (beyond SHA256) for downloads where
|
|
48
|
+
upstream publishes signatures.
|
|
49
|
+
|
|
50
|
+
## CLI and Automation UX
|
|
51
|
+
|
|
52
|
+
- [ ] Add `--json` output mode for `list`, `status`, and `update-versions`.
|
|
53
|
+
- [ ] Add a focused `doctor` command for environment checks (PATH,
|
|
54
|
+
prerequisites, command health).
|
|
55
|
+
- [ ] Consider `install --force` for reinstall/repair flows.
|
|
56
|
+
- [ ] Add cleanup support for stale direct-download versions no longer in use.
|
|
57
|
+
|
|
58
|
+
## Documentation
|
|
59
|
+
|
|
60
|
+
- [ ] Document that running `code-aide` with no subcommand defaults to `status`.
|
|
61
|
+
- [ ] Add `install --dryrun` to the README usage examples.
|
|
62
|
+
- [ ] Document environment variables and config file paths
|
|
63
|
+
(`~/.config/code-aide/versions.json`).
|
|
64
|
+
|
|
65
|
+
## Platform and Package Detection
|
|
66
|
+
|
|
67
|
+
- [ ] Broaden system package metadata detection beyond Gentoo-specific tooling
|
|
68
|
+
where practical.
|
|
69
|
+
|
|
70
|
+
## Maintainability and Tests
|
|
71
|
+
|
|
72
|
+
- [ ] Split larger modules into smaller focused files where practical
|
|
73
|
+
(`commands_actions.py`, `versions.py`, `install.py`).
|
|
74
|
+
- [ ] Add tests for remaining untested functions:
|
|
75
|
+
- `fetch_url()` (network; needs mocking)
|
|
76
|
+
- `get_system_package_info()` (Gentoo tooling)
|
|
77
|
+
- [ ] Add tests for more prerequisite edge cases and PATH oddities.
|
|
@@ -6,7 +6,7 @@ from typing import Any, Dict, List
|
|
|
6
6
|
|
|
7
7
|
from code_aide.constants import TOOLS
|
|
8
8
|
from code_aide.detection import detect_install_method, get_brew_package_info
|
|
9
|
-
from code_aide.install import install_tool
|
|
9
|
+
from code_aide.install import fetch_download_checksum, install_tool
|
|
10
10
|
from code_aide.install_types import (
|
|
11
11
|
InstallMethod,
|
|
12
12
|
InstallType,
|
|
@@ -34,6 +34,7 @@ from code_aide.versions import (
|
|
|
34
34
|
print_check_results_table,
|
|
35
35
|
)
|
|
36
36
|
from code_aide.config import (
|
|
37
|
+
ensure_versions_cache,
|
|
37
38
|
load_bundled_tools,
|
|
38
39
|
load_versions_cache,
|
|
39
40
|
merge_cached_versions,
|
|
@@ -75,7 +76,7 @@ def cmd_install(args: argparse.Namespace) -> None:
|
|
|
75
76
|
)
|
|
76
77
|
|
|
77
78
|
installed = []
|
|
78
|
-
installed_bin_dirs = []
|
|
79
|
+
installed_bin_dirs: List[str] = []
|
|
79
80
|
failed = []
|
|
80
81
|
|
|
81
82
|
for tool in tools_to_install:
|
|
@@ -136,6 +137,9 @@ def cmd_upgrade(args: argparse.Namespace) -> None:
|
|
|
136
137
|
info(f"Upgrading specified tools: {', '.join(tools_to_upgrade)}")
|
|
137
138
|
else:
|
|
138
139
|
tools_to_upgrade = []
|
|
140
|
+
# Default selection is driven by latest_version, so refresh stale
|
|
141
|
+
# cache data first; named upgrades below skip this.
|
|
142
|
+
ensure_versions_cache(TOOLS)
|
|
139
143
|
for name, config in TOOLS.items():
|
|
140
144
|
assessment = ToolUpgradeEvaluator(name, config).evaluate()
|
|
141
145
|
if assessment.actionable_by_upgrade and name not in tools_to_upgrade:
|
|
@@ -198,14 +202,37 @@ def cmd_upgrade(args: argparse.Namespace) -> None:
|
|
|
198
202
|
)
|
|
199
203
|
|
|
200
204
|
|
|
205
|
+
def _confirm_remove_all(tools: List[str]) -> bool:
|
|
206
|
+
"""Prompt before removing every managed tool."""
|
|
207
|
+
print(f"This will remove {len(tools)} managed tools: {', '.join(tools)}")
|
|
208
|
+
try:
|
|
209
|
+
answer = input("Remove all of them? [y/N] ").strip().lower()
|
|
210
|
+
except (EOFError, KeyboardInterrupt):
|
|
211
|
+
print()
|
|
212
|
+
return False
|
|
213
|
+
return answer in ("y", "yes")
|
|
214
|
+
|
|
215
|
+
|
|
201
216
|
def cmd_remove(args: argparse.Namespace) -> None:
|
|
202
217
|
"""Handle remove command."""
|
|
218
|
+
dryrun = getattr(args, "dryrun", False)
|
|
219
|
+
assume_yes = getattr(args, "yes", False)
|
|
220
|
+
|
|
203
221
|
if args.tools:
|
|
204
222
|
tools_to_remove = args.tools
|
|
205
223
|
info(f"Removing specified tools: {', '.join(tools_to_remove)}")
|
|
206
224
|
else:
|
|
207
225
|
tools_to_remove = list(TOOLS.keys())
|
|
208
|
-
|
|
226
|
+
if dryrun:
|
|
227
|
+
info(
|
|
228
|
+
"[DRYRUN] Would remove all managed tools: "
|
|
229
|
+
f"{', '.join(tools_to_remove)}"
|
|
230
|
+
)
|
|
231
|
+
else:
|
|
232
|
+
info(f"No tools specified, removing all: {', '.join(tools_to_remove)}")
|
|
233
|
+
if not assume_yes and not _confirm_remove_all(tools_to_remove):
|
|
234
|
+
print("Aborted.")
|
|
235
|
+
return
|
|
209
236
|
|
|
210
237
|
tools_to_remove = resolve_tool_names(tools_to_remove, TOOLS)
|
|
211
238
|
validate_tools(tools_to_remove)
|
|
@@ -216,6 +243,14 @@ def cmd_remove(args: argparse.Namespace) -> None:
|
|
|
216
243
|
|
|
217
244
|
for tool in tools_to_remove:
|
|
218
245
|
print()
|
|
246
|
+
if dryrun:
|
|
247
|
+
info(f"=== Checking {tool} ===")
|
|
248
|
+
if is_tool_installed(tool):
|
|
249
|
+
removed.append(tool)
|
|
250
|
+
else:
|
|
251
|
+
skipped.append(tool)
|
|
252
|
+
continue
|
|
253
|
+
|
|
219
254
|
info(f"=== Removing {tool} ===")
|
|
220
255
|
|
|
221
256
|
if not is_tool_installed(tool):
|
|
@@ -229,8 +264,19 @@ def cmd_remove(args: argparse.Namespace) -> None:
|
|
|
229
264
|
|
|
230
265
|
print()
|
|
231
266
|
print("=" * 42)
|
|
232
|
-
|
|
267
|
+
if dryrun:
|
|
268
|
+
info("Removal Summary (dry run)")
|
|
269
|
+
else:
|
|
270
|
+
info("Removal Summary")
|
|
233
271
|
print("=" * 42)
|
|
272
|
+
if dryrun:
|
|
273
|
+
if removed:
|
|
274
|
+
success(f"Would remove: {', '.join(removed)}")
|
|
275
|
+
if skipped:
|
|
276
|
+
warning(f"Not installed (skipped): {', '.join(skipped)}")
|
|
277
|
+
print()
|
|
278
|
+
success("Dry run completed without removing anything!")
|
|
279
|
+
return
|
|
234
280
|
|
|
235
281
|
if removed:
|
|
236
282
|
success(f"Successfully removed: {', '.join(removed)}")
|
|
@@ -326,6 +372,30 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
|
|
|
326
372
|
tool_entry["latest_version"] = normalized
|
|
327
373
|
version_info_changed = True
|
|
328
374
|
|
|
375
|
+
# Record the tarball checksum for direct-download tools so later
|
|
376
|
+
# installs can verify integrity against it.
|
|
377
|
+
if not args.dryrun:
|
|
378
|
+
for tool_name in tool_names:
|
|
379
|
+
tool_entry = config["tools"][tool_name]
|
|
380
|
+
if (
|
|
381
|
+
parse_install_type(tool_entry.get("install_type"))
|
|
382
|
+
!= InstallType.DIRECT_DOWNLOAD
|
|
383
|
+
):
|
|
384
|
+
continue
|
|
385
|
+
if "download_url_template" not in tool_entry:
|
|
386
|
+
continue
|
|
387
|
+
if not tool_entry.get("latest_version"):
|
|
388
|
+
continue
|
|
389
|
+
checksum = fetch_download_checksum(tool_entry)
|
|
390
|
+
if not checksum:
|
|
391
|
+
continue
|
|
392
|
+
if tool_entry.get("download_sha256") != checksum:
|
|
393
|
+
tool_entry["download_sha256"] = checksum
|
|
394
|
+
version_info_changed = True
|
|
395
|
+
print(f"Recorded download SHA256 for {tool_name}.")
|
|
396
|
+
else:
|
|
397
|
+
print(f"Download SHA256 for {tool_name} is unchanged.")
|
|
398
|
+
|
|
329
399
|
def _save(tools: dict) -> str:
|
|
330
400
|
"""Save versions to user cache. Returns description."""
|
|
331
401
|
save_updated_versions(tools)
|
|
@@ -30,6 +30,7 @@ from code_aide.status import (
|
|
|
30
30
|
print_brew_version_status,
|
|
31
31
|
print_pkg_version_status,
|
|
32
32
|
print_system_version_status,
|
|
33
|
+
ToolUpgradeAssessment,
|
|
33
34
|
ToolUpgradeEvaluator,
|
|
34
35
|
UpgradeDecision,
|
|
35
36
|
VersionDisplayState,
|
|
@@ -161,6 +162,51 @@ def _generic_version_annotation(
|
|
|
161
162
|
)
|
|
162
163
|
|
|
163
164
|
|
|
165
|
+
def _print_version_status(
|
|
166
|
+
assessment: ToolUpgradeAssessment,
|
|
167
|
+
status_version: str,
|
|
168
|
+
tool_path: str | None,
|
|
169
|
+
tool_config: dict,
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Print the long-form version line for one installed tool."""
|
|
172
|
+
package_info = assessment.package_info
|
|
173
|
+
if assessment.install_method == InstallMethod.SYSTEM and tool_path and package_info:
|
|
174
|
+
print_system_version_status(
|
|
175
|
+
status_version, assessment.latest_version, package_info
|
|
176
|
+
)
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
if assessment.install_method == InstallMethod.PKG:
|
|
180
|
+
if package_info and package_info.get("available_version"):
|
|
181
|
+
print_pkg_version_status(
|
|
182
|
+
status_version,
|
|
183
|
+
assessment.latest_version,
|
|
184
|
+
package_info,
|
|
185
|
+
repo=tool_config.get("freebsd_pkg_repo"),
|
|
186
|
+
)
|
|
187
|
+
return
|
|
188
|
+
elif assessment.install_method in (
|
|
189
|
+
InstallMethod.BREW_FORMULA,
|
|
190
|
+
InstallMethod.BREW_CASK,
|
|
191
|
+
):
|
|
192
|
+
if package_info and package_info.get("available_version"):
|
|
193
|
+
print_brew_version_status(
|
|
194
|
+
status_version, assessment.latest_version, package_info
|
|
195
|
+
)
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
if (
|
|
199
|
+
assessment.latest_version
|
|
200
|
+
and assessment.version_state == VersionDisplayState.UP_TO_DATE
|
|
201
|
+
):
|
|
202
|
+
print(
|
|
203
|
+
f" Version: {status_version} "
|
|
204
|
+
f"{Colors.GREEN}(up to date){Colors.NC}"
|
|
205
|
+
)
|
|
206
|
+
else:
|
|
207
|
+
print(_generic_version_annotation(status_version, assessment.latest_version))
|
|
208
|
+
|
|
209
|
+
|
|
164
210
|
def cmd_status_compact() -> None:
|
|
165
211
|
"""Show compact one-line-per-tool status."""
|
|
166
212
|
ensure_versions_cache(TOOLS)
|
|
@@ -242,80 +288,9 @@ def cmd_status(args: argparse.Namespace) -> None:
|
|
|
242
288
|
print(f" Status: {Colors.GREEN}✓ Installed{Colors.NC}")
|
|
243
289
|
|
|
244
290
|
if status["version"]:
|
|
245
|
-
|
|
246
|
-
assessment
|
|
247
|
-
|
|
248
|
-
and assessment.package_info
|
|
249
|
-
):
|
|
250
|
-
print_system_version_status(
|
|
251
|
-
status["version"],
|
|
252
|
-
assessment.latest_version,
|
|
253
|
-
assessment.package_info,
|
|
254
|
-
)
|
|
255
|
-
elif assessment.install_method == InstallMethod.PKG:
|
|
256
|
-
if assessment.package_info and assessment.package_info.get(
|
|
257
|
-
"available_version"
|
|
258
|
-
):
|
|
259
|
-
print_pkg_version_status(
|
|
260
|
-
status["version"],
|
|
261
|
-
assessment.latest_version,
|
|
262
|
-
assessment.package_info,
|
|
263
|
-
repo=tool_config.get("freebsd_pkg_repo"),
|
|
264
|
-
)
|
|
265
|
-
elif assessment.latest_version:
|
|
266
|
-
if assessment.version_state == VersionDisplayState.UP_TO_DATE:
|
|
267
|
-
print(
|
|
268
|
-
f" Version: {status['version']} "
|
|
269
|
-
f"{Colors.GREEN}(up to date){Colors.NC}"
|
|
270
|
-
)
|
|
271
|
-
else:
|
|
272
|
-
print(
|
|
273
|
-
_generic_version_annotation(
|
|
274
|
-
status["version"], assessment.latest_version
|
|
275
|
-
)
|
|
276
|
-
)
|
|
277
|
-
else:
|
|
278
|
-
print(f" Version: {status['version']}")
|
|
279
|
-
elif assessment.install_method in (
|
|
280
|
-
InstallMethod.BREW_FORMULA,
|
|
281
|
-
InstallMethod.BREW_CASK,
|
|
282
|
-
):
|
|
283
|
-
if assessment.package_info and assessment.package_info.get(
|
|
284
|
-
"available_version"
|
|
285
|
-
):
|
|
286
|
-
print_brew_version_status(
|
|
287
|
-
status["version"],
|
|
288
|
-
assessment.latest_version,
|
|
289
|
-
assessment.package_info,
|
|
290
|
-
)
|
|
291
|
-
elif assessment.latest_version:
|
|
292
|
-
if assessment.version_state == VersionDisplayState.UP_TO_DATE:
|
|
293
|
-
print(
|
|
294
|
-
f" Version: {status['version']} "
|
|
295
|
-
f"{Colors.GREEN}(up to date){Colors.NC}"
|
|
296
|
-
)
|
|
297
|
-
else:
|
|
298
|
-
print(
|
|
299
|
-
_generic_version_annotation(
|
|
300
|
-
status["version"], assessment.latest_version
|
|
301
|
-
)
|
|
302
|
-
)
|
|
303
|
-
else:
|
|
304
|
-
print(f" Version: {status['version']}")
|
|
305
|
-
elif assessment.latest_version:
|
|
306
|
-
if assessment.version_state == VersionDisplayState.UP_TO_DATE:
|
|
307
|
-
print(
|
|
308
|
-
f" Version: {status['version']} "
|
|
309
|
-
f"{Colors.GREEN}(up to date){Colors.NC}"
|
|
310
|
-
)
|
|
311
|
-
else:
|
|
312
|
-
print(
|
|
313
|
-
_generic_version_annotation(
|
|
314
|
-
status["version"], assessment.latest_version
|
|
315
|
-
)
|
|
316
|
-
)
|
|
317
|
-
else:
|
|
318
|
-
print(f" Version: {status['version']}")
|
|
291
|
+
_print_version_status(
|
|
292
|
+
assessment, status["version"], tool_path, tool_config
|
|
293
|
+
)
|
|
319
294
|
|
|
320
295
|
if assessment.decision == UpgradeDecision.UPGRADE:
|
|
321
296
|
outdated_count += 1
|