cli: torb parses its command line with std/cli (CLI slice 2) #124

Open
opened 2026-10-05 21:07:23 +00:00 by orion · 12 comments
Collaborator

Context

The compiler imports std/cli.

Source

Acceptance criteria

  • torb's commands on std/cli
  • Help text unchanged or better

Dependencies

  • Depends on #123 (cli: std/cli (CLI slice 1))

Notes

Adds or changes a native, syntax or a name the compiler looks up: land it in two commits (teach both forms, refresh the seed, then migrate), as CLAUDE.md "Seed and breaking changes" says.

Moved from the planning lists of the docs; the design record stays the specification.

Steps

  • 1. #492 std/cli: optional, repeatable, pass-through (landed, PR #493)
  • 2. #502 skeleton (cli/declaration.trb, parse + match parsed.path for migrated commands, old match for the rest) and check, build, run, test (landed, PR #521)
  • 3. #550 ir, manifest, parse, tokens, ast, highlight, natives (landed, PR #556)
  • 4. #568 new, init, upgrade (--version stays a special case)
  • 5. package and registry commands (add remove update install publish lock vendor audit, login logout owner yank deprecate)
  • 6. tooling commands (repl with its sandbox flags, format/canon, lint, rename, doc, docs ..., lsp, debug)
  • 7. clean-up and docs: delete cli/usage.trb, torb --help from the tree, CLI.md status, regenerated skills/; Closes #124

Steps are filed as issues just in time.

## Context The compiler imports `std/cli`. ## Source - [CLI.md slice 2](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/design/CLI.md#L51) ## Acceptance criteria - [ ] `torb`'s commands on `std/cli` - [ ] Help text unchanged or better ## Dependencies - Depends on #123 (cli: `std/cli` (CLI slice 1)) ## Notes Adds or changes a native, syntax or a name the compiler looks up: land it in two commits (teach both forms, refresh the seed, then migrate), as `CLAUDE.md` "Seed and breaking changes" says. _Moved from the planning lists of the docs; the design record stays the specification._ ## Steps - [x] 1. #492 `std/cli`: optional, repeatable, pass-through (landed, PR #493) - [x] 2. #502 skeleton (`cli/declaration.trb`, parse + `match parsed.path` for migrated commands, old `match` for the rest) and `check`, `build`, `run`, `test` (landed, PR #521) - [x] 3. #550 `ir`, `manifest`, `parse`, `tokens`, `ast`, `highlight`, `natives` (landed, PR #556) - [ ] 4. #568 `new`, `init`, `upgrade` (`--version` stays a special case) - [ ] 5. package and registry commands (`add remove update install publish lock vendor audit`, `login logout owner yank deprecate`) - [ ] 6. tooling commands (`repl` with its sandbox flags, `format`/`canon`, `lint`, `rename`, `doc`, `docs ...`, `lsp`, `debug`) - [ ] 7. clean-up and docs: delete `cli/usage.trb`, `torb --help` from the tree, CLI.md status, regenerated `skills/`; `Closes #124` Steps are filed as issues just in time.
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop), source CLI.md slice 2, not a duplicate. Touches natives or compiler lookups, so the two-commit rule applies. Depends on #123. next: waiting (dependency #123) until 2026-10-10T04:00:00Z

[loop:torbscript] intake: in scope (author orion, label loop), source CLI.md slice 2, not a duplicate. Touches natives or compiler lookups, so the two-commit rule applies. Depends on #123. next: waiting (dependency #123) until 2026-10-10T04:00:00Z
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261026 until 2026-10-26T08:00:00Z

[loop:torbscript] claim refine by session:loop-torbscript-20261026 until 2026-10-26T08:00:00Z
Author
Collaborator

[loop:torbscript] refine: #124 is an epic, split into steps; step 1 is #492 (ready), next: waiting (epic, step 1 #492 first; later steps are filed just in time)

#123 verified on main. std/cli (project.trb, src/{argument,command,error,input,lib}.trb, tests/cli.test.trb, docs/standard-library/cli.md) landed in PR #424; the newest published seed (32d880c96f) already contains it.

Seed / two-commit rule: does not apply. Importing std/cli into the compiler adds no syntax, native, driver flag or looked-up std name, and the seed compiles std from the checkout and is newer than std/cli. (CLI.md slice 2 says "needs a seed refresh"; that is no longer true, update that line in the last step.) Re-check in CI of step 2: if the seed cannot compile the import, stop and comment, do not force it.

