@rigour-labs/core 2.22.0 → 3.0.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.
Files changed (103) hide show
  1. package/README.md +58 -0
  2. package/dist/context.test.js +2 -3
  3. package/dist/environment.test.js +2 -1
  4. package/dist/gates/agent-team.d.ts +2 -1
  5. package/dist/gates/agent-team.js +1 -0
  6. package/dist/gates/base.d.ts +3 -1
  7. package/dist/gates/base.js +3 -0
  8. package/dist/gates/checkpoint.d.ts +2 -1
  9. package/dist/gates/checkpoint.js +3 -2
  10. package/dist/gates/context-window-artifacts.d.ts +2 -1
  11. package/dist/gates/context-window-artifacts.js +6 -3
  12. package/dist/gates/context.d.ts +2 -1
  13. package/dist/gates/context.js +1 -0
  14. package/dist/gates/coverage.js +3 -1
  15. package/dist/gates/dependency.js +5 -5
  16. package/dist/gates/duplication-drift.d.ts +2 -1
  17. package/dist/gates/duplication-drift.js +4 -1
  18. package/dist/gates/environment.js +4 -4
  19. package/dist/gates/hallucinated-imports.d.ts +21 -2
  20. package/dist/gates/hallucinated-imports.js +116 -2
  21. package/dist/gates/inconsistent-error-handling.d.ts +2 -1
  22. package/dist/gates/inconsistent-error-handling.js +21 -7
  23. package/dist/gates/promise-safety.d.ts +68 -0
  24. package/dist/gates/promise-safety.js +509 -0
  25. package/dist/gates/retry-loop-breaker.d.ts +2 -1
  26. package/dist/gates/retry-loop-breaker.js +2 -1
  27. package/dist/gates/runner.js +34 -1
  28. package/dist/gates/safety.d.ts +2 -1
  29. package/dist/gates/safety.js +2 -1
  30. package/dist/gates/security-patterns.d.ts +2 -1
  31. package/dist/gates/security-patterns.js +1 -0
  32. package/dist/gates/structure.js +1 -1
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.js +1 -0
  35. package/dist/services/fix-packet-service.d.ts +0 -1
  36. package/dist/services/fix-packet-service.js +9 -14
  37. package/dist/services/score-history.d.ts +54 -0
  38. package/dist/services/score-history.js +122 -0
  39. package/dist/templates/index.js +169 -0
  40. package/dist/types/fix-packet.d.ts +5 -5
  41. package/dist/types/fix-packet.js +1 -1
  42. package/dist/types/index.d.ts +153 -0
  43. package/dist/types/index.js +19 -0
  44. package/package.json +21 -1
  45. package/src/context.test.ts +0 -256
  46. package/src/discovery.test.ts +0 -88
  47. package/src/discovery.ts +0 -112
  48. package/src/environment.test.ts +0 -115
  49. package/src/gates/agent-team.test.ts +0 -134
  50. package/src/gates/agent-team.ts +0 -210
  51. package/src/gates/ast-handlers/base.ts +0 -13
  52. package/src/gates/ast-handlers/python.ts +0 -145
  53. package/src/gates/ast-handlers/python_parser.py +0 -181
  54. package/src/gates/ast-handlers/typescript.ts +0 -264
  55. package/src/gates/ast-handlers/universal.ts +0 -184
  56. package/src/gates/ast.ts +0 -54
  57. package/src/gates/base.ts +0 -28
  58. package/src/gates/checkpoint.test.ts +0 -135
  59. package/src/gates/checkpoint.ts +0 -311
  60. package/src/gates/content.ts +0 -51
  61. package/src/gates/context-window-artifacts.ts +0 -277
  62. package/src/gates/context.ts +0 -270
  63. package/src/gates/coverage.ts +0 -74
  64. package/src/gates/dependency.ts +0 -108
  65. package/src/gates/duplication-drift.ts +0 -231
  66. package/src/gates/environment.ts +0 -94
  67. package/src/gates/file.ts +0 -46
  68. package/src/gates/hallucinated-imports.ts +0 -361
  69. package/src/gates/inconsistent-error-handling.ts +0 -254
  70. package/src/gates/retry-loop-breaker.ts +0 -151
  71. package/src/gates/runner.ts +0 -188
  72. package/src/gates/safety.ts +0 -56
  73. package/src/gates/security-patterns.test.ts +0 -162
  74. package/src/gates/security-patterns.ts +0 -306
  75. package/src/gates/structure.ts +0 -36
  76. package/src/index.ts +0 -13
  77. package/src/pattern-index/embeddings.ts +0 -84
  78. package/src/pattern-index/index.ts +0 -59
  79. package/src/pattern-index/indexer.test.ts +0 -276
  80. package/src/pattern-index/indexer.ts +0 -1023
  81. package/src/pattern-index/matcher.test.ts +0 -293
  82. package/src/pattern-index/matcher.ts +0 -493
  83. package/src/pattern-index/overrides.ts +0 -235
  84. package/src/pattern-index/security.ts +0 -151
  85. package/src/pattern-index/staleness.test.ts +0 -313
  86. package/src/pattern-index/staleness.ts +0 -568
  87. package/src/pattern-index/types.ts +0 -339
  88. package/src/safety.test.ts +0 -53
  89. package/src/services/adaptive-thresholds.test.ts +0 -189
  90. package/src/services/adaptive-thresholds.ts +0 -275
  91. package/src/services/context-engine.ts +0 -104
  92. package/src/services/fix-packet-service.ts +0 -42
  93. package/src/services/state-service.ts +0 -138
  94. package/src/smoke.test.ts +0 -18
  95. package/src/templates/index.ts +0 -338
  96. package/src/types/fix-packet.ts +0 -32
  97. package/src/types/index.ts +0 -200
  98. package/src/utils/logger.ts +0 -43
  99. package/src/utils/scanner.test.ts +0 -37
  100. package/src/utils/scanner.ts +0 -43
  101. package/tsconfig.json +0 -10
  102. package/vitest.config.ts +0 -7
  103. package/vitest.setup.ts +0 -30
