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

msgcli

v0.1.10

Published

Multi-platform messaging CLI - send messages to individuals and groups via DingTalk, with extensible platform support

Readme

msgcli

Multi-platform messaging CLI — send notifications to individuals and groups from your terminal.

Supports DingTalk out of the box. Designed with a clean platform interface so you can add WeChat Work, Lark, Slack, Telegram, or any other messenger with minimal code.

Quick Start

npm install -g msgcli

# Initialize config
msgcli config init

# Set your DingTalk credentials
msgcli config set dingtalk.default.client_id "your-client-id"
msgcli config set dingtalk.default.client_secret "your-client-secret"
msgcli config set dingtalk.default.robot_code "your-robot-code"
msgcli config set dingtalk.default.open_conversation_id "your-group-conversation-id"

# Send a message
msgcli send "Hello from CLI!"

Installation

npm (recommended)

# Global install — use `msgcli` anywhere
npm install -g msgcli

# Or run on the fly without installing
npx msgcli send "Hello"

Bun (for contributors / local development)

git clone <repo-url> && cd msgcli
bun install
bun link          # makes `msgcli` globally available

# Or run directly
bun run src/index.ts send "Hello"

Usage

Send a message

msgcli send "Your message here"
msgcli send -p dingtalk -t user123 --to-type user "Hi there"
msgcli send -p dingtalk -t conv123456 "Group announcement"

Send a file

msgcli send -f report.pdf "Check this file"

File is uploaded to DingTalk storage and sent as a file message. Works with groups and individual users.

msgcli send -f photo.jpg -t user123 --to-type user
msgcli send -f data.csv -t conv123456

Options

| Flag | Short | Description | |------|-------|-------------| | --platform | -p | Target platform (default: dingtalk) | | --to | -t | Recipient — user ID or conversation ID | | --to-type | | Recipient type: user or group (default: group) | | --profile | | Config profile name (default: default) | | --file | -f | Attach a file (uploads to DingTalk and sends as file message) | | --help | -h | Show help |

Config management

# Initialize empty config
msgcli config init

# Set a value (supports nested keys with dot notation)
msgcli config set dingtalk.default.client_id "your-client-id"
msgcli config set dingtalk.default.client_secret "your-client-secret"

# Get a value
msgcli config get dingtalk.default.client_id

# List all config
msgcli config list

Configuration

Config file location: ~/.config/msgcli/auth.json

Format

{
  // Platform name → profile name → key-value pairs
  "dingtalk": {
    "default": {
      "client_id":            "your-app-key",
      "client_secret":        "your-app-secret",
      "robot_code":           "your-robot-code",
      "open_conversation_id": "your-group-conversation-id"
    },
    "work": {
      "client_id":            "...",
      "client_secret":        "...",
      "robot_code":           "...",
      "open_conversation_id": "..."
    }
  },

  "feishu": {
    "default": {
      "app_id":             "your-app-id",
      "app_secret":         "your-app-secret",
      "chat_id":            "your-group-chat-id"
    }
  },

  "wechat_work": {
    "default": {
      "webhook_url": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-key"
    }
  },

  "slack": {
    "default": {
      "token":   "...",
      "channel": "..."
    }
  }
}

Each platform can have multiple named profiles (e.g. default, work, personal). Select one with --profile.

Manual editing

You can edit ~/.config/msgcli/auth.json directly with any text editor:

vim ~/.config/msgcli/auth.json

Platform: DingTalk

Prerequisites

  1. Go to DingTalk Open Platform and create an application.
  2. Obtain Client ID (AppKey) and Client Secret (AppSecret).
  3. Create a robot under the application and get the Robot Code.
  4. For group messages: get the openConversationId from a group the robot has joined.
  5. For single user messages: know the user's DingTalk user ID.

API Reference

| Action | Endpoint | |--------|----------| | Get access token | POST https://api.dingtalk.com/v1.0/oauth2/accessToken | | Send group message | POST https://api.dingtalk.com/v1.0/robot/groupMessages/send | | Send single message | POST https://api.dingtalk.com/v1.0/robot/oToMessages/send | | Upload media | POST https://oapi.dingtalk.com/media/upload |

Examples

# Send to default group (uses open_conversation_id from config)
msgcli send "Daily standup reminder"

# Send to a specific user
msgcli send -t "manager123" --to-type user "Please review the PR"

# Send to a specific group conversation
msgcli send -t "cidXxxXxxxXxxxXxxx==" "Hello group"

# Use a different profile
msgcli send --profile work "Production deploy starting"

# Send a file to the default group
msgcli send -f report.pdf "Monthly report attached"

# Send a file to an individual user
msgcli send -t user123 --to-type user -f photo.jpg

Platform: Feishu (飞书)

Prerequisites

  1. Go to Feishu Open Platform and create an application.
  2. Obtain App ID and App Secret from the "Credentials" page.
  3. Add the Robot capability and grant required permissions:
    • im:message
    • im:resource
  4. For group messages: get the chat_id from a group the bot is a member of.
  5. For single user messages: know the user's open_id (Feishu's user identifier).
    • Grant contact:user.base:readonly permission and use the Get User API.

