From 69128ccf728647cdb72f695b48455d45be0b7dc1 Mon Sep 17 00:00:00 2001 From: Andrey Avtomonov Date: Mon, 11 May 2026 20:06:13 +0200 Subject: [PATCH] fix: link Conductor agent overlays from root checkout --- scripts/conductor-scripts.test.mjs | 8 ++-- scripts/conductor-setup.sh | 64 ++++++++++-------------------- 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/scripts/conductor-scripts.test.mjs b/scripts/conductor-scripts.test.mjs index d33fa73a..9dc17f0f 100644 --- a/scripts/conductor-scripts.test.mjs +++ b/scripts/conductor-scripts.test.mjs @@ -32,11 +32,13 @@ describe('Conductor workspace scripts', () => { assert.doesNotMatch(setupScript, /scripts\/conductor\//); }); - it('links private agent overlays when KTX_AGENT_OVERLAYS_ROOT is set', async () => { + it('links private agent overlays from the Conductor root checkout', async () => { const workspaceScript = await readText('scripts/conductor-setup.sh'); - assert.match(workspaceScript, /KTX_AGENT_OVERLAYS_ROOT/); - assert.match(workspaceScript, /ln -s "\$\{KTX_AGENT_OVERLAYS_ROOT\}\/\.agents" \.agents/); + assert.match(workspaceScript, /link_shared_path "\$CONDUCTOR_ROOT_PATH\/\.agents" \.agents/); + assert.match(workspaceScript, /link_shared_path "\$CONDUCTOR_ROOT_PATH\/\.claude" \.claude/); + assert.doesNotMatch(workspaceScript, /KTX_AGENT_OVERLAYS_ROOT/); + assert.doesNotMatch(workspaceScript, /link_agent_skills_for_claude/); }); it('runs the KTX daemon on the documented fixed local port', async () => { diff --git a/scripts/conductor-setup.sh b/scripts/conductor-setup.sh index 15dbf776..34d16216 100755 --- a/scripts/conductor-setup.sh +++ b/scripts/conductor-setup.sh @@ -82,63 +82,39 @@ resolve_uv_for_project() { printf '%s\n' "$workspace_uv" } -link_agent_overlays() { - if [ -z "${KTX_AGENT_OVERLAYS_ROOT:-}" ] || [ ! -d "${KTX_AGENT_OVERLAYS_ROOT}/.agents" ]; then +link_shared_path() { + local source_path="$1" + local link_path="$2" + + if [ ! -e "$source_path" ] && [ ! -L "$source_path" ]; then + return 1 + fi + + if [ -L "$link_path" ]; then + ln -sfn "$source_path" "$link_path" + echo "Linked $link_path" return 0 fi - if [ -L .agents ]; then - return 0 + if [ -e "$link_path" ]; then + echo "Skipping $link_path symlink because $link_path already exists and is not a symlink." >&2 + return 1 fi - if [ -e .agents ]; then - echo "Skipping .agents symlink because .agents already exists and is not a symlink." >&2 - return 0 - fi - - ln -s "${KTX_AGENT_OVERLAYS_ROOT}/.agents" .agents + ln -s "$source_path" "$link_path" + echo "Linked $link_path" } -# Expose .agents/skills/* to Claude Code by symlinking each entry under -# .claude/skills/. Codex CLI reads .agents/skills/ directly; Claude Code only -# scans .claude/skills/, so the overlay needs both sides to be visible to both -# tools. -link_agent_skills_for_claude() { - if [ ! -d .agents/skills ]; then - return 0 +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 fi - - mkdir -p .claude/skills - - for skill_path in .agents/skills/*; do - [ -e "$skill_path" ] || continue - - local skill_name - skill_name="$(basename "$skill_path")" - local link_path=".claude/skills/$skill_name" - local target="../../.agents/skills/$skill_name" - - if [ -L "$link_path" ]; then - if [ "$(readlink "$link_path")" = "$target" ]; then - continue - fi - echo "Skipping $link_path: existing symlink points elsewhere." >&2 - continue - fi - - if [ -e "$link_path" ]; then - echo "Skipping $link_path: already exists and is not a symlink." >&2 - continue - fi - - ln -s "$target" "$link_path" - done } echo "=== Conductor KTX workspace setup ===" link_agent_overlays -link_agent_skills_for_claude if [ -n "${CONDUCTOR_ROOT_PATH:-}" ] && [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; then ln -sf "$CONDUCTOR_ROOT_PATH/.env" .env