feat(cli): mothc run + devices — the flutter-run loop - #17
Merged
Conversation
`mothc run [app.dart] [-d DEVICE]` compiles, puts the program on a device, and stays attached streaming its output. Device selection is flutter run's: -d wins (exact id or unique substring, so the /dev/cu. spelling is optional), one connected board auto-selects, no board falls back to the simulator when it is built. `mothc devices` lists both kinds; listing never probes a port, because probing resets most dev boards and "listing devices rebooted my board" is a terrible surprise. Attached keys: r recompiles and pushes — measured 37ms to a restarted program on the simulator — h help, q quit. It is named a hot RESTART throughout, because state genuinely resets; borrowing Flutter's "reload" would promise state preservation moth does not have yet. A compile error during r is shown and the session stays attached with the old program still running, exactly like flutter run. On a board the attach session owns the serial port for its whole life: restarts push through the same open port the console streams from, so there is no port contention and no reset-on-reopen between edits. The board sends each verdict three times on the shared console; a display filter strips the frames from what the user sees without eating innocent "MPH" text or frames split across reads — both pinned in run_test.dart along with the selection rules. Terminal raw mode is entered defensively: hasTerminal can report true where the mode getters throw (backgrounded shells, CI), and a session that cannot read keys still streams. Sim E2E scripted end to end: launch, stream, r -> Restarted in 37ms with fresh state, q -> clean exit. Board run pending the USB re-seat; the transport primitives it uses are the ones the serial suite pins.
SIGTERM/SIGHUP now restore the terminal (and close the port / kill the simulator child) before exiting — finally does not run on signal death, and a raw terminal is the one failure the user cannot fix with a keystroke in a session built on them. flutter run installs handlers for exactly this; now so does moth's. The display filter only strips a verdict frame whose trailing nonce is one THIS session issued — a program that print()s the literal text "MPOK" keeps all its bytes (pinned by test). And a held partial match is flushed when the wire goes quiet, so output ending on a verdict prefix is no longer withheld until bytes that may never come; the old test pinned the release-on-next-chunk path and read as though it covered this — the new one covers the quiet case explicitly. The sim path cleans its temp directory and kills the child on every exit path, not just q.
Ambiguity with a human at the keyboard becomes a numbered picker (all devices listed, sim included) instead of an error; three bad answers give up. Scripts keep the error-with-list, since they cannot answer, and an explicit -d that matches nothing stays an error — the user asked for something specific. The parse rule is pure and pinned: 1-based index, whitespace tolerated, junk/EOF/out-of-range re-prompt.
Owner
Author
|
On-board verified: attached session on /dev/cu.usbmodem21201 — pushed in 178ms, console streamed, r restarted in 172ms (inside the documented ~150ms class), q exited clean. Note the board re-enumerated on a new port number after a re-seat and discovery/auto-select handled it. |
shbmx
added a commit
that referenced
this pull request
Aug 15, 2026
162ms appeared in two sample blocks and nowhere in any measurement record — likely a transcription slip of the recorded 163. Replaced with 178ms, the number recorded publicly in PR #17's on-board verification comment, so the figure a reader meets first is one they can trace. (Timing samples stay hand-checked: unlike byte counts they are samples of a distribution, not constants a test can pin.)
shbmx
added a commit
that referenced
this pull request
Aug 15, 2026
* chore(release): publish prep for v0.1.0 Both packages are pub.dev-ready: real pubspecs (repository, issue tracker, executables: mothc), package READMEs written for their pub.dev pages, CHANGELOGs, and the MIT license in each package directory. Dry-runs pass with the only warning being the uncommitted state this commit resolves; package:moth archives at 14KB. The scaffold's no-checkout fallback flips to the hosted `moth: ^0.1.0` — the exact change the last review flagged as dangerous BEFORE publishing is what makes pub-global installs work AFTER it, which is why this branch merges at publish time and not before (RELEASING.md step 4 claims the name first). RELEASING.md records the order that matters: green suite, versions agree, dry-runs, publish moth then mothc, tag, repo public, then the stranger's sanity loop. getting-started opens with the pub-global path; the clone remains the route to the simulator and boards. Release notes for the tag live in docs/release-notes-v0.1.0.md. * docs(release): review round 1 — capability claims match what ships The moth README promised checks 'on every save'; the scaffold wires a BUILD task (Ctrl/Cmd-Shift-B), invoked manually — the wording now matches mothc's own careful latency claim. The image CHANGELOG line regains the stored-program qualifier PR 14's code comment kept. And RELEASING step 4 now states the load-bearing reason for moth-then-mothc: the scaffold writes the hosted name the moment mothc is installable. * chore(release): refresh v0.1.0 artifacts for run, devices and parity The publish prep predated three merged PRs; the package pages and release notes now describe what actually ships. mothc installs TWO names via the executables map — `moth` (the friendly entry the README now leads with: moth create, moth run) and `mothc` (every existing doc stays true). The mothc README's hero is the flutter-run loop with the measured numbers; the CHANGELOG covers run/devices/check/create/push. package:moth's CHANGELOG gains Prefs, Servo and bulk I2C. The release notes lead with `moth run`, extend the hardware story to both firmwares sharing one native set, and the honest-limits paragraph now names attachInterrupt and SPI explicitly. RELEASING's stranger loop runs `moth run` under the alias name specifically, since the alias only exists installed. Both dry-runs: 0 issues beyond the dirty state this commit resolves; 15KB and 57KB archives. * docs(release): the sample push time is a recorded one 162ms appeared in two sample blocks and nowhere in any measurement record — likely a transcription slip of the recorded 163. Replaced with 178ms, the number recorded publicly in PR #17's on-board verification comment, so the figure a reader meets first is one they can trace. (Timing samples stay hand-checked: unlike byte counts they are samples of a distribution, not constants a test can pin.) * docs(create): the scaffold teaches moth run, not the pre-run flow The first file a newcomer reads still led with make ui and bare mothc --push — both superseded by moth run as the hero flow. WiFi stays on mothc --push because run has no network target; claiming one here would be the drift the docs rules exist to prevent. * docs(readme): the clips — moth run and touch, one unedited take each Two GIFs recorded off the real S3, terminal and board camera composited live in one OBS canvas so the timing between 'pushed in 174ms' and the panel changing is genuine: the moth run loop with the device picker and an r-restart to a new color, and controls.dart tracking a finger. Captions claim only what is legible in frame — the restart figure scrolled off, so the text does not cite one. examples/ui/hello.dart is the clip's program (identical to the mothc create scaffold), committed so a cloner can moth run it directly. * docs: claim only what the clip shows; the pubspec is load-bearing Review round on the GIF commit: the caption cited a 174ms line the three-row pane never displays (board logs overwrite it within one frame) — clause dropped. 'exactly what mothc create scaffolds' softened to 'the same program' (headers differ deliberately). The scaffold README stopped calling the pubspec editor-only: outside a checkout the compiler resolves package:moth through the package config pub get writes from it, so deleting it breaks compiles. Accepted as-is: 12.2MB of clip weight per clone — front-page proof is worth it and neither published package carries it.
shbmx
added a commit
that referenced
this pull request
Aug 15, 2026
feat(cli): mothc run + devices — the flutter-run loop
shbmx
added a commit
that referenced
this pull request
Aug 15, 2026
* chore(release): publish prep for v0.1.0 Both packages are pub.dev-ready: real pubspecs (repository, issue tracker, executables: mothc), package READMEs written for their pub.dev pages, CHANGELOGs, and the MIT license in each package directory. Dry-runs pass with the only warning being the uncommitted state this commit resolves; package:moth archives at 14KB. The scaffold's no-checkout fallback flips to the hosted `moth: ^0.1.0` — the exact change the last review flagged as dangerous BEFORE publishing is what makes pub-global installs work AFTER it, which is why this branch merges at publish time and not before (RELEASING.md step 4 claims the name first). RELEASING.md records the order that matters: green suite, versions agree, dry-runs, publish moth then mothc, tag, repo public, then the stranger's sanity loop. getting-started opens with the pub-global path; the clone remains the route to the simulator and boards. Release notes for the tag live in docs/release-notes-v0.1.0.md. * docs(release): review round 1 — capability claims match what ships The moth README promised checks 'on every save'; the scaffold wires a BUILD task (Ctrl/Cmd-Shift-B), invoked manually — the wording now matches mothc's own careful latency claim. The image CHANGELOG line regains the stored-program qualifier PR 14's code comment kept. And RELEASING step 4 now states the load-bearing reason for moth-then-mothc: the scaffold writes the hosted name the moment mothc is installable. * chore(release): refresh v0.1.0 artifacts for run, devices and parity The publish prep predated three merged PRs; the package pages and release notes now describe what actually ships. mothc installs TWO names via the executables map — `moth` (the friendly entry the README now leads with: moth create, moth run) and `mothc` (every existing doc stays true). The mothc README's hero is the flutter-run loop with the measured numbers; the CHANGELOG covers run/devices/check/create/push. package:moth's CHANGELOG gains Prefs, Servo and bulk I2C. The release notes lead with `moth run`, extend the hardware story to both firmwares sharing one native set, and the honest-limits paragraph now names attachInterrupt and SPI explicitly. RELEASING's stranger loop runs `moth run` under the alias name specifically, since the alias only exists installed. Both dry-runs: 0 issues beyond the dirty state this commit resolves; 15KB and 57KB archives. * docs(release): the sample push time is a recorded one 162ms appeared in two sample blocks and nowhere in any measurement record — likely a transcription slip of the recorded 163. Replaced with 178ms, the number recorded publicly in PR #17's on-board verification comment, so the figure a reader meets first is one they can trace. (Timing samples stay hand-checked: unlike byte counts they are samples of a distribution, not constants a test can pin.) * docs(create): the scaffold teaches moth run, not the pre-run flow The first file a newcomer reads still led with make ui and bare mothc --push — both superseded by moth run as the hero flow. WiFi stays on mothc --push because run has no network target; claiming one here would be the drift the docs rules exist to prevent. * docs(readme): the clips — moth run and touch, one unedited take each Two GIFs recorded off the real S3, terminal and board camera composited live in one OBS canvas so the timing between 'pushed in 174ms' and the panel changing is genuine: the moth run loop with the device picker and an r-restart to a new color, and controls.dart tracking a finger. Captions claim only what is legible in frame — the restart figure scrolled off, so the text does not cite one. examples/ui/hello.dart is the clip's program (identical to the mothc create scaffold), committed so a cloner can moth run it directly. * docs: claim only what the clip shows; the pubspec is load-bearing Review round on the GIF commit: the caption cited a 174ms line the three-row pane never displays (board logs overwrite it within one frame) — clause dropped. 'exactly what mothc create scaffolds' softened to 'the same program' (headers differ deliberately). The scaffold README stopped calling the pubspec editor-only: outside a checkout the compiler resolves package:moth through the package config pub get writes from it, so deleting it breaks compiles. Accepted as-is: 12.2MB of clip weight per clone — front-page proof is worth it and neither published package carries it.
shbmx
added a commit
that referenced
this pull request
Aug 15, 2026
feat(cli): mothc run + devices — the flutter-run loop
shbmx
added a commit
that referenced
this pull request
Aug 15, 2026
* chore(release): publish prep for v0.1.0 Both packages are pub.dev-ready: real pubspecs (repository, issue tracker, executables: mothc), package READMEs written for their pub.dev pages, CHANGELOGs, and the MIT license in each package directory. Dry-runs pass with the only warning being the uncommitted state this commit resolves; package:moth archives at 14KB. The scaffold's no-checkout fallback flips to the hosted `moth: ^0.1.0` — the exact change the last review flagged as dangerous BEFORE publishing is what makes pub-global installs work AFTER it, which is why this branch merges at publish time and not before (RELEASING.md step 4 claims the name first). RELEASING.md records the order that matters: green suite, versions agree, dry-runs, publish moth then mothc, tag, repo public, then the stranger's sanity loop. getting-started opens with the pub-global path; the clone remains the route to the simulator and boards. Release notes for the tag live in docs/release-notes-v0.1.0.md. * docs(release): review round 1 — capability claims match what ships The moth README promised checks 'on every save'; the scaffold wires a BUILD task (Ctrl/Cmd-Shift-B), invoked manually — the wording now matches mothc's own careful latency claim. The image CHANGELOG line regains the stored-program qualifier PR 14's code comment kept. And RELEASING step 4 now states the load-bearing reason for moth-then-mothc: the scaffold writes the hosted name the moment mothc is installable. * chore(release): refresh v0.1.0 artifacts for run, devices and parity The publish prep predated three merged PRs; the package pages and release notes now describe what actually ships. mothc installs TWO names via the executables map — `moth` (the friendly entry the README now leads with: moth create, moth run) and `mothc` (every existing doc stays true). The mothc README's hero is the flutter-run loop with the measured numbers; the CHANGELOG covers run/devices/check/create/push. package:moth's CHANGELOG gains Prefs, Servo and bulk I2C. The release notes lead with `moth run`, extend the hardware story to both firmwares sharing one native set, and the honest-limits paragraph now names attachInterrupt and SPI explicitly. RELEASING's stranger loop runs `moth run` under the alias name specifically, since the alias only exists installed. Both dry-runs: 0 issues beyond the dirty state this commit resolves; 15KB and 57KB archives. * docs(release): the sample push time is a recorded one 162ms appeared in two sample blocks and nowhere in any measurement record — likely a transcription slip of the recorded 163. Replaced with 178ms, the number recorded publicly in PR #17's on-board verification comment, so the figure a reader meets first is one they can trace. (Timing samples stay hand-checked: unlike byte counts they are samples of a distribution, not constants a test can pin.) * docs(create): the scaffold teaches moth run, not the pre-run flow The first file a newcomer reads still led with make ui and bare mothc --push — both superseded by moth run as the hero flow. WiFi stays on mothc --push because run has no network target; claiming one here would be the drift the docs rules exist to prevent. * docs(readme): the clips — moth run and touch, one unedited take each Two GIFs recorded off the real S3, terminal and board camera composited live in one OBS canvas so the timing between 'pushed in 174ms' and the panel changing is genuine: the moth run loop with the device picker and an r-restart to a new color, and controls.dart tracking a finger. Captions claim only what is legible in frame — the restart figure scrolled off, so the text does not cite one. examples/ui/hello.dart is the clip's program (identical to the mothc create scaffold), committed so a cloner can moth run it directly. * docs: claim only what the clip shows; the pubspec is load-bearing Review round on the GIF commit: the caption cited a 174ms line the three-row pane never displays (board logs overwrite it within one frame) — clause dropped. 'exactly what mothc create scaffolds' softened to 'the same program' (headers differ deliberately). The scaffold README stopped calling the pubspec editor-only: outside a checkout the compiler resolves package:moth through the package config pub get writes from it, so deleting it breaks compiles. Accepted as-is: 12.2MB of clip weight per clone — front-page proof is worth it and neither published package carries it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mothc run [app.dart] [-d DEVICE]— compile, deploy, stay attached: program output streams,r= hot restart (recompile + push; 37ms measured on the sim, ~150ms expected on serial),hhelp,qquit. Compile errors duringrkeep the session alive with the old program running.mothc devices— boards (serial candidates, never probed: probing resets boards) + the simulator when built.-dexact-or-unique-substring; one board auto-selects; simulator fallback; ambiguity refuses with the list.Test plan