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

@ocdb/plugin

v0.1.5

Published

openclaw-debug-toolkit 的 OpenClaw plugin bundle。安装后随 OpenClaw gateway 启动,自动启动 Debug Service(默认 `:7887`)。

Readme

@ocdb/plugin

openclaw-debug-toolkit 的 OpenClaw plugin bundle。安装后随 OpenClaw gateway 启动,自动启动 Debug Service(默认 :7887)。


安装

openclaw plugins install @ocdb/plugin

或在本地开发时:

openclaw plugins install /path/to/openclaw-debug-toolkit/packages/plugin

快速验证

安装并重启 gateway 后:

curl http://localhost:7887/health
# → {"status":"ok"}

组件说明

plugin bundle 内部由 6 个组件组成,通过 createPlugin() 统一组装。

Capture Hooks

挂载在 OpenClaw 的 7 个生命周期 hook 上,将每次 Agent 执行的关键状态写入 CheckpointStore。

| Hook | 产出 | 说明 | |------|------|------| | before_agent_run | DebugRun 记录 | run 开始,创建元数据记录 | | before_prompt_build | Checkpoint(before_prompt_build) | 记录当时的 messages + runtimeContext | | before_model_resolve | — | 记录 model 配置(附在 llm_input checkpoint) | | llm_input | Checkpoint(before_model_call) | 发给模型的最终 prompt + system prompt | | llm_output | Checkpoint(after_model_call) | 模型输出 + finishReason + token usage | | before_tool_call | Checkpoint(before_tool_call) | 工具调用前快照;fork 模式下执行 cassette 拦截 | | after_tool_call | Checkpoint(after_tool_call) | 工具结果;更新 ToolCallRecord | | agent_end | Checkpoint(agent_end) | 更新 run status + endedAt |

fork 模式下的额外行为:

  • before_prompt_build — 调用 DebugContextEngine.assemble(),注入历史 messages 和调试上下文
  • before_tool_call — 调用 ToolIntercept.check(),按 replayPolicy 决定是否跳过真实执行
  • llm_input — 若 ReplayProvider.isReplayMode() 为 true,返回历史 LLM 输出(--captured 模式)

CheckpointStore

本地持久化存储,内存 LRU + 磁盘 JSONL 双层设计。

存储位置: ~/.ocdt/runs/<run-id>/

run.json              — DebugRun 元数据(不含 checkpoints 和 toolLedger 数组)
checkpoints.jsonl     — 追加写,每行一个 Checkpoint
tool-ledger.jsonl     — 追加写(预留,目前 ledger 存于 checkpoint 快照中)

API:

const store = new CheckpointStore({ storeDir: '~/.ocdt/runs', maxRuns: 100 })
await store.init()           // 初始化目录,加载磁盘数据到内存索引

await store.saveRun(run)     // 保存/更新 run 元数据
await store.updateRun(id, patch)  // 局部更新(如更新 status)
await store.appendCheckpoint(ckp) // 追加 checkpoint(append-only)

await store.getRun(id)           // → DebugRun | undefined
await store.getCheckpoints(id)   // → Checkpoint[]
await store.listRuns(limit?)     // → DebugRun[](按 startedAt 降序)

maxRuns 控制内存中保留的最近 run 数量;超出时按 startedAt 淘汰最旧的记录(磁盘文件保留,不删除)。


HTTP Debug Service

plugin 内嵌的轻量 HTTP server,使用 Node.js 内置 http 模块,无框架依赖。

默认端口: 7887(可通过配置修改)

端点

| 方法 | 路径 | 说明 | |------|------|------| | GET | /health | 健康检查,返回 {"status":"ok"} | | GET | /runs | 列出最近 runs(支持 ?status=?limit= 参数) | | GET | /runs/:id | 获取单个 run 元数据 | | GET | /runs/:id/checkpoints | 获取 run 的所有 checkpoints | | GET | /runs/:id/diff/:id2 | 对比两次 run | | POST | /fork | 从 checkpoint 创建 fork run | | POST | /import | 导入 trajectory JSONL(当前版本仅计数) |

示例

# 获取最近失败的 run
curl 'http://localhost:7887/runs?status=failed&limit=5' | jq .

# 查看 checkpoints
curl http://localhost:7887/runs/run-abc123/checkpoints | jq '.checkpoints[].boundary'

# 发起 fork
curl -X POST http://localhost:7887/fork \
  -H 'Content-Type: application/json' \
  -d '{
    "sourceRunId": "run-abc123",
    "sourceCheckpointId": "ckp-xxx",
    "modelOverride": { "mode": "captured" },
    "toolPolicyMap": { "execute_sql": "reuse_result", "save_report": "forbid_replay" }
  }'

ReplayProvider

管理 LLM 输出的捕获和重放。在 --captured 模式下,按 runId + callIndex 顺序返回历史输出,实现完全确定性重放。

// 正常 live run 时:capture.ts 的 llmOutput hook 调用
replayProvider.storeCapture(runId, checkpointId, callIndex, output)

// fork run 启动时(mode=captured):
replayProvider.enableReplayMode(forkRunId, sourceRunId, sourceCheckpointId)

// fork run 的 before_model_resolve hook 中调用:
const output = replayProvider.getNextCapturedOutput(forkRunId)
// → 返回 { content, finishReason, usage } 或 undefined

DebugContextEngine

管理 fork 模式下的消息注入。在 before_prompt_build hook 中调用,将历史 messages 替换进新 session。

// fork 创建时注册
contextEngine.registerFork(forkRunId, historicMessages, forkConfig)

// before_prompt_build hook 中调用
const result = contextEngine.assemble(runId, currentMessages)
// → { messages, systemPromptAddition? }
// fork 模式:messages = 历史消息,systemPromptAddition = [DEBUG REPLAY CONTEXT]...
// live 模式:messages = currentMessages,systemPromptAddition = undefined

// fork run 结束时清理
contextEngine.deregisterFork(forkRunId)

systemPromptAddition 的内容示例:

[DEBUG REPLAY CONTEXT]
sourceRunId: run-abc123
sourceCheckpointId: ckp-xxx
mode: fork
promptVersion: v2
toolPolicies: {"*":"reuse_result","save_report":"forbid_replay"}

ForkEngine

准备和管理 fork session。

const engine = new ForkEngine(store)

// 发起 fork:创建 fork DebugRun,注册活跃 session
const forkRun = await engine.prepareFork(forkConfig)
// forkRun.mode === 'fork'
// forkRun.parentRunId === forkConfig.sourceRunId

// 查询活跃 fork session(供 hooks 使用)
const session = engine.getForkSession(forkRun.runId)
// → { forkRun, config } | undefined

// fork run 结束时清理
engine.completeFork(forkRun.runId)

DiffEngine

对比两次 run 的差异,覆盖 status、checkpoint 数量、工具调用 args 和 result。

const engine = new DiffEngine()
const diff = engine.diff(runA, checkpointsA, runB, checkpointsB)
// → RunDiff {
//     runA, runB,
//     status: { changed, a, b },
//     checkpointCount: { changed, a, b },
//     toolCallCount: { changed, a, b },
//     toolCallDiffs: ToolCallDiff[],
//     summary: string
//   }

Tool Cassette(createToolIntercept

before_tool_call hook 中的拦截逻辑,根据 ForkConfig 中的 toolPolicyMap 决定每个工具调用的处理方式。

const intercept = createToolIntercept()

// fork 创建时注册(含历史 tool ledger 供 reuse_result 使用)
intercept.registerFork(forkRunId, forkConfig, historicToolLedger)

// before_tool_call hook 中调用
const result = await intercept.check(runId, toolCallId, toolName, args)
// → undefined                   (re_execute: 让工具正常执行)
// → { intercepted, result }     (reuse_result / mock_result: 直接返回数据)
// → { intercepted, error }      (forbid_replay: 报错阻止执行)

策略优先级: 具名工具 > '*' 通配符 > 默认 re_execute


createPlugin() API

import { createPlugin } from '@ocdb/plugin'

const plugin = createPlugin({
  port?: number,      // Debug Service 端口,默认 7887
  storeDir?: string,  // 存储目录,默认 ~/.ocdt/runs
  maxRuns?: number,   // 内存保留数量,默认 100
})

// 返回值供 OpenClaw 注册:
plugin.name     // 'openclaw-debug-toolkit'
plugin.version  // '0.1.0'
plugin.hooks    // { beforeAgentRun, beforePromptBuild, llmInput, ... }

// 内部组件(测试 / 扩展用):
plugin._store
plugin._server
plugin._replayProvider
plugin._contextEngine
plugin._toolIntercept
plugin._forkEngine
await plugin._ready  // 等待 store + server 启动完成

OpenClaw 接入配置

安装插件后,需在 OpenClaw gateway 配置文件中启用 conversation access(否则 LLM 输入/输出 hook 无法工作):

{
  "plugins": {
    "entries": {
      "openclaw-debug-toolkit": {
        "hooks": {
          "allowConversationAccess": true
        }
      }
    }
  }
}

然后重启 gateway:

openclaw gateway restart

插件入口由 @ocdb/plugin/openclaw 子路径导出,OpenClaw gateway 在运行时加载该入口(而非 @ocdb/plugin 默认入口)。definePluginEntry 来自 openclaw peer dependency,需在 gateway 环境中提供。


对接真实 OpenClaw SDK

packages/plugin/src/openclaw.d.ts 现为内部适配器类型文件(非 SDK 类型)。src/openclaw-entry.ts 通过 definePluginEntry 挂载真实 hook,将 OpenClaw 原生事件字段映射到内部适配器类型后交给 capture.ts 处理。

openclaw 包的实际事件字段与 openclaw-entry.ts 中的映射有出入,按实际字段调整 openclaw-entry.ts 中的 event.* 取值逻辑即可,无需改动 capture.ts