Files
Kill_LIFE/tools/bootstrap_mac_mcp.sh
Clément SAILLANT 5efb380da5 feat: automate yiacad PR review lane (#18)
* feat: automate yiacad pr review lane

* fix: stabilize yiacad review and spec gates

* fix: scope kicad exports to repo hardware

* fix: ignore kicad block library sources in exports

* feat: Add infra VPS monitoring runbook and healthcheck scripts

- Created INFRA_VPS_RUNBOOK_2026.md detailing operational procedures for monitoring VPS services.
- Added infra_vps_healthcheck.sh script for automated health checks on DNS, TLS, TCP, and HTTP for VPS services.
- Introduced infra_vps_security_audit.sh for non-intrusive security checks on external VPS services.
- Established JSON schema for infra VPS inventory in infra_vps.schema.json.
- Developed integration for runtime status reporting in the Next.js API route.
- Implemented Playwright tests for smoke testing the application and ensuring core functionalities.
- Updated Makefile for development dependencies and testing commands.
- Created various test files for unit and end-to-end testing across different components.

* feat(agentics): update mesh agents, gates, prompts, and workflows
2026-03-29 17:14:16 +02:00

383 lines
8.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MODE="${1:-codex}"
KILL_LIFE_DIR="$REPO_DIR"
CODEX_BIN="${CODEX_BIN:-codex}"
INCLUDE_PLAYWRIGHT=1
INCLUDE_KICAD="auto"
INCLUDE_HUGGINGFACE="auto"
APPLY=0
source "$REPO_DIR/tools/lib/runtime_home.sh"
usage() {
cat <<'EOF'
Usage:
bash tools/bootstrap_mac_mcp.sh codex [--apply] [--kill-life-dir DIR] [--mascarade-dir DIR] [--without-playwright] [--with-kicad|--without-kicad] [--with-huggingface|--without-huggingface]
bash tools/bootstrap_mac_mcp.sh json [--kill-life-dir DIR] [--mascarade-dir DIR] [--without-playwright] [--with-kicad|--without-kicad] [--with-huggingface|--without-huggingface]
Modes:
codex Print Codex MCP registration commands. Use --apply on the target Mac to execute them.
json Print a generic mcpServers JSON config with absolute paths.
Notes:
- The target Mac should clone Kill_LIFE and the companion mascarade repo side by side.
- Playwright MCP uses the official package `@playwright/mcp@latest`.
- For Codex, this script relies on `codex mcp add`.
- By default, `kicad` is included only when `mascarade/finetune/kicad_mcp_server` is populated.
- By default, `huggingface` is included only when `HUGGINGFACE_API_KEY` is already set.
EOF
}
abs_path() {
local input="$1"
(cd "$input" >/dev/null 2>&1 && pwd)
}
quote_cmd() {
local first=1
for arg in "$@"; do
if [[ $first -eq 0 ]]; then
printf ' '
fi
printf '%q' "$arg"
first=0
done
printf '\n'
}
is_truthy() {
case "${1:-}" in
1|true|TRUE|yes|YES|on|ON)
return 0
;;
*)
return 1
;;
esac
}
kicad_server_dir() {
printf '%s' "$MASCARADE_DIR/finetune/kicad_mcp_server"
}
has_kicad_server_source() {
local server_dir
server_dir="$(kicad_server_dir)"
[[ -f "$server_dir/package.json" || -f "$server_dir/dist/index.js" ]]
}
has_kicad_seeed_runtime() {
command -v uvx >/dev/null 2>&1
}
resolve_kicad_launcher() {
if has_kicad_server_source; then
printf '%s' "$KILL_LIFE_DIR/tools/hw/run_kicad_mcp.sh"
return 0
fi
if has_kicad_seeed_runtime; then
printf '%s' "$KILL_LIFE_DIR/tools/hw/run_kicad_seeed_mcp.sh"
return 0
fi
return 1
}
explain_kicad_skip() {
if has_kicad_server_source; then
return 0
fi
if has_kicad_seeed_runtime; then
return 0
fi
printf 'missing %s/package.json, %s/dist/index.js, and no uvx on PATH' "$(kicad_server_dir)" "$(kicad_server_dir)"
}
should_include_kicad() {
case "${INCLUDE_KICAD:-auto}" in
auto)
has_kicad_server_source || has_kicad_seeed_runtime
;;
*)
is_truthy "$INCLUDE_KICAD"
;;
esac
}
should_include_huggingface() {
case "${INCLUDE_HUGGINGFACE:-auto}" in
auto)
[[ -n "${HUGGINGFACE_API_KEY:-}" ]]
;;
*)
is_truthy "$INCLUDE_HUGGINGFACE"
;;
esac
}
warn_skip() {
printf '[bootstrap_mac_mcp] skipping %s: %s\n' "$1" "$2" >&2
}
emit_json() {
local -a blocks=()
local kicad_launcher=""
if should_include_kicad; then
kicad_launcher="$(resolve_kicad_launcher)"
blocks+=("$(cat <<EOF
"kicad": {
"type": "local",
"command": "bash",
"args": ["$kicad_launcher"],
"tools": ["*"]
}
EOF
)")
else
warn_skip "kicad" "$(explain_kicad_skip)"
fi
blocks+=("$(cat <<EOF
"validate-specs": {
"type": "local",
"command": "bash",
"args": ["$KILL_LIFE_DIR/tools/run_validate_specs_mcp.sh"],
"tools": ["*"]
}
EOF
)")
blocks+=("$(cat <<EOF
"knowledge-base": {
"type": "local",
"command": "bash",
"args": ["$KILL_LIFE_DIR/tools/run_knowledge_base_mcp.sh"],
"env": {
"MASCARADE_DIR": "$MASCARADE_DIR"
},
"tools": ["*"]
}
EOF
)")
blocks+=("$(cat <<EOF
"github-dispatch": {
"type": "local",
"command": "bash",
"args": ["$KILL_LIFE_DIR/tools/run_github_dispatch_mcp.sh"],
"env": {
"MASCARADE_DIR": "$MASCARADE_DIR"
},
"tools": ["*"]
}
EOF
)")
blocks+=("$(cat <<EOF
"freecad": {
"type": "local",
"command": "bash",
"args": ["$KILL_LIFE_DIR/tools/run_freecad_mcp.sh"],
"env": {
"MASCARADE_DIR": "$MASCARADE_DIR"
},
"tools": ["*"]
}
EOF
)")
blocks+=("$(cat <<EOF
"openscad": {
"type": "local",
"command": "bash",
"args": ["$KILL_LIFE_DIR/tools/run_openscad_mcp.sh"],
"env": {
"MASCARADE_DIR": "$MASCARADE_DIR"
},
"tools": ["*"]
}
EOF
)")
if should_include_huggingface; then
blocks+=("$(cat <<'EOF'
"huggingface": {
"type": "url",
"url": "https://huggingface.co/mcp",
"headers": {
"Authorization": "Bearer ${HUGGINGFACE_API_KEY}"
}
}
EOF
)")
else
warn_skip "huggingface" "HUGGINGFACE_API_KEY is not set"
fi
if [[ $INCLUDE_PLAYWRIGHT -eq 1 ]]; then
blocks+=("$(cat <<'EOF'
"playwright": {
"type": "local",
"command": "npx",
"args": ["-y", "@playwright/mcp@latest"],
"tools": ["*"]
}
EOF
)")
fi
printf '{\n'
printf ' "mcpServers": {\n'
local i
for ((i = 0; i < ${#blocks[@]}; i++)); do
if (( i > 0 )); then
printf ',\n'
fi
printf '%s' "${blocks[$i]}"
done
printf '\n'
printf ' }\n'
printf '}\n'
}
codex_add() {
local name="$1"
shift
local -a cmd=("$CODEX_BIN" mcp add "$name")
while [[ $# -gt 0 ]]; do
case "$1" in
--env)
cmd+=("--env" "$2")
shift 2
;;
--url)
cmd+=("--url" "$2")
shift 2
;;
--bearer-token-env-var)
cmd+=("--bearer-token-env-var" "$2")
shift 2
;;
--)
cmd+=("--")
shift
while [[ $# -gt 0 ]]; do
cmd+=("$1")
shift
done
;;
*)
echo "Unknown codex_add arg: $1" >&2
exit 1
;;
esac
done
if [[ $APPLY -eq 1 ]]; then
"${cmd[@]}"
else
quote_cmd "${cmd[@]}"
fi
}
emit_codex() {
local kicad_launcher=""
if should_include_kicad; then
kicad_launcher="$(resolve_kicad_launcher)"
if [[ "$kicad_launcher" == *"/run_kicad_mcp.sh" ]]; then
codex_add kicad --env "MASCARADE_DIR=$MASCARADE_DIR" -- bash "$kicad_launcher"
else
codex_add kicad -- bash "$kicad_launcher"
fi
else
warn_skip "kicad" "$(explain_kicad_skip)"
fi
codex_add validate-specs -- bash "$KILL_LIFE_DIR/tools/run_validate_specs_mcp.sh"
codex_add knowledge-base --env "MASCARADE_DIR=$MASCARADE_DIR" -- bash "$KILL_LIFE_DIR/tools/run_knowledge_base_mcp.sh"
codex_add github-dispatch --env "MASCARADE_DIR=$MASCARADE_DIR" -- bash "$KILL_LIFE_DIR/tools/run_github_dispatch_mcp.sh"
codex_add freecad --env "MASCARADE_DIR=$MASCARADE_DIR" -- bash "$KILL_LIFE_DIR/tools/run_freecad_mcp.sh"
codex_add openscad --env "MASCARADE_DIR=$MASCARADE_DIR" -- bash "$KILL_LIFE_DIR/tools/run_openscad_mcp.sh"
if should_include_huggingface; then
codex_add huggingface --url "https://huggingface.co/mcp" --bearer-token-env-var "HUGGINGFACE_API_KEY"
else
warn_skip "huggingface" "HUGGINGFACE_API_KEY is not set"
fi
if [[ $INCLUDE_PLAYWRIGHT -eq 1 ]]; then
codex_add playwright -- npx -y "@playwright/mcp@latest"
fi
}
shift || true
while [[ $# -gt 0 ]]; do
case "$1" in
--kill-life-dir)
KILL_LIFE_DIR="$(abs_path "$2")"
shift 2
;;
--mascarade-dir)
MASCARADE_DIR="$(abs_path "$2")"
shift 2
;;
--without-playwright)
INCLUDE_PLAYWRIGHT=0
shift
;;
--with-kicad)
INCLUDE_KICAD=1
shift
;;
--without-kicad)
INCLUDE_KICAD=0
shift
;;
--with-huggingface)
INCLUDE_HUGGINGFACE=1
shift
;;
--without-huggingface)
INCLUDE_HUGGINGFACE=0
shift
;;
--apply)
APPLY=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
[[ -n "$KILL_LIFE_DIR" ]] || { echo "Unable to resolve Kill_LIFE path" >&2; exit 1; }
if [[ -z "${MASCARADE_DIR:-}" ]]; then
MASCARADE_DIR="$(
kill_life_resolve_mascarade_dir \
"$REPO_DIR" \
"core/mascarade" \
"finetune"
)"
fi
[[ -n "$MASCARADE_DIR" ]] || { echo "Unable to resolve mascarade companion path" >&2; exit 1; }
case "$MODE" in
codex)
emit_codex
;;
json)
emit_json
;;
*)
usage >&2
exit 1
;;
esac