depwire-cli 1.0.1 → 1.0.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.
@@ -31,10 +31,12 @@ function scanDirectory(rootDir, baseDir = rootDir) {
31
31
  const isPython = entry.endsWith(".py");
32
32
  const isGo = entry.endsWith(".go") && !entry.endsWith("_test.go");
33
33
  const isRust = entry.endsWith(".rs");
34
- const isC = entry.endsWith(".c") || entry.endsWith(".h");
34
+ const isC = entry.endsWith(".c");
35
+ const isCpp = entry.endsWith(".cpp") || entry.endsWith(".cc") || entry.endsWith(".cxx") || entry.endsWith(".c++") || entry.endsWith(".hpp") || entry.endsWith(".hh") || entry.endsWith(".hxx") || entry.endsWith(".h++") || entry.endsWith(".h") || entry.endsWith(".inl") || entry.endsWith(".ipp");
35
36
  const isCSharp = entry.endsWith(".cs") || entry.endsWith(".csx") || entry.endsWith(".csproj");
36
37
  const isJava = entry.endsWith(".java") || entry === "pom.xml" || entry === "build.gradle" || entry === "build.gradle.kts";
37
- if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCSharp || isJava) {
38
+ const isCppBuild = entry === "CMakeLists.txt" || entry === "conanfile.txt" || entry === "vcpkg.json";
39
+ if (isTypeScript || isJavaScript || isPython || isGo || isRust || isC || isCpp || isCSharp || isJava || isCppBuild) {
38
40
  files.push(relative(rootDir, fullPath));
39
41
  }
40
42
  }
@@ -109,11 +111,11 @@ function findProjectRoot(startDir = process.cwd()) {
109
111
  }
110
112
 
111
113
  // src/parser/index.ts
112
- import { readFileSync as readFileSync7, statSync as statSync4 } from "fs";
113
- import { join as join10, resolve as resolve5 } from "path";
114
+ import { readFileSync as readFileSync8, statSync as statSync5 } from "fs";
115
+ import { join as join11, resolve as resolve5 } from "path";
114
116
 
115
117
  // src/parser/detect.ts
116
- import { extname as extname5, basename as basename3 } from "path";
118
+ import { extname as extname6, basename as basename4 } from "path";
117
119
 
118
120
  // src/parser/wasm-init.ts
119
121
  import { Parser, Language } from "web-tree-sitter";
@@ -142,7 +144,8 @@ async function initParser() {
142
144
  "rust": "tree-sitter-rust.wasm",
143
145
  "c": "tree-sitter-c.wasm",
144
146
  "c_sharp": "tree-sitter-c_sharp.wasm",
145
- "java": "tree-sitter-java.wasm"
147
+ "java": "tree-sitter-java.wasm",
148
+ "cpp": "tree-sitter-cpp.wasm"
146
149
  };
