npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xubill/xx-cli

v2.0.0

Published

个人工具集

Readme

xx-cli

个人开发工具集,支持插件系统,提供常用开发工具功能。

安装与使用

# 全局安装 xx-cli
npm i @xubill/xx-cli -g

# 添加插件
xx p add xxxx.js

# 使用命令
xx <command> [options]

版本记录

v1.0.0

  • 初始化项目,搭建基本框架
  • 实现插件系统核心功能
  • 添加基础命令(help, version, history)
  • 修复原生插件和用户插件区别
  • 壳功能移动到原生插件目录

v2.0.0

  • 支持新格式命令注册,兼容旧格式插件
  • 更新插件创建模板,采用配置对象格式并包含类结构实现

框架自带命令

xx-cli 框架自带以下核心命令(位于 core 模块中):

基础命令

| 命令 | 别名 | 描述 | |------|------|------| | help | - | 显示帮助信息 | | version | v | 显示版本信息 | | history | h | 查看命令历史记录 |

插件管理命令

| 命令 | 别名 | 描述 | |------|------|------| | plugin list | p ls | 列出所有插件 | | plugin enable <plugin> | p en <plugin> | 启用插件 | | plugin disable <plugin> | p dis <plugin> | 禁用插件 | | plugin add <url> | p add <url> | 添加外部自定义插件 | | plugin remove <plugin> | p rm <plugin> | 删除指定插件 | | plugin create <name> | p cr <name> | 创建指定名称的插件模板 | | plugin config <plugin> [key] [value] | p c <plugin> [key] [value] | 查看和设置插件配置 |

配置管理命令

| 命令 | 别名 | 描述 | |------|------|------| | config-manager export [target] | conf export [target] | 导出所有插件配置到指定目录 | | config-manager import [source] | conf import [source] | 从指定目录导入配置并覆盖 | | config-manager list | conf list | 列出所有插件的配置文件位置和状态 |

项目结构

xx-cli 项目采用模块化设计,主要包含以下核心目录:

核心模块目录 (/Users/xub/xx-cli/lib/core)

核心模块目录包含 xx-cli 的核心功能实现,负责初始化系统、注册命令、管理插件等。

文件结构

lib/core/
  ├── index.js         # 核心模块,负责初始化系统、注册命令、管理插件等
  └── base-plugin.js   # 插件基础类,提供标准化的插件接口和通用功能

核心文件说明

  • index.js:核心模块,负责初始化系统、注册命令、管理插件等。它包含了插件加载、命令注册、钩子管理等核心功能。
  • base-plugin.js:插件基础类,提供标准化的插件接口和通用功能。所有插件应该继承此类以确保一致性,它提供了命令注册、配置管理、用户界面等通用功能。

插件目录 (/Users/xub/xx-cli/lib/plugins)

插件目录包含 xx-cli 的内置插件,这些插件提供了各种功能,如配置管理、历史记录管理、插件管理等。

文件结构

lib/plugins/
  ├── config-manager.js   # 配置管理插件,用于管理所有插件的配置文件
  ├── history.js          # 历史记录插件,用于查看命令历史记录
  └── plugin-manager.js   # 插件管理插件,用于管理所有插件

内置插件说明

  • config-manager.js:配置管理插件,用于管理所有插件的配置文件。它提供了导出、导入、列出配置等功能。
  • history.js:历史记录插件,用于查看命令历史记录。它提供了查看、清除、搜索历史记录等功能。
  • plugin-manager.js:插件管理插件,用于管理所有插件。它提供了列出、启用、禁用、添加、删除、创建插件等功能。

插件开发

本部分将详细介绍如何在 xx-cli 中创建、开发和部署插件。

创建插件

使用 plugin create 命令

xx-cli 提供了 plugin create 命令,可以快速生成插件模板。这是推荐的创建插件的方式。

基本用法
# 创建插件到插件目录(默认使用新格式,包含类结构实现)
xx plugin create <plugin-name>

# 或者使用别名
xx p create <plugin-name>

# 或者使用更短的别名
xx p cr <plugin-name>
插件模板格式

从 v2.0.0 版本开始,plugin create 命令生成的插件模板采用统一的格式:

  • 配置对象格式:使用配置对象定义插件的基本信息和命令
  • 包含类结构实现:核心功能通过类结构实现,提高代码模块化和可维护性
  • 自动生成命令名称:根据插件名称自动生成驼峰命名的命令名称
  • 标准的用户提示:使用标准化的用户提示和错误处理

