scaffolding: root README, plan, VS Code build tasks, Gitea Actions release workflow
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmdG9GqfSWCzts7AkDwRDh
This commit is contained in:
105
.gitea/workflows/release.yml
Normal file
105
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,105 @@
|
||||
name: release-tools
|
||||
|
||||
# På varje push till master/main: bygg de tools som fått ändringar
|
||||
# (linux x64 + arm64) och lägg binärerna på en rullande
|
||||
# "<tool>-latest"-release på släppsidan i Gitea.
|
||||
on:
|
||||
push:
|
||||
branches: [master, main]
|
||||
workflow_dispatch: {} # manuell körning bygger ALLA tools
|
||||
|
||||
jobs:
|
||||
build-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # hela historiken behövs för diffen mot 'before'
|
||||
|
||||
- name: Detektera ändrade tools
|
||||
id: changed
|
||||
run: |
|
||||
TOOLS="pixel-sprite-maker mesh-tool"
|
||||
BEFORE="${{ github.event.before }}"
|
||||
CHANGED=""
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ] \
|
||||
|| [ -z "$BEFORE" ] \
|
||||
|| echo "$BEFORE" | grep -Eq '^0+$' \
|
||||
|| ! git cat-file -e "$BEFORE" 2>/dev/null; then
|
||||
echo "första push / manuell körning -> bygger alla tools"
|
||||
CHANGED="$TOOLS"
|
||||
else
|
||||
for t in $TOOLS; do
|
||||
if ! git diff --quiet "$BEFORE" "${{ github.sha }}" -- "$t/"; then
|
||||
CHANGED="$CHANGED $t"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
CHANGED="$(echo $CHANGED)" # trimma whitespace
|
||||
echo "tools=$CHANGED" >> "$GITHUB_OUTPUT"
|
||||
echo "bygger: ${CHANGED:-inget}"
|
||||
|
||||
- name: Installera Go
|
||||
if: steps.changed.outputs.tools != ''
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.24"
|
||||
cache: false
|
||||
|
||||
- name: Testa + bygg (x64 + arm64)
|
||||
if: steps.changed.outputs.tools != ''
|
||||
run: |
|
||||
set -e
|
||||
VERSION="latest-$(git rev-parse --short HEAD)"
|
||||
for t in ${{ steps.changed.outputs.tools }}; do
|
||||
case "$t" in
|
||||
pixel-sprite-maker) BIN=spritec ;;
|
||||
mesh-tool) BIN=mesht ;;
|
||||
*) echo "okänt tool $t"; exit 1 ;;
|
||||
esac
|
||||
echo "=== $t ($BIN) ==="
|
||||
cd "$t"
|
||||
go test ./...
|
||||
mkdir -p build
|
||||
GOOS=linux GOARCH=amd64 go build -trimpath \
|
||||
-ldflags "-s -w -X main.version=$VERSION" -o "build/$BIN-linux-x64" .
|
||||
GOOS=linux GOARCH=arm64 go build -trimpath \
|
||||
-ldflags "-s -w -X main.version=$VERSION" -o "build/$BIN-linux-arm64" .
|
||||
(cd build && sha256sum "$BIN"-linux-* > checksums.txt && ls -la)
|
||||
cd ..
|
||||
done
|
||||
|
||||
- name: Skapa/uppdatera releaser + ladda upp binärer
|
||||
if: steps.changed.outputs.tools != ''
|
||||
env:
|
||||
API: http://gitea-d:3000/api/v1
|
||||
REPO: ${{ github.repository }}
|
||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -e
|
||||
for t in ${{ steps.changed.outputs.tools }}; do
|
||||
case "$t" in
|
||||
pixel-sprite-maker) BIN=spritec ;;
|
||||
mesh-tool) BIN=mesht ;;
|
||||
esac
|
||||
TAG="$t-latest"
|
||||
BODY="$t (binär: $BIN) - rullande bygge från senaste master. Commit: ${{ github.sha }}. Arkitekturer: linux x64 + arm64 (Pi5)."
|
||||
rid=$(curl -s -X POST "$API/repos/$REPO/releases" \
|
||||
-H "Authorization: token $TOKEN" -H 'Content-Type: application/json' \
|
||||
-d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\",\"body\":\"$BODY\"}" | jq -r '.id // empty')
|
||||
[ -z "$rid" ] && rid=$(curl -s "$API/repos/$REPO/releases/tags/$TAG" \
|
||||
-H "Authorization: token $TOKEN" | jq -r '.id')
|
||||
echo "$t -> release id $rid"
|
||||
for f in "$BIN-linux-x64" "$BIN-linux-arm64" checksums.txt; do
|
||||
aid=$(curl -s "$API/repos/$REPO/releases/$rid/assets" \
|
||||
-H "Authorization: token $TOKEN" | jq -r ".[] | select(.name==\"$f\") | .id")
|
||||
if [ -n "$aid" ] && [ "$aid" != "null" ]; then
|
||||
curl -s -X DELETE "$API/repos/$REPO/releases/$rid/assets/$aid" \
|
||||
-H "Authorization: token $TOKEN" -o /dev/null
|
||||
fi
|
||||
curl -s -X POST "$API/repos/$REPO/releases/$rid/assets?name=$f" \
|
||||
-H "Authorization: token $TOKEN" \
|
||||
-F "attachment=@$t/build/$f" -o /dev/null -w " $f -> HTTP %{http_code}\n"
|
||||
done
|
||||
done
|
||||
44
.vscode/tasks.json
vendored
Normal file
44
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build pixel-sprite-maker",
|
||||
"type": "shell",
|
||||
"command": "go build -trimpath -ldflags '-s -w' -o build/spritec .",
|
||||
"options": { "cwd": "${workspaceFolder}/pixel-sprite-maker" },
|
||||
"group": "build",
|
||||
"problemMatcher": ["$go"]
|
||||
},
|
||||
{
|
||||
"label": "build mesh-tool",
|
||||
"type": "shell",
|
||||
"command": "go build -trimpath -ldflags '-s -w' -o build/mesht .",
|
||||
"options": { "cwd": "${workspaceFolder}/mesh-tool" },
|
||||
"group": "build",
|
||||
"problemMatcher": ["$go"]
|
||||
},
|
||||
{
|
||||
"label": "test pixel-sprite-maker",
|
||||
"type": "shell",
|
||||
"command": "go test ./...",
|
||||
"options": { "cwd": "${workspaceFolder}/pixel-sprite-maker" },
|
||||
"group": "test",
|
||||
"problemMatcher": ["$go"]
|
||||
},
|
||||
{
|
||||
"label": "test mesh-tool",
|
||||
"type": "shell",
|
||||
"command": "go test ./...",
|
||||
"options": { "cwd": "${workspaceFolder}/mesh-tool" },
|
||||
"group": "test",
|
||||
"problemMatcher": ["$go"]
|
||||
},
|
||||
{
|
||||
"label": "build",
|
||||
"dependsOn": ["build pixel-sprite-maker", "build mesh-tool"],
|
||||
"dependsOrder": "parallel",
|
||||
"group": { "kind": "build", "isDefault": true },
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
45
README.md
45
README.md
@@ -1,3 +1,46 @@
|
||||
# agent-tools
|
||||
|
||||
smal tools for ai agents
|
||||
Small, self-contained CLI tools built for **AI agents** to use during
|
||||
development work. Every tool is a single static Go binary with a
|
||||
text-first interface: input formats an agent can read and write
|
||||
directly, and output (names, errors, previews) explicit enough that the
|
||||
agent understands the result without opening an image viewer.
|
||||
|
||||
| Tool | Binary | What it does |
|
||||
|------|--------|--------------|
|
||||
| [`pixel-sprite-maker/`](pixel-sprite-maker/) | `spritec` | Turns `.sprite` text files (palette + character grid) into PNG/JPG/SVG pixel art, up to 256x256 px per sprite. Combines several sprites into sprite sheets / animation strips whose **file names document the layout** (`walk_8x8_4x1.png` = 8x8 px frames, 4 columns, 1 row). |
|
||||
| [`mesh-tool/`](mesh-tool/) | `mesht` | Creates, inspects and edits 3D models (OBJ + STL). ASCII multi-view rendering + measurements (bbox, volume, watertightness) let an agent *see* a model, edit it (scale/rotate/mirror/merge/primitives) and verify the result. |
|
||||
|
||||
Each tool has its own folder, its own README with the full format/CLI
|
||||
reference, its own tests and its own dev branch (`dev/<tool>`).
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
# Arch/Garuda prerequisite:
|
||||
sudo pacman -S go
|
||||
|
||||
cd <tool>/ && go build -o build/<binary> . # per tool
|
||||
go test ./... # per tool
|
||||
```
|
||||
|
||||
VS Code: **Terminal → Run Build Task** — `build` builds every tool into
|
||||
its own `<tool>/build/` folder; per-tool `build <tool>` and
|
||||
`test <tool>` tasks also exist.
|
||||
|
||||
## CI / releases
|
||||
|
||||
`.gitea/workflows/release.yml` runs on every push to `master`/`main` on
|
||||
the self-hosted runner: tools whose folders changed are tested, built
|
||||
for **linux x64 + arm64** (the Pi5), and published to a rolling
|
||||
release per tool on the repo's release page:
|
||||
|
||||
- tag `pixel-sprite-maker-latest` → assets `spritec-linux-x64`, `spritec-linux-arm64`, `checksums.txt`
|
||||
- tag `mesh-tool-latest` → assets `mesht-linux-x64`, `mesht-linux-arm64`, `checksums.txt`
|
||||
|
||||
A manual `workflow_dispatch` run builds all tools regardless of diffs.
|
||||
|
||||
## Branch layout
|
||||
|
||||
- `main` — stable, releases are built from here
|
||||
- `dev/pixel-sprite-maker`, `dev/mesh-tool` — per-tool development branches
|
||||
|
||||
43
doc/plan.md
Normal file
43
doc/plan.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# agent-tools — plan
|
||||
|
||||
## Goal
|
||||
|
||||
A collection of small, agent-friendly CLI tools. The common thread:
|
||||
**text in, verifiable artifacts out**. An agent should be able to author
|
||||
the input format directly, predict what the output will look like, and
|
||||
verify results without a GUI.
|
||||
|
||||
## Stack
|
||||
|
||||
- Go (single static binaries, zero deps, trivial cross-compile to the
|
||||
Pi5's arm64 runner), one Go module per tool.
|
||||
- Targets: linux x64 + linux arm64.
|
||||
|
||||
## Deploy target
|
||||
|
||||
Pattern A (distributable binaries): rolling `<tool>-latest` release per
|
||||
tool on Gitea, built by `.gitea/workflows/release.yml` on push to
|
||||
master/main. Only tools whose folders changed get rebuilt.
|
||||
|
||||
## Milestones
|
||||
|
||||
1. ✅ `pixel-sprite-maker` (`spritec`): .sprite text format → PNG/JPG/SVG,
|
||||
sprite sheets with self-documenting file names, terminal preview.
|
||||
2. ✅ `mesh-tool` (`mesht`): OBJ/STL create/inspect/edit with ASCII
|
||||
multi-view rendering, measurements and watertightness checks.
|
||||
3. ✅ Per-tool VS Code build tasks → `<tool>/build/`.
|
||||
4. ✅ CI: changed-tool detection + per-tool rolling releases.
|
||||
|
||||
## Roadmap / expansion ideas (not agreed yet)
|
||||
|
||||
- spritec: palette import from image files, GIF export for animations,
|
||||
tile-map composer (map file referencing sprite tiles).
|
||||
- mesht: OBJ vertex-color support, simple boolean ops (union via
|
||||
voxelization), PNG snapshot rendering, glTF export.
|
||||
- New tools: bitmap-font maker, sound-effect generator (sfxr-style text
|
||||
presets), tiled-map (.tmx) writer.
|
||||
|
||||
## Open questions
|
||||
|
||||
- Versioned releases (`vX.Y.Z` tags per tool) on top of the rolling
|
||||
`latest` — add when something depends on a pinned version.
|
||||
Reference in New Issue
Block a user