# Context 构建测试计划 ## 概述 Context 构建系统负责组装发送给 Claude API 的系统提示和用户上下文。包括 git 状态获取、CLAUDE.md 文件发现与加载、系统提示拼装三部分。 ## 被测文件 | 文件 | 关键导出 | |------|----------| | `src/context.ts` | `getSystemContext`, `getUserContext`, `getGitStatus`, `setSystemPromptInjection` | | `src/utils/claudemd.ts` | `stripHtmlComments`, `getClaudeMds`, `isMemoryFilePath`, `getLargeMemoryFiles`, `filterInjectedMemoryFiles`, `getExternalClaudeMdIncludes`, `hasExternalClaudeMdIncludes`, `processMemoryFile`, `getMemoryFiles` | | `src/utils/systemPrompt.ts` | `buildEffectiveSystemPrompt` | --- ## 测试用例 ### src/utils/claudemd.ts — 纯函数部分 #### describe('stripHtmlComments') - test('strips block-level HTML comments') — `"text more"` → content 不含注释 - test('preserves inline content') — 行内文本保留 - test('preserves code block content') — ` ```html\n\n``` ` 内的注释不移除 - test('returns stripped: false when no comments') — 无注释时 stripped 为 false - test('returns stripped: true when comments exist') - test('handles empty string') — `""` → `{ content: "", stripped: false }` - test('handles multiple comments') — 多个注释全部移除 #### describe('getClaudeMds') - test('assembles memory files with type descriptions') — 不同 type 的文件有不同前缀描述 - test('includes instruction prompt prefix') — 输出包含指令前缀 - test('handles empty memory files array') — 空数组返回空字符串或最小前缀 - test('respects filter parameter') — filter 函数可过滤特定类型 - test('concatenates multiple files with separators') #### describe('isMemoryFilePath') - test('returns true for CLAUDE.md path') — `"/project/CLAUDE.md"` → true - test('returns true for .claude/rules/ path') — `"/project/.claude/rules/foo.md"` → true - test('returns true for memory file path') — `"~/.claude/memory/foo.md"` → true - test('returns false for regular file') — `"/project/src/main.ts"` → false - test('returns false for unrelated .md file') — `"/project/README.md"` → false #### describe('getLargeMemoryFiles') - test('returns files exceeding 40K chars') — 内容 > MAX_MEMORY_CHARACTER_COUNT 的文件被返回 - test('returns empty array when all files are small') - test('correctly identifies threshold boundary') #### describe('filterInjectedMemoryFiles') - test('filters out AutoMem type files') — feature flag 开启时移除自动记忆 - test('filters out TeamMem type files') - test('preserves other types') — 非 AutoMem/TeamMem 的文件保留 #### describe('getExternalClaudeMdIncludes') - test('returns includes from outside CWD') — 外部 @include 路径被识别 - test('returns empty array when all includes are internal') #### describe('hasExternalClaudeMdIncludes') - test('returns true when external includes exist') - test('returns false when no external includes') --- ### src/utils/systemPrompt.ts #### describe('buildEffectiveSystemPrompt') - test('returns default system prompt when no overrides') — 无任何覆盖时使用默认提示 - test('overrideSystemPrompt replaces everything') — override 模式替换全部内容 - test('customSystemPrompt replaces default') — `--system-prompt` 参数替换默认 - test('appendSystemPrompt is appended after main prompt') — append 在主提示之后 - test('agent definition replaces default prompt') — agent 模式使用 agent prompt - test('agent definition with append combines both') — agent prompt + append - test('override takes precedence over agent and custom') — 优先级最高 - test('returns array of strings') — 返回值为 SystemPrompt 类型(字符串数组) --- ### src/context.ts — 需 Mock 的部分 #### describe('getGitStatus') - test('returns formatted git status string') — 包含 branch、status、log、user - test('truncates status at 2000 chars') — 超长 status 被截断 - test('returns null in test environment') — `NODE_ENV=test` 时返回 null - test('returns null in non-git directory') — 非 git 仓库返回 null - test('runs git commands in parallel') — 多个 git 命令并行执行 #### describe('getSystemContext') - test('includes gitStatus key') — 返回对象包含 gitStatus - test('returns memoized result on subsequent calls') — 多次调用返回同一结果 - test('skips git when instructions disabled') #### describe('getUserContext') - test('includes currentDate key') — 返回对象包含当前日期 - test('includes claudeMd key when CLAUDE.md exists') — 加载 CLAUDE.md 内容 - test('respects CLAUDE_CODE_DISABLE_CLAUDE_MDS env') — 设置后不加载 CLAUDE.md - test('returns memoized result') #### describe('setSystemPromptInjection') - test('clears memoized context caches') — 调用后下次 getSystemContext/getUserContext 重新计算 - test('injection value is accessible via getSystemPromptInjection') --- ## Mock 需求 | 依赖 | Mock 方式 | 用途 | |------|-----------|------| | `execFileNoThrow` | `mock.module` | `getGitStatus` 中的 git 命令 | | `getMemoryFiles` | `mock.module` | `getUserContext` 中的 CLAUDE.md 加载 | | `getCwd` | `mock.module` | 路径解析上下文 | | `process.env.NODE_ENV` | 直接设置 | 测试环境检测 | | `process.env.CLAUDE_CODE_DISABLE_CLAUDE_MDS` | 直接设置 | 禁用 CLAUDE.md | ## 集成测试场景 放在 `tests/integration/context-build.test.ts`: ### describe('Context assembly pipeline') - test('getUserContext produces claudeMd containing CLAUDE.md content') — 端到端验证 CLAUDE.md 被正确加载到 context - test('buildEffectiveSystemPrompt + getUserContext produces complete prompt') — 系统提示 + 用户上下文完整性 - test('setSystemPromptInjection invalidates and rebuilds context') — 注入后重新构建上下文