k0ntext 3.0.0 β†’ 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +159 -3
  2. package/dist/agents/drift-agent.d.ts +114 -0
  3. package/dist/agents/drift-agent.d.ts.map +1 -0
  4. package/dist/agents/drift-agent.js +324 -0
  5. package/dist/agents/drift-agent.js.map +1 -0
  6. package/dist/agents/fact-check-agent.d.ts +103 -0
  7. package/dist/agents/fact-check-agent.d.ts.map +1 -0
  8. package/dist/agents/fact-check-agent.js +273 -0
  9. package/dist/agents/fact-check-agent.js.map +1 -0
  10. package/dist/cli/commands/cleanup.d.ts.map +1 -1
  11. package/dist/cli/commands/cleanup.js +77 -5
  12. package/dist/cli/commands/cleanup.js.map +1 -1
  13. package/dist/cli/commands/cross-sync.d.ts +10 -0
  14. package/dist/cli/commands/cross-sync.d.ts.map +1 -0
  15. package/dist/cli/commands/cross-sync.js +398 -0
  16. package/dist/cli/commands/cross-sync.js.map +1 -0
  17. package/dist/cli/commands/drift-detect.d.ts +10 -0
  18. package/dist/cli/commands/drift-detect.d.ts.map +1 -0
  19. package/dist/cli/commands/drift-detect.js +120 -0
  20. package/dist/cli/commands/drift-detect.js.map +1 -0
  21. package/dist/cli/commands/fact-check.d.ts +10 -0
  22. package/dist/cli/commands/fact-check.d.ts.map +1 -0
  23. package/dist/cli/commands/fact-check.js +105 -0
  24. package/dist/cli/commands/fact-check.js.map +1 -0
  25. package/dist/cli/commands/hooks.d.ts +13 -0
  26. package/dist/cli/commands/hooks.d.ts.map +1 -0
  27. package/dist/cli/commands/hooks.js +216 -0
  28. package/dist/cli/commands/hooks.js.map +1 -0
  29. package/dist/cli/generate.d.ts.map +1 -1
  30. package/dist/cli/generate.js +278 -12
  31. package/dist/cli/generate.js.map +1 -1
  32. package/dist/cli/index.js +33 -8
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/config/models.d.ts +112 -0
  35. package/dist/config/models.d.ts.map +1 -0
  36. package/dist/config/models.js +116 -0
  37. package/dist/config/models.js.map +1 -0
  38. package/dist/db/client.d.ts.map +1 -1
  39. package/dist/db/client.js +2 -2
  40. package/dist/db/client.js.map +1 -1
  41. package/dist/embeddings/openrouter.d.ts +8 -0
  42. package/dist/embeddings/openrouter.d.ts.map +1 -1
  43. package/dist/embeddings/openrouter.js +16 -6
  44. package/dist/embeddings/openrouter.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/agents/drift-agent.ts +430 -0
  47. package/src/agents/fact-check-agent.ts +348 -0
  48. package/src/cli/commands/cleanup.ts +86 -5
  49. package/src/cli/commands/cross-sync.ts +473 -0
  50. package/src/cli/commands/drift-detect.ts +139 -0
  51. package/src/cli/commands/fact-check.ts +127 -0
  52. package/src/cli/commands/hooks.ts +244 -0
  53. package/src/cli/generate.ts +286 -12
  54. package/src/cli/index.ts +36 -8
  55. package/src/config/models.ts +136 -0
  56. package/src/db/client.ts +4 -3
  57. package/src/embeddings/openrouter.ts +19 -7
  58. package/templates/map/claude.md +82 -0
  59. package/templates/map/cline.md +37 -0
  60. package/templates/map/copilot.md +31 -0
  61. package/templates/map/cursor.md +39 -0
  62. package/templates/map/gemini.md +47 -0
package/README.md CHANGED
@@ -73,6 +73,7 @@ K0ntext uses native SQLite extensions for high-performance vector search.
73
73
  - Tech stack detection and documentation
