Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Ad9rqAB8pXXvyzh7f4X8v
60 lines
2.8 KiB
Bash
Executable File
60 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Nightly review: today's staging commits and agent comments → docs/agents/LESSONS.md.
|
|
# Pushes docs-only changes to staging (enforced by the pre-push hook via AGENT_LOOP_DOCS_ONLY=1).
|
|
set -euo pipefail
|
|
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
GITEA="$HERE/gitea.sh"
|
|
REPO_DIR="${JYOTISHA_REPO_DIR:-/workspace/Jyotisha}"
|
|
LOOP_WT="${AGENT_LOOP_WORKTREE:-$REPO_DIR/.worktrees/agent-loop}"
|
|
CONF_DIR="$HOME/.config/jyotisha-agent"
|
|
STATE_DIR="${AGENT_LOOP_STATE_DIR:-$HOME/.local/state/jyotisha-agent}"
|
|
MAX_BUDGET="${AGENT_LOOP_NIGHTLY_BUDGET_USD:-10}"
|
|
LOG="$STATE_DIR/nightly.log"
|
|
mkdir -p "$STATE_DIR/runs"
|
|
log() { printf '%s %s\n' "$(date -u +%FT%TZ)" "$*" >> "$LOG"; }
|
|
|
|
[[ -e "$CONF_DIR/STOP" ]] && { log "STOP file present, skipping"; exit 0; }
|
|
# Shares the tick lock so a review never runs beside a tick in the same worktree.
|
|
exec 9> "$STATE_DIR/claude.lock"
|
|
flock -w 3600 9 || { log "tick lock busy for an hour, skipping tonight"; exit 0; }
|
|
|
|
RUN_DIR="$STATE_DIR/runs/nightly-$(date -u +%Y%m%dT%H%M%SZ)"
|
|
mkdir -p "$RUN_DIR"
|
|
today="$(TZ=Asia/Shanghai date +%F)"
|
|
|
|
git -C "$REPO_DIR" fetch -q origin --prune
|
|
[[ -d "$LOOP_WT" ]] || git -C "$REPO_DIR" worktree add -q --detach "$LOOP_WT" origin/staging
|
|
git -C "$LOOP_WT" checkout -q --detach -f origin/staging
|
|
git -C "$LOOP_WT" clean -q -fd
|
|
|
|
# Today's agent comments on loop issues (owner account only).
|
|
since="$(TZ=Asia/Shanghai date -d "$today 00:00" -u +%FT%TZ)"
|
|
"$GITEA" issues "agent/试点" > "$RUN_DIR/open.json" || echo '[]' > "$RUN_DIR/open.json"
|
|
jq -n '[]' > "$RUN_DIR/comments.json"
|
|
for n in $(jq -r '.[].number' "$RUN_DIR/open.json"); do
|
|
"$GITEA" comments "$n" | jq --arg s "$since" --argjson n "$n" \
|
|
'[.[] | select(.created_at >= $s and (.body | startswith("<!-- agent:"))) | {issue: $n, created_at, body}]' \
|
|
> "$RUN_DIR/c.json"
|
|
jq -s 'add' "$RUN_DIR/comments.json" "$RUN_DIR/c.json" > "$RUN_DIR/m.json" && mv "$RUN_DIR/m.json" "$RUN_DIR/comments.json"
|
|
done
|
|
jq -n --arg day "$today" --arg staging "$(git -C "$REPO_DIR" rev-parse origin/staging)" \
|
|
--slurpfile c "$RUN_DIR/comments.json" '{date: $day, origin_staging: $staging, agent_comments: $c[0]}' > "$RUN_DIR/context.json"
|
|
|
|
(
|
|
cd "$LOOP_WT"
|
|
export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=core.hooksPath GIT_CONFIG_VALUE_0="$HERE/hooks/claude"
|
|
export AGENT_LOOP_DOCS_ONLY=1
|
|
timeout --kill-after=60 30m claude -p \
|
|
"$(cat "$HERE/prompts/claude-nightly.md")
|
|
|
|
本轮上下文文件(JSON):$RUN_DIR/context.json" \
|
|
--output-format json \
|
|
--json-schema "$(cat "$HERE/prompts/claude-nightly.schema.json")" \
|
|
--settings "$HERE/claude-settings.json" \
|
|
--permission-mode dontAsk \
|
|
--max-budget-usd "$MAX_BUDGET"
|
|
) > "$RUN_DIR/out.json" 2>> "$LOG" || { log "nightly run failed ($RUN_DIR)"; exit 0; }
|
|
|
|
log "nightly: $(jq -c '.structured_output // {error: "no structured output"}' "$RUN_DIR/out.json")"
|