diff --git a/AGENTS.md b/AGENTS.md index a6ac1fd..a12b61f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,7 +27,7 @@ disinto/ (code repo) │ preflight.sh — pre-flight data collection for supervisor formula │ supervisor-poll.sh — legacy bash orchestrator (superseded) ├── vault/ vault-env.sh — shared env setup (vault redesign in progress, see #73-#77) -├── lib/ env.sh, agent-session.sh, ci-helpers.sh, ci-debug.sh, load-project.sh, parse-deps.sh, guard.sh, mirrors.sh, pr-lifecycle.sh, issue-lifecycle.sh, worktree.sh, formula-session.sh, profile.sh, build-graph.py +├── lib/ env.sh, agent-session.sh, ci-helpers.sh, ci-debug.sh, load-project.sh, parse-deps.sh, guard.sh, mirrors.sh, pr-lifecycle.sh, issue-lifecycle.sh, worktree.sh, build-graph.py ├── projects/ *.toml.example — templates; *.toml — local per-box config (gitignored) ├── formulas/ Issue templates (TOML specs for multi-step agent tasks) └── docs/ Protocol docs (PHASE-PROTOCOL.md, EVIDENCE-ARCHITECTURE.md) diff --git a/lib/profile.sh b/lib/profile.sh deleted file mode 100644 index 79f8514..0000000 --- a/lib/profile.sh +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env bash -# profile.sh — Helpers for agent .profile repo management -# -# Source after lib/env.sh and lib/formula-session.sh: -# source "$(dirname "$0")/../lib/env.sh" -# source "$(dirname "$0")/lib/formula-session.sh" -# source "$(dirname "$0")/lib/profile.sh" -# -# Required globals: FORGE_TOKEN, FORGE_URL, AGENT_IDENTITY, PROFILE_REPO_PATH -# -# Functions: -# profile_propose_formula NEW_FORMULA CONTENT REASON — create PR to update formula.toml - -set -euo pipefail - -# Internal log helper -_profile_log() { - if declare -f log >/dev/null 2>&1; then - log "profile: $*" - else - printf '[%s] profile: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >&2 - fi -} - -# ----------------------------------------------------------------------------- -# profile_propose_formula — Propose a formula change via PR -# -# Creates a branch, writes updated formula.toml, opens a PR, and returns PR number. -# Branch is protected (requires admin approval per #87). -# -# Args: -# $1 - NEW_FORMULA_CONTENT: The complete new formula.toml content -# $2 - REASON: Human-readable explanation of what changed and why -# -# Returns: -# 0 on success, prints PR number to stdout -# 1 on failure -# -# Example: -# source "$(dirname "$0")/../lib/env.sh" -# source "$(dirname "$0")/lib/formula-session.sh" -# source "$(dirname "$0")/lib/profile.sh" -# AGENT_IDENTITY="dev-bot" -# ensure_profile_repo "$AGENT_IDENTITY" -# profile_propose_formula "$new_formula" "Added new prompt pattern for code review" -# ----------------------------------------------------------------------------- -profile_propose_formula() { - local new_formula="$1" - local reason="$2" - - if [ -z "${AGENT_IDENTITY:-}" ]; then - _profile_log "ERROR: AGENT_IDENTITY not set" - return 1 - fi - - if [ -z "${PROFILE_REPO_PATH:-}" ]; then - _profile_log "ERROR: PROFILE_REPO_PATH not set — ensure_profile_repo not called" - return 1 - fi - - if [ -z "${FORGE_TOKEN:-}" ]; then - _profile_log "ERROR: FORGE_TOKEN not set" - return 1 - fi - - if [ -z "${FORGE_URL:-}" ]; then - _profile_log "ERROR: FORGE_URL not set" - return 1 - fi - - # Generate short description from reason for branch name - local short_desc - short_desc=$(printf '%s' "$reason" | \ - tr '[:upper:]' '[:lower:]' | \ - sed 's/[^a-z0-9 ]//g' | \ - sed 's/ */ /g' | \ - sed 's/^ *//;s/ *$//' | \ - cut -c1-40 | \ - tr ' ' '-') - - if [ -z "$short_desc" ]; then - short_desc="formula-update" - fi - - local branch_name="formula/${short_desc}" - local formula_path="${PROFILE_REPO_PATH}/formula.toml" - - _profile_log "Proposing formula change: ${branch_name}" - _profile_log "Reason: ${reason}" - - # Ensure we're on main branch and up-to-date - _profile_log "Fetching .profile repo" - ( - cd "$PROFILE_REPO_PATH" || return 1 - - git fetch origin main --quiet 2>/dev/null || \ - git fetch origin master --quiet 2>/dev/null || true - - # Reset to main/master - if git checkout main --quiet 2>/dev/null; then - git pull --ff-only origin main --quiet 2>/dev/null || true - elif git checkout master --quiet 2>/dev/null; then - git pull --ff-only origin master --quiet 2>/dev/null || true - else - _profile_log "ERROR: Failed to checkout main/master branch" - return 1 - fi - - # Create and checkout new branch - git checkout -b "$branch_name" 2>/dev/null || { - _profile_log "Branch ${branch_name} may already exist" - git checkout "$branch_name" 2>/dev/null || return 1 - } - - # Write formula.toml - printf '%s' "$new_formula" > "$formula_path" - - # Commit the change - git config user.name "${AGENT_IDENTITY}" || true - git config user.email "${AGENT_IDENTITY}@users.noreply.codeberg.org" || true - - git add "$formula_path" - git commit -m "formula: ${reason}" --no-verify || { - _profile_log "No changes to commit (formula unchanged)" - # Check if branch has any commits - if git rev-parse HEAD >/dev/null 2>&1; then - : # branch has commits, continue - else - _profile_log "ERROR: Failed to create commit" - return 1 - fi - } - - # Push branch - local remote="${FORGE_REMOTE:-origin}" - git push --set-upstream "$remote" "$branch_name" --quiet 2>/dev/null || { - _profile_log "ERROR: Failed to push branch" - return 1 - } - - _profile_log "Branch pushed: ${branch_name}" - - # Create PR - local forge_url="${FORGE_URL%/}" - local api_url="${forge_url}/api/v1/repos/${AGENT_IDENTITY}/.profile" - local primary_branch="main" - - # Check if main or master is the primary branch - if ! curl -sf -o /dev/null -w "%{http_code}" \ - -H "Authorization: token ${FORGE_TOKEN}" \ - "${api_url}/git/branches/main" 2>/dev/null | grep -q "200"; then - primary_branch="master" - fi - - local pr_title="formula: ${reason}" - local pr_body="# Formula Update - -**Reason:** ${reason} - ---- -*This PR was auto-generated by ${AGENT_IDENTITY}.* -" - - local pr_response http_code - local pr_json - pr_json=$(jq -n \ - --arg t "$pr_title" \ - --arg b "$pr_body" \ - --arg h "$branch_name" \ - --arg base "$primary_branch" \ - '{title:$t, body:$b, head:$h, base:$base}') || { - _profile_log "ERROR: Failed to build PR JSON" - return 1 - } - - pr_response=$(curl -s -w "\n%{http_code}" -X POST \ - -H "Authorization: token ${FORGE_TOKEN}" \ - -H "Content-Type: application/json" \ - "${api_url}/pulls" \ - -d "$pr_json" || true) - - http_code=$(printf '%s\n' "$pr_response" | tail -1) - pr_response=$(printf '%s\n' "$pr_response" | sed '$d') - - if [ "$http_code" = "201" ] || [ "$http_code" = "200" ]; then - local pr_num - pr_num=$(printf '%s' "$pr_response" | jq -r '.number') - _profile_log "PR created: #${pr_num}" - printf '%s' "$pr_num" - return 0 - else - # Check if PR already exists (409 conflict) - if [ "$http_code" = "409" ]; then - local existing_pr - existing_pr=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ - "${api_url}/pulls?state=open&head=${AGENT_IDENTITY}:formula/${short_desc}" 2>/dev/null | \ - jq -r '.[0].number // empty') || true - if [ -n "$existing_pr" ]; then - _profile_log "PR already exists: #${existing_pr}" - printf '%s' "$existing_pr" - return 0 - fi - fi - _profile_log "ERROR: Failed to create PR (HTTP ${http_code})" - return 1 - fi - ) - - return $? -}