74
74
  - Workflow discovery and categorization
75
75
  - Automatic context generation
76
+ - **Centralized model configuration** (v3.1.0) - Single source of truth for all AI operations
76
77
 
77
78
  ### πŸ” Semantic Search
78
79
  - Vector database (sqlite-vec) for intelligent code retrieval
@@ -85,6 +86,29 @@ K0ntext uses native SQLite extensions for high-performance vector search.
85
86
  - Automatic synchronization between tool configurations
86
87
  - Change detection with SHA256 hashing
87
88
  - Sync status monitoring
89
+ - **Intelligent cross-sync** (v3.1.0) - AI-powered propagation of changes across tools
90
+
91
+ ### πŸ€– Git Hooks Automation (v3.1.0)
92
+ - **Pre-commit workflow** - Automatic context maintenance
93
+ - Drift detection on every commit
94
+ - Automatic cross-sync when drift detected
95
+ - Updated context files auto-added to commits
96
+
97
+ ### 🎯 Drift Detection (v3.1.0)
98
+ - **AI-powered semantic analysis** - Detect when documentation diverges from code
99
+ - Replaces hash-based checks with intelligent understanding
100
+ - Severity-based reporting (high/medium/low)
101
+ - Automatic fix suggestions
102
+
103
+ ### πŸ“‹ Fact-Checking (v3.1.0)
104
+ - Validate documentation accuracy against codebase
105
+ - Identify outdated APIs, wrong file paths, missing dependencies
106
+ - Confidence scoring for each claim
107
+
108
+ ### πŸ—ΊοΈ Map-Based Context (v3.1.0)
109
+ - Concise, structured context files
110
+ - Reduce hallucination through precise references
111
+ - Alternative to verbose documentation format
88
112
 
89
113
  ### πŸ€– MCP Server
90
114
  - **10 Tools:** search_context, get_item, add_knowledge, analyze, get_tool_configs, query_graph, get_stats
@@ -92,7 +116,7 @@ K0ntext uses native SQLite extensions for high-performance vector search.
92
116
  - Real-time context access for AI assistants
93
117
  - Knowledge graph traversal
94
118
 
95
- ### πŸ› οΈ Complete CLI (13 Commands)
119
+ ### πŸ› οΈ Complete CLI (18 Commands)
96
120
  - `init` - Initialize with intelligent analysis
97
121
  - `generate` - Generate context files for all tools
98
122
  - `mcp` - Start MCP server
@@ -106,10 +130,17 @@ K0ntext uses native SQLite extensions for high-performance vector search.
106
130
  - `index` - Index codebase
107
131
  - `search` - Search indexed content
108
132
  - `stats` - View database statistics
133
+ - **`drift-detect`** - AI-powered documentation drift detection
134
+ - **`cross-sync`** - Intelligent sync across all AI tools
135
+ - **`hooks`** - Git hooks management (install/uninstall/status)
136
+ - **`fact-check`** - Validate documentation accuracy
137
+ - `generate --map` - Generate concise map-based context files
109
138
 
110
139
  ### πŸ“Š Smart Agents
111
140
  - **CleanupAgent** - Remove conflicting AI tool folders (.cursor, .windsurf, .cline, etc.)
112
141
  - **PerformanceMonitorAgent** - Track database performance and suggest optimizations
142
+ - **DriftAgent** (v3.1.0) - AI-powered documentation drift detection
143
+ - **FactCheckAgent** (v3.1.0) - Validate documentation accuracy against codebase
113
144
 
114
145
  ### πŸ—ƒοΈ SQLite Storage
115
146
  - Persistent database with SHA256 change detection
@@ -159,6 +190,7 @@ k0ntext generate -v
159
190
  **Options:**
160
191
  - `-ai, --ai <tools>` - Specific tools (comma-separated)
161
192
  - `--force` - Force regenerate all files
