Architecture
Architecture
repl/
├── *.go — the repl package (library): tokenizer, expansion (glob +
│ tilde), flag translation, per-command registry, pipeline
│ assembly, the REPL engine, line reader
├── yupsh/main.go — thin main: wires os I/O + afero.NewOsFs into the engine;
│ on a TTY drives it through a golang.org/x/term.Terminal
│ for history/editing, else the scanner path
├── integration_test.go — black-box tests of the compiled binary (build-tagged)
├── go.mod — module dependencies and tool gate
└── Makefile — quality gate (make check) + integration target
All behaviour lives in the repl package and is covered to 100%. main is the
single os-wiring seam.
How a line is executed
parseLinetokenizes the line, recording quoting, and splits on|.expandArgsapplies tilde then glob expansion to each command’s arguments (unquoted tokens only), against the injectedafero.Fs.- Each segment’s flags are translated against the command’s flag table to the
typed options its
cmd-*constructor expects. - The first stage selects the input source (source command, files, or stdin); later stages become filters.
- The pipeline runs via
gloo.RunContext(ctx, source, gloo.ByteWriteTo(out), …).
Adding a command
Add one entry to the map in registry.go. Most filters are a single line:
"wc": {flags: wcFlags, build: filter(func(o []any) gloo.Command[[]byte, []byte] {
return wc.Wc(o...)
}), summary: "count lines, words, and bytes"},
Declare its flags as a flagSet of boolFlag/valueFlag/numFlag entries that
map each Unix flag to the typed option, then add a behavioral case to the
integration tests if it introduces a new capability.
During local development the gloo-foo/framework and gloo-foo/cmd-* modules
are wired via replace directives to their sibling checkouts (see go.mod).