driftdetect 0.1.6 ā 0.1.7
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.
- package/dist/bin/drift.js +5 -1
- package/dist/bin/drift.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/watch.d.ts +12 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +264 -0
- package/dist/commands/watch.js.map +1 -0
- package/package.json +1 -1
package/dist/bin/drift.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { Command } from 'commander';
|
|
11
11
|
import { VERSION } from '../index.js';
|
|
12
|
-
import { initCommand, scanCommand, checkCommand, statusCommand, approveCommand, ignoreCommand, reportCommand, exportCommand, whereCommand, filesCommand, } from '../commands/index.js';
|
|
12
|
+
import { initCommand, scanCommand, checkCommand, statusCommand, approveCommand, ignoreCommand, reportCommand, exportCommand, whereCommand, filesCommand, watchCommand, } from '../commands/index.js';
|
|
13
13
|
/**
|
|
14
14
|
* Create and configure the main CLI program
|
|
15
15
|
*/
|
|
@@ -32,6 +32,7 @@ function createProgram() {
|
|
|
32
32
|
program.addCommand(exportCommand);
|
|
33
33
|
program.addCommand(whereCommand);
|
|
34
34
|
program.addCommand(filesCommand);
|
|
35
|
+
program.addCommand(watchCommand);
|
|
35
36
|
// Add help examples
|
|
36
37
|
program.addHelpText('after', `
|
|
37
38
|
Examples:
|
|
@@ -51,6 +52,9 @@ Examples:
|
|
|
51
52
|
$ drift export --format ai-context Export for AI consumption
|
|
52
53
|
$ drift where <pattern> Find pattern locations
|
|
53
54
|
$ drift files <path> Show patterns in a file
|
|
55
|
+
$ drift watch Watch for changes in real-time
|
|
56
|
+
$ drift watch --verbose Watch with detailed output
|
|
57
|
+
$ drift watch --context .drift-context.md Auto-update AI context file
|
|
54
58
|
|
|
55
59
|
Documentation:
|
|
56
60
|
https://github.com/drift/drift
|
package/dist/bin/drift.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/bin/drift.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,GACb,MAAM,sBAAsB,CAAC;AAE9B;;GAEG;AACH,SAAS,aAAa;IACpB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,OAAO,CAAC;SACb,WAAW,CAAC,qEAAqE,CAAC;SAClF,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,4BAA4B,CAAC;SAC/D,MAAM,CAAC,WAAW,EAAE,uBAAuB,CAAC;SAC5C,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;IAElD,wBAAwB;IACxB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IACnC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IACjC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAEjC,oBAAoB;IACpB,OAAO,CAAC,WAAW,CACjB,OAAO,EACP
|
|
1
|
+
{"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/bin/drift.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,sBAAsB,CAAC;AAE9B;;GAEG;AACH,SAAS,aAAa;IACpB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,OAAO,CAAC;SACb,WAAW,CAAC,qEAAqE,CAAC;SAClF,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,4BAA4B,CAAC;SAC/D,MAAM,CAAC,WAAW,EAAE,uBAAuB,CAAC;SAC5C,MAAM,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;IAElD,wBAAwB;IACxB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IACnC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IACjC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IACjC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAEjC,oBAAoB;IACpB,OAAO,CAAC,WAAW,CACjB,OAAO,EACP;;;;;;;;;;;;;;;;;;;;;;;;CAwBH,CACE,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAEhC,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACzC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,cAAc;AACd,IAAI,EAAE,CAAC"}
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -13,4 +13,5 @@ export { reportCommand } from './report.js';
|
|
|
13
13
|
export { exportCommand } from './export.js';
|
|
14
14
|
export { whereCommand } from './where.js';
|
|
15
15
|
export { filesCommand } from './files.js';
|
|
16
|
+
export { watchCommandDef as watchCommand } from './watch.js';
|
|
16
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/commands/index.js
CHANGED
|
@@ -13,4 +13,5 @@ export { reportCommand } from './report.js';
|
|
|
13
13
|
export { exportCommand } from './export.js';
|
|
14
14
|
export { whereCommand } from './where.js';
|
|
15
15
|
export { filesCommand } from './files.js';
|
|
16
|
+
export { watchCommandDef as watchCommand } from './watch.js';
|
|
16
17
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drift Watch Command
|
|
3
|
+
*
|
|
4
|
+
* Real-time file watching with pattern detection.
|
|
5
|
+
* Monitors file changes and reports violations as they happen.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
/**
|
|
9
|
+
* Create the watch command
|
|
10
|
+
*/
|
|
11
|
+
export declare const watchCommandDef: Command;
|
|
12
|
+
//# sourceMappingURL=watch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuSpC;;GAEG;AACH,eAAO,MAAM,eAAe,SAML,CAAC"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drift Watch Command
|
|
3
|
+
*
|
|
4
|
+
* Real-time file watching with pattern detection.
|
|
5
|
+
* Monitors file changes and reports violations as they happen.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { createAllDetectorsArray } from 'driftdetect-detectors';
|
|
12
|
+
/**
|
|
13
|
+
* Format timestamp for output
|
|
14
|
+
*/
|
|
15
|
+
function timestamp() {
|
|
16
|
+
return chalk.gray(`[${new Date().toLocaleTimeString()}]`);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Scan a single file for violations
|
|
20
|
+
*/
|
|
21
|
+
async function scanFile(filePath, detectors, categories) {
|
|
22
|
+
const violations = [];
|
|
23
|
+
try {
|
|
24
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
25
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
const relativePath = path.relative(cwd, filePath);
|
|
28
|
+
let language = 'typescript';
|
|
29
|
+
if (['.ts', '.tsx'].includes(ext))
|
|
30
|
+
language = 'typescript';
|
|
31
|
+
else if (['.js', '.jsx'].includes(ext))
|
|
32
|
+
language = 'javascript';
|
|
33
|
+
else if (['.py'].includes(ext))
|
|
34
|
+
language = 'python';
|
|
35
|
+
else if (['.css', '.scss'].includes(ext))
|
|
36
|
+
language = 'css';
|
|
37
|
+
else if (['.json'].includes(ext))
|
|
38
|
+
language = 'json';
|
|
39
|
+
else if (['.md'].includes(ext))
|
|
40
|
+
language = 'markdown';
|
|
41
|
+
// Check if test file
|
|
42
|
+
const isTestFile = /\.(test|spec)\.[jt]sx?$/.test(filePath) ||
|
|
43
|
+
filePath.includes('__tests__') ||
|
|
44
|
+
filePath.includes('/test/') ||
|
|
45
|
+
filePath.includes('/tests/');
|
|
46
|
+
// Check if type definition
|
|
47
|
+
const isTypeDefinition = ext === '.d.ts';
|
|
48
|
+
// Create minimal project context
|
|
49
|
+
const projectContext = {
|
|
50
|
+
rootDir: cwd,
|
|
51
|
+
files: [relativePath],
|
|
52
|
+
config: {},
|
|
53
|
+
};
|
|
54
|
+
// Run detectors
|
|
55
|
+
for (const detector of detectors) {
|
|
56
|
+
// Filter by category if specified
|
|
57
|
+
if (categories && !categories.includes(detector.category)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
// Check if detector supports this language
|
|
61
|
+
if (!detector.supportsLanguage(language)) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
// Create full detection context
|
|
66
|
+
const context = {
|
|
67
|
+
file: relativePath,
|
|
68
|
+
content,
|
|
69
|
+
ast: null,
|
|
70
|
+
imports: [],
|
|
71
|
+
exports: [],
|
|
72
|
+
projectContext,
|
|
73
|
+
language,
|
|
74
|
+
extension: ext,
|
|
75
|
+
isTestFile,
|
|
76
|
+
isTypeDefinition,
|
|
77
|
+
};
|
|
78
|
+
const result = await detector.detect(context);
|
|
79
|
+
// Check for violations
|
|
80
|
+
if (result.violations && result.violations.length > 0) {
|
|
81
|
+
for (const v of result.violations) {
|
|
82
|
+
violations.push({
|
|
83
|
+
file: filePath,
|
|
84
|
+
line: v.range?.start?.line ?? 1,
|
|
85
|
+
message: v.message,
|
|
86
|
+
severity: v.severity,
|
|
87
|
+
patternName: detector.name,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Skip detector errors silently
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// File read error - skip
|
|
99
|
+
}
|
|
100
|
+
return violations;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Print violations to console
|
|
104
|
+
*/
|
|
105
|
+
function printViolations(filePath, violations, verbose) {
|
|
106
|
+
const relativePath = path.relative(process.cwd(), filePath);
|
|
107
|
+
if (violations.length === 0) {
|
|
108
|
+
console.log(`${timestamp()} ${chalk.green('ā')} ${relativePath}`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const errors = violations.filter(v => v.severity === 'error');
|
|
112
|
+
const warnings = violations.filter(v => v.severity === 'warning');
|
|
113
|
+
let summary = '';
|
|
114
|
+
if (errors.length > 0)
|
|
115
|
+
summary += chalk.red(`${errors.length} error${errors.length > 1 ? 's' : ''}`);
|
|
116
|
+
if (warnings.length > 0) {
|
|
117
|
+
if (summary)
|
|
118
|
+
summary += ', ';
|
|
119
|
+
summary += chalk.yellow(`${warnings.length} warning${warnings.length > 1 ? 's' : ''}`);
|
|
120
|
+
}
|
|
121
|
+
console.log(`${timestamp()} ${chalk.red('ā')} ${relativePath} - ${summary}`);
|
|
122
|
+
if (verbose) {
|
|
123
|
+
for (const v of violations) {
|
|
124
|
+
const icon = v.severity === 'error' ? chalk.red('ā') : chalk.yellow('ā');
|
|
125
|
+
console.log(` ${icon} Line ${v.line}: ${v.message}`);
|
|
126
|
+
console.log(` ${chalk.gray(`[${v.patternName}]`)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Update AI context file
|
|
132
|
+
*/
|
|
133
|
+
function updateContextFile(contextPath) {
|
|
134
|
+
try {
|
|
135
|
+
const content = `# Drift Context (Auto-updated)
|
|
136
|
+
|
|
137
|
+
Last updated: ${new Date().toISOString()}
|
|
138
|
+
|
|
139
|
+
This file is auto-updated by \`drift watch\`.
|
|
140
|
+
Run \`drift export --format ai-context\` for full pattern details.
|
|
141
|
+
|
|
142
|
+
## Quick Commands
|
|
143
|
+
- \`drift where <pattern>\` - Find pattern locations
|
|
144
|
+
- \`drift files <path>\` - See patterns in a specific file
|
|
145
|
+
- \`drift status\` - View pattern summary
|
|
146
|
+
`;
|
|
147
|
+
fs.writeFileSync(contextPath, content);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Silently fail context updates
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Watch command implementation
|
|
155
|
+
*/
|
|
156
|
+
async function watchCommand(options) {
|
|
157
|
+
const cwd = process.cwd();
|
|
158
|
+
const verbose = options.verbose ?? false;
|
|
159
|
+
const contextPath = options.context;
|
|
160
|
+
const debounceMs = parseInt(options.debounce ?? '300', 10);
|
|
161
|
+
const categories = options.categories?.split(',').map(c => c.trim()) ?? null;
|
|
162
|
+
console.log(chalk.cyan('\nš Drift Watch Mode\n'));
|
|
163
|
+
console.log(` Watching: ${chalk.white(cwd)}`);
|
|
164
|
+
if (categories) {
|
|
165
|
+
console.log(` Categories: ${chalk.white(categories.join(', '))}`);
|
|
166
|
+
}
|
|
167
|
+
if (contextPath) {
|
|
168
|
+
console.log(` Context file: ${chalk.white(contextPath)}`);
|
|
169
|
+
}
|
|
170
|
+
console.log(` Debounce: ${chalk.white(`${debounceMs}ms`)}`);
|
|
171
|
+
console.log(chalk.gray('\n Press Ctrl+C to stop\n'));
|
|
172
|
+
console.log(chalk.gray('ā'.repeat(50)));
|
|
173
|
+
// Load detectors
|
|
174
|
+
const detectors = createAllDetectorsArray();
|
|
175
|
+
console.log(`${timestamp()} Loaded ${chalk.cyan(String(detectors.length))} detectors`);
|
|
176
|
+
// Track pending scans (for debouncing)
|
|
177
|
+
const pendingScans = new Map();
|
|
178
|
+
// Ignore patterns
|
|
179
|
+
const ignorePatterns = [
|
|
180
|
+
'node_modules',
|
|
181
|
+
'.git',
|
|
182
|
+
'dist',
|
|
183
|
+
'build',
|
|
184
|
+
'coverage',
|
|
185
|
+
'.turbo',
|
|
186
|
+
];
|
|
187
|
+
/**
|
|
188
|
+
* Handle file change
|
|
189
|
+
*/
|
|
190
|
+
function handleFileChange(filePath) {
|
|
191
|
+
// Check if file should be ignored
|
|
192
|
+
const relativePath = path.relative(cwd, filePath);
|
|
193
|
+
for (const pattern of ignorePatterns) {
|
|
194
|
+
if (relativePath.includes(pattern)) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Debounce
|
|
199
|
+
const existing = pendingScans.get(filePath);
|
|
200
|
+
if (existing) {
|
|
201
|
+
clearTimeout(existing);
|
|
202
|
+
}
|
|
203
|
+
pendingScans.set(filePath, setTimeout(async () => {
|
|
204
|
+
pendingScans.delete(filePath);
|
|
205
|
+
const violations = await scanFile(filePath, detectors, categories);
|
|
206
|
+
printViolations(filePath, violations, verbose);
|
|
207
|
+
// Update context file if specified
|
|
208
|
+
if (contextPath) {
|
|
209
|
+
updateContextFile(contextPath);
|
|
210
|
+
}
|
|
211
|
+
}, debounceMs));
|
|
212
|
+
}
|
|
213
|
+
// Watch for file changes using fs.watch recursively
|
|
214
|
+
const watchers = [];
|
|
215
|
+
function watchDirectory(dir) {
|
|
216
|
+
try {
|
|
217
|
+
const watcher = fs.watch(dir, { recursive: true }, (_eventType, filename) => {
|
|
218
|
+
if (!filename)
|
|
219
|
+
return;
|
|
220
|
+
const fullPath = path.join(dir, filename);
|
|
221
|
+
// Only watch supported file types
|
|
222
|
+
const ext = path.extname(filename).toLowerCase();
|
|
223
|
+
const supportedExts = ['.ts', '.tsx', '.js', '.jsx', '.py', '.css', '.scss', '.json', '.md'];
|
|
224
|
+
if (!supportedExts.includes(ext))
|
|
225
|
+
return;
|
|
226
|
+
// Check if file exists (might be deleted)
|
|
227
|
+
if (!fs.existsSync(fullPath))
|
|
228
|
+
return;
|
|
229
|
+
handleFileChange(fullPath);
|
|
230
|
+
});
|
|
231
|
+
watchers.push(watcher);
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
console.error(chalk.red(`Failed to watch ${dir}:`), err);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Start watching
|
|
238
|
+
watchDirectory(cwd);
|
|
239
|
+
console.log(`${timestamp()} ${chalk.green('Watching for changes...')}\n`);
|
|
240
|
+
// Handle shutdown
|
|
241
|
+
process.on('SIGINT', () => {
|
|
242
|
+
console.log(chalk.gray('\n\nStopping watch mode...'));
|
|
243
|
+
for (const watcher of watchers) {
|
|
244
|
+
watcher.close();
|
|
245
|
+
}
|
|
246
|
+
for (const timeout of pendingScans.values()) {
|
|
247
|
+
clearTimeout(timeout);
|
|
248
|
+
}
|
|
249
|
+
process.exit(0);
|
|
250
|
+
});
|
|
251
|
+
// Keep process alive
|
|
252
|
+
await new Promise(() => { });
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Create the watch command
|
|
256
|
+
*/
|
|
257
|
+
export const watchCommandDef = new Command('watch')
|
|
258
|
+
.description('Watch for file changes and report violations in real-time')
|
|
259
|
+
.option('--verbose', 'Show detailed violation information')
|
|
260
|
+
.option('--context <file>', 'Auto-update AI context file on changes')
|
|
261
|
+
.option('-c, --categories <categories>', 'Filter by categories (comma-separated)')
|
|
262
|
+
.option('--debounce <ms>', 'Debounce delay in milliseconds', '300')
|
|
263
|
+
.action(watchCommand);
|
|
264
|
+
//# sourceMappingURL=watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"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"}
|