code-aide 1.15.6__tar.gz → 1.16.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 (63) hide show
  1. {code_aide-1.15.6 → code_aide-1.16.0}/PKG-INFO +37 -29
  2. {code_aide-1.15.6 → code_aide-1.16.0}/README.md +35 -27
  3. {code_aide-1.15.6 → code_aide-1.16.0}/pyproject.toml +1 -1
  4. code_aide-1.16.0/script-archive/antigravity-install.sh +239 -0
  5. code_aide-1.16.0/specs/antigravity-cli-integration.md +35 -0
  6. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/__init__.py +1 -1
  7. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/commands_actions.py +11 -4
  8. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/config.py +21 -1
  9. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/data/tools.json +26 -3
  10. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/install.py +49 -13
  11. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/operations.py +7 -0
  12. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/prereqs.py +9 -14
  13. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/status.py +15 -0
  14. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/versions.py +40 -0
  15. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_commands_actions.py +64 -1
  16. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_config.py +63 -0
  17. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_install.py +16 -0
  18. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_operations.py +21 -0
  19. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_prereqs.py +3 -9
  20. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_status.py +18 -0
  21. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_versions.py +69 -0
  22. {code_aide-1.15.6 → code_aide-1.16.0}/.github/workflows/ci.yml +0 -0
  23. {code_aide-1.15.6 → code_aide-1.16.0}/.github/workflows/publish.yml +0 -0
  24. {code_aide-1.15.6 → code_aide-1.16.0}/.gitignore +0 -0
  25. {code_aide-1.15.6 → code_aide-1.16.0}/.gitlab-ci.yml +0 -0
  26. {code_aide-1.15.6 → code_aide-1.16.0}/.pre-commit-config.yaml +0 -0
  27. {code_aide-1.15.6 → code_aide-1.16.0}/AGENTS.md +0 -0
  28. {code_aide-1.15.6 → code_aide-1.16.0}/CLAUDE.md +0 -0
  29. {code_aide-1.15.6 → code_aide-1.16.0}/LICENSE +0 -0
  30. {code_aide-1.15.6 → code_aide-1.16.0}/TODO.md +0 -0
  31. {code_aide-1.15.6 → code_aide-1.16.0}/script-archive/README.md +0 -0
  32. {code_aide-1.15.6 → code_aide-1.16.0}/script-archive/amp-install.sh +0 -0
  33. {code_aide-1.15.6 → code_aide-1.16.0}/script-archive/claude-install.sh +0 -0
  34. {code_aide-1.15.6 → code_aide-1.16.0}/script-archive/cursor-install.sh +0 -0
  35. {code_aide-1.15.6 → code_aide-1.16.0}/specs/2026-05-03-qwen3.6-code-quality-analysis-original.md +0 -0
  36. {code_aide-1.15.6 → code_aide-1.16.0}/specs/2026-05-03-qwen3.6-code-quality-analysis.md +0 -0
  37. {code_aide-1.15.6 → code_aide-1.16.0}/specs/auto-migrate-deprecated-installs.md +0 -0
  38. {code_aide-1.15.6 → code_aide-1.16.0}/specs/claude-native-installer-migration.md +0 -0
  39. {code_aide-1.15.6 → code_aide-1.16.0}/specs/missing-coding-llm-cli-tools.md +0 -0
  40. {code_aide-1.15.6 → code_aide-1.16.0}/specs/pre-commit-uv-setup.md +0 -0
  41. {code_aide-1.15.6 → code_aide-1.16.0}/specs/remove-bundled-version-baseline.md +0 -0
  42. {code_aide-1.15.6 → code_aide-1.16.0}/specs/unify-upgrade-eligibility-with-shared-evaluator.md +0 -0
  43. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/__main__.py +0 -0
  44. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/commands_tools.py +0 -0
  45. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/console.py +0 -0
  46. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/constants.py +0 -0
  47. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/detection.py +0 -0
  48. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/detection_types.py +0 -0
  49. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/entry.py +0 -0
  50. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/install_types.py +0 -0
  51. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/operation_handlers.py +0 -0
  52. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/package_info.py +0 -0
  53. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/package_managers.py +0 -0
  54. {code_aide-1.15.6 → code_aide-1.16.0}/src/code_aide/status_print.py +0 -0
  55. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_commands_tools.py +0 -0
  56. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_console.py +0 -0
  57. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_constants.py +0 -0
  58. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_detection.py +0 -0
  59. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_entry.py +0 -0
  60. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_error_paths.py +0 -0
  61. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_install_types.py +0 -0
  62. {code_aide-1.15.6 → code_aide-1.16.0}/tests/test_package_managers.py +0 -0
  63. {code_aide-1.15.6 → code_aide-1.16.0}/uv.lock +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-aide
