faf-mcp 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/CHANGELOG.md +34 -0
- package/CLAUDE.md +73 -0
- package/LICENSE +22 -0
- package/README.md +165 -0
- package/assets/Project-faf-pckg-json-README.png +0 -0
- package/assets/icons/faf-icon-128.png +0 -0
- package/assets/icons/faf-icon-256.png +0 -0
- package/assets/icons/faf-icon-48.png +0 -0
- package/assets/icons/faf-icon-512.png +0 -0
- package/assets/icons/orange-smiley.svg +6 -0
- package/dist/src/compiler/index.d.ts +7 -0
- package/dist/src/compiler/index.js +24 -0
- package/dist/src/compiler/index.js.map +1 -0
- package/dist/src/compiler/scorer.d.ts +53 -0
- package/dist/src/compiler/scorer.js +189 -0
- package/dist/src/compiler/scorer.js.map +1 -0
- package/dist/src/compiler/slot-validator.d.ts +32 -0
- package/dist/src/compiler/slot-validator.js +293 -0
- package/dist/src/compiler/slot-validator.js.map +1 -0
- package/dist/src/compiler/type-detector.d.ts +62 -0
- package/dist/src/compiler/type-detector.js +388 -0
- package/dist/src/compiler/type-detector.js.map +1 -0
- package/dist/src/config/visibility.d.ts +41 -0
- package/dist/src/config/visibility.js +158 -0
- package/dist/src/config/visibility.js.map +1 -0
- package/dist/src/faf-core/commands/audit.d.ts +21 -0
- package/dist/src/faf-core/commands/audit.js +83 -0
- package/dist/src/faf-core/commands/audit.js.map +1 -0
- package/dist/src/faf-core/commands/auto.d.ts +25 -0
- package/dist/src/faf-core/commands/auto.js +74 -0
- package/dist/src/faf-core/commands/auto.js.map +1 -0
- package/dist/src/faf-core/commands/bi-sync.d.ts +26 -0
- package/dist/src/faf-core/commands/bi-sync.js +157 -0
- package/dist/src/faf-core/commands/bi-sync.js.map +1 -0
- package/dist/src/faf-core/commands/doctor.d.ts +17 -0
- package/dist/src/faf-core/commands/doctor.js +198 -0
- package/dist/src/faf-core/commands/doctor.js.map +1 -0
- package/dist/src/faf-core/commands/enhance.d.ts +46 -0
- package/dist/src/faf-core/commands/enhance.js +360 -0
- package/dist/src/faf-core/commands/enhance.js.map +1 -0
- package/dist/src/faf-core/commands/formats.d.ts +22 -0
- package/dist/src/faf-core/commands/formats.js +117 -0
- package/dist/src/faf-core/commands/formats.js.map +1 -0
- package/dist/src/faf-core/commands/init.d.ts +26 -0
- package/dist/src/faf-core/commands/init.js +114 -0
- package/dist/src/faf-core/commands/init.js.map +1 -0
- package/dist/src/faf-core/commands/innit.d.ts +7 -0
- package/dist/src/faf-core/commands/innit.js +13 -0
- package/dist/src/faf-core/commands/innit.js.map +1 -0
- package/dist/src/faf-core/commands/migrate.d.ts +15 -0
- package/dist/src/faf-core/commands/migrate.js +86 -0
- package/dist/src/faf-core/commands/migrate.js.map +1 -0
- package/dist/src/faf-core/commands/quick.d.ts +16 -0
- package/dist/src/faf-core/commands/quick.js +184 -0
- package/dist/src/faf-core/commands/quick.js.map +1 -0
- package/dist/src/faf-core/commands/score.d.ts +47 -0
- package/dist/src/faf-core/commands/score.js +49 -0
- package/dist/src/faf-core/commands/score.js.map +1 -0
- package/dist/src/faf-core/commands/sync.d.ts +16 -0
- package/dist/src/faf-core/commands/sync.js +210 -0
- package/dist/src/faf-core/commands/sync.js.map +1 -0
- package/dist/src/faf-core/commands/update.d.ts +12 -0
- package/dist/src/faf-core/commands/update.js +46 -0
- package/dist/src/faf-core/commands/update.js.map +1 -0
- package/dist/src/faf-core/commands/validate.d.ts +21 -0
- package/dist/src/faf-core/commands/validate.js +81 -0
- package/dist/src/faf-core/commands/validate.js.map +1 -0
- package/dist/src/faf-core/compiler/faf-compiler.d.ts +138 -0
- package/dist/src/faf-core/compiler/faf-compiler.js +794 -0
- package/dist/src/faf-core/compiler/faf-compiler.js.map +1 -0
- package/dist/src/faf-core/engines/dependency-tsa.d.ts +88 -0
- package/dist/src/faf-core/engines/dependency-tsa.js +361 -0
- package/dist/src/faf-core/engines/dependency-tsa.js.map +1 -0
- package/dist/src/faf-core/engines/fab-formats-processor.d.ts +166 -0
- package/dist/src/faf-core/engines/fab-formats-processor.js +1274 -0
- package/dist/src/faf-core/engines/fab-formats-processor.js.map +1 -0
- package/dist/src/faf-core/engines/faf-dna.d.ts +159 -0
- package/dist/src/faf-core/engines/faf-dna.js +554 -0
- package/dist/src/faf-core/engines/faf-dna.js.map +1 -0
- package/dist/src/faf-core/engines/relentless-context-extractor.d.ts +100 -0
- package/dist/src/faf-core/engines/relentless-context-extractor.js +625 -0
- package/dist/src/faf-core/engines/relentless-context-extractor.js.map +1 -0
- package/dist/src/faf-core/fix-once/colors.d.ts +104 -0
- package/dist/src/faf-core/fix-once/colors.js +236 -0
- package/dist/src/faf-core/fix-once/colors.js.map +1 -0
- package/dist/src/faf-core/fix-once/types.d.ts +257 -0
- package/dist/src/faf-core/fix-once/types.js +26 -0
- package/dist/src/faf-core/fix-once/types.js.map +1 -0
- package/dist/src/faf-core/fix-once/yaml.d.ts +57 -0
- package/dist/src/faf-core/fix-once/yaml.js +172 -0
- package/dist/src/faf-core/fix-once/yaml.js.map +1 -0
- package/dist/src/faf-core/generators/faf-generator-championship.d.ts +16 -0
- package/dist/src/faf-core/generators/faf-generator-championship.js +462 -0
- package/dist/src/faf-core/generators/faf-generator-championship.js.map +1 -0
- package/dist/src/faf-core/utils/balance-visualizer.d.ts +37 -0
- package/dist/src/faf-core/utils/balance-visualizer.js +197 -0
- package/dist/src/faf-core/utils/balance-visualizer.js.map +1 -0
- package/dist/src/faf-core/utils/championship-style.d.ts +109 -0
- package/dist/src/faf-core/utils/championship-style.js +219 -0
- package/dist/src/faf-core/utils/championship-style.js.map +1 -0
- package/dist/src/faf-core/utils/chrome-extension-detector.d.ts +73 -0
- package/dist/src/faf-core/utils/chrome-extension-detector.js +268 -0
- package/dist/src/faf-core/utils/chrome-extension-detector.js.map +1 -0
- package/dist/src/faf-core/utils/fafignore-parser.d.ts +20 -0
- package/dist/src/faf-core/utils/fafignore-parser.js +178 -0
- package/dist/src/faf-core/utils/fafignore-parser.js.map +1 -0
- package/dist/src/faf-core/utils/file-utils.d.ts +112 -0
- package/dist/src/faf-core/utils/file-utils.js +846 -0
- package/dist/src/faf-core/utils/file-utils.js.map +1 -0
- package/dist/src/faf-core/utils/native-file-finder.d.ts +115 -0
- package/dist/src/faf-core/utils/native-file-finder.js +211 -0
- package/dist/src/faf-core/utils/native-file-finder.js.map +1 -0
- package/dist/src/faf-core/utils/platform-detector.d.ts +30 -0
- package/dist/src/faf-core/utils/platform-detector.js +218 -0
- package/dist/src/faf-core/utils/platform-detector.js.map +1 -0
- package/dist/src/faf-core/utils/technical-credit.d.ts +35 -0
- package/dist/src/faf-core/utils/technical-credit.js +286 -0
- package/dist/src/faf-core/utils/technical-credit.js.map +1 -0
- package/dist/src/faf-core/utils/yaml-generator.d.ts +41 -0
- package/dist/src/faf-core/utils/yaml-generator.js +360 -0
- package/dist/src/faf-core/utils/yaml-generator.js.map +1 -0
- package/dist/src/handlers/behavioral-instruction.d.ts +16 -0
- package/dist/src/handlers/behavioral-instruction.js +43 -0
- package/dist/src/handlers/behavioral-instruction.js.map +1 -0
- package/dist/src/handlers/championship-tools.d.ts +113 -0
- package/dist/src/handlers/championship-tools.js +2602 -0
- package/dist/src/handlers/championship-tools.js.map +1 -0
- package/dist/src/handlers/engine-adapter.d.ts +28 -0
- package/dist/src/handlers/engine-adapter.js +603 -0
- package/dist/src/handlers/engine-adapter.js.map +1 -0
- package/dist/src/handlers/fileHandler.d.ts +36 -0
- package/dist/src/handlers/fileHandler.js +246 -0
- package/dist/src/handlers/fileHandler.js.map +1 -0
- package/dist/src/handlers/resources.d.ts +18 -0
- package/dist/src/handlers/resources.js +78 -0
- package/dist/src/handlers/resources.js.map +1 -0
- package/dist/src/handlers/tool-registry.d.ts +23 -0
- package/dist/src/handlers/tool-registry.js +68 -0
- package/dist/src/handlers/tool-registry.js.map +1 -0
- package/dist/src/handlers/tool-types.d.ts +167 -0
- package/dist/src/handlers/tool-types.js +7 -0
- package/dist/src/handlers/tool-types.js.map +1 -0
- package/dist/src/handlers/tools.d.ts +25 -0
- package/dist/src/handlers/tools.js +1168 -0
- package/dist/src/handlers/tools.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +17 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/server.d.ts +28 -0
- package/dist/src/server.js +179 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/test-all-functions.d.ts +15 -0
- package/dist/src/test-all-functions.js +163 -0
- package/dist/src/test-all-functions.js.map +1 -0
- package/dist/src/types/mcp-tools.d.ts +53 -0
- package/dist/src/types/mcp-tools.js +77 -0
- package/dist/src/types/mcp-tools.js.map +1 -0
- package/dist/src/types/project-types.d.ts +22 -0
- package/dist/src/types/project-types.js +85 -0
- package/dist/src/types/project-types.js.map +1 -0
- package/dist/src/types/slots.d.ts +39 -0
- package/dist/src/types/slots.js +162 -0
- package/dist/src/types/slots.js.map +1 -0
- package/dist/src/types/tool-visibility.d.ts +36 -0
- package/dist/src/types/tool-visibility.js +510 -0
- package/dist/src/types/tool-visibility.js.map +1 -0
- package/dist/src/utils/auto-path-detection.d.ts +26 -0
- package/dist/src/utils/auto-path-detection.js +198 -0
- package/dist/src/utils/auto-path-detection.js.map +1 -0
- package/dist/src/utils/championship-format.d.ts +30 -0
- package/dist/src/utils/championship-format.js +79 -0
- package/dist/src/utils/championship-format.js.map +1 -0
- package/dist/src/utils/cli-detector.d.ts +20 -0
- package/dist/src/utils/cli-detector.js +230 -0
- package/dist/src/utils/cli-detector.js.map +1 -0
- package/dist/src/utils/display-protocol.d.ts +57 -0
- package/dist/src/utils/display-protocol.js +131 -0
- package/dist/src/utils/display-protocol.js.map +1 -0
- package/dist/src/utils/faf-file-finder.d.ts +59 -0
- package/dist/src/utils/faf-file-finder.js +139 -0
- package/dist/src/utils/faf-file-finder.js.map +1 -0
- package/dist/src/utils/fuzzy-detector.d.ts +56 -0
- package/dist/src/utils/fuzzy-detector.js +221 -0
- package/dist/src/utils/fuzzy-detector.js.map +1 -0
- package/dist/src/utils/path-resolver.d.ts +51 -0
- package/dist/src/utils/path-resolver.js +214 -0
- package/dist/src/utils/path-resolver.js.map +1 -0
- package/dist/src/utils/type-guards.d.ts +9 -0
- package/dist/src/utils/type-guards.js +27 -0
- package/dist/src/utils/type-guards.js.map +1 -0
- package/dist/src/utils/username-detector.d.ts +27 -0
- package/dist/src/utils/username-detector.js +90 -0
- package/dist/src/utils/username-detector.js.map +1 -0
- package/dist/src/utils/visual-style.d.ts +62 -0
- package/dist/src/utils/visual-style.js +164 -0
- package/dist/src/utils/visual-style.js.map +1 -0
- package/dist/src/version.d.ts +9 -0
- package/dist/src/version.js +37 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +114 -0
- package/scripts/discord-sync-curated.js +233 -0
- package/scripts/discord-sync-final.js +218 -0
- package/scripts/discord-sync-simple.js +175 -0
- package/scripts/discord-sync-working.js +187 -0
- package/scripts/discord-sync.js +181 -0
- package/scripts/postinstall.js +46 -0
- package/skill/SKILL.md +385 -0
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 📁 File Utilities
|
|
4
|
+
* Helper functions for finding and working with .faf files
|
|
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.findFafFile = findFafFile;
|
|
11
|
+
exports.fileExists = fileExists;
|
|
12
|
+
exports.getFileModTime = getFileModTime;
|
|
13
|
+
exports.findPackageJson = findPackageJson;
|
|
14
|
+
exports.findPyprojectToml = findPyprojectToml;
|
|
15
|
+
exports.findRequirementsTxt = findRequirementsTxt;
|
|
16
|
+
exports.findTsConfig = findTsConfig;
|
|
17
|
+
exports.analyzeTsConfig = analyzeTsConfig;
|
|
18
|
+
exports.findN8nWorkflows = findN8nWorkflows;
|
|
19
|
+
exports.findMakeScenarios = findMakeScenarios;
|
|
20
|
+
exports.findOpalMiniApps = findOpalMiniApps;
|
|
21
|
+
exports.findOpenAIAssistants = findOpenAIAssistants;
|
|
22
|
+
exports.detectProjectType = detectProjectType;
|
|
23
|
+
exports.daysSinceModified = daysSinceModified;
|
|
24
|
+
exports.detectPythonProjectType = detectPythonProjectType;
|
|
25
|
+
exports.detectPythonPatterns = detectPythonPatterns;
|
|
26
|
+
const fs_1 = require("fs");
|
|
27
|
+
const path_1 = __importDefault(require("path"));
|
|
28
|
+
const native_file_finder_js_1 = require("./native-file-finder.js");
|
|
29
|
+
const fafignore_parser_1 = require("./fafignore-parser");
|
|
30
|
+
/**
|
|
31
|
+
* Find project.faf file in current directory or parent directories
|
|
32
|
+
*
|
|
33
|
+
* v3.0.0: ONLY supports project.faf (no legacy .faf support)
|
|
34
|
+
*/
|
|
35
|
+
async function findFafFile(startDir = process.cwd()) {
|
|
36
|
+
let currentDir = path_1.default.resolve(startDir);
|
|
37
|
+
// Check up to 10 parent directories to avoid infinite loops
|
|
38
|
+
for (let i = 0; i < 10; i++) {
|
|
39
|
+
try {
|
|
40
|
+
const projectFafPath = path_1.default.join(currentDir, 'project.faf');
|
|
41
|
+
// Check if project.faf exists and is a file
|
|
42
|
+
if (await fileExists(projectFafPath)) {
|
|
43
|
+
const stats = await fs_1.promises.stat(projectFafPath);
|
|
44
|
+
if (stats.isFile()) {
|
|
45
|
+
return projectFafPath;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// v3.0.0: Support legacy .faf with migration suggestion
|
|
49
|
+
const legacyFafPath = path_1.default.join(currentDir, '.faf');
|
|
50
|
+
if (await fileExists(legacyFafPath)) {
|
|
51
|
+
const stats = await fs_1.promises.stat(legacyFafPath);
|
|
52
|
+
if (stats.isFile()) {
|
|
53
|
+
console.warn('\n💡 Using legacy .faf file. Run "faf migrate" to upgrade to project.faf (<1 second)\n');
|
|
54
|
+
return legacyFafPath;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Move to parent directory
|
|
58
|
+
const parentDir = path_1.default.dirname(currentDir);
|
|
59
|
+
if (parentDir === currentDir) {
|
|
60
|
+
// Reached filesystem root
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
currentDir = parentDir;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Skip this directory if we can't read it
|
|
67
|
+
const parentDir = path_1.default.dirname(currentDir);
|
|
68
|
+
if (parentDir === currentDir) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
currentDir = parentDir;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Check if file exists and is readable
|
|
78
|
+
*/
|
|
79
|
+
async function fileExists(filePath) {
|
|
80
|
+
try {
|
|
81
|
+
await fs_1.promises.access(filePath, fs_1.promises.constants.F_OK | fs_1.promises.constants.R_OK);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get file modification time
|
|
90
|
+
*/
|
|
91
|
+
async function getFileModTime(filePath) {
|
|
92
|
+
try {
|
|
93
|
+
const stats = await fs_1.promises.stat(filePath);
|
|
94
|
+
return stats.mtime;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Find package.json in project
|
|
102
|
+
*/
|
|
103
|
+
async function findPackageJson(startDir = process.cwd()) {
|
|
104
|
+
let currentDir = path_1.default.resolve(startDir); // Fix: resolve to absolute path
|
|
105
|
+
while (currentDir !== path_1.default.dirname(currentDir)) {
|
|
106
|
+
const packagePath = path_1.default.join(currentDir, "package.json");
|
|
107
|
+
if (await fileExists(packagePath)) {
|
|
108
|
+
return packagePath;
|
|
109
|
+
}
|
|
110
|
+
currentDir = path_1.default.dirname(currentDir);
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Find pyproject.toml in project (Python Poetry/PEP 518)
|
|
116
|
+
*/
|
|
117
|
+
async function findPyprojectToml(startDir = process.cwd()) {
|
|
118
|
+
let currentDir = path_1.default.resolve(startDir); // Fix: resolve to absolute path
|
|
119
|
+
while (currentDir !== path_1.default.dirname(currentDir)) {
|
|
120
|
+
const pyprojectPath = path_1.default.join(currentDir, "pyproject.toml");
|
|
121
|
+
if (await fileExists(pyprojectPath)) {
|
|
122
|
+
return pyprojectPath;
|
|
123
|
+
}
|
|
124
|
+
currentDir = path_1.default.dirname(currentDir);
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Find requirements.txt in project (Python pip)
|
|
130
|
+
*/
|
|
131
|
+
async function findRequirementsTxt(startDir = process.cwd()) {
|
|
132
|
+
let currentDir = path_1.default.resolve(startDir); // Fix: resolve to absolute path
|
|
133
|
+
while (currentDir !== path_1.default.dirname(currentDir)) {
|
|
134
|
+
const requirementsPath = path_1.default.join(currentDir, "requirements.txt");
|
|
135
|
+
if (await fileExists(requirementsPath)) {
|
|
136
|
+
return requirementsPath;
|
|
137
|
+
}
|
|
138
|
+
currentDir = path_1.default.dirname(currentDir);
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Find tsconfig.json in project (TypeScript)
|
|
144
|
+
*/
|
|
145
|
+
async function findTsConfig(startDir = process.cwd()) {
|
|
146
|
+
let currentDir = path_1.default.resolve(startDir); // Fix: resolve to absolute path
|
|
147
|
+
while (currentDir !== path_1.default.dirname(currentDir)) {
|
|
148
|
+
const tsconfigPath = path_1.default.join(currentDir, "tsconfig.json");
|
|
149
|
+
if (await fileExists(tsconfigPath)) {
|
|
150
|
+
return tsconfigPath;
|
|
151
|
+
}
|
|
152
|
+
currentDir = path_1.default.dirname(currentDir);
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Analyze tsconfig.json for F1-Inspired TypeScript intelligence
|
|
158
|
+
*/
|
|
159
|
+
async function analyzeTsConfig(filePath) {
|
|
160
|
+
try {
|
|
161
|
+
const content = await fs_1.promises.readFile(filePath, "utf-8");
|
|
162
|
+
// Strip comments from JSON (tsconfig.json often has comments)
|
|
163
|
+
const cleanedContent = content
|
|
164
|
+
.replace(/\/\*[\s\S]*?\*\//g, "") // Remove /* */ comments
|
|
165
|
+
.replace(/\/\/.*$/gm, ""); // Remove // comments
|
|
166
|
+
const config = JSON.parse(cleanedContent);
|
|
167
|
+
const compilerOptions = config.compilerOptions || {};
|
|
168
|
+
// Detect F1-Inspired engineering quality
|
|
169
|
+
const strictnessLevel = calculateStrictnessLevel(compilerOptions);
|
|
170
|
+
const frameworkIntegration = detectFrameworkIntegration(compilerOptions, config);
|
|
171
|
+
const performanceOptimizations = detectPerformanceConfig(compilerOptions);
|
|
172
|
+
return {
|
|
173
|
+
target: compilerOptions.target || "ES5",
|
|
174
|
+
module: compilerOptions.module || "CommonJS",
|
|
175
|
+
moduleResolution: compilerOptions.moduleResolution || "node",
|
|
176
|
+
strict: compilerOptions.strict || false,
|
|
177
|
+
strictnessLevel,
|
|
178
|
+
frameworkIntegration,
|
|
179
|
+
performanceOptimizations,
|
|
180
|
+
includes: config.include || [],
|
|
181
|
+
excludes: config.exclude || [],
|
|
182
|
+
engineeringQuality: assessEngineeringQuality(compilerOptions),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Detect n8n workflow files in directory
|
|
191
|
+
*/
|
|
192
|
+
async function findN8nWorkflows(projectDir = process.cwd()) {
|
|
193
|
+
const workflows = [];
|
|
194
|
+
try {
|
|
195
|
+
const files = await fs_1.promises.readdir(projectDir);
|
|
196
|
+
for (const file of files) {
|
|
197
|
+
if (file.endsWith('.json') && !file.includes('package')) {
|
|
198
|
+
try {
|
|
199
|
+
const filePath = path_1.default.join(projectDir, file);
|
|
200
|
+
const content = await fs_1.promises.readFile(filePath, 'utf-8');
|
|
201
|
+
const json = JSON.parse(content);
|
|
202
|
+
// Check if it's an n8n workflow (has nodes, connections, and name)
|
|
203
|
+
if (json.nodes && Array.isArray(json.nodes) &&
|
|
204
|
+
json.connections && typeof json.connections === 'object' &&
|
|
205
|
+
json.name && typeof json.name === 'string') {
|
|
206
|
+
workflows.push(file);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Not valid JSON or not n8n format, skip
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Directory read error, return empty
|
|
217
|
+
}
|
|
218
|
+
return workflows;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Find Make.com scenario files in a project directory
|
|
222
|
+
*
|
|
223
|
+
* Detects Make.com blueprint JSON files by checking for:
|
|
224
|
+
* - name string (scenario name)
|
|
225
|
+
* - flow array (modules/steps)
|
|
226
|
+
* - metadata object (scenario metadata)
|
|
227
|
+
*
|
|
228
|
+
* @param projectDir - Directory to search (defaults to cwd)
|
|
229
|
+
* @returns Array of Make.com scenario file names
|
|
230
|
+
*/
|
|
231
|
+
async function findMakeScenarios(projectDir = process.cwd()) {
|
|
232
|
+
const scenarios = [];
|
|
233
|
+
try {
|
|
234
|
+
const files = await fs_1.promises.readdir(projectDir);
|
|
235
|
+
for (const file of files) {
|
|
236
|
+
if (file.endsWith('.json') && !file.includes('package')) {
|
|
237
|
+
try {
|
|
238
|
+
const filePath = path_1.default.join(projectDir, file);
|
|
239
|
+
const content = await fs_1.promises.readFile(filePath, 'utf-8');
|
|
240
|
+
const json = JSON.parse(content);
|
|
241
|
+
// Check if it's a Make.com blueprint (has name, flow array, and metadata)
|
|
242
|
+
if (json.name && typeof json.name === 'string' &&
|
|
243
|
+
json.flow && Array.isArray(json.flow) &&
|
|
244
|
+
json.metadata && typeof json.metadata === 'object') {
|
|
245
|
+
scenarios.push(file);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// Not valid JSON or not Make format, skip
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// Directory read error, return empty
|
|
256
|
+
}
|
|
257
|
+
return scenarios;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Find Google Opal mini-app files in a project directory
|
|
261
|
+
*
|
|
262
|
+
* Detects Opal mini-app JSON files by checking for:
|
|
263
|
+
* - steps array (mini-app steps)
|
|
264
|
+
* - model string (AI model used)
|
|
265
|
+
*
|
|
266
|
+
* @param projectDir - Directory to search (defaults to cwd)
|
|
267
|
+
* @returns Array of Opal mini-app file names
|
|
268
|
+
*/
|
|
269
|
+
async function findOpalMiniApps(projectDir = process.cwd()) {
|
|
270
|
+
const miniApps = [];
|
|
271
|
+
try {
|
|
272
|
+
const files = await fs_1.promises.readdir(projectDir);
|
|
273
|
+
for (const file of files) {
|
|
274
|
+
if (file.endsWith('.json') && !file.includes('package')) {
|
|
275
|
+
try {
|
|
276
|
+
const filePath = path_1.default.join(projectDir, file);
|
|
277
|
+
const content = await fs_1.promises.readFile(filePath, 'utf-8');
|
|
278
|
+
const json = JSON.parse(content);
|
|
279
|
+
// Check if it's an Opal mini-app (has steps and model)
|
|
280
|
+
if (json.steps && Array.isArray(json.steps) &&
|
|
281
|
+
json.model && typeof json.model === 'string') {
|
|
282
|
+
miniApps.push(file);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// Not valid JSON or not Opal format, skip
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
// Directory read error, return empty
|
|
293
|
+
}
|
|
294
|
+
return miniApps;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Find OpenAI Assistant files in a project directory
|
|
298
|
+
*
|
|
299
|
+
* Detects OpenAI Assistant JSON files (OpenAPI 3.x schemas) by checking for:
|
|
300
|
+
* - openapi string (OpenAPI version)
|
|
301
|
+
* - paths object (API endpoints/actions)
|
|
302
|
+
*
|
|
303
|
+
* @param projectDir - Directory to search (defaults to cwd)
|
|
304
|
+
* @returns Array of OpenAI Assistant file names
|
|
305
|
+
*/
|
|
306
|
+
async function findOpenAIAssistants(projectDir = process.cwd()) {
|
|
307
|
+
const assistants = [];
|
|
308
|
+
try {
|
|
309
|
+
const files = await fs_1.promises.readdir(projectDir);
|
|
310
|
+
for (const file of files) {
|
|
311
|
+
if (file.endsWith('.json') && !file.includes('package')) {
|
|
312
|
+
try {
|
|
313
|
+
const filePath = path_1.default.join(projectDir, file);
|
|
314
|
+
const content = await fs_1.promises.readFile(filePath, 'utf-8');
|
|
315
|
+
const json = JSON.parse(content);
|
|
316
|
+
// Check if it's an OpenAI Assistant schema (has openapi and paths)
|
|
317
|
+
if (json.openapi && typeof json.openapi === 'string' &&
|
|
318
|
+
json.paths && typeof json.paths === 'object') {
|
|
319
|
+
assistants.push(file);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
// Not valid JSON or not OpenAI format, skip
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
// Directory read error, return empty
|
|
330
|
+
}
|
|
331
|
+
return assistants;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Detect project type from files and structure
|
|
335
|
+
*
|
|
336
|
+
* CHAMPIONSHIP DETECTION STRATEGY:
|
|
337
|
+
* 1. 😽 TURBO-CAT: Format discovery (finds config files)
|
|
338
|
+
* 2. 🛂 TSA: Dependency intelligence (analyzes actual usage)
|
|
339
|
+
* 3. Cross-reference both engines for definitive answer
|
|
340
|
+
* 4. Fallback to file patterns if engines unavailable
|
|
341
|
+
*
|
|
342
|
+
* Goal: Championship-grade detection using existing engines
|
|
343
|
+
*/
|
|
344
|
+
async function detectProjectType(projectDir = process.cwd()) {
|
|
345
|
+
// PHASE 1: TURBO-CAT + TSA CHAMPIONSHIP DETECTION
|
|
346
|
+
// ============================================================================
|
|
347
|
+
try {
|
|
348
|
+
// Try to use TSA for smart dependency analysis (if package.json exists)
|
|
349
|
+
const packageJsonPath = path_1.default.join(projectDir, "package.json");
|
|
350
|
+
if (await fileExists(packageJsonPath)) {
|
|
351
|
+
try {
|
|
352
|
+
// Dynamic import to avoid circular dependencies and performance impact
|
|
353
|
+
const { DependencyTSA } = await import('../engines/dependency-tsa.js');
|
|
354
|
+
const tsa = new DependencyTSA(projectDir);
|
|
355
|
+
const report = await tsa.inspect();
|
|
356
|
+
// Analyze CORE dependencies (>10 imports = actually used)
|
|
357
|
+
const coreDeps = report.inspections
|
|
358
|
+
.filter((i) => i.status === 'CORE')
|
|
359
|
+
.map((i) => i.package);
|
|
360
|
+
const activeDeps = report.inspections
|
|
361
|
+
.filter((i) => i.status === 'ACTIVE')
|
|
362
|
+
.map((i) => i.package);
|
|
363
|
+
// Read package.json for structural hints
|
|
364
|
+
const packageContent = await fs_1.promises.readFile(packageJsonPath, "utf-8");
|
|
365
|
+
const packageData = JSON.parse(packageContent);
|
|
366
|
+
// Check for TypeScript
|
|
367
|
+
const hasTypeScript = await fileExists(path_1.default.join(projectDir, "tsconfig.json")) ||
|
|
368
|
+
coreDeps.includes('typescript') ||
|
|
369
|
+
activeDeps.includes('typescript');
|
|
370
|
+
// PRIORITY 1: CLI DETECTION (package.json.bin is DEFINITIVE)
|
|
371
|
+
if (packageData.bin) {
|
|
372
|
+
return hasTypeScript ? "cli-ts" : "cli";
|
|
373
|
+
}
|
|
374
|
+
// Secondary CLI check using TSA intelligence
|
|
375
|
+
const cliDeps = ['commander', 'yargs', 'oclif', 'inquirer'];
|
|
376
|
+
const hasCliCore = coreDeps.some((dep) => cliDeps.includes(dep));
|
|
377
|
+
const hasCliActive = activeDeps.some((dep) => cliDeps.includes(dep));
|
|
378
|
+
if (hasCliCore || hasCliActive) {
|
|
379
|
+
return hasTypeScript ? "cli-ts" : "cli";
|
|
380
|
+
}
|
|
381
|
+
// PRIORITY 2: FULLSTACK (based on CORE usage)
|
|
382
|
+
if (coreDeps.includes('next') || coreDeps.includes('@next/core')) {
|
|
383
|
+
return hasTypeScript ? "fullstack-ts" : "fullstack";
|
|
384
|
+
}
|
|
385
|
+
if (coreDeps.includes('nuxt') || coreDeps.includes('@nuxt/core')) {
|
|
386
|
+
return hasTypeScript ? "fullstack-ts" : "fullstack";
|
|
387
|
+
}
|
|
388
|
+
if (coreDeps.includes('@sveltejs/kit')) {
|
|
389
|
+
return hasTypeScript ? "svelte-ts" : "svelte";
|
|
390
|
+
}
|
|
391
|
+
// PRIORITY 3: FRONTEND (based on CORE usage)
|
|
392
|
+
if (coreDeps.includes('react') || coreDeps.includes('react-dom')) {
|
|
393
|
+
return hasTypeScript ? "react-ts" : "react";
|
|
394
|
+
}
|
|
395
|
+
if (coreDeps.includes('vue') || coreDeps.includes('@vue/core')) {
|
|
396
|
+
return hasTypeScript ? "vue-ts" : "vue";
|
|
397
|
+
}
|
|
398
|
+
if (coreDeps.includes('svelte')) {
|
|
399
|
+
return hasTypeScript ? "svelte-ts" : "svelte";
|
|
400
|
+
}
|
|
401
|
+
if (coreDeps.includes('angular') || coreDeps.includes('@angular/core')) {
|
|
402
|
+
return "angular";
|
|
403
|
+
}
|
|
404
|
+
// PRIORITY 4: BACKEND/API (based on CORE usage)
|
|
405
|
+
const backendFrameworks = ['express', 'fastify', 'koa', 'hapi'];
|
|
406
|
+
if (coreDeps.some((dep) => backendFrameworks.includes(dep))) {
|
|
407
|
+
return hasTypeScript ? "node-api-ts" : "node-api";
|
|
408
|
+
}
|
|
409
|
+
// If TSA worked but found nothing definitive, continue to fallback
|
|
410
|
+
}
|
|
411
|
+
catch (tsaError) {
|
|
412
|
+
// TSA failed or not available, continue to fallback detection
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
// TURBO-CAT/TSA unavailable, use fallback detection
|
|
418
|
+
}
|
|
419
|
+
// PHASE 2: FALLBACK DETECTION (when engines unavailable)
|
|
420
|
+
// ============================================================================
|
|
421
|
+
// TypeScript detection - check for tsconfig.json
|
|
422
|
+
const tsconfigPath = path_1.default.join(projectDir, "tsconfig.json");
|
|
423
|
+
let hasTypeScript = false;
|
|
424
|
+
if (await fileExists(tsconfigPath)) {
|
|
425
|
+
hasTypeScript = true;
|
|
426
|
+
}
|
|
427
|
+
// Check for package.json (fallback to naive dependency checking)
|
|
428
|
+
const packageJsonPath = path_1.default.join(projectDir, "package.json");
|
|
429
|
+
if (await fileExists(packageJsonPath)) {
|
|
430
|
+
try {
|
|
431
|
+
const packageContent = await fs_1.promises.readFile(packageJsonPath, "utf-8");
|
|
432
|
+
const packageData = JSON.parse(packageContent);
|
|
433
|
+
// Check dependencies for framework indicators (NAIVE - no usage analysis)
|
|
434
|
+
const deps = {
|
|
435
|
+
...packageData.dependencies,
|
|
436
|
+
...packageData.devDependencies,
|
|
437
|
+
};
|
|
438
|
+
// Detect TypeScript in dependencies
|
|
439
|
+
if (deps.typescript ||
|
|
440
|
+
deps["@types/node"] ||
|
|
441
|
+
Object.keys(deps).some((dep) => dep.startsWith("@types/"))) {
|
|
442
|
+
hasTypeScript = true;
|
|
443
|
+
}
|
|
444
|
+
// CLI detection (structural only, no TSA intelligence)
|
|
445
|
+
if (packageData.bin) {
|
|
446
|
+
return hasTypeScript ? "cli-ts" : "cli";
|
|
447
|
+
}
|
|
448
|
+
const hasCliDeps = deps.commander || deps.yargs || deps.oclif || deps.inquirer;
|
|
449
|
+
const hasCliKeywords = packageData.keywords?.includes('cli') ||
|
|
450
|
+
packageData.keywords?.includes('command-line');
|
|
451
|
+
const hasCliName = packageData.name?.includes('cli');
|
|
452
|
+
if (hasCliDeps || hasCliKeywords || hasCliName) {
|
|
453
|
+
return hasTypeScript ? "cli-ts" : "cli";
|
|
454
|
+
}
|
|
455
|
+
// Framework detection (naive - just checks if dependency exists)
|
|
456
|
+
if (deps.next || deps["@next/core"]) {
|
|
457
|
+
return hasTypeScript ? "fullstack-ts" : "fullstack";
|
|
458
|
+
}
|
|
459
|
+
if (deps.nuxt || deps["@nuxt/core"]) {
|
|
460
|
+
return hasTypeScript ? "fullstack-ts" : "fullstack";
|
|
461
|
+
}
|
|
462
|
+
if (deps["@sveltejs/kit"]) {
|
|
463
|
+
return hasTypeScript ? "svelte-ts" : "svelte";
|
|
464
|
+
}
|
|
465
|
+
if (deps.react || deps["react-dom"]) {
|
|
466
|
+
return hasTypeScript ? "react-ts" : "react";
|
|
467
|
+
}
|
|
468
|
+
if (deps.vue || deps["@vue/core"]) {
|
|
469
|
+
return hasTypeScript ? "vue-ts" : "vue";
|
|
470
|
+
}
|
|
471
|
+
if (deps.svelte) {
|
|
472
|
+
return hasTypeScript ? "svelte-ts" : "svelte";
|
|
473
|
+
}
|
|
474
|
+
if (deps.angular || deps["@angular/core"]) {
|
|
475
|
+
return "angular";
|
|
476
|
+
}
|
|
477
|
+
if (deps.express || deps.fastify || deps.koa || deps.hapi) {
|
|
478
|
+
return hasTypeScript ? "node-api-ts" : "node-api";
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
catch {
|
|
482
|
+
// Continue with file-based detection
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
// PHASE 3: PYTHON DETECTION (check for Python-specific files)
|
|
486
|
+
// ============================================================================
|
|
487
|
+
const pythonType = await detectPythonProjectType(projectDir);
|
|
488
|
+
if (pythonType !== "latest-idea") {
|
|
489
|
+
return pythonType;
|
|
490
|
+
}
|
|
491
|
+
// PHASE 3: FILE-BASED DETECTION (when package.json unavailable or inconclusive)
|
|
492
|
+
// ============================================================================
|
|
493
|
+
const ignorePatterns = await (0, fafignore_parser_1.parseFafIgnore)(projectDir);
|
|
494
|
+
// File-based detection - using native file finder (NO GLOB!)
|
|
495
|
+
const files = await native_file_finder_js_1.globReplacements.allSource(projectDir, {
|
|
496
|
+
ignore: ignorePatterns.filter((p) => !p.startsWith("*.")) // Remove *.ext patterns
|
|
497
|
+
});
|
|
498
|
+
// ============================================================================
|
|
499
|
+
// PRIORITY 5: PYTHON FILE DETECTION (fallback when no pyproject.toml/requirements.txt)
|
|
500
|
+
// ============================================================================
|
|
501
|
+
if (files.some((f) => f.endsWith(".py"))) {
|
|
502
|
+
const pythonPatternType = await detectPythonPatterns(projectDir, files.filter((f) => f.endsWith(".py")));
|
|
503
|
+
if (pythonPatternType !== "python-generic") {
|
|
504
|
+
return pythonPatternType;
|
|
505
|
+
}
|
|
506
|
+
return "python-generic";
|
|
507
|
+
}
|
|
508
|
+
// ============================================================================
|
|
509
|
+
// PRIORITY 6: FRAMEWORK FILE PATTERNS (when no package.json found)
|
|
510
|
+
// ============================================================================
|
|
511
|
+
// TypeScript file detection
|
|
512
|
+
if (files.some((f) => f.endsWith(".ts") && !f.endsWith(".d.ts"))) {
|
|
513
|
+
hasTypeScript = true;
|
|
514
|
+
}
|
|
515
|
+
// Check for framework-specific file extensions
|
|
516
|
+
const hasSvelteFiles = files.some((f) => f.endsWith(".svelte"));
|
|
517
|
+
const hasReactFiles = files.some((f) => f.endsWith(".jsx") || f.endsWith(".tsx"));
|
|
518
|
+
const hasVueFiles = files.some((f) => f.endsWith(".vue"));
|
|
519
|
+
if (hasSvelteFiles) {
|
|
520
|
+
return hasTypeScript ? "svelte-ts" : "svelte";
|
|
521
|
+
}
|
|
522
|
+
if (hasReactFiles) {
|
|
523
|
+
return hasTypeScript ? "react-ts" : "react";
|
|
524
|
+
}
|
|
525
|
+
if (hasVueFiles) {
|
|
526
|
+
return hasTypeScript ? "vue-ts" : "vue";
|
|
527
|
+
}
|
|
528
|
+
// ============================================================================
|
|
529
|
+
// PRIORITY 7: STATIC HTML DETECTION (no package.json, has HTML/CSS)
|
|
530
|
+
// ============================================================================
|
|
531
|
+
const hasIndexHtml = files.some((f) => f.endsWith('index.html') || f === 'index.html');
|
|
532
|
+
const hasCssFiles = files.some((f) => f.endsWith('.css'));
|
|
533
|
+
const hasHtmlFiles = files.some((f) => f.endsWith('.html'));
|
|
534
|
+
// Check for package.json ONLY in project directory (not parent directories)
|
|
535
|
+
const projectPackageJson = path_1.default.join(projectDir, 'package.json');
|
|
536
|
+
const hasProjectPackageJson = await fileExists(projectPackageJson);
|
|
537
|
+
// Detect static HTML: index.html without package.json in project dir + (CSS files OR other HTML files)
|
|
538
|
+
if (hasIndexHtml && !hasProjectPackageJson && (hasCssFiles || hasHtmlFiles)) {
|
|
539
|
+
return 'static-html';
|
|
540
|
+
}
|
|
541
|
+
// ============================================================================
|
|
542
|
+
// PRIORITY 8: PURE TYPESCRIPT PROJECT (has .ts files but no framework)
|
|
543
|
+
// ============================================================================
|
|
544
|
+
if (hasTypeScript) {
|
|
545
|
+
return "typescript";
|
|
546
|
+
}
|
|
547
|
+
// ============================================================================
|
|
548
|
+
// FINAL FALLBACK: Unknown/early-stage project
|
|
549
|
+
// ============================================================================
|
|
550
|
+
return "latest-idea";
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Calculate days since file was modified
|
|
554
|
+
*/
|
|
555
|
+
function daysSinceModified(date) {
|
|
556
|
+
const now = new Date();
|
|
557
|
+
const diffTime = Math.abs(now.getTime() - date.getTime());
|
|
558
|
+
return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Detect Python project type using dependency files (Option A)
|
|
562
|
+
*/
|
|
563
|
+
async function detectPythonProjectType(projectDir) {
|
|
564
|
+
// Priority order: pyproject.toml > requirements.txt
|
|
565
|
+
const pyprojectPath = await findPyprojectToml(projectDir);
|
|
566
|
+
if (pyprojectPath) {
|
|
567
|
+
const framework = await analyzePyprojectToml(pyprojectPath);
|
|
568
|
+
if (framework) {
|
|
569
|
+
return framework;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
const requirementsPath = await findRequirementsTxt(projectDir);
|
|
573
|
+
if (requirementsPath) {
|
|
574
|
+
const framework = await analyzeRequirementsTxt(requirementsPath);
|
|
575
|
+
if (framework) {
|
|
576
|
+
return framework;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return "latest-idea";
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Analyze pyproject.toml for Python frameworks
|
|
583
|
+
*/
|
|
584
|
+
async function analyzePyprojectToml(filePath) {
|
|
585
|
+
try {
|
|
586
|
+
const content = await fs_1.promises.readFile(filePath, "utf-8");
|
|
587
|
+
// Simple string-based detection for now (could use TOML parser later)
|
|
588
|
+
if (content.includes("fastapi")) {
|
|
589
|
+
return "python-fastapi";
|
|
590
|
+
}
|
|
591
|
+
if (content.includes("django")) {
|
|
592
|
+
return "python-django";
|
|
593
|
+
}
|
|
594
|
+
if (content.includes("flask")) {
|
|
595
|
+
return "python-flask";
|
|
596
|
+
}
|
|
597
|
+
if (content.includes("starlette")) {
|
|
598
|
+
return "python-starlette";
|
|
599
|
+
}
|
|
600
|
+
// If it has Python dependencies but no specific framework
|
|
601
|
+
if (content.includes("python = ")) {
|
|
602
|
+
return "python-generic";
|
|
603
|
+
}
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
catch {
|
|
607
|
+
return null;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Analyze requirements.txt for Python frameworks
|
|
612
|
+
*/
|
|
613
|
+
async function analyzeRequirementsTxt(filePath) {
|
|
614
|
+
try {
|
|
615
|
+
const content = await fs_1.promises.readFile(filePath, "utf-8");
|
|
616
|
+
if (content.includes("fastapi")) {
|
|
617
|
+
return "python-fastapi";
|
|
618
|
+
}
|
|
619
|
+
if (content.includes("django")) {
|
|
620
|
+
return "python-django";
|
|
621
|
+
}
|
|
622
|
+
if (content.includes("flask")) {
|
|
623
|
+
return "python-flask";
|
|
624
|
+
}
|
|
625
|
+
if (content.includes("starlette")) {
|
|
626
|
+
return "python-starlette";
|
|
627
|
+
}
|
|
628
|
+
// Any Python packages detected
|
|
629
|
+
if (content.trim().length > 0) {
|
|
630
|
+
return "python-generic";
|
|
631
|
+
}
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
catch {
|
|
635
|
+
return null;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Detect Python frameworks using code patterns (Option B)
|
|
640
|
+
*/
|
|
641
|
+
async function detectPythonPatterns(projectDir, pythonFiles) {
|
|
642
|
+
try {
|
|
643
|
+
// Check main Python files first (main.py, app.py, api.py)
|
|
644
|
+
const mainFiles = pythonFiles.filter((f) => f.includes("main.py") || f.includes("app.py") || f.includes("api.py"));
|
|
645
|
+
const filesToCheck = mainFiles.length > 0 ? mainFiles : pythonFiles.slice(0, 5);
|
|
646
|
+
for (const file of filesToCheck) {
|
|
647
|
+
const filePath = path_1.default.join(projectDir, file);
|
|
648
|
+
try {
|
|
649
|
+
const content = await fs_1.promises.readFile(filePath, "utf-8");
|
|
650
|
+
// FastAPI patterns
|
|
651
|
+
if (content.includes("from fastapi import") ||
|
|
652
|
+
content.includes("FastAPI()")) {
|
|
653
|
+
return "python-fastapi";
|
|
654
|
+
}
|
|
655
|
+
// Django patterns
|
|
656
|
+
if (content.includes("from django.") ||
|
|
657
|
+
content.includes("django.http")) {
|
|
658
|
+
return "python-django";
|
|
659
|
+
}
|
|
660
|
+
// Flask patterns
|
|
661
|
+
if (content.includes("from flask import") ||
|
|
662
|
+
content.includes("Flask(")) {
|
|
663
|
+
return "python-flask";
|
|
664
|
+
}
|
|
665
|
+
// Starlette patterns
|
|
666
|
+
if (content.includes("from starlette.") ||
|
|
667
|
+
content.includes("Starlette(")) {
|
|
668
|
+
return "python-starlette";
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
catch {
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return "python-generic";
|
|
676
|
+
}
|
|
677
|
+
catch {
|
|
678
|
+
return "python-generic";
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Calculate TypeScript strictness level for F1-Inspired quality assessment
|
|
683
|
+
*/
|
|
684
|
+
function calculateStrictnessLevel(compilerOptions) {
|
|
685
|
+
let strictnessScore = 0;
|
|
686
|
+
// Basic strictness
|
|
687
|
+
if (compilerOptions.strict) {
|
|
688
|
+
strictnessScore += 2;
|
|
689
|
+
}
|
|
690
|
+
if (compilerOptions.noImplicitAny) {
|
|
691
|
+
strictnessScore += 1;
|
|
692
|
+
}
|
|
693
|
+
if (compilerOptions.strictNullChecks) {
|
|
694
|
+
strictnessScore += 1;
|
|
695
|
+
}
|
|
696
|
+
// Advanced strictness
|
|
697
|
+
if (compilerOptions.exactOptionalPropertyTypes) {
|
|
698
|
+
strictnessScore += 2;
|
|
699
|
+
}
|
|
700
|
+
if (compilerOptions.noUncheckedIndexedAccess) {
|
|
701
|
+
strictnessScore += 2;
|
|
702
|
+
}
|
|
703
|
+
if (compilerOptions.noImplicitReturns) {
|
|
704
|
+
strictnessScore += 1;
|
|
705
|
+
}
|
|
706
|
+
if (compilerOptions.noFallthroughCasesInSwitch) {
|
|
707
|
+
strictnessScore += 1;
|
|
708
|
+
}
|
|
709
|
+
if (compilerOptions.noUnusedLocals) {
|
|
710
|
+
strictnessScore += 1;
|
|
711
|
+
}
|
|
712
|
+
if (compilerOptions.noUnusedParameters) {
|
|
713
|
+
strictnessScore += 1;
|
|
714
|
+
}
|
|
715
|
+
// F1-Inspired ultra-strict
|
|
716
|
+
if (compilerOptions.allowUnreachableCode === false) {
|
|
717
|
+
strictnessScore += 1;
|
|
718
|
+
}
|
|
719
|
+
if (compilerOptions.allowUnusedLabels === false) {
|
|
720
|
+
strictnessScore += 1;
|
|
721
|
+
}
|
|
722
|
+
if (compilerOptions.noPropertyAccessFromIndexSignature) {
|
|
723
|
+
strictnessScore += 1;
|
|
724
|
+
}
|
|
725
|
+
if (compilerOptions.verbatimModuleSyntax) {
|
|
726
|
+
strictnessScore += 1;
|
|
727
|
+
}
|
|
728
|
+
if (strictnessScore >= 12) {
|
|
729
|
+
return "f1_inspired";
|
|
730
|
+
}
|
|
731
|
+
if (strictnessScore >= 8) {
|
|
732
|
+
return "ultra_strict";
|
|
733
|
+
}
|
|
734
|
+
if (strictnessScore >= 4) {
|
|
735
|
+
return "strict";
|
|
736
|
+
}
|
|
737
|
+
return "basic";
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Detect framework integration patterns
|
|
741
|
+
*/
|
|
742
|
+
function detectFrameworkIntegration(compilerOptions, config) {
|
|
743
|
+
const includes = config.include || [];
|
|
744
|
+
const includesStr = includes.join(" ");
|
|
745
|
+
// Svelte detection
|
|
746
|
+
if (includesStr.includes("svelte") || config.extends?.includes("svelte")) {
|
|
747
|
+
if (compilerOptions.verbatimModuleSyntax) {
|
|
748
|
+
return "svelte_5_runes_native";
|
|
749
|
+
}
|
|
750
|
+
return "svelte_native";
|
|
751
|
+
}
|
|
752
|
+
// React detection
|
|
753
|
+
if (compilerOptions.jsx) {
|
|
754
|
+
if (compilerOptions.jsx === "react-jsx") {
|
|
755
|
+
return "react_17_native";
|
|
756
|
+
}
|
|
757
|
+
return "react_native";
|
|
758
|
+
}
|
|
759
|
+
// Next.js detection
|
|
760
|
+
if (config.extends?.includes("next")) {
|
|
761
|
+
return "nextjs_native";
|
|
762
|
+
}
|
|
763
|
+
// Vue detection
|
|
764
|
+
if (includesStr.includes("vue")) {
|
|
765
|
+
return "vue_native";
|
|
766
|
+
}
|
|
767
|
+
// Node.js detection
|
|
768
|
+
if (compilerOptions.moduleResolution === "NodeNext") {
|
|
769
|
+
return "nodejs_native";
|
|
770
|
+
}
|
|
771
|
+
if (compilerOptions.module === "NodeNext") {
|
|
772
|
+
return "nodejs_esm_native";
|
|
773
|
+
}
|
|
774
|
+
// Pure TypeScript project detection
|
|
775
|
+
if (compilerOptions.target &&
|
|
776
|
+
compilerOptions.module &&
|
|
777
|
+
!compilerOptions.jsx) {
|
|
778
|
+
return "pure_typescript";
|
|
779
|
+
}
|
|
780
|
+
return "standard";
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Detect performance optimizations
|
|
784
|
+
*/
|
|
785
|
+
function detectPerformanceConfig(compilerOptions) {
|
|
786
|
+
const optimizations = [];
|
|
787
|
+
if (compilerOptions.target && compilerOptions.target.includes("2022")) {
|
|
788
|
+
optimizations.push("modern_target_es2022");
|
|
789
|
+
}
|
|
790
|
+
if (compilerOptions.moduleResolution === "NodeNext") {
|
|
791
|
+
optimizations.push("nodejs_native_modules");
|
|
792
|
+
}
|
|
793
|
+
if (compilerOptions.verbatimModuleSyntax) {
|
|
794
|
+
optimizations.push("verbatim_module_syntax");
|
|
795
|
+
}
|
|
796
|
+
if (compilerOptions.isolatedModules) {
|
|
797
|
+
optimizations.push("isolated_modules");
|
|
798
|
+
}
|
|
799
|
+
if (compilerOptions.skipLibCheck) {
|
|
800
|
+
optimizations.push("skip_lib_check");
|
|
801
|
+
}
|
|
802
|
+
if (compilerOptions.allowImportingTsExtensions) {
|
|
803
|
+
optimizations.push("ts_extension_imports");
|
|
804
|
+
}
|
|
805
|
+
return optimizations;
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Assess overall engineering quality based on configuration
|
|
809
|
+
*/
|
|
810
|
+
function assessEngineeringQuality(compilerOptions) {
|
|
811
|
+
let qualityScore = 0;
|
|
812
|
+
// Quality indicators
|
|
813
|
+
if (compilerOptions.declaration) {
|
|
814
|
+
qualityScore += 1;
|
|
815
|
+
}
|
|
816
|
+
if (compilerOptions.declarationMap) {
|
|
817
|
+
qualityScore += 1;
|
|
818
|
+
}
|
|
819
|
+
if (compilerOptions.sourceMap) {
|
|
820
|
+
qualityScore += 1;
|
|
821
|
+
}
|
|
822
|
+
if (compilerOptions.forceConsistentCasingInFileNames) {
|
|
823
|
+
qualityScore += 1;
|
|
824
|
+
}
|
|
825
|
+
if (compilerOptions.removeComments === false) {
|
|
826
|
+
qualityScore += 1;
|
|
827
|
+
} // Keeping docs
|
|
828
|
+
// F1-Inspired indicators
|
|
829
|
+
if (compilerOptions.exactOptionalPropertyTypes) {
|
|
830
|
+
qualityScore += 2;
|
|
831
|
+
}
|
|
832
|
+
if (compilerOptions.noUncheckedIndexedAccess) {
|
|
833
|
+
qualityScore += 2;
|
|
834
|
+
}
|
|
835
|
+
if (compilerOptions.verbatimModuleSyntax) {
|
|
836
|
+
qualityScore += 2;
|
|
837
|
+
}
|
|
838
|
+
if (qualityScore >= 8) {
|
|
839
|
+
return "f1_inspired";
|
|
840
|
+
}
|
|
841
|
+
if (qualityScore >= 5) {
|
|
842
|
+
return "professional";
|
|
843
|
+
}
|
|
844
|
+
return "standard";
|
|
845
|
+
}
|
|
846
|
+
//# sourceMappingURL=file-utils.js.map
|