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

cmdc-sdk

v0.1.0

Published

CMDC Agent Kernel Node.js/Browser SDK — connect to cmdc_gateway via HTTP + SSE + WebSocket

Readme

cmdc (Node.js / Browser SDK)

CMDC Agent Kernel TypeScript/JavaScript SDK — 通过 HTTP + SSE + WebSocket 连接 cmdc_gateway,在 Node.js 或浏览器中使用 CMDC Agent 能力。


安装

npm install cmdc
# 或
yarn add cmdc
# 或
pnpm add cmdc

依赖要求:

  • Node.js 18+(使用原生 Fetch API)
  • 浏览器:支持 Fetch + ReadableStream + WebSocket 的现代浏览器

快速开始(5 分钟)

1. 启动 cmdc_gateway

cd cmdc_gateway
CMDC_API_KEYS=sk-abc123 mix run --no-halt

2. Node.js(ESM)

import { CMDCClient } from 'cmdc';

const client = new CMDCClient({
  baseUrl: 'http://localhost:4000',
  apiKey: 'sk-abc123',
});

const session = await client.createSession({
  model: 'deepseek:deepseek-chat',
  systemPrompt: '你是一个专业的编程助手',
  tools: ['CMDC.Tool.Shell', 'CMDC.Tool.ReadFile'],
});

try {
  for await (const event of session.prompt('帮我写一个快速排序')) {
    if (event.type === 'message_delta') {
      process.stdout.write(event.data.delta);
    }
  }
} finally {
  await session.stop();
}

3. 自动管理 Session 生命周期

await client.withSession({ model: 'deepseek:deepseek-chat' }, async (session) => {
  const reply = await session.promptSync('1+1=?');
  console.log(reply);
}); // session 自动 stop

4. 浏览器(<script> 标签)

<script src="https://unpkg.com/cmdc/dist/index.iife.global.js"></script>
<script>
  const client = new CMDC.CMDCClient({
    baseUrl: 'http://localhost:4000',
    apiKey: 'sk-abc123',
  });

  async function run() {
    const session = await client.createSession({ model: 'deepseek:deepseek-chat' });
    for await (const event of session.prompt('你好')) {
      if (event.type === 'message_delta') {
        document.getElementById('output').textContent += event.data.delta;
      }
    }
    await session.stop();
  }
  run();
</script>

API 参考

CMDCClient

import { CMDCClient } from 'cmdc';

const client = new CMDCClient({
  baseUrl: 'http://localhost:4000',  // Gateway 地址
  apiKey: 'sk-abc123',               // API Key
});

方法

| 方法 | 说明 | |------|------| | createSession(options) | 创建 Session,返回 Session 实例 | | withSession(options, fn) | 创建 Session,回调结束后自动 stop | | health() | 检查 Gateway 健康状态 |

SessionOptions

const session = await client.createSession({
  model: 'deepseek:deepseek-chat',    // 必填
  sessionId: 'my-session-001',         // 自定义 ID(可选)
  systemPrompt: '你是助手',            // 系统提示词
  workingDir: '/home/user/project',    // 工具工作目录
  tools: ['CMDC.Tool.Shell'],          // 启用的工具模块
  plugins: ['CMDC.Plugin.Builtin.SecurityGuard'],  // 插件
  blueprint: 'CMDC.Blueprint.Base',   // 蓝图模块
  maxTurns: 50,                        // 最大轮次
  maxTokens: 4096,                     // 最大输出 token
  skillsDirs: ['/skills'],             // Skill 目录
  providerOpts: { temperature: 0.7 }, // Provider 额外参数
});

Session

发送消息

// 方式一:AsyncGenerator 流式迭代
for await (const event of session.prompt('你好')) {
  if (event.type === 'message_delta') {
    process.stdout.write(event.data.delta);
  }
}

// 方式二:阻塞等待完整回复
const reply = await session.promptSync('简单回答:1+1=?');
console.log(reply); // "2"

// 方式三:仅投递,不监听
const { requestId } = await session.sendPrompt('开始任务');

EventEmitter 模式

// 注册 token 事件处理器
session.on('token', (delta) => {
  process.stdout.write(delta as string);
});

// 注册所有事件
session.on('event', (event) => {
  console.log((event as Event).type);
});

// 注册特定事件类型
session.on('agent_end', (event) => {
  const e = event as AgentEndEvent;
  console.log(`完成,共 ${e.data.tokenUsage.totalTokens} tokens`);
});

// 触发 EventEmitter 的同时迭代
for await (const event of session.prompt('你好')) {
  // token 事件已通过 on() 处理
}

控制操作

await session.approve('apr_x7y8z9');           // 审批通过
await session.reject('apr_x7y8z9');            // 审批拒绝
await session.respond('ask_001', '快速排序');  // 回答提问
await session.stop();                           // 停止 Agent

查询

const info = await session.getInfo();       // SessionInfo
const stats = await session.getStats();     // Stats(含 meter 用量)
const messages = await session.getMessages(); // Message[]

事件类型(15 种)

import type { Event, MessageDeltaEvent, AgentEndEvent, ApprovalRequiredEvent } from 'cmdc';

for await (const event of session.prompt('你好')) {
  switch (event.type) {
    case 'agent_start':
      console.log('Agent 开始处理');
      break;
    case 'message_delta':
      process.stdout.write(event.data.delta);
      break;
    case 'thinking_delta':
      console.log('[思考]', event.data.delta);
      break;
    case 'tool_execution_start':
      console.log(`工具 ${event.data.toolName} 开始执行`);
      break;
    case 'tool_execution_end':
      console.log(`工具完成: ${event.data.status}`);
      break;
    case 'approval_required':
      await session.approve(event.data.approvalId);
      break;
    case 'ask_user':
      await session.respond(event.data.ref, '我的回答');
      break;
    case 'agent_end':
      console.log(`\n完成,共 ${event.data.tokenUsage.totalTokens} tokens`);
      break;
    case 'error':
      console.error('错误:', event.data.reason);
      break;
  }
}

| 事件类型 | data 字段 | |---------|----------| | agent_start | {} | | agent_end | messageCount, lastMessage, tokenUsage | | agent_abort | reason | | prompt_received | text | | message_start | {} | | message_delta | delta | | thinking_start | {} | | thinking_delta | delta | | tool_calls | count | | tool_execution_start | toolName, callId, args | | tool_execution_end | toolName, callId, status, result | | approval_required | approvalId, toolName, args, hint | | approval_resolved | approvalId, status | | ask_user | ref, question, options | | error | reason |


HITL 审批

// 内置策略
for await (const event of session.prompt('执行任务', {
  approvalPolicy: 'auto_approve',  // 或 'auto_reject'
})) { ... }

// 自定义策略(callable)
for await (const event of session.prompt('执行任务', {
  approvalPolicy: (e) => e.data.toolName !== 'Shell',
})) { ... }

// 异步策略
for await (const event of session.prompt('执行任务', {
  approvalPolicy: async (e) => {
    const confirmed = await askUser(`允许执行 ${e.data.toolName}?`);
    return confirmed;
  },
})) { ... }

WebSocket 双向连接

const ws = session.connectWs();
await ws.connect();

// 发送 prompt
await ws.sendPrompt('执行危险操作');

// 迭代接收所有事件
for await (const event of ws.iterEvents()) {
  switch (event.type) {
    case 'approval_required':
      console.log(`需要审批: ${event.data.toolName}`);
      await ws.approve(event.data.approvalId);
      break;
    case 'message_delta':
      process.stdout.write(event.data.delta);
      break;
    case 'agent_end':
      ws.close();
      break;
  }
}

本地工具注册

await session.registerTool({
  name: 'search_database',
  description: '在本地数据库中搜索信息',
  parameters: {
    type: 'object',
    properties: {
      query: { type: 'string', description: '搜索关键词' },
    },
    required: ['query'],
  },
  callback: async (args) => {
    // 本地执行逻辑
    return `查询结果: ${args.query}`;
  },
  callbackUrl: 'http://my-service:8080/tools/search_database',
});

错误处理

import {
  CMDCError,
  AuthError,
  SessionNotFoundError,
  RateLimitError,
  SessionCreateError,
} from 'cmdc';

try {
  const session = await client.createSession({ model: 'unknown:model' });
} catch (err) {
  if (err instanceof AuthError) {
    console.error('API Key 无效');
  } else if (err instanceof SessionCreateError) {
    console.error('创建失败:', err.message);
  } else if (err instanceof RateLimitError) {
    console.error(`超出限流,${err.retryAfter}s 后重试`);
  } else if (err instanceof CMDCError) {
    console.error(`错误 [${err.statusCode}]: ${err.message}`);
  }
}

构建产物

| 文件 | 格式 | 用途 | |------|------|------| | dist/index.js | ESM | Node.js import / 现代打包工具 | | dist/index.cjs | CJS | Node.js require / CommonJS | | dist/index.iife.global.js | IIFE | 浏览器 <script> 标签直接使用 | | dist/index.d.ts | TypeScript 类型 | IDE 自动补全 |


开发

npm install
npm run build       # 构建三格式产物
npm test            # 运行测试(44 个用例)
npm run typecheck   # TypeScript 类型检查

环境变量

const client = new CMDCClient({
  baseUrl: process.env.CMDC_BASE_URL ?? 'http://localhost:4000',
  apiKey: process.env.CMDC_API_KEY!,
});