@rigour-labs/core 1.5.1 → 1.6.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/services/state-service.d.ts +26 -0
- package/dist/services/state-service.js +112 -0
- package/dist/templates/index.js +34 -5
- package/dist/types/index.d.ts +48 -0
- package/dist/types/index.js +4 -0
- package/package.json +1 -1
- package/src/services/state-service.ts +138 -0
- package/src/templates/index.ts +34 -5
- package/src/types/index.ts +4 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare class StateService {
|
|
2
|
+
private statePath;
|
|
3
|
+
private state;
|
|
4
|
+
constructor(cwd: string);
|
|
5
|
+
private load;
|
|
6
|
+
private createEmpty;
|
|
7
|
+
/**
|
|
8
|
+
* Record violation occurrences for prioritization.
|
|
9
|
+
* PRIVACY: Only stores rule IDs and counts, never file contents or paths.
|
|
10
|
+
*/
|
|
11
|
+
recordViolations(ruleIds: string[]): void;
|
|
12
|
+
/**
|
|
13
|
+
* Prioritize violations for Fix Packet ordering.
|
|
14
|
+
* Most frequent + recent violations appear first.
|
|
15
|
+
*/
|
|
16
|
+
prioritize(ruleIds: string[]): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Get repeat violation hints for agent feedback.
|
|
19
|
+
*/
|
|
20
|
+
getRepeatHints(ruleIds: string[]): Record<string, string>;
|
|
21
|
+
save(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Clear all state (user privacy action).
|
|
24
|
+
*/
|
|
25
|
+
clear(): void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StateService = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const STATE_DIR = '.rigour';
|
|
10
|
+
const STATE_FILE = 'state.json';
|
|
11
|
+
const CURRENT_VERSION = 1;
|
|
12
|
+
class StateService {
|
|
13
|
+
statePath;
|
|
14
|
+
state;
|
|
15
|
+
constructor(cwd) {
|
|
16
|
+
this.statePath = path_1.default.join(cwd, STATE_DIR, STATE_FILE);
|
|
17
|
+
this.state = this.load();
|
|
18
|
+
}
|
|
19
|
+
load() {
|
|
20
|
+
try {
|
|
21
|
+
if (fs_extra_1.default.existsSync(this.statePath)) {
|
|
22
|
+
const content = fs_extra_1.default.readFileSync(this.statePath, 'utf-8');
|
|
23
|
+
return JSON.parse(content);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Corrupted or missing state - reset
|
|
28
|
+
}
|
|
29
|
+
return this.createEmpty();
|
|
30
|
+
}
|
|
31
|
+
createEmpty() {
|
|
32
|
+
return {
|
|
33
|
+
version: CURRENT_VERSION,
|
|
34
|
+
createdAt: new Date().toISOString(),
|
|
35
|
+
violations: {},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Record violation occurrences for prioritization.
|
|
40
|
+
* PRIVACY: Only stores rule IDs and counts, never file contents or paths.
|
|
41
|
+
*/
|
|
42
|
+
recordViolations(ruleIds) {
|
|
43
|
+
const now = new Date().toISOString();
|
|
44
|
+
for (const ruleId of ruleIds) {
|
|
45
|
+
if (!this.state.violations[ruleId]) {
|
|
46
|
+
this.state.violations[ruleId] = { count: 0, lastSeen: now, coOccurs: {} };
|
|
47
|
+
}
|
|
48
|
+
this.state.violations[ruleId].count++;
|
|
49
|
+
this.state.violations[ruleId].lastSeen = now;
|
|
50
|
+
// Track co-occurrences for pattern detection
|
|
51
|
+
for (const otherId of ruleIds) {
|
|
52
|
+
if (otherId !== ruleId) {
|
|
53
|
+
this.state.violations[ruleId].coOccurs[otherId] =
|
|
54
|
+
(this.state.violations[ruleId].coOccurs[otherId] || 0) + 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Prioritize violations for Fix Packet ordering.
|
|
61
|
+
* Most frequent + recent violations appear first.
|
|
62
|
+
*/
|
|
63
|
+
prioritize(ruleIds) {
|
|
64
|
+
return [...ruleIds].sort((a, b) => {
|
|
65
|
+
const statsA = this.state.violations[a];
|
|
66
|
+
const statsB = this.state.violations[b];
|
|
67
|
+
if (!statsA && !statsB)
|
|
68
|
+
return 0;
|
|
69
|
+
if (!statsA)
|
|
70
|
+
return 1;
|
|
71
|
+
if (!statsB)
|
|
72
|
+
return -1;
|
|
73
|
+
// Higher count = higher priority
|
|
74
|
+
return statsB.count - statsA.count;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get repeat violation hints for agent feedback.
|
|
79
|
+
*/
|
|
80
|
+
getRepeatHints(ruleIds) {
|
|
81
|
+
const hints = {};
|
|
82
|
+
for (const ruleId of ruleIds) {
|
|
83
|
+
const stats = this.state.violations[ruleId];
|
|
84
|
+
if (stats && stats.count > 2) {
|
|
85
|
+
hints[ruleId] = `This violation has occurred ${stats.count} times. Consider root-cause analysis.`;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return hints;
|
|
89
|
+
}
|
|
90
|
+
save() {
|
|
91
|
+
try {
|
|
92
|
+
fs_extra_1.default.ensureDirSync(path_1.default.dirname(this.statePath));
|
|
93
|
+
fs_extra_1.default.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Silent fail - state is optional
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Clear all state (user privacy action).
|
|
101
|
+
*/
|
|
102
|
+
clear() {
|
|
103
|
+
this.state = this.createEmpty();
|
|
104
|
+
try {
|
|
105
|
+
fs_extra_1.default.removeSync(this.statePath);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Silent fail
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.StateService = StateService;
|
package/dist/templates/index.js
CHANGED
|
@@ -100,26 +100,51 @@ exports.PARADIGM_TEMPLATES = [
|
|
|
100
100
|
'interface ',
|
|
101
101
|
'implements ',
|
|
102
102
|
'extends ',
|
|
103
|
+
'constructor(',
|
|
104
|
+
'private ',
|
|
105
|
+
'public ',
|
|
106
|
+
'protected ',
|
|
103
107
|
],
|
|
104
108
|
config: {
|
|
105
109
|
paradigm: 'oop',
|
|
106
110
|
gates: {
|
|
107
|
-
|
|
111
|
+
max_file_lines: 400,
|
|
112
|
+
ast: {
|
|
113
|
+
complexity: 10,
|
|
114
|
+
max_methods: 10,
|
|
115
|
+
max_params: 5,
|
|
116
|
+
max_nesting: 4,
|
|
117
|
+
max_inheritance_depth: 3,
|
|
118
|
+
max_class_dependencies: 5,
|
|
119
|
+
max_function_lines: 60,
|
|
120
|
+
},
|
|
108
121
|
},
|
|
109
122
|
},
|
|
110
123
|
},
|
|
111
124
|
{
|
|
112
125
|
name: 'functional',
|
|
126
|
+
// Removed '=>' as primary marker - too broad (appears in OOP callbacks)
|
|
113
127
|
markers: [
|
|
114
|
-
'=>',
|
|
115
128
|
'export const',
|
|
116
|
-
'
|
|
117
|
-
'
|
|
129
|
+
'reduce(',
|
|
130
|
+
'.pipe(',
|
|
131
|
+
'compose(',
|
|
132
|
+
'curry(',
|
|
133
|
+
'readonly ',
|
|
118
134
|
],
|
|
119
135
|
config: {
|
|
120
136
|
paradigm: 'functional',
|
|
121
137
|
gates: {
|
|
122
|
-
|
|
138
|
+
max_file_lines: 350,
|
|
139
|
+
ast: {
|
|
140
|
+
complexity: 8,
|
|
141
|
+
max_methods: 15, // Functions, not classes
|
|
142
|
+
max_params: 4,
|
|
143
|
+
max_nesting: 3,
|
|
144
|
+
max_inheritance_depth: 3,
|
|
145
|
+
max_class_dependencies: 5,
|
|
146
|
+
max_function_lines: 40,
|
|
147
|
+
},
|
|
123
148
|
},
|
|
124
149
|
},
|
|
125
150
|
},
|
|
@@ -137,6 +162,10 @@ exports.UNIVERSAL_CONFIG = {
|
|
|
137
162
|
complexity: 10,
|
|
138
163
|
max_methods: 10,
|
|
139
164
|
max_params: 5,
|
|
165
|
+
max_nesting: 4,
|
|
166
|
+
max_inheritance_depth: 3,
|
|
167
|
+
max_class_dependencies: 5,
|
|
168
|
+
max_function_lines: 50,
|
|
140
169
|
},
|
|
141
170
|
dependencies: {
|
|
142
171
|
forbid: [],
|
package/dist/types/index.d.ts
CHANGED
|
@@ -9,14 +9,26 @@ export declare const GatesSchema: z.ZodObject<{
|
|
|
9
9
|
complexity: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
10
10
|
max_methods: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
11
11
|
max_params: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
12
|
+
max_nesting: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
13
|
+
max_inheritance_depth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
14
|
+
max_class_dependencies: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
15
|
+
max_function_lines: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
12
16
|
}, "strip", z.ZodTypeAny, {
|
|
13
17
|
complexity: number;
|
|
14
18
|
max_methods: number;
|
|
15
19
|
max_params: number;
|
|
20
|
+
max_nesting: number;
|
|
21
|
+
max_inheritance_depth: number;
|
|
22
|
+
max_class_dependencies: number;
|
|
23
|
+
max_function_lines: number;
|
|
16
24
|
}, {
|
|
17
25
|
complexity?: number | undefined;
|
|
18
26
|
max_methods?: number | undefined;
|
|
19
27
|
max_params?: number | undefined;
|
|
28
|
+
max_nesting?: number | undefined;
|
|
29
|
+
max_inheritance_depth?: number | undefined;
|
|
30
|
+
max_class_dependencies?: number | undefined;
|
|
31
|
+
max_function_lines?: number | undefined;
|
|
20
32
|
}>>>;
|
|
21
33
|
dependencies: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
22
34
|
forbid: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
|
|
@@ -75,6 +87,10 @@ export declare const GatesSchema: z.ZodObject<{
|
|
|
75
87
|
complexity: number;
|
|
76
88
|
max_methods: number;
|
|
77
89
|
max_params: number;
|
|
90
|
+
max_nesting: number;
|
|
91
|
+
max_inheritance_depth: number;
|
|
92
|
+
max_class_dependencies: number;
|
|
93
|
+
max_function_lines: number;
|
|
78
94
|
};
|
|
79
95
|
dependencies: {
|
|
80
96
|
forbid: string[];
|
|
@@ -101,6 +117,10 @@ export declare const GatesSchema: z.ZodObject<{
|
|
|
101
117
|
complexity?: number | undefined;
|
|
102
118
|
max_methods?: number | undefined;
|
|
103
119
|
max_params?: number | undefined;
|
|
120
|
+
max_nesting?: number | undefined;
|
|
121
|
+
max_inheritance_depth?: number | undefined;
|
|
122
|
+
max_class_dependencies?: number | undefined;
|
|
123
|
+
max_function_lines?: number | undefined;
|
|
104
124
|
} | undefined;
|
|
105
125
|
dependencies?: {
|
|
106
126
|
forbid?: string[] | undefined;
|
|
@@ -164,14 +184,26 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
164
184
|
complexity: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
165
185
|
max_methods: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
166
186
|
max_params: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
187
|
+
max_nesting: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
188
|
+
max_inheritance_depth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
189
|
+
max_class_dependencies: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
190
|
+
max_function_lines: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
167
191
|
}, "strip", z.ZodTypeAny, {
|
|
168
192
|
complexity: number;
|
|
169
193
|
max_methods: number;
|
|
170
194
|
max_params: number;
|
|
195
|
+
max_nesting: number;
|
|
196
|
+
max_inheritance_depth: number;
|
|
197
|
+
max_class_dependencies: number;
|
|
198
|
+
max_function_lines: number;
|
|
171
199
|
}, {
|
|
172
200
|
complexity?: number | undefined;
|
|
173
201
|
max_methods?: number | undefined;
|
|
174
202
|
max_params?: number | undefined;
|
|
203
|
+
max_nesting?: number | undefined;
|
|
204
|
+
max_inheritance_depth?: number | undefined;
|
|
205
|
+
max_class_dependencies?: number | undefined;
|
|
206
|
+
max_function_lines?: number | undefined;
|
|
175
207
|
}>>>;
|
|
176
208
|
dependencies: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
177
209
|
forbid: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
|
|
@@ -230,6 +262,10 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
230
262
|
complexity: number;
|
|
231
263
|
max_methods: number;
|
|
232
264
|
max_params: number;
|
|
265
|
+
max_nesting: number;
|
|
266
|
+
max_inheritance_depth: number;
|
|
267
|
+
max_class_dependencies: number;
|
|
268
|
+
max_function_lines: number;
|
|
233
269
|
};
|
|
234
270
|
dependencies: {
|
|
235
271
|
forbid: string[];
|
|
@@ -256,6 +292,10 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
256
292
|
complexity?: number | undefined;
|
|
257
293
|
max_methods?: number | undefined;
|
|
258
294
|
max_params?: number | undefined;
|
|
295
|
+
max_nesting?: number | undefined;
|
|
296
|
+
max_inheritance_depth?: number | undefined;
|
|
297
|
+
max_class_dependencies?: number | undefined;
|
|
298
|
+
max_function_lines?: number | undefined;
|
|
259
299
|
} | undefined;
|
|
260
300
|
dependencies?: {
|
|
261
301
|
forbid?: string[] | undefined;
|
|
@@ -299,6 +339,10 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
299
339
|
complexity: number;
|
|
300
340
|
max_methods: number;
|
|
301
341
|
max_params: number;
|
|
342
|
+
max_nesting: number;
|
|
343
|
+
max_inheritance_depth: number;
|
|
344
|
+
max_class_dependencies: number;
|
|
345
|
+
max_function_lines: number;
|
|
302
346
|
};
|
|
303
347
|
dependencies: {
|
|
304
348
|
forbid: string[];
|
|
@@ -342,6 +386,10 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
342
386
|
complexity?: number | undefined;
|
|
343
387
|
max_methods?: number | undefined;
|
|
344
388
|
max_params?: number | undefined;
|
|
389
|
+
max_nesting?: number | undefined;
|
|
390
|
+
max_inheritance_depth?: number | undefined;
|
|
391
|
+
max_class_dependencies?: number | undefined;
|
|
392
|
+
max_function_lines?: number | undefined;
|
|
345
393
|
} | undefined;
|
|
346
394
|
dependencies?: {
|
|
347
395
|
forbid?: string[] | undefined;
|
package/dist/types/index.js
CHANGED
|
@@ -17,6 +17,10 @@ exports.GatesSchema = zod_1.z.object({
|
|
|
17
17
|
complexity: zod_1.z.number().optional().default(10),
|
|
18
18
|
max_methods: zod_1.z.number().optional().default(10),
|
|
19
19
|
max_params: zod_1.z.number().optional().default(5),
|
|
20
|
+
max_nesting: zod_1.z.number().optional().default(4),
|
|
21
|
+
max_inheritance_depth: zod_1.z.number().optional().default(3),
|
|
22
|
+
max_class_dependencies: zod_1.z.number().optional().default(5),
|
|
23
|
+
max_function_lines: zod_1.z.number().optional().default(50),
|
|
20
24
|
}).optional().default({}),
|
|
21
25
|
dependencies: zod_1.z.object({
|
|
22
26
|
forbid: zod_1.z.array(zod_1.z.string()).optional().default([]),
|
package/package.json
CHANGED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Local Calibration State Service
|
|
7
|
+
*
|
|
8
|
+
* DOCTRINE COMPLIANCE (§6):
|
|
9
|
+
* - Local-only, deletable, optional
|
|
10
|
+
* - Used ONLY for prioritization, ordering, early warnings
|
|
11
|
+
* - NEVER stores: source code, file contents, raw paths, prompts, user identifiers
|
|
12
|
+
* - State NEVER changes PASS/FAIL results (only ordering/messaging)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface ViolationStats {
|
|
16
|
+
count: number;
|
|
17
|
+
lastSeen: string; // ISO timestamp
|
|
18
|
+
coOccurs: Record<string, number>; // Rule ID -> co-occurrence count
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface LocalState {
|
|
22
|
+
version: number;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
violations: Record<string, ViolationStats>; // Rule ID -> stats
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const STATE_DIR = '.rigour';
|
|
28
|
+
const STATE_FILE = 'state.json';
|
|
29
|
+
const CURRENT_VERSION = 1;
|
|
30
|
+
|
|
31
|
+
export class StateService {
|
|
32
|
+
private statePath: string;
|
|
33
|
+
private state: LocalState;
|
|
34
|
+
|
|
35
|
+
constructor(cwd: string) {
|
|
36
|
+
this.statePath = path.join(cwd, STATE_DIR, STATE_FILE);
|
|
37
|
+
this.state = this.load();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private load(): LocalState {
|
|
41
|
+
try {
|
|
42
|
+
if (fs.existsSync(this.statePath)) {
|
|
43
|
+
const content = fs.readFileSync(this.statePath, 'utf-8');
|
|
44
|
+
return JSON.parse(content);
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// Corrupted or missing state - reset
|
|
48
|
+
}
|
|
49
|
+
return this.createEmpty();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private createEmpty(): LocalState {
|
|
53
|
+
return {
|
|
54
|
+
version: CURRENT_VERSION,
|
|
55
|
+
createdAt: new Date().toISOString(),
|
|
56
|
+
violations: {},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Record violation occurrences for prioritization.
|
|
62
|
+
* PRIVACY: Only stores rule IDs and counts, never file contents or paths.
|
|
63
|
+
*/
|
|
64
|
+
recordViolations(ruleIds: string[]): void {
|
|
65
|
+
const now = new Date().toISOString();
|
|
66
|
+
|
|
67
|
+
for (const ruleId of ruleIds) {
|
|
68
|
+
if (!this.state.violations[ruleId]) {
|
|
69
|
+
this.state.violations[ruleId] = { count: 0, lastSeen: now, coOccurs: {} };
|
|
70
|
+
}
|
|
71
|
+
this.state.violations[ruleId].count++;
|
|
72
|
+
this.state.violations[ruleId].lastSeen = now;
|
|
73
|
+
|
|
74
|
+
// Track co-occurrences for pattern detection
|
|
75
|
+
for (const otherId of ruleIds) {
|
|
76
|
+
if (otherId !== ruleId) {
|
|
77
|
+
this.state.violations[ruleId].coOccurs[otherId] =
|
|
78
|
+
(this.state.violations[ruleId].coOccurs[otherId] || 0) + 1;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Prioritize violations for Fix Packet ordering.
|
|
86
|
+
* Most frequent + recent violations appear first.
|
|
87
|
+
*/
|
|
88
|
+
prioritize(ruleIds: string[]): string[] {
|
|
89
|
+
return [...ruleIds].sort((a, b) => {
|
|
90
|
+
const statsA = this.state.violations[a];
|
|
91
|
+
const statsB = this.state.violations[b];
|
|
92
|
+
|
|
93
|
+
if (!statsA && !statsB) return 0;
|
|
94
|
+
if (!statsA) return 1;
|
|
95
|
+
if (!statsB) return -1;
|
|
96
|
+
|
|
97
|
+
// Higher count = higher priority
|
|
98
|
+
return statsB.count - statsA.count;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get repeat violation hints for agent feedback.
|
|
104
|
+
*/
|
|
105
|
+
getRepeatHints(ruleIds: string[]): Record<string, string> {
|
|
106
|
+
const hints: Record<string, string> = {};
|
|
107
|
+
|
|
108
|
+
for (const ruleId of ruleIds) {
|
|
109
|
+
const stats = this.state.violations[ruleId];
|
|
110
|
+
if (stats && stats.count > 2) {
|
|
111
|
+
hints[ruleId] = `This violation has occurred ${stats.count} times. Consider root-cause analysis.`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return hints;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
save(): void {
|
|
119
|
+
try {
|
|
120
|
+
fs.ensureDirSync(path.dirname(this.statePath));
|
|
121
|
+
fs.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
|
|
122
|
+
} catch {
|
|
123
|
+
// Silent fail - state is optional
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Clear all state (user privacy action).
|
|
129
|
+
*/
|
|
130
|
+
clear(): void {
|
|
131
|
+
this.state = this.createEmpty();
|
|
132
|
+
try {
|
|
133
|
+
fs.removeSync(this.statePath);
|
|
134
|
+
} catch {
|
|
135
|
+
// Silent fail
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
package/src/templates/index.ts
CHANGED
|
@@ -112,26 +112,51 @@ export const PARADIGM_TEMPLATES: Template[] = [
|
|
|
112
112
|
'interface ',
|
|
113
113
|
'implements ',
|
|
114
114
|
'extends ',
|
|
115
|
+
'constructor(',
|
|
116
|
+
'private ',
|
|
117
|
+
'public ',
|
|
118
|
+
'protected ',
|
|
115
119
|
],
|
|
116
120
|
config: {
|
|
117
121
|
paradigm: 'oop',
|
|
118
122
|
gates: {
|
|
119
|
-
|
|
123
|
+
max_file_lines: 400,
|
|
124
|
+
ast: {
|
|
125
|
+
complexity: 10,
|
|
126
|
+
max_methods: 10,
|
|
127
|
+
max_params: 5,
|
|
128
|
+
max_nesting: 4,
|
|
129
|
+
max_inheritance_depth: 3,
|
|
130
|
+
max_class_dependencies: 5,
|
|
131
|
+
max_function_lines: 60,
|
|
132
|
+
},
|
|
120
133
|
},
|
|
121
134
|
},
|
|
122
135
|
},
|
|
123
136
|
{
|
|
124
137
|
name: 'functional',
|
|
138
|
+
// Removed '=>' as primary marker - too broad (appears in OOP callbacks)
|
|
125
139
|
markers: [
|
|
126
|
-
'=>',
|
|
127
140
|
'export const',
|
|
128
|
-
'
|
|
129
|
-
'
|
|
141
|
+
'reduce(',
|
|
142
|
+
'.pipe(',
|
|
143
|
+
'compose(',
|
|
144
|
+
'curry(',
|
|
145
|
+
'readonly ',
|
|
130
146
|
],
|
|
131
147
|
config: {
|
|
132
148
|
paradigm: 'functional',
|
|
133
149
|
gates: {
|
|
134
|
-
|
|
150
|
+
max_file_lines: 350,
|
|
151
|
+
ast: {
|
|
152
|
+
complexity: 8,
|
|
153
|
+
max_methods: 15, // Functions, not classes
|
|
154
|
+
max_params: 4,
|
|
155
|
+
max_nesting: 3,
|
|
156
|
+
max_inheritance_depth: 3,
|
|
157
|
+
max_class_dependencies: 5,
|
|
158
|
+
max_function_lines: 40,
|
|
159
|
+
},
|
|
135
160
|
},
|
|
136
161
|
},
|
|
137
162
|
},
|
|
@@ -150,6 +175,10 @@ export const UNIVERSAL_CONFIG: Config = {
|
|
|
150
175
|
complexity: 10,
|
|
151
176
|
max_methods: 10,
|
|
152
177
|
max_params: 5,
|
|
178
|
+
max_nesting: 4,
|
|
179
|
+
max_inheritance_depth: 3,
|
|
180
|
+
max_class_dependencies: 5,
|
|
181
|
+
max_function_lines: 50,
|
|
153
182
|
},
|
|
154
183
|
dependencies: {
|
|
155
184
|
forbid: [],
|
package/src/types/index.ts
CHANGED
|
@@ -15,6 +15,10 @@ export const GatesSchema = z.object({
|
|
|
15
15
|
complexity: z.number().optional().default(10),
|
|
16
16
|
max_methods: z.number().optional().default(10),
|
|
17
17
|
max_params: z.number().optional().default(5),
|
|
18
|
+
max_nesting: z.number().optional().default(4),
|
|
19
|
+
max_inheritance_depth: z.number().optional().default(3),
|
|
20
|
+
max_class_dependencies: z.number().optional().default(5),
|
|
21
|
+
max_function_lines: z.number().optional().default(50),
|
|
18
22
|
}).optional().default({}),
|
|
19
23
|
dependencies: z.object({
|
|
20
24
|
forbid: z.array(z.string()).optional().default([]),
|