3
- Version: 1.15.6
4
- Summary: Manage AI coding CLI tools (Claude, Copilot, Cursor, Gemini, Amp, Codex)
3
+ Version: 1.16.0
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
7
7
  Project-URL: Issues, https://github.com/dajobe/code-aide/issues
@@ -30,7 +30,8 @@ Description-Content-Type: text/markdown
30
30
  An aide for your AI coding tools.
31
31
 
32
32
  Manages installation, upgrade, removal, and version tracking of AI coding CLI
33
- tools: Claude Code, Copilot, Cursor, Gemini, Amp, Codex, OpenCode, and Kilo.
33
+ tools: Claude Code, Antigravity, Copilot, Cursor, Gemini, Amp, Codex, OpenCode,
34
+ and Kilo.
34
35
 
35
36
  ## Installation
36
37
 
@@ -58,7 +59,7 @@ code-aide status
58
59
  code-aide status -l
59
60
 
60
61
  # Install specific tools
61
- code-aide install claude gemini
62
+ code-aide install claude antigravity
62
63
 
63
64
  # Install all default tools
64
65
  code-aide install
@@ -83,15 +84,19 @@ code-aide update-versions -y
83
84
 
84
85
  | Tool | Command | Install Type | Default |
85
86
  |:-------------------------|:-----------|:----------------|:--------|
86
- | Cursor CLI | `agent` | Direct download | Yes |
87
+ | Cursor CLI | `agent` | Direct download | No |
87
88
  | Claude CLI (Claude Code) | `claude` | Script | Yes |
88
- | Gemini CLI | `gemini` | npm | Yes |
89
+ | Antigravity CLI | `agy` | Script | Yes |
90
+ | Gemini CLI | `gemini` | npm | No |
89
91
  | OpenCode | `opencode` | npm | No |
90
92
  | Kilo CLI | `kilo` | npm | No |
91
93
  | Amp (Sourcegraph) | `amp` | Script | No |
92
94
  | Codex CLI | `codex` | npm | No |
93
95
  | Copilot CLI | `copilot` | npm | No |
94
96
 
97
+ Command aliases are also accepted: `agy` resolves to `antigravity`, and `agent`
98
+ resolves to `cursor`.
99
+
95
100
  ## How Version Data Works
96
101
 
97
102
  code-aide uses a two-layer version data model:
@@ -113,29 +118,32 @@ Each entry in `tools.json` describes one managed tool. Required fields are
113
118
  `name`, `command`, and `install_type`; the others are optional and only
114
119
  consulted when the relevant install method or platform applies.
115
120
 
