fix(cli): scaffold a project that compiles, and validate flags

`ludic new my-game` wrote `program My-Game`, so the first thing anyone did with
a new project — run it — failed with `expected '{', got '-'`. The project name
is a directory name and the identifier is Ludic source, and they do not accept
the same characters: names are now folded into a valid identifier (my-game ->
MyGame, 2048 -> Game2048, a.b.c -> ABC) and a name that cannot be a directory or
a package is refused with the rule instead of being mangled into one.

An audit of every command's flags turned up more of the same shape, all fixed:

- build/run ignored unknown options, so `--headles` silently produced a windowed
  binary, and `-o` with no path was silently dropped.
- `ludic fmt` printed the formatted text to stdout while its help said "in
  place", so it appeared to do nothing. It writes now, with --check for the
  report-only case a hook wants.
- `ludic test nosuch.ludic` deferred the error to the compiler.
- build-lib's failure messages ran `{tmp_dir()}` through the shell literally —
  an interpolation written inside a non-interpolating string — and its argument
  guess matched package.lock.ludic, then tried to compile the lockfile.
- Several messages still identified the tool as `x`.

`ludic-dev test` now scaffolds under four awkward names, builds and tests each,
and asserts a space-bearing name is refused — the case that shipped broken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-05 23:27:16 +03:00
parent b24f0dd572
commit b839304f91
6 changed files with 208 additions and 31 deletions

24
changes/cli-audit.md Normal file
View file

@ -0,0 +1,24 @@
bump: patch
type: fix
**`ludic new` scaffolded a project that would not compile.** The project name went
straight into the `program <Name>` identifier, so `ludic new my-game` wrote
`program My-Game` — a subtraction — and the first `ludic run` failed with
`expected '{', got '-'`. A name is now turned into a valid identifier
(`my-game` → `MyGame`, `2048` → `Game2048`), and a name that cannot be a
directory or a package is refused with the rule rather than mangled.
Found while auditing every command's flags and arguments, along with:
- **Unknown options are errors.** `ludic build --headles` silently built a
windowed binary; `ludic build -o` with no path silently ignored it. Both now
say what is wrong and exit non-zero.
- **`ludic fmt` formats in place**, as its help always claimed — it was printing
the file to stdout and changing nothing. `ludic fmt --check` reports drift
without writing, for a hook or CI.
- **`ludic test nosuch.ludic`** says the file does not exist instead of passing it
to the compiler.
- **`ludic build-lib`** reported failures as a shell syntax error (an
interpolation written in a non-interpolating string), and its no-argument
auto-detection picked up `package.lock.ludic` as a module to compile.
- Error messages that still began with `x:` — the CLI's old name — now say
`ludic:`.