这种格式结合了配置对象的简洁性和类结构的模块化优势,是推荐的插件开发方式。

示例
# 创建一个名为 `hello-world` 的插件
xx plugin create hello-world

# 输出:
# 创建插件模板...
# 插件模板已成功创建到:/Users/xub/.xx-cli/plugins/hello-world.js
# 提示:请编辑插件文件,实现具体功能
# 测试方法:运行 "node bin/cli.js <插件命令>"
# 已自动打开 vscode 编辑插件文件

手动创建插件

如果需要更灵活地控制插件结构,也可以手动创建插件文件。

  1. lib/plugins 目录下创建一个新的 JavaScript 文件,例如 my-plugin.js
  2. 实现插件类,包含必要的方法

插件结构

插件格式

xx-cli 支持两种插件格式:

  1. 旧格式(类结构格式):继承自 BasePlugin 类的插件实现
  2. 新格式(配置对象格式):使用配置对象定义的插件实现(推荐)

新格式(配置对象格式)插件结构

使用 plugin create 命令生成的默认插件模板包含以下结构(v2.0.0 版本更新):

/**
 * hello-world 插件
 * 用于实现 hello-world 相关功能
 * 
 * 命令说明:
 * - helloWorld [options]:hello-world 相关功能
 *   - 示例:helloWorld
 * 
 * 功能说明:
 * - 实现 hello-world 相关功能
 * 
 * 用户体验:
 * - 使用标准化的用户提示
 * - 提供清晰的错误提示
 * - 支持命令行参数
 */

/**
 * hello-world 插件类
 * 实现 hello-world 相关核心功能
 */
class HelloWorldPlugin {
  constructor() {
    this.pluginName = 'hello-world';
  }

  /**
   * 执行 hello-world 命令
   * @param {Array} args - 命令参数
   * @param {Object} options - 命令选项
   * @param {Object} helper - 插件帮助器
   */
  async execute(args, options, helper) {
    helper.showInfo('hello-world 命令执行成功!');
    if (options && options.verbose) {
      helper.showInfo('详细信息:');
      helper.showInfo('- 命令名称: helloWorld');
      helper.showInfo('- 执行时间: ' + new Date().toLocaleString());
    }
  }
}

// 创建插件实例
const pluginInstance = new HelloWorldPlugin();

module.exports = {
  name: "helloWorld",
  alias: "h",
  description: "hello-world 相关功能",
  options: [
    {
      name: "-v, --verbose",
      description: "显示详细信息",
    },
    {
      name: "-h, --help",
      description: "显示帮助信息",
    },
  ],
  action: async (args, options, helper) => {
    await pluginInstance.execute(args, options, helper);
  },
};

旧格式(类结构格式)插件结构

使用 plugin create --format old 命令生成的插件模板包含以下结构:

/**
 * hello-world 插件
 * 用于实现 hello-world 相关功能
 * 
 * 命令说明:
 * - helloWorld [options]:hello-world 相关功能
 *   - 示例:helloWorld
 * 
 * 功能说明:
 * - 实现 hello-world 相关功能
 * 
 * 用户体验:
 * - 使用标准化的用户提示
 * - 提供清晰的错误提示
 * - 支持命令行参数
 */

const BasePlugin = require('../core/base-plugin');

class HelloWorldPlugin extends BasePlugin {
  constructor(options = {}) {
    super(options);
    this.pluginName = 'hello-world';
  }

  /**
   * 注册命令
   * @param {Object} program - Commander.js 实例
   */
  registerCommands(program) {
    program.command('helloWorld')
      .description('hello-world 相关功能')
      .option('-v, --verbose', '显示详细信息')
      .option('-h, --help', '显示帮助信息')
      .action((options) => this.helloWorldCommand(options));
  }

  /**
   * hello-world 命令
   * @param {Object} options - 命令选项
   */
  helloWorldCommand(options) {
    console.log('hello-world 命令执行成功!');
    if (options && options.verbose) {
      console.log('详细信息:');
      console.log('- 命令名称:', 'helloWorld');
      console.log('- 执行时间:', new Date().toLocaleString());
    }
  }
}