Configuration

msgcli config set feishu.default.app_id "cli_xxxxx"
msgcli config set feishu.default.app_secret "xxxxxxxx"
msgcli config set feishu.default.chat_id "oc_xxxxxxxx"

API Reference

| Action | Endpoint | |--------|----------| | Get tenant access token | POST https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal | | Send message | POST https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type={type} | | Upload file | POST https://open.feishu.cn/open-apis/im/v1/files |

Examples

# Send to default group (uses chat_id from config)
msgcli send -p feishu "Daily standup reminder"

# Send to a specific group chat
msgcli send -p feishu -t "oc_xxx" "Hello group"

# Send to a specific user (by open_id)
msgcli send -p feishu -t "ou_xxx" --to-type user "Direct message"

# Send a file
msgcli send -p feishu -f report.pdf "Monthly report"

Platform: WeChat Work (Webhook)

Prerequisites

  1. Open a group chat in WeChat Work, click Group Settings > Group Robot > Add Robot.
  2. Choose Custom Robot, give it a name, and save.
  3. Copy the Webhook URL (format: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx).

Configuration

msgcli config set wechat_work.default.webhook_url "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-key"

API Reference

| Action | Endpoint | |--------|----------| | Send message | POST {webhook_url} | | Upload media | POST https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key={key}&type=file |

Limitations

  • Webhook robots can only send to the group they are added to (no --to / --to-type support).
  • Rate limit: 3 messages per second.
  • File upload max: 10 MB.

Examples

# Send text message to the group
msgcli send -p wechat_work "Deploy completed"

# Send a file
msgcli send -p wechat_work -f report.pdf

Extending: Adding a new platform

Create a new file in src/platforms/ that implements the Platform interface:

// src/platforms/wechat_work.ts
import type { Platform, SendOptions, MessageResult } from "./index.ts"

export const wechat_work: Platform = {
  name: "wechat_work",

  async sendMessage(
    config: Record<string, unknown>,
    options: SendOptions
  ): Promise<MessageResult> {
    // Your implementation here
    return { success: true, data: {}, platform: "wechat_work" }
  },
}

Then register it in src/index.ts:

import { wechat_work } from "./platforms/wechat_work.ts"

const PLATFORMS: Record<string, Platform> = {
  dingtalk,
  wechat_work,  // <-- add here
}

Users can then configure it under the same profile system:

msgcli config set wechat_work.default.webhook_url "https://qyapi.weixin.qq.com/..."
msgcli send -p wechat_work "Message via WeChat Work"

All platforms can be listed with msgcli send --help.

Supported Platforms

| Platform | Identifier | Text | File | |----------|-----------|------|------| | DingTalk | dingtalk | ✓ | ✓ | | Feishu (Lark) | feishu | ✓ | ✓ | | WeChat Work (Webhook) | wechat_work | ✓ | ✓ |

Architecture

msgcli/
├── package.json              # NPM package config, bin, scripts
├── tsconfig.json
├── LICENSE
├── README.md
├── .gitignore
├── scripts/
│   └── build.ts              # Build script (bun build -> dist/)
├── src/
│   ├── index.ts              # CLI entry point, arg parsing, dispatch
│   ├── config.ts             # ~/.config/msgcli/auth.json management
│   └── platforms/
│       ├── index.ts          # Platform interface definitions
│       ├── dingtalk.ts       # DingTalk implementation
│       └── feishu.ts         # Feishu (Lark) implementation
└── dist/                     # Build output (published to npm)
    └── index.js

How it works

  1. config.ts loads/stores profiles from ~/.config/msgcli/auth.json using dot-notation keys.
  2. index.ts parses CLI args, loads the requested platform's profile, and calls platform.sendMessage().
  3. Each platform module implements the Platform interface — it receives a flat config object and send options, performs the API call, and returns a MessageResult.

Development

# Run locally (source)
bun run src/index.ts send "test"

# Build for npm distribution
bun run build

# Test the built bundle
node dist/index.js send "test"

# Type checking
bun run tsc --noEmit

Publishing to npm

Prerequisites

  1. A npm account: npm adduser or npm login
  2. Node.js >= 18 installed
  3. Bun installed (for building)

Steps

# 1. Bump version
npm version patch   # or minor / major

# 2. Build
bun run build

# 3. Dry run to verify package contents
npm pack --dry-run

# 4. Publish
npm publish

The prepublishOnly script automatically runs bun run build before publish, so you can also just run npm publish directly.

Package contents

The published package includes:

  • dist/ — compiled JS bundle (platform-agnostic, works with Node >= 18)
  • README.md, LICENSE

No npm runtime dependencies — fetch is built into Node 18+. No bun required at runtime — the published bundle runs on plain Node.js.

CI publish (GitHub Actions)

# .github/workflows/publish.yml
name: Publish to npm
on:
  push:
    tags: "v*"
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          registry-url: "https://registry.npmjs.org"
      - run: bun install
      - run: bun run build
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

License

MIT