Pass a custom template and mixin kits through to sbx
Sandboxes ignore the host ~/.claude by design: the agent runs as a separate user with HOME elsewhere, so even a read-only mount is not picked up. Skills can be shared with sbx skills import, but plugins carry commands, hooks and MCP servers that only a custom image can deliver. Adds --template, --stock-template and a repeatable --kit, persisted per repository so run and refresh reuse them. AI_SBX_TEMPLATE supplies the default image, so one custom template can be declared once in the user's mise config and apply to every repository, with --template overriding it per repository and --stock-template opting out. save_config now packs two arrays into one argument list separated by a count, so it ships with a round-trip test covering empty arrays, values containing spaces, and the boundary between kits and AWS profiles.
This commit is contained in:
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# shellcheck source-path=SCRIPTDIR
|
||||
# shellcheck source=tasks/ai/sbx
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../tasks/ai/sbx"
|
||||
|
||||
failures=0
|
||||
work="$(mktemp -d)"
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$1" >&2
|
||||
failures=$((failures + 1))
|
||||
}
|
||||
|
||||
REPOSITORY="CareEvolution/api-portal"
|
||||
SANDBOX_NAME="ai-test"
|
||||
CONFIG_ROOT="$work/config"
|
||||
REPO_CONFIG_DIR="$CONFIG_ROOT/repos/deadbeef"
|
||||
REPO_CONFIG_FILE="$REPO_CONFIG_DIR/config"
|
||||
|
||||
roundtrip() {
|
||||
local agent="$1" mode="$2" template="$3" kit_count="$4"
|
||||
shift 4
|
||||
|
||||
rm -rf "$CONFIG_ROOT"
|
||||
save_config "$agent" "$mode" "$template" "$kit_count" "$@"
|
||||
|
||||
unset CONFIG_KITS CONFIG_AWS_PROFILES CONFIG_TEMPLATE
|
||||
load_config
|
||||
}
|
||||
|
||||
roundtrip codex clone "" 0
|
||||
[[ "$CONFIG_TEMPLATE" == "" ]] || fail "empty template did not survive: $CONFIG_TEMPLATE"
|
||||
((${#CONFIG_KITS[@]} == 0)) || fail "expected no kits, got ${#CONFIG_KITS[@]}"
|
||||
((${#CONFIG_AWS_PROFILES[@]} == 0)) || fail "expected no profiles, got ${#CONFIG_AWS_PROFILES[@]}"
|
||||
|
||||
roundtrip claude direct ghcr.io/me/img:v1 0 dev-readonly prod-readonly
|
||||
[[ "$CONFIG_TEMPLATE" == "ghcr.io/me/img:v1" ]] || fail "template lost: $CONFIG_TEMPLATE"
|
||||
((${#CONFIG_KITS[@]} == 0)) || fail "profiles leaked into kits: ${CONFIG_KITS[*]}"
|
||||
[[ "${CONFIG_AWS_PROFILES[*]}" == "dev-readonly prod-readonly" ]] ||
|
||||
fail "profiles wrong: ${CONFIG_AWS_PROFILES[*]}"
|
||||
|
||||
roundtrip claude clone img:v2 2 /kits/a /kits/b api-portal
|
||||
((${#CONFIG_KITS[@]} == 2)) || fail "expected 2 kits, got ${#CONFIG_KITS[@]}"
|
||||
[[ "${CONFIG_KITS[*]}" == "/kits/a /kits/b" ]] || fail "kits wrong: ${CONFIG_KITS[*]}"
|
||||
[[ "${CONFIG_AWS_PROFILES[*]}" == "api-portal" ]] ||
|
||||
fail "kits leaked into profiles: ${CONFIG_AWS_PROFILES[*]}"
|
||||
|
||||
roundtrip claude clone "reg/img:v3" 1 "/kits/with space" "profile one"
|
||||
[[ "${CONFIG_KITS[0]}" == "/kits/with space" ]] || fail "kit with space mangled: ${CONFIG_KITS[0]}"
|
||||
[[ "${CONFIG_AWS_PROFILES[0]}" == "profile one" ]] ||
|
||||
fail "profile with space mangled: ${CONFIG_AWS_PROFILES[0]}"
|
||||
|
||||
[[ "$(stat -c '%a' "$REPO_CONFIG_FILE")" == "600" ]] ||
|
||||
fail "config file is not mode 600"
|
||||
|
||||
grep -q 'CONFIG_TEMPLATE=' "$REPO_CONFIG_FILE" || fail "template not persisted"
|
||||
|
||||
if ((failures)); then
|
||||
printf '%d assertion(s) failed\n' "$failures" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'All config round-trip assertions passed.\n'
|
||||
Reference in New Issue
Block a user