#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" LB_DIR="$ROOT_DIR/.loop-build" STATE_DIR="$LB_DIR/state" CONFIG_DIR="$LB_DIR/config" TASKS_FILE="$LB_DIR/TASKS.md" STATE_FILE="$STATE_DIR/current_task.json" HISTORY_FILE="$STATE_DIR/history.ndjson" need_approval_files=("$TASKS_FILE" "$STATE_FILE" "$HISTORY_FILE") log() { printf '%s\n' "$*" } check_dependencies() { local missing=0 for dep in git bash rg jq; do if ! command -v "$dep" >/dev/null 2>&1; then printf '[init][MISSING] %s\n' "$dep" printf ' install suggestion: use your package manager (e.g. apt, brew, or winget)\n' missing=1 else printf '[init][OK] %s\n' "$dep" fi done if (( missing != 0 )); then log "[init] dependency check found missing tools. init continues with warnings only." fi } render_task_template() { cat > "$TASKS_FILE" <<'EOF_TPL' # loop-build Task Template ## Task - task_id: - goal: - constraints: - repo_context_hint: - created_at: - updated_at: ## Plan source - generated_by: prompts/planner.md - plan_status: not_started - current_step: - verify_targets: ## Progress - completed_steps: - next_step: - open_questions: - last_verification: ## Notes - plan diff scope should stay <= 2 files/step - each step should be one incremental change and one verification - avoid full-file rewrites EOF_TPL } init_state_file() { if [[ -f "$STATE_FILE" ]]; then return 0 fi cat > "$STATE_FILE" < "$CONFIG_DIR/policy.env" <<'EOF_CFG' # Loop Build policy toggles # Commands in denylist can execute only after explicit unlock + secondary confirm. POLICY_SECONDARY_CONFIRM=0 ALLOW_SUDO=0 ALLOW_RM_RF=0 ALLOW_NETWORK=0 ALLOW_CURL_BASH=0 ALLOW_INSTALL=0 ALLOW_GIT_NETWORK=0 ALLOW_PROFILE_MODIFY=0 EOF_CFG } ensure_default_files() { if [[ ! -f "$STATE_DIR/history.ndjson" ]]; then : > "$HISTORY_FILE" fi if [[ ! -f "$TASKS_FILE" ]]; then render_task_template fi if [[ ! -f "$CONFIG_DIR/allowlist.txt" ]]; then cat > "$CONFIG_DIR/allowlist.txt" <<'EOF_ALLOW' ls ls -la cat rg grep tree git status git diff git rev-parse git log git show git branch git branch --show-current git status --short git blame sed awk head tail wc printf echo find pwd false true EOF_ALLOW fi if [[ ! -f "$CONFIG_DIR/denylist.txt" ]]; then cat > "$CONFIG_DIR/denylist.txt" <<'EOF_DENY' sudo rm -rf rm -fr git clone git push git pull git commit git rebase git reset curl wget npm install npm i yarn add yarn install pnpm add pnpm install pip install pip3 install composer install bash -c sh -c curl | bash wget | sh EOF_DENY fi } check_git_state_hint() { if [[ -d "$ROOT_DIR/.git" ]] && command -v git >/dev/null 2>&1; then changed=$(git -C "$ROOT_DIR" status --short | wc -l | tr -d ' ') if [[ "$changed" != "0" ]]; then log "[init][WARN] repository is not clean; recommended for safer incremental steps." else log "[init] repo clean check: passed" fi else log "[init][WARN] no .git metadata detected; diff/rollback features are limited." fi } main() { log "[init] starting loop-build bootstrap" check_dependencies mkdir -p "$STATE_DIR" "$CONFIG_DIR" init_state_file ensure_default_files init_default_config check_git_state_hint log "[init] done." log "[init] next steps:" log " 1) complete .loop-build/state/current_task.json from a planner response" log " 2) run ./ .loop-build/scripts/run_task.sh APPROVE_PLAN" log " 3) run ./ .loop-build/scripts/run_task.sh step" } main "$@"