cdx-manager 0.21.1 → 0.21.3
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_21_2.md +9 -0
- package/changelogs/CHANGELOGS_0_21_3.md +5 -0
- package/checksums/release-archives.json +22 -0
- package/docs/operations.md +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/claude_usage.py +41 -25
- package/src/session_service.py +4 -3
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.21.
|
|
1
|
+
0.21.3
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# CDX Manager 0.21.2
|
|
2
|
+
|
|
3
|
+
## Fixes
|
|
4
|
+
|
|
5
|
+
- Keep the tray companion visible to CDX on long runs: macOS purges per-user temp files untouched for about three days, which removed the companion's instance lock. CDX then saw no tray, so an update replaced the binary without stopping the old process and `cdx tray launch` could not start a new one. The companion now restores its lock within a minute when it disappears.
|
|
6
|
+
|
|
7
|
+
## Release process
|
|
8
|
+
|
|
9
|
+
- GitHub release titles are exactly their tag (`vX.Y.Z`); the checksum workflow now enforces it on publish.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# CDX Manager 0.21.3
|
|
2
|
+
|
|
3
|
+
## Fixes
|
|
4
|
+
|
|
5
|
+
- Claude in Chrome now works from CDX Claude profiles (`claude --chrome`, `/chrome`, or `cdx set <name> --extra-args '--chrome'`). Profile isolation redirects HOME, so Claude Code looked for Chrome and its Claude extension inside the profile home, found neither, and never installed its native-messaging host where Chrome reads it. CDX now links the real Chrome directory into each Claude profile home, as it already did for the macOS keychain: `~/Library/Application Support/Google/Chrome` on macOS, `~/.config/google-chrome` on Linux. Windows needed no change: Chrome lives under `%LOCALAPPDATA%` and the host is registered in the registry, neither of which CDX redirects. Profile copies keep the link as a link and never copy the Chrome profile itself.
|
|
@@ -485,6 +485,28 @@
|
|
|
485
485
|
"x86_64-pc-windows-msvc": "20af5c24d62b673458c1ad7245df58d3cadb0be27116338fa39f66f896cd3d9f",
|
|
486
486
|
"x86_64-unknown-linux-musl": "4f7bc612c378a6e746a5bd737f89763ddaea0398182b49df28a9954e955fcd63"
|
|
487
487
|
}
|
|
488
|
+
},
|
|
489
|
+
"v0.21.1": {
|
|
490
|
+
"github_tarball_sha256": "be99bab2b7b0e86a36db8f891881fdc940631ca7f5b08e9402f1f6d44b614c56",
|
|
491
|
+
"github_zip_sha256": "06114c024b75125a081c0ca19d794604f259bf1ca9a5e2b8030218d3e58a926e",
|
|
492
|
+
"tray_assets": {
|
|
493
|
+
"aarch64-apple-darwin": "80df87fb4f8ed6ecddb5c8719d7f9a18a0dfb46625ea9f6137efe0b5a2cfe7bd",
|
|
494
|
+
"aarch64-unknown-linux-musl": "3c6b81b39f0abec33309835873f62c7fef37d4b3ddd30a2670081f5e930803c3",
|
|
495
|
+
"x86_64-apple-darwin": "dd087d256e54aad2a0781b7b98e21a416ba7b14f92344413959d7a26c8a81468",
|
|
496
|
+
"x86_64-pc-windows-msvc": "c316d753c055be48d74e23537ca66093a1a7c36df8fb8518d6b909484ccb9415",
|
|
497
|
+
"x86_64-unknown-linux-musl": "f5a034ba301ecf10de33498cd99f00fa3aa6afda94d7c743390af05f4f718790"
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
"v0.21.2": {
|
|
501
|
+
"github_tarball_sha256": "b6225a95b590cc931988260597b870edbff00b3175f5c8091a0e23503d408e5e",
|
|
502
|
+
"github_zip_sha256": "b0714ed222e17ae9bdd658c37b6ba32b9026ddddfb4d20794783b2203f4ccc88",
|
|
503
|
+
"tray_assets": {
|
|
504
|
+
"aarch64-apple-darwin": "c4b8938b62fad445351938f79e0cd42d5342a530e88eeb0f52c51e2fe77e3391",
|
|
505
|
+
"aarch64-unknown-linux-musl": "6f9c959e4a17a39c3d548b48afe326ca2d68bee0e298f532c4880d080d41eb20",
|
|
506
|
+
"x86_64-apple-darwin": "f41652aa24d27e2e4deef566cd66c11fc7cb3b5155dc8d5a917433a3e172d33b",
|
|
507
|
+
"x86_64-pc-windows-msvc": "856f9dc459182adb10f66f2836abc862be82feff1cc3f1cf859764336487d781",
|
|
508
|
+
"x86_64-unknown-linux-musl": "f1832fdbe7114b4625da21d6a3a0f0c100f18d3a441796e809e568620e4cd345"
|
|
509
|
+
}
|
|
488
510
|
}
|
|
489
511
|
}
|
|
490
512
|
}
|
package/docs/operations.md
CHANGED
|
@@ -29,7 +29,7 @@ Notes:
|
|
|
29
29
|
|
|
30
30
|
## Release checklist
|
|
31
31
|
|
|
32
|
-
- Name the GitHub Release
|
|
32
|
+
- Name the GitHub Release exactly as its tag, `vX.Y.Z` (for example, `v0.21.1`); use the checked-in versioned changelog for its notes.
|
|
33
33
|
- Before publishing npm or PyPI packages, run `npm run release:validate`.
|
|
34
34
|
- The release tag must match `package.json`, `pyproject.toml`, `src/cli.py`, and `VERSION`.
|
|
35
35
|
- `checksums/release-archives.json` must include the matching `vX.Y.Z` entry with both `github_tarball_sha256` and `github_zip_sha256`.
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
package/src/claude_usage.py
CHANGED
|
@@ -117,36 +117,52 @@ def claude_profile_store_dir(auth_home):
|
|
|
117
117
|
return os.path.join(auth_home, "credentials")
|
|
118
118
|
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
120
|
+
# Real-home directories a redirected profile home must still reach on macOS.
|
|
121
|
+
# Keychains: the login keychain (else a "Keychain Not Found" dialog on every launch).
|
|
122
|
+
# Chrome: Claude in Chrome looks for its extension and installs its native-messaging
|
|
123
|
+
# host under $HOME/Library/Application Support/Google/Chrome; without the link,
|
|
124
|
+
# `claude --chrome` sees no extension and Chrome never finds the host.
|
|
125
|
+
# Linux keeps Chrome under ~/.config (XDG), also resolved from HOME. Windows needs
|
|
126
|
+
# nothing: the host is registered in the registry and Chrome lives in
|
|
127
|
+
# %LOCALAPPDATA%, which profile isolation does not redirect.
|
|
128
|
+
_MACOS_SHARED_DIRS = (
|
|
129
|
+
("Library", "Keychains"),
|
|
130
|
+
("Library", "Application Support", "Google", "Chrome"),
|
|
131
|
+
)
|
|
132
|
+
_LINUX_SHARED_DIRS = ((".config", "google-chrome"),)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _link_real_home_dirs(auth_home):
|
|
136
|
+
"""Link the real-home directories in `_MACOS_SHARED_DIRS` (or `_LINUX_SHARED_DIRS`) into a redirected home.
|
|
137
|
+
|
|
138
|
+
Profile isolation redirects HOME (see `_home_env_overrides`), so these
|
|
139
|
+
paths do not exist in the profile home. A real directory already there is
|
|
140
|
+
left alone. Failure is non-fatal, and deliberately quiet: the profile
|
|
141
|
+
simply keeps working without that integration.
|
|
130
142
|
"""
|
|
131
|
-
if sys.platform
|
|
143
|
+
shared = _MACOS_SHARED_DIRS if sys.platform == "darwin" else _LINUX_SHARED_DIRS if sys.platform.startswith("linux") else ()
|
|
144
|
+
if not shared or pwd is None:
|
|
132
145
|
return
|
|
133
146
|
try:
|
|
134
147
|
real_home = pwd.getpwuid(os.getuid()).pw_dir
|
|
135
148
|
except (KeyError, OSError):
|
|
136
149
|
return
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
os.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
for parts in shared:
|
|
151
|
+
source = os.path.join(real_home, *parts)
|
|
152
|
+
if not os.path.isdir(source):
|
|
153
|
+
continue
|
|
154
|
+
link = os.path.join(auth_home, *parts)
|
|
155
|
+
if os.path.realpath(link) == os.path.realpath(source):
|
|
156
|
+
continue
|
|
157
|
+
if os.path.exists(link) and not os.path.islink(link):
|
|
158
|
+
continue
|
|
159
|
+
try:
|
|
160
|
+
os.makedirs(os.path.dirname(link), exist_ok=True)
|
|
161
|
+
if os.path.islink(link):
|
|
162
|
+
os.unlink(link)
|
|
163
|
+
os.symlink(source, link)
|
|
164
|
+
except OSError:
|
|
165
|
+
continue
|
|
150
166
|
|
|
151
167
|
|
|
152
168
|
def _secure_storage_overrides(auth_home):
|
|
@@ -167,7 +183,7 @@ def _secure_storage_overrides(auth_home):
|
|
|
167
183
|
the variable overrides that directory as well as naming the entry. Any
|
|
168
184
|
other value would also move where credentials are read from.
|
|
169
185
|
"""
|
|
170
|
-
|
|
186
|
+
_link_real_home_dirs(auth_home)
|
|
171
187
|
return {"CLAUDE_SECURESTORAGE_CONFIG_DIR": os.path.join(auth_home, ".claude")}
|
|
172
188
|
|
|
173
189
|
|
package/src/session_service.py
CHANGED
|
@@ -35,7 +35,7 @@ from contextlib import nullcontext
|
|
|
35
35
|
from functools import partial
|
|
36
36
|
|
|
37
37
|
from .claude_credentials import copy_keychain_credentials, delete_keychain_credentials
|
|
38
|
-
from .claude_usage import
|
|
38
|
+
from .claude_usage import _link_real_home_dirs
|
|
39
39
|
from .codex_usage import fetch_codex_rate_limits
|
|
40
40
|
from .config import (
|
|
41
41
|
MAX_LAUNCH_BUDGET_USD,
|
|
@@ -573,8 +573,9 @@ def copy_session(base_dir, store, source_name, dest_name):
|
|
|
573
573
|
with credential_copy:
|
|
574
574
|
if source["provider"] == PROVIDER_CLAUDE:
|
|
575
575
|
shutil.copytree(source_root, temp_root, symlinks=True,
|
|
576
|
-
ignore=lambda
|
|
577
|
-
|
|
576
|
+
ignore=lambda directory, names: [n for n in names if n == "Keychains" or (
|
|
577
|
+
n == "Chrome" and os.path.islink(os.path.join(directory, n)))])
|
|
578
|
+
_link_real_home_dirs(os.path.join(temp_root, "claude-home"))
|
|
578
579
|
else:
|
|
579
580
|
shutil.copytree(source_root, temp_root)
|
|
580
581
|
if existing:
|