cdx-manager 0.12.4 → 0.15.0
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 +214 -19
- package/changelogs/CHANGELOGS_0_14_0.md +146 -0
- package/changelogs/CHANGELOGS_0_15_0.md +139 -0
- package/checksums/release-archives.json +12 -0
- package/package.json +3 -3
- package/pyproject.toml +1 -1
- package/src/cli.py +64 -4
- package/src/cli_args.py +324 -39
- package/src/cli_commands.py +251 -3049
- package/src/cli_helpers.py +190 -2
- package/src/cli_render.py +17 -0
- package/src/commands/__init__.py +6 -0
- package/src/commands/auth.py +224 -0
- package/src/commands/backup.py +112 -0
- package/src/commands/context_memory.py +341 -0
- package/src/commands/launch.py +218 -0
- package/src/commands/lifecycle.py +154 -0
- package/src/commands/maintenance.py +723 -0
- package/src/commands/runs.py +849 -0
- package/src/commands/settings.py +107 -0
- package/src/commands/status.py +713 -0
- package/src/config.py +70 -0
- package/src/errors.py +17 -0
- package/src/health.py +151 -3
- package/src/notify.py +11 -5
- package/src/provider_background.py +263 -0
- package/src/provider_runtime.py +142 -15
- package/src/run_command.py +112 -4
- package/src/run_failover.py +221 -0
- package/src/run_registry.py +127 -2
- package/src/session_backup.py +343 -0
- package/src/session_helpers.py +179 -0
- package/src/session_ranking.py +259 -0
- package/src/session_service.py +698 -1426
- package/src/session_status.py +550 -0
- package/src/status_source.py +45 -0
- package/src/status_view.py +15 -34
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Session lifecycle domain commands: add, cp, ren, rmv, label, enable, disable.
|
|
2
|
+
|
|
3
|
+
Split out of cli_commands.py. Moved verbatim; re-exported by cli_commands.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from ..cli_args import (
|
|
7
|
+
_parse_add_args,
|
|
8
|
+
_parse_copy_args,
|
|
9
|
+
_parse_json_flag,
|
|
10
|
+
_parse_label_args,
|
|
11
|
+
_parse_remove_args,
|
|
12
|
+
_parse_rename_args,
|
|
13
|
+
_parse_toggle_args,
|
|
14
|
+
)
|
|
15
|
+
from ..cli_helpers import _bootstrap_claude_setup_token, _json_success, _local_now_iso, _resolve_confirmation, _write_json
|
|
16
|
+
from ..cli_render import _success, _warn
|
|
17
|
+
from ..config import PROVIDER_CLAUDE, PROVIDER_OLLAMA
|
|
18
|
+
from ..errors import CdxError
|
|
19
|
+
from ..provider_runtime import _ensure_session_authentication
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _confirm_removal(name):
|
|
23
|
+
answer = input(f"Remove session {name}? [y/N] ")
|
|
24
|
+
return answer.strip().lower() in ("y", "yes")
|
|
25
|
+
|
|
26
|
+
def handle_add(rest, ctx):
|
|
27
|
+
json_flag, args = _parse_json_flag(rest)
|
|
28
|
+
parsed = _parse_add_args(args)
|
|
29
|
+
if parsed["provider"] == PROVIDER_OLLAMA and not parsed.get("model"):
|
|
30
|
+
raise CdxError("Usage: cdx add ollama <name> --model MODEL [--json]")
|
|
31
|
+
if parsed.get("model") and parsed["provider"] != PROVIDER_OLLAMA:
|
|
32
|
+
raise CdxError("--model is only supported when adding an ollama session.")
|
|
33
|
+
session = ctx["service"]["create_session"](parsed["name"], parsed["provider"])
|
|
34
|
+
if parsed.get("model"):
|
|
35
|
+
session = ctx["service"]["set_launch_settings"](parsed["name"], {"model": parsed["model"]})
|
|
36
|
+
message = f"Created session {parsed['name']} ({parsed['provider']})"
|
|
37
|
+
if session["provider"] == PROVIDER_CLAUDE and ctx["stdin_is_tty"]:
|
|
38
|
+
# ponytail: mint a ~1yr setup-token instead of the ~daily claude login token
|
|
39
|
+
_bootstrap_claude_setup_token(session, ctx)
|
|
40
|
+
else:
|
|
41
|
+
_ensure_session_authentication(
|
|
42
|
+
session,
|
|
43
|
+
ctx["service"],
|
|
44
|
+
spawn=ctx.get("spawn"),
|
|
45
|
+
spawn_sync=ctx.get("spawn_sync"),
|
|
46
|
+
env_override=ctx.get("env"),
|
|
47
|
+
stdin_is_tty=ctx["stdin_is_tty"],
|
|
48
|
+
behavior="bootstrap",
|
|
49
|
+
signal_emitter=ctx.get("signal_emitter"),
|
|
50
|
+
)
|
|
51
|
+
now = _local_now_iso()
|
|
52
|
+
ctx["service"]["update_auth_state"](parsed["name"], lambda auth: {
|
|
53
|
+
**auth,
|
|
54
|
+
"status": "authenticated",
|
|
55
|
+
"lastCheckedAt": now,
|
|
56
|
+
"lastAuthenticatedAt": now,
|
|
57
|
+
"lastLoggedOutAt": auth.get("lastLoggedOutAt"),
|
|
58
|
+
})
|
|
59
|
+
if json_flag:
|
|
60
|
+
_write_json(ctx, _json_success(
|
|
61
|
+
"add",
|
|
62
|
+
message,
|
|
63
|
+
session=ctx["service"]["get_session"](parsed["name"]),
|
|
64
|
+
))
|
|
65
|
+
return 0
|
|
66
|
+
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
67
|
+
return 0
|
|
68
|
+
|
|
69
|
+
def handle_copy(rest, ctx):
|
|
70
|
+
json_flag, args = _parse_json_flag(rest)
|
|
71
|
+
parsed = _parse_copy_args(args)
|
|
72
|
+
result = ctx["service"]["copy_session"](parsed["source"], parsed["dest"])
|
|
73
|
+
overwritten = " (overwritten)" if result["overwritten"] else ""
|
|
74
|
+
message = f"Copied session {parsed['source']} to {parsed['dest']}{overwritten}"
|
|
75
|
+
if json_flag:
|
|
76
|
+
_write_json(ctx, _json_success(
|
|
77
|
+
"copy",
|
|
78
|
+
message,
|
|
79
|
+
session=result["session"],
|
|
80
|
+
overwritten=result["overwritten"],
|
|
81
|
+
))
|
|
82
|
+
return 0
|
|
83
|
+
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
84
|
+
return 0
|
|
85
|
+
|
|
86
|
+
def handle_rename(rest, ctx):
|
|
87
|
+
json_flag, args = _parse_json_flag(rest)
|
|
88
|
+
parsed = _parse_rename_args(args)
|
|
89
|
+
session = ctx["service"]["rename_session"](parsed["source"], parsed["dest"])
|
|
90
|
+
message = f"Renamed session {parsed['source']} to {parsed['dest']}"
|
|
91
|
+
if json_flag:
|
|
92
|
+
_write_json(ctx, _json_success("rename", message, session=session))
|
|
93
|
+
return 0
|
|
94
|
+
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
95
|
+
return 0
|
|
96
|
+
|
|
97
|
+
def handle_label(rest, ctx):
|
|
98
|
+
parsed = _parse_label_args(rest)
|
|
99
|
+
if parsed["clear"]:
|
|
100
|
+
session = ctx["service"]["clear_session_label"](parsed["name"])
|
|
101
|
+
message = f"Cleared label for {parsed['name']}"
|
|
102
|
+
else:
|
|
103
|
+
session = ctx["service"]["set_session_label"](parsed["name"], parsed["label"])
|
|
104
|
+
message = f"Set label for {parsed['name']}: {session['label']}"
|
|
105
|
+
if parsed["json"]:
|
|
106
|
+
_write_json(ctx, _json_success("label", message, session=session, label=session.get("label")))
|
|
107
|
+
return 0
|
|
108
|
+
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
109
|
+
return 0
|
|
110
|
+
|
|
111
|
+
def handle_remove(rest, ctx):
|
|
112
|
+
json_flag, args = _parse_json_flag(rest)
|
|
113
|
+
parsed = _parse_remove_args(args)
|
|
114
|
+
if not parsed["force"]:
|
|
115
|
+
confirm_fn = ctx["options"].get("confirmRemove")
|
|
116
|
+
if confirm_fn:
|
|
117
|
+
confirmed = _resolve_confirmation(confirm_fn, parsed["name"])
|
|
118
|
+
elif not ctx["stdin_is_tty"]:
|
|
119
|
+
raise CdxError("Removal requires confirmation in an interactive terminal or --force in non-interactive mode.")
|
|
120
|
+
else:
|
|
121
|
+
confirmed = _confirm_removal(parsed["name"])
|
|
122
|
+
if not confirmed:
|
|
123
|
+
if json_flag:
|
|
124
|
+
_write_json(ctx, _json_success("remove", "Cancelled.", cancelled=True, session=None))
|
|
125
|
+
return 0
|
|
126
|
+
ctx["out"](f"{_warn('Cancelled.', ctx['use_color'])}\n")
|
|
127
|
+
return 0
|
|
128
|
+
removed = ctx["service"]["remove_session"](parsed["name"])
|
|
129
|
+
message = f"Removed session {parsed['name']}"
|
|
130
|
+
if json_flag:
|
|
131
|
+
_write_json(ctx, _json_success("remove", message, session=removed, cancelled=False))
|
|
132
|
+
return 0
|
|
133
|
+
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
134
|
+
return 0
|
|
135
|
+
|
|
136
|
+
def handle_disable(rest, ctx):
|
|
137
|
+
parsed = _parse_toggle_args(rest, "Usage: cdx disable <name> [--json]")
|
|
138
|
+
session = ctx["service"]["set_session_enabled"](parsed["name"], False)
|
|
139
|
+
message = f"Disabled session {parsed['name']}"
|
|
140
|
+
if parsed["json"]:
|
|
141
|
+
_write_json(ctx, _json_success("disable", message, session=session))
|
|
142
|
+
return 0
|
|
143
|
+
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
144
|
+
return 0
|
|
145
|
+
|
|
146
|
+
def handle_enable(rest, ctx):
|
|
147
|
+
parsed = _parse_toggle_args(rest, "Usage: cdx enable <name> [--json]")
|
|
148
|
+
session = ctx["service"]["set_session_enabled"](parsed["name"], True)
|
|
149
|
+
message = f"Enabled session {parsed['name']}"
|
|
150
|
+
if parsed["json"]:
|
|
151
|
+
_write_json(ctx, _json_success("enable", message, session=session))
|
|
152
|
+
return 0
|
|
153
|
+
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
154
|
+
return 0
|