@hasankemaldemirci/aro 1.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.
- package/.agent_context_pro.json +57 -0
- package/.env.example +3 -0
- package/.github/workflows/aro.yml +41 -0
- package/.husky/pre-commit +19 -0
- package/CONTRIBUTING.md +34 -0
- package/LICENSE +21 -0
- package/README.md +55 -0
- package/bin/aro.ts +86 -0
- package/dist/bin/aro.d.ts +7 -0
- package/dist/bin/aro.js +118 -0
- package/dist/src/badge.d.ts +6 -0
- package/dist/src/badge.js +64 -0
- package/dist/src/constants.d.ts +20 -0
- package/dist/src/constants.js +68 -0
- package/dist/src/core.d.ts +12 -0
- package/dist/src/core.js +107 -0
- package/dist/src/enterprise.d.ts +8 -0
- package/dist/src/enterprise.js +125 -0
- package/dist/src/init.d.ts +1 -0
- package/dist/src/init.js +64 -0
- package/dist/src/mcp.d.ts +5 -0
- package/dist/src/mcp.js +138 -0
- package/dist/src/refactor.d.ts +6 -0
- package/dist/src/refactor.js +91 -0
- package/dist/src/rules.d.ts +6 -0
- package/dist/src/rules.js +67 -0
- package/dist/src/types.d.ts +39 -0
- package/dist/src/types.js +6 -0
- package/dist/src/utils.d.ts +14 -0
- package/dist/src/utils.js +194 -0
- package/dist/tests/cli.test.d.ts +1 -0
- package/dist/tests/cli.test.js +56 -0
- package/dist/tests/core.test.d.ts +5 -0
- package/dist/tests/core.test.js +129 -0
- package/dist/tests/enterprise.test.d.ts +1 -0
- package/dist/tests/enterprise.test.js +74 -0
- package/dist/tests/mcp.test.d.ts +1 -0
- package/dist/tests/mcp.test.js +81 -0
- package/eslint.config.mjs +9 -0
- package/package.json +66 -0
- package/src/badge.ts +77 -0
- package/src/constants.ts +68 -0
- package/src/core.ts +141 -0
- package/src/enterprise.ts +159 -0
- package/src/init.ts +75 -0
- package/src/mcp.ts +158 -0
- package/src/refactor.ts +122 -0
- package/src/rules.ts +78 -0
- package/src/types.ts +43 -0
- package/src/utils.ts +199 -0
- package/tests/cli.test.ts +71 -0
- package/tests/core.test.ts +146 -0
- package/tests/enterprise.test.ts +78 -0
- package/tests/mcp.test.ts +89 -0
- package/tsconfig.json +23 -0
package/dist/src/core.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @aro-context-marker
|
|
4
|
+
* AI READABILITY NOTE: This file is monitored for AI-Readability.
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.run = run;
|
|
11
|
+
exports.handleError = handleError;
|
|
12
|
+
exports.displayScore = displayScore;
|
|
13
|
+
/**
|
|
14
|
+
* @aro-context-marker
|
|
15
|
+
* AI READABILITY NOTE: This file is monitored for AI-Readability.
|
|
16
|
+
*/
|
|
17
|
+
const fs_1 = __importDefault(require("fs"));
|
|
18
|
+
const path_1 = __importDefault(require("path"));
|
|
19
|
+
const constants_1 = require("./constants");
|
|
20
|
+
const utils_1 = require("./utils");
|
|
21
|
+
/**
|
|
22
|
+
* @aro-context-marker
|
|
23
|
+
* AI READABILITY NOTE: Orchestration layer for ARO analysis.
|
|
24
|
+
*/
|
|
25
|
+
async function run() {
|
|
26
|
+
const isSilent = process.argv.includes("--silent");
|
|
27
|
+
if (!isSilent) {
|
|
28
|
+
console.log(constants_1.Branding.border(""));
|
|
29
|
+
console.log(constants_1.Branding.cyan.bold("š°ļø ARO") + constants_1.Branding.gray(" | v2.1.0-TS"));
|
|
30
|
+
console.log(constants_1.Branding.white('"SEO for your code, optimized for AI Agents."'));
|
|
31
|
+
console.log(constants_1.Branding.border(""));
|
|
32
|
+
}
|
|
33
|
+
const projectPath = process.cwd();
|
|
34
|
+
const pkgPath = path_1.default.join(projectPath, "package.json");
|
|
35
|
+
if (!fs_1.default.existsSync(pkgPath)) {
|
|
36
|
+
handleError("package.json not found. Please run this in a Node.js project.");
|
|
37
|
+
}
|
|
38
|
+
let pkg;
|
|
39
|
+
try {
|
|
40
|
+
pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, "utf8"));
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
handleError(`Failed to parse package.json: ${e.message}`);
|
|
44
|
+
}
|
|
45
|
+
const framework = (0, utils_1.detectFramework)(pkg);
|
|
46
|
+
const techStack = (0, utils_1.detectTechStack)(pkg);
|
|
47
|
+
const entryPoints = (0, utils_1.findEntryPoints)(projectPath);
|
|
48
|
+
if (!isSilent) {
|
|
49
|
+
console.log(constants_1.Branding.white(`\nšÆ Framework: `) + constants_1.Branding.magenta.bold(framework));
|
|
50
|
+
console.log(constants_1.Branding.gray(`š ļø Tech Stack: `) + constants_1.Branding.cyan(techStack.join(", ")));
|
|
51
|
+
console.log(constants_1.Branding.gray(`š Scope: `) + constants_1.Branding.white(projectPath));
|
|
52
|
+
}
|
|
53
|
+
const ignoreList = (0, utils_1.loadIgnoreList)(projectPath);
|
|
54
|
+
try {
|
|
55
|
+
const metrics = (0, utils_1.analyzeMetrics)(projectPath, ignoreList);
|
|
56
|
+
const score = (0, utils_1.calculateScore)(metrics);
|
|
57
|
+
const contextMap = {
|
|
58
|
+
projectName: pkg.name || "Unknown",
|
|
59
|
+
version: pkg.version || "0.0.1",
|
|
60
|
+
framework,
|
|
61
|
+
techStack,
|
|
62
|
+
entryPoints,
|
|
63
|
+
analyzedAt: new Date().toISOString(),
|
|
64
|
+
metrics,
|
|
65
|
+
score,
|
|
66
|
+
blindSpots: metrics.blindSpots,
|
|
67
|
+
structure: (0, utils_1.getRepoStructure)(projectPath, 0, ignoreList),
|
|
68
|
+
};
|
|
69
|
+
const contextFilePath = path_1.default.join(projectPath, ".agent_context_pro.json");
|
|
70
|
+
fs_1.default.writeFileSync(contextFilePath, JSON.stringify(contextMap, null, 2));
|
|
71
|
+
if (!isSilent) {
|
|
72
|
+
console.log(constants_1.Branding.success(`\nā
Knowledge Map: `) +
|
|
73
|
+
constants_1.Branding.white.bold(".agent_context_pro.json"));
|
|
74
|
+
displayScore(score);
|
|
75
|
+
if (score < 100 && metrics.blindSpots.length > 0) {
|
|
76
|
+
console.log(constants_1.Branding.warning("\nš© Blind Spots & Recommendations:"));
|
|
77
|
+
metrics.blindSpots.forEach((spot) => {
|
|
78
|
+
console.log(constants_1.Branding.gray(` ⢠${spot}`));
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return contextMap;
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
handleError(`Analysis failed: ${e.message}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function handleError(message) {
|
|
89
|
+
console.log(constants_1.Branding.error(`\nā Error: ${message}`));
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
function displayScore(score) {
|
|
93
|
+
const color = score > 80
|
|
94
|
+
? constants_1.Branding.success
|
|
95
|
+
: score > 60
|
|
96
|
+
? constants_1.Branding.warning
|
|
97
|
+
: constants_1.Branding.error;
|
|
98
|
+
console.log(constants_1.Branding.white(`š Quality Score: `) + color.bold(`${score}/100`));
|
|
99
|
+
if (score < 80) {
|
|
100
|
+
console.log(constants_1.Branding.warning(`\nā ļø At Risk: High Hallucination Tax detected.`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (require.main === module) {
|
|
104
|
+
run().catch((err) => {
|
|
105
|
+
handleError(err.message);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EnterpriseOptions, ARODebt } from "./types";
|
|
2
|
+
import { AROMetrics } from "./utils";
|
|
3
|
+
/**
|
|
4
|
+
* @aro-context-marker
|
|
5
|
+
* AI READABILITY NOTE: This file is monitored for AI-Readability.
|
|
6
|
+
*/
|
|
7
|
+
export declare function calculateDebt(metrics: AROMetrics, options?: Partial<EnterpriseOptions>): ARODebt;
|
|
8
|
+
export declare function run(): void;
|
|
@@ -0,0 +1,125 @@
|
|
|
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.calculateDebt = calculateDebt;
|
|
7
|
+
exports.run = run;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const constants_1 = require("./constants");
|
|
11
|
+
/**
|
|
12
|
+
* @aro-context-marker
|
|
13
|
+
* AI READABILITY NOTE: This file is monitored for AI-Readability.
|
|
14
|
+
*/
|
|
15
|
+
function calculateDebt(metrics, options) {
|
|
16
|
+
const m = metrics;
|
|
17
|
+
const rate = options?.rate || 100;
|
|
18
|
+
const interactions = options?.interactions || 2400;
|
|
19
|
+
let docDebt = 0;
|
|
20
|
+
if (!m.hasReadme)
|
|
21
|
+
docDebt = 15000;
|
|
22
|
+
else if (m.readmeSize < 500)
|
|
23
|
+
docDebt = 6000;
|
|
24
|
+
const truncationDebt = m.largeFiles * 5000;
|
|
25
|
+
let structuralDebt = 0;
|
|
26
|
+
if (!m.hasSrc)
|
|
27
|
+
structuralDebt += 10000;
|
|
28
|
+
// Align with Score: Score gives max points for 2 config files.
|
|
29
|
+
const configRequirement = 2;
|
|
30
|
+
const missingConfigs = Math.max(0, configRequirement - m.hasConfig);
|
|
31
|
+
structuralDebt += missingConfigs * 5000;
|
|
32
|
+
const tokenWasteDebt = m.largeFiles * interactions * 0.05;
|
|
33
|
+
const totalDebt = docDebt + truncationDebt + structuralDebt + tokenWasteDebt;
|
|
34
|
+
const wastedHours = totalDebt / rate;
|
|
35
|
+
return {
|
|
36
|
+
docDebt,
|
|
37
|
+
truncationDebt,
|
|
38
|
+
structuralDebt,
|
|
39
|
+
tokenWasteDebt,
|
|
40
|
+
totalDebt,
|
|
41
|
+
wastedHours,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function run() {
|
|
45
|
+
const args = process.argv.slice(2);
|
|
46
|
+
const options = {
|
|
47
|
+
rate: 120,
|
|
48
|
+
interactions: 2400,
|
|
49
|
+
};
|
|
50
|
+
args.forEach((arg) => {
|
|
51
|
+
if (arg.startsWith("--rate="))
|
|
52
|
+
options.rate = parseInt(arg.split("=")[1]);
|
|
53
|
+
if (arg.startsWith("--interactions="))
|
|
54
|
+
options.interactions = parseInt(arg.split("=")[1]);
|
|
55
|
+
if (arg.startsWith("--threshold="))
|
|
56
|
+
options.threshold = parseInt(arg.split("=")[1]);
|
|
57
|
+
if (arg.startsWith("--output="))
|
|
58
|
+
options.output = arg.split("=")[1];
|
|
59
|
+
});
|
|
60
|
+
const projectPath = process.cwd();
|
|
61
|
+
const contextPath = path_1.default.join(projectPath, ".agent_context_pro.json");
|
|
62
|
+
if (!fs_1.default.existsSync(contextPath)) {
|
|
63
|
+
console.log(constants_1.Branding.error("ā Knowledge Map not found. Run analysis first."));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const context = JSON.parse(fs_1.default.readFileSync(contextPath, "utf8"));
|
|
67
|
+
const debt = calculateDebt(context.metrics, options);
|
|
68
|
+
let reportContent = `
|
|
69
|
+
# ARO AI-Financial Report
|
|
70
|
+
Analyzed At: ${context.analyzedAt}
|
|
71
|
+
Project: ${context.projectName}
|
|
72
|
+
Score: ${context.score}/100
|
|
73
|
+
|
|
74
|
+
## Business Metrics
|
|
75
|
+
- AI-Onboarding Ready: ${context.score}%
|
|
76
|
+
- Developer Hourly Rate (Avg): $${options.rate}
|
|
77
|
+
- Annual Interactions: ${options.interactions}
|
|
78
|
+
|
|
79
|
+
## Financial Breakdown (Annual)
|
|
80
|
+
- Documentation Gap: $${Math.round(debt.docDebt).toLocaleString()}
|
|
81
|
+
- Truncation Risk: $${Math.round(debt.truncationDebt).toLocaleString()}
|
|
82
|
+
- Structural Debt: $${Math.round(debt.structuralDebt).toLocaleString()}
|
|
83
|
+
- Token Waste: $${Math.round(debt.tokenWasteDebt).toLocaleString()}
|
|
84
|
+
|
|
85
|
+
**TOTAL ANNUAL AI DEBT: $${Math.round(debt.totalDebt).toLocaleString()}**
|
|
86
|
+
Monthly Productivity Loss: $${Math.round(debt.totalDebt / 12).toLocaleString()}
|
|
87
|
+
Wasted Billable Hours: ${Math.round(debt.wastedHours)} hrs/year
|
|
88
|
+
`;
|
|
89
|
+
if (options.output) {
|
|
90
|
+
// SECURITY: Path Traversal Prevention
|
|
91
|
+
// Ensure output is directed within the project directory or a safe subdirectory
|
|
92
|
+
// We basename the filename to prevent escaping with ../..
|
|
93
|
+
const safeFileName = path_1.default.basename(options.output);
|
|
94
|
+
const outputPath = path_1.default.join(projectPath, safeFileName);
|
|
95
|
+
fs_1.default.writeFileSync(outputPath, reportContent);
|
|
96
|
+
console.log(constants_1.Branding.success(`\nš¾ Exported (Sanitized): `) +
|
|
97
|
+
constants_1.Branding.white.bold(safeFileName));
|
|
98
|
+
}
|
|
99
|
+
// Console Output
|
|
100
|
+
console.log(constants_1.Branding.border(""));
|
|
101
|
+
console.log(constants_1.Branding.magenta.bold("š° ARO Financial Analyzer") +
|
|
102
|
+
constants_1.Branding.gray(" | Enterprise Report"));
|
|
103
|
+
console.log(constants_1.Branding.border(""));
|
|
104
|
+
console.log(constants_1.Branding.cyan("\n[BUSINESS METRICS]"));
|
|
105
|
+
console.log(constants_1.Branding.white(`Score: `) + constants_1.Branding.success.bold(`${context.score}%`));
|
|
106
|
+
console.log(constants_1.Branding.white(`Rate: `) + constants_1.Branding.gray(`$${options.rate}/hr`));
|
|
107
|
+
console.log(constants_1.Branding.error("\n[DANGER ZONE - ANNUAL DEBT]"));
|
|
108
|
+
console.log(constants_1.Branding.gray(`Total Debt: `) +
|
|
109
|
+
constants_1.Branding.error.bold(`$${Math.round(debt.totalDebt).toLocaleString()}`));
|
|
110
|
+
console.log(constants_1.Branding.gray(`Wasted Hours: `) +
|
|
111
|
+
constants_1.Branding.warning.bold(`${Math.round(debt.wastedHours)} hrs/yr`));
|
|
112
|
+
if (options.threshold !== undefined) {
|
|
113
|
+
console.log(constants_1.Branding.border(""));
|
|
114
|
+
if (context.score < options.threshold) {
|
|
115
|
+
console.log(constants_1.Branding.error(`ā CI/CD REJECTED: Score ${context.score} < Threshold ${options.threshold}`));
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
console.log(constants_1.Branding.success(`ā
CI/CD PASSED: Score ${context.score} >= Threshold ${options.threshold}`));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (require.main === module) {
|
|
124
|
+
run();
|
|
125
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function run(): void;
|
package/dist/src/init.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
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.run = run;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const constants_1 = require("./constants");
|
|
10
|
+
/**
|
|
11
|
+
* @aro-context-marker
|
|
12
|
+
* AI READABILITY NOTE: CI/CD Initializer for ARO.
|
|
13
|
+
* Sets up GitHub Actions workflows to automate readability audits.
|
|
14
|
+
*/
|
|
15
|
+
const GITHUB_WORKFLOW_YAML = `name: ARO Audit
|
|
16
|
+
|
|
17
|
+
on:
|
|
18
|
+
push:
|
|
19
|
+
branches: [ main, master ]
|
|
20
|
+
pull_request:
|
|
21
|
+
branches: [ main, master ]
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
audit:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- name: Use Node.js
|
|
29
|
+
uses: actions/setup-node@v4
|
|
30
|
+
with:
|
|
31
|
+
node-version: '20'
|
|
32
|
+
cache: 'npm'
|
|
33
|
+
- run: npm ci
|
|
34
|
+
- name: Run ARO Audit
|
|
35
|
+
run: npx @hasankemaldemirci/aro audit --threshold=80
|
|
36
|
+
`;
|
|
37
|
+
function run() {
|
|
38
|
+
const projectPath = process.cwd();
|
|
39
|
+
const workflowDir = path_1.default.join(projectPath, ".github", "workflows");
|
|
40
|
+
const workflowPath = path_1.default.join(workflowDir, "aro.yml");
|
|
41
|
+
console.log(constants_1.Branding.border(""));
|
|
42
|
+
console.log(constants_1.Branding.cyan.bold("š¤ ARO CI/CD Initializer"));
|
|
43
|
+
console.log(constants_1.Branding.border(""));
|
|
44
|
+
if (!fs_1.default.existsSync(workflowDir)) {
|
|
45
|
+
fs_1.default.mkdirSync(workflowDir, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
if (fs_1.default.existsSync(workflowPath)) {
|
|
48
|
+
console.log(constants_1.Branding.warning("ā ļø GitHub Action already exists at .github/workflows/aro.yml"));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
fs_1.default.writeFileSync(workflowPath, GITHUB_WORKFLOW_YAML);
|
|
53
|
+
console.log(constants_1.Branding.success("\nā
Created GitHub Action: ") +
|
|
54
|
+
constants_1.Branding.white(".github/workflows/aro.yml"));
|
|
55
|
+
console.log(constants_1.Branding.gray("\nYour project will now be automatically audited on every push."));
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
console.log(constants_1.Branding.error(`\nā Failed to create workflow: ${e.message}`));
|
|
59
|
+
}
|
|
60
|
+
console.log(constants_1.Branding.border(""));
|
|
61
|
+
}
|
|
62
|
+
if (require.main === module) {
|
|
63
|
+
run();
|
|
64
|
+
}
|
package/dist/src/mcp.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @aro-context-marker
|
|
4
|
+
* AI READABILITY NOTE: This file is monitored for AI-Readability.
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
/**
|
|
11
|
+
* @aro-context-marker
|
|
12
|
+
* AI READABILITY NOTE: This file is monitored for AI-Readability.
|
|
13
|
+
*/
|
|
14
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
15
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
16
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
17
|
+
const child_process_1 = require("child_process");
|
|
18
|
+
const fs_1 = __importDefault(require("fs"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
/**
|
|
21
|
+
* @aro-context-marker
|
|
22
|
+
* AI READABILITY NOTE: MCP Server in TypeScript.
|
|
23
|
+
* Provides tools for AI models to self-audit and optimize context.
|
|
24
|
+
*/
|
|
25
|
+
const SRC_PATH = __dirname;
|
|
26
|
+
const server = new index_js_1.Server({
|
|
27
|
+
name: "aro-ai-readability",
|
|
28
|
+
version: "2.0.0",
|
|
29
|
+
}, {
|
|
30
|
+
capabilities: {
|
|
31
|
+
tools: {},
|
|
32
|
+
resources: {},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
// --- Resources ---
|
|
36
|
+
server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => ({
|
|
37
|
+
resources: [
|
|
38
|
+
{
|
|
39
|
+
uri: "aro://current-metrics",
|
|
40
|
+
name: "ARO AI-Readability Metrics",
|
|
41
|
+
description: "The latest analysis results and AI debt report.",
|
|
42
|
+
mimeType: "application/json",
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
}));
|
|
46
|
+
server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) => {
|
|
47
|
+
if (request.params.uri === "aro://current-metrics") {
|
|
48
|
+
const contextPath = path_1.default.join(process.cwd(), ".agent_context_pro.json");
|
|
49
|
+
if (!fs_1.default.existsSync(contextPath)) {
|
|
50
|
+
throw new Error("No analysis data found. Run analyze_readability first.");
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
contents: [
|
|
54
|
+
{
|
|
55
|
+
uri: request.params.uri,
|
|
56
|
+
mimeType: "application/json",
|
|
57
|
+
text: fs_1.default.readFileSync(contextPath, "utf8"),
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
throw new Error("Resource not found");
|
|
63
|
+
});
|
|
64
|
+
// --- Tools ---
|
|
65
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
66
|
+
tools: [
|
|
67
|
+
{
|
|
68
|
+
name: "analyze_readability",
|
|
69
|
+
description: "Performs a deep audit of the codebase to calculate AI-Readiness score and Hallucination Tax.",
|
|
70
|
+
inputSchema: { type: "object", properties: {} },
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "optimize_readability",
|
|
74
|
+
description: "Automatically applies AI-SEO markers and generates missing configurations to improve AI context retention.",
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: "object",
|
|
77
|
+
properties: {
|
|
78
|
+
applyFixes: {
|
|
79
|
+
type: "boolean",
|
|
80
|
+
description: "Whether to apply automated fixes.",
|
|
81
|
+
default: true,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
}));
|
|
88
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
89
|
+
const { name } = request.params;
|
|
90
|
+
try {
|
|
91
|
+
if (name === "analyze_readability") {
|
|
92
|
+
(0, child_process_1.execSync)(`node ${path_1.default.join(SRC_PATH, "core.js")}`);
|
|
93
|
+
const contextPath = path_1.default.join(process.cwd(), ".agent_context_pro.json");
|
|
94
|
+
const data = JSON.parse(fs_1.default.readFileSync(contextPath, "utf8"));
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: "text",
|
|
99
|
+
text: `Analysis complete.\nScore: ${data.score}/100\nFramework: ${data.framework}\nBlind Spots: ${data.blindSpots.join(", ")}`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (name === "optimize_readability") {
|
|
105
|
+
(0, child_process_1.execSync)(`node ${path_1.default.join(SRC_PATH, "refactor.js")}`);
|
|
106
|
+
(0, child_process_1.execSync)(`node ${path_1.default.join(SRC_PATH, "core.js")}`);
|
|
107
|
+
const contextPath = path_1.default.join(process.cwd(), ".agent_context_pro.json");
|
|
108
|
+
const data = JSON.parse(fs_1.default.readFileSync(contextPath, "utf8"));
|
|
109
|
+
return {
|
|
110
|
+
content: [
|
|
111
|
+
{
|
|
112
|
+
type: "text",
|
|
113
|
+
text: `Optimizations applied successfully.\nNew AI-Readiness Score: ${data.score}/100`,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
throw new Error(`Tool not found: ${name}`);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
return {
|
|
122
|
+
isError: true,
|
|
123
|
+
content: [
|
|
124
|
+
{ type: "text", text: `Error executing ARO tool: ${error.message}` },
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
// --- Start Server ---
|
|
130
|
+
async function main() {
|
|
131
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
132
|
+
await server.connect(transport);
|
|
133
|
+
console.error("ARO MCP Server running on stdio");
|
|
134
|
+
}
|
|
135
|
+
main().catch((error) => {
|
|
136
|
+
console.error("Fatal error starting ARO MCP server:", error);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
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.run = run;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
10
|
+
const constants_1 = require("./constants");
|
|
11
|
+
const utils_1 = require("./utils");
|
|
12
|
+
/**
|
|
13
|
+
* @aro-context-marker
|
|
14
|
+
* AI READABILITY NOTE: Performance Optimized Refactor Module.
|
|
15
|
+
* Using fast-glob for rapid complexity detection.
|
|
16
|
+
*/
|
|
17
|
+
async function run() {
|
|
18
|
+
const projectPath = process.cwd();
|
|
19
|
+
const contextPath = path_1.default.join(projectPath, ".agent_context_pro.json");
|
|
20
|
+
const ignoreList = (0, utils_1.loadIgnoreList)(projectPath);
|
|
21
|
+
if (!fs_1.default.existsSync(contextPath)) {
|
|
22
|
+
console.log(constants_1.Branding.error("ā Error: No .agent_context_pro.json found. Run analysis first."));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
const data = JSON.parse(fs_1.default.readFileSync(contextPath, "utf8"));
|
|
26
|
+
const metrics = data.metrics;
|
|
27
|
+
console.log(constants_1.Branding.magenta.bold("\nš ļø ARO Auto-Refactor: Commencing Optimization..."));
|
|
28
|
+
// 1. Documentation Optimization
|
|
29
|
+
if (!metrics.hasReadme) {
|
|
30
|
+
console.log(constants_1.Branding.warning("š Generating missing README.md..."));
|
|
31
|
+
const baseReadme = `# ${data.projectName}\n\n## Overview\nThis project is a ${data.framework} application.\n\n## Architecture\n*(Auto-generated by ARO)*\nThis project uses a standard ${data.framework} structure.`;
|
|
32
|
+
fs_1.default.writeFileSync(path_1.default.join(projectPath, "README.md"), baseReadme);
|
|
33
|
+
console.log(constants_1.Branding.success("ā
README.md created."));
|
|
34
|
+
}
|
|
35
|
+
// 2. Configuration Recovery
|
|
36
|
+
const requiredConfigs = {
|
|
37
|
+
".env.example": "# Environment variables template\nPORT=3000\nAPI_" + "KEY=your_key_here",
|
|
38
|
+
"tsconfig.json": '{\n "compilerOptions": {\n "target": "es5",\n "module": "commonjs",\n "strict": true\n }\n}',
|
|
39
|
+
".gitignore": "node_modules\n.DS_Store\n.env\n.agent_context_pro.json",
|
|
40
|
+
};
|
|
41
|
+
for (const [file, content] of Object.entries(requiredConfigs)) {
|
|
42
|
+
if (!fs_1.default.existsSync(path_1.default.join(projectPath, file))) {
|
|
43
|
+
console.log(constants_1.Branding.warning(`š ļø Recovering missing config: ${file}...`));
|
|
44
|
+
fs_1.default.writeFileSync(path_1.default.join(projectPath, file), content);
|
|
45
|
+
console.log(constants_1.Branding.success(`ā
${file} generated.`));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// 3. Complexity Optimization: AI-SEO Markers (Optimized Scan)
|
|
49
|
+
const filesToOptimize = fast_glob_1.default.sync(["**/*.{js,ts,tsx,jsx}"], {
|
|
50
|
+
cwd: projectPath,
|
|
51
|
+
ignore: ignoreList.map((i) => `**/${i}/**`),
|
|
52
|
+
absolute: true,
|
|
53
|
+
deep: 5,
|
|
54
|
+
});
|
|
55
|
+
for (const file of filesToOptimize) {
|
|
56
|
+
const content = fs_1.default.readFileSync(file, "utf8");
|
|
57
|
+
if (content.split("\n").length > 100) {
|
|
58
|
+
optimizeFile(file);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
console.log(constants_1.Branding.success("\n⨠Refactoring Pass Complete. Run ARO again to see updated scores!"));
|
|
62
|
+
}
|
|
63
|
+
function optimizeFile(filePath) {
|
|
64
|
+
try {
|
|
65
|
+
let content = fs_1.default.readFileSync(filePath, "utf8");
|
|
66
|
+
if (content.includes("@aro-context-marker"))
|
|
67
|
+
return;
|
|
68
|
+
const lines = content.split("\n");
|
|
69
|
+
let extraNote = "";
|
|
70
|
+
if (lines.length > 300) {
|
|
71
|
+
extraNote =
|
|
72
|
+
"\n * CRITICAL: This file exceeds 300 lines. AI Agents may experience context truncation.\n * ACTION: Consider refactoring core logic into smaller sub-modules.";
|
|
73
|
+
console.log(constants_1.Branding.warning(`ā ļø Self-Healing: Detected high-complexity in ${path_1.default.basename(filePath)} (${lines.length} lines). Applying advisory markers.`));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log(constants_1.Branding.gray(`š Adding AI-SEO markers to: ${path_1.default.basename(filePath)}`));
|
|
77
|
+
}
|
|
78
|
+
const marker = `/**\n * @aro-context-marker\n * AI READABILITY NOTE: This file is monitored for AI-Readability.${extraNote}\n */\n`;
|
|
79
|
+
if (lines[0].startsWith("#!")) {
|
|
80
|
+
lines.splice(1, 0, marker);
|
|
81
|
+
fs_1.default.writeFileSync(filePath, lines.join("\n"));
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
fs_1.default.writeFileSync(filePath, marker + content);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (e) { }
|
|
88
|
+
}
|
|
89
|
+
if (require.main === module) {
|
|
90
|
+
run();
|
|
91
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
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.run = run;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const constants_1 = require("./constants");
|
|
10
|
+
/**
|
|
11
|
+
* @aro-context-marker
|
|
12
|
+
* AI READABILITY NOTE: Rules generator for AI Agents (Cursor/Windsurf).
|
|
13
|
+
* Creates a .cursorrules file based on the local project context.
|
|
14
|
+
*/
|
|
15
|
+
function run() {
|
|
16
|
+
const projectPath = process.cwd();
|
|
17
|
+
const contextPath = path_1.default.join(projectPath, ".agent_context_pro.json");
|
|
18
|
+
if (!fs_1.default.existsSync(contextPath)) {
|
|
19
|
+
console.log(constants_1.Branding.error("ā Knowledge Map not found. Run 'aro audit' first."));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const data = JSON.parse(fs_1.default.readFileSync(contextPath, "utf8"));
|
|
23
|
+
const rulesContent = `
|
|
24
|
+
# ARO: AI Agent Constitutional Rules š°ļø
|
|
25
|
+
Version: ${data.version} | Framework: ${data.framework}
|
|
26
|
+
|
|
27
|
+
## Core Directives for the AI Agent
|
|
28
|
+
You are working in a codebase optimized by **ARO**. To maintain a 100/100 Readiness Score:
|
|
29
|
+
|
|
30
|
+
1. **Modular Consistency:** NEVER create or expand files beyond 300 lines. If logic grows, refactor into smaller sub-modules immediately.
|
|
31
|
+
2. **Context Retention:** Always refer to \`.agent_context_pro.json\` for the latest project structure and tech stack.
|
|
32
|
+
3. **Deep Context Awareness:**
|
|
33
|
+
- Framework: ${data.framework}
|
|
34
|
+
- Tech Stack: ${data.techStack.join(", ")}
|
|
35
|
+
- Active Entry Points: ${data.entryPoints.join(", ")}
|
|
36
|
+
|
|
37
|
+
4. **SEO Markers:** Always include \`@aro-context-marker\` in the headers of complex or core files to ensure context mapping persistence.
|
|
38
|
+
5. **No Placeholders:** When generating code, provide complete, production-ready implementations.
|
|
39
|
+
|
|
40
|
+
## Refactoring Protocol
|
|
41
|
+
- Prioritize modularity over monolithic functions.
|
|
42
|
+
- Ensure all new features are reflected in the documentation.
|
|
43
|
+
- Maintain a clear directory hierarchy as defined in the structural audit.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
*Optimized by ARO - "SEO for your code, optimized for AI Agents."*
|
|
47
|
+
`.trim();
|
|
48
|
+
try {
|
|
49
|
+
const rulesFiles = [".cursorrules", ".windsurfrules", "AI-CONSTITUTION.md"];
|
|
50
|
+
rulesFiles.forEach((file) => {
|
|
51
|
+
fs_1.default.writeFileSync(path_1.default.join(projectPath, file), rulesContent);
|
|
52
|
+
});
|
|
53
|
+
console.log(constants_1.Branding.border(""));
|
|
54
|
+
console.log(constants_1.Branding.cyan.bold("š ARO Multi-Agent Constitution"));
|
|
55
|
+
console.log(constants_1.Branding.border(""));
|
|
56
|
+
console.log(constants_1.Branding.success("\nā
Rules deployed to: ") +
|
|
57
|
+
constants_1.Branding.white(rulesFiles.join(", ")));
|
|
58
|
+
console.log(constants_1.Branding.gray("\nTargeting: Cursor, Windsurf, Devin, and any ARO-compatible AI Agent."));
|
|
59
|
+
console.log(constants_1.Branding.border(""));
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
console.log(constants_1.Branding.error(`\nā Failed to deploy AI rules: ${e.message}`));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (require.main === module) {
|
|
66
|
+
run();
|
|
67
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aro-context-marker
|
|
3
|
+
* AI READABILITY NOTE: Centralized type definitions.
|
|
4
|
+
*/
|
|
5
|
+
export interface AROMetrics {
|
|
6
|
+
hasReadme: boolean;
|
|
7
|
+
readmeSize: number;
|
|
8
|
+
hasSrc: boolean;
|
|
9
|
+
hasConfig: number;
|
|
10
|
+
largeFiles: number;
|
|
11
|
+
securityIssues: number;
|
|
12
|
+
blindSpots: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface AROContext {
|
|
15
|
+
projectName: string;
|
|
16
|
+
version: string;
|
|
17
|
+
framework: string;
|
|
18
|
+
techStack: string[];
|
|
19
|
+
entryPoints: string[];
|
|
20
|
+
analyzedAt: string;
|
|
21
|
+
metrics: AROMetrics;
|
|
22
|
+
score: number;
|
|
23
|
+
blindSpots: string[];
|
|
24
|
+
structure: any;
|
|
25
|
+
}
|
|
26
|
+
export interface EnterpriseOptions {
|
|
27
|
+
rate: number;
|
|
28
|
+
interactions: number;
|
|
29
|
+
threshold?: number;
|
|
30
|
+
output?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ARODebt {
|
|
33
|
+
docDebt: number;
|
|
34
|
+
truncationDebt: number;
|
|
35
|
+
structuralDebt: number;
|
|
36
|
+
tokenWasteDebt: number;
|
|
37
|
+
totalDebt: number;
|
|
38
|
+
wastedHours: number;
|
|
39
|
+
}
|