Why a split. compiler/src/main.trb (1221 lines) dispatches ~30 commands, and the option readers sit in a dozen more files (cli/check, cli/packages 1232 lines, cli/registry 781, cli/repl, cli/test, cli/upgrade, format/command, lint/command, lint/rename-command, reference/command, documentation/command, documentation/source). One PR would blow the worker's context and review size.

Gaps of std/cli for torb (cause of step 1). Optional options without default (--output, --target, --template), repeatable options (--filter, --environment, --modules), pass-through after the first positional (torb run tool.trb --emit-c hands the flag to the program). Not covered by slice 1, so step 1 adds them.

Design decisions of the loop (internal, no owner question).

  • Use Command.parse plus one match parsed.path at the top level of main.trb, not Command.run handlers: handlers are (Input) => Void, but the commands use ? on Result and top-level Tasks (a top-level await would make the VM refuse its scheduler, see the comment at the package commands in main.trb).
  • --color stays stripped before parsing (colorArguments), --version stays a special case; exit code 2 for a wrong line stays (matches CliError handling).
  • Profile/target values become Argument instances via extend in the compiler (as CLI.md section 2 item 1 says).
  • "Help text unchanged or better": one command-tree declaration is the single source for torb --help and torb <command> --help; cli/usage.trb blocks are retired as each command moves. Existing tests that assert usage/option errors (compiler/tests/{deprecation,format,lint,registry-commands,repl}.test.trb) move with their command; error message wording may change only where the new one names command and argument.

