Welcome to the first chapter of our journey into the Plugin system!
Before we dive into how plugins are discovered, verified, or installed deep in the system, we need to understand how the user actually talks to the tool.
Imagine you are building a car. You have a powerful engine (the logic) that can drive wheels, switch gears, and burn fuel. However, you can't ask the driver to reach into the hood and pull wires to accelerate. You need a steering wheel and a dashboard.
In our project, the CLI Command Interface is that dashboard.
The Central Use Case: A user types the following command in their terminal:
tengu plugin install my-cool-plugin
We need a specific layer of code to:
โ Success or โ Error).To solve this, we split our code into two parts. This chapter covers the Presentation Layer.
0 (success) or 1 (error).
Let's look at how we implement the install command. We use a function called installPlugin.
Here is how you would use it (conceptually):
import { installPlugin } from './pluginCliCommands.js'
// The user wants to install 'my-plugin' globally ('user' scope)
await installPlugin('my-plugin', 'user')
// Note: You don't need to handle what happens next.
// This function will exit the process automatically!
This function is designed to be the "end of the line" for the CLI execution.
When installPlugin is called, it orchestrates a conversation between the user, the core logic, and the analytics system.
Here is the flow of a successful operation:
Let's look at the actual code in pluginCliCommands.ts. We will break the installPlugin function down into small, manageable pieces.
First, we tell the user what we are doing, and then we ask the "Core" to do the heavy lifting.
export async function installPlugin(
plugin: string,
scope: InstallableScope = 'user',
): Promise<void> {
try {
console.log(`Installing plugin "${plugin}"...`)
// We delegate the hard work to the Core Operations layer
const result = await installPluginOp(plugin, scope)
if (!result.success) {
throw new Error(result.message)
}
Explanation:
console.log to give immediate feedback.installPluginOp is the "engine." You will learn about how that works in Core Plugin Operations.If the engine did its job, we celebrate and take notes.
// Print a nice checkmark figure
console.log(`${figures.tick} ${result.message}`)
// Log the event for analytics
logEvent('tengu_plugin_installed_cli', {
_PROTO_plugin_name: parsePluginIdentifier(result.pluginId || plugin).name,
scope: result.scope || scope,
install_source: 'cli-explicit',
// ... other metadata fields
})
// Exit the program successfully
process.exit(0)
Explanation:
figures.tick prints a green checkmark (โ).logEvent sends data to our dashboard so we know which plugins are popular.process.exit(0) stops the Node.js program. 0 tells the terminal "Everything went okay."
But what if something goes wrong? The catch block handles it politely.
} catch (error) {
// This helper function handles logging the error and exiting with code 1
handlePluginCommandError(error, 'install', plugin)
}
}
Explanation:
handlePluginCommandError, a shared utility that prints a nice "โ Failed to install..." message and exits with code 1 (failure).The CLI Command Interface acts as the polite front desk of our plugin system.
console.log) and outputs (process.exit).
Now that we know how to call the commands, we need to understand what exactly we are installing. How does the system know the difference between a plugin name like my-plugin and a complex ID?
Find out in the next chapter: Plugin Identification & Discovery
Generated by Code IQ