@phantomind/core 0.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.
- package/dist/adapters/aider.d.ts +12 -0
- package/dist/adapters/aider.d.ts.map +1 -0
- package/dist/adapters/aider.js +24 -0
- package/dist/adapters/aider.js.map +1 -0
- package/dist/adapters/base.d.ts +21 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +83 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +12 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +31 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/cline.d.ts +12 -0
- package/dist/adapters/cline.d.ts.map +1 -0
- package/dist/adapters/cline.js +32 -0
- package/dist/adapters/cline.js.map +1 -0
- package/dist/adapters/codex.d.ts +18 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +38 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/continue.d.ts +12 -0
- package/dist/adapters/continue.d.ts.map +1 -0
- package/dist/adapters/continue.js +29 -0
- package/dist/adapters/continue.js.map +1 -0
- package/dist/adapters/copilot.d.ts +12 -0
- package/dist/adapters/copilot.d.ts.map +1 -0
- package/dist/adapters/copilot.js +31 -0
- package/dist/adapters/copilot.js.map +1 -0
- package/dist/adapters/cursor.d.ts +12 -0
- package/dist/adapters/cursor.d.ts.map +1 -0
- package/dist/adapters/cursor.js +34 -0
- package/dist/adapters/cursor.js.map +1 -0
- package/dist/adapters/index.d.ts +32 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +64 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/windsurf.d.ts +12 -0
- package/dist/adapters/windsurf.d.ts.map +1 -0
- package/dist/adapters/windsurf.js +32 -0
- package/dist/adapters/windsurf.js.map +1 -0
- package/dist/adapters/zed.d.ts +12 -0
- package/dist/adapters/zed.d.ts.map +1 -0
- package/dist/adapters/zed.js +27 -0
- package/dist/adapters/zed.js.map +1 -0
- package/dist/agent/decomposer.d.ts +55 -0
- package/dist/agent/decomposer.d.ts.map +1 -0
- package/dist/agent/decomposer.js +172 -0
- package/dist/agent/decomposer.js.map +1 -0
- package/dist/agent/executor.d.ts +33 -0
- package/dist/agent/executor.d.ts.map +1 -0
- package/dist/agent/executor.js +260 -0
- package/dist/agent/executor.js.map +1 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +8 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/memory.d.ts +95 -0
- package/dist/agent/memory.d.ts.map +1 -0
- package/dist/agent/memory.js +211 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/orchestrator.d.ts +54 -0
- package/dist/agent/orchestrator.d.ts.map +1 -0
- package/dist/agent/orchestrator.js +190 -0
- package/dist/agent/orchestrator.js.map +1 -0
- package/dist/agent/queue.d.ts +95 -0
- package/dist/agent/queue.d.ts.map +1 -0
- package/dist/agent/queue.js +231 -0
- package/dist/agent/queue.js.map +1 -0
- package/dist/agent/retry.d.ts +61 -0
- package/dist/agent/retry.d.ts.map +1 -0
- package/dist/agent/retry.js +162 -0
- package/dist/agent/retry.js.map +1 -0
- package/dist/agent/roles.d.ts +35 -0
- package/dist/agent/roles.d.ts.map +1 -0
- package/dist/agent/roles.js +269 -0
- package/dist/agent/roles.js.map +1 -0
- package/dist/cli/agent.d.ts +12 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +85 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/audit.d.ts +11 -0
- package/dist/cli/audit.d.ts.map +1 -0
- package/dist/cli/audit.js +63 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/eval.d.ts +11 -0
- package/dist/cli/eval.d.ts.map +1 -0
- package/dist/cli/eval.js +79 -0
- package/dist/cli/eval.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +9 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +13 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +157 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/main.d.ts +7 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +153 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/serve.d.ts +11 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +23 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/stats.d.ts +10 -0
- package/dist/cli/stats.d.ts.map +1 -0
- package/dist/cli/stats.js +68 -0
- package/dist/cli/stats.js.map +1 -0
- package/dist/cli/sync.d.ts +11 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +49 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli/validate.d.ts +13 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +125 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +25 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +190 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/context/embedder.d.ts +53 -0
- package/dist/context/embedder.d.ts.map +1 -0
- package/dist/context/embedder.js +235 -0
- package/dist/context/embedder.js.map +1 -0
- package/dist/context/engine.d.ts +82 -0
- package/dist/context/engine.d.ts.map +1 -0
- package/dist/context/engine.js +343 -0
- package/dist/context/engine.js.map +1 -0
- package/dist/context/index.d.ts +5 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +5 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/learner.d.ts +44 -0
- package/dist/context/learner.d.ts.map +1 -0
- package/dist/context/learner.js +246 -0
- package/dist/context/learner.js.map +1 -0
- package/dist/context/versioning.d.ts +29 -0
- package/dist/context/versioning.d.ts.map +1 -0
- package/dist/context/versioning.js +81 -0
- package/dist/context/versioning.js.map +1 -0
- package/dist/index.d.ts +169 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +285 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +31 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +334 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/observability/audit.d.ts +61 -0
- package/dist/observability/audit.d.ts.map +1 -0
- package/dist/observability/audit.js +168 -0
- package/dist/observability/audit.js.map +1 -0
- package/dist/observability/cost-tracker.d.ts +71 -0
- package/dist/observability/cost-tracker.d.ts.map +1 -0
- package/dist/observability/cost-tracker.js +206 -0
- package/dist/observability/cost-tracker.js.map +1 -0
- package/dist/observability/dashboard.d.ts +52 -0
- package/dist/observability/dashboard.d.ts.map +1 -0
- package/dist/observability/dashboard.js +134 -0
- package/dist/observability/dashboard.js.map +1 -0
- package/dist/observability/index.d.ts +4 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +4 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/providers/anthropic.d.ts +14 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +99 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/base.d.ts +52 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +68 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/deepseek.d.ts +15 -0
- package/dist/providers/deepseek.d.ts.map +1 -0
- package/dist/providers/deepseek.js +99 -0
- package/dist/providers/deepseek.js.map +1 -0
- package/dist/providers/gemini.d.ts +15 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +118 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/groq.d.ts +15 -0
- package/dist/providers/groq.d.ts.map +1 -0
- package/dist/providers/groq.js +101 -0
- package/dist/providers/groq.js.map +1 -0
- package/dist/providers/index.d.ts +11 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +11 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/mistral.d.ts +15 -0
- package/dist/providers/mistral.d.ts.map +1 -0
- package/dist/providers/mistral.js +99 -0
- package/dist/providers/mistral.js.map +1 -0
- package/dist/providers/ollama.d.ts +14 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +122 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/providers/openai.d.ts +14 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +80 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/openrouter.d.ts +15 -0
- package/dist/providers/openrouter.d.ts.map +1 -0
- package/dist/providers/openrouter.js +101 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/router.d.ts +51 -0
- package/dist/providers/router.d.ts.map +1 -0
- package/dist/providers/router.js +198 -0
- package/dist/providers/router.js.map +1 -0
- package/dist/quality/anomaly.d.ts +32 -0
- package/dist/quality/anomaly.d.ts.map +1 -0
- package/dist/quality/anomaly.js +126 -0
- package/dist/quality/anomaly.js.map +1 -0
- package/dist/quality/consistency.d.ts +26 -0
- package/dist/quality/consistency.d.ts.map +1 -0
- package/dist/quality/consistency.js +156 -0
- package/dist/quality/consistency.js.map +1 -0
- package/dist/quality/dual-verifier.d.ts +22 -0
- package/dist/quality/dual-verifier.d.ts.map +1 -0
- package/dist/quality/dual-verifier.js +137 -0
- package/dist/quality/dual-verifier.js.map +1 -0
- package/dist/quality/hallucination-guard.d.ts +57 -0
- package/dist/quality/hallucination-guard.d.ts.map +1 -0
- package/dist/quality/hallucination-guard.js +245 -0
- package/dist/quality/hallucination-guard.js.map +1 -0
- package/dist/quality/index.d.ts +7 -0
- package/dist/quality/index.d.ts.map +1 -0
- package/dist/quality/index.js +7 -0
- package/dist/quality/index.js.map +1 -0
- package/dist/quality/regression.d.ts +44 -0
- package/dist/quality/regression.d.ts.map +1 -0
- package/dist/quality/regression.js +181 -0
- package/dist/quality/regression.js.map +1 -0
- package/dist/quality/secret-scanner.d.ts +36 -0
- package/dist/quality/secret-scanner.d.ts.map +1 -0
- package/dist/quality/secret-scanner.js +187 -0
- package/dist/quality/secret-scanner.js.map +1 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/registry.d.ts +72 -0
- package/dist/schemas/registry.d.ts.map +1 -0
- package/dist/schemas/registry.js +483 -0
- package/dist/schemas/registry.js.map +1 -0
- package/dist/templates/engine.d.ts +70 -0
- package/dist/templates/engine.d.ts.map +1 -0
- package/dist/templates/engine.js +71 -0
- package/dist/templates/engine.js.map +1 -0
- package/dist/templates/index.d.ts +2 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +2 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/types.d.ts +912 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +75 -0
- package/dist/types.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhantomMindAI — Cross-File Consistency Enforcer
|
|
3
|
+
* Detect naming, pattern, and architecture inconsistencies.
|
|
4
|
+
*/
|
|
5
|
+
import type { ConsistencyReport } from '../types.js';
|
|
6
|
+
export declare class ConsistencyEnforcer {
|
|
7
|
+
private projectRoot;
|
|
8
|
+
constructor(projectRoot: string);
|
|
9
|
+
/**
|
|
10
|
+
* Run full consistency scan
|
|
11
|
+
*/
|
|
12
|
+
scan(scope?: 'naming' | 'pattern' | 'architecture' | 'all'): Promise<ConsistencyReport>;
|
|
13
|
+
/**
|
|
14
|
+
* Check naming convention consistency
|
|
15
|
+
*/
|
|
16
|
+
private checkNamingConsistency;
|
|
17
|
+
/**
|
|
18
|
+
* Check async pattern consistency
|
|
19
|
+
*/
|
|
20
|
+
private checkPatternConsistency;
|
|
21
|
+
/**
|
|
22
|
+
* Check architecture layer consistency
|
|
23
|
+
*/
|
|
24
|
+
private checkArchitectureConsistency;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=consistency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consistency.d.ts","sourceRoot":"","sources":["../../src/quality/consistency.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAoB,MAAM,aAAa,CAAC;AAEvE,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,EAAE,MAAM;IAI/B;;OAEG;IACG,IAAI,CAAC,KAAK,GAAE,QAAQ,GAAG,SAAS,GAAG,cAAc,GAAG,KAAa,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAsCpG;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA6C9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgC/B;;OAEG;IACH,OAAO,CAAC,4BAA4B;CAoCrC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhantomMindAI — Cross-File Consistency Enforcer
|
|
3
|
+
* Detect naming, pattern, and architecture inconsistencies.
|
|
4
|
+
*/
|
|
5
|
+
import { readFile } from 'node:fs/promises';
|
|
6
|
+
import { join, extname } from 'node:path';
|
|
7
|
+
import fastGlob from 'fast-glob';
|
|
8
|
+
export class ConsistencyEnforcer {
|
|
9
|
+
projectRoot;
|
|
10
|
+
constructor(projectRoot) {
|
|
11
|
+
this.projectRoot = projectRoot;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Run full consistency scan
|
|
15
|
+
*/
|
|
16
|
+
async scan(scope = 'all') {
|
|
17
|
+
const start = Date.now();
|
|
18
|
+
const issues = [];
|
|
19
|
+
const files = await fastGlob('**/*.{ts,tsx,js,jsx,swift,go,py}', {
|
|
20
|
+
cwd: this.projectRoot,
|
|
21
|
+
ignore: ['node_modules/**', 'dist/**', '.git/**'],
|
|
22
|
+
});
|
|
23
|
+
const fileContents = new Map();
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
try {
|
|
26
|
+
const content = await readFile(join(this.projectRoot, file), 'utf-8');
|
|
27
|
+
fileContents.set(file, content);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (scope === 'all' || scope === 'naming') {
|
|
34
|
+
issues.push(...this.checkNamingConsistency(fileContents));
|
|
35
|
+
}
|
|
36
|
+
if (scope === 'all' || scope === 'pattern') {
|
|
37
|
+
issues.push(...this.checkPatternConsistency(fileContents));
|
|
38
|
+
}
|
|
39
|
+
if (scope === 'all' || scope === 'architecture') {
|
|
40
|
+
issues.push(...this.checkArchitectureConsistency(fileContents));
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
issues,
|
|
44
|
+
scannedFiles: files.length,
|
|
45
|
+
duration: Date.now() - start,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Check naming convention consistency
|
|
50
|
+
*/
|
|
51
|
+
checkNamingConsistency(files) {
|
|
52
|
+
const issues = [];
|
|
53
|
+
const errorTypes = new Map();
|
|
54
|
+
const serviceTypes = new Map();
|
|
55
|
+
for (const [file, content] of files) {
|
|
56
|
+
// Check error type naming
|
|
57
|
+
const errorMatches = content.match(/(?:class|type|interface)\s+(\w*(?:Error|Exception|Failure)\w*)/g) ?? [];
|
|
58
|
+
for (const match of errorMatches) {
|
|
59
|
+
const name = match.split(/\s+/).pop();
|
|
60
|
+
const suffix = name.endsWith('Error') ? 'Error' : name.endsWith('Exception') ? 'Exception' : 'Failure';
|
|
61
|
+
const list = errorTypes.get(suffix) ?? [];
|
|
62
|
+
list.push(file);
|
|
63
|
+
errorTypes.set(suffix, list);
|
|
64
|
+
}
|
|
65
|
+
// Check service naming
|
|
66
|
+
const serviceMatches = content.match(/(?:class|type|interface)\s+(\w*(?:Service|Manager|Controller|Handler)\w*)/g) ?? [];
|
|
67
|
+
for (const match of serviceMatches) {
|
|
68
|
+
const name = match.split(/\s+/).pop();
|
|
69
|
+
for (const suffix of ['Service', 'Manager', 'Controller', 'Handler']) {
|
|
70
|
+
if (name.endsWith(suffix)) {
|
|
71
|
+
const list = serviceTypes.get(suffix) ?? [];
|
|
72
|
+
list.push(file);
|
|
73
|
+
serviceTypes.set(suffix, list);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Flag if multiple error naming conventions
|
|
79
|
+
if (errorTypes.size > 1) {
|
|
80
|
+
const allFiles = [...errorTypes.values()].flat();
|
|
81
|
+
issues.push({
|
|
82
|
+
type: 'naming',
|
|
83
|
+
description: `Mixed error type naming: ${[...errorTypes.keys()].join(', ')}. Use one convention.`,
|
|
84
|
+
files: [...new Set(allFiles)],
|
|
85
|
+
suggestion: 'Standardize error types to use a single suffix (e.g., always "Error").',
|
|
86
|
+
autoFixable: false,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return issues;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check async pattern consistency
|
|
93
|
+
*/
|
|
94
|
+
checkPatternConsistency(files) {
|
|
95
|
+
const issues = [];
|
|
96
|
+
const asyncPatterns = new Map();
|
|
97
|
+
for (const [file, content] of files) {
|
|
98
|
+
const ext = extname(file);
|
|
99
|
+
if (ext !== '.ts' && ext !== '.tsx' && ext !== '.js' && ext !== '.jsx')
|
|
100
|
+
continue;
|
|
101
|
+
// Check for mixed callback and async/await
|
|
102
|
+
const hasCallbacks = /\.then\s*\(/.test(content);
|
|
103
|
+
const hasAsyncAwait = /async\s+/.test(content);
|
|
104
|
+
if (hasCallbacks && hasAsyncAwait) {
|
|
105
|
+
const list = asyncPatterns.get('mixed') ?? [];
|
|
106
|
+
list.push(file);
|
|
107
|
+
asyncPatterns.set('mixed', list);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (asyncPatterns.has('mixed') && (asyncPatterns.get('mixed')?.length ?? 0) > 2) {
|
|
111
|
+
issues.push({
|
|
112
|
+
type: 'pattern',
|
|
113
|
+
description: 'Mixed async patterns: both .then() callbacks and async/await used.',
|
|
114
|
+
files: asyncPatterns.get('mixed'),
|
|
115
|
+
suggestion: 'Prefer async/await consistently over .then() callbacks.',
|
|
116
|
+
autoFixable: false,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return issues;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Check architecture layer consistency
|
|
123
|
+
*/
|
|
124
|
+
checkArchitectureConsistency(files) {
|
|
125
|
+
const issues = [];
|
|
126
|
+
for (const [file, content] of files) {
|
|
127
|
+
// Check if ViewModels import from data layer directly
|
|
128
|
+
if (file.includes('ViewModel') || file.includes('viewmodel') || file.includes('view-model')) {
|
|
129
|
+
if (content.includes('import') && (content.match(/from\s+['"].*(?:database|db|sql|prisma|mongoose|typeorm)/i) ||
|
|
130
|
+
content.match(/from\s+['"].*(?:repository|repo)/i))) {
|
|
131
|
+
issues.push({
|
|
132
|
+
type: 'architecture',
|
|
133
|
+
description: `ViewModel directly imports data layer in ${file}.`,
|
|
134
|
+
files: [file],
|
|
135
|
+
suggestion: 'ViewModels should access data through a service/use-case layer, not directly.',
|
|
136
|
+
autoFixable: false,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Check if Views import from data layer
|
|
141
|
+
if (file.includes('View') || file.includes('Component') || file.includes('.vue') || file.includes('.svelte')) {
|
|
142
|
+
if (content.match(/from\s+['"].*(?:database|db|sql|prisma|mongoose|typeorm)/i)) {
|
|
143
|
+
issues.push({
|
|
144
|
+
type: 'architecture',
|
|
145
|
+
description: `View/Component directly imports data layer in ${file}.`,
|
|
146
|
+
files: [file],
|
|
147
|
+
suggestion: 'Views should never access the data layer directly.',
|
|
148
|
+
autoFixable: false,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return issues;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=consistency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consistency.js","sourceRoot":"","sources":["../../src/quality/consistency.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhantomMindAI — Dual-Model Verifier
|
|
3
|
+
* Verify critical outputs with a second model from a different provider.
|
|
4
|
+
*/
|
|
5
|
+
import type { ProviderRouter } from '../providers/router.js';
|
|
6
|
+
import type { ContextEngine } from '../context/engine.js';
|
|
7
|
+
import type { VerificationResult, PhantomConfig } from '../types.js';
|
|
8
|
+
export declare class DualVerifier {
|
|
9
|
+
private router;
|
|
10
|
+
private contextEngine;
|
|
11
|
+
private config;
|
|
12
|
+
constructor(router: ProviderRouter, contextEngine: ContextEngine, config: PhantomConfig);
|
|
13
|
+
/**
|
|
14
|
+
* Verify generated content using a second model
|
|
15
|
+
*/
|
|
16
|
+
verify(generatedContent: string, taskDescription: string, sourceFile?: string): Promise<VerificationResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Parse the verification model's response
|
|
19
|
+
*/
|
|
20
|
+
private parseVerificationResponse;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=dual-verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dual-verifier.d.ts","sourceRoot":"","sources":["../../src/quality/dual-verifier.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAyC,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5G,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa;IAMvF;;OAEG;IACG,MAAM,CACV,gBAAgB,EAAE,MAAM,EACxB,eAAe,EAAE,MAAM,EACvB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAqG9B;;OAEG;IACH,OAAO,CAAC,yBAAyB;CAuBlC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhantomMindAI — Dual-Model Verifier
|
|
3
|
+
* Verify critical outputs with a second model from a different provider.
|
|
4
|
+
*/
|
|
5
|
+
export class DualVerifier {
|
|
6
|
+
router;
|
|
7
|
+
contextEngine;
|
|
8
|
+
config;
|
|
9
|
+
constructor(router, contextEngine, config) {
|
|
10
|
+
this.router = router;
|
|
11
|
+
this.contextEngine = contextEngine;
|
|
12
|
+
this.config = config;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Verify generated content using a second model
|
|
16
|
+
*/
|
|
17
|
+
async verify(generatedContent, taskDescription, sourceFile) {
|
|
18
|
+
const start = Date.now();
|
|
19
|
+
// Get project context for verification
|
|
20
|
+
const context = await this.contextEngine.getProjectContext({
|
|
21
|
+
file: sourceFile,
|
|
22
|
+
maxTokens: 2000,
|
|
23
|
+
includeSkills: true,
|
|
24
|
+
includeRules: true,
|
|
25
|
+
});
|
|
26
|
+
const contextText = context.layers.map(l => l.content).join('\n\n');
|
|
27
|
+
const verificationPrompt = `You are a code reviewer verifying AI-generated output against project conventions.
|
|
28
|
+
|
|
29
|
+
## Project Context
|
|
30
|
+
${contextText}
|
|
31
|
+
|
|
32
|
+
## Task Description
|
|
33
|
+
${taskDescription}
|
|
34
|
+
|
|
35
|
+
## Generated Content
|
|
36
|
+
\`\`\`
|
|
37
|
+
${generatedContent}
|
|
38
|
+
\`\`\`
|
|
39
|
+
|
|
40
|
+
## Review Checklist
|
|
41
|
+
1. Does this conform to the project conventions described above?
|
|
42
|
+
2. Are there unhandled edge cases?
|
|
43
|
+
3. Any security concerns (injection, auth bypass, data exposure)?
|
|
44
|
+
4. Any performance concerns?
|
|
45
|
+
5. Are there correctness issues?
|
|
46
|
+
|
|
47
|
+
Respond in this exact JSON format:
|
|
48
|
+
{
|
|
49
|
+
"approved": true/false,
|
|
50
|
+
"issues": [
|
|
51
|
+
{
|
|
52
|
+
"severity": "error|warning|info",
|
|
53
|
+
"category": "convention|security|edge-case|performance|correctness",
|
|
54
|
+
"description": "description of the issue",
|
|
55
|
+
"suggestion": "how to fix it",
|
|
56
|
+
"line": null
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Only respond with the JSON, no other text.`;
|
|
62
|
+
// Use the verification provider
|
|
63
|
+
const verificationProvider = this.config.quality.dualVerificationProvider ?? 'openai';
|
|
64
|
+
const provider = this.router.getProvider(verificationProvider) ?? this.router.getSlotProvider('fallback');
|
|
65
|
+
if (!provider) {
|
|
66
|
+
return {
|
|
67
|
+
approved: true,
|
|
68
|
+
provider: verificationProvider,
|
|
69
|
+
model: 'unavailable',
|
|
70
|
+
issues: [{
|
|
71
|
+
severity: 'info',
|
|
72
|
+
category: 'correctness',
|
|
73
|
+
description: 'Verification provider not available. Skipped.',
|
|
74
|
+
}],
|
|
75
|
+
duration: Date.now() - start,
|
|
76
|
+
cost: { inputTokens: 0, outputTokens: 0, totalTokens: 0, estimatedCost: 0 },
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const response = await provider.complete({
|
|
81
|
+
prompt: verificationPrompt,
|
|
82
|
+
temperature: 0.1,
|
|
83
|
+
maxTokens: 2000,
|
|
84
|
+
});
|
|
85
|
+
const parsed = this.parseVerificationResponse(response.content);
|
|
86
|
+
return {
|
|
87
|
+
approved: parsed.approved,
|
|
88
|
+
provider: verificationProvider,
|
|
89
|
+
model: response.model,
|
|
90
|
+
issues: parsed.issues,
|
|
91
|
+
duration: Date.now() - start,
|
|
92
|
+
cost: response.usage,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return {
|
|
97
|
+
approved: true,
|
|
98
|
+
provider: verificationProvider,
|
|
99
|
+
model: 'error',
|
|
100
|
+
issues: [{
|
|
101
|
+
severity: 'info',
|
|
102
|
+
category: 'correctness',
|
|
103
|
+
description: `Verification failed: ${error.message}`,
|
|
104
|
+
}],
|
|
105
|
+
duration: Date.now() - start,
|
|
106
|
+
cost: { inputTokens: 0, outputTokens: 0, totalTokens: 0, estimatedCost: 0 },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Parse the verification model's response
|
|
112
|
+
*/
|
|
113
|
+
parseVerificationResponse(content) {
|
|
114
|
+
try {
|
|
115
|
+
// Extract JSON from response
|
|
116
|
+
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
117
|
+
if (!jsonMatch) {
|
|
118
|
+
return { approved: true, issues: [] };
|
|
119
|
+
}
|
|
120
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
121
|
+
return {
|
|
122
|
+
approved: parsed.approved ?? true,
|
|
123
|
+
issues: (parsed.issues ?? []).map((issue) => ({
|
|
124
|
+
severity: issue.severity ?? 'info',
|
|
125
|
+
category: issue.category ?? 'correctness',
|
|
126
|
+
description: issue.description ?? '',
|
|
127
|
+
suggestion: issue.suggestion,
|
|
128
|
+
line: issue.line,
|
|
129
|
+
})),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return { approved: true, issues: [] };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=dual-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dual-verifier.js","sourceRoot":"","sources":["../../src/quality/dual-verifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhantomMindAI — Hallucination Guard
|
|
3
|
+
* Pre-write check that detects when AI references non-existent entities.
|
|
4
|
+
*/
|
|
5
|
+
import type { HallucinationCheck } from '../types.js';
|
|
6
|
+
export declare class HallucinationGuard {
|
|
7
|
+
private projectRoot;
|
|
8
|
+
private packageNames;
|
|
9
|
+
private projectFiles;
|
|
10
|
+
private projectTypes;
|
|
11
|
+
constructor(projectRoot: string);
|
|
12
|
+
/**
|
|
13
|
+
* Check content for hallucinations
|
|
14
|
+
*/
|
|
15
|
+
check(content: string, fileName?: string): Promise<HallucinationCheck[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Check import statements against actual dependencies
|
|
18
|
+
*/
|
|
19
|
+
private checkImports;
|
|
20
|
+
/**
|
|
21
|
+
* Check file path references
|
|
22
|
+
*/
|
|
23
|
+
private checkFilePaths;
|
|
24
|
+
/**
|
|
25
|
+
* Check type/class references in TypeScript
|
|
26
|
+
*/
|
|
27
|
+
private checkTypeReferences;
|
|
28
|
+
/**
|
|
29
|
+
* Get all package names from package.json
|
|
30
|
+
*/
|
|
31
|
+
private getPackageNames;
|
|
32
|
+
/**
|
|
33
|
+
* Get list of all project files
|
|
34
|
+
*/
|
|
35
|
+
private getProjectFiles;
|
|
36
|
+
/**
|
|
37
|
+
* Check if a file path exists
|
|
38
|
+
*/
|
|
39
|
+
private fileExists;
|
|
40
|
+
/**
|
|
41
|
+
* Check if a module is a Node.js built-in
|
|
42
|
+
*/
|
|
43
|
+
private isNodeBuiltin;
|
|
44
|
+
/**
|
|
45
|
+
* Find similar strings using edit distance
|
|
46
|
+
*/
|
|
47
|
+
private findSimilar;
|
|
48
|
+
/**
|
|
49
|
+
* Simple string similarity (Dice coefficient)
|
|
50
|
+
*/
|
|
51
|
+
private similarity;
|
|
52
|
+
/**
|
|
53
|
+
* Clear cached data
|
|
54
|
+
*/
|
|
55
|
+
clearCache(): void;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=hallucination-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hallucination-guard.d.ts","sourceRoot":"","sources":["../../src/quality/hallucination-guard.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,YAAY,CAA4B;gBAEpC,WAAW,EAAE,MAAM;IAI/B;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAuBjF;;OAEG;YACW,YAAY;IA4D1B;;OAEG;YACW,cAAc;IA8B5B;;OAEG;YACW,mBAAmB;IAKjC;;OAEG;YACW,eAAe;IAuB7B;;OAEG;YACW,eAAe;IAiB7B;;OAEG;YACW,UAAU;IASxB;;OAEG;IACH,OAAO,CAAC,aAAa;IAoBrB;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,UAAU;IAuBlB;;OAEG;IACH,UAAU,IAAI,IAAI;CAKnB"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhantomMindAI — Hallucination Guard
|
|
3
|
+
* Pre-write check that detects when AI references non-existent entities.
|
|
4
|
+
*/
|
|
5
|
+
import { readFile, access } from 'node:fs/promises';
|
|
6
|
+
import { join, extname } from 'node:path';
|
|
7
|
+
import fastGlob from 'fast-glob';
|
|
8
|
+
export class HallucinationGuard {
|
|
9
|
+
projectRoot;
|
|
10
|
+
packageNames = null;
|
|
11
|
+
projectFiles = null;
|
|
12
|
+
projectTypes = null;
|
|
13
|
+
constructor(projectRoot) {
|
|
14
|
+
this.projectRoot = projectRoot;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check content for hallucinations
|
|
18
|
+
*/
|
|
19
|
+
async check(content, fileName = 'unknown') {
|
|
20
|
+
const checks = [];
|
|
21
|
+
const lines = content.split('\n');
|
|
22
|
+
for (let i = 0; i < lines.length; i++) {
|
|
23
|
+
const line = lines[i];
|
|
24
|
+
// Check import statements
|
|
25
|
+
const importChecks = await this.checkImports(line, fileName, i + 1);
|
|
26
|
+
checks.push(...importChecks);
|
|
27
|
+
// Check file path references
|
|
28
|
+
const fileChecks = await this.checkFilePaths(line, fileName, i + 1);
|
|
29
|
+
checks.push(...fileChecks);
|
|
30
|
+
// Check type/class references
|
|
31
|
+
const typeChecks = await this.checkTypeReferences(line, fileName, i + 1);
|
|
32
|
+
checks.push(...typeChecks);
|
|
33
|
+
}
|
|
34
|
+
return checks.filter(c => !c.exists);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check import statements against actual dependencies
|
|
38
|
+
*/
|
|
39
|
+
async checkImports(line, file, lineNum) {
|
|
40
|
+
const checks = [];
|
|
41
|
+
// TypeScript/JavaScript imports
|
|
42
|
+
const tsImportMatch = line.match(/(?:import|from)\s+['"]([^'"./][^'"]*)['"]/);
|
|
43
|
+
if (tsImportMatch) {
|
|
44
|
+
const pkgName = tsImportMatch[1].startsWith('@')
|
|
45
|
+
? tsImportMatch[1].split('/').slice(0, 2).join('/')
|
|
46
|
+
: tsImportMatch[1].split('/')[0];
|
|
47
|
+
const packages = await this.getPackageNames();
|
|
48
|
+
const exists = packages.has(pkgName) || this.isNodeBuiltin(pkgName);
|
|
49
|
+
checks.push({
|
|
50
|
+
type: 'import',
|
|
51
|
+
reference: pkgName,
|
|
52
|
+
exists,
|
|
53
|
+
suggestions: exists ? undefined : this.findSimilar(pkgName, [...packages]),
|
|
54
|
+
file,
|
|
55
|
+
line: lineNum,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Swift imports
|
|
59
|
+
const swiftImportMatch = line.match(/^import\s+(\w+)/);
|
|
60
|
+
if (swiftImportMatch && !tsImportMatch) {
|
|
61
|
+
const module = swiftImportMatch[1];
|
|
62
|
+
const swiftBuiltins = new Set([
|
|
63
|
+
'Foundation', 'UIKit', 'SwiftUI', 'Combine', 'CoreData', 'MapKit',
|
|
64
|
+
'WebKit', 'AVFoundation', 'CoreLocation', 'StoreKit', 'WidgetKit',
|
|
65
|
+
'ActivityKit', 'SwiftData', 'Observation', 'XCTest', 'Testing',
|
|
66
|
+
]);
|
|
67
|
+
checks.push({
|
|
68
|
+
type: 'import',
|
|
69
|
+
reference: module,
|
|
70
|
+
exists: swiftBuiltins.has(module),
|
|
71
|
+
suggestions: this.findSimilar(module, [...swiftBuiltins]),
|
|
72
|
+
file,
|
|
73
|
+
line: lineNum,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// Python imports
|
|
77
|
+
const pyImportMatch = line.match(/^(?:from|import)\s+([\w.]+)/);
|
|
78
|
+
if (pyImportMatch && !tsImportMatch && !swiftImportMatch) {
|
|
79
|
+
const module = pyImportMatch[1].split('.')[0];
|
|
80
|
+
// We can't fully validate Python imports without pip list, so mark as exists
|
|
81
|
+
checks.push({
|
|
82
|
+
type: 'import',
|
|
83
|
+
reference: module,
|
|
84
|
+
exists: true,
|
|
85
|
+
file,
|
|
86
|
+
line: lineNum,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return checks;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check file path references
|
|
93
|
+
*/
|
|
94
|
+
async checkFilePaths(line, file, lineNum) {
|
|
95
|
+
const checks = [];
|
|
96
|
+
// Match quoted file paths that look like relative paths
|
|
97
|
+
const pathMatches = line.matchAll(/['"](\.\/?[^'"]+\.(ts|js|tsx|jsx|swift|go|py|json|yaml|yml|md))['"]/g);
|
|
98
|
+
for (const match of pathMatches) {
|
|
99
|
+
const refPath = match[1];
|
|
100
|
+
const exists = await this.fileExists(refPath);
|
|
101
|
+
if (!exists) {
|
|
102
|
+
const projectFiles = await this.getProjectFiles();
|
|
103
|
+
const baseName = refPath.split('/').pop() ?? '';
|
|
104
|
+
const suggestions = [...projectFiles]
|
|
105
|
+
.filter(f => f.includes(baseName.replace(extname(baseName), '')))
|
|
106
|
+
.slice(0, 3);
|
|
107
|
+
checks.push({
|
|
108
|
+
type: 'file',
|
|
109
|
+
reference: refPath,
|
|
110
|
+
exists: false,
|
|
111
|
+
suggestions,
|
|
112
|
+
file,
|
|
113
|
+
line: lineNum,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return checks;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check type/class references in TypeScript
|
|
121
|
+
*/
|
|
122
|
+
async checkTypeReferences(line, file, lineNum) {
|
|
123
|
+
// Skip checking type references for performance — rely on TypeScript compiler
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get all package names from package.json
|
|
128
|
+
*/
|
|
129
|
+
async getPackageNames() {
|
|
130
|
+
if (this.packageNames)
|
|
131
|
+
return this.packageNames;
|
|
132
|
+
this.packageNames = new Set();
|
|
133
|
+
try {
|
|
134
|
+
const pkgJson = await readFile(join(this.projectRoot, 'package.json'), 'utf-8');
|
|
135
|
+
const pkg = JSON.parse(pkgJson);
|
|
136
|
+
const deps = {
|
|
137
|
+
...pkg.dependencies,
|
|
138
|
+
...pkg.devDependencies,
|
|
139
|
+
...pkg.peerDependencies,
|
|
140
|
+
};
|
|
141
|
+
for (const name of Object.keys(deps)) {
|
|
142
|
+
this.packageNames.add(name);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// No package.json
|
|
147
|
+
}
|
|
148
|
+
return this.packageNames;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get list of all project files
|
|
152
|
+
*/
|
|
153
|
+
async getProjectFiles() {
|
|
154
|
+
if (this.projectFiles)
|
|
155
|
+
return this.projectFiles;
|
|
156
|
+
try {
|
|
157
|
+
const files = await fastGlob('**/*', {
|
|
158
|
+
cwd: this.projectRoot,
|
|
159
|
+
ignore: ['node_modules/**', 'dist/**', '.git/**'],
|
|
160
|
+
onlyFiles: true,
|
|
161
|
+
});
|
|
162
|
+
this.projectFiles = new Set(files);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
this.projectFiles = new Set();
|
|
166
|
+
}
|
|
167
|
+
return this.projectFiles;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Check if a file path exists
|
|
171
|
+
*/
|
|
172
|
+
async fileExists(refPath) {
|
|
173
|
+
try {
|
|
174
|
+
await access(join(this.projectRoot, refPath));
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Check if a module is a Node.js built-in
|
|
183
|
+
*/
|
|
184
|
+
isNodeBuiltin(name) {
|
|
185
|
+
const builtins = new Set([
|
|
186
|
+
'assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',
|
|
187
|
+
'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https',
|
|
188
|
+
'module', 'net', 'os', 'path', 'perf_hooks', 'process', 'punycode',
|
|
189
|
+
'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'sys',
|
|
190
|
+
'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'wasi',
|
|
191
|
+
'worker_threads', 'zlib',
|
|
192
|
+
'node:assert', 'node:buffer', 'node:child_process', 'node:cluster',
|
|
193
|
+
'node:crypto', 'node:dgram', 'node:dns', 'node:events', 'node:fs',
|
|
194
|
+
'node:http', 'node:https', 'node:module', 'node:net', 'node:os',
|
|
195
|
+
'node:path', 'node:perf_hooks', 'node:process', 'node:readline',
|
|
196
|
+
'node:stream', 'node:string_decoder', 'node:timers', 'node:tls',
|
|
197
|
+
'node:tty', 'node:url', 'node:util', 'node:v8', 'node:vm',
|
|
198
|
+
'node:worker_threads', 'node:zlib', 'node:test',
|
|
199
|
+
]);
|
|
200
|
+
return builtins.has(name) || name.startsWith('node:');
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Find similar strings using edit distance
|
|
204
|
+
*/
|
|
205
|
+
findSimilar(target, candidates, maxResults = 3) {
|
|
206
|
+
const scored = candidates
|
|
207
|
+
.map(c => ({ name: c, score: this.similarity(target, c) }))
|
|
208
|
+
.filter(c => c.score > 0.3)
|
|
209
|
+
.sort((a, b) => b.score - a.score);
|
|
210
|
+
return scored.slice(0, maxResults).map(s => s.name);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Simple string similarity (Dice coefficient)
|
|
214
|
+
*/
|
|
215
|
+
similarity(a, b) {
|
|
216
|
+
if (a === b)
|
|
217
|
+
return 1;
|
|
218
|
+
if (a.length < 2 || b.length < 2)
|
|
219
|
+
return 0;
|
|
220
|
+
const aBigrams = new Map();
|
|
221
|
+
for (let i = 0; i < a.length - 1; i++) {
|
|
222
|
+
const bigram = a.slice(i, i + 2).toLowerCase();
|
|
223
|
+
aBigrams.set(bigram, (aBigrams.get(bigram) ?? 0) + 1);
|
|
224
|
+
}
|
|
225
|
+
let matches = 0;
|
|
226
|
+
for (let i = 0; i < b.length - 1; i++) {
|
|
227
|
+
const bigram = b.slice(i, i + 2).toLowerCase();
|
|
228
|
+
const count = aBigrams.get(bigram) ?? 0;
|
|
229
|
+
if (count > 0) {
|
|
230
|
+
aBigrams.set(bigram, count - 1);
|
|
231
|
+
matches++;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return (2 * matches) / (a.length + b.length - 2);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Clear cached data
|
|
238
|
+
*/
|
|
239
|
+
clearCache() {
|
|
240
|
+
this.packageNames = null;
|
|
241
|
+
this.projectFiles = null;
|
|
242
|
+
this.projectTypes = null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=hallucination-guard.js.map
|