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.
@@ -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 join14, resolve as resolve8 } from "path";
127
+ import { join as join15, resolve as resolve9 } from "path";
125
128
 
126
129
  // src/parser/detect.ts
127
- import { extname as extname9, basename as basename7 } from "path";
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 = extname9(filePath).toLowerCase();
6826
- const fileName = basename7(filePath);
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 = join14(projectRoot, file);
6863
- if (!resolve8(fullPath).startsWith(resolve8(projectRoot))) {
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 join15, resolve as resolve9 } from "path";
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 = join15(projectRoot, file.filePath);
7500
- if (!resolve9(fullPath).startsWith(resolve9(projectRoot))) continue;
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 join16, resolve as resolve10, basename as basename8 } from "path";
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 = basename8(f.filePath);
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 = join16(projectRoot, file.filePath);
7709
- if (!resolve10(fullPath).startsWith(resolve10(projectRoot))) continue;
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 = basename8(call.calledFile);
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 dirname13 } from "path";
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 = dirname13(sourceAttrs.filePath).split("/")[0];
8137
- const targetDir = dirname13(targetAttrs.filePath).split("/")[0];
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 = dirname13(sourceAttrs.filePath);
8185
- const targetDir = dirname13(targetAttrs.filePath);
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 dirname14, resolve as resolve11 } from "path";
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 = resolve11(projectRoot);
8568
- const historyFile = resolve11(resolvedRoot, ".depwire", "health-history.json");
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(dirname14(historyFile), { recursive: true });
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 = resolve11(projectRoot);
8601
- const historyFile = resolve11(resolvedRoot, ".depwire", "health-history.json");
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 basename12 = path3.basename(filePath);
9052
- return basename12 === "index.ts" || basename12 === "index.js";
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 join20 } from "path";
9657
+ import { join as join21 } from "path";
9233
9658
 
9234
9659
  // src/docs/architecture.ts
9235
- import { dirname as dirname15 } from "path";
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 = dirname15(attrs.filePath);
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 = dirname15(attrs.filePath);
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 = dirname15(sourceAttrs.filePath);
9427
- const targetDir = dirname15(targetAttrs.filePath);
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 basename9, extname as extname10 } from "path";
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 = basename9(attrs.filePath);
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 = basename9(attrs.filePath, extname10(attrs.filePath));
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 dirname16 } from "path";
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 = dirname16(attrs.filePath);
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 = dirname16(attrs.filePath);
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 = dirname16(attrs.filePath);
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 = dirname16(sourceAttrs.filePath);
10602
- const targetDir = dirname16(targetAttrs.filePath);
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 = dirname16(attrs.filePath);
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 = dirname16(files[0]);
10738
- if (files.every((f) => dirname16(f) === commonDir)) {
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 dirname17, basename as basename10 } from "path";
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 = dirname17(file.filePath);
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 = basename10(file.filePath);
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 basename11, dirname as dirname18 } from "path";
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 = basename11(filePath).toLowerCase();
11572
- const dirPath = dirname18(filePath).toLowerCase();
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 = basename11(testFile);
11631
- const testDir = dirname18(testFile);
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 = dirname18(testDir);
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 ? `\`${basename11(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 = dirname18(sourceFile).split("/")[0];
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 dirname19 } from "path";
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 = dirname19(attrs.filePath);
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 dirname20 } from "path";
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 = dirname20(info.filePath);
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 resolve12 } from "path";
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 = resolve12(projectRoot);
12603
- const fullPath = resolve12(resolvedRoot, filePath);
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 resolve13 } from "path";
13616
+ import { resolve as resolve14 } from "path";
13192
13617
  function loadMetadata(outputDir) {
13193
- const resolvedDir = resolve13(outputDir);
13194
- const metadataPath = resolve13(resolvedDir, "metadata.json");
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 = resolve13(outputDir);
13208
- const metadataPath = resolve13(resolvedDir, "metadata.json");
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 = join20(options.outputDir, "ARCHITECTURE.md");
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 = join20(options.outputDir, "CONVENTIONS.md");
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 = join20(options.outputDir, "DEPENDENCIES.md");
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 = join20(options.outputDir, "ONBOARDING.md");
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 = join20(options.outputDir, "FILES.md");
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 = join20(options.outputDir, "API_SURFACE.md");
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 = join20(options.outputDir, "ERRORS.md");
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 = join20(options.outputDir, "TESTS.md");
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 = join20(options.outputDir, "HISTORY.md");
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 = join20(options.outputDir, "CURRENT.md");
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 = join20(options.outputDir, "STATUS.md");
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 = join20(options.outputDir, "HEALTH.md");
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 = join20(options.outputDir, "DEAD_CODE.md");
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 dirname21, join as join21 } from "path";
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 = join21(dirname21(target), newName);
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 join31 } from "path";
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 join22 } from "path";
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(join22(projectRoot, "package.json"))) {
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(join22(projectRoot, "requirements.txt")) || existsSync19(join22(projectRoot, "pyproject.toml"))) {
14247
+ if (existsSync19(join23(projectRoot, "requirements.txt")) || existsSync19(join23(projectRoot, "pyproject.toml"))) {
13823
14248
  findings.push(...checkPipAudit(projectRoot));
13824
14249
  }
13825
- if (existsSync19(join22(projectRoot, "Cargo.toml"))) {
14250
+ if (existsSync19(join23(projectRoot, "Cargo.toml"))) {
13826
14251
  findings.push(...checkCargoAudit(projectRoot));
13827
14252
  }
13828
- if (existsSync19(join22(projectRoot, "go.mod"))) {
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 = join22(projectRoot, "package.json");
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 = join22(projectRoot, "node_modules");
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 = join22(nodeModules, dep, "package.json");
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(join22(projectRoot, "requirements.txt")) ? "requirements.txt" : "pyproject.toml",
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 join23 } from "path";
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(join23(projectRoot, file.filePath), "utf-8");
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 join24 } from "path";
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(join24(projectRoot, file.filePath), "utf-8");
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 join25 } from "path";
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(join25(projectRoot, file.filePath), "utf-8");
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 join26 } from "path";
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(join26(projectRoot, file.filePath), "utf-8");
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 join27 } from "path";
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(join27(projectRoot, file.filePath), "utf-8");
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 join28 } from "path";
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(join28(projectRoot, file.filePath), "utf-8");
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 join29 } from "path";
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(join29(projectRoot, file.filePath), "utf-8");
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 join30 } from "path";
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(join30(projectRoot, file.filePath), "utf-8");
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(join31(projectRoot, "package.json"))) return "npm";
15740
- if (existsSync20(join31(projectRoot, "requirements.txt"))) return "pip";
15741
- if (existsSync20(join31(projectRoot, "pyproject.toml"))) return "pip";
15742
- if (existsSync20(join31(projectRoot, "Cargo.toml"))) return "cargo";
15743
- if (existsSync20(join31(projectRoot, "go.mod"))) return "go";
15744
- if (existsSync20(join31(projectRoot, "pom.xml"))) return "maven";
15745
- if (existsSync20(join31(projectRoot, "build.gradle")) || existsSync20(join31(projectRoot, "build.gradle.kts"))) return "gradle";
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