cdx-manager 0.9.9 → 0.9.11

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # CDX Manager
2
2
 
3
- [![License](https://img.shields.io/badge/license-MIT-4C8BF5)](LICENSE) ![Version](https://img.shields.io/badge/version-v0.9.9-4C8BF5) ![Python](https://img.shields.io/badge/python-3.9%2B-3776AB?logo=python&logoColor=white)
3
+ [![License](https://img.shields.io/badge/license-MIT-4C8BF5)](LICENSE) ![Version](https://img.shields.io/badge/version-v0.9.11-4C8BF5) ![Python](https://img.shields.io/badge/python-3.9%2B-3776AB?logo=python&logoColor=white)
4
4
 
5
5
  **Run multiple Codex, Claude, Antigravity, and Ollama sessions from one terminal. Switch between accounts instantly.**
6
6
 
@@ -0,0 +1,33 @@
1
+ # CDX Manager 0.9.10
2
+
3
+ ## Highlights
4
+
5
+ - Clarified Claude status warnings when quota refresh fails but local Claude auth is still valid.
6
+
7
+ ## Changes
8
+
9
+ ### Claude status diagnostics
10
+
11
+ `cdx status` now distinguishes a Claude quota refresh failure from a local Claude login failure.
12
+
13
+ When Anthropic quota probing returns an invalid-credentials response while `claude auth status` still reports an authenticated session, the JSON warning keeps the existing `claude_refresh_failed` code for compatibility and adds:
14
+
15
+ - `auth_status: authenticated`
16
+ - `status_freshness: stale`
17
+ - a message explaining that cached quota values may be stale
18
+
19
+ The text-mode warning now says that local auth is still valid instead of implying that the Claude account itself is down.
20
+
21
+ Regression coverage verifies both the JSON payload and terminal warning for this mixed auth/quota-refresh state.
22
+
23
+ ## Validation
24
+
25
+ - `npm run release:validate`
26
+ - `npm run lint`
27
+ - `npm test`
28
+ - `logics-manager lint --require-status`
29
+ - `logics-manager audit`
30
+ - `git diff --check`
31
+ - `npm --cache /private/tmp/cdx-npm-cache pack --dry-run`
32
+ - `python -m build`
33
+ - `python -m twine check dist/*`
@@ -0,0 +1,44 @@
1
+ # CDX Manager 0.9.11
2
+
3
+ ## Highlights
4
+
5
+ - Hardened transcript cleanup so captured handoff logs strip ANSI and control-sequence noise before reuse.
6
+ - Broadened lint coverage with Ruff's bugbear rules and fixed the newly surfaced issues.
7
+ - Split the CLI facade into dedicated argument and helper modules, reducing the size of the main command surface without changing user-facing commands.
8
+
9
+ ## Changes
10
+
11
+ ### Transcript and status reliability
12
+
13
+ Script-captured transcripts now remove additional terminal control noise before they are parsed or copied into handoff context.
14
+
15
+ Status and session helper internals also gained focused validation coverage for merge behavior, malformed records, and rate-limit parsing.
16
+
17
+ ### CLI maintainability
18
+
19
+ The CLI command layer now reuses shared JSON, table, and parser helpers from extracted modules. The public CLI entrypoint remains stable, while tests can exercise smaller units directly.
20
+
21
+ Shared OAuth token cleanup and JWT decoding helpers were deduplicated into the Claude usage path so provider status code uses the same parsing behavior in one place.
22
+
23
+ ### Validation coverage
24
+
25
+ Ruff now checks a wider rule set, including bugbear rules, while keeping only deferred stylistic exceptions out of the release gate.
26
+
27
+ New regression tests cover:
28
+
29
+ - Codex rate-limit payload parsing
30
+ - provider launch argument construction
31
+ - session status merge and validation helpers
32
+ - handoff transcript control-sequence cleanup
33
+
34
+ ## Validation
35
+
36
+ - `npm run release:validate`
37
+ - `npm run lint`
38
+ - `npm test`
39
+ - `logics-manager lint --require-status`
40
+ - `logics-manager audit`
41
+ - `git diff --check`
42
+ - `npm --cache /private/tmp/cdx-npm-cache pack --dry-run`
43
+ - `python -m build`
44
+ - `python -m twine check dist/*`
@@ -100,6 +100,14 @@
100
100
  "v0.9.8": {
101
101
  "github_tarball_sha256": "8f05d052b7890d74de7ac510c20376430515ad2616e139941cb9bb8edc4fb680",
102
102
  "github_zip_sha256": "3bc3834ecf84784c77cf603fcd4f6f439e42005612f82fabab588886519179eb"
103
+ },
104
+ "v0.9.9": {
105
+ "github_tarball_sha256": "092c564803dd9a674250040ac308055de3701aa993237f257676403c24eb1318",
106
+ "github_zip_sha256": "0fbd8de7a97cde5aef14f23036def2e34dd690c2aa78ef93ddfeef0bb3e9547b"
107
+ },
108
+ "v0.9.10": {
109
+ "github_tarball_sha256": "4e876d3552eca1b441492a36606f2f0583bff9523801a923d834fe2a4da3c644",
110
+ "github_zip_sha256": "b6c9435f7e36558ac8698dbd6d6c4888e58c64a08d2b06c3bcbb45ce2cd25f7c"
103
111
  }
104
112
  }
105
113
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdx-manager",
3
- "version": "0.9.9",
3
+ "version": "0.9.11",
4
4
  "description": "Terminal session manager for Codex and Claude accounts.",
5
5
  "license": "MIT",
6
6
  "author": "Alexandre Agostini",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cdx-manager"
7
- version = "0.9.9"
7
+ version = "0.9.11"
8
8
  description = "Terminal session manager for Codex and Claude accounts."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -67,4 +67,7 @@ target-version = "py39"
67
67
  line-length = 140
68
68
 
69
69
  [tool.ruff.lint]
70
- select = ["E9", "F63", "F7", "F82"]
70
+ select = ["E", "F", "W", "I", "UP", "B"]
71
+ # Deferred / stylistic-only: E501 (140-col overflows), E741/E731 naming & lambda
72
+ # style. Not chasing these now; logic-catching rules (F, bugbear B) stay on.
73
+ ignore = ["E501", "E741", "E731"]
@@ -7,7 +7,6 @@ from datetime import datetime, timezone
7
7
 
8
8
  from .errors import CdxError
9
9
 
10
-
11
10
  BUNDLE_SCHEMA_VERSION = 1
12
11
  _SALT_BYTES = 16
13
12
  _NONCE_BYTES = 16
@@ -1,10 +1,11 @@
1
+ import base64
1
2
  import json
2
3
  import os
3
4
  import re
4
5
  import subprocess
5
6
  import sys
6
- import urllib.request
7
7
  import urllib.error
8
+ import urllib.request
8
9
  from datetime import datetime, timezone
9
10
 
10
11
  from .errors import CdxError
@@ -28,10 +29,25 @@ def _clean_oauth_token(token):
28
29
  return text
29
30
 
30
31
 
32
+ def _decode_jwt_claims(token):
33
+ if not token or "." not in str(token):
34
+ return {}
35
+ parts = str(token).split(".")
36
+ if len(parts) < 2:
37
+ return {}
38
+ payload = parts[1]
39
+ padding = "=" * (-len(payload) % 4)
40
+ try:
41
+ decoded = base64.urlsafe_b64decode(payload + padding)
42
+ return json.loads(decoded.decode("utf-8"))
43
+ except (ValueError, json.JSONDecodeError, UnicodeDecodeError):
44
+ return {}
45
+
46
+
31
47
  def _read_claude_credentials(auth_home):
32
48
  cred_path = os.path.join(auth_home, ".claude", ".credentials.json")
33
49
  try:
34
- with open(cred_path, "r", encoding="utf-8") as f:
50
+ with open(cred_path, encoding="utf-8") as f:
35
51
  data = json.load(f)
36
52
  creds = data.get("claudeAiOauth") if isinstance(data, dict) else None
37
53
  token = _clean_oauth_token(creds.get("accessToken")) if isinstance(creds, dict) else None
@@ -42,7 +58,7 @@ def _read_claude_credentials(auth_home):
42
58
 
43
59
  anthropic_cred_path = os.path.join(auth_home, "credentials", "default.json")
44
60
  try:
45
- with open(anthropic_cred_path, "r", encoding="utf-8") as f:
61
+ with open(anthropic_cred_path, encoding="utf-8") as f:
46
62
  data = json.load(f)
47
63
  token = _clean_oauth_token(data.get("access_token") if isinstance(data, dict) else None)
48
64
  if token:
package/src/cli.py CHANGED
@@ -8,38 +8,38 @@ from .cli_commands import (
8
8
  API_SCHEMA_VERSION,
9
9
  STATUS_USAGE,
10
10
  handle_add,
11
+ handle_can_resume,
11
12
  handle_clean,
12
13
  handle_config,
13
14
  handle_configs,
14
- handle_can_resume,
15
15
  handle_context,
16
16
  handle_copy,
17
- handle_doctor,
18
17
  handle_disable,
18
+ handle_doctor,
19
19
  handle_enable,
20
20
  handle_export,
21
- handle_import,
22
21
  handle_handoff,
23
22
  handle_history,
23
+ handle_import,
24
24
  handle_last,
25
25
  handle_launch,
26
+ handle_launch_setting_alias,
26
27
  handle_login,
27
28
  handle_logout,
28
- handle_launch_setting_alias,
29
- handle_notify,
30
29
  handle_next,
30
+ handle_notify,
31
31
  handle_remove,
32
- handle_repair,
33
32
  handle_rename,
33
+ handle_repair,
34
34
  handle_resume,
35
35
  handle_run,
36
36
  handle_run_report,
37
37
  handle_run_status,
38
38
  handle_runs,
39
39
  handle_select,
40
+ handle_set,
40
41
  handle_stats,
41
42
  handle_status,
42
- handle_set,
43
43
  handle_unset,
44
44
  handle_update,
45
45
  handle_view,
@@ -66,7 +66,25 @@ from .status_view import (
66
66
  )
67
67
  from .update_check import check_for_update, check_logics_manager_for_update
68
68
 
69
- VERSION = "0.9.9"
69
+ VERSION = "0.9.11"
70
+
71
+ # Public surface: this module is a facade. Names below are imported above
72
+ # purely to be re-exported (consumed by tests and external callers); listing
73
+ # them here documents that and stops F401 from treating them as dead imports.
74
+ __all__ = [
75
+ "STATUS_USAGE",
76
+ "LOG_ROTATE_BYTES",
77
+ "_format_blocking_quota",
78
+ "_format_reset_time",
79
+ "_format_status_detail",
80
+ "_format_status_rows",
81
+ "_pad_table",
82
+ "_rotate_log_if_needed",
83
+ "_visible_len",
84
+ "cli_entry",
85
+ "format_json_error",
86
+ "main",
87
+ ]
70
88
 
71
89
 
72
90
  _COMMAND_HANDLERS = {
@@ -427,7 +445,7 @@ def cli_entry():
427
445
  sys.stderr.write(f"{format_json_error(error)}\n")
428
446
  else:
429
447
  sys.stderr.write(f"{format_error(error)}\n")
430
- raise SystemExit(error.exit_code)
448
+ raise SystemExit(error.exit_code) from None
431
449
 
432
450
 
433
451
  if __name__ == "__main__":