Skip to content

开发指南

从源码构建

先决条件

  • Node.js 18.0.0 或更高版本
  • npm(随 Node.js 一起提供)
  • Git

克隆与构建

bash
# Clone repository
git clone https://github.com/thedotmack/claude-mem.git
cd claude-mem

# Install dependencies
npm install

# Build all components
npm run build

构建过程

构建过程使用 esbuild 来编译 TypeScript:

  1. 将 TypeScript 编译为 JavaScript
  2. plugin/scripts/ 中的每个钩子创建独立的可执行文件
  3. 将 MCP 搜索服务器打包到 plugin/scripts/mcp-server.cjs
  4. 将Worker 进程打包到 plugin/scripts/worker-service.cjs
  5. 将网页查看器 UI 打包到 plugin/ui/viewer.html

构建输出

  • 挂钩可执行文件:*-hook.js(ESM 格式)
  • 智能安装程序:smart-install.js(ESM 格式)
  • Worker 进程服务:worker-service.cjs(CJS 格式)
  • MCP 服务器:mcp-server.cjs(CJS 格式)
  • 查看器界面: viewer.html(独立 HTML 包)

构建脚本

bash
# Build everything
npm run build

# Build only hooks
npm run build:hooks

# The build script is defined in scripts/build-hooks.js

开发工作流程

1. 进行更改

src/ 中编辑 TypeScript 源文件:

src/
├── hooks/           # Hook implementations (entry points + logic)
├── services/        # Worker service and database
├── servers/         # MCP search server
├── sdk/             # Claude Agent SDK integration
├── shared/          # Shared utilities
├── ui/
│   └── viewer/      # React web viewer UI components
└── utils/           # General utilities

2. 构建

bash
npm run build

3. 测试

bash
# Run all tests
npm test

# Test specific file
node --test tests/session-lifecycle.test.ts

# Test context injection
npm run test:context

# Verbose context test
npm run test:context:verbose

4. 手动测试

bash
# Start worker manually
npm run worker:start

# Check worker status
npm run worker:status

# View logs
npm run worker:logs

# Test hooks manually
echo '{"session_id":"test-123","cwd":"'$(pwd)'","source":"startup"}' | node plugin/scripts/context-hook.js

5. 迭代

重复步骤1-4,直到你的更改按预期工作。

查看器界面开发

使用 React 查看器

网页查看器 UI 是一个内置在自包含 HTML 包中的 React 应用程序。

地点: src/ui/viewer/

结构:

src/ui/viewer/
├── index.tsx              # Entry point
├── App.tsx                # Main application component
├── components/            # React components
│   ├── Header.tsx         # Header with logo and actions
│   ├── Sidebar.tsx        # Project filter sidebar
│   ├── Feed.tsx           # Main feed with infinite scroll
│   ├── cards/             # Card components
│   │   ├── ObservationCard.tsx
│   │   ├── PromptCard.tsx
│   │   ├── SummaryCard.tsx
│   │   └── SkeletonCard.tsx
├── hooks/                 # Custom React hooks
│   ├── useSSE.ts          # Server-Sent Events connection
│   ├── usePagination.ts   # Infinite scroll pagination
│   ├── useSettings.ts     # Settings persistence
│   └── useStats.ts        # Database statistics
├── utils/                 # Utilities
│   ├── constants.ts       # Constants (API URLs, etc.)
│   ├── formatters.ts      # Date/time formatting
│   └── merge.ts           # Data merging and deduplication
└── assets/                # Static assets (fonts, logos)

建筑查看器界面

bash
# Build everything including viewer
npm run build

# The viewer is built to plugin/ui/viewer.html
# It's a self-contained HTML file with inlined JS and CSS

测试查看器更改

  1. src/ui/viewer/ 中对 React 组件进行更改
  2. 版本:npm run build
  3. 同步到已安装插件:npm run sync-marketplace
  4. 重启Worker 进程:npm run worker:restart
  5. http://localhost:37777 刷新浏览器