116
- | Field | Required | Notes |
117
- |:------------------------------|:---------|:---------------------------------------------------------------------------------------------|
118
- | `name` | Yes | Display name for status output |
119
- | `command` | Yes | Binary name (looked up in `PATH`) |
120
- | `install_type` | Yes | One of `npm`, `script`, `direct_download`, `pkg` |
121
- | `version_args` | No | List of arguments passed to the binary to print its version (default: `["--version"]`) |
122
- | `version_url` | No | URL queried by `update-versions` to discover the latest upstream version |
123
- | `latest_version` | Cache | Last known upstream version (filled by `update-versions`) |
124
- | `latest_date` | Cache | Release date for `latest_version` |
125
- | `prerequisites` | No | List of required external commands (e.g. `["npm"]`) |
126
- | `min_node_version` | No | Minimum major Node.js version required |
127
- | `npm_package` | npm | npm package name (e.g. `@anthropic-ai/claude-code`) |
128
- | `install_url` | script | URL of the install script that will be downloaded and piped to `bash` |
129
- | `install_sha256` | script | SHA-256 of the install script body — required for verified installs |
130
- | `install_script_path_prepend` | script | Extra directories prepended to `PATH` when the install script runs (e.g. `["~/.local/bin"]`) |
131
- | `download_url_template` | direct | URL template with `{version}`, `{os}`, `{arch}` placeholders |
132
- | `install_dir` | direct | Directory to extract into; supports `{version}` |
133
- | `bin_dir` | direct | Directory where symlinks for `command` are created (e.g. `~/.local/bin`) |
134
- | `symlinks` | direct | Map of `link_name` → relative path inside `install_dir` to symlink into `bin_dir` |
135
- | `freebsd_port` | FreeBSD | FreeBSD ports/pkg name (used when running on FreeBSD) |
136
- | `freebsd_pkg_repo` | FreeBSD | Optional non-default pkg repository name (passed via `pkg install -r <repo>`) |
137
- | `next_steps` | No | Free-form text printed after a successful install |
138
- | `docs_url` | No | Documentation URL printed after install |
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
+ | `latest_version` | Cache | Last known upstream version (filled by `update-versions`) |
131
+ | `latest_date` | Cache | Release date for `latest_version` |
132
+ | `prerequisites` | No | List of required external commands (e.g. `["npm"]`) |
133
+ | `min_node_version` | No | Minimum major Node.js version required |
134
+ | `npm_package` | npm | npm package name (e.g. `@anthropic-ai/claude-code`) |
135
+ | `install_url` | script | URL of the install script that will be downloaded and piped to `bash` |
136
+ | `install_sha256` | script | SHA-256 of the install script body — required for verified installs |
137
+ | `install_script_path_prepend` | script | Extra directories prepended to `PATH` when the install script runs (e.g. `["~/.local/bin"]`) |
138
+ | `download_url_template` | direct | URL template with `{version}`, `{os}`, `{arch}` placeholders |
139
+ | `install_dir` | direct | Directory to extract into; supports `{version}` |
140
+ | `bin_dir` | direct | Directory where symlinks for `command` are created (e.g. `~/.local/bin`) |
141
+ | `symlinks` | direct | Map of `link_name` relative path inside `install_dir` to symlink into `bin_dir` |
142
+ | `freebsd_port` | FreeBSD | FreeBSD ports/pkg name (used when running on FreeBSD) |
143
+ | `freebsd_pkg_repo` | FreeBSD | Optional non-default pkg repository name (passed via `pkg install -r <repo>`) |
144
+ | `next_steps` | No | Free-form text printed after a successful install |
145
+ | `docs_url` | No | Documentation URL printed after install |
146
+ | `self_updates` | No | Tool updates itself when run; excludes it from managed upgrade actions |
139
147
 
140
148
  ## Features
141
149
 
@@ -3,7 +3,8 @@
3
3
  An aide for your AI coding tools.
4
4
 
5
5
  Manages installation, upgrade, removal, and version tracking of AI coding CLI
6
- tools: Claude Code, Copilot, Cursor, Gemini, Amp, Codex, OpenCode, and Kilo.
6
+ tools: Claude Code, Antigravity, Copilot, Cursor, Gemini, Amp, Codex, OpenCode,
7
+ and Kilo.
7
8
 
8
9
  ## Installation
9
10
 
@@ -31,7 +32,7 @@ code-aide status
31
32
  code-aide status -l
32
33
 
33
34
  # Install specific tools
34
- code-aide install claude gemini
35
+ code-aide install claude antigravity
35
36
 
36
37
  # Install all default tools
37
38
  code-aide install
@@ -56,15 +57,19 @@ code-aide update-versions -y
56
57
 
57
58
  | Tool | Command | Install Type | Default |
58
59
  |:-------------------------|:-----------|:----------------|:--------|
59
- | Cursor CLI | `agent` | Direct download | Yes |
60
+ | Cursor CLI | `agent` | Direct download | No |
60
61
  | Claude CLI (Claude Code) | `claude` | Script | Yes |
61
- | Gemini CLI | `gemini` | npm | Yes |
62
+ | Antigravity CLI | `agy` | Script | Yes |
63
+ | Gemini CLI | `gemini` | npm | No |
62
64
  | OpenCode | `opencode` | npm | No |
63
65
  | Kilo CLI | `kilo` | npm | No |
64
66
  | Amp (Sourcegraph) | `amp` | Script | No |
65
67
  | Codex CLI | `codex` | npm | No |
66
68
  | Copilot CLI | `copilot` | npm | No |
67
69
 
70
+ Command aliases are also accepted: `agy` resolves to `antigravity`, and `agent`
71
+ resolves to `cursor`.
72
+
68
73
  ## How Version Data Works
69
74
 
70
75
  code-aide uses a two-layer version data model:
@@ -86,29 +91,32 @@ Each entry in `tools.json` describes one managed tool. Required fields are
86
91
  `name`, `command`, and `install_type`; the others are optional and only
