Skip to content

andrealeone/cti

Repository files navigation

concise-ti

Concise Terminal Interface is a lightweight, dependency-free, Bun-native TypeScript framework for building command-line tools. Install it as a dependency, call it once from your entrypoint, and start writing command files. The tool automatically discovers them, parses their arguments, routes to them, and renders their output.


Vision

Managing a command-line interface should feel like working with Next.js, not starting with a boilerplate kit. Install concise-ti and you're ready to go. Write an entrypoint that's one line long, drop files into a /commands directory, and you have a working, typed, compilable CLI. Everything between the argument vector and your handler is concise-ti's job, not yours.

There are no configuration files and no wiring code to handle. The framework handles all the plumbing.

                 ┌───────────────────────────┐
   argv    ───►  │   run(config, meta)       │
                 │   The only line you write │
                 └────────────┬──────────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
        Resolve route   Parse & coerce   Build context
       (commands/ tree)  (your flags)   (io, cwd, env…)
              │               │               │
              └───────────────┴───────┬───────┘
                                      ▼
                              Your command's run()
                                      │
                                      ▼
                                  Exit code

Features

  • No Boilerplate No manual imports or routing logic, just create files in the /commands directory or define your own.
  • Typed Arguments Flags and positionals are declared once and arrive in the handler function already parsed, coerced, and typed.
  • Zero-Config Auto-discover commands from the filesystem, leaving you nothing to wire up by hand.
  • Lightweight No runtime dependencies: the framework is the only thing in your node modules.
  • Bun-Optimized Lean on Bun's speed and native TypeScript.
  • Compiles to Binary Ship your CLI as a single standalone executable with bun build --compile.



Getting Started

Requires Bun 1.3 or later.

mkdir new-cli && cd new-cli

bun init -y
bun add concise-ti

You only ever touch two kinds of files: the entrypoint, written once, and command files, dropped in as your CLI grows:

new-cli/
├── main.ts      ← written once, never touched again
└── commands/
    └── fib.ts   ← app fib

Create commands/fib.ts:

import { command } from 'concise-ti'

export default command({
  meta: { description: 'Compute a Fibonacci number, or the sequence leading to it' },
  flags: {
    sequence: { type: 'boolean', short: 's', description: 'Print the whole sequence up to n' },
  },
  run(ctx) {
    const n = Number(ctx.positionals[0] ?? 10),
      sequence = ctx.flags.sequence === true,
      values = [0, 1]

    for (let i = 2; i <= n; i++) values.push(values[i - 1] + values[i - 2])

    ctx.io.write(sequence ? values.slice(0, n + 1).join(', ') : String(values[n]))
  },
})

The flags block is enough to get a typed --sequence toggle in ctx.flags. No manual parsing, no wiring it into a parser yourself.


Create main.ts:

import { run } from 'concise-ti'

void run({ name: 'new-cli', version: '1.0.0' }, import.meta)

That's the whole entrypoint, and it's the last time you'll edit it. concise-ti automatically discovers commands from the commands directory, turns fib.ts into the fib route, parses argv against its declared flags, and dispatches automatically on every run. Add a second file and app second-command exists with no further wiring. See Command Routing for how the file structure maps to commands. Prefer to list commands by hand instead of relying on the filesystem? See Manifest for the inline defineManifest alternative.


Run it:

bun run ./main.ts fib 10
# Output: 55

bun run ./main.ts fib 10 --sequence
# Output: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55

Compile it to a standalone binary:

bunx concise-ti compile ./main.ts --outfile dist/my-cli
./dist/my-cli fib 10 --sequence

A CLI built entirely with defineManifest, no commands/ directory, can compile directly with bun build --compile; concise-ti compile is only needed to make filesystem-discovered commands work inside the compiled binary. See Manifest.



Documentation

The example above is just a taste. Full docs live in /docs; pick the one below based on what you're trying to do:


About

Concise Terminal Interface Framework

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Contributors