@agentsdock/server 1.0.7-beta.5 → 1.0.8-beta.2
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 +20 -6
- package/package.json +1 -1
- package/server/VERSION +1 -1
- package/server/agent_server.py +5283 -698
- package/server/agentsdock_chats.py +2 -1
- package/server/chat_mailbox.py +23 -6
- package/server/claude_history_repair.py +45 -4
- package/server/claude_model_catalog.py +200 -0
- package/server/claude_sdk_client.py +63 -24
- package/server/claude_side_question.py +1 -8
- package/server/codex_app_server.py +90 -30
- package/server/codex_auth.py +119 -0
- package/server/codex_history_repair.py +79 -14
- package/server/codex_provider.py +160 -77
- package/server/codex_side_question.py +154 -57
- package/server/cursor_agent_client.py +27 -1
- package/server/cursor_api_key.py +64 -0
- package/server/cursor_history.py +219 -0
- package/server/cursor_provider_mcp.py +290 -0
- package/server/execution_durability.py +10 -6
- package/server/execution_preparation.py +6 -2
- package/server/install.sh +282 -78
- package/server/instances.sh +15 -0
- package/server/interactive_chat_native.py +4 -3
- package/server/interactive_chat_projection.py +6 -19
- package/server/interactive_chat_share_routes.py +71 -45
- package/server/interactive_chat_share_web.py +2 -2
- package/server/interactive_chat_shares.py +6 -11
- package/server/local_session_ownership.py +232 -0
- package/server/opencode_agent_client.py +685 -0
- package/server/provider_commands.py +579 -0
- package/server/provider_connections.py +665 -0
- package/server/provider_usage.py +241 -0
- package/server/public_chat_shares.py +60 -62
- package/server/public_chat_transcript.py +9 -31
- package/server/pyproject.toml +1 -0
- package/server/server_instances.py +931 -0
- package/server/shared_chat_video_stream.py +21 -2
- package/server/shared_chat_videos.py +54 -24
- package/server/side_questions.py +493 -10
- package/server/title_generation.py +4 -1
- package/server/uninstall.sh +95 -17
- package/server/update_preparation.py +4 -1
- package/server/update_runner.py +16 -0
- package/server/uv.lock +3 -1
package/server/uninstall.sh
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
+
UNINSTALL_SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
# Bare uninstall previews ALL instances and requires their exact names. Keep
|
|
6
|
+
# legacy explicit --yes automation default-scoped; --all opts into bulk removal.
|
|
7
|
+
if (($# == 0)); then
|
|
8
|
+
exec bash "$UNINSTALL_SCRIPT_DIR/instances.sh" remove --all
|
|
9
|
+
fi
|
|
10
|
+
for uninstall_option in "$@"; do
|
|
11
|
+
if [[ "$uninstall_option" == "--all" || "$uninstall_option" == "--instance" ]]; then
|
|
12
|
+
exec bash "$UNINSTALL_SCRIPT_DIR/instances.sh" remove "$@"
|
|
13
|
+
fi
|
|
14
|
+
done
|
|
15
|
+
INSTANCE_NAME="${AGENTS_SERVER_INSTANCE:-default}"
|
|
16
|
+
MANAGED_REMOVAL="false"
|
|
17
|
+
if [[ "$1" == "--managed-instance" ]]; then
|
|
18
|
+
MANAGED_REMOVAL="true"
|
|
19
|
+
INSTANCE_NAME="${2:?missing instance name}"
|
|
20
|
+
shift 2
|
|
21
|
+
fi
|
|
22
|
+
if [[ ! "$INSTANCE_NAME" =~ ^[a-z][a-z0-9-]{0,31}$ ]]; then
|
|
23
|
+
echo "Invalid instance name." >&2
|
|
24
|
+
exit 2
|
|
25
|
+
fi
|
|
26
|
+
|
|
4
27
|
INSTALL_ROOT="${AGENTS_SERVER_INSTALL_DIR:-$HOME/.local/share/agents-server}"
|
|
5
28
|
CONFIG_ROOT="${AGENTS_SERVER_CONFIG_DIR:-$HOME/.config/agents-server}"
|
|
6
29
|
LEGACY_STATE_ROOT="$HOME/.zenithbot-agent"
|
|
@@ -14,10 +37,29 @@ else
|
|
|
14
37
|
STATE_ROOT="$HOME/.agentsdock"
|
|
15
38
|
fi
|
|
16
39
|
SERVICE_NAME="agents-server"
|
|
40
|
+
LABEL="com.agentsdock.server"
|
|
41
|
+
INSTANCE_LOG_DIR="$HOME/Library/Logs/AgentsServer"
|
|
42
|
+
if [[ "$INSTANCE_NAME" != "default" ]]; then
|
|
43
|
+
instance_bindings="$(bash "$UNINSTALL_SCRIPT_DIR/instances.sh" _bindings "$INSTANCE_NAME")" || exit 2
|
|
44
|
+
eval "$instance_bindings"
|
|
45
|
+
fi
|
|
17
46
|
OS_NAME="$(uname -s)"
|
|
18
47
|
|
|
19
48
|
ASSUME_YES="false"
|
|
20
49
|
PURGE_STATE="false"
|
|
50
|
+
MANAGED_RELEASE_NAME="false"
|
|
51
|
+
UNINSTALL_RED=""
|
|
52
|
+
UNINSTALL_GREEN=""
|
|
53
|
+
UNINSTALL_RESET=""
|
|
54
|
+
if [[ -t 1 && "${TERM:-}" != "dumb" && -z "${NO_COLOR+x}" ]]; then
|
|
55
|
+
UNINSTALL_RED=$'\033[31m'
|
|
56
|
+
UNINSTALL_GREEN=$'\033[32m'
|
|
57
|
+
UNINSTALL_RESET=$'\033[0m'
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
uninstall_status() {
|
|
61
|
+
printf '%s%s%s\n' "$1" "$2" "$UNINSTALL_RESET"
|
|
62
|
+
}
|
|
21
63
|
|
|
22
64
|
normalize_managed_path() {
|
|
23
65
|
local label="$1"
|
|
@@ -97,6 +139,12 @@ usage() {
|
|
|
97
139
|
cat <<USAGE
|
|
98
140
|
Usage: ./uninstall.sh [--yes] [--purge-state]
|
|
99
141
|
|
|
142
|
+
With no arguments: show all current-user instances and confirm their exact names.
|
|
143
|
+
--instance NAME Remove only NAME (preview + confirmation).
|
|
144
|
+
--all Remove all instances (preview + confirmation).
|
|
145
|
+
--all --exclude default Keep the original/default server untouched.
|
|
146
|
+
Legacy --yes without --all remains default-scoped for compatibility.
|
|
147
|
+
|
|
100
148
|
Stops and removes the AgentsServer user service, versioned release runtime,
|
|
101
149
|
and generated configuration (including the access token). Chat history, jobs,
|
|
102
150
|
files, secure-peer credentials, and terminals under $STATE_ROOT are preserved
|
|
@@ -117,11 +165,21 @@ while (($#)); do
|
|
|
117
165
|
case "$1" in
|
|
118
166
|
--yes) ASSUME_YES="true"; shift ;;
|
|
119
167
|
--purge-state) PURGE_STATE="true"; shift ;;
|
|
168
|
+
--managed-release-name) MANAGED_RELEASE_NAME="true"; shift ;;
|
|
120
169
|
-h|--help) usage; exit 0 ;;
|
|
121
170
|
*) echo "Unknown option: $1" >&2; usage >&2; exit 2 ;;
|
|
122
171
|
esac
|
|
123
172
|
done
|
|
124
173
|
|
|
174
|
+
# This flag only controls progress text. The manager separately archives state
|
|
175
|
+
# after a successful service removal, using the user's affirmative choice.
|
|
176
|
+
if [[ "$MANAGED_RELEASE_NAME" == "true" \
|
|
177
|
+
&& ( "$MANAGED_REMOVAL" != "true" || "$INSTANCE_NAME" == "default" \
|
|
178
|
+
|| "$ASSUME_YES" != "true" || "$PURGE_STATE" == "true" ) ]]; then
|
|
179
|
+
echo "--managed-release-name is only for a confirmed named-instance manager removal." >&2
|
|
180
|
+
exit 2
|
|
181
|
+
fi
|
|
182
|
+
|
|
125
183
|
# The split lifecycle validates its installed layout, obtains an exact idle
|
|
126
184
|
# execution hold, and owns the shared lock through both native service stops
|
|
127
185
|
# and filesystem removal. Keep legacy uninstall unchanged for old layouts.
|
|
@@ -243,14 +301,15 @@ else
|
|
|
243
301
|
echo "Aborted; nothing was changed." >&2
|
|
244
302
|
exit 1
|
|
245
303
|
fi
|
|
304
|
+
echo
|
|
246
305
|
|
|
247
306
|
case "$OS_NAME" in
|
|
248
307
|
Darwin)
|
|
249
|
-
LABEL="com.agentsdock.server"
|
|
308
|
+
LABEL="${LABEL:-com.agentsdock.server}"
|
|
250
309
|
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
|
251
310
|
SERVICE_TARGET="gui/$(id -u)/$LABEL"
|
|
252
311
|
if launchctl print "$SERVICE_TARGET" >/dev/null 2>&1; then
|
|
253
|
-
|
|
312
|
+
uninstall_status "$UNINSTALL_RED" "Stopping $LABEL"
|
|
254
313
|
if ! launchctl bootout "$SERVICE_TARGET" >/dev/null 2>&1 && \
|
|
255
314
|
launchctl print "$SERVICE_TARGET" >/dev/null 2>&1; then
|
|
256
315
|
echo "Could not stop $LABEL; no files were removed." >&2
|
|
@@ -270,12 +329,12 @@ case "$OS_NAME" in
|
|
|
270
329
|
fi
|
|
271
330
|
fi
|
|
272
331
|
if [[ -f "$PLIST" ]]; then
|
|
273
|
-
|
|
332
|
+
uninstall_status "$UNINSTALL_RED" "Removing $PLIST"
|
|
274
333
|
rm -f "$PLIST"
|
|
275
334
|
fi
|
|
276
|
-
LOG_DIR="$
|
|
335
|
+
LOG_DIR="$INSTANCE_LOG_DIR"
|
|
277
336
|
if [[ -d "$LOG_DIR" ]]; then
|
|
278
|
-
|
|
337
|
+
uninstall_status "$UNINSTALL_RED" "Removing $LOG_DIR"
|
|
279
338
|
rm -rf "$LOG_DIR"
|
|
280
339
|
fi
|
|
281
340
|
;;
|
|
@@ -286,7 +345,7 @@ case "$OS_NAME" in
|
|
|
286
345
|
exit 1
|
|
287
346
|
fi
|
|
288
347
|
if [[ -f "$SERVICE_FILE" ]] || systemctl --user is-active --quiet "$SERVICE_NAME.service"; then
|
|
289
|
-
|
|
348
|
+
uninstall_status "$UNINSTALL_RED" "Stopping $SERVICE_NAME.service"
|
|
290
349
|
if ! systemctl --user disable --now "$SERVICE_NAME.service" >/dev/null 2>&1 && \
|
|
291
350
|
systemctl --user is-active --quiet "$SERVICE_NAME.service"; then
|
|
292
351
|
echo "Could not stop $SERVICE_NAME.service; no files were removed." >&2
|
|
@@ -306,7 +365,7 @@ case "$OS_NAME" in
|
|
|
306
365
|
fi
|
|
307
366
|
fi
|
|
308
367
|
if [[ -f "$SERVICE_FILE" ]]; then
|
|
309
|
-
|
|
368
|
+
uninstall_status "$UNINSTALL_RED" "Removing $SERVICE_FILE"
|
|
310
369
|
rm -f "$SERVICE_FILE"
|
|
311
370
|
systemctl --user daemon-reload || true
|
|
312
371
|
fi
|
|
@@ -318,7 +377,7 @@ case "$OS_NAME" in
|
|
|
318
377
|
esac
|
|
319
378
|
|
|
320
379
|
if [[ -d "$INSTALL_ROOT" ]]; then
|
|
321
|
-
|
|
380
|
+
uninstall_status "$UNINSTALL_RED" "Removing release runtime at $INSTALL_ROOT"
|
|
322
381
|
shopt -s dotglob nullglob
|
|
323
382
|
for install_entry in "$INSTALL_ROOT"/*; do
|
|
324
383
|
[[ "$install_entry" == "$INSTALL_LOCK_DIR" ]] || rm -rf -- "$install_entry"
|
|
@@ -327,20 +386,30 @@ if [[ -d "$INSTALL_ROOT" ]]; then
|
|
|
327
386
|
fi
|
|
328
387
|
|
|
329
388
|
if [[ -d "$CONFIG_ROOT" ]]; then
|
|
330
|
-
|
|
389
|
+
uninstall_status "$UNINSTALL_RED" "Removing configuration at $CONFIG_ROOT"
|
|
331
390
|
rm -rf "$CONFIG_ROOT"
|
|
332
391
|
fi
|
|
333
392
|
|
|
334
393
|
if [[ "$PURGE_STATE" == "true" ]]; then
|
|
335
394
|
if [[ -e "$STATE_ROOT" || -L "$LEGACY_STATE_ROOT" ]]; then
|
|
336
|
-
[[
|
|
395
|
+
if [[ "$INSTANCE_NAME" == "default" ]]; then
|
|
396
|
+
[[ ! -L "$LEGACY_STATE_ROOT" ]] || rm -f "$LEGACY_STATE_ROOT"
|
|
397
|
+
fi
|
|
337
398
|
[[ ! -e "$STATE_ROOT" ]] || rm -rf "$STATE_ROOT"
|
|
338
|
-
|
|
399
|
+
uninstall_status "$UNINSTALL_RED" "Deleted $STATE_ROOT"
|
|
400
|
+
fi
|
|
401
|
+
elif [[ -e "$STATE_ROOT" && "$MANAGED_RELEASE_NAME" != "true" ]]; then
|
|
402
|
+
echo
|
|
403
|
+
uninstall_status "$UNINSTALL_GREEN" "Preserved chat history, jobs, files, tokens, and secure-peer credentials at $STATE_ROOT."
|
|
404
|
+
echo
|
|
405
|
+
if [[ "$INSTANCE_NAME" == "default" ]]; then
|
|
406
|
+
echo "Re-running ./install.sh will pick ordinary AgentsServer state back up. Pass --purge-state to also delete it."
|
|
407
|
+
else
|
|
408
|
+
echo "To reuse this named history, run ./install.sh --instance $INSTANCE_NAME --port PORT (choose an available port)."
|
|
409
|
+
echo "Do not use bare ./install.sh for this instance; it targets the default server. Pass --purge-state to also delete history."
|
|
339
410
|
fi
|
|
340
|
-
elif [[ -e "$STATE_ROOT" ]]; then
|
|
341
|
-
echo "Preserved chat history, jobs, files, tokens, and secure-peer credentials at $STATE_ROOT."
|
|
342
|
-
echo "Re-running ./install.sh will pick ordinary AgentsServer state back up. Pass --purge-state to also delete it."
|
|
343
411
|
if [[ -e "$STATE_ROOT/team-hub/team-hub.sqlite3" || -L "$STATE_ROOT/team-hub/team-hub.sqlite3" ]]; then
|
|
412
|
+
echo
|
|
344
413
|
echo "Preserved Team Hub state is not auto-reactivated in this beta; use a signed managed recovery or support-assisted restoration."
|
|
345
414
|
fi
|
|
346
415
|
fi
|
|
@@ -354,6 +423,15 @@ if [[ -d "$INSTALL_ROOT" ]] && ! rmdir "$INSTALL_ROOT"; then
|
|
|
354
423
|
exit 1
|
|
355
424
|
fi
|
|
356
425
|
|
|
357
|
-
echo
|
|
358
|
-
|
|
359
|
-
echo "
|
|
426
|
+
echo
|
|
427
|
+
if [[ "$INSTANCE_NAME" == "default" ]]; then
|
|
428
|
+
echo "Note: any persistent chat terminals (tmux sessions named zd_*) keep running"
|
|
429
|
+
echo "independently and are not touched by this script. List them with: tmux ls"
|
|
430
|
+
else
|
|
431
|
+
echo "Note: persistent chat terminals for $INSTANCE_NAME keep running independently and are not touched by this script."
|
|
432
|
+
echo "List only this instance's terminals with: tmux -L agents-server-$INSTANCE_NAME ls"
|
|
433
|
+
fi
|
|
434
|
+
if [[ "$MANAGED_REMOVAL" != "true" ]]; then
|
|
435
|
+
echo
|
|
436
|
+
uninstall_status "$UNINSTALL_GREEN" "Successful!"
|
|
437
|
+
fi
|
|
@@ -217,7 +217,10 @@ def run_preparation(*, status_path: Path, root: Path, public_key: Path, preparat
|
|
|
217
217
|
archive.write_bytes(data)
|
|
218
218
|
source = updates.safe_extract(archive, work / "extracted",
|
|
219
219
|
npm_manifest=manifest if manifest.get("schema") == 2 else None)
|
|
220
|
-
|
|
220
|
+
instance_arguments = updates.instance_installer_arguments(source)
|
|
221
|
+
if instance_arguments or not (source / "execution_preparation.py").is_file():
|
|
222
|
+
# Named instances use their isolated legacy service, not the
|
|
223
|
+
# default-only split gateway preparation/activation protocol.
|
|
221
224
|
# Older signed releases retain their established installer.
|
|
222
225
|
prepared = {"mode": "legacy", "preparation_id": preparation_id, "envelope": envelope}
|
|
223
226
|
else:
|
package/server/update_runner.py
CHANGED
|
@@ -335,6 +335,21 @@ def installer_environment() -> dict[str, str]:
|
|
|
335
335
|
return environment
|
|
336
336
|
|
|
337
337
|
|
|
338
|
+
def instance_installer_arguments(source: Path) -> list[str]:
|
|
339
|
+
"""Never let a named server run an old default-only installer."""
|
|
340
|
+
from server_instances import instance_name
|
|
341
|
+
name = instance_name(os.environ.get("AGENTS_SERVER_INSTANCE", "default"))
|
|
342
|
+
if name == "default":
|
|
343
|
+
return [] # Preserve older signed default installers.
|
|
344
|
+
helper = source / "server_instances.py"
|
|
345
|
+
installer = source / "install.sh"
|
|
346
|
+
if (not helper.is_file() or helper.is_symlink()
|
|
347
|
+
or "INSTANCE_PROTOCOL = 1" not in helper.read_text()
|
|
348
|
+
or '--instance)' not in installer.read_text()):
|
|
349
|
+
raise RuntimeError("This release does not support named instances; the existing server was not replaced.")
|
|
350
|
+
return ["--instance", name]
|
|
351
|
+
|
|
352
|
+
|
|
338
353
|
def run_installer(
|
|
339
354
|
command: list[str],
|
|
340
355
|
*,
|
|
@@ -1549,6 +1564,7 @@ def run_update(args: argparse.Namespace) -> None:
|
|
|
1549
1564
|
command.extend(["--execution-handoff-file", handoff_file])
|
|
1550
1565
|
if manifest.get("schema") == 2 or prepared_update is not None:
|
|
1551
1566
|
command.extend(["--expected-api-contract", str(manifest["api_contract_version"])])
|
|
1567
|
+
command.extend(instance_installer_arguments(source))
|
|
1552
1568
|
if expected_team_hub_id is not None:
|
|
1553
1569
|
command.extend(
|
|
1554
1570
|
[
|
package/server/uv.lock
CHANGED
|
@@ -30,6 +30,7 @@ dependencies = [
|
|
|
30
30
|
{ name = "croniter" },
|
|
31
31
|
{ name = "cryptography" },
|
|
32
32
|
{ name = "fastapi" },
|
|
33
|
+
{ name = "httpx" },
|
|
33
34
|
{ name = "pydantic" },
|
|
34
35
|
{ name = "python-dateutil" },
|
|
35
36
|
{ name = "python-multipart" },
|
|
@@ -44,6 +45,7 @@ requires-dist = [
|
|
|
44
45
|
{ name = "croniter", specifier = ">=6,<7" },
|
|
45
46
|
{ name = "cryptography", specifier = ">=50.0.1,<51" },
|
|
46
47
|
{ name = "fastapi", specifier = ">=0.115,<1" },
|
|
48
|
+
{ name = "httpx", specifier = ">=0.28.1,<1" },
|
|
47
49
|
{ name = "pydantic", specifier = ">=2.10,<3" },
|
|
48
50
|
{ name = "python-dateutil", specifier = ">=2.9,<3" },
|
|
49
51
|
{ name = "python-multipart", specifier = ">=0.0.20,<1" },
|
|
@@ -326,7 +328,7 @@ name = "exceptiongroup"
|
|
|
326
328
|
version = "1.3.1"
|
|
327
329
|
source = { registry = "https://pypi.org/simple" }
|
|
328
330
|
dependencies = [
|
|
329
|
-
{ name = "typing-extensions"
|
|
331
|
+
{ name = "typing-extensions" },
|
|
330
332
|
]
|
|
331
333
|
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
|
332
334
|
wheels = [
|