Initial segregate: proxy source, deploy manifests, ImagePolicy Flux CRs.
build-and-push / build (push) Failing after 2m45s
build-and-push / build (push) Failing after 2m45s
Move workload out of infra with cursor-devbox-style GitRepository + run_number-sha image automation.
This commit is contained in:
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
# Bootstrap: seed ~/.cursor/cli-config.json and verify the cursor-agent
|
||||
# binary works before the HTTP server starts serving traffic.
|
||||
set -euo pipefail
|
||||
|
||||
CURSOR_HOME="${HOME}/.cursor"
|
||||
BOOTSTRAP="/opt/cursor-bootstrap"
|
||||
export NO_OPEN_BROWSER=1
|
||||
|
||||
mkdir -p "${CURSOR_HOME}"
|
||||
|
||||
if [[ -f "${BOOTSTRAP}/cli-config.json" ]] && [[ ! -f "${CURSOR_HOME}/cli-config.json" ]]; then
|
||||
cp -f "${BOOTSTRAP}/cli-config.json" "${CURSOR_HOME}/cli-config.json"
|
||||
fi
|
||||
|
||||
# cursor-agent auth via env (no interactive login).
|
||||
if [[ -z "${CURSOR_API_KEY:-}" ]]; then
|
||||
echo "CURSOR_API_KEY is not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
export CURSOR_API_KEY
|
||||
|
||||
# cursor-agent itself must respond.
|
||||
if ! /usr/local/bin/agent.real --version >/dev/null 2>&1; then
|
||||
echo "cursor-agent binary is not executable" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "cursor-agent bootstrap: auth ok, agent responds"
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
# Local E2E: build image, run container with .env secrets, smoke-test text + image.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
IMAGE="${E2E_IMAGE:-cursor-agent-api-proxy:latest}"
|
||||
PORT="${E2E_PORT:-18766}"
|
||||
CONTAINER="${E2E_CONTAINER:-cursor-agent-api-e2e}"
|
||||
TIMEOUT="${E2E_TIMEOUT:-180}"
|
||||
|
||||
ENV_FILE="${REPO_ROOT}/.env"
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Error: .env not found at $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
docker rm -f "$CONTAINER" >/dev/null 2>&1 || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "==> Building $IMAGE"
|
||||
docker build -t "$IMAGE" "$ROOT"
|
||||
|
||||
cleanup
|
||||
echo "==> Starting container (host network, PORT=$PORT)"
|
||||
docker run -d --name "$CONTAINER" --network host --env-file "$ENV_FILE" -e "PORT=$PORT" "$IMAGE" >/dev/null
|
||||
|
||||
echo "==> Waiting for /health"
|
||||
for i in $(seq 1 60); do
|
||||
if curl -sf "http://127.0.0.1:${PORT}/health" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
if [ "$i" -eq 60 ]; then
|
||||
echo "Health check failed" >&2
|
||||
docker logs "$CONTAINER" 2>&1 | tail -30
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "==> Plain text chat"
|
||||
AUTH_ARGS=()
|
||||
if [ -n "${PROXY_INTERNAL_TOKEN:-}" ]; then
|
||||
AUTH_ARGS=(-H "Authorization: Bearer ${PROXY_INTERNAL_TOKEN}")
|
||||
fi
|
||||
TEXT_RESP="$(curl -sf --max-time "$TIMEOUT" "http://127.0.0.1:${PORT}/v1/chat/completions" \
|
||||
"${AUTH_ARGS[@]}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"auto","stream":false,"messages":[{"role":"user","content":"Reply with exactly: HELLO"}]}')"
|
||||
echo "$TEXT_RESP" | grep -q '"content":"HELLO"' || {
|
||||
echo "Plain chat failed:" >&2
|
||||
echo "$TEXT_RESP" >&2
|
||||
exit 1
|
||||
}
|
||||
echo "OK: plain chat"
|
||||
|
||||
PNG_B64="iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
|
||||
echo "==> Image chat (data: PNG)"
|
||||
IMG_RESP="$(curl -sf --max-time "$TIMEOUT" "http://127.0.0.1:${PORT}/v1/chat/completions" \
|
||||
"${AUTH_ARGS[@]}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"model\":\"auto\",\"stream\":false,\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"What color is this 1x1 pixel? Reply with one color word only.\"},{\"type\":\"image_url\",\"image_url\":{\"url\":\"data:image/png;base64,${PNG_B64}\"}}]}]}")"
|
||||
echo "$IMG_RESP" | grep -q '"finish_reason":"stop"' || {
|
||||
echo "Image chat failed:" >&2
|
||||
echo "$IMG_RESP" >&2
|
||||
docker logs "$CONTAINER" 2>&1 | tail -40
|
||||
exit 1
|
||||
}
|
||||
CONTENT="$(echo "$IMG_RESP" | sed -n 's/.*"content":"\([^"]*\)".*/\1/p' | head -1)"
|
||||
if [ -z "$CONTENT" ]; then
|
||||
echo "Image chat returned empty content:" >&2
|
||||
echo "$IMG_RESP" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: image chat → $CONTENT"
|
||||
|
||||
echo "==> All E2E checks passed"
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
# Bridge: cursor-agent spawns this as a stdio MCP server. We connect to a
|
||||
# per-session unix socket provided as $1 and tunnel newline-delimited
|
||||
# JSON-RPC frames between cursor-agent's stdin/stdout and the proxy-owned
|
||||
# socket server (which is the real MCP server).
|
||||
#
|
||||
# Uses Node (always available in the image) rather than nc, to avoid
|
||||
# depending on netcat variants that may not support -U for unix sockets.
|
||||
socket="$1"
|
||||
if [ -z "$socket" ]; then
|
||||
echo "usage: $0 <socket-path>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec node -e '
|
||||
const sock = process.argv[1];
|
||||
if (!sock) { console.error("mcp-stdio-bridge: missing socket arg"); process.exit(1); }
|
||||
const net = require("node:net");
|
||||
const conn = net.createConnection(sock);
|
||||
let buf = "";
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (chunk) => {
|
||||
// Forward as-is; JSON-RPC frames are newline-delimited on both sides.
|
||||
conn.write(chunk);
|
||||
});
|
||||
process.stdin.on("end", () => conn.end());
|
||||
conn.setEncoding("utf8");
|
||||
conn.on("data", (chunk) => process.stdout.write(chunk));
|
||||
conn.on("end", () => process.exit(0));
|
||||
conn.on("close", () => process.exit(0));
|
||||
conn.on("error", (e) => {
|
||||
console.error("[mcp-stdio-bridge] socket error: " + e.message);
|
||||
process.exit(1);
|
||||
});
|
||||
process.on("SIGPIPE", () => process.exit(0));
|
||||
' "$socket"
|
||||
Reference in New Issue
Block a user