@rigour-labs/core 1.5.0 → 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.
@@ -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;
@@ -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
- // Future: class-specific gates
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
- 'map(',
117
- 'filter(',
129
+ 'reduce(',
130
+ '.pipe(',
131
+ 'compose(',
132
+ 'curry(',
133
+ 'readonly ',
118
134
  ],
119
135
  config: {
120
136
  paradigm: 'functional',
121
137
  gates: {
122
- // Future: function-specific gates
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: [],
@@ -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;
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/core",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {
@@ -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
+ }
@@ -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
- // Future: class-specific gates
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
- 'map(',
129
- 'filter(',
141
+ 'reduce(',
142
+ '.pipe(',
143
+ 'compose(',
144
+ 'curry(',
145
+ 'readonly ',
130
146
  ],
131
147
  config: {
132
148
  paradigm: 'functional',
133
149
  gates: {
134
- // Future: function-specific gates
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: [],
@@ -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([]),