cdx-manager 0.9.6 → 0.9.7

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.6-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.7-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,25 @@
1
+ # CDX Manager 0.9.7
2
+
3
+ ## Highlights
4
+
5
+ - Hardened profile cleanup so read-only provider cache files do not block session removal or repair cleanup.
6
+
7
+ ## Changes
8
+
9
+ ### Read-only profile cleanup
10
+
11
+ `cdx rmv`, session overwrite rollback cleanup, and repair quarantine cleanup now make profile trees user-writable before deleting them.
12
+
13
+ This fixes failures seen when provider-managed caches contain read-only files, including nested Go module cache paths created under session-specific provider homes.
14
+
15
+ ## Validation
16
+
17
+ - `npm run release:validate`
18
+ - `npm run lint`
19
+ - `npm test`
20
+ - `logics-manager lint --require-status`
21
+ - `logics-manager audit`
22
+ - `git diff --check`
23
+ - `npm --cache /private/tmp/cdx-npm-cache pack --dry-run`
24
+ - `python -m build`
25
+ - `python -m twine check dist/*`
@@ -88,6 +88,10 @@
88
88
  "v0.9.5": {
89
89
  "github_tarball_sha256": "29c512600ed366e06bcaa8ae12f105cc198f85c6887d46c9032d677c5335203b",
90
90
  "github_zip_sha256": "a7be652ba39b929eae6e90c48410ce8b7c9c122625da55bfcd50edb755d6d609"
91
+ },
92
+ "v0.9.6": {
93
+ "github_tarball_sha256": "7706ba127f247dfab50404ca175921c7874624e835c920799b3b122a45f7dc4b",
94
+ "github_zip_sha256": "be11246f65eae006512247067bff22863a6ebe8d5738b056fe17f654fd5d9b5c"
91
95
  }
92
96
  }
93
97
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdx-manager",
3
- "version": "0.9.6",
3
+ "version": "0.9.7",
4
4
  "description": "Terminal session manager for Codex and Claude accounts.",
5
5
  "license": "MIT",
6
6
  "author": "Alexandre Agostini",
@@ -42,6 +42,7 @@
42
42
  "cdx": "bin/cdx.js"
43
43
  },
