Skip to content

2. MEMORY.md 设计

2.1 文件结构

markdown
# Project Memory

> Auto-generated memory file. Lines after 200 will be truncated.

## Tech Stack
- Framework: React 18 + TypeScript
- Build: Vite 5
- State: Zustand
- Styling: Tailwind CSS

## Project Structure
- `/src/components` - React components
- `/src/hooks` - Custom hooks
- `/src/store` - Zustand stores
- `/src/utils` - Utility functions

## Coding Conventions
- Use functional components with hooks
- Prefer named exports over default
- Use TypeScript strict mode
- Follow Airbnb style guide

## User Preferences
- Always use `tnpm` instead of `npm`
- Run `tnpm run lint:fix` after code changes
- Prefer composition over inheritance

## Important Decisions
- [2026-03-10] Migrated from Redux to Zustand for simpler state management
- [2026-03-08] Adopted Tailwind CSS for consistent styling

## Common Issues
- **Build errors**: Check Node version (requires 18+)
- **Type errors**: Run `tnpm run type-check` first

## Links to Detailed Memory
- [Debugging Guide](./debugging.md)
- [Component Patterns](./patterns.md)
- [API Integration](./api-integration.md)

2.2 自动管理机制

typescript
class MemoryManager {
  private memoryPath: string;
  private maxLines = 200;

  constructor(projectRoot: string) {
    this.memoryPath = path.join(
      projectRoot,
      '.claude',
      'projects',
      projectRoot.replace(/\//g, '-'),
      'memory',
      'MEMORY.md'
    );
  }

  // 读取记忆
  async read(): Promise<string> {
    if (!await fs.exists(this.memoryPath)) {
      return '';
    }

    const content = await fs.readFile(this.memoryPath, 'utf-8');
    const lines = content.split('\n');

    // 只返回前 200 行
    if (lines.length > this.maxLines) {
      return lines.slice(0, this.maxLines).join('\n') +
        '\n\n<!-- Truncated at 200 lines -->';
    }

    return content;
  }

  // 写入记忆
  async write(content: string) {
    await fs.ensureDir(path.dirname(this.memoryPath));
    await fs.writeFile(this.memoryPath, content, 'utf-8');
  }

  // 追加记忆
  async append(section: string, content: string) {
    const current = await this.read();
    const updated = this.insertOrUpdate(current, section, content);

    // 检查是否超过限制
    if (updated.split('\n').length > this.maxLines) {
      console.warn('⚠️ MEMORY.md exceeds 200 lines. Consider moving content to topic files.');
    }

    await this.write(updated);
  }

  // 插入或更新章节
  private insertOrUpdate(content: string, section: string, newContent: string): string {
    const sectionRegex = new RegExp(`## ${section}[\\s\\S]*?(?=## |$)`);

    if (sectionRegex.test(content)) {
      // 更新现有章节
      return content.replace(sectionRegex, `## ${section}\n${newContent}\n\n`);
    } else {
      // 添加新章节
      return content + `\n## ${section}\n${newContent}\n`;
    }
  }

  // 压缩记忆(当接近 200 行时)
  async compress() {
    const content = await this.read();
    const lines = content.split('\n');

    if (lines.length < 180) return;  // 还有空间

    // 1. 移除过时的决策记录
    const decisions = this.extractSection(content, 'Important Decisions');
    const recentDecisions = this.keepRecentOnly(decisions, 30);  // 只保留 30 天内的

    // 2. 将详细内容移到主题文件
    const detailedSections = ['Common Issues', 'Debugging Guide'];
    for (const section of detailedSections) {
      const sectionContent = this.extractSection(content, section);
      if (sectionContent.length > 500) {
        // 移到单独文件
        await this.moveToTopicFile(section, sectionContent);
        // 在 MEMORY.md 中保留链接
        content = this.replaceSection(
          content,
          section,
          `See [${section}](./${this.slugify(section)}.md)`
        );
      }
    }

    await this.write(content);
  }
}

前端面试知识库