2026-05-11 09:55:42 +02:00
|
|
|
#!/bin/bash
|
|
|
|
|
# conductor-setup.sh - Runs once when Conductor creates a KTX workspace.
|
|
|
|
|
#
|
|
|
|
|
# Prepares the standalone pnpm + uv workspace and builds the local CLI.
|
|
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
set -o pipefail
|
|
|
|
|
|
|
|
|
|
read_required_uv_version() {
|
|
|
|
|
local project_file="$1"
|
|
|
|
|
|
|
|
|
|
if [ ! -f "$project_file" ]; then
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
sed -nE 's/^[[:space:]]*required-version[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/p' "$project_file" | head -n 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uv_version() {
|
|
|
|
|
local uv_bin="$1"
|
|
|
|
|
|
|
|
|
|
"$uv_bin" --version 2>/dev/null | awk '{print $2}'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
install_workspace_uv() {
|
|
|
|
|
local required_version="$1"
|
|
|
|
|
local install_dir="$PWD/.context/bin/uv-$required_version"
|
|
|
|
|
|
|
|
|
|
mkdir -p "$install_dir"
|
|
|
|
|
|
|
|
|
|
if [ ! -x "$install_dir/uv" ] || [ "$(uv_version "$install_dir/uv")" != "$required_version" ]; then
|
|
|
|
|
echo "Installing workspace-local uv $required_version..." >&2
|
|
|
|
|
curl -LsSf "https://astral.sh/uv/$required_version/install.sh" |
|
|
|
|
|
env UV_INSTALL_DIR="$install_dir" UV_NO_MODIFY_PATH=1 sh >&2
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
printf '%s\n' "$install_dir/uv"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resolve_uv_for_project() {
|
|
|
|
|
local project_file="$1"
|
|
|
|
|
local required_version
|
|
|
|
|
local system_uv
|
|
|
|
|
local system_version
|
|
|
|
|
local workspace_uv
|
|
|
|
|
|
|
|
|
|
required_version="$(read_required_uv_version "$project_file" || true)"
|
|
|
|
|
required_version="${required_version#==}"
|
|
|
|
|
|
|
|
|
|
if [ -z "$required_version" ]; then
|
|
|
|
|
command -v uv
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! [[ "$required_version" =~ ^[0-9]+[.][0-9]+[.][0-9]+$ ]]; then
|
|
|
|
|
echo "WARNING: Unsupported uv required-version '$required_version'; using uv from PATH." >&2
|
|
|
|
|
command -v uv
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if command -v uv >/dev/null 2>&1; then
|
|
|
|
|
system_uv="$(command -v uv)"
|
|
|
|
|
system_version="$(uv_version "$system_uv")"
|
|
|
|
|
|
|
|
|
|
if [ "$system_version" = "$required_version" ]; then
|
|
|
|
|
printf '%s\n' "$system_uv"
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "Found uv $system_version at $system_uv; $project_file requires uv $required_version." >&2
|
|
|
|
|
else
|
|
|
|
|
echo "uv is not installed on PATH; $project_file requires uv $required_version." >&2
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
workspace_uv="$(install_workspace_uv "$required_version")"
|
|
|
|
|
|
|
|
|
|
if [ "$(uv_version "$workspace_uv")" != "$required_version" ]; then
|
|
|
|
|
echo "ERROR: Expected uv $required_version at $workspace_uv, got $("$workspace_uv" --version 2>&1 || true)." >&2
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
printf '%s\n' "$workspace_uv"
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-11 20:06:13 +02:00
|
|
|
link_shared_path() {
|
|
|
|
|
local source_path="$1"
|
|
|
|
|
local link_path="$2"
|
|
|
|
|
|
|
|
|
|
if [ ! -e "$source_path" ] && [ ! -L "$source_path" ]; then
|
|
|
|
|
return 1
|
2026-05-11 10:40:30 +02:00
|
|
|
fi
|
|
|
|
|
|
2026-05-11 20:06:13 +02:00
|
|
|
if [ -L "$link_path" ]; then
|
|
|
|
|
ln -sfn "$source_path" "$link_path"
|
|
|
|
|
echo "Linked $link_path"
|
2026-05-11 10:40:30 +02:00
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
2026-05-11 20:06:13 +02:00
|
|
|
if [ -e "$link_path" ]; then
|
|
|
|
|
echo "Skipping $link_path symlink because $link_path already exists and is not a symlink." >&2
|
|
|
|
|
return 1
|
2026-05-11 10:40:30 +02:00
|
|
|
fi
|
|
|
|
|
|
2026-05-11 20:06:13 +02:00
|
|
|
ln -s "$source_path" "$link_path"
|
|
|
|
|
echo "Linked $link_path"
|
2026-05-11 10:40:30 +02:00
|
|
|
}
|
|
|
|
|
|
2026-05-11 20:06:13 +02:00
|
|
|
link_agent_overlays() {
|
|
|
|
|
if [ -n "${CONDUCTOR_ROOT_PATH:-}" ]; then
|
|
|
|
|
link_shared_path "$CONDUCTOR_ROOT_PATH/.agents" .agents || true
|
|
|
|
|
link_shared_path "$CONDUCTOR_ROOT_PATH/.claude" .claude || true
|
2026-05-11 16:21:40 +02:00
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-11 09:55:42 +02:00
|
|
|
echo "=== Conductor KTX workspace setup ==="
|
|
|
|
|
|
2026-05-11 10:40:30 +02:00
|
|
|
link_agent_overlays
|
|
|
|
|
|
2026-05-11 09:55:42 +02:00
|
|
|
if [ -n "${CONDUCTOR_ROOT_PATH:-}" ] && [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; then
|
|
|
|
|
ln -sf "$CONDUCTOR_ROOT_PATH/.env" .env
|
|
|
|
|
echo "Linked .env"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
KTX_UV_BIN="$(resolve_uv_for_project "pyproject.toml")"
|
|
|
|
|
export PATH="$(dirname "$KTX_UV_BIN"):$PATH"
|
|
|
|
|
|
|
|
|
|
echo "Installing KTX Python dependencies..."
|
|
|
|
|
uv sync --all-packages --all-groups
|
|
|
|
|
|
|
|
|
|
echo "Installing KTX JS dependencies..."
|
|
|
|
|
pnpm install --frozen-lockfile --prefer-offline
|
|
|
|
|
|
|
|
|
|
echo "Rebuilding native JS dependencies..."
|
|
|
|
|
pnpm run native:rebuild
|
|
|
|
|
|
|
|
|
|
echo "Building KTX packages..."
|
|
|
|
|
pnpm run build
|
|
|
|
|
|
|
|
|
|
echo "Running KTX setup doctor..."
|
2026-05-12 23:51:46 +02:00
|
|
|
node packages/cli/dist/bin.js status --no-input
|
2026-05-11 09:55:42 +02:00
|
|
|
|
|
|
|
|
echo "=== Setup complete ==="
|