@@ -1,184 +0,0 @@
1
- import * as _Parser from 'web-tree-sitter';
2
- const Parser = (_Parser as any).default || _Parser;
3
- import { ASTHandler, ASTHandlerContext } from './base.js';
4
- import { Failure } from '../../types/index.js';
5
- import path from 'path';
6
- import { fileURLToPath } from 'url';
7
-
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
-
10
- interface LanguageConfig {
11
- grammarPath: string;
12
- extensions: string[];
13
- queries: {
14
- methods: string;
15
- parameters: string;
16
- complexity: string; // Cyclomatic
17
- nesting: string; // For Cognitive Complexity
18
- securitySinks?: string;
19
- resourceLeaks?: string;
20
- nPlusOne?: string;
21
- ecosystemBlunders?: string;
22
- }
23
- }
24
-
25
- export class UniversalASTHandler extends ASTHandler {
26
- private parser?: any;
27
- private languages: Record<string, LanguageConfig> = {
28
- '.go': {
29
- grammarPath: '../../vendor/grammars/tree-sitter-go.wasm',
30
- extensions: ['.go'],
31
- queries: {
32
- complexity: '(if_statement) (for_statement) (select_statement) (case_clause)',
33
- nesting: '(if_statement (block . (if_statement))) (for_statement (block . (for_statement)))',
34
- parameters: '(parameter_list (parameter_declaration) @param)',
35
- methods: '(method_declaration) @method (function_declaration) @method',
36
- securitySinks: '(call_expression function: (selector_expression field: (field_identifier) @id (#match? @id "^(Command|exec|System)$")))',
37
- ecosystemBlunders: '(if_statement !condition: (binary_expression left: (identifier) @err (#eq? @err "err")))' // Missing err check
38
- }
39
- },
40
- '.py': {
41
- grammarPath: '../../vendor/grammars/tree-sitter-python.wasm',
42
- extensions: ['.py'],
43
- queries: {
44
- complexity: '(if_statement) (for_statement) (while_statement) (with_statement)',
45
- nesting: '(if_statement (block (if_statement)))',
46
- parameters: '(parameters (identifier) @param)',
47
- methods: '(function_definition) @method',
48
- securitySinks: '(call_expression function: (identifier) @func (#match? @func "^(eval|exec|os\\.system)$"))',
49
- ecosystemBlunders: '(parameters (default_parameter value: (list) @mutable))' // Mutable default
50
- }
51
- },
52
- '.java': {
53
- grammarPath: '../../vendor/grammars/tree-sitter-java.wasm',
54
- extensions: ['.java'],
55
- queries: {
56
- complexity: '(if_statement) (for_statement) (while_statement) (switch_label)',
57
- nesting: '(if_statement (block (if_statement))) (for_statement (block (for_statement)))',
58
- parameters: '(formal_parameters (formal_parameter) @param)',
59
- methods: '(method_declaration) @method',
60
- securitySinks: '(method_declaration (modifiers (native))) @native (method_invocation name: (identifier) @name (#match? @name "^(exec|System\\.load)$"))',
61
- ecosystemBlunders: '(catch_clause body: (block . ))' // Empty catch
62
- }
63
- },
64
- '.rs': {
65
- grammarPath: '../../vendor/grammars/tree-sitter-rust.wasm',
66
- extensions: ['.rs'],
67
- queries: {
68
- complexity: '(if_expression) (for_expression) (while_expression) (loop_expression) (match_arm)',
69
- nesting: '(if_expression (block (if_expression))) (for_expression (block (for_expression)))',
70
- parameters: '(parameters (parameter) @param)',
71
- methods: '(impl_item (function_item)) @method (function_item) @method',
72
- securitySinks: '(unsafe_block) @unsafe',
73
- ecosystemBlunders: '(call_expression function: (field_expression field: (field_identifier) @id (#eq? @id "unwrap")))' // .unwrap()
74
- }
75
- },
76
- '.cs': {
77
- grammarPath: '../../vendor/grammars/tree-sitter-c_sharp.wasm',
78
- extensions: ['.cs'],
79
- queries: {
80
- complexity: '(if_statement) (for_statement) (foreach_statement) (while_statement) (switch_section)',
81
- nesting: '(if_statement (block (if_statement))) (for_statement (block (for_statement)))',
82
- parameters: '(parameter_list (parameter) @param)',
83
- methods: '(method_declaration) @method',
84
- securitySinks: '(attribute name: (identifier) @attr (#eq? @attr "DllImport")) @violation'
85
- }
86
- },
87
- '.cpp': {
88
- grammarPath: '../../vendor/grammars/tree-sitter-cpp.wasm',
89
- extensions: ['.cpp', '.cc', '.cxx', '.h', '.hpp'],
90
- queries: {
91
- complexity: '(if_statement) (for_statement) (while_statement) (case_statement)',
92
- nesting: '(if_statement (compound_statement (if_statement)))',
93
- parameters: '(parameter_list (parameter_declaration) @param)',
94
- methods: '(function_definition) @method',
95
- securitySinks: '(call_expression function: (identifier) @name (#match? @name "^(malloc|free|system|popen)$"))'
96
- }
97
- }
98
- };
99
-
100
- supports(file: string): boolean {
101
- const ext = path.extname(file).toLowerCase();
102
- return ext in this.languages;
103
- }
104
-
105
- async run(context: ASTHandlerContext): Promise<Failure[]> {
106
- const failures: Failure[] = [];
107
- const ext = path.extname(context.file).toLowerCase();
108
- const config = this.languages[ext];
109
- if (!config) return [];
110
-
111
- if (!this.parser) {
112
- await (Parser as any).init();
113
- this.parser = new (Parser as any)();
114
- }
115
-
116
- try {
117
- const Lang = await Parser.Language.load(path.resolve(__dirname, config.grammarPath));
118
- this.parser.setLanguage(Lang);
119
- const tree = this.parser.parse(context.content);
120
- const astConfig = this.config.ast || {};
121
-
122
- // 1. Structural Methods Audit
123
- const methodQuery = (Lang as any).query(config.queries.methods);
124
- const methodMatches = methodQuery.matches(tree.rootNode);
125
-
126
- for (const match of methodMatches) {
127
- for (const capture of match.captures) {
128
- const node = capture.node;
129
- const name = node.childForFieldName('name')?.text || 'anonymous';
130
-
131
- // SME: Cognitive Complexity (Nesting depth + Cyclomatic)
132
- const nesting = (Lang as any).query(config.queries.nesting).captures(node).length;
133
- const cyclomatic = (Lang as any).query(config.queries.complexity).captures(node).length + 1;
134
- const cognitive = cyclomatic + (nesting * 2);
135
-
136
- if (cognitive > (astConfig.complexity || 10)) {
137
- failures.push({
138
- id: 'SME_COGNITIVE_LOAD',
139
- title: `Method '${name}' has high cognitive load (${cognitive})`,
140
- details: `Deeply nested or complex logic detected in ${context.file}.`,
141
- files: [context.file],
142
- hint: `Flatten logical branches and extract nested loops.`
143
- });
144
- }
145
- }
146
- }
147
-
148
- // 2. Security Sinks
149
- if (config.queries.securitySinks) {
150
- const securityQuery = (Lang as any).query(config.queries.securitySinks);
151
- const sinks = securityQuery.captures(tree.rootNode);
152
- for (const capture of sinks) {
153
- failures.push({
154
- id: 'SME_SECURITY_SINK',
155
- title: `Unsafe function call detected: ${capture.node.text}`,
156
- details: `Potentially dangerous execution in ${context.file}.`,
157
- files: [context.file],
158
- hint: `Avoid using shell execution or eval. Use safe alternatives.`
159
- });
160
- }
161
- }
162
-
163
- // 3. Ecosystem Blunders
164
- if (config.queries.ecosystemBlunders) {
165
- const blunderQuery = (Lang as any).query(config.queries.ecosystemBlunders);
166
- const blunders = blunderQuery.captures(tree.rootNode);
167
- for (const capture of blunders) {
168
- failures.push({
169
- id: 'SME_BEST_PRACTICE',
170
- title: `Ecosystem anti-pattern detected`,
171
- details: `Violation of ${ext} best practices in ${context.file}.`,
172
- files: [context.file],
173
- hint: `Review language-specific best practices (e.g., error handling or mutable defaults).`
174
- });
175
- }
176
- }
177
-
178
- } catch (e) {
179
- // Parser skip
180
- }
181
-
182
- return failures;
183
- }
184
- }
package/src/gates/ast.ts DELETED
@@ -1,54 +0,0 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
- import { globby } from 'globby';
4
- import { Gate, GateContext } from './base.js';
5
- import { Failure, Gates } from '../types/index.js';
6
- import { ASTHandler } from './ast-handlers/base.js';
7
- import { TypeScriptHandler } from './ast-handlers/typescript.js';
8
- import { PythonHandler } from './ast-handlers/python.js';
9
- import { UniversalASTHandler } from './ast-handlers/universal.js';
10
-
11
- export class ASTGate extends Gate {
12
- private handlers: ASTHandler[] = [];
13
-
14
- constructor(private config: Gates) {
15
- super('ast-analysis', 'AST Structural Analysis');
16
- this.handlers.push(new TypeScriptHandler(config));
17
- this.handlers.push(new PythonHandler(config));
18
- this.handlers.push(new UniversalASTHandler(config));
19
- }
20
-
21
- async run(context: GateContext): Promise<Failure[]> {
22
- const failures: Failure[] = [];
23
-
24
- const patterns = (context.patterns || ['**/*.{ts,js,tsx,jsx,py,go,rs,cs,java,rb,c,cpp,php,swift,kt}']).map(p => p.replace(/\\/g, '/'));
25
- const ignore = (context.ignore || ['**/node_modules/**', '**/dist/**', '**/build/**', '**/*.test.*', '**/*.spec.*', '**/__pycache__/**']).map(p => p.replace(/\\/g, '/'));
26
- const normalizedCwd = context.cwd.replace(/\\/g, '/');
27
-
28
- // Find all supported files
29
- const files = await globby(patterns, {
30
- cwd: normalizedCwd,
31
- ignore: ignore,
32
- });
33
-
34
- for (const file of files) {
35
- const handler = this.handlers.find(h => h.supports(file));
36
- if (!handler) continue;
37
-
38
- const fullPath = path.join(context.cwd, file);
39
- try {
40
- const content = await fs.readFile(fullPath, 'utf-8');
41
- const gateFailures = await handler.run({
42
- cwd: context.cwd,
43
- file: file,
44
- content
45
- });
46
- failures.push(...gateFailures);
47
- } catch (error: any) {
48
- // Individual file read failures shouldn't crash the whole run
49
- }
50
- }
51
-
52
- return failures;
53
- }
54
- }
package/src/gates/base.ts DELETED
@@ -1,28 +0,0 @@
1
- import { GoldenRecord } from '../services/context-engine.js';
2
- import { Failure, Severity } from '../types/index.js';
3
-
4
- export interface GateContext {
5
- cwd: string;
6
- record?: GoldenRecord;
7
- ignore?: string[];
8
- patterns?: string[];
9
- }
10
-
11
- export abstract class Gate {
12
- constructor(public readonly id: string, public readonly title: string) { }
13
-
14
- abstract run(context: GateContext): Promise<Failure[]>;
15
-
16
- protected createFailure(details: string, files?: string[], hint?: string, title?: string, line?: number, endLine?: number, severity?: Severity): Failure {
17
- return {
18
- id: this.id,
19
- title: title || this.title,
20
- details,
21
- severity: severity || 'medium',
22
- files,
23
- line,
24
- endLine,
25
- hint,
26
- };
27
- }
28
- }
@@ -1,135 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import {
3
- CheckpointGate,
4
- recordCheckpoint,
5
- getCheckpointSession,
6
- clearCheckpointSession,
7
- getOrCreateCheckpointSession,
8
- completeCheckpointSession,
9
- abortCheckpointSession
10
- } from './checkpoint.js';
11
- import * as fs from 'fs';
12
- import * as path from 'path';
13
- import * as os from 'os';
14
-
15
- describe('CheckpointGate', () => {
16
- let testDir: string;
17
-
18
- beforeEach(() => {
19
- testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'checkpoint-test-'));
20
- });
21
-
22
- afterEach(() => {
23
- clearCheckpointSession(testDir);
24
- fs.rmSync(testDir, { recursive: true, force: true });
25
- });
26
-
27
- describe('gate initialization', () => {
28
- it('should create gate with default config', () => {
29
- const gate = new CheckpointGate();
30
- expect(gate.id).toBe('checkpoint');
31
- expect(gate.title).toBe('Checkpoint Supervision');
32
- });
33
-
34
- it('should skip when not enabled', async () => {
35
- const gate = new CheckpointGate({ enabled: false });
36
- const failures = await gate.run({ cwd: testDir });
37
- expect(failures).toEqual([]);
38
- });
39
- });
40
-
41
- describe('session management', () => {
42
- it('should create a new session', () => {
43
- const session = getOrCreateCheckpointSession(testDir);
44
- expect(session.sessionId).toMatch(/^chk-session-/);
45
- expect(session.status).toBe('active');
46
- expect(session.checkpoints).toHaveLength(0);
47
- });
48
-
49
- it('should record a checkpoint', () => {
50
- const result = recordCheckpoint(
51
- testDir,
52
- 25, // progressPct
53
- ['src/api/users.ts'],
54
- 'Implemented user API',
55
- 85 // qualityScore
56
- );
57
-
58
- expect(result.continue).toBe(true);
59
- expect(result.checkpoint.progressPct).toBe(25);
60
- expect(result.checkpoint.qualityScore).toBe(85);
61
- });
62
-
63
- it('should persist session to disk', () => {
64
- recordCheckpoint(testDir, 50, [], 'Test', 90);
65
- const sessionPath = path.join(testDir, '.rigour', 'checkpoint-session.json');
66
- expect(fs.existsSync(sessionPath)).toBe(true);
67
- });
68
-
69
- it('should complete session', () => {
70
- getOrCreateCheckpointSession(testDir);
71
- completeCheckpointSession(testDir);
72
- const session = getCheckpointSession(testDir);
73
- expect(session?.status).toBe('completed');
74
- });
75
-
76
- it('should abort session with reason', () => {
77
- getOrCreateCheckpointSession(testDir);
78
- abortCheckpointSession(testDir, 'Quality too low');
79
- const session = getCheckpointSession(testDir);
80
- expect(session?.status).toBe('aborted');
81
- expect(session?.checkpoints[0].summary).toContain('Quality too low');
82
- });
83
- });
84
-
85
- describe('quality threshold', () => {
86
- it('should continue when quality above threshold', () => {
87
- const result = recordCheckpoint(testDir, 50, [], 'Good work', 85);
88
- expect(result.continue).toBe(true);
89
- expect(result.warnings).toHaveLength(0);
90
- });
91
-
92
- it('should stop when quality below threshold', () => {
93
- const result = recordCheckpoint(testDir, 50, [], 'Poor work', 70);
94
- expect(result.continue).toBe(false);
95
- expect(result.warnings).toContain('Quality score 70% is below threshold 80%');
96
- });
97
- });
98
-
99
- describe('drift detection', () => {
100
- it('should detect quality degradation', () => {
101
- // Record several checkpoints with declining quality
102
- recordCheckpoint(testDir, 20, [], 'Start', 95);
103
- recordCheckpoint(testDir, 40, [], 'Middle', 90);
104
- const result = recordCheckpoint(testDir, 60, [], 'Decline', 75);
105
-
106
- expect(result.warnings.some(w => w.includes('Drift detected'))).toBe(true);
107
- });
108
-
109
- it('should not flag stable quality', () => {
110
- recordCheckpoint(testDir, 20, [], 'Start', 85);
111
- recordCheckpoint(testDir, 40, [], 'Middle', 85);
112
- const result = recordCheckpoint(testDir, 60, [], 'Stable', 85);
113
-
114
- expect(result.warnings.filter(w => w.includes('Drift'))).toHaveLength(0);
115
- });
116
- });
117
-
118
- describe('gate run', () => {
119
- it('should pass with healthy checkpoints', async () => {
120
- const gate = new CheckpointGate({ enabled: true, quality_threshold: 80 });
121
- recordCheckpoint(testDir, 50, [], 'Good work', 90);
122
-
123
- const failures = await gate.run({ cwd: testDir });
124
- expect(failures).toHaveLength(0);
125
- });
126
-
127
- it('should fail when quality below threshold', async () => {
128
- const gate = new CheckpointGate({ enabled: true, quality_threshold: 80 });
129
- recordCheckpoint(testDir, 50, [], 'Poor work', 70);
130
-
131
- const failures = await gate.run({ cwd: testDir });
132
- expect(failures.some(f => f.title === 'Quality Below Threshold')).toBe(true);
133
- });
134
- });
135
- });