Module: Toy::Core::CLI
- Defined in:
- lib/toy/core/cli.rb,
lib/toy/core/cli/new.rb,
lib/toy/core/cli/eval.rb,
lib/toy/core/cli/list.rb,
lib/toy/core/cli/fetch.rb,
lib/toy/core/cli/infer.rb,
lib/toy/core/cli/serve.rb,
lib/toy/core/cli/train.rb,
lib/toy/core/cli/install.rb,
lib/toy/core/cli/describe.rb,
lib/toy/core/cli/manifest.rb,
lib/toy/core/cli/exit_codes.rb
Defined Under Namespace
Classes: Describe, Eval, Fetch, Infer, Install, List, Manifest, New, Serve, Train
Constant Summary collapse
- COMMANDS =
Single source of truth. Each entry: the command class + a machine/human description of its surface. The manifest is generated from this; –help reads summaries from it.
{ "new" => { class: New, summary: "Scaffold a conventional toy project tree", args: [{ name: "path", required: true, desc: "target dir" }], flags: [{ name: "--lib", desc: "scaffold a library-composition project (Gemfile + experiment.rb) instead of an app" }, { name: "--force", desc: "overwrite a non-empty dir" }, { name: "--json", desc: "machine output" }] }, "list" => { class: List, summary: "Find GGUF models in caches + project data/", args: [], flags: [{ name: "--json", desc: "machine output" }] }, "describe" => { class: Describe, summary: "Read GGUF metadata, render the arch-derived Card", args: [{ name: "model", required: true, desc: "path to a .gguf file" }], flags: [{ name: "--json", desc: "machine output" }] }, "fetch" => { class: Fetch, summary: "Download a GGUF from HuggingFace into the cache + data/ symlink", args: [{ name: "hf-repo", required: true, desc: "HF repo id" }, { name: "file.gguf", required: false, desc: "GGUF filename in the repo" }], flags: [{ name: "--json", desc: "machine output" }] }, "install" => { class: Install, summary: "Build/verify the CPU backend for this project", args: [], flags: [{ name: "--json", desc: "machine output" }] }, "infer" => { class: Infer, summary: "Generate text from a GGUF model (greedy decode)", args: [{ name: "model", required: true, desc: "path to a .gguf file" }], flags: [{ name: "--prompt", desc: "prompt text (default \"Once upon a time\")" }, { name: "--prompt-ids", desc: "space-separated token IDs (tokenizer-less models; overrides --prompt)" }, { name: "--n", desc: "tokens to generate (default 16)" }, { name: "--device", desc: "cpu (default) | cuda | metal (macOS)" }, { name: "--json", desc: "machine output" }] }, "train" => { class: Train, summary: "Train a model from scratch (records runs/<id>/ + loss curve)", args: [{ name: "recipe", required: true, desc: "'from-scratch'" }], flags: [{ name: "--steps", desc: "training steps (default 5)" }, { name: "--seed", desc: "random-init seed (default 0)" }, { name: "--arch", desc: "llama (default) | gpt2 (from-scratch, CPU)" }, { name: "--device", desc: "cpu (default) | cuda | metal (macOS)" }, { name: "--out", desc: "run dir override (default runs/<id>)" }, { name: "--json", desc: "machine output" }] }, "eval" => { class: Eval, summary: "Score a GGUF model (per-token logprobs; `eval lmc` for two-checkpoint LMC)", args: [{ name: "model", required: true, desc: "path to a .gguf file" }], flags: [{ name: "--top-k", desc: "top-K logprobs to report (default 5)" }, { name: "--device", desc: "cpu (default) | cuda | metal (macOS)" }, { name: "--json", desc: "machine output" }] }, "serve" => { class: Serve, summary: "Serve a GGUF model over an OpenAI-compatible HTTP API (CPU)", args: [{ name: "model", required: true, desc: "path to a .gguf file" }], flags: [{ name: "--port", desc: "TCP port to bind (default 4567)" }, { name: "--name", desc: "model label in /v1/models (default GGUF basename)" }] } }.freeze
- GLOBAL_FLAGS =
[ { name: "--manifest", desc: "emit the machine-readable command manifest (JSON)" }, { name: "--help", desc: "show usage" }, { name: "--version", desc: "show the toy version" } ].freeze
- EXIT_OK =
0- EXIT_FAILURE =
1- EXIT_BAD_INPUT =
2
Class Method Summary collapse
Class Method Details
.print_usage(io) ⇒ Object
150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/toy/core/cli.rb', line 150 def print_usage(io) io.puts "usage: toy <command> [args] [flags]" io.puts "" io.puts "Commands:" COMMANDS.each do |cmd_name, entry| io.puts format(" %-10s %s", cmd_name, entry[:summary]) end io.puts "" io.puts "Global flags:" GLOBAL_FLAGS.each do |f| io.puts format(" %-12s %s", f[:name], f[:desc]) end end |
.run(argv) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/toy/core/cli.rb', line 117 def run(argv) argv = argv.dup # (1) Peel global flags BEFORE subcommand lookup so they work with # no subcommand (e.g. `toy --manifest`, `toy --version`). return Manifest.new([]).run if argv.include?("--manifest") if argv.include?("--version") puts "toy #{Toy::VERSION}" return EXIT_OK end if argv.empty? || argv.first == "--help" || argv.first == "-h" print_usage($stdout) return argv.empty? ? EXIT_BAD_INPUT : EXIT_OK end # (2) Shift the subcommand token. name = argv.shift # (3) Unknown subcommand → usage to stderr + bad-input. entry = COMMANDS[name] unless entry $stderr.puts "toy: unknown command #{name.inspect}" print_usage($stderr) return EXIT_BAD_INPUT end # (4) Instantiate the command with remaining argv; #run returns # an Integer exit code. Each command parses its OWN flags. entry[:class].new(argv).run rescue Interrupt EXIT_FAILURE end |