Welcome to the Effort project tutorial! In this series, we are going to build a CLI (Command Line Interface) feature that allows users to control how "hard" an AI model thinks before answering.
Imagine you are building a massive CLI tool that has 50 different commands.
If the application loaded the code for all 50 commands every time you started it, the program would be slow and sluggish. It would be like a restaurant chef cooking every single item on the menu before you even sat down to order!
Command Module Registration solves this. It acts like a Menu. It lists what is available (the command name) and a brief description, but it doesn't do the "heavy lifting" (loading the actual logic) until the user specifically asks for it.
We want to create a command that looks like this:
my-cli effort high
To make this work, we need a small file that tells the CLI:
effort."low, high, or auto."The registration file is a lightweight "ID Card" for your feature. Here are the key parts:
effort).
Let's look at the file index.ts. We will break it down into small, manageable pieces.
First, we export a default object. We use satisfies Command to make sure we don't forget any required information. This is like filling out a formβTypeScript will yell at us if we leave a box blank.
import type { Command } from '../../commands.js'
export default {
type: 'local-jsx', // Defines the rendering engine
name: 'effort', // The command the user types
// ... more settings below
} satisfies Command
Command. The type: 'local-jsx' tells the CLI that we will eventually draw the interface using React (we'll cover that in React-based Command Lifecycle).Next, we tell the user what this command does and what arguments it accepts.
// Inside the object...
description: 'Set effort level for model usage',
// Shows the user what options are available
argumentHint: '[low|medium|high|max|auto]',
my-cli help, they will see this description. The argumentHint is a visual cue telling them they can type effort low or effort max.
This is the most important part for performance. We define a load function.
// ...
// This function is ONLY called if the user types "effort"
load: () => import('./effort.js'),
} satisfies Command
() => import(...). This means we do not read the file ./effort.js right now. We wait until the CLI specifically asks for it. This keeps the application startup fast.Sometimes, we need to decide if the command runs immediately or waits for user interaction.
import { shouldInferenceConfigCommandBeImmediate } from '../../utils/immediateCommand.js'
// ... inside the object
get immediate() {
// Returns true/false based on system state
return shouldInferenceConfigCommandBeImmediate()
},
What happens when you actually run the program? Let's visualize the flow.
This diagram shows how the CLI uses the Registration module to find and run your command.
index.ts files. It reads the Name and Description, but it ignores the load function for now.effort, the CLI looks through its list of names. It finds a match in our registration file.effort, it executes the load() function.load() function imports ./effort.js. This file contains the actual React logic and controllers.
The file ./effort.js (which we just loaded) is where the real magic happens. This leads us directly into the next concepts, specifically the React-based Command Lifecycle where we draw the UI, and the Effort Level Controller which handles the logic.
You have successfully created the "Entry Point" for your feature!
effort).low, high, etc.).Currently, our command is registered, but we haven't defined how it behaves once it runs. For that, we need to look at the implementation file we just pointed to.
Next Chapter: React-based Command Lifecycle
Generated by Code IQ