Co-authored-by: Kimi Claw <kimi@timmytime.ai> Co-committed-by: Kimi Claw <kimi@timmytime.ai>
111 lines
4.5 KiB
Bash
Executable File
111 lines
4.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# kimi-heartbeat.sh — Polls Gitea for assigned-kimi tickets, dispatches to OpenClaw
|
|
# Run as: bash ~/.timmy/uniwizard/kimi-heartbeat.sh
|
|
# Or as a cron: every 5m
|
|
|
|
set -euo pipefail
|
|
|
|
TOKEN=$(cat /Users/apayne/.timmy/kimi_gitea_token | tr -d '[:space:]')
|
|
BASE="http://100.126.61.75:3000/api/v1"
|
|
LOG="/tmp/kimi-heartbeat.log"
|
|
|
|
log() { echo "[$(date '+%H:%M:%S')] $*" | tee -a "$LOG"; }
|
|
|
|
# Find all issues labeled "assigned-kimi" across repos
|
|
REPOS=("Timmy_Foundation/timmy-home" "Timmy_Foundation/timmy-config" "Timmy_Foundation/the-nexus")
|
|
|
|
for repo in "${REPOS[@]}"; do
|
|
# Get issues with assigned-kimi label but NOT kimi-in-progress or kimi-done
|
|
issues=$(curl -s -H "Authorization: token $TOKEN" \
|
|
"$BASE/repos/$repo/issues?state=open&labels=assigned-kimi&limit=10" | \
|
|
python3 -c "
|
|
import json, sys
|
|
issues = json.load(sys.stdin)
|
|
for i in issues:
|
|
labels = [l['name'] for l in i.get('labels',[])]
|
|
# Skip if already in-progress or done
|
|
if 'kimi-in-progress' in labels or 'kimi-done' in labels:
|
|
continue
|
|
body = (i.get('body','') or '')[:500].replace('\n',' ')
|
|
print(f\"{i['number']}|{i['title']}|{body}\")
|
|
" 2>/dev/null)
|
|
|
|
if [ -z "$issues" ]; then
|
|
continue
|
|
fi
|
|
|
|
while IFS='|' read -r issue_num title body; do
|
|
[ -z "$issue_num" ] && continue
|
|
log "DISPATCH: $repo #$issue_num — $title"
|
|
|
|
# Add kimi-in-progress label
|
|
# First get the label ID
|
|
label_id=$(curl -s -H "Authorization: token $TOKEN" \
|
|
"$BASE/repos/$repo/labels" | \
|
|
python3 -c "import json,sys; [print(l['id']) for l in json.load(sys.stdin) if l['name']=='kimi-in-progress']" 2>/dev/null)
|
|
|
|
if [ -n "$label_id" ]; then
|
|
curl -s -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
-d "{\"labels\":[$label_id]}" \
|
|
"$BASE/repos/$repo/issues/$issue_num/labels" > /dev/null 2>&1
|
|
fi
|
|
|
|
# Post "picking up" comment
|
|
curl -s -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
-d "{\"body\":\"🟠 **Kimi picking up this task** via OpenClaw heartbeat.\\nBackend: kimi/kimi-code\\nTimestamp: $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"}" \
|
|
"$BASE/repos/$repo/issues/$issue_num/comments" > /dev/null 2>&1
|
|
|
|
# Dispatch to OpenClaw
|
|
# Build a self-contained prompt from the issue
|
|
prompt="You are Timmy, working on $repo issue #$issue_num: $title
|
|
|
|
ISSUE BODY:
|
|
$body
|
|
|
|
YOUR TASK:
|
|
1. Read the issue carefully
|
|
2. Do the work described — create files, write code, analyze, review as needed
|
|
3. Work in ~/.timmy/uniwizard/ for new files
|
|
4. When done, post a summary of what you did as a comment on the Gitea issue
|
|
Gitea API: $BASE, token in /Users/apayne/.config/gitea/token
|
|
Repo: $repo, Issue: $issue_num
|
|
5. Be thorough but practical. Ship working code."
|
|
|
|
# Fire via openclaw agent (async via background)
|
|
(
|
|
result=$(openclaw agent --agent main --message "$prompt" --json 2>/dev/null)
|
|
status=$(echo "$result" | python3 -c "import json,sys; print(json.load(sys.stdin).get('status','error'))" 2>/dev/null)
|
|
|
|
if [ "$status" = "ok" ]; then
|
|
log "COMPLETED: $repo #$issue_num"
|
|
# Swap kimi-in-progress for kimi-done
|
|
done_id=$(curl -s -H "Authorization: token $TOKEN" \
|
|
"$BASE/repos/$repo/labels" | \
|
|
python3 -c "import json,sys; [print(l['id']) for l in json.load(sys.stdin) if l['name']=='kimi-done']" 2>/dev/null)
|
|
progress_id=$(curl -s -H "Authorization: token $TOKEN" \
|
|
"$BASE/repos/$repo/labels" | \
|
|
python3 -c "import json,sys; [print(l['id']) for l in json.load(sys.stdin) if l['name']=='kimi-in-progress']" 2>/dev/null)
|
|
|
|
[ -n "$progress_id" ] && curl -s -X DELETE -H "Authorization: token $TOKEN" \
|
|
"$BASE/repos/$repo/issues/$issue_num/labels/$progress_id" > /dev/null 2>&1
|
|
[ -n "$done_id" ] && curl -s -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
-d "{\"labels\":[$done_id]}" \
|
|
"$BASE/repos/$repo/issues/$issue_num/labels" > /dev/null 2>&1
|
|
else
|
|
log "FAILED: $repo #$issue_num — $status"
|
|
curl -s -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
-d "{\"body\":\"🔴 **Kimi failed on this task.**\\nStatus: $status\\nTimestamp: $(date -u '+%Y-%m-%dT%H:%M:%SZ')\"}" \
|
|
"$BASE/repos/$repo/issues/$issue_num/comments" > /dev/null 2>&1
|
|
fi
|
|
) &
|
|
|
|
log "DISPATCHED: $repo #$issue_num (background PID $!)"
|
|
|
|
# Don't flood — wait 5s between dispatches
|
|
sleep 5
|
|
|
|
done <<< "$issues"
|
|
done
|
|
|
|
log "Heartbeat complete. $(date)"
|