Welcome to the third chapter of the Plugins project!
In the previous chapter, Plugin Namespacing, we learned how to give every plugin a unique ID (like git-helper@builtin) so we never confuse official features with community ones.
Now we face a new question: Is the plugin actually running?
Imagine you have a lamp.
Just because you bought a bulb (registered a plugin) doesn't mean the room is lit. You need to know the state of the switch.
This chapter explains how we convert a static definition into a LoadedPluginβan object that tells the system if a feature is ready to use.
We ship a git-helper plugin.
To calculate this state, we look at three inputs:
isAvailable): Does the computer actually support this? (e.g., You can't use the bluetooth plugin if your computer has no Bluetooth chip).true or false in their config file?LoadedPlugin Object
The result of this calculation is an interface called LoadedPlugin. This is the "live" version of the plugin used by the app.
Unlike the static definition (which just describes the code), the LoadedPlugin contains the state.
// A simplified look at the result
interface LoadedPlugin {
name: string
source: string // e.g., 'git-helper@builtin'
enabled: boolean // <--- The most important part!
// ... other details
}
How does the system calculate that enabled boolean? It acts like a logic gate.
When the application asks "What plugins do I have?", the system runs a specific sequence:
git-helper@builtin) in the user's settings file.
Let's look at the real logic inside builtinPlugins.ts. We will break the getBuiltinPlugins function into small pieces.
First, we check if the plugin is even allowed to run on this computer.
// inside getBuiltinPlugins()...
for (const [name, definition] of BUILTIN_PLUGINS) {
// If the plugin has a hardware check and fails it...
if (definition.isAvailable && !definition.isAvailable()) {
continue // Skip it entirely!
}
// ... proceed to settings check
}
Explanation: Some plugins might define an isAvailable() function. If this returns false (e.g., "This is a Windows plugin but you are on Mac"), we skip the plugin immediately.
We need to see what the user wants. We use a helper to get the persistent settings.
import { getSettings_DEPRECATED } from '../utils/settings/settings.js'
// ... inside the loop
const settings = getSettings_DEPRECATED()
// Recall from Chapter 2: We use the unique ID!
const pluginId = `${name}@builtin`
const userSetting = settings?.enabledPlugins?.[pluginId]
Explanation: We retrieve the value stored under the unique ID. userSetting will be true, false, or undefined (if the user has never touched the switch).
This is the core logic that resolves conflicts.
// Logic: User preference > Plugin default > true
const isEnabled =
userSetting !== undefined
? userSetting === true
: (definition.defaultEnabled ?? true)
Explanation:
userSetting defined?"defaultEnabled.true (Enabled).
Finally, we bundle this decision into the LoadedPlugin object.
const plugin: LoadedPlugin = {
name,
source: pluginId,
enabled: isEnabled, // The result of our logic
isBuiltin: true,
// ... passing through hooks and skills
}
The function returns two arrays so the UI knows how to display them.
if (isEnabled) {
enabled.push(plugin)
} else {
disabled.push(plugin)
}
return { enabled, disabled }
Explanation: The UI receives { enabled: [...], disabled: [...] }. It can now show active tools in green and inactive ones in gray.
In this chapter, we learned:
LoadedPlugin abstraction represents this final state.At this point, we have a list of enabled plugins. These plugins contain "skills" (functions code can run). But the CLI doesn't speak "Skill"βit speaks "Command."
In the next chapter, we will see how we translate these raw skills into commands the CLI can execute.
Next Chapter: Skill-to-Command Adaptation
Generated by Code IQ