mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-05 23:50:48 +00:00
* fix: claude snapshot build — remove npm fallback from install command
The native install (curl | bash) succeeds but exits non-zero due to a
PATH warning. The || fallback then tries `npm install` which doesn't
exist on the "minimal" tier → exit 127.
Fix: replace npm fallback with binary existence check (same pattern
as hermes agent). If install exits non-zero but ~/.local/bin/claude
exists, the build succeeds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: snapshot cleanup and lookup — use name prefix instead of tags
DO Packer builder `tags` only apply to the temporary build droplet,
not the resulting snapshot image. Both the workflow cleanup step and
the CLI's findSpawnSnapshot() were querying by `tag_name` which
returned nothing — old snapshots piled up and the CLI couldn't find
existing snapshots.
Fix: filter by snapshot name prefix (`spawn-{agent}-`) instead of
tags, in both the workflow and the CLI. Remove misleading `tags`
from the Packer template. Add test cases for name-prefix filtering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
107 lines
3.3 KiB
YAML
107 lines
3.3 KiB
YAML
name: Packer DO Snapshots
|
|
|
|
on:
|
|
schedule:
|
|
# Nightly at 4 AM UTC (before tarball build at 5 AM)
|
|
- cron: "0 4 * * *"
|
|
workflow_dispatch:
|
|
inputs:
|
|
agent:
|
|
description: "Single agent to build (leave empty for all)"
|
|
required: false
|
|
type: string
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
matrix:
|
|
name: Generate matrix
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
agents: ${{ steps.set.outputs.agents }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- id: set
|
|
run: |
|
|
SINGLE_AGENT="${SINGLE_AGENT_INPUT}"
|
|
if [ -n "$SINGLE_AGENT" ]; then
|
|
echo "agents=[\"${SINGLE_AGENT}\"]" >> "$GITHUB_OUTPUT"
|
|
else
|
|
AGENTS=$(jq -c 'keys' packer/agents.json)
|
|
echo "agents=${AGENTS}" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
env:
|
|
SINGLE_AGENT_INPUT: ${{ inputs.agent }}
|
|
|
|
build:
|
|
name: "Build ${{ matrix.agent }}"
|
|
needs: matrix
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
agent: ${{ fromJson(needs.matrix.outputs.agents) }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Read agent config
|
|
id: config
|
|
run: |
|
|
TIER=$(jq -r --arg a "$AGENT_NAME" '.[$a].tier // "minimal"' packer/agents.json)
|
|
INSTALL=$(jq -c --arg a "$AGENT_NAME" '.[$a].install // []' packer/agents.json)
|
|
echo "tier=${TIER}" >> "$GITHUB_OUTPUT"
|
|
echo "install=${INSTALL}" >> "$GITHUB_OUTPUT"
|
|
env:
|
|
AGENT_NAME: ${{ matrix.agent }}
|
|
|
|
- name: Setup Packer
|
|
uses: hashicorp/setup-packer@main
|
|
with:
|
|
version: latest
|
|
|
|
- name: Init Packer plugins
|
|
run: packer init packer/digitalocean.pkr.hcl
|
|
|
|
- name: Generate variables file
|
|
run: |
|
|
jq -n \
|
|
--arg token "$DO_API_TOKEN" \
|
|
--arg agent "$AGENT_NAME" \
|
|
--arg tier "$TIER" \
|
|
--argjson install "$INSTALL_COMMANDS" \
|
|
'{
|
|
do_api_token: $token,
|
|
agent_name: $agent,
|
|
cloud_init_tier: $tier,
|
|
install_commands: $install
|
|
}' > packer/auto.pkrvars.json
|
|
env:
|
|
DO_API_TOKEN: ${{ secrets.DO_API_TOKEN }}
|
|
AGENT_NAME: ${{ matrix.agent }}
|
|
TIER: ${{ steps.config.outputs.tier }}
|
|
INSTALL_COMMANDS: ${{ steps.config.outputs.install }}
|
|
|
|
- name: Build snapshot
|
|
run: packer build -var-file=packer/auto.pkrvars.json packer/digitalocean.pkr.hcl
|
|
env:
|
|
PACKER_LOG: "1"
|
|
|
|
- name: Cleanup old snapshots
|
|
if: success()
|
|
run: |
|
|
# DO snapshots don't support tags — filter by name prefix instead
|
|
PREFIX="spawn-${AGENT_NAME}-"
|
|
SNAPSHOTS=$(curl -s -H "Authorization: Bearer ${DO_API_TOKEN}" \
|
|
"https://api.digitalocean.com/v2/images?private=true&per_page=100" \
|
|
| jq -r --arg prefix "$PREFIX" \
|
|
'[.images[] | select(.name | startswith($prefix))] | sort_by(.created_at) | reverse | .[1:] | .[].id')
|
|
|
|
for ID in $SNAPSHOTS; do
|
|
echo "Deleting old snapshot: ${ID}"
|
|
curl -s -X DELETE -H "Authorization: Bearer ${DO_API_TOKEN}" \
|
|
"https://api.digitalocean.com/v2/images/${ID}" || true
|
|
done
|
|
env:
|
|
DO_API_TOKEN: ${{ secrets.DO_API_TOKEN }}
|
|
AGENT_NAME: ${{ matrix.agent }}
|