Visual primitives
Compose boxes, tables, spinners, progress, links, trees, and diffs with the same output system.
Visual primitives are small on purpose. Some return strings for composition. Others print directly through the shared output system.
Primitive overview
Prop
Type
Box and table
Use cli.table() when you want aligned text, then pass that string into
cli.box() when you want framing.
await cli.run(async () => {
const summary = cli.table(
["Field", "Value"],
[
["project", "oscli"],
["teamSize", 3],
["approved", true],
],
);
cli.box({
title: "Summary",
content: summary,
});
}); ┌─ Summary ───────────────┐
│ Field Value │
│ ───────────────── │
│ project oscli │
│ teamSize 3 │
│ approved true │
└─────────────────────────┘Spinner
Use cli.spin() around one async operation.
await cli.run(async () => {
await cli.spin("Installing packages", async () => {
await new Promise((resolve) => setTimeout(resolve, 300));
});
}); ⠸ Installing packages... 0.2s
✓ Installed packages 0.3sIf you do not pass doneLabel, oscli tries to convert common gerunds to a
past-tense completion label.
Progress
Use cli.progress() when your work already has named steps.
await cli.run(async () => {
const steps = ["Validate", "Build", "Finalize"] as const;
await cli.progress("Running steps", steps, async (step) => {
if (step === "Validate") {
await new Promise((resolve) => setTimeout(resolve, 150));
}
if (step === "Build") {
await new Promise((resolve) => setTimeout(resolve, 150));
}
if (step === "Finalize") {
await new Promise((resolve) => setTimeout(resolve, 150));
}
});
}); ⠸ Running steps [######--------------] [00:01] 33%
✓ Running steps [####################] [00:03] 100%Divider and link
Use dividers for section boundaries and links for docs or support URLs.
await cli.run(async () => {
cli.divider("Results");
cli.link("oscli docs", "https://github.com/aidankmcalister/oscli");
}); ───────────────── Results ────────────────
oscli docs (https://github.com/aidankmcalister/oscli)Tree
Use cli.tree() when you want to render directory-style output inside another
primitive.
export const structure = cli.tree({
src: {
"index.ts": null,
"client.ts": null,
},
"package.json": null,
});
cli.box({
title: "Project",
content: structure,
}); ┌─ Project ───────────────┐
│ ├─ src │
│ │ ├─ index.ts │
│ │ └─ client.ts │
│ └─ package.json │
└────────────────────────┘Diff
Use cli.diff() when you want to show a text change without pulling in an
external diff library.
await cli.run(async () => {
cli.diff("hello\nworld", "hello\noscli");
}); hello
- world
+ osclicli.table() and cli.tree() return strings. cli.box(), cli.diff(),
cli.divider(), and cli.link() print immediately.