Step 9 — autonomous patch loop:
- patcher.py: clawdforge session → unified diff → worktree apply → verify recipe → push branch → open Gitea PR
- migration 007: patch_attempts (UNIQUE per finding+attempt, max 3 attempts)
- runner.py: post-parse hook fires patcher.maybe_draft_for_job when notify.auto_patch=true
- server.py: POST /jobs/{id}/patches, GET /patches, GET /patches/{id}
- digest.py: patch-drafted lines + open-follow-up count via Gitea PR state check
- mcp: crafting_table_draft_patch stub replaced with real implementation
- tests/test_patcher.py + tests/test_patches_api.py: 27 new tests
No auto-merge — patches stop at PR-open. Cobb merges.
Step 10 — production recipes:
- examples/recipes/clawdforge.json: 14 subprojects across all SDKs, audit nightly
- examples/recipes/cauldron.json: single Flask subproject, audit nightly
- examples/recipes/tradecraft.json: nightly audit, auto_patch=false (manual review)
- examples/register-all.sh: bulk-register helper with GITEA_TOKEN substitution
- README "Autonomous patch loop" + "First production recipes" sections
Tests: server 116→143, mcp 65→67. All green.
Spec: memory/spec-crafting-table.md
48 lines
1.8 KiB
Bash
Executable file
48 lines
1.8 KiB
Bash
Executable file
#!/bin/bash
|
|
# Register all example recipes against a running crafting-table instance.
|
|
#
|
|
# Reads the bearer token from $CRAFTING_TABLE_TOKEN, falling back to
|
|
# /data/admin-bearer.txt (the path inside the container) if unset. The
|
|
# admin bearer file is also bind-mounted at
|
|
# /mnt/user/appdata/crafting-table/data/admin-bearer.txt on the Lucy host
|
|
# — that's the recommended source on the host side.
|
|
#
|
|
# IMPORTANT: the recipe JSON files in recipes/ ship with a placeholder
|
|
# git_url containing "REPLACE_WITH_GITEA_TOKEN". This script substitutes
|
|
# $GITEA_TOKEN into each recipe before posting; commit-time the real
|
|
# token never lives on disk.
|
|
set -euo pipefail
|
|
|
|
BASE_URL=${CRAFTING_TABLE_URL:-http://192.168.0.5:8810}
|
|
TOKEN=${CRAFTING_TABLE_TOKEN:-$(cat /data/admin-bearer.txt 2>/dev/null || echo "")}
|
|
GITEA_TOKEN=${GITEA_TOKEN:-}
|
|
|
|
if [ -z "$TOKEN" ]; then
|
|
echo "no crafting-table token (set CRAFTING_TABLE_TOKEN or ensure /data/admin-bearer.txt exists)" >&2
|
|
exit 1
|
|
fi
|
|
if [ -z "$GITEA_TOKEN" ]; then
|
|
echo "no Gitea token (set GITEA_TOKEN to substitute into recipe git_url)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
DIR="$(dirname "$0")/recipes"
|
|
for recipe in "$DIR"/*.json; do
|
|
name="$(basename "$recipe" .json)"
|
|
echo "registering $name from $recipe..."
|
|
body="$(sed "s|REPLACE_WITH_GITEA_TOKEN|$GITEA_TOKEN|g" "$recipe")"
|
|
code=$(printf '%s' "$body" | curl -s -o /tmp/register-resp.json \
|
|
-w "%{http_code}" \
|
|
-X POST \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
--data-binary @- \
|
|
"$BASE_URL/projects" || true)
|
|
if [ "$code" = "200" ]; then
|
|
echo " ok"
|
|
elif [ "$code" = "409" ]; then
|
|
echo " already exists — use PUT /projects/$name to update"
|
|
else
|
|
echo " FAILED ($code): $(cat /tmp/register-resp.json 2>/dev/null || echo no-body)"
|
|
fi
|
|
done
|