Skip to content

Parse CLI arguments with effect/unstable/cli #33

Description

@FreshlyBrewedCode

Parent

#32

What to build

factory parses its own arguments with effect/unstable/cli instead of four hand-rolled parsers.
Every existing command keeps its current surface — init, serve, start, runs, log, run,
with the same flags, the same defaults, the same exit codes and the same $FACTORY_URL fallback —
but help text is generated rather than hand-maintained, flag values are validated before they reach
a command body, and the argv layer becomes testable.

Today's parsers disagree with each other in ways that are defects, not style: parseFlags walks
argv at stride 2 and so structurally cannot represent a boolean flag (one --watch and every
subsequent pair is misread), which is why factory start needed a second, different parser;
init's flags are parsed inline in the import.meta.main block; and serve passes an unvalidated
Number(portRaw) straight to Bun.serve, so --port abc becomes NaN. Because usageError
calls process.exit inside a parser, none of this can be tested, and every current CLI test
bypasses argv and calls the command functions with structured options.

The command bodies themselves stay as they are — plain async functions — wrapped at the boundary.
This ticket does not change what any command does.

See ADR 0009 §5 (docs/adr/0009-imperative-workflows-effect-boundary.md) for why the CLI is the
one place the boundary moves first.

Acceptance criteria

  • Every command and flag documented in the current USAGE string works identically, including --watch, $FACTORY_URL, and the --clone/--git-name/--git-email group
  • --port and any other numeric flag reject a non-numeric value with a clear error instead of passing NaN downstream
  • Help output is generated by the CLI definition; the hand-maintained USAGE constant is gone
  • Exit codes are unchanged: 0 completed, 1 failed, 130 cancelled
  • Argv parsing is covered by tests that feed argv directly, rather than bypassing it
  • No process.exit call remains inside a parsing function
  • bun run check passes

Blocked by

None (can start immediately).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    taskA single self-contained piece of work that ships as one PR

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions