- Node.js ≥ 24.14.1
- Ableton Live 12 beta with the Extension Host (
…/Contents/Helpers/ExtensionHost/ExtensionHostNodeModule.nodeon macOS) - The SDK/CLI tarballs are vendored in
vendor/—npm installneeds no registry access for them.
| Script | What it does |
|---|---|
npm start |
typecheck + dev build, then extensions-cli run (loads into Live; needs .env + Developer Mode in Live's Extensions preferences) |
npm test |
engine tests via Node's built-in runner (node --import tsx --test) — no Live required |
npm run typecheck |
tsc --noEmit over src, tests, scripts |
npm run build |
production bundles (minified, no sourcemaps) |
npm run package |
production build + extensions-cli package → Live-Console-<version>.ablx |
npx tsx scripts/dev-preview.ts |
render the console dialog with demo state to dist/preview/index.html for browser-only UI work |
Extension logs (console.log/... from the extension process) land in Live's ExtensionHost.txt (macOS: ~/Library/Preferences/Ableton/Live x.x.x/). extensions-cli run --inspect attaches a debugger.
src/
extension.ts entrypoint: activate(), context-menu registration, console session loop
core/ PURE TypeScript — no SDK imports; runs in Node AND the dialog browser
types.ts snapshot, ParsedCommand, PlannedOp, Resolution, dialog protocol
tokenizer.ts quoted-string tokenizer
parser.ts deterministic grammar v0 → ParsedCommand | ParseError
resolve.ts ParsedCommand + SetSnapshot → concrete plan (ops, preview, warnings)
grammar.ts help entries (single source for help panel + docs)
capabilities.ts static capability facts for SDK 1.0.0 (audited, not runtime-detected)
colors.ts color names → 0xRRGGBB
audit.ts audit set report
cleanNames.ts clean-name suggestions (preview-only)
live/ the ONLY layer that touches @ableton-extensions/sdk
adapter.ts LiveAdapter interface + SdkLiveAdapter (snapshot building, guarded mutations)
selection.ts context-menu invocation → selection (tracks/clips/scene)
executor.ts plan → adapter calls inside withinTransaction, per-target outcomes
ui/
console.html dialog template (dark Live-style CSS, STATE/SCRIPT placeholders)
main.ts dialog app: live preview, confirm-gate, history ↑/↓, help panel
state/history.ts persisted command history (storageDirectory, best-effort JSON)
util/inlineHtml.ts safe inlining of state JSON + UI bundle into the dialog HTML
tests/ node:test suites for everything in core/, util/, and the executor
Core rule: the parser, resolver, and executor logic are testable without Ableton Live. tests/executor.test.ts runs the full execution path against an in-memory LiveAdapter.
SDK 1.0.0-beta.0 offers exactly one extension UI surface: ui.showModalDialog(url, w, h) which resolves once with a single string posted by the dialog (close_and_send). There are no persistent panels and no host→dialog messaging. So the session loop in extension.ts is:
build snapshot → open dialog (state embedded in the data: URL)
→ user types; dialog previews locally against the snapshot (zero round-trips)
→ Execute posts {action:"execute", raw} and the dialog closes
→ extension re-parses + re-resolves raw against the same snapshot, applies in one
undo step, then reopens the dialog with results + refreshed snapshot
Read-only commands (audit, clean names, help) execute inside the dialog with no round-trip; their raw text is persisted to history on the next close/execute via historyAppend.
- Preview-first: nothing mutates until Execute; >5 targets require a confirm click.
- Every op carries
expectName; the adapter re-reads the object's name and skips (with a per-target message) if it changed since the preview. - All SDK property writes are individually try/caught — one bad target never aborts the rest; failures are reported per target.
- Mutations run inside
withinTransaction→ one Live undo step per command. - Set names are rendered with
textContentonly, and state JSON / UI JS are escaped against</script>breakout (src/util/inlineHtml.ts, tested).
src/ui/main.ts→ IIFE browser bundle →src/generated/ui.bundle.js.txt(gitignored)src/extension.ts→ CJS Node bundle →dist/extension.js(the manifest entry), inliningconsole.htmland the UI bundle as text
The repo intentionally diverges from the SDK template in two places: moduleResolution: "bundler" (extensionless imports; esbuild and tsx both resolve them) and tests via Node's built-in runner (zero extra dependencies).