cdx-manager 0.25.5 → 0.25.6
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.
- package/README.md +1 -1
- package/VERSION +1 -1
- package/changelogs/CHANGELOGS_0_25_6.md +15 -0
- package/changelogs/CHANGELOGS_UNRELEASED.md +3 -0
- package/checksums/release-archives.json +11 -0
- package/docs/cli.md +19 -5
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/commands/maintenance.py +2 -1
- package/src/update_all.py +29 -5
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<br clear="left"/>
|
|
6
6
|
|
|
7
|
-
[](LICENSE) ](LICENSE)  
|
|
8
8
|
|
|
9
9
|
**The right AI coding account, when you need it.** CDX Manager keeps your Codex and Claude accounts in separate profiles, shows which ones have quota, and helps you pick the next usable session from your terminal.
|
|
10
10
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.25.
|
|
1
|
+
0.25.6
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# CDX Manager 0.25.6
|
|
2
|
+
|
|
3
|
+
Release date: 2026-11-02
|
|
4
|
+
|
|
5
|
+
This patch release fixes provider update detection and verifies installed versions after updates.
|
|
6
|
+
|
|
7
|
+
## Fixes
|
|
8
|
+
|
|
9
|
+
- Detect advertised provider updaters and version output on both stdout and stderr. After an update, verify the installed version and report failure if it is missing, unchanged, downgraded, or still below the published version. Successful text output shows the version transition, and JSON results include before, after, and latest versions. (#87)
|
|
10
|
+
- Fall back to the latest stable GitHub release when Ollama's vendor API returns an empty, invalid, or failed response. Keep Linux Ollama updates manual, with an explicit maintenance reason. (#87)
|
|
11
|
+
|
|
12
|
+
## Maintenance
|
|
13
|
+
|
|
14
|
+
- Record tray companion checksums for v0.25.5. (`b64a372f9ab4abb61f1440943fca19703ad555eb`)
|
|
15
|
+
- Record release archive checksums for v0.25.5. (`1218145eae4201e40b8140e7a94cbcec18454e17`)
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Truthful workstation updates
|
|
4
4
|
|
|
5
|
+
- Detect native updater subcommands in both stdout and stderr, including Antigravity's indented `Available subcommands:` help. Verify the installed CLI version after updating, fail unchanged or unverified updates, and expose before/after versions without hiding major upgrades.
|
|
6
|
+
- Fall back from empty or failed Ollama vendor responses (including Linux HTTP 204) to the latest stable `ollama/ollama` GitHub release. Keep Linux updates manual with `update_available`, a null command, and a service-safety reason; never replace a potentially active binary or restart models automatically.
|
|
7
|
+
|
|
5
8
|
- Verify latest versions from npm, RTK GitHub releases, and Antigravity/Ollama vendor update endpoints with short read-only probes. Report `unknown` on unavailable evidence; reserve `up_to_date` for identical known versions, including Ponytail revisions.
|
|
6
9
|
- Preserve the existing JSON fields and `update_available` status, show uncertainty and manual-update reasons in text, and apply only supported native commands or verified Homebrew package upgrades. Cover matching/outdated versions, source failures, missing tools, and command execution with faked sources.
|
|
7
10
|
|
|
@@ -738,6 +738,17 @@
|
|
|
738
738
|
"x86_64-pc-windows-msvc": "8e2c1925f025a7227ef909f27e8b4696c03bb5a86e0c61c989da6a942b5638a6",
|
|
739
739
|
"x86_64-unknown-linux-musl": "9ae1164abc3ff4b30d25c44696569855138f8ac0e3b6e1c3451c716d20f221fa"
|
|
740
740
|
}
|
|
741
|
+
},
|
|
742
|
+
"v0.25.5": {
|
|
743
|
+
"github_tarball_sha256": "4a2ece21e32f59a84d8bc7b2a565817c6c90bb314f179319bc19cf85a0c71a60",
|
|
744
|
+
"github_zip_sha256": "959de4dca501fd53c937f4045936b12acbea58d255a4e3cae510ec82a230bef8",
|
|
745
|
+
"tray_assets": {
|
|
746
|
+
"aarch64-apple-darwin": "727c4ded1ee4d9d8ed9853badcb10efd1cc76bd6dcd6012b6739920d42e6273c",
|
|
747
|
+
"aarch64-unknown-linux-musl": "9270224db6be83d4a4787f9b523a6fa059267f56ed1cf12f022f65bf68c0474f",
|
|
748
|
+
"x86_64-apple-darwin": "10c555671cdeb3ce4c0372f6f8a48e6cfeac9132e980c466fe5a8978dc1a2862",
|
|
749
|
+
"x86_64-pc-windows-msvc": "85945b30580cb82c64ece94652ae0633a6156dfd85e02108c0d4b7676cab9911",
|
|
750
|
+
"x86_64-unknown-linux-musl": "7c5a23938b84c5952be71b5956ed3167c218d05ce661940b0c86f2dde2d8221f"
|
|
751
|
+
}
|
|
741
752
|
}
|
|
742
753
|
}
|
|
743
754
|
}
|
package/docs/cli.md
CHANGED
|
@@ -567,19 +567,33 @@ an installed server, not the latest published release, and is not used.
|
|
|
567
567
|
Antigravity Hub and IDE 2 have separate feeds and are not substituted for `agy`.
|
|
568
568
|
HTTP and read-only CLI probes have a five-second timeout; source failures leave
|
|
569
569
|
`latest_version: null` and `status: unknown`. Ponytail also reports `unknown`
|
|
570
|
-
when its remote revision is unavailable. An empty
|
|
571
|
-
HTTP 204
|
|
572
|
-
|
|
570
|
+
when its remote revision is unavailable. An empty, failed, or invalid Ollama
|
|
571
|
+
response (including Linux HTTP 204) falls back to the latest stable GitHub
|
|
572
|
+
release for `ollama/ollama`. If that source also fails, status is `unknown`;
|
|
573
|
+
a different platform's vendor response is never substituted.
|
|
573
574
|
|
|
574
575
|
For an outdated tool, CDX uses a native update command advertised by its
|
|
575
|
-
`--help` (including Claude
|
|
576
|
+
`--help` on either stdout or stderr (including Claude, Antigravity, and RTK
|
|
577
|
+
when available), Codex's updater,
|
|
576
578
|
or Homebrew only when the resolved executable belongs to a Caskroom/Cellar
|
|
577
579
|
package. An outdated tool without such a path retains `update_available`,
|
|
578
580
|
`update_command: null`, and a human-readable `reason`; it requires the vendor's
|
|
579
|
-
manual update mechanism.
|
|
581
|
+
manual update mechanism. On Linux, Ollama always retains `update_available`
|
|
582
|
+
with `update_command: null` and an explicit maintenance reason: its installer
|
|
583
|
+
writes system paths and may restart a service. A binary in `~/.local/bin` can
|
|
584
|
+
also serve running models, so CDX neither replaces it nor restarts services.
|
|
585
|
+
Arrange a manual maintenance window. Source uncertainty never schedules a guessed install.
|
|
580
586
|
The text table shows `UNKNOWN` and the reason, and an empty action list makes
|
|
581
587
|
no claim that all tools are current. JSON consumers, including external
|
|
582
588
|
remote-ops auto-update scripts, should inspect statuses separately from successful
|
|
583
589
|
command execution: exit code zero means no attempted action failed, not that
|
|
584
590
|
every installed tool was verified current. With `--yes`, the returned plan is the
|
|
585
591
|
pre-update inventory; `results` records attempted actions and their exit codes.
|
|
592
|
+
|
|
593
|
+
After each successful tool update command, CDX probes the CLI version again.
|
|
594
|
+
An unchanged, unreadable, downgraded, or still older-than-published version
|
|
595
|
+
makes the action fail, even if the updater exited zero. Successful text output
|
|
596
|
+
shows the before/after versions, including major upgrades. JSON keeps the
|
|
597
|
+
pre-update plan and existing result fields; tool verification adds
|
|
598
|
+
`version_before`, `version_after`, and `latest_version` to successful-command
|
|
599
|
+
results, plus `reason` and a nonzero `returncode` if verification fails.
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -52,7 +52,8 @@ def _format_update_all_result(result, use_color=False):
|
|
|
52
52
|
if result.get("skipped"):
|
|
53
53
|
return _warn(f"skipped: {result['name']} (blocked by {result['blocked_by']})", use_color)
|
|
54
54
|
if result.get("returncode") == 0:
|
|
55
|
-
|
|
55
|
+
versions = f" ({result['version_before']} -> {result['version_after']})" if "version_after" in result else ""
|
|
56
|
+
return _success(f"done: {result['name']}{versions}", use_color)
|
|
56
57
|
detail = str(result.get("stderr") or result.get("stdout") or "No error output.").strip().replace("\n", " ")
|
|
57
58
|
detail = detail[-500:]
|
|
58
59
|
command = shlex.join(result.get("command") or [])
|
package/src/update_all.py
CHANGED
|
@@ -56,7 +56,7 @@ def _version(command, env, runner):
|
|
|
56
56
|
result = _run([command, "--version"], env, runner, timeout=_SOURCE_TIMEOUT)
|
|
57
57
|
if result["returncode"]:
|
|
58
58
|
return None
|
|
59
|
-
text = (result["stdout"] or result["stderr"] or "").strip()
|
|
59
|
+
text = "\n".join((result["stdout"] or "", result["stderr"] or "")).strip()
|
|
60
60
|
# Ollama can print the server version before the CLI version.
|
|
61
61
|
client = re.search(r"client version is (\S+)", text)
|
|
62
62
|
match = client or re.search(r"\b(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)\b", text)
|
|
@@ -85,9 +85,19 @@ def _latest_version(name):
|
|
|
85
85
|
if name == PROVIDER_OLLAMA:
|
|
86
86
|
arch = {"x86_64": "amd64", "aarch64": "arm64"}.get(platform.machine().lower(), platform.machine().lower())
|
|
87
87
|
query = urlencode({"os": platform.system().lower(), "arch": arch, "version": "0.0.0"})
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
try:
|
|
89
|
+
release = _fetch_json(f"https://ollama.com/api/update?{query}")
|
|
90
|
+
# The vendor updater extracts the release tag from the artifact URL.
|
|
91
|
+
version = _parse_version(os.path.basename(os.path.dirname(urlparse(release["url"]).path)))
|
|
92
|
+
if version:
|
|
93
|
+
return version
|
|
94
|
+
except Exception:
|
|
95
|
+
# Linux can return HTTP 204 with no JSON body.
|
|
96
|
+
pass
|
|
97
|
+
release = _fetch_json("https://api.github.com/repos/ollama/ollama/releases/latest")
|
|
98
|
+
if release.get("draft") or release.get("prerelease"):
|
|
99
|
+
return None
|
|
100
|
+
return _parse_version(release["tag_name"])
|
|
91
101
|
except Exception:
|
|
92
102
|
# A failed or changed source is uncertainty, never evidence of currency.
|
|
93
103
|
return None
|
|
@@ -101,6 +111,8 @@ def _newer(latest, current):
|
|
|
101
111
|
|
|
102
112
|
|
|
103
113
|
def _native_update_command(name, command, path, env, runner):
|
|
114
|
+
if name == PROVIDER_OLLAMA and platform.system().lower() == "linux":
|
|
115
|
+
return None
|
|
104
116
|
real_path = os.path.realpath(path)
|
|
105
117
|
cask = re.search(r"/Caskroom/([^/]+)/", real_path)
|
|
106
118
|
formula = re.search(r"/Cellar/([^/]+)/", real_path)
|
|
@@ -111,7 +123,7 @@ def _native_update_command(name, command, path, env, runner):
|
|
|
111
123
|
return [command, "update"]
|
|
112
124
|
help_result = _run([command, "--help"], env, runner, timeout=_SOURCE_TIMEOUT)
|
|
113
125
|
if help_result["returncode"] == 0:
|
|
114
|
-
help_text = help_result["stdout"]
|
|
126
|
+
help_text = "\n".join((help_result["stdout"] or "", help_result["stderr"] or ""))
|
|
115
127
|
for subcommand in ("self-update", "update", "--update"):
|
|
116
128
|
if re.search(r"(?m)^\s*" + re.escape(subcommand) + r"(?:\s|$)", help_text):
|
|
117
129
|
return [command, subcommand]
|
|
@@ -153,6 +165,9 @@ def collect_update_all_plan(service, env=None, runner=None):
|
|
|
153
165
|
steps.append({"name": name, "command": item["update_command"], "env": {}})
|
|
154
166
|
else:
|
|
155
167
|
item["reason"] = "No supported CLI updater or verified Homebrew installation; use the vendor's updater manually."
|
|
168
|
+
if name == PROVIDER_OLLAMA and platform.system().lower() == "linux":
|
|
169
|
+
item["reason"] = ("No supported safe automatic Linux update: Ollama's installer writes system paths and may restart a service. "
|
|
170
|
+
"Even a user-local binary may serve running models; arrange a manual maintenance window.")
|
|
156
171
|
else:
|
|
157
172
|
item["status"] = "unknown"
|
|
158
173
|
item["reason"] = "Latest version unavailable from the official source." if not latest else "Installed version unavailable or does not match the published release."
|
|
@@ -214,6 +229,15 @@ def apply_update_all_plan(plan, service, env=None, runner=None, progress=None):
|
|
|
214
229
|
continue
|
|
215
230
|
result = _run(step["command"], {**env, **step.get("env", {})}, runner, timeout=120)
|
|
216
231
|
result = {"name": step["name"], "command": step["command"], **result}
|
|
232
|
+
item = next((item for item in plan.get("items", []) if item["name"] == step["name"]), None)
|
|
233
|
+
if result["returncode"] == 0 and item:
|
|
234
|
+
after = _version(item["command"], env, runner)
|
|
235
|
+
result.update(version_before=item["version"], version_after=after, latest_version=item["latest_version"])
|
|
236
|
+
if not (_newer(after, item["version"]) and
|
|
237
|
+
(after == item["latest_version"] or _newer(after, item["latest_version"]))):
|
|
238
|
+
result["returncode"] = 1
|
|
239
|
+
result["reason"] = "Update verification failed: installed version did not advance to the published release."
|
|
240
|
+
result["stderr"] = (result["stderr"] + "\n" + result["reason"]).strip()
|
|
217
241
|
results.append(result)
|
|
218
242
|
if result["returncode"] == 0 and step.get("id"):
|
|
219
243
|
completed.add(step["id"])
|