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

hmcommand-runner

v1.3.3

Published

Command suite 命令组调度与跨平台执行框架

Readme

hmcommand-runner

跨平台命令组调度与执行库。用 CommandDef 描述单条命令,按命名组编排顺序,统一支持 Shell 子进程、进程内函数与内置轻量操作。

安装

npm install hmcommand-runner

快速开始

import { executeAll, CommandKind, type Groups } from "hmcommand-runner";

const groups: Groups = {
  init: [
    { kind: CommandKind.Embed, run: "sleep 0.1", description: "预热" },
    { kind: CommandKind.Mac, run: "echo hello", description: "打印" },
  ],
};

const results = await executeAll(groups.init, { stopOnError: true });

按组调度与重复执行:

import { runGroupChunks, getGroupChunks, parseGroupSpecs } from "hmcommand-runner";

const chunks = getGroupChunks(groups, parseGroupSpecs(["init:2", "build"], ["init", "build"]));
const { failed } = await runGroupChunks(chunks, { stopOnError: true, intervalMs: 100 });

命令种类

每条命令通过 kind 选择执行通道。Shell 类可声明单个平台或平台数组;embed / builtin 仅支持单值。

| 种类 | kind | 执行方式 | 典型场景 | |------|--------|----------|----------| | Shell | linux / mac / windows 或其数组 | 启动对应平台 Shell 子进程 | 调用 CLI 工具、运行脚本、采集外部命令输出 | | Builtin | builtin | 调用 func(context),进程内同步/异步 | 业务判断、读写共享上下文、按结果短路后续命令 | | Embed | embed | 解析 run 字符串,进程内执行内置操作 | 固定延时、定时等待、删除本地文件 |

Shell

// 内联脚本(优先于 file)
{ kind: CommandKind.Mac, run: "git status", cwd: "/path/to/repo" }

// 可执行文件
{ kind: CommandKind.Linux, file: "/usr/bin/node", args: ["-v"] }

// 多平台同一条定义
{ kind: [CommandKind.Linux, CommandKind.Mac], run: "uname -a" }
  • 默认仅在当前宿主 OS 匹配 kind 时执行;ignorePlatform: true 时用当前 Shell 执行声明的命令。
  • 支持 background / backgroundDelayMs(后台不阻塞队列)、captureToVar(抓取 stdout/stderr 到上下文)。
  • backgroundDelayMs > 0:调度成功即视为本条成功并立即继续后续命令;stopOnError--continue-on-error 均不因延后 spawn 或子进程后续失败而中断队列(详见下方说明)。
  • runfile+args 二选一;有 run 时走 Shell 脚本模式。

backgroundbackgroundDelayMs

| 配置 | 队列行为 | stopOnError | |------|----------|---------------| | background: true,无 delay 或 backgroundDelayMs: 0 | 尽快 spawn,不等待子进程结束 | spawn 失败时本条失败,可 fail-fast | | background: truebackgroundDelayMs > 0 | 不阻塞;调度成功即记成功并继续 | 不关注延后 spawn / 子进程结果,不回写失败 |

典型用法:先调度「80s 后执行的状态检测」后台命令,紧接着启动前台采集;两者并行,无需在宿主侧空等 80s。

Builtin

{
  kind: CommandKind.Builtin,
  description: "检查前置条件",
  func(ctx) {
    if (!ctx.get("ready")) {
      return { shortCircuit: true, error: true, message: "未就绪" };
    }
  },
}
  • func 返回 false 记为失败;void / true 为成功。
  • 返回 { shortCircuit: true } 跳过后续命令:error: true 视同失败并中止,error 缺省为中性短路(不计失败)。
  • 通过 CommandContext 在同批次命令间共享数据;后续 Shell 命令可用 {{key}} 模板引用字符串值。

Embed

进程内执行的轻量指令,通过 run 字符串声明,无需 Shell。详见 Embed 命令 章节。

Embed 命令

kind: CommandKind.Embed(或 "embed")时,执行器解析 run 字段并匹配内置指令。所有 Embed 命令在进程内运行、跨平台可用,不支持 background / backgroundDelayMs

{ kind: CommandKind.Embed, run: "sleep 2", description: "组间间隔" }

未识别的 run 或非法参数将返回失败(stderr未知的内置命令)。

sleep

固定等待,阻塞当前命令队列直至到时。

| 项 | 说明 | |----|------| | 语法 | sleep <秒数> | | 秒数 | 非负浮点数,如 0.52 | | 成功时 | exitCode: 0stdout / stderr 为空 |

{ kind: CommandKind.Embed, run: "sleep 1.5" }

场景:组间固定间隔、等待外部资源就绪前的占位延时。纯倒计时且需交互跳过请用 timeout

timeout

倒计时等待;TTY 下显示剩余时间,可按任意键提前结束。

