code-aide 1.1.0__tar.gz → 1.2.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.1.0 → code_aide-1.2.0}/PKG-INFO +1 -1
- code_aide-1.2.0/TODO.md +70 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/__init__.py +1 -1
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/commands_actions.py +2 -2
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/detection.py +3 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/entry.py +1 -1
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/install.py +7 -2
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_commands_actions.py +3 -3
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_install.py +54 -0
- code_aide-1.1.0/TODO.md +0 -39
- {code_aide-1.1.0 → code_aide-1.2.0}/.github/workflows/ci.yml +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/.github/workflows/publish.yml +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/.gitignore +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/AGENTS.md +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/CLAUDE.md +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/LICENSE +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/README.md +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/pyproject.toml +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/__main__.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/commands_tools.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/config.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/console.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/constants.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/data/tools.json +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/operations.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/prereqs.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/status.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/src/code_aide/versions.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_commands_tools.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_config.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_console.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_constants.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_detection.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_operations.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_status.py +0 -0
- {code_aide-1.1.0 → code_aide-1.2.0}/tests/test_versions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-aide
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.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
|
code_aide-1.2.0/TODO.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
Keep the project focused on managing AI coding CLI tools (install, upgrade,
|
|
4
|
+
remove, status, and version metadata).
|
|
5
|
+
|
|
6
|
+
## Bugs
|
|
7
|
+
|
|
8
|
+
- [x] Standardize `--dryrun` flag: `update-versions` uses `--dry-run` but
|
|
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()`).
|
|
12
|
+
- [x] Replace PID-based temp directory naming with `tempfile.mkdtemp()` in
|
|
13
|
+
`install.py` `install_direct_download()`.
|
|
14
|
+
- [x] Guard `package.split("/", 1)` in `detection.py`
|
|
15
|
+
`get_system_package_info()` against missing `/` in subprocess output.
|
|
16
|
+
|
|
17
|
+
## Reliability and Correctness
|
|
18
|
+
|
|
19
|
+
- [ ] Handle missing `node` cleanly during prerequisite checks
|
|
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.
|
|
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.
|
|
27
|
+
- [ ] Use `os.pathsep` instead of hardcoded `":"` in `prereqs.py`
|
|
28
|
+
`check_path_directories()`.
|
|
29
|
+
|
|
30
|
+
## Security and Integrity
|
|
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.
|
|
36
|
+
|
|
37
|
+
## CLI and Automation UX
|
|
38
|
+
|
|
39
|
+
- [ ] Add `--json` output mode for `list`, `status`, and `update-versions`.
|
|
40
|
+
- [ ] Add a focused `doctor` command for environment checks (PATH,
|
|
41
|
+
prerequisites, command health).
|
|
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.
|
|
46
|
+
|
|
47
|
+
## Documentation
|
|
48
|
+
|
|
49
|
+
- [ ] Document that running `code-aide` with no subcommand defaults to `status`.
|
|
50
|
+
- [ ] Add `install --dryrun` to the README usage examples.
|
|
51
|
+
- [ ] Document environment variables and config file paths
|
|
52
|
+
(`~/.config/code-aide/versions.json`).
|
|
53
|
+
|
|
54
|
+
## Platform and Package Detection
|
|
55
|
+
|
|
56
|
+
- [ ] Broaden system package metadata detection beyond Gentoo-specific tooling
|
|
57
|
+
where practical.
|
|
58
|
+
|
|
59
|
+
## Maintainability and Tests
|
|
60
|
+
|
|
61
|
+
- [ ] Split larger modules into smaller focused files where practical
|
|
62
|
+
(`commands_actions.py`, `versions.py`, `install.py`).
|
|
63
|
+
- [ ] Add tests for major untested functions:
|
|
64
|
+
- `upgrade_tool()` (completely untested)
|
|
65
|
+
- `cmd_remove()` (completely untested)
|
|
66
|
+
- `fetch_url()` (completely untested)
|
|
67
|
+
- `check_prerequisites()` / `install_nodejs_npm()` (completely untested)
|
|
68
|
+
- `save_bundled_versions()` (untested)
|
|
69
|
+
- `get_system_package_info()` (completely untested)
|
|
70
|
+
- [ ] Add tests for prerequisite edge cases and cache write behavior.
|
|
@@ -302,7 +302,7 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
|
|
|
302
302
|
|
|
303
303
|
updates = [result for result in results if result["update"]]
|
|
304
304
|
if not updates:
|
|
305
|
-
if version_info_changed and not args.
|
|
305
|
+
if version_info_changed and not args.dryrun:
|
|
306
306
|
dest = _save(config["tools"])
|
|
307
307
|
print(f"Updated latest version info in {dest}.")
|
|
308
308
|
if version_info_changed:
|
|
@@ -323,7 +323,7 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
|
|
|
323
323
|
for result in updates:
|
|
324
324
|
print(f" {result['tool']}: SHA256 changed")
|
|
325
325
|
|
|
326
|
-
if args.
|
|
326
|
+
if args.dryrun:
|
|
327
327
|
print("\nDry run mode - no changes written.")
|
|
328
328
|
return
|
|
329
329
|
|
|
@@ -105,6 +105,9 @@ def get_system_package_info(binary_path: str) -> Dict[str, Optional[str]]:
|
|
|
105
105
|
except Exception:
|
|
106
106
|
pass
|
|
107
107
|
|
|
108
|
+
if "/" not in package:
|
|
109
|
+
return result
|
|
110
|
+
|
|
108
111
|
category, package_name = package.split("/", 1)
|
|
109
112
|
ebuild_dirs = globmod.glob(f"/var/db/repos/*/{category}/{package_name}/")
|
|
110
113
|
ebuilds = []
|
|
@@ -7,6 +7,7 @@ import platform
|
|
|
7
7
|
import shutil
|
|
8
8
|
import subprocess
|
|
9
9
|
import tarfile
|
|
10
|
+
import tempfile
|
|
10
11
|
from typing import Any, Dict, Optional
|
|
11
12
|
|
|
12
13
|
from code_aide.constants import TOOLS
|
|
@@ -162,8 +163,11 @@ def install_direct_download(
|
|
|
162
163
|
tarball_data, _ = fetch_url(download_url, timeout=120)
|
|
163
164
|
success(f"Downloaded {len(tarball_data)} bytes")
|
|
164
165
|
|
|
165
|
-
|
|
166
|
-
os.makedirs(
|
|
166
|
+
install_parent = os.path.dirname(install_dir) or "."
|
|
167
|
+
os.makedirs(install_parent, exist_ok=True)
|
|
168
|
+
temp_dir = tempfile.mkdtemp(
|
|
169
|
+
prefix=os.path.basename(install_dir) + ".tmp-", dir=install_parent
|
|
170
|
+
)
|
|
167
171
|
|
|
168
172
|
try:
|
|
169
173
|
with tarfile.open(fileobj=io.BytesIO(tarball_data), mode="r:gz") as tf:
|
|
@@ -275,6 +279,7 @@ def install_tool(tool_name: str, dryrun: bool = False) -> bool:
|
|
|
275
279
|
if dryrun:
|
|
276
280
|
success(f"{tool_config['name']} verification passed")
|
|
277
281
|
else:
|
|
282
|
+
success(f"{tool_config['name']} installed successfully")
|
|
278
283
|
info(tool_config["next_steps"])
|
|
279
284
|
if "docs_url" in tool_config:
|
|
280
285
|
info(f"Documentation: {tool_config['docs_url']}")
|
|
@@ -59,7 +59,7 @@ class TestCmdUpdateVersions(unittest.TestCase):
|
|
|
59
59
|
(),
|
|
60
60
|
{
|
|
61
61
|
"tools": ["missing"],
|
|
62
|
-
"
|
|
62
|
+
"dryrun": False,
|
|
63
63
|
"yes": False,
|
|
64
64
|
"verbose": False,
|
|
65
65
|
"bundled": False,
|
|
@@ -81,7 +81,7 @@ class TestCmdUpdateVersions(unittest.TestCase):
|
|
|
81
81
|
(),
|
|
82
82
|
{
|
|
83
83
|
"tools": [],
|
|
84
|
-
"
|
|
84
|
+
"dryrun": True,
|
|
85
85
|
"yes": False,
|
|
86
86
|
"verbose": False,
|
|
87
87
|
"bundled": False,
|
|
@@ -131,7 +131,7 @@ class TestCmdUpdateVersions(unittest.TestCase):
|
|
|
131
131
|
(),
|
|
132
132
|
{
|
|
133
133
|
"tools": [],
|
|
134
|
-
"
|
|
134
|
+
"dryrun": False,
|
|
135
135
|
"yes": True,
|
|
136
136
|
"verbose": False,
|
|
137
137
|
"bundled": True,
|
|
@@ -122,3 +122,57 @@ class TestInstallDirectDownloadDryrun(unittest.TestCase):
|
|
|
122
122
|
|
|
123
123
|
result = cli_install.install_direct_download("test", tool_config, dryrun=True)
|
|
124
124
|
self.assertFalse(result)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class TestInstallDirectDownload(unittest.TestCase):
|
|
128
|
+
"""Tests for install_direct_download in non-dryrun mode."""
|
|
129
|
+
|
|
130
|
+
@mock.patch.object(cli_install, "detect_os_arch", return_value=("linux", "x64"))
|
|
131
|
+
@mock.patch.object(cli_install, "fetch_url")
|
|
132
|
+
def test_creates_missing_install_parent_directory(self, mock_fetch, mock_os_arch):
|
|
133
|
+
script_content = b"echo install"
|
|
134
|
+
expected_sha256 = cli_install.hashlib.sha256(script_content).hexdigest()
|
|
135
|
+
|
|
136
|
+
tarball_data = io.BytesIO()
|
|
137
|
+
with tarfile.open(fileobj=tarball_data, mode="w:gz") as tf:
|
|
138
|
+
payload = b"#!/bin/sh\necho ok\n"
|
|
139
|
+
info = tarfile.TarInfo("package/test-bin")
|
|
140
|
+
info.mode = 0o755
|
|
141
|
+
info.size = len(payload)
|
|
142
|
+
tf.addfile(info, io.BytesIO(payload))
|
|
143
|
+
tarball_bytes = tarball_data.getvalue()
|
|
144
|
+
|
|
145
|
+
def _fake_fetch(url, timeout=30):
|
|
146
|
+
if url.endswith("/install"):
|
|
147
|
+
return script_content, None
|
|
148
|
+
return tarball_bytes, None
|
|
149
|
+
|
|
150
|
+
mock_fetch.side_effect = _fake_fetch
|
|
151
|
+
|
|
152
|
+
tool_config = {
|
|
153
|
+
"name": "Test Tool",
|
|
154
|
+
"install_url": "https://example.com/install",
|
|
155
|
+
"install_sha256": expected_sha256,
|
|
156
|
+
"download_url_template": "https://example.com/{version}/{os}/{arch}/pkg.tar.gz",
|
|
157
|
+
"install_dir": "/tmp/test-{version}",
|
|
158
|
+
"bin_dir": "/tmp/test-bin",
|
|
159
|
+
"symlinks": {"test": "test-bin"},
|
|
160
|
+
"latest_version": "1.0.0",
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
with tempfile.TemporaryDirectory() as td:
|
|
164
|
+
install_dir = os.path.join(td, "missing", "versions", "1.0.0")
|
|
165
|
+
bin_dir = os.path.join(td, "bin")
|
|
166
|
+
|
|
167
|
+
result = cli_install.install_direct_download(
|
|
168
|
+
"test",
|
|
169
|
+
tool_config,
|
|
170
|
+
dryrun=False,
|
|
171
|
+
install_dir_override=install_dir,
|
|
172
|
+
bin_dir_override=bin_dir,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
self.assertTrue(result)
|
|
176
|
+
self.assertTrue(os.path.isdir(os.path.dirname(install_dir)))
|
|
177
|
+
self.assertTrue(os.path.exists(os.path.join(install_dir, "test-bin")))
|
|
178
|
+
self.assertTrue(os.path.islink(os.path.join(bin_dir, "test")))
|
code_aide-1.1.0/TODO.md
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# TODO
|
|
2
|
-
|
|
3
|
-
Keep the project focused on managing AI coding CLI tools (install, upgrade,
|
|
4
|
-
remove, status, and version metadata).
|
|
5
|
-
|
|
6
|
-
## Reliability and Correctness
|
|
7
|
-
|
|
8
|
-
- [ ] Handle missing `node` cleanly during prerequisite checks
|
|
9
|
-
(`FileNotFoundError` path in Node version probing).
|
|
10
|
-
- [ ] Read tool version output from both stdout and stderr so status does not
|
|
11
|
-
miss installed versions.
|
|
12
|
-
- [ ] Make version cache writes atomic (write temp file + rename) to avoid
|
|
13
|
-
partial/corrupted `versions.json`.
|
|
14
|
-
|
|
15
|
-
## Security and Integrity
|
|
16
|
-
|
|
17
|
-
- [ ] Add integrity verification for direct-download tarballs (not only install
|
|
18
|
-
script SHA256).
|
|
19
|
-
- [ ] Extend tool metadata to support tarball checksum/signature fields where
|
|
20
|
-
applicable.
|
|
21
|
-
|
|
22
|
-
## CLI and Automation UX
|
|
23
|
-
|
|
24
|
-
- [ ] Add `--json` output mode for `list`, `status`, and `update-versions`.
|
|
25
|
-
- [ ] Add a focused `doctor` command for environment checks (PATH,
|
|
26
|
-
prerequisites, command health).
|
|
27
|
-
- [ ] Consider `install --force` for reinstall/repair flows.
|
|
28
|
-
- [ ] Add cleanup support for stale direct-download versions no longer in use.
|
|
29
|
-
|
|
30
|
-
## Platform and Package Detection
|
|
31
|
-
|
|
32
|
-
- [ ] Broaden system package metadata detection beyond Gentoo-specific tooling
|
|
33
|
-
where practical.
|
|
34
|
-
|
|
35
|
-
## Maintainability and Tests
|
|
36
|
-
|
|
37
|
-
- [ ] Split larger modules into smaller focused files where practical
|
|
38
|
-
(`commands_actions.py`, `versions.py`, `install.py`).
|
|
39
|
-
- [ ] Add tests for prerequisite edge cases and cache write behavior.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|