Steps (checklist; each one PR, ~one worker; a step is filed as an issue only when it starts next; its PR says Refs #124, only the last says Closes #124).

  • 1. #492 std/cli: optional, repeatable, pass-through (std/cli + tests + docs page).
  • 2. Skeleton and the small commands: new compiler/src/cli/declaration.trb (tree: program torb, description) and main.trb switched to parse + match parsed.path for --version, check, build, run, test, ir, manifest, repl, parse, tokens, ast, highlight, natives, new, init, upgrade; the remaining commands still go through the old match (the old arms stay as a fallback after cli.parse reports unknown command, or the tree names them as pass-through so they keep their own readers). Retire their blocks in cli/usage.trb, checkOptionsOf/buildOptionsOf/runOptionsOf/testOptionsOf/newOptionsOf/initOptionsOf/upgradeOptionsOf/sandboxSettingsOf as they are replaced. Tests: argument lists per command (parsed values, help, errors) in compiler/tests/.
  • 3. Package and registry commands: add remove update install publish lock vendor audit (cli/packages.trb) and login logout owner yank deprecate (cli/registry.trb), owner add|remove|list as nested commands. Tests in compiler/tests/registry-commands.test.trb and the package tests move to argument lists.
  • 4. Tooling commands: format (+canon), lint, rename, doc, docs {check,source,index,declarations,skill,bundle,site}, lsp, debug (incl. --debuggee).
  • 5. Clean-up and docs: delete cli/usage.trb and dead option readers, torb --help generated from the tree, CLI.md status (slice 2 done, remove the seed-refresh note), docs/standard-library/cli.md cross-link, regenerated skills/, shell completion (#125) unblocked; Closes #124.

Acceptance criteria of #124 (unchanged, now by step 5): torb's commands on std/cli; help text unchanged or better (every flag/option of today's torb --help still listed, per-command --help works); wrong lines exit 2 with a message naming command and argument.

Checks per step: torb format --check on touched files, one quick test locally; tier A in forge CI via ci-wait.sh; no local bootstrap or gates.

Tokens used by this refine worker: not exposed (read-only pass: issue, std/cli, main.trb, CLI.md, seed list).

[loop:torbscript] refine: #124 is an epic, split into steps; step 1 is #492 (ready), next: waiting (epic, step 1 #492 first; later steps are filed just in time) **#123 verified on main.** `std/cli` (project.trb, src/{argument,command,error,input,lib}.trb, tests/cli.test.trb, docs/standard-library/cli.md) landed in PR #424; the newest published seed (32d880c96f15) already contains it. **Seed / two-commit rule: does not apply.** Importing `std/cli` into the compiler adds no syntax, native, driver flag or looked-up std name, and the seed compiles std from the checkout and is newer than `std/cli`. (CLI.md slice 2 says "needs a seed refresh"; that is no longer true, update that line in the last step.) Re-check in CI of step 2: if the seed cannot compile the import, stop and comment, do not force it. **Why a split.** `compiler/src/main.trb` (1221 lines) dispatches ~30 commands, and the option readers sit in a dozen more files (`cli/check`, `cli/packages` 1232 lines, `cli/registry` 781, `cli/repl`, `cli/test`, `cli/upgrade`, `format/command`, `lint/command`, `lint/rename-command`, `reference/command`, `documentation/command`, `documentation/source`). One PR would blow the worker's context and review size. **Gaps of `std/cli` for `torb` (cause of step 1).** Optional options without default (`--output`, `--target`, `--template`), repeatable options (`--filter`, `--environment`, `--modules`), pass-through after the first positional (`torb run tool.trb --emit-c` hands the flag to the program). Not covered by slice 1, so step 1 adds them. **Design decisions of the loop (internal, no owner question).** - Use `Command.parse` plus one `match parsed.path` at the top level of `main.trb`, not `Command.run` handlers: handlers are `(Input) => Void`, but the commands use `?` on `Result` and top-level `Task`s (a top-level `await` would make the VM refuse its scheduler, see the comment at the package commands in `main.trb`). - `--color` stays stripped before parsing (`colorArguments`), `--version` stays a special case; exit code 2 for a wrong line stays (matches `CliError` handling). - Profile/target values become `Argument` instances via `extend` in the compiler (as CLI.md section 2 item 1 says). - "Help text unchanged or better": one command-tree declaration is the single source for `torb --help` and `torb <command> --help`; `cli/usage.trb` blocks are retired as each command moves. Existing tests that assert usage/option errors (`compiler/tests/{deprecation,format,lint,registry-commands,repl}.test.trb`) move with their command; error message wording may change only where the new one names command and argument. **Steps (checklist; each one PR, ~one worker; a step is filed as an issue only when it starts next; its PR says `Refs #124`, only the last says `Closes #124`).** - [ ] 1. #492 `std/cli`: optional, repeatable, pass-through (std/cli + tests + docs page). - [ ] 2. Skeleton and the small commands: new `compiler/src/cli/declaration.trb` (tree: program `torb`, description) and `main.trb` switched to `parse` + `match parsed.path` for `--version`, `check`, `build`, `run`, `test`, `ir`, `manifest`, `repl`, `parse`, `tokens`, `ast`, `highlight`, `natives`, `new`, `init`, `upgrade`; the remaining commands still go through the old `match` (the old arms stay as a fallback after `cli.parse` reports unknown command, or the tree names them as pass-through so they keep their own readers). Retire their blocks in `cli/usage.trb`, `checkOptionsOf`/`buildOptionsOf`/`runOptionsOf`/`testOptionsOf`/`newOptionsOf`/`initOptionsOf`/`upgradeOptionsOf`/`sandboxSettingsOf` as they are replaced. Tests: argument lists per command (parsed values, help, errors) in `compiler/tests/`. - [ ] 3. Package and registry commands: `add remove update install publish lock vendor audit` (`cli/packages.trb`) and `login logout owner yank deprecate` (`cli/registry.trb`), `owner add|remove|list` as nested commands. Tests in `compiler/tests/registry-commands.test.trb` and the package tests move to argument lists. - [ ] 4. Tooling commands: `format` (+`canon`), `lint`, `rename`, `doc`, `docs {check,source,index,declarations,skill,bundle,site}`, `lsp`, `debug` (incl. `--debuggee`). - [ ] 5. Clean-up and docs: delete `cli/usage.trb` and dead option readers, `torb --help` generated from the tree, CLI.md status (slice 2 done, remove the seed-refresh note), `docs/standard-library/cli.md` cross-link, regenerated `skills/`, shell completion (#125) unblocked; `Closes #124`. **Acceptance criteria of #124 (unchanged, now by step 5):** `torb`'s commands on `std/cli`; help text unchanged or better (every flag/option of today's `torb --help` still listed, per-command `--help` works); wrong lines exit 2 with a message naming command and argument. Checks per step: `torb format --check` on touched files, one quick test locally; tier A in forge CI via `ci-wait.sh`; no local bootstrap or gates. Tokens used by this refine worker: not exposed (read-only pass: issue, std/cli, main.trb, CLI.md, seed list).
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261026-1044 until 2026-10-26T15:59:16Z

[loop:torbscript] claim refine by session:loop-torbscript-20261026-1044 until 2026-10-26T15:59:16Z
Author
Collaborator

[loop:torbscript] decided by the loop: the step list of the first refine comment is re-cut. Its step 2 (16 commands in one PR) is too big for one worker and review, so step 2 (#502) is the skeleton plus check, build, run, test; the old match stays as the path for every command not yet migrated (dispatch by first argument), so each step is independent and byte-identical for the rest. The small commands (old step 2) become step 3, package/registry 4, tooling 5, clean-up 6. Internal design, no owner question.

[loop:torbscript] decided by the loop: the step list of the first refine comment is re-cut. Its step 2 (16 commands in one PR) is too big for one worker and review, so step 2 (#502) is the skeleton plus `check`, `build`, `run`, `test`; the old `match` stays as the path for every command not yet migrated (dispatch by first argument), so each step is independent and byte-identical for the rest. The small commands (old step 2) become step 3, package/registry 4, tooling 5, clean-up 6. Internal design, no owner question.
Author
Collaborator

[loop:torbscript] refine: step 2 = #502 filed and ready (skeleton + check/build/run/test, no seed touch, one PR with one or two Conventional Commits, Refs #124), epic checklist updated, next: waiting (epic, step 2 = #502 ready for implement)

Duplicates: none among open issues. #492/PR #493 verified merged (0cc53412). Tokens used by this refine worker: ~45k (estimate).

[loop:torbscript] refine: step 2 = #502 filed and `ready` (skeleton + check/build/run/test, no seed touch, one PR with one or two Conventional Commits, `Refs #124`), epic checklist updated, next: waiting (epic, step 2 = #502 ready for implement) Duplicates: none among open issues. #492/PR #493 verified merged (0cc53412). Tokens used by this refine worker: ~45k (estimate).
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261028 until 2026-10-28T18:28:33Z

[loop:torbscript] claim refine by session:loop-torbscript-20261028 until 2026-10-28T18:28:33Z
Author
Collaborator

[loop:torbscript] decided by the loop: step 2 (#502) is verified done on main: PR #521 landed as da964275 (feat(cli): torb check, build, run and test parse their command line with std/cli), the landing commit's CI is green (tier A, tier B, gates, bootstrap), compiler/src/cli/declaration.trb (318 lines) holds the tree, and main.trb has the single arm [first, ...more] if declaredCommands().contains(first) with match parsed.path; every other command still goes through the old match. The epic is not complete: 20+ commands remain.

Next step cut just in time: #550 = ir, manifest, parse, tokens, ast, highlight, natives (flags and paths only, no option reader, one refuseUnknownFlag or a fixed arm each today). Why this slice and not the "small commands" list of the checklist as a whole: new, init, upgrade and repl bring newOptionsOf, initOptionsOf, upgradeOptionsOf and sandboxSettingsOf with their own tests, and #502 needed three worker rounds plus two CI fix rounds for four commands, so twelve in one PR would not fit one worker or one review. Those four become step 4, the later steps shift by one (checklist updated, step 2 ticked, #550 linked). Seed: no impact, the two-commit rule does not apply (no syntax, native, driver flag or looked-up name; the pattern and std/cli are on main). Dependencies: none open. Duplicate check: keyword search of the open issues for std/cli, declaration.trb, tokens found only #124 and #125 (shell completion, unblocked by the last step, not a duplicate). Internal design, no owner question.

[loop:torbscript] decided by the loop: step 2 (#502) is verified done on main: PR #521 landed as da964275 (`feat(cli): torb check, build, run and test parse their command line with std/cli`), the landing commit's CI is green (tier A, tier B, gates, bootstrap), `compiler/src/cli/declaration.trb` (318 lines) holds the tree, and `main.trb` has the single arm `[first, ...more] if declaredCommands().contains(first)` with `match parsed.path`; every other command still goes through the old `match`. The epic is not complete: 20+ commands remain. Next step cut just in time: #550 = `ir`, `manifest`, `parse`, `tokens`, `ast`, `highlight`, `natives` (flags and paths only, no option reader, one `refuseUnknownFlag` or a fixed arm each today). Why this slice and not the "small commands" list of the checklist as a whole: `new`, `init`, `upgrade` and `repl` bring `newOptionsOf`, `initOptionsOf`, `upgradeOptionsOf` and `sandboxSettingsOf` with their own tests, and #502 needed three worker rounds plus two CI fix rounds for four commands, so twelve in one PR would not fit one worker or one review. Those four become step 4, the later steps shift by one (checklist updated, step 2 ticked, #550 linked). Seed: no impact, the two-commit rule does not apply (no syntax, native, driver flag or looked-up name; the pattern and `std/cli` are on main). Dependencies: none open. Duplicate check: keyword search of the open issues for `std/cli`, `declaration.trb`, `tokens` found only #124 and #125 (shell completion, unblocked by the last step, not a duplicate). Internal design, no owner question.
Author
Collaborator

[loop:torbscript] refine: step 2 (#502) verified landed (da964275, CI green); step 3 = #550 filed with loop and ready (ir manifest parse tokens ast highlight natives, one PR, no seed touch), epic checklist updated, next: waiting (epic, step 3 = #550 ready for implement)

[loop:torbscript] refine: step 2 (#502) verified landed (da964275, CI green); step 3 = #550 filed with `loop` and `ready` (`ir manifest parse tokens ast highlight natives`, one PR, no seed touch), epic checklist updated, next: waiting (epic, step 3 = #550 ready for implement)
Author
Collaborator

[loop:torbscript] claim refine (next step after the landed one) by session:loop-torbscript-20261029 until 2026-10-29T08:35Z

[loop:torbscript] claim refine (next step after the landed one) by session:loop-torbscript-20261029 until 2026-10-29T08:35Z
Author
Collaborator

[loop:torbscript] decided by the loop: step 3 (#550) is verified done on main: PR #556 landed as b471d025 (after a main-CI fix round for the allocation budgets), main CI is green on 38d3edd4 which contains it, #550 is closed. declaredCommands() now lists check build run test manifest ir natives parse tokens ast highlight. The epic is not complete: new, init, upgrade, repl, the package/registry commands and the tooling commands remain.

Next step cut just in time: #568 = new, init, upgrade. repl is left out of it and moves to the tooling step: sandboxSettingsOf carries its own pattern and module validation and tests, and with new/init (shared scaffoldChoicesOf, its test group in template.test.trb) it would be the same size problem that made #502 and #550 slices. Seed: no impact, the two-commit rule does not apply. Duplicate check: keyword search of open and closed issues for upgrade and scaffold found nothing but #124 and #550. Internal design, no owner question.

[loop:torbscript] refine: step 3 (#550) verified landed (b471d025, main CI green), step 4 = #568 filed with loop and ready (new init upgrade, one PR, no seed touch), epic checklist updated (3 ticked, 4 linked, repl moved to step 6), next: ready (#568)

Tokens used by this refine worker: ~60k (estimate).

[loop:torbscript] decided by the loop: step 3 (#550) is verified done on main: PR #556 landed as b471d025 (after a main-CI fix round for the allocation budgets), `main` CI is green on 38d3edd4 which contains it, #550 is closed. `declaredCommands()` now lists `check build run test manifest ir natives parse tokens ast highlight`. The epic is not complete: `new`, `init`, `upgrade`, `repl`, the package/registry commands and the tooling commands remain. Next step cut just in time: #568 = `new`, `init`, `upgrade`. `repl` is left out of it and moves to the tooling step: `sandboxSettingsOf` carries its own pattern and module validation and tests, and with `new`/`init` (shared `scaffoldChoicesOf`, its test group in `template.test.trb`) it would be the same size problem that made #502 and #550 slices. Seed: no impact, the two-commit rule does not apply. Duplicate check: keyword search of open and closed issues for `upgrade` and `scaffold` found nothing but #124 and #550. Internal design, no owner question. [loop:torbscript] refine: step 3 (#550) verified landed (b471d025, main CI green), step 4 = #568 filed with `loop` and `ready` (`new init upgrade`, one PR, no seed touch), epic checklist updated (3 ticked, 4 linked, `repl` moved to step 6), next: ready (#568) Tokens used by this refine worker: ~60k (estimate).
Author
Collaborator

[loop:torbscript] refine: step 3 (#550) verified landed; step 4 filed just in time as #568 (labels loop, ready), decision recorded above. Claim of session:loop-torbscript-20261029 released. Worker usage: about 66k tokens (Sonnet 5.5 refine worker). next: ready (#568)

[loop:torbscript] refine: step 3 (#550) verified landed; step 4 filed just in time as https://git.torb.dev/torbscript/language/issues/568 (labels `loop`, `ready`), decision recorded above. Claim of session:loop-torbscript-20261029 released. Worker usage: about 66k tokens (Sonnet 5.5 refine worker). next: ready (#568)
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#124
No description provided.