cdx-manager 0.9.12 → 0.9.14
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 +4 -4
- package/changelogs/CHANGELOGS_0_9_13.md +27 -0
- package/changelogs/CHANGELOGS_0_9_14.md +27 -0
- package/checksums/release-archives.json +8 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/cli.py +3 -3
- package/src/cli_args.py +10 -4
- package/src/cli_commands.py +11 -2
- package/src/provider_runtime.py +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CDX Manager
|
|
2
2
|
|
|
3
|
-
[](LICENSE) ](LICENSE)  
|
|
4
4
|
|
|
5
5
|
**Run multiple Codex, Claude, Antigravity, and Ollama sessions from one terminal. Switch between accounts instantly.**
|
|
6
6
|
|
|
@@ -359,8 +359,8 @@ cdx history --summary --from 2026-05-01 --to 2026-05-28
|
|
|
359
359
|
| `cdx handoff <source> <target> [--json]` | Build shared context from the source session's latest launch transcript, install it into the target session, and launch the target unless `--json` is used; supports cross-provider handoff |
|
|
360
360
|
| `cdx rmv <name> [--force] [--json]` | Remove a session and its auth data (prompts for confirmation unless `--force`) |
|
|
361
361
|
| `cdx clean [name] [--json]` | Clear launch transcript logs for one session or all sessions |
|
|
362
|
-
| `cdx export <file> [--include-auth] [--sessions a,b] [--passphrase-env VAR] [--force] [--json]` | Export sessions to a portable bundle; `--include-auth` encrypts auth data with a passphrase |
|
|
363
|
-
| `cdx import <file> [--sessions a,b] [--passphrase-env VAR] [--force] [--json]` | Import sessions from a bundle into the current `CDX_HOME` |
|
|
362
|
+
| `cdx export <file> [--include-auth] [--sessions a,b] [--passphrase-env VAR\|--passphrase-stdin] [--force] [--json]` | Export sessions to a portable bundle; `--include-auth` encrypts auth data with a passphrase |
|
|
363
|
+
| `cdx import <file> [--sessions a,b] [--passphrase-env VAR\|--passphrase-stdin] [--force] [--json]` | Import sessions from a bundle into the current `CDX_HOME` |
|
|
364
364
|
| `cdx doctor [--json]` | Inspect CLI dependencies, CDX_HOME permissions, missing state, orphan profiles, and pending quarantines |
|
|
365
365
|
| `cdx repair [--dry-run] [--force] [--json]` | Plan or apply safe repairs for missing state files, quarantines, and orphan profiles |
|
|
366
366
|
| `cdx view [--json] [--lan] [--lan-rw] [--focus <ref>] [--read] [--port <port>] [--host <host>] [--refresh-interval <s>] [--tls] [--tls-cert <path>] [--tls-key <path>] [--open] [--no-open]` | Open the Logics browser/focus viewer by delegating to `logics-manager view`; all viewer flags are forwarded; JSON mode reports diagnostics without launching it |
|
|
@@ -510,7 +510,7 @@ cdx import backup-auth.cdx --passphrase-env CDX_BUNDLE_PASSPHRASE
|
|
|
510
510
|
Notes:
|
|
511
511
|
|
|
512
512
|
- `--include-auth` is encrypted, requires a passphrase, and exports only provider credential files rather than full profile caches or logs.
|
|
513
|
-
- Without `--passphrase-env`, `cdx` prompts in an interactive terminal.
|
|
513
|
+
- Without `--passphrase-env`, `cdx` prompts in an interactive terminal. Non-interactive callers can pass `--passphrase-stdin` to read the passphrase from stdin (one line) instead of exposing it in the child environment.
|
|
514
514
|
- `--sessions work,perso` exports or imports only a subset.
|
|
515
515
|
- `--force` allows overwriting existing destination sessions during import or replacing an existing bundle file during export.
|
|
516
516
|
- Auth bundles contain credentials. Treat them like secrets and delete them after transfer.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# CDX Manager 0.9.13
|
|
2
|
+
|
|
3
|
+
## Highlights
|
|
4
|
+
|
|
5
|
+
- Fixed Claude `setup-token` capture on Linux by using the util-linux `script` flush flag.
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
### Claude setup-token capture
|
|
10
|
+
|
|
11
|
+
Linux terminals now run transcript capture with `script -f` instead of the BSD/macOS-only `script -F` spelling.
|
|
12
|
+
|
|
13
|
+
This prevents util-linux `script` from exiting with `invalid option -- 'F'`, which previously made `cdx` fall back to running `claude setup-token` without transcript capture and miss the printed token.
|
|
14
|
+
|
|
15
|
+
macOS keeps the existing `script -F` behavior.
|
|
16
|
+
|
|
17
|
+
## Validation
|
|
18
|
+
|
|
19
|
+
- `npm run release:validate`
|
|
20
|
+
- `npm run lint`
|
|
21
|
+
- `npm test`
|
|
22
|
+
- `logics-manager lint --require-status`
|
|
23
|
+
- `logics-manager audit`
|
|
24
|
+
- `git diff --check`
|
|
25
|
+
- `npm --cache /private/tmp/cdx-npm-cache pack --dry-run`
|
|
26
|
+
- `python -m build`
|
|
27
|
+
- `python -m twine check dist/*`
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# CDX Manager 0.9.14
|
|
2
|
+
|
|
3
|
+
## Highlights
|
|
4
|
+
|
|
5
|
+
- Added `--passphrase-stdin` for auth bundle export/import flows, avoiding passphrases in child process environments.
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
### Auth bundle passphrase input
|
|
10
|
+
|
|
11
|
+
`cdx export --include-auth` and `cdx import` now accept `--passphrase-stdin` as an alternative to `--passphrase-env`.
|
|
12
|
+
|
|
13
|
+
This lets non-interactive callers provide the bundle passphrase through standard input instead of storing it in an environment variable. The new flag is mutually exclusive with `--passphrase-env`, and export still requires `--include-auth` before a passphrase is accepted.
|
|
14
|
+
|
|
15
|
+
Usage strings, command help, README examples, and regression coverage were updated for the new input mode.
|
|
16
|
+
|
|
17
|
+
## Validation
|
|
18
|
+
|
|
19
|
+
- `npm run release:validate`
|
|
20
|
+
- `npm run lint`
|
|
21
|
+
- `npm test`
|
|
22
|
+
- `logics-manager lint --require-status`
|
|
23
|
+
- `logics-manager audit`
|
|
24
|
+
- `git diff --check`
|
|
25
|
+
- `npm --cache /private/tmp/cdx-npm-cache pack --dry-run`
|
|
26
|
+
- `python -m build`
|
|
27
|
+
- `python -m twine check dist/*`
|
|
@@ -112,6 +112,14 @@
|
|
|
112
112
|
"v0.9.11": {
|
|
113
113
|
"github_tarball_sha256": "8ab8f673af4ad9c0e4fd64110d47285a1de02c095fd0f6d79eb67e061255093d",
|
|
114
114
|
"github_zip_sha256": "ee5fffa543b8a02c082a180c624d31951c5ff662d492132cd83d4f099da70441"
|
|
115
|
+
},
|
|
116
|
+
"v0.9.12": {
|
|
117
|
+
"github_tarball_sha256": "ed9de98e1b4df5e42a1e389580f03d4b4b2e09ee8f63d23110090e6f164b8ae6",
|
|
118
|
+
"github_zip_sha256": "55f9ead146411ae740db1cae3f91c56d6ebe33c03345f9d4bfd487e45962e412"
|
|
119
|
+
},
|
|
120
|
+
"v0.9.13": {
|
|
121
|
+
"github_tarball_sha256": "4541dcecbfc12705f8e50e61ab1cb1f53dd6a209cc4a6d33ec3a4e533a3da3eb",
|
|
122
|
+
"github_zip_sha256": "a8df11be1910a0562e0f97f69e9f35ee2fdf90ef50cb40689c85bf5ee5937027"
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
}
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
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.
|
|
69
|
+
VERSION = "0.9.14"
|
|
70
70
|
|
|
71
71
|
# Public surface: this module is a facade. Names below are imported above
|
|
72
72
|
# purely to be re-exported (consumed by tests and external callers); listing
|
|
@@ -192,8 +192,8 @@ def _print_help(use_color=False):
|
|
|
192
192
|
f" {_style('cdx enable <name> [--json]', '36', use_color)}",
|
|
193
193
|
f" {_style('cdx rmv <name> [--force] [--json]', '36', use_color)}",
|
|
194
194
|
f" {_style('cdx clean [name] [--json]', '36', use_color)}",
|
|
195
|
-
f" {_style('cdx export <file> [--include-auth] [--sessions a,b] [--passphrase-env VAR] [--force] [--json]', '36', use_color)}",
|
|
196
|
-
f" {_style('cdx import <file> [--sessions a,b] [--passphrase-env VAR] [--force|--merge] [--json]', '36', use_color)}",
|
|
195
|
+
f" {_style('cdx export <file> [--include-auth] [--sessions a,b] [--passphrase-env VAR|--passphrase-stdin] [--force] [--json]', '36', use_color)}",
|
|
196
|
+
f" {_style('cdx import <file> [--sessions a,b] [--passphrase-env VAR|--passphrase-stdin] [--force|--merge] [--json]', '36', use_color)}",
|
|
197
197
|
f" {_style('cdx doctor [--json]', '36', use_color)}",
|
|
198
198
|
f" {_style('cdx repair [--dry-run] [--force] [--json]', '36', use_color)}",
|
|
199
199
|
f" {_style('cdx view [--json]', '36', use_color)}",
|
package/src/cli_args.py
CHANGED
|
@@ -15,8 +15,8 @@ STATUS_USAGE = "Usage: cdx status [--json] [--refresh|--cached] [--timeout SECON
|
|
|
15
15
|
DOCTOR_USAGE = "Usage: cdx doctor [--json]"
|
|
16
16
|
REPAIR_USAGE = "Usage: cdx repair [--dry-run] [--force] [--json]"
|
|
17
17
|
UPDATE_USAGE = "Usage: cdx update [--check] [--yes] [--json] [--version TAG]"
|
|
18
|
-
EXPORT_USAGE = "Usage: cdx export <file> [--include-auth] [--force] [--json] [--sessions name1,name2] [--passphrase-env VAR]"
|
|
19
|
-
IMPORT_USAGE = "Usage: cdx import <file> [--force|--merge] [--json] [--sessions name1,name2] [--passphrase-env VAR]"
|
|
18
|
+
EXPORT_USAGE = "Usage: cdx export <file> [--include-auth] [--force] [--json] [--sessions name1,name2] [--passphrase-env VAR|--passphrase-stdin]"
|
|
19
|
+
IMPORT_USAGE = "Usage: cdx import <file> [--force|--merge] [--json] [--sessions name1,name2] [--passphrase-env VAR|--passphrase-stdin]"
|
|
20
20
|
CONTEXT_USAGE = "Usage: cdx context show|path|init|edit|clear|set [text...] [--json]"
|
|
21
21
|
HANDOFF_USAGE = "Usage: cdx handoff <name> [--json] | cdx handoff <source> <target> [--json]"
|
|
22
22
|
SET_USAGE = "Usage: cdx set <name>|--sessions all|a,b|--provider PROVIDER [--power minimal|low|medium|high|xhigh] [--permission review|default|auto|full] [--fast on|off] [--rtk on|off] [--logics on|off] [--model MODEL] [--priority 0..100] [--json]"
|
|
@@ -585,12 +585,15 @@ def _parse_export_args(args):
|
|
|
585
585
|
"transform": _parse_session_names,
|
|
586
586
|
},
|
|
587
587
|
"--passphrase-env": {"key": "passphrase_env", "type": "str", "default": None},
|
|
588
|
+
"--passphrase-stdin": {"key": "passphrase_stdin", "type": "bool", "default": False},
|
|
588
589
|
}, EXPORT_USAGE, positionals_key="positionals", max_positionals=1)
|
|
589
590
|
parsed["file_path"] = parsed.pop("positionals")[0] if parsed["positionals"] else None
|
|
590
591
|
if not parsed["file_path"]:
|
|
591
592
|
raise CdxError(EXPORT_USAGE)
|
|
592
|
-
if parsed["passphrase_env"] and
|
|
593
|
-
raise CdxError("--passphrase-env
|
|
593
|
+
if parsed["passphrase_env"] and parsed["passphrase_stdin"]:
|
|
594
|
+
raise CdxError("--passphrase-env and --passphrase-stdin are mutually exclusive.")
|
|
595
|
+
if (parsed["passphrase_env"] or parsed["passphrase_stdin"]) and not parsed["include_auth"]:
|
|
596
|
+
raise CdxError("--passphrase-env/--passphrase-stdin requires --include-auth for export.")
|
|
594
597
|
return parsed
|
|
595
598
|
|
|
596
599
|
|
|
@@ -606,12 +609,15 @@ def _parse_import_args(args):
|
|
|
606
609
|
"transform": _parse_session_names,
|
|
607
610
|
},
|
|
608
611
|
"--passphrase-env": {"key": "passphrase_env", "type": "str", "default": None},
|
|
612
|
+
"--passphrase-stdin": {"key": "passphrase_stdin", "type": "bool", "default": False},
|
|
609
613
|
}, IMPORT_USAGE, positionals_key="positionals", max_positionals=1)
|
|
610
614
|
parsed["file_path"] = parsed.pop("positionals")[0] if parsed["positionals"] else None
|
|
611
615
|
if not parsed["file_path"]:
|
|
612
616
|
raise CdxError(IMPORT_USAGE)
|
|
613
617
|
if parsed["force"] and parsed["merge"]:
|
|
614
618
|
raise CdxError("--force and --merge are mutually exclusive.")
|
|
619
|
+
if parsed["passphrase_env"] and parsed["passphrase_stdin"]:
|
|
620
|
+
raise CdxError("--passphrase-env and --passphrase-stdin are mutually exclusive.")
|
|
615
621
|
return parsed
|
|
616
622
|
|
|
617
623
|
|
package/src/cli_commands.py
CHANGED
|
@@ -107,15 +107,22 @@ from .update_check import LatestReleaseCheckError, fetch_latest_release, fetch_l
|
|
|
107
107
|
from .update_manager import build_update_plan, format_update_failure, run_update_plan, verify_updated_command
|
|
108
108
|
|
|
109
109
|
|
|
110
|
-
def _resolve_bundle_passphrase(ctx, env_var, prompt, confirm=False):
|
|
110
|
+
def _resolve_bundle_passphrase(ctx, env_var, prompt, confirm=False, use_stdin=False):
|
|
111
111
|
env = ctx.get("env", {})
|
|
112
112
|
if env_var:
|
|
113
113
|
passphrase = env.get(env_var)
|
|
114
114
|
if not passphrase:
|
|
115
115
|
raise CdxError(f"Environment variable {env_var} is empty or unset.")
|
|
116
116
|
return passphrase
|
|
117
|
+
if use_stdin:
|
|
118
|
+
reader = ctx["options"].get("read_stdin")
|
|
119
|
+
raw = reader() if callable(reader) else sys.stdin.readline()
|
|
120
|
+
passphrase = (raw or "").rstrip("\r\n")
|
|
121
|
+
if not passphrase:
|
|
122
|
+
raise CdxError("Bundle passphrase from stdin is empty.")
|
|
123
|
+
return passphrase
|
|
117
124
|
if not ctx["stdin_is_tty"]:
|
|
118
|
-
raise CdxError("Encrypted bundle export/import requires an interactive terminal or --passphrase-
|
|
125
|
+
raise CdxError("Encrypted bundle export/import requires an interactive terminal, --passphrase-env, or --passphrase-stdin.")
|
|
119
126
|
getpass_fn = ctx["options"].get("getpass") or getpass.getpass
|
|
120
127
|
passphrase = getpass_fn(prompt)
|
|
121
128
|
if not passphrase:
|
|
@@ -1757,6 +1764,7 @@ def handle_export(rest, ctx):
|
|
|
1757
1764
|
parsed["passphrase_env"],
|
|
1758
1765
|
"Bundle passphrase: ",
|
|
1759
1766
|
confirm=True,
|
|
1767
|
+
use_stdin=parsed["passphrase_stdin"],
|
|
1760
1768
|
)
|
|
1761
1769
|
result = ctx["service"]["export_bundle"](
|
|
1762
1770
|
parsed["file_path"],
|
|
@@ -1796,6 +1804,7 @@ def handle_import(rest, ctx):
|
|
|
1796
1804
|
parsed["passphrase_env"],
|
|
1797
1805
|
"Bundle passphrase: ",
|
|
1798
1806
|
confirm=False,
|
|
1807
|
+
use_stdin=parsed["passphrase_stdin"],
|
|
1799
1808
|
)
|
|
1800
1809
|
result = ctx["service"]["import_bundle"](
|
|
1801
1810
|
parsed["file_path"],
|
package/src/provider_runtime.py
CHANGED
|
@@ -375,8 +375,9 @@ def _wrap_launch_with_transcript(session, spec, capture_transcript=True, env=Non
|
|
|
375
375
|
|
|
376
376
|
def _default_script_args(transcript_path, spec):
|
|
377
377
|
if sys.platform.startswith("linux"):
|
|
378
|
+
# util-linux `script` flushes with -f (lowercase); -F is the BSD/macOS spelling and errors here.
|
|
378
379
|
command = shlex.join([spec["command"]] + spec["args"])
|
|
379
|
-
return ["-q", "-
|
|
380
|
+
return ["-q", "-f", "-c", command, transcript_path]
|
|
380
381
|
return ["-q", "-F", transcript_path, spec["command"]] + spec["args"]
|
|
381
382
|
|
|
382
383
|
|