热重载:当前不支持。更改需要完全重建并重启。

添加新的查看器功能

示例:添加一种新卡类型

  1. src/ui/viewer/components/cards/YourCard.tsx 中创建组件:
tsx

  // Your data structure
}

  return (
    <div className="card">
      {/* Your UI */}
    </div>
  );
};
  1. Feed.tsx 中导入和使用:
tsx

// In render logic:
{item.type === 'your_type' && <YourCard {...item} />}
  1. 如有必要,在 src/ui/viewer/types.ts 中更新类型

  2. 重建并测试

查看器用户界面架构

数据流

  1. Worker 服务暴露 HTTP SSE 端点
  2. React 应用通过 HTTP 获取初始数据(分页)
  3. SSE 连接提供实时更新
  4. 自定义钩子处理状态管理和数据合并
  5. 组件根据项目类型渲染卡片

关键模式:

  • 无限滚动:使用 Intersection Observer 的 usePagination 钩子
  • 实时更新:带自动重连的 useSSE 钩子
  • 去重merge.ts 工具可以防止重复项
  • 设置持久性useSettings 钩子与 localStorage
  • 主题支持:带有亮色/暗色/系统主题的 CSS 变量

添加新功能

添加新钩子

  1. src/hooks/your-hook.ts 中创建钩子实现:
typescript
#!/usr/bin/env node

async function main() {
  const input = await readStdin();

  // Hook implementation
  const result = {
    hookSpecificOutput: 'Optional output'
  };

  console.log(JSON.stringify(result));
}

main().catch(console.error);

注意:从 v4.3.1 版本开始,hooks 是自包含的文件。shebang 将在构建过程中由 esbuild 自动添加。

  1. 添加到 plugin/hooks/hooks.json
json
{
  "YourHook": [{
    "hooks": [{
      "type": "command",
      "command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/your-hook.js",
      "timeout": 120
    }]
  }]
}
  1. 重建:
bash
npm run build

修改数据库模式

  1. src/services/sqlite/migrations.ts 添加迁移:
typescript

  version: 11,
  up: (db: Database) => {
    db.run(`
      ALTER TABLE observations ADD COLUMN new_field TEXT;
    `);
  },
  down: (db: Database) => {
    // Optional: define rollback
  }
};
  1. src/services/sqlite/types.ts 中的更新类型:
typescript

  // ... existing fields
  new_field?: string;
}
  1. 更新 src/services/sqlite/SessionStore.ts 中的数据库方法:
typescript
createObservation(obs: Observation) {
  // Include new_field in INSERT
}
  1. 测试迁移:
bash
# Backup database first!
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup

# Run tests
npm test

扩展 SDK 提示

  1. 修改 src/sdk/prompts.ts 中的提示:
typescript

  return `
    <observation>
      <!-- Add new XML structure -->
    </observation>
  `;
}
  1. 更新 src/sdk/parser.ts 中的解析器:
typescript

  // Parse new XML fields
}
  1. 测试:
bash
npm test

添加 MCP 搜索工具

  1. src/servers/mcp-server.ts 中添加工具定义:
typescript
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === 'your_new_tool') {
    // Implement tool logic
    const results = await search.yourNewSearch(params);
    return formatResults(results);
  }
});
  1. src/services/sqlite/SessionSearch.ts 中添加搜索方法:
typescript
yourNewSearch(params: YourParams): SearchResult[] {
  // Implement FTS5 search
}
  1. 重建并测试:
bash
npm run build
npm test

测试

测试哲学

Claude-mem 依赖于真实世界的使用和手动测试,而不是传统的单元测试。该项目的理念优先考虑:

  1. 手动验证 - 在实际的 Claude Code 会话中测试功能
  2. 集成测试 - 运行完整系统的端到端测试
  3. 数据库检查 - 通过 SQLite 查询验证数据的正确性
  4. 命令行工具 - 用于检查系统状态的交互式工具
  5. 可观察性 - 全面的日志记录和工作节点健康检查

