code-aide 1.15.2__tar.gz → 1.15.4__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.15.2 → code_aide-1.15.4}/AGENTS.md +3 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/PKG-INFO +5 -4
- {code_aide-1.15.2 → code_aide-1.15.4}/README.md +4 -3
- {code_aide-1.15.2 → code_aide-1.15.4}/script-archive/cursor-install.sh +5 -5
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/__init__.py +1 -1
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/data/tools.json +1 -1
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/versions.py +14 -4
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_install.py +8 -1
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_versions.py +44 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/.github/workflows/ci.yml +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/.github/workflows/publish.yml +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/.gitignore +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/.gitlab-ci.yml +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/.pre-commit-config.yaml +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/CLAUDE.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/LICENSE +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/TODO.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/pyproject.toml +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/script-archive/README.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/script-archive/amp-install.sh +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/script-archive/claude-install.sh +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/specs/2026-05-03-qwen3.6-code-quality-analysis-original.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/specs/2026-05-03-qwen3.6-code-quality-analysis.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/specs/auto-migrate-deprecated-installs.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/specs/claude-native-installer-migration.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/specs/missing-coding-llm-cli-tools.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/specs/pre-commit-uv-setup.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/specs/remove-bundled-version-baseline.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/specs/unify-upgrade-eligibility-with-shared-evaluator.md +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/__main__.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/commands_actions.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/commands_tools.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/config.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/console.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/constants.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/detection.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/detection_types.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/entry.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/install.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/install_types.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/operation_handlers.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/operations.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/package_info.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/package_managers.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/prereqs.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/status.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/status_print.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_commands_actions.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_commands_tools.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_config.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_console.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_constants.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_detection.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_entry.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_error_paths.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_install_types.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_operations.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_package_managers.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_prereqs.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_status.py +0 -0
- {code_aide-1.15.2 → code_aide-1.15.4}/uv.lock +0 -0
|
@@ -36,3 +36,6 @@
|
|
|
36
36
|
- When pushing tags, always push them explicitly with `git push <remote> <tag>`
|
|
37
37
|
rather than relying on `--follow-tags`, which silently skips tags when the
|
|
38
38
|
branch commits are already on the remote
|
|
39
|
+
- For releases, push both the branch and the tag to all remotes (origin, gitlab,
|
|
40
|
+
codeberg): `git push <remote> main && git push <remote> <tag>` for each remote
|
|
41
|
+
in turn.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-aide
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.4
|
|
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
|
|
@@ -186,10 +186,11 @@ uv run pytest tests/test_install.py::TestDetectOsArch -v
|
|
|
186
186
|
- Keep subjects user-facing so auto-generated release notes are meaningful.
|
|
187
187
|
- Group related changes into focused commits instead of one broad commit.
|
|
188
188
|
- Example: `Fixed timeout handling in status command`
|
|
189
|
-
5. Tag and push:
|
|
189
|
+
5. Tag and push to all remotes (origin/GitHub, gitlab, codeberg):
|
|
190
190
|
- `git tag vX.Y.Z`
|
|
191
|
-
- `git push origin main`
|
|
192
|
-
- `git push
|
|
191
|
+
- `git push origin main && git push origin vX.Y.Z`
|
|
192
|
+
- `git push gitlab main && git push gitlab vX.Y.Z`
|
|
193
|
+
- `git push codeberg main && git push codeberg vX.Y.Z`
|
|
193
194
|
6. Confirm GitHub Actions:
|
|
194
195
|
- CI should pass.
|
|
195
196
|
- Publish workflow should upload to PyPI and create GitHub Release notes.
|
|
@@ -159,10 +159,11 @@ uv run pytest tests/test_install.py::TestDetectOsArch -v
|
|
|
159
159
|
- Keep subjects user-facing so auto-generated release notes are meaningful.
|
|
160
160
|
- Group related changes into focused commits instead of one broad commit.
|
|
161
161
|
- Example: `Fixed timeout handling in status command`
|
|
162
|
-
5. Tag and push:
|
|
162
|
+
5. Tag and push to all remotes (origin/GitHub, gitlab, codeberg):
|
|
163
163
|
- `git tag vX.Y.Z`
|
|
164
|
-
- `git push origin main`
|
|
165
|
-
- `git push
|
|
164
|
+
- `git push origin main && git push origin vX.Y.Z`
|
|
165
|
+
- `git push gitlab main && git push gitlab vX.Y.Z`
|
|
166
|
+
- `git push codeberg main && git push codeberg vX.Y.Z`
|
|
166
167
|
6. Confirm GitHub Actions:
|
|
167
168
|
- CI should pass.
|
|
168
169
|
- Publish workflow should upload to PyPI and create GitHub Release notes.
|
|
@@ -75,14 +75,14 @@ print_success "Detected ${OS}/${ARCH}"
|
|
|
75
75
|
# Installation steps
|
|
76
76
|
print_step "Creating installation directory..."
|
|
77
77
|
# Create temporary directory for atomic download inside versions folder
|
|
78
|
-
TEMP_EXTRACT_DIR="$HOME/.local/share/cursor-agent/versions/.tmp-2026.
|
|
78
|
+
TEMP_EXTRACT_DIR="$HOME/.local/share/cursor-agent/versions/.tmp-2026.06.12-19-59-36-f6aba9a-$(date +%s)"
|
|
79
79
|
mkdir -p "${TEMP_EXTRACT_DIR}"
|
|
80
80
|
|
|
81
81
|
print_success "Directory created"
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
print_step "Downloading Cursor Agent package..."
|
|
85
|
-
DOWNLOAD_URL="https://downloads.cursor.com/lab/2026.
|
|
85
|
+
DOWNLOAD_URL="https://downloads.cursor.com/lab/2026.06.12-19-59-36-f6aba9a/${OS}/${ARCH}/agent-cli-package.tar.gz"
|
|
86
86
|
echo -e "${DIM} Download URL: ${DOWNLOAD_URL}${NC}"
|
|
87
87
|
|
|
88
88
|
# Cleanup function
|
|
@@ -107,7 +107,7 @@ fi
|
|
|
107
107
|
|
|
108
108
|
print_step "Finalizing installation..."
|
|
109
109
|
# Atomically move from temp to final destination
|
|
110
|
-
FINAL_DIR="$HOME/.local/share/cursor-agent/versions/2026.
|
|
110
|
+
FINAL_DIR="$HOME/.local/share/cursor-agent/versions/2026.06.12-19-59-36-f6aba9a"
|
|
111
111
|
command rm -rf "${FINAL_DIR}"
|
|
112
112
|
if mv "${TEMP_EXTRACT_DIR}" "${FINAL_DIR}"; then
|
|
113
113
|
print_success "Package installed successfully"
|
|
@@ -127,8 +127,8 @@ print_step "Creating symlinks to agent executable..."
|
|
|
127
127
|
# Remove any existing symlink or file
|
|
128
128
|
command rm -f ~/.local/bin/agent ~/.local/bin/cursor-agent
|
|
129
129
|
# Create symlinks to the Cursor Agent executable (primary: agent, legacy: cursor-agent)
|
|
130
|
-
ln -s ~/.local/share/cursor-agent/versions/2026.
|
|
131
|
-
ln -s ~/.local/share/cursor-agent/versions/2026.
|
|
130
|
+
ln -s ~/.local/share/cursor-agent/versions/2026.06.12-19-59-36-f6aba9a/cursor-agent ~/.local/bin/agent
|
|
131
|
+
ln -s ~/.local/share/cursor-agent/versions/2026.06.12-19-59-36-f6aba9a/cursor-agent ~/.local/bin/cursor-agent
|
|
132
132
|
print_success "Symlink created"
|
|
133
133
|
|
|
134
134
|
# Success message
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"install_script_path_prepend": [
|
|
69
69
|
"~/.local/bin"
|
|
70
70
|
],
|
|
71
|
-
"version_url": "https://
|
|
71
|
+
"version_url": "https://static.ampcode.com/cli/cli-version.txt",
|
|
72
72
|
"prerequisites": [],
|
|
73
73
|
"min_node_version": null,
|
|
74
74
|
"next_steps": "Run 'amp login' to authenticate",
|
|
@@ -191,7 +191,12 @@ def extract_script_version(
|
|
|
191
191
|
text = script_content.decode("utf-8", errors="replace")
|
|
192
192
|
|
|
193
193
|
if tool_name == "cursor":
|
|
194
|
-
|
|
194
|
+
# Cursor versions are date-stamped with one or more hyphen-separated
|
|
195
|
+
# segments: historically YYYY.MM.DD-<githash>, now extended with a
|
|
196
|
+
# build time, e.g. 2026.06.12-19-59-36-f6aba9a. Capture every segment
|
|
197
|
+
# so the download URL path matches; stopping at the first segment
|
|
198
|
+
# yields a nonexistent build (HTTP 403).
|
|
199
|
+
match = re.search(r"(\d{4}\.\d{2}\.\d{2}(?:-[0-9a-f]+)+)", text)
|
|
195
200
|
if match:
|
|
196
201
|
return match.group(1)
|
|
197
202
|
|
|
@@ -200,9 +205,14 @@ def extract_script_version(
|
|
|
200
205
|
r"VERSION='([^']+)'",
|
|
201
206
|
r"VERSION=(\S+)",
|
|
202
207
|
]:
|
|
203
|
-
match
|
|
204
|
-
|
|
205
|
-
|
|
208
|
+
for match in re.finditer(pattern, text):
|
|
209
|
+
candidate = match.group(1)
|
|
210
|
+
# Skip shell-variable placeholders such as the literal
|
|
211
|
+
# ${AMP_VERSION:-} in `AMP_VERSION="${AMP_VERSION:-}"`; a real
|
|
212
|
+
# version string never contains shell expansion characters.
|
|
213
|
+
if "$" in candidate or "{" in candidate:
|
|
214
|
+
continue
|
|
215
|
+
return candidate
|
|
206
216
|
|
|
207
217
|
return None
|
|
208
218
|
|
|
@@ -5,6 +5,7 @@ import os
|
|
|
5
5
|
import tarfile
|
|
6
6
|
import tempfile
|
|
7
7
|
import unittest
|
|
8
|
+
import warnings
|
|
8
9
|
from unittest import mock
|
|
9
10
|
|
|
10
11
|
from code_aide import constants, install as cli_install
|
|
@@ -142,7 +143,13 @@ class TestExtractTarMember(unittest.TestCase):
|
|
|
142
143
|
with mock.patch.object(
|
|
143
144
|
tf, "extract", side_effect=_extract_with_legacy_signature
|
|
144
145
|
):
|
|
145
|
-
|
|
146
|
+
# The simulated legacy extract (no filter kwarg) emits a
|
|
147
|
+
# DeprecationWarning on Python 3.12+. In production the
|
|
148
|
+
# fallback only runs on Python too old to warn, so suppress
|
|
149
|
+
# it here rather than letting filterwarnings=error fail.
|
|
150
|
+
with warnings.catch_warnings():
|
|
151
|
+
warnings.simplefilter("ignore", DeprecationWarning)
|
|
152
|
+
cli_install.extract_tar_member(tf, member, td)
|
|
146
153
|
|
|
147
154
|
extracted = os.path.join(td, "payload", "file.txt")
|
|
148
155
|
self.assertTrue(os.path.exists(extracted))
|
|
@@ -279,3 +279,47 @@ class TestExtractScriptDate(unittest.TestCase):
|
|
|
279
279
|
|
|
280
280
|
def test_non_date_version_no_header_returns_none(self):
|
|
281
281
|
self.assertIsNone(cli_versions.extract_script_date("v1.2.3", None))
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class TestExtractScriptVersion(unittest.TestCase):
|
|
285
|
+
"""Tests for extract_script_version (cursor version parsing)."""
|
|
286
|
+
|
|
287
|
+
def test_cursor_legacy_date_hash_format(self):
|
|
288
|
+
script = b'DOWNLOAD_URL="https://downloads.cursor.com/lab/2026.03.20-44cb435/${OS}/${ARCH}/agent-cli-package.tar.gz"'
|
|
289
|
+
self.assertEqual(
|
|
290
|
+
cli_versions.extract_script_version("cursor", {}, script),
|
|
291
|
+
"2026.03.20-44cb435",
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
def test_cursor_date_time_hash_format(self):
|
|
295
|
+
# Cursor extended the version with a build time (HH-MM-SS). The whole
|
|
296
|
+
# string must be captured or the download URL path 403s.
|
|
297
|
+
script = b'DOWNLOAD_URL="https://downloads.cursor.com/lab/2026.06.12-19-59-36-f6aba9a/${OS}/${ARCH}/agent-cli-package.tar.gz"'
|
|
298
|
+
self.assertEqual(
|
|
299
|
+
cli_versions.extract_script_version("cursor", {}, script),
|
|
300
|
+
"2026.06.12-19-59-36-f6aba9a",
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def test_cursor_no_version_returns_none(self):
|
|
304
|
+
self.assertIsNone(
|
|
305
|
+
cli_versions.extract_script_version("cursor", {}, b"echo hello")
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
def test_skips_shell_variable_placeholder(self):
|
|
309
|
+
# The amp script declares AMP_VERSION="${AMP_VERSION:-}"; the literal
|
|
310
|
+
# placeholder must not be returned as a version.
|
|
311
|
+
script = b'AMP_VERSION="${AMP_VERSION:-}"\n'
|
|
312
|
+
self.assertIsNone(cli_versions.extract_script_version("amp", {}, script))
|
|
313
|
+
|
|
314
|
+
def test_returns_real_version_after_placeholder(self):
|
|
315
|
+
script = b'AMP_VERSION="${AMP_VERSION:-}"\nVERSION="1.2.3"\n'
|
|
316
|
+
self.assertEqual(
|
|
317
|
+
cli_versions.extract_script_version("amp", {}, script),
|
|
318
|
+
"1.2.3",
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
def test_plain_version_assignment(self):
|
|
322
|
+
self.assertEqual(
|
|
323
|
+
cli_versions.extract_script_version("amp", {}, b'VERSION="2.0.1"\n'),
|
|
324
|
+
"2.0.1",
|
|
325
|
+
)
|
|
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
|
{code_aide-1.15.2 → code_aide-1.15.4}/specs/2026-05-03-qwen3.6-code-quality-analysis-original.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_aide-1.15.2 → code_aide-1.15.4}/specs/unify-upgrade-eligibility-with-shared-evaluator.md
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|