mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
* feat(install): add hardened Docker test harness * feat(docker): complete isolated CLI session lifecycle * fix(docker): exercise packed public CLI offline * fix(docker): close hardened harness review gaps * test(docker): bound harness subprocesses
127 lines
3.0 KiB
Bash
Executable File
127 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
readonly ECC_ROOT=/ecc
|
|
readonly SOURCE_PROJECT=/source-project
|
|
readonly MODE="${1:-dry-run}"
|
|
readonly requested_project_dir="${ECC_PROJECT_DIR:-/workspace/project}"
|
|
|
|
NPM_CONFIG_CACHE=/tmp/npm-cache
|
|
export NPM_CONFIG_CACHE
|
|
readonly NPM_CONFIG_CACHE
|
|
|
|
usage() {
|
|
printf '%s\n' \
|
|
'Usage: docker compose run --rm real-cli <mode>' \
|
|
'' \
|
|
'Modes:' \
|
|
' dry-run Inspect a project-local ECC install without mutation (default).' \
|
|
' install Install ECC into the isolated project copy.' \
|
|
' plugin Launch Claude with the local ECC checkout via --plugin-dir.' \
|
|
' shell Open a shell in the isolated project copy.'
|
|
}
|
|
|
|
case "$MODE" in
|
|
dry-run|install|plugin|shell)
|
|
;;
|
|
help|--help|-h)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
printf 'Unknown mode: %s\n\n' "$MODE" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
if [[ ! -f "$ECC_ROOT/package.json" ]]; then
|
|
printf 'ECC checkout is not mounted at %s\n' "$ECC_ROOT" >&2
|
|
exit 2
|
|
fi
|
|
if [[ ! -d "$SOURCE_PROJECT" ]]; then
|
|
printf 'Source project is not mounted at %s\n' "$SOURCE_PROJECT" >&2
|
|
exit 2
|
|
fi
|
|
project_dir="$(
|
|
node "$ECC_ROOT/docker/plugin-setup/resolve-project-dir.js" \
|
|
"$requested_project_dir"
|
|
)"
|
|
readonly project_dir
|
|
|
|
mkdir -p "$HOME" "$CLAUDE_CONFIG_DIR" "$NPM_CONFIG_CACHE"
|
|
chmod 0700 "$HOME" "$CLAUDE_CONFIG_DIR" "$NPM_CONFIG_CACHE"
|
|
|
|
if [[ ! -e "$project_dir" ]]; then
|
|
mkdir -m 0700 "$project_dir"
|
|
cp -a "$SOURCE_PROJECT/." "$project_dir/"
|
|
elif [[ ! -d "$project_dir" ]]; then
|
|
printf 'ECC project path is not a directory: %s\n' "$project_dir" >&2
|
|
exit 2
|
|
fi
|
|
cd "$project_dir"
|
|
|
|
if [[ ! -d .git ]]; then
|
|
git init --quiet
|
|
fi
|
|
|
|
packed_cli=''
|
|
if [[ "$MODE" == dry-run || "$MODE" == install ]]; then
|
|
packed_cli="$(
|
|
node "$ECC_ROOT/docker/plugin-setup/prepare-packed-cli.js" \
|
|
"$ECC_ROOT" \
|
|
/tmp/ecc-packed-cli
|
|
)"
|
|
fi
|
|
readonly packed_cli
|
|
|
|
run_ecc() {
|
|
if [[ ! -x "$packed_cli" ]]; then
|
|
printf 'Packed ECC public executable is unavailable\n' >&2
|
|
return 1
|
|
fi
|
|
"$packed_cli" "$@"
|
|
}
|
|
|
|
run_install() {
|
|
run_ecc install \
|
|
--profile core \
|
|
--target claude-project \
|
|
"$@"
|
|
}
|
|
|
|
claude --version
|
|
printf 'Isolated project: %s\n' "$project_dir"
|
|
|
|
case "$MODE" in
|
|
dry-run)
|
|
plan_file="$(mktemp /tmp/ecc-install-plan.XXXXXX.json)"
|
|
run_install \
|
|
--dry-run \
|
|
--json > "$plan_file"
|
|
if [[ -e "$project_dir/.claude" ]]; then
|
|
printf 'Dry run unexpectedly mutated %s/.claude\n' "$project_dir" >&2
|
|
exit 1
|
|
fi
|
|
node "$ECC_ROOT/docker/plugin-setup/verify-install-plan.js" "$project_dir" --dry-run < "$plan_file"
|
|
cat "$plan_file"
|
|
;;
|
|
install)
|
|
run_install --json
|
|
if [[ ! -f "$project_dir/.claude/ecc/install-state.json" ]]; then
|
|
printf 'Install did not create confined install state\n' >&2
|
|
exit 1
|
|
fi
|
|
run_install --json
|
|
run_ecc list-installed --json
|
|
run_ecc doctor --target claude-project
|
|
;;
|
|
plugin)
|
|
exec claude --plugin-dir "$ECC_ROOT"
|
|
;;
|
|
shell)
|
|
exec /bin/bash
|
|
;;
|
|
esac
|