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.
Files changed (61) hide show
  1. {code_aide-1.15.2 → code_aide-1.15.4}/AGENTS.md +3 -0
  2. {code_aide-1.15.2 → code_aide-1.15.4}/PKG-INFO +5 -4
  3. {code_aide-1.15.2 → code_aide-1.15.4}/README.md +4 -3
  4. {code_aide-1.15.2 → code_aide-1.15.4}/script-archive/cursor-install.sh +5 -5
  5. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/__init__.py +1 -1
  6. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/data/tools.json +1 -1
  7. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/versions.py +14 -4
  8. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_install.py +8 -1
  9. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_versions.py +44 -0
  10. {code_aide-1.15.2 → code_aide-1.15.4}/.github/workflows/ci.yml +0 -0
  11. {code_aide-1.15.2 → code_aide-1.15.4}/.github/workflows/publish.yml +0 -0
  12. {code_aide-1.15.2 → code_aide-1.15.4}/.gitignore +0 -0
  13. {code_aide-1.15.2 → code_aide-1.15.4}/.gitlab-ci.yml +0 -0
  14. {code_aide-1.15.2 → code_aide-1.15.4}/.pre-commit-config.yaml +0 -0
  15. {code_aide-1.15.2 → code_aide-1.15.4}/CLAUDE.md +0 -0
  16. {code_aide-1.15.2 → code_aide-1.15.4}/LICENSE +0 -0
  17. {code_aide-1.15.2 → code_aide-1.15.4}/TODO.md +0 -0
  18. {code_aide-1.15.2 → code_aide-1.15.4}/pyproject.toml +0 -0
  19. {code_aide-1.15.2 → code_aide-1.15.4}/script-archive/README.md +0 -0
  20. {code_aide-1.15.2 → code_aide-1.15.4}/script-archive/amp-install.sh +0 -0
  21. {code_aide-1.15.2 → code_aide-1.15.4}/script-archive/claude-install.sh +0 -0
  22. {code_aide-1.15.2 → code_aide-1.15.4}/specs/2026-05-03-qwen3.6-code-quality-analysis-original.md +0 -0
  23. {code_aide-1.15.2 → code_aide-1.15.4}/specs/2026-05-03-qwen3.6-code-quality-analysis.md +0 -0
  24. {code_aide-1.15.2 → code_aide-1.15.4}/specs/auto-migrate-deprecated-installs.md +0 -0
  25. {code_aide-1.15.2 → code_aide-1.15.4}/specs/claude-native-installer-migration.md +0 -0
  26. {code_aide-1.15.2 → code_aide-1.15.4}/specs/missing-coding-llm-cli-tools.md +0 -0
  27. {code_aide-1.15.2 → code_aide-1.15.4}/specs/pre-commit-uv-setup.md +0 -0
  28. {code_aide-1.15.2 → code_aide-1.15.4}/specs/remove-bundled-version-baseline.md +0 -0
  29. {code_aide-1.15.2 → code_aide-1.15.4}/specs/unify-upgrade-eligibility-with-shared-evaluator.md +0 -0
  30. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/__main__.py +0 -0
  31. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/commands_actions.py +0 -0
  32. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/commands_tools.py +0 -0
  33. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/config.py +0 -0
  34. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/console.py +0 -0
  35. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/constants.py +0 -0
  36. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/detection.py +0 -0
  37. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/detection_types.py +0 -0
  38. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/entry.py +0 -0
  39. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/install.py +0 -0
  40. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/install_types.py +0 -0
  41. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/operation_handlers.py +0 -0
  42. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/operations.py +0 -0
  43. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/package_info.py +0 -0
  44. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/package_managers.py +0 -0
  45. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/prereqs.py +0 -0
  46. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/status.py +0 -0
  47. {code_aide-1.15.2 → code_aide-1.15.4}/src/code_aide/status_print.py +0 -0
  48. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_commands_actions.py +0 -0
  49. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_commands_tools.py +0 -0
  50. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_config.py +0 -0
  51. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_console.py +0 -0
  52. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_constants.py +0 -0
  53. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_detection.py +0 -0
  54. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_entry.py +0 -0
  55. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_error_paths.py +0 -0
  56. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_install_types.py +0 -0
  57. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_operations.py +0 -0
  58. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_package_managers.py +0 -0
  59. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_prereqs.py +0 -0
  60. {code_aide-1.15.2 → code_aide-1.15.4}/tests/test_status.py +0 -0
  61. {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.2
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 origin vX.Y.Z`
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 origin vX.Y.Z`
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.03.20-44cb435-$(date +%s)"
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.03.20-44cb435/${OS}/${ARCH}/agent-cli-package.tar.gz"
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.03.20-44cb435"
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.03.20-44cb435/cursor-agent ~/.local/bin/agent
131
- ln -s ~/.local/share/cursor-agent/versions/2026.03.20-44cb435/cursor-agent ~/.local/bin/cursor-agent
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
@@ -1,3 +1,3 @@
1
1
  """code-aide - Manage AI coding CLI tools."""
2
2
 
3
- __version__ = "1.15.2"
3
+ __version__ = "1.15.4"
@@ -68,7 +68,7 @@
68
68
  "install_script_path_prepend": [
69
69
  "~/.local/bin"
70
70
  ],
71
- "version_url": "https://storage.googleapis.com/amp-public-assets-prod-0/cli/cli-version.txt",
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
- match = re.search(r"(\d{4}\.\d{2}\.\d{2}-[0-9a-f]+)", text)
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 = re.search(pattern, text)
204
- if match:
205
- return match.group(1)
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
- cli_install.extract_tar_member(tf, member, td)
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