cli-upkaran (Upkaran meaning "Tools" or "Instruments" in Hindi) is a modular and extensible command-line interface designed to streamline development workflows. It provides a core foundation and allows extending its capabilities through a simple plugin system.
Built with TypeScript and using pnpm workspaces for monorepo management.
The cli-upkaran toolkit follows a modular architecture designed for extensibility. The core platform loads pluggable tools (commands) based on a user-managed registry, and these tools can leverage shared supporting libraries like data preparation components.
graph TD
A["User @ Terminal"] --> B["cli-upkaran CLI (cli-upkaran)"];
subgraph "Core Infrastructure"
direction LR
B -- Manages --> Reg["Plugin Registry<br/>(~/.config/...)"];
B -- Uses --> Core["Core Engine<br/>(@cli-upkaran/core)"];
Core -- Reads --> Reg;
Core -- Loads Plugins --> Loader["Plugin Loader"];
end
subgraph "Type 1: Command Plugins (Loaded by Core)"
CmdDigest["`@cli-upkaran/digest`"];
CmdFetch["`@cli-upkaran/fetch`"];
CmdCustom["Your Custom Command Plugin"];
CmdCommunity["Community Plugin Example"];
Loader -- Imports 'registerCommands' from --> CmdDigest;
Loader -- Imports 'registerCommands' from --> CmdFetch;
Loader -- Imports 'registerCommands' from --> CmdCustom;
Loader -- Imports 'registerCommands' from --> CmdCommunity;
end
subgraph "Supporting Libraries"
DataPrep["@cli-upkaran/dataprep-core"];
AdapterFS["Filesystem Adapter"];
AdapterWeb["Website Adapter"];
TransformerX["Custom Transformer"];
LibOther["Other Utility Library"];
%% Show DataPrep providing interfaces/structure
DataPrep -.-> AdapterFS;
DataPrep -.-> AdapterWeb;
DataPrep -.-> TransformerX;
end
%% Show CLI dispatching to loaded command plugins
B -- Dispatches To --> CmdDigest;
B -- Dispatches To --> CmdFetch;
B -- Dispatches To --> CmdCustom;
B -- Dispatches To --> CmdCommunity;
%% Show Command Plugins using Supporting Libraries
CmdDigest -- Imports/Uses --> DataPrep;
CmdDigest -- Imports/Uses --> AdapterFS;
CmdFetch -- Imports/Uses --> DataPrep;
CmdFetch -- Imports/Uses --> AdapterWeb;
%% Example: Custom command using DataPrep core
CmdCustom -- Imports/Uses --> DataPrep;
%% Example: Custom command using a custom transformer
CmdCustom -- Imports/Uses --> TransformerX;
%% Example: Community plugin using another utility library
CmdCommunity -- Imports/Uses --> LibOther;
%% Styling Definitions
classDef core fill:#def,stroke:#333;
class Core,Loader,DataPrep core;
classDef cli fill:#dde,stroke:#333;
class B,Reg cli;
classDef plugin fill:#fdf,stroke:#969,stroke-width:2px;
class CmdDigest,CmdFetch,CmdCustom,CmdCommunity plugin;
classDef support fill:#edf,stroke:#696,stroke-width:1px;
class AdapterFS,AdapterWeb,TransformerX,LibOther support;
Key Extension Points:
- Command Plugins: The primary way to add functionality. Create separate npm packages exporting a
registerCommandsfunction. Users install these via thecli-upkaran plugins addcommand, adding them to the registry for the core engine to load. - Supporting Libraries (e.g., Data Prep): For more complex tasks, command plugins can import and use shared libraries like
@cli-upkaran/dataprep-core. You can create and publish new adapters or transformers for the data prep system, which command plugins can then depend on.
- Modular Architecture: Core functionality is kept separate from command implementations, which reside in distinct packages.
- Extensible via Plugins: Easily add new commands by installing or creating plugin packages.
- Central Plugin Registry: Manage installed plugins effortlessly using built-in commands (
plugins list,add,remove,cleanup). Plugins are stored locally in~/.config/cli-upkaran/plugins.json. - Robust Plugin Loading: Automatically loads registered plugins on startup, handling resolution errors gracefully (tries name then path, skips broken plugins).
- Automatic Plugin Installation: The
plugins addcommand can validate, prompt, and install missing plugins from npm using the--installflag. - Namespace Resolution: Prevents command name collisions between plugins by using qualified names (
<packageName>:<commandName>). - Interactive Mode (Optional): Provides an interactive prompt for discovering and running commands if no specific command is provided on the command line (if implemented).
- Global Options: Control verbosity (
--verbose) and color output (--no-color). Override loaded plugins (--plugin). - Automated Versioning & Releases: Uses Changesets and GitHub Actions for automated version bumping, changelog generation, and publishing (including pre-releases).
Prerequisites:
- Node.js (v20 or higher recommended)
- pnpm (v9 or higher recommended)
Install the main CLI package globally using npm (or pnpm):
# Using npm
npm install -g cli-upkaran
# OR Using pnpm
pnpm add -g cli-upkaran(Note: Verify cli-upkaran is the correct published package name if it differs.)
This will make the cli-upkaran command available in your terminal.
When working within the monorepo, use pnpm exec from the root directory to run your local development version:
pnpm exec cli-upkaran <command> [options...]
# Example:
pnpm exec cli-upkaran plugins listAlternatively, add a script to the root package.json:
// package.json
"scripts": {
// ...
"cli": "cli-upkaran"
}And run via:
pnpm run cli <command> [options...]Once installed globally, you can run commands directly:
# Run a command from a specific plugin package
cli-upkaran @cli-upkaran/fetch:fetch --help
# Run a command from another registered plugin
cli-upkaran some-other-plugin:do-thing --input data.jsonThese options can be used with any command:
--verbose: Enable detailed logging output for debugging.--no-color: Disable colored output in the terminal.--plugin <path_or_name>: Load only the specified plugin(s) for this execution, overriding the registry. Can be specified multiple times. Useful for testing local plugins. If the plugin isn't installed, you'll be prompted to install it (checks npm).
cli-upkaran uses a central registry (~/.config/cli-upkaran/plugins.json) to keep track of your installed plugins. Manage this registry using the cli-upkaran plugins commands.
1. Listing Registered Plugins:
cli-upkaran plugins list
# Alias: cli-upkaran plugins ls2. Adding / Registering a Plugin:
# Add a plugin by package name (checks if installed first)
cli-upkaran plugins add <plugin-package-name>
# Add a specific version/tag (checks if installed first)
cli-upkaran plugins add <plugin-package-name>@<version_or_tag>
# Add and attempt to install if not found (prompts if available on npm)
cli-upkaran plugins add <plugin-package-name>[@version] --install
# Add a plugin from a local path (useful for development)
cli-upkaran plugins add /path/to/my/local-plugin- The
addcommand validates the input. - It tries to resolve the plugin locally first.
- If not found and
--installis used, it checks npm, prompts for confirmation, installs globally, then registers. - The registry stores the name you provided and the successfully resolved absolute path.
3. Removing / Unregistering a Plugin:
cli-upkaran plugins remove <plugin-package-name>
# Alias: cli-upkaran plugins rm <plugin-package-name>- Removes the plugin entry from the registry file.
- Does not uninstall the package from your system.
4. Cleaning Up Broken Plugins:
cli-upkaran plugins cleanup- Checks if all registered plugins can still be resolved (by name or stored path).
- Lists any plugins that cannot be found.
- Prompts for confirmation before removing the broken entries from the registry.
Create your own commands by building a Node.js package that exports a registration function.
-
Create Package: Standard Node.js package setup.
-
Add Core Dependency: Add
@cli-upkaran/coreas a dependency. -
Implement Commands: Define command logic and create definitions using the
CommandDefinitioninterface (name,description,aliases?,configure?,handler). -
Export
registerCommands: Your package's main entry point must exportregisterCommands: RegisterCommandsFn. This function returns aCommandPluginobject (or an array of them).// Example plugin index.ts import type { Command } from 'commander'; import type { CommandDefinition, CommandPlugin, RegisterCommandsFn } from '@cli-upkaran/core'; const myHandler = async (options: any, command: Command): Promise<void> => { /* ... */ }; const myCommandDef: CommandDefinition = { name: 'my-command', description: 'Does something amazing', handler: myHandler, }; export const registerCommands: RegisterCommandsFn = () => { return { type: 'command', commands: [myCommandDef], }; };
-
Testing Locally:
- Use the
--pluginflag with a relative or absolute path:# From monorepo root pnpm exec cli-upkaran --plugin ./packages/my-local-plugin --verbose my-local-plugin:my-command
- Or, register the local path using
plugins add:pnpm exec cli-upkaran plugins add ./packages/my-local-plugin pnpm exec cli-upkaran my-local-plugin:my-command
- Use the
Refer to existing packages like @cli-upkaran/digest or @cli-upkaran/command-fetch for concrete examples.
This project uses Changesets for version management and changelog generation, integrated with GitHub Actions for automation.
- Developers: Use
pnpm changesetafter making changes to document the intent for version bumps and provide changelog summaries. - Automation: Merging PRs with changesets into
maintriggers workflows that version packages, update changelogs, publish to npm, and create Git tags. - Pre-Releases: Supports
alpha/beta/rcworkflows viapnpm changeset pre enter/exit.
For detailed steps on the release workflow (including pre-releases), please see:
➡️ Release Workflow Documentation
Contributions are welcome! Please refer to the CONTRIBUTING.md file (if it exists) for guidelines on how to contribute, report issues, and set up your development environment.
This project is licensed under the MIT License.