87
92
  consulted when the relevant install method or platform applies.
88
93
 
89
- | Field | Required | Notes |
90
- |:------------------------------|:---------|:---------------------------------------------------------------------------------------------|
91
- | `name` | Yes | Display name for status output |
92
- | `command` | Yes | Binary name (looked up in `PATH`) |
93
- | `install_type` | Yes | One of `npm`, `script`, `direct_download`, `pkg` |
94
- | `version_args` | No | List of arguments passed to the binary to print its version (default: `["--version"]`) |
95
- | `version_url` | No | URL queried by `update-versions` to discover the latest upstream version |
96
- | `latest_version` | Cache | Last known upstream version (filled by `update-versions`) |
97
- | `latest_date` | Cache | Release date for `latest_version` |
98
- | `prerequisites` | No | List of required external commands (e.g. `["npm"]`) |
99
- | `min_node_version` | No | Minimum major Node.js version required |
100
- | `npm_package` | npm | npm package name (e.g. `@anthropic-ai/claude-code`) |
101
- | `install_url` | script | URL of the install script that will be downloaded and piped to `bash` |
102
- | `install_sha256` | script | SHA-256 of the install script body — required for verified installs |
103
- | `install_script_path_prepend` | script | Extra directories prepended to `PATH` when the install script runs (e.g. `["~/.local/bin"]`) |
104
- | `download_url_template` | direct | URL template with `{version}`, `{os}`, `{arch}` placeholders |
105
- | `install_dir` | direct | Directory to extract into; supports `{version}` |
106
- | `bin_dir` | direct | Directory where symlinks for `command` are created (e.g. `~/.local/bin`) |
107
- | `symlinks` | direct | Map of `link_name` → relative path inside `install_dir` to symlink into `bin_dir` |
108
- | `freebsd_port` | FreeBSD | FreeBSD ports/pkg name (used when running on FreeBSD) |
109
- | `freebsd_pkg_repo` | FreeBSD | Optional non-default pkg repository name (passed via `pkg install -r <repo>`) |
110
- | `next_steps` | No | Free-form text printed after a successful install |
111
- | `docs_url` | No | Documentation URL printed after install |
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
+ | `latest_version` | Cache | Last known upstream version (filled by `update-versions`) |
104
+ | `latest_date` | Cache | Release date for `latest_version` |
105
+ | `prerequisites` | No | List of required external commands (e.g. `["npm"]`) |
106
+ | `min_node_version` | No | Minimum major Node.js version required |
107
+ | `npm_package` | npm | npm package name (e.g. `@anthropic-ai/claude-code`) |
108
+ | `install_url` | script | URL of the install script that will be downloaded and piped to `bash` |
109
+ | `install_sha256` | script | SHA-256 of the install script body — required for verified installs |
110
+ | `install_script_path_prepend` | script | Extra directories prepended to `PATH` when the install script runs (e.g. `["~/.local/bin"]`) |
111
+ | `download_url_template` | direct | URL template with `{version}`, `{os}`, `{arch}` placeholders |
112
+ | `install_dir` | direct | Directory to extract into; supports `{version}` |
113
+ | `bin_dir` | direct | Directory where symlinks for `command` are created (e.g. `~/.local/bin`) |
114
+ | `symlinks` | direct | Map of `link_name` relative path inside `install_dir` to symlink into `bin_dir` |
115
+ | `freebsd_port` | FreeBSD | FreeBSD ports/pkg name (used when running on FreeBSD) |
116
+ | `freebsd_pkg_repo` | FreeBSD | Optional non-default pkg repository name (passed via `pkg install -r <repo>`) |
117
+ | `next_steps` | No | Free-form text printed after a successful install |
118
+ | `docs_url` | No | Documentation URL printed after install |
119
+ | `self_updates` | No | Tool updates itself when run; excludes it from managed upgrade actions |
112
120
 
113
121
  ## Features
114
122
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "code-aide"
3
3
  dynamic = ["version"]
4
- description = "Manage AI coding CLI tools (Claude, Copilot, Cursor, Gemini, Amp, Codex)"
4
+ description = "Manage AI coding CLI tools (Claude, Antigravity, Copilot, Cursor, Gemini, Amp, Codex)"
5
5
  readme = "README.md"
