agent-control-plane 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env bash
2
+ # openclaw-adapter.sh
3
+ # Adapter implementation for OpenClaw.
4
+
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ source "${SCRIPT_DIR}/adapter-interface.sh"
9
+ source "${SCRIPT_DIR}/adapter-capabilities.sh"
10
+
11
+ ADAPTER_ID="openclaw"
12
+ ADAPTER_NAME="OpenClaw"
13
+ ADAPTER_TYPE="cloud-api"
14
+ ADAPTER_VERSION="1.0.0"
15
+ ADAPTER_MODEL="${OPENCLAW_MODEL:-openrouter/qwen/qwen3.5-plus:free}"
16
+
17
+ # OpenClaw capabilities
18
+ ADAPTER_CAP_CLOUD_API=true
19
+ ADAPTER_CAP_STREAMING=true
20
+ ADAPTER_CAP_JSON_OUTPUT=true
21
+ ADAPTER_CAP_RESIDENT_MODE=true
22
+ ADAPTER_CAP_MAX_TIMEOUT=900
23
+
24
+ adapter_info() {
25
+ cat <<EOF
26
+ id=${ADAPTER_ID}
27
+ name=${ADAPTER_NAME}
28
+ type=${ADAPTER_TYPE}
29
+ version=${ADAPTER_VERSION}
30
+ model=${ADAPTER_MODEL}
31
+ EOF
32
+ }
33
+
34
+ adapter_health_check() {
35
+ if ! command -v openclaw >/dev/null 2>&1; then
36
+ echo "ERROR: openclaw CLI not found in PATH"
37
+ return 1
38
+ fi
39
+ echo "OK: OpenClaw adapter healthy"
40
+ return 0
41
+ }
42
+
43
+ adapter_run() {
44
+ local mode="${1:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
45
+ local session="${2:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
46
+ local worktree="${3:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
47
+ local prompt_file="${4:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
48
+
49
+ local timeout_seconds="${OPENCLAW_TIMEOUT_SECONDS:-900}"
50
+
51
+ echo "OpenClaw adapter: Running session ${session}"
52
+
53
+ cd "${worktree}" || return 1
54
+
55
+ prompt="$(cat "${prompt_file}")"
56
+
57
+ if ! timeout "${timeout_seconds}" openclaw --model "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
58
+ echo "ERROR: OpenClaw run failed"
59
+ return 1
60
+ fi
61
+
62
+ return 0
63
+ }
64
+
65
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
66
+ adapter_info
67
+ echo "---"
68
+ adapter_health_check
69
+ fi
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env bash
2
+ # opencode-adapter.sh
3
+ # Adapter implementation for OpenCode (Crush)
4
+
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ source "${SCRIPT_DIR}/adapter-interface.sh"
9
+ source "${SCRIPT_DIR}/adapter-capabilities.sh"
10
+
11
+ ADAPTER_ID="opencode"
12
+ ADAPTER_NAME="OpenCode (Crush)"
13
+ ADAPTER_TYPE="cloud-api"
14
+ ADAPTER_VERSION="1.0.0"
15
+ ADAPTER_MODEL="${OPENCODE_MODEL:-anthropic/claude-sonnet-4-20250514}"
16
+
17
+ # OpenCode capabilities
18
+ ADAPTER_CAP_CLOUD_API=true
19
+ ADAPTER_CAP_STREAMING=true
20
+ ADAPTER_CAP_JSON_OUTPUT=true
21
+ ADAPTER_CAP_MAX_TIMEOUT=900
22
+
23
+ adapter_info() {
24
+ cat <<EOF
25
+ id=${ADAPTER_ID}
26
+ name=${ADAPTER_NAME}
27
+ type=${ADAPTER_TYPE}
28
+ version=${ADAPTER_VERSION}
29
+ model=${ADAPTER_MODEL}
30
+ EOF
31
+ }
32
+
33
+ adapter_health_check() {
34
+ if ! command -v crush >/dev/null 2>&1; then
35
+ echo "ERROR: crush CLI not found in PATH"
36
+ return 1
37
+ fi
38
+
39
+ # Verify crush can actually run (version check)
40
+ if ! crush --version >/dev/null 2>&1; then
41
+ echo "ERROR: crush CLI cannot run (check installation)"
42
+ return 1
43
+ fi
44
+
45
+ local version
46
+ version="$(crush --version 2>/dev/null || true)"
47
+ if [[ -z "$version" ]]; then
48
+ echo "WARN: Could not detect crush version"
49
+ else
50
+ echo "INFO: Crush version: $version"
51
+ fi
52
+
53
+ # Verify model is specified
54
+ if [[ -z "${ADAPTER_MODEL}" ]]; then
55
+ echo "WARN: No model specified for OpenCode adapter"
56
+ fi
57
+
58
+ echo "OK: OpenCode adapter healthy (model: ${ADAPTER_MODEL})"
59
+ return 0
60
+ }
61
+
62
+ adapter_run() {
63
+ local mode="${1:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
64
+ local session="${2:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
65
+ local worktree="${3:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
66
+ local prompt_file="${4:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
67
+
68
+ # Validate prompt file
69
+ if [[ ! -f "${prompt_file}" ]]; then
70
+ echo "ERROR: Prompt file not found: ${prompt_file}"
71
+ return 1
72
+ fi
73
+ if [[ ! -s "${prompt_file}" ]]; then
74
+ echo "ERROR: Prompt file is empty: ${prompt_file}"
75
+ return 1
76
+ fi
77
+
78
+ local timeout_seconds="${OPENCODE_TIMEOUT_SECONDS:-900}"
79
+
80
+ echo "OpenCode adapter: Running session ${session} with model ${ADAPTER_MODEL}"
81
+
82
+ cd "${worktree}" || return 1
83
+
84
+ prompt="$(cat "${prompt_file}")"
85
+
86
+ if ! timeout "${timeout_seconds}" crush --model "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
87
+ echo "ERROR: OpenCode run failed"
88
+ return 1
89
+ fi
90
+
91
+ return 0
92
+ }
93
+
94
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
95
+ adapter_info
96
+ echo "---"
97
+ adapter_health_check
98
+ fi
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env bash
2
+ # pi-adapter.sh
3
+ # Adapter implementation for Pi CLI (OpenRouter)
4
+
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ source "${SCRIPT_DIR}/adapter-interface.sh"
9
+ source "${SCRIPT_DIR}/adapter-capabilities.sh"
10
+
11
+ ADAPTER_ID="pi"
12
+ ADAPTER_NAME="Pi Coding Agent"
13
+ ADAPTER_TYPE="cloud-api"
14
+ ADAPTER_VERSION="1.0.0"
15
+ ADAPTER_MODEL="${PI_MODEL:-openrouter/qwen/qwen3.5-plus:free}"
16
+
17
+ # Pi capabilities
18
+ ADAPTER_CAP_CLOUD_API=true
19
+ ADAPTER_CAP_STREAMING=true
20
+ ADAPTER_CAP_JSON_OUTPUT=true
21
+ ADAPTER_CAP_MAX_TIMEOUT=900
22
+
23
+ adapter_info() {
24
+ cat <<EOF
25
+ id=${ADAPTER_ID}
26
+ name=${ADAPTER_NAME}
27
+ type=${ADAPTER_TYPE}
28
+ version=${ADAPTER_VERSION}
29
+ model=${ADAPTER_MODEL}
30
+ EOF
31
+ }
32
+
33
+ adapter_health_check() {
34
+ if ! command -v pi >/dev/null 2>&1; then
35
+ echo "ERROR: pi CLI not found in PATH"
36
+ return 1
37
+ fi
38
+
39
+ if [[ -z "${OPENROUTER_API_KEY:-}" ]]; then
40
+ echo "ERROR: OPENROUTER_API_KEY is required for Pi adapter"
41
+ return 1
42
+ fi
43
+
44
+ # Test API connectivity with a simple model list call
45
+ if ! pi models 2>/dev/null | grep -q "."; then
46
+ echo "ERROR: Pi CLI cannot connect to OpenRouter API (check OPENROUTER_API_KEY)"
47
+ return 1
48
+ fi
49
+
50
+ # Verify configured model is available
51
+ if [[ -n "${ADAPTER_MODEL}" ]] && ! pi models 2>/dev/null | grep -q "${ADAPTER_MODEL}"; then
52
+ echo "WARN: Configured model ${ADAPTER_MODEL} not found in available models"
53
+ fi
54
+
55
+ echo "OK: Pi adapter healthy (model: ${ADAPTER_MODEL})"
56
+ return 0
57
+ }
58
+
59
+ adapter_run() {
60
+ local mode="${1:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
61
+ local session="${2:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
62
+ local worktree="${3:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
63
+ local prompt_file="${4:?usage: adapter_run MODE SESSION WORKTREE PROMPT_FILE}"
64
+
65
+ # Validate prompt file
66
+ if [[ ! -f "${prompt_file}" ]]; then
67
+ echo "ERROR: Prompt file not found: ${prompt_file}"
68
+ return 1
69
+ fi
70
+ if [[ ! -s "${prompt_file}" ]]; then
71
+ echo "ERROR: Prompt file is empty: ${prompt_file}"
72
+ return 1
73
+ fi
74
+
75
+ local timeout_seconds="${PI_TIMEOUT_SECONDS:-900}"
76
+
77
+ echo "Pi adapter: Running session ${session}"
78
+
79
+ cd "${worktree}" || return 1
80
+
81
+ prompt="$(cat "${prompt_file}")"
82
+
83
+ if ! timeout "${timeout_seconds}" pi --model "${ADAPTER_MODEL}" "${prompt}" 2>&1; then
84
+ echo "ERROR: Pi run failed"
85
+ return 1
86
+ fi
87
+
88
+ return 0
89
+ }
90
+
91
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
92
+ adapter_info
93
+ echo "---"
94
+ adapter_health_check
95
+ fi
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ # shellcheck source=/dev/null
6
+ source "${SCRIPT_DIR}/flow-config-lib.sh"
7
+
8
+ FLOW_SKILL_DIR="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
9
+ PROFILE_REGISTRY_ROOT="$(resolve_flow_profile_registry_root)"
10
+ CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
11
+ # Do NOT export execution env for the current profile here — render-flow-config
12
+ # is meant to render the SELECTED profile's config (via CONFIG_YAML), and exporting
13
+ # the ambient profile's vars into the shell causes config_or_env to silently override
14
+ # per-profile YAML with defaults from the current resident worker's own config.
15
+ # Also, ambient env vars from the shell are cleared below so they don't leak into
16
+ # profile-smoke or other callers.
17
+ for _clean in ACP_CODING_WORKER ACP_OPENCLAW_MODEL ACP_CLAUDE_MODEL \
18
+ ACP_CLAUDE_TIMEOUT_SECONDS ACP_CLAUDE_MAX_ATTEMPTS ACP_CLAUDE_RETRY_BACKOFF_SECONDS \
19
+ ACP_OPENCLAW_THINKING ACP_OPENCLAW_TIMEOUT_SECONDS \
20
+ CODING_WORKER; do
21
+ unset "${_clean}" 2>/dev/null || true
22
+ done
23
+ unset _clean
24
+ AVAILABLE_PROFILES="$(flow_list_profile_ids "${FLOW_SKILL_DIR}" | paste -sd, -)"
25
+ INSTALLED_PROFILES="$(flow_list_installed_profile_ids | paste -sd, -)"
26
+ PROFILE_ID="$(flow_resolve_adapter_id "${CONFIG_YAML}")"
27
+ PROFILE_SELECTION_MODE="$(flow_profile_selection_mode "${FLOW_SKILL_DIR}")"
28
+ PROFILE_SELECTION_HINT="$(flow_profile_selection_hint "${FLOW_SKILL_DIR}")"
29
+ PROFILE_NOTES="$(flow_resolve_profile_notes_file "${CONFIG_YAML}")"
30
+
31
+ config_or_env() {
32
+ local env_names="${1:?env names required}"
33
+ local config_key="${2:-}"
34
+ local env_name=""
35
+ local value=""
36
+
37
+ for env_name in ${env_names}; do
38
+ value="${!env_name:-}"
39
+ if [[ -n "${value}" ]]; then
40
+ printf '%s\n' "${value}"
41
+ return 0
42
+ fi
43
+ done
44
+
45
+ if [[ -n "${config_key}" && -f "${CONFIG_YAML}" ]]; then
46
+ flow_config_get "${CONFIG_YAML}" "${config_key}"
47
+ return 0
48
+ fi
49
+
50
+ printf '\n'
51
+ }
52
+
53
+ printf 'FLOW_SKILL_DIR=%s\n' "${FLOW_SKILL_DIR}"
54
+ printf 'PROFILE_REGISTRY_ROOT=%s\n' "${PROFILE_REGISTRY_ROOT}"
55
+ printf 'CONFIG_YAML=%s\n' "${CONFIG_YAML}"
56
+ printf 'PROFILE_ID=%s\n' "${PROFILE_ID}"
57
+ printf 'PROFILE_SELECTION_MODE=%s\n' "${PROFILE_SELECTION_MODE}"
58
+ if [[ -n "${PROFILE_SELECTION_HINT}" ]]; then
59
+ printf 'PROFILE_SELECTION_HINT=%s\n' "${PROFILE_SELECTION_HINT}"
60
+ fi
61
+ printf 'AVAILABLE_PROFILES=%s\n' "${AVAILABLE_PROFILES}"
62
+ printf 'INSTALLED_PROFILES=%s\n' "${INSTALLED_PROFILES}"
63
+ printf 'PROFILE_NOTES=%s\n' "${PROFILE_NOTES}"
64
+ if [[ -f "${PROFILE_NOTES}" ]]; then
65
+ printf 'PROFILE_NOTES_EXISTS=yes\n'
66
+ else
67
+ printf 'PROFILE_NOTES_EXISTS=no\n'
68
+ fi
69
+ printf 'EFFECTIVE_REPO_ROOT=%s\n' "$(config_or_env 'ACP_REPO_ROOT' repo.root)"
70
+ printf 'EFFECTIVE_AGENT_REPO_ROOT=%s\n' "$(config_or_env 'ACP_AGENT_REPO_ROOT' runtime.agent_repo_root)"
71
+ printf 'EFFECTIVE_WORKTREE_ROOT=%s\n' "$(config_or_env 'ACP_WORKTREE_ROOT' runtime.worktree_root)"
72
+ printf 'EFFECTIVE_RUNS_ROOT=%s\n' "$(config_or_env 'ACP_RUNS_ROOT' runtime.runs_root)"
73
+ printf 'EFFECTIVE_STATE_ROOT=%s\n' "$(config_or_env 'ACP_STATE_ROOT' runtime.state_root)"
74
+ printf 'EFFECTIVE_RETAINED_REPO_ROOT=%s\n' "$(config_or_env 'ACP_RETAINED_REPO_ROOT' runtime.retained_repo_root)"
75
+ printf 'EFFECTIVE_VSCODE_WORKSPACE_FILE=%s\n' "$(config_or_env 'ACP_VSCODE_WORKSPACE_FILE' runtime.vscode_workspace_file)"
76
+ printf 'EFFECTIVE_CODING_WORKER=%s\n' "$(config_or_env 'ACP_CODING_WORKER' execution.coding_worker)"
77
+ printf 'EFFECTIVE_PROVIDER_QUOTA_COOLDOWNS=%s\n' "$(config_or_env 'ACP_PROVIDER_QUOTA_COOLDOWNS' execution.provider_quota.cooldowns)"
78
+ printf 'EFFECTIVE_PROVIDER_POOL_ORDER=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_ORDER' execution.provider_pool_order)"
79
+ printf 'EFFECTIVE_PROVIDER_POOL_NAME=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_POOL_NAME')"
80
+ printf 'EFFECTIVE_PROVIDER_POOL_BACKEND=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_BACKEND')"
81
+ printf 'EFFECTIVE_PROVIDER_POOL_MODEL=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_MODEL')"
82
+ printf 'EFFECTIVE_PROVIDER_POOL_KEY=%s\n' "$(config_or_env 'ACP_ACTIVE_PROVIDER_KEY')"
83
+ printf 'EFFECTIVE_PROVIDER_POOLS_EXHAUSTED=%s\n' "$(config_or_env 'ACP_PROVIDER_POOLS_EXHAUSTED')"
84
+ printf 'EFFECTIVE_PROVIDER_POOL_SELECTION_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_SELECTION_REASON')"
85
+ printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_EPOCH')"
86
+ printf 'EFFECTIVE_PROVIDER_POOL_NEXT_ATTEMPT_AT=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_NEXT_ATTEMPT_AT')"
87
+ printf 'EFFECTIVE_PROVIDER_POOL_LAST_REASON=%s\n' "$(config_or_env 'ACP_PROVIDER_POOL_LAST_REASON')"
88
+ printf 'EFFECTIVE_CODEX_PROFILE_SAFE=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_SAFE' execution.safe_profile)"
89
+ printf 'EFFECTIVE_CODEX_PROFILE_BYPASS=%s\n' "$(config_or_env 'ACP_CODEX_PROFILE_BYPASS' execution.bypass_profile)"
90
+ printf 'EFFECTIVE_CLAUDE_MODEL=%s\n' "$(config_or_env 'ACP_CLAUDE_MODEL' execution.claude.model)"
91
+ printf 'EFFECTIVE_CLAUDE_PERMISSION_MODE=%s\n' "$(config_or_env 'ACP_CLAUDE_PERMISSION_MODE' execution.claude.permission_mode)"
92
+ printf 'EFFECTIVE_CLAUDE_EFFORT=%s\n' "$(config_or_env 'ACP_CLAUDE_EFFORT' execution.claude.effort)"
93
+ printf 'EFFECTIVE_CLAUDE_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_TIMEOUT_SECONDS' execution.claude.timeout_seconds)"
94
+ printf 'EFFECTIVE_CLAUDE_MAX_ATTEMPTS=%s\n' "$(config_or_env 'ACP_CLAUDE_MAX_ATTEMPTS' execution.claude.max_attempts)"
95
+ printf 'EFFECTIVE_CLAUDE_RETRY_BACKOFF_SECONDS=%s\n' "$(config_or_env 'ACP_CLAUDE_RETRY_BACKOFF_SECONDS' execution.claude.retry_backoff_seconds)"
96
+ printf 'EFFECTIVE_OPENCLAW_MODEL=%s\n' "$(config_or_env 'ACP_OPENCLAW_MODEL' execution.openclaw.model)"
97
+ printf 'EFFECTIVE_OPENCLAW_THINKING=%s\n' "$(config_or_env 'ACP_OPENCLAW_THINKING' execution.openclaw.thinking)"
98
+ printf 'EFFECTIVE_OPENCLAW_TIMEOUT_SECONDS=%s\n' "$(config_or_env 'ACP_OPENCLAW_TIMEOUT_SECONDS' execution.openclaw.timeout_seconds)"
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ # run-with-adapter.sh
3
+ # Generic runner that uses the adapter interface
4
+ # Usage: run-with-adapter.sh ADAPTER_SCRIPT MODE SESSION WORKTREE PROMPT_FILE
5
+
6
+ set -euo pipefail
7
+
8
+ ADAPTER_SCRIPT="${1:?usage: run-with-adapter.sh ADAPTER_SCRIPT MODE SESSION WORKTREE PROMPT_FILE}"
9
+ MODE="${2:?usage: run-with-adapter.sh ADAPTER_SCRIPT MODE SESSION WORKTREE PROMPT_FILE}"
10
+ SESSION="${3:?usage: run-with-adapter.sh ADAPTER_SCRIPT MODE SESSION WORKTREE PROMPT_FILE}"
11
+ WORKTREE="${4:?usage: run-with-adapter.sh ADAPTER_SCRIPT MODE SESSION WORKTREE PROMPT_FILE}"
12
+ PROMPT_FILE="${5:?usage: run-with-adapter.sh ADAPTER_SCRIPT MODE SESSION WORKTREE PROMPT_FILE}"
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+
16
+ # Load adapter interface
17
+ source "${SCRIPT_DIR}/adapter-interface.sh"
18
+
19
+ # Load adapter implementation
20
+ adapter_load "${ADAPTER_SCRIPT}"
21
+
22
+ # Validate adapter
23
+ if ! adapter_validate; then
24
+ echo "ERROR: Adapter validation failed"
25
+ exit 1
26
+ fi
27
+
28
+ # Print adapter info
29
+ echo "=== Using Adapter ==="
30
+ adapter_info
31
+ echo "===================="
32
+
33
+ # Run the task
34
+ adapter_run "${MODE}" "${SESSION}" "${WORKTREE}" "${PROMPT_FILE}"
@@ -78,6 +78,29 @@ sync_skill_copies() {
78
78
  if [[ -n "${TARGET_FLOW_COMPAT_ALIAS}" ]]; then
79
79
  sync_tree_into_target "${FLOW_SKILL_SOURCE}" "${TARGET_FLOW_COMPAT_ALIAS}"
80
80
  fi
81
+
82
+ # Explicitly ensure profile-smoke.sh is synced to runtime home
83
+ local profile_smoke_source="${FLOW_SKILL_SOURCE}/tools/bin/profile-smoke.sh"
84
+ local profile_smoke_target="${FLOW_SKILL_TARGET}/tools/bin/profile-smoke.sh"
85
+ if [[ -f "${profile_smoke_source}" ]]; then
86
+ mkdir -p "$(dirname "${profile_smoke_target}")"
87
+ cp "${profile_smoke_source}" "${profile_smoke_target}"
88
+ chmod +x "${profile_smoke_target}"
89
+ fi
90
+
91
+ # Ensure test scripts are synced for regression coverage
92
+ for test_script in \
93
+ "${FLOW_SKILL_SOURCE}/tools/bin/kick-scheduler-wrapper.sh" \
94
+ "${FLOW_SKILL_SOURCE}/tools/tests/test-kick-scheduler-wrapper.sh" \
95
+ "${FLOW_SKILL_SOURCE}/tools/tests/test-runtime-operator-smoke.sh" \
96
+ "${FLOW_SKILL_SOURCE}/tools/tests/test-package-tarball-surface.sh"; do
97
+ if [[ -f "${test_script}" ]]; then
98
+ target_script="${FLOW_SKILL_TARGET}${test_script#${FLOW_SKILL_SOURCE}}"
99
+ mkdir -p "$(dirname "${target_script}")"
100
+ cp "${test_script}" "${target_script}"
101
+ chmod +x "${target_script}"
102
+ fi
103
+ done
81
104
  }
82
105
 
83
106
  refresh_legacy_profile_templates() {