Skip to content

Instantly share code, notes, and snippets.

@Kcrong
Last active September 6, 2026 01:51
Show Gist options
  • Select an option

  • Save Kcrong/3dd66eaeda6838e4e9e8650059b75908 to your computer and use it in GitHub Desktop.

Select an option

Save Kcrong/3dd66eaeda6838e4e9e8650059b75908 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# AI-DLC V2 Kiro CLI Installer
# ============================
#
# This script is intentionally documented for review before execution.
#
# Safety contract
# ---------------
# - Installs into the current working directory only. It accepts no arguments.
# - Reads the release from the official public repository below.
# - Does not run sudo, install packages, or directly read credential files.
# - Does not modify global ~/.kiro settings.
# - Clones the fixed release into a temporary directory and checks out only dist/kiro.
# - Scans every destination file before changing the project.
# - Lists every overlap and requires explicit confirmation through /dev/tty.
# - Refusal exits before creating, modifying, or deleting any project file.
# - Approval copies every release file individually; no directory is overwritten as a unit.
# - Unrelated and stale project files are never deleted.
# - The temporary clone is the only directory automatically deleted.
# - Doctor is requested through the configured Kiro CLI aidlc agent in no-interactive mode.
# - The doctor request may invoke a configured model, consume credits, and use provider networking.
# - Installation succeeds only when Kiro CLI exits successfully and reports N passed, 0 failed.
#
# Overwrite limitations
# ---------------------
# - One confirmation covers the complete displayed overlap list.
# - Approved files are replaced without backups. Use source control if rollback is required.
# - A forced termination after approval may leave a partial installation; rerun to repair it.
# - A terminal is mandatory when overlaps exist. Non-interactive overwrites fail closed.
#
# Fail on command errors, undeclared variables, and failures inside pipelines.
set -Eeuo pipefail
IFS=$'\n\t'
# User input cannot redirect the installer to another repository or release.
readonly REPO_URL="https://github.com/awslabs/aidlc-workflows.git"
# Latest official GitHub release verified on 2026-09-06.
# This fixed tag makes a future curl | bash one-liner reproducible.
readonly RELEASE_TAG="v2.7.0"
tmp_dir=""
log() { printf '==> %s\n' "$*"; }
warn() { printf 'WARNING: %s\n' "$*" >&2; }
die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
# tmp_dir receives only the path returned by mktemp below.
cleanup() { [[ -z "$tmp_dir" || ! -d "$tmp_dir" ]] || find "$tmp_dir" -depth -delete; }
trap cleanup EXIT
# This is a single-purpose one-liner installer. Reject all arguments instead of maintaining
# path, ref, usage, and help branches that could diverge from the reviewed defaults.
(($# == 0)) || die "this installer does not accept arguments"
# Check prerequisites without installing anything automatically.
# bun is required by the installed AI-DLC hooks and tools, but this installer does not invoke
# a TypeScript utility directly for doctor; it sends the doctor prompt through Kiro CLI.
for tool in git bun kiro-cli cp dirname find mktemp uname; do
command -v "$tool" >/dev/null 2>&1 || die "required command not found: $tool"
done
os="$(uname -s)"
[[ "$os" == "Linux" || "$os" == "Darwin" ]] || die "supported operating systems: macOS and Linux"
# Check only the local Kiro CLI version here. The doctor step later invokes the aidlc agent.
kiro_version="$(kiro-cli --version 2>&1)" || die "kiro-cli --version failed"
[[ "$kiro_version" =~ ([0-9]+)\.([0-9]+) ]] || die "unable to parse Kiro CLI version"
(( BASH_REMATCH[1] > 2 || (BASH_REMATCH[1] == 2 && BASH_REMATCH[2] >= 6) )) \
|| die "Kiro CLI 2.6 or newer is required"
# Resolve the existing current directory. No project directory is created by the installer.
project="$(pwd -P)"
[[ "$project" != *$'\n'* && "$project" != *$'\r'* ]] \
|| die "current directory contains a control character"
# Reject symlinks in managed destinations so a copy cannot escape the project boundary.
for path in "$project/.kiro" "$project/aidlc" "$project/AGENTS.md" "$project/.gitignore"; do
[[ ! -L "$path" ]] || die "refusing to install through symlink: $path"
done
for dir in "$project/.kiro" "$project/aidlc"; do
[[ ! -d "$dir" || -z "$(find "$dir" -type l -print -quit)" ]] \
|| die "managed tree contains a symlink: $dir"
done
# Keep V1 rules untouched and warn after installation if they were present.
v1_rules_present=false
if [[ -d "$project/.kiro/steering/aws-aidlc-rules" \
|| -d "$project/.kiro/aws-aidlc-rule-details" ]]; then
v1_rules_present=true
fi
# Prefer a session-scoped scratch directory, then TMPDIR, then the Unix fallback.
temp_root="${KIROCREW_SCRATCH:-${TMPDIR:-/tmp}}"
[[ -d "$temp_root" && -w "$temp_root" ]] || die "temporary directory is not writable: $temp_root"
tmp_dir="$(mktemp -d "$temp_root/aidlc-v2-install.XXXXXX")"
source_dir="$tmp_dir/source"
# Clone exactly the fixed release tag. Sparse checkout materializes only dist/kiro.
GIT_TERMINAL_PROMPT=0 git clone --quiet --branch "$RELEASE_TAG" --single-branch \
--depth=1 --filter=blob:none --sparse --no-checkout "$REPO_URL" "$source_dir"
git -C "$source_dir" sparse-checkout set dist/kiro
git -C "$source_dir" checkout --quiet --detach "$RELEASE_TAG"
# Verify that the checkout is exactly the reviewed release tag.
resolved_tag="$(git -C "$source_dir" describe --tags --exact-match HEAD)"
[[ "$resolved_tag" == "$RELEASE_TAG" ]] || die "resolved release tag does not match: $resolved_tag"
resolved_sha="$(git -C "$source_dir" rev-parse HEAD)"
distribution="$source_dir/dist/kiro"
# Fail before touching the project if the release layout is incomplete or contains symlinks.
for path in .kiro aidlc AGENTS.md .gitignore; do
[[ -e "$distribution/$path" ]] || die "release distribution is missing: $path"
done
[[ -z "$(find "$distribution" -type l -print -quit)" ]] || die "release distribution contains a symlink"
# Build a complete file-level plan. No project file is changed in this phase.
declare -a source_files=()
declare -a target_files=()
declare -a overlap_indexes=()
while IFS= read -r -d '' source_file; do
relative_path="${source_file#"$distribution/"}"
target_file="$project/$relative_path"
index="${#source_files[@]}"
source_files[$index]="$source_file"
target_files[$index]="$target_file"
if [[ -e "$target_file" ]]; then
[[ -f "$target_file" ]] || die "destination exists but is not a regular file: $relative_path"
overlap_indexes[${#overlap_indexes[@]}]="$index"
fi
done < <(find "$distribution" -type f -print0)
((${#source_files[@]} > 0)) || die "release distribution contains no files"
log "Release: $RELEASE_TAG"
log "Files to install: ${#source_files[@]}"
log "Overlapping files: ${#overlap_indexes[@]}"
# Show every destructive target before requesting one batch confirmation.
# /dev/tty keeps the prompt usable when the script itself arrives through stdin.
if ((${#overlap_indexes[@]} > 0)); then
[[ -r /dev/tty && -w /dev/tty ]] \
|| die "overlapping files require an interactive terminal for confirmation"
{
printf '\nThe following existing files would be overwritten:\n'
for index in "${overlap_indexes[@]}"; do
printf ' %s\n' "${target_files[$index]#"$project/"}"
done
printf '\nOverwrite all listed files and continue? [y/N] '
} >/dev/tty
answer=""
IFS= read -r answer </dev/tty || die "unable to read overwrite confirmation"
case "$answer" in
y|Y|yes|Yes|YES) log "Overwrite approved for ${#overlap_indexes[@]} file(s)" ;;
*) die "installation cancelled; no project files were changed" ;;
esac
fi
# Copy each release file separately. Existing files reached this point only after approval.
for index in "${!source_files[@]}"; do
source_file="${source_files[$index]}"
target_file="${target_files[$index]}"
mkdir -p "$(dirname "$target_file")"
cp -p "$source_file" "$target_file"
done
[[ "$v1_rules_present" == false ]] \
|| warn "legacy V1 rule directories were retained for manual review"
# Ask the aidlc agent to route --doctor through the normal Kiro CLI workflow.
# The `--` separator is required; without it, Kiro CLI parses --doctor as its own unknown option.
# Capture stdout so exit status 0 alone is insufficient: the output must also contain a clean
# doctor summary. Stderr remains visible for hook and model progress reporting.
log "Running AI-DLC doctor through Kiro CLI"
doctor_output="$(
cd "$project"
kiro-cli chat --no-interactive --agent aidlc -- '--doctor'
)" || die "Kiro CLI doctor prompt failed"
printf '%s\n' "$doctor_output"
[[ "$doctor_output" =~ [0-9]+[[:space:]]passed,[[:space:]]0[[:space:]]failed ]] \
|| die "AI-DLC doctor did not report a clean result"
# Print only reproducibility data, not credentials, environment dumps, or project paths.
printf '\nAI-DLC V2 installation complete.\n'
printf 'Release: %s\nSource commit: %s\n' "$resolved_tag" "$resolved_sha"
@Kcrong

Kcrong commented Jan 30, 2026

Copy link
Copy Markdown
Author
curl -sL https://gist.githubusercontent.com/Kcrong/3dd66eaeda6838e4e9e8650059b75908/raw | bash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment