depwire-cli 1.1.1 → 1.1.4
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/README.md +6 -4
- package/dist/{chunk-R263B2GF.js → chunk-M5BETAND.js} +8 -8
- package/dist/{chunk-Y2CGCAMZ.js → chunk-ZO3LWFDE.js} +630 -118
- package/dist/index.js +2 -2
- package/dist/mcpb-entry.js +2 -2
- package/dist/sdk.js +1 -1
- package/package.json +5 -2
- package/scripts/postinstall.js +25 -0
|
@@ -38,8 +38,9 @@ function scanDirectory(rootDir, baseDir = rootDir) {
|
|
|
38
38
|
const isKotlin = entry.endsWith(".kt") || entry.endsWith(".kts") || entry === "settings.gradle.kts" || entry === "settings.gradle";
|
|
39
39
|
const isPhp = entry.endsWith(".php");
|
|
40
40
|
const isSwift = entry.endsWith(".swift");
|
|
41
|
+
const isMojo = entry.endsWith(".mojo") || entry.endsWith(".\u{1F525}");
|
|
41
42
|
const isCppBuild = entry === "CMakeLists.txt" || entry === "conanfile.txt" || entry === "vcpkg.json";
|
|
42
|
-
if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCpp || isCSharp || isJava || isKotlin || isPhp || isSwift || isCppBuild) {
|
|
43
|
+
if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCpp || isCSharp || isJava || isKotlin || isPhp || isSwift || isMojo || isCppBuild) {
|
|
43
44
|
files.push(relative(rootDir, fullPath));
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -87,6 +88,8 @@ function findProjectRoot(startDir = process.cwd()) {
|
|
|
87
88
|
// PHP
|
|
88
89
|
"Package.swift",
|
|
89
90
|
// Swift (SPM)
|
|
91
|
+
"mojoproject.toml",
|
|
92
|
+
// Mojo
|
|
90
93
|
".git"
|
|
91
94
|
// Any git repo
|
|
92
95
|
];
|
|
@@ -121,10 +124,10 @@ function findProjectRoot(startDir = process.cwd()) {
|
|
|
121
124
|
|
|
122
125
|
// src/parser/index.ts
|
|
123
126
|
import { readFileSync as readFileSync11, statSync as statSync8 } from "fs";
|
|
124
|
-
import { join as
|
|
127
|
+
import { join as join15, resolve as resolve9 } from "path";
|
|
125
128
|
|
|
126
129
|
// src/parser/detect.ts
|
|
127
|
-
import { extname as
|
|
130
|
+
import { extname as extname10, basename as basename8 } from "path";
|
|
128
131
|
|
|
129
132
|
// src/parser/wasm-init.ts
|
|
130
133
|
import { Parser, Language } from "web-tree-sitter";
|
|
@@ -158,6 +161,7 @@ async function initParser() {
|
|
|
158
161
|
"kotlin": "tree-sitter-kotlin.wasm",
|
|
159
162
|
"php": "tree-sitter-php.wasm",
|
|
160
163
|
"swift": "tree-sitter-swift.wasm"
|
|
164
|
+
// Note: Mojo uses a pattern-based parser (no tree-sitter-mojo WASM available)
|
|
161
165
|
};
|
|
162
166
|
for (const [name, file] of Object.entries(grammarFiles)) {
|
|
163
167
|
const wasmPath = path.join(grammarsDir, file);
|
|
@@ -6805,6 +6809,351 @@ var swiftParser = {
|
|
|
6805
6809
|
parseFile: parseSwiftFile
|
|
6806
6810
|
};
|
|
6807
6811
|
|
|
6812
|
+
// src/parser/mojo.ts
|
|
6813
|
+
import { dirname as dirname13, join as join14, basename as basename7 } from "path";
|
|
6814
|
+
function parseMojoFile(filePath, sourceCode, projectRoot) {
|
|
6815
|
+
if (filePath.endsWith("mojoproject.toml")) {
|
|
6816
|
+
return parseMojoProject(filePath, sourceCode, projectRoot);
|
|
6817
|
+
}
|
|
6818
|
+
const context = {
|
|
6819
|
+
filePath,
|
|
6820
|
+
projectRoot,
|
|
6821
|
+
sourceCode,
|
|
6822
|
+
symbols: [],
|
|
6823
|
+
edges: [],
|
|
6824
|
+
currentScope: [],
|
|
6825
|
+
currentClass: null,
|
|
6826
|
+
imports: /* @__PURE__ */ new Map()
|
|
6827
|
+
};
|
|
6828
|
+
const lines = sourceCode.split("\n");
|
|
6829
|
+
parseLines(lines, context);
|
|
6830
|
+
return {
|
|
6831
|
+
filePath,
|
|
6832
|
+
symbols: context.symbols,
|
|
6833
|
+
edges: context.edges
|
|
6834
|
+
};
|
|
6835
|
+
}
|
|
6836
|
+
function parseLines(lines, context) {
|
|
6837
|
+
let i = 0;
|
|
6838
|
+
while (i < lines.length) {
|
|
6839
|
+
const line = lines[i];
|
|
6840
|
+
const trimmed = line.trimStart();
|
|
6841
|
+
const indent = line.length - trimmed.length;
|
|
6842
|
+
const lineNum = i + 1;
|
|
6843
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
6844
|
+
i++;
|
|
6845
|
+
continue;
|
|
6846
|
+
}
|
|
6847
|
+
if (trimmed.startsWith("@")) {
|
|
6848
|
+
i++;
|
|
6849
|
+
continue;
|
|
6850
|
+
}
|
|
6851
|
+
if (trimmed.startsWith("import ") || trimmed.startsWith("from ")) {
|
|
6852
|
+
processImport(trimmed, lineNum, context);
|
|
6853
|
+
i++;
|
|
6854
|
+
continue;
|
|
6855
|
+
}
|
|
6856
|
+
const fnMatch = trimmed.match(/^fn\s+(\w+)\s*[\[(]/);
|
|
6857
|
+
if (fnMatch) {
|
|
6858
|
+
const name = fnMatch[1];
|
|
6859
|
+
const endLine = findBlockEnd(lines, i, indent);
|
|
6860
|
+
addFunction(name, lineNum, endLine, context);
|
|
6861
|
+
i = endLine;
|
|
6862
|
+
continue;
|
|
6863
|
+
}
|
|
6864
|
+
const defMatch = trimmed.match(/^def\s+(\w+)\s*[\[(]/);
|
|
6865
|
+
if (defMatch) {
|
|
6866
|
+
const name = defMatch[1];
|
|
6867
|
+
const endLine = findBlockEnd(lines, i, indent);
|
|
6868
|
+
addFunction(name, lineNum, endLine, context);
|
|
6869
|
+
i = endLine;
|
|
6870
|
+
continue;
|
|
6871
|
+
}
|
|
6872
|
+
const structMatch = trimmed.match(/^struct\s+(\w+)/);
|
|
6873
|
+
if (structMatch) {
|
|
6874
|
+
const name = structMatch[1];
|
|
6875
|
+
const endLine = findBlockEnd(lines, i, indent);
|
|
6876
|
+
addType(name, "class", lineNum, endLine, context);
|
|
6877
|
+
parseStructBody(lines, i + 1, endLine, indent, name, context);
|
|
6878
|
+
i = endLine;
|
|
6879
|
+
continue;
|
|
6880
|
+
}
|
|
6881
|
+
const classMatch = trimmed.match(/^class\s+(\w+)/);
|
|
6882
|
+
if (classMatch) {
|
|
6883
|
+
const name = classMatch[1];
|
|
6884
|
+
const endLine = findBlockEnd(lines, i, indent);
|
|
6885
|
+
addType(name, "class", lineNum, endLine, context);
|
|
6886
|
+
parseStructBody(lines, i + 1, endLine, indent, name, context);
|
|
6887
|
+
i = endLine;
|
|
6888
|
+
continue;
|
|
6889
|
+
}
|
|
6890
|
+
const traitMatch = trimmed.match(/^trait\s+(\w+)/);
|
|
6891
|
+
if (traitMatch) {
|
|
6892
|
+
const name = traitMatch[1];
|
|
6893
|
+
const endLine = findBlockEnd(lines, i, indent);
|
|
6894
|
+
addType(name, "interface", lineNum, endLine, context);
|
|
6895
|
+
parseStructBody(lines, i + 1, endLine, indent, name, context);
|
|
6896
|
+
i = endLine;
|
|
6897
|
+
continue;
|
|
6898
|
+
}
|
|
6899
|
+
const aliasMatch = trimmed.match(/^alias\s+(\w+)\s*[=:]/);
|
|
6900
|
+
if (aliasMatch) {
|
|
6901
|
+
const name = aliasMatch[1];
|
|
6902
|
+
context.symbols.push({
|
|
6903
|
+
id: `${context.filePath}::${name}`,
|
|
6904
|
+
name,
|
|
6905
|
+
kind: "type_alias",
|
|
6906
|
+
filePath: context.filePath,
|
|
6907
|
+
startLine: lineNum,
|
|
6908
|
+
endLine: lineNum,
|
|
6909
|
+
exported: true
|
|
6910
|
+
});
|
|
6911
|
+
i++;
|
|
6912
|
+
continue;
|
|
6913
|
+
}
|
|
6914
|
+
const varMatch = trimmed.match(/^(var|let)\s+(\w+)/);
|
|
6915
|
+
if (varMatch && indent === 0) {
|
|
6916
|
+
const name = varMatch[2];
|
|
6917
|
+
const kind = varMatch[1] === "let" ? "constant" : "var";
|
|
6918
|
+
context.symbols.push({
|
|
6919
|
+
id: `${context.filePath}::${name}`,
|
|
6920
|
+
name,
|
|
6921
|
+
kind,
|
|
6922
|
+
filePath: context.filePath,
|
|
6923
|
+
startLine: lineNum,
|
|
6924
|
+
endLine: lineNum,
|
|
6925
|
+
exported: true
|
|
6926
|
+
});
|
|
6927
|
+
i++;
|
|
6928
|
+
continue;
|
|
6929
|
+
}
|
|
6930
|
+
processCallsInLine(trimmed, lineNum, context);
|
|
6931
|
+
i++;
|
|
6932
|
+
}
|
|
6933
|
+
}
|
|
6934
|
+
function processImport(line, lineNum, context) {
|
|
6935
|
+
let importName = null;
|
|
6936
|
+
const fromMatch = line.match(/^from\s+([\w.]+)\s+import\s+(.+)/);
|
|
6937
|
+
if (fromMatch) {
|
|
6938
|
+
const module = fromMatch[1];
|
|
6939
|
+
const symbols = fromMatch[2].split(",").map((s) => s.trim());
|
|
6940
|
+
importName = module;
|
|
6941
|
+
for (const sym of symbols) {
|
|
6942
|
+
const cleanSym = sym.split(" as ")[0].trim();
|
|
6943
|
+
if (cleanSym && cleanSym !== "*") {
|
|
6944
|
+
context.imports.set(cleanSym, `${module}::${cleanSym}`);
|
|
6945
|
+
}
|
|
6946
|
+
}
|
|
6947
|
+
} else {
|
|
6948
|
+
const importMatch = line.match(/^import\s+([\w.]+)(?:\s+as\s+(\w+))?/);
|
|
6949
|
+
if (importMatch) {
|
|
6950
|
+
importName = importMatch[1];
|
|
6951
|
+
const alias = importMatch[2] || importMatch[1].split(".").pop();
|
|
6952
|
+
context.imports.set(alias, `${importMatch[1]}::__module__`);
|
|
6953
|
+
}
|
|
6954
|
+
}
|
|
6955
|
+
if (importName) {
|
|
6956
|
+
context.symbols.push({
|
|
6957
|
+
id: `${context.filePath}::import:${importName}`,
|
|
6958
|
+
name: importName,
|
|
6959
|
+
kind: "import",
|
|
6960
|
+
filePath: context.filePath,
|
|
6961
|
+
startLine: lineNum,
|
|
6962
|
+
endLine: lineNum,
|
|
6963
|
+
exported: false
|
|
6964
|
+
});
|
|
6965
|
+
}
|
|
6966
|
+
}
|
|
6967
|
+
function addFunction(name, startLine, endLine, context) {
|
|
6968
|
+
const scope = context.currentClass || void 0;
|
|
6969
|
+
const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
|
|
6970
|
+
context.symbols.push({
|
|
6971
|
+
id: symbolId,
|
|
6972
|
+
name,
|
|
6973
|
+
kind: context.currentClass ? "method" : "function",
|
|
6974
|
+
filePath: context.filePath,
|
|
6975
|
+
startLine,
|
|
6976
|
+
endLine,
|
|
6977
|
+
exported: true,
|
|
6978
|
+
scope
|
|
6979
|
+
});
|
|
6980
|
+
}
|
|
6981
|
+
function addType(name, kind, startLine, endLine, context) {
|
|
6982
|
+
context.symbols.push({
|
|
6983
|
+
id: `${context.filePath}::${name}`,
|
|
6984
|
+
name,
|
|
6985
|
+
kind,
|
|
6986
|
+
filePath: context.filePath,
|
|
6987
|
+
startLine,
|
|
6988
|
+
endLine,
|
|
6989
|
+
exported: true
|
|
6990
|
+
});
|
|
6991
|
+
}
|
|
6992
|
+
function parseStructBody(lines, start, end, baseIndent, className, context) {
|
|
6993
|
+
const oldClass = context.currentClass;
|
|
6994
|
+
context.currentClass = className;
|
|
6995
|
+
let i = start;
|
|
6996
|
+
while (i < end && i < lines.length) {
|
|
6997
|
+
const line = lines[i];
|
|
6998
|
+
const trimmed = line.trimStart();
|
|
6999
|
+
const indent = line.length - trimmed.length;
|
|
7000
|
+
const lineNum = i + 1;
|
|
7001
|
+
if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("@")) {
|
|
7002
|
+
i++;
|
|
7003
|
+
continue;
|
|
7004
|
+
}
|
|
7005
|
+
if (indent <= baseIndent) break;
|
|
7006
|
+
const fnMatch = trimmed.match(/^(fn|def)\s+(\w+)\s*[\[(]/);
|
|
7007
|
+
if (fnMatch) {
|
|
7008
|
+
const name = fnMatch[2];
|
|
7009
|
+
const fnEnd = findBlockEnd(lines, i, indent);
|
|
7010
|
+
addFunction(name, lineNum, fnEnd, context);
|
|
7011
|
+
i = fnEnd;
|
|
7012
|
+
continue;
|
|
7013
|
+
}
|
|
7014
|
+
const varMatch = trimmed.match(/^(var|let)\s+(\w+)/);
|
|
7015
|
+
if (varMatch) {
|
|
7016
|
+
const name = varMatch[2];
|
|
7017
|
+
context.symbols.push({
|
|
7018
|
+
id: `${context.filePath}::${className}.${name}`,
|
|
7019
|
+
name,
|
|
7020
|
+
kind: "property",
|
|
7021
|
+
filePath: context.filePath,
|
|
7022
|
+
startLine: lineNum,
|
|
7023
|
+
endLine: lineNum,
|
|
7024
|
+
exported: true,
|
|
7025
|
+
scope: className
|
|
7026
|
+
});
|
|
7027
|
+
i++;
|
|
7028
|
+
continue;
|
|
7029
|
+
}
|
|
7030
|
+
const aliasMatch = trimmed.match(/^alias\s+(\w+)\s*[=:]/);
|
|
7031
|
+
if (aliasMatch) {
|
|
7032
|
+
const name = aliasMatch[1];
|
|
7033
|
+
context.symbols.push({
|
|
7034
|
+
id: `${context.filePath}::${className}.${name}`,
|
|
7035
|
+
name,
|
|
7036
|
+
kind: "type_alias",
|
|
7037
|
+
filePath: context.filePath,
|
|
7038
|
+
startLine: lineNum,
|
|
7039
|
+
endLine: lineNum,
|
|
7040
|
+
exported: true,
|
|
7041
|
+
scope: className
|
|
7042
|
+
});
|
|
7043
|
+
i++;
|
|
7044
|
+
continue;
|
|
7045
|
+
}
|
|
7046
|
+
i++;
|
|
7047
|
+
}
|
|
7048
|
+
context.currentClass = oldClass;
|
|
7049
|
+
}
|
|
7050
|
+
function processCallsInLine(line, lineNum, context) {
|
|
7051
|
+
const callRegex = /\b(\w+)\s*(?:\[[^\]]*\]\s*)?\(/g;
|
|
7052
|
+
let match;
|
|
7053
|
+
const builtins = /* @__PURE__ */ new Set([
|
|
7054
|
+
"print",
|
|
7055
|
+
"len",
|
|
7056
|
+
"range",
|
|
7057
|
+
"int",
|
|
7058
|
+
"str",
|
|
7059
|
+
"float",
|
|
7060
|
+
"bool",
|
|
7061
|
+
"type",
|
|
7062
|
+
"if",
|
|
7063
|
+
"elif",
|
|
7064
|
+
"while",
|
|
7065
|
+
"for",
|
|
7066
|
+
"return",
|
|
7067
|
+
"raise",
|
|
7068
|
+
"assert",
|
|
7069
|
+
"fn",
|
|
7070
|
+
"def",
|
|
7071
|
+
"struct",
|
|
7072
|
+
"class",
|
|
7073
|
+
"trait",
|
|
7074
|
+
"alias",
|
|
7075
|
+
"var",
|
|
7076
|
+
"let",
|
|
7077
|
+
"from",
|
|
7078
|
+
"import",
|
|
7079
|
+
"inout",
|
|
7080
|
+
"owned",
|
|
7081
|
+
"borrowed"
|
|
7082
|
+
]);
|
|
7083
|
+
while ((match = callRegex.exec(line)) !== null) {
|
|
7084
|
+
const name = match[1];
|
|
7085
|
+
if (builtins.has(name)) continue;
|
|
7086
|
+
if (name.startsWith("_") && name !== "__init__") continue;
|
|
7087
|
+
if (context.currentScope.length > 0 || context.currentClass) {
|
|
7088
|
+
const callerId = context.currentClass ? `${context.filePath}::${context.currentClass}` : `${context.filePath}::__file__`;
|
|
7089
|
+
const targetId = context.imports.get(name) || `${context.filePath}::${name}`;
|
|
7090
|
+
context.edges.push({
|
|
7091
|
+
source: callerId,
|
|
7092
|
+
target: targetId,
|
|
7093
|
+
kind: "calls",
|
|
7094
|
+
filePath: context.filePath,
|
|
7095
|
+
line: lineNum
|
|
7096
|
+
});
|
|
7097
|
+
}
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
function findBlockEnd(lines, startIdx, baseIndent) {
|
|
7101
|
+
let i = startIdx + 1;
|
|
7102
|
+
while (i < lines.length) {
|
|
7103
|
+
const line = lines[i];
|
|
7104
|
+
if (line.trim() === "") {
|
|
7105
|
+
i++;
|
|
7106
|
+
continue;
|
|
7107
|
+
}
|
|
7108
|
+
const indent = line.length - line.trimStart().length;
|
|
7109
|
+
if (indent <= baseIndent) {
|
|
7110
|
+
return i;
|
|
7111
|
+
}
|
|
7112
|
+
i++;
|
|
7113
|
+
}
|
|
7114
|
+
return i;
|
|
7115
|
+
}
|
|
7116
|
+
function parseMojoProject(filePath, sourceCode, projectRoot) {
|
|
7117
|
+
const symbols = [];
|
|
7118
|
+
const edges = [];
|
|
7119
|
+
const lines = sourceCode.split("\n");
|
|
7120
|
+
let projectName = basename7(dirname13(join14(projectRoot, filePath)));
|
|
7121
|
+
const nameMatch = sourceCode.match(/name\s*=\s*["']([^"']+)["']/);
|
|
7122
|
+
if (nameMatch) {
|
|
7123
|
+
projectName = nameMatch[1];
|
|
7124
|
+
}
|
|
7125
|
+
symbols.push({
|
|
7126
|
+
id: `${filePath}::${projectName}`,
|
|
7127
|
+
name: projectName,
|
|
7128
|
+
kind: "module",
|
|
7129
|
+
filePath,
|
|
7130
|
+
startLine: 1,
|
|
7131
|
+
endLine: lines.length,
|
|
7132
|
+
exported: true
|
|
7133
|
+
});
|
|
7134
|
+
for (let i = 0; i < lines.length; i++) {
|
|
7135
|
+
const line = lines[i].trim();
|
|
7136
|
+
const depMatch = line.match(/^(\w[\w-]*)\s*=\s*["']([^"']+)["']/);
|
|
7137
|
+
if (depMatch) {
|
|
7138
|
+
symbols.push({
|
|
7139
|
+
id: `${filePath}::dep:${depMatch[1]}`,
|
|
7140
|
+
name: depMatch[1],
|
|
7141
|
+
kind: "import",
|
|
7142
|
+
filePath,
|
|
7143
|
+
startLine: i + 1,
|
|
7144
|
+
endLine: i + 1,
|
|
7145
|
+
exported: false
|
|
7146
|
+
});
|
|
7147
|
+
}
|
|
7148
|
+
}
|
|
7149
|
+
return { filePath, symbols, edges };
|
|
7150
|
+
}
|
|
7151
|
+
var mojoParser = {
|
|
7152
|
+
name: "mojo",
|
|
7153
|
+
extensions: [".mojo", ".\u{1F525}", "mojoproject.toml"],
|
|
7154
|
+
parseFile: parseMojoFile
|
|
7155
|
+
};
|
|
7156
|
+
|
|
6808
7157
|
// src/parser/detect.ts
|
|
6809
7158
|
var parsers = [
|
|
6810
7159
|
typescriptParser,
|
|
@@ -6818,12 +7167,13 @@ var parsers = [
|
|
|
6818
7167
|
cppParser,
|
|
6819
7168
|
kotlinParser,
|
|
6820
7169
|
phpParser,
|
|
6821
|
-
swiftParser
|
|
7170
|
+
swiftParser,
|
|
7171
|
+
mojoParser
|
|
6822
7172
|
];
|
|
6823
7173
|
var CPP_KEYWORDS = /\b(?:class|namespace|template|public:|private:|protected:|virtual|nullptr|constexpr|auto\s+\w+\s*=|using\s+\w+\s*=|static_cast|dynamic_cast|reinterpret_cast|const_cast|noexcept|override|final|decltype|concept|requires|co_await|co_yield|co_return|std::)\b/;
|
|
6824
7174
|
function getParserForFile(filePath, content) {
|
|
6825
|
-
const ext =
|
|
6826
|
-
const fileName =
|
|
7175
|
+
const ext = extname10(filePath).toLowerCase();
|
|
7176
|
+
const fileName = basename8(filePath);
|
|
6827
7177
|
if (ext === ".h" && content) {
|
|
6828
7178
|
if (CPP_KEYWORDS.test(content)) {
|
|
6829
7179
|
return cppParser;
|
|
@@ -6859,8 +7209,8 @@ async function parseProject(projectRoot, options) {
|
|
|
6859
7209
|
let errorFiles = 0;
|
|
6860
7210
|
for (const file of files) {
|
|
6861
7211
|
try {
|
|
6862
|
-
const fullPath =
|
|
6863
|
-
if (!
|
|
7212
|
+
const fullPath = join15(projectRoot, file);
|
|
7213
|
+
if (!resolve9(fullPath).startsWith(resolve9(projectRoot))) {
|
|
6864
7214
|
skippedFiles++;
|
|
6865
7215
|
continue;
|
|
6866
7216
|
}
|
|
@@ -6913,7 +7263,7 @@ async function parseProject(projectRoot, options) {
|
|
|
6913
7263
|
|
|
6914
7264
|
// src/cross-language/detectors/rest-api.ts
|
|
6915
7265
|
import { readFileSync as readFileSync12 } from "fs";
|
|
6916
|
-
import { join as
|
|
7266
|
+
import { join as join16, resolve as resolve10 } from "path";
|
|
6917
7267
|
function getLanguage(filePath) {
|
|
6918
7268
|
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
|
|
6919
7269
|
if (filePath.endsWith(".js") || filePath.endsWith(".jsx") || filePath.endsWith(".mjs") || filePath.endsWith(".cjs")) return "javascript";
|
|
@@ -6924,6 +7274,7 @@ function getLanguage(filePath) {
|
|
|
6924
7274
|
if (filePath.endsWith(".kt") || filePath.endsWith(".kts")) return "kotlin";
|
|
6925
7275
|
if (filePath.endsWith(".php")) return "php";
|
|
6926
7276
|
if (filePath.endsWith(".swift")) return "swift";
|
|
7277
|
+
if (filePath.endsWith(".mojo") || filePath.endsWith(".\u{1F525}")) return "mojo";
|
|
6927
7278
|
if (filePath.endsWith(".cpp") || filePath.endsWith(".cc") || filePath.endsWith(".cxx") || filePath.endsWith(".c++") || filePath.endsWith(".hpp") || filePath.endsWith(".hh") || filePath.endsWith(".hxx") || filePath.endsWith(".h++") || filePath.endsWith(".h") || filePath.endsWith(".inl") || filePath.endsWith(".ipp")) return "cpp";
|
|
6928
7279
|
return "unknown";
|
|
6929
7280
|
}
|
|
@@ -7382,6 +7733,34 @@ function extractRouteDefinitions(source, filePath) {
|
|
|
7382
7733
|
});
|
|
7383
7734
|
}
|
|
7384
7735
|
}
|
|
7736
|
+
if (lang === "mojo") {
|
|
7737
|
+
const pythonMatch = line.match(/@(?:app|router)\s*\.\s*(get|post|put|delete|patch)\s*\(\s*(['"])([^'"]+)\2/i);
|
|
7738
|
+
if (pythonMatch) {
|
|
7739
|
+
const path6 = pythonMatch[3];
|
|
7740
|
+
if (path6.startsWith("/")) {
|
|
7741
|
+
routes.push({
|
|
7742
|
+
method: pythonMatch[1].toUpperCase(),
|
|
7743
|
+
path: path6,
|
|
7744
|
+
normalizedPath: normalizePath(path6),
|
|
7745
|
+
file: filePath,
|
|
7746
|
+
line: i + 1
|
|
7747
|
+
});
|
|
7748
|
+
}
|
|
7749
|
+
}
|
|
7750
|
+
const mojoHttpMatch = line.match(/(?:server|app)\s*\.\s*(?:route|handle)\s*\(\s*['"]([^'"]+)['"]\s*,\s*['"]?(GET|POST|PUT|DELETE|PATCH)['"]?/i);
|
|
7751
|
+
if (mojoHttpMatch) {
|
|
7752
|
+
const path6 = mojoHttpMatch[1];
|
|
7753
|
+
if (path6.startsWith("/")) {
|
|
7754
|
+
routes.push({
|
|
7755
|
+
method: mojoHttpMatch[2].toUpperCase(),
|
|
7756
|
+
path: path6,
|
|
7757
|
+
normalizedPath: normalizePath(path6),
|
|
7758
|
+
file: filePath,
|
|
7759
|
+
line: i + 1
|
|
7760
|
+
});
|
|
7761
|
+
}
|
|
7762
|
+
}
|
|
7763
|
+
}
|
|
7385
7764
|
if (lang === "cpp") {
|
|
7386
7765
|
const crowMatch = line.match(/CROW_ROUTE\s*\(\s*\w+\s*,\s*"([^"]+)"/);
|
|
7387
7766
|
if (crowMatch) {
|
|
@@ -7496,8 +7875,8 @@ function detectRestApiEdges(files, projectRoot) {
|
|
|
7496
7875
|
const allCalls = [];
|
|
7497
7876
|
const allRoutes = [];
|
|
7498
7877
|
for (const file of files) {
|
|
7499
|
-
const fullPath =
|
|
7500
|
-
if (!
|
|
7878
|
+
const fullPath = join16(projectRoot, file.filePath);
|
|
7879
|
+
if (!resolve10(fullPath).startsWith(resolve10(projectRoot))) continue;
|
|
7501
7880
|
let source;
|
|
7502
7881
|
try {
|
|
7503
7882
|
source = readFileSync12(fullPath, "utf-8");
|
|
@@ -7601,7 +7980,7 @@ function detectRestApiEdges(files, projectRoot) {
|
|
|
7601
7980
|
|
|
7602
7981
|
// src/cross-language/detectors/subprocess.ts
|
|
7603
7982
|
import { readFileSync as readFileSync13 } from "fs";
|
|
7604
|
-
import { join as
|
|
7983
|
+
import { join as join17, resolve as resolve11, basename as basename9 } from "path";
|
|
7605
7984
|
var SCRIPT_EXTENSIONS = [".py", ".js", ".ts", ".go", ".rs"];
|
|
7606
7985
|
function getLanguage2(filePath) {
|
|
7607
7986
|
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
|
|
@@ -7700,13 +8079,13 @@ function detectSubprocessEdges(files, projectRoot) {
|
|
|
7700
8079
|
const knownFiles = new Set(files.map((f) => f.filePath));
|
|
7701
8080
|
const basenameMap = /* @__PURE__ */ new Map();
|
|
7702
8081
|
for (const f of files) {
|
|
7703
|
-
const base =
|
|
8082
|
+
const base = basename9(f.filePath);
|
|
7704
8083
|
if (!basenameMap.has(base)) basenameMap.set(base, []);
|
|
7705
8084
|
basenameMap.get(base).push(f.filePath);
|
|
7706
8085
|
}
|
|
7707
8086
|
for (const file of files) {
|
|
7708
|
-
const fullPath =
|
|
7709
|
-
if (!
|
|
8087
|
+
const fullPath = join17(projectRoot, file.filePath);
|
|
8088
|
+
if (!resolve11(fullPath).startsWith(resolve11(projectRoot))) continue;
|
|
7710
8089
|
let source;
|
|
7711
8090
|
try {
|
|
7712
8091
|
source = readFileSync13(fullPath, "utf-8");
|
|
@@ -7721,7 +8100,7 @@ function detectSubprocessEdges(files, projectRoot) {
|
|
|
7721
8100
|
targetFile = call.calledFile;
|
|
7722
8101
|
confidence = "high";
|
|
7723
8102
|
} else {
|
|
7724
|
-
const base =
|
|
8103
|
+
const base = basename9(call.calledFile);
|
|
7725
8104
|
const candidates = basenameMap.get(base);
|
|
7726
8105
|
if (candidates && candidates.length > 0) {
|
|
7727
8106
|
const exactCandidate = candidates.find((c) => c.endsWith(call.calledFile));
|
|
@@ -8100,7 +8479,7 @@ function getArchitectureSummary(graph) {
|
|
|
8100
8479
|
}
|
|
8101
8480
|
|
|
8102
8481
|
// src/health/metrics.ts
|
|
8103
|
-
import { dirname as
|
|
8482
|
+
import { dirname as dirname14 } from "path";
|
|
8104
8483
|
function scoreToGrade(score) {
|
|
8105
8484
|
if (score >= 90) return "A";
|
|
8106
8485
|
if (score >= 80) return "B";
|
|
@@ -8133,8 +8512,8 @@ function calculateCouplingScore(graph) {
|
|
|
8133
8512
|
totalEdges++;
|
|
8134
8513
|
fileConnections.set(sourceAttrs.filePath, (fileConnections.get(sourceAttrs.filePath) || 0) + 1);
|
|
8135
8514
|
fileConnections.set(targetAttrs.filePath, (fileConnections.get(targetAttrs.filePath) || 0) + 1);
|
|
8136
|
-
const sourceDir =
|
|
8137
|
-
const targetDir =
|
|
8515
|
+
const sourceDir = dirname14(sourceAttrs.filePath).split("/")[0];
|
|
8516
|
+
const targetDir = dirname14(targetAttrs.filePath).split("/")[0];
|
|
8138
8517
|
if (sourceDir !== targetDir) {
|
|
8139
8518
|
crossDirEdges++;
|
|
8140
8519
|
}
|
|
@@ -8181,8 +8560,8 @@ function calculateCohesionScore(graph) {
|
|
|
8181
8560
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
8182
8561
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
8183
8562
|
if (sourceAttrs.filePath !== targetAttrs.filePath) {
|
|
8184
|
-
const sourceDir =
|
|
8185
|
-
const targetDir =
|
|
8563
|
+
const sourceDir = dirname14(sourceAttrs.filePath);
|
|
8564
|
+
const targetDir = dirname14(targetAttrs.filePath);
|
|
8186
8565
|
if (!dirEdges.has(sourceDir)) {
|
|
8187
8566
|
dirEdges.set(sourceDir, { internal: 0, total: 0 });
|
|
8188
8567
|
}
|
|
@@ -8465,7 +8844,7 @@ function calculateDepthScore(graph) {
|
|
|
8465
8844
|
|
|
8466
8845
|
// src/health/index.ts
|
|
8467
8846
|
import { readFileSync as readFileSync14, writeFileSync, existsSync as existsSync14, mkdirSync } from "fs";
|
|
8468
|
-
import { dirname as
|
|
8847
|
+
import { dirname as dirname15, resolve as resolve12 } from "path";
|
|
8469
8848
|
function calculateHealthScore(graph, projectRoot) {
|
|
8470
8849
|
const coupling = calculateCouplingScore(graph);
|
|
8471
8850
|
const cohesion = calculateCohesionScore(graph);
|
|
@@ -8564,8 +8943,8 @@ function getHealthTrend(projectRoot, currentScore) {
|
|
|
8564
8943
|
}
|
|
8565
8944
|
}
|
|
8566
8945
|
function saveHealthHistory(projectRoot, report) {
|
|
8567
|
-
const resolvedRoot =
|
|
8568
|
-
const historyFile =
|
|
8946
|
+
const resolvedRoot = resolve12(projectRoot);
|
|
8947
|
+
const historyFile = resolve12(resolvedRoot, ".depwire", "health-history.json");
|
|
8569
8948
|
if (!historyFile.startsWith(resolvedRoot)) {
|
|
8570
8949
|
return;
|
|
8571
8950
|
}
|
|
@@ -8592,13 +8971,13 @@ function saveHealthHistory(projectRoot, report) {
|
|
|
8592
8971
|
if (history.length > 50) {
|
|
8593
8972
|
history = history.slice(-50);
|
|
8594
8973
|
}
|
|
8595
|
-
mkdirSync(
|
|
8974
|
+
mkdirSync(dirname15(historyFile), { recursive: true });
|
|
8596
8975
|
if (!historyFile.startsWith(resolvedRoot)) return;
|
|
8597
8976
|
writeFileSync(historyFile, JSON.stringify(history, null, 2), "utf-8");
|
|
8598
8977
|
}
|
|
8599
8978
|
function loadHealthHistory(projectRoot) {
|
|
8600
|
-
const resolvedRoot =
|
|
8601
|
-
const historyFile =
|
|
8979
|
+
const resolvedRoot = resolve12(projectRoot);
|
|
8980
|
+
const historyFile = resolve12(resolvedRoot, ".depwire", "health-history.json");
|
|
8602
8981
|
if (!historyFile.startsWith(resolvedRoot) || !existsSync14(historyFile)) {
|
|
8603
8982
|
return [];
|
|
8604
8983
|
}
|
|
@@ -8813,6 +9192,9 @@ function shouldExclude(attrs, context, includeTests, packageEntryPoints) {
|
|
|
8813
9192
|
if (isSwiftExcluded(attrs)) {
|
|
8814
9193
|
return "framework";
|
|
8815
9194
|
}
|
|
9195
|
+
if (isMojoExcluded(attrs)) {
|
|
9196
|
+
return "framework";
|
|
9197
|
+
}
|
|
8816
9198
|
return null;
|
|
8817
9199
|
}
|
|
8818
9200
|
function isRealPackageEntryPoint(filePath, packageEntryPoints) {
|
|
@@ -8982,6 +9364,49 @@ function isSwiftExcluded(attrs) {
|
|
|
8982
9364
|
if (name.startsWith("test") || name === "setUp" || name === "tearDown" || name === "setUpWithError" || name === "tearDownWithError") return true;
|
|
8983
9365
|
return false;
|
|
8984
9366
|
}
|
|
9367
|
+
function isMojoExcluded(attrs) {
|
|
9368
|
+
const filePath = attrs.file || attrs.filePath || "";
|
|
9369
|
+
const name = attrs.name || "";
|
|
9370
|
+
if (!filePath.endsWith(".mojo") && !filePath.endsWith(".\u{1F525}")) return false;
|
|
9371
|
+
const lifecycleMethods = [
|
|
9372
|
+
"__init__",
|
|
9373
|
+
"__copyinit__",
|
|
9374
|
+
"__moveinit__",
|
|
9375
|
+
"__del__",
|
|
9376
|
+
"__enter__",
|
|
9377
|
+
"__exit__"
|
|
9378
|
+
];
|
|
9379
|
+
if (lifecycleMethods.includes(name)) return true;
|
|
9380
|
+
const traitMethods = [
|
|
9381
|
+
"__str__",
|
|
9382
|
+
"__repr__",
|
|
9383
|
+
"__len__",
|
|
9384
|
+
"__getitem__",
|
|
9385
|
+
"__setitem__",
|
|
9386
|
+
"__eq__",
|
|
9387
|
+
"__ne__",
|
|
9388
|
+
"__lt__",
|
|
9389
|
+
"__le__",
|
|
9390
|
+
"__gt__",
|
|
9391
|
+
"__ge__",
|
|
9392
|
+
"__add__",
|
|
9393
|
+
"__sub__",
|
|
9394
|
+
"__mul__",
|
|
9395
|
+
"__truediv__",
|
|
9396
|
+
"__floordiv__",
|
|
9397
|
+
"__hash__",
|
|
9398
|
+
"__bool__",
|
|
9399
|
+
"__int__",
|
|
9400
|
+
"__float__",
|
|
9401
|
+
"__iter__",
|
|
9402
|
+
"__next__",
|
|
9403
|
+
"__contains__"
|
|
9404
|
+
];
|
|
9405
|
+
if (traitMethods.includes(name)) return true;
|
|
9406
|
+
if (name.startsWith("__mlir_") || name.startsWith("_mlir_")) return true;
|
|
9407
|
+
if (name === "main") return true;
|
|
9408
|
+
return false;
|
|
9409
|
+
}
|
|
8985
9410
|
|
|
8986
9411
|
// src/dead-code/classifier.ts
|
|
8987
9412
|
import path3 from "path";
|
|
@@ -9048,8 +9473,8 @@ function generateReason(symbol, confidence) {
|
|
|
9048
9473
|
return "Potentially unused";
|
|
9049
9474
|
}
|
|
9050
9475
|
function isBarrelFile(filePath) {
|
|
9051
|
-
const
|
|
9052
|
-
return
|
|
9476
|
+
const basename13 = path3.basename(filePath);
|
|
9477
|
+
return basename13 === "index.ts" || basename13 === "index.js";
|
|
9053
9478
|
}
|
|
9054
9479
|
function isTestFile2(filePath) {
|
|
9055
9480
|
return filePath.includes("__tests__/") || filePath.includes(".test.") || filePath.includes(".spec.") || filePath.includes("/test/") || filePath.includes("/tests/");
|
|
@@ -9229,10 +9654,10 @@ function filterByConfidence(symbols, minConfidence) {
|
|
|
9229
9654
|
|
|
9230
9655
|
// src/docs/generator.ts
|
|
9231
9656
|
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync18 } from "fs";
|
|
9232
|
-
import { join as
|
|
9657
|
+
import { join as join21 } from "path";
|
|
9233
9658
|
|
|
9234
9659
|
// src/docs/architecture.ts
|
|
9235
|
-
import { dirname as
|
|
9660
|
+
import { dirname as dirname16 } from "path";
|
|
9236
9661
|
|
|
9237
9662
|
// src/docs/templates.ts
|
|
9238
9663
|
function header(text, level = 1) {
|
|
@@ -9383,7 +9808,7 @@ function generateModuleStructure(graph) {
|
|
|
9383
9808
|
function getDirectoryStats(graph) {
|
|
9384
9809
|
const dirMap = /* @__PURE__ */ new Map();
|
|
9385
9810
|
graph.forEachNode((node, attrs) => {
|
|
9386
|
-
const dir =
|
|
9811
|
+
const dir = dirname16(attrs.filePath);
|
|
9387
9812
|
if (dir === ".") return;
|
|
9388
9813
|
if (!dirMap.has(dir)) {
|
|
9389
9814
|
dirMap.set(dir, {
|
|
@@ -9408,7 +9833,7 @@ function getDirectoryStats(graph) {
|
|
|
9408
9833
|
});
|
|
9409
9834
|
const filesPerDir = /* @__PURE__ */ new Map();
|
|
9410
9835
|
graph.forEachNode((node, attrs) => {
|
|
9411
|
-
const dir =
|
|
9836
|
+
const dir = dirname16(attrs.filePath);
|
|
9412
9837
|
if (!filesPerDir.has(dir)) {
|
|
9413
9838
|
filesPerDir.set(dir, /* @__PURE__ */ new Set());
|
|
9414
9839
|
}
|
|
@@ -9423,8 +9848,8 @@ function getDirectoryStats(graph) {
|
|
|
9423
9848
|
graph.forEachEdge((edge, attrs, source, target) => {
|
|
9424
9849
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
9425
9850
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
9426
|
-
const sourceDir =
|
|
9427
|
-
const targetDir =
|
|
9851
|
+
const sourceDir = dirname16(sourceAttrs.filePath);
|
|
9852
|
+
const targetDir = dirname16(targetAttrs.filePath);
|
|
9428
9853
|
if (sourceDir !== targetDir) {
|
|
9429
9854
|
if (!dirEdges.has(sourceDir)) {
|
|
9430
9855
|
dirEdges.set(sourceDir, { in: 0, out: 0 });
|
|
@@ -9631,7 +10056,7 @@ function detectCycles(graph) {
|
|
|
9631
10056
|
}
|
|
9632
10057
|
|
|
9633
10058
|
// src/docs/conventions.ts
|
|
9634
|
-
import { basename as
|
|
10059
|
+
import { basename as basename10, extname as extname11 } from "path";
|
|
9635
10060
|
function generateConventions(graph, projectRoot, version) {
|
|
9636
10061
|
let output = "";
|
|
9637
10062
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -9669,7 +10094,7 @@ function generateFileOrganization(graph) {
|
|
|
9669
10094
|
graph.forEachNode((node, attrs) => {
|
|
9670
10095
|
if (!files.has(attrs.filePath)) {
|
|
9671
10096
|
files.add(attrs.filePath);
|
|
9672
|
-
const fileName =
|
|
10097
|
+
const fileName = basename10(attrs.filePath);
|
|
9673
10098
|
if (fileName === "index.ts" || fileName === "index.js" || fileName === "index.tsx" || fileName === "index.jsx") {
|
|
9674
10099
|
barrelFileCount++;
|
|
9675
10100
|
}
|
|
@@ -9728,7 +10153,7 @@ function generateNamingPatterns(graph) {
|
|
|
9728
10153
|
graph.forEachNode((node, attrs) => {
|
|
9729
10154
|
if (!files.has(attrs.filePath)) {
|
|
9730
10155
|
files.add(attrs.filePath);
|
|
9731
|
-
const fileName =
|
|
10156
|
+
const fileName = basename10(attrs.filePath, extname11(attrs.filePath));
|
|
9732
10157
|
if (isCamelCase(fileName)) patterns.files.camelCase++;
|
|
9733
10158
|
else if (isPascalCase(fileName)) patterns.files.PascalCase++;
|
|
9734
10159
|
else if (isKebabCase(fileName)) patterns.files.kebabCase++;
|
|
@@ -10405,7 +10830,7 @@ function detectCyclesDetailed(graph) {
|
|
|
10405
10830
|
}
|
|
10406
10831
|
|
|
10407
10832
|
// src/docs/onboarding.ts
|
|
10408
|
-
import { dirname as
|
|
10833
|
+
import { dirname as dirname17 } from "path";
|
|
10409
10834
|
function generateOnboarding(graph, projectRoot, version) {
|
|
10410
10835
|
let output = "";
|
|
10411
10836
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -10464,7 +10889,7 @@ function generateQuickOrientation(graph) {
|
|
|
10464
10889
|
const primaryLang = Object.entries(languages2).sort((a, b) => b[1] - a[1])[0];
|
|
10465
10890
|
const dirs = /* @__PURE__ */ new Set();
|
|
10466
10891
|
graph.forEachNode((node, attrs) => {
|
|
10467
|
-
const dir =
|
|
10892
|
+
const dir = dirname17(attrs.filePath);
|
|
10468
10893
|
if (dir !== ".") {
|
|
10469
10894
|
const topLevel = dir.split("/")[0];
|
|
10470
10895
|
dirs.add(topLevel);
|
|
@@ -10568,7 +10993,7 @@ function generateModuleMap(graph) {
|
|
|
10568
10993
|
function getDirectoryStats2(graph) {
|
|
10569
10994
|
const dirMap = /* @__PURE__ */ new Map();
|
|
10570
10995
|
graph.forEachNode((node, attrs) => {
|
|
10571
|
-
const dir =
|
|
10996
|
+
const dir = dirname17(attrs.filePath);
|
|
10572
10997
|
if (dir === ".") return;
|
|
10573
10998
|
if (!dirMap.has(dir)) {
|
|
10574
10999
|
dirMap.set(dir, {
|
|
@@ -10583,7 +11008,7 @@ function getDirectoryStats2(graph) {
|
|
|
10583
11008
|
});
|
|
10584
11009
|
const filesPerDir = /* @__PURE__ */ new Map();
|
|
10585
11010
|
graph.forEachNode((node, attrs) => {
|
|
10586
|
-
const dir =
|
|
11011
|
+
const dir = dirname17(attrs.filePath);
|
|
10587
11012
|
if (!filesPerDir.has(dir)) {
|
|
10588
11013
|
filesPerDir.set(dir, /* @__PURE__ */ new Set());
|
|
10589
11014
|
}
|
|
@@ -10598,8 +11023,8 @@ function getDirectoryStats2(graph) {
|
|
|
10598
11023
|
graph.forEachEdge((edge, attrs, source, target) => {
|
|
10599
11024
|
const sourceAttrs = graph.getNodeAttributes(source);
|
|
10600
11025
|
const targetAttrs = graph.getNodeAttributes(target);
|
|
10601
|
-
const sourceDir =
|
|
10602
|
-
const targetDir =
|
|
11026
|
+
const sourceDir = dirname17(sourceAttrs.filePath);
|
|
11027
|
+
const targetDir = dirname17(targetAttrs.filePath);
|
|
10603
11028
|
if (sourceDir !== targetDir) {
|
|
10604
11029
|
if (!dirEdges.has(sourceDir)) {
|
|
10605
11030
|
dirEdges.set(sourceDir, { in: 0, out: 0 });
|
|
@@ -10680,7 +11105,7 @@ function detectClusters(graph) {
|
|
|
10680
11105
|
const dirFiles = /* @__PURE__ */ new Map();
|
|
10681
11106
|
const fileEdges = /* @__PURE__ */ new Map();
|
|
10682
11107
|
graph.forEachNode((node, attrs) => {
|
|
10683
|
-
const dir =
|
|
11108
|
+
const dir = dirname17(attrs.filePath);
|
|
10684
11109
|
if (!dirFiles.has(dir)) {
|
|
10685
11110
|
dirFiles.set(dir, /* @__PURE__ */ new Set());
|
|
10686
11111
|
}
|
|
@@ -10734,8 +11159,8 @@ function inferClusterName(files) {
|
|
|
10734
11159
|
if (sortedWords.length > 0 && sortedWords[0][1] > 1) {
|
|
10735
11160
|
return capitalizeFirst2(sortedWords[0][0]);
|
|
10736
11161
|
}
|
|
10737
|
-
const commonDir =
|
|
10738
|
-
if (files.every((f) =>
|
|
11162
|
+
const commonDir = dirname17(files[0]);
|
|
11163
|
+
if (files.every((f) => dirname17(f) === commonDir)) {
|
|
10739
11164
|
return capitalizeFirst2(commonDir.split("/").pop() || "Core");
|
|
10740
11165
|
}
|
|
10741
11166
|
return "Core";
|
|
@@ -10793,7 +11218,7 @@ function generateDepwireUsage(projectRoot) {
|
|
|
10793
11218
|
}
|
|
10794
11219
|
|
|
10795
11220
|
// src/docs/files.ts
|
|
10796
|
-
import { dirname as
|
|
11221
|
+
import { dirname as dirname18, basename as basename11 } from "path";
|
|
10797
11222
|
function generateFiles(graph, projectRoot, version) {
|
|
10798
11223
|
let output = "";
|
|
10799
11224
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -10897,7 +11322,7 @@ function generateDirectoryBreakdown(graph) {
|
|
|
10897
11322
|
const fileStats = getFileStats2(graph);
|
|
10898
11323
|
const dirMap = /* @__PURE__ */ new Map();
|
|
10899
11324
|
for (const file of fileStats) {
|
|
10900
|
-
const dir =
|
|
11325
|
+
const dir = dirname18(file.filePath);
|
|
10901
11326
|
const topDir = dir === "." ? "." : dir.split("/")[0];
|
|
10902
11327
|
if (!dirMap.has(topDir)) {
|
|
10903
11328
|
dirMap.set(topDir, {
|
|
@@ -10912,7 +11337,7 @@ function generateDirectoryBreakdown(graph) {
|
|
|
10912
11337
|
dirStats.symbolCount += file.symbolCount;
|
|
10913
11338
|
if (file.totalConnections > dirStats.maxConnections) {
|
|
10914
11339
|
dirStats.maxConnections = file.totalConnections;
|
|
10915
|
-
dirStats.mostConnectedFile =
|
|
11340
|
+
dirStats.mostConnectedFile = basename11(file.filePath);
|
|
10916
11341
|
}
|
|
10917
11342
|
}
|
|
10918
11343
|
if (dirMap.size === 0) {
|
|
@@ -11540,7 +11965,7 @@ function generateRecommendations(graph) {
|
|
|
11540
11965
|
}
|
|
11541
11966
|
|
|
11542
11967
|
// src/docs/tests.ts
|
|
11543
|
-
import { basename as
|
|
11968
|
+
import { basename as basename12, dirname as dirname19 } from "path";
|
|
11544
11969
|
function generateTests(graph, projectRoot, version) {
|
|
11545
11970
|
let output = "";
|
|
11546
11971
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -11568,8 +11993,8 @@ function getFileCount8(graph) {
|
|
|
11568
11993
|
return files.size;
|
|
11569
11994
|
}
|
|
11570
11995
|
function isTestFile3(filePath) {
|
|
11571
|
-
const fileName =
|
|
11572
|
-
const dirPath =
|
|
11996
|
+
const fileName = basename12(filePath).toLowerCase();
|
|
11997
|
+
const dirPath = dirname19(filePath).toLowerCase();
|
|
11573
11998
|
if (dirPath.includes("test") || dirPath.includes("spec") || dirPath.includes("__tests__")) {
|
|
11574
11999
|
return true;
|
|
11575
12000
|
}
|
|
@@ -11627,13 +12052,13 @@ function generateTestFileInventory(graph) {
|
|
|
11627
12052
|
return output;
|
|
11628
12053
|
}
|
|
11629
12054
|
function matchTestToSource(testFile) {
|
|
11630
|
-
const testFileName =
|
|
11631
|
-
const testDir =
|
|
12055
|
+
const testFileName = basename12(testFile);
|
|
12056
|
+
const testDir = dirname19(testFile);
|
|
11632
12057
|
let sourceFileName = testFileName.replace(/\.test\./g, ".").replace(/\.spec\./g, ".").replace(/_test\./g, ".").replace(/_spec\./g, ".");
|
|
11633
12058
|
const possiblePaths = [];
|
|
11634
12059
|
possiblePaths.push(testDir + "/" + sourceFileName);
|
|
11635
12060
|
if (testDir.endsWith("/test") || testDir.endsWith("/tests") || testDir.endsWith("/__tests__")) {
|
|
11636
|
-
const parentDir =
|
|
12061
|
+
const parentDir = dirname19(testDir);
|
|
11637
12062
|
possiblePaths.push(parentDir + "/" + sourceFileName);
|
|
11638
12063
|
}
|
|
11639
12064
|
if (testDir.includes("test")) {
|
|
@@ -11789,7 +12214,7 @@ function generateTestCoverageMap(graph) {
|
|
|
11789
12214
|
const rows = mappings.slice(0, 30).map((m) => [
|
|
11790
12215
|
`\`${m.sourceFile}\``,
|
|
11791
12216
|
m.hasTest ? "\u2705" : "\u274C",
|
|
11792
|
-
m.testFile ? `\`${
|
|
12217
|
+
m.testFile ? `\`${basename12(m.testFile)}\`` : "-",
|
|
11793
12218
|
formatNumber(m.symbolCount)
|
|
11794
12219
|
]);
|
|
11795
12220
|
let output = table(headers, rows);
|
|
@@ -11830,7 +12255,7 @@ function generateTestStatistics(graph) {
|
|
|
11830
12255
|
`;
|
|
11831
12256
|
const dirTestCoverage = /* @__PURE__ */ new Map();
|
|
11832
12257
|
for (const sourceFile of sourceFiles) {
|
|
11833
|
-
const dir =
|
|
12258
|
+
const dir = dirname19(sourceFile).split("/")[0];
|
|
11834
12259
|
if (!dirTestCoverage.has(dir)) {
|
|
11835
12260
|
dirTestCoverage.set(dir, { total: 0, tested: 0 });
|
|
11836
12261
|
}
|
|
@@ -11853,7 +12278,7 @@ function generateTestStatistics(graph) {
|
|
|
11853
12278
|
}
|
|
11854
12279
|
|
|
11855
12280
|
// src/docs/history.ts
|
|
11856
|
-
import { dirname as
|
|
12281
|
+
import { dirname as dirname20 } from "path";
|
|
11857
12282
|
import { execSync } from "child_process";
|
|
11858
12283
|
function generateHistory(graph, projectRoot, version) {
|
|
11859
12284
|
let output = "";
|
|
@@ -12134,7 +12559,7 @@ function generateFeatureClusters(graph) {
|
|
|
12134
12559
|
const dirFiles = /* @__PURE__ */ new Map();
|
|
12135
12560
|
const fileEdges = /* @__PURE__ */ new Map();
|
|
12136
12561
|
graph.forEachNode((node, attrs) => {
|
|
12137
|
-
const dir =
|
|
12562
|
+
const dir = dirname20(attrs.filePath);
|
|
12138
12563
|
if (!dirFiles.has(dir)) {
|
|
12139
12564
|
dirFiles.set(dir, /* @__PURE__ */ new Set());
|
|
12140
12565
|
}
|
|
@@ -12216,7 +12641,7 @@ function capitalizeFirst3(str) {
|
|
|
12216
12641
|
}
|
|
12217
12642
|
|
|
12218
12643
|
// src/docs/current.ts
|
|
12219
|
-
import { dirname as
|
|
12644
|
+
import { dirname as dirname21 } from "path";
|
|
12220
12645
|
function generateCurrent(graph, projectRoot, version) {
|
|
12221
12646
|
let output = "";
|
|
12222
12647
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -12354,7 +12779,7 @@ function generateCompleteFileIndex(graph) {
|
|
|
12354
12779
|
fileInfos.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
12355
12780
|
const dirGroups = /* @__PURE__ */ new Map();
|
|
12356
12781
|
for (const info of fileInfos) {
|
|
12357
|
-
const dir =
|
|
12782
|
+
const dir = dirname21(info.filePath);
|
|
12358
12783
|
const topDir = dir === "." ? "root" : dir.split("/")[0];
|
|
12359
12784
|
if (!dirGroups.has(topDir)) {
|
|
12360
12785
|
dirGroups.set(topDir, []);
|
|
@@ -12566,7 +12991,7 @@ function getTopLevelDir2(filePath) {
|
|
|
12566
12991
|
|
|
12567
12992
|
// src/docs/status.ts
|
|
12568
12993
|
import { readFileSync as readFileSync16, existsSync as existsSync16 } from "fs";
|
|
12569
|
-
import { resolve as
|
|
12994
|
+
import { resolve as resolve13 } from "path";
|
|
12570
12995
|
function generateStatus(graph, projectRoot, version) {
|
|
12571
12996
|
let output = "";
|
|
12572
12997
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -12599,8 +13024,8 @@ function getFileCount11(graph) {
|
|
|
12599
13024
|
}
|
|
12600
13025
|
function extractComments(projectRoot, filePath) {
|
|
12601
13026
|
const comments = [];
|
|
12602
|
-
const resolvedRoot =
|
|
12603
|
-
const fullPath =
|
|
13027
|
+
const resolvedRoot = resolve13(projectRoot);
|
|
13028
|
+
const fullPath = resolve13(resolvedRoot, filePath);
|
|
12604
13029
|
if (!fullPath.startsWith(resolvedRoot)) {
|
|
12605
13030
|
return comments;
|
|
12606
13031
|
}
|
|
@@ -13188,10 +13613,10 @@ function generateConfidenceSection(title, description, symbols, projectRoot) {
|
|
|
13188
13613
|
|
|
13189
13614
|
// src/docs/metadata.ts
|
|
13190
13615
|
import { existsSync as existsSync17, readFileSync as readFileSync17, writeFileSync as writeFileSync2 } from "fs";
|
|
13191
|
-
import { resolve as
|
|
13616
|
+
import { resolve as resolve14 } from "path";
|
|
13192
13617
|
function loadMetadata(outputDir) {
|
|
13193
|
-
const resolvedDir =
|
|
13194
|
-
const metadataPath =
|
|
13618
|
+
const resolvedDir = resolve14(outputDir);
|
|
13619
|
+
const metadataPath = resolve14(resolvedDir, "metadata.json");
|
|
13195
13620
|
if (!metadataPath.startsWith(resolvedDir) || !existsSync17(metadataPath)) {
|
|
13196
13621
|
return null;
|
|
13197
13622
|
}
|
|
@@ -13204,8 +13629,8 @@ function loadMetadata(outputDir) {
|
|
|
13204
13629
|
}
|
|
13205
13630
|
}
|
|
13206
13631
|
function saveMetadata(outputDir, metadata) {
|
|
13207
|
-
const resolvedDir =
|
|
13208
|
-
const metadataPath =
|
|
13632
|
+
const resolvedDir = resolve14(outputDir);
|
|
13633
|
+
const metadataPath = resolve14(resolvedDir, "metadata.json");
|
|
13209
13634
|
if (!metadataPath.startsWith(resolvedDir)) {
|
|
13210
13635
|
throw new Error(`Path traversal attempt blocked: ${metadataPath}`);
|
|
13211
13636
|
}
|
|
@@ -13290,7 +13715,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13290
13715
|
try {
|
|
13291
13716
|
if (options.verbose) console.log("Generating ARCHITECTURE.md...");
|
|
13292
13717
|
const content = generateArchitecture(graph, projectRoot, version, parseTime);
|
|
13293
|
-
const filePath =
|
|
13718
|
+
const filePath = join21(options.outputDir, "ARCHITECTURE.md");
|
|
13294
13719
|
writeFileSync3(filePath, content, "utf-8");
|
|
13295
13720
|
generated.push("ARCHITECTURE.md");
|
|
13296
13721
|
} catch (err) {
|
|
@@ -13301,7 +13726,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13301
13726
|
try {
|
|
13302
13727
|
if (options.verbose) console.log("Generating CONVENTIONS.md...");
|
|
13303
13728
|
const content = generateConventions(graph, projectRoot, version);
|
|
13304
|
-
const filePath =
|
|
13729
|
+
const filePath = join21(options.outputDir, "CONVENTIONS.md");
|
|
13305
13730
|
writeFileSync3(filePath, content, "utf-8");
|
|
13306
13731
|
generated.push("CONVENTIONS.md");
|
|
13307
13732
|
} catch (err) {
|
|
@@ -13312,7 +13737,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13312
13737
|
try {
|
|
13313
13738
|
if (options.verbose) console.log("Generating DEPENDENCIES.md...");
|
|
13314
13739
|
const content = generateDependencies(graph, projectRoot, version);
|
|
13315
|
-
const filePath =
|
|
13740
|
+
const filePath = join21(options.outputDir, "DEPENDENCIES.md");
|
|
13316
13741
|
writeFileSync3(filePath, content, "utf-8");
|
|
13317
13742
|
generated.push("DEPENDENCIES.md");
|
|
13318
13743
|
} catch (err) {
|
|
@@ -13323,7 +13748,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13323
13748
|
try {
|
|
13324
13749
|
if (options.verbose) console.log("Generating ONBOARDING.md...");
|
|
13325
13750
|
const content = generateOnboarding(graph, projectRoot, version);
|
|
13326
|
-
const filePath =
|
|
13751
|
+
const filePath = join21(options.outputDir, "ONBOARDING.md");
|
|
13327
13752
|
writeFileSync3(filePath, content, "utf-8");
|
|
13328
13753
|
generated.push("ONBOARDING.md");
|
|
13329
13754
|
} catch (err) {
|
|
@@ -13334,7 +13759,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13334
13759
|
try {
|
|
13335
13760
|
if (options.verbose) console.log("Generating FILES.md...");
|
|
13336
13761
|
const content = generateFiles(graph, projectRoot, version);
|
|
13337
|
-
const filePath =
|
|
13762
|
+
const filePath = join21(options.outputDir, "FILES.md");
|
|
13338
13763
|
writeFileSync3(filePath, content, "utf-8");
|
|
13339
13764
|
generated.push("FILES.md");
|
|
13340
13765
|
} catch (err) {
|
|
@@ -13345,7 +13770,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13345
13770
|
try {
|
|
13346
13771
|
if (options.verbose) console.log("Generating API_SURFACE.md...");
|
|
13347
13772
|
const content = generateApiSurface(graph, projectRoot, version);
|
|
13348
|
-
const filePath =
|
|
13773
|
+
const filePath = join21(options.outputDir, "API_SURFACE.md");
|
|
13349
13774
|
writeFileSync3(filePath, content, "utf-8");
|
|
13350
13775
|
generated.push("API_SURFACE.md");
|
|
13351
13776
|
} catch (err) {
|
|
@@ -13356,7 +13781,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13356
13781
|
try {
|
|
13357
13782
|
if (options.verbose) console.log("Generating ERRORS.md...");
|
|
13358
13783
|
const content = generateErrors(graph, projectRoot, version);
|
|
13359
|
-
const filePath =
|
|
13784
|
+
const filePath = join21(options.outputDir, "ERRORS.md");
|
|
13360
13785
|
writeFileSync3(filePath, content, "utf-8");
|
|
13361
13786
|
generated.push("ERRORS.md");
|
|
13362
13787
|
} catch (err) {
|
|
@@ -13367,7 +13792,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13367
13792
|
try {
|
|
13368
13793
|
if (options.verbose) console.log("Generating TESTS.md...");
|
|
13369
13794
|
const content = generateTests(graph, projectRoot, version);
|
|
13370
|
-
const filePath =
|
|
13795
|
+
const filePath = join21(options.outputDir, "TESTS.md");
|
|
13371
13796
|
writeFileSync3(filePath, content, "utf-8");
|
|
13372
13797
|
generated.push("TESTS.md");
|
|
13373
13798
|
} catch (err) {
|
|
@@ -13378,7 +13803,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13378
13803
|
try {
|
|
13379
13804
|
if (options.verbose) console.log("Generating HISTORY.md...");
|
|
13380
13805
|
const content = generateHistory(graph, projectRoot, version);
|
|
13381
|
-
const filePath =
|
|
13806
|
+
const filePath = join21(options.outputDir, "HISTORY.md");
|
|
13382
13807
|
writeFileSync3(filePath, content, "utf-8");
|
|
13383
13808
|
generated.push("HISTORY.md");
|
|
13384
13809
|
} catch (err) {
|
|
@@ -13389,7 +13814,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13389
13814
|
try {
|
|
13390
13815
|
if (options.verbose) console.log("Generating CURRENT.md...");
|
|
13391
13816
|
const content = generateCurrent(graph, projectRoot, version);
|
|
13392
|
-
const filePath =
|
|
13817
|
+
const filePath = join21(options.outputDir, "CURRENT.md");
|
|
13393
13818
|
writeFileSync3(filePath, content, "utf-8");
|
|
13394
13819
|
generated.push("CURRENT.md");
|
|
13395
13820
|
} catch (err) {
|
|
@@ -13400,7 +13825,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13400
13825
|
try {
|
|
13401
13826
|
if (options.verbose) console.log("Generating STATUS.md...");
|
|
13402
13827
|
const content = generateStatus(graph, projectRoot, version);
|
|
13403
|
-
const filePath =
|
|
13828
|
+
const filePath = join21(options.outputDir, "STATUS.md");
|
|
13404
13829
|
writeFileSync3(filePath, content, "utf-8");
|
|
13405
13830
|
generated.push("STATUS.md");
|
|
13406
13831
|
} catch (err) {
|
|
@@ -13411,7 +13836,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13411
13836
|
try {
|
|
13412
13837
|
if (options.verbose) console.log("Generating HEALTH.md...");
|
|
13413
13838
|
const content = generateHealth(graph, projectRoot, version);
|
|
13414
|
-
const filePath =
|
|
13839
|
+
const filePath = join21(options.outputDir, "HEALTH.md");
|
|
13415
13840
|
writeFileSync3(filePath, content, "utf-8");
|
|
13416
13841
|
generated.push("HEALTH.md");
|
|
13417
13842
|
} catch (err) {
|
|
@@ -13422,7 +13847,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
|
|
|
13422
13847
|
try {
|
|
13423
13848
|
if (options.verbose) console.log("Generating DEAD_CODE.md...");
|
|
13424
13849
|
const content = generateDeadCode(graph, projectRoot, version);
|
|
13425
|
-
const filePath =
|
|
13850
|
+
const filePath = join21(options.outputDir, "DEAD_CODE.md");
|
|
13426
13851
|
writeFileSync3(filePath, content, "utf-8");
|
|
13427
13852
|
generated.push("DEAD_CODE.md");
|
|
13428
13853
|
} catch (err) {
|
|
@@ -13466,7 +13891,7 @@ function getFileCount13(graph) {
|
|
|
13466
13891
|
}
|
|
13467
13892
|
|
|
13468
13893
|
// src/simulation/engine.ts
|
|
13469
|
-
import { dirname as
|
|
13894
|
+
import { dirname as dirname22, join as join22 } from "path";
|
|
13470
13895
|
function normalizePath2(p) {
|
|
13471
13896
|
return p.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
13472
13897
|
}
|
|
@@ -13598,7 +14023,7 @@ var SimulationEngine = class {
|
|
|
13598
14023
|
}
|
|
13599
14024
|
}
|
|
13600
14025
|
applyRename(clone, target, newName, brokenImports) {
|
|
13601
|
-
const destination =
|
|
14026
|
+
const destination = join22(dirname22(target), newName);
|
|
13602
14027
|
this.applyMove(clone, target, destination, brokenImports);
|
|
13603
14028
|
}
|
|
13604
14029
|
applySplit(clone, target, newFile, symbols, brokenImports) {
|
|
@@ -13799,12 +14224,12 @@ var SimulationEngine = class {
|
|
|
13799
14224
|
|
|
13800
14225
|
// src/security/scanner.ts
|
|
13801
14226
|
import { existsSync as existsSync20 } from "fs";
|
|
13802
|
-
import { join as
|
|
14227
|
+
import { join as join32 } from "path";
|
|
13803
14228
|
|
|
13804
14229
|
// src/security/checks/dependencies.ts
|
|
13805
14230
|
import { execSync as execSync2 } from "child_process";
|
|
13806
14231
|
import { existsSync as existsSync19, readFileSync as readFileSync18, readdirSync as readdirSync11 } from "fs";
|
|
13807
|
-
import { join as
|
|
14232
|
+
import { join as join23 } from "path";
|
|
13808
14233
|
function cvssToSeverity(score) {
|
|
13809
14234
|
if (score >= 9) return "critical";
|
|
13810
14235
|
if (score >= 7) return "high";
|
|
@@ -13814,18 +14239,18 @@ function cvssToSeverity(score) {
|
|
|
13814
14239
|
async function checkDependencies(_files, projectRoot) {
|
|
13815
14240
|
const findings = [];
|
|
13816
14241
|
try {
|
|
13817
|
-
if (existsSync19(
|
|
14242
|
+
if (existsSync19(join23(projectRoot, "package.json"))) {
|
|
13818
14243
|
findings.push(...checkNpmAudit(projectRoot));
|
|
13819
14244
|
findings.push(...checkPackageJsonPatterns(projectRoot));
|
|
13820
14245
|
findings.push(...checkPostinstallScripts(projectRoot));
|
|
13821
14246
|
}
|
|
13822
|
-
if (existsSync19(
|
|
14247
|
+
if (existsSync19(join23(projectRoot, "requirements.txt")) || existsSync19(join23(projectRoot, "pyproject.toml"))) {
|
|
13823
14248
|
findings.push(...checkPipAudit(projectRoot));
|
|
13824
14249
|
}
|
|
13825
|
-
if (existsSync19(
|
|
14250
|
+
if (existsSync19(join23(projectRoot, "Cargo.toml"))) {
|
|
13826
14251
|
findings.push(...checkCargoAudit(projectRoot));
|
|
13827
14252
|
}
|
|
13828
|
-
if (existsSync19(
|
|
14253
|
+
if (existsSync19(join23(projectRoot, "go.mod"))) {
|
|
13829
14254
|
findings.push(...checkGoVerify(projectRoot));
|
|
13830
14255
|
}
|
|
13831
14256
|
} catch (err) {
|
|
@@ -13914,7 +14339,7 @@ function checkNpmAudit(projectRoot) {
|
|
|
13914
14339
|
function checkPackageJsonPatterns(projectRoot) {
|
|
13915
14340
|
const findings = [];
|
|
13916
14341
|
try {
|
|
13917
|
-
const pkgPath =
|
|
14342
|
+
const pkgPath = join23(projectRoot, "package.json");
|
|
13918
14343
|
const pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
13919
14344
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13920
14345
|
for (const [name, version] of Object.entries(allDeps)) {
|
|
@@ -13937,12 +14362,12 @@ function checkPackageJsonPatterns(projectRoot) {
|
|
|
13937
14362
|
}
|
|
13938
14363
|
function checkPostinstallScripts(projectRoot) {
|
|
13939
14364
|
const findings = [];
|
|
13940
|
-
const nodeModules =
|
|
14365
|
+
const nodeModules = join23(projectRoot, "node_modules");
|
|
13941
14366
|
if (!existsSync19(nodeModules)) return findings;
|
|
13942
14367
|
try {
|
|
13943
14368
|
const topLevelDeps = readdirSync11(nodeModules).filter((d) => !d.startsWith("."));
|
|
13944
14369
|
for (const dep of topLevelDeps) {
|
|
13945
|
-
const depPkgPath =
|
|
14370
|
+
const depPkgPath = join23(nodeModules, dep, "package.json");
|
|
13946
14371
|
if (!existsSync19(depPkgPath)) continue;
|
|
13947
14372
|
try {
|
|
13948
14373
|
const depPkg = JSON.parse(readFileSync18(depPkgPath, "utf-8"));
|
|
@@ -13983,7 +14408,7 @@ function checkPipAudit(projectRoot) {
|
|
|
13983
14408
|
id: "",
|
|
13984
14409
|
severity: cvssToSeverity(vuln.cvss?.score || 5),
|
|
13985
14410
|
vulnerabilityClass: "dependency-cve",
|
|
13986
|
-
file: existsSync19(
|
|
14411
|
+
file: existsSync19(join23(projectRoot, "requirements.txt")) ? "requirements.txt" : "pyproject.toml",
|
|
13987
14412
|
title: `Vulnerable Python dependency: ${vuln.name}`,
|
|
13988
14413
|
description: `${vuln.name}@${vuln.version} \u2014 ${vuln.id}: ${vuln.description || "Known vulnerability"}`,
|
|
13989
14414
|
attackScenario: `An attacker could exploit the vulnerability in ${vuln.name}.`,
|
|
@@ -14081,7 +14506,7 @@ function checkGoVerify(projectRoot) {
|
|
|
14081
14506
|
|
|
14082
14507
|
// src/security/checks/injection.ts
|
|
14083
14508
|
import { readFileSync as readFileSync19 } from "fs";
|
|
14084
|
-
import { join as
|
|
14509
|
+
import { join as join24 } from "path";
|
|
14085
14510
|
var SKIP_DIRS = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14086
14511
|
var TEST_PATTERNS = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__"];
|
|
14087
14512
|
var USER_INPUT_NAMES = /(?:input|user|name|path|query|branch|hash|cmd|command|req\.|params|body|args|url|dir|file|subdirectory)/i;
|
|
@@ -14405,6 +14830,52 @@ var PATTERNS = [
|
|
|
14405
14830
|
description: "Sensitive data stored in UserDefaults without encryption \u2014 easily accessible on jailbroken devices.",
|
|
14406
14831
|
attackScenario: "An attacker with device access could read UserDefaults plist to extract credentials.",
|
|
14407
14832
|
suggestedFix: "Use Keychain Services for storing sensitive data. Never store passwords or tokens in UserDefaults."
|
|
14833
|
+
},
|
|
14834
|
+
// Mojo injection patterns
|
|
14835
|
+
{
|
|
14836
|
+
regex: /\bPointer\s*\[\s*\w+\s*\]/,
|
|
14837
|
+
title: "Mojo unsafe Pointer[T] usage",
|
|
14838
|
+
vulnClass: "code-injection",
|
|
14839
|
+
baseSeverity: "medium",
|
|
14840
|
+
description: "Mojo Pointer[T] bypasses memory safety \u2014 potential for memory corruption or buffer overflow.",
|
|
14841
|
+
attackScenario: "An attacker could exploit unsafe pointer operations to corrupt memory or execute arbitrary code.",
|
|
14842
|
+
suggestedFix: "Use safe Mojo abstractions (SIMD, Tensor) instead of raw pointers where possible. Validate bounds."
|
|
14843
|
+
},
|
|
14844
|
+
{
|
|
14845
|
+
regex: /\bDTypePointer\b/,
|
|
14846
|
+
title: "Mojo unsafe DTypePointer usage",
|
|
14847
|
+
vulnClass: "code-injection",
|
|
14848
|
+
baseSeverity: "medium",
|
|
14849
|
+
description: "DTypePointer provides raw memory access without bounds checking.",
|
|
14850
|
+
attackScenario: "An attacker could exploit unvalidated pointer operations for buffer overflow or memory corruption.",
|
|
14851
|
+
suggestedFix: "Use Tensor or SIMD types with bounds checking instead of raw DTypePointer."
|
|
14852
|
+
},
|
|
14853
|
+
{
|
|
14854
|
+
regex: /from\s+python\s+import.*\beval\b/,
|
|
14855
|
+
title: "Mojo Python interop: eval() imported",
|
|
14856
|
+
vulnClass: "code-injection",
|
|
14857
|
+
baseSeverity: "high",
|
|
14858
|
+
description: "Python eval() imported via Mojo Python interop \u2014 can execute arbitrary code.",
|
|
14859
|
+
attackScenario: "An attacker could inject malicious code strings executed through the Python bridge.",
|
|
14860
|
+
suggestedFix: "Avoid importing eval. Use safe parsing alternatives or validate all input strictly."
|
|
14861
|
+
},
|
|
14862
|
+
{
|
|
14863
|
+
regex: /\b__get_address_as_lvalue\b/,
|
|
14864
|
+
title: "Mojo uninitialized memory access pattern",
|
|
14865
|
+
vulnClass: "code-injection",
|
|
14866
|
+
baseSeverity: "medium",
|
|
14867
|
+
description: "Low-level memory access without initialization \u2014 potential for use of uninitialized data.",
|
|
14868
|
+
attackScenario: "An attacker could exploit uninitialized memory to leak data or corrupt program state.",
|
|
14869
|
+
suggestedFix: "Always initialize memory before use. Use safe constructors and value semantics."
|
|
14870
|
+
},
|
|
14871
|
+
{
|
|
14872
|
+
regex: /SIMD\s*\[[^\]]*\]\s*\.\s*(?:store|load)\s*\(/,
|
|
14873
|
+
title: "Mojo SIMD store/load without bounds check",
|
|
14874
|
+
vulnClass: "code-injection",
|
|
14875
|
+
baseSeverity: "medium",
|
|
14876
|
+
description: "SIMD store/load operations without explicit bounds checking \u2014 buffer overflow risk.",
|
|
14877
|
+
attackScenario: "An attacker could trigger out-of-bounds SIMD operations to corrupt memory.",
|
|
14878
|
+
suggestedFix: "Validate buffer size against SIMD width before store/load operations."
|
|
14408
14879
|
}
|
|
14409
14880
|
];
|
|
14410
14881
|
function shouldSkip(filePath) {
|
|
@@ -14421,7 +14892,7 @@ async function checkInjection(files, projectRoot) {
|
|
|
14421
14892
|
if (shouldSkip(file.filePath) || isTestFile4(file.filePath)) continue;
|
|
14422
14893
|
let content;
|
|
14423
14894
|
try {
|
|
14424
|
-
content = readFileSync19(
|
|
14895
|
+
content = readFileSync19(join24(projectRoot, file.filePath), "utf-8");
|
|
14425
14896
|
} catch {
|
|
14426
14897
|
continue;
|
|
14427
14898
|
}
|
|
@@ -14460,7 +14931,7 @@ async function checkInjection(files, projectRoot) {
|
|
|
14460
14931
|
|
|
14461
14932
|
// src/security/checks/secrets.ts
|
|
14462
14933
|
import { readFileSync as readFileSync20 } from "fs";
|
|
14463
|
-
import { join as
|
|
14934
|
+
import { join as join25 } from "path";
|
|
14464
14935
|
var SKIP_DIRS2 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14465
14936
|
var TEST_PATTERNS2 = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__", ".example", ".sample"];
|
|
14466
14937
|
var SECRET_PATTERNS = [
|
|
@@ -14493,7 +14964,7 @@ async function checkSecrets(files, projectRoot) {
|
|
|
14493
14964
|
if (shouldSkip2(file.filePath) || isTestFile5(file.filePath)) continue;
|
|
14494
14965
|
let content;
|
|
14495
14966
|
try {
|
|
14496
|
-
content = readFileSync20(
|
|
14967
|
+
content = readFileSync20(join25(projectRoot, file.filePath), "utf-8");
|
|
14497
14968
|
} catch {
|
|
14498
14969
|
continue;
|
|
14499
14970
|
}
|
|
@@ -14527,7 +14998,7 @@ async function checkSecrets(files, projectRoot) {
|
|
|
14527
14998
|
|
|
14528
14999
|
// src/security/checks/path-traversal.ts
|
|
14529
15000
|
import { readFileSync as readFileSync21 } from "fs";
|
|
14530
|
-
import { join as
|
|
15001
|
+
import { join as join26 } from "path";
|
|
14531
15002
|
var SKIP_DIRS3 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14532
15003
|
var USER_INPUT_VARS = /(?:req\.|params|query|body|input|path|dir|subdirectory|file|userInput|fileName|filePath)/i;
|
|
14533
15004
|
var PATTERNS2 = [
|
|
@@ -14574,7 +15045,7 @@ async function checkPathTraversal(files, projectRoot) {
|
|
|
14574
15045
|
if (shouldSkip3(file.filePath)) continue;
|
|
14575
15046
|
let content;
|
|
14576
15047
|
try {
|
|
14577
|
-
content = readFileSync21(
|
|
15048
|
+
content = readFileSync21(join26(projectRoot, file.filePath), "utf-8");
|
|
14578
15049
|
} catch {
|
|
14579
15050
|
continue;
|
|
14580
15051
|
}
|
|
@@ -14617,7 +15088,7 @@ async function checkPathTraversal(files, projectRoot) {
|
|
|
14617
15088
|
|
|
14618
15089
|
// src/security/checks/auth.ts
|
|
14619
15090
|
import { readFileSync as readFileSync22 } from "fs";
|
|
14620
|
-
import { join as
|
|
15091
|
+
import { join as join27 } from "path";
|
|
14621
15092
|
var SKIP_DIRS4 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14622
15093
|
function shouldSkip4(filePath) {
|
|
14623
15094
|
return SKIP_DIRS4.some((d) => filePath.includes(d));
|
|
@@ -14633,7 +15104,7 @@ async function checkAuth(files, projectRoot) {
|
|
|
14633
15104
|
if (shouldSkip4(file.filePath)) continue;
|
|
14634
15105
|
let content;
|
|
14635
15106
|
try {
|
|
14636
|
-
content = readFileSync22(
|
|
15107
|
+
content = readFileSync22(join27(projectRoot, file.filePath), "utf-8");
|
|
14637
15108
|
} catch {
|
|
14638
15109
|
continue;
|
|
14639
15110
|
}
|
|
@@ -14725,7 +15196,7 @@ async function checkAuth(files, projectRoot) {
|
|
|
14725
15196
|
|
|
14726
15197
|
// src/security/checks/input-validation.ts
|
|
14727
15198
|
import { readFileSync as readFileSync23 } from "fs";
|
|
14728
|
-
import { join as
|
|
15199
|
+
import { join as join28 } from "path";
|
|
14729
15200
|
var SKIP_DIRS5 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14730
15201
|
function shouldSkip5(filePath) {
|
|
14731
15202
|
return SKIP_DIRS5.some((d) => filePath.includes(d));
|
|
@@ -14737,7 +15208,7 @@ async function checkInputValidation(files, projectRoot) {
|
|
|
14737
15208
|
if (shouldSkip5(file.filePath)) continue;
|
|
14738
15209
|
let content;
|
|
14739
15210
|
try {
|
|
14740
|
-
content = readFileSync23(
|
|
15211
|
+
content = readFileSync23(join28(projectRoot, file.filePath), "utf-8");
|
|
14741
15212
|
} catch {
|
|
14742
15213
|
continue;
|
|
14743
15214
|
}
|
|
@@ -14815,7 +15286,7 @@ async function checkInputValidation(files, projectRoot) {
|
|
|
14815
15286
|
|
|
14816
15287
|
// src/security/checks/information-disclosure.ts
|
|
14817
15288
|
import { readFileSync as readFileSync24 } from "fs";
|
|
14818
|
-
import { join as
|
|
15289
|
+
import { join as join29 } from "path";
|
|
14819
15290
|
var SKIP_DIRS6 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14820
15291
|
function shouldSkip6(filePath) {
|
|
14821
15292
|
return SKIP_DIRS6.some((d) => filePath.includes(d));
|
|
@@ -14827,7 +15298,7 @@ async function checkInformationDisclosure(files, projectRoot) {
|
|
|
14827
15298
|
if (shouldSkip6(file.filePath)) continue;
|
|
14828
15299
|
let content;
|
|
14829
15300
|
try {
|
|
14830
|
-
content = readFileSync24(
|
|
15301
|
+
content = readFileSync24(join29(projectRoot, file.filePath), "utf-8");
|
|
14831
15302
|
} catch {
|
|
14832
15303
|
continue;
|
|
14833
15304
|
}
|
|
@@ -14898,7 +15369,7 @@ async function checkInformationDisclosure(files, projectRoot) {
|
|
|
14898
15369
|
|
|
14899
15370
|
// src/security/checks/cryptography.ts
|
|
14900
15371
|
import { readFileSync as readFileSync25 } from "fs";
|
|
14901
|
-
import { join as
|
|
15372
|
+
import { join as join30 } from "path";
|
|
14902
15373
|
var SKIP_DIRS7 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
14903
15374
|
var USER_INPUT_NAMES2 = /(?:input|user|name|path|query|param|request|body|args|url)/i;
|
|
14904
15375
|
function shouldSkip7(filePath) {
|
|
@@ -14915,7 +15386,7 @@ async function checkCryptography(files, projectRoot) {
|
|
|
14915
15386
|
if (shouldSkip7(file.filePath)) continue;
|
|
14916
15387
|
let content;
|
|
14917
15388
|
try {
|
|
14918
|
-
content = readFileSync25(
|
|
15389
|
+
content = readFileSync25(join30(projectRoot, file.filePath), "utf-8");
|
|
14919
15390
|
} catch {
|
|
14920
15391
|
continue;
|
|
14921
15392
|
}
|
|
@@ -15251,6 +15722,47 @@ async function checkCryptography(files, projectRoot) {
|
|
|
15251
15722
|
suggestedFix: "Use HTTPS for all external URLs to ensure data confidentiality and integrity."
|
|
15252
15723
|
});
|
|
15253
15724
|
}
|
|
15725
|
+
if (/from\s+python\s+import\s+random/.test(line)) {
|
|
15726
|
+
findings.push({
|
|
15727
|
+
id: "",
|
|
15728
|
+
severity: "medium",
|
|
15729
|
+
vulnerabilityClass: "cryptography",
|
|
15730
|
+
file: file.filePath,
|
|
15731
|
+
line: i + 1,
|
|
15732
|
+
title: "Mojo weak random via Python random module",
|
|
15733
|
+
description: "Python random module imported via Mojo interop \u2014 not cryptographically secure.",
|
|
15734
|
+
attackScenario: "An attacker could predict random values to forge tokens or bypass security checks.",
|
|
15735
|
+
suggestedFix: "Use Python secrets module through interop, or implement CSPRNG natively in Mojo."
|
|
15736
|
+
});
|
|
15737
|
+
}
|
|
15738
|
+
if (/\balias\s+(?:key|secret|password|token|api_key)\s*[=:]\s*["'][^"']{4,}["']/i.test(line)) {
|
|
15739
|
+
findings.push({
|
|
15740
|
+
id: "",
|
|
15741
|
+
severity: "high",
|
|
15742
|
+
vulnerabilityClass: "cryptography",
|
|
15743
|
+
file: file.filePath,
|
|
15744
|
+
line: i + 1,
|
|
15745
|
+
title: "Hardcoded credentials in Mojo alias declaration",
|
|
15746
|
+
description: "A secret, key, or password is hardcoded in a compile-time alias \u2014 visible in source.",
|
|
15747
|
+
attackScenario: "An attacker with access to source or compiled binary could extract the credential.",
|
|
15748
|
+
suggestedFix: "Load credentials from environment variables at runtime instead of alias declarations."
|
|
15749
|
+
});
|
|
15750
|
+
}
|
|
15751
|
+
if (/from\s+python\s+import\s+hashlib/.test(line)) {
|
|
15752
|
+
if (isCryptoFile) {
|
|
15753
|
+
findings.push({
|
|
15754
|
+
id: "",
|
|
15755
|
+
severity: "medium",
|
|
15756
|
+
vulnerabilityClass: "cryptography",
|
|
15757
|
+
file: file.filePath,
|
|
15758
|
+
line: i + 1,
|
|
15759
|
+
title: "Mojo Python hashlib imported in security context",
|
|
15760
|
+
description: "Python hashlib imported via interop \u2014 ensure only strong algorithms (SHA-256+) are used.",
|
|
15761
|
+
attackScenario: "If MD5 or SHA-1 from hashlib is used, an attacker could exploit weak hash collisions.",
|
|
15762
|
+
suggestedFix: "Only use hashlib.sha256() or stronger. Avoid md5() and sha1() for security purposes."
|
|
15763
|
+
});
|
|
15764
|
+
}
|
|
15765
|
+
}
|
|
15254
15766
|
}
|
|
15255
15767
|
}
|
|
15256
15768
|
} catch {
|
|
@@ -15260,7 +15772,7 @@ async function checkCryptography(files, projectRoot) {
|
|
|
15260
15772
|
|
|
15261
15773
|
// src/security/checks/frontend.ts
|
|
15262
15774
|
import { readFileSync as readFileSync26 } from "fs";
|
|
15263
|
-
import { join as
|
|
15775
|
+
import { join as join31 } from "path";
|
|
15264
15776
|
var SKIP_DIRS8 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
|
|
15265
15777
|
function shouldSkip8(filePath) {
|
|
15266
15778
|
return SKIP_DIRS8.some((d) => filePath.includes(d));
|
|
@@ -15276,7 +15788,7 @@ async function checkFrontend(files, projectRoot) {
|
|
|
15276
15788
|
if (!isFrontendFile(file.filePath)) continue;
|
|
15277
15789
|
let content;
|
|
15278
15790
|
try {
|
|
15279
|
-
content = readFileSync26(
|
|
15791
|
+
content = readFileSync26(join31(projectRoot, file.filePath), "utf-8");
|
|
15280
15792
|
} catch {
|
|
15281
15793
|
continue;
|
|
15282
15794
|
}
|
|
@@ -15736,13 +16248,13 @@ async function scanSecurity(projectRoot, graph, options = {}) {
|
|
|
15736
16248
|
};
|
|
15737
16249
|
}
|
|
15738
16250
|
function detectPackageManager(projectRoot) {
|
|
15739
|
-
if (existsSync20(
|
|
15740
|
-
if (existsSync20(
|
|
15741
|
-
if (existsSync20(
|
|
15742
|
-
if (existsSync20(
|
|
15743
|
-
if (existsSync20(
|
|
15744
|
-
if (existsSync20(
|
|
15745
|
-
if (existsSync20(
|
|
16251
|
+
if (existsSync20(join32(projectRoot, "package.json"))) return "npm";
|
|
16252
|
+
if (existsSync20(join32(projectRoot, "requirements.txt"))) return "pip";
|
|
16253
|
+
if (existsSync20(join32(projectRoot, "pyproject.toml"))) return "pip";
|
|
16254
|
+
if (existsSync20(join32(projectRoot, "Cargo.toml"))) return "cargo";
|
|
16255
|
+
if (existsSync20(join32(projectRoot, "go.mod"))) return "go";
|
|
16256
|
+
if (existsSync20(join32(projectRoot, "pom.xml"))) return "maven";
|
|
16257
|
+
if (existsSync20(join32(projectRoot, "build.gradle")) || existsSync20(join32(projectRoot, "build.gradle.kts"))) return "gradle";
|
|
15746
16258
|
return "unknown";
|
|
15747
16259
|
}
|
|
15748
16260
|
|