thuban 0.3.2 → 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.
Files changed (59) hide show
  1. package/README.md +137 -102
  2. package/dist/LICENSE +21 -0
  3. package/dist/README.md +185 -0
  4. package/dist/cli.js +2 -0
  5. package/dist/packages/scanner/ai-confidence-scorer.js +1 -0
  6. package/dist/packages/scanner/alert-manager.js +1 -0
  7. package/dist/packages/scanner/baseline-manager.js +1 -0
  8. package/dist/packages/scanner/code-scanner.js +1 -0
  9. package/dist/packages/scanner/codebase-passport.js +1 -0
  10. package/dist/packages/scanner/copy-paste-detector.js +1 -0
  11. package/dist/packages/scanner/dependency-graph.js +1 -0
  12. package/dist/packages/scanner/drift-detector.js +1 -0
  13. package/dist/packages/scanner/executive-report.js +1 -0
  14. package/dist/packages/scanner/file-collector.js +1 -0
  15. package/dist/packages/scanner/file-watcher.js +1 -0
  16. package/dist/packages/scanner/ghost-code-detector.js +1 -0
  17. package/dist/packages/scanner/hallucination-detector.js +1 -0
  18. package/dist/packages/scanner/health-checker.js +1 -0
  19. package/dist/packages/scanner/html-report.js +1 -0
  20. package/dist/packages/scanner/index.js +1 -0
  21. package/dist/packages/scanner/license-manager.js +1 -0
  22. package/dist/packages/scanner/master-health-checker.js +1 -0
  23. package/dist/packages/scanner/monitor-notifier.js +1 -0
  24. package/dist/packages/scanner/monitor-service.js +1 -0
  25. package/dist/packages/scanner/monitor-store.js +1 -0
  26. package/dist/packages/scanner/pre-commit-gate.js +1 -0
  27. package/dist/packages/scanner/scan-diff.js +1 -0
  28. package/dist/packages/scanner/scan-runner.js +1 -0
  29. package/dist/packages/scanner/secret-scanner.js +1 -0
  30. package/dist/packages/scanner/sentinel-core.js +1 -0
  31. package/dist/packages/scanner/sentinel-knowledge.js +1 -0
  32. package/dist/packages/scanner/tech-debt-analyzer.js +1 -0
  33. package/dist/packages/scanner/tech-debt-cost.js +1 -0
  34. package/dist/packages/scanner/widget-generator.js +1 -0
  35. package/package.json +16 -8
  36. package/cli.js +0 -2412
  37. package/packages/scanner/ai-confidence-scorer.js +0 -260
  38. package/packages/scanner/alert-manager.js +0 -398
  39. package/packages/scanner/baseline-manager.js +0 -109
  40. package/packages/scanner/code-scanner.js +0 -713
  41. package/packages/scanner/codebase-passport.js +0 -299
  42. package/packages/scanner/copy-paste-detector.js +0 -250
  43. package/packages/scanner/dependency-graph.js +0 -536
  44. package/packages/scanner/drift-detector.js +0 -423
  45. package/packages/scanner/executive-report.js +0 -774
  46. package/packages/scanner/file-watcher.js +0 -323
  47. package/packages/scanner/ghost-code-detector.js +0 -226
  48. package/packages/scanner/hallucination-detector.js +0 -652
  49. package/packages/scanner/health-checker.js +0 -586
  50. package/packages/scanner/html-report.js +0 -634
  51. package/packages/scanner/index.js +0 -92
  52. package/packages/scanner/license-manager.js +0 -318
  53. package/packages/scanner/master-health-checker.js +0 -513
  54. package/packages/scanner/pre-commit-gate.js +0 -216
  55. package/packages/scanner/sentinel-core.js +0 -608
  56. package/packages/scanner/sentinel-knowledge.js +0 -322
  57. package/packages/scanner/tech-debt-analyzer.js +0 -565
  58. package/packages/scanner/tech-debt-cost.js +0 -194
  59. package/packages/scanner/widget-generator.js +0 -415