147
150
  for (const [name, file] of Object.entries(grammarFiles)) {
148
151
  const wasmPath = path.join(grammarsDir, file);
@@ -2786,7 +2789,7 @@ function getCurrentSymbolId6(context) {
2786
2789
  }
2787
2790
  var cParser = {
2788
2791
  name: "c",
2789
- extensions: [".c", ".h"],
2792
+ extensions: [".c"],
2790
2793
  parseFile: parseCFile
2791
2794
  };
2792
2795
 
@@ -4096,6 +4099,834 @@ var javaParser = {
4096
4099
  parseFile: parseJavaFile
4097
4100
  };
4098
4101
 
4102
+ // src/parser/cpp.ts
4103
+ import { dirname as dirname9, join as join10, relative as relative5, basename as basename3 } from "path";
4104
+ import { existsSync as existsSync10 } from "fs";
4105
+ function parseCppFile(filePath, sourceCode, projectRoot) {
4106
+ if (basename3(filePath) === "CMakeLists.txt") {
4107
+ return parseCMakeLists(filePath, sourceCode, projectRoot);
4108
+ }
4109
+ if (basename3(filePath) === "conanfile.txt") {
4110
+ return parseConanfileTxt(filePath, sourceCode, projectRoot);
4111
+ }
4112
+ if (basename3(filePath) === "vcpkg.json") {
4113
+ return parseVcpkgJson(filePath, sourceCode, projectRoot);
4114
+ }
4115
+ const parser = getParser("cpp");
4116
+ const tree = parser.parse(sourceCode, null, { bufferSize: 1024 * 1024 });
4117
+ const context = {
4118
+ filePath,
4119
+ projectRoot,
4120
+ sourceCode,
4121
+ symbols: [],
4122
+ edges: [],
4123
+ currentScope: [],
4124
+ currentClass: null,
4125
+ currentNamespace: null,
4126
+ imports: /* @__PURE__ */ new Map(),
4127
+ isBuildFile: false
4128
+ };
4129
+ walkNode9(tree.rootNode, context);
4130
+ return {
4131
+ filePath,
4132
+ symbols: context.symbols,
4133
+ edges: context.edges
4134
+ };
4135
+ }
4136
+ function walkNode9(node, context) {
4137
+ processNode9(node, context);
4138
+ for (let i = 0; i < node.childCount; i++) {
4139
+ const child = node.child(i);
4140
+ if (child) {
4141
+ walkNode9(child, context);
4142
+ }
4143
+ }
4144
+ }
4145
+ function processNode9(node, context) {
4146
+ switch (node.type) {
4147
+ case "namespace_definition":
4148
+ processNamespaceDefinition(node, context);
4149
+ break;
4150
+ case "class_specifier":
4151
+ processClassSpecifier(node, context);
4152
+ break;
4153
+ case "struct_specifier":
4154
+ processStructSpecifier2(node, context);
4155
+ break;
4156
+ case "union_specifier":
4157
+ processUnionSpecifier(node, context);
4158
+ break;
4159
+ case "enum_specifier":
4160
+ processEnumSpecifier2(node, context);
4161
+ break;
4162
+ case "function_definition":
4163
+ processFunctionDefinition3(node, context);
4164
+ break;
4165
+ case "declaration":
4166
+ processDeclaration2(node, context);
4167
+ break;
4168
+ case "alias_declaration":
4169
+ processAliasDeclaration(node, context);
4170
+ break;
4171
+ case "type_definition":
4172
+ processTypeDefinition2(node, context);
4173
+ break;
4174
+ case "preproc_include":
4175
+ processIncludeDirective2(node, context);
4176
+ break;
4177
+ case "preproc_def":
4178
+ case "preproc_function_def":
4179
+ processMacroDefinition2(node, context);
4180
+ break;
4181
+ case "template_declaration":
4182
+ processTemplateDeclaration(node, context);
4183
+ break;
4184
+ case "call_expression":
4185
+ processCallExpression9(node, context);
4186
+ break;
4187
+ case "static_assert_declaration":
4188
+ processStaticAssert(node, context);
4189
+ break;
4190
+ }
4191
+ }
4192
+ function processNamespaceDefinition(node, context) {
4193
+ const nameNode = node.childForFieldName("name");
4194
+ const name = nameNode ? nodeText8(nameNode, context) : "<anonymous>";
4195
+ if (name !== "<anonymous>") {
4196
+ const symbolId = `${context.filePath}::${name}`;
4197
+ context.symbols.push({
4198
+ id: symbolId,
4199
+ name,
4200
+ kind: "module",
4201
+ filePath: context.filePath,
4202
+ startLine: node.startPosition.row + 1,
4203
+ endLine: node.endPosition.row + 1,
4204
+ exported: true
4205
+ });
4206
+ }
4207
+ const oldNamespace = context.currentNamespace;
4208
+ context.currentNamespace = name !== "<anonymous>" ? name : oldNamespace;
4209
+ if (name !== "<anonymous>") context.currentScope.push(name);
4210
+ const body = node.childForFieldName("body") || findChildByType9(node, "declaration_list");
4211
+ if (body) {
4212
+ walkNode9(body, context);
4213
+ }
4214
+ if (name !== "<anonymous>") context.currentScope.pop();
4215
+ context.currentNamespace = oldNamespace;
4216
+ }
4217
+ function processClassSpecifier(node, context) {
4218
+ processTypeSpecifier(node, context, "class");
4219
+ }
4220
+ function processStructSpecifier2(node, context) {
4221
+ processTypeSpecifier(node, context, "class");
4222
+ }
4223
+ function processUnionSpecifier(node, context) {
4224
+ processTypeSpecifier(node, context, "class");
4225
+ }
4226
+ function processTypeSpecifier(node, context, kind) {
4227
+ let nameNode = node.childForFieldName("name");
4228
+ let name = null;
4229
+ if (nameNode) {
4230
+ name = nodeText8(nameNode, context);
4231
+ const angleBracketIdx = name.indexOf("<");
4232
+ if (angleBracketIdx > 0) {
4233
+ name = name.substring(0, angleBracketIdx);
4234
+ }
4235
+ }
4236
+ if (!name) {
4237
+ const parent = node.parent;
4238
+ if (parent && parent.type === "type_definition") {
4239
+ const typedefDecl = parent.childForFieldName("declarator");
4240
+ if (typedefDecl) {
4241
+ name = extractIdentifierFromDeclarator2(typedefDecl, context);
4242
+ }
4243
+ }
4244
+ }
4245
+ if (!name) return;
4246
+ const exported = true;
4247
+ const scope = context.currentClass || void 0;
4248
+ const symbolId = `${context.filePath}::${name}`;
4249
+ context.symbols.push({
4250
+ id: symbolId,
4251
+ name,
4252
+ kind,
4253
+ filePath: context.filePath,
4254
+ startLine: node.startPosition.row + 1,
4255
+ endLine: node.endPosition.row + 1,
4256
+ exported,
4257
+ scope
4258
+ });
4259
+ const baseClause = findChildByType9(node, "base_class_clause");
4260
+ if (baseClause) {
4261
+ processBaseClassClause(baseClause, symbolId, context);
4262
+ }
4263
+ const oldClass = context.currentClass;
4264
+ context.currentClass = name;
4265
+ context.currentScope.push(name);
4266
+ const body = node.childForFieldName("body") || findChildByType9(node, "field_declaration_list");
4267
+ if (body) {
4268
+ walkNode9(body, context);
4269
+ }
4270
+ context.currentScope.pop();
4271
+ context.currentClass = oldClass;
4272
+ }
4273
+ function processBaseClassClause(node, sourceId, context) {
4274
+ for (let i = 0; i < node.childCount; i++) {
4275
+ const child = node.child(i);
4276
+ if (!child) continue;
4277
+ if (child.type === "base_class_specifier" || child.type === "type_identifier" || child.type === "qualified_identifier" || child.type === "template_type") {
4278
+ const baseName = extractTypeName4(child, context);
4279
+ if (baseName) {
4280
+ const baseId = resolveSymbol8(baseName, context);
4281
+ if (baseId) {
4282
+ context.edges.push({
4283
+ source: sourceId,
4284
+ target: baseId,
4285
+ kind: "inherits",
4286
+ filePath: context.filePath,
4287
+ line: child.startPosition.row + 1
4288
+ });
4289
+ }
4290
+ }
4291
+ }
4292
+ }
4293
+ }
4294
+ function processEnumSpecifier2(node, context) {
4295
+ let nameNode = node.childForFieldName("name");
4296
+ let name = null;
4297
+ if (nameNode) {
4298
+ name = nodeText8(nameNode, context);
4299
+ }
4300
+ if (!name) {
4301
+ const parent = node.parent;
4302
+ if (parent && parent.type === "type_definition") {
4303
+ const typedefDecl = parent.childForFieldName("declarator");
4304
+ if (typedefDecl) {
4305
+ name = extractIdentifierFromDeclarator2(typedefDecl, context);
4306
+ }
4307
+ }
4308
+ }
4309
+ if (!name) return;
4310
+ const symbolId = `${context.filePath}::${name}`;
4311
+ context.symbols.push({
4312
+ id: symbolId,
4313
+ name,
4314
+ kind: "enum",
4315
+ filePath: context.filePath,
4316
+ startLine: node.startPosition.row + 1,
4317
+ endLine: node.endPosition.row + 1,
4318
+ exported: true
4319
+ });
4320
+ const body = node.childForFieldName("body") || findChildByType9(node, "enumerator_list");
4321
+ if (body) {
4322
+ for (let i = 0; i < body.childCount; i++) {
4323
+ const child = body.child(i);
4324
+ if (child && child.type === "enumerator") {
4325
+ const constNameNode = child.childForFieldName("name");
4326
+ if (!constNameNode) continue;
4327
+ const constName = nodeText8(constNameNode, context);
4328
+ const constId = `${context.filePath}::${name}.${constName}`;
4329
+ context.symbols.push({
4330
+ id: constId,
4331
+ name: constName,
4332
+ kind: "constant",
4333
+ filePath: context.filePath,
4334
+ startLine: child.startPosition.row + 1,
4335
+ endLine: child.endPosition.row + 1,
4336
+ exported: true,
4337
+ scope: name
4338
+ });
4339
+ }
4340
+ }
4341
+ }
4342
+ }
4343
+ function processFunctionDefinition3(node, context) {
4344
+ const declarator = node.childForFieldName("declarator");
4345
+ if (!declarator) return;
4346
+ const nameNode = extractFunctionName2(declarator);
4347
+ if (!nameNode) return;
4348
+ let name = nodeText8(nameNode, context);
4349
+ if (name === "operator") {
4350
+ const fullText = nodeText8(declarator, context);
4351
+ const opMatch = fullText.match(/operator\s*([^\s(]+)/);
4352
+ if (opMatch) {
4353
+ name = `operator${opMatch[1]}`;
4354
+ }
4355
+ }
4356
+ const fullDeclText = nodeText8(declarator, context);
4357
+ if (fullDeclText.includes("~")) {
4358
+ const tildeMatch = fullDeclText.match(/~\s*(\w+)/);
4359
+ if (tildeMatch) {
4360
+ name = `~${tildeMatch[1]}`;
4361
+ }
4362
+ }
4363
+ const isConstructor = context.currentClass !== null && name === context.currentClass;
4364
+ const isDestructor = name.startsWith("~");
4365
+ const isStatic = hasStorageClass2(node, "static", context);
4366
+ const exported = !isStatic;
4367
+ const scope = context.currentClass || void 0;
4368
+ const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
4369
+ context.symbols.push({
4370
+ id: symbolId,
4371
+ name,
4372
+ kind: context.currentClass ? "method" : "function",
4373
+ filePath: context.filePath,
4374
+ startLine: node.startPosition.row + 1,
4375
+ endLine: node.endPosition.row + 1,
4376
+ exported,
4377
+ scope
4378
+ });
4379
+ const scopeName = scope ? `${scope}.${name}` : name;
4380
+ context.currentScope.push(scopeName);
4381
+ const body = node.childForFieldName("body");
4382
+ if (body) {
4383
+ walkNode9(body, context);
4384
+ }
4385
+ context.currentScope.pop();
4386
+ }
4387
+ function processDeclaration2(node, context) {
4388
+ if (context.currentClass) {
4389
+ processFieldDeclaration2(node, context);
4390
+ return;
4391
+ }
4392
+ const parent = node.parent;
4393
+ if (!parent || parent.type !== "translation_unit" && parent.type !== "declaration_list") {
4394
+ return;
4395
+ }
4396
+ const declarator = node.childForFieldName("declarator");
4397
+ if (!declarator) return;
4398
+ if (containsType(declarator, "function_declarator")) {
4399
+ return;
4400
+ }
4401
+ const name = extractIdentifierFromDeclarator2(declarator, context);
4402
+ if (!name) return;
4403
+ const isStatic = hasStorageClass2(node, "static", context);
4404
+ const isConst = nodeText8(node, context).includes("const");
4405
+ const symbolId = `${context.filePath}::${name}`;
4406
+ context.symbols.push({
4407
+ id: symbolId,
4408
+ name,
4409
+ kind: isConst ? "constant" : "variable",
4410
+ filePath: context.filePath,
4411
+ startLine: node.startPosition.row + 1,
4412
+ endLine: node.endPosition.row + 1,
4413
+ exported: !isStatic
4414
+ });
4415
+ }
4416
+ function processFieldDeclaration2(node, context) {
4417
+ const declarator = node.childForFieldName("declarator");
4418
+ if (!declarator) return;
4419
+ if (containsType(declarator, "function_declarator")) {
4420
+ const fnName = extractFunctionName2(declarator);
4421
+ if (fnName) {
4422
+ let name2 = nodeText8(fnName, context);
4423
+ const scope2 = context.currentClass || void 0;
4424
+ const symbolId2 = scope2 ? `${context.filePath}::${scope2}.${name2}` : `${context.filePath}::${name2}`;
4425
+ if (!context.symbols.find((s) => s.id === symbolId2)) {
4426
+ const exported = !hasAccessSpecifier(node, "private", context);
4427
+ context.symbols.push({
4428
+ id: symbolId2,
4429
+ name: name2,
4430
+ kind: "method",
4431
+ filePath: context.filePath,
4432
+ startLine: node.startPosition.row + 1,
4433
+ endLine: node.endPosition.row + 1,
4434
+ exported,
4435
+ scope: scope2
4436
+ });
4437
+ }
4438
+ }
4439
+ return;
4440
+ }
4441
+ const name = extractIdentifierFromDeclarator2(declarator, context);
4442
+ if (!name) return;
4443
+ const scope = context.currentClass || void 0;
4444
+ const symbolId = scope ? `${context.filePath}::${scope}.${name}` : `${context.filePath}::${name}`;
4445
+ const isConst = nodeText8(node, context).includes("const");
4446
+ const isStatic = nodeText8(node, context).includes("static");
4447
+ context.symbols.push({
4448
+ id: symbolId,
4449
+ name,
4450
+ kind: isConst && isStatic ? "constant" : "property",
4451
+ filePath: context.filePath,
4452
+ startLine: node.startPosition.row + 1,
4453
+ endLine: node.endPosition.row + 1,
4454
+ exported: !hasAccessSpecifier(node, "private", context),
4455
+ scope
4456
+ });
4457
+ }
4458
+ function processAliasDeclaration(node, context) {
4459
+ const nameNode = node.childForFieldName("name");
4460
+ if (!nameNode) return;
4461
+ const name = nodeText8(nameNode, context);
4462
+ const symbolId = `${context.filePath}::${name}`;
4463
+ context.symbols.push({
4464
+ id: symbolId,
4465
+ name,
4466
+ kind: "type_alias",
4467
+ filePath: context.filePath,
4468
+ startLine: node.startPosition.row + 1,
4469
+ endLine: node.endPosition.row + 1,
4470
+ exported: true
4471
+ });
4472
+ }
4473
+ function processTypeDefinition2(node, context) {
4474
+ const typeNode = node.childForFieldName("type");
4475
+ if (!typeNode) return;
4476
+ if (typeNode.type === "struct_specifier" || typeNode.type === "enum_specifier" || typeNode.type === "union_specifier") {
4477
+ return;
4478
+ }
4479
+ const declarator = node.childForFieldName("declarator");
4480
+ if (!declarator) return;
4481
+ const name = extractIdentifierFromDeclarator2(declarator, context);
4482
+ if (!name) return;
4483
+ const symbolId = `${context.filePath}::${name}`;
4484
+ context.symbols.push({
4485
+ id: symbolId,
4486
+ name,
4487
+ kind: "type_alias",
4488
+ filePath: context.filePath,
4489
+ startLine: node.startPosition.row + 1,
4490
+ endLine: node.endPosition.row + 1,
4491
+ exported: true
4492
+ });
4493
+ }
4494
+ function processTemplateDeclaration(node, context) {
4495
+ }
4496
+ function processStaticAssert(node, context) {
4497
+ const symbolId = `${context.filePath}::static_assert:${node.startPosition.row + 1}`;
4498
+ context.symbols.push({
4499
+ id: symbolId,
4500
+ name: "static_assert",
4501
+ kind: "constant",
4502
+ filePath: context.filePath,
4503
+ startLine: node.startPosition.row + 1,
4504
+ endLine: node.endPosition.row + 1,
4505
+ exported: false
4506
+ });
4507
+ }
4508
+ function processMacroDefinition2(node, context) {
4509
+ const nameNode = node.childForFieldName("name");
4510
+ if (!nameNode) return;
4511
+ const name = nodeText8(nameNode, context);
4512
+ const kind = node.type === "preproc_function_def" ? "function" : "constant";
4513
+ const symbolId = `${context.filePath}::${name}`;
4514
+ context.symbols.push({
4515
+ id: symbolId,
4516
+ name,
4517
+ kind,
4518
+ filePath: context.filePath,
4519
+ startLine: node.startPosition.row + 1,
4520
+ endLine: node.endPosition.row + 1,
4521
+ exported: true
4522
+ });
4523
+ }
4524
+ function processIncludeDirective2(node, context) {
4525
+ const pathNode = node.childForFieldName("path");
4526
+ if (!pathNode) return;
4527
+ const pathText = nodeText8(pathNode, context);
4528
+ const isLocalInclude = pathText.startsWith('"') && pathText.endsWith('"');
4529
+ if (!isLocalInclude) {
4530
+ const includeName = pathText.replace(/[<>"]/g, "");
4531
+ const symbolId = `${context.filePath}::include:${includeName}`;
4532
+ context.symbols.push({
4533
+ id: symbolId,
4534
+ name: includeName,
4535
+ kind: "import",
4536
+ filePath: context.filePath,
4537
+ startLine: node.startPosition.row + 1,
4538
+ endLine: node.endPosition.row + 1,
4539
+ exported: false
4540
+ });
4541
+ return;
4542
+ }
4543
+ const includePath = pathText.slice(1, -1);
4544
+ const resolvedFiles = resolveIncludePath2(includePath, context.filePath, context.projectRoot);
4545
+ if (resolvedFiles.length === 0) return;
4546
+ const sourceId = `${context.filePath}::__file__`;
4547
+ for (const targetPath of resolvedFiles) {
4548
+ const targetId = `${targetPath}::__file__`;
4549
+ context.edges.push({
4550
+ source: sourceId,
4551
+ target: targetId,
4552
+ kind: "imports",
4553
+ filePath: context.filePath,
4554
+ line: node.startPosition.row + 1
4555
+ });
4556
+ }
4557
+ }
4558
+ function processCallExpression9(node, context) {
4559
+ if (context.currentScope.length === 0) return;
4560
+ const functionNode = node.childForFieldName("function");
4561
+ if (!functionNode) return;
4562
+ let calleeName = null;
4563
+ if (functionNode.type === "identifier") {
4564
+ calleeName = nodeText8(functionNode, context);
4565
+ } else if (functionNode.type === "field_expression" || functionNode.type === "qualified_identifier") {
4566
+ const nameNode = functionNode.childForFieldName("name") || functionNode.childForFieldName("field");
4567
+ if (nameNode) {
4568
+ calleeName = nodeText8(nameNode, context);
4569
+ }
4570
+ } else if (functionNode.type === "template_function") {
4571
+ const nameNode = functionNode.childForFieldName("name");
4572
+ if (nameNode) {
4573
+ calleeName = nodeText8(nameNode, context);
4574
+ }
4575
+ }
4576
+ if (!calleeName) return;
4577
+ const builtins = /* @__PURE__ */ new Set([
4578
+ "printf",
4579
+ "scanf",
4580
+ "malloc",
4581
+ "free",
4582
+ "memcpy",
4583
+ "strlen",
4584
+ "strcmp",
4585
+ "strcpy",
4586
+ "strcat",
4587
+ "cout",
4588
+ "cin",
4589
+ "cerr",
4590
+ "endl",
4591
+ "make_shared",
4592
+ "make_unique",
4593
+ "make_pair",
4594
+ "make_tuple",
4595
+ "move",
4596
+ "forward",
4597
+ "swap",
4598
+ "begin",
4599
+ "end",
4600
+ "size",
4601
+ "empty",
4602
+ "push_back",
4603
+ "emplace_back",
4604
+ "insert",
4605
+ "erase",
4606
+ "find",
4607
+ "sort",
4608
+ "transform",
4609
+ "for_each",
4610
+ "accumulate",
4611
+ "static_cast",
4612
+ "dynamic_cast",
4613
+ "reinterpret_cast",
4614
+ "const_cast"
4615
+ ]);
4616
+ if (builtins.has(calleeName)) return;
4617
+ const callerId = getCurrentSymbolId9(context);
4618
+ if (!callerId) return;
4619
+ const calleeId = resolveSymbol8(calleeName, context);
4620
+ if (calleeId) {
4621
+ context.edges.push({
4622
+ source: callerId,
4623
+ target: calleeId,
4624
+ kind: "calls",
4625
+ filePath: context.filePath,
4626
+ line: node.startPosition.row + 1
4627
+ });
4628
+ }
4629
+ }
4630
+ function parseCMakeLists(filePath, sourceCode, projectRoot) {
4631
+ const symbols = [];
4632
+ const edges = [];
4633
+ const lines = sourceCode.split("\n");
4634
+ const projectName = basename3(dirname9(join10(projectRoot, filePath)));
4635
+ symbols.push({
4636
+ id: `${filePath}::${projectName}`,
4637
+ name: projectName,
4638
+ kind: "module",
4639
+ filePath,
4640
+ startLine: 1,
4641
+ endLine: lines.length,
4642
+ exported: true
4643
+ });
4644
+ for (let i = 0; i < lines.length; i++) {
4645
+ const line = lines[i].trim();
4646
+ const lineNum = i + 1;
4647
+ const findPkgMatch = line.match(/find_package\s*\(\s*(\w+)/i);
4648
+ if (findPkgMatch) {
4649
+ symbols.push({
4650
+ id: `${filePath}::dep:${findPkgMatch[1]}`,
4651
+ name: findPkgMatch[1],
4652
+ kind: "import",
4653
+ filePath,
4654
+ startLine: lineNum,
4655
+ endLine: lineNum,
4656
+ exported: false
4657
+ });
4658
+ }
4659
+ const linkLibsMatch = line.match(/target_link_libraries\s*\(\s*\w+\s+(?:PRIVATE|PUBLIC|INTERFACE)?\s*(.*)\)/i);
4660
+ if (linkLibsMatch) {
4661
+ const libs = linkLibsMatch[1].trim().split(/\s+/).filter((l) => l && !["PRIVATE", "PUBLIC", "INTERFACE"].includes(l));
4662
+ for (const lib of libs) {
4663
+ symbols.push({
4664
+ id: `${filePath}::dep:${lib}`,
4665
+ name: lib,
4666
+ kind: "import",
4667
+ filePath,
4668
+ startLine: lineNum,
4669
+ endLine: lineNum,
4670
+ exported: false
4671
+ });
4672
+ }
4673
+ }
4674
+ const addSubdirMatch = line.match(/add_subdirectory\s*\(\s*([^\s)]+)/i);
4675
+ if (addSubdirMatch) {
4676
+ const subdir = addSubdirMatch[1];
4677
+ const cmakeDir = dirname9(join10(projectRoot, filePath));
4678
+ const subdirCMake = join10(relative5(projectRoot, cmakeDir), subdir, "CMakeLists.txt");
4679
+ if (existsSync10(join10(projectRoot, subdirCMake))) {
4680
+ edges.push({
4681
+ source: `${filePath}::__file__`,
4682
+ target: `${subdirCMake}::__file__`,
4683
+ kind: "imports",
4684
+ filePath,
4685
+ line: lineNum
4686
+ });
4687
+ }
4688
+ }
4689
+ const projectMatch = line.match(/project\s*\(\s*(\w+)/i);
4690
+ if (projectMatch) {
4691
+ symbols.push({
4692
+ id: `${filePath}::project:${projectMatch[1]}`,
4693
+ name: projectMatch[1],
4694
+ kind: "module",
4695
+ filePath,
4696
+ startLine: lineNum,
4697
+ endLine: lineNum,
4698
+ exported: true
4699
+ });
4700
+ }
4701
+ }
4702
+ return { filePath, symbols, edges };
4703
+ }
4704
+ function parseConanfileTxt(filePath, sourceCode, _projectRoot) {
4705
+ const symbols = [];
4706
+ const lines = sourceCode.split("\n");
4707
+ let inRequires = false;
4708
+ for (let i = 0; i < lines.length; i++) {
4709
+ const line = lines[i].trim();
4710
+ const lineNum = i + 1;
4711
+ if (line === "[requires]") {
4712
+ inRequires = true;
4713
+ continue;
4714
+ }
4715
+ if (line.startsWith("[") && line.endsWith("]")) {
4716
+ inRequires = false;
4717
+ continue;
4718
+ }
4719
+ if (inRequires && line.length > 0) {
4720
+ symbols.push({
4721
+ id: `${filePath}::dep:${line}`,
4722
+ name: line,
4723
+ kind: "import",
4724
+ filePath,
4725
+ startLine: lineNum,
4726
+ endLine: lineNum,
4727
+ exported: false
4728
+ });
4729
+ }
4730
+ }
4731
+ return { filePath, symbols, edges: [] };
4732
+ }
4733
+ function parseVcpkgJson(filePath, sourceCode, _projectRoot) {
4734
+ const symbols = [];
4735
+ try {
4736
+ const vcpkg = JSON.parse(sourceCode);
4737
+ if (vcpkg.dependencies && Array.isArray(vcpkg.dependencies)) {
4738
+ for (let i = 0; i < vcpkg.dependencies.length; i++) {
4739
+ const dep = vcpkg.dependencies[i];
4740
+ const name = typeof dep === "string" ? dep : dep.name || "";
4741
+ if (name) {
4742
+ symbols.push({
4743
+ id: `${filePath}::dep:${name}`,
4744
+ name,
4745
+ kind: "import",
4746
+ filePath,
4747
+ startLine: 1,
4748
+ endLine: 1,
4749
+ exported: false
4750
+ });
4751
+ }
4752
+ }
4753
+ }
4754
+ } catch {
4755
+ }
4756
+ return { filePath, symbols, edges: [] };
4757
+ }
4758
+ function resolveIncludePath2(includePath, currentFile, projectRoot) {
4759
+ const currentFileAbs = join10(projectRoot, currentFile);
4760
+ const currentDir = dirname9(currentFileAbs);
4761
+ const possibleFiles = [
4762
+ join10(currentDir, includePath),
4763
+ join10(projectRoot, includePath),
4764
+ join10(projectRoot, "include", includePath),
4765
+ join10(projectRoot, "src", includePath)
4766
+ ];
4767
+ const resolvedFiles = [];
4768
+ for (const absPath of possibleFiles) {
4769
+ if (existsSync10(absPath)) {
4770
+ const relPath = relative5(projectRoot, absPath);
4771
+ if (!resolvedFiles.includes(relPath)) {
4772
+ resolvedFiles.push(relPath);
4773
+ }
4774
+ }
4775
+ }
4776
+ return resolvedFiles;
4777
+ }
4778
+ function resolveSymbol8(name, context) {
4779
+ if (context.imports.has(name)) {
4780
+ return context.imports.get(name) || null;
4781
+ }
4782
+ const currentFileId = `${context.filePath}::${name}`;
4783
+ if (context.symbols.find((s) => s.id === currentFileId)) {
4784
+ return currentFileId;
4785
+ }
4786
+ if (context.currentClass) {
4787
+ const classMethodId = `${context.filePath}::${context.currentClass}.${name}`;
4788
+ if (context.symbols.find((s) => s.id === classMethodId)) {
4789
+ return classMethodId;
4790
+ }
4791
+ }
4792
+ return null;
4793
+ }
4794
+ function hasStorageClass2(node, className, context) {
4795
+ for (let i = 0; i < node.childCount; i++) {
4796
+ const child = node.child(i);
4797
+ if (child && child.type === "storage_class_specifier") {
4798
+ if (nodeText8(child, context) === className) {
4799
+ return true;
4800
+ }
4801
+ }
4802
+ }
4803
+ return false;
4804
+ }
4805
+ function hasAccessSpecifier(node, specifier, context) {
4806
+ const parent = node.parent;
4807
+ if (!parent) return false;
4808
+ let lastAccess = "";
4809
+ for (let i = 0; i < parent.childCount; i++) {
4810
+ const child = parent.child(i);
4811
+ if (!child) continue;
4812
+ if (child.type === "access_specifier") {
4813
+ lastAccess = nodeText8(child, context).replace(":", "").trim();
4814
+ }
4815
+ if (child === node) break;
4816
+ }
4817
+ return lastAccess === specifier;
4818
+ }
4819
+ function extractFunctionName2(declarator) {
4820
+ if (declarator.type === "identifier") {
4821
+ return declarator;
4822
+ }
4823
+ if (declarator.type === "function_declarator") {
4824
+ const innerDeclarator = declarator.childForFieldName("declarator");
4825
+ if (innerDeclarator) {
4826
+ return extractFunctionName2(innerDeclarator);
4827
+ }
4828
+ }
4829
+ if (declarator.type === "pointer_declarator" || declarator.type === "reference_declarator") {
4830
+ const innerDeclarator = declarator.childForFieldName("declarator");
4831
+ if (innerDeclarator) {
4832
+ return extractFunctionName2(innerDeclarator);
4833
+ }
4834
+ }
4835
+ if (declarator.type === "qualified_identifier" || declarator.type === "template_function") {
4836
+ const nameNode = declarator.childForFieldName("name");
4837
+ if (nameNode) {
4838
+ return extractFunctionName2(nameNode);
4839
+ }
4840
+ }
4841
+ if (declarator.type === "destructor_name") {
4842
+ return declarator;
4843
+ }
4844
+ if (declarator.type === "operator_name") {
4845
+ return declarator;
4846
+ }
4847
+ for (let i = 0; i < declarator.childCount; i++) {
4848
+ const child = declarator.child(i);
4849
+ if (child && child.type === "identifier") {
4850
+ return child;
4851
+ }
4852
+ }
4853
+ return null;
4854
+ }
4855
+ function extractIdentifierFromDeclarator2(declarator, context) {
4856
+ if (declarator.type === "identifier") {
4857
+ return nodeText8(declarator, context);
4858
+ }
4859
+ if (declarator.type === "type_identifier") {
4860
+ return nodeText8(declarator, context);
4861
+ }
4862
+ const identifierNode = findChildByType9(declarator, "identifier");
4863
+ if (identifierNode) {
4864
+ return nodeText8(identifierNode, context);
4865
+ }
4866
+ const typeIdNode = findChildByType9(declarator, "type_identifier");
4867
+ if (typeIdNode) {
4868
+ return nodeText8(typeIdNode, context);
4869
+ }
4870
+ for (let i = 0; i < declarator.childCount; i++) {
4871
+ const child = declarator.child(i);
4872
+ if (child) {
4873
+ const name = extractIdentifierFromDeclarator2(child, context);
4874
+ if (name) return name;
4875
+ }
4876
+ }
4877
+ return null;
4878
+ }
4879
+ function extractTypeName4(node, context) {
4880
+ const text = nodeText8(node, context).trim();
4881
+ if (!text || text === ":" || text === ",") return null;
4882
+ const accessStripped = text.replace(/^(?:public|protected|private|virtual)\s+/g, "");
4883
+ const angleBracketIdx = accessStripped.indexOf("<");
4884
+ const name = angleBracketIdx > 0 ? accessStripped.substring(0, angleBracketIdx) : accessStripped;
4885
+ const colonIdx = name.lastIndexOf("::");
4886
+ return colonIdx >= 0 ? name.substring(colonIdx + 2) : name;
4887
+ }
4888
+ function containsType(node, type) {
4889
+ if (node.type === type) return true;
4890
+ for (let i = 0; i < node.childCount; i++) {
4891
+ const child = node.child(i);
4892
+ if (child && containsType(child, type)) return true;
4893
+ }
4894
+ return false;
4895
+ }
4896
+ function findChildByType9(node, type) {
4897
+ for (let i = 0; i < node.childCount; i++) {
4898
+ const child = node.child(i);
4899
+ if (child && child.type === type) return child;
4900
+ }
4901
+ return null;
4902
+ }
4903
+ function nodeText8(node, context) {
4904
+ return context.sourceCode.substring(node.startIndex, node.endIndex);
4905
+ }
4906
+ function getCurrentSymbolId9(context) {
4907
+ if (context.currentScope.length === 0) return null;
4908
+ return `${context.filePath}::${context.currentScope[context.currentScope.length - 1]}`;
4909
+ }
4910
+ var cppParser = {
4911
+ name: "cpp",
4912
+ extensions: [
4913
+ ".cpp",
4914
+ ".cc",
4915
+ ".cxx",
4916
+ ".c++",
4917
+ ".hpp",
4918
+ ".hh",
4919
+ ".hxx",
4920
+ ".h++",
4921
+ ".inl",
4922
+ ".ipp",
4923
+ "CMakeLists.txt",
4924
+ "conanfile.txt",
4925
+ "vcpkg.json"
4926
+ ],
4927
+ parseFile: parseCppFile
4928
+ };
4929
+
4099
4930
  // src/parser/detect.ts
4100
4931
  var parsers = [
4101
4932
  typescriptParser,
@@ -4105,11 +4936,22 @@ var parsers = [
4105
4936
  rustParser,
4106
4937
  cParser,
4107
4938
  csharpParser,
4108
- javaParser
4939
+ javaParser,
4940
+ cppParser
4109
4941
  ];
4110
- function getParserForFile(filePath) {
4111
- const ext = extname5(filePath).toLowerCase();
4112
- const fileName = basename3(filePath);
4942
+ 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/;
4943
+ function getParserForFile(filePath, content) {
4944
+ const ext = extname6(filePath).toLowerCase();
4945
+ const fileName = basename4(filePath);
4946
+ if (ext === ".h" && content) {
4947
+ if (CPP_KEYWORDS.test(content)) {
4948
+ return cppParser;
4949
+ }
4950
+ return cParser;
4951
+ }
4952
+ if (ext === ".h") {
4953
+ return cParser;
4954
+ }
4113
4955
  return parsers.find((p) => p.extensions.includes(ext) || p.extensions.includes(fileName)) || null;
4114
4956
  }
4115
4957
 
@@ -4118,7 +4960,7 @@ import { minimatch } from "minimatch";
4118
4960
  var MAX_FILE_SIZE = 1e6;
4119
4961
  function shouldParseFile(fullPath) {
4120
4962
  try {
4121
- const stats = statSync4(fullPath);
4963
+ const stats = statSync5(fullPath);
4122
4964
  if (stats.size > MAX_FILE_SIZE) {
4123
4965
  console.error(`[Parser] Skipping ${fullPath} \u2014 file too large (${(stats.size / 1024).toFixed(0)}KB)`);
4124
4966
  return false;
@@ -4136,7 +4978,7 @@ async function parseProject(projectRoot, options) {
4136
4978
  let errorFiles = 0;
4137
4979
  for (const file of files) {
4138
4980
  try {
4139
- const fullPath = join10(projectRoot, file);
4981
+ const fullPath = join11(projectRoot, file);
4140
4982
  if (!resolve5(fullPath).startsWith(resolve5(projectRoot))) {
4141
4983
  skippedFiles++;
4142
4984
  continue;
@@ -4160,13 +5002,13 @@ async function parseProject(projectRoot, options) {
4160
5002
  if (options?.verbose) {
4161
5003
  console.error(`[Parser] Parsing: ${file}`);
4162
5004
  }
4163
- const parser = getParserForFile(file);
5005
+ const sourceCode = readFileSync8(fullPath, "utf-8");
5006
+ const parser = getParserForFile(file, sourceCode);
4164
5007
  if (!parser) {
4165
5008
  console.error(`No parser found for file: ${file}`);
4166
5009
  skippedFiles++;
4167
5010
  continue;
4168
5011
  }
4169
- const sourceCode = readFileSync7(fullPath, "utf-8");
4170
5012
  const parsed = parser.parseFile(file, sourceCode, projectRoot);
4171
5013
  parsedFiles.push(parsed);
4172
5014
  } catch (err) {
@@ -4189,8 +5031,8 @@ async function parseProject(projectRoot, options) {
4189
5031
  }
4190
5032
 
4191
5033
  // src/cross-language/detectors/rest-api.ts
4192
- import { readFileSync as readFileSync8 } from "fs";
4193
- import { join as join11, resolve as resolve6 } from "path";
5034
+ import { readFileSync as readFileSync9 } from "fs";
5035
+ import { join as join12, resolve as resolve6 } from "path";
4194
5036
  function getLanguage(filePath) {
4195
5037
  if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
4196
5038
  if (filePath.endsWith(".js") || filePath.endsWith(".jsx") || filePath.endsWith(".mjs") || filePath.endsWith(".cjs")) return "javascript";
@@ -4198,6 +5040,7 @@ function getLanguage(filePath) {
4198
5040
  if (filePath.endsWith(".go")) return "go";
4199
5041
  if (filePath.endsWith(".cs") || filePath.endsWith(".csx")) return "csharp";
4200
5042
  if (filePath.endsWith(".java")) return "java";
5043
+ 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";
4201
5044
  return "unknown";
4202
5045
  }
4203
5046
  function normalizePath(routePath) {
@@ -4451,6 +5294,72 @@ function extractRouteDefinitions(source, filePath) {
4451
5294
  });
4452
5295
  }
4453
5296
  }
5297
+ if (lang === "cpp") {
5298
+ const crowMatch = line.match(/CROW_ROUTE\s*\(\s*\w+\s*,\s*"([^"]+)"/);
5299
+ if (crowMatch) {
5300
+ const path6 = crowMatch[1];
5301
+ if (path6.startsWith("/")) {
5302
+ const methodsMatch = line.match(/methods\s*\(\s*"([^"]+)"_method/);
5303
+ const method = methodsMatch ? methodsMatch[1].toUpperCase() : "ANY";
5304
+ routes.push({
5305
+ method,
5306
+ path: path6,
5307
+ normalizedPath: normalizePath(path6),
5308
+ file: filePath,
5309
+ line: i + 1
5310
+ });
5311
+ }
5312
+ }
5313
+ const drogonMatch = line.match(/ADD_METHOD_TO\s*\(\s*[^,]+,\s*"([^"]+)"\s*,\s*(\w+)/);
5314
+ if (drogonMatch) {
5315
+ const path6 = drogonMatch[1].startsWith("/") ? drogonMatch[1] : "/" + drogonMatch[1];
5316
+ routes.push({
5317
+ method: drogonMatch[2].toUpperCase(),
5318
+ path: path6,
5319
+ normalizedPath: normalizePath(path6),
5320
+ file: filePath,
5321
+ line: i + 1
5322
+ });
5323
+ }
5324
+ const pathAddMatch = line.match(/PATH_ADD\s*\(\s*"([^"]+)"\s*,\s*(\w+)/);
5325
+ if (pathAddMatch) {
5326
+ const path6 = pathAddMatch[1].startsWith("/") ? pathAddMatch[1] : "/" + pathAddMatch[1];
5327
+ routes.push({
5328
+ method: pathAddMatch[2].toUpperCase(),
5329
+ path: path6,
5330
+ normalizedPath: normalizePath(path6),
5331
+ file: filePath,
5332
+ line: i + 1
5333
+ });
5334
+ }
5335
+ const pistacheMatch = line.match(/router\s*\.\s*(get|post|put|del|patch)\s*\(\s*"([^"]+)"/i);
5336
+ if (pistacheMatch) {
5337
+ const method = pistacheMatch[1].toUpperCase() === "DEL" ? "DELETE" : pistacheMatch[1].toUpperCase();
5338
+ const path6 = pistacheMatch[2];
5339
+ if (path6.startsWith("/")) {
5340
+ routes.push({
5341
+ method,
5342
+ path: path6,
5343
+ normalizedPath: normalizePath(path6),
5344
+ file: filePath,
5345
+ line: i + 1
5346
+ });
5347
+ }
5348
+ }
5349
+ const httplibMatch = line.match(/(?:svr|server)\s*\.\s*(Get|Post|Put|Delete|Patch)\s*\(\s*"([^"]+)"/);
5350
+ if (httplibMatch) {
5351
+ const path6 = httplibMatch[2];
5352
+ if (path6.startsWith("/")) {
5353
+ routes.push({
5354
+ method: httplibMatch[1].toUpperCase(),
5355
+ path: path6,
5356
+ normalizedPath: normalizePath(path6),
5357
+ file: filePath,
5358
+ line: i + 1
5359
+ });
5360
+ }
5361
+ }
5362
+ }
4454
5363
  }
4455
5364
  return routes;
4456
5365
  }
@@ -4499,11 +5408,11 @@ function detectRestApiEdges(files, projectRoot) {
4499
5408
  const allCalls = [];
4500
5409
  const allRoutes = [];
4501
5410
  for (const file of files) {
4502
- const fullPath = join11(projectRoot, file.filePath);
5411
+ const fullPath = join12(projectRoot, file.filePath);
4503
5412
  if (!resolve6(fullPath).startsWith(resolve6(projectRoot))) continue;
4504
5413
  let source;
4505
5414
  try {
4506
- source = readFileSync8(fullPath, "utf-8");
5415
+ source = readFileSync9(fullPath, "utf-8");
4507
5416
  } catch {
4508
5417
  continue;
4509
5418
  }
@@ -4539,8 +5448,8 @@ function detectRestApiEdges(files, projectRoot) {
4539
5448
  }
4540
5449
 
4541
5450
  // src/cross-language/detectors/subprocess.ts
4542
- import { readFileSync as readFileSync9 } from "fs";
4543
- import { join as join12, resolve as resolve7, basename as basename4 } from "path";
5451
+ import { readFileSync as readFileSync10 } from "fs";
5452
+ import { join as join13, resolve as resolve7, basename as basename5 } from "path";
4544
5453
  var SCRIPT_EXTENSIONS = [".py", ".js", ".ts", ".go", ".rs"];
4545
5454
  function getLanguage2(filePath) {
4546
5455
  if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
@@ -4639,16 +5548,16 @@ function detectSubprocessEdges(files, projectRoot) {
4639
5548
  const knownFiles = new Set(files.map((f) => f.filePath));
4640
5549
  const basenameMap = /* @__PURE__ */ new Map();
4641
5550
  for (const f of files) {
4642
- const base = basename4(f.filePath);
5551
+ const base = basename5(f.filePath);
4643
5552
  if (!basenameMap.has(base)) basenameMap.set(base, []);
4644
5553
  basenameMap.get(base).push(f.filePath);
4645
5554
  }
4646
5555
  for (const file of files) {
4647
- const fullPath = join12(projectRoot, file.filePath);
5556
+ const fullPath = join13(projectRoot, file.filePath);
4648
5557
  if (!resolve7(fullPath).startsWith(resolve7(projectRoot))) continue;
4649
5558
  let source;
4650
5559
  try {
4651
- source = readFileSync9(fullPath, "utf-8");
5560
+ source = readFileSync10(fullPath, "utf-8");
4652
5561
  } catch {
4653
5562
  continue;
4654
5563
  }
@@ -4660,7 +5569,7 @@ function detectSubprocessEdges(files, projectRoot) {
4660
5569
  targetFile = call.calledFile;
4661
5570
  confidence = "high";
4662
5571
  } else {
4663
- const base = basename4(call.calledFile);
5572
+ const base = basename5(call.calledFile);
4664
5573
  const candidates = basenameMap.get(base);
4665
5574
  if (candidates && candidates.length > 0) {
4666
5575
  const exactCandidate = candidates.find((c) => c.endsWith(call.calledFile));
@@ -5039,7 +5948,7 @@ function getArchitectureSummary(graph) {
5039
5948
  }
5040
5949
 
5041
5950
  // src/health/metrics.ts
5042
- import { dirname as dirname9 } from "path";
5951
+ import { dirname as dirname10 } from "path";
5043
5952
  function scoreToGrade(score) {
5044
5953
  if (score >= 90) return "A";
5045
5954
  if (score >= 80) return "B";
@@ -5072,8 +5981,8 @@ function calculateCouplingScore(graph) {
5072
5981
  totalEdges++;
5073
5982
  fileConnections.set(sourceAttrs.filePath, (fileConnections.get(sourceAttrs.filePath) || 0) + 1);
5074
5983
  fileConnections.set(targetAttrs.filePath, (fileConnections.get(targetAttrs.filePath) || 0) + 1);
5075
- const sourceDir = dirname9(sourceAttrs.filePath).split("/")[0];
5076
- const targetDir = dirname9(targetAttrs.filePath).split("/")[0];
5984
+ const sourceDir = dirname10(sourceAttrs.filePath).split("/")[0];
5985
+ const targetDir = dirname10(targetAttrs.filePath).split("/")[0];
5077
5986
  if (sourceDir !== targetDir) {
5078
5987
  crossDirEdges++;
5079
5988
  }
@@ -5120,8 +6029,8 @@ function calculateCohesionScore(graph) {
5120
6029
  const sourceAttrs = graph.getNodeAttributes(source);
5121
6030
  const targetAttrs = graph.getNodeAttributes(target);
5122
6031
  if (sourceAttrs.filePath !== targetAttrs.filePath) {
5123
- const sourceDir = dirname9(sourceAttrs.filePath);
5124
- const targetDir = dirname9(targetAttrs.filePath);
6032
+ const sourceDir = dirname10(sourceAttrs.filePath);
6033
+ const targetDir = dirname10(targetAttrs.filePath);
5125
6034
  if (!dirEdges.has(sourceDir)) {
5126
6035
  dirEdges.set(sourceDir, { internal: 0, total: 0 });
5127
6036
  }
@@ -5403,8 +6312,8 @@ function calculateDepthScore(graph) {
5403
6312
  }
5404
6313
 
5405
6314
  // src/health/index.ts
5406
- import { readFileSync as readFileSync10, writeFileSync, existsSync as existsSync10, mkdirSync } from "fs";
5407
- import { dirname as dirname10, resolve as resolve8 } from "path";
6315
+ import { readFileSync as readFileSync11, writeFileSync, existsSync as existsSync11, mkdirSync } from "fs";
6316
+ import { dirname as dirname11, resolve as resolve8 } from "path";
5408
6317
  function calculateHealthScore(graph, projectRoot) {
5409
6318
  const coupling = calculateCouplingScore(graph);
5410
6319
  const cohesion = calculateCohesionScore(graph);
@@ -5519,10 +6428,10 @@ function saveHealthHistory(projectRoot, report) {
5519
6428
  }))
5520
6429
  };
5521
6430
  let history = [];
5522
- if (existsSync10(historyFile)) {
6431
+ if (existsSync11(historyFile)) {
5523
6432
  try {
5524
6433
  if (!historyFile.startsWith(resolvedRoot)) return;
5525
- const content = readFileSync10(historyFile, "utf-8");
6434
+ const content = readFileSync11(historyFile, "utf-8");
5526
6435
  history = JSON.parse(content);
5527
6436
  } catch {
5528
6437
  }
@@ -5531,19 +6440,19 @@ function saveHealthHistory(projectRoot, report) {
5531
6440
  if (history.length > 50) {
5532
6441
  history = history.slice(-50);
5533
6442
  }
5534
- mkdirSync(dirname10(historyFile), { recursive: true });
6443
+ mkdirSync(dirname11(historyFile), { recursive: true });
5535
6444
  if (!historyFile.startsWith(resolvedRoot)) return;
5536
6445
  writeFileSync(historyFile, JSON.stringify(history, null, 2), "utf-8");
5537
6446
  }
5538
6447
  function loadHealthHistory(projectRoot) {
5539
6448
  const resolvedRoot = resolve8(projectRoot);
5540
6449
  const historyFile = resolve8(resolvedRoot, ".depwire", "health-history.json");
5541
- if (!historyFile.startsWith(resolvedRoot) || !existsSync10(historyFile)) {
6450
+ if (!historyFile.startsWith(resolvedRoot) || !existsSync11(historyFile)) {
5542
6451
  return [];
5543
6452
  }
5544
6453
  try {
5545
6454
  if (!historyFile.startsWith(resolvedRoot)) return [];
5546
- const content = readFileSync10(historyFile, "utf-8");
6455
+ const content = readFileSync11(historyFile, "utf-8");
5547
6456
  return JSON.parse(content);
5548
6457
  } catch {
5549
6458
  return [];
@@ -5552,7 +6461,7 @@ function loadHealthHistory(projectRoot) {
5552
6461
 
5553
6462
  // src/dead-code/detector.ts
5554
6463
  import path2 from "path";
5555
- import { readFileSync as readFileSync11, existsSync as existsSync11 } from "fs";
6464
+ import { readFileSync as readFileSync12, existsSync as existsSync12 } from "fs";
5556
6465
  function findDeadSymbols(graph, projectRoot, includeTests = false, debug = false) {
5557
6466
  const deadSymbols = [];
5558
6467
  const context = { graph, projectRoot };
@@ -5685,11 +6594,11 @@ function getPackageEntryPoints(projectRoot) {
5685
6594
  const entryPoints = /* @__PURE__ */ new Set();
5686
6595
  const resolvedRoot = path2.resolve(projectRoot);
5687
6596
  const packageJsonPath = path2.resolve(resolvedRoot, "package.json");
5688
- if (!packageJsonPath.startsWith(resolvedRoot) || !existsSync11(packageJsonPath)) {
6597
+ if (!packageJsonPath.startsWith(resolvedRoot) || !existsSync12(packageJsonPath)) {
5689
6598
  return entryPoints;
5690
6599
  }
5691
6600
  try {
5692
- const packageJson = JSON.parse(readFileSync11(packageJsonPath, "utf-8"));
6601
+ const packageJson = JSON.parse(readFileSync12(packageJsonPath, "utf-8"));
5693
6602
  if (packageJson.main) {
5694
6603
  entryPoints.add(path2.resolve(projectRoot, packageJson.main));
5695
6604
  }
@@ -5740,6 +6649,9 @@ function shouldExclude(attrs, context, includeTests, packageEntryPoints) {
5740
6649
  if (isFrameworkAutoLoadedFile(relativePath)) {
5741
6650
  return "framework";
5742
6651
  }
6652
+ if (isCppExcluded(attrs)) {
6653
+ return "framework";
6654
+ }
5743
6655
  return null;
5744
6656
  }
5745
6657
  function isRealPackageEntryPoint(filePath, packageEntryPoints) {
@@ -5765,6 +6677,19 @@ function isFrameworkAutoLoadedFile(filePath) {
5765
6677
  return filePath.includes("/pages/") || filePath.includes("/routes/") || filePath.includes("/middleware/") || filePath.includes("/commands/") || filePath.includes("/api/") || filePath.includes("/app/") || filePath.includes("/Controllers/") || filePath.includes("/Hubs/") || filePath.includes("/Migrations/") || // Java / Spring / Jakarta
5766
6678
  filePath.includes("/controller/") || filePath.includes("/controllers/") || filePath.includes("/service/") || filePath.includes("/repository/") || filePath.includes("/config/") || filePath.includes("/configuration/");
5767
6679
  }
6680
+ function isCppExcluded(attrs) {
6681
+ const filePath = attrs.file || attrs.filePath || "";
6682
+ const name = attrs.name || "";
6683
+ const kind = attrs.kind || "";
6684
+ if (/\.(?:h|hpp|hh|hxx|h\+\+|inl|ipp)$/.test(filePath)) {
6685
+ return true;
6686
+ }
6687
+ if (name === "main") return true;
6688
+ if (name.startsWith("operator")) return true;
6689
+ if (name.startsWith("~")) return true;
6690
+ if (kind === "constant" && /\.(?:h|hpp)$/.test(filePath)) return true;
6691
+ return false;
6692
+ }
5768
6693
 
5769
6694
  // src/dead-code/classifier.ts
5770
6695
  import path3 from "path";
@@ -5831,8 +6756,8 @@ function generateReason(symbol, confidence) {
5831
6756
  return "Potentially unused";
5832
6757
  }
5833
6758
  function isBarrelFile(filePath) {
5834
- const basename8 = path3.basename(filePath);
5835
- return basename8 === "index.ts" || basename8 === "index.js";
6759
+ const basename9 = path3.basename(filePath);
6760
+ return basename9 === "index.ts" || basename9 === "index.js";
5836
6761
  }
5837
6762
  function isTestFile2(filePath) {
5838
6763
  return filePath.includes("__tests__/") || filePath.includes(".test.") || filePath.includes(".spec.") || filePath.includes("/test/") || filePath.includes("/tests/");
@@ -6011,11 +6936,11 @@ function filterByConfidence(symbols, minConfidence) {
6011
6936
  }
6012
6937
 
6013
6938
  // src/docs/generator.ts
6014
- import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync14 } from "fs";
6015
- import { join as join16 } from "path";
6939
+ import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync15 } from "fs";
6940
+ import { join as join17 } from "path";
6016
6941
 
6017
6942
  // src/docs/architecture.ts
6018
- import { dirname as dirname11 } from "path";
6943
+ import { dirname as dirname12 } from "path";
6019
6944
 
6020
6945
  // src/docs/templates.ts
6021
6946
  function header(text, level = 1) {
@@ -6166,7 +7091,7 @@ function generateModuleStructure(graph) {
6166
7091
  function getDirectoryStats(graph) {
6167
7092
  const dirMap = /* @__PURE__ */ new Map();
6168
7093
  graph.forEachNode((node, attrs) => {
6169
- const dir = dirname11(attrs.filePath);
7094
+ const dir = dirname12(attrs.filePath);
6170
7095
  if (dir === ".") return;
6171
7096
  if (!dirMap.has(dir)) {
6172
7097
  dirMap.set(dir, {
@@ -6191,7 +7116,7 @@ function getDirectoryStats(graph) {
6191
7116
  });
6192
7117
  const filesPerDir = /* @__PURE__ */ new Map();
6193
7118
  graph.forEachNode((node, attrs) => {
6194
- const dir = dirname11(attrs.filePath);
7119
+ const dir = dirname12(attrs.filePath);
6195
7120
  if (!filesPerDir.has(dir)) {
6196
7121
  filesPerDir.set(dir, /* @__PURE__ */ new Set());
6197
7122
  }
@@ -6206,8 +7131,8 @@ function getDirectoryStats(graph) {
6206
7131
  graph.forEachEdge((edge, attrs, source, target) => {
6207
7132
  const sourceAttrs = graph.getNodeAttributes(source);
6208
7133
  const targetAttrs = graph.getNodeAttributes(target);
6209
- const sourceDir = dirname11(sourceAttrs.filePath);
6210
- const targetDir = dirname11(targetAttrs.filePath);
7134
+ const sourceDir = dirname12(sourceAttrs.filePath);
7135
+ const targetDir = dirname12(targetAttrs.filePath);
6211
7136
  if (sourceDir !== targetDir) {
6212
7137
  if (!dirEdges.has(sourceDir)) {
6213
7138
  dirEdges.set(sourceDir, { in: 0, out: 0 });
@@ -6414,7 +7339,7 @@ function detectCycles(graph) {
6414
7339
  }
6415
7340
 
6416
7341
  // src/docs/conventions.ts
6417
- import { basename as basename5, extname as extname6 } from "path";
7342
+ import { basename as basename6, extname as extname7 } from "path";
6418
7343
  function generateConventions(graph, projectRoot, version) {
6419
7344
  let output = "";
6420
7345
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -6452,7 +7377,7 @@ function generateFileOrganization(graph) {
6452
7377
  graph.forEachNode((node, attrs) => {
6453
7378
  if (!files.has(attrs.filePath)) {
6454
7379
  files.add(attrs.filePath);
6455
- const fileName = basename5(attrs.filePath);
7380
+ const fileName = basename6(attrs.filePath);
6456
7381
  if (fileName === "index.ts" || fileName === "index.js" || fileName === "index.tsx" || fileName === "index.jsx") {
6457
7382
  barrelFileCount++;
6458
7383
  }
@@ -6511,7 +7436,7 @@ function generateNamingPatterns(graph) {
6511
7436
  graph.forEachNode((node, attrs) => {
6512
7437
  if (!files.has(attrs.filePath)) {
6513
7438
  files.add(attrs.filePath);
6514
- const fileName = basename5(attrs.filePath, extname6(attrs.filePath));
7439
+ const fileName = basename6(attrs.filePath, extname7(attrs.filePath));
6515
7440
  if (isCamelCase(fileName)) patterns.files.camelCase++;
6516
7441
  else if (isPascalCase(fileName)) patterns.files.PascalCase++;
6517
7442
  else if (isKebabCase(fileName)) patterns.files.kebabCase++;
@@ -7188,7 +8113,7 @@ function detectCyclesDetailed(graph) {
7188
8113
  }
7189
8114
 
7190
8115
  // src/docs/onboarding.ts
7191
- import { dirname as dirname12 } from "path";
8116
+ import { dirname as dirname13 } from "path";
7192
8117
  function generateOnboarding(graph, projectRoot, version) {
7193
8118
  let output = "";
7194
8119
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -7247,7 +8172,7 @@ function generateQuickOrientation(graph) {
7247
8172
  const primaryLang = Object.entries(languages2).sort((a, b) => b[1] - a[1])[0];
7248
8173
  const dirs = /* @__PURE__ */ new Set();
7249
8174
  graph.forEachNode((node, attrs) => {
7250
- const dir = dirname12(attrs.filePath);
8175
+ const dir = dirname13(attrs.filePath);
7251
8176
  if (dir !== ".") {
7252
8177
  const topLevel = dir.split("/")[0];
7253
8178
  dirs.add(topLevel);
@@ -7351,7 +8276,7 @@ function generateModuleMap(graph) {
7351
8276
  function getDirectoryStats2(graph) {
7352
8277
  const dirMap = /* @__PURE__ */ new Map();
7353
8278
  graph.forEachNode((node, attrs) => {
7354
- const dir = dirname12(attrs.filePath);
8279
+ const dir = dirname13(attrs.filePath);
7355
8280
  if (dir === ".") return;
7356
8281
  if (!dirMap.has(dir)) {
7357
8282
  dirMap.set(dir, {
@@ -7366,7 +8291,7 @@ function getDirectoryStats2(graph) {
7366
8291
  });
7367
8292
  const filesPerDir = /* @__PURE__ */ new Map();
7368
8293
  graph.forEachNode((node, attrs) => {
7369
- const dir = dirname12(attrs.filePath);
8294
+ const dir = dirname13(attrs.filePath);
7370
8295
  if (!filesPerDir.has(dir)) {
7371
8296
  filesPerDir.set(dir, /* @__PURE__ */ new Set());
7372
8297
  }
@@ -7381,8 +8306,8 @@ function getDirectoryStats2(graph) {
7381
8306
  graph.forEachEdge((edge, attrs, source, target) => {
7382
8307
  const sourceAttrs = graph.getNodeAttributes(source);
7383
8308
  const targetAttrs = graph.getNodeAttributes(target);
7384
- const sourceDir = dirname12(sourceAttrs.filePath);
7385
- const targetDir = dirname12(targetAttrs.filePath);
8309
+ const sourceDir = dirname13(sourceAttrs.filePath);
8310
+ const targetDir = dirname13(targetAttrs.filePath);
7386
8311
  if (sourceDir !== targetDir) {
7387
8312
  if (!dirEdges.has(sourceDir)) {
7388
8313
  dirEdges.set(sourceDir, { in: 0, out: 0 });
@@ -7463,7 +8388,7 @@ function detectClusters(graph) {
7463
8388
  const dirFiles = /* @__PURE__ */ new Map();
7464
8389
  const fileEdges = /* @__PURE__ */ new Map();
7465
8390
  graph.forEachNode((node, attrs) => {
7466
- const dir = dirname12(attrs.filePath);
8391
+ const dir = dirname13(attrs.filePath);
7467
8392
  if (!dirFiles.has(dir)) {
7468
8393
  dirFiles.set(dir, /* @__PURE__ */ new Set());
7469
8394
  }
@@ -7517,8 +8442,8 @@ function inferClusterName(files) {
7517
8442
  if (sortedWords.length > 0 && sortedWords[0][1] > 1) {
7518
8443
  return capitalizeFirst2(sortedWords[0][0]);
7519
8444
  }
7520
- const commonDir = dirname12(files[0]);
7521
- if (files.every((f) => dirname12(f) === commonDir)) {
8445
+ const commonDir = dirname13(files[0]);
8446
+ if (files.every((f) => dirname13(f) === commonDir)) {
7522
8447
  return capitalizeFirst2(commonDir.split("/").pop() || "Core");
7523
8448
  }
7524
8449
  return "Core";
@@ -7576,7 +8501,7 @@ function generateDepwireUsage(projectRoot) {
7576
8501
  }
7577
8502
 
7578
8503
  // src/docs/files.ts
7579
- import { dirname as dirname13, basename as basename6 } from "path";
8504
+ import { dirname as dirname14, basename as basename7 } from "path";
7580
8505
  function generateFiles(graph, projectRoot, version) {
7581
8506
  let output = "";
7582
8507
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -7680,7 +8605,7 @@ function generateDirectoryBreakdown(graph) {
7680
8605
  const fileStats = getFileStats2(graph);
7681
8606
  const dirMap = /* @__PURE__ */ new Map();
7682
8607
  for (const file of fileStats) {
7683
- const dir = dirname13(file.filePath);
8608
+ const dir = dirname14(file.filePath);
7684
8609
  const topDir = dir === "." ? "." : dir.split("/")[0];
7685
8610
  if (!dirMap.has(topDir)) {
7686
8611
  dirMap.set(topDir, {
@@ -7695,7 +8620,7 @@ function generateDirectoryBreakdown(graph) {
7695
8620
  dirStats.symbolCount += file.symbolCount;
7696
8621
  if (file.totalConnections > dirStats.maxConnections) {
7697
8622
  dirStats.maxConnections = file.totalConnections;
7698
- dirStats.mostConnectedFile = basename6(file.filePath);
8623
+ dirStats.mostConnectedFile = basename7(file.filePath);
7699
8624
  }
7700
8625
  }
7701
8626
  if (dirMap.size === 0) {
@@ -8323,7 +9248,7 @@ function generateRecommendations(graph) {
8323
9248
  }
8324
9249
 
8325
9250
  // src/docs/tests.ts
8326
- import { basename as basename7, dirname as dirname14 } from "path";
9251
+ import { basename as basename8, dirname as dirname15 } from "path";
8327
9252
  function generateTests(graph, projectRoot, version) {
8328
9253
  let output = "";
8329
9254
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -8351,8 +9276,8 @@ function getFileCount8(graph) {
8351
9276
  return files.size;
8352
9277
  }
8353
9278
  function isTestFile3(filePath) {
8354
- const fileName = basename7(filePath).toLowerCase();
8355
- const dirPath = dirname14(filePath).toLowerCase();
9279
+ const fileName = basename8(filePath).toLowerCase();
9280
+ const dirPath = dirname15(filePath).toLowerCase();
8356
9281
  if (dirPath.includes("test") || dirPath.includes("spec") || dirPath.includes("__tests__")) {
8357
9282
  return true;
8358
9283
  }
@@ -8410,13 +9335,13 @@ function generateTestFileInventory(graph) {
8410
9335
  return output;
8411
9336
  }
8412
9337
  function matchTestToSource(testFile) {
8413
- const testFileName = basename7(testFile);
8414
- const testDir = dirname14(testFile);
9338
+ const testFileName = basename8(testFile);
9339
+ const testDir = dirname15(testFile);
8415
9340
  let sourceFileName = testFileName.replace(/\.test\./g, ".").replace(/\.spec\./g, ".").replace(/_test\./g, ".").replace(/_spec\./g, ".");
8416
9341
  const possiblePaths = [];
8417
9342
  possiblePaths.push(testDir + "/" + sourceFileName);
8418
9343
  if (testDir.endsWith("/test") || testDir.endsWith("/tests") || testDir.endsWith("/__tests__")) {
8419
- const parentDir = dirname14(testDir);
9344
+ const parentDir = dirname15(testDir);
8420
9345
  possiblePaths.push(parentDir + "/" + sourceFileName);
8421
9346
  }
8422
9347
  if (testDir.includes("test")) {
@@ -8572,7 +9497,7 @@ function generateTestCoverageMap(graph) {
8572
9497
  const rows = mappings.slice(0, 30).map((m) => [
8573
9498
  `\`${m.sourceFile}\``,
8574
9499
  m.hasTest ? "\u2705" : "\u274C",
8575
- m.testFile ? `\`${basename7(m.testFile)}\`` : "-",
9500
+ m.testFile ? `\`${basename8(m.testFile)}\`` : "-",
8576
9501
  formatNumber(m.symbolCount)
8577
9502
  ]);
8578
9503
  let output = table(headers, rows);
@@ -8613,7 +9538,7 @@ function generateTestStatistics(graph) {
8613
9538
  `;
8614
9539
  const dirTestCoverage = /* @__PURE__ */ new Map();
8615
9540
  for (const sourceFile of sourceFiles) {
8616
- const dir = dirname14(sourceFile).split("/")[0];
9541
+ const dir = dirname15(sourceFile).split("/")[0];
8617
9542
  if (!dirTestCoverage.has(dir)) {
8618
9543
  dirTestCoverage.set(dir, { total: 0, tested: 0 });
8619
9544
  }
@@ -8636,7 +9561,7 @@ function generateTestStatistics(graph) {
8636
9561
  }
8637
9562
 
8638
9563
  // src/docs/history.ts
8639
- import { dirname as dirname15 } from "path";
9564
+ import { dirname as dirname16 } from "path";
8640
9565
  import { execSync } from "child_process";
8641
9566
  function generateHistory(graph, projectRoot, version) {
8642
9567
  let output = "";
@@ -8917,7 +9842,7 @@ function generateFeatureClusters(graph) {
8917
9842
  const dirFiles = /* @__PURE__ */ new Map();
8918
9843
  const fileEdges = /* @__PURE__ */ new Map();
8919
9844
  graph.forEachNode((node, attrs) => {
8920
- const dir = dirname15(attrs.filePath);
9845
+ const dir = dirname16(attrs.filePath);
8921
9846
  if (!dirFiles.has(dir)) {
8922
9847
  dirFiles.set(dir, /* @__PURE__ */ new Set());
8923
9848
  }
@@ -8999,7 +9924,7 @@ function capitalizeFirst3(str) {
8999
9924
  }
9000
9925
 
9001
9926
  // src/docs/current.ts
9002
- import { dirname as dirname16 } from "path";
9927
+ import { dirname as dirname17 } from "path";
9003
9928
  function generateCurrent(graph, projectRoot, version) {
9004
9929
  let output = "";
9005
9930
  const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -9137,7 +10062,7 @@ function generateCompleteFileIndex(graph) {
9137
10062
  fileInfos.sort((a, b) => a.filePath.localeCompare(b.filePath));
9138
10063
  const dirGroups = /* @__PURE__ */ new Map();
9139
10064
  for (const info of fileInfos) {
9140
- const dir = dirname16(info.filePath);
10065
+ const dir = dirname17(info.filePath);
9141
10066
  const topDir = dir === "." ? "root" : dir.split("/")[0];
9142
10067
  if (!dirGroups.has(topDir)) {
9143
10068
  dirGroups.set(topDir, []);
@@ -9348,7 +10273,7 @@ function getTopLevelDir2(filePath) {
9348
10273
  }
9349
10274
 
9350
10275
  // src/docs/status.ts
9351
- import { readFileSync as readFileSync12, existsSync as existsSync12 } from "fs";
10276
+ import { readFileSync as readFileSync13, existsSync as existsSync13 } from "fs";
9352
10277
  import { resolve as resolve9 } from "path";
9353
10278
  function generateStatus(graph, projectRoot, version) {
9354
10279
  let output = "";
@@ -9387,11 +10312,11 @@ function extractComments(projectRoot, filePath) {
9387
10312
  if (!fullPath.startsWith(resolvedRoot)) {
9388
10313
  return comments;
9389
10314
  }
9390
- if (!existsSync12(fullPath)) {
10315
+ if (!existsSync13(fullPath)) {
9391
10316
  return comments;
9392
10317
  }
9393
10318
  try {
9394
- const content = readFileSync12(fullPath, "utf-8");
10319
+ const content = readFileSync13(fullPath, "utf-8");
9395
10320
  const lines = content.split("\n");
9396
10321
  const patterns = [
9397
10322
  { type: "TODO", regex: /(?:\/\/|#|\/\*)\s*TODO:?\s*(.+)/i },
@@ -9970,16 +10895,16 @@ function generateConfidenceSection(title, description, symbols, projectRoot) {
9970
10895
  }
9971
10896
 
9972
10897
  // src/docs/metadata.ts
9973
- import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync2 } from "fs";
10898
+ import { existsSync as existsSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync2 } from "fs";
9974
10899
  import { resolve as resolve10 } from "path";
9975
10900
  function loadMetadata(outputDir) {
9976
10901
  const resolvedDir = resolve10(outputDir);
9977
10902
  const metadataPath = resolve10(resolvedDir, "metadata.json");
9978
- if (!metadataPath.startsWith(resolvedDir) || !existsSync13(metadataPath)) {
10903
+ if (!metadataPath.startsWith(resolvedDir) || !existsSync14(metadataPath)) {
9979
10904
  return null;
9980
10905
  }
9981
10906
  try {
9982
- const content = readFileSync13(metadataPath, "utf-8");
10907
+ const content = readFileSync14(metadataPath, "utf-8");
9983
10908
  return JSON.parse(content);
9984
10909
  } catch (err) {
9985
10910
  console.error("Failed to load metadata:", err);
@@ -10034,7 +10959,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10034
10959
  const generated = [];
10035
10960
  const errors = [];
10036
10961
  try {
10037
- if (!existsSync14(options.outputDir)) {
10962
+ if (!existsSync15(options.outputDir)) {
10038
10963
  mkdirSync2(options.outputDir, { recursive: true });
10039
10964
  if (options.verbose) {
10040
10965
  console.log(`Created output directory: ${options.outputDir}`);
@@ -10073,7 +10998,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10073
10998
  try {
10074
10999
  if (options.verbose) console.log("Generating ARCHITECTURE.md...");
10075
11000
  const content = generateArchitecture(graph, projectRoot, version, parseTime);
10076
- const filePath = join16(options.outputDir, "ARCHITECTURE.md");
11001
+ const filePath = join17(options.outputDir, "ARCHITECTURE.md");
10077
11002
  writeFileSync3(filePath, content, "utf-8");
10078
11003
  generated.push("ARCHITECTURE.md");
10079
11004
  } catch (err) {
@@ -10084,7 +11009,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10084
11009
  try {
10085
11010
  if (options.verbose) console.log("Generating CONVENTIONS.md...");
10086
11011
  const content = generateConventions(graph, projectRoot, version);
10087
- const filePath = join16(options.outputDir, "CONVENTIONS.md");
11012
+ const filePath = join17(options.outputDir, "CONVENTIONS.md");
10088
11013
  writeFileSync3(filePath, content, "utf-8");
10089
11014
  generated.push("CONVENTIONS.md");
10090
11015
  } catch (err) {
@@ -10095,7 +11020,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10095
11020
  try {
10096
11021
  if (options.verbose) console.log("Generating DEPENDENCIES.md...");
10097
11022
  const content = generateDependencies(graph, projectRoot, version);
10098
- const filePath = join16(options.outputDir, "DEPENDENCIES.md");
11023
+ const filePath = join17(options.outputDir, "DEPENDENCIES.md");
10099
11024
  writeFileSync3(filePath, content, "utf-8");
10100
11025
  generated.push("DEPENDENCIES.md");
10101
11026
  } catch (err) {
@@ -10106,7 +11031,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10106
11031
  try {
10107
11032
  if (options.verbose) console.log("Generating ONBOARDING.md...");
10108
11033
  const content = generateOnboarding(graph, projectRoot, version);
10109
- const filePath = join16(options.outputDir, "ONBOARDING.md");
11034
+ const filePath = join17(options.outputDir, "ONBOARDING.md");
10110
11035
  writeFileSync3(filePath, content, "utf-8");
10111
11036
  generated.push("ONBOARDING.md");
10112
11037
  } catch (err) {
@@ -10117,7 +11042,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10117
11042
  try {
10118
11043
  if (options.verbose) console.log("Generating FILES.md...");
10119
11044
  const content = generateFiles(graph, projectRoot, version);
10120
- const filePath = join16(options.outputDir, "FILES.md");
11045
+ const filePath = join17(options.outputDir, "FILES.md");
10121
11046
  writeFileSync3(filePath, content, "utf-8");
10122
11047
  generated.push("FILES.md");
10123
11048
  } catch (err) {
@@ -10128,7 +11053,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10128
11053
  try {
10129
11054
  if (options.verbose) console.log("Generating API_SURFACE.md...");
10130
11055
  const content = generateApiSurface(graph, projectRoot, version);
10131
- const filePath = join16(options.outputDir, "API_SURFACE.md");
11056
+ const filePath = join17(options.outputDir, "API_SURFACE.md");
10132
11057
  writeFileSync3(filePath, content, "utf-8");
10133
11058
  generated.push("API_SURFACE.md");
10134
11059
  } catch (err) {
@@ -10139,7 +11064,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10139
11064
  try {
10140
11065
  if (options.verbose) console.log("Generating ERRORS.md...");
10141
11066
  const content = generateErrors(graph, projectRoot, version);
10142
- const filePath = join16(options.outputDir, "ERRORS.md");
11067
+ const filePath = join17(options.outputDir, "ERRORS.md");
10143
11068
  writeFileSync3(filePath, content, "utf-8");
10144
11069
  generated.push("ERRORS.md");
10145
11070
  } catch (err) {
@@ -10150,7 +11075,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10150
11075
  try {
10151
11076
  if (options.verbose) console.log("Generating TESTS.md...");
10152
11077
  const content = generateTests(graph, projectRoot, version);
10153
- const filePath = join16(options.outputDir, "TESTS.md");
11078
+ const filePath = join17(options.outputDir, "TESTS.md");
10154
11079
  writeFileSync3(filePath, content, "utf-8");
10155
11080
  generated.push("TESTS.md");
10156
11081
  } catch (err) {
@@ -10161,7 +11086,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10161
11086
  try {
10162
11087
  if (options.verbose) console.log("Generating HISTORY.md...");
10163
11088
  const content = generateHistory(graph, projectRoot, version);
10164
- const filePath = join16(options.outputDir, "HISTORY.md");
11089
+ const filePath = join17(options.outputDir, "HISTORY.md");
10165
11090
  writeFileSync3(filePath, content, "utf-8");
10166
11091
  generated.push("HISTORY.md");
10167
11092
  } catch (err) {
@@ -10172,7 +11097,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10172
11097
  try {
10173
11098
  if (options.verbose) console.log("Generating CURRENT.md...");
10174
11099
  const content = generateCurrent(graph, projectRoot, version);
10175
- const filePath = join16(options.outputDir, "CURRENT.md");
11100
+ const filePath = join17(options.outputDir, "CURRENT.md");
10176
11101
  writeFileSync3(filePath, content, "utf-8");
10177
11102
  generated.push("CURRENT.md");
10178
11103
  } catch (err) {
@@ -10183,7 +11108,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10183
11108
  try {
10184
11109
  if (options.verbose) console.log("Generating STATUS.md...");
10185
11110
  const content = generateStatus(graph, projectRoot, version);
10186
- const filePath = join16(options.outputDir, "STATUS.md");
11111
+ const filePath = join17(options.outputDir, "STATUS.md");
10187
11112
  writeFileSync3(filePath, content, "utf-8");
10188
11113
  generated.push("STATUS.md");
10189
11114
  } catch (err) {
@@ -10194,7 +11119,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10194
11119
  try {
10195
11120
  if (options.verbose) console.log("Generating HEALTH.md...");
10196
11121
  const content = generateHealth(graph, projectRoot, version);
10197
- const filePath = join16(options.outputDir, "HEALTH.md");
11122
+ const filePath = join17(options.outputDir, "HEALTH.md");
10198
11123
  writeFileSync3(filePath, content, "utf-8");
10199
11124
  generated.push("HEALTH.md");
10200
11125
  } catch (err) {
@@ -10205,7 +11130,7 @@ async function generateDocs(graph, projectRoot, version, parseTime, options) {
10205
11130
  try {
10206
11131
  if (options.verbose) console.log("Generating DEAD_CODE.md...");
10207
11132
  const content = generateDeadCode(graph, projectRoot, version);
10208
- const filePath = join16(options.outputDir, "DEAD_CODE.md");
11133
+ const filePath = join17(options.outputDir, "DEAD_CODE.md");
10209
11134
  writeFileSync3(filePath, content, "utf-8");
10210
11135
  generated.push("DEAD_CODE.md");
10211
11136
  } catch (err) {
@@ -10249,7 +11174,7 @@ function getFileCount13(graph) {
10249
11174
  }
10250
11175
 
10251
11176
  // src/simulation/engine.ts
10252
- import { dirname as dirname17, join as join17 } from "path";
11177
+ import { dirname as dirname18, join as join18 } from "path";
10253
11178
  function normalizePath2(p) {
10254
11179
  return p.replace(/^\.\//, "").replace(/\/+$/, "");
10255
11180
  }
@@ -10380,7 +11305,7 @@ var SimulationEngine = class {
10380
11305
  }
10381
11306
  }
10382
11307
  applyRename(clone, target, newName, brokenImports) {
10383
- const destination = join17(dirname17(target), newName);
11308
+ const destination = join18(dirname18(target), newName);
10384
11309
  this.applyMove(clone, target, destination, brokenImports);
10385
11310
  }
10386
11311
  applySplit(clone, target, newFile, symbols, brokenImports) {
@@ -10580,13 +11505,13 @@ var SimulationEngine = class {
10580
11505
  };
10581
11506
 
10582
11507
  // src/security/scanner.ts
10583
- import { existsSync as existsSync16 } from "fs";
10584
- import { join as join27 } from "path";
11508
+ import { existsSync as existsSync17 } from "fs";
11509
+ import { join as join28 } from "path";
10585
11510
 
10586
11511
  // src/security/checks/dependencies.ts
10587
11512
  import { execSync as execSync2 } from "child_process";
10588
- import { existsSync as existsSync15, readFileSync as readFileSync14, readdirSync as readdirSync7 } from "fs";
10589
- import { join as join18 } from "path";
11513
+ import { existsSync as existsSync16, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "fs";
11514
+ import { join as join19 } from "path";
10590
11515
  function cvssToSeverity(score) {
10591
11516
  if (score >= 9) return "critical";
10592
11517
  if (score >= 7) return "high";
@@ -10596,18 +11521,18 @@ function cvssToSeverity(score) {
10596
11521
  async function checkDependencies(_files, projectRoot) {
10597
11522
  const findings = [];
10598
11523
  try {
10599
- if (existsSync15(join18(projectRoot, "package.json"))) {
11524
+ if (existsSync16(join19(projectRoot, "package.json"))) {
10600
11525
  findings.push(...checkNpmAudit(projectRoot));
10601
11526
  findings.push(...checkPackageJsonPatterns(projectRoot));
10602
11527
  findings.push(...checkPostinstallScripts(projectRoot));
10603
11528
  }
10604
- if (existsSync15(join18(projectRoot, "requirements.txt")) || existsSync15(join18(projectRoot, "pyproject.toml"))) {
11529
+ if (existsSync16(join19(projectRoot, "requirements.txt")) || existsSync16(join19(projectRoot, "pyproject.toml"))) {
10605
11530
  findings.push(...checkPipAudit(projectRoot));
10606
11531
  }
10607
- if (existsSync15(join18(projectRoot, "Cargo.toml"))) {
11532
+ if (existsSync16(join19(projectRoot, "Cargo.toml"))) {
10608
11533
  findings.push(...checkCargoAudit(projectRoot));
10609
11534
  }
10610
- if (existsSync15(join18(projectRoot, "go.mod"))) {
11535
+ if (existsSync16(join19(projectRoot, "go.mod"))) {
10611
11536
  findings.push(...checkGoVerify(projectRoot));
10612
11537
  }
10613
11538
  } catch (err) {
@@ -10696,8 +11621,8 @@ function checkNpmAudit(projectRoot) {
10696
11621
  function checkPackageJsonPatterns(projectRoot) {
10697
11622
  const findings = [];
10698
11623
  try {
10699
- const pkgPath = join18(projectRoot, "package.json");
10700
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
11624
+ const pkgPath = join19(projectRoot, "package.json");
11625
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
10701
11626
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
10702
11627
  for (const [name, version] of Object.entries(allDeps)) {
10703
11628
  if (version.startsWith("^") || version.startsWith("~")) {
@@ -10719,15 +11644,15 @@ function checkPackageJsonPatterns(projectRoot) {
10719
11644
  }
10720
11645
  function checkPostinstallScripts(projectRoot) {
10721
11646
  const findings = [];
10722
- const nodeModules = join18(projectRoot, "node_modules");
10723
- if (!existsSync15(nodeModules)) return findings;
11647
+ const nodeModules = join19(projectRoot, "node_modules");
11648
+ if (!existsSync16(nodeModules)) return findings;
10724
11649
  try {
10725
- const topLevelDeps = readdirSync7(nodeModules).filter((d) => !d.startsWith("."));
11650
+ const topLevelDeps = readdirSync8(nodeModules).filter((d) => !d.startsWith("."));
10726
11651
  for (const dep of topLevelDeps) {
10727
- const depPkgPath = join18(nodeModules, dep, "package.json");
10728
- if (!existsSync15(depPkgPath)) continue;
11652
+ const depPkgPath = join19(nodeModules, dep, "package.json");
11653
+ if (!existsSync16(depPkgPath)) continue;
10729
11654
  try {
10730
- const depPkg = JSON.parse(readFileSync14(depPkgPath, "utf-8"));
11655
+ const depPkg = JSON.parse(readFileSync15(depPkgPath, "utf-8"));
10731
11656
  const scripts = depPkg.scripts || {};
10732
11657
  if (scripts.postinstall || scripts.preinstall || scripts.install) {
10733
11658
  const scriptName = scripts.postinstall ? "postinstall" : scripts.preinstall ? "preinstall" : "install";
@@ -10765,7 +11690,7 @@ function checkPipAudit(projectRoot) {
10765
11690
  id: "",
10766
11691
  severity: cvssToSeverity(vuln.cvss?.score || 5),
10767
11692
  vulnerabilityClass: "dependency-cve",
10768
- file: existsSync15(join18(projectRoot, "requirements.txt")) ? "requirements.txt" : "pyproject.toml",
11693
+ file: existsSync16(join19(projectRoot, "requirements.txt")) ? "requirements.txt" : "pyproject.toml",
10769
11694
  title: `Vulnerable Python dependency: ${vuln.name}`,
10770
11695
  description: `${vuln.name}@${vuln.version} \u2014 ${vuln.id}: ${vuln.description || "Known vulnerability"}`,
10771
11696
  attackScenario: `An attacker could exploit the vulnerability in ${vuln.name}.`,
@@ -10862,8 +11787,8 @@ function checkGoVerify(projectRoot) {
10862
11787
  }
10863
11788
 
10864
11789
  // src/security/checks/injection.ts
10865
- import { readFileSync as readFileSync15 } from "fs";
10866
- import { join as join19 } from "path";
11790
+ import { readFileSync as readFileSync16 } from "fs";
11791
+ import { join as join20 } from "path";
10867
11792
  var SKIP_DIRS = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
10868
11793
  var TEST_PATTERNS = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__"];
10869
11794
  var USER_INPUT_NAMES = /(?:input|user|name|path|query|branch|hash|cmd|command|req\.|params|body|args|url|dir|file|subdirectory)/i;
@@ -11012,6 +11937,43 @@ var PATTERNS = [
11012
11937
  description: "permitAll() applied to a path that appears security-sensitive.",
11013
11938
  attackScenario: "An attacker could access administrative or destructive endpoints without authentication.",
11014
11939
  suggestedFix: 'Use .hasRole("ADMIN") or .authenticated() for sensitive endpoints.'
11940
+ },
11941
+ // C++ injection patterns
11942
+ {
11943
+ regex: /\b(?:strcpy|strcat|sprintf|gets)\s*\(/,
11944
+ title: "C++ buffer overflow risk: unsafe string function",
11945
+ vulnClass: "shell-injection",
11946
+ baseSeverity: "high",
11947
+ description: "Unsafe C string functions (strcpy, strcat, sprintf, gets) with no bounds checking \u2014 buffer overflow risk.",
11948
+ attackScenario: "An attacker could provide oversized input to overflow the buffer, enabling arbitrary code execution.",
11949
+ suggestedFix: "Use bounded alternatives: strncpy, strncat, snprintf, or C++ std::string."
11950
+ },
11951
+ {
11952
+ regex: /printf\s*\(\s*(?!")[a-zA-Z_]\w*/,
11953
+ title: "C++ format string vulnerability",
11954
+ vulnClass: "shell-injection",
11955
+ baseSeverity: "high",
11956
+ description: "printf called with a variable as the format string \u2014 format string attack risk.",
11957
+ attackScenario: "An attacker could inject format specifiers (%x, %n) to read/write arbitrary memory.",
11958
+ suggestedFix: 'Always use a literal format string: printf("%s", userInput).'
11959
+ },
11960
+ {
11961
+ regex: /\bsystem\s*\(\s*(?!")[a-zA-Z_]\w*/,
11962
+ title: "C++ command injection via system()",
11963
+ vulnClass: "shell-injection",
11964
+ baseSeverity: "high",
11965
+ description: "system() called with a variable argument \u2014 potential command injection.",
11966
+ attackScenario: "An attacker could inject shell metacharacters to execute arbitrary commands.",
11967
+ suggestedFix: "Avoid system(). Use execvp with an argument array, or validate input with a strict allowlist."
11968
+ },
11969
+ {
11970
+ regex: /\bpopen\s*\(\s*(?!")[a-zA-Z_]\w*/,
11971
+ title: "C++ command injection via popen()",
11972
+ vulnClass: "shell-injection",
11973
+ baseSeverity: "high",
11974
+ description: "popen() called with a variable argument \u2014 potential command injection.",
11975
+ attackScenario: "An attacker could inject shell metacharacters to execute arbitrary commands.",
11976
+ suggestedFix: "Avoid popen(). Use pipe/fork/exec with argument arrays instead."
11015
11977
  }
11016
11978
  ];
11017
11979
  function shouldSkip(filePath) {
@@ -11028,7 +11990,7 @@ async function checkInjection(files, projectRoot) {
11028
11990
  if (shouldSkip(file.filePath) || isTestFile4(file.filePath)) continue;
11029
11991
  let content;
11030
11992
  try {
11031
- content = readFileSync15(join19(projectRoot, file.filePath), "utf-8");
11993
+ content = readFileSync16(join20(projectRoot, file.filePath), "utf-8");
11032
11994
  } catch {
11033
11995
  continue;
11034
11996
  }
@@ -11066,8 +12028,8 @@ async function checkInjection(files, projectRoot) {
11066
12028
  }
11067
12029
 
11068
12030
  // src/security/checks/secrets.ts
11069
- import { readFileSync as readFileSync16 } from "fs";
11070
- import { join as join20 } from "path";
12031
+ import { readFileSync as readFileSync17 } from "fs";
12032
+ import { join as join21 } from "path";
11071
12033
  var SKIP_DIRS2 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
11072
12034
  var TEST_PATTERNS2 = ["test", "spec", "fixture", "mock", "__tests__", "__mocks__", ".example", ".sample"];
11073
12035
  var SECRET_PATTERNS = [
@@ -11100,7 +12062,7 @@ async function checkSecrets(files, projectRoot) {
11100
12062
  if (shouldSkip2(file.filePath) || isTestFile5(file.filePath)) continue;
11101
12063
  let content;
11102
12064
  try {
11103
- content = readFileSync16(join20(projectRoot, file.filePath), "utf-8");
12065
+ content = readFileSync17(join21(projectRoot, file.filePath), "utf-8");
11104
12066
  } catch {
11105
12067
  continue;
11106
12068
  }
@@ -11133,8 +12095,8 @@ async function checkSecrets(files, projectRoot) {
11133
12095
  }
11134
12096
 
11135
12097
  // src/security/checks/path-traversal.ts
11136
- import { readFileSync as readFileSync17 } from "fs";
11137
- import { join as join21 } from "path";
12098
+ import { readFileSync as readFileSync18 } from "fs";
12099
+ import { join as join22 } from "path";
11138
12100
  var SKIP_DIRS3 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
11139
12101
  var USER_INPUT_VARS = /(?:req\.|params|query|body|input|path|dir|subdirectory|file|userInput|fileName|filePath)/i;
11140
12102
  var PATTERNS2 = [
@@ -11181,7 +12143,7 @@ async function checkPathTraversal(files, projectRoot) {
11181
12143
  if (shouldSkip3(file.filePath)) continue;
11182
12144
  let content;
11183
12145
  try {
11184
- content = readFileSync17(join21(projectRoot, file.filePath), "utf-8");
12146
+ content = readFileSync18(join22(projectRoot, file.filePath), "utf-8");
11185
12147
  } catch {
11186
12148
  continue;
11187
12149
  }
@@ -11223,8 +12185,8 @@ async function checkPathTraversal(files, projectRoot) {
11223
12185
  }
11224
12186
 
11225
12187
  // src/security/checks/auth.ts
11226
- import { readFileSync as readFileSync18 } from "fs";
11227
- import { join as join22 } from "path";
12188
+ import { readFileSync as readFileSync19 } from "fs";
12189
+ import { join as join23 } from "path";
11228
12190
  var SKIP_DIRS4 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
11229
12191
  function shouldSkip4(filePath) {
11230
12192
  return SKIP_DIRS4.some((d) => filePath.includes(d));
@@ -11240,7 +12202,7 @@ async function checkAuth(files, projectRoot) {
11240
12202
  if (shouldSkip4(file.filePath)) continue;
11241
12203
  let content;
11242
12204
  try {
11243
- content = readFileSync18(join22(projectRoot, file.filePath), "utf-8");
12205
+ content = readFileSync19(join23(projectRoot, file.filePath), "utf-8");
11244
12206
  } catch {
11245
12207
  continue;
11246
12208
  }
@@ -11331,8 +12293,8 @@ async function checkAuth(files, projectRoot) {
11331
12293
  }
11332
12294
 
11333
12295
  // src/security/checks/input-validation.ts
11334
- import { readFileSync as readFileSync19 } from "fs";
11335
- import { join as join23 } from "path";
12296
+ import { readFileSync as readFileSync20 } from "fs";
12297
+ import { join as join24 } from "path";
11336
12298
  var SKIP_DIRS5 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
11337
12299
  function shouldSkip5(filePath) {
11338
12300
  return SKIP_DIRS5.some((d) => filePath.includes(d));
@@ -11344,7 +12306,7 @@ async function checkInputValidation(files, projectRoot) {
11344
12306
  if (shouldSkip5(file.filePath)) continue;
11345
12307
  let content;
11346
12308
  try {
11347
- content = readFileSync19(join23(projectRoot, file.filePath), "utf-8");
12309
+ content = readFileSync20(join24(projectRoot, file.filePath), "utf-8");
11348
12310
  } catch {
11349
12311
  continue;
11350
12312
  }
@@ -11421,8 +12383,8 @@ async function checkInputValidation(files, projectRoot) {
11421
12383
  }
11422
12384
 
11423
12385
  // src/security/checks/information-disclosure.ts
11424
- import { readFileSync as readFileSync20 } from "fs";
11425
- import { join as join24 } from "path";
12386
+ import { readFileSync as readFileSync21 } from "fs";
12387
+ import { join as join25 } from "path";
11426
12388
  var SKIP_DIRS6 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
11427
12389
  function shouldSkip6(filePath) {
11428
12390
  return SKIP_DIRS6.some((d) => filePath.includes(d));
@@ -11434,7 +12396,7 @@ async function checkInformationDisclosure(files, projectRoot) {
11434
12396
  if (shouldSkip6(file.filePath)) continue;
11435
12397
  let content;
11436
12398
  try {
11437
- content = readFileSync20(join24(projectRoot, file.filePath), "utf-8");
12399
+ content = readFileSync21(join25(projectRoot, file.filePath), "utf-8");
11438
12400
  } catch {
11439
12401
  continue;
11440
12402
  }
@@ -11504,8 +12466,8 @@ async function checkInformationDisclosure(files, projectRoot) {
11504
12466
  }
11505
12467
 
11506
12468
  // src/security/checks/cryptography.ts
11507
- import { readFileSync as readFileSync21 } from "fs";
11508
- import { join as join25 } from "path";
12469
+ import { readFileSync as readFileSync22 } from "fs";
12470
+ import { join as join26 } from "path";
11509
12471
  var SKIP_DIRS7 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
11510
12472
  var USER_INPUT_NAMES2 = /(?:input|user|name|path|query|param|request|body|args|url)/i;
11511
12473
  function shouldSkip7(filePath) {
@@ -11522,7 +12484,7 @@ async function checkCryptography(files, projectRoot) {
11522
12484
  if (shouldSkip7(file.filePath)) continue;
11523
12485
  let content;
11524
12486
  try {
11525
- content = readFileSync21(join25(projectRoot, file.filePath), "utf-8");
12487
+ content = readFileSync22(join26(projectRoot, file.filePath), "utf-8");
11526
12488
  } catch {
11527
12489
  continue;
11528
12490
  }
@@ -11624,6 +12586,32 @@ async function checkCryptography(files, projectRoot) {
11624
12586
  suggestedFix: "Generate a unique random salt per user using crypto.randomBytes(16)."
11625
12587
  });
11626
12588
  }
12589
+ if (/\brand\s*\(\s*\)/.test(line) && isCryptoFile) {
12590
+ findings.push({
12591
+ id: "",
12592
+ severity: "medium",
12593
+ vulnerabilityClass: "cryptography",
12594
+ file: file.filePath,
12595
+ line: i + 1,
12596
+ title: "Weak random: rand() in security context",
12597
+ description: "rand() is not cryptographically secure \u2014 its output can be predicted.",
12598
+ attackScenario: "An attacker could predict rand() values to forge tokens or bypass security checks.",
12599
+ suggestedFix: "Use std::random_device or platform-specific CSPRNG (e.g., /dev/urandom, BCryptGenRandom)."
12600
+ });
12601
+ }
12602
+ if (/(?:const\s+(?:char|std::string)\s*\*?\s*(?:password|secret|api_key|apiKey|token)\s*=\s*["'])/i.test(line)) {
12603
+ findings.push({
12604
+ id: "",
12605
+ severity: "high",
12606
+ vulnerabilityClass: "cryptography",
12607
+ file: file.filePath,
12608
+ line: i + 1,
12609
+ title: "Hardcoded credentials in C++ source",
12610
+ description: "A password, secret, or API key is hardcoded as a string literal.",
12611
+ attackScenario: "An attacker with access to the binary or source could extract the credential.",
12612
+ suggestedFix: "Load credentials from environment variables or a secure vault at runtime."
12613
+ });
12614
+ }
11627
12615
  }
11628
12616
  }
11629
12617
  } catch {
@@ -11632,8 +12620,8 @@ async function checkCryptography(files, projectRoot) {
11632
12620
  }
11633
12621
 
11634
12622
  // src/security/checks/frontend.ts
11635
- import { readFileSync as readFileSync22 } from "fs";
11636
- import { join as join26 } from "path";
12623
+ import { readFileSync as readFileSync23 } from "fs";
12624
+ import { join as join27 } from "path";
11637
12625
  var SKIP_DIRS8 = ["node_modules/", "dist/", ".git/", ".wrangler/", "src/security/checks/"];
11638
12626
  function shouldSkip8(filePath) {
11639
12627
  return SKIP_DIRS8.some((d) => filePath.includes(d));
@@ -11649,7 +12637,7 @@ async function checkFrontend(files, projectRoot) {
11649
12637
  if (!isFrontendFile(file.filePath)) continue;
11650
12638
  let content;
11651
12639
  try {
11652
- content = readFileSync22(join26(projectRoot, file.filePath), "utf-8");
12640
+ content = readFileSync23(join27(projectRoot, file.filePath), "utf-8");
11653
12641
  } catch {
11654
12642
  continue;
11655
12643
  }
@@ -12109,13 +13097,13 @@ async function scanSecurity(projectRoot, graph, options = {}) {
12109
13097
  };
12110
13098
  }
12111
13099
  function detectPackageManager(projectRoot) {
12112
- if (existsSync16(join27(projectRoot, "package.json"))) return "npm";
12113
- if (existsSync16(join27(projectRoot, "requirements.txt"))) return "pip";
12114
- if (existsSync16(join27(projectRoot, "pyproject.toml"))) return "pip";
12115
- if (existsSync16(join27(projectRoot, "Cargo.toml"))) return "cargo";
12116
- if (existsSync16(join27(projectRoot, "go.mod"))) return "go";
12117
- if (existsSync16(join27(projectRoot, "pom.xml"))) return "maven";
12118
- if (existsSync16(join27(projectRoot, "build.gradle")) || existsSync16(join27(projectRoot, "build.gradle.kts"))) return "gradle";
13100
+ if (existsSync17(join28(projectRoot, "package.json"))) return "npm";
13101
+ if (existsSync17(join28(projectRoot, "requirements.txt"))) return "pip";
13102
+ if (existsSync17(join28(projectRoot, "pyproject.toml"))) return "pip";
13103
+ if (existsSync17(join28(projectRoot, "Cargo.toml"))) return "cargo";
13104
+ if (existsSync17(join28(projectRoot, "go.mod"))) return "go";
13105
+ if (existsSync17(join28(projectRoot, "pom.xml"))) return "maven";
13106
+ if (existsSync17(join28(projectRoot, "build.gradle")) || existsSync17(join28(projectRoot, "build.gradle.kts"))) return "gradle";
12119
13107
  return "unknown";
12120
13108
  }
12121
13109