@rigour-labs/core 1.0.0 → 1.4.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/LICENSE +1 -1
- package/dist/discovery.d.ts +18 -2
- package/dist/discovery.js +62 -10
- package/dist/gates/ast.d.ts +10 -0
- package/dist/gates/ast.js +124 -0
- package/dist/gates/dependency.d.ts +7 -0
- package/dist/gates/dependency.js +43 -0
- package/dist/gates/runner.js +6 -0
- package/dist/gates/safety.d.ts +8 -0
- package/dist/gates/safety.js +47 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -0
- package/dist/services/fix-packet-service.d.ts +6 -0
- package/dist/services/fix-packet-service.js +43 -0
- package/dist/templates/index.d.ts +9 -2
- package/dist/templates/index.js +115 -29
- package/dist/types/fix-packet.d.ts +112 -0
- package/dist/types/fix-packet.js +32 -0
- package/dist/types/index.d.ts +249 -0
- package/dist/types/index.js +23 -0
- package/package.json +5 -2
- package/src/discovery.ts +76 -12
- package/src/gates/ast.ts +150 -0
- package/src/gates/dependency.ts +44 -0
- package/src/gates/runner.ts +6 -0
- package/src/gates/safety.ts +49 -0
- package/src/index.ts +3 -0
- package/src/services/fix-packet-service.ts +42 -0
- package/src/templates/index.ts +123 -30
- package/src/types/fix-packet.ts +32 -0
- package/src/types/index.ts +23 -0
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026 Rigour
|
|
3
|
+
Copyright (c) 2026 Ashutosh (https://github.com/erashu212), Rigour Labs.
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/dist/discovery.d.ts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { Config } from './types/index.js';
|
|
2
|
+
export interface DiscoveryResult {
|
|
3
|
+
config: Config;
|
|
4
|
+
matches: {
|
|
5
|
+
preset?: {
|
|
6
|
+
name: string;
|
|
7
|
+
marker: string;
|
|
8
|
+
};
|
|
9
|
+
paradigm?: {
|
|
10
|
+
name: string;
|
|
11
|
+
marker: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
}
|
|
2
15
|
export declare class DiscoveryService {
|
|
3
|
-
discover(cwd: string): Promise<
|
|
4
|
-
private
|
|
16
|
+
discover(cwd: string): Promise<DiscoveryResult>;
|
|
17
|
+
private mergeConfig;
|
|
18
|
+
private findFirstMarker;
|
|
19
|
+
private existsInContent;
|
|
20
|
+
private findSourceFiles;
|
|
5
21
|
}
|
package/dist/discovery.js
CHANGED
|
@@ -9,24 +9,76 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const index_js_1 = require("./templates/index.js");
|
|
10
10
|
class DiscoveryService {
|
|
11
11
|
async discover(cwd) {
|
|
12
|
-
|
|
12
|
+
let config = { ...index_js_1.UNIVERSAL_CONFIG };
|
|
13
|
+
const matches = {};
|
|
14
|
+
// 1. Detect Role (ui, api, infra, data)
|
|
13
15
|
for (const template of index_js_1.TEMPLATES) {
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const marker = await this.findFirstMarker(cwd, template.markers, true); // Search content for roles too
|
|
17
|
+
if (marker) {
|
|
18
|
+
config = this.mergeConfig(config, template.config);
|
|
19
|
+
matches.preset = { name: template.name, marker };
|
|
20
|
+
break; // Only one role for now
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
|
-
|
|
23
|
+
// 2. Detect Paradigm (oop, functional)
|
|
24
|
+
for (const template of index_js_1.PARADIGM_TEMPLATES) {
|
|
25
|
+
const marker = await this.findFirstMarker(cwd, template.markers, true); // Search content
|
|
26
|
+
if (marker) {
|
|
27
|
+
config = this.mergeConfig(config, template.config);
|
|
28
|
+
matches.paradigm = { name: template.name, marker };
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return { config, matches };
|
|
33
|
+
}
|
|
34
|
+
mergeConfig(base, extension) {
|
|
35
|
+
return {
|
|
36
|
+
...base,
|
|
37
|
+
preset: extension.preset || base.preset,
|
|
38
|
+
paradigm: extension.paradigm || base.paradigm,
|
|
39
|
+
commands: { ...base.commands, ...extension.commands },
|
|
40
|
+
gates: { ...base.gates, ...extension.gates },
|
|
41
|
+
};
|
|
22
42
|
}
|
|
23
|
-
async
|
|
43
|
+
async findFirstMarker(cwd, markers, searchContent = false) {
|
|
24
44
|
for (const marker of markers) {
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
const fullPath = path_1.default.join(cwd, marker);
|
|
46
|
+
// File/Directory existence check
|
|
47
|
+
if (await fs_extra_1.default.pathExists(fullPath)) {
|
|
48
|
+
return marker;
|
|
49
|
+
}
|
|
50
|
+
// Deep content check for paradigms
|
|
51
|
+
if (searchContent) {
|
|
52
|
+
const match = await this.existsInContent(cwd, marker);
|
|
53
|
+
if (match)
|
|
54
|
+
return `content:${marker}`;
|
|
27
55
|
}
|
|
28
56
|
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
async existsInContent(cwd, pattern) {
|
|
60
|
+
// Simple heuristic: search in top 5 source files
|
|
61
|
+
const files = await this.findSourceFiles(cwd);
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
const content = await fs_extra_1.default.readFile(file, 'utf-8');
|
|
64
|
+
if (content.includes(pattern))
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
29
67
|
return false;
|
|
30
68
|
}
|
|
69
|
+
async findSourceFiles(cwd) {
|
|
70
|
+
// Find a few files to sample
|
|
71
|
+
const extensions = ['.ts', '.js', '.py', '.go', '.java', '.tf', 'package.json'];
|
|
72
|
+
const samples = [];
|
|
73
|
+
const files = await fs_extra_1.default.readdir(cwd);
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
if (extensions.some(ext => file.endsWith(ext))) {
|
|
76
|
+
samples.push(path_1.default.join(cwd, file));
|
|
77
|
+
if (samples.length >= 5)
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return samples;
|
|
82
|
+
}
|
|
31
83
|
}
|
|
32
84
|
exports.DiscoveryService = DiscoveryService;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Gate, GateContext } from './base.js';
|
|
2
|
+
import { Failure, Gates } from '../types/index.js';
|
|
3
|
+
export declare class ASTGate extends Gate {
|
|
4
|
+
private config;
|
|
5
|
+
constructor(config: Gates);
|
|
6
|
+
run(context: GateContext): Promise<Failure[]>;
|
|
7
|
+
private analyzeSourceFile;
|
|
8
|
+
private checkBoundary;
|
|
9
|
+
private getNodeName;
|
|
10
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
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.ASTGate = void 0;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const globby_1 = require("globby");
|
|
11
|
+
const base_js_1 = require("./base.js");
|
|
12
|
+
const micromatch_1 = __importDefault(require("micromatch"));
|
|
13
|
+
class ASTGate extends base_js_1.Gate {
|
|
14
|
+
config;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
super('ast-analysis', 'AST Structural Analysis');
|
|
17
|
+
this.config = config;
|
|
18
|
+
}
|
|
19
|
+
async run(context) {
|
|
20
|
+
const failures = [];
|
|
21
|
+
const files = await (0, globby_1.globby)(['**/*.{ts,js,tsx,jsx}'], {
|
|
22
|
+
cwd: context.cwd,
|
|
23
|
+
ignore: ['node_modules/**', 'dist/**', 'build/**', '**/*.test.*', '**/*.spec.*'],
|
|
24
|
+
});
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
const fullPath = path_1.default.join(context.cwd, file);
|
|
27
|
+
const content = await fs_extra_1.default.readFile(fullPath, 'utf-8');
|
|
28
|
+
const sourceFile = typescript_1.default.createSourceFile(file, content, typescript_1.default.ScriptTarget.Latest, true);
|
|
29
|
+
this.analyzeSourceFile(sourceFile, file, failures);
|
|
30
|
+
}
|
|
31
|
+
return failures;
|
|
32
|
+
}
|
|
33
|
+
analyzeSourceFile(sourceFile, relativePath, failures) {
|
|
34
|
+
const astConfig = this.config.ast || {};
|
|
35
|
+
const maxComplexity = astConfig.complexity || 10;
|
|
36
|
+
const maxMethods = astConfig.max_methods || 10;
|
|
37
|
+
const maxParams = astConfig.max_params || 5;
|
|
38
|
+
const visit = (node) => {
|
|
39
|
+
// 1. Complexity & Params for functions
|
|
40
|
+
if (typescript_1.default.isFunctionDeclaration(node) || typescript_1.default.isMethodDeclaration(node) || typescript_1.default.isArrowFunction(node)) {
|
|
41
|
+
const name = this.getNodeName(node);
|
|
42
|
+
// Parameter count
|
|
43
|
+
if (node.parameters.length > maxParams) {
|
|
44
|
+
failures.push(this.createFailure(`Function '${name}' has ${node.parameters.length} parameters (max: ${maxParams})`, [relativePath], `Reduce number of parameters or use an options object.`));
|
|
45
|
+
// Update: Failures in Runner will be mapped to FixPacket
|
|
46
|
+
failures[failures.length - 1].metrics = { count: node.parameters.length, max: maxParams };
|
|
47
|
+
}
|
|
48
|
+
// Cyclomatic Complexity (Simplified: nodes that cause branching)
|
|
49
|
+
let complexity = 1;
|
|
50
|
+
const countComplexity = (n) => {
|
|
51
|
+
if (typescript_1.default.isIfStatement(n) || typescript_1.default.isCaseClause(n) || typescript_1.default.isDefaultClause(n) ||
|
|
52
|
+
typescript_1.default.isForStatement(n) || typescript_1.default.isForInStatement(n) || typescript_1.default.isForOfStatement(n) ||
|
|
53
|
+
typescript_1.default.isWhileStatement(n) || typescript_1.default.isDoStatement(n) || typescript_1.default.isConditionalExpression(n)) {
|
|
54
|
+
complexity++;
|
|
55
|
+
}
|
|
56
|
+
if (typescript_1.default.isBinaryExpression(n)) {
|
|
57
|
+
if (n.operatorToken.kind === typescript_1.default.SyntaxKind.AmpersandAmpersandToken ||
|
|
58
|
+
n.operatorToken.kind === typescript_1.default.SyntaxKind.BarBarToken) {
|
|
59
|
+
complexity++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
typescript_1.default.forEachChild(n, countComplexity);
|
|
63
|
+
};
|
|
64
|
+
typescript_1.default.forEachChild(node, countComplexity);
|
|
65
|
+
if (complexity > maxComplexity) {
|
|
66
|
+
failures.push(this.createFailure(`Function '${name}' has cyclomatic complexity of ${complexity} (max: ${maxComplexity})`, [relativePath], `Refactor '${name}' into smaller, more focused functions.`));
|
|
67
|
+
failures[failures.length - 1].metrics = { complexity, max: maxComplexity };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// 2. Class metrics
|
|
71
|
+
if (typescript_1.default.isClassDeclaration(node)) {
|
|
72
|
+
const name = node.name?.text || 'Anonymous Class';
|
|
73
|
+
const methods = node.members.filter(typescript_1.default.isMethodDeclaration);
|
|
74
|
+
if (methods.length > maxMethods) {
|
|
75
|
+
failures.push(this.createFailure(`Class '${name}' has ${methods.length} methods (max: ${maxMethods})`, [relativePath], `Class '${name}' is becoming a 'God Object'. Split it into smaller services.`));
|
|
76
|
+
failures[failures.length - 1].metrics = { methodCount: methods.length, max: maxMethods };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// 3. Import check for Layer Boundaries
|
|
80
|
+
if (typescript_1.default.isImportDeclaration(node)) {
|
|
81
|
+
const importPath = node.moduleSpecifier.text;
|
|
82
|
+
this.checkBoundary(importPath, relativePath, failures);
|
|
83
|
+
}
|
|
84
|
+
typescript_1.default.forEachChild(node, visit);
|
|
85
|
+
};
|
|
86
|
+
typescript_1.default.forEachChild(sourceFile, visit);
|
|
87
|
+
}
|
|
88
|
+
checkBoundary(importPath, relativePath, failures) {
|
|
89
|
+
const boundaries = this.config.architecture?.boundaries || [];
|
|
90
|
+
if (boundaries.length === 0)
|
|
91
|
+
return;
|
|
92
|
+
for (const rule of boundaries) {
|
|
93
|
+
const isFromMatch = micromatch_1.default.isMatch(relativePath, rule.from);
|
|
94
|
+
if (isFromMatch) {
|
|
95
|
+
// Approximate resolution (simplified for now)
|
|
96
|
+
// Real implementation would need to handle alias and absolute path resolution
|
|
97
|
+
const resolved = importPath.startsWith('.')
|
|
98
|
+
? path_1.default.join(path_1.default.dirname(relativePath), importPath)
|
|
99
|
+
: importPath;
|
|
100
|
+
const isToMatch = micromatch_1.default.isMatch(resolved, rule.to);
|
|
101
|
+
if (rule.mode === 'deny' && isToMatch) {
|
|
102
|
+
failures.push(this.createFailure(`Architectural Violation: '${relativePath}' is forbidden from importing '${importPath}' (denied by boundary rule).`, [relativePath], `Remove this import to maintain architectural layering.`));
|
|
103
|
+
}
|
|
104
|
+
else if (rule.mode === 'allow' && !isToMatch && importPath.startsWith('.')) {
|
|
105
|
+
// Complexity: Allow rules are trickier to implement strictly without full resolution
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
getNodeName(node) {
|
|
111
|
+
if (typescript_1.default.isFunctionDeclaration(node) || typescript_1.default.isMethodDeclaration(node)) {
|
|
112
|
+
return node.name?.getText() || 'anonymous';
|
|
113
|
+
}
|
|
114
|
+
if (typescript_1.default.isArrowFunction(node)) {
|
|
115
|
+
const parent = node.parent;
|
|
116
|
+
if (typescript_1.default.isVariableDeclaration(parent)) {
|
|
117
|
+
return parent.name.getText();
|
|
118
|
+
}
|
|
119
|
+
return 'anonymous arrow';
|
|
120
|
+
}
|
|
121
|
+
return 'unknown';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.ASTGate = ASTGate;
|
|
@@ -0,0 +1,43 @@
|
|
|
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.DependencyGate = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const base_js_1 = require("./base.js");
|
|
10
|
+
class DependencyGate extends base_js_1.Gate {
|
|
11
|
+
config;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
super('dependency-guardian', 'Dependency Guardian');
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
async run(context) {
|
|
17
|
+
const failures = [];
|
|
18
|
+
const forbidden = this.config.gates.dependencies?.forbid || [];
|
|
19
|
+
if (forbidden.length === 0)
|
|
20
|
+
return [];
|
|
21
|
+
const { cwd } = context;
|
|
22
|
+
// 1. Scan Node.js (package.json)
|
|
23
|
+
const pkgPath = path_1.default.join(cwd, 'package.json');
|
|
24
|
+
if (await fs_extra_1.default.pathExists(pkgPath)) {
|
|
25
|
+
try {
|
|
26
|
+
const pkg = await fs_extra_1.default.readJson(pkgPath);
|
|
27
|
+
const allDeps = {
|
|
28
|
+
...(pkg.dependencies || {}),
|
|
29
|
+
...(pkg.devDependencies || {}),
|
|
30
|
+
...(pkg.peerDependencies || {}),
|
|
31
|
+
};
|
|
32
|
+
for (const dep of forbidden) {
|
|
33
|
+
if (allDeps[dep]) {
|
|
34
|
+
failures.push(this.createFailure(`The package '${dep}' is forbidden by project standards.`, ['package.json'], `Remove '${dep}' from package.json and use approved alternatives.`));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (e) { }
|
|
39
|
+
}
|
|
40
|
+
return failures;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.DependencyGate = DependencyGate;
|
package/dist/gates/runner.js
CHANGED
|
@@ -4,6 +4,9 @@ exports.GateRunner = void 0;
|
|
|
4
4
|
const file_js_1 = require("./file.js");
|
|
5
5
|
const content_js_1 = require("./content.js");
|
|
6
6
|
const structure_js_1 = require("./structure.js");
|
|
7
|
+
const ast_js_1 = require("./ast.js");
|
|
8
|
+
const safety_js_1 = require("./safety.js");
|
|
9
|
+
const dependency_js_1 = require("./dependency.js");
|
|
7
10
|
const execa_1 = require("execa");
|
|
8
11
|
const logger_js_1 = require("../utils/logger.js");
|
|
9
12
|
class GateRunner {
|
|
@@ -24,6 +27,9 @@ class GateRunner {
|
|
|
24
27
|
if (this.config.gates.required_files) {
|
|
25
28
|
this.gates.push(new structure_js_1.StructureGate({ requiredFiles: this.config.gates.required_files }));
|
|
26
29
|
}
|
|
30
|
+
this.gates.push(new ast_js_1.ASTGate(this.config.gates));
|
|
31
|
+
this.gates.push(new dependency_js_1.DependencyGate(this.config));
|
|
32
|
+
this.gates.push(new safety_js_1.SafetyGate(this.config.gates));
|
|
27
33
|
}
|
|
28
34
|
/**
|
|
29
35
|
* Allows adding custom gates dynamically (SOLID - Open/Closed Principle)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Gate, GateContext } from './base.js';
|
|
2
|
+
import { Failure, Gates } from '../types/index.js';
|
|
3
|
+
export declare class SafetyGate extends Gate {
|
|
4
|
+
private config;
|
|
5
|
+
constructor(config: Gates);
|
|
6
|
+
run(context: GateContext): Promise<Failure[]>;
|
|
7
|
+
private isProtected;
|
|
8
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SafetyGate = void 0;
|
|
4
|
+
const base_js_1 = require("./base.js");
|
|
5
|
+
const execa_1 = require("execa");
|
|
6
|
+
class SafetyGate extends base_js_1.Gate {
|
|
7
|
+
config;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
super('safety-rail', 'Safety & Protection Rails');
|
|
10
|
+
this.config = config;
|
|
11
|
+
}
|
|
12
|
+
async run(context) {
|
|
13
|
+
const failures = [];
|
|
14
|
+
const safety = this.config.safety || {};
|
|
15
|
+
const protectedPaths = safety.protected_paths || [];
|
|
16
|
+
if (protectedPaths.length === 0)
|
|
17
|
+
return [];
|
|
18
|
+
try {
|
|
19
|
+
// Check for modified files in protected paths using git
|
|
20
|
+
// This is a "Safety Rail" - if an agent touched these, we fail.
|
|
21
|
+
const { stdout } = await (0, execa_1.execa)('git', ['status', '--porcelain'], { cwd: context.cwd });
|
|
22
|
+
const modifiedFiles = stdout.split('\n')
|
|
23
|
+
.filter(line => line.trim().length > 0)
|
|
24
|
+
.map(line => line.slice(3));
|
|
25
|
+
for (const file of modifiedFiles) {
|
|
26
|
+
if (this.isProtected(file, protectedPaths)) {
|
|
27
|
+
failures.push(this.createFailure(`Protected file '${file}' was modified.`, [file], `Agents are forbidden from modifying files in ${protectedPaths.join(', ')}.`));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
// If not a git repo, skip safety for now
|
|
33
|
+
}
|
|
34
|
+
return failures;
|
|
35
|
+
}
|
|
36
|
+
isProtected(file, patterns) {
|
|
37
|
+
return patterns.some(p => {
|
|
38
|
+
const cleanP = p.replace('/**', '').replace('/*', '');
|
|
39
|
+
if (file === cleanP)
|
|
40
|
+
return true;
|
|
41
|
+
if (cleanP.endsWith('/'))
|
|
42
|
+
return file.startsWith(cleanP);
|
|
43
|
+
return file.startsWith(cleanP + '/');
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.SafetyGate = SafetyGate;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from './types/index.js';
|
|
2
2
|
export * from './gates/runner.js';
|
|
3
3
|
export * from './discovery.js';
|
|
4
|
+
export * from './services/fix-packet-service.js';
|
|
4
5
|
export * from './templates/index.js';
|
|
6
|
+
export * from './types/fix-packet.js';
|
|
7
|
+
export { Gate, GateContext } from './gates/base.js';
|
|
5
8
|
export * from './utils/logger.js';
|
package/dist/index.js
CHANGED
|
@@ -14,8 +14,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Gate = void 0;
|
|
17
18
|
__exportStar(require("./types/index.js"), exports);
|
|
18
19
|
__exportStar(require("./gates/runner.js"), exports);
|
|
19
20
|
__exportStar(require("./discovery.js"), exports);
|
|
21
|
+
__exportStar(require("./services/fix-packet-service.js"), exports);
|
|
20
22
|
__exportStar(require("./templates/index.js"), exports);
|
|
23
|
+
__exportStar(require("./types/fix-packet.js"), exports);
|
|
24
|
+
var base_js_1 = require("./gates/base.js");
|
|
25
|
+
Object.defineProperty(exports, "Gate", { enumerable: true, get: function () { return base_js_1.Gate; } });
|
|
21
26
|
__exportStar(require("./utils/logger.js"), exports);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FixPacketService = void 0;
|
|
4
|
+
const fix_packet_js_1 = require("../types/fix-packet.js");
|
|
5
|
+
class FixPacketService {
|
|
6
|
+
generate(report, config) {
|
|
7
|
+
const violations = report.failures.map(f => ({
|
|
8
|
+
id: f.id,
|
|
9
|
+
gate: f.id,
|
|
10
|
+
severity: this.inferSeverity(f),
|
|
11
|
+
title: f.title,
|
|
12
|
+
details: f.details,
|
|
13
|
+
files: f.files,
|
|
14
|
+
hint: f.hint,
|
|
15
|
+
instructions: f.hint ? [f.hint] : [], // Use hint as first instruction
|
|
16
|
+
metrics: f.metrics,
|
|
17
|
+
}));
|
|
18
|
+
const packet = {
|
|
19
|
+
version: 2,
|
|
20
|
+
goal: "Achieve PASS state by resolving all listed engineering violations.",
|
|
21
|
+
violations,
|
|
22
|
+
constraints: {
|
|
23
|
+
paradigm: config.paradigm,
|
|
24
|
+
protected_paths: config.gates.safety?.protected_paths,
|
|
25
|
+
do_not_touch: config.gates.safety?.protected_paths,
|
|
26
|
+
max_files_changed: config.gates.safety?.max_files_changed_per_cycle,
|
|
27
|
+
no_new_deps: true,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
return fix_packet_js_1.FixPacketV2Schema.parse(packet);
|
|
31
|
+
}
|
|
32
|
+
inferSeverity(f) {
|
|
33
|
+
// High complexity or God objects are usually High severity
|
|
34
|
+
if (f.id === 'ast-analysis')
|
|
35
|
+
return 'high';
|
|
36
|
+
// Unit test or Lint failures are Medium
|
|
37
|
+
if (f.id === 'test' || f.id === 'lint')
|
|
38
|
+
return 'medium';
|
|
39
|
+
// Documentation or small file size issues are Low
|
|
40
|
+
return 'medium';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.FixPacketService = FixPacketService;
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import { Config } from '../types/index.js';
|
|
1
|
+
import { Config, Commands, Gates } from '../types/index.js';
|
|
2
2
|
export interface Template {
|
|
3
3
|
name: string;
|
|
4
4
|
markers: string[];
|
|
5
|
-
config:
|
|
5
|
+
config: {
|
|
6
|
+
preset?: string;
|
|
7
|
+
paradigm?: string;
|
|
8
|
+
commands?: Partial<Commands>;
|
|
9
|
+
gates?: Partial<Gates>;
|
|
10
|
+
planned?: string[];
|
|
11
|
+
};
|
|
6
12
|
}
|
|
7
13
|
export declare const TEMPLATES: Template[];
|
|
14
|
+
export declare const PARADIGM_TEMPLATES: Template[];
|
|
8
15
|
export declare const UNIVERSAL_CONFIG: Config;
|
package/dist/templates/index.js
CHANGED
|
@@ -1,55 +1,125 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UNIVERSAL_CONFIG = exports.TEMPLATES = void 0;
|
|
3
|
+
exports.UNIVERSAL_CONFIG = exports.PARADIGM_TEMPLATES = exports.TEMPLATES = void 0;
|
|
4
4
|
exports.TEMPLATES = [
|
|
5
5
|
{
|
|
6
|
-
name: '
|
|
7
|
-
markers: [
|
|
6
|
+
name: 'ui',
|
|
7
|
+
markers: [
|
|
8
|
+
'react',
|
|
9
|
+
'next',
|
|
10
|
+
'vue',
|
|
11
|
+
'svelte',
|
|
12
|
+
'next.config.js',
|
|
13
|
+
'vite.config.ts',
|
|
14
|
+
'tailwind.config.js',
|
|
15
|
+
'base.css',
|
|
16
|
+
'index.html',
|
|
17
|
+
],
|
|
8
18
|
config: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
preset: 'ui',
|
|
20
|
+
gates: {
|
|
21
|
+
max_file_lines: 300,
|
|
22
|
+
required_files: ['docs/SPEC.md', 'docs/ARCH.md', 'README.md'],
|
|
12
23
|
},
|
|
24
|
+
planned: [
|
|
25
|
+
'Layer Boundary: Components cannot import from DB',
|
|
26
|
+
'Prop-Drilling Detection: Max depth 5',
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'api',
|
|
32
|
+
markers: [
|
|
33
|
+
'express',
|
|
34
|
+
'fastify',
|
|
35
|
+
'nestjs',
|
|
36
|
+
'go.mod',
|
|
37
|
+
'requirements.txt',
|
|
38
|
+
'pyproject.toml',
|
|
39
|
+
'app.py',
|
|
40
|
+
'main.go',
|
|
41
|
+
'index.js',
|
|
42
|
+
],
|
|
43
|
+
config: {
|
|
44
|
+
preset: 'api',
|
|
13
45
|
gates: {
|
|
14
|
-
max_file_lines:
|
|
15
|
-
forbid_todos: true,
|
|
16
|
-
forbid_fixme: true,
|
|
17
|
-
forbid_paths: [],
|
|
46
|
+
max_file_lines: 400,
|
|
18
47
|
required_files: ['docs/SPEC.md', 'docs/ARCH.md', 'README.md'],
|
|
19
48
|
},
|
|
49
|
+
planned: [
|
|
50
|
+
'Service Layer Enforcement: Controllers -> Services only',
|
|
51
|
+
'Repo Pattern: Databases access isolated to repositories/',
|
|
52
|
+
],
|
|
20
53
|
},
|
|
21
54
|
},
|
|
22
55
|
{
|
|
23
|
-
name: '
|
|
24
|
-
markers: [
|
|
56
|
+
name: 'infra',
|
|
57
|
+
markers: [
|
|
58
|
+
'Dockerfile',
|
|
59
|
+
'docker-compose.yml',
|
|
60
|
+
'main.tf',
|
|
61
|
+
'k8s/',
|
|
62
|
+
'helm/',
|
|
63
|
+
'ansible/',
|
|
64
|
+
],
|
|
25
65
|
config: {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
66
|
+
preset: 'infra',
|
|
67
|
+
gates: {
|
|
68
|
+
max_file_lines: 300,
|
|
69
|
+
required_files: ['docs/RUNBOOK.md', 'docs/ARCH.md', 'README.md'],
|
|
29
70
|
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'data',
|
|
75
|
+
markers: [
|
|
76
|
+
'ipynb',
|
|
77
|
+
'spark',
|
|
78
|
+
'pandas',
|
|
79
|
+
'data/',
|
|
80
|
+
'dbt_project.yml',
|
|
81
|
+
],
|
|
82
|
+
config: {
|
|
83
|
+
preset: 'data',
|
|
30
84
|
gates: {
|
|
31
85
|
max_file_lines: 500,
|
|
32
|
-
|
|
33
|
-
forbid_fixme: true,
|
|
34
|
-
forbid_paths: [],
|
|
35
|
-
required_files: ['docs/SPEC.md', 'docs/ARCH.md', 'README.md'],
|
|
86
|
+
required_files: ['docs/DATA_DICTIONARY.md', 'docs/PIPELINE.md', 'README.md'],
|
|
36
87
|
},
|
|
88
|
+
planned: [
|
|
89
|
+
'Stochastic Determinism: Seed setting enforcement',
|
|
90
|
+
'Data Leaks: Detecting PII in notebook outputs',
|
|
91
|
+
],
|
|
37
92
|
},
|
|
38
93
|
},
|
|
94
|
+
];
|
|
95
|
+
exports.PARADIGM_TEMPLATES = [
|
|
39
96
|
{
|
|
40
|
-
name: '
|
|
41
|
-
markers: [
|
|
97
|
+
name: 'oop',
|
|
98
|
+
markers: [
|
|
99
|
+
'class ',
|
|
100
|
+
'interface ',
|
|
101
|
+
'implements ',
|
|
102
|
+
'extends ',
|
|
103
|
+
],
|
|
42
104
|
config: {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
105
|
+
paradigm: 'oop',
|
|
106
|
+
gates: {
|
|
107
|
+
// Future: class-specific gates
|
|
46
108
|
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'functional',
|
|
113
|
+
markers: [
|
|
114
|
+
'=>',
|
|
115
|
+
'export const',
|
|
116
|
+
'map(',
|
|
117
|
+
'filter(',
|
|
118
|
+
],
|
|
119
|
+
config: {
|
|
120
|
+
paradigm: 'functional',
|
|
47
121
|
gates: {
|
|
48
|
-
|
|
49
|
-
forbid_todos: true,
|
|
50
|
-
forbid_fixme: true,
|
|
51
|
-
forbid_paths: [],
|
|
52
|
-
required_files: ['docs/SPEC.md', 'docs/ARCH.md', 'README.md'],
|
|
122
|
+
// Future: function-specific gates
|
|
53
123
|
},
|
|
54
124
|
},
|
|
55
125
|
},
|
|
@@ -63,8 +133,24 @@ exports.UNIVERSAL_CONFIG = {
|
|
|
63
133
|
forbid_fixme: true,
|
|
64
134
|
forbid_paths: [],
|
|
65
135
|
required_files: ['docs/SPEC.md', 'docs/ARCH.md', 'docs/DECISIONS.md', 'docs/TASKS.md'],
|
|
136
|
+
ast: {
|
|
137
|
+
complexity: 10,
|
|
138
|
+
max_methods: 10,
|
|
139
|
+
max_params: 5,
|
|
140
|
+
},
|
|
141
|
+
dependencies: {
|
|
142
|
+
forbid: [],
|
|
143
|
+
},
|
|
144
|
+
architecture: {
|
|
145
|
+
boundaries: [],
|
|
146
|
+
},
|
|
147
|
+
safety: {
|
|
148
|
+
max_files_changed_per_cycle: 10,
|
|
149
|
+
protected_paths: ['.github/**', 'docs/**', 'rigour.yml'],
|
|
150
|
+
},
|
|
66
151
|
},
|
|
67
152
|
output: {
|
|
68
153
|
report_path: 'rigour-report.json',
|
|
69
154
|
},
|
|
155
|
+
planned: [],
|
|
70
156
|
};
|