@agentsdock/server 1.0.7-beta.5 → 1.0.7
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 +21 -7
- package/package.json +1 -1
- package/server/VERSION +1 -1
- package/server/agent_server.py +4913 -660
- 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 +78 -30
- package/server/codex_auth.py +119 -0
- package/server/codex_provider.py +1 -1
- package/server/codex_side_question.py +154 -57
- package/server/cursor_agent_client.py +27 -1
- 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 +281 -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 +653 -0
- package/server/provider_commands.py +579 -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/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/uninstall.sh +95 -17
- package/server/update_preparation.py +4 -1
- package/server/update_runner.py +16 -0
package/server/install.sh
CHANGED
|
@@ -84,6 +84,10 @@ else
|
|
|
84
84
|
STATE_ROOT="$HOME/.agentsdock"
|
|
85
85
|
fi
|
|
86
86
|
SERVICE_NAME="agents-server"
|
|
87
|
+
INSTANCE_NAME="${AGENTS_SERVER_INSTANCE:-default}"
|
|
88
|
+
INSTANCE_EXPLICIT="false"
|
|
89
|
+
LABEL="com.agentsdock.server"
|
|
90
|
+
INSTANCE_LOG_DIR="$HOME/Library/Logs/AgentsServer"
|
|
87
91
|
LEGACY_SERVICE_NAME="zenithbot-agent"
|
|
88
92
|
# AgentsServer's cooperative shutdown has 18 independently bounded cleanup
|
|
89
93
|
# phases in addition to uvicorn's graceful window. Five seconds was shorter
|
|
@@ -141,7 +145,7 @@ SYSTEMD_MANAGED_STOP_ATTEMPTS=50
|
|
|
141
145
|
SYSTEMD_MANAGED_STOP_DELAY=0.1
|
|
142
146
|
SYSTEMD_MANAGED_KILL_ATTEMPTS=20
|
|
143
147
|
|
|
144
|
-
if [[ -t 1 ]] && [[ "${TERM:-}" != "dumb" ]] && [[ -z "${NO_COLOR
|
|
148
|
+
if [[ -t 1 ]] && [[ "${TERM:-}" != "dumb" ]] && [[ -z "${NO_COLOR+x}" ]]; then
|
|
145
149
|
COLOR_GREEN=$'\033[32m'
|
|
146
150
|
COLOR_RED=$'\033[31m'
|
|
147
151
|
COLOR_YELLOW=$'\033[33m'
|
|
@@ -162,13 +166,16 @@ usage() {
|
|
|
162
166
|
cat <<'USAGE'
|
|
163
167
|
Usage: ./install.sh [--port PORT] [--bind ADDRESS] [--release-version VERSION] [--team-hub-host|--reactivate-team-hub-host|--no-team-hub-host] [--team-hub-tailscale-serve-url URL] [--team-hub-direct-ip-url URL] [--non-interactive] [--allow-port-fallback|--no-port-fallback]
|
|
164
168
|
|
|
169
|
+
--instance NAME updates a named instance (use ./instances.sh new to create one
|
|
170
|
+
with an automatically selected name/port). No arguments retain default setup.
|
|
171
|
+
|
|
165
172
|
Installs or updates AgentsServer for the current user. Releases and Python
|
|
166
173
|
runtimes are versioned, the previous healthy release is retained for rollback,
|
|
167
174
|
and existing chat state and generated tokens are preserved. No sudo privileges
|
|
168
175
|
are required.
|
|
169
176
|
|
|
170
|
-
--non-interactive skips
|
|
171
|
-
|
|
177
|
+
--non-interactive skips optional prompts (including clipboard copy); use it for
|
|
178
|
+
unattended/SSH-driven runs.
|
|
172
179
|
|
|
173
180
|
--fresh-install-only refuses an existing installation, state, configuration or
|
|
174
181
|
service. The npm fresh-install command uses it; existing servers update through
|
|
@@ -214,7 +221,8 @@ never silently reactivates preserved state. Without an explicit host option, an
|
|
|
214
221
|
existing host/disabled setting is preserved; new installs default to disabled.
|
|
215
222
|
|
|
216
223
|
--show-token prints the current access token for an already-installed
|
|
217
|
-
AgentsServer
|
|
224
|
+
AgentsServer without reinstalling or restarting. Interactive terminals offer
|
|
225
|
+
optional clipboard copy; redirected output remains just the raw token.
|
|
218
226
|
USAGE
|
|
219
227
|
}
|
|
220
228
|
|
|
@@ -222,6 +230,7 @@ SHOW_TOKEN="false"
|
|
|
222
230
|
|
|
223
231
|
while (($#)); do
|
|
224
232
|
case "$1" in
|
|
233
|
+
--instance) INSTANCE_NAME="${2:?--instance requires a name}"; INSTANCE_EXPLICIT="true"; shift 2 ;;
|
|
225
234
|
--port) PORT="${2:-}"; PORT_EXPLICIT="true"; shift 2 ;;
|
|
226
235
|
--bind) BIND_ADDRESS="${2:-}"; BIND_EXPLICIT="true"; shift 2 ;;
|
|
227
236
|
--release-version) RELEASE_VERSION="${2:-}"; shift 2 ;;
|
|
@@ -340,6 +349,41 @@ while (($#)); do
|
|
|
340
349
|
esac
|
|
341
350
|
done
|
|
342
351
|
|
|
352
|
+
if [[ ! "$INSTANCE_NAME" =~ ^[a-z][a-z0-9-]{0,31}$ ]]; then
|
|
353
|
+
echo "Invalid instance name." >&2
|
|
354
|
+
exit 2
|
|
355
|
+
fi
|
|
356
|
+
if [[ "$INSTANCE_NAME" != "default" || ( "$INSTANCE_EXPLICIT" == "true" && "${AGENTS_SERVER_INSTANCE:-default}" != "default" ) ]]; then
|
|
357
|
+
INSTANCE_SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
358
|
+
instance_bindings="$(bash "$INSTANCE_SCRIPT_DIR/instances.sh" _bindings "$INSTANCE_NAME")" || exit 2
|
|
359
|
+
eval "$instance_bindings"
|
|
360
|
+
# Never inherit the default instance's token, Hub designation or history.
|
|
361
|
+
unset AGENTSDOCK_AGENT_TOKEN ZENITHDOCK_AGENT_TOKEN ZENITHBOT_AGENT_TOKEN
|
|
362
|
+
export AGENTS_SERVER_INSTANCE="$INSTANCE_NAME"
|
|
363
|
+
export AGENTS_SERVER_INSTALL_DIR="$INSTALL_ROOT" AGENTS_SERVER_CONFIG_DIR="$CONFIG_ROOT" AGENTSDOCK_STATE_DIR="$STATE_ROOT"
|
|
364
|
+
[[ -n "${AGENTSDOCK_SERVER_NAME:-}" ]] || export AGENTSDOCK_SERVER_NAME="$INSTANCE_NAME"
|
|
365
|
+
PORT_FALLBACK="false"
|
|
366
|
+
fi
|
|
367
|
+
# Named services keep their independently named legacy unit. The split service
|
|
368
|
+
# protocol currently reserves the default gateway labels; never take them over.
|
|
369
|
+
if [[ "$INSTANCE_NAME" != "default" ]]; then
|
|
370
|
+
if [[ "$EXECUTION_MODE_EXPLICIT" == "true" && "$EXECUTION_MODE" != "legacy" ]]; then
|
|
371
|
+
echo "Named instances currently require --execution-mode legacy; no services were changed." >&2
|
|
372
|
+
exit 2
|
|
373
|
+
fi
|
|
374
|
+
if [[ -e "$INSTALL_ROOT/execution-layout.json" || -L "$INSTALL_ROOT/execution-layout.json" ]]; then
|
|
375
|
+
echo "A named instance cannot use the default split service layout." >&2
|
|
376
|
+
exit 2
|
|
377
|
+
fi
|
|
378
|
+
EXECUTION_MODE="legacy"
|
|
379
|
+
EXECUTION_MODE_EXPLICIT="true"
|
|
380
|
+
fi
|
|
381
|
+
export AGENTS_SERVER_INSTANCE="$INSTANCE_NAME"
|
|
382
|
+
if [[ "$INSTANCE_NAME" != "default" && ! -f "$CONFIG_ROOT/env" && "$PORT_EXPLICIT" != "true" && "$SHOW_TOKEN" != "true" ]]; then
|
|
383
|
+
echo "A new named instance needs --port; use ./instances.sh new for automatic allocation." >&2
|
|
384
|
+
exit 2
|
|
385
|
+
fi
|
|
386
|
+
|
|
343
387
|
if [[ "$PORT_FALLBACK" == "auto" ]]; then
|
|
344
388
|
if [[ "$PORT_EXPLICIT" == "true" ]]; then
|
|
345
389
|
PORT_FALLBACK="false"
|
|
@@ -1278,7 +1322,7 @@ canonical_team_hub_direct_ipv4_url() {
|
|
|
1278
1322
|
|
|
1279
1323
|
LEGACY_ENV_FILE=""
|
|
1280
1324
|
LEGACY_SERVICE_CONTENTS=""
|
|
1281
|
-
if [[ -e "$LEGACY_SERVICE_FILE" || -L "$LEGACY_SERVICE_FILE" ]]; then
|
|
1325
|
+
if [[ "$INSTANCE_NAME" == "default" && ( -e "$LEGACY_SERVICE_FILE" || -L "$LEGACY_SERVICE_FILE" ) ]]; then
|
|
1282
1326
|
if ! LEGACY_SERVICE_CONTENTS="$(read_owned_config_file "$LEGACY_SERVICE_FILE")"; then
|
|
1283
1327
|
echo "$LEGACY_SERVICE_FILE is not a safe regular legacy service file." >&2
|
|
1284
1328
|
exit 1
|
|
@@ -1295,7 +1339,7 @@ if [[ -e "$LEGACY_SERVICE_FILE" || -L "$LEGACY_SERVICE_FILE" ]]; then
|
|
|
1295
1339
|
exit 1
|
|
1296
1340
|
fi
|
|
1297
1341
|
fi
|
|
1298
|
-
if [[ -z "$LEGACY_ENV_FILE" \
|
|
1342
|
+
if [[ "$INSTANCE_NAME" == "default" && -z "$LEGACY_ENV_FILE" \
|
|
1299
1343
|
&& ( -e "$HOME/Zenithbot/.env" || -L "$HOME/Zenithbot/.env" ) ]]; then
|
|
1300
1344
|
LEGACY_ENV_FILE="$HOME/Zenithbot/.env"
|
|
1301
1345
|
fi
|
|
@@ -1334,9 +1378,55 @@ find_existing_token() {
|
|
|
1334
1378
|
return 1
|
|
1335
1379
|
}
|
|
1336
1380
|
|
|
1381
|
+
interactive_token_output() {
|
|
1382
|
+
[[ "$NON_INTERACTIVE" != "true" && -t 0 && -t 1 && -z "$EXPECTED_SERVER_IDENTITY" ]]
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
print_token_for_copy() {
|
|
1386
|
+
local access_token="$1"
|
|
1387
|
+
local copy_reply=""
|
|
1388
|
+
local clipboard_command=()
|
|
1389
|
+
printf '\nAccess token (%s):\n%s\n\n' "$INSTANCE_NAME" "$access_token"
|
|
1390
|
+
# A remote clipboard is not the user's local clipboard. Do not emit OSC 52
|
|
1391
|
+
# sequences or attempt to modify a remote desktop's clipboard over SSH.
|
|
1392
|
+
if [[ -n "${SSH_CONNECTION:-}${SSH_CLIENT:-}${SSH_TTY:-}" ]]; then
|
|
1393
|
+
printf '%s\n' 'Clipboard copy is unavailable over SSH; copy the token line above manually.'
|
|
1394
|
+
return 0
|
|
1395
|
+
fi
|
|
1396
|
+
if [[ "$(uname -s)" == "Darwin" ]] && command -v pbcopy >/dev/null 2>&1; then
|
|
1397
|
+
clipboard_command=(pbcopy)
|
|
1398
|
+
elif [[ -n "${WAYLAND_DISPLAY:-}" ]] && command -v wl-copy >/dev/null 2>&1; then
|
|
1399
|
+
clipboard_command=(wl-copy)
|
|
1400
|
+
elif [[ -n "${DISPLAY:-}" ]] && command -v xclip >/dev/null 2>&1; then
|
|
1401
|
+
clipboard_command=(xclip -selection clipboard)
|
|
1402
|
+
elif [[ -n "${DISPLAY:-}" ]] && command -v xsel >/dev/null 2>&1; then
|
|
1403
|
+
clipboard_command=(xsel --clipboard --input)
|
|
1404
|
+
fi
|
|
1405
|
+
if ((${#clipboard_command[@]} == 0)); then
|
|
1406
|
+
printf '%s\n' 'Clipboard copy is unavailable here; copy the token line above manually.'
|
|
1407
|
+
return 0
|
|
1408
|
+
fi
|
|
1409
|
+
read -r -p "Copy token to this machine's clipboard? [y/N] " copy_reply || return 0
|
|
1410
|
+
case "$copy_reply" in
|
|
1411
|
+
y|Y|[yY][eE][sS]) ;;
|
|
1412
|
+
*) return 0 ;;
|
|
1413
|
+
esac
|
|
1414
|
+
# Pass the credential via stdin, never an external process's argv. Optional
|
|
1415
|
+
# clipboard failures must not turn a successful installation into a failure.
|
|
1416
|
+
if printf '%s' "$access_token" | "${clipboard_command[@]}" >/dev/null 2>&1; then
|
|
1417
|
+
printf '%s\n' 'Copied to your clipboard.'
|
|
1418
|
+
else
|
|
1419
|
+
printf '%s\n' 'Could not copy to the clipboard; copy the token line above manually.'
|
|
1420
|
+
fi
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1337
1423
|
if [[ "$SHOW_TOKEN" == "true" ]]; then
|
|
1338
1424
|
if TOKEN_TO_SHOW="$(find_existing_token)"; then
|
|
1339
|
-
|
|
1425
|
+
if interactive_token_output; then
|
|
1426
|
+
print_token_for_copy "$TOKEN_TO_SHOW"
|
|
1427
|
+
else
|
|
1428
|
+
printf '%s\n' "$TOKEN_TO_SHOW"
|
|
1429
|
+
fi
|
|
1340
1430
|
exit 0
|
|
1341
1431
|
fi
|
|
1342
1432
|
echo "No AgentsServer access token found at $ENV_FILE. Run install.sh first." >&2
|
|
@@ -1345,7 +1435,7 @@ fi
|
|
|
1345
1435
|
|
|
1346
1436
|
OS_NAME="$(uname -s)"
|
|
1347
1437
|
SYSTEMD_SERVICE_FILE="$HOME/.config/systemd/user/$SERVICE_NAME.service"
|
|
1348
|
-
LABEL="com.agentsdock.server"
|
|
1438
|
+
LABEL="${LABEL:-com.agentsdock.server}"
|
|
1349
1439
|
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
|
|
1350
1440
|
|
|
1351
1441
|
validate_legacy_macos_update_roots() {
|
|
@@ -1749,7 +1839,7 @@ if [[ "$TEAM_HUB_MODE" == "host" && "$TEAM_HUB_OPERATION_PENDING" != "true" \
|
|
|
1749
1839
|
fi
|
|
1750
1840
|
fi
|
|
1751
1841
|
|
|
1752
|
-
RELEASE_FILES=(activation_transaction.py execution_activation.py execution_legacy_runner.py execution_preparation.py update_preparation.py update_handoff.py update_recovery.py execution_update_status.py execution_uninstall.py execution_recovery.py execution_recovery_status.py execution_http.py execution_durability.py execution_control.py execution_install.py execution_maintenance.py execution_manage.py execution_ownership.py execution_service.py execution_transport.py agent_server.py workspace_git.py team_hub_host.py secure_peer_runtime.py team_mail_runtime.py team_mail_websocket.py team_mail_grants.py secure_peer_delivery.py agentsdock_jobs.py agentsdock_chats.py chat_mailbox.py agentsdock_emergency.py agentsdock_publish.py agentsdock_mail.py agentsdock_team.py provider_commands.py claude_sdk_client.py claude_goals.py claude_background_reconciliation.py codex_app_server.py codex_auth.py codex_provider.py side_questions.py title_generation.py codex_side_question.py claude_side_question.py cursor_agent_client.py cursor_process_guard.py claude_history_repair.py claude_history_provenance.py codex_history_repair.py public_chat_shares.py public_chat_transcript.py public_chat_share_routes.py interactive_chat_shares.py interactive_chat_share_routes.py interactive_chat_share_web.py interactive_chat_projection.py interactive_chat_runtime.py interactive_chat_native.py shared_chat_videos.py shared_chat_video_stream.py interactive_chat_controls.py install.sh uninstall.sh update_runner.py pyproject.toml uv.lock VERSION release-public-key.pem LICENSE NOTICE)
|
|
1842
|
+
RELEASE_FILES=(activation_transaction.py execution_activation.py execution_legacy_runner.py execution_preparation.py update_preparation.py update_handoff.py update_recovery.py execution_update_status.py execution_uninstall.py execution_recovery.py execution_recovery_status.py execution_http.py execution_durability.py execution_control.py execution_install.py execution_maintenance.py execution_manage.py execution_ownership.py execution_service.py execution_transport.py agent_server.py local_session_ownership.py cursor_history.py workspace_git.py team_hub_host.py secure_peer_runtime.py team_mail_runtime.py team_mail_websocket.py team_mail_grants.py secure_peer_delivery.py agentsdock_jobs.py agentsdock_chats.py chat_mailbox.py agentsdock_emergency.py agentsdock_publish.py agentsdock_mail.py agentsdock_team.py provider_commands.py provider_usage.py claude_sdk_client.py claude_model_catalog.py claude_goals.py claude_background_reconciliation.py codex_app_server.py codex_auth.py codex_provider.py side_questions.py title_generation.py codex_side_question.py claude_side_question.py cursor_agent_client.py cursor_provider_mcp.py opencode_agent_client.py cursor_process_guard.py claude_history_repair.py claude_history_provenance.py codex_history_repair.py public_chat_shares.py public_chat_transcript.py public_chat_share_routes.py interactive_chat_shares.py interactive_chat_share_routes.py interactive_chat_share_web.py interactive_chat_projection.py interactive_chat_runtime.py interactive_chat_native.py shared_chat_videos.py shared_chat_video_stream.py interactive_chat_controls.py install.sh uninstall.sh instances.sh server_instances.py update_runner.py pyproject.toml uv.lock VERSION release-public-key.pem LICENSE NOTICE)
|
|
1753
1843
|
RELEASE_DIRECTORIES=(agentsdock_team_hub)
|
|
1754
1844
|
TEAM_HUB_RELEASE_FILES=(
|
|
1755
1845
|
__init__.py
|
|
@@ -1801,12 +1891,11 @@ for name in "${RELEASE_DIRECTORIES[@]}"; do
|
|
|
1801
1891
|
echo "$name is missing beside install.sh or is not a real directory." >&2
|
|
1802
1892
|
exit 1
|
|
1803
1893
|
fi
|
|
1894
|
+
# Local Python runs create bytecode caches. Never copy those (staging uses
|
|
1895
|
+
# the explicit manifest below), but still reject links/special files anywhere,
|
|
1896
|
+
# including inside a cache directory.
|
|
1804
1897
|
if find "$SOURCE_DIR/$name" \( -type l -o \( ! -type d ! -type f \) \) -print -quit | grep -q .; then
|
|
1805
|
-
echo "$name contains
|
|
1806
|
-
exit 1
|
|
1807
|
-
fi
|
|
1808
|
-
if [[ -z "$ACTIVATE_PREPARED" && "$RECOVER_ONLY" != "true" ]] && find "$SOURCE_DIR/$name" \( -type f \( -name '*.pyc' -o -name '*.pyo' \) -o -type d -name '__pycache__' \) -print -quit | grep -q .; then
|
|
1809
|
-
echo "$name contains linked or generated entries and cannot be installed." >&2
|
|
1898
|
+
echo "$name contains linked or special entries and cannot be installed." >&2
|
|
1810
1899
|
exit 1
|
|
1811
1900
|
fi
|
|
1812
1901
|
done
|
|
@@ -1820,13 +1909,13 @@ done
|
|
|
1820
1909
|
# bound by the receipt or owned recovery journal before activation; raw source
|
|
1821
1910
|
# archives continue to require the exact clean allowlist.
|
|
1822
1911
|
if [[ -z "$ACTIVATE_PREPARED" && "$RECOVER_ONLY" != "true" ]]; then
|
|
1823
|
-
TEAM_HUB_RELEASE_FILE_COUNT="$(find "$SOURCE_DIR/agentsdock_team_hub" -type f | wc -l)"
|
|
1912
|
+
TEAM_HUB_RELEASE_FILE_COUNT="$(find "$SOURCE_DIR/agentsdock_team_hub" -type d -name '__pycache__' -prune -o -type f ! -name '*.pyc' ! -name '*.pyo' -print | wc -l)"
|
|
1824
1913
|
TEAM_HUB_RELEASE_FILE_COUNT="${TEAM_HUB_RELEASE_FILE_COUNT//[[:space:]]/}"
|
|
1825
1914
|
if [[ "$TEAM_HUB_RELEASE_FILE_COUNT" != "${#TEAM_HUB_RELEASE_FILES[@]}" ]]; then
|
|
1826
1915
|
echo "agentsdock_team_hub contains unexpected release files." >&2
|
|
1827
1916
|
exit 1
|
|
1828
1917
|
fi
|
|
1829
|
-
TEAM_HUB_RELEASE_DIRECTORY_COUNT="$(find "$SOURCE_DIR/agentsdock_team_hub" -type d | wc -l)"
|
|
1918
|
+
TEAM_HUB_RELEASE_DIRECTORY_COUNT="$(find "$SOURCE_DIR/agentsdock_team_hub" -type d -name '__pycache__' -prune -o -type d -print | wc -l)"
|
|
1830
1919
|
TEAM_HUB_RELEASE_DIRECTORY_COUNT="${TEAM_HUB_RELEASE_DIRECTORY_COUNT//[[:space:]]/}"
|
|
1831
1920
|
if [[ "$TEAM_HUB_RELEASE_DIRECTORY_COUNT" != "2" ]]; then
|
|
1832
1921
|
echo "agentsdock_team_hub contains unexpected release directories." >&2
|
|
@@ -2459,7 +2548,7 @@ backup_runtime_configuration() {
|
|
|
2459
2548
|
current_snapshot="${current_snapshot#*|}"
|
|
2460
2549
|
PRIOR_SERVICE_ENABLED="${current_snapshot%%|*}"
|
|
2461
2550
|
fi
|
|
2462
|
-
if [[ "$OS_NAME" == "Linux" ]]; then
|
|
2551
|
+
if [[ "$OS_NAME" == "Linux" && "${INSTANCE_NAME:-default}" == "default" ]]; then
|
|
2463
2552
|
local legacy_exists="false"
|
|
2464
2553
|
local legacy_snapshot=""
|
|
2465
2554
|
if [[ -e "$LEGACY_SERVICE_FILE" || -L "$LEGACY_SERVICE_FILE" ]]; then
|
|
@@ -3496,6 +3585,7 @@ sync_release_dependencies() (
|
|
|
3496
3585
|
--project "$STAGE_DIR" \
|
|
3497
3586
|
--python '>=3.10' \
|
|
3498
3587
|
--no-dev \
|
|
3588
|
+
--quiet \
|
|
3499
3589
|
--frozen
|
|
3500
3590
|
)
|
|
3501
3591
|
|
|
@@ -3526,6 +3616,8 @@ validate_staged_release_runtime() (
|
|
|
3526
3616
|
"$STAGE_DIR/execution_service.py" \
|
|
3527
3617
|
"$STAGE_DIR/execution_transport.py" \
|
|
3528
3618
|
"$STAGE_DIR/agent_server.py" \
|
|
3619
|
+
"$STAGE_DIR/local_session_ownership.py" \
|
|
3620
|
+
"$STAGE_DIR/cursor_history.py" \
|
|
3529
3621
|
"$STAGE_DIR/team_hub_host.py" \
|
|
3530
3622
|
"$STAGE_DIR/secure_peer_runtime.py" \
|
|
3531
3623
|
"$STAGE_DIR/team_mail_runtime.py" \
|
|
@@ -3540,7 +3632,9 @@ validate_staged_release_runtime() (
|
|
|
3540
3632
|
"$STAGE_DIR/agentsdock_mail.py" \
|
|
3541
3633
|
"$STAGE_DIR/agentsdock_team.py" \
|
|
3542
3634
|
"$STAGE_DIR/provider_commands.py" \
|
|
3635
|
+
"$STAGE_DIR/provider_usage.py" \
|
|
3543
3636
|
"$STAGE_DIR/claude_sdk_client.py" \
|
|
3637
|
+
"$STAGE_DIR/claude_model_catalog.py" \
|
|
3544
3638
|
"$STAGE_DIR/claude_goals.py" \
|
|
3545
3639
|
"$STAGE_DIR/claude_background_reconciliation.py" \
|
|
3546
3640
|
"$STAGE_DIR/codex_app_server.py" \
|
|
@@ -3552,6 +3646,8 @@ validate_staged_release_runtime() (
|
|
|
3552
3646
|
"$STAGE_DIR/title_generation.py" \
|
|
3553
3647
|
"$STAGE_DIR/claude_side_question.py" \
|
|
3554
3648
|
"$STAGE_DIR/cursor_agent_client.py" \
|
|
3649
|
+
"$STAGE_DIR/cursor_provider_mcp.py" \
|
|
3650
|
+
"$STAGE_DIR/opencode_agent_client.py" \
|
|
3555
3651
|
"$STAGE_DIR/cursor_process_guard.py" \
|
|
3556
3652
|
"$STAGE_DIR/claude_history_repair.py" \
|
|
3557
3653
|
"$STAGE_DIR/claude_history_provenance.py" \
|
|
@@ -3569,8 +3665,9 @@ validate_staged_release_runtime() (
|
|
|
3569
3665
|
"$STAGE_DIR/shared_chat_video_stream.py" \
|
|
3570
3666
|
"$STAGE_DIR/interactive_chat_controls.py" \
|
|
3571
3667
|
"$STAGE_DIR/update_runner.py"
|
|
3668
|
+
"$STAGE_DIR/.venv/bin/python" -m py_compile "$STAGE_DIR/server_instances.py"
|
|
3572
3669
|
"$STAGE_DIR/.venv/bin/python" -m compileall -q "$STAGE_DIR/agentsdock_team_hub"
|
|
3573
|
-
PYTHONPATH="$STAGE_DIR" "$STAGE_DIR/.venv/bin/python" -c 'import execution_activation, execution_preparation, update_preparation, update_handoff, update_recovery, execution_update_status, execution_uninstall, execution_recovery, execution_recovery_status, execution_http, execution_durability, execution_control, execution_install, execution_maintenance, execution_manage, execution_ownership, execution_service, execution_transport; import workspace_git; import codex_auth, codex_provider, side_questions, title_generation, codex_side_question, claude_side_question, agentsdock_team_hub, cursor_agent_client, cursor_process_guard, secure_peer_delivery, secure_peer_runtime, team_mail_runtime, team_mail_websocket, team_mail_grants, team_hub_host, agentsdock_mail, agentsdock_team, claude_history_repair, claude_history_provenance, claude_goals, claude_background_reconciliation, codex_history_repair, public_chat_shares, public_chat_transcript, public_chat_share_routes, interactive_chat_shares, interactive_chat_share_routes, interactive_chat_share_web, interactive_chat_projection, interactive_chat_runtime, interactive_chat_native, shared_chat_videos, shared_chat_video_stream, interactive_chat_controls, chat_mailbox, provider_commands; from agentsdock_team_hub import secure_peer, secure_peer_hub' >/dev/null
|
|
3670
|
+
PYTHONPATH="$STAGE_DIR" "$STAGE_DIR/.venv/bin/python" -c 'import execution_activation, execution_preparation, update_preparation, update_handoff, update_recovery, execution_update_status, execution_uninstall, execution_recovery, execution_recovery_status, execution_http, execution_durability, execution_control, execution_install, execution_maintenance, execution_manage, execution_ownership, execution_service, execution_transport; import workspace_git, claude_model_catalog, server_instances, local_session_ownership, cursor_history; import codex_auth, codex_provider, side_questions, title_generation, codex_side_question, claude_side_question, agentsdock_team_hub, cursor_agent_client, cursor_provider_mcp, opencode_agent_client, cursor_process_guard, secure_peer_delivery, secure_peer_runtime, team_mail_runtime, team_mail_websocket, team_mail_grants, team_hub_host, agentsdock_mail, agentsdock_team, claude_history_repair, claude_history_provenance, claude_goals, claude_background_reconciliation, codex_history_repair, public_chat_shares, public_chat_transcript, public_chat_share_routes, interactive_chat_shares, interactive_chat_share_routes, interactive_chat_share_web, interactive_chat_projection, interactive_chat_runtime, interactive_chat_native, shared_chat_videos, shared_chat_video_stream, interactive_chat_controls, chat_mailbox, provider_commands, provider_usage; from agentsdock_team_hub import secure_peer, secure_peer_hub' >/dev/null
|
|
3574
3671
|
)
|
|
3575
3672
|
|
|
3576
3673
|
abort_unclaimed_team_hub_reactivation() {
|
|
@@ -3898,6 +3995,7 @@ for name in "${TEAM_HUB_RELEASE_FILES[@]}"; do
|
|
|
3898
3995
|
"$STAGE_DIR/agentsdock_team_hub/$name"
|
|
3899
3996
|
done
|
|
3900
3997
|
chmod 755 "$STAGE_DIR/agent_server.py" "$STAGE_DIR/agentsdock_jobs.py" "$STAGE_DIR/agentsdock_chats.py" "$STAGE_DIR/agentsdock_emergency.py" "$STAGE_DIR/agentsdock_publish.py" "$STAGE_DIR/agentsdock_mail.py" "$STAGE_DIR/agentsdock_team.py" "$STAGE_DIR/install.sh" "$STAGE_DIR/uninstall.sh" "$STAGE_DIR/update_runner.py"
|
|
3998
|
+
chmod 755 "$STAGE_DIR/instances.sh"
|
|
3901
3999
|
|
|
3902
4000
|
if [[ "$PREPARE_ONLY" == "true" ]]; then
|
|
3903
4001
|
source_inventory="$(mktemp "$INSTALL_ROOT/.prepared-inventory.XXXXXXXX")" || exit 1
|
|
@@ -3922,7 +4020,9 @@ with output.open("w") as stream:
|
|
|
3922
4020
|
PYINVENTORY
|
|
3923
4021
|
fi
|
|
3924
4022
|
|
|
3925
|
-
echo "[2/7]
|
|
4023
|
+
echo "[2/7] Preparing private Python dependencies for instance $INSTANCE_NAME"
|
|
4024
|
+
echo " Reusing uv's package cache where available; errors will still be shown."
|
|
4025
|
+
echo " This does not reinstall Claude Code, Codex, or tmux."
|
|
3926
4026
|
if run_timed_stage \
|
|
3927
4027
|
"dependency resolution" \
|
|
3928
4028
|
"$DEPENDENCY_SYNC_TIMEOUT_SECONDS" \
|
|
@@ -3998,7 +4098,7 @@ write_runtime_env() {
|
|
|
3998
4098
|
local filter_status=0
|
|
3999
4099
|
preserved_contents="$(read_owned_config_file "$PRESERVE_SOURCE")" || return 1
|
|
4000
4100
|
if printf '%s\n' "$preserved_contents" \
|
|
4001
|
-
| grep -Ev '^(AGENTSDOCK_(STATE_DIR|AGENT_CWD|AGENT_BIND|AGENT_PORT|AGENT_TOKEN|SERVER_NAME|TEAM_HUB_MODE|TEAM_HUB_TRANSPORT|TEAM_HUB_URL|TEAM_HUB_DIRECT_IP_URL|TEAM_HUB_REACTIVATION_HUB_ID|TEAM_HUB_REACTIVATION_OPERATION_ID|TEAM_HUB_REACTIVATION_SNAPSHOT|TEAM_HUB_UPDATE_HUB_ID|TEAM_HUB_UPDATE_OPERATION_ID|TEAM_HUB_UPDATE_SNAPSHOT)|AGENTS_SERVER_(STATE_DIR|INSTALL_DIR)|ZENITHBOT_AGENT_(DIR|CWD|BIND|PORT|TOKEN)|ZENITHDOCK_AGENT_TOKEN|PATH)=' \
|
|
4101
|
+
| grep -Ev '^(AGENTSDOCK_(STATE_DIR|AGENT_CWD|AGENT_BIND|AGENT_PORT|AGENT_TOKEN|SERVER_NAME|TEAM_HUB_MODE|TEAM_HUB_TRANSPORT|TEAM_HUB_URL|TEAM_HUB_DIRECT_IP_URL|TEAM_HUB_REACTIVATION_HUB_ID|TEAM_HUB_REACTIVATION_OPERATION_ID|TEAM_HUB_REACTIVATION_SNAPSHOT|TEAM_HUB_UPDATE_HUB_ID|TEAM_HUB_UPDATE_OPERATION_ID|TEAM_HUB_UPDATE_SNAPSHOT)|AGENTS_SERVER_(STATE_DIR|INSTALL_DIR|CONFIG_DIR|INSTANCE)|ZENITHBOT_AGENT_(DIR|CWD|BIND|PORT|TOKEN)|ZENITHDOCK_AGENT_TOKEN|PATH)=' \
|
|
4002
4102
|
> "$env_temp"; then
|
|
4003
4103
|
:
|
|
4004
4104
|
else
|
|
@@ -4024,6 +4124,8 @@ AGENTSDOCK_TEAM_HUB_TRANSPORT=$TEAM_HUB_TRANSPORT
|
|
|
4024
4124
|
AGENTSDOCK_TEAM_HUB_URL=$TEAM_HUB_URL
|
|
4025
4125
|
AGENTSDOCK_TEAM_HUB_DIRECT_IP_URL=$TEAM_HUB_DIRECT_IP_URL
|
|
4026
4126
|
AGENTS_SERVER_INSTALL_DIR=$INSTALL_ROOT
|
|
4127
|
+
AGENTS_SERVER_CONFIG_DIR=$CONFIG_ROOT
|
|
4128
|
+
AGENTS_SERVER_INSTANCE=${INSTANCE_NAME:-default}
|
|
4027
4129
|
PATH=$SERVER_PATH
|
|
4028
4130
|
EOF
|
|
4029
4131
|
if ! replace_activation_config env "$env_temp" 600; then
|
|
@@ -4181,21 +4283,23 @@ restart_service() {
|
|
|
4181
4283
|
return
|
|
4182
4284
|
fi
|
|
4183
4285
|
if [[ "$OS_NAME" == "Linux" ]]; then
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
&&
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
"$
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
"$
|
|
4197
|
-
|
|
4198
|
-
|
|
4286
|
+
if [[ "${INSTANCE_NAME:-default}" == "default" ]]; then
|
|
4287
|
+
local legacy_exists="false"
|
|
4288
|
+
local legacy_snapshot=""
|
|
4289
|
+
[[ -f "$LEGACY_SERVICE_FILE" && ! -L "$LEGACY_SERVICE_FILE" ]] \
|
|
4290
|
+
&& legacy_exists="true"
|
|
4291
|
+
if [[ "$PRIOR_LEGACY_SERVICE_STATE" == "absent" ]]; then
|
|
4292
|
+
legacy_snapshot="$(systemd_unit_snapshot \
|
|
4293
|
+
"$LEGACY_SERVICE_NAME.service" "$legacy_exists")" || return 1
|
|
4294
|
+
[[ "${legacy_snapshot%%|*}" == "absent" ]] || return 1
|
|
4295
|
+
else
|
|
4296
|
+
systemctl --user disable --now "$LEGACY_SERVICE_NAME.service" \
|
|
4297
|
+
>/dev/null || return 1
|
|
4298
|
+
legacy_snapshot="$(systemd_unit_snapshot \
|
|
4299
|
+
"$LEGACY_SERVICE_NAME.service" "$legacy_exists")" || return 1
|
|
4300
|
+
[[ "${legacy_snapshot%%|*}" == "stopped" \
|
|
4301
|
+
&& "${legacy_snapshot#*|}" == "false|"* ]] || return 1
|
|
4302
|
+
fi
|
|
4199
4303
|
fi
|
|
4200
4304
|
systemctl --user daemon-reload || return
|
|
4201
4305
|
systemctl --user enable "$SERVICE_NAME.service" >/dev/null || return
|
|
@@ -4527,19 +4631,21 @@ restore_prior_service_state() {
|
|
|
4527
4631
|
[[ "$PRIOR_SERVICE_STATE" == "absent" ]] || return 1
|
|
4528
4632
|
}
|
|
4529
4633
|
fi
|
|
4530
|
-
if [[ "$
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4634
|
+
if [[ "${INSTANCE_NAME:-default}" == "default" ]]; then
|
|
4635
|
+
if [[ "$PRIOR_LEGACY_SERVICE_ENABLED" == "true" ]]; then
|
|
4636
|
+
systemctl --user enable "$LEGACY_SERVICE_NAME.service" >/dev/null || return 1
|
|
4637
|
+
elif [[ "$PRIOR_LEGACY_SERVICE_STATE" == "absent" ]]; then
|
|
4638
|
+
systemctl --user disable "$LEGACY_SERVICE_NAME.service" >/dev/null 2>&1 || true
|
|
4639
|
+
else
|
|
4640
|
+
systemctl --user disable "$LEGACY_SERVICE_NAME.service" >/dev/null || return 1
|
|
4641
|
+
fi
|
|
4642
|
+
if [[ "$PRIOR_LEGACY_SERVICE_STATE" == "running" ]]; then
|
|
4643
|
+
systemctl --user start "$LEGACY_SERVICE_NAME.service" || return 1
|
|
4644
|
+
else
|
|
4645
|
+
systemctl --user stop "$LEGACY_SERVICE_NAME.service" >/dev/null 2>&1 || {
|
|
4646
|
+
[[ "$PRIOR_LEGACY_SERVICE_STATE" == "absent" ]] || return 1
|
|
4647
|
+
}
|
|
4648
|
+
fi
|
|
4543
4649
|
fi
|
|
4544
4650
|
local current_exists="false"
|
|
4545
4651
|
local legacy_exists="false"
|
|
@@ -4555,7 +4661,7 @@ restore_prior_service_state() {
|
|
|
4555
4661
|
&& "${observed_snapshot#*|}" == "$PRIOR_SERVICE_ENABLED|"* ]] \
|
|
4556
4662
|
|| return 1
|
|
4557
4663
|
fi
|
|
4558
|
-
if [[ "$PRIOR_LEGACY_SERVICE_STATE" != "running" ]]; then
|
|
4664
|
+
if [[ "${INSTANCE_NAME:-default}" == "default" && "$PRIOR_LEGACY_SERVICE_STATE" != "running" ]]; then
|
|
4559
4665
|
observed_snapshot="$(systemd_unit_snapshot \
|
|
4560
4666
|
"$LEGACY_SERVICE_NAME.service" "$legacy_exists")" || return 1
|
|
4561
4667
|
[[ "${observed_snapshot%%|*}" == "$PRIOR_LEGACY_SERVICE_STATE" \
|
|
@@ -4722,7 +4828,7 @@ write_service_files() {
|
|
|
4722
4828
|
if [[ "$OS_NAME" == "Linux" ]]; then
|
|
4723
4829
|
USER_SERVICE_DIR="$HOME/.config/systemd/user"
|
|
4724
4830
|
mkdir -p "$USER_SERVICE_DIR"
|
|
4725
|
-
service_temp="$USER_SERVICE_DIR
|
|
4831
|
+
service_temp="$USER_SERVICE_DIR/.$SERVICE_NAME.service.activation-$ACTIVATION_TRANSACTION_ID-service.source"
|
|
4726
4832
|
(umask 077; set -o noclobber; : > "$service_temp") 2>/dev/null || return 1
|
|
4727
4833
|
chmod 600 "$service_temp" || return 1
|
|
4728
4834
|
cat > "$service_temp" <<EOF
|
|
@@ -4756,8 +4862,9 @@ EOF
|
|
|
4756
4862
|
SERVICE_KIND="systemd-user"
|
|
4757
4863
|
elif [[ "$OS_NAME" == "Darwin" ]]; then
|
|
4758
4864
|
LAUNCH_AGENTS="$HOME/Library/LaunchAgents"
|
|
4759
|
-
|
|
4760
|
-
|
|
4865
|
+
local instance_log_dir="${INSTANCE_LOG_DIR:-$HOME/Library/Logs/AgentsServer}"
|
|
4866
|
+
mkdir -p "$LAUNCH_AGENTS" "$instance_log_dir"
|
|
4867
|
+
service_temp="$LAUNCH_AGENTS/.$LABEL.plist.activation-$ACTIVATION_TRANSACTION_ID-service.source"
|
|
4761
4868
|
(umask 077; set -o noclobber; : > "$service_temp") 2>/dev/null || return 1
|
|
4762
4869
|
chmod 600 "$service_temp" || return 1
|
|
4763
4870
|
local launchd_server_name_entry=""
|
|
@@ -4790,11 +4897,13 @@ $launchd_server_name_entry
|
|
|
4790
4897
|
<key>AGENTSDOCK_TEAM_HUB_URL</key><string>$TEAM_HUB_URL</string>
|
|
4791
4898
|
<key>AGENTSDOCK_TEAM_HUB_DIRECT_IP_URL</key><string>$TEAM_HUB_DIRECT_IP_URL</string>
|
|
4792
4899
|
<key>AGENTS_SERVER_INSTALL_DIR</key><string>$INSTALL_ROOT</string>
|
|
4900
|
+
<key>AGENTS_SERVER_CONFIG_DIR</key><string>$CONFIG_ROOT</string>
|
|
4901
|
+
<key>AGENTS_SERVER_INSTANCE</key><string>${INSTANCE_NAME:-default}</string>
|
|
4793
4902
|
<key>PATH</key><string>$SERVER_PATH</string>
|
|
4794
4903
|
</dict>
|
|
4795
4904
|
<key>RunAtLoad</key><true/><key>KeepAlive</key><true/>
|
|
4796
|
-
<key>StandardOutPath</key><string>$
|
|
4797
|
-
<key>StandardErrorPath</key><string>$
|
|
4905
|
+
<key>StandardOutPath</key><string>$instance_log_dir/server.log</string>
|
|
4906
|
+
<key>StandardErrorPath</key><string>$instance_log_dir/server-error.log</string>
|
|
4798
4907
|
</dict></plist>
|
|
4799
4908
|
EOF
|
|
4800
4909
|
if ! replace_activation_config service "$service_temp" 600; then
|
|
@@ -4928,7 +5037,8 @@ service_manager_owns_listener() {
|
|
|
4928
5037
|
services=("$LABEL")
|
|
4929
5038
|
[[ "$EXECUTION_MODE" != "split" ]] || services+=("com.agentsdock.gateway")
|
|
4930
5039
|
else
|
|
4931
|
-
services=("$SERVICE_NAME"
|
|
5040
|
+
services=("$SERVICE_NAME")
|
|
5041
|
+
[[ "${INSTANCE_NAME:-default}" != "default" ]] || services+=("${LEGACY_SERVICE_NAME:-}")
|
|
4932
5042
|
[[ "$EXECUTION_MODE" != "split" ]] || services+=("agents-server-gateway")
|
|
4933
5043
|
fi
|
|
4934
5044
|
for service in "${services[@]}"; do
|
|
@@ -4968,7 +5078,8 @@ pinned_managed_http_get() {
|
|
|
4968
5078
|
services=("$LABEL")
|
|
4969
5079
|
[[ "$EXECUTION_MODE" != "split" ]] || services+=("com.agentsdock.gateway")
|
|
4970
5080
|
else
|
|
4971
|
-
services=("$SERVICE_NAME"
|
|
5081
|
+
services=("$SERVICE_NAME")
|
|
5082
|
+
[[ "${INSTANCE_NAME:-default}" != "default" ]] || services+=("${LEGACY_SERVICE_NAME:-}")
|
|
4972
5083
|
[[ "$EXECUTION_MODE" != "split" ]] || services+=("agents-server-gateway")
|
|
4973
5084
|
fi
|
|
4974
5085
|
for service in "${services[@]}"; do
|
|
@@ -7013,36 +7124,125 @@ if [[ "$CLAUDE_READY" == "false" && "$CODEX_READY" == "false" ]]; then
|
|
|
7013
7124
|
echo " Sign in to at least one before starting a chat."
|
|
7014
7125
|
fi
|
|
7015
7126
|
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
SERVER_URL="
|
|
7023
|
-
|
|
7127
|
+
setup_network_summary() {
|
|
7128
|
+
TAILSCALE_IP=""
|
|
7129
|
+
TAILSCALE_STATUS="unknown"
|
|
7130
|
+
TAILSCALE_BIND_MATCH="false"
|
|
7131
|
+
SERVER_LOCAL_ONLY="false"
|
|
7132
|
+
NETWORK_URLS=""
|
|
7133
|
+
SERVER_URL="$(health_origin "$PORT")"
|
|
7134
|
+
local network_bindings=""
|
|
7135
|
+
# The shipped helper emits only fixed keys and shell-quoted validated values.
|
|
7136
|
+
# Optional network diagnostics must not fail an already healthy installation.
|
|
7137
|
+
if network_bindings="$("$CURRENT_LINK/.venv/bin/python" \
|
|
7138
|
+
"$CURRENT_LINK/server_instances.py" _setup-network \
|
|
7139
|
+
--bind "$BIND_ADDRESS" --port "$PORT" 2>/dev/null)" \
|
|
7140
|
+
&& [[ -n "$network_bindings" ]]; then
|
|
7141
|
+
eval "$network_bindings"
|
|
7142
|
+
fi
|
|
7143
|
+
}
|
|
7144
|
+
|
|
7145
|
+
print_tailscale_summary() {
|
|
7146
|
+
case "$TAILSCALE_STATUS" in
|
|
7147
|
+
connected)
|
|
7148
|
+
if [[ "$TAILSCALE_BIND_MATCH" == "true" ]]; then
|
|
7149
|
+
echo " $CHECK_MARK Tailscale already connected: http://$TAILSCALE_IP:$PORT (tailnet access rules still apply)"
|
|
7150
|
+
elif [[ "$SERVER_LOCAL_ONLY" == "true" ]]; then
|
|
7151
|
+
echo " $DOT_MARK Tailscale already connected; this server is bound to localhost only, so phones cannot connect directly."
|
|
7152
|
+
echo " For phone access, choose a reachable server bind: https://github.com/ZhengyiLuo/AgentsServer"
|
|
7153
|
+
else
|
|
7154
|
+
echo " $DOT_MARK Tailscale already connected; its IPv4 address is not available on this server's configured bind."
|
|
7155
|
+
echo " For tailnet access, review the server bind: https://github.com/ZhengyiLuo/AgentsServer"
|
|
7156
|
+
fi
|
|
7157
|
+
;;
|
|
7158
|
+
disconnected)
|
|
7159
|
+
echo " $DOT_MARK Tailscale already installed but not connected; no installation or configuration changes made."
|
|
7160
|
+
echo " To connect from other networks, open Tailscale and sign in/connect."
|
|
7161
|
+
;;
|
|
7162
|
+
not-installed)
|
|
7163
|
+
echo " $DOT_MARK optional: Tailscale was not found; use your LAN address on the same network, or see https://tailscale.com/download"
|
|
7164
|
+
;;
|
|
7165
|
+
unavailable)
|
|
7166
|
+
echo " $DOT_MARK Tailscale already installed; connection status could not be checked. No setup changes made."
|
|
7167
|
+
echo " Open Tailscale to check the connection, or try: tailscale status"
|
|
7168
|
+
;;
|
|
7169
|
+
*)
|
|
7170
|
+
echo " $DOT_MARK Tailscale connection status could not be checked; no installation or configuration changes made."
|
|
7171
|
+
echo " If you use Tailscale, check its app or try: tailscale status"
|
|
7172
|
+
;;
|
|
7173
|
+
esac
|
|
7174
|
+
}
|
|
7175
|
+
|
|
7176
|
+
print_setup_checklist() {
|
|
7177
|
+
local network_ready="false"
|
|
7178
|
+
[[ "$TAILSCALE_STATUS" != "connected" || "$TAILSCALE_BIND_MATCH" != "true" ]] || network_ready="true"
|
|
7179
|
+
if [[ -z "$TMUX_WARNING" && "$network_ready" == "true" \
|
|
7180
|
+
&& ( "$CLAUDE_READY" == "true" || "$CODEX_READY" == "true" ) ]]; then
|
|
7181
|
+
echo " ${COLOR_GREEN}${COLOR_BOLD}You are all set${COLOR_RESET}"
|
|
7182
|
+
echo " $CHECK_MARK tmux available"
|
|
7183
|
+
print_tailscale_summary
|
|
7184
|
+
return
|
|
7185
|
+
fi
|
|
7186
|
+
|
|
7187
|
+
echo " ${COLOR_BOLD}You already have${COLOR_RESET}"
|
|
7188
|
+
echo " $CHECK_MARK AgentsServer running"
|
|
7189
|
+
if [[ -z "$TMUX_WARNING" ]]; then
|
|
7190
|
+
echo " $CHECK_MARK tmux available"
|
|
7191
|
+
fi
|
|
7192
|
+
if [[ "$network_ready" == "true" ]]; then
|
|
7193
|
+
print_tailscale_summary
|
|
7194
|
+
elif [[ "$TAILSCALE_STATUS" == "connected" || "$TAILSCALE_STATUS" == "disconnected" || "$TAILSCALE_STATUS" == "unavailable" ]]; then
|
|
7195
|
+
echo " $CHECK_MARK Tailscale installed"
|
|
7196
|
+
fi
|
|
7197
|
+
|
|
7198
|
+
if [[ "$CLAUDE_READY" == "false" && "$CODEX_READY" == "false" ]]; then
|
|
7199
|
+
echo
|
|
7200
|
+
echo " ${COLOR_BOLD}To start chats${COLOR_RESET}"
|
|
7201
|
+
echo " $DOT_MARK Choose one agent CLI and sign in:"
|
|
7202
|
+
echo " Claude Code: npm install -g @anthropic-ai/claude-code, then run: claude"
|
|
7203
|
+
echo " Codex: npm install -g @openai/codex, then run: codex login"
|
|
7204
|
+
fi
|
|
7205
|
+
if [[ -n "$TMUX_WARNING" || "$network_ready" != "true" ]]; then
|
|
7206
|
+
echo
|
|
7207
|
+
echo " ${COLOR_BOLD}Optional next steps${COLOR_RESET}"
|
|
7208
|
+
echo " You can skip these unless you need the features below."
|
|
7209
|
+
if [[ -n "$TMUX_WARNING" ]]; then
|
|
7210
|
+
echo " $DOT_MARK For persistent terminals, pane inspection and in-app updates, install tmux:"
|
|
7211
|
+
if [[ "$OS_NAME" == "Darwin" ]]; then
|
|
7212
|
+
echo " With Homebrew: brew install tmux"
|
|
7213
|
+
else
|
|
7214
|
+
echo " Use your package manager, for example: sudo apt install tmux"
|
|
7215
|
+
fi
|
|
7216
|
+
fi
|
|
7217
|
+
if [[ "$network_ready" != "true" ]]; then
|
|
7218
|
+
print_tailscale_summary
|
|
7219
|
+
fi
|
|
7220
|
+
fi
|
|
7221
|
+
}
|
|
7222
|
+
|
|
7223
|
+
setup_network_summary
|
|
7024
7224
|
|
|
7025
7225
|
echo "[7/7] AgentsServer $RELEASE_VERSION is ready"
|
|
7226
|
+
if [[ "$PRIOR_SERVICE_STATE" == "absent" && "$PRIOR_LEGACY_SERVICE_STATE" == "absent" && -z "$EXPECTED_SERVER_IDENTITY" ]]; then
|
|
7227
|
+
printf '\n%s%s\n%s\n%s%s\n' \
|
|
7228
|
+
"$COLOR_GREEN" '================================' \
|
|
7229
|
+
'Your new service is up!' \
|
|
7230
|
+
'================================' "$COLOR_RESET"
|
|
7231
|
+
fi
|
|
7026
7232
|
echo
|
|
7027
7233
|
echo " ${COLOR_BOLD}Server URL${COLOR_RESET} $SERVER_URL"
|
|
7234
|
+
if [[ -n "$NETWORK_URLS" ]]; then
|
|
7235
|
+
echo " Other local/network addresses (reachability depends on network/firewall):"
|
|
7236
|
+
while IFS= read -r network_url; do
|
|
7237
|
+
[[ -z "$network_url" ]] || echo " $network_url"
|
|
7238
|
+
done <<< "$NETWORK_URLS"
|
|
7239
|
+
fi
|
|
7028
7240
|
echo
|
|
7029
|
-
|
|
7241
|
+
print_setup_checklist
|
|
7030
7242
|
if [[ "$PORT_AUTO_SELECTED" == "true" ]]; then
|
|
7243
|
+
echo
|
|
7031
7244
|
echo " $DOT_MARK port $ORIGINAL_PORT was already in use, installed on $PORT instead (--port pins an exact port unless --allow-port-fallback is supplied)"
|
|
7032
7245
|
fi
|
|
7033
|
-
if [[ "$CLAUDE_READY" == "false" && "$CODEX_READY" == "false" ]]; then
|
|
7034
|
-
echo " $CROSS_MARK install and sign in to Claude Code or Codex (see [6/7] above) before starting a chat"
|
|
7035
|
-
fi
|
|
7036
|
-
if [[ -n "$TMUX_WARNING" ]]; then
|
|
7037
|
-
echo " $CROSS_MARK tmux unavailable: persistent terminal, pane inspection, and in-app updates won't work - $TMUX_WARNING"
|
|
7038
|
-
else
|
|
7039
|
-
echo " $CHECK_MARK tmux available"
|
|
7040
|
-
fi
|
|
7041
|
-
if [[ -n "$TAILSCALE_IP" ]]; then
|
|
7042
|
-
echo " $CHECK_MARK reachable via Tailscale at $TAILSCALE_IP"
|
|
7043
|
-
else
|
|
7044
|
-
echo " $DOT_MARK optional: install and connect Tailscale to reach this server from another device or WiFi network: https://tailscale.com/download"
|
|
7045
|
-
fi
|
|
7046
7246
|
if [[ "$TEAM_HUB_MODE" == "host" ]]; then
|
|
7047
7247
|
echo
|
|
7048
7248
|
if [[ "$TEAM_HUB_TRANSPORT" == "tailscale_serve" ]]; then
|
|
@@ -7071,4 +7271,7 @@ echo
|
|
|
7071
7271
|
if [[ -z "$EXPECTED_SERVER_IDENTITY" ]]; then
|
|
7072
7272
|
printf 'AGENTSDOCK_SETUP_RESULT={"server_url":"%s","access_token":"%s","service":"%s","tailscale_ip":"%s","server_version":"%s"}\n' \
|
|
7073
7273
|
"$SERVER_URL" "$TOKEN" "$SERVICE_KIND" "$TAILSCALE_IP" "$RELEASE_VERSION"
|
|
7274
|
+
if interactive_token_output; then
|
|
7275
|
+
print_token_for_copy "$TOKEN"
|
|
7276
|
+
fi
|
|
7074
7277
|
fi
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# No downloads or package installation just to list/manage existing instances.
|
|
5
|
+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
for instance_python in "$SCRIPT_DIR/.venv/bin/python" \
|
|
7
|
+
"$HOME/.local/share/agents-server/current/.venv/bin/python" \
|
|
8
|
+
"$(command -v python3 || true)"; do
|
|
9
|
+
if [[ -n "$instance_python" && -x "$instance_python" ]] \
|
|
10
|
+
&& "$instance_python" -c 'import sys; sys.exit(sys.version_info < (3, 10))'; then
|
|
11
|
+
exec "$instance_python" "$SCRIPT_DIR/server_instances.py" "$@"
|
|
12
|
+
fi
|
|
13
|
+
done
|
|
14
|
+
echo "Instance management needs Python 3.10+; run ./install.sh first or install Python." >&2
|
|
15
|
+
exit 1
|