选择这种方法的原因是:

  • 钩子行为在很大程度上取决于Claude Code的运行时环境
  • SDK 交互需要真实的 API 调用和响应
  • SQLite 和 Bun 运行时提供稳定性保证
  • 手动测试可以发现单元测试未能检测到的集成问题

手动测试工作流程

在开发新功能时:

  1. 构建和同步

    bash
    npm run build
    npm run sync-marketplace
    npm run worker:restart
  2. 在实际课程中测试:

    • 启动Claude代码
    • 触发你正在测试的功能
    • 验证预期行为
  3. 检查数据库状态

    bash
    sqlite3 ~/.claude-mem/claude-mem.db "SELECT * FROM your_table;"
  4. 监控 Worker 日志

    bash
    npm run worker:logs
  5. 验证队列健康状况(用于恢复功能)

    bash
    bun scripts/check-pending-queue.ts

测试工具

健康检查

bash
# Worker status
npm run worker:status

# Queue inspection
curl http://localhost:37777/api/pending-queue

# Database integrity
sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"

钩子测试

bash
# Test context hook manually
echo '{"session_id":"test-123","cwd":"'$(pwd)'","source":"startup"}' | node plugin/scripts/context-hook.js

# Test new hook
echo '{"session_id":"test-123","cwd":"'$(pwd)'","prompt":"test"}' | node plugin/scripts/new-hook.js

数据验证

bash
# Check recent observations
sqlite3 ~/.claude-mem/claude-mem.db "
  SELECT id, tool_name, created_at
  FROM observations
  ORDER BY created_at_epoch DESC
  LIMIT 10;
"

# Check summaries
sqlite3 ~/.claude-mem/claude-mem.db "
  SELECT id, request, completed
  FROM session_summaries
  ORDER BY created_at_epoch DESC
  LIMIT 5;
"

恢复功能测试

专门针对手动恢复功能:

  1. 模拟卡住的消息

    bash
    # Manually create stuck message (for testing only)
    sqlite3 ~/.claude-mem/claude-mem.db "
      UPDATE pending_messages
      SET status = 'processing',
          started_processing_at_epoch = strftime('%s', 'now', '-10 minutes') * 1000
      WHERE id = 123;
    "
  2. 测试恢复

    bash
    bun scripts/check-pending-queue.ts
  3. 验证结果

    bash
    curl http://localhost:37777/api/pending-queue | jq '.queue'

回归测试

发布前:

  1. 测试所有钩子触发器

    • 会话开始:启动新的Claude Code会话
    • 用户提示提交:提交提示
    • 使用工具后:使用像 Read 这样的工具
    • 摘要:让会话完成
    • 会话结束:关闭Claude代码
  2. 测试核心功能

    • 上下文注入(最近的会话显示)
    • 观察处理(生成的摘要)
    • MCP 搜索工具(搜索返回结果)
    • 查看器界面(在 http://localhost:37777 加载)
    • 手动恢复(卡住的消息已恢复)
  3. 测试边界情况:

  • Worker 崩溃恢复
  • 数据库锁
  • 端口冲突
  • 大型数据库
  1. 跨平台(如适用):
    • macOS
    • Linux
    • 窗口

代码风格

TypeScript 指南

  • 使用 TypeScript 严格模式
  • 为所有数据结构定义接口
  • 对异步代码使用 async/await
  • 明确处理错误
  • 为公共 API 添加 JSDoc 注释

格式化

  • 遵循现有的代码格式
  • 使用 2 空格缩进
  • 字符串使用单引号
  • 在对象/数组中添加尾随逗号

例子

typescript
/**
 * Create a new observation in the database
 */

  obs: Observation
): Promise<number> {
  try {
    const result = await db.insert('observations', {
      session_id: obs.session_id,
      tool_name: obs.tool_name,
      // ...
    });
    return result.id;
  } catch (error) {
    logger.error('Failed to create observation', error);
    throw error;
  }
}

