Add Conductor workspace scripts

This commit is contained in:
Andrey Avtomonov 2026-05-11 00:13:38 +02:00
parent d89be2390f
commit 379abc69f2
4 changed files with 255 additions and 0 deletions

7
conductor.json Normal file
View file

@ -0,0 +1,7 @@
{
"scripts": {
"setup": "bash scripts/conductor-setup.sh",
"run": "bash scripts/conductor-run.sh"
},
"runScriptMode": "nonconcurrent"
}

98
scripts/conductor-run.sh Executable file
View file

@ -0,0 +1,98 @@
#!/bin/bash
# conductor-run.sh - Starts the long-lived local KTX daemon for Conductor.
#
# Uses a fixed port because Conductor runs this workspace in nonconcurrent mode.
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"
}
echo "=== Starting KTX for Conductor ==="
echo "Building KTX packages..."
pnpm run build
KTX_UV_BIN="$(resolve_uv_for_project "pyproject.toml")"
export PATH="$(dirname "$KTX_UV_BIN"):$PATH"
if [ -f ".venv/bin/activate" ]; then
source .venv/bin/activate
fi
echo "KTX daemon: http://127.0.0.1:8765"
exec uv run ktx-daemon serve-http --host 127.0.0.1 --port 8765

View file

@ -0,0 +1,40 @@
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { describe, it } from 'node:test';
async function readText(relativePath) {
return readFile(new URL(`../${relativePath}`, import.meta.url), 'utf8');
}
describe('Conductor workspace scripts', () => {
it('registers setup and run scripts in nonconcurrent mode', async () => {
const manifest = JSON.parse(await readText('conductor.json'));
assert.deepEqual(manifest.scripts, {
setup: 'bash scripts/conductor-setup.sh',
run: 'bash scripts/conductor-run.sh',
});
assert.equal(manifest.runScriptMode, 'nonconcurrent');
});
it('sets up exact uv, Python packages, JS packages, and the built CLI', async () => {
const setupScript = await readText('scripts/conductor-setup.sh');
assert.match(setupScript, /read_required_uv_version\(\)/);
assert.match(setupScript, /\.context\/bin\/uv-\$required_version/);
assert.match(setupScript, /uv sync --all-packages --all-groups/);
assert.match(setupScript, /pnpm install --frozen-lockfile --prefer-offline/);
assert.match(setupScript, /pnpm run native:rebuild/);
assert.match(setupScript, /pnpm run build/);
assert.match(setupScript, /packages\/cli\/dist\/bin\.js dev doctor setup --no-input/);
});
it('runs the KTX daemon on the documented fixed local port', async () => {
const runScript = await readText('scripts/conductor-run.sh');
assert.match(runScript, /pnpm run build/);
assert.match(runScript, /source \.venv\/bin\/activate/);
assert.match(runScript, /uv run ktx-daemon serve-http --host 127\.0\.0\.1 --port 8765/);
assert.doesNotMatch(runScript, /frontend|@kaelio\/server|python-service|npx/);
});
});

110
scripts/conductor-setup.sh Executable file
View file

@ -0,0 +1,110 @@
#!/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"
}
echo "=== Conductor KTX workspace setup ==="
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..."
node packages/cli/dist/bin.js dev doctor setup --no-input
echo "=== Setup complete ==="