Skip to content

Commit cc7c873

Browse files
committed
fix: remaining pipeline robustness — phase error handling, journal grep, Discord JSON safety, branch cleanup, configurable model/URL, remove local iteragent copy
1 parent efc1666 commit cc7c873

4 files changed

Lines changed: 45 additions & 43 deletions

File tree

.github/workflows/evolve.yml

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,10 @@ jobs:
2020
with:
2121
fetch-depth: 0
2222

23-
- uses: actions/checkout@v4
24-
with:
25-
repository: GrayCodeAI/iteragent
26-
path: iteragent-pkg
27-
fetch-depth: 0
28-
2923
- uses: actions/setup-go@v5
3024
with:
3125
go-version: '1.25'
3226

33-
- name: Setup iteragent
34-
run: |
35-
mkdir -p ..
36-
cp -r iteragent-pkg ../iteragent
37-
3827
- name: Configure git
3928
run: |
4029
git config user.name "iterate-evolve[bot]"
@@ -43,9 +32,9 @@ jobs:
4332
- name: Run evolution
4433
env:
4534
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
46-
OPENCODE_BASE_URL: https://opencode.ai/zen/go/v1
35+
OPENCODE_BASE_URL: ${{ secrets.OPENCODE_BASE_URL || 'https://opencode.ai/zen/go/v1' }}
4736
ITERATE_PROVIDER: opencode
48-
ITERATE_MODEL: kimi-k2.5
37+
ITERATE_MODEL: ${{ secrets.ITERATE_MODEL || 'kimi-k2.5' }}
4938
GH_TOKEN: ${{ secrets.GH_PAT }}
5039
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5140
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}

internal/evolution/phases.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,13 @@ func (e *Engine) RunImplementPhase(ctx context.Context, p iteragent.Provider) er
165165

166166
// Commit any remaining tracked-file changes.
167167
// Use git add -u (not -A) to avoid staging untracked artifacts from failed tasks.
168+
sessionTitle := extractSessionTitle(plan)
169+
finalMsg := "iterate: implement session changes"
170+
if sessionTitle != "" {
171+
finalMsg = "chore: " + sessionTitle
172+
}
168173
if _, err := e.runTool(ctx, "bash", map[string]string{
169-
"cmd": "git add -u && git diff --cached --quiet || git commit -m 'iterate: implement session changes'",
174+
"cmd": fmt.Sprintf("git add -u && git diff --cached --quiet || git commit -m %q", finalMsg),
170175
}); err != nil {
171176
e.logger.Warn("final commit failed", "err", err)
172177
}

internal/evolution/phases_communicate.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ func (e *Engine) RunCommunicatePhase(ctx context.Context, p iteragent.Provider)
2222

2323
planBytes, err := os.ReadFile(filepath.Join(e.repoPath, "SESSION_PLAN.md"))
2424
if err != nil {
25-
e.logger.Warn("SESSION_PLAN.md not found, skipping communicate")
26-
return nil
25+
e.logger.Warn("SESSION_PLAN.md not found, writing fallback journal entry and skipping issue comments")
26+
planBytes = []byte("")
2727
}
2828

2929
day := e.readDayCount()
@@ -96,7 +96,10 @@ Rules:
9696

