Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,35 @@

All notable changes to dawg are recorded here. Versions follow [semantic versioning](https://semver.org); releases are published as immutable GitHub Releases with a tarball, `SHA256SUMS` and a build provenance attestation.

## Unreleased
## 0.10.0

History and comments, a preset library and an agent that works on files: every edit, comment and agent turn lands in a per-project SQLite history you can search with `/history`, `dawg history` or the agent, `/comment` pins a note to the moment, 157 presets in 17 categories pass measured loudness and peak limits and open from a browser, the agent gains file, inspect, history, audio chop and allowlisted exec tools and can dispatch subagents, dev mode credits hot reloads to the coding agent that made them, and the lyric model and machine vox let the built-in singer sing words. Plus a QWERTY play-mode keyboard, a friendlier dawg.sh with moving real screens, and fixes for PTY settling, auto-naming across windows and piano tails.

### Added

- **Lyrics you can edit (machine vox V0).** Notes and tracks can carry a `vox` field (phones, breath, consonant timing, dynamics; a track voice) with the score version unchanged. The lyric grammar adds a stored trailing `-` for word continuation, `[hh eh l]` phone overrides, `,` breaths and `/` line breaks; 0.7 lines read as before. `/lyrics 5-8 <text>` retypes a bar range without touching notes, `/lyrics reflow` re-seats words after notes move, `/note split` holds the second half (`_`) and `/note join` reports dropped syllables. `song.ts` prints and reads `vox` byte-stably (SDK 1.36.0, `vox()` helper), MIDI export writes lyric meta events, the highway draws a one-row lyric strip, `dawg history` records `lyrics` and `vox` targets, and the agent gets `inspect_vox`, `set_vox` and a ranged `set_lyrics`.
- **Machine vox.** The built-in singer can sing words: the `robot` and `speak` sing presets (and the `machine-vox` and `talk-singer` sounds) turn on `articulate`, which adds each lyric's consonants (hissed fricatives, stops with a closure and burst, hummed nasals, gliding w, y, r and l) to its vowel. A small English letter-to-sound converter, rules plus a hand-written dictionary, reads the lyric, joining `hel-lo` across notes. `dawg doctor` gains a voice section that lists the built-in voice and an installed espeak-ng. Existing projects render byte-identically: `articulate` defaults to 0.
- **Subagents.** The agent's `dispatch` tool runs up to four subagents in parallel on the same provider (the fast model by default), each confined to its own tracks, bars and files. Overlapping scopes are refused before anything runs; edits to different tracks rebase onto each other, a real clash is reported as a conflict rather than forced, and every child edit is its own `[task]`-labelled revision you can undo on its own. Esc cancels them all, and their spend joins the turn's.
- **History database.** Every project keeps `.dawg/history.db` (SQLite with full-text search), a sidecar of the session record written after each record write: edits, agent tool calls and turns, comments, media assets and dev-mode logs, each with its targets (track, instrument, param, bars). The first open imports `.dawg/sessions/*.json` and each open reconciles what the record has and the database lacks; session files are never rewritten. A failed or missing database never fails an edit, a corrupt one is moved aside and rebuilt from the records and `.dawg/comments.jsonl` (comments included), a newer schema opens read-only, and `DAWG_HISTORY=off` turns it off. Undo and redo read from the store, so they reach past the record's capped log. An abandoned timeline is marked superseded and kept, never deleted, and subagent edits are recorded as `subagent` rows under their task.
- **Comments and `/history`.** `/comment` (`/c`) pins a note, with `#tags` and `@last`, `@agent`, `@mine`, `@rev N` or `@<id>` refs, and captures the moment: pane, screen, focused track and instrument, param, selection, patch node, playhead, loop and transport. `/comments` lists them and `/history [filters]` is a picker where Enter jumps back to a row's moment (Ctrl-K › Project › session). `dawg history` filters by `--track --instrument --param --bars --kind --actor --pane --tag --grep --since --rev`, prints JSONL with `--json`, and has `show`, `comment`, `stats` and `import`; it reconciles before it lists and never creates `.dawg/`. A coding agent's edits and comments show its name (`A claude-code`).
- **Dev mode.** `dawg dev`, `dawg --dev` or `DAWG_DEV=1` runs the editor with a `dev` header word and writes `log` rows to history: sync evaluations with a summarized diff, typecheck diagnostics as `file:line`, rejected evaluations, agent tool arguments and uncaught errors, rate-limited with a `dropped N` row (errors are never dropped). Each dev pane writes its last frame for `dawg dev screen [A]`. `dawg history --follow` waits for the first session, prints a short backlog and streams without gaps or repeats, and `dawg dev --reload` restarts the editor after a source change only when a smoke import passes, restoring the terminal on a crash.
- **Attributed hot reload.** An edit applied from files is credited to dawg's agent or a subagent from its pending writes (shared across windows, `exec` edits included), else to a coding agent whose `dawg check --as <name> [--files a,b]` heartbeat (or `DAWG_ACTOR`, or `claude-code` under `CLAUDECODE=1`) matches the applied hashes, else to `external`. The card reads `applied from files · … · by <actor>`. A late heartbeat credits an earlier save only for the files it names, so your own saves are never claimed.
- **Agent file and inspect tools.** `glob`, `grep`, `move_file` (never overwrites) and `delete_file` (copies to `.dawg/trash/` first) span the project except `.dawg/`, `.git/` and `node_modules/`, with symlink escapes refused. `inspect` gives compact, paged read-only views of the score, a track, notes, mix, sections, a patch or a sample. Read roots outside the project are set by you only (`/agent read-root add|remove|list`, Ctrl-K › Project › agent › read roots), and `/agent shell on|off` is the trusted-shell switch. After a turn reads web content (or runs `yt-dlp`), code writes and the trusted shell are refused for the rest of the turn and in its subagents. Long tool descriptions moved into per-tool docs, keeping the catalog under its budget.
- **Agent comments and history.** The `comment` tool leaves a note with the window's live context, and a turn that edited without commenting leaves one `#auto` comment on its newest edit; read-only turns leave none. `history_query` reads history compactly (20 rows by default, paged) with the same filters as `dawg history`, and the agent's brief carries the playhead, loop and your newest comments.
- **Agent docs.** One docs lens built from guide `agent` blocks, a page per tool and recipes in `docs/agent/recipes/` (chop a break, stems to MIDI, fix tempo, pitch a vocal, parallel arrangement, exec, read history first, the coding-agent loop with dev mode). The agent reads it with the `docs` tool, a coding agent with `dawg docs --agent [page | --search <words> | --write]`, and `dawg init` writes `AGENTS.md` and a pointer `CLAUDE.md` when they are absent; `--write` refreshes only the marked block and refuses a file whose markers are broken.
- **Audio chop toolkit.** Onsets, tempo and beats, segments, cuts snapped to zero crossings, slice to a sampler, stretch, pitch, fades, normalize, reverse, gain, trim and loop points, in deterministic TypeScript with optional ffmpeg and rubberband backends. Three doors: the agent's `audio` tool, `/chop <op> <file>` (Ctrl-K › Project › media › chop) and `dawg media chop`. Each written file is a 24-bit WAV registered as a sample and recorded in history.
- **Allowlisted exec.** The agent's `exec` tool runs installed media CLIs by argv only, with no shell: a per-tool flag allowlist, inputs confined to the project and your read roots, outputs never in `.dawg/`, `.git/` or `node_modules/` (ffmpeg filter file writes included), refused protocol and playlist inputs, a scrubbed environment, timeouts and logs in `.dawg/logs/exec/`. It never installs anything; a missing tool returns its install command.
- **Preset library.** 157 built-in presets in 17 categories (init to chain), each with tags, a one-line description, the advanced feature it shows and four musically named knobs. Every preset is rendered over a standard phrase and held to measured limits: loudness per category (±2 LU), true peak ≤ -1 dBTP, DC, tail decay, stereo correlation and mono loss, spectral balance, aliasing, velocity response and patch cost. Knobs now reach engine nodes in offline renders.
- **Preset browser and `preset` command.** `/presets [category]` (Ctrl-K › Sound › preset library) lists categories, then presets with their knobs; moving auditions, Enter keeps, Esc reverts, typing filters, `→` finds similar and `*` stars. `preset <name> | list | find | info | similar | fav | favs | next | prev | browse` does the same from the prompt, `,` and `.` step presets in play mode, and the agent gets `preset_catalog` and `use_preset`.
- **New drum kits.** `syn606`, `syn707`, `synlinn` and `breaks`. Drum presets load a kit with a measured drum-bus patch whose four knobs are Punch, Grit or Dust, Tone and Room, held to the same loudness and peak limits as every other preset.
- **Play-mode keyboard.** The on-screen keyboard is drawn as the keys sit under your hands, two rows with a label under each key: the note on a keys track, the drum it hits on a kit. The octave, velocity, click and record keys sit beside it. The mapping is unchanged, and ASCII replaces the marks under `TERM=dumb`.
- **dawg.sh.** A friendlier home page whose real screens move again: `bun run screens` records the in-between frames of animated scenes from the real TUI, and the site plays them in place (paused offscreen, still under reduced motion). Items for unreleased features appear once the latest release includes them.

### Fixed

- **Piano tails no longer stall on subnormal numbers.** The piano body EQ's state decayed into subnormal doubles after a note ended and stayed there for the rest of the render; x86 CPUs that trap subnormals ran those silent seconds several times slower (sporadic 30 s test timeouts on CI). The state now flushes to zero below 1e-30, as the patch nodes already did; audible output is unchanged.
- **PTY tests settle on the drawn frame.** The state report used by the PTY harness could run ahead of the screen when the frame gate deferred a frame; a skipped frame now reports nothing until it is drawn. The audio, autotune and three-window tests wait for the effect, not for text that can appear first.
- **One auto-name per revision across windows.** Two windows could each auto-name the session and the older one could win. A name now lands only at the score revision it was computed from, so it always describes the newest score.

## 0.9.0

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,17 @@ and its own undo, and they share one transport (`guide panes`).
Install the release tarball from GitHub directly:

```sh
bun add -g https://github.com/hraness/dawg/releases/download/v0.9.0/hraness-dawg-0.9.0.tgz
bun add -g https://github.com/hraness/dawg/releases/download/v0.10.0/hraness-dawg-0.10.0.tgz
dawg --help
```

Each [release](https://github.com/hraness/dawg/releases) is immutable and ships the tarball, a `SHA256SUMS` file and a build provenance attestation. To check a download before installing it:

```sh
gh release download v0.9.0 --repo hraness/dawg
gh release download v0.10.0 --repo hraness/dawg
shasum -a 256 -c SHA256SUMS
gh attestation verify hraness-dawg-0.9.0.tgz --repo hraness/dawg
bun add -g "$PWD/hraness-dawg-0.9.0.tgz"
gh attestation verify hraness-dawg-0.10.0.tgz --repo hraness/dawg
bun add -g "$PWD/hraness-dawg-0.10.0.tgz"
```

dawg is also on npm as [`@hraness/dawg`](https://www.npmjs.com/package/@hraness/dawg):
Expand Down
8 changes: 4 additions & 4 deletions docs/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ authentication, from the exact Release tarball:

```sh
npm login
gh release download v0.9.0 --repo hraness/dawg
gh release download v0.10.0 --repo hraness/dawg
shasum -a 256 -c SHA256SUMS
gh attestation verify hraness-dawg-0.9.0.tgz --repo hraness/dawg
npm publish "$PWD/hraness-dawg-0.9.0.tgz" --access public
gh attestation verify hraness-dawg-0.10.0.tgz --repo hraness/dawg
npm publish "$PWD/hraness-dawg-0.10.0.tgz" --access public
npm trust github @hraness/dawg --repo hraness/dawg --file release.yml --environment npm-release --allow-publish --yes
npm trust list @hraness/dawg
```

Then rerun the failed `npm` job of the `v0.9.0` release run. It finds the same
Then rerun the failed `npm` job of the `v0.10.0` release run. It finds the same
integrity on npm and succeeds without publishing again. Every later version is
published only by the workflow's OIDC identity. Do not add a long-lived npm
token.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hraness/dawg",
"version": "0.9.0",
"version": "0.10.0",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion site/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# `bun add -g <that absolute path>`.
#
# Settings (all optional):
# DAWG_VERSION=0.9.0 install this version instead of the latest
# DAWG_VERSION=0.10.0 install this version instead of the latest
# DAWG_INSTALL_DIR=<dir> where verified tarballs are kept
# DAWG_INSTALL_BASE_URL=<url> download from <url>/hraness-dawg-<v>.tgz and
# <url>/SHA256SUMS instead of GitHub (testing;
Expand Down
Loading