7124b16fc1
Docs: - AGENTS.md: updated toolchain section with js-lint/js-test tasks, expanded web/ui/ directory listing, added event delegation and Web Audio API to key patterns, updated testing section - README: marked issue #9 (Audio Preview Player) as done - .gitignore: added akai-fetch.test and cover.out Tests: - Moved groupWavs and cleanName to util.js (pure functions) - Added 10 new JS tests: 6 groupWavs, 4 cleanName - Total JS tests: 29 (up from 19)
6.3 KiB
6.3 KiB
AGENTS.md — AKAI Utils Development Guide
Toolchain (mise)
mise trust # trust the mise.toml config (first time only)
mise install # installs go 1.26, node 22
mise run gopls # install gopls (Go LSP) — one-time dev setup
All build/run tasks are defined in mise.toml:
mise run build # → ./akai-fetch
mise run serve # → starts HTTP server, opens browser
mise run electron-deps # installs electron + electron-builder
mise run electron-dev # runs electron in dev mode
mise run docker-up # docker compose up --build
mise run lint # golangci-lint run (Go)
mise run js-lint # eslint (JS)
mise run js-test # node --test (JS)
mise run check-all # verify gcc, brew, mise, go, node, docker, colima
Install golangci-lint:
mise install golangci-lint # one-time setup
golangci-lint run # comprehensive lint
Build & Run (manual)
# Build Go binary (zero CGO)
go build -buildvcs=false -o akai-fetch . # → ./akai-fetch
# Build and run web server
./akai-fetch serve # → starts on free port, opens browser
./akai-fetch serve --host 0.0.0.0 -p 8080 # → Docker / network-accessible mode
# Docker
docker compose up --build # serves on :8080, binds 0.0.0.0
# Electron dev
(cd electron && npm install)
(cd electron && npx electron .)
# Cross-compile for macOS (from Linux)
GOOS=darwin GOARCH=arm64 go build -o akai-fetch-darwin-arm64 .
GOOS=darwin GOARCH=amd64 go build -o akai-fetch-darwin-amd64 .
Architecture
Single binary (fetch) with subcommands. No external Go dependencies — pure stdlib.
main.go CLI entry, commands (search/list/download/extract/pipeline/serve)
serve.go HTTP server + REST API + embedded web UI (embed.FS)
web/ui/ Static frontend
├── index.html HTML layout
├── style.css CSS custom properties theme
├── util.js shared utility functions
├── app.js application logic, event delegation
├── util.test.js JS tests (node --test)
├── eslint.config.js ESLint flat config
└── package.json ESLint + test scripts
electron/ Electron wrapper shell
scripts/ Bash helpers called via exec
├── extract_wavs.sh batch WAV extraction via akaiutil
├── check-toolchain.sh verify gcc, brew, mise, go, node
└── check-docker-toolchain.sh verify docker, compose, colima
third_party/ Vendored akaiutil C binary (GPLv2)
Key patterns
- Subcommand dispatch:
main.go:60— switch onos.Args[1], each case callscmdXxx(args) - Flag parsing: each command creates its own
flag.NewFlagSet— avoids global flag state - Concurrency: semaphore channel pattern (
sem := make(chan struct{}, N)) for bounded parallelism - SSE progress:
serve.go:handleProgress— 500ms ticker, EventSource stream, auto-closes when all done - Event delegation:
app.js— single click listener on document, dispatches by[data-action]attribute (download, list, play) - akaiutil wrapper:
extract.go— persistent stdin/stdout pipes, no bash intermediary - Zero-deps web UI: vanilla JS, no bundler, no framework. API calls use
fetch()+EventSource. Web Audio API for WAV playback. - Embed directive:
//go:embed web/ui/*inserve.go— frontend baked into the binary - Bind address handling:
serve.go:37—--hostflag defaults to127.0.0.1for local dev; set--host 0.0.0.0for Docker. When binding to0.0.0.0, prints bothlocalhostand<host-ip>URLs for clarity.
akaiutil integration
extract.go wraps akaiutil via stdin/stdout pipes — no bash intermediary.
scripts/check-toolchain.sh and check-docker-toolchain.sh verify the dev environment.
akaiutil is used for:
df— disk info (partitions, block counts)dir— list volumes/filessample2wavall— batch WAV extraction- Many more commands available (see
docs/akaiutil.md)
All akaiutil calls use -r (read-only) flag. Write operations (S900 compress, partitioning, tagging) require removing -r.
macOS compatibility
third_party/akaiutil/commoninclude.hhasbcopy/bzerodeclarations guarded with#ifdef _VISUALCPCto avoid conflicts with macOS system headers that define these in<strings.h>.
Electron integration
electron/main.js spawns the Go binary in serve mode:
- Finds
akai-fetchbinary next to app or inprocess.resourcesPath - Spawns
akai-fetch serve -p 0 --no-browser - Parses
stdoutforLocal: http://localhost:XXXXto get port - Creates
BrowserWindowpointing at that URL - Kills server on quit
Adding a new feature
- New API endpoint: add handler in
serve.go, register incmdServemux - New web UI section: add HTML in
index.html, CSS instyle.css, JS inapp.js - New akaiutil wrapper: create a bash script in
scripts/or call akaiutil directly viaexec.Commandin Go - New CLI subcommand: add case in
main.go:60, implementcmdXxx(args)function
API conventions
- All responses have
Content-Type: application/jsonandAccess-Control-Allow-Origin: * - Use
writeJSON(w, v)for responses, it sets headers and marshals - Download progress uses SSE (
text/event-stream) withdata: <json>\n\n - Error responses use
http.Error(w, msg, code)or return JSON with"error"key
Format conventions
- Go: standard
gofmt(no custom formatter) - Bash:
set -euo pipefail, shellcheck-compatible - JS: no semicolons (ASI style),
constpreferred overlet - CSS: CSS custom properties for theming (
:root { --bg: ... })
Testing
# Go
go test -cover # unit tests (extract, serve, http, download, cli, util)
go vet ./... # static analysis
golangci-lint run # comprehensive lint (uses .golangci.yml)
# JavaScript
mise run js-test # node --test (19 tests: esc, sanitize, formatBytes, formatTime)
mise run js-lint # eslint (flat config)
Secrets & Tokens
None required. archive.org API is public and unauthenticated. AKAIUTIL environment variable controls the akaiutil binary path.
Project Repo
Git remote: git@git.notsosm.art:david/akai-utils.git
Issues managed via tea CLI.