9797
// persistJournalEntry writes the journal entry, generating a fallback if needed.
9898
func (e *Engine) persistJournalEntry(journalEntry string, day string) {
99-
dayNum, _ := strconv.Atoi(day)
99+
dayNum, err := strconv.Atoi(day)
100+
if err != nil {
101+
dayNum = 0
102+
}
100103
now := time.Now().UTC().Format("15:04")
101104

102105
if journalEntry == "" {

scripts/evolution/evolve.sh

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ rm -f "$PLAN_FILE"
9696

9797
# ── Phase A: Planning ──
9898
log "Phase A: Planning..."
99-
./iterate --phase plan --gh-owner GrayCodeAI --gh-repo iterate 2>>"$LOG_FILE" || true
99+
if ! ./iterate --phase plan --gh-owner GrayCodeAI --gh-repo iterate 2>>"$LOG_FILE"; then
100+
log "WARNING: plan phase exited with error — checking for fallback"
101+
fi
100102

101103
# Fallback plan if agent didn't create one
102104
if [[ ! -f "$PLAN_FILE" ]]; then
@@ -134,15 +136,19 @@ fi
134136
# ── Phase B: Implementation ──
135137
log "Phase B: Implementation..."
136138
sleep 5 # Brief pause between phases
137-
./iterate --phase implement --gh-owner GrayCodeAI --gh-repo iterate 2>>"$LOG_FILE" || true
139+
if ! ./iterate --phase implement --gh-owner GrayCodeAI --gh-repo iterate 2>>"$LOG_FILE"; then
140+
log "WARNING: implement phase exited with error — continuing to communicate"
141+
fi
138142

139143
# ── Phase C: Communication ──
140144
log "Phase C: Communication..."
141145
sleep 5 # Brief pause between phases
142-
./iterate --phase communicate --gh-owner GrayCodeAI --gh-repo iterate 2>>"$LOG_FILE" || true
146+
if ! ./iterate --phase communicate --gh-owner GrayCodeAI --gh-repo iterate 2>>"$LOG_FILE"; then
147+
log "WARNING: communicate phase exited with error"
148+
fi
143149

144150
# ── Verify journal was written ──
145-
if grep -q "^## Day $DAY" "${REPOPATH}/docs/JOURNAL.md" 2>/dev/null; then
151+
if grep -qP "^## Day ${DAY}(\s|$|—)" "${REPOPATH}/docs/JOURNAL.md" 2>/dev/null || grep -q "^## Day ${DAY} " "${REPOPATH}/docs/JOURNAL.md" 2>/dev/null; then
146152
log "Journal entry written for Day $DAY"
147153
else
148154
log "WARNING: No journal entry found for Day $DAY — writing fallback"
@@ -319,11 +325,11 @@ gh api repos/"$GITHUB_REPO"/branches --jq '.[].name' 2>/dev/null | grep "^evolut
319325
if [[ "$branch" == "$BRANCH" ]]; then
320326
continue
321327
fi
322-
# Check if branch's PR is merged or closed
323-
PR_STATE=$(gh pr list --repo "$GITHUB_REPO" --head "$branch" --json state --jq '.[0].state' 2>/dev/null)
328+
# Use gh pr view for reliable single-branch state (avoids race with gh pr list pagination)
329+
PR_STATE=$(gh pr view --repo "$GITHUB_REPO" --json state --jq '.state' --head "$branch" 2>/dev/null || echo "")
324330
if [[ "$PR_STATE" == "MERGED" || "$PR_STATE" == "CLOSED" ]]; then
325-
log "Deleting stale branch: $branch"
326-
git push origin --delete "$branch" 2>/dev/null || true
331+
log "Deleting stale branch: $branch (PR state: $PR_STATE)"
332+
git push origin --delete "$branch" 2>/dev/null || log "Failed to delete branch: $branch"
327333
fi
328334
done
329335

@@ -343,24 +349,23 @@ log "Duration: ${SESSION_DURATION}s"
343349
if [[ -n "${DISCORD_WEBHOOK_URL:-}" ]]; then
344350
log "Sending Discord notification..."
345351

346-
# Get journal entry for this day
347-
JOURNAL_ENTRY=$(grep -A3 "^## Day $DAY" docs/JOURNAL.md 2>/dev/null | head -4 || echo "No journal entry")
348-
349-
DISCORD_MSG="{
350-
\"embeds\": [{
351-
\"title\": \"🧬 Evolution Day $DAY Complete\",
352-
\"color\": 5814783,
353-
\"fields\": [
354-
{\"name\": \"PR\", \"value\": \"${PR_NUMBER:-none}\", \"inline\": true},
355-
{\"name\": \"Duration\", \"value\": \"${SESSION_DURATION}s\", \"inline\": true},
356-
{\"name\": \"Commits\", \"value\": \"$(git log --oneline origin/main..HEAD 2>/dev/null | wc -l | tr -d ' ')\", \"inline\": true},
357-
{\"name\": \"Journal\", \"value\": \"$(echo "$JOURNAL_ENTRY" | head -3 | tr '\n' ' ' | cut -c1-100)\"}
358-
],
359-
\"footer\": {\"text\": \"iterate-evolve[bot]\"},
360-
\"timestamp\": \"$(date -u +'%Y-%m-%dT%H:%M:%SZ')\"
361-
}]
362-
}"
363-
352+
JOURNAL_ENTRY=$(grep -A3 "^## Day ${DAY} \|^## Day ${DAY}" docs/JOURNAL.md 2>/dev/null | head -4 || echo "No journal entry")
353+
COMMIT_COUNT=$(git log --oneline origin/main..HEAD 2>/dev/null | wc -l | tr -d ' ')
354+
355+
DISCORD_MSG=$(jq -n \
356+
--arg title "🧬 Evolution Day $DAY Complete" \
357+
--arg pr "${PR_NUMBER:-none}" \
358+
--arg dur "${SESSION_DURATION}s" \
359+
--arg commits "$COMMIT_COUNT" \
360+
--arg journal "$(echo "$JOURNAL_ENTRY" | head -3 | tr '\n' ' ' | cut -c1-100)" \
361+
--arg ts "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
362+
'{embeds:[{title:$title,color:5814783,fields:[
363+
{name:"PR",value:$pr,inline:true},
364+
{name:"Duration",value:$dur,inline:true},
365+
{name:"Commits",value:$commits,inline:true},
366+
{name:"Journal",value:$journal}
367+
],footer:{text:"iterate-evolve[bot]"},timestamp:$ts}]}')
368+
364369
curl -s -H "Content-Type: application/json" \
365370
-d "$DISCORD_MSG" \
366371
"$DISCORD_WEBHOOK_URL" >/dev/null 2>&1 || log "Discord notification failed"

0 commit comments

Comments
 (0)