6
6
  authors = [
7
7
  { name = "Dave Beckett" },
@@ -0,0 +1,239 @@
1
+ #!/bin/bash
2
+ #
3
+ # Antigravity CLI - Unix Bootstrapper Script (Bash/Zsh/Fish)
4
+ #
5
+ # Downloads, staging-verifies, and installs the Antigravity CLI flat native build.
6
+ #
7
+
8
+ set -euo pipefail
9
+
10
+ # 1. Default Setup & Constants
11
+ DOWNLOAD_BASE_URL="https://antigravity-cli-auto-updater-974169037036.us-central1.run.app"
12
+ TARGET_DIR="$HOME/.local/bin"
13
+ CUSTOM_DIR=""
14
+
15
+ # Helper: Display usage instructions
16
+ show_usage() {
17
+ echo "Usage: install.sh [options]"
18
+ echo ""
19
+ echo "Options:"
20
+ echo " -d, --dir <path> Specify a custom directory to install the binary"
21
+ echo " -h, --help Display this help menu"
22
+ echo ""
23
+ }
24
+
25
+ # Parse Arguments
26
+ while [ "$#" -gt 0 ]; do
27
+ case $1 in
28
+ -d|--dir)
29
+ if [ -z "${2:-}" ]; then
30
+ echo "[ERROR] Missing path for --dir parameter" >&2
31
+ exit 1
32
+ fi
33
+ CUSTOM_DIR="$2"
34
+ shift
35
+ ;;
36
+ -h|--help)
37
+ show_usage
38
+ exit 0
39
+ ;;
40
+ *)
41
+ echo "[ERROR] Unknown parameter: $1" >&2
42
+ show_usage
43
+ exit 1
44
+ ;;
45
+ esac
46
+ shift
47
+ done
48
+
49
+ # Resolve dynamic installation target directory
50
+ if [ -n "$CUSTOM_DIR" ]; then
51
+ TARGET_DIR="$CUSTOM_DIR"
52
+ fi
53
+
54
+ BINARY_PATH="$TARGET_DIR/agy"
55
+
56
+ # 2. STEP 1: Pre-existence & Dynamic Path Check
57
+ if [ -f "$BINARY_PATH" ]; then
58
+ echo "Notice: 'agy' is already installed at $BINARY_PATH."
59
+ echo "The Antigravity CLI automatically self-updates in the background during regular runs."
60
+ echo ""
61
+ echo "If you want to perform a fresh installation, delete the binary first:"
62
+ echo " rm \"$BINARY_PATH\""
63
+ exit 0
64
+ fi
65
+
66
+ echo "⠋ Detecting system environment..."
67
+
68
+ # 3. Detect Platform
69
+ case "$(uname -s)" in
70
+ Darwin) os="darwin" ;;
71
+ Linux) os="linux" ;;
72
+ *) echo "Fatal: Unsupported operating system: $(uname -s). Antigravity CLI currently supports 64-bit Windows, macOS, and Linux." >&2; exit 1 ;;
73
+ esac
74
+
75
+ case "$(uname -m)" in
76
+ x86_64|amd64) arch="amd64" ;;
77
+ arm64|aarch64) arch="arm64" ;;
78
+ *) echo "Fatal: Unsupported architecture: $(uname -m). Antigravity CLI currently supports 64-bit Windows, macOS, and Linux." >&2; exit 1 ;;
79
+ esac
80
+
81
+ # musl libc detection on Linux
82
+ platform=""
83
+ if [ "$os" = "linux" ]; then
84
+ if [ -f /lib/libc.musl-x86_64.so.1 ] || [ -f /lib/libc.musl-aarch64.so.1 ] || ldd /bin/ls 2>&1 | grep -q musl; then
85
+ platform="linux_${arch}_musl"
86
+ else
87
+ platform="linux_${arch}"
88
+ fi
89
+ else
90
+ platform="${os}_${arch}"
91
+ fi
92
+
93
+ echo "✓ Platform detected: $platform"
94
+
95
+ # 4. Manifest Query & JSON Parsing (POSIX-Compliant)
96
+ echo "⠋ Querying release repository..."
97
+
98
+ # Construct Platform JSON Manifest URL
99
+ MANIFEST_URL="$DOWNLOAD_BASE_URL/manifests/$platform.json"
100
+
101
+ DOWNLOADER=""
102
+ if command -v curl >/dev/null 2>&1; then
103
+ DOWNLOADER="curl"
104
+ elif command -v wget >/dev/null 2>&1; then
105
+ DOWNLOADER="wget"
106
+ else
107
+ echo "Fatal: Either curl or wget is required but neither is installed." >&2
108
+ exit 1
109
+ fi
110
+
111
+ fetch_manifest() {
112
+ if [ "$DOWNLOADER" = "curl" ]; then
113
+ curl -fsSL "$1"
114
+ else
115
+ wget -q -O - "$1"
116
+ fi
117
+ }
118
+
119
+ manifest_json=$(fetch_manifest "$MANIFEST_URL" 2>/dev/null || true)
120
+ if [ -z "$manifest_json" ]; then
121
+ echo "Fatal: Could not connect to the release server to download the manifest. Please check your internet connection or firewall settings." >&2
122
+ exit 1
123
+ fi
124
+
125
+ # POSIX-compliant JSON parser (no jq or grep -o dependencies)
126
+ parse_json_key() {
127
+ local payload="$1"
128
+ local key="$2"
129
+ echo "$payload" | sed -n 's/.*"'"$key"'"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p'
130
+ }
131
+
132
+ version=$(parse_json_key "$manifest_json" "version")
133
+ url=$(parse_json_key "$manifest_json" "url")
134
+ sha512=$(parse_json_key "$manifest_json" "sha512")
135
+
136
+ if [ -z "$url" ] || [ -z "$sha512" ]; then
137
+ echo "Fatal: Failed to parse release manifest. The manifest may be corrupted or malformed." >&2
138
+ exit 1
139
+ fi
140
+
141
+ echo "✓ Latest available version: $version"
142
+
143
+ # 5. Download & SHA512 Checksum Verification
144
+ STAGING_DIR="$HOME/.cache/antigravity/staging"
145
+ if ! mkdir -p "$STAGING_DIR" 2>/dev/null; then
146
+ echo "Error: Failed to create staging directory at $STAGING_DIR. Please check your home directory write permissions." >&2
147
+ exit 1
148
+ fi
149
+
150
+ is_tar_gz=false
151
+ case "$url" in
152
+ *.tar.gz*) is_tar_gz=true ;;
153
+ esac
154
+
155
+ if [ "$is_tar_gz" = true ]; then
156
+ staging_payload="$STAGING_DIR/agy.tar.gz"
157
+ extracted_binary="$STAGING_DIR/antigravity"
158
+ else
159
+ staging_payload="$STAGING_DIR/agy"
160
+ extracted_binary="$staging_payload"
161
+ fi
162
+
163
+ # Robust cleanup trap to ensure staging files are reaped on any exit (success or failure)
164
+ cleanup() {
165
+ rm -f "${staging_payload:-}" "${extracted_binary:-}" 2>/dev/null || true
166
+ }
167
+ trap cleanup EXIT
168
+
169
+ download_file() {
170
+ local src="$1"
171
+ local dst="$2"
172
+ if [ "$DOWNLOADER" = "curl" ]; then
173
+ curl -fsSL -o "$dst" "$src"
174
+ else
175
+ wget -q -O "$dst" "$src"
176
+ fi
177
+ }
178
+
179
+ echo "⠋ Downloading release package..."
180
+ if ! download_file "$url" "$staging_payload"; then
181
+ echo "Fatal: Failed to download release package from $url. Please check your internet connection or firewall settings." >&2
182
+ exit 1
183
+ fi
184
+
185
+ # Compute OS-Specific SHA512 Checksum
186
+ actual_hash=""
187
+ if [ "$os" = "darwin" ]; then
188
+ actual_hash=$(shasum -a 512 "$staging_payload" | cut -d' ' -f1 || true)
189
+ else
190
+ actual_hash=$(sha512sum "$staging_payload" | cut -d' ' -f1 || true)
191
+ fi
192
+
193
+ if [ "$actual_hash" != "$sha512" ]; then
194
+ echo "Security Halt: The downloaded payload checksum does not match the manifest. The file may be corrupted or compromised. Installation aborted." >&2
195
+ exit 1
196
+ fi
197
+ echo "✓ Download complete and checksum verified."
198
+
199
+ # 6. Direct Binary Extraction & Write Permission Validation
200
+ if ! mkdir -p "$TARGET_DIR" 2>/dev/null; then
201
+ echo "Write Error: Permission denied when attempting to create $TARGET_DIR. Please re-run the installer using the '--dir' flag to specify a writable custom directory." >&2
202
+ exit 1
203
+ fi
204
+
205
+ if [ "$is_tar_gz" = true ]; then
206
+ echo "⠋ Extracting binary from archive..."
207
+ if ! tar -xzf "$staging_payload" -C "$STAGING_DIR" antigravity 2>/dev/null; then
208
+ echo "Extraction Error: Failed to extract binary from archive." >&2
209
+ exit 1
210
+ fi
211
+ else
212
+ echo "⠋ Copying binary directly to destination..."
213
+ fi
214
+
215
+ if ! cp "$extracted_binary" "$BINARY_PATH" 2>/dev/null; then
216
+ echo "Write Error: Permission denied when attempting to write binary to $BINARY_PATH. Please re-run the installer using the '--dir' flag to specify a writable custom directory." >&2
217
+ exit 1
218
+ fi
219
+
220
+ # Ensure Executable Permission Bit (soft fallback if filesystem doesn't support chmod)
221
+ chmod +x "$BINARY_PATH" || echo "Warning: Could not set executable permission bit on $BINARY_PATH. You may need to ensure the partition supports execution." >&2
222
+
223
+ # Clear macOS Gatekeeper Quarantine attribute to prevent unidentified developer blocks
224
+ if [ "$os" = "darwin" ]; then
225
+ xattr -d com.apple.quarantine "$BINARY_PATH" 2>/dev/null || true
226
+ fi
227
+
228
+ # 7. Native Setup Handoff (Go-Native Setup Trigger - POSIX /bin/sh Compliant)
229
+ echo "⠋ Configuring shell environment..."
230
+
231
+ if [ -n "$CUSTOM_DIR" ]; then
232
+ # Run with custom directory and absorb non-fatal soft warning exits
233
+ "$BINARY_PATH" install --dir "$CUSTOM_DIR" || true
234
+ else
235
+ # Run standard configuration and absorb non-fatal soft warning exits
236
+ "$BINARY_PATH" install || true
237
+ fi
238
+
239
+
@@ -0,0 +1,35 @@
1
+ # Add Antigravity CLI support
2
+
3
+ ## Context
4
+
5
+ Google transitioned consumer Gemini CLI access to Antigravity CLI on June 18,
6
+ 2026. Gemini CLI remains valid for enterprise, Google Cloud, and supported API
7
+ key authentication, so code-aide must manage the two commands separately and
8
+ must not remove or migrate existing Gemini installations.
9
+
10
+ ## Design
11
+
12
+ - Add Antigravity as the default tool key `antigravity`, using command `agy`.
13
+ - Accept `agy` as a command-line alias for the canonical `antigravity` key.
14
+ - Install it through Google's native script and verify the archived script's
15
+ SHA-256 before execution.
16
+ - Query the installer's official platform manifest and read its `version` field
17
+ when refreshing the latest-version cache.
18
+ - Record that `agy` uses its native background self-updater, so code-aide does
19
+ not repeatedly invoke an installer that intentionally exits when the binary
20
+ already exists.
21
+ - Keep Gemini CLI available as an opt-in npm tool with updated authentication
22
+ guidance.
23
+ - Do not infer a user's Google subscription or automatically migrate Gemini.
24
+
25
+ The manifest URL uses `{platform}` values such as `darwin_arm64` and
26
+ `linux_amd64`. The formatter supports the macOS and Linux architectures that the
27
+ upstream Unix installer supports.
28
+
29
+ ## Verification
30
+
31
+ 1. Confirm the archived installer exactly matches the configured SHA-256.
32
+ 2. Test manifest URL formatting and JSON version extraction.
33
+ 3. Run `uv run pytest` and `pre-commit run --all-files`.
34
+ 4. Dry-run `code-aide update-versions` and confirm Antigravity reports the
35
+ manifest version.
@@ -1,3 +1,3 @@
1
1
  """code-aide - Manage AI coding CLI tools."""
