agent-control-plane 0.7.1 → 0.9.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.
@@ -1,461 +0,0 @@
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
- usage() {
9
- cat <<'EOF'
10
- Usage:
11
- profile-smoke.sh [--profile-id <id>] [--help]
12
-
13
- Validate available control-plane profiles before using them in the scheduler.
14
- Checks:
15
- - canonical profile YAML exists
16
- - render-flow-config resolves the selected profile
17
- - required runtime/session fields are non-empty
18
- - session and branch prefixes do not collide across installed profiles
19
- EOF
20
- }
21
-
22
- profile_filter=""
23
-
24
- while [[ $# -gt 0 ]]; do
25
- case "$1" in
26
- --profile-id) profile_filter="${2:-}"; shift 2 ;;
27
- --help|-h) usage; exit 0 ;;
28
- *) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
29
- esac
30
- done
31
-
32
- flow_skill_dir="$(resolve_flow_skill_dir "${BASH_SOURCE[0]}")"
33
- render_script="${flow_skill_dir}/tools/bin/render-flow-config.sh"
34
- profiles_file="$(mktemp)"
35
- records_file="$(mktemp)"
36
- trap 'rm -f "$profiles_file" "$records_file"' EXIT
37
- failures=0
38
-
39
- if [[ -n "$profile_filter" ]]; then
40
- printf '%s\n' "$profile_filter" >"$profiles_file"
41
- else
42
- flow_list_profile_ids "${flow_skill_dir}" >"$profiles_file"
43
- fi
44
-
45
- if [[ ! -s "$profiles_file" ]]; then
46
- echo "no installed profiles found" >&2
47
- exit 1
48
- fi
49
-
50
- render_field() {
51
- local key="${1:?key required}"
52
- local payload="${2:-}"
53
- awk -F= -v key="$key" '$1 == key { print substr($0, length(key) + 2); exit }' <<<"$payload"
54
- }
55
-
56
- report_failure() {
57
- local profile_id="${1:?profile id required}"
58
- local message="${2:?message required}"
59
- printf 'PROFILE_ID=%s\n' "$profile_id"
60
- printf 'PROFILE_STATUS=failed\n'
61
- printf 'FAILURE=%s\n' "$message"
62
- failures=$((failures + 1))
63
- }
64
-
65
- require_nonempty() {
66
- local profile_id="${1:?profile id required}"
67
- local label="${2:?label required}"
68
- local value="${3:-}"
69
- if [[ -z "$value" ]]; then
70
- report_failure "$profile_id" "${label} missing"
71
- return 1
72
- fi
73
- return 0
74
- }
75
-
76
- require_positive_integer() {
77
- local profile_id="${1:?profile id required}"
78
- local label="${2:?label required}"
79
- local value="${3:-}"
80
- if [[ -z "$value" ]]; then
81
- report_failure "$profile_id" "${label} missing"
82
- return 1
83
- fi
84
- case "$value" in
85
- ''|*[!0-9]*|0)
86
- report_failure "$profile_id" "${label} must be a positive integer"
87
- return 1
88
- ;;
89
- esac
90
- return 0
91
- }
92
-
93
- require_nonnegative_integer() {
94
- local profile_id="${1:?profile id required}"
95
- local label="${2:?label required}"
96
- local value="${3:-}"
97
- if [[ -z "$value" ]]; then
98
- report_failure "$profile_id" "${label} missing"
99
- return 1
100
- fi
101
- case "$value" in
102
- ''|*[!0-9]*)
103
- report_failure "$profile_id" "${label} must be a non-negative integer"
104
- return 1
105
- ;;
106
- esac
107
- return 0
108
- }
109
-
110
- validate_provider_pool_config() {
111
- local profile_id="${1:?profile id required}"
112
- local config_yaml="${2:?config yaml required}"
113
- local pool_name="${3:?pool name required}"
114
- local pool_state=""
115
- local pool_valid=""
116
- local pool_backend=""
117
- local pool_model=""
118
- local pool_safe_profile=""
119
- local pool_bypass_profile=""
120
- local pool_claude_model=""
121
- local pool_claude_permission_mode=""
122
- local pool_claude_effort=""
123
- local pool_claude_timeout_seconds=""
124
- local pool_claude_max_attempts=""
125
- local pool_claude_retry_backoff_seconds=""
126
- local pool_openclaw_model=""
127
- local pool_openclaw_thinking=""
128
- local pool_openclaw_timeout_seconds=""
129
- local pool_failed="no"
130
-
131
- pool_state="$(flow_provider_pool_state_get "$config_yaml" "$pool_name")"
132
- pool_valid="$(flow_kv_get "$pool_state" "VALID")"
133
- pool_backend="$(flow_kv_get "$pool_state" "BACKEND")"
134
- pool_model="$(flow_kv_get "$pool_state" "MODEL")"
135
- pool_safe_profile="$(flow_kv_get "$pool_state" "SAFE_PROFILE")"
136
- pool_bypass_profile="$(flow_kv_get "$pool_state" "BYPASS_PROFILE")"
137
- pool_claude_model="$(flow_kv_get "$pool_state" "CLAUDE_MODEL")"
138
- pool_claude_permission_mode="$(flow_kv_get "$pool_state" "CLAUDE_PERMISSION_MODE")"
139
- pool_claude_effort="$(flow_kv_get "$pool_state" "CLAUDE_EFFORT")"
140
- pool_claude_timeout_seconds="$(flow_kv_get "$pool_state" "CLAUDE_TIMEOUT_SECONDS")"
141
- pool_claude_max_attempts="$(flow_kv_get "$pool_state" "CLAUDE_MAX_ATTEMPTS")"
142
- pool_claude_retry_backoff_seconds="$(flow_kv_get "$pool_state" "CLAUDE_RETRY_BACKOFF_SECONDS")"
143
- pool_openclaw_model="$(flow_kv_get "$pool_state" "OPENCLAW_MODEL")"
144
- pool_openclaw_thinking="$(flow_kv_get "$pool_state" "OPENCLAW_THINKING")"
145
- pool_openclaw_timeout_seconds="$(flow_kv_get "$pool_state" "OPENCLAW_TIMEOUT_SECONDS")"
146
-
147
- if [[ "${pool_valid}" != "yes" ]]; then
148
- report_failure "$profile_id" "provider pool ${pool_name} is invalid"
149
- pool_failed="yes"
150
- fi
151
-
152
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.coding_worker" "$pool_backend"; then
153
- pool_failed="yes"
154
- fi
155
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.model" "$pool_model"; then
156
- pool_failed="yes"
157
- fi
158
-
159
- case "$pool_backend" in
160
- codex)
161
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.safe_profile" "$pool_safe_profile"; then
162
- pool_failed="yes"
163
- fi
164
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.bypass_profile" "$pool_bypass_profile"; then
165
- pool_failed="yes"
166
- fi
167
- ;;
168
- claude)
169
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.claude.model" "$pool_claude_model"; then
170
- pool_failed="yes"
171
- fi
172
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.claude.permission_mode" "$pool_claude_permission_mode"; then
173
- pool_failed="yes"
174
- fi
175
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.claude.effort" "$pool_claude_effort"; then
176
- pool_failed="yes"
177
- fi
178
- case "$pool_claude_effort" in
179
- low|medium|high|max) ;;
180
- *)
181
- report_failure "$profile_id" "provider_pool.${pool_name}.claude.effort must be one of: low, medium, high, max"
182
- pool_failed="yes"
183
- ;;
184
- esac
185
- if ! require_positive_integer "$profile_id" "provider_pool.${pool_name}.claude.timeout_seconds" "$pool_claude_timeout_seconds"; then
186
- pool_failed="yes"
187
- fi
188
- if ! require_positive_integer "$profile_id" "provider_pool.${pool_name}.claude.max_attempts" "$pool_claude_max_attempts"; then
189
- pool_failed="yes"
190
- fi
191
- if ! require_nonnegative_integer "$profile_id" "provider_pool.${pool_name}.claude.retry_backoff_seconds" "$pool_claude_retry_backoff_seconds"; then
192
- pool_failed="yes"
193
- fi
194
- ;;
195
- openclaw)
196
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.openclaw.model" "$pool_openclaw_model"; then
197
- pool_failed="yes"
198
- fi
199
- if ! require_nonempty "$profile_id" "provider_pool.${pool_name}.openclaw.thinking" "$pool_openclaw_thinking"; then
200
- pool_failed="yes"
201
- fi
202
- if ! require_positive_integer "$profile_id" "provider_pool.${pool_name}.openclaw.timeout_seconds" "$pool_openclaw_timeout_seconds"; then
203
- pool_failed="yes"
204
- fi
205
- ;;
206
- '')
207
- ;;
208
- *)
209
- report_failure "$profile_id" "provider_pool.${pool_name}.coding_worker unsupported: ${pool_backend}"
210
- pool_failed="yes"
211
- ;;
212
- esac
213
-
214
- [[ "$pool_failed" != "yes" ]]
215
- }
216
-
217
- while IFS= read -r profile_id; do
218
- [[ -n "$profile_id" ]] || continue
219
-
220
- config_yaml="$(flow_find_profile_dir_by_id "${flow_skill_dir}" "${profile_id}")/control-plane.yaml"
221
- if [[ ! -f "$config_yaml" ]]; then
222
- report_failure "$profile_id" "canonical profile missing: $config_yaml"
223
- continue
224
- fi
225
-
226
- if ! render_output="$(ACP_PROJECT_ID="$profile_id" bash "$render_script" 2>/dev/null)"; then
227
- report_failure "$profile_id" "render-flow-config failed"
228
- continue
229
- fi
230
-
231
- rendered_profile_id="$(render_field "PROFILE_ID" "$render_output")"
232
- available_profiles="$(render_field "AVAILABLE_PROFILES" "$render_output")"
233
- effective_repo_root="$(render_field "EFFECTIVE_REPO_ROOT" "$render_output")"
234
- effective_agent_repo_root="$(render_field "EFFECTIVE_AGENT_REPO_ROOT" "$render_output")"
235
- effective_worktree_root="$(render_field "EFFECTIVE_WORKTREE_ROOT" "$render_output")"
236
- effective_runs_root="$(render_field "EFFECTIVE_RUNS_ROOT" "$render_output")"
237
- effective_state_root="$(render_field "EFFECTIVE_STATE_ROOT" "$render_output")"
238
- effective_coding_worker="$(render_field "EFFECTIVE_CODING_WORKER" "$render_output")"
239
- effective_codex_profile_safe="$(render_field "EFFECTIVE_CODEX_PROFILE_SAFE" "$render_output")"
240
- effective_codex_profile_bypass="$(render_field "EFFECTIVE_CODEX_PROFILE_BYPASS" "$render_output")"
241
- effective_provider_pool_order="$(render_field "EFFECTIVE_PROVIDER_POOL_ORDER" "$render_output")"
242
- effective_provider_pool_name="$(render_field "EFFECTIVE_PROVIDER_POOL_NAME" "$render_output")"
243
- effective_provider_pool_backend="$(render_field "EFFECTIVE_PROVIDER_POOL_BACKEND" "$render_output")"
244
- effective_provider_pool_model="$(render_field "EFFECTIVE_PROVIDER_POOL_MODEL" "$render_output")"
245
- effective_provider_pool_selection_reason="$(render_field "EFFECTIVE_PROVIDER_POOL_SELECTION_REASON" "$render_output")"
246
- effective_claude_model="$(render_field "EFFECTIVE_CLAUDE_MODEL" "$render_output")"
247
- effective_claude_permission_mode="$(render_field "EFFECTIVE_CLAUDE_PERMISSION_MODE" "$render_output")"
248
- effective_claude_effort="$(render_field "EFFECTIVE_CLAUDE_EFFORT" "$render_output")"
249
- effective_claude_timeout_seconds="$(render_field "EFFECTIVE_CLAUDE_TIMEOUT_SECONDS" "$render_output")"
250
- effective_claude_max_attempts="$(render_field "EFFECTIVE_CLAUDE_MAX_ATTEMPTS" "$render_output")"
251
- effective_claude_retry_backoff_seconds="$(render_field "EFFECTIVE_CLAUDE_RETRY_BACKOFF_SECONDS" "$render_output")"
252
- effective_openclaw_model="$(render_field "EFFECTIVE_OPENCLAW_MODEL" "$render_output")"
253
- effective_openclaw_thinking="$(render_field "EFFECTIVE_OPENCLAW_THINKING" "$render_output")"
254
- effective_openclaw_timeout_seconds="$(render_field "EFFECTIVE_OPENCLAW_TIMEOUT_SECONDS" "$render_output")"
255
-
256
- issue_prefix="$(flow_config_get "$config_yaml" "session_naming.issue_prefix")"
257
- pr_prefix="$(flow_config_get "$config_yaml" "session_naming.pr_prefix")"
258
- issue_branch_prefix="$(flow_config_get "$config_yaml" "session_naming.issue_branch_prefix")"
259
- pr_worktree_branch_prefix="$(flow_config_get "$config_yaml" "session_naming.pr_worktree_branch_prefix")"
260
- repo_slug="$(flow_config_get "$config_yaml" "repo.slug")"
261
- remote_repo_slug="$(flow_git_remote_repo_slug "$effective_repo_root" "origin" 2>/dev/null || true)"
262
-
263
- profile_failed="no"
264
- if [[ "$rendered_profile_id" != "$profile_id" ]]; then
265
- report_failure "$profile_id" "rendered profile id mismatch: ${rendered_profile_id:-<empty>}"
266
- profile_failed="yes"
267
- fi
268
- if [[ ",${available_profiles}," != *",${profile_id},"* ]]; then
269
- report_failure "$profile_id" "available profiles missing selected profile"
270
- profile_failed="yes"
271
- fi
272
-
273
- for required_pair in \
274
- "repo.slug:${repo_slug}" \
275
- "session_naming.issue_prefix:${issue_prefix}" \
276
- "session_naming.pr_prefix:${pr_prefix}" \
277
- "session_naming.issue_branch_prefix:${issue_branch_prefix}" \
278
- "session_naming.pr_worktree_branch_prefix:${pr_worktree_branch_prefix}" \
279
- "effective.repo_root:${effective_repo_root}" \
280
- "effective.agent_repo_root:${effective_agent_repo_root}" \
281
- "effective.worktree_root:${effective_worktree_root}" \
282
- "effective.runs_root:${effective_runs_root}" \
283
- "effective.state_root:${effective_state_root}" \
284
- "effective.coding_worker:${effective_coding_worker}"; do
285
- label="${required_pair%%:*}"
286
- value="${required_pair#*:}"
287
- if ! require_nonempty "$profile_id" "$label" "$value"; then
288
- profile_failed="yes"
289
- fi
290
- done
291
-
292
- case "$effective_coding_worker" in
293
- codex|openclaw|claude) ;;
294
- *)
295
- report_failure "$profile_id" "unsupported coding worker: ${effective_coding_worker}"
296
- profile_failed="yes"
297
- ;;
298
- esac
299
-
300
- case "$effective_coding_worker" in
301
- codex)
302
- if ! require_nonempty "$profile_id" "effective.codex_profile_safe" "$effective_codex_profile_safe"; then
303
- profile_failed="yes"
304
- fi
305
- if ! require_nonempty "$profile_id" "effective.codex_profile_bypass" "$effective_codex_profile_bypass"; then
306
- profile_failed="yes"
307
- fi
308
- ;;
309
- claude)
310
- if ! require_nonempty "$profile_id" "effective.claude.model" "$effective_claude_model"; then
311
- profile_failed="yes"
312
- fi
313
- if ! require_nonempty "$profile_id" "effective.claude.permission_mode" "$effective_claude_permission_mode"; then
314
- profile_failed="yes"
315
- fi
316
- if ! require_nonempty "$profile_id" "effective.claude.effort" "$effective_claude_effort"; then
317
- profile_failed="yes"
318
- fi
319
- case "$effective_claude_effort" in
320
- low|medium|high|max) ;;
321
- *)
322
- report_failure "$profile_id" "effective.claude.effort must be one of: low, medium, high, max"
323
- profile_failed="yes"
324
- ;;
325
- esac
326
- if ! require_positive_integer "$profile_id" "effective.claude.timeout_seconds" "$effective_claude_timeout_seconds"; then
327
- profile_failed="yes"
328
- fi
329
- if ! require_positive_integer "$profile_id" "effective.claude.max_attempts" "$effective_claude_max_attempts"; then
330
- profile_failed="yes"
331
- fi
332
- if ! require_nonnegative_integer "$profile_id" "effective.claude.retry_backoff_seconds" "$effective_claude_retry_backoff_seconds"; then
333
- profile_failed="yes"
334
- fi
335
- ;;
336
- openclaw)
337
- if ! require_nonempty "$profile_id" "effective.openclaw.model" "$effective_openclaw_model"; then
338
- profile_failed="yes"
339
- fi
340
- if ! require_nonempty "$profile_id" "effective.openclaw.thinking" "$effective_openclaw_thinking"; then
341
- profile_failed="yes"
342
- fi
343
- if ! require_positive_integer "$profile_id" "effective.openclaw.timeout_seconds" "$effective_openclaw_timeout_seconds"; then
344
- profile_failed="yes"
345
- fi
346
- ;;
347
- esac
348
-
349
- if [[ -n "$effective_provider_pool_order" ]]; then
350
- if ! require_nonempty "$profile_id" "effective.provider_pool_name" "$effective_provider_pool_name"; then
351
- profile_failed="yes"
352
- fi
353
- if ! require_nonempty "$profile_id" "effective.provider_pool_backend" "$effective_provider_pool_backend"; then
354
- profile_failed="yes"
355
- fi
356
- if ! require_nonempty "$profile_id" "effective.provider_pool_model" "$effective_provider_pool_model"; then
357
- profile_failed="yes"
358
- fi
359
- if ! require_nonempty "$profile_id" "effective.provider_pool_selection_reason" "$effective_provider_pool_selection_reason"; then
360
- profile_failed="yes"
361
- fi
362
- if [[ -n "$effective_provider_pool_backend" && "$effective_provider_pool_backend" != "$effective_coding_worker" ]]; then
363
- report_failure "$profile_id" "effective provider pool backend does not match effective coding worker"
364
- profile_failed="yes"
365
- fi
366
-
367
- while IFS= read -r pool_name; do
368
- [[ -n "$pool_name" ]] || continue
369
- if ! validate_provider_pool_config "$profile_id" "$config_yaml" "$pool_name"; then
370
- profile_failed="yes"
371
- fi
372
- done < <(flow_provider_pool_names "$config_yaml")
373
- fi
374
-
375
- if [[ "$issue_prefix" == "$pr_prefix" ]]; then
376
- report_failure "$profile_id" "issue and pr session prefixes must differ"
377
- profile_failed="yes"
378
- fi
379
-
380
- if [[ "$issue_branch_prefix" == "$pr_worktree_branch_prefix" ]]; then
381
- report_failure "$profile_id" "issue and pr branch prefixes must differ"
382
- profile_failed="yes"
383
- fi
384
-
385
- if [[ -n "$remote_repo_slug" && "$remote_repo_slug" != "$repo_slug" ]]; then
386
- report_failure "$profile_id" "repo.slug mismatch: config=${repo_slug} origin=${remote_repo_slug}"
387
- profile_failed="yes"
388
- fi
389
-
390
- if [[ "$profile_failed" == "yes" ]]; then
391
- continue
392
- fi
393
-
394
- printf '%s\t%s\t%s\t%s\t%s\n' \
395
- "$profile_id" \
396
- "$issue_prefix" \
397
- "$pr_prefix" \
398
- "$issue_branch_prefix" \
399
- "$pr_worktree_branch_prefix" >>"$records_file"
400
-
401
- printf 'PROFILE_ID=%s\n' "$profile_id"
402
- printf 'CONFIG_YAML=%s\n' "$config_yaml"
403
- printf 'REPO_SLUG=%s\n' "$repo_slug"
404
- printf 'ISSUE_PREFIX=%s\n' "$issue_prefix"
405
- printf 'PR_PREFIX=%s\n' "$pr_prefix"
406
- printf 'ISSUE_BRANCH_PREFIX=%s\n' "$issue_branch_prefix"
407
- printf 'PR_WORKTREE_BRANCH_PREFIX=%s\n' "$pr_worktree_branch_prefix"
408
- printf 'CODING_WORKER=%s\n' "$effective_coding_worker"
409
- printf 'PROFILE_STATUS=ok\n'
410
- done <"$profiles_file"
411
-
412
- check_duplicate_column() {
413
- local column_index="${1:?column index required}"
414
- local label="${2:?label required}"
415
- local duplicate_output=""
416
-
417
- duplicate_output="$(
418
- awk -F'\t' -v column_index="$column_index" '
419
- {
420
- key = $column_index
421
- if (key == "") next
422
- counts[key] += 1
423
- if (profiles[key] == "") {
424
- profiles[key] = $1
425
- } else {
426
- profiles[key] = profiles[key] "," $1
427
- }
428
- }
429
- END {
430
- for (key in counts) {
431
- if (counts[key] > 1) {
432
- print key "\t" profiles[key]
433
- }
434
- }
435
- }
436
- ' "$records_file" | sort
437
- )"
438
-
439
- [[ -n "$duplicate_output" ]] || return 0
440
-
441
- while IFS=$'\t' read -r duplicate_value duplicate_profiles; do
442
- [[ -n "${duplicate_value:-}" ]] || continue
443
- printf 'DUPLICATE_%s=%s\n' "$label" "$duplicate_value"
444
- printf 'DUPLICATE_%s_PROFILES=%s\n' "$label" "$duplicate_profiles"
445
- failures=$((failures + 1))
446
- done <<<"$duplicate_output"
447
- }
448
-
449
- if [[ -s "$records_file" ]]; then
450
- check_duplicate_column 2 ISSUE_PREFIX
451
- check_duplicate_column 3 PR_PREFIX
452
- check_duplicate_column 4 ISSUE_BRANCH_PREFIX
453
- check_duplicate_column 5 PR_WORKTREE_BRANCH_PREFIX
454
- fi
455
-
456
- if (( failures > 0 )); then
457
- printf 'PROFILE_SMOKE_STATUS=failed\n'
458
- exit 1
459
- fi
460
-
461
- printf 'PROFILE_SMOKE_STATUS=ok\n'
@@ -1,119 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- FLOW_SKILL_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
6
-
7
- usage() {
8
- cat <<'EOF'
9
- Usage:
10
- test-smoke.sh [--help]
11
-
12
- Run the main smoke gates for the shared agent-control-plane package in one command.
13
-
14
- Steps:
15
- 1. check-skill-contracts.sh
16
- 2. profile-smoke.sh against a temporary scaffolded profile registry
17
- 3. project-runtimectl.sh status against a temporary scaffolded profile
18
-
19
- Environment overrides:
20
- ACP_TEST_SMOKE_CHECK_CONTRACTS_SCRIPT
21
- ACP_TEST_SMOKE_PROFILE_SMOKE_SCRIPT
22
- ACP_TEST_SMOKE_RUNTIMECTL_SCRIPT
23
- ACP_TEST_SMOKE_SCAFFOLD_PROFILE_SCRIPT
24
- EOF
25
- }
26
-
27
- while [[ $# -gt 0 ]]; do
28
- case "$1" in
29
- --help|-h) usage; exit 0 ;;
30
- *) echo "Unknown argument: $1" >&2; usage >&2; exit 64 ;;
31
- esac
32
- done
33
-
34
- check_contracts_script="${ACP_TEST_SMOKE_CHECK_CONTRACTS_SCRIPT:-${FLOW_SKILL_DIR}/tools/bin/check-skill-contracts.sh}"
35
- profile_smoke_script="${ACP_TEST_SMOKE_PROFILE_SMOKE_SCRIPT:-${FLOW_SKILL_DIR}/tools/bin/profile-smoke.sh}"
36
- runtimectl_script="${ACP_TEST_SMOKE_RUNTIMECTL_SCRIPT:-${FLOW_SKILL_DIR}/tools/bin/project-runtimectl.sh}"
37
- scaffold_profile_script="${ACP_TEST_SMOKE_SCAFFOLD_PROFILE_SCRIPT:-${FLOW_SKILL_DIR}/tools/bin/scaffold-profile.sh}"
38
-
39
- run_step() {
40
- local label="${1:?label required}"
41
- shift
42
- local status=0
43
-
44
- printf 'SMOKE_STEP=%s\n' "${label}"
45
- set +e
46
- "$@"
47
- status=$?
48
- set -e
49
- if [[ "${status}" -eq 0 ]]; then
50
- printf 'SMOKE_STEP_STATUS=ok\n'
51
- return 0
52
- fi
53
-
54
- printf 'SMOKE_STEP_STATUS=failed\n'
55
- printf 'FAILED_STEP=%s\n' "${label}"
56
- printf 'EXIT_CODE=%s\n' "${status}"
57
- printf 'SMOKE_TEST_STATUS=failed\n'
58
- return "${status}"
59
- }
60
-
61
- if [[ -f "${check_contracts_script}" ]]; then
62
- run_step "check-skill-contracts" bash "${check_contracts_script}"
63
- else
64
- printf 'SMOKE_STEP=%s\n' "check-skill-contracts"
65
- printf 'SMOKE_STEP_STATUS=%s\n' "skipped"
66
- fi
67
-
68
- run_profile_smoke_fixture() (
69
- set -euo pipefail
70
- local tmpdir=""
71
- local profile_home=""
72
-
73
- tmpdir="$(mktemp -d)"
74
- trap 'rm -rf "${tmpdir}"' EXIT
75
- profile_home="${tmpdir}/profiles"
76
-
77
- bash "${scaffold_profile_script}" \
78
- --profile-home "${profile_home}" \
79
- --profile-id smoke-alpha \
80
- --repo-slug example/smoke-alpha >/dev/null
81
-
82
- ACP_PROFILE_REGISTRY_ROOT="${profile_home}" \
83
- bash "${profile_smoke_script}" --profile-id smoke-alpha >/dev/null
84
- )
85
-
86
- run_runtimectl_fixture() (
87
- set -euo pipefail
88
- local tmpdir=""
89
- local profile_home=""
90
- local runtime_root=""
91
- local profile_id="smoke-runtime"
92
- local output=""
93
-
94
- tmpdir="$(mktemp -d)"
95
- trap 'rm -rf "${tmpdir}"' EXIT
96
- profile_home="${tmpdir}/profiles"
97
- runtime_root="${tmpdir}/runtime/${profile_id}"
98
-
99
- bash "${scaffold_profile_script}" \
100
- --profile-home "${profile_home}" \
101
- --profile-id "${profile_id}" \
102
- --repo-slug example/${profile_id} \
103
- --agent-root "${runtime_root}" \
104
- --agent-repo-root "${runtime_root}/repo" \
105
- --worktree-root "${runtime_root}/worktrees" >/dev/null
106
-
107
- output="$(
108
- ACP_PROFILE_REGISTRY_ROOT="${profile_home}" \
109
- bash "${runtimectl_script}" status --profile-id "${profile_id}"
110
- )"
111
-
112
- grep -q "^PROFILE_ID=${profile_id}\$" <<<"${output}"
113
- grep -q '^RUNTIME_STATUS=' <<<"${output}"
114
- )
115
-
116
- run_step "profile-smoke" run_profile_smoke_fixture
117
- run_step "project-runtimectl" run_runtimectl_fixture
118
-
119
- printf 'SMOKE_TEST_STATUS=ok\n'