193
+ - `--map` - Use concise map-based format (new in v3.1.0)
162
194
  - `-v, --verbose` - Show detailed output
163
195
 
164
196
  #### `k0ntext mcp`
@@ -218,6 +250,7 @@ k0ntext cleanup -v
218
250
  **Options:**
219
251
  - `--dry-run` - Show what would be removed
220
252
  - `--keep <folders>` - Folders to keep (comma-separated)
253
+ - `--ai` - Use AI to intelligently analyze which folders can be safely removed (new in v3.1.0)
221
254
  - `-v, --verbose` - Show detailed output
222
255
 
223
256
  #### `k0ntext validate`
@@ -362,6 +395,128 @@ k0ntext stats
362
395
  k0ntext stats | grep "Context Items"
363
396
  ```
364
397
 
398
+ ### v3.1.0 New Commands
399
+
400
+ #### `k0ntext drift-detect`
401
+ AI-powered documentation drift detection using semantic analysis.
402
+
403
+ ```bash
404
+ # Detect drift in all context files
405
+ k0ntext drift-detect
406
+
407
+ # Detect drift in specific paths
408
+ k0ntext drift-detect -p CLAUDE.md,.cursorrules
409
+
410
+ # Check up to 20 files
411
+ k0ntext drift-detect --max-files 20
412
+
413
+ # Strict mode (fails on any drift)
414
+ k0ntext drift-detect --strict
415
+
416
+ # Verbose output
417
+ k0ntext drift-detect -v
418
+ ```
419
+
420
+ **Options:**
421
+ - `--fix` - Automatically fix detected drift (experimental)
422
+ - `--strict` - Fail on any drift detected
423
+ - `-p, --paths <paths>` - Comma-separated paths to check
424
+ - `--max-files <number>` - Maximum files to check (default: 50)
425
+ - `--model <model>` - Override model (not recommended)
426
+ - `-v, --verbose` - Show detailed output
427
+
428
+ #### `k0ntext cross-sync`
429
+ Intelligently synchronize context across all AI tools after drift detection.
430
+
431
+ ```bash
432
+ # Sync all affected files
433
+ k0ntext cross-sync
434
+
435
+ # Dry run to see what would be synced
436
+ k0ntext cross-sync --dry-run
437
+
438
+ # Sync to specific tools only
439
+ k0ntext cross-sync --to claude,cursor
440
+
441
+ # Sync from specific files
442
+ k0ntext cross-sync --affected CLAUDE.md,.cursorrules
443
+
444
+ # Verbose output with details
445
+ k0ntext cross-sync -v
446
+ ```
447
+
448
+ **Options:**
449
+ - `--dry-run` - Show what would be synced without making changes
450
+ - `--from <tool>` - Sync only from specific tool
451
+ - `--to <tools>` - Sync only to specific tools (comma-separated)
452
+ - `--affected <files>` - Comma-separated list of affected files
453
+ - `-v, --verbose` - Show detailed sync output
454
+
455
+ #### `k0ntext hooks`
456
+ Manage git hooks for automatic context synchronization.
457
+
458
+ ```bash
459
+ # Install git hooks
460
+ k0ntext hooks install
461
+
462
+ # Install with force (overwrite existing)
463
+ k0ntext hooks install -f
464
+
465
+ # Uninstall git hooks
466
+ k0ntext hooks uninstall
467
+
468
+ # Check hooks status
469
+ k0ntext hooks status
470
+ ```
471
+
472
+ **Subcommands:**
473
+ - `install` - Install pre-commit hook for automatic workflow
474
+ - `uninstall` - Remove installed hooks
475
+ - `status` - Show hook installation status
476
+
477
+ **Install Options:**
478
+ - `-f, --force` - Overwrite existing hooks
479
+ - `--skip-backup` - Skip backing up existing hooks
480
+
481
+ #### `k0ntext fact-check [files...]`
482
+ Validate documentation accuracy using AI analysis.
483
+
484
+ ```bash
485
+ # Check all documentation files
486
+ k0ntext fact-check
487
+
488
+ # Check specific files
489
+ k0ntext fact-check CLAUDE.md .cursorrules
490
+
491
+ # Set minimum confidence threshold
492
+ k0ntext fact-check --min-confidence 0.7
493
+
494
+ # Verbose output
495
+ k0ntext fact-check -v
496
+ ```
497
+
498
+ **Options:**
499
+ - `--fix` - Automatically fix detected issues (experimental)
500
+ - `-v, --verbose` - Show detailed output
501
+ - `--min-confidence <number>` - Minimum confidence to report (0-1, default: 0.5)
502
+
503
+ ### Git Hooks Workflow (v3.1.0)
504
+
505
+ When you install hooks with `k0ntext hooks install`, the pre-commit hook automatically:
506
+
507
+ 1. **Autosync** - Sync context from source of truth
508
+ 2. **Validate** - Check for context errors
509
+ 3. **Drift Detect** - AI-powered drift detection
510
+ 4. **Cross-Sync** - Update all AI tool contexts if drift found
511
+ 5. **Auto-Add** - Include updated context files in commit
512
+
513
+ **Skip hooks temporarily:**
514
+ ```bash
515
+ K0NTEXT_SKIP_HOOKS=1 git commit -m "message"
516
+ # or
517
+ git commit --no-verify -m "message"
518
+ ```
519
+
365
520
  ## πŸ€– MCP Server Usage
366
521
 
367
522
  ### Start the Server
@@ -467,11 +622,12 @@ Each AI tool has its own configuration file path:
467
622
  ```