44
44
  "scripts": {
45
+ "status": "node bin/cdx.js status",
45
46
  "test": "npm run test:py",
46
47
  "test:py": "node bin/python-runner.js -m unittest discover -s test -p test_*_py.py",
47
48
  "lint": "node --check bin/cdx.js && node --check bin/python-runner.js && node bin/python-runner.js scripts/verify_project_docs.py && node bin/python-runner.js -m py_compile bin/cdx src/*.py scripts/*.py test/test_*_py.py",
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.6"
7
+ version = "0.9.7"
8
8
  description = "Terminal session manager for Codex and Claude accounts."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
package/src/cli.py CHANGED
@@ -66,7 +66,7 @@ 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.6"
69
+ VERSION = "0.9.7"
70
70
 
71
71
 
72
72
  # ---------------------------------------------------------------------------
@@ -0,0 +1,50 @@
1
+ import os
2
+ import shutil
3
+ import stat
4
+
5
+
6
+ def _make_user_writable(path):
7
+ if os.path.islink(path):
8
+ return
9
+ try:
10
+ current = os.stat(path).st_mode
11
+ except OSError:
12
+ return
13
+ mode = current | stat.S_IRUSR | stat.S_IWUSR
14
+ if stat.S_ISDIR(current):
15
+ mode |= stat.S_IXUSR
16
+ try:
17
+ os.chmod(path, mode)
18
+ except OSError:
19
+ pass
20
+
21
+
22
+ def _make_tree_user_writable(path):
23
+ if not os.path.exists(path):
24
+ return
25
+ for root, dirs, files in os.walk(path, topdown=False):
26
+ for name in files:
27
+ file_path = os.path.join(root, name)
28
+ if not os.path.islink(file_path):
29
+ _make_user_writable(file_path)
30
+ for name in dirs:
31
+ dir_path = os.path.join(root, name)
32
+ if not os.path.islink(dir_path):
33
+ _make_user_writable(dir_path)
34
+ _make_user_writable(root)
35
+
36
+
37
+ def remove_tree(path, ignore_errors=False):
38
+ def onerror(func, failing_path, _exc_info):
39
+ parent = os.path.dirname(failing_path)
40
+ if parent:
41
+ _make_user_writable(parent)
42
+ _make_user_writable(failing_path)
43
+ try:
44
+ func(failing_path)
45
+ except OSError:
46
+ if not ignore_errors:
47
+ raise
48
+
49
+ _make_tree_user_writable(path)
50
+ shutil.rmtree(path, ignore_errors=ignore_errors, onerror=onerror)
@@ -335,8 +335,6 @@ def _launch_config_args(session):
335
335
  args += ["--dangerously-skip-permissions"]
336
336
  return args
337
337
  if provider == PROVIDER_OLLAMA:
338
- if power:
339
- args += ["--think", power if power in ("low", "medium", "high") else "high"]
340
338
  if permission == "full":
341
339
  args += ["--experimental-yolo"]
342
340
  return args
@@ -424,6 +422,8 @@ def _logics_enabled(session, env=None):
424
422
 
425
423
 
426
424
  def _with_launch_preferences(session, initial_prompt=None, env=None):
425
+ if session["provider"] == PROVIDER_OLLAMA:
426
+ return initial_prompt
427
427
  prompts = []
428
428
  if _rtk_enabled(session):
429
429
  prompts.append(RTK_PROMPT)
package/src/repair.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import os
3
- import shutil
4
3
 
4
+ from .fs_utils import remove_tree
5
5
  from .health import collect_health_report
6
6
 
7
7
 
@@ -69,7 +69,7 @@ def _apply_recreate_state(service, name):
69
69
 
70
70
 
71
71
  def _apply_remove_path(path):
72
- shutil.rmtree(path)
72
+ remove_tree(path)
73
73
  return "applied"
74
74
 
75
75
 
@@ -13,6 +13,7 @@ from .backup_bundle import decode_bundle, encode_bundle
13
13
  from .config import PROVIDER_ANTIGRAVITY, PROVIDER_CLAUDE, PROVIDER_CODEX, PROVIDERS, get_cdx_home
14
14
  from .codex_usage import fetch_codex_rate_limits
15
15
  from .errors import CdxError
16
+ from .fs_utils import remove_tree
16
17
  from .session_store import create_session_store
17
18
  from .status_source import find_latest_status_artifact
18
19
 
@@ -641,7 +642,7 @@ def create_session_service(options=None):
641
642
  raise CdxError(f"Unknown session: {name}")
642
643
  if quarantine_root:
643
644
  try:
644
- shutil.rmtree(quarantine_root)
645
+ remove_tree(quarantine_root)
645
646
  except OSError as error:
646
647
  raise CdxError(
647
648
  f"Removed session {name}, but failed to delete archived profile {quarantine_root}: {error}"
@@ -701,14 +702,14 @@ def create_session_service(options=None):
701
702
  overwritten = bool(existing)
702
703
  except Exception:
703
704
  if moved_temp and os.path.exists(dest_root):
704
- shutil.rmtree(dest_root, ignore_errors=True)
705
+ remove_tree(dest_root, ignore_errors=True)
705
706
  if backup_root and os.path.exists(backup_root) and not os.path.exists(dest_root):
706
707
  os.rename(backup_root, dest_root)
707
708
  raise
708
709
  finally:
709
710
  if backup_root and os.path.exists(backup_root):
710
- shutil.rmtree(backup_root, ignore_errors=True)
711
- shutil.rmtree(temp_parent, ignore_errors=True)
711
+ remove_tree(backup_root, ignore_errors=True)
712
+ remove_tree(temp_parent, ignore_errors=True)
712
713
  if not result["ok"]:
713
714
  raise CdxError(f"Failed to create session: {dest_name}")
714
715
  return {"session": result["session"], "overwritten": overwritten}