| 项 | 说明 | |----|------| | 语法 | timeout <秒数>(兼容拼写 timieout) | | 秒数 | 非负浮点数 | | 成功时 stdout | timeout_elapsed(自然到时)或 stopped_by_key(按键跳过) | | 终端输出 | 非静默时刷新 [timeout] 剩余 Ns,按任意键可跳过... |

{ kind: CommandKind.Embed, run: "timeout 30", description: "等待用户确认" }

场景:需要人工介入的等待窗口(如「按任意键继续」)。无交互需求时用 sleep 即可。

unlink

静默删除本地文件;文件不存在或删除失败均不抛错、不阻断流水线。

| 项 | 说明 | |----|------| | 语法 | unlink <路径>unlink <JSON 字符串> | | 路径含空格 | 使用 JSON.stringify 包裹,如 unlink ${JSON.stringify(path)} | | 成功时 | exitCode: 0(即使文件本不存在) |

{ kind: CommandKind.Embed, run: `unlink ${JSON.stringify("/tmp/cache.log")}` }
{ kind: CommandKind.Embed, run: "unlink ./output.tmp" }

场景:流水线收尾清理临时文件。目录删除或复杂文件操作请用 Shell 或 builtin

选用建议

| 需求 | 推荐 | |------|------| | 固定延时 | sleep | | 可中断的倒计时 | timeout | | 删除单个本地文件 | unlink | | 条件判断、读写上下文、短路后续命令 | builtin | | 调用外部 CLI、脚本、后台进程 | Shell |

组与命令套件

  • GroupsRecord<string, CommandDef[]>,组名映射命令序列。
  • GroupSpecnamename:N(重复 N 次),由 parseGroupSpecs 从 CLI --group 解析。
  • CommandSuiteModule:导出 groupsdefaultGroupOrder,可选 applyOptions(opts) 按运行时选项生成组,供 CLI 注册为子命令。
import { resolveCommandSuite, runCommandSuiteGroups } from "hmcommand-runner";

const { groups, defaultGroupOrder } = resolveCommandSuite(commandSuiteModule, cliOptions);
await runCommandSuiteGroups({ groups, defaultGroupOrder, groupSpecs, ...runOptions });

CLI 集成

registerCommandSuites 支持两种注册方式(可组合):静态模块commandSuiteModules)与目录扫描commandSuiteDirs)。同名子命令后注册的会被跳过。

静态注册(推荐用于打包/固定子命令集)

import { program } from "commander";
import { registerCommandSuites } from "hmcommand-runner/cli";
import * as reportMod from "./commands/report.js";

await registerCommandSuites({
  program,
  commandSuiteModules: [
    {
      commandName: "report",
      module: reportMod,
      displayPath: "commands/report.ts",
    },
  ],
  mergeCommandSuiteOptions: (opts, globals) => ({ ...opts, ...globals }),
});

目录扫描(动态 import

import { program } from "commander";
import { registerCommandSuites } from "hmcommand-runner/cli";

await registerCommandSuites({
  program,
  commandSuiteDirs: [{ dirPath: "/abs/path/to/commands", displayPrefix: "commands" }],
  mergeCommandSuiteOptions: (opts, globals) => ({ ...opts, ...globals }),
});

各命令套件可声明专属 CLI 选项,与全局选项合并后传入 applyOptions。JSON 输出中套件标识字段为 command_suiteschema_versionCOMMAND_SUITE_CLI_RESULT_SCHEMA_VERSION)。

执行选项(常用)

| 选项 | 说明 | |------|------| | stopOnError | 任一条失败时中止本批剩余命令;runCommandSuiteGroups 与 CLI 默认 true(fail-fast)。例外backgroundDelayMs > 0 且调度成功的后台命令不参与 fail-fast(见 Shell · backgroundDelayMs) | | guaranteedOnFailureGroupNames | fail-fast 中止后补跑计划中尚未执行的组名(如 restore) | | silent | 不向终端流式输出子进程 stdout/stderr | | waitForBackground | 前台结束后等待或终止后台子进程 | | ignorePlatform | Shell 命令忽略平台过滤,按当前宿主 Shell 执行 | | intervalMs | 组块(chunk)之间的等待间隔 |

CLI 命令套件子命令默认遇错即停;需继续执行时使用 --continue-on-errorregisterCommandSuites 可配置 guaranteedOnFailureGroupNames

1.3.0 破坏性变更

1.3.0 起,原 Scenario* 命名统一为 CommandSuite*(如 resolveCommandSuiteregisterCommandSuitesCommandSuiteModule)。CLI JSON 结果中 scenario 字段更名为 command_suite。升级时请同步替换符号与 JSON 字段名。

开发

npm install
npm run build
npm run test:all

许可证

MIT