468
623
  k0ntext/
469
624
  β”œβ”€β”€ src/ # TypeScript source
470
- β”‚ β”œβ”€β”€ cli/ # CLI commands (13 commands)
625
+ β”‚ β”œβ”€β”€ cli/ # CLI commands (18 commands)
626
+ β”‚ β”œβ”€β”€ config/ # Centralized configuration (v3.1.0)
471
627
  β”‚ β”œβ”€β”€ db/ # SQLite database client
472
628
  β”‚ β”œβ”€β”€ analyzer/ # Intelligent codebase analysis
473
629
  β”‚ β”œβ”€β”€ embeddings/ # OpenRouter integration
474
- β”‚ β”œβ”€β”€ agents/ # Smart agents (Cleanup, Performance)
630
+ β”‚ β”œβ”€β”€ agents/ # Smart agents (Cleanup, Performance, Drift, FactCheck)
475
631
  β”‚ └── mcp.ts # MCP server implementation
476
632
  β”œβ”€β”€ agents/ # Agent definitions
477
633
  β”œβ”€β”€ skills/ # RPI workflow skills
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Drift Detection Agent
3
+ *
4
+ * Uses AI to detect when documentation drifts from the actual codebase.
5
+ * This is the core of intelligent drift detection for k0ntext v3.1.0.
6
+ *
7
+ * @version 3.1.0
8
+ */
9
+ import { OpenRouterClient } from '../embeddings/openrouter.js';
10
+ /**
11
+ * A detected drift issue
12
+ */
13
+ export interface DriftIssue {
14
+ /** The file where drift was detected */
15
+ file: string;
16
+ /** Severity level */
17
+ severity: 'low' | 'medium' | 'high';
18
+ /** What the documentation says */
19
+ expected: string;
20
+ /** What the actual codebase has */
21
+ actual: string;
22
+ /** Suggested fix (optional) */
23
+ suggestion?: string;
24
+ /** Line number where drift occurs (optional) */
25
+ line?: number;
26
+ }
27
+ /**
28
+ * Result of drift detection
29
+ */
30
+ export interface DriftResult {
31
+ /** All detected drifts */
32
+ drifts: DriftIssue[];
33
+ /** Number of drifts automatically fixed */
34
+ fixed: number;
35
+ /** Files checked */
36
+ filesChecked: number;
37
+ /** Time taken in milliseconds */
38
+ duration: number;
39
+ }
40
+ /**
41
+ * Configuration for the drift agent
42
+ */
43
+ export interface DriftAgentConfig {
44
+ /** OpenRouter client for AI analysis */
45
+ openRouter: OpenRouterClient;
46
+ /** Model override (not recommended) */
47
+ model?: string;
48
+ /** Whether to fail on any drift */
49
+ strict?: boolean;
50
+ /** Project root directory */
51
+ projectRoot: string;
52
+ }
53
+ /**
54
+ * Drift Detection Agent
55
+ *
56
+ * Analyzes documentation files and compares them against the actual
57
+ * codebase to detect discrepancies using AI semantic analysis.
58
+ */
59
+ export declare class DriftAgent {
60
+ private openRouter;
61
+ private model;
62
+ private strict;
63
+ private projectRoot;
64
+ constructor(config: DriftAgentConfig);
65
+ /**
66
+ * Detect drift across all context files
67
+ */
68
+ detectDrift(options: {
69
+ paths?: string[];
70
+ autoFix?: boolean;
71
+ maxFiles?: number;
72
+ }): Promise<DriftResult>;
73
+ /**
74
+ * Check a single file for drift
75
+ */
76
+ private checkFileForDrift;
77
+ /**
78
+ * Get the drift detection system prompt
79
+ */
80
+ private getDriftDetectionPrompt;
81
+ /**
82
+ * Build the drift analysis prompt for a specific file
83
+ */
84
+ private buildDriftAnalysisPrompt;
85
+ /**
86
+ * Parse the drift detection response
87
+ */
88
+ private parseDriftResponse;
89
+ /**
90
+ * Get relevant source code samples for comparison
91
+ */
92
+ private getRelevantSourceSamples;
93
+ /**
94
+ * Discover source files in the project
95
+ */
96
+ private discoverSourceFiles;
97
+ /**
98
+ * Get all context files to check
99
+ */
100
+ private getContextFiles;
101
+ /**
102
+ * Attempt to fix drift in a file
103
+ */
104
+ private fixDrift;
105
+ /**
106
+ * Close the agent and clean up resources
107
+ */
108
+ close(): void;
109
+ }
110
+ /**
111
+ * Create a drift agent
112
+ */
113
+ export declare function createDriftAgent(config: Omit<DriftAgentConfig, 'projectRoot'>): DriftAgent;
114
+ //# sourceMappingURL=drift-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift-agent.d.ts","sourceRoot":"","sources":["../../src/agents/drift-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAG/D;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB;AA4CD;;;;;GAKG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,gBAAgB;IAOpC;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE;QACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,WAAW,CAAC;IAuCxB;;OAEG;YACW,iBAAiB;IAsD/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA4B/B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAqBhC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA4B1B;;OAEG;YACW,wBAAwB;IAuCtC;;OAEG;YACW,mBAAmB;IA0BjC;;OAEG;YACW,eAAe;IAgB7B;;OAEG;YACW,QAAQ;IAQtB;;OAEG;IACH,KAAK,IAAI,IAAI;CAId;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,GAAG,UAAU,CAK1F"}
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Drift Detection Agent
3
+ *
4
+ * Uses AI to detect when documentation drifts from the actual codebase.
5
+ * This is the core of intelligent drift detection for k0ntext v3.1.0.
6
+ *
7
+ * @version 3.1.0
8
+ */
9
+ import fs from 'fs/promises';
10
+ import path from 'path';
11
+ import { glob } from 'glob';
12
+ import { MODEL_CONFIG, getModelFor } from '../config/models.js';
13
+ /**
14
+ * Default ignore patterns for file discovery
15
+ */
16
+ const DEFAULT_IGNORE = [
17
+ '**/node_modules/**',
18
+ '**/dist/**',
19
+ '**/build/**',
20
+ '**/.git/**',
21
+ '**/vendor/**',
22
+ '**/__pycache__/**',
23
+ '**/target/**',
24
+ '**/bin/**',
25
+ '**/obj/**',
26
+ '**/.next/**',
27
+ '**/.nuxt/**',
28
+ '**/*.min.js',
29
+ '**/*.map',
30
+ '**/package-lock.json',
31
+ '**/yarn.lock',
32
+ '**/pnpm-lock.yaml'
33
+ ];
34
+ /**
35
+ * Default context files to check for drift
36
+ */
37
+ const DEFAULT_CONTEXT_FILES = [
38
+ 'CLAUDE.md',
39
+ 'CLAUDE.md.local',
40
+ 'AI_CONTEXT.md',
41
+ '.github/copilot-instructions.md',
42
+ '.clinerules',
43
+ '.windsurf/rules.md',
44
+ '.cursorrules',
45
+ '.aider.conf.yml',
46
+ '.continue/config.json',
47
+ '.gemini/config.md',
48
+ '.claude/context/**/*.md',
49
+ '.claude/commands/**/*.md',
50
+ 'docs/**/*.md',
51
+ 'README.md'
52
+ ];
53
+ /**
54
+ * Drift Detection Agent
55
+ *
56
+ * Analyzes documentation files and compares them against the actual
57
+ * codebase to detect discrepancies using AI semantic analysis.
58
+ */
59
+ export class DriftAgent {
60
+ openRouter;
61
+ model;
62
+ strict;
63
+ projectRoot;
64
+ constructor(config) {
65
+ this.openRouter = config.openRouter;
66
+ this.model = config.model || getModelFor('DRIFT_DETECTION');
67
+ this.strict = config.strict ?? false;
68
+ this.projectRoot = config.projectRoot;
69
+ }
70
+ /**
71
+ * Detect drift across all context files
72
+ */
73
+ async detectDrift(options) {
74
+ const startTime = Date.now();
75
+ const drifts = [];
76
+ let fixed = 0;
77
+ // Get list of files to check
78
+ const filesToCheck = options.paths
79
+ ? options.paths
80
+ : await this.getContextFiles();
81
+ // Limit files if specified
82
+ const filesToProcess = options.maxFiles
83
+ ? filesToCheck.slice(0, options.maxFiles)
84
+ : filesToCheck;
85
+ // Discover relevant source code for comparison
86
+ const sourceFiles = await this.discoverSourceFiles();
87
+ // Analyze each file for drift
88
+ for (const relativePath of filesToProcess) {
89
+ const drift = await this.checkFileForDrift(relativePath, sourceFiles);
90
+ if (drift) {
91
+ drifts.push(drift);
92
+ if (options.autoFix && drift.suggestion) {
93
+ const didFix = await this.fixDrift(relativePath, drift);
94
+ if (didFix)
95
+ fixed++;
96
+ }
97
+ }
98
+ }
99
+ return {
100
+ drifts,
101
+ fixed,
102
+ filesChecked: filesToProcess.length,
103
+ duration: Date.now() - startTime
104
+ };
105
+ }
106
+ /**
107
+ * Check a single file for drift
108
+ */
109
+ async checkFileForDrift(relativePath, sourceFiles) {
110
+ const fullPath = path.join(this.projectRoot, relativePath);
111
+ try {
112
+ const content = await fs.readFile(fullPath, 'utf-8');
113
+ // Get relevant source file samples for comparison
114
+ const relevantSource = await this.getRelevantSourceSamples(relativePath, sourceFiles);
115
+ // Use AI to analyze drift
116
+ const analysis = await this.openRouter.chat([
117
+ {
118
+ role: 'system',
119
+ content: this.getDriftDetectionPrompt()
120
+ },
121
+ {
122
+ role: 'user',
123
+ content: this.buildDriftAnalysisPrompt(relativePath, content, relevantSource)
124
+ }
125
+ ], {
126
+ model: this.model,
127
+ temperature: MODEL_CONFIG.ANALYSIS_TEMPERATURE,
128
+ maxTokens: MODEL_CONFIG.DRIFT_MAX_TOKENS
129
+ });
130
+ // Parse JSON response
131
+ const result = this.parseDriftResponse(analysis);
132
+ if (result && result.hasDrift) {
133
+ return {
134
+ file: relativePath,
135
+ severity: result.severity || 'medium',
136
+ expected: result.expected || 'Documentation does not match current code',
137
+ actual: result.actual || 'Code has changed',
138
+ suggestion: result.suggestion,
139
+ line: result.line
140
+ };
141
+ }
142
+ return null;
143
+ }
144
+ catch (error) {
145
+ // If analysis fails, log but don't fail the entire process
146
+ console.error(`Failed to analyze ${relativePath}: ${error instanceof Error ? error.message : error}`);
147
+ return null;
148
+ }
149
+ }
150
+ /**
151
+ * Get the drift detection system prompt
152
+ */
153
+ getDriftDetectionPrompt() {
154
+ return `You are a drift detection expert for AI context engineering.
155
+
156
+ Your task is to analyze if documentation accurately reflects the current codebase state.
157
+
158
+ Look for these types of drift:
159
+ 1. **File references** - Documentation mentions files that don't exist or have moved
160
+ 2. **API signatures** - Function/method signatures that have changed
161
+ 3. **Architecture changes** - Structural changes not reflected in docs
162
+ 4. **Workflow changes** - Process changes not documented
163
+ 5. **Configuration changes** - Settings/options that have changed
164
+
165
+ Respond with valid JSON only (no markdown formatting):
166
+ {
167
+ "hasDrift": boolean,
168
+ "severity": "low" | "medium" | "high",
169
+ "expected": "what the documentation claims",
170
+ "actual": "what the actual code has",
171
+ "suggestion": "how to fix the documentation",
172
+ "line": number (if applicable)
173
+ }
174
+
175
+ Severity guidelines:
176
+ - high: Breaking changes, missing files, incorrect API signatures
177
+ - medium: Changed workflows, outdated architecture descriptions
178
+ - low: Minor inconsistencies, outdated examples`;
179
+ }
180
+ /**
181
+ * Build the drift analysis prompt for a specific file
182
+ */
183
+ buildDriftAnalysisPrompt(docPath, docContent, sourceSamples) {
184
+ let prompt = `Check for drift in: ${docPath}\n\n`;
185
+ prompt += `## Documentation Content\n${docContent}\n\n`;
186
+ if (sourceSamples.length > 0) {
187
+ prompt += `## Relevant Source Code Samples\n`;
188
+ prompt += `Use these to verify documentation accuracy:\n\n`;
189
+ for (const sample of sourceSamples.slice(0, 5)) { // Limit to 5 samples
190
+ prompt += `---\n${sample}\n---\n`;
191
+ }
192
+ }
193
+ prompt += `\nAnalyze the documentation against the code samples and identify any discrepancies.`;
194
+ return prompt;
195
+ }
196
+ /**
197
+ * Parse the drift detection response
198
+ */
199
+ parseDriftResponse(response) {
200
+ try {
201
+ // Try direct parse first
202
+ return JSON.parse(response);
203
+ }
204
+ catch {
205
+ // Try to extract JSON from response
206
+ const start = response.indexOf('{');
207
+ const end = response.lastIndexOf('}');
208
+ if (start !== -1 && end !== -1 && end > start) {
209
+ try {
210
+ const jsonSubstring = response.slice(start, end + 1);
211
+ return JSON.parse(jsonSubstring);
212
+ }
213
+ catch {
214
+ // Still failed, return null
215
+ }
216
+ }
217
+ }
218
+ return null;
219
+ }
220
+ /**
221
+ * Get relevant source code samples for comparison
222
+ */
223
+ async getRelevantSourceSamples(docPath, sourceFiles) {
224
+ const samples = [];
225
+ const maxSampleSize = 2000; // bytes
226
+ // Extract file references from doc path
227
+ const docName = path.basename(docPath, '.md').toLowerCase();
228
+ // Find related source files
229
+ const relatedFiles = sourceFiles.filter(file => {
230
+ const lowerFile = file.toLowerCase();
231
+ // Files that might be related to this doc
232
+ if (docName.includes('claude') && lowerFile.includes('claude'))
233
+ return true;
234
+ if (docName.includes('readme') && (lowerFile.includes('index') || lowerFile.includes('main')))
235
+ return true;
236
+ return true; // Include all for now, could be smarter
237
+ }).slice(0, 10); // Limit to 10 files
238
+ for (const file of relatedFiles) {
239
+ try {
240
+ const fullPath = path.join(this.projectRoot, file);
241
+ const stats = await fs.stat(fullPath);
242
+ if (stats.isFile() && stats.size < maxSampleSize * 2) {
243
+ const content = await fs.readFile(fullPath, 'utf-8');
244
+ const truncated = content.length > maxSampleSize
245
+ ? content.slice(0, maxSampleSize) + '\n... [truncated]'
246
+ : content;
247
+ samples.push(`### ${file}\n${truncated}`);
248
+ }
249
+ }
250
+ catch {
251
+ // Skip files that can't be read
252
+ }
253
+ }
254
+ return samples;
255
+ }
256
+ /**
257
+ * Discover source files in the project
258
+ */
259
+ async discoverSourceFiles() {
260
+ const patterns = [
261
+ '**/*.ts',
262
+ '**/*.tsx',
263
+ '**/*.js',
264
+ '**/*.jsx',
265
+ '**/*.py',
266
+ '**/*.go',
267
+ '**/*.rs',
268
+ '**/*.java'
269
+ ];
270
+ const allFiles = [];
271
+ for (const pattern of patterns) {
272
+ const files = await glob(pattern, {
273
+ cwd: this.projectRoot,
274
+ ignore: DEFAULT_IGNORE,
275
+ absolute: false
276
+ });
277
+ allFiles.push(...files);
278
+ }
279
+ return allFiles;
280
+ }
281
+ /**
282
+ * Get all context files to check
283
+ */
284
+ async getContextFiles() {
285
+ const files = [];
286
+ for (const pattern of DEFAULT_CONTEXT_FILES) {
287
+ const matched = await glob(pattern, {
288
+ cwd: this.projectRoot,
289
+ ignore: DEFAULT_IGNORE,
290
+ absolute: false
291
+ });
292
+ files.push(...matched);
293
+ }
294
+ // Deduplicate
295
+ return Array.from(new Set(files));
296
+ }
297
+ /**
298
+ * Attempt to fix drift in a file
299
+ */
300
+ async fixDrift(relativePath, drift) {
301
+ // For now, just log what would be fixed
302
+ // Auto-fixing requires careful implementation to avoid breaking things
303
+ console.log(`Would fix drift in ${relativePath}:`);
304
+ console.log(` ${drift.suggestion || 'No suggestion available'}`);
305
+ return false; // Not implementing auto-fix yet
306
+ }
307
+ /**
308
+ * Close the agent and clean up resources
309
+ */
310
+ close() {
311
+ // OpenRouterClient has its own cache management
312
+ // Nothing to clean up here for now
313
+ }
314
+ }
315
+ /**
316
+ * Create a drift agent
317
+ */
318
+ export function createDriftAgent(config) {
319
+ return new DriftAgent({
320
+ ...config,
321
+ projectRoot: process.cwd()
322
+ });
323
+ }
324
+ //# sourceMappingURL=drift-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift-agent.js","sourceRoot":"","sources":["../../src/agents/drift-agent.ts"],"names":[],"mappings":"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"}