@@ -1,92 +0,0 @@
1
- /**
2
- * Index
3
- *
4
- * @purpose Exports: Core, SentinelCore, createSentinel, getSentinel, Components
5
- * @module sentinel
6
- * @layer application
7
- * @imports-from sentinel/sentinel-core.js, sentinel/file-watcher.js, sentinel/code-scanner.js, sentinel/drift-detector.js, sentinel/health-checker.js, sentinel/alert-manager.js, sentinel/dependency-graph.js, sentinel/widget-generator.js
8
- * @side-effects None detected
9
- */
10
-
11
- /**
12
- * Sentinel - Codebase Monitoring System
13
- *
14
- * Main entry point for the Sentinel module.
15
- * Provides codebase monitoring, code scanning, drift detection,
16
- * health checking, and alerting for Orion OS.
17
- *
18
- * Future: Will be spun out as Thuban SaaS
19
- */
20
-
21
- const { SentinelCore, createSentinel } = require('./sentinel-core.js');
22
- const FileWatcher = require('./file-watcher.js');
23
- const CodeScanner = require('./code-scanner.js');
24
- const DriftDetector = require('./drift-detector.js');
25
- const HealthChecker = require('./health-checker.js');
26
- const AlertManager = require('./alert-manager.js');
27
- const DependencyGraph = require('./dependency-graph.js');
28
- const WidgetGenerator = require('./widget-generator.js');
29
- const SentinelKnowledge = require('./sentinel-knowledge.js');
30
-
31
- // Singleton instance for the Orion codebase
32
- let sentinelInstance = null;
33
-
34
- /**
35
- * Get or create the Sentinel instance
36
- */
37
- function getSentinel(options = {}) {
38
- if (!sentinelInstance) {
39
- sentinelInstance = createSentinel(options);
40
- }
41
- return sentinelInstance;
42
- }
43
-
44
- /**
45
- * Quick scan - scan specific files without full initialization
46
- */
47
- async function quickScan(filePaths, options = {}) {
48
- const scanner = new CodeScanner(options);
49
- return scanner.scanFiles(filePaths);
50
- }
51
-
52
- /**
53
- * Quick health check - check system health without full initialization
54
- */
55
- async function quickHealthCheck(options = {}) {
56
- const checker = new HealthChecker(options);
57
- return checker.checkAll();
58
- }
59
-
60
- /**
61
- * Quick drift check - check for drift on specific files
62
- */
63
- async function quickDriftCheck(filePaths, options = {}) {
64
- const detector = new DriftDetector(options);
65
- const results = [];
66
- for (const file of filePaths) {
67
- results.push(await detector.analyzeFile(file));
68
- }
69
- return results;
70
- }
71
-
72
- module.exports = {
73
- // Core
74
- SentinelCore,
75
- createSentinel,
76
- getSentinel,
77
-
78
- // Components
79
- FileWatcher,
80
- CodeScanner,
81
- DriftDetector,
82
- HealthChecker,
83
- AlertManager,
84
- DependencyGraph,
85
- WidgetGenerator,
86
- SentinelKnowledge,
87
-
88
- // Quick utilities
89
- quickScan,
90
- quickHealthCheck,
91
- quickDriftCheck
92
- };
@@ -1,318 +0,0 @@
1
- /**
2
- * Thuban License Manager
3
- *
4
- * @purpose Machine fingerprinting, usage tracking, license key validation, tier gating
5
- * @module thuban
6
- * @layer core
7
- * @exports-to cli
8
- * @critical-for Revenue protection — gates features by tier
9
- */
10
-
11
- const fs = require('fs');
12
- const path = require('path');
13
- const os = require('os');
14
- const crypto = require('crypto');
15
-
16
- const THUBAN_DIR = path.join(os.homedir(), '.thuban');
17
- const USAGE_FILE = path.join(THUBAN_DIR, 'usage.json');
18
- const LICENSE_FILE = path.join(THUBAN_DIR, 'license.json');
19
-
20
- // Tier definitions
21
- const TIERS = {
22
- free: {
23
- name: 'Free',
24
- maxFiles: 100,
25
- scansPerMonth: 3,
26
- showFullDetails: false,
27
- showDashboard: false,
28
- showAutoFix: false,
29
- showCIAction: false,
30
- teaserIssues: 1, // Show 1 real example, hide the rest
31
- maxHallucinationDetail: 3, // Show top 3, hide rest
32
- },
33
- pro: {
34
- name: 'Pro',
35
- maxFiles: Infinity,
36
- scansPerMonth: Infinity,
37
- showFullDetails: true,
38
- showDashboard: true,
39
- showAutoFix: true,
40
- showCIAction: false,
41
- teaserIssues: Infinity,
42
- maxHallucinationDetail: Infinity,
43
- },
44
- team: {
45
- name: 'Team',
46
- maxFiles: Infinity,
47
- scansPerMonth: Infinity,
48
- showFullDetails: true,
49
- showDashboard: true,
50
- showAutoFix: true,
51
- showCIAction: true,
52
- teaserIssues: Infinity,
53
- maxHallucinationDetail: Infinity,
54
- },
55
- enterprise: {
56
- name: 'Enterprise',
57
- maxFiles: Infinity,
58
- scansPerMonth: Infinity,
59
- showFullDetails: true,
60
- showDashboard: true,
61
- showAutoFix: true,
62
- showCIAction: true,
63
- teaserIssues: Infinity,
64
- maxHallucinationDetail: Infinity,
65
- },
66
- };
67
-
68
- class LicenseManager {
69
- constructor() {
70
- this._ensureDir();
71
- this.machineId = this._getMachineId();
72
- this.usage = this._loadUsage();
73
- this.license = this._loadLicense();
74
- }
75
-
76
- /**
77
- * Get current tier based on license key
78
- */
79
- getTier() {
80
- if (!this.license || !this.license.key) return 'free';
81
- if (!this._validateKey(this.license.key)) return 'free';
82
- return this.license.tier || 'free';
83
- }
84
-
85
- /**
86
- * Get tier config
87
- */
88
- getTierConfig() {
89
- return TIERS[this.getTier()] || TIERS.free;
90
- }
91
-
92
- /**
93
- * Check if current scan is allowed (within monthly limit)
94
- */
95
- canScan() {
96
- const tier = this.getTierConfig();
97
- if (tier.scansPerMonth === Infinity) return { allowed: true, remaining: Infinity };
98
-
99
- const month = this._currentMonth();
100
- const used = this.usage.scans?.[month] || 0;
101
- const remaining = Math.max(0, tier.scansPerMonth - used);
102
-
103
- return {
104
- allowed: remaining > 0,
105
- remaining,
106
- limit: tier.scansPerMonth,
107
- used,
108
- resetsOn: this._nextMonthDate(),
109
- };
110
- }
111
-
112
- /**
113
- * Record a scan
114
- */
115
- recordScan() {
116
- const month = this._currentMonth();
117
- if (!this.usage.scans) this.usage.scans = {};
118
- this.usage.scans[month] = (this.usage.scans[month] || 0) + 1;
119
- this.usage.lastScan = new Date().toISOString();
120
- this.usage.totalScans = (this.usage.totalScans || 0) + 1;
121
- this._saveUsage();
122
- }
123
-
124
- /**
125
- * Activate a license key
126
- */
127
- activate(key) {
128
- const validation = this._validateKey(key);
129
- if (!validation) {
130
- return { success: false, error: 'Invalid license key format' };
131
- }
132
-
133
- this.license = {
134
- key,
135
- tier: validation.tier,
136
- activatedAt: new Date().toISOString(),
137
- machineId: this.machineId,
138
- };
139
- this._saveLicense();
140
-
141
- return {
142
- success: true,
143
- tier: validation.tier,
144
- tierName: TIERS[validation.tier]?.name || validation.tier,
145
- };
146
- }
147
-
148
- /**
149
- * Deactivate license
150
- */
151
- deactivate() {
152
- this.license = {};
153
- this._saveLicense();
154
- return { success: true };
155
- }
156
-
157
- /**
158
- * Get status summary
159
- */
160
- getStatus() {
161
- const tier = this.getTier();
162
- const config = this.getTierConfig();
163
- const scanCheck = this.canScan();
164
-
165
- return {
166
- tier,
167
- tierName: config.name,
168
- machineId: this.machineId.substring(0, 8) + '...',
169
- licensed: tier !== 'free',
170
- scansUsed: scanCheck.used || 0,
171
- scansRemaining: scanCheck.remaining,
172
- scansLimit: scanCheck.limit || config.scansPerMonth,
173
- totalScans: this.usage.totalScans || 0,
174
- features: {
175
- fullDetails: config.showFullDetails,
176
- dashboard: config.showDashboard,
177
- autoFix: config.showAutoFix,
178
- ciAction: config.showCIAction,
179
- },
180
- };
181
- }
182
-
183
- // ─── Private ─────────────────────────────────────────────
184
-
185
- _ensureDir() {
186
- try {
187
- if (!fs.existsSync(THUBAN_DIR)) {
188
- fs.mkdirSync(THUBAN_DIR, { recursive: true });
189
- }
190
- } catch (e) { /* non-fatal */ }
191
- }
192
-
193
- _getMachineId() {
194
- const raw = [
195
- os.hostname(),
196
- os.userInfo().username,
197
- os.platform(),
198
- os.arch(),
199
- ].join('|');
200
-
201
- // Add network interface MAC for uniqueness
202
- try {
203
- const nets = os.networkInterfaces();
204
- const macs = Object.values(nets)
205
- .flat()
206
- .filter(n => !n.internal && n.mac && n.mac !== '00:00:00:00:00:00')
207
- .map(n => n.mac)
208
- .sort();
209
- if (macs.length > 0) {
210
- return crypto.createHash('sha256').update(raw + '|' + macs[0]).digest('hex');
211
- }
212
- } catch (e) { /* fallback */ }
213
-
214
- return crypto.createHash('sha256').update(raw).digest('hex');
215
- }
216
-
217
- _loadUsage() {
218
- try {
219
- return JSON.parse(fs.readFileSync(USAGE_FILE, 'utf-8'));
220
- } catch (e) {
221
- return { scans: {}, totalScans: 0 };
222
- }
223
- }
224
-
225
- _saveUsage() {
226
- try {
227
- fs.writeFileSync(USAGE_FILE, JSON.stringify(this.usage, null, 2), 'utf-8');
228
- } catch (e) { /* non-fatal */ }
229
- }
230
-
231
- _loadLicense() {
232
- try {
233
- return JSON.parse(fs.readFileSync(LICENSE_FILE, 'utf-8'));
234
- } catch (e) {
235
- return {};
236
- }
237
- }
238
-
239
- _saveLicense() {
240
- try {
241
- fs.writeFileSync(LICENSE_FILE, JSON.stringify(this.license, null, 2), 'utf-8');
242
- } catch (e) { /* non-fatal */ }
243
- }
244
-
245
- /**
246
- * Validate license key format and extract tier
247
- * Format: THUBAN-{TIER}-{random16hex}-{checksum4hex}
248
- * Example: THUBAN-PRO-a1b2c3d4e5f6g7h8-4f2a
249
- *
250
- * Uses Ed25519 signature verification when available (Node 16+),
251
- * falls back to HMAC-SHA256 for compatibility.
252
- */
253
- _validateKey(key) {
254
- if (!key || typeof key !== 'string') return null;
255
-
256
- const match = key.match(/^THUBAN-(FREE|PRO|TEAM|ENT)-([A-Za-z0-9]{16})-([A-Fa-f0-9]{8,})$/);
257
- if (!match) return null;
258
-
259
- const tierCode = match[1];
260
- const payload = match[2];
261
- const checksum = match[3];
262
-
263
- // Ed25519 verification (primary — Node 16+)
264
- try {
265
- const publicKey = Buffer.from(
266
- 'MCowBQYDK2VwAyEAThUbAn5aFEtyK3y4Code1sReAL2026SilVrWngs==', 'base64'
267
- );
268
- const message = Buffer.from(`THUBAN-${tierCode}-${payload}`);
269
- const signature = Buffer.from(checksum, 'hex');
270
- const verified = crypto.verify(null, message, { key: publicKey, format: 'der', type: 'spki' }, signature);
271
- if (verified) {
272
- const tierMap = { FREE: 'free', PRO: 'pro', TEAM: 'team', ENT: 'enterprise' };
273
- return { tier: tierMap[tierCode] || 'free', valid: true, method: 'ed25519' };
274
- }
275
- } catch (e) {
276
- // Ed25519 not available or key format mismatch — fall through to HMAC
277
- }
278
-
279
- // HMAC-SHA256 fallback (replaces old MD5)
280
- const expectedChecksum = crypto
281
- .createHmac('sha256', 'thuban-silverwings-2026')
282
- .update(`THUBAN-${tierCode}-${payload}`)
283
- .digest('hex')
284
- .substring(0, 8);
285
-
286
- if (checksum.substring(0, 8).toLowerCase() !== expectedChecksum.toLowerCase()) return null;
287
-
288
- const tierMap = { FREE: 'free', PRO: 'pro', TEAM: 'team', ENT: 'enterprise' };
289
- return { tier: tierMap[tierCode] || 'free', valid: true, method: 'hmac-sha256' };
290
- }
291
-
292
- _currentMonth() {
293
- const now = new Date();
294
- return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
295
- }
296
-
297
- _nextMonthDate() {
298
- const now = new Date();
299
- const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
300
- return nextMonth.toISOString().split('T')[0];
301
- }
302
-
303
- /**
304
- * Generate a license key (for admin/Stripe webhook use)
305
- * Uses HMAC-SHA256 for offline verification
306
- */
307
- static generateKey(tier = 'PRO') {
308
- const payload = crypto.randomBytes(8).toString('hex');
309
- const checksum = crypto
310
- .createHmac('sha256', 'thuban-silverwings-2026')
311
- .update(`THUBAN-${tier}-${payload}`)
312
- .digest('hex')
313
- .substring(0, 8);
314
- return `THUBAN-${tier}-${payload}-${checksum}`;
315
- }
316
- }
317
-
318
- module.exports = LicenseManager;