cdx-manager 0.9.3 → 0.9.4
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 -1
- package/changelogs/CHANGELOGS_0_9_4.md +43 -0
- package/checksums/release-archives.json +4 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/cli.py +14 -4
- package/src/cli_commands.py +89 -4
- package/src/provider_runtime.py +92 -5
- package/src/session_service.py +2 -0
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
|
|
|
@@ -329,6 +329,7 @@ cdx history --summary --from 2026-05-01 --to 2026-05-28
|
|
|
329
329
|
| `cdx --json` | List all sessions as a machine-readable JSON payload |
|
|
330
330
|
| `cdx <name>` | Launch a session (checks auth first) |
|
|
331
331
|
| `cdx <name> [--json]` | Launch a session; `--json` returns a structured success payload after the interactive run ends |
|
|
332
|
+
| `cdx <name> -r` / `cdx <name> --resume` | Resume the provider-native conversation for a session when supported |
|
|
332
333
|
| `cdx add [provider] <name> [--model MODEL] [--json]` | Register a new session (`provider`: `codex`, `claude`, `antigravity`, or `ollama`; Ollama requires `--model`) |
|
|
333
334
|
| `cdx cp <source> <dest> [--json]` | Copy a session into another session name, overwriting the destination if it exists |
|
|
334
335
|
| `cdx ren <source> <dest> [--json]` | Rename a session and move its auth data |
|
|
@@ -343,6 +344,8 @@ cdx history --summary --from 2026-05-01 --to 2026-05-28
|
|
|
343
344
|
| `cdx unset <name>\|--sessions all\|a,b\|--provider PROVIDER (--power\|--permission\|--fast\|--rtk\|--logics\|--model\|--priority\|--all) [--json]` | Remove persisted launch settings and fall back to provider defaults |
|
|
344
345
|
| `cdx history [name] [--limit N] [--summary] [--since 7d\|today\|DATE] [--from DATE] [--to DATE] [--json]` | Show recent launch history or aggregate total launch time per assistant, optionally filtered by period |
|
|
345
346
|
| `cdx last [--json]` | Launch the most recent existing session from launch history |
|
|
347
|
+
| `cdx resume <name> [--json]` | Resume the provider-native conversation for a session using the named command form |
|
|
348
|
+
| `cdx can-resume <name> [--json]` | Check whether a session supports native resume without launching the provider |
|
|
346
349
|
| `cdx context show\|path\|init\|edit\|clear\|set [text...] [--json]` | Manage the shared Markdown context for the current workspace |
|
|
347
350
|
| `cdx handoff <name> [--json]` | Install the current workspace context into a target session and launch it unless `--json` is used |
|
|
348
351
|
| `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 |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# CDX Manager 0.9.4
|
|
2
|
+
|
|
3
|
+
## Highlights
|
|
4
|
+
|
|
5
|
+
- Added provider-native resume commands for named sessions.
|
|
6
|
+
- Added a non-launching capability check for resume support.
|
|
7
|
+
- Closed the Logics workflow for the resume command delivery.
|
|
8
|
+
|
|
9
|
+
## Changes
|
|
10
|
+
|
|
11
|
+
### Provider-native resume commands
|
|
12
|
+
|
|
13
|
+
`cdx` can now resume supported provider conversations without requiring users to remember provider-specific commands:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
cdx main -r
|
|
17
|
+
cdx main --resume
|
|
18
|
+
cdx resume main
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Codex sessions resume with `codex resume --last --cd <cwd>` inside the named session's isolated `CODEX_HOME`. Claude sessions resume with `claude --continue --name <name>` inside the named session's isolated `HOME`.
|
|
22
|
+
|
|
23
|
+
Providers without a verified native resume mode, currently Antigravity and Ollama, return a clear unsupported result instead of falling back to a normal launch.
|
|
24
|
+
|
|
25
|
+
### Resume capability checks
|
|
26
|
+
|
|
27
|
+
`cdx can-resume <name>` reports whether a session can resume without launching an interactive provider. JSON mode exposes a provider-neutral payload with the session name, provider, resumable state, strategy, reason, and command preview.
|
|
28
|
+
|
|
29
|
+
### Workflow traceability
|
|
30
|
+
|
|
31
|
+
The Logics request, backlog item, task, and ADR for provider-native resume are complete, with validation evidence attached to the delivery task.
|
|
32
|
+
|
|
33
|
+
## Validation
|
|
34
|
+
|
|
35
|
+
- `python -m unittest discover -s test -p 'test_runtime_py.py' -k resume`
|
|
36
|
+
- `python -m unittest discover -s test -p 'test_cli_py.py' -k resume`
|
|
37
|
+
- `python -m unittest discover -s test -p 'test_cli_py.py' -k help`
|
|
38
|
+
- `python -m unittest discover -s test -p 'test_*_py.py' -k resume`
|
|
39
|
+
- `npm run lint`
|
|
40
|
+
- `npm test`
|
|
41
|
+
- `logics-manager lint --require-status`
|
|
42
|
+
- `logics-manager audit`
|
|
43
|
+
- `git diff --check`
|
|
@@ -76,6 +76,10 @@
|
|
|
76
76
|
"v0.9.2": {
|
|
77
77
|
"github_tarball_sha256": "3e3ae4e4efc63a97dc6623ae8ddff36f04f4b7a0b531878a28c041298223d0b8",
|
|
78
78
|
"github_zip_sha256": "09acd2866770f4dc7f9aaba6aff8308766bb211dabddd7f28bdfde9ace427e78"
|
|
79
|
+
},
|
|
80
|
+
"v0.9.3": {
|
|
81
|
+
"github_tarball_sha256": "cb3cfd9134447d1049b510836014001fb6c38a89de588adc8cdbb1fe5deb4d6d",
|
|
82
|
+
"github_zip_sha256": "056eb2d1a3f0fa721a7a0e597cd0409e496618cfa35791a78d4e184397596754"
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
}
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
package/src/cli.py
CHANGED
|
@@ -11,6 +11,7 @@ from .cli_commands import (
|
|
|
11
11
|
handle_clean,
|
|
12
12
|
handle_config,
|
|
13
13
|
handle_configs,
|
|
14
|
+
handle_can_resume,
|
|
14
15
|
handle_context,
|
|
15
16
|
handle_copy,
|
|
16
17
|
handle_doctor,
|
|
@@ -30,6 +31,7 @@ from .cli_commands import (
|
|
|
30
31
|
handle_remove,
|
|
31
32
|
handle_repair,
|
|
32
33
|
handle_rename,
|
|
34
|
+
handle_resume,
|
|
33
35
|
handle_run,
|
|
34
36
|
handle_run_report,
|
|
35
37
|
handle_run_status,
|
|
@@ -64,7 +66,7 @@ from .status_view import (
|
|
|
64
66
|
)
|
|
65
67
|
from .update_check import check_for_update, check_logics_manager_for_update
|
|
66
68
|
|
|
67
|
-
VERSION = "0.9.
|
|
69
|
+
VERSION = "0.9.4"
|
|
68
70
|
|
|
69
71
|
|
|
70
72
|
# ---------------------------------------------------------------------------
|
|
@@ -96,6 +98,8 @@ def _print_help(use_color=False):
|
|
|
96
98
|
f" {_style('cdx history [name] [--limit N] [--summary] [--since 7d|today|DATE] [--from DATE] [--to DATE] [--json]', '36', use_color)}",
|
|
97
99
|
f" {_style('cdx stats [name] [--since 7d|today|DATE] [--from DATE] [--to DATE] [--json]', '36', use_color)}",
|
|
98
100
|
f" {_style('cdx last [--json]', '36', use_color)}",
|
|
101
|
+
f" {_style('cdx resume <name> [--json]', '36', use_color)}",
|
|
102
|
+
f" {_style('cdx can-resume <name> [--json]', '36', use_color)}",
|
|
99
103
|
f" {_style('cdx handoff <name> [--json]', '36', use_color)}",
|
|
100
104
|
f" {_style('cdx handoff <source> <target> [--json]', '36', use_color)}",
|
|
101
105
|
f" {_style('cdx add [provider] <name> [--model MODEL] [--json]', '36', use_color)}",
|
|
@@ -283,7 +287,7 @@ def main(argv, options=None):
|
|
|
283
287
|
"version": VERSION,
|
|
284
288
|
"cwd": options.get("cwd") or os.getcwd(),
|
|
285
289
|
"update_notices": _get_update_notices(service, env, options) if command not in (
|
|
286
|
-
"add", "cp", "ren", "rename", "mv", "rmv", "clean", "doctor", "repair", "view", "update", "ready", "notify", "next", "context", "config", "configs", "set", "unset", "power", "perm", "fast", "model", "history", "stats", "handoff", "login", "logout", "disable", "enable", "export", "import", "select", "run", "help", "version"
|
|
290
|
+
"add", "cp", "ren", "rename", "mv", "rmv", "clean", "doctor", "repair", "view", "update", "ready", "notify", "next", "context", "config", "configs", "set", "unset", "power", "perm", "fast", "model", "history", "stats", "resume", "can-resume", "handoff", "login", "logout", "disable", "enable", "export", "import", "select", "run", "help", "version"
|
|
287
291
|
) else None,
|
|
288
292
|
"use_color": use_color,
|
|
289
293
|
}
|
|
@@ -365,6 +369,12 @@ def main(argv, options=None):
|
|
|
365
369
|
if command == "last":
|
|
366
370
|
return handle_last(rest, ctx)
|
|
367
371
|
|
|
372
|
+
if command == "resume":
|
|
373
|
+
return handle_resume(rest, ctx)
|
|
374
|
+
|
|
375
|
+
if command == "can-resume":
|
|
376
|
+
return handle_can_resume(rest, ctx)
|
|
377
|
+
|
|
368
378
|
if command == "handoff":
|
|
369
379
|
return handle_handoff(rest, ctx)
|
|
370
380
|
|
|
@@ -400,8 +410,8 @@ def main(argv, options=None):
|
|
|
400
410
|
out(f"{_print_version()}\n")
|
|
401
411
|
return 0
|
|
402
412
|
|
|
403
|
-
if
|
|
404
|
-
return handle_launch(command, ctx)
|
|
413
|
+
if all(arg in ("--json", "-r", "--resume") for arg in rest):
|
|
414
|
+
return handle_launch(command, ctx, resume=("-r" in rest or "--resume" in rest))
|
|
405
415
|
|
|
406
416
|
raise CdxError(f"Unknown command: {command}. Use cdx --help.")
|
|
407
417
|
|
package/src/cli_commands.py
CHANGED
|
@@ -3,6 +3,7 @@ import getpass
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
5
|
import re
|
|
6
|
+
import shlex
|
|
6
7
|
import sys
|
|
7
8
|
import time
|
|
8
9
|
from datetime import datetime, timedelta
|
|
@@ -37,6 +38,7 @@ from .provider_runtime import (
|
|
|
37
38
|
_list_launch_transcript_paths,
|
|
38
39
|
_normalize_reasoning_effort,
|
|
39
40
|
_probe_provider_auth,
|
|
41
|
+
get_resume_capability,
|
|
40
42
|
_run_headless_provider_command,
|
|
41
43
|
_run_interactive_provider_command,
|
|
42
44
|
)
|
|
@@ -66,6 +68,8 @@ CONFIGS_USAGE = "Usage: cdx configs [--json]"
|
|
|
66
68
|
HISTORY_USAGE = "Usage: cdx history [name] [--limit N] [--summary] [--since 7d|today|DATE] [--from DATE] [--to DATE] [--json]"
|
|
67
69
|
STATS_USAGE = "Usage: cdx stats [name] [--since 7d|today|DATE] [--from DATE] [--to DATE] [--json]"
|
|
68
70
|
LAST_USAGE = "Usage: cdx last [--json]"
|
|
71
|
+
RESUME_USAGE = "Usage: cdx resume <name> [--json]"
|
|
72
|
+
CAN_RESUME_USAGE = "Usage: cdx can-resume <name> [--json]"
|
|
69
73
|
SELECT_USAGE = "Usage: cdx select --provider PROVIDER [--min-reasoning-effort minimal|low|medium|high|xhigh] [--min-power minimal|low|medium|high|xhigh] [--require-ready] [--refresh] --json"
|
|
70
74
|
NEXT_USAGE = "Usage: cdx next [--json] [--refresh]"
|
|
71
75
|
RUN_USAGE = "Usage: cdx run [session] --cwd PATH (--prompt-file PATH|--prompt TEXT) [--provider PROVIDER] [--model MODEL] [--kind assistant|code-review] [--reasoning-effort minimal|low|medium|high|xhigh] [--power minimal|low|medium|high|xhigh] [--permission review|default|auto|full|workspace-write|read-only|danger-full-access] [--timeout-seconds N] --json"
|
|
@@ -2844,10 +2848,83 @@ def handle_update(rest, ctx):
|
|
|
2844
2848
|
return 0
|
|
2845
2849
|
|
|
2846
2850
|
|
|
2847
|
-
def
|
|
2851
|
+
def _resume_capability_for_session(session, ctx):
|
|
2852
|
+
capability = get_resume_capability(session, cwd=ctx.get("cwd") or os.getcwd())
|
|
2853
|
+
return {
|
|
2854
|
+
"session": session["name"],
|
|
2855
|
+
"provider": session["provider"],
|
|
2856
|
+
"resumable": bool(capability.get("resumable")),
|
|
2857
|
+
"strategy": capability.get("strategy"),
|
|
2858
|
+
"reason": capability.get("reason"),
|
|
2859
|
+
"command_preview": capability.get("command_preview") or [],
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
|
|
2863
|
+
def _format_resume_capability(capability, use_color=False):
|
|
2864
|
+
name = capability["session"]
|
|
2865
|
+
provider = capability["provider"]
|
|
2866
|
+
if capability["resumable"]:
|
|
2867
|
+
preview = shlex.join(capability.get("command_preview") or [])
|
|
2868
|
+
detail = f"({provider}, {capability['strategy']})"
|
|
2869
|
+
return (
|
|
2870
|
+
f"{_success(f'{name} can resume', use_color)} "
|
|
2871
|
+
f"{_dim(detail, use_color)}\n"
|
|
2872
|
+
f"{_dim(preview, use_color)}"
|
|
2873
|
+
)
|
|
2874
|
+
reason = capability.get("reason") or "not_supported"
|
|
2875
|
+
return (
|
|
2876
|
+
f"{_warn(f'{name} cannot resume', use_color)} "
|
|
2877
|
+
f"{_dim(f'({provider}, {reason})', use_color)}"
|
|
2878
|
+
)
|
|
2879
|
+
|
|
2880
|
+
|
|
2881
|
+
def handle_can_resume(rest, ctx):
|
|
2882
|
+
json_flag, args = _parse_json_flag(rest)
|
|
2883
|
+
if len(args) != 1:
|
|
2884
|
+
raise CdxError(CAN_RESUME_USAGE)
|
|
2885
|
+
session = ctx["service"]["get_session"](args[0])
|
|
2886
|
+
if not session:
|
|
2887
|
+
raise CdxError(f"Unknown session: {args[0]}")
|
|
2888
|
+
if session.get("enabled", True) is False:
|
|
2889
|
+
capability = {
|
|
2890
|
+
"session": session["name"],
|
|
2891
|
+
"provider": session["provider"],
|
|
2892
|
+
"resumable": False,
|
|
2893
|
+
"strategy": "session_disabled",
|
|
2894
|
+
"reason": "session_disabled",
|
|
2895
|
+
"command_preview": [],
|
|
2896
|
+
}
|
|
2897
|
+
else:
|
|
2898
|
+
capability = _resume_capability_for_session(session, ctx)
|
|
2899
|
+
if json_flag:
|
|
2900
|
+
_write_json(ctx, {
|
|
2901
|
+
"schema_version": API_SCHEMA_VERSION,
|
|
2902
|
+
"ok": True,
|
|
2903
|
+
**capability,
|
|
2904
|
+
})
|
|
2905
|
+
return 0
|
|
2906
|
+
ctx["out"](f"{_format_resume_capability(capability, ctx['use_color'])}\n")
|
|
2907
|
+
return 0
|
|
2908
|
+
|
|
2909
|
+
|
|
2910
|
+
def handle_resume(rest, ctx):
|
|
2911
|
+
json_flag, args = _parse_json_flag(rest)
|
|
2912
|
+
if len(args) != 1:
|
|
2913
|
+
raise CdxError(RESUME_USAGE)
|
|
2914
|
+
return handle_launch(args[0], ctx, resume=True, force_json=json_flag)
|
|
2915
|
+
|
|
2916
|
+
|
|
2917
|
+
def handle_launch(command, ctx, initial_prompt=None, resume=False, force_json=None):
|
|
2848
2918
|
json_flag = "--json" in ctx.get("raw_args", ctx["options"].get("raw_args", []))
|
|
2919
|
+
if force_json is not None:
|
|
2920
|
+
json_flag = force_json
|
|
2849
2921
|
warnings = _update_notice_warnings(ctx)
|
|
2850
2922
|
session = ctx["service"]["launch_session"](command)
|
|
2923
|
+
capability = _resume_capability_for_session(session, ctx) if resume else None
|
|
2924
|
+
if capability and not capability["resumable"]:
|
|
2925
|
+
raise CdxError(
|
|
2926
|
+
f"Provider {session['provider']} does not support native resume through cdx."
|
|
2927
|
+
)
|
|
2851
2928
|
_ensure_session_authentication(
|
|
2852
2929
|
session,
|
|
2853
2930
|
ctx["service"],
|
|
@@ -2859,7 +2936,11 @@ def handle_launch(command, ctx, initial_prompt=None):
|
|
|
2859
2936
|
signal_emitter=ctx.get("signal_emitter"),
|
|
2860
2937
|
trust_local_credentials=False,
|
|
2861
2938
|
)
|
|
2862
|
-
message =
|
|
2939
|
+
message = (
|
|
2940
|
+
f"Resuming {session['provider']} session {session['name']}"
|
|
2941
|
+
if resume else
|
|
2942
|
+
f"Launching {session['provider']} session {session['name']}"
|
|
2943
|
+
)
|
|
2863
2944
|
if not json_flag:
|
|
2864
2945
|
ctx["out"](f"{_info(message, ctx['use_color'])}\n")
|
|
2865
2946
|
_write_update_notice(ctx)
|
|
@@ -2880,7 +2961,7 @@ def handle_launch(command, ctx, initial_prompt=None):
|
|
|
2880
2961
|
|
|
2881
2962
|
try:
|
|
2882
2963
|
run_info = _run_interactive_provider_command(
|
|
2883
|
-
session, "launch", spawn=ctx.get("spawn"), cwd=cwd, env_override=ctx.get("env"),
|
|
2964
|
+
session, "resume" if resume else "launch", spawn=ctx.get("spawn"), cwd=cwd, env_override=ctx.get("env"),
|
|
2884
2965
|
signal_emitter=ctx.get("signal_emitter"), initial_prompt=initial_prompt,
|
|
2885
2966
|
lifecycle_callback=runtime_lifecycle,
|
|
2886
2967
|
)
|
|
@@ -2903,12 +2984,16 @@ def handle_launch(command, ctx, initial_prompt=None):
|
|
|
2903
2984
|
raise
|
|
2904
2985
|
ctx["service"]["record_launch_history"](session["name"], {
|
|
2905
2986
|
"status": "success",
|
|
2987
|
+
"action": "resume" if resume else "launch",
|
|
2906
2988
|
"cwd": cwd,
|
|
2907
2989
|
"exit_code": 0,
|
|
2908
2990
|
**run_info,
|
|
2909
2991
|
})
|
|
2910
2992
|
if json_flag:
|
|
2911
|
-
|
|
2993
|
+
extra = {"session": ctx["service"]["get_session"](session["name"])}
|
|
2994
|
+
if capability:
|
|
2995
|
+
extra["resume"] = capability
|
|
2996
|
+
_write_json(ctx, _json_success("resume" if resume else "launch", message, warnings=warnings, **extra))
|
|
2912
2997
|
return 0
|
|
2913
2998
|
|
|
2914
2999
|
|
package/src/provider_runtime.py
CHANGED
|
@@ -511,6 +511,90 @@ def _build_launch_spec(session, cwd=None, env_override=None, initial_prompt=None
|
|
|
511
511
|
}, capture_transcript=capture_transcript, env=env)
|
|
512
512
|
|
|
513
513
|
|
|
514
|
+
def _redacted_resume_command_preview(session, cwd=None):
|
|
515
|
+
capability = get_resume_capability(session, cwd=cwd)
|
|
516
|
+
return capability.get("command_preview")
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def get_resume_capability(session, cwd=None):
|
|
520
|
+
provider = session.get("provider")
|
|
521
|
+
cwd = cwd or os.getcwd()
|
|
522
|
+
if provider == PROVIDER_CODEX:
|
|
523
|
+
return {
|
|
524
|
+
"resumable": True,
|
|
525
|
+
"provider": provider,
|
|
526
|
+
"strategy": "provider_last",
|
|
527
|
+
"reason": "supported",
|
|
528
|
+
"command_preview": ["codex", "resume", "--last", "--cd", cwd],
|
|
529
|
+
}
|
|
530
|
+
if provider == PROVIDER_CLAUDE:
|
|
531
|
+
return {
|
|
532
|
+
"resumable": True,
|
|
533
|
+
"provider": provider,
|
|
534
|
+
"strategy": "provider_continue",
|
|
535
|
+
"reason": "supported",
|
|
536
|
+
"command_preview": ["claude", "--continue"],
|
|
537
|
+
}
|
|
538
|
+
return {
|
|
539
|
+
"resumable": False,
|
|
540
|
+
"provider": provider,
|
|
541
|
+
"strategy": "not_supported",
|
|
542
|
+
"reason": "not_supported",
|
|
543
|
+
"command_preview": [],
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def _build_resume_spec(session, cwd=None, env_override=None, capture_transcript=True):
|
|
548
|
+
cwd = cwd or os.getcwd()
|
|
549
|
+
env_override = env_override or {}
|
|
550
|
+
env = {**os.environ, **env_override}
|
|
551
|
+
capability = get_resume_capability(session, cwd=cwd)
|
|
552
|
+
if not capability["resumable"]:
|
|
553
|
+
raise CdxError(f"Provider {session.get('provider')} does not support native resume through cdx.")
|
|
554
|
+
|
|
555
|
+
resume_prompt = _with_launch_preferences(session, env=env)
|
|
556
|
+
_validate_initial_prompt(resume_prompt)
|
|
557
|
+
|
|
558
|
+
if session["provider"] == PROVIDER_CLAUDE:
|
|
559
|
+
launch = session.get("launch") or {}
|
|
560
|
+
args = ["--continue", "--name", session["name"]]
|
|
561
|
+
if launch.get("model"):
|
|
562
|
+
args += ["--model", _claude_cli_model(launch["model"])]
|
|
563
|
+
args += _launch_config_args(session)
|
|
564
|
+
if resume_prompt:
|
|
565
|
+
args.append(resume_prompt)
|
|
566
|
+
auth_home = _get_auth_home(session)
|
|
567
|
+
claude_env = _claude_env(env, auth_home)
|
|
568
|
+
oauth_token = _read_claude_launch_oauth_token(auth_home)
|
|
569
|
+
if oauth_token:
|
|
570
|
+
claude_env["CLAUDE_CODE_OAUTH_TOKEN"] = oauth_token
|
|
571
|
+
return _wrap_launch_with_transcript(session, {
|
|
572
|
+
"command": "claude",
|
|
573
|
+
"args": args,
|
|
574
|
+
"options": {
|
|
575
|
+
"cwd": cwd,
|
|
576
|
+
"env": claude_env,
|
|
577
|
+
},
|
|
578
|
+
"label": "claude resume",
|
|
579
|
+
}, capture_transcript=capture_transcript, env=env)
|
|
580
|
+
|
|
581
|
+
launch = session.get("launch") or {}
|
|
582
|
+
args = ["resume", "--last", "--cd", cwd]
|
|
583
|
+
if launch.get("model"):
|
|
584
|
+
args += ["--model", launch["model"]]
|
|
585
|
+
args += _launch_config_args(session)
|
|
586
|
+
if resume_prompt:
|
|
587
|
+
args.append(resume_prompt)
|
|
588
|
+
return _wrap_launch_with_transcript(session, {
|
|
589
|
+
"command": "codex",
|
|
590
|
+
"args": args,
|
|
591
|
+
"options": {
|
|
592
|
+
"env": {**env, "CODEX_HOME": _get_auth_home(session)},
|
|
593
|
+
},
|
|
594
|
+
"label": "codex resume",
|
|
595
|
+
}, capture_transcript=capture_transcript, env=env)
|
|
596
|
+
|
|
597
|
+
|
|
514
598
|
def _validate_initial_prompt(initial_prompt):
|
|
515
599
|
if initial_prompt is not None:
|
|
516
600
|
if not isinstance(initial_prompt, str):
|
|
@@ -846,11 +930,14 @@ def _run_interactive_provider_command(session, action, spawn=None, cwd=None,
|
|
|
846
930
|
env_override=None, signal_emitter=None,
|
|
847
931
|
initial_prompt=None, lifecycle_callback=None):
|
|
848
932
|
spawn = spawn or subprocess.Popen
|
|
849
|
-
|
|
850
|
-
_build_launch_spec(session, cwd=cwd, env_override=env_override, initial_prompt=initial_prompt)
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
933
|
+
if action == "launch":
|
|
934
|
+
spec = _build_launch_spec(session, cwd=cwd, env_override=env_override, initial_prompt=initial_prompt)
|
|
935
|
+
elif action == "resume":
|
|
936
|
+
if initial_prompt is not None:
|
|
937
|
+
raise CdxError("initial_prompt is not supported for resume.")
|
|
938
|
+
spec = _build_resume_spec(session, cwd=cwd, env_override=env_override)
|
|
939
|
+
else:
|
|
940
|
+
spec = _build_auth_action_spec(session, action, cwd=cwd, env_override=env_override)
|
|
854
941
|
def start_child(current_spec):
|
|
855
942
|
command = current_spec["command"]
|
|
856
943
|
if spawn is subprocess.Popen:
|
package/src/session_service.py
CHANGED
|
@@ -21,6 +21,7 @@ ALLOWED_PROVIDERS = set(PROVIDERS)
|
|
|
21
21
|
MAX_SESSION_NAME_LENGTH = 64
|
|
22
22
|
RESERVED_SESSION_NAMES = {
|
|
23
23
|
"add",
|
|
24
|
+
"can-resume",
|
|
24
25
|
"clean",
|
|
25
26
|
"context",
|
|
26
27
|
"configs",
|
|
@@ -45,6 +46,7 @@ RESERVED_SESSION_NAMES = {
|
|
|
45
46
|
"power",
|
|
46
47
|
"ready",
|
|
47
48
|
"repair",
|
|
49
|
+
"resume",
|
|
48
50
|
"ren",
|
|
49
51
|
"rename",
|
|
50
52
|
"rmv",
|