thuban 0.3.3 → 0.3.4
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/LICENSE +21 -0
- package/dist/README.md +185 -0
- package/dist/cli.js +2 -0
- package/dist/packages/scanner/ai-confidence-scorer.js +1 -0
- package/dist/packages/scanner/alert-manager.js +1 -0
- package/dist/packages/scanner/baseline-manager.js +1 -0
- package/dist/packages/scanner/code-scanner.js +1 -0
- package/dist/packages/scanner/codebase-passport.js +1 -0
- package/dist/packages/scanner/copy-paste-detector.js +1 -0
- package/dist/packages/scanner/dependency-graph.js +1 -0
- package/dist/packages/scanner/drift-detector.js +1 -0
- package/dist/packages/scanner/executive-report.js +1 -0
- package/dist/packages/scanner/file-collector.js +1 -0
- package/dist/packages/scanner/file-watcher.js +1 -0
- package/dist/packages/scanner/ghost-code-detector.js +1 -0
- package/dist/packages/scanner/hallucination-detector.js +1 -0
- package/dist/packages/scanner/health-checker.js +1 -0
- package/dist/packages/scanner/html-report.js +1 -0
- package/dist/packages/scanner/index.js +1 -0
- package/dist/packages/scanner/license-manager.js +1 -0
- package/dist/packages/scanner/master-health-checker.js +1 -0
- package/dist/packages/scanner/monitor-notifier.js +1 -0
- package/dist/packages/scanner/monitor-service.js +1 -0
- package/dist/packages/scanner/monitor-store.js +1 -0
- package/dist/packages/scanner/pre-commit-gate.js +1 -0
- package/dist/packages/scanner/scan-diff.js +1 -0
- package/dist/packages/scanner/scan-runner.js +1 -0
- package/dist/packages/scanner/secret-scanner.js +1 -0
- package/dist/packages/scanner/sentinel-core.js +1 -0
- package/dist/packages/scanner/sentinel-knowledge.js +1 -0
- package/dist/packages/scanner/tech-debt-analyzer.js +1 -0
- package/dist/packages/scanner/tech-debt-cost.js +1 -0
- package/dist/packages/scanner/widget-generator.js +1 -0
- package/package.json +12 -7
- package/cli.js +0 -2627
- package/packages/scanner/ai-confidence-scorer.js +0 -260
- package/packages/scanner/alert-manager.js +0 -398
- package/packages/scanner/baseline-manager.js +0 -109
- package/packages/scanner/code-scanner.js +0 -758
- package/packages/scanner/codebase-passport.js +0 -299
- package/packages/scanner/copy-paste-detector.js +0 -276
- package/packages/scanner/dependency-graph.js +0 -541
- package/packages/scanner/drift-detector.js +0 -423
- package/packages/scanner/executive-report.js +0 -774
- package/packages/scanner/file-collector.js +0 -64
- package/packages/scanner/file-watcher.js +0 -323
- package/packages/scanner/ghost-code-detector.js +0 -301
- package/packages/scanner/hallucination-detector.js +0 -822
- package/packages/scanner/health-checker.js +0 -586
- package/packages/scanner/html-report.js +0 -634
- package/packages/scanner/index.js +0 -100
- package/packages/scanner/license-manager.js +0 -331
- package/packages/scanner/master-health-checker.js +0 -513
- package/packages/scanner/monitor-notifier.js +0 -64
- package/packages/scanner/monitor-service.js +0 -103
- package/packages/scanner/monitor-store.js +0 -117
- package/packages/scanner/pre-commit-gate.js +0 -216
- package/packages/scanner/scan-diff.js +0 -50
- package/packages/scanner/scan-runner.js +0 -172
- package/packages/scanner/secret-scanner.js +0 -612
- package/packages/scanner/secret-scanner.test.js +0 -103
- package/packages/scanner/sentinel-core.js +0 -616
- package/packages/scanner/sentinel-knowledge.js +0 -322
- package/packages/scanner/tech-debt-analyzer.js +0 -583
- package/packages/scanner/tech-debt-cost.js +0 -194
- package/packages/scanner/widget-generator.js +0 -415
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sentinel Knowledge Interface
|
|
3
|
-
*
|
|
4
|
-
* Provides a unified API for other Orion systems to query codebase knowledge.
|
|
5
|
-
* Used by: Astra (voice queries), CITADEL (enforcement), Forge (auto-widgets)
|
|
6
|
-
*
|
|
7
|
-
* @purpose Unified codebase knowledge API for Orion systems
|
|
8
|
-
* @module sentinel
|
|
9
|
-
* @layer infrastructure
|
|
10
|
-
* @imports-from sentinel/dependency-graph.js, sentinel/widget-generator.js, sentinel/code-scanner.js
|
|
11
|
-
* @exports-to astra-service, citadel/enforcer, forge, server
|
|
12
|
-
* @side-effects File system reads
|
|
13
|
-
* @critical-for System-wide codebase awareness
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const path = require('path');
|
|
17
|
-
const fs = require('fs');
|
|
18
|
-
const DependencyGraph = require('./dependency-graph');
|
|
19
|
-
const WidgetGenerator = require('./widget-generator');
|
|
20
|
-
const CodeScanner = require('./code-scanner');
|
|
21
|
-
|
|
22
|
-
// Singleton instances
|
|
23
|
-
let dependencyGraph = null;
|
|
24
|
-
let widgetGenerator = null;
|
|
25
|
-
let codeScanner = null;
|
|
26
|
-
let initialized = false;
|
|
27
|
-
let rootPath = null;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Initialize Sentinel Knowledge (call once at startup)
|
|
31
|
-
*/
|
|
32
|
-
async function initialize(config = {}) {
|
|
33
|
-
rootPath = config.rootPath || process.cwd();
|
|
34
|
-
|
|
35
|
-
console.log('[SENTINEL-KNOWLEDGE] Initializing codebase knowledge...');
|
|
36
|
-
|
|
37
|
-
// Initialize dependency graph
|
|
38
|
-
dependencyGraph = new DependencyGraph({ rootPath });
|
|
39
|
-
await dependencyGraph.build();
|
|
40
|
-
|
|
41
|
-
// Initialize widget generator (with graph)
|
|
42
|
-
widgetGenerator = new WidgetGenerator({
|
|
43
|
-
rootPath,
|
|
44
|
-
dependencyGraph,
|
|
45
|
-
dryRun: true // Default to dry run
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Initialize code scanner
|
|
49
|
-
codeScanner = new CodeScanner({ rootPath });
|
|
50
|
-
|
|
51
|
-
initialized = true;
|
|
52
|
-
console.log('[SENTINEL-KNOWLEDGE] Codebase knowledge ready');
|
|
53
|
-
|
|
54
|
-
return getStats();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Ensure initialized
|
|
59
|
-
*/
|
|
60
|
-
async function ensureInitialized() {
|
|
61
|
-
if (!initialized) {
|
|
62
|
-
await initialize();
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ============================================================
|
|
67
|
-
// QUERY FUNCTIONS (for Astra and other systems)
|
|
68
|
-
// ============================================================
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Get impact analysis for a file
|
|
72
|
-
* "What will break if I change this file?"
|
|
73
|
-
*/
|
|
74
|
-
async function getImpact(filePath) {
|
|
75
|
-
await ensureInitialized();
|
|
76
|
-
|
|
77
|
-
const fullPath = path.isAbsolute(filePath)
|
|
78
|
-
? filePath
|
|
79
|
-
: path.join(rootPath, filePath);
|
|
80
|
-
|
|
81
|
-
return dependencyGraph.getImpactAnalysis(fullPath);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Get what a file depends on
|
|
86
|
-
*/
|
|
87
|
-
async function getDependencies(filePath) {
|
|
88
|
-
await ensureInitialized();
|
|
89
|
-
|
|
90
|
-
const fullPath = path.isAbsolute(filePath)
|
|
91
|
-
? filePath
|
|
92
|
-
: path.join(rootPath, filePath);
|
|
93
|
-
|
|
94
|
-
const deps = dependencyGraph.getDependencies(fullPath);
|
|
95
|
-
return deps.map(d => ({
|
|
96
|
-
module: d.module,
|
|
97
|
-
resolved: d.resolved ? path.relative(rootPath, d.resolved) : null
|
|
98
|
-
}));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Get what depends on a file
|
|
103
|
-
*/
|
|
104
|
-
async function getDependents(filePath) {
|
|
105
|
-
await ensureInitialized();
|
|
106
|
-
|
|
107
|
-
const fullPath = path.isAbsolute(filePath)
|
|
108
|
-
? filePath
|
|
109
|
-
: path.join(rootPath, filePath);
|
|
110
|
-
|
|
111
|
-
const deps = dependencyGraph.getDependents(fullPath);
|
|
112
|
-
return deps.map(d => path.relative(rootPath, d));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Get most critical files in the codebase
|
|
117
|
-
*/
|
|
118
|
-
async function getCriticalFiles(limit = 10) {
|
|
119
|
-
await ensureInitialized();
|
|
120
|
-
return dependencyGraph.getMostCriticalFiles(limit);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Get module summary
|
|
125
|
-
*/
|
|
126
|
-
async function getModules() {
|
|
127
|
-
await ensureInitialized();
|
|
128
|
-
return dependencyGraph.getModuleSummary();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Get orphan files (potential dead code)
|
|
133
|
-
*/
|
|
134
|
-
async function getOrphans() {
|
|
135
|
-
await ensureInitialized();
|
|
136
|
-
return dependencyGraph.getOrphanFiles();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Get overall codebase stats
|
|
141
|
-
*/
|
|
142
|
-
async function getStats() {
|
|
143
|
-
await ensureInitialized();
|
|
144
|
-
return {
|
|
145
|
-
...dependencyGraph.getStats(),
|
|
146
|
-
initialized,
|
|
147
|
-
rootPath
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Natural language query handler (for Astra)
|
|
153
|
-
*/
|
|
154
|
-
async function query(question) {
|
|
155
|
-
await ensureInitialized();
|
|
156
|
-
|
|
157
|
-
const q = question.toLowerCase();
|
|
158
|
-
|
|
159
|
-
// Impact queries
|
|
160
|
-
if (q.includes('break') || q.includes('impact') || q.includes('affect')) {
|
|
161
|
-
const fileMatch = question.match(/['"]?([a-zA-Z0-9\-_./\\]+\.js)['"]?/);
|
|
162
|
-
if (fileMatch) {
|
|
163
|
-
const impact = await getImpact(fileMatch[1]);
|
|
164
|
-
return {
|
|
165
|
-
type: 'impact',
|
|
166
|
-
file: fileMatch[1],
|
|
167
|
-
result: impact,
|
|
168
|
-
summary: `Changing ${fileMatch[1]} could affect ${impact.totalImpact} files. Risk level: ${impact.riskLevel.toUpperCase()}.`
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Dependency queries
|
|
174
|
-
if (q.includes('depend') || q.includes('import') || q.includes('use')) {
|
|
175
|
-
const fileMatch = question.match(/['"]?([a-zA-Z0-9\-_./\\]+\.js)['"]?/);
|
|
176
|
-
if (fileMatch) {
|
|
177
|
-
if (q.includes('on') || q.includes('import')) {
|
|
178
|
-
// What does X depend on?
|
|
179
|
-
const deps = await getDependencies(fileMatch[1]);
|
|
180
|
-
return {
|
|
181
|
-
type: 'dependencies',
|
|
182
|
-
file: fileMatch[1],
|
|
183
|
-
result: deps,
|
|
184
|
-
summary: `${fileMatch[1]} depends on ${deps.length} files: ${deps.slice(0, 5).map(d => d.module).join(', ')}${deps.length > 5 ? '...' : ''}`
|
|
185
|
-
};
|
|
186
|
-
} else {
|
|
187
|
-
// What depends on X?
|
|
188
|
-
const deps = await getDependents(fileMatch[1]);
|
|
189
|
-
return {
|
|
190
|
-
type: 'dependents',
|
|
191
|
-
file: fileMatch[1],
|
|
192
|
-
result: deps,
|
|
193
|
-
summary: `${deps.length} files depend on ${fileMatch[1]}: ${deps.slice(0, 5).join(', ')}${deps.length > 5 ? '...' : ''}`
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Critical files query
|
|
200
|
-
if (q.includes('critical') || q.includes('important') || q.includes('core')) {
|
|
201
|
-
const critical = await getCriticalFiles(10);
|
|
202
|
-
return {
|
|
203
|
-
type: 'critical',
|
|
204
|
-
result: critical,
|
|
205
|
-
summary: `Top critical files: ${critical.slice(0, 5).map(f => f.relativePath).join(', ')}`
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Module query
|
|
210
|
-
if (q.includes('module') || q.includes('system') || q.includes('component')) {
|
|
211
|
-
const modules = await getModules();
|
|
212
|
-
return {
|
|
213
|
-
type: 'modules',
|
|
214
|
-
result: modules,
|
|
215
|
-
summary: `Codebase has ${modules.length} modules. Largest: ${modules.slice(0, 3).map(m => `${m.name} (${m.fileCount} files)`).join(', ')}`
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Orphan/dead code query
|
|
220
|
-
if (q.includes('orphan') || q.includes('dead') || q.includes('unused')) {
|
|
221
|
-
const orphans = await getOrphans();
|
|
222
|
-
return {
|
|
223
|
-
type: 'orphans',
|
|
224
|
-
result: orphans,
|
|
225
|
-
summary: `Found ${orphans.length} potentially unused files: ${orphans.slice(0, 5).map(o => o.relativePath).join(', ')}${orphans.length > 5 ? '...' : ''}`
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Stats query
|
|
230
|
-
if (q.includes('stat') || q.includes('overview') || q.includes('summary')) {
|
|
231
|
-
const stats = await getStats();
|
|
232
|
-
return {
|
|
233
|
-
type: 'stats',
|
|
234
|
-
result: stats,
|
|
235
|
-
summary: `Codebase: ${stats.totalFiles} files, ${stats.totalImports} imports, ${stats.circularCount} circular dependencies`
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Default
|
|
240
|
-
return {
|
|
241
|
-
type: 'unknown',
|
|
242
|
-
result: null,
|
|
243
|
-
summary: 'I can answer questions about: file impact, dependencies, critical files, modules, orphan/dead code, and codebase stats.'
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// ============================================================
|
|
248
|
-
// WIDGET FUNCTIONS (for CITADEL and Forge)
|
|
249
|
-
// ============================================================
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Check if a file has a valid widget
|
|
253
|
-
*/
|
|
254
|
-
function hasWidget(filePath) {
|
|
255
|
-
try {
|
|
256
|
-
const fullPath = path.isAbsolute(filePath)
|
|
257
|
-
? filePath
|
|
258
|
-
: path.join(rootPath, filePath);
|
|
259
|
-
|
|
260
|
-
const content = fs.readFileSync(fullPath, 'utf8');
|
|
261
|
-
const widgetPattern = /\/\*\*[\s\S]*?@(purpose|module|layer)[\s\S]*?\*\//;
|
|
262
|
-
return widgetPattern.test(content);
|
|
263
|
-
} catch (e) {
|
|
264
|
-
return false;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Generate widget for a file (returns string, doesn't write)
|
|
270
|
-
*/
|
|
271
|
-
async function generateWidget(filePath, content = null) {
|
|
272
|
-
await ensureInitialized();
|
|
273
|
-
|
|
274
|
-
const fullPath = path.isAbsolute(filePath)
|
|
275
|
-
? filePath
|
|
276
|
-
: path.join(rootPath, filePath);
|
|
277
|
-
|
|
278
|
-
const widget = await widgetGenerator.generateWidget(fullPath, content);
|
|
279
|
-
return widget.widgetString;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Generate and prepend widget to content
|
|
284
|
-
*/
|
|
285
|
-
async function addWidgetToContent(filePath, content) {
|
|
286
|
-
const widgetString = await generateWidget(filePath, content);
|
|
287
|
-
return widgetString + '\n\n' + content;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Refresh the dependency graph (call after files change)
|
|
292
|
-
*/
|
|
293
|
-
async function refresh() {
|
|
294
|
-
if (dependencyGraph) {
|
|
295
|
-
await dependencyGraph.build();
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// ============================================================
|
|
300
|
-
// EXPORT
|
|
301
|
-
// ============================================================
|
|
302
|
-
|
|
303
|
-
module.exports = {
|
|
304
|
-
// Initialization
|
|
305
|
-
initialize,
|
|
306
|
-
refresh,
|
|
307
|
-
|
|
308
|
-
// Query functions (for Astra)
|
|
309
|
-
query,
|
|
310
|
-
getImpact,
|
|
311
|
-
getDependencies,
|
|
312
|
-
getDependents,
|
|
313
|
-
getCriticalFiles,
|
|
314
|
-
getModules,
|
|
315
|
-
getOrphans,
|
|
316
|
-
getStats,
|
|
317
|
-
|
|
318
|
-
// Widget functions (for CITADEL/Forge)
|
|
319
|
-
hasWidget,
|
|
320
|
-
generateWidget,
|
|
321
|
-
addWidgetToContent
|
|
322
|
-
};
|