2026-03-19 07:25:25 +00:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
# action-poll.sh — Cron scheduler: find open 'action' issues, spawn action-agent
|
|
|
|
|
#
|
|
|
|
|
# An issue is ready for action if:
|
|
|
|
|
# - It is open and labeled 'action'
|
2026-03-21 17:05:09 +00:00
|
|
|
# - No tmux session named action-{project}-{issue_num} is already active
|
2026-03-19 07:25:25 +00:00
|
|
|
#
|
|
|
|
|
# Usage:
|
|
|
|
|
# cron every 10min
|
|
|
|
|
# action-poll.sh [projects/foo.toml] # optional project config
|
|
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
export PROJECT_TOML="${1:-}"
|
|
|
|
|
source "$(dirname "$0")/../lib/env.sh"
|
fix: Per-agent Forgejo accounts — identity and permissions via authorship (#747)
Each agent now gets its own Forgejo account (dev-bot, review-bot,
planner-bot, gardener-bot, vault-bot, supervisor-bot, predictor-bot,
action-bot) with a dedicated API token. This enables:
- Audit trail: every forge action attributable to a specific agent
- Permission boundaries: agents act under their own identity
- Vault authorization model: vault-bot comments = proof of approval
Changes:
- bin/disinto: setup_forge() creates all 8 bot accounts during init,
stores per-agent tokens (FORGE_*_TOKEN) in .env, adds all bots as
repo collaborators
- lib/env.sh: exports per-agent token vars with fallback to FORGE_TOKEN
for backwards compat; sets FORGE_BOT_USERNAMES default to all 8 bots
- Agent scripts: each agent overrides FORGE_TOKEN with its per-agent
token after sourcing env.sh (gardener, planner, supervisor, predictor,
vault, action)
- .env.example: documents all per-agent token fields
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:16:13 +00:00
|
|
|
# Use action-bot's own Forgejo identity (#747)
|
|
|
|
|
FORGE_TOKEN="${FORGE_ACTION_TOKEN:-${FORGE_TOKEN}}"
|
2026-03-23 21:46:59 +00:00
|
|
|
# shellcheck source=../lib/guard.sh
|
|
|
|
|
source "$(dirname "$0")/../lib/guard.sh"
|
|
|
|
|
check_active action
|
2026-03-19 07:25:25 +00:00
|
|
|
|
2026-03-27 14:29:22 +00:00
|
|
|
LOGFILE="${DISINTO_LOG_DIR}/action/action-poll-${PROJECT_NAME:-default}.log"
|
2026-03-19 07:25:25 +00:00
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
|
|
|
|
|
|
log() {
|
|
|
|
|
printf '[%s] poll: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Memory guard ---
|
2026-03-26 15:00:12 +00:00
|
|
|
memory_guard 2000
|
2026-03-19 07:25:25 +00:00
|
|
|
|
|
|
|
|
# --- Find open 'action' issues ---
|
|
|
|
|
log "scanning for open action issues"
|
fix: Replace Codeberg dependency with local Forgejo instance (#611)
- Add setup_forge() to bin/disinto: provisions Forgejo via Docker,
creates admin + bot users (dev-bot, review-bot), generates API
tokens, creates repo, and pushes code — all automated
- Rename env vars: CODEBERG_TOKEN→FORGE_TOKEN, REVIEW_BOT_TOKEN→
FORGE_REVIEW_TOKEN, CODEBERG_REPO→FORGE_REPO, CODEBERG_API→
FORGE_API, CODEBERG_WEB→FORGE_WEB, CODEBERG_BOT_USERNAMES→
FORGE_BOT_USERNAMES (with backwards-compat fallbacks)
- Rename API helpers: codeberg_api()→forge_api(), codeberg_api_all()
→forge_api_all() (with compat aliases)
- Add forge_url field to project TOML; load-project.sh derives
FORGE_API/FORGE_WEB from forge_url + repo
- Update parse_repo_slug() to accept any host URL, not just codeberg
- Forgejo data stored under ~/.disinto/forgejo/ (not in factory repo)
- Update all 58 files: agent scripts, formulas, docs, site HTML
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 16:57:12 +00:00
|
|
|
ACTION_ISSUES=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
|
|
|
|
"${FORGE_API}/issues?state=open&labels=action&limit=50&type=issues") || true
|
2026-03-19 07:25:25 +00:00
|
|
|
|
|
|
|
|
if [ -z "$ACTION_ISSUES" ] || [ "$ACTION_ISSUES" = "null" ]; then
|
|
|
|
|
log "no action issues found"
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
COUNT=$(printf '%s' "$ACTION_ISSUES" | jq 'length')
|
|
|
|
|
if [ "$COUNT" -eq 0 ]; then
|
|
|
|
|
log "no action issues found"
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
log "found ${COUNT} open action issue(s)"
|
|
|
|
|
|
|
|
|
|
# Spawn action-agent for each issue that has no active tmux session.
|
|
|
|
|
# Only one agent is spawned per poll to avoid memory pressure; the next
|
|
|
|
|
# poll picks up remaining issues.
|
|
|
|
|
for i in $(seq 0 $((COUNT - 1))); do
|
|
|
|
|
ISSUE_NUM=$(printf '%s' "$ACTION_ISSUES" | jq -r ".[$i].number")
|
2026-03-21 17:05:09 +00:00
|
|
|
SESSION="action-${PROJECT_NAME}-${ISSUE_NUM}"
|
2026-03-19 07:25:25 +00:00
|
|
|
|
|
|
|
|
if tmux has-session -t "$SESSION" 2>/dev/null; then
|
|
|
|
|
log "issue #${ISSUE_NUM}: session ${SESSION} already active, skipping"
|
|
|
|
|
continue
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
LOCKFILE="/tmp/action-agent-${ISSUE_NUM}.lock"
|
|
|
|
|
if [ -f "$LOCKFILE" ]; then
|
|
|
|
|
LOCK_PID=$(cat "$LOCKFILE" 2>/dev/null || echo "")
|
|
|
|
|
if [ -n "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2>/dev/null; then
|
|
|
|
|
log "issue #${ISSUE_NUM}: agent starting (PID ${LOCK_PID}), skipping"
|
|
|
|
|
continue
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
log "spawning action-agent for issue #${ISSUE_NUM}"
|
2026-03-19 22:16:01 +00:00
|
|
|
nohup "${SCRIPT_DIR}/action-agent.sh" "$ISSUE_NUM" "$PROJECT_TOML" >> "$LOGFILE" 2>&1 &
|
2026-03-19 07:25:25 +00:00
|
|
|
log "started action-agent PID $! for issue #${ISSUE_NUM}"
|
|
|
|
|
break
|
|
|
|
|
done
|