调试

启用调试日志

bash

npm run worker:restart
npm run worker:logs

检查数据库

bash
sqlite3 ~/.claude-mem/claude-mem.db

# View schema
.schema observations

# Query data
SELECT * FROM observations LIMIT 10;

痕迹观察

使用相关 ID 跟踪整个流程中的观察记录:

bash
sqlite3 ~/.claude-mem/claude-mem.db
SELECT correlation_id, tool_name, created_at
FROM observations
WHERE session_id = 'YOUR_SESSION_ID'
ORDER BY created_at;

调试钩子

使用测试输入手动运行钩子:

bash
# Test context hook
echo '{"session_id":"test-123","cwd":"'$(pwd)'","source":"startup"}' | node plugin/scripts/context-hook.js

# Test new hook
echo '{"session_id":"test-123","cwd":"'$(pwd)'","prompt":"test"}' | node plugin/scripts/new-hook.js

出版

NPM 发布

bash
# Update version in package.json
npm version patch  # or minor, or major

# Build
npm run build

# Publish to NPM
npm run release

release 脚本:

  1. 运行测试
  2. 构建所有组件
  3. 发布到 NPM 注册表

创建发布

  1. package.json 中更新版本
  2. 更新 CHANGELOG.md
  3. 提交更改
  4. 创建 git 标签
  5. 推送到 GitHub
  6. 发布到 NPM
bash
# Manual version bump:
# 1. Update version in package.json
# 2. Update version in plugin/.claude-plugin/plugin.json
# 3. Update version at top of CLAUDE.md
# 4. Update version badge in README.md
# 5. Run: npm run build && npm run sync-marketplace

# Or use npm version command:
npm version 4.3.2

# Update changelog
# Edit CHANGELOG.md manually

# Commit
git add .
git commit -m "chore: Release v4.3.2"

# Tag
git tag v4.3.2

# Push
git push origin main --tags

# Publish to NPM
npm run release

贡献

贡献工作流程

  1. 派生该仓库
  2. 创建一个功能分支 (git checkout -b feature/amazing-feature)
  3. 进行更改
  4. 编写测试
  5. 更新文档
  6. 提交你的更改 (git commit -m 'Add amazing feature')
  7. 推送到分支 (git push origin feature/amazing-feature)
  8. 打开拉取请求

拉取请求指南

  • 清晰标题:描述该 PR 的作用
  • 描述:解释为什么需要进行更改
  • 测试:包括新功能的测试
  • 文档:根据需要更新文档
  • 更新日志:在 CHANGELOG.md 中添加条目
  • 提交:使用清晰、描述性的提交信息

代码审查流程

  1. 自动化测试必须通过
  2. 维护者的代码审查
  3. 处理反馈
  4. 最终批准
  5. 合并到主分支

开发工具

推荐的 VSCode 扩展

  • TypeScript
  • ESLint
  • 更漂亮
  • SQLite 查看器

有用的命令

bash
# Check TypeScript types
npx tsc --noEmit

# Lint code (if configured)
npm run lint

# Format code (if configured)
npm run format

# Clean build artifacts
rm -rf plugin/scripts/*.js plugin/scripts/*.cjs

开发故障排除

构建失败

  1. 清理 node_modules:

    bash
    rm -rf node_modules
    npm install
  2. 检查 Node.js 版本:

    bash
    node --version  # Should be >= 18.0.0
  3. 检查语法错误:

    bash
    npx tsc --noEmit

测试失败

  1. 检查数据库:

    bash
    rm ~/.claude-mem/claude-mem.db
    npm test
  2. 检查工作状态:

    bash
    npm run worker:status
  3. 查看日志:

    bash
    npm run worker:logs

Worker 进程无法启动

  1. 结束现有进程:

    bash
    npm run worker:stop
  2. 检查端口:

    bash
    lsof -i :37777
  3. 尝试自定义端口:

    bash
    
    npm run worker:start

下一步