module.exports = HelloWorldPlugin;

命令注册

新格式(配置对象格式)命令注册

对于新格式的插件,命令注册通过配置对象的 optionsaction 属性实现:

module.exports = {
  name: 'hello-world',
  alias: 'hw',
  description: 'hello-world 相关功能',
  options: [
    {
      name: '-v, --verbose',
      description: '显示详细信息'
    },
    {
      name: '-n, --name <name>',
      description: '指定名称'
    }
  ],
  action: (args, options, cmd) => {
    const helper = createPluginsHelper('hello-world');
    helloWorldCommand(args.alias, options, helper);
  }
};
旧格式(类结构格式)命令注册

对于旧格式的插件,命令注册通过实现 registerCommands 方法实现:

registerCommands(program) {
  program.command('helloWorld [alias]')
    .alias('hw')
    .description('hello-world 相关功能')
    .option('-v, --verbose', '显示详细信息')
    .option('-n, --name <name>', '指定名称')
    .action((alias, options) => this.helloWorldCommand(alias, options));
}

命令选项

可以为命令添加各种选项,以增强命令的灵活性。

常用选项类型
  • 布尔选项:不需要参数的选项

    .option('-v, --verbose', '显示详细信息')
  • 值选项:需要参数的选项

    .option('-n, --name <name>', '指定名称')
  • 数组选项:可以接收多个值的选项

    .option('-a, --array <items...>', '指定数组参数')
  • 带默认值的选项

    .option('-p, --port <port>', '指定端口', '3000')
  • 带验证器的选项

    .option('-p, --port <port>', '指定端口', parseInt)

插件配置

插件可以使用配置文件来存储和管理配置信息。

配置文件结构

配置文件通常存储在用户主目录的 .xx 文件夹中,例如:

~/.xx/
  └── hello-world/
      └── config.json

读取配置

const fs = require('fs');
const path = require('path');

// 获取用户主目录
const homeDir = process.env.HOME || process.env.USERPROFILE;
const xxDir = path.join(homeDir, '.xx-cli');
const pluginConfigDir = path.join(xxDir, this.pluginName);
const configFile = path.join(pluginConfigDir, 'config.json');

// 读取配置
let config = {};
if (fs.existsSync(configFile)) {
  config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
}

写入配置

const fs = require('fs');
const path = require('path');

// 确保配置目录存在
fs.ensureDirSync(pluginConfigDir);

// 写入配置
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));

插件工具

新格式(配置对象格式)插件工具

对于新格式的插件,使用 plugins-helper 提供的功能来替代 BasePlugin 类的方法:

导入 plugins-helper
const { createPluginsHelper } = require('../utils/plugins-helper');
核心功能

plugins-helper 提供了以下核心功能:

1. 用户界面
  • helper.showInfo(text):显示信息
  • helper.showSuccess(text):显示成功信息
  • helper.showWarning(text):显示警告信息
  • helper.showError(text):显示错误信息
  • helper.startLoading(text):显示加载状态
  • helper.stopLoading(text):停止加载状态
2. 配置管理

可以使用 fs-extrapath 模块来实现配置管理:

const fs = require('fs-extra');
const path = require('path');

// 确保配置目录存在
function ensureConfigDir(pluginName) {
  const homeDir = process.env.HOME || process.env.USERPROFILE;
  const xxDir = path.join(homeDir, '.xx-cli');
  const pluginConfigDir = path.join(xxDir, pluginName);
  fs.ensureDirSync(pluginConfigDir);
  return pluginConfigDir;
}

// 加载配置
function loadConfig(pluginName) {
  const configDir = ensureConfigDir(pluginName);
  const configFile = path.join(configDir, 'config.json');
  if (fs.existsSync(configFile)) {
    return JSON.parse(fs.readFileSync(configFile, 'utf8'));
  }
  return {};
}

// 保存配置
function saveConfig(pluginName, config) {
  const configDir = ensureConfigDir(pluginName);
  const configFile = path.join(configDir, 'config.json');
  fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
}
使用示例
const { createPluginsHelper } = require('../utils/plugins-helper');

