cdx-manager 0.17.0 → 0.17.1
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 +15 -4
- package/changelogs/CHANGELOGS_0_17_1.md +29 -0
- package/checksums/release-archives.json +4 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/agent_notify.py +40 -5
- package/src/cli.py +6 -3
- package/src/cli_args.py +4 -2
- package/src/cli_helpers.py +5 -4
- package/src/cli_render.py +1 -0
- package/src/commands/settings.py +29 -0
- package/src/commands/status.py +2 -1
- package/src/session_service.py +13 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CDX Manager
|
|
2
2
|
|
|
3
|
-
[](LICENSE) ](LICENSE)  
|
|
4
4
|
|
|
5
5
|
**Stop guessing which AI account still has quota.** `cdx` tracks the rate-limit window of every Codex and Claude account you own, tells you which one is usable right now, and launches it with isolated auth — in one command.
|
|
6
6
|
|
|
@@ -349,8 +349,8 @@ When a session's agent finishes a turn, or stops to wait for you, cdx raises a
|
|
|
349
349
|
desktop notification naming the session and the repository:
|
|
350
350
|
|
|
351
351
|
```text
|
|
352
|
-
✓ work1 logics-manager ·
|
|
353
|
-
✓ codex-a cdx-manager ·
|
|
352
|
+
✓ work1 logics-manager · needs your attention
|
|
353
|
+
✓ codex-a cdx-manager · turn complete
|
|
354
354
|
```
|
|
355
355
|
|
|
356
356
|
Off until you ask for it, per session:
|
|
@@ -359,6 +359,7 @@ Off until you ask for it, per session:
|
|
|
359
359
|
cdx set work1 --notify on # turn it on for one session
|
|
360
360
|
cdx set --all --notify on # turn it on everywhere
|
|
361
361
|
cdx set work1 --notify off # and back off; cdx removes what it installed
|
|
362
|
+
cdx set work1 --notify-preview on # include a short final-response preview
|
|
362
363
|
```
|
|
363
364
|
|
|
364
365
|
Turning it on records the setting. The wiring happens at that session's **next
|
|
@@ -372,6 +373,16 @@ It is off by default because turning it on writes into the provider's own
|
|
|
372
373
|
configuration and, on Codex, puts an approval prompt in front of you. That is
|
|
373
374
|
not something to do to sessions you already own without being asked.
|
|
374
375
|
|
|
376
|
+
Response previews are separately off by default. When enabled, a completion
|
|
377
|
+
notification includes at most 180 characters of the agent's final response.
|
|
378
|
+
That text can be visible on a lock screen, so enable it only for sessions whose
|
|
379
|
+
output is safe to expose. Previews never read transcripts and are not shown for
|
|
380
|
+
permission requests.
|
|
381
|
+
|
|
382
|
+
`cdx notify` is the internal hook target, called by the provider; it is not the
|
|
383
|
+
setup command. `cdx ready` is separate: it notifies you when the next cooling-
|
|
384
|
+
down session becomes usable.
|
|
385
|
+
|
|
375
386
|
Per platform: macOS uses `osascript`, Linux `notify-send`, Windows a toast, and
|
|
376
387
|
WSL reaches the Windows notification centre through interop. On a host with no
|
|
377
388
|
way to deliver one — a headless or SSH Linux session, or WSL with interop
|
|
@@ -489,7 +500,7 @@ cdx history --summary --from 2026-05-01 --to 2026-05-28
|
|
|
489
500
|
| `cdx update [--check] [--yes] [--json] [--version TAG]` | Update cdx-manager using the installer that matches how it was installed |
|
|
490
501
|
| `cdx update all [--yes] [--json]` | Check installed providers, RTK, and Ponytail across Codex profiles; show the plan and ask once before applying safe native/Homebrew updates and missing RTK/Ponytail setup |
|
|
491
502
|
| `cdx ready [--refresh] [--json]` | Schedule an OS notification for the next cooling-down assistant that becomes ready, then return immediately |
|
|
492
|
-
| `cdx notify` |
|
|
503
|
+
| `cdx notify` | Internal provider hook target for agent alerts; use `cdx set <name> --notify on` to enable it |
|
|
493
504
|
| `cdx next [--json] [--refresh]` | Select the best next assistant using the same priority logic as `cdx status` |
|
|
494
505
|
| `cdx select --provider PROVIDER [--min-reasoning-effort minimal\|low\|medium\|high\|xhigh] [--min-power minimal\|low\|medium\|high\|xhigh] [--require-ready] [--refresh] --json` | Select a suitable session for headless automation |
|
|
495
506
|
| `cdx run [session] --cwd PATH (--prompt-file PATH\|--prompt TEXT\|--prompt-file -) [--provider PROVIDER] [--model MODEL] [--reasoning-effort minimal\|low\|medium\|high\|xhigh] [--power minimal\|low\|medium\|high\|xhigh] [--permission MODE] [--timeout-seconds N] [--detach] [--failover] [--refresh] --json` | Run one headless task and return a stable JSON result; `--detach` returns the `run_id` at launch without waiting, `--failover` continues the task on the next account when this one hits its rate limit, `--prompt-file -` reads the prompt from stdin |
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# CDX Manager 0.17.1
|
|
2
|
+
|
|
3
|
+
## Fixes
|
|
4
|
+
|
|
5
|
+
### Agent-alert setup now reports provider support accurately
|
|
6
|
+
|
|
7
|
+
`cdx set <name> --notify on` now distinguishes sessions where cdx can install
|
|
8
|
+
provider hooks (Claude and Codex) from providers that do not expose that
|
|
9
|
+
integration yet. A mixed bulk selection reports both outcomes instead of
|
|
10
|
+
promising a future hook installation that cannot happen.
|
|
11
|
+
|
|
12
|
+
The setting remains storable for unsupported providers, so bulk configuration
|
|
13
|
+
remains predictable and a future provider integration can honour the existing
|
|
14
|
+
opt-in.
|
|
15
|
+
|
|
16
|
+
### Permission-request notifications constrain tool names
|
|
17
|
+
|
|
18
|
+
Tool names supplied by provider hook payloads now use the same printable,
|
|
19
|
+
single-line normalization as response previews and are capped at 80 characters.
|
|
20
|
+
This keeps permission notifications readable and prevents malformed payloads
|
|
21
|
+
from expanding or controlling desktop notification text.
|
|
22
|
+
|
|
23
|
+
## Validation
|
|
24
|
+
|
|
25
|
+
- `npm run lint`
|
|
26
|
+
- `npm test`
|
|
27
|
+
- `npm run release:validate`
|
|
28
|
+
- `logics-manager lint --require-status`
|
|
29
|
+
- `logics-manager audit --legacy-cutoff-version 1.1.0 --group-by-doc`
|
|
@@ -184,6 +184,10 @@
|
|
|
184
184
|
"v0.16.0": {
|
|
185
185
|
"github_tarball_sha256": "bdcd2808922410b20567ba86589d49166c5c2b9404325195b28457df80ca3dad",
|
|
186
186
|
"github_zip_sha256": "e89cb8c964304f0805d06da9d355d543f8a590e0febbf07e585a692ccf73ef99"
|
|
187
|
+
},
|
|
188
|
+
"v0.17.0": {
|
|
189
|
+
"github_tarball_sha256": "6f321106aa426590ce809788fab4f26401b4cc499a6c518a56a4f24f8bfb6c2e",
|
|
190
|
+
"github_zip_sha256": "72665a0006df40bb27301140b0ed6600a0d91b456facbb5a2aad2a917357ae75"
|
|
187
191
|
}
|
|
188
192
|
}
|
|
189
193
|
}
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
package/src/agent_notify.py
CHANGED
|
@@ -19,13 +19,21 @@ from .notify import notification_channel, send_desktop_notification
|
|
|
19
19
|
# Set on the provider process at launch; the hook runs as its child and inherits both.
|
|
20
20
|
SESSION_ENV = "CDX_SESSION_NAME"
|
|
21
21
|
ENABLED_ENV = "CDX_NOTIFY"
|
|
22
|
+
PREVIEW_ENV = "CDX_NOTIFY_PREVIEW"
|
|
22
23
|
|
|
23
24
|
# Our entries are recognised by the command they run, not by a marker key of our
|
|
24
25
|
# own: both providers validate this file against their own schema, and an extra
|
|
25
26
|
# key they do not know is a rejection risk for no gain.
|
|
26
27
|
HOOK_ARG = "notify"
|
|
27
28
|
|
|
28
|
-
_WAITING_EVENTS = {"notification", "permissionrequest"
|
|
29
|
+
_WAITING_EVENTS = {"notification", "permissionrequest"}
|
|
30
|
+
_PREVIEW_LIMIT = 180
|
|
31
|
+
_TOOL_NAME_LIMIT = 80
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def supports_agent_alerts(provider):
|
|
35
|
+
"""Whether cdx can provision provider hooks for this session."""
|
|
36
|
+
return provider in {"claude", "codex"}
|
|
29
37
|
|
|
30
38
|
|
|
31
39
|
def resolve_hook_command(env=None):
|
|
@@ -70,9 +78,29 @@ def compose_notification(payload, env=None, cwd=None):
|
|
|
70
78
|
return None
|
|
71
79
|
directory = payload.get("cwd") or payload.get("workspace") or cwd or os.getcwd()
|
|
72
80
|
event = str(payload.get("hook_event_name") or payload.get("eventName") or payload.get("type") or "").lower()
|
|
73
|
-
|
|
81
|
+
event = event.replace("_", "").replace("-", "")
|
|
82
|
+
state = "needs your attention" if event in _WAITING_EVENTS else "turn complete"
|
|
83
|
+
tool_name = _notification_text(payload.get("tool_name"), _TOOL_NAME_LIMIT)
|
|
84
|
+
if event == "permissionrequest" and tool_name:
|
|
85
|
+
state += f" ({tool_name})"
|
|
74
86
|
where = os.path.basename(str(directory).rstrip("/\\")) or directory
|
|
75
|
-
|
|
87
|
+
preview = _notification_preview(payload, event, env)
|
|
88
|
+
return f"✓ {session}", f"{where} · {state}" + (f" — {preview}" if preview else "")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _notification_preview(payload, event, env):
|
|
92
|
+
if event != "stop" or env.get(PREVIEW_ENV) != "1":
|
|
93
|
+
return ""
|
|
94
|
+
return _notification_text(payload.get("last_assistant_message"), _PREVIEW_LIMIT)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _notification_text(value, limit):
|
|
98
|
+
if not isinstance(value, str):
|
|
99
|
+
return ""
|
|
100
|
+
value = " ".join("".join(char if char.isprintable() else " " for char in value).split())
|
|
101
|
+
if len(value) <= limit:
|
|
102
|
+
return value
|
|
103
|
+
return value[:limit - 1].rstrip() + "…"
|
|
76
104
|
|
|
77
105
|
|
|
78
106
|
def handle_notify(rest, ctx):
|
|
@@ -82,9 +110,12 @@ def handle_notify(rest, ctx):
|
|
|
82
110
|
stdin_text = None
|
|
83
111
|
# "stdin" in ctx is the {"isTTY": ...} descriptor, not a stream.
|
|
84
112
|
reader = ctx.get("prompt_stdin") or sys.stdin
|
|
113
|
+
env = os.environ if ctx.get("env") is None else ctx["env"]
|
|
114
|
+
if ctx.get("stdin_is_tty") and not env.get(SESSION_ENV):
|
|
115
|
+
ctx["out"]("cdx notify is called by provider hooks. Enable agent alerts with: cdx set <name> --notify on\n")
|
|
116
|
+
return 0
|
|
85
117
|
if reader is not None and not ctx.get("stdin_is_tty"):
|
|
86
118
|
stdin_text = reader.read()
|
|
87
|
-
env = os.environ if ctx.get("env") is None else ctx["env"]
|
|
88
119
|
composed = compose_notification(read_hook_payload(rest, stdin_text), env, ctx.get("cwd"))
|
|
89
120
|
if composed:
|
|
90
121
|
send_desktop_notification(*composed, spawn_sync=ctx.get("spawn_sync"), env=env)
|
|
@@ -98,6 +129,8 @@ def launch_notify_env(session, enabled, env=None):
|
|
|
98
129
|
values = {SESSION_ENV: session["name"]}
|
|
99
130
|
if not enabled:
|
|
100
131
|
values[ENABLED_ENV] = "0"
|
|
132
|
+
elif (session.get("launch") or {}).get("notify_preview") is True:
|
|
133
|
+
values[PREVIEW_ENV] = "1"
|
|
101
134
|
return values
|
|
102
135
|
|
|
103
136
|
|
|
@@ -130,6 +163,8 @@ def provision(auth_home, provider, enabled, env=None, spawn_sync=None, base_dir=
|
|
|
130
163
|
# Nothing could be delivered on this host, so installing a hook would only
|
|
131
164
|
# buy the user an approval prompt for a feature that shows nothing.
|
|
132
165
|
enabled = False
|
|
166
|
+
if not supports_agent_alerts(provider):
|
|
167
|
+
return False
|
|
133
168
|
command = resolve_hook_command(env)
|
|
134
169
|
if provider == "claude":
|
|
135
170
|
return _apply_hooks(hook_config_path(auth_home, provider), enabled, command)
|
|
@@ -224,7 +259,7 @@ def _write_codex_plugin(auth_home, command, base_dir=None):
|
|
|
224
259
|
os.path.join(root, "hooks", "cdx-hooks.json"): {
|
|
225
260
|
"hooks": {
|
|
226
261
|
event: [{"hooks": [{"type": "command", "command": f"{command} {HOOK_ARG}"}]}]
|
|
227
|
-
for event in ("Stop", "
|
|
262
|
+
for event in ("Stop", "PermissionRequest")
|
|
228
263
|
},
|
|
229
264
|
},
|
|
230
265
|
}
|
package/src/cli.py
CHANGED
|
@@ -231,8 +231,8 @@ def _print_help(use_color=False):
|
|
|
231
231
|
f" {_style('cdx config <name> [--json]', '36', use_color)}",
|
|
232
232
|
f" {_style('cdx configs [--json]', '36', use_color)}",
|
|
233
233
|
f" {_style('cdx power|perm|fast|model <name|all|provider:PROVIDER|a,b> <value|default> [--json]', '36', use_color)}",
|
|
234
|
-
f" {_style('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]', '36', use_color)}",
|
|
235
|
-
f" {_style('cdx unset <name>|--sessions all|a,b|--provider PROVIDER (--power|--permission|--fast|--rtk|--logics|--model|--priority|--all) [--json]', '36', use_color)}",
|
|
234
|
+
f" {_style('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] [--notify on|off] [--notify-preview on|off] [--model MODEL] [--priority 0..100] [--json]', '36', use_color)}",
|
|
235
|
+
f" {_style('cdx unset <name>|--sessions all|a,b|--provider PROVIDER (--power|--permission|--fast|--rtk|--logics|--notify|--notify-preview|--model|--priority|--all) [--json]', '36', use_color)}",
|
|
236
236
|
f" {_style('cdx history [name] [--limit N] [--summary] [--since 7d|today|DATE] [--from DATE] [--to DATE] [--json]', '36', use_color)}",
|
|
237
237
|
f" {_style('cdx stats [name] [--since 7d|today|DATE] [--from DATE] [--to DATE] [--json]', '36', use_color)}",
|
|
238
238
|
f" {_style('cdx last [--json]', '36', use_color)}",
|
|
@@ -259,7 +259,10 @@ def _print_help(use_color=False):
|
|
|
259
259
|
f" {_style('cdx view [--json]', '36', use_color)}",
|
|
260
260
|
f" {_style('cdx update [all] [--check] [--yes] [--json] [--version TAG]', '36', use_color)}",
|
|
261
261
|
f" {_style('cdx ready [--refresh] [--json]', '36', use_color)}",
|
|
262
|
-
|
|
262
|
+
"",
|
|
263
|
+
_style("Notifications:", "1", use_color),
|
|
264
|
+
f" {_style('cdx set <name> --notify on', '36', use_color)} # agent finishes or needs attention",
|
|
265
|
+
f" {_style('cdx ready', '36', use_color)} # next session to become ready",
|
|
263
266
|
f" {_style('cdx <name> [--json]', '36', use_color)}",
|
|
264
267
|
f" {_style('cdx --help', '36', use_color)}",
|
|
265
268
|
f" {_style('cdx --version', '36', use_color)}",
|
package/src/cli_args.py
CHANGED
|
@@ -249,6 +249,7 @@ def _parse_set_args(args):
|
|
|
249
249
|
"--rtk": {"key": "rtk", "type": "str", "default": None, "transform": _parse_fast_value},
|
|
250
250
|
"--logics": {"key": "logics", "type": "str", "default": None, "transform": _parse_fast_value},
|
|
251
251
|
"--notify": {"key": "notify", "type": "str", "default": None, "transform": _parse_fast_value},
|
|
252
|
+
"--notify-preview": {"key": "notify_preview", "type": "str", "default": None, "transform": _parse_fast_value},
|
|
252
253
|
"--model": {"key": "model", "type": "str", "default": None},
|
|
253
254
|
"--fallback-model": {"key": "fallback_model", "type": "str", "default": None},
|
|
254
255
|
"--budget": {"key": "budget", "type": "str", "default": None, "transform": _parse_budget_value},
|
|
@@ -270,7 +271,7 @@ def _parse_set_args(args):
|
|
|
270
271
|
raise CdxError(SET_USAGE)
|
|
271
272
|
settings = {
|
|
272
273
|
key: parsed[key]
|
|
273
|
-
for key in ("power", "permission", "fast", "rtk", "logics", "notify", "model", "fallback_model", "budget", "extra_args", "priority")
|
|
274
|
+
for key in ("power", "permission", "fast", "rtk", "logics", "notify", "notify_preview", "model", "fallback_model", "budget", "extra_args", "priority")
|
|
274
275
|
if parsed[key] is not None
|
|
275
276
|
}
|
|
276
277
|
if not settings:
|
|
@@ -293,6 +294,7 @@ def _parse_unset_args(args):
|
|
|
293
294
|
"--rtk": {"key": "rtk", "type": "bool", "default": False},
|
|
294
295
|
"--logics": {"key": "logics", "type": "bool", "default": False},
|
|
295
296
|
"--notify": {"key": "notify", "type": "bool", "default": False},
|
|
297
|
+
"--notify-preview": {"key": "notify_preview", "type": "bool", "default": False},
|
|
296
298
|
"--model": {"key": "model", "type": "bool", "default": False},
|
|
297
299
|
"--fallback-model": {"key": "fallback_model", "type": "bool", "default": False},
|
|
298
300
|
"--budget": {"key": "budget", "type": "bool", "default": False},
|
|
@@ -314,7 +316,7 @@ def _parse_unset_args(args):
|
|
|
314
316
|
if not parsed["names"] and not parsed["sessions"] and not parsed["provider"]:
|
|
315
317
|
raise CdxError(UNSET_USAGE)
|
|
316
318
|
_UNSET_KEYS = (
|
|
317
|
-
"power", "reasoning_effort", "permission", "fast", "rtk", "logics", "notify",
|
|
319
|
+
"power", "reasoning_effort", "permission", "fast", "rtk", "logics", "notify", "notify_preview",
|
|
318
320
|
"model", "fallback_model", "budget", "extra_args", "priority",
|
|
319
321
|
)
|
|
320
322
|
keys = list(_UNSET_KEYS) if parsed["all"] else [key for key in _UNSET_KEYS if parsed[key]]
|
package/src/cli_helpers.py
CHANGED
|
@@ -486,7 +486,8 @@ def _format_launch_config(session, use_color=False):
|
|
|
486
486
|
("fast", "Fast"),
|
|
487
487
|
("rtk", "RTK"),
|
|
488
488
|
("logics", "Logics"),
|
|
489
|
-
("notify", "
|
|
489
|
+
("notify", "Agent alerts"),
|
|
490
|
+
("notify_preview", "Response preview"),
|
|
490
491
|
("model", "Model"),
|
|
491
492
|
("fallback_model", "Fallback"),
|
|
492
493
|
("budget", "Budget"),
|
|
@@ -509,18 +510,18 @@ def _format_launch_config(session, use_color=False):
|
|
|
509
510
|
def _format_launch_settings_hint(name="<name>"):
|
|
510
511
|
return (
|
|
511
512
|
f"Set a value: cdx set {name} --power medium --permission auto "
|
|
512
|
-
"--fast on --rtk on --logics on --notify on --model MODEL --priority 80"
|
|
513
|
+
"--fast on --rtk on --logics on --notify on --notify-preview on --model MODEL --priority 80"
|
|
513
514
|
)
|
|
514
515
|
|
|
515
516
|
def _format_launch_setting_value(launch, key, use_color=False):
|
|
516
|
-
if key in ("fast", "rtk", "logics", "notify"):
|
|
517
|
+
if key in ("fast", "rtk", "logics", "notify", "notify_preview"):
|
|
517
518
|
if launch.get(key) is True:
|
|
518
519
|
return _style("on", "32", use_color)
|
|
519
520
|
if launch.get(key) is False:
|
|
520
521
|
return _style("off", "2", use_color)
|
|
521
522
|
if key == "logics":
|
|
522
523
|
return _dim("auto", use_color)
|
|
523
|
-
if key
|
|
524
|
+
if key in ("notify", "notify_preview"):
|
|
524
525
|
return _style("off", "2", use_color)
|
|
525
526
|
return _dim("default", use_color)
|
|
526
527
|
value = launch.get(key)
|
package/src/cli_render.py
CHANGED
|
@@ -175,6 +175,7 @@ def _format_sessions(service, use_color=False):
|
|
|
175
175
|
f" {_style('cdx configs', '36', use_color)}",
|
|
176
176
|
f" {_style('cdx stats', '36', use_color)}",
|
|
177
177
|
f" {_style('cdx ready', '36', use_color)}",
|
|
178
|
+
f" {_style('cdx set <name> --notify on', '36', use_color)}",
|
|
178
179
|
f" {_style('cdx perm all default', '36', use_color)}",
|
|
179
180
|
f" {_style('cdx handoff <source> <target>', '36', use_color)}",
|
|
180
181
|
f" {_style('cdx history', '36', use_color)}",
|
package/src/commands/settings.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Split out of cli_commands.py. Moved verbatim; re-exported by cli_commands.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from ..agent_notify import supports_agent_alerts
|
|
6
7
|
from ..cli_args import _parse_launch_setting_alias_args, _parse_set_args, _parse_unset_args
|
|
7
8
|
from ..cli_helpers import _format_launch_config, _json_success, _write_json
|
|
8
9
|
from ..cli_render import _success
|
|
@@ -40,6 +41,28 @@ def _format_bulk_launch_summary(sessions):
|
|
|
40
41
|
return ", ".join(names)
|
|
41
42
|
return ", ".join(names[:8]) + f", +{len(names) - 8} more"
|
|
42
43
|
|
|
44
|
+
|
|
45
|
+
def _notification_setting_notice(settings, sessions, action):
|
|
46
|
+
if "notify" in settings:
|
|
47
|
+
supported = [session for session in sessions if supports_agent_alerts(session["provider"])]
|
|
48
|
+
unsupported = [session for session in sessions if not supports_agent_alerts(session["provider"])]
|
|
49
|
+
notices = []
|
|
50
|
+
if supported:
|
|
51
|
+
names = _format_bulk_launch_summary(supported)
|
|
52
|
+
if action == "set" and settings["notify"]:
|
|
53
|
+
notices.append(f"Agent alerts enabled for {names} — hooks install on the next interactive launch.")
|
|
54
|
+
else:
|
|
55
|
+
notices.append(f"Agent alerts disabled for {names} — cdx removes its hooks on the next interactive launch.")
|
|
56
|
+
if unsupported:
|
|
57
|
+
names = _format_bulk_launch_summary(unsupported)
|
|
58
|
+
notices.append(f"Agent alerts updated for {names} — this provider does not support notification hooks.")
|
|
59
|
+
return "\n".join(notices)
|
|
60
|
+
if "notify_preview" in settings:
|
|
61
|
+
if action == "set" and settings["notify_preview"]:
|
|
62
|
+
return f"Response previews enabled for {names} — completion text may be visible on the lock screen."
|
|
63
|
+
return f"Response previews disabled for {names}."
|
|
64
|
+
return None
|
|
65
|
+
|
|
43
66
|
def _apply_launch_settings(parsed, ctx, action="set"):
|
|
44
67
|
targets = _resolve_bulk_launch_targets(parsed, ctx["service"])
|
|
45
68
|
sessions = [
|
|
@@ -63,6 +86,9 @@ def _apply_launch_settings(parsed, ctx, action="set"):
|
|
|
63
86
|
_write_json(ctx, payload)
|
|
64
87
|
return 0
|
|
65
88
|
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
89
|
+
notice = _notification_setting_notice(parsed["settings"], sessions, action)
|
|
90
|
+
if notice:
|
|
91
|
+
ctx["out"](f"{notice}\n")
|
|
66
92
|
if len(sessions) == 1:
|
|
67
93
|
ctx["out"](f"{_format_launch_config(sessions[0], ctx['use_color'])}\n")
|
|
68
94
|
return 0
|
|
@@ -90,6 +116,9 @@ def _clear_launch_settings(parsed, ctx, action="unset"):
|
|
|
90
116
|
_write_json(ctx, payload)
|
|
91
117
|
return 0
|
|
92
118
|
ctx["out"](f"{_success(message, ctx['use_color'])}\n")
|
|
119
|
+
notice = _notification_setting_notice({key: False for key in parsed["keys"]}, sessions, action)
|
|
120
|
+
if notice:
|
|
121
|
+
ctx["out"](f"{notice}\n")
|
|
93
122
|
if len(sessions) == 1:
|
|
94
123
|
ctx["out"](f"{_format_launch_config(sessions[0], ctx['use_color'])}\n")
|
|
95
124
|
return 0
|
package/src/commands/status.py
CHANGED
|
@@ -126,7 +126,7 @@ def _format_launch_configs(sessions, use_color=False):
|
|
|
126
126
|
for key in ("fallback_model", "budget")
|
|
127
127
|
)
|
|
128
128
|
has_extra = any((session.get("launch") or {}).get("extra_args") for session in sessions)
|
|
129
|
-
headers = ["SESSION", "PROVIDER", "POWER", "PERMISSION", "FAST", "RTK", "LOGICS", "MODEL"]
|
|
129
|
+
headers = ["SESSION", "PROVIDER", "POWER", "PERMISSION", "FAST", "RTK", "LOGICS", "ALERTS", "MODEL"]
|
|
130
130
|
if has_headless:
|
|
131
131
|
headers += ["FALLBACK", "BUDGET"]
|
|
132
132
|
if has_extra:
|
|
@@ -143,6 +143,7 @@ def _format_launch_configs(sessions, use_color=False):
|
|
|
143
143
|
_format_launch_setting_value(launch, "fast", use_color),
|
|
144
144
|
_format_launch_setting_value(launch, "rtk", use_color),
|
|
145
145
|
_format_launch_setting_value(launch, "logics", use_color),
|
|
146
|
+
_format_launch_setting_value(launch, "notify", use_color),
|
|
146
147
|
_format_launch_setting_value(launch, "model", use_color),
|
|
147
148
|
]
|
|
148
149
|
if has_headless:
|
package/src/session_service.py
CHANGED
|
@@ -223,6 +223,18 @@ def _normalize_launch_settings(settings, mark_fast_service_tier=True):
|
|
|
223
223
|
normalized["notify"] = False
|
|
224
224
|
else:
|
|
225
225
|
raise CdxError(f"Unsupported notify value: {settings['notify']}")
|
|
226
|
+
if "notify_preview" in settings and settings["notify_preview"] is not None:
|
|
227
|
+
value = settings["notify_preview"]
|
|
228
|
+
if isinstance(value, bool):
|
|
229
|
+
normalized["notify_preview"] = value
|
|
230
|
+
else:
|
|
231
|
+
text = str(value).strip().lower()
|
|
232
|
+
if text in ("on", "true", "1", "yes"):
|
|
233
|
+
normalized["notify_preview"] = True
|
|
234
|
+
elif text in ("off", "false", "0", "no"):
|
|
235
|
+
normalized["notify_preview"] = False
|
|
236
|
+
else:
|
|
237
|
+
raise CdxError(f"Unsupported notify preview value: {settings['notify_preview']}")
|
|
226
238
|
if "model" in settings and settings["model"] is not None:
|
|
227
239
|
model = str(settings["model"]).strip()
|
|
228
240
|
if not model:
|
|
@@ -361,7 +373,7 @@ def unset_launch_settings(store, name, keys):
|
|
|
361
373
|
if not keys:
|
|
362
374
|
raise CdxError("At least one launch setting is required.")
|
|
363
375
|
allowed = {
|
|
364
|
-
"power", "reasoning_effort", "reasoningEffort", "permission", "fast", "rtk", "logics", "notify",
|
|
376
|
+
"power", "reasoning_effort", "reasoningEffort", "permission", "fast", "rtk", "logics", "notify", "notify_preview",
|
|
365
377
|
"model", "fallback_model", "budget", "extra_args", "priority",
|
|
366
378
|
}
|
|
367
379
|
unknown = [key for key in keys if key not in allowed]
|