#
tokens: 32325/50000 2/307 files (page 26/33)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 26 of 33. Use http://codebase.md/tosin2013/documcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .dockerignore
├── .eslintignore
├── .eslintrc.json
├── .github
│   ├── agents
│   │   ├── documcp-ast.md
│   │   ├── documcp-deploy.md
│   │   ├── documcp-memory.md
│   │   ├── documcp-test.md
│   │   └── documcp-tool.md
│   ├── copilot-instructions.md
│   ├── dependabot.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── automated-changelog.md
│   │   ├── bug_report.md
│   │   ├── bug_report.yml
│   │   ├── documentation_issue.md
│   │   ├── feature_request.md
│   │   ├── feature_request.yml
│   │   ├── npm-publishing-fix.md
│   │   └── release_improvements.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── release-drafter.yml
│   └── workflows
│       ├── auto-merge.yml
│       ├── ci.yml
│       ├── codeql.yml
│       ├── dependency-review.yml
│       ├── deploy-docs.yml
│       ├── README.md
│       ├── release-drafter.yml
│       └── release.yml
├── .gitignore
├── .husky
│   ├── commit-msg
│   └── pre-commit
├── .linkcheck.config.json
├── .markdown-link-check.json
├── .nvmrc
├── .pre-commit-config.yaml
├── .versionrc.json
├── ARCHITECTURAL_CHANGES_SUMMARY.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── commitlint.config.js
├── CONTRIBUTING.md
├── docker-compose.docs.yml
├── Dockerfile.docs
├── docs
│   ├── .docusaurus
│   │   ├── docusaurus-plugin-content-docs
│   │   │   └── default
│   │   │       └── __mdx-loader-dependency.json
│   │   └── docusaurus-plugin-content-pages
│   │       └── default
│   │           └── __plugin.json
│   ├── adrs
│   │   ├── adr-0001-mcp-server-architecture.md
│   │   ├── adr-0002-repository-analysis-engine.md
│   │   ├── adr-0003-static-site-generator-recommendation-engine.md
│   │   ├── adr-0004-diataxis-framework-integration.md
│   │   ├── adr-0005-github-pages-deployment-automation.md
│   │   ├── adr-0006-mcp-tools-api-design.md
│   │   ├── adr-0007-mcp-prompts-and-resources-integration.md
│   │   ├── adr-0008-intelligent-content-population-engine.md
│   │   ├── adr-0009-content-accuracy-validation-framework.md
│   │   ├── adr-0010-mcp-resource-pattern-redesign.md
│   │   ├── adr-0011-ce-mcp-compatibility.md
│   │   ├── adr-0012-priority-scoring-system-for-documentation-drift.md
│   │   ├── adr-0013-release-pipeline-and-package-distribution.md
│   │   └── README.md
│   ├── api
│   │   ├── .nojekyll
│   │   ├── assets
│   │   │   ├── hierarchy.js
│   │   │   ├── highlight.css
│   │   │   ├── icons.js
│   │   │   ├── icons.svg
│   │   │   ├── main.js
│   │   │   ├── navigation.js
│   │   │   ├── search.js
│   │   │   └── style.css
│   │   ├── hierarchy.html
│   │   ├── index.html
│   │   ├── modules.html
│   │   └── variables
│   │       └── TOOLS.html
│   ├── assets
│   │   └── logo.svg
│   ├── CE-MCP-FINDINGS.md
│   ├── development
│   │   └── MCP_INSPECTOR_TESTING.md
│   ├── docusaurus.config.js
│   ├── explanation
│   │   ├── architecture.md
│   │   └── index.md
│   ├── guides
│   │   ├── link-validation.md
│   │   ├── playwright-integration.md
│   │   └── playwright-testing-workflow.md
│   ├── how-to
│   │   ├── analytics-setup.md
│   │   ├── change-watcher.md
│   │   ├── custom-domains.md
│   │   ├── documentation-freshness-tracking.md
│   │   ├── drift-priority-scoring.md
│   │   ├── github-pages-deployment.md
│   │   ├── index.md
│   │   ├── llm-integration.md
│   │   ├── local-testing.md
│   │   ├── performance-optimization.md
│   │   ├── prompting-guide.md
│   │   ├── repository-analysis.md
│   │   ├── seo-optimization.md
│   │   ├── site-monitoring.md
│   │   ├── troubleshooting.md
│   │   └── usage-examples.md
│   ├── index.md
│   ├── knowledge-graph.md
│   ├── package-lock.json
│   ├── package.json
│   ├── phase-2-intelligence.md
│   ├── reference
│   │   ├── api-overview.md
│   │   ├── cli.md
│   │   ├── configuration.md
│   │   ├── deploy-pages.md
│   │   ├── index.md
│   │   ├── mcp-tools.md
│   │   └── prompt-templates.md
│   ├── research
│   │   ├── cross-domain-integration
│   │   │   └── README.md
│   │   ├── domain-1-mcp-architecture
│   │   │   ├── index.md
│   │   │   └── mcp-performance-research.md
│   │   ├── domain-2-repository-analysis
│   │   │   └── README.md
│   │   ├── domain-3-ssg-recommendation
│   │   │   ├── index.md
│   │   │   └── ssg-performance-analysis.md
│   │   ├── domain-4-diataxis-integration
│   │   │   └── README.md
│   │   ├── domain-5-github-deployment
│   │   │   ├── github-pages-security-analysis.md
│   │   │   └── index.md
│   │   ├── domain-6-api-design
│   │   │   └── README.md
│   │   ├── README.md
│   │   ├── research-integration-summary-2025-01-14.md
│   │   ├── research-progress-template.md
│   │   └── research-questions-2025-01-14.md
│   ├── robots.txt
│   ├── sidebars.js
│   ├── sitemap.xml
│   ├── src
│   │   └── css
│   │       └── custom.css
│   └── tutorials
│       ├── development-setup.md
│       ├── environment-setup.md
│       ├── first-deployment.md
│       ├── getting-started.md
│       ├── index.md
│       ├── memory-workflows.md
│       └── user-onboarding.md
├── ISSUE_IMPLEMENTATION_SUMMARY.md
├── jest.config.js
├── LICENSE
├── Makefile
├── MCP_PHASE2_IMPLEMENTATION.md
├── mcp-config-example.json
├── mcp.json
├── package-lock.json
├── package.json
├── README.md
├── release.sh
├── scripts
│   └── check-package-structure.cjs
├── SECURITY.md
├── setup-precommit.sh
├── src
│   ├── benchmarks
│   │   └── performance.ts
│   ├── index.ts
│   ├── memory
│   │   ├── contextual-retrieval.ts
│   │   ├── deployment-analytics.ts
│   │   ├── enhanced-manager.ts
│   │   ├── export-import.ts
│   │   ├── freshness-kg-integration.ts
│   │   ├── index.ts
│   │   ├── integration.ts
│   │   ├── kg-code-integration.ts
│   │   ├── kg-health.ts
│   │   ├── kg-integration.ts
│   │   ├── kg-link-validator.ts
│   │   ├── kg-storage.ts
│   │   ├── knowledge-graph.ts
│   │   ├── learning.ts
│   │   ├── manager.ts
│   │   ├── multi-agent-sharing.ts
│   │   ├── pruning.ts
│   │   ├── schemas.ts
│   │   ├── storage.ts
│   │   ├── temporal-analysis.ts
│   │   ├── user-preferences.ts
│   │   └── visualization.ts
│   ├── prompts
│   │   └── technical-writer-prompts.ts
│   ├── scripts
│   │   └── benchmark.ts
│   ├── templates
│   │   └── playwright
│   │       ├── accessibility.spec.template.ts
│   │       ├── Dockerfile.template
│   │       ├── docs-e2e.workflow.template.yml
│   │       ├── link-validation.spec.template.ts
│   │       └── playwright.config.template.ts
│   ├── tools
│   │   ├── analyze-deployments.ts
│   │   ├── analyze-readme.ts
│   │   ├── analyze-repository.ts
│   │   ├── change-watcher.ts
│   │   ├── check-documentation-links.ts
│   │   ├── cleanup-agent-artifacts.ts
│   │   ├── deploy-pages.ts
│   │   ├── detect-gaps.ts
│   │   ├── evaluate-readme-health.ts
│   │   ├── generate-config.ts
│   │   ├── generate-contextual-content.ts
│   │   ├── generate-llm-context.ts
│   │   ├── generate-readme-template.ts
│   │   ├── generate-technical-writer-prompts.ts
│   │   ├── kg-health-check.ts
│   │   ├── manage-preferences.ts
│   │   ├── manage-sitemap.ts
│   │   ├── optimize-readme.ts
│   │   ├── populate-content.ts
│   │   ├── readme-best-practices.ts
│   │   ├── recommend-ssg.ts
│   │   ├── setup-playwright-tests.ts
│   │   ├── setup-structure.ts
│   │   ├── simulate-execution.ts
│   │   ├── sync-code-to-docs.ts
│   │   ├── test-local-deployment.ts
│   │   ├── track-documentation-freshness.ts
│   │   ├── update-existing-documentation.ts
│   │   ├── validate-content.ts
│   │   ├── validate-documentation-freshness.ts
│   │   ├── validate-readme-checklist.ts
│   │   └── verify-deployment.ts
│   ├── types
│   │   └── api.ts
│   ├── utils
│   │   ├── artifact-detector.ts
│   │   ├── ast-analyzer.ts
│   │   ├── change-watcher.ts
│   │   ├── code-scanner.ts
│   │   ├── content-extractor.ts
│   │   ├── drift-detector.ts
│   │   ├── execution-simulator.ts
│   │   ├── freshness-tracker.ts
│   │   ├── language-parsers-simple.ts
│   │   ├── llm-client.ts
│   │   ├── permission-checker.ts
│   │   ├── semantic-analyzer.ts
│   │   ├── sitemap-generator.ts
│   │   ├── usage-metadata.ts
│   │   └── user-feedback-integration.ts
│   └── workflows
│       └── documentation-workflow.ts
├── test-docs-local.sh
├── tests
│   ├── api
│   │   └── mcp-responses.test.ts
│   ├── benchmarks
│   │   └── performance.test.ts
│   ├── call-graph-builder.test.ts
│   ├── change-watcher-priority.integration.test.ts
│   ├── change-watcher.test.ts
│   ├── edge-cases
│   │   └── error-handling.test.ts
│   ├── execution-simulator.test.ts
│   ├── functional
│   │   └── tools.test.ts
│   ├── integration
│   │   ├── kg-documentation-workflow.test.ts
│   │   ├── knowledge-graph-workflow.test.ts
│   │   ├── mcp-readme-tools.test.ts
│   │   ├── memory-mcp-tools.test.ts
│   │   ├── readme-technical-writer.test.ts
│   │   └── workflow.test.ts
│   ├── memory
│   │   ├── contextual-retrieval.test.ts
│   │   ├── enhanced-manager.test.ts
│   │   ├── export-import.test.ts
│   │   ├── freshness-kg-integration.test.ts
│   │   ├── kg-code-integration.test.ts
│   │   ├── kg-health.test.ts
│   │   ├── kg-link-validator.test.ts
│   │   ├── kg-storage-validation.test.ts
│   │   ├── kg-storage.test.ts
│   │   ├── knowledge-graph-documentation-examples.test.ts
│   │   ├── knowledge-graph-enhanced.test.ts
│   │   ├── knowledge-graph.test.ts
│   │   ├── learning.test.ts
│   │   ├── manager-advanced.test.ts
│   │   ├── manager.test.ts
│   │   ├── mcp-resource-integration.test.ts
│   │   ├── mcp-tool-persistence.test.ts
│   │   ├── schemas-documentation-examples.test.ts
│   │   ├── schemas.test.ts
│   │   ├── storage.test.ts
│   │   ├── temporal-analysis.test.ts
│   │   └── user-preferences.test.ts
│   ├── performance
│   │   ├── memory-load-testing.test.ts
│   │   └── memory-stress-testing.test.ts
│   ├── prompts
│   │   ├── guided-workflow-prompts.test.ts
│   │   └── technical-writer-prompts.test.ts
│   ├── server.test.ts
│   ├── setup.ts
│   ├── tools
│   │   ├── all-tools.test.ts
│   │   ├── analyze-coverage.test.ts
│   │   ├── analyze-deployments.test.ts
│   │   ├── analyze-readme.test.ts
│   │   ├── analyze-repository.test.ts
│   │   ├── check-documentation-links.test.ts
│   │   ├── cleanup-agent-artifacts.test.ts
│   │   ├── deploy-pages-kg-retrieval.test.ts
│   │   ├── deploy-pages-tracking.test.ts
│   │   ├── deploy-pages.test.ts
│   │   ├── detect-gaps.test.ts
│   │   ├── evaluate-readme-health.test.ts
│   │   ├── generate-contextual-content.test.ts
│   │   ├── generate-llm-context.test.ts
│   │   ├── generate-readme-template.test.ts
│   │   ├── generate-technical-writer-prompts.test.ts
│   │   ├── kg-health-check.test.ts
│   │   ├── manage-sitemap.test.ts
│   │   ├── optimize-readme.test.ts
│   │   ├── readme-best-practices.test.ts
│   │   ├── recommend-ssg-historical.test.ts
│   │   ├── recommend-ssg-preferences.test.ts
│   │   ├── recommend-ssg.test.ts
│   │   ├── simple-coverage.test.ts
│   │   ├── sync-code-to-docs.test.ts
│   │   ├── test-local-deployment.test.ts
│   │   ├── tool-error-handling.test.ts
│   │   ├── track-documentation-freshness.test.ts
│   │   ├── validate-content.test.ts
│   │   ├── validate-documentation-freshness.test.ts
│   │   └── validate-readme-checklist.test.ts
│   ├── types
│   │   └── type-safety.test.ts
│   └── utils
│       ├── artifact-detector.test.ts
│       ├── ast-analyzer.test.ts
│       ├── content-extractor.test.ts
│       ├── drift-detector-diataxis.test.ts
│       ├── drift-detector-priority.test.ts
│       ├── drift-detector.test.ts
│       ├── freshness-tracker.test.ts
│       ├── llm-client.test.ts
│       ├── semantic-analyzer.test.ts
│       ├── sitemap-generator.test.ts
│       ├── usage-metadata.test.ts
│       └── user-feedback-integration.test.ts
├── tsconfig.json
└── typedoc.json
```

# Files

--------------------------------------------------------------------------------
/tests/tools/validate-content.test.ts:
--------------------------------------------------------------------------------

```typescript
   1 | import { describe, it, expect, beforeEach, afterEach } from "@jest/globals";
   2 | import * as fs from "fs/promises";
   3 | import * as path from "path";
   4 | import {
   5 |   handleValidateDiataxisContent,
   6 |   validateGeneralContent,
   7 | } from "../../src/tools/validate-content.js";
   8 | import { ValidationResult } from "../../src/tools/validate-content.js";
   9 | 
  10 | describe("Content Validation Tool", () => {
  11 |   const testTempDir = path.join(__dirname, "../../.tmp/test-validation");
  12 | 
  13 |   beforeEach(async () => {
  14 |     // Create test directory
  15 |     await fs.mkdir(testTempDir, { recursive: true });
  16 |   });
  17 | 
  18 |   afterEach(async () => {
  19 |     // Clean up test directory
  20 |     try {
  21 |       await fs.rm(testTempDir, { recursive: true });
  22 |     } catch {
  23 |       // Ignore cleanup errors
  24 |     }
  25 |   });
  26 | 
  27 |   describe("Application Code Validation", () => {
  28 |     it("should detect application code path correctly", async () => {
  29 |       // Create mock application structure
  30 |       const appDir = path.join(testTempDir, "mock-app");
  31 |       await fs.mkdir(appDir, { recursive: true });
  32 |       await fs.mkdir(path.join(appDir, "src"), { recursive: true });
  33 |       await fs.writeFile(
  34 |         path.join(appDir, "package.json"),
  35 |         '{"name": "test-app"}',
  36 |       );
  37 | 
  38 |       // Create TypeScript file without documentation
  39 |       const tsFile = path.join(appDir, "src", "index.ts");
  40 |       await fs.writeFile(
  41 |         tsFile,
  42 |         `
  43 | export function undocumentedFunction(param: string): string {
  44 |   return param.toUpperCase();
  45 | }
  46 | 
  47 | export const anotherFunction = (value: number) => {
  48 |   if (value < 0) {
  49 |     throw new Error('Invalid value');
  50 |   }
  51 |   return value * 2;
  52 | };
  53 |       `.trim(),
  54 |       );
  55 | 
  56 |       const result = await handleValidateDiataxisContent({
  57 |         contentPath: appDir,
  58 |         validationType: "compliance",
  59 |         includeCodeValidation: true,
  60 |       });
  61 | 
  62 |       expect(result).toBeDefined();
  63 |       expect(result.issues).toBeDefined();
  64 | 
  65 |       // Should find issues with undocumented exported functions
  66 |       const undocumentedIssues = result.issues.filter((issue) =>
  67 |         issue.description.includes("lacks documentation"),
  68 |       );
  69 |       expect(undocumentedIssues.length).toBeGreaterThan(0);
  70 | 
  71 |       // Should find issues with undocumented error throwing
  72 |       const errorDocIssues = result.issues.filter((issue) =>
  73 |         issue.description.includes(
  74 |           "Error throwing code found without error documentation",
  75 |         ),
  76 |       );
  77 |       expect(errorDocIssues.length).toBeGreaterThan(0);
  78 |     });
  79 | 
  80 |     it("should validate application architecture structure", async () => {
  81 |       // Create mock application with missing directories
  82 |       const appDir = path.join(testTempDir, "incomplete-app");
  83 |       await fs.mkdir(appDir, { recursive: true });
  84 |       await fs.writeFile(
  85 |         path.join(appDir, "package.json"),
  86 |         '{"name": "incomplete-app"}',
  87 |       );
  88 | 
  89 |       // Missing tools and types directories
  90 |       await fs.mkdir(path.join(appDir, "src"), { recursive: true });
  91 |       await fs.writeFile(
  92 |         path.join(appDir, "src", "index.ts"),
  93 |         'export const app = "test";',
  94 |       );
  95 | 
  96 |       const result = await handleValidateDiataxisContent({
  97 |         contentPath: appDir,
  98 |         validationType: "compliance",
  99 |         includeCodeValidation: false,
 100 |       });
 101 | 
 102 |       const structureIssues = result.issues.filter(
 103 |         (issue) => issue.location.file === "application structure",
 104 |       );
 105 |       expect(structureIssues.length).toBeGreaterThan(0);
 106 | 
 107 |       // Should suggest missing tools directory
 108 |       const toolsIssue = structureIssues.find((issue) =>
 109 |         issue.description.includes("tools directory"),
 110 |       );
 111 |       expect(toolsIssue).toBeDefined();
 112 |     });
 113 | 
 114 |     it("should validate README structure", async () => {
 115 |       const appDir = path.join(testTempDir, "readme-test");
 116 |       await fs.mkdir(appDir, { recursive: true });
 117 |       await fs.mkdir(path.join(appDir, "src"), { recursive: true });
 118 |       await fs.writeFile(
 119 |         path.join(appDir, "package.json"),
 120 |         '{"name": "readme-test"}',
 121 |       );
 122 |       await fs.writeFile(
 123 |         path.join(appDir, "src", "index.ts"),
 124 |         'export const app = "test";',
 125 |       );
 126 | 
 127 |       // Create README with missing sections
 128 |       await fs.writeFile(
 129 |         path.join(appDir, "README.md"),
 130 |         `
 131 | This is a project without proper structure.
 132 | Some description here.
 133 |       `.trim(),
 134 |       );
 135 | 
 136 |       const result = await handleValidateDiataxisContent({
 137 |         contentPath: appDir,
 138 |         validationType: "compliance",
 139 |         includeCodeValidation: false,
 140 |       });
 141 | 
 142 |       // Application validation should find issues
 143 | 
 144 |       const readmeIssues = result.issues.filter(
 145 |         (issue) => issue.location.file === "README.md",
 146 |       );
 147 |       expect(readmeIssues.length).toBeGreaterThan(0);
 148 | 
 149 |       // Should find issues with README structure
 150 |       const structureIssue = readmeIssues.find((issue) =>
 151 |         issue.description.includes("lacks essential sections"),
 152 |       );
 153 |       expect(structureIssue).toBeDefined();
 154 |     });
 155 | 
 156 |     it("should detect properly documented functions", async () => {
 157 |       const appDir = path.join(testTempDir, "documented-app");
 158 |       await fs.mkdir(appDir, { recursive: true });
 159 |       await fs.mkdir(path.join(appDir, "src"), { recursive: true });
 160 |       await fs.writeFile(
 161 |         path.join(appDir, "package.json"),
 162 |         '{"name": "documented-app"}',
 163 |       );
 164 | 
 165 |       // Create well-documented TypeScript file
 166 |       const tsFile = path.join(appDir, "src", "documented.ts");
 167 |       await fs.writeFile(
 168 |         tsFile,
 169 |         `
 170 | /**
 171 |  * Converts a string to uppercase
 172 |  * @param param - The input string
 173 |  * @returns The uppercase string
 174 |  */
 175 | export function documentedFunction(param: string): string {
 176 |   return param.toUpperCase();
 177 | }
 178 | 
 179 | /**
 180 |  * Doubles a positive number
 181 |  * @param value - The input number (must be positive)
 182 |  * @returns The doubled value
 183 |  * @throws {Error} When value is negative
 184 |  */
 185 | export const wellDocumentedFunction = (value: number) => {
 186 |   if (value < 0) {
 187 |     throw new Error('Invalid value');
 188 |   }
 189 |   return value * 2;
 190 | };
 191 |       `.trim(),
 192 |       );
 193 | 
 194 |       const result = await handleValidateDiataxisContent({
 195 |         contentPath: appDir,
 196 |         validationType: "compliance",
 197 |         includeCodeValidation: true,
 198 |       });
 199 | 
 200 |       // Should have no undocumented issues since functions are properly documented
 201 |       const undocumentedIssues = result.issues.filter((issue) =>
 202 |         issue.description.includes("lacks documentation"),
 203 |       );
 204 |       expect(undocumentedIssues.length).toBe(0);
 205 | 
 206 |       // Should not complain about error documentation
 207 |       const errorDocIssues = result.issues.filter((issue) =>
 208 |         issue.description.includes(
 209 |           "Error throwing code found without error documentation",
 210 |         ),
 211 |       );
 212 |       expect(errorDocIssues.length).toBe(0);
 213 |     });
 214 |   });
 215 | 
 216 |   describe("Documentation Validation", () => {
 217 |     it("should detect documentation directory correctly", async () => {
 218 |       // Create mock documentation structure
 219 |       const docsDir = path.join(testTempDir, "docs");
 220 |       await fs.mkdir(docsDir, { recursive: true });
 221 |       await fs.mkdir(path.join(docsDir, "tutorials"), { recursive: true });
 222 | 
 223 |       await fs.writeFile(
 224 |         path.join(docsDir, "tutorials", "tutorial1.md"),
 225 |         `
 226 | # Tutorial 1
 227 | 
 228 | This is a tutorial without prerequisites section.
 229 | 
 230 | \`\`\`javascript
 231 | console.log("hello")
 232 | \`\`\`
 233 |       `.trim(),
 234 |       );
 235 | 
 236 |       const result = await handleValidateDiataxisContent({
 237 |         contentPath: docsDir,
 238 |         validationType: "compliance",
 239 |         includeCodeValidation: true,
 240 |       });
 241 | 
 242 |       expect(result).toBeDefined();
 243 | 
 244 |       // Should find Diataxis compliance issues
 245 |       const complianceIssues = result.issues.filter(
 246 |         (issue) => issue.category === "compliance",
 247 |       );
 248 |       expect(complianceIssues.length).toBeGreaterThan(0);
 249 | 
 250 |       // Should find missing prerequisites in tutorial
 251 |       const prereqIssue = complianceIssues.find((issue) =>
 252 |         issue.description.includes("prerequisites"),
 253 |       );
 254 |       expect(prereqIssue).toBeDefined();
 255 |     });
 256 | 
 257 |     it("should validate link integrity", async () => {
 258 |       const docsDir = path.join(testTempDir, "docs-links");
 259 |       await fs.mkdir(docsDir, { recursive: true });
 260 | 
 261 |       // Create file with broken internal link
 262 |       await fs.writeFile(
 263 |         path.join(docsDir, "index.md"),
 264 |         `
 265 | # Documentation
 266 | 
 267 | [Broken Link](./nonexistent.md)
 268 | [Another Link](./other.md)
 269 |       `.trim(),
 270 |       );
 271 | 
 272 |       // Create the referenced file
 273 |       await fs.writeFile(path.join(docsDir, "other.md"), "# Other Page");
 274 | 
 275 |       const result = await handleValidateDiataxisContent({
 276 |         contentPath: docsDir,
 277 |         validationType: "accuracy",
 278 |         includeCodeValidation: false,
 279 |       });
 280 | 
 281 |       const linkIssues = result.issues.filter((issue) =>
 282 |         issue.description.includes("Broken internal link"),
 283 |       );
 284 |       expect(linkIssues.length).toBe(1);
 285 | 
 286 |       const brokenLink = linkIssues[0];
 287 |       expect(brokenLink.description).toContain("nonexistent.md");
 288 |     });
 289 | 
 290 |     it("should validate code blocks in documentation", async () => {
 291 |       const docsDir = path.join(testTempDir, "docs-code");
 292 |       await fs.mkdir(docsDir, { recursive: true });
 293 | 
 294 |       await fs.writeFile(
 295 |         path.join(docsDir, "guide.md"),
 296 |         `
 297 | # Code Examples
 298 | 
 299 | \`\`\`javascript
 300 | // Missing semicolon
 301 | console.log("test")
 302 | \`\`\`
 303 | 
 304 | \`\`\`json
 305 | { "valid": "json" }
 306 | \`\`\`
 307 | 
 308 | \`\`\`json
 309 | { "invalid": json }
 310 | \`\`\`
 311 |       `.trim(),
 312 |       );
 313 | 
 314 |       const result = await handleValidateDiataxisContent({
 315 |         contentPath: docsDir,
 316 |         validationType: "all",
 317 |         includeCodeValidation: true,
 318 |       });
 319 | 
 320 |       expect(result.codeValidation).toBeDefined();
 321 |       expect(result.codeValidation!.exampleResults.length).toBeGreaterThan(0);
 322 | 
 323 |       // Should find JSON syntax error
 324 |       const jsonErrors = result.codeValidation!.exampleResults.filter((ex) =>
 325 |         ex.issues.some((issue) => issue.description.includes("Invalid JSON")),
 326 |       );
 327 |       expect(jsonErrors.length).toBeGreaterThan(0);
 328 |     });
 329 |   });
 330 | 
 331 |   describe("General Content Validation", () => {
 332 |     it("should validate general content with link checking", async () => {
 333 |       const contentDir = path.join(testTempDir, "general-content");
 334 |       await fs.mkdir(contentDir, { recursive: true });
 335 | 
 336 |       await fs.writeFile(
 337 |         path.join(contentDir, "page.md"),
 338 |         `
 339 | # Test Page
 340 | 
 341 | [Good Link](./existing.md)
 342 | [Bad Link](./missing.md)
 343 | 
 344 | \`\`\`js
 345 | console.log("missing semicolon")
 346 | \`\`\`
 347 |       `.trim(),
 348 |       );
 349 | 
 350 |       await fs.writeFile(
 351 |         path.join(contentDir, "existing.md"),
 352 |         "# Existing Page",
 353 |       );
 354 | 
 355 |       const result = await validateGeneralContent({
 356 |         contentPath: contentDir,
 357 |         validationType: "all",
 358 |         includeCodeValidation: true,
 359 |       });
 360 | 
 361 |       expect(result.success).toBe(false);
 362 |       expect(result.brokenLinks.length).toBe(1);
 363 |       expect(result.brokenLinks[0]).toContain("missing.md");
 364 |       expect(result.codeBlocksValidated).toBeGreaterThan(0);
 365 |       expect(result.codeErrors.length).toBeGreaterThan(0);
 366 |       expect(result.recommendations.length).toBeGreaterThan(0);
 367 |     });
 368 | 
 369 |     it("should pass validation for clean content", async () => {
 370 |       const contentDir = path.join(testTempDir, "clean-content");
 371 |       await fs.mkdir(contentDir, { recursive: true });
 372 | 
 373 |       await fs.writeFile(
 374 |         path.join(contentDir, "clean.md"),
 375 |         `
 376 | # Clean Page
 377 | 
 378 | [Good Link](./other.md)
 379 | 
 380 | \`\`\`json
 381 | { "valid": "json" }
 382 | \`\`\`
 383 |       `.trim(),
 384 |       );
 385 | 
 386 |       await fs.writeFile(path.join(contentDir, "other.md"), "# Other Page");
 387 | 
 388 |       const result = await validateGeneralContent({
 389 |         contentPath: contentDir,
 390 |         validationType: "all",
 391 |         includeCodeValidation: true,
 392 |       });
 393 | 
 394 |       expect(result.success).toBe(true);
 395 |       expect(result.brokenLinks.length).toBe(0);
 396 |       expect(result.recommendations).toContain(
 397 |         "Content validation passed - no critical issues found",
 398 |       );
 399 |     });
 400 |   });
 401 | 
 402 |   describe("Confidence Metrics", () => {
 403 |     it("should calculate confidence metrics correctly", async () => {
 404 |       const appDir = path.join(testTempDir, "confidence-test");
 405 |       await fs.mkdir(appDir, { recursive: true });
 406 |       await fs.mkdir(path.join(appDir, "src"), { recursive: true });
 407 |       await fs.writeFile(
 408 |         path.join(appDir, "package.json"),
 409 |         '{"name": "confidence-test"}',
 410 |       );
 411 |       await fs.writeFile(
 412 |         path.join(appDir, "src", "index.ts"),
 413 |         'export const test = "value";',
 414 |       );
 415 | 
 416 |       const result = await handleValidateDiataxisContent({
 417 |         contentPath: appDir,
 418 |         validationType: "all",
 419 |         includeCodeValidation: true,
 420 |       });
 421 | 
 422 |       expect(result.confidence).toBeDefined();
 423 |       expect(result.confidence.overall).toBeGreaterThan(0);
 424 |       expect(result.confidence.overall).toBeLessThanOrEqual(100);
 425 | 
 426 |       expect(result.confidence.breakdown).toBeDefined();
 427 |       expect(result.confidence.breakdown.technologyDetection).toBeDefined();
 428 |       expect(result.confidence.breakdown.codeExampleRelevance).toBeDefined();
 429 |       expect(
 430 |         result.confidence.breakdown.architecturalAssumptions,
 431 |       ).toBeDefined();
 432 |     });
 433 | 
 434 |     it("should provide recommendations based on confidence", async () => {
 435 |       const appDir = path.join(testTempDir, "recommendations-test");
 436 |       await fs.mkdir(appDir, { recursive: true });
 437 |       await fs.writeFile(
 438 |         path.join(appDir, "package.json"),
 439 |         '{"name": "recommendations-test"}',
 440 |       );
 441 | 
 442 |       // Create content that will generate issues
 443 |       await fs.writeFile(path.join(appDir, "README.md"), "No proper structure");
 444 | 
 445 |       const result = await handleValidateDiataxisContent({
 446 |         contentPath: appDir,
 447 |         validationType: "all",
 448 |         includeCodeValidation: false,
 449 |       });
 450 | 
 451 |       expect(result.recommendations).toBeDefined();
 452 |       expect(result.recommendations.length).toBeGreaterThan(0);
 453 |       expect(result.nextSteps).toBeDefined();
 454 |       expect(result.nextSteps.length).toBeGreaterThan(0);
 455 | 
 456 |       if (result.confidence.overall < 70) {
 457 |         expect(
 458 |           result.recommendations.some((rec) =>
 459 |             rec.includes("comprehensive review"),
 460 |           ),
 461 |         ).toBe(true);
 462 |       }
 463 |     });
 464 |   });
 465 | 
 466 |   describe("Error Handling and Edge Cases", () => {
 467 |     it("should handle non-existent content path gracefully", async () => {
 468 |       const nonExistentPath = path.join(testTempDir, "does-not-exist");
 469 | 
 470 |       const result = await handleValidateDiataxisContent({
 471 |         contentPath: nonExistentPath,
 472 |         validationType: "all",
 473 |         includeCodeValidation: false,
 474 |       });
 475 | 
 476 |       expect(result).toBeDefined();
 477 |       // The function handles non-existent paths gracefully but may still succeed
 478 |       expect(result.confidence).toBeDefined();
 479 |     });
 480 | 
 481 |     it("should handle empty directory", async () => {
 482 |       const emptyDir = path.join(testTempDir, "empty-dir");
 483 |       await fs.mkdir(emptyDir, { recursive: true });
 484 | 
 485 |       const result = await handleValidateDiataxisContent({
 486 |         contentPath: emptyDir,
 487 |         validationType: "all",
 488 |         includeCodeValidation: true,
 489 |       });
 490 | 
 491 |       expect(result).toBeDefined();
 492 |       expect(result.confidence.breakdown.architecturalAssumptions).toBeLessThan(
 493 |         80,
 494 |       );
 495 |     });
 496 | 
 497 |     it("should handle project context loading with analysis ID", async () => {
 498 |       const appDir = path.join(testTempDir, "context-test");
 499 |       await fs.mkdir(appDir, { recursive: true });
 500 |       await fs.writeFile(
 501 |         path.join(appDir, "package.json"),
 502 |         '{"name": "context-test"}',
 503 |       );
 504 | 
 505 |       // Create .documcp directory with analysis
 506 |       const docucmpDir = path.join(appDir, ".documcp", "analyses");
 507 |       await fs.mkdir(docucmpDir, { recursive: true });
 508 |       await fs.writeFile(
 509 |         path.join(docucmpDir, "test-analysis.json"),
 510 |         JSON.stringify({
 511 |           metadata: {
 512 |             projectName: "test-project",
 513 |             primaryLanguage: "TypeScript",
 514 |           },
 515 |           technologies: { framework: "React" },
 516 |           dependencies: { packages: ["react", "typescript"] },
 517 |         }),
 518 |       );
 519 | 
 520 |       const result = await handleValidateDiataxisContent({
 521 |         contentPath: appDir,
 522 |         analysisId: "test-analysis",
 523 |         validationType: "accuracy",
 524 |         includeCodeValidation: false,
 525 |       });
 526 | 
 527 |       expect(result).toBeDefined();
 528 |       expect(result.confidence).toBeDefined();
 529 |     });
 530 | 
 531 |     it("should handle missing analysis ID gracefully", async () => {
 532 |       const appDir = path.join(testTempDir, "missing-analysis");
 533 |       await fs.mkdir(appDir, { recursive: true });
 534 |       await fs.writeFile(
 535 |         path.join(appDir, "package.json"),
 536 |         '{"name": "missing-analysis"}',
 537 |       );
 538 | 
 539 |       const result = await handleValidateDiataxisContent({
 540 |         contentPath: appDir,
 541 |         analysisId: "non-existent-analysis",
 542 |         validationType: "accuracy",
 543 |         includeCodeValidation: false,
 544 |       });
 545 | 
 546 |       expect(result).toBeDefined();
 547 |       expect(result.confidence).toBeDefined();
 548 |     });
 549 | 
 550 |     it("should detect documentation directory correctly", async () => {
 551 |       const docsPath = path.join(testTempDir, "project", "docs");
 552 |       await fs.mkdir(docsPath, { recursive: true });
 553 |       await fs.writeFile(path.join(docsPath, "index.md"), "# Documentation");
 554 | 
 555 |       const result = await handleValidateDiataxisContent({
 556 |         contentPath: docsPath,
 557 |         validationType: "compliance",
 558 |         includeCodeValidation: false,
 559 |       });
 560 | 
 561 |       expect(result).toBeDefined();
 562 |       expect(result.confidence).toBeDefined();
 563 |       // Documentation directory should be processed
 564 |       expect(
 565 |         result.confidence.breakdown.architecturalAssumptions,
 566 |       ).toBeGreaterThan(0);
 567 |     });
 568 | 
 569 |     it("should handle different validation types", async () => {
 570 |       const appDir = path.join(testTempDir, "validation-types");
 571 |       await fs.mkdir(appDir, { recursive: true });
 572 |       await fs.writeFile(
 573 |         path.join(appDir, "test.md"),
 574 |         "# Test\n[broken link](./missing.md)",
 575 |       );
 576 | 
 577 |       // Test accuracy only
 578 |       const accuracyResult = await handleValidateDiataxisContent({
 579 |         contentPath: appDir,
 580 |         validationType: "accuracy",
 581 |         includeCodeValidation: false,
 582 |       });
 583 |       expect(accuracyResult).toBeDefined();
 584 | 
 585 |       // Test completeness only
 586 |       const completenessResult = await handleValidateDiataxisContent({
 587 |         contentPath: appDir,
 588 |         validationType: "completeness",
 589 |         includeCodeValidation: false,
 590 |       });
 591 |       expect(completenessResult).toBeDefined();
 592 | 
 593 |       // Test compliance only
 594 |       const complianceResult = await handleValidateDiataxisContent({
 595 |         contentPath: appDir,
 596 |         validationType: "compliance",
 597 |         includeCodeValidation: false,
 598 |       });
 599 |       expect(complianceResult).toBeDefined();
 600 |     });
 601 | 
 602 |     it("should handle code validation failure scenarios", async () => {
 603 |       const appDir = path.join(testTempDir, "code-validation-fail");
 604 |       await fs.mkdir(appDir, { recursive: true });
 605 | 
 606 |       // Create markdown with broken code examples
 607 |       await fs.writeFile(
 608 |         path.join(appDir, "broken-code.md"),
 609 |         `
 610 | # Broken Code Examples
 611 | 
 612 | \`\`\`javascript
 613 | // Syntax error
 614 | console.log("missing quote);
 615 | \`\`\`
 616 | 
 617 | \`\`\`json
 618 | { "invalid": json }
 619 | \`\`\`
 620 |       `.trim(),
 621 |       );
 622 | 
 623 |       const result = await handleValidateDiataxisContent({
 624 |         contentPath: appDir,
 625 |         validationType: "all",
 626 |         includeCodeValidation: true,
 627 |       });
 628 | 
 629 |       expect(result.codeValidation).toBeDefined();
 630 |       expect(result.codeValidation!.overallSuccess).toBe(false);
 631 |       expect(
 632 |         result.recommendations.some((rec) => rec.includes("Fix code examples")),
 633 |       ).toBe(true);
 634 |     });
 635 | 
 636 |     it("should generate risk factors for critical issues", async () => {
 637 |       const appDir = path.join(testTempDir, "risk-factors");
 638 |       await fs.mkdir(appDir, { recursive: true });
 639 | 
 640 |       // Create content with multiple critical issues
 641 |       await fs.writeFile(
 642 |         path.join(appDir, "critical-issues.md"),
 643 |         `
 644 | # Critical Issues
 645 | 
 646 | [Broken Link 1](./missing1.md)
 647 | [Broken Link 2](./missing2.md)
 648 | [Broken Link 3](./missing3.md)
 649 |       `.trim(),
 650 |       );
 651 | 
 652 |       const result = await handleValidateDiataxisContent({
 653 |         contentPath: appDir,
 654 |         validationType: "all",
 655 |         includeCodeValidation: false,
 656 |       });
 657 | 
 658 |       expect(result.confidence.riskFactors).toBeDefined();
 659 |       expect(result.confidence.riskFactors.length).toBeGreaterThan(0);
 660 | 
 661 |       const highRiskFactors = result.confidence.riskFactors.filter(
 662 |         (rf) => rf.type === "high",
 663 |       );
 664 |       expect(highRiskFactors.length).toBeGreaterThan(0);
 665 |     });
 666 | 
 667 |     it("should handle uncertainty flags and medium risk factors", async () => {
 668 |       const appDir = path.join(testTempDir, "uncertainty-test");
 669 |       await fs.mkdir(appDir, { recursive: true });
 670 | 
 671 |       // Create content that generates uncertainties
 672 |       await fs.writeFile(
 673 |         path.join(appDir, "uncertain.md"),
 674 |         `
 675 | # Uncertain Content
 676 | 
 677 | This content has many ambiguous references and unclear instructions.
 678 | Multiple areas need clarification for proper understanding.
 679 |       `.trim(),
 680 |       );
 681 | 
 682 |       const result = await handleValidateDiataxisContent({
 683 |         contentPath: appDir,
 684 |         validationType: "all",
 685 |         includeCodeValidation: false,
 686 |       });
 687 | 
 688 |       // Manually add uncertainties to test the risk factor generation
 689 |       result.uncertainties = [
 690 |         {
 691 |           area: "test1",
 692 |           severity: "high",
 693 |           description: "test",
 694 |           potentialImpact: "test",
 695 |           clarificationNeeded: "test",
 696 |           fallbackStrategy: "test",
 697 |         },
 698 |         {
 699 |           area: "test2",
 700 |           severity: "high",
 701 |           description: "test",
 702 |           potentialImpact: "test",
 703 |           clarificationNeeded: "test",
 704 |           fallbackStrategy: "test",
 705 |         },
 706 |         {
 707 |           area: "test3",
 708 |           severity: "high",
 709 |           description: "test",
 710 |           potentialImpact: "test",
 711 |           clarificationNeeded: "test",
 712 |           fallbackStrategy: "test",
 713 |         },
 714 |         {
 715 |           area: "test4",
 716 |           severity: "high",
 717 |           description: "test",
 718 |           potentialImpact: "test",
 719 |           clarificationNeeded: "test",
 720 |           fallbackStrategy: "test",
 721 |         },
 722 |         {
 723 |           area: "test5",
 724 |           severity: "high",
 725 |           description: "test",
 726 |           potentialImpact: "test",
 727 |           clarificationNeeded: "test",
 728 |           fallbackStrategy: "test",
 729 |         },
 730 |         {
 731 |           area: "test6",
 732 |           severity: "high",
 733 |           description: "test",
 734 |           potentialImpact: "test",
 735 |           clarificationNeeded: "test",
 736 |           fallbackStrategy: "test",
 737 |         },
 738 |       ];
 739 | 
 740 |       expect(result.uncertainties.length).toBeGreaterThan(5);
 741 | 
 742 |       const highUncertainties = result.uncertainties.filter(
 743 |         (u) => u.severity === "high" || u.severity === "critical",
 744 |       );
 745 |       expect(highUncertainties.length).toBeGreaterThan(0);
 746 |     });
 747 | 
 748 |     it("should handle Diataxis structure analysis", async () => {
 749 |       const docsDir = path.join(testTempDir, "diataxis-structure");
 750 |       await fs.mkdir(docsDir, { recursive: true });
 751 | 
 752 |       // Create Diataxis structure
 753 |       await fs.mkdir(path.join(docsDir, "tutorials"), { recursive: true });
 754 |       await fs.mkdir(path.join(docsDir, "how-to"), { recursive: true });
 755 |       await fs.mkdir(path.join(docsDir, "reference"), { recursive: true });
 756 |       await fs.mkdir(path.join(docsDir, "explanation"), { recursive: true });
 757 | 
 758 |       await fs.writeFile(
 759 |         path.join(docsDir, "tutorials", "tutorial.md"),
 760 |         "# Tutorial",
 761 |       );
 762 |       await fs.writeFile(
 763 |         path.join(docsDir, "how-to", "guide.md"),
 764 |         "# How-to Guide",
 765 |       );
 766 |       await fs.writeFile(
 767 |         path.join(docsDir, "reference", "api.md"),
 768 |         "# API Reference",
 769 |       );
 770 |       await fs.writeFile(
 771 |         path.join(docsDir, "explanation", "concept.md"),
 772 |         "# Explanation",
 773 |       );
 774 | 
 775 |       const result = await handleValidateDiataxisContent({
 776 |         contentPath: docsDir,
 777 |         validationType: "compliance",
 778 |         includeCodeValidation: false,
 779 |       });
 780 | 
 781 |       expect(result).toBeDefined();
 782 |       expect(
 783 |         result.confidence.breakdown.architecturalAssumptions,
 784 |       ).toBeGreaterThan(60);
 785 |     });
 786 | 
 787 |     it("should handle successful validation with no issues", async () => {
 788 |       const cleanDir = path.join(testTempDir, "clean-validation");
 789 |       await fs.mkdir(cleanDir, { recursive: true });
 790 | 
 791 |       // Create clean content with no issues
 792 |       await fs.writeFile(
 793 |         path.join(cleanDir, "clean.md"),
 794 |         `
 795 | # Clean Documentation
 796 | 
 797 | This is well-structured documentation with no issues.
 798 | 
 799 | \`\`\`json
 800 | { "valid": "json" }
 801 | \`\`\`
 802 |       `.trim(),
 803 |       );
 804 | 
 805 |       const result = await handleValidateDiataxisContent({
 806 |         contentPath: cleanDir,
 807 |         validationType: "all",
 808 |         includeCodeValidation: true,
 809 |       });
 810 | 
 811 |       // Should have minimal issues and good confidence
 812 |       expect(result.confidence.overall).toBeGreaterThan(0);
 813 |       expect(result.recommendations).toBeDefined();
 814 |       expect(result.recommendations.length).toBeGreaterThan(0);
 815 |     });
 816 | 
 817 |     it("should handle timeout scenarios", async () => {
 818 |       // Test timeout handling by creating a scenario that might take time
 819 |       const largeDir = path.join(testTempDir, "timeout-test");
 820 |       await fs.mkdir(largeDir, { recursive: true });
 821 | 
 822 |       // Create multiple markdown files to simulate processing time
 823 |       for (let i = 0; i < 5; i++) {
 824 |         await fs.writeFile(
 825 |           path.join(largeDir, `file${i}.md`),
 826 |           `
 827 | # File ${i}
 828 | 
 829 | Content for file ${i} with some text.
 830 | 
 831 | \`\`\`javascript
 832 | console.log("File ${i}");
 833 | \`\`\`
 834 |         `.trim(),
 835 |         );
 836 |       }
 837 | 
 838 |       const result = await handleValidateDiataxisContent({
 839 |         contentPath: largeDir,
 840 |         validationType: "all",
 841 |         includeCodeValidation: true,
 842 |       });
 843 | 
 844 |       expect(result).toBeDefined();
 845 |       expect(result.confidence).toBeDefined();
 846 |     });
 847 | 
 848 |     it("should handle confidence levels and validation modes", async () => {
 849 |       const testDir = path.join(testTempDir, "confidence-levels");
 850 |       await fs.mkdir(testDir, { recursive: true });
 851 |       await fs.writeFile(path.join(testDir, "test.md"), "# Test Content");
 852 | 
 853 |       // Test different confidence levels
 854 |       const strictResult = await handleValidateDiataxisContent({
 855 |         contentPath: testDir,
 856 |         validationType: "all",
 857 |         includeCodeValidation: false,
 858 |         confidence: "strict",
 859 |       });
 860 |       expect(strictResult).toBeDefined();
 861 | 
 862 |       const moderateResult = await handleValidateDiataxisContent({
 863 |         contentPath: testDir,
 864 |         validationType: "all",
 865 |         includeCodeValidation: false,
 866 |         confidence: "moderate",
 867 |       });
 868 |       expect(moderateResult).toBeDefined();
 869 | 
 870 |       const permissiveResult = await handleValidateDiataxisContent({
 871 |         contentPath: testDir,
 872 |         validationType: "all",
 873 |         includeCodeValidation: false,
 874 |         confidence: "permissive",
 875 |       });
 876 |       expect(permissiveResult).toBeDefined();
 877 |     });
 878 | 
 879 |     it("should handle TypeScript files without package.json", async () => {
 880 |       const tsDir = path.join(testTempDir, "typescript-only");
 881 |       await fs.mkdir(tsDir, { recursive: true });
 882 |       await fs.mkdir(path.join(tsDir, "src"), { recursive: true });
 883 | 
 884 |       // Create TypeScript files without package.json
 885 |       await fs.writeFile(
 886 |         path.join(tsDir, "src", "app.ts"),
 887 |         `
 888 | export class TestClass {
 889 |   public method(): void {
 890 |     console.log('test');
 891 |   }
 892 | }
 893 |       `.trim(),
 894 |       );
 895 | 
 896 |       const result = await handleValidateDiataxisContent({
 897 |         contentPath: tsDir,
 898 |         validationType: "compliance",
 899 |         includeCodeValidation: false,
 900 |       });
 901 | 
 902 |       expect(result).toBeDefined();
 903 |       expect(result.confidence).toBeDefined();
 904 |     });
 905 | 
 906 |     it("should handle mixed content scenarios", async () => {
 907 |       const mixedDir = path.join(testTempDir, "mixed-content");
 908 |       await fs.mkdir(mixedDir, { recursive: true });
 909 |       await fs.mkdir(path.join(mixedDir, "src"), { recursive: true });
 910 | 
 911 |       // Create both application and documentation content
 912 |       await fs.writeFile(
 913 |         path.join(mixedDir, "package.json"),
 914 |         '{"name": "mixed-app"}',
 915 |       );
 916 |       await fs.writeFile(
 917 |         path.join(mixedDir, "src", "index.ts"),
 918 |         'export const app = "test";',
 919 |       );
 920 |       await fs.writeFile(
 921 |         path.join(mixedDir, "README.md"),
 922 |         `
 923 | # Mixed Content App
 924 | 
 925 | ## Installation
 926 | 
 927 | Run \`npm install\`
 928 | 
 929 | ## Usage
 930 | 
 931 | See the documentation.
 932 |       `.trim(),
 933 |       );
 934 | 
 935 |       const result = await handleValidateDiataxisContent({
 936 |         contentPath: mixedDir,
 937 |         validationType: "all",
 938 |         includeCodeValidation: true,
 939 |       });
 940 | 
 941 |       expect(result).toBeDefined();
 942 |       expect(
 943 |         result.confidence.breakdown.architecturalAssumptions,
 944 |       ).toBeGreaterThanOrEqual(60);
 945 |     });
 946 | 
 947 |     it("should handle business context alignment scoring", async () => {
 948 |       const businessDir = path.join(testTempDir, "business-context");
 949 |       await fs.mkdir(businessDir, { recursive: true });
 950 | 
 951 |       // Create content with business context
 952 |       await fs.writeFile(
 953 |         path.join(businessDir, "business.md"),
 954 |         `
 955 | # Business Requirements
 956 | 
 957 | This application serves enterprise customers with specific needs.
 958 | The solution addresses market requirements and business objectives.
 959 |       `.trim(),
 960 |       );
 961 | 
 962 |       const result = await handleValidateDiataxisContent({
 963 |         contentPath: businessDir,
 964 |         validationType: "all",
 965 |         includeCodeValidation: false,
 966 |       });
 967 | 
 968 |       expect(result).toBeDefined();
 969 |       expect(
 970 |         result.confidence.breakdown.businessContextAlignment,
 971 |       ).toBeGreaterThanOrEqual(0);
 972 |     });
 973 | 
 974 |     it("should handle deprecated patterns in technical accuracy checks", async () => {
 975 |       const deprecatedDir = path.join(testTempDir, "deprecated-patterns");
 976 |       await fs.mkdir(deprecatedDir, { recursive: true });
 977 | 
 978 |       await fs.writeFile(
 979 |         path.join(deprecatedDir, "deprecated.md"),
 980 |         `
 981 | # Deprecated Patterns
 982 | 
 983 | \`\`\`bash
 984 | npm install -g some-package
 985 | \`\`\`
 986 | 
 987 | \`\`\`javascript
 988 | var oldVariable = "test";
 989 | function() {
 990 |   console.log("old style");
 991 | }
 992 | \`\`\`
 993 | 
 994 | Visit http://example.com for more info.
 995 |       `.trim(),
 996 |       );
 997 | 
 998 |       const result = await handleValidateDiataxisContent({
 999 |         contentPath: deprecatedDir,
1000 |         validationType: "accuracy",
1001 |         includeCodeValidation: false,
1002 |       });
1003 | 
1004 |       const deprecatedIssues = result.issues.filter((issue) =>
1005 |         issue.description.includes("Potentially outdated pattern"),
1006 |       );
1007 |       expect(deprecatedIssues.length).toBeGreaterThan(0);
1008 |     });
1009 | 
1010 |     it("should handle async code without error handling", async () => {
1011 |       const asyncDir = path.join(testTempDir, "async-code");
1012 |       await fs.mkdir(asyncDir, { recursive: true });
1013 | 
1014 |       await fs.writeFile(
1015 |         path.join(asyncDir, "async.md"),
1016 |         `
1017 | # Async Code Examples
1018 | 
1019 | \`\`\`javascript
1020 | async function fetchData() {
1021 |   const response = await fetch('/api/data');
1022 |   return response.json();
1023 | }
1024 | \`\`\`
1025 | 
1026 | \`\`\`typescript
1027 | const getData = async (): Promise<any> => {
1028 |   const result = await someAsyncOperation();
1029 |   return result;
1030 | };
1031 | \`\`\`
1032 |       `.trim(),
1033 |       );
1034 | 
1035 |       const result = await handleValidateDiataxisContent({
1036 |         contentPath: asyncDir,
1037 |         validationType: "accuracy",
1038 |         includeCodeValidation: false,
1039 |       });
1040 | 
1041 |       const asyncIssues = result.issues.filter((issue) =>
1042 |         issue.description.includes("Async code without error handling"),
1043 |       );
1044 |       expect(asyncIssues.length).toBeGreaterThan(0);
1045 |     });
1046 | 
1047 |     it("should handle version compatibility checks with project context", async () => {
1048 |       const versionDir = path.join(testTempDir, "version-compat");
1049 |       await fs.mkdir(versionDir, { recursive: true });
1050 | 
1051 |       // Create .documcp directory with analysis
1052 |       const docucmpDir = path.join(versionDir, ".documcp", "analyses");
1053 |       await fs.mkdir(docucmpDir, { recursive: true });
1054 |       await fs.writeFile(
1055 |         path.join(docucmpDir, "version-analysis.json"),
1056 |         JSON.stringify({
1057 |           metadata: {
1058 |             projectName: "version-test",
1059 |             primaryLanguage: "TypeScript",
1060 |           },
1061 |           technologies: { framework: "React" },
1062 |           dependencies: { packages: ["[email protected]", "[email protected]"] },
1063 |         }),
1064 |       );
1065 | 
1066 |       await fs.writeFile(
1067 |         path.join(versionDir, "versions.md"),
1068 |         `
1069 | # Version Information
1070 | 
1071 | This project uses React @18.2.0 and TypeScript @4.9.0.
1072 | Also compatible with Node.js @16.14.0.
1073 |       `.trim(),
1074 |       );
1075 | 
1076 |       const result = await handleValidateDiataxisContent({
1077 |         contentPath: versionDir,
1078 |         analysisId: "version-analysis",
1079 |         validationType: "accuracy",
1080 |         includeCodeValidation: false,
1081 |       });
1082 | 
1083 |       const versionUncertainties = result.uncertainties.filter(
1084 |         (u) => u.area === "version-compatibility",
1085 |       );
1086 |       expect(versionUncertainties.length).toBeGreaterThan(0);
1087 |     });
1088 | 
1089 |     it("should handle dangerous bash commands", async () => {
1090 |       const bashDir = path.join(testTempDir, "dangerous-bash");
1091 |       await fs.mkdir(bashDir, { recursive: true });
1092 | 
1093 |       await fs.writeFile(
1094 |         path.join(bashDir, "dangerous.md"),
1095 |         `
1096 | # Dangerous Commands
1097 | 
1098 | \`\`\`bash
1099 | rm -rf /
1100 | sudo rm -rf /tmp/important
1101 | chmod 777 /etc/passwd
1102 | command > /dev/null 2>&1
1103 | \`\`\`
1104 |       `.trim(),
1105 |       );
1106 | 
1107 |       const result = await handleValidateDiataxisContent({
1108 |         contentPath: bashDir,
1109 |         validationType: "accuracy",
1110 |         includeCodeValidation: false,
1111 |       });
1112 | 
1113 |       const dangerousIssues = result.issues.filter((issue) =>
1114 |         issue.description.includes("Potentially dangerous command"),
1115 |       );
1116 |       expect(dangerousIssues.length).toBeGreaterThan(0);
1117 |     });
1118 | 
1119 |     it("should handle mixed path separators in commands", async () => {
1120 |       const pathDir = path.join(testTempDir, "mixed-paths");
1121 |       await fs.mkdir(pathDir, { recursive: true });
1122 | 
1123 |       await fs.writeFile(
1124 |         path.join(pathDir, "paths.md"),
1125 |         `
1126 | # Mixed Path Examples
1127 | 
1128 | \`\`\`bash
1129 | cp /unix/path\\windows\\mixed /destination/path
1130 | \`\`\`
1131 |       `.trim(),
1132 |       );
1133 | 
1134 |       const result = await handleValidateDiataxisContent({
1135 |         contentPath: pathDir,
1136 |         validationType: "accuracy",
1137 |         includeCodeValidation: false,
1138 |       });
1139 | 
1140 |       const pathIssues = result.issues.filter((issue) =>
1141 |         issue.description.includes("Mixed path separators"),
1142 |       );
1143 |       expect(pathIssues.length).toBeGreaterThan(0);
1144 |     });
1145 | 
1146 |     it("should handle external links in accuracy validation", async () => {
1147 |       const linksDir = path.join(testTempDir, "external-links");
1148 |       await fs.mkdir(linksDir, { recursive: true });
1149 | 
1150 |       await fs.writeFile(
1151 |         path.join(linksDir, "external.md"),
1152 |         `
1153 | # External Links
1154 | 
1155 | [GitHub](https://github.com)
1156 | [Documentation](https://docs.example.com)
1157 |       `.trim(),
1158 |       );
1159 | 
1160 |       const result = await handleValidateDiataxisContent({
1161 |         contentPath: linksDir,
1162 |         validationType: "accuracy",
1163 |         includeCodeValidation: false,
1164 |       });
1165 | 
1166 |       const linkUncertainties = result.uncertainties.filter(
1167 |         (u) => u.area === "external-links",
1168 |       );
1169 |       expect(linkUncertainties.length).toBeGreaterThan(0);
1170 |     });
1171 | 
1172 |     it("should handle Diataxis compliance rules for different sections", async () => {
1173 |       const complianceDir = path.join(testTempDir, "diataxis-compliance");
1174 |       await fs.mkdir(complianceDir, { recursive: true });
1175 | 
1176 |       // Create directories for each Diataxis section
1177 |       await fs.mkdir(path.join(complianceDir, "tutorials"), {
1178 |         recursive: true,
1179 |       });
1180 |       await fs.mkdir(path.join(complianceDir, "how-to"), { recursive: true });
1181 |       await fs.mkdir(path.join(complianceDir, "reference"), {
1182 |         recursive: true,
1183 |       });
1184 |       await fs.mkdir(path.join(complianceDir, "explanation"), {
1185 |         recursive: true,
1186 |       });
1187 | 
1188 |       // Tutorial without prerequisites
1189 |       await fs.writeFile(
1190 |         path.join(complianceDir, "tutorials", "bad-tutorial.md"),
1191 |         `
1192 | # Bad Tutorial
1193 | 
1194 | This tutorial doesn't have prerequisites or clear steps.
1195 |       `.trim(),
1196 |       );
1197 | 
1198 |       // How-to without task focus
1199 |       await fs.writeFile(
1200 |         path.join(complianceDir, "how-to", "bad-howto.md"),
1201 |         `
1202 | # Bad Guide
1203 | 
1204 | Short guide.
1205 |       `.trim(),
1206 |       );
1207 | 
1208 |       // Reference without structure
1209 |       await fs.writeFile(
1210 |         path.join(complianceDir, "reference", "bad-reference.md"),
1211 |         `
1212 | Bad reference without headings or tables.
1213 |       `.trim(),
1214 |       );
1215 | 
1216 |       // Explanation without "why"
1217 |       await fs.writeFile(
1218 |         path.join(complianceDir, "explanation", "bad-explanation.md"),
1219 |         `
1220 | # Bad Explanation
1221 | 
1222 | Short explanation.
1223 |       `.trim(),
1224 |       );
1225 | 
1226 |       const result = await handleValidateDiataxisContent({
1227 |         contentPath: complianceDir,
1228 |         validationType: "compliance",
1229 |         includeCodeValidation: false,
1230 |       });
1231 | 
1232 |       const complianceIssues = result.issues.filter(
1233 |         (issue) => issue.category === "compliance",
1234 |       );
1235 |       expect(complianceIssues.length).toBeGreaterThan(4); // Should find issues in each section
1236 |     });
1237 | 
1238 |     it("should handle TypeScript code validation with compilation errors", async () => {
1239 |       const tsDir = path.join(testTempDir, "typescript-validation");
1240 |       await fs.mkdir(tsDir, { recursive: true });
1241 | 
1242 |       await fs.writeFile(
1243 |         path.join(tsDir, "typescript.md"),
1244 |         `
1245 | # TypeScript Examples
1246 | 
1247 | \`\`\`typescript
1248 | // This has type errors
1249 | let x: string = 123;
1250 | function badFunction(param: number): string {
1251 |   return param; // Type error
1252 | }
1253 | \`\`\`
1254 |       `.trim(),
1255 |       );
1256 | 
1257 |       const result = await handleValidateDiataxisContent({
1258 |         contentPath: tsDir,
1259 |         validationType: "all",
1260 |         includeCodeValidation: true,
1261 |       });
1262 | 
1263 |       expect(result.codeValidation).toBeDefined();
1264 |       expect(result.codeValidation!.overallSuccess).toBe(false);
1265 |     });
1266 | 
1267 |     it("should handle bash code validation with complex chaining", async () => {
1268 |       const bashComplexDir = path.join(testTempDir, "bash-complex");
1269 |       await fs.mkdir(bashComplexDir, { recursive: true });
1270 | 
1271 |       await fs.writeFile(
1272 |         path.join(bashComplexDir, "complex-bash.md"),
1273 |         `
1274 | # Complex Bash
1275 | 
1276 | \`\`\`bash
1277 | # Complex command chaining
1278 | command1 && command2 || command3
1279 | rm $VARIABLE
1280 | \`\`\`
1281 |       `.trim(),
1282 |       );
1283 | 
1284 |       const result = await handleValidateDiataxisContent({
1285 |         contentPath: bashComplexDir,
1286 |         validationType: "all",
1287 |         includeCodeValidation: true,
1288 |       });
1289 | 
1290 |       expect(result.codeValidation).toBeDefined();
1291 |       const bashIssues = result.codeValidation!.exampleResults.flatMap(
1292 |         (ex) => ex.issues,
1293 |       );
1294 |       expect(bashIssues.length).toBeGreaterThan(0);
1295 |     });
1296 | 
1297 |     it("should handle file limit reached scenario", async () => {
1298 |       const largeDir = path.join(testTempDir, "large-directory");
1299 |       await fs.mkdir(largeDir, { recursive: true });
1300 | 
1301 |       // Create many markdown files to test file limit
1302 |       for (let i = 0; i < 10; i++) {
1303 |         await fs.writeFile(
1304 |           path.join(largeDir, `file${i}.md`),
1305 |           `# File ${i}\nContent for file ${i}.`,
1306 |         );
1307 |       }
1308 | 
1309 |       const result = await handleValidateDiataxisContent({
1310 |         contentPath: largeDir,
1311 |         validationType: "all",
1312 |         includeCodeValidation: false,
1313 |       });
1314 | 
1315 |       expect(result).toBeDefined();
1316 |       expect(
1317 |         result.confidence.breakdown.architecturalAssumptions,
1318 |       ).toBeGreaterThan(60);
1319 |     });
1320 | 
1321 |     it("should handle symlink detection in file scanning", async () => {
1322 |       const symlinkDir = path.join(testTempDir, "symlink-test");
1323 |       await fs.mkdir(symlinkDir, { recursive: true });
1324 | 
1325 |       // Create a regular file
1326 |       await fs.writeFile(path.join(symlinkDir, "regular.md"), "# Regular File");
1327 | 
1328 |       // Create a subdirectory
1329 |       await fs.mkdir(path.join(symlinkDir, "subdir"), { recursive: true });
1330 |       await fs.writeFile(
1331 |         path.join(symlinkDir, "subdir", "nested.md"),
1332 |         "# Nested File",
1333 |       );
1334 | 
1335 |       const result = await handleValidateDiataxisContent({
1336 |         contentPath: symlinkDir,
1337 |         validationType: "all",
1338 |         includeCodeValidation: false,
1339 |       });
1340 | 
1341 |       expect(result).toBeDefined();
1342 |       expect(
1343 |         result.confidence.breakdown.architecturalAssumptions,
1344 |       ).toBeGreaterThanOrEqual(60);
1345 |     });
1346 | 
1347 |     it("should handle timeout scenario", async () => {
1348 |       const timeoutDir = path.join(testTempDir, "timeout-scenario");
1349 |       await fs.mkdir(timeoutDir, { recursive: true });
1350 |       await fs.writeFile(path.join(timeoutDir, "test.md"), "# Test");
1351 | 
1352 |       // Mock a timeout by creating a very short timeout
1353 |       const originalTimeout = 120000;
1354 | 
1355 |       const result = await handleValidateDiataxisContent({
1356 |         contentPath: timeoutDir,
1357 |         validationType: "all",
1358 |         includeCodeValidation: false,
1359 |       });
1360 | 
1361 |       expect(result).toBeDefined();
1362 |     });
1363 | 
1364 |     it("should handle general content validation with external links", async () => {
1365 |       const generalDir = path.join(testTempDir, "general-external");
1366 |       await fs.mkdir(generalDir, { recursive: true });
1367 | 
1368 |       await fs.writeFile(
1369 |         path.join(generalDir, "external.md"),
1370 |         `
1371 | # External Links Test
1372 | 
1373 | [GitHub](https://github.com)
1374 | [Local](./local.md)
1375 |       `.trim(),
1376 |       );
1377 | 
1378 |       await fs.writeFile(path.join(generalDir, "local.md"), "# Local File");
1379 | 
1380 |       const result = await validateGeneralContent({
1381 |         contentPath: generalDir,
1382 |         validationType: "all",
1383 |         includeCodeValidation: true,
1384 |         followExternalLinks: false,
1385 |       });
1386 | 
1387 |       expect(result.linksChecked).toBeGreaterThan(0);
1388 |       expect(result.success).toBe(true);
1389 |     });
1390 | 
1391 |     it("should handle general content validation with code validation", async () => {
1392 |       const codeDir = path.join(testTempDir, "general-code");
1393 |       await fs.mkdir(codeDir, { recursive: true });
1394 | 
1395 |       await fs.writeFile(
1396 |         path.join(codeDir, "code.md"),
1397 |         `
1398 | # Code Test
1399 | 
1400 | \`\`\`javascript
1401 | console.log("test")
1402 | \`\`\`
1403 | 
1404 | \`\`\`js
1405 | console.log("another test");
1406 | \`\`\`
1407 |       `.trim(),
1408 |       );
1409 | 
1410 |       const result = await validateGeneralContent({
1411 |         contentPath: codeDir,
1412 |         validationType: "code",
1413 |         includeCodeValidation: true,
1414 |       });
1415 | 
1416 |       expect(result.codeBlocksValidated).toBeGreaterThan(0);
1417 |       expect(result.codeErrors.length).toBeGreaterThan(0); // Missing semicolon
1418 |     });
1419 | 
1420 |     it("should handle validation with no code blocks", async () => {
1421 |       const noCodeDir = path.join(testTempDir, "no-code");
1422 |       await fs.mkdir(noCodeDir, { recursive: true });
1423 | 
1424 |       await fs.writeFile(
1425 |         path.join(noCodeDir, "text.md"),
1426 |         `
1427 | # Text Only
1428 | 
1429 | This is just text with no code blocks.
1430 |       `.trim(),
1431 |       );
1432 | 
1433 |       const result = await validateGeneralContent({
1434 |         contentPath: noCodeDir,
1435 |         validationType: "all",
1436 |         includeCodeValidation: true,
1437 |       });
1438 | 
1439 |       expect(result.codeBlocksValidated).toBe(0);
1440 |       expect(result.success).toBe(true);
1441 |     });
1442 |   });
1443 | });
1444 | 
```

--------------------------------------------------------------------------------
/tests/tools/sync-code-to-docs.test.ts:
--------------------------------------------------------------------------------

```typescript
   1 | /**
   2 |  * Sync Code to Docs Tool Tests (Phase 3)
   3 |  */
   4 | 
   5 | import { handleSyncCodeToDocs } from "../../src/tools/sync-code-to-docs.js";
   6 | import { promises as fs } from "fs";
   7 | import { tmpdir } from "os";
   8 | import { join } from "path";
   9 | import { mkdtemp, rm } from "fs/promises";
  10 | import { DriftDetector } from "../../src/utils/drift-detector.js";
  11 | 
  12 | describe("sync_code_to_docs tool", () => {
  13 |   let tempDir: string;
  14 |   let projectPath: string;
  15 |   let docsPath: string;
  16 | 
  17 |   beforeEach(async () => {
  18 |     tempDir = await mkdtemp(join(tmpdir(), "sync-test-"));
  19 |     projectPath = join(tempDir, "project");
  20 |     docsPath = join(tempDir, "docs");
  21 | 
  22 |     await fs.mkdir(join(projectPath, "src"), { recursive: true });
  23 |     await fs.mkdir(docsPath, { recursive: true });
  24 |   });
  25 | 
  26 |   afterEach(async () => {
  27 |     await rm(tempDir, { recursive: true, force: true });
  28 |   });
  29 | 
  30 |   describe("Detect Mode", () => {
  31 |     test("should detect drift without making changes", async () => {
  32 |       // Create source file
  33 |       const sourceCode = `
  34 | export function calculate(x: number): number {
  35 |   return x * 2;
  36 | }
  37 |       `.trim();
  38 | 
  39 |       await fs.writeFile(join(projectPath, "src", "calc.ts"), sourceCode);
  40 | 
  41 |       // Create documentation
  42 |       const docContent = `
  43 | # Calculator
  44 | 
  45 | ## calculate(x: number): number
  46 | 
  47 | Doubles the input.
  48 |       `.trim();
  49 | 
  50 |       await fs.writeFile(join(docsPath, "calc.md"), docContent);
  51 | 
  52 |       // Run in detect mode
  53 |       const result = await handleSyncCodeToDocs({
  54 |         projectPath,
  55 |         docsPath,
  56 |         mode: "detect",
  57 |         createSnapshot: true,
  58 |       });
  59 | 
  60 |       expect(result).toBeDefined();
  61 |       expect(result.content).toBeDefined();
  62 |       expect(result.content[0]).toBeDefined();
  63 | 
  64 |       const data = JSON.parse(result.content[0].text);
  65 |       expect(data.success).toBe(true);
  66 |       expect(data.data.mode).toBe("detect");
  67 | 
  68 |       // Verify no changes were made
  69 |       const docAfter = await fs.readFile(join(docsPath, "calc.md"), "utf-8");
  70 |       expect(docAfter).toBe(docContent);
  71 |     });
  72 | 
  73 |     test("should create baseline snapshot on first run", async () => {
  74 |       const sourceCode = `export function test(): void {}`;
  75 |       await fs.writeFile(join(projectPath, "src", "test.ts"), sourceCode);
  76 | 
  77 |       const result = await handleSyncCodeToDocs({
  78 |         projectPath,
  79 |         docsPath,
  80 |         mode: "detect",
  81 |         createSnapshot: true,
  82 |       });
  83 | 
  84 |       expect(result).toBeDefined();
  85 | 
  86 |       const data = JSON.parse(result.content[0].text);
  87 |       expect(data.success).toBe(true);
  88 |       expect(data.data.snapshotId).toBeTruthy();
  89 | 
  90 |       // Check snapshot was created
  91 |       const snapshotDir = join(tempDir, "project", ".documcp", "snapshots");
  92 |       const files = await fs.readdir(snapshotDir);
  93 |       expect(files.length).toBeGreaterThan(0);
  94 |     });
  95 | 
  96 |     test("should report drift statistics", async () => {
  97 |       // Create initial snapshot
  98 |       const oldCode = `
  99 | export function oldFunction(): void {}
 100 |       `.trim();
 101 | 
 102 |       await fs.writeFile(join(projectPath, "src", "changes.ts"), oldCode);
 103 | 
 104 |       await handleSyncCodeToDocs({
 105 |         projectPath,
 106 |         docsPath,
 107 |         mode: "detect",
 108 |         createSnapshot: true,
 109 |       });
 110 | 
 111 |       // Make changes
 112 |       const newCode = `
 113 | export function newFunction(): void {}
 114 |       `.trim();
 115 | 
 116 |       await fs.writeFile(join(projectPath, "src", "changes.ts"), newCode);
 117 | 
 118 |       // Detect drift
 119 |       const result = await handleSyncCodeToDocs({
 120 |         projectPath,
 121 |         docsPath,
 122 |         mode: "detect",
 123 |         createSnapshot: true,
 124 |       });
 125 | 
 126 |       const data = JSON.parse(result.content[0].text);
 127 |       expect(data.success).toBe(true);
 128 |       expect(data.data.stats).toBeDefined();
 129 |       expect(data.data.stats.filesAnalyzed).toBeGreaterThanOrEqual(0);
 130 |     });
 131 |   });
 132 | 
 133 |   describe("Apply Mode", () => {
 134 |     test("should apply high-confidence changes automatically", async () => {
 135 |       // Create code with JSDoc
 136 |       const sourceCode = `
 137 | /**
 138 |  * Calculates the sum of two numbers
 139 |  * @param a First number
 140 |  * @param b Second number
 141 |  * @returns The sum
 142 |  */
 143 | export function add(a: number, b: number): number {
 144 |   return a + b;
 145 | }
 146 |       `.trim();
 147 | 
 148 |       await fs.writeFile(join(projectPath, "src", "math.ts"), sourceCode);
 149 | 
 150 |       // Create minimal documentation
 151 |       const docContent = `
 152 | # Math Module
 153 | 
 154 | Documentation needed.
 155 |       `.trim();
 156 | 
 157 |       await fs.writeFile(join(docsPath, "math.md"), docContent);
 158 | 
 159 |       // Create baseline
 160 |       await handleSyncCodeToDocs({
 161 |         projectPath,
 162 |         docsPath,
 163 |         mode: "detect",
 164 |         createSnapshot: true,
 165 |       });
 166 | 
 167 |       // Run in apply mode with high threshold
 168 |       const result = await handleSyncCodeToDocs({
 169 |         projectPath,
 170 |         docsPath,
 171 |         mode: "apply",
 172 |         autoApplyThreshold: 0.9,
 173 |         createSnapshot: true,
 174 |       });
 175 | 
 176 |       const data = JSON.parse(result.content[0].text);
 177 |       expect(data.success).toBe(true);
 178 |       expect(data.data.mode).toBe("apply");
 179 | 
 180 |       // Stats should show applied or pending changes
 181 |       const stats = data.data.stats;
 182 |       expect(
 183 |         stats.changesApplied + stats.changesPending,
 184 |       ).toBeGreaterThanOrEqual(0);
 185 |     });
 186 | 
 187 |     test("should respect confidence threshold", async () => {
 188 |       // Setup code and docs
 189 |       const sourceCode = `export function test(): void {}`;
 190 |       await fs.writeFile(join(projectPath, "src", "test.ts"), sourceCode);
 191 | 
 192 |       const docContent = `# Test`;
 193 |       await fs.writeFile(join(docsPath, "test.md"), docContent);
 194 | 
 195 |       // Create baseline
 196 |       await handleSyncCodeToDocs({
 197 |         projectPath,
 198 |         docsPath,
 199 |         mode: "detect",
 200 |       });
 201 | 
 202 |       // Apply with very high threshold (most changes won't meet it)
 203 |       const result = await handleSyncCodeToDocs({
 204 |         projectPath,
 205 |         docsPath,
 206 |         mode: "apply",
 207 |         autoApplyThreshold: 0.99,
 208 |       });
 209 | 
 210 |       const data = JSON.parse(result.content[0].text);
 211 |       expect(data.success).toBe(true);
 212 | 
 213 |       // With high threshold, most changes should be pending
 214 |       if (data.data.stats.driftsDetected > 0) {
 215 |         expect(data.data.pendingChanges.length).toBeGreaterThanOrEqual(0);
 216 |       }
 217 |     });
 218 | 
 219 |     test("should create snapshot before applying changes", async () => {
 220 |       const sourceCode = `export function test(): void {}`;
 221 |       await fs.writeFile(
 222 |         join(projectPath, "src", "snapshot-test.ts"),
 223 |         sourceCode,
 224 |       );
 225 | 
 226 |       await handleSyncCodeToDocs({
 227 |         projectPath,
 228 |         docsPath,
 229 |         mode: "apply",
 230 |         createSnapshot: true,
 231 |       });
 232 | 
 233 |       // Verify snapshot exists
 234 |       const snapshotDir = join(projectPath, ".documcp", "snapshots");
 235 |       const files = await fs.readdir(snapshotDir);
 236 |       expect(files.length).toBeGreaterThan(0);
 237 |     });
 238 |   });
 239 | 
 240 |   describe("Auto Mode", () => {
 241 |     test("should apply all changes in auto mode", async () => {
 242 |       const sourceCode = `
 243 | export function autoFunction(param: string): string {
 244 |   return param.toUpperCase();
 245 | }
 246 |       `.trim();
 247 | 
 248 |       await fs.writeFile(join(projectPath, "src", "auto.ts"), sourceCode);
 249 | 
 250 |       const result = await handleSyncCodeToDocs({
 251 |         projectPath,
 252 |         docsPath,
 253 |         mode: "auto",
 254 |         createSnapshot: true,
 255 |       });
 256 | 
 257 |       const data = JSON.parse(result.content[0].text);
 258 |       expect(data.success).toBe(true);
 259 |       expect(data.data.mode).toBe("auto");
 260 |     });
 261 |   });
 262 | 
 263 |   describe("Error Handling", () => {
 264 |     test("should handle invalid project path", async () => {
 265 |       const result = await handleSyncCodeToDocs({
 266 |         projectPath: "/nonexistent/path",
 267 |         docsPath,
 268 |         mode: "detect",
 269 |       });
 270 | 
 271 |       expect(result).toBeDefined();
 272 |       expect(result.content).toBeDefined();
 273 | 
 274 |       const data = JSON.parse(result.content[0].text);
 275 |       // Should either fail gracefully or handle missing path
 276 |       expect(data).toBeDefined();
 277 |     });
 278 | 
 279 |     test("should handle invalid docs path", async () => {
 280 |       const sourceCode = `export function test(): void {}`;
 281 |       await fs.writeFile(join(projectPath, "src", "test.ts"), sourceCode);
 282 | 
 283 |       const result = await handleSyncCodeToDocs({
 284 |         projectPath,
 285 |         docsPath: "/nonexistent/docs",
 286 |         mode: "detect",
 287 |       });
 288 | 
 289 |       expect(result).toBeDefined();
 290 |       const data = JSON.parse(result.content[0].text);
 291 |       expect(data).toBeDefined();
 292 |     });
 293 | 
 294 |     test("should handle empty project", async () => {
 295 |       // Empty project directory
 296 |       const result = await handleSyncCodeToDocs({
 297 |         projectPath,
 298 |         docsPath,
 299 |         mode: "detect",
 300 |       });
 301 | 
 302 |       expect(result).toBeDefined();
 303 |       const data = JSON.parse(result.content[0].text);
 304 |       expect(data.success).toBe(true);
 305 |       expect(data.data.stats.filesAnalyzed).toBe(0);
 306 |     });
 307 |   });
 308 | 
 309 |   describe("Recommendations and Next Steps", () => {
 310 |     test("should provide recommendations based on results", async () => {
 311 |       const sourceCode = `
 312 | export function critical(param: number): void {}
 313 |       `.trim();
 314 | 
 315 |       await fs.writeFile(join(projectPath, "src", "critical.ts"), sourceCode);
 316 | 
 317 |       // Create baseline
 318 |       await handleSyncCodeToDocs({
 319 |         projectPath,
 320 |         docsPath,
 321 |         mode: "detect",
 322 |       });
 323 | 
 324 |       // Make breaking change
 325 |       const newCode = `
 326 | export function critical(param: string, extra: boolean): void {}
 327 |       `.trim();
 328 | 
 329 |       await fs.writeFile(join(projectPath, "src", "critical.ts"), newCode);
 330 | 
 331 |       // Detect changes
 332 |       const result = await handleSyncCodeToDocs({
 333 |         projectPath,
 334 |         docsPath,
 335 |         mode: "detect",
 336 |       });
 337 | 
 338 |       const data = JSON.parse(result.content[0].text);
 339 |       expect(data.success).toBe(true);
 340 |       expect(data.recommendations).toBeDefined();
 341 |       expect(Array.isArray(data.recommendations)).toBe(true);
 342 |     });
 343 | 
 344 |     test("should provide next steps", async () => {
 345 |       const result = await handleSyncCodeToDocs({
 346 |         projectPath,
 347 |         docsPath,
 348 |         mode: "detect",
 349 |       });
 350 | 
 351 |       const data = JSON.parse(result.content[0].text);
 352 |       expect(data.success).toBe(true);
 353 |       expect(data.nextSteps).toBeDefined();
 354 |       expect(Array.isArray(data.nextSteps)).toBe(true);
 355 |     });
 356 |   });
 357 | 
 358 |   describe("Integration with Knowledge Graph", () => {
 359 |     test("should store sync events", async () => {
 360 |       const sourceCode = `export function kgTest(): void {}`;
 361 |       await fs.writeFile(join(projectPath, "src", "kg-test.ts"), sourceCode);
 362 | 
 363 |       const result = await handleSyncCodeToDocs({
 364 |         projectPath,
 365 |         docsPath,
 366 |         mode: "detect",
 367 |       });
 368 | 
 369 |       const data = JSON.parse(result.content[0].text);
 370 |       expect(data.success).toBe(true);
 371 | 
 372 |       // Sync event should be created (even if storage fails, shouldn't error)
 373 |       expect(data.data).toBeDefined();
 374 |     });
 375 |   });
 376 | 
 377 |   describe("Preview Mode", () => {
 378 |     test("should show changes in preview mode without applying", async () => {
 379 |       const sourceCode = `
 380 | export function previewFunc(x: number): number {
 381 |   return x * 3;
 382 | }
 383 |       `.trim();
 384 | 
 385 |       await fs.writeFile(join(projectPath, "src", "preview.ts"), sourceCode);
 386 | 
 387 |       const docContent = `
 388 | # Preview
 389 | 
 390 | Old documentation.
 391 |       `.trim();
 392 | 
 393 |       await fs.writeFile(join(docsPath, "preview.md"), docContent);
 394 | 
 395 |       // Create baseline
 396 |       await handleSyncCodeToDocs({
 397 |         projectPath,
 398 |         docsPath,
 399 |         mode: "detect",
 400 |       });
 401 | 
 402 |       // Change code
 403 |       const newCode = `
 404 | export function previewFunc(x: number, y: number): number {
 405 |   return x * y;
 406 | }
 407 |       `.trim();
 408 | 
 409 |       await fs.writeFile(join(projectPath, "src", "preview.ts"), newCode);
 410 | 
 411 |       // Preview changes
 412 |       const result = await handleSyncCodeToDocs({
 413 |         projectPath,
 414 |         docsPath,
 415 |         mode: "preview",
 416 |       });
 417 | 
 418 |       const data = JSON.parse(result.content[0].text);
 419 |       expect(data.success).toBe(true);
 420 |       expect(data.data.mode).toBe("preview");
 421 | 
 422 |       // Verify documentation wasn't changed
 423 |       const docAfter = await fs.readFile(join(docsPath, "preview.md"), "utf-8");
 424 |       expect(docAfter).toBe(docContent);
 425 |     });
 426 |   });
 427 | 
 428 |   describe("Documentation Change Application", () => {
 429 |     test("should apply changes when low-confidence changes exist in auto mode", async () => {
 430 |       // Create a source file with documentation
 431 |       const sourceCode = `
 432 | /**
 433 |  * Multiplies two numbers together
 434 |  * @param x First number
 435 |  * @param y Second number
 436 |  */
 437 | export function multiply(x: number, y: number): number {
 438 |   return x * y;
 439 | }
 440 |       `.trim();
 441 | 
 442 |       await fs.writeFile(join(projectPath, "src", "math.ts"), sourceCode);
 443 | 
 444 |       // Create outdated documentation
 445 |       const docContent = `
 446 | # Math Module
 447 | 
 448 | ## multiply
 449 | 
 450 | Adds two numbers.
 451 |       `.trim();
 452 | 
 453 |       await fs.writeFile(join(docsPath, "math.md"), docContent);
 454 | 
 455 |       // Create baseline
 456 |       await handleSyncCodeToDocs({
 457 |         projectPath,
 458 |         docsPath,
 459 |         mode: "detect",
 460 |       });
 461 | 
 462 |       // Run in auto mode (applies all changes)
 463 |       const result = await handleSyncCodeToDocs({
 464 |         projectPath,
 465 |         docsPath,
 466 |         mode: "auto",
 467 |       });
 468 | 
 469 |       const data = JSON.parse(result.content[0].text);
 470 |       expect(data.success).toBe(true);
 471 |       expect(data.data.mode).toBe("auto");
 472 |     });
 473 | 
 474 |     test("should handle apply errors gracefully", async () => {
 475 |       // Create source file
 476 |       const sourceCode = `export function testFunc(): void {}`;
 477 |       await fs.writeFile(join(projectPath, "src", "test.ts"), sourceCode);
 478 | 
 479 |       // Create documentation in a read-only parent directory would fail
 480 |       // But for this test, we'll just verify the error handling path exists
 481 |       const docContent = `# Test`;
 482 |       await fs.writeFile(join(docsPath, "test.md"), docContent);
 483 | 
 484 |       // Create baseline
 485 |       await handleSyncCodeToDocs({
 486 |         projectPath,
 487 |         docsPath,
 488 |         mode: "detect",
 489 |       });
 490 | 
 491 |       // Modify code
 492 |       const newCode = `export function testFunc(param: string): void {}`;
 493 |       await fs.writeFile(join(projectPath, "src", "test.ts"), newCode);
 494 | 
 495 |       // Try to apply changes
 496 |       const result = await handleSyncCodeToDocs({
 497 |         projectPath,
 498 |         docsPath,
 499 |         mode: "apply",
 500 |         autoApplyThreshold: 0.0, // Very low threshold
 501 |       });
 502 | 
 503 |       // Should complete without crashing
 504 |       expect(result).toBeDefined();
 505 |       const data = JSON.parse(result.content[0].text);
 506 |       expect(data.success).toBe(true);
 507 |     });
 508 |   });
 509 | 
 510 |   describe("Recommendation Edge Cases", () => {
 511 |     test("should recommend review for breaking changes", async () => {
 512 |       // Create initial code
 513 |       const oldCode = `
 514 | export function oldApi(x: number): string {
 515 |   return x.toString();
 516 | }
 517 |       `.trim();
 518 | 
 519 |       await fs.writeFile(join(projectPath, "src", "api.ts"), oldCode);
 520 | 
 521 |       // Create baseline
 522 |       await handleSyncCodeToDocs({
 523 |         projectPath,
 524 |         docsPath,
 525 |         mode: "detect",
 526 |       });
 527 | 
 528 |       // Make breaking change
 529 |       const newCode = `
 530 | export function newApi(x: number, y: string): boolean {
 531 |   return x > 0;
 532 | }
 533 |       `.trim();
 534 | 
 535 |       await fs.writeFile(join(projectPath, "src", "api.ts"), newCode);
 536 | 
 537 |       // Detect changes
 538 |       const result = await handleSyncCodeToDocs({
 539 |         projectPath,
 540 |         docsPath,
 541 |         mode: "detect",
 542 |       });
 543 | 
 544 |       const data = JSON.parse(result.content[0].text);
 545 |       expect(data.success).toBe(true);
 546 | 
 547 |       // Should have recommendations
 548 |       expect(data.recommendations).toBeDefined();
 549 |       expect(Array.isArray(data.recommendations)).toBe(true);
 550 |     });
 551 | 
 552 |     test("should show info when no drift detected", async () => {
 553 |       // Create code
 554 |       const sourceCode = `export function stable(): void {}`;
 555 |       await fs.writeFile(join(projectPath, "src", "stable.ts"), sourceCode);
 556 | 
 557 |       // Create baseline
 558 |       await handleSyncCodeToDocs({
 559 |         projectPath,
 560 |         docsPath,
 561 |         mode: "detect",
 562 |       });
 563 | 
 564 |       // Run again without changes
 565 |       const result = await handleSyncCodeToDocs({
 566 |         projectPath,
 567 |         docsPath,
 568 |         mode: "detect",
 569 |       });
 570 | 
 571 |       const data = JSON.parse(result.content[0].text);
 572 |       expect(data.success).toBe(true);
 573 |       expect(data.recommendations).toBeDefined();
 574 | 
 575 |       // Should have "No Drift Detected" recommendation
 576 |       const noDriftRec = data.recommendations.find(
 577 |         (r: any) => r.title?.includes("No Drift"),
 578 |       );
 579 |       expect(noDriftRec).toBeDefined();
 580 |     });
 581 | 
 582 |     test("should recommend validation after applying changes", async () => {
 583 |       const sourceCode = `
 584 | /**
 585 |  * Test function
 586 |  */
 587 | export function test(): void {}
 588 |       `.trim();
 589 | 
 590 |       await fs.writeFile(join(projectPath, "src", "validated.ts"), sourceCode);
 591 | 
 592 |       // Create baseline
 593 |       await handleSyncCodeToDocs({
 594 |         projectPath,
 595 |         docsPath,
 596 |         mode: "detect",
 597 |       });
 598 | 
 599 |       // Modify code
 600 |       const newCode = `
 601 | /**
 602 |  * Modified test function
 603 |  */
 604 | export function test(param: string): void {}
 605 |       `.trim();
 606 | 
 607 |       await fs.writeFile(join(projectPath, "src", "validated.ts"), newCode);
 608 | 
 609 |       // Apply changes
 610 |       const result = await handleSyncCodeToDocs({
 611 |         projectPath,
 612 |         docsPath,
 613 |         mode: "auto",
 614 |       });
 615 | 
 616 |       const data = JSON.parse(result.content[0].text);
 617 |       expect(data.success).toBe(true);
 618 | 
 619 |       // Should have next steps
 620 |       expect(data.nextSteps).toBeDefined();
 621 |       expect(Array.isArray(data.nextSteps)).toBe(true);
 622 |     });
 623 |   });
 624 | 
 625 |   describe("Next Steps Generation", () => {
 626 |     test("should suggest apply mode when in detect mode with pending changes", async () => {
 627 |       const sourceCode = `export function needsSync(): void {}`;
 628 |       await fs.writeFile(join(projectPath, "src", "sync.ts"), sourceCode);
 629 | 
 630 |       // Create baseline
 631 |       await handleSyncCodeToDocs({
 632 |         projectPath,
 633 |         docsPath,
 634 |         mode: "detect",
 635 |       });
 636 | 
 637 |       // Change code
 638 |       const newCode = `export function needsSync(param: number): void {}`;
 639 |       await fs.writeFile(join(projectPath, "src", "sync.ts"), newCode);
 640 | 
 641 |       // Detect in detect mode
 642 |       const result = await handleSyncCodeToDocs({
 643 |         projectPath,
 644 |         docsPath,
 645 |         mode: "detect",
 646 |       });
 647 | 
 648 |       const data = JSON.parse(result.content[0].text);
 649 |       expect(data.success).toBe(true);
 650 |       expect(data.nextSteps).toBeDefined();
 651 | 
 652 |       // If there are pending changes, should suggest apply mode
 653 |       if (data.data.pendingChanges?.length > 0) {
 654 |         const applyStep = data.nextSteps.find(
 655 |           (s: any) => s.action?.includes("Apply"),
 656 |         );
 657 |         expect(applyStep).toBeDefined();
 658 |       }
 659 |     });
 660 | 
 661 |     test("should suggest review for pending manual changes", async () => {
 662 |       const sourceCode = `export function complex(): void {}`;
 663 |       await fs.writeFile(join(projectPath, "src", "complex.ts"), sourceCode);
 664 | 
 665 |       // Create baseline
 666 |       await handleSyncCodeToDocs({
 667 |         projectPath,
 668 |         docsPath,
 669 |         mode: "detect",
 670 |       });
 671 | 
 672 |       // Change code
 673 |       const newCode = `export function complex(a: number, b: string): boolean { return true; }`;
 674 |       await fs.writeFile(join(projectPath, "src", "complex.ts"), newCode);
 675 | 
 676 |       // Detect with very high threshold (forces manual review)
 677 |       const result = await handleSyncCodeToDocs({
 678 |         projectPath,
 679 |         docsPath,
 680 |         mode: "apply",
 681 |         autoApplyThreshold: 0.99,
 682 |       });
 683 | 
 684 |       const data = JSON.parse(result.content[0].text);
 685 |       expect(data.success).toBe(true);
 686 |       expect(data.nextSteps).toBeDefined();
 687 |     });
 688 |   });
 689 | 
 690 |   describe("Snapshot Management", () => {
 691 |     test("should not create snapshot when createSnapshot is false in detect mode", async () => {
 692 |       const sourceCode = `export function noSnapshot(): void {}`;
 693 |       await fs.writeFile(join(projectPath, "src", "nosnapshot.ts"), sourceCode);
 694 | 
 695 |       await handleSyncCodeToDocs({
 696 |         projectPath,
 697 |         docsPath,
 698 |         mode: "detect",
 699 |         createSnapshot: false,
 700 |       });
 701 | 
 702 |       // Should still work even without snapshot
 703 |       const result = await handleSyncCodeToDocs({
 704 |         projectPath,
 705 |         docsPath,
 706 |         mode: "detect",
 707 |         createSnapshot: false,
 708 |       });
 709 | 
 710 |       const data = JSON.parse(result.content[0].text);
 711 |       expect(data.success).toBe(true);
 712 |     });
 713 |   });
 714 | 
 715 |   describe("Error Path Coverage", () => {
 716 |     test("should handle KG storage failures gracefully", async () => {
 717 |       const sourceCode = `export function kgError(): void {}`;
 718 |       await fs.writeFile(join(projectPath, "src", "kg-error.ts"), sourceCode);
 719 | 
 720 |       // The tool should complete even if KG storage fails
 721 |       const result = await handleSyncCodeToDocs({
 722 |         projectPath,
 723 |         docsPath,
 724 |         mode: "detect",
 725 |       });
 726 | 
 727 |       const data = JSON.parse(result.content[0].text);
 728 |       expect(data.success).toBe(true);
 729 |     });
 730 | 
 731 |     test("should handle zero drift detections", async () => {
 732 |       const sourceCode = `export function stable(): void {}`;
 733 |       await fs.writeFile(join(projectPath, "src", "stable.ts"), sourceCode);
 734 | 
 735 |       // Create baseline
 736 |       await handleSyncCodeToDocs({
 737 |         projectPath,
 738 |         docsPath,
 739 |         mode: "detect",
 740 |       });
 741 | 
 742 |       // Run again with no changes
 743 |       const result = await handleSyncCodeToDocs({
 744 |         projectPath,
 745 |         docsPath,
 746 |         mode: "detect",
 747 |       });
 748 | 
 749 |       const data = JSON.parse(result.content[0].text);
 750 |       expect(data.success).toBe(true);
 751 |       expect(data.data.stats.driftsDetected).toBe(0);
 752 |     });
 753 | 
 754 |     test("should handle files with no drift suggestions", async () => {
 755 |       const sourceCode = `export function noDrift(): void {}`;
 756 |       await fs.writeFile(join(projectPath, "src", "nodrift.ts"), sourceCode);
 757 | 
 758 |       const result = await handleSyncCodeToDocs({
 759 |         projectPath,
 760 |         docsPath,
 761 |         mode: "apply",
 762 |         autoApplyThreshold: 0.5,
 763 |       });
 764 | 
 765 |       const data = JSON.parse(result.content[0].text);
 766 |       expect(data.success).toBe(true);
 767 |       // Should handle case with no drift gracefully
 768 |       expect(data.data.appliedChanges).toBeDefined();
 769 |       expect(data.data.pendingChanges).toBeDefined();
 770 |     });
 771 | 
 772 |     test("should handle recommendations with zero breaking changes", async () => {
 773 |       const sourceCode = `export function minor(): void {}`;
 774 |       await fs.writeFile(join(projectPath, "src", "minor.ts"), sourceCode);
 775 | 
 776 |       const result = await handleSyncCodeToDocs({
 777 |         projectPath,
 778 |         docsPath,
 779 |         mode: "detect",
 780 |       });
 781 | 
 782 |       const data = JSON.parse(result.content[0].text);
 783 |       expect(data.success).toBe(true);
 784 |       // Should not have critical recommendations for no breaking changes
 785 |       const criticalRecs = data.recommendations?.filter(
 786 |         (r: any) => r.type === "critical",
 787 |       );
 788 |       expect(criticalRecs || []).toHaveLength(0);
 789 |     });
 790 | 
 791 |     test("should handle pending changes without manual review", async () => {
 792 |       const sourceCode = `export function autoApply(): void {}`;
 793 |       await fs.writeFile(join(projectPath, "src", "autoapply.ts"), sourceCode);
 794 | 
 795 |       // Create baseline
 796 |       await handleSyncCodeToDocs({
 797 |         projectPath,
 798 |         docsPath,
 799 |         mode: "detect",
 800 |       });
 801 | 
 802 |       // Modify
 803 |       const newCode = `export function autoApply(x: number): number { return x; }`;
 804 |       await fs.writeFile(join(projectPath, "src", "autoapply.ts"), newCode);
 805 | 
 806 |       const result = await handleSyncCodeToDocs({
 807 |         projectPath,
 808 |         docsPath,
 809 |         mode: "auto", // Auto applies all
 810 |       });
 811 | 
 812 |       const data = JSON.parse(result.content[0].text);
 813 |       expect(data.success).toBe(true);
 814 |     });
 815 | 
 816 |     test("should handle next steps when no breaking changes exist", async () => {
 817 |       const sourceCode = `export function noBreaking(): void {}`;
 818 |       await fs.writeFile(join(projectPath, "src", "nobreaking.ts"), sourceCode);
 819 | 
 820 |       const result = await handleSyncCodeToDocs({
 821 |         projectPath,
 822 |         docsPath,
 823 |         mode: "detect",
 824 |       });
 825 | 
 826 |       const data = JSON.parse(result.content[0].text);
 827 |       expect(data.success).toBe(true);
 828 |       // Should not suggest reviewing breaking changes when there are none
 829 |       const breakingStep = data.nextSteps?.find(
 830 |         (s: any) => s.action?.toLowerCase().includes("breaking"),
 831 |       );
 832 |       expect(breakingStep).toBeUndefined();
 833 |     });
 834 | 
 835 |     test("should handle next steps when no changes were applied", async () => {
 836 |       const sourceCode = `export function noApplied(): void {}`;
 837 |       await fs.writeFile(join(projectPath, "src", "noapplied.ts"), sourceCode);
 838 | 
 839 |       const result = await handleSyncCodeToDocs({
 840 |         projectPath,
 841 |         docsPath,
 842 |         mode: "detect", // Detect mode doesn't apply
 843 |       });
 844 | 
 845 |       const data = JSON.parse(result.content[0].text);
 846 |       expect(data.success).toBe(true);
 847 |       expect(data.data.appliedChanges).toHaveLength(0);
 848 |     });
 849 | 
 850 |     test("should handle next steps when no pending changes require review", async () => {
 851 |       const sourceCode = `export function noPending(): void {}`;
 852 |       await fs.writeFile(join(projectPath, "src", "nopending.ts"), sourceCode);
 853 | 
 854 |       const result = await handleSyncCodeToDocs({
 855 |         projectPath,
 856 |         docsPath,
 857 |         mode: "auto", // Auto applies everything
 858 |       });
 859 | 
 860 |       const data = JSON.parse(result.content[0].text);
 861 |       expect(data.success).toBe(true);
 862 |     });
 863 | 
 864 |     test("should handle apply mode with suggestions below threshold", async () => {
 865 |       const sourceCode = `export function lowConfidence(): void {}`;
 866 |       await fs.writeFile(
 867 |         join(projectPath, "src", "lowconfidence.ts"),
 868 |         sourceCode,
 869 |       );
 870 | 
 871 |       // Create baseline
 872 |       await handleSyncCodeToDocs({
 873 |         projectPath,
 874 |         docsPath,
 875 |         mode: "detect",
 876 |       });
 877 | 
 878 |       // Modify
 879 |       const newCode = `export function lowConfidence(param: string): void {}`;
 880 |       await fs.writeFile(join(projectPath, "src", "lowconfidence.ts"), newCode);
 881 | 
 882 |       // Very high threshold - suggestions won't meet it
 883 |       const result = await handleSyncCodeToDocs({
 884 |         projectPath,
 885 |         docsPath,
 886 |         mode: "apply",
 887 |         autoApplyThreshold: 1.0,
 888 |       });
 889 | 
 890 |       const data = JSON.parse(result.content[0].text);
 891 |       expect(data.success).toBe(true);
 892 |     });
 893 | 
 894 |     test("should handle context parameter with info logging", async () => {
 895 |       const sourceCode = `export function withContext(): void {}`;
 896 |       await fs.writeFile(join(projectPath, "src", "context.ts"), sourceCode);
 897 | 
 898 |       const mockContext = {
 899 |         info: jest.fn(),
 900 |         warn: jest.fn(),
 901 |       };
 902 | 
 903 |       const result = await handleSyncCodeToDocs(
 904 |         {
 905 |           projectPath,
 906 |           docsPath,
 907 |           mode: "detect",
 908 |         },
 909 |         mockContext,
 910 |       );
 911 | 
 912 |       const data = JSON.parse(result.content[0].text);
 913 |       expect(data.success).toBe(true);
 914 |       // Context info should have been called
 915 |       expect(mockContext.info).toHaveBeenCalled();
 916 |     });
 917 | 
 918 |     test("should handle snapshot creation in non-detect modes", async () => {
 919 |       const sourceCode = `export function modeSnapshot(): void {}`;
 920 |       await fs.writeFile(
 921 |         join(projectPath, "src", "modesnapshot.ts"),
 922 |         sourceCode,
 923 |       );
 924 | 
 925 |       // Apply mode should create snapshot even if createSnapshot not specified
 926 |       const result = await handleSyncCodeToDocs({
 927 |         projectPath,
 928 |         docsPath,
 929 |         mode: "apply",
 930 |         createSnapshot: false, // But mode !== "detect" overrides this
 931 |       });
 932 | 
 933 |       const data = JSON.parse(result.content[0].text);
 934 |       expect(data.success).toBe(true);
 935 |     });
 936 |   });
 937 | 
 938 |   describe("Mocked Drift Detector Tests", () => {
 939 |     let mockDetector: jest.Mocked<DriftDetector>;
 940 | 
 941 |     beforeEach(() => {
 942 |       // Create a real detector instance but spy on its methods
 943 |       mockDetector = new DriftDetector(
 944 |         projectPath,
 945 |       ) as jest.Mocked<DriftDetector>;
 946 |     });
 947 | 
 948 |     test("should apply high-confidence suggestions automatically", async () => {
 949 |       // Create real documentation file
 950 |       const docPath = join(docsPath, "api.md");
 951 |       const originalDoc = `# API
 952 | 
 953 | ## oldFunction
 954 | 
 955 | This is outdated.`;
 956 |       await fs.writeFile(docPath, originalDoc);
 957 | 
 958 |       // Mock drift detector to return suggestions
 959 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
 960 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
 961 |         timestamp: "2025-01-01T00:00:00.000Z",
 962 |         projectPath,
 963 |         files: new Map([
 964 |           [
 965 |             "src/api.ts",
 966 |             {
 967 |               filePath: "src/api.ts",
 968 |               language: "typescript",
 969 |               functions: [],
 970 |               classes: [],
 971 |               interfaces: [],
 972 |               types: [],
 973 |               imports: [],
 974 |               exports: [],
 975 |               contentHash: "abc123",
 976 |               lastModified: "2025-01-01T00:00:00.000Z",
 977 |               linesOfCode: 10,
 978 |               complexity: 1,
 979 |             },
 980 |           ],
 981 |         ]),
 982 |         documentation: new Map(),
 983 |       });
 984 | 
 985 |       jest
 986 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
 987 |         .mockResolvedValue({
 988 |           timestamp: "2025-01-01T00:00:00.000Z",
 989 |           projectPath,
 990 |           files: new Map(),
 991 |           documentation: new Map(),
 992 |         });
 993 | 
 994 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
 995 |         {
 996 |           filePath: "src/api.ts",
 997 |           hasDrift: true,
 998 |           severity: "medium",
 999 |           drifts: [
1000 |             {
1001 |               type: "outdated",
1002 |               affectedDocs: [docPath],
1003 |               codeChanges: [
1004 |                 {
1005 |                   type: "modified",
1006 |                   category: "function",
1007 |                   name: "oldFunction",
1008 |                   details: "Function renamed to newFunction",
1009 |                   impactLevel: "major",
1010 |                 },
1011 |               ],
1012 |               description: "Function signature changed",
1013 |               detectedAt: "2025-01-01T00:00:00.000Z",
1014 |               severity: "medium",
1015 |             },
1016 |           ],
1017 |           impactAnalysis: {
1018 |             breakingChanges: 0,
1019 |             majorChanges: 1,
1020 |             minorChanges: 0,
1021 |             affectedDocFiles: [docPath],
1022 |             estimatedUpdateEffort: "medium",
1023 |             requiresManualReview: false,
1024 |           },
1025 |           suggestions: [
1026 |             {
1027 |               docFile: docPath,
1028 |               section: "oldFunction",
1029 |               currentContent: "This is outdated.",
1030 |               suggestedContent: `## newFunction
1031 | 
1032 | Updated documentation for new function.`,
1033 |               reasoning: "Function was renamed from oldFunction to newFunction",
1034 |               confidence: 0.95,
1035 |               autoApplicable: true,
1036 |             },
1037 |           ],
1038 |         },
1039 |       ]);
1040 | 
1041 |       // Run in apply mode
1042 |       const result = await handleSyncCodeToDocs({
1043 |         projectPath,
1044 |         docsPath,
1045 |         mode: "apply",
1046 |         autoApplyThreshold: 0.8,
1047 |       });
1048 | 
1049 |       const data = JSON.parse(result.content[0].text);
1050 |       expect(data.success).toBe(true);
1051 |       expect(data.data.appliedChanges.length).toBeGreaterThan(0);
1052 | 
1053 |       // Verify the file was actually modified
1054 |       const updatedDoc = await fs.readFile(docPath, "utf-8");
1055 |       expect(updatedDoc).toContain("newFunction");
1056 |     });
1057 | 
1058 |     test("should not apply low-confidence suggestions", async () => {
1059 |       const docPath = join(docsPath, "lowconf.md");
1060 |       const originalDoc = `# Low Confidence
1061 | 
1062 | ## someFunction
1063 | 
1064 | Original content.`;
1065 |       await fs.writeFile(docPath, originalDoc);
1066 | 
1067 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1068 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1069 |         timestamp: "2025-01-01T00:00:00.000Z",
1070 |         projectPath,
1071 |         files: new Map(),
1072 |         documentation: new Map(),
1073 |       });
1074 | 
1075 |       jest
1076 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1077 |         .mockResolvedValue({
1078 |           timestamp: "2025-01-01T00:00:00.000Z",
1079 |           projectPath,
1080 |           files: new Map(),
1081 |           documentation: new Map(),
1082 |         });
1083 | 
1084 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1085 |         {
1086 |           filePath: "src/lowconf.ts",
1087 |           hasDrift: true,
1088 |           severity: "low",
1089 |           drifts: [
1090 |             {
1091 |               type: "outdated",
1092 |               affectedDocs: [docPath],
1093 |               codeChanges: [
1094 |                 {
1095 |                   type: "modified",
1096 |                   category: "function",
1097 |                   name: "someFunction",
1098 |                   details: "Minor change",
1099 |                   impactLevel: "minor",
1100 |                 },
1101 |               ],
1102 |               description: "Minor change",
1103 |               detectedAt: "2025-01-01T00:00:00.000Z",
1104 |               severity: "low",
1105 |             },
1106 |           ],
1107 |           impactAnalysis: {
1108 |             breakingChanges: 0,
1109 |             majorChanges: 0,
1110 |             minorChanges: 1,
1111 |             affectedDocFiles: [docPath],
1112 |             estimatedUpdateEffort: "low",
1113 |             requiresManualReview: false,
1114 |           },
1115 |           suggestions: [
1116 |             {
1117 |               docFile: docPath,
1118 |               section: "someFunction",
1119 |               currentContent: "Original content.",
1120 |               suggestedContent: "Suggested content.",
1121 |               reasoning: "Minor update needed",
1122 |               confidence: 0.5, // Low confidence
1123 |               autoApplicable: true,
1124 |             },
1125 |           ],
1126 |         },
1127 |       ]);
1128 | 
1129 |       const result = await handleSyncCodeToDocs({
1130 |         projectPath,
1131 |         docsPath,
1132 |         mode: "apply",
1133 |         autoApplyThreshold: 0.8, // Higher than suggestion confidence
1134 |       });
1135 | 
1136 |       const data = JSON.parse(result.content[0].text);
1137 |       expect(data.success).toBe(true);
1138 |       expect(data.data.pendingChanges.length).toBeGreaterThan(0);
1139 |       expect(data.data.appliedChanges.length).toBe(0);
1140 | 
1141 |       // Verify file was NOT modified
1142 |       const unchangedDoc = await fs.readFile(docPath, "utf-8");
1143 |       expect(unchangedDoc).toBe(originalDoc);
1144 |     });
1145 | 
1146 |     test("should apply all suggestions in auto mode regardless of confidence", async () => {
1147 |       const docPath = join(docsPath, "auto.md");
1148 |       const originalDoc = `# Auto Mode
1149 | 
1150 | ## function1
1151 | 
1152 | Old content.`;
1153 |       await fs.writeFile(docPath, originalDoc);
1154 | 
1155 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1156 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1157 |         timestamp: "2025-01-01T00:00:00.000Z",
1158 |         projectPath,
1159 |         files: new Map(),
1160 |         documentation: new Map(),
1161 |       });
1162 | 
1163 |       jest
1164 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1165 |         .mockResolvedValue({
1166 |           timestamp: "2025-01-01T00:00:00.000Z",
1167 |           projectPath,
1168 |           files: new Map(),
1169 |           documentation: new Map(),
1170 |         });
1171 | 
1172 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1173 |         {
1174 |           filePath: "src/auto.ts",
1175 |           hasDrift: true,
1176 |           severity: "low",
1177 |           drifts: [
1178 |             {
1179 |               type: "outdated",
1180 |               affectedDocs: [docPath],
1181 |               codeChanges: [
1182 |                 {
1183 |                   type: "modified",
1184 |                   category: "function",
1185 |                   name: "function1",
1186 |                   details: "Change",
1187 |                   impactLevel: "minor",
1188 |                 },
1189 |               ],
1190 |               description: "Change",
1191 |               detectedAt: "2025-01-01T00:00:00.000Z",
1192 |               severity: "low",
1193 |             },
1194 |           ],
1195 |           impactAnalysis: {
1196 |             breakingChanges: 0,
1197 |             majorChanges: 0,
1198 |             minorChanges: 1,
1199 |             affectedDocFiles: [docPath],
1200 |             estimatedUpdateEffort: "low",
1201 |             requiresManualReview: false,
1202 |           },
1203 |           suggestions: [
1204 |             {
1205 |               docFile: docPath,
1206 |               section: "function1",
1207 |               currentContent: "Old content.",
1208 |               suggestedContent: `## function1
1209 | 
1210 | New content from auto mode.`,
1211 |               reasoning: "Auto-applied update",
1212 |               confidence: 0.3, // Very low confidence
1213 |               autoApplicable: false, // Not auto-applicable
1214 |             },
1215 |           ],
1216 |         },
1217 |       ]);
1218 | 
1219 |       const result = await handleSyncCodeToDocs({
1220 |         projectPath,
1221 |         docsPath,
1222 |         mode: "auto", // Auto mode applies everything
1223 |       });
1224 | 
1225 |       const data = JSON.parse(result.content[0].text);
1226 |       expect(data.success).toBe(true);
1227 |       expect(data.data.appliedChanges.length).toBeGreaterThan(0);
1228 | 
1229 |       // Verify file was modified
1230 |       const updatedDoc = await fs.readFile(docPath, "utf-8");
1231 |       expect(updatedDoc).toContain("New content from auto mode");
1232 |     });
1233 | 
1234 |     test("should handle apply errors and mark as pending", async () => {
1235 |       const docPath = join(docsPath, "error.md");
1236 |       // Don't create the file - this will cause an error
1237 | 
1238 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1239 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1240 |         timestamp: "2025-01-01T00:00:00.000Z",
1241 |         projectPath,
1242 |         files: new Map(),
1243 |         documentation: new Map(),
1244 |       });
1245 | 
1246 |       jest
1247 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1248 |         .mockResolvedValue({
1249 |           timestamp: "2025-01-01T00:00:00.000Z",
1250 |           projectPath,
1251 |           files: new Map(),
1252 |           documentation: new Map(),
1253 |         });
1254 | 
1255 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1256 |         {
1257 |           filePath: "src/error.ts",
1258 |           hasDrift: true,
1259 |           severity: "medium",
1260 |           drifts: [
1261 |             {
1262 |               type: "outdated",
1263 |               affectedDocs: [docPath],
1264 |               codeChanges: [
1265 |                 {
1266 |                   type: "modified",
1267 |                   category: "function",
1268 |                   name: "errorFunction",
1269 |                   details: "Change",
1270 |                   impactLevel: "minor",
1271 |                 },
1272 |               ],
1273 |               description: "Change",
1274 |               detectedAt: "2025-01-01T00:00:00.000Z",
1275 |               severity: "medium",
1276 |             },
1277 |           ],
1278 |           impactAnalysis: {
1279 |             breakingChanges: 0,
1280 |             majorChanges: 1,
1281 |             minorChanges: 0,
1282 |             affectedDocFiles: [docPath],
1283 |             estimatedUpdateEffort: "medium",
1284 |             requiresManualReview: false,
1285 |           },
1286 |           suggestions: [
1287 |             {
1288 |               docFile: docPath, // File doesn't exist
1289 |               section: "errorSection",
1290 |               currentContent: "N/A",
1291 |               suggestedContent: "New content",
1292 |               reasoning: "Should fail",
1293 |               confidence: 0.95,
1294 |               autoApplicable: true,
1295 |             },
1296 |           ],
1297 |         },
1298 |       ]);
1299 | 
1300 |       const mockContext = {
1301 |         info: jest.fn(),
1302 |         warn: jest.fn(),
1303 |       };
1304 | 
1305 |       const result = await handleSyncCodeToDocs(
1306 |         {
1307 |           projectPath,
1308 |           docsPath,
1309 |           mode: "apply",
1310 |           autoApplyThreshold: 0.8,
1311 |         },
1312 |         mockContext,
1313 |       );
1314 | 
1315 |       const data = JSON.parse(result.content[0].text);
1316 |       expect(data.success).toBe(true);
1317 |       // Failed applies should be added to pending changes
1318 |       expect(data.data.pendingChanges.length).toBeGreaterThan(0);
1319 |       expect(mockContext.warn).toHaveBeenCalled();
1320 |     });
1321 | 
1322 |     test("should add new section when section doesn't exist", async () => {
1323 |       const docPath = join(docsPath, "newsection.md");
1324 |       const originalDoc = `# New Section Test
1325 | 
1326 | ## existingSection
1327 | 
1328 | Existing content.`;
1329 |       await fs.writeFile(docPath, originalDoc);
1330 | 
1331 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1332 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1333 |         timestamp: "2025-01-01T00:00:00.000Z",
1334 |         projectPath,
1335 |         files: new Map(),
1336 |         documentation: new Map(),
1337 |       });
1338 | 
1339 |       jest
1340 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1341 |         .mockResolvedValue({
1342 |           timestamp: "2025-01-01T00:00:00.000Z",
1343 |           projectPath,
1344 |           files: new Map(),
1345 |           documentation: new Map(),
1346 |         });
1347 | 
1348 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1349 |         {
1350 |           filePath: "src/new.ts",
1351 |           hasDrift: true,
1352 |           severity: "low",
1353 |           drifts: [
1354 |             {
1355 |               type: "missing",
1356 |               affectedDocs: [docPath],
1357 |               codeChanges: [
1358 |                 {
1359 |                   type: "added",
1360 |                   category: "function",
1361 |                   name: "newFunction",
1362 |                   details: "New function added",
1363 |                   impactLevel: "minor",
1364 |                 },
1365 |               ],
1366 |               description: "New function",
1367 |               detectedAt: "2025-01-01T00:00:00.000Z",
1368 |               severity: "low",
1369 |             },
1370 |           ],
1371 |           impactAnalysis: {
1372 |             breakingChanges: 0,
1373 |             majorChanges: 0,
1374 |             minorChanges: 1,
1375 |             affectedDocFiles: [docPath],
1376 |             estimatedUpdateEffort: "low",
1377 |             requiresManualReview: false,
1378 |           },
1379 |           suggestions: [
1380 |             {
1381 |               docFile: docPath,
1382 |               section: "newSection", // This section doesn't exist
1383 |               currentContent: "",
1384 |               suggestedContent: `## newSection
1385 | 
1386 | This is a brand new section.`,
1387 |               reasoning: "New function added",
1388 |               confidence: 0.9,
1389 |               autoApplicable: true,
1390 |             },
1391 |           ],
1392 |         },
1393 |       ]);
1394 | 
1395 |       const result = await handleSyncCodeToDocs({
1396 |         projectPath,
1397 |         docsPath,
1398 |         mode: "apply",
1399 |         autoApplyThreshold: 0.8,
1400 |       });
1401 | 
1402 |       const data = JSON.parse(result.content[0].text);
1403 |       expect(data.success).toBe(true);
1404 |       expect(data.data.appliedChanges.length).toBeGreaterThan(0);
1405 | 
1406 |       // Verify new section was appended
1407 |       const updatedDoc = await fs.readFile(docPath, "utf-8");
1408 |       expect(updatedDoc).toContain("newSection");
1409 |       expect(updatedDoc).toContain("brand new section");
1410 |     });
1411 | 
1412 |     test("should handle breaking changes recommendation", async () => {
1413 |       const docPath = join(docsPath, "breaking.md");
1414 |       await fs.writeFile(docPath, "# Breaking");
1415 | 
1416 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1417 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1418 |         timestamp: "2025-01-01T00:00:00.000Z",
1419 |         projectPath,
1420 |         files: new Map(),
1421 |         documentation: new Map(),
1422 |       });
1423 | 
1424 |       jest
1425 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1426 |         .mockResolvedValue({
1427 |           timestamp: "2025-01-01T00:00:00.000Z",
1428 |           projectPath,
1429 |           files: new Map(),
1430 |           documentation: new Map(),
1431 |         });
1432 | 
1433 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1434 |         {
1435 |           filePath: "src/breaking.ts",
1436 |           hasDrift: true,
1437 |           severity: "critical",
1438 |           drifts: [
1439 |             {
1440 |               type: "breaking",
1441 |               affectedDocs: [docPath],
1442 |               codeChanges: [
1443 |                 {
1444 |                   type: "removed",
1445 |                   category: "function",
1446 |                   name: "oldAPI",
1447 |                   details: "Breaking change",
1448 |                   impactLevel: "breaking",
1449 |                 },
1450 |               ],
1451 |               description: "Breaking change",
1452 |               detectedAt: "2025-01-01T00:00:00.000Z",
1453 |               severity: "critical",
1454 |             },
1455 |           ],
1456 |           impactAnalysis: {
1457 |             breakingChanges: 2, // Multiple breaking changes
1458 |             majorChanges: 0,
1459 |             minorChanges: 0,
1460 |             affectedDocFiles: [docPath],
1461 |             estimatedUpdateEffort: "high",
1462 |             requiresManualReview: true,
1463 |           },
1464 |           suggestions: [
1465 |             {
1466 |               docFile: docPath,
1467 |               section: "API",
1468 |               currentContent: "Old API",
1469 |               suggestedContent: "New API",
1470 |               reasoning: "Breaking change",
1471 |               confidence: 0.9,
1472 |               autoApplicable: true,
1473 |             },
1474 |           ],
1475 |         },
1476 |       ]);
1477 | 
1478 |       const result = await handleSyncCodeToDocs({
1479 |         projectPath,
1480 |         docsPath,
1481 |         mode: "detect",
1482 |       });
1483 | 
1484 |       const data = JSON.parse(result.content[0].text);
1485 |       expect(data.success).toBe(true);
1486 |       expect(data.data.stats.breakingChanges).toBe(2);
1487 | 
1488 |       // Should have critical recommendation
1489 |       const criticalRec = data.recommendations.find(
1490 |         (r: any) => r.type === "critical",
1491 |       );
1492 |       expect(criticalRec).toBeDefined();
1493 |       expect(criticalRec.title).toContain("Breaking");
1494 |     });
1495 | 
1496 |     afterEach(() => {
1497 |       jest.restoreAllMocks();
1498 |     });
1499 |   });
1500 | });
1501 | 
```
Page 26/33FirstPrevNextLast