function myCommand(options, helper) {
  try {
    helper.showInfo('执行操作...');
    
    // 执行操作
    setTimeout(() => {
      helper.showSuccess('操作成功');
      
      if (options && options.verbose) {
        helper.showInfo('详细信息:');
        helper.showInfo('- 执行时间:', new Date().toLocaleString());
      }
    }, 1000);
  } catch (error) {
    helper.showError(`执行命令失败: ${error.message}`);
  }
}

module.exports = {
  name: 'my-plugin',
  description: 'My plugin command',
  options: [
    {
      name: '-v, --verbose',
      description: '显示详细信息'
    }
  ],
  action: (args, options, cmd) => {
    const helper = createPluginsHelper('my-plugin');
    myCommand(options, helper);
  }
};

旧格式(类结构格式)基础插件类

对于旧格式的插件,使用 BasePlugin 基类:

基础插件类路径

BasePlugin 类位于 /Users/xub/xx-cli/lib/core/base-plugin.js,插件可以通过以下方式导入:

const BasePlugin = require('../core/base-plugin');
核心功能

BasePlugin 类提供了以下核心功能:

1. 命令注册
  • registerCommands(program):注册命令到 Commander.js 实例,子类必须实现此方法
2. 插件初始化
  • init():插件初始化逻辑,子类可以覆盖
  • getInfo():获取插件信息
3. 用户界面
  • startLoading(text):显示加载状态
  • stopLoading(text):停止加载状态
  • showError(text):显示错误信息
  • startProgressBar(text, total):启动进度条
  • updateProgressBar(current, text):更新进度条
  • stopProgressBar(text):停止进度条
  • showSuccess(text):显示成功信息
  • showWarning(text):显示警告信息
  • showInfo(text):显示信息
4. 配置管理
  • loadConfig(configName, cliOptions):加载配置
  • saveConfig(config, configName, isGlobal):保存配置
5. 错误处理
  • handleError(error, message):处理错误
6. 异步操作
  • executeAsync(fn, loadingText, successText, errorText):执行异步操作并显示加载状态
7. 钩子系统
  • registerHook(event, callback):注册钩子
  • triggerHook(event, data):触发钩子
  • hasHook(event):检查是否注册了指定钩子
8. 剪贴板操作
  • copyToClipboard(text, successMessage):复制文本到剪贴板
使用示例
const BasePlugin = require('../core/base-plugin');

class MyPlugin extends BasePlugin {
  constructor(options = {}) {
    super(options);
    this.pluginName = 'my-plugin';
  }

  registerCommands(program) {
    program.command('mycommand')
      .description('My plugin command')
      .action(() => this.myCommand());
  }

  async myCommand() {
    try {
      await this.executeAsync(
        async () => {
          // 执行异步操作
          await new Promise(resolve => setTimeout(resolve, 1000));
          return '操作结果';
        },
        '执行操作...',
        '操作成功',
        '操作失败'
      );
    } catch (error) {
      this.handleError(error, '执行命令失败');
    }
  }
}

module.exports = MyPlugin;

插件生命周期

插件的生命周期包括:

  1. 初始化:插件被加载时
  2. 命令注册:调用 registerCommands 方法
  3. 命令执行:用户运行插件命令时
  4. 清理:命令执行完成后

测试插件

本地测试

  1. 创建插件:

    xx plugin create <plugin-name>
  2. 编辑插件文件,实现具体功能

  3. 运行插件命令:

    # 直接运行
    node bin/cli.js <plugin-command>
       
    # 或者使用 xx 命令(如果已全局安装)
    xx <plugin-command>

测试命令选项

# 测试布尔选项
xx <plugin-command> --verbose

# 测试值选项
xx <plugin-command> --name John

# 测试组合选项
xx <plugin-command> --verbose --name John

部署插件

发布到插件目录

  1. 确保插件文件位于 lib/plugins 目录
  2. 运行 xx plugin list 命令,确认插件已被识别
  3. 插件会自动加载并注册到命令系统中

分享插件

如果要与他人分享插件,可以:

  1. 将插件文件发送给他人
  2. 他人将插件文件放入其 lib/plugins 目录
  3. 运行 xx plugin list 命令,确认插件已被识别

从外部添加插件

可以使用 plugin add 命令从 URL 或本地文件添加插件:

# 从 URL 添加插件
xx plugin add https://example.com/my-plugin.js

# 从本地文件添加插件
xx plugin add /path/to/my-plugin.js