direxio-deployer 0.1.0 → 0.1.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 +10 -2
- package/README_zh.md +10 -2
- package/SKILL.md +32 -8
- package/bin/direxio-deployer.mjs +1 -2
- package/package.json +2 -3
- package/references/agent-targets.md +7 -1
- package/references/deployment-lessons.md +5 -7
- package/references/deployment-workflow.md +8 -4
- package/references/runtime-wiring.md +5 -5
- package/references/tooling.md +11 -12
- package/references/user-journey.md +2 -2
- package/references/voip-turn-runbook.md +2 -2
- package/references/windows-deployment-notes.md +2 -1
- package/scripts/destroy.sh +24 -43
- package/scripts/json.mjs +841 -0
- package/scripts/lib/aws.sh +5 -1
- package/scripts/lib/json.sh +114 -0
- package/scripts/lib/operation_report.sh +8 -195
- package/scripts/lib/ops.sh +8 -21
- package/scripts/lib/state.sh +18 -44
- package/scripts/mcp-tools-list.mjs +66 -5
- package/scripts/orchestrate.sh +166 -249
- package/scripts/phases/s3_provision.sh +5 -10
- package/scripts/phases/s5_init_tokens.sh +7 -17
- package/scripts/phases/s6_wire_local.sh +22 -42
- package/scripts/phases/s7_verify_e2e.sh +5 -5
- package/scripts/pricing-estimate.sh +36 -80
- package/tests/aws_credentials_test.sh +0 -139
- package/tests/connect_daemon_runtime_check_test.sh +0 -120
- package/tests/default_paths_test.sh +0 -58
- package/tests/destroy_local_bridge_test.sh +0 -154
- package/tests/destroy_root_identity_test.sh +0 -91
- package/tests/destroy_route53_zone_test.sh +0 -80
- package/tests/domain_authoritative_dns_test.sh +0 -49
- package/tests/mcp_doctor_runtime_check_test.sh +0 -86
- package/tests/mcp_smoke_runtime_check_test.sh +0 -121
- package/tests/mcp_tools_runtime_check_test.sh +0 -123
- package/tests/npm_skill_distribution_test.sh +0 -95
- package/tests/operation_report_test.sh +0 -258
- package/tests/orchestrate_status_recovery_test.sh +0 -91
- package/tests/phase_timeout_test.sh +0 -88
- package/tests/pricing_estimate_test.sh +0 -159
- package/tests/render_userdata_remote_nodes_test.sh +0 -40
- package/tests/root_volume_tracking_test.sh +0 -41
- package/tests/route53_overwrite_guard_test.sh +0 -86
- package/tests/route53_zone_auto_create_test.sh +0 -66
- package/tests/runtime_summary_check_test.sh +0 -203
- package/tests/s6_wire_local_test.sh +0 -405
- package/tests/skill_structure_test.sh +0 -298
- package/tests/update_reset_ops_test.sh +0 -230
- package/tests/user_confirmation_gates_test.sh +0 -152
package/scripts/orchestrate.sh
CHANGED
|
@@ -23,9 +23,7 @@ set -uo pipefail
|
|
|
23
23
|
HERE=$(cd "$(dirname "$0")" && pwd)
|
|
24
24
|
P2P_INSTALL_SCRIPTS_DIR="$HERE"
|
|
25
25
|
|
|
26
|
-
# Prefer workspace-local tools when present.
|
|
27
|
-
# into .tools/bin/jq.exe by the operator/system and is discoverable from
|
|
28
|
-
# Git Bash/MSYS only when this path is prepended.
|
|
26
|
+
# Prefer workspace-local tools when present.
|
|
29
27
|
REPO_ROOT=$(cd "$HERE/.." && pwd)
|
|
30
28
|
if [ -d "$REPO_ROOT/.tools/bin" ]; then
|
|
31
29
|
PATH="$REPO_ROOT/.tools/bin:$PATH"
|
|
@@ -58,17 +56,12 @@ phase_file() {
|
|
|
58
56
|
# Dependency check.
|
|
59
57
|
check_deps() {
|
|
60
58
|
local b missing=""
|
|
61
|
-
for b in aws
|
|
59
|
+
for b in aws ssh scp curl; do
|
|
62
60
|
command -v "$b" >/dev/null 2>&1 || missing="$missing $b"
|
|
63
61
|
done
|
|
64
62
|
[ -z "$missing" ] && return 0
|
|
65
63
|
|
|
66
64
|
warn "Missing dependencies:$missing"
|
|
67
|
-
case " $missing " in
|
|
68
|
-
*" jq "*)
|
|
69
|
-
warn "jq is required for state.json. If this workspace has .tools/bin/jq.exe, run from a POSIX shell that can see that path."
|
|
70
|
-
;;
|
|
71
|
-
esac
|
|
72
65
|
case " $missing " in
|
|
73
66
|
*" aws "*)
|
|
74
67
|
warn "Install AWS CLI v2 and configure credentials first:"
|
|
@@ -108,9 +101,9 @@ cmd_status_inventory() {
|
|
|
108
101
|
[ -f "$state" ] || continue
|
|
109
102
|
found=1
|
|
110
103
|
service_dir=${state%/state.json}
|
|
111
|
-
domain=$(
|
|
112
|
-
phase=$(
|
|
113
|
-
instance=$(
|
|
104
|
+
domain=$(json_get "$state" domain)
|
|
105
|
+
phase=$(json_get "$state" phase)
|
|
106
|
+
instance=$(json_get "$state" resources.instance_id)
|
|
114
107
|
if STATE_JSON="$state" first_unfinished_phase >/dev/null 2>&1; then
|
|
115
108
|
current=$(STATE_JSON="$state" first_unfinished_phase)
|
|
116
109
|
else
|
|
@@ -287,7 +280,7 @@ cmd_status() {
|
|
|
287
280
|
printf " %-20s %s\n" "$p" "$(phase_status "$p")"
|
|
288
281
|
done
|
|
289
282
|
echo "-- resources --"
|
|
290
|
-
|
|
283
|
+
json_entries "$STATE_JSON" resources | sed 's/^/ /'
|
|
291
284
|
print_recovery_summary "$current"
|
|
292
285
|
}
|
|
293
286
|
|
|
@@ -320,10 +313,10 @@ print_delivery() {
|
|
|
320
313
|
install_mode=$(state_get agent_install_mode)
|
|
321
314
|
install_status=$(state_get agent_install_status)
|
|
322
315
|
install_command=$(state_get agent_install_command)
|
|
323
|
-
runtime_summary=$(
|
|
324
|
-
app_gate=$(
|
|
325
|
-
real_chat_gate=$(
|
|
326
|
-
agent_runtime_gate=$(
|
|
316
|
+
runtime_summary=$(json_get "$STATE_JSON" runtime_checks.summary.status "not_run")
|
|
317
|
+
app_gate=$(json_get "$STATE_JSON" user_confirmations.app_initialization.status "pending_user_confirmation")
|
|
318
|
+
real_chat_gate=$(json_get "$STATE_JSON" user_confirmations.real_chat.status "pending_user_confirmation")
|
|
319
|
+
agent_runtime_gate=$(json_get "$STATE_JSON" user_confirmations.agent_mcp_runtime.status "pending_runtime_confirmation")
|
|
327
320
|
echo
|
|
328
321
|
echo -e "\033[32m========== Automated Deployment Gates Passed ==========\033[0m"
|
|
329
322
|
echo " App domain : $domain"
|
|
@@ -391,10 +384,10 @@ ensure_cost_estimate() {
|
|
|
391
384
|
fi
|
|
392
385
|
|
|
393
386
|
if output=$(bash "$HERE/pricing-estimate.sh" "${args[@]}" 2>/dev/null); then
|
|
394
|
-
status=$(printf '%s\n' "$output" |
|
|
395
|
-
total=$(printf '%s\n' "$output" |
|
|
396
|
-
region=$(printf '%s\n' "$output" |
|
|
397
|
-
instance_type=$(printf '%s\n' "$output" |
|
|
387
|
+
status=$(printf '%s\n' "$output" | json_stdin_get pricing_status "unknown" 2>/dev/null)
|
|
388
|
+
total=$(printf '%s\n' "$output" | json_stdin_get total_monthly_usd "unknown" 2>/dev/null)
|
|
389
|
+
region=$(printf '%s\n' "$output" | json_stdin_get region "unknown" 2>/dev/null)
|
|
390
|
+
instance_type=$(printf '%s\n' "$output" | json_stdin_get components.ec2_instance.instance_type "unknown" 2>/dev/null)
|
|
398
391
|
log "Cost estimate recorded (status=${status:-unknown}, region=${region:-unknown}, instance=${instance_type:-unknown}, monthly_usd≈${total:-unknown})."
|
|
399
392
|
if [ "$status" = "fallback" ]; then
|
|
400
393
|
warn "AWS Pricing API was unavailable or incomplete; cost_estimate uses conservative fallback values."
|
|
@@ -402,6 +395,25 @@ ensure_cost_estimate() {
|
|
|
402
395
|
else
|
|
403
396
|
warn "Could not write AWS cost estimate. Continue only after giving the user a manual billing estimate."
|
|
404
397
|
fi
|
|
398
|
+
ensure_free_tier_credit_notice
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
ensure_free_tier_credit_notice() {
|
|
402
|
+
local output plan_status plan_type amount unit expires
|
|
403
|
+
if output=$(aws freetier get-account-plan-state --output json 2>/dev/null); then
|
|
404
|
+
plan_type=$(printf '%s\n' "$output" | json_stdin_get accountPlanType "unknown" 2>/dev/null)
|
|
405
|
+
plan_status=$(printf '%s\n' "$output" | json_stdin_get accountPlanStatus "unknown" 2>/dev/null)
|
|
406
|
+
amount=$(printf '%s\n' "$output" | json_stdin_get accountPlanRemainingCredits.amount "" 2>/dev/null)
|
|
407
|
+
unit=$(printf '%s\n' "$output" | json_stdin_get accountPlanRemainingCredits.unit "USD" 2>/dev/null)
|
|
408
|
+
expires=$(printf '%s\n' "$output" | json_stdin_get accountPlanExpirationDate "" 2>/dev/null)
|
|
409
|
+
if [ -n "$amount" ]; then
|
|
410
|
+
log "AWS Free Tier plan: type=${plan_type:-unknown}, status=${plan_status:-unknown}, remaining_credits=${amount} ${unit:-USD}${expires:+, expires=$expires}."
|
|
411
|
+
warn "Credits can reduce actual charges, but AWS resources still accrue charges until destroyed; verify credit coverage in AWS Billing Console."
|
|
412
|
+
return 0
|
|
413
|
+
fi
|
|
414
|
+
fi
|
|
415
|
+
warn "AWS new customer accounts may include Free Tier credits, currently advertised as 100 USD initial credits plus possible additional credits."
|
|
416
|
+
warn "Credits may cover a small trial deployment, but coverage is account-specific; verify credits in AWS Billing Console and destroy the node when finished."
|
|
405
417
|
}
|
|
406
418
|
|
|
407
419
|
precheck_new_deploy_domain_env() {
|
|
@@ -439,7 +451,7 @@ ensure_production_domain_selected() {
|
|
|
439
451
|
state_domain=$(domain_normalize "$state_domain")
|
|
440
452
|
state_mode=$(state_get domain_mode)
|
|
441
453
|
env_domain=$(domain_normalize "${DOMAIN:-}")
|
|
442
|
-
confirmed=$(
|
|
454
|
+
confirmed=$(json_get "$STATE_JSON" domain_confirmed_irreversible false)
|
|
443
455
|
|
|
444
456
|
if [ -n "$env_domain" ] && [ -n "$state_domain" ] && [ "$env_domain" != "$state_domain" ]; then
|
|
445
457
|
warn "Deployment blocked: current state is bound to DOMAIN=$state_domain, but this run passed DOMAIN=${env_domain}."
|
|
@@ -484,22 +496,22 @@ ensure_production_domain_selected() {
|
|
|
484
496
|
guard_existing_state() {
|
|
485
497
|
[ -f "$STATE_JSON" ] || return 0
|
|
486
498
|
local resources_count confirmed action
|
|
487
|
-
resources_count=$(
|
|
499
|
+
resources_count=$(json_length "$STATE_JSON" resources)
|
|
488
500
|
[ "$resources_count" -eq 0 ] && return 0
|
|
489
|
-
if [ "$(
|
|
501
|
+
if [ "$(json_get "$STATE_JSON" domain_mode)" = "ec2" ]; then
|
|
490
502
|
warn "Found legacy temporary-domain deployment state (domain_mode=ec2). Production deployment no longer supports resuming this mode."
|
|
491
503
|
warn "Destroy and rebuild, or use a new service directory:"
|
|
492
504
|
warn " P2P_EXISTING_STATE_ACTION=destroy bash $0"
|
|
493
505
|
warn " DOMAIN=__DOMAIN__ DOMAIN_MODE=user CONFIRM_DOMAIN_BINDING=1 bash $0"
|
|
494
506
|
return 2
|
|
495
507
|
fi
|
|
496
|
-
confirmed=$(
|
|
508
|
+
confirmed=$(json_get "$STATE_JSON" existing_state_confirmed false)
|
|
497
509
|
[ "$confirmed" = "true" ] && return 0
|
|
498
510
|
|
|
499
511
|
action=${P2P_EXISTING_STATE_ACTION:-}
|
|
500
512
|
if [ -z "$action" ] && [ -t 0 ]; then
|
|
501
513
|
warn "Found existing deployment state with recorded AWS resources:"
|
|
502
|
-
|
|
514
|
+
json_entries "$STATE_JSON" resources | sed 's/^/ /' >&2
|
|
503
515
|
warn "Choose: continue=resume / destroy=destroy and rebuild / abort=stop now"
|
|
504
516
|
printf "Action [abort]: " >&2
|
|
505
517
|
read -r action
|
|
@@ -601,7 +613,7 @@ cmd_confirm() {
|
|
|
601
613
|
warn "DIREXIO_CONFIRM_EVIDENCE is too short; provide a concrete user/runtime evidence note."
|
|
602
614
|
return 1
|
|
603
615
|
fi
|
|
604
|
-
runtime_summary_status=$(
|
|
616
|
+
runtime_summary_status=$(json_get "$STATE_JSON" runtime_checks.summary.status "not_run")
|
|
605
617
|
runtime_probe_confirmed=false
|
|
606
618
|
if [ "$gate" = "agent_mcp_runtime" ]; then
|
|
607
619
|
if [ "$runtime_summary_status" != "passed" ]; then
|
|
@@ -614,21 +626,19 @@ cmd_confirm() {
|
|
|
614
626
|
fi
|
|
615
627
|
runtime_probe_confirmed=true
|
|
616
628
|
fi
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
status
|
|
620
|
-
ts
|
|
621
|
-
evidence
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
--arg runtime_summary_status "$runtime_summary_status" \
|
|
631
|
-
--arg runtime_probe_confirmed "$runtime_probe_confirmed"
|
|
629
|
+
if [ "$gate" = "agent_mcp_runtime" ]; then
|
|
630
|
+
state_set_object "user_confirmations.$gate" \
|
|
631
|
+
status=confirmed \
|
|
632
|
+
"ts=$(_now)" \
|
|
633
|
+
"evidence=$evidence" \
|
|
634
|
+
"runtime_summary_status=$runtime_summary_status" \
|
|
635
|
+
"runtime_probe_confirmed=$runtime_probe_confirmed"
|
|
636
|
+
else
|
|
637
|
+
state_set_object "user_confirmations.$gate" \
|
|
638
|
+
status=confirmed \
|
|
639
|
+
"ts=$(_now)" \
|
|
640
|
+
"evidence=$evidence"
|
|
641
|
+
fi
|
|
632
642
|
echo "confirmed gate: $gate"
|
|
633
643
|
}
|
|
634
644
|
|
|
@@ -638,10 +648,11 @@ cmd_verify_mcp_doctor() {
|
|
|
638
648
|
return 1
|
|
639
649
|
}
|
|
640
650
|
|
|
641
|
-
local credentials mcp_cmd node_id out err report token_status
|
|
642
|
-
credentials=$(
|
|
643
|
-
|
|
644
|
-
|
|
651
|
+
local credentials mcp_cmd node_id out err report token_status report_domain report_room
|
|
652
|
+
credentials=$(json_get "$STATE_JSON" agent_credentials_file)
|
|
653
|
+
[ -n "$credentials" ] || credentials=$(json_get "$STATE_JSON" mcp_credentials_file)
|
|
654
|
+
mcp_cmd=$(json_get "$STATE_JSON" mcp_command "direxio-mcp")
|
|
655
|
+
node_id=$(json_get "$STATE_JSON" agent_node_id)
|
|
645
656
|
[ -n "$credentials" ] || {
|
|
646
657
|
warn "mcp doctor check requires agent_credentials_file or mcp_credentials_file in state.json"
|
|
647
658
|
return 1
|
|
@@ -651,45 +662,34 @@ cmd_verify_mcp_doctor() {
|
|
|
651
662
|
out=$(mktemp)
|
|
652
663
|
err=$(mktemp)
|
|
653
664
|
if ! DIREXIO_CREDENTIALS_FILE="$credentials" DIREXIO_AGENT_NODE_ID="$node_id" bash -c "$mcp_cmd doctor --json" > "$out" 2> "$err"; then
|
|
654
|
-
|
|
655
|
-
.runtime_checks.mcp_doctor = {
|
|
656
|
-
status: "failed",
|
|
657
|
-
ts: $ts,
|
|
658
|
-
evidence: "direxio-mcp doctor failed"
|
|
659
|
-
}
|
|
660
|
-
' --arg ts "$(_now)"
|
|
665
|
+
state_set_object runtime_checks.mcp_doctor status=failed "ts=$(_now)" "evidence=direxio-mcp doctor failed"
|
|
661
666
|
cat "$err" >&2
|
|
662
667
|
rm -f "$out" "$err"
|
|
663
668
|
return 1
|
|
664
669
|
fi
|
|
665
|
-
if !
|
|
666
|
-
|
|
667
|
-
.runtime_checks.mcp_doctor = {
|
|
668
|
-
status: "failed",
|
|
669
|
-
ts: $ts,
|
|
670
|
-
evidence: "direxio-mcp doctor returned non-json output"
|
|
671
|
-
}
|
|
672
|
-
' --arg ts "$(_now)"
|
|
670
|
+
if ! json_valid "$out" >/dev/null 2>&1; then
|
|
671
|
+
state_set_object runtime_checks.mcp_doctor status=failed "ts=$(_now)" "evidence=direxio-mcp doctor returned non-json output"
|
|
673
672
|
rm -f "$out" "$err"
|
|
674
673
|
return 1
|
|
675
674
|
fi
|
|
676
675
|
report=$(cat "$out")
|
|
677
|
-
token_status=$(printf '%s\n' "$report" |
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
676
|
+
token_status=$(printf '%s\n' "$report" | json_stdin_get token)
|
|
677
|
+
if [ "$token_status" = "redacted" ]; then
|
|
678
|
+
token_status=redacted
|
|
679
|
+
elif [ -n "$token_status" ]; then
|
|
680
|
+
token_status=present_redacted
|
|
681
|
+
else
|
|
682
|
+
token_status=missing
|
|
683
|
+
fi
|
|
684
|
+
report_domain=$(json_get "$out" domain)
|
|
685
|
+
report_room=$(json_get "$out" agent_room_id)
|
|
686
|
+
state_set_object runtime_checks.mcp_doctor \
|
|
687
|
+
status=passed \
|
|
688
|
+
"ts=$(_now)" \
|
|
689
|
+
"evidence=direxio-mcp doctor --json succeeded" \
|
|
690
|
+
"domain=$report_domain" \
|
|
691
|
+
"agent_room_id=$report_room" \
|
|
692
|
+
"token=$token_status"
|
|
693
693
|
rm -f "$out" "$err"
|
|
694
694
|
echo "verified runtime check: mcp_doctor"
|
|
695
695
|
}
|
|
@@ -700,56 +700,49 @@ cmd_verify_mcp_smoke() {
|
|
|
700
700
|
return 1
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
-
local service_url token room_id body code payload
|
|
704
|
-
service_url=$(
|
|
703
|
+
local service_url token room_id body code payload url response_room_id response_messages_type
|
|
704
|
+
service_url=$(json_get "$STATE_JSON" as_url)
|
|
705
705
|
if [ -z "$service_url" ]; then
|
|
706
706
|
local domain
|
|
707
|
-
domain=$(
|
|
707
|
+
domain=$(json_get "$STATE_JSON" domain)
|
|
708
708
|
[ -n "$domain" ] && service_url="https://$domain"
|
|
709
709
|
fi
|
|
710
|
-
token=$(
|
|
711
|
-
room_id=$(
|
|
710
|
+
token=$(json_get "$STATE_JSON" agent_token)
|
|
711
|
+
room_id=$(json_get "$STATE_JSON" agent_room_id)
|
|
712
712
|
if [ -z "$service_url" ] || [ -z "$token" ] || [ -z "$room_id" ]; then
|
|
713
713
|
warn "mcp smoke check requires as_url/domain, agent_token, and agent_room_id in state.json"
|
|
714
714
|
return 1
|
|
715
715
|
fi
|
|
716
716
|
|
|
717
717
|
body=$(mktemp)
|
|
718
|
-
payload=$(
|
|
718
|
+
payload=$(json_build mcp-messages-list "$room_id")
|
|
719
719
|
url="${service_url%/}/_p2p/query"
|
|
720
720
|
code=$(curl -sk -o "$body" -w '%{http_code}' \
|
|
721
721
|
-X POST "$url" \
|
|
722
722
|
-H 'Content-Type: application/json' \
|
|
723
723
|
-H "Authorization: Bearer $token" \
|
|
724
724
|
-d "$payload" 2>/dev/null)
|
|
725
|
-
if [ "$code" != "200" ] || !
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
evidence: $evidence
|
|
732
|
-
}
|
|
733
|
-
' --arg ts "$(_now)" --arg evidence "mcp.messages.list returned HTTP $code or invalid response"
|
|
725
|
+
if [ "$code" != "200" ] || ! json_assert "$body" messages-response >/dev/null 2>&1; then
|
|
726
|
+
state_set_object runtime_checks.mcp_smoke \
|
|
727
|
+
status=failed \
|
|
728
|
+
"ts=$(_now)" \
|
|
729
|
+
action=mcp.messages.list \
|
|
730
|
+
"evidence=mcp.messages.list returned HTTP $code or invalid response"
|
|
734
731
|
rm -f "$body"
|
|
735
732
|
return 1
|
|
736
733
|
fi
|
|
737
734
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
evidence: "read-only backend smoke check succeeded"
|
|
750
|
-
}' > "$tmp"
|
|
751
|
-
_state_write '.runtime_checks.mcp_smoke = $check[0]' --slurpfile check "$tmp"
|
|
752
|
-
rm -f "$body" "$tmp"
|
|
735
|
+
response_room_id=$(json_get "$body" room_id)
|
|
736
|
+
response_messages_type=$(json_type "$body" messages)
|
|
737
|
+
state_set_object runtime_checks.mcp_smoke \
|
|
738
|
+
status=passed \
|
|
739
|
+
"ts=$(_now)" \
|
|
740
|
+
action=mcp.messages.list \
|
|
741
|
+
"room_id=$room_id" \
|
|
742
|
+
"response_room_id=$response_room_id" \
|
|
743
|
+
"response_messages_type=$response_messages_type" \
|
|
744
|
+
"evidence=read-only backend smoke check succeeded"
|
|
745
|
+
rm -f "$body"
|
|
753
746
|
echo "verified runtime check: mcp_smoke"
|
|
754
747
|
}
|
|
755
748
|
|
|
@@ -760,9 +753,10 @@ cmd_verify_mcp_tools() {
|
|
|
760
753
|
}
|
|
761
754
|
|
|
762
755
|
local credentials mcp_cmd node_id node_cmd node_script out err report
|
|
763
|
-
credentials=$(
|
|
764
|
-
|
|
765
|
-
|
|
756
|
+
credentials=$(json_get "$STATE_JSON" agent_credentials_file)
|
|
757
|
+
[ -n "$credentials" ] || credentials=$(json_get "$STATE_JSON" mcp_credentials_file)
|
|
758
|
+
mcp_cmd=$(json_get "$STATE_JSON" mcp_command "direxio-mcp")
|
|
759
|
+
node_id=$(json_get "$STATE_JSON" agent_node_id)
|
|
766
760
|
[ -n "$credentials" ] || {
|
|
767
761
|
warn "mcp tools check requires agent_credentials_file or mcp_credentials_file in state.json"
|
|
768
762
|
return 1
|
|
@@ -778,52 +772,29 @@ cmd_verify_mcp_tools() {
|
|
|
778
772
|
out=$(mktemp)
|
|
779
773
|
err=$(mktemp)
|
|
780
774
|
if ! DIREXIO_CREDENTIALS_FILE="$credentials" DIREXIO_AGENT_NODE_ID="$node_id" "$node_cmd" "$node_script" "$mcp_cmd" > "$out" 2> "$err"; then
|
|
781
|
-
|
|
782
|
-
.runtime_checks.mcp_tools = {
|
|
783
|
-
status: "failed",
|
|
784
|
-
ts: $ts,
|
|
785
|
-
evidence: "MCP tools/list failed"
|
|
786
|
-
}
|
|
787
|
-
' --arg ts "$(_now)"
|
|
775
|
+
state_set_object runtime_checks.mcp_tools status=failed "ts=$(_now)" "evidence=MCP tools/list failed"
|
|
788
776
|
cat "$err" >&2
|
|
789
777
|
rm -f "$out" "$err"
|
|
790
778
|
return 1
|
|
791
779
|
fi
|
|
792
|
-
if !
|
|
793
|
-
|
|
794
|
-
.runtime_checks.mcp_tools = {
|
|
795
|
-
status: "failed",
|
|
796
|
-
ts: $ts,
|
|
797
|
-
evidence: "MCP tools/list returned invalid output"
|
|
798
|
-
}
|
|
799
|
-
' --arg ts "$(_now)"
|
|
780
|
+
if ! json_assert "$out" tools-list >/dev/null 2>&1; then
|
|
781
|
+
state_set_object runtime_checks.mcp_tools status=failed "ts=$(_now)" "evidence=MCP tools/list returned invalid output"
|
|
800
782
|
rm -f "$out" "$err"
|
|
801
783
|
return 1
|
|
802
784
|
fi
|
|
803
785
|
report=$(cat "$out")
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
tools: ($report.tools // [])
|
|
811
|
-
}
|
|
812
|
-
' --arg ts "$(_now)" --argjson report "$report"
|
|
786
|
+
state_set_object runtime_checks.mcp_tools \
|
|
787
|
+
status=passed \
|
|
788
|
+
"ts=$(_now)" \
|
|
789
|
+
"evidence=MCP tools/list succeeded" \
|
|
790
|
+
"tool_count=$(json_get "$out" tool_count 0)" \
|
|
791
|
+
"tools=$(json_get "$out" tools "[]")"
|
|
813
792
|
rm -f "$out" "$err"
|
|
814
793
|
echo "verified runtime check: mcp_tools"
|
|
815
794
|
}
|
|
816
795
|
|
|
817
796
|
_node_command() {
|
|
818
|
-
|
|
819
|
-
command -v node
|
|
820
|
-
return 0
|
|
821
|
-
fi
|
|
822
|
-
if command -v node.exe >/dev/null 2>&1; then
|
|
823
|
-
command -v node.exe
|
|
824
|
-
return 0
|
|
825
|
-
fi
|
|
826
|
-
return 1
|
|
797
|
+
json_node
|
|
827
798
|
}
|
|
828
799
|
|
|
829
800
|
_node_script_path() {
|
|
@@ -907,11 +878,12 @@ cmd_verify_connect_daemon() {
|
|
|
907
878
|
}
|
|
908
879
|
|
|
909
880
|
local service_name service_dir config runtime_dir binary target_work_dir status_out daemon_status work_dir evidence agent_error
|
|
910
|
-
service_name=$(
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
881
|
+
service_name=$(json_get "$STATE_JSON" agent_service_id)
|
|
882
|
+
[ -n "$service_name" ] || service_name=$(json_get "$STATE_JSON" domain)
|
|
883
|
+
service_dir=$(json_get "$STATE_JSON" agent_service_dir)
|
|
884
|
+
config=$(json_get "$STATE_JSON" cc_connect_config)
|
|
885
|
+
runtime_dir=$(json_get "$STATE_JSON" cc_connect_runtime_dir)
|
|
886
|
+
binary=$(json_get "$STATE_JSON" cc_connect_binary "direxio-connect")
|
|
915
887
|
[ -n "$service_name" ] || service_name=cc-connect
|
|
916
888
|
[ -n "$binary" ] || binary=direxio-connect
|
|
917
889
|
|
|
@@ -930,13 +902,7 @@ cmd_verify_connect_daemon() {
|
|
|
930
902
|
*/*|[A-Za-z]:/*|[A-Za-z]:\\*) ;;
|
|
931
903
|
*)
|
|
932
904
|
command -v "$binary" >/dev/null 2>&1 || {
|
|
933
|
-
|
|
934
|
-
.runtime_checks.connect_daemon = {
|
|
935
|
-
status: "failed",
|
|
936
|
-
ts: $ts,
|
|
937
|
-
evidence: "direxio-connect binary not found"
|
|
938
|
-
}
|
|
939
|
-
' --arg ts "$(_now)"
|
|
905
|
+
state_set_object runtime_checks.connect_daemon status=failed "ts=$(_now)" "evidence=direxio-connect binary not found"
|
|
940
906
|
warn "connect daemon check could not find binary: $binary"
|
|
941
907
|
return 1
|
|
942
908
|
}
|
|
@@ -944,14 +910,7 @@ cmd_verify_connect_daemon() {
|
|
|
944
910
|
esac
|
|
945
911
|
|
|
946
912
|
status_out=$("$binary" daemon status --service-name "$service_name" 2>/dev/null) || {
|
|
947
|
-
|
|
948
|
-
.runtime_checks.connect_daemon = {
|
|
949
|
-
status: "failed",
|
|
950
|
-
ts: $ts,
|
|
951
|
-
service_name: $service_name,
|
|
952
|
-
evidence: "direxio-connect daemon status failed"
|
|
953
|
-
}
|
|
954
|
-
' --arg ts "$(_now)" --arg service_name "$service_name"
|
|
913
|
+
state_set_object runtime_checks.connect_daemon status=failed "ts=$(_now)" "service_name=$service_name" "evidence=direxio-connect daemon status failed"
|
|
955
914
|
return 1
|
|
956
915
|
}
|
|
957
916
|
daemon_status=$(printf '%s\n' "$status_out" | sed -nE 's/^[[:space:]]*Status:[[:space:]]*//p' | head -n 1)
|
|
@@ -966,68 +925,45 @@ cmd_verify_connect_daemon() {
|
|
|
966
925
|
else
|
|
967
926
|
agent_error=$(connect_daemon_agent_error_from_logs "$binary" "$service_name")
|
|
968
927
|
if [ -n "$agent_error" ]; then
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
agent_error: $agent_error
|
|
979
|
-
}
|
|
980
|
-
' --arg ts "$(_now)" \
|
|
981
|
-
--arg service_name "$service_name" \
|
|
982
|
-
--arg daemon_status "$daemon_status" \
|
|
983
|
-
--arg work_dir "$(normalize_check_path "$work_dir")" \
|
|
984
|
-
--arg target_work_dir "$(normalize_check_path "$target_work_dir")" \
|
|
985
|
-
--arg agent_error "$agent_error"
|
|
928
|
+
state_set_object runtime_checks.connect_daemon \
|
|
929
|
+
status=failed \
|
|
930
|
+
"ts=$(_now)" \
|
|
931
|
+
"evidence=direxio-connect daemon logs report ACP session initialization failure" \
|
|
932
|
+
"service_name=$service_name" \
|
|
933
|
+
"daemon_status=$daemon_status" \
|
|
934
|
+
"work_dir=$(normalize_check_path "$work_dir")" \
|
|
935
|
+
"expected_work_dir=$(normalize_check_path "$target_work_dir")" \
|
|
936
|
+
"agent_error=$agent_error"
|
|
986
937
|
warn "direxio-connect daemon logs report ACP session initialization failure"
|
|
987
938
|
return 1
|
|
988
939
|
fi
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
expected_work_dir: $target_work_dir
|
|
998
|
-
}
|
|
999
|
-
' --arg ts "$(_now)" \
|
|
1000
|
-
--arg service_name "$service_name" \
|
|
1001
|
-
--arg daemon_status "$daemon_status" \
|
|
1002
|
-
--arg work_dir "$(normalize_check_path "$work_dir")" \
|
|
1003
|
-
--arg target_work_dir "$(normalize_check_path "$target_work_dir")"
|
|
940
|
+
state_set_object runtime_checks.connect_daemon \
|
|
941
|
+
status=passed \
|
|
942
|
+
"ts=$(_now)" \
|
|
943
|
+
"evidence=direxio-connect daemon is running for this service" \
|
|
944
|
+
"service_name=$service_name" \
|
|
945
|
+
"daemon_status=$daemon_status" \
|
|
946
|
+
"work_dir=$(normalize_check_path "$work_dir")" \
|
|
947
|
+
"expected_work_dir=$(normalize_check_path "$target_work_dir")"
|
|
1004
948
|
echo "verified runtime check: connect_daemon"
|
|
1005
949
|
return 0
|
|
1006
950
|
fi
|
|
1007
951
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
expected_work_dir: $target_work_dir
|
|
1017
|
-
}
|
|
1018
|
-
' --arg ts "$(_now)" \
|
|
1019
|
-
--arg evidence "$evidence" \
|
|
1020
|
-
--arg service_name "$service_name" \
|
|
1021
|
-
--arg daemon_status "$daemon_status" \
|
|
1022
|
-
--arg work_dir "$(normalize_check_path "$work_dir")" \
|
|
1023
|
-
--arg target_work_dir "$(normalize_check_path "$target_work_dir")"
|
|
952
|
+
state_set_object runtime_checks.connect_daemon \
|
|
953
|
+
status=failed \
|
|
954
|
+
"ts=$(_now)" \
|
|
955
|
+
"evidence=$evidence" \
|
|
956
|
+
"service_name=$service_name" \
|
|
957
|
+
"daemon_status=$daemon_status" \
|
|
958
|
+
"work_dir=$(normalize_check_path "$work_dir")" \
|
|
959
|
+
"expected_work_dir=$(normalize_check_path "$target_work_dir")"
|
|
1024
960
|
warn "$evidence"
|
|
1025
961
|
return 1
|
|
1026
962
|
}
|
|
1027
963
|
|
|
1028
964
|
runtime_check_status() {
|
|
1029
965
|
local check=$1
|
|
1030
|
-
|
|
966
|
+
json_get "$STATE_JSON" "runtime_checks.$check.status" "not_run"
|
|
1031
967
|
}
|
|
1032
968
|
|
|
1033
969
|
cmd_verify_runtime() {
|
|
@@ -1053,47 +989,28 @@ cmd_verify_runtime() {
|
|
|
1053
989
|
done
|
|
1054
990
|
|
|
1055
991
|
if [ "$failed_count" -eq 0 ]; then
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
mcp_tools: $tools_status,
|
|
1066
|
-
mcp_smoke: $smoke_status
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
' --arg ts "$(_now)" \
|
|
1070
|
-
--arg connect_status "$connect_status" \
|
|
1071
|
-
--arg doctor_status "$doctor_status" \
|
|
1072
|
-
--arg tools_status "$tools_status" \
|
|
1073
|
-
--arg smoke_status "$smoke_status"
|
|
992
|
+
state_set_object runtime_checks.summary \
|
|
993
|
+
status=passed \
|
|
994
|
+
"ts=$(_now)" \
|
|
995
|
+
failed_count=0 \
|
|
996
|
+
"evidence=all runtime checks passed" \
|
|
997
|
+
"checks.connect_daemon=$connect_status" \
|
|
998
|
+
"checks.mcp_doctor=$doctor_status" \
|
|
999
|
+
"checks.mcp_tools=$tools_status" \
|
|
1000
|
+
"checks.mcp_smoke=$smoke_status"
|
|
1074
1001
|
echo "verified runtime checks: passed"
|
|
1075
1002
|
return 0
|
|
1076
1003
|
fi
|
|
1077
1004
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
mcp_tools: $tools_status,
|
|
1088
|
-
mcp_smoke: $smoke_status
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
' --arg ts "$(_now)" \
|
|
1092
|
-
--arg failed_count "$failed_count" \
|
|
1093
|
-
--arg connect_status "$connect_status" \
|
|
1094
|
-
--arg doctor_status "$doctor_status" \
|
|
1095
|
-
--arg tools_status "$tools_status" \
|
|
1096
|
-
--arg smoke_status "$smoke_status"
|
|
1005
|
+
state_set_object runtime_checks.summary \
|
|
1006
|
+
status=failed \
|
|
1007
|
+
"ts=$(_now)" \
|
|
1008
|
+
"failed_count=$failed_count" \
|
|
1009
|
+
"evidence=one or more runtime checks failed" \
|
|
1010
|
+
"checks.connect_daemon=$connect_status" \
|
|
1011
|
+
"checks.mcp_doctor=$doctor_status" \
|
|
1012
|
+
"checks.mcp_tools=$tools_status" \
|
|
1013
|
+
"checks.mcp_smoke=$smoke_status"
|
|
1097
1014
|
warn "runtime checks failed: $failed_count"
|
|
1098
1015
|
return "${rc:-1}"
|
|
1099
1016
|
}
|