2
2
 
3
- __version__ = "1.15.6"
3
+ __version__ = "1.16.0"
@@ -37,6 +37,7 @@ from code_aide.config import (
37
37
  load_bundled_tools,
38
38
  load_versions_cache,
39
39
  merge_cached_versions,
40
+ resolve_tool_names,
40
41
  save_updated_versions,
41
42
  )
42
43
 
@@ -65,6 +66,7 @@ def cmd_install(args: argparse.Namespace) -> None:
65
66
  f"{', '.join(tools_to_install)}"
66
67
  )
67
68
 
69
+ tools_to_install = resolve_tool_names(tools_to_install, TOOLS)
68
70
  validate_tools(tools_to_install)
69
71
 
70
72
  if not dryrun:
@@ -73,6 +75,7 @@ def cmd_install(args: argparse.Namespace) -> None:
73
75
  )
74
76
 
75
77
  installed = []
78
+ installed_bin_dirs = []
76
79
  failed = []
77
80
 
78
81
  for tool in tools_to_install:
@@ -82,8 +85,10 @@ def cmd_install(args: argparse.Namespace) -> None:
82
85
  else:
83
86
  info(f"=== Installing {tool} ===")
84
87
 
85
- if install_tool(tool, dryrun=dryrun):
88
+ outcome = install_tool(tool, dryrun=dryrun)
89
+ if outcome:
86
90
  installed.append(tool)
91
+ installed_bin_dirs.extend(outcome.bin_dirs)
87
92
  else:
88
93
  failed.append(tool)
89
94
 
@@ -120,7 +125,7 @@ def cmd_install(args: argparse.Namespace) -> None:
120
125
  print(f" {tool_config['next_steps']}")
121
126
 
122
127
  print()
123
- check_path_directories(installed)
128
+ check_path_directories(installed_bin_dirs)
124
129
  success("All installations completed successfully!")
125
130
 
126
131
 
@@ -141,6 +146,7 @@ def cmd_upgrade(args: argparse.Namespace) -> None:
141
146
  info("All installed tools are up to date")
142
147
  return
143
148
 
149
+ tools_to_upgrade = resolve_tool_names(tools_to_upgrade, TOOLS)
144
150
  validate_tools(tools_to_upgrade)
145
151
 
146
152
  updated = []
@@ -201,6 +207,7 @@ def cmd_remove(args: argparse.Namespace) -> None:
201
207
  tools_to_remove = list(TOOLS.keys())
202
208
  info(f"No tools specified, removing all: {', '.join(tools_to_remove)}")
203
209
 
210
+ tools_to_remove = resolve_tool_names(tools_to_remove, TOOLS)
204
211
  validate_tools(tools_to_remove)
205
212
 
206
213
  removed = []
@@ -250,12 +257,12 @@ def cmd_update_versions(args: argparse.Namespace) -> None:
250
257
  config: Dict[str, Any] = {"tools": tools}
251
258
 
252
259
  if args.tools:
253
- invalid = [tool for tool in args.tools if tool not in tools]
260
+ tool_names = resolve_tool_names(args.tools, tools)
261
+ invalid = [tool for tool in tool_names if tool not in tools]
254
262
  if invalid:
255
263
  error(f"Unknown tool(s): {', '.join(invalid)}")
256
264
  print(f"Available: {', '.join(tools.keys())}", file=sys.stderr)
257
265
  sys.exit(1)
258
- tool_names = args.tools
259
266
  else:
260
267
  tool_names = list(tools.keys())
261
268
 
@@ -118,6 +118,23 @@ def load_tools_config() -> dict:
118
118
  return tools
119
119
 
120
120
 
121
+ def resolve_tool_names(
122
+ names: list[str], tools: Mapping[str, Dict[str, Any]]
123
+ ) -> list[str]:
124
+ """Resolve configured aliases to canonical tool names, preserving order."""
125
+ aliases = {
126
+ alias: tool_name
127
+ for tool_name, tool_config in tools.items()
128
+ for alias in tool_config.get("aliases", [])
129
+ }
130
+ resolved = []
131
+ for name in names:
132
+ canonical = aliases.get(name, name)
133
+ if canonical not in resolved:
134
+ resolved.append(canonical)
135
+ return resolved
136
+
137
+
121
138
  def save_updated_versions(tools: Mapping[str, Dict[str, Any]]) -> None:
122
139
  """Save only dynamic version fields to the user's cache.
123
140
 
@@ -158,7 +175,10 @@ def versions_cache_is_fresh(tools: Mapping[str, Dict[str, Any]]) -> bool:
158
175
  if not tool_config.get("latest_version"):
159
176
  return False
160
177
  elif install_type in (InstallType.SCRIPT, InstallType.DIRECT_DOWNLOAD):
161
- if tool_config.get("version_url") and not tool_config.get("latest_version"):
178
+ has_version_source = tool_config.get("version_url") or tool_config.get(
179
+ "version_manifest_url_template"
180
+ )
181
+ if has_version_source and not tool_config.get("latest_version"):
162
182
  return False
163
183
  return True
164
184