@aiready/context-analyzer 0.9.34 → 0.9.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/FUNDING.yml +2 -2
- package/.turbo/turbo-build.log +9 -9
- package/.turbo/turbo-test.log +19 -19
- package/CONTRIBUTING.md +10 -2
- package/dist/chunk-7LUSCLGR.mjs +2058 -0
- package/dist/cli.js +346 -83
- package/dist/cli.mjs +137 -33
- package/dist/index.js +231 -56
- package/dist/index.mjs +1 -1
- package/dist/python-context-GOH747QU.mjs +202 -0
- package/package.json +2 -2
- package/src/__tests__/analyzer.test.ts +69 -17
- package/src/__tests__/auto-detection.test.ts +1 -1
- package/src/__tests__/enhanced-cohesion.test.ts +19 -7
- package/src/__tests__/file-classification.test.ts +188 -53
- package/src/__tests__/fragmentation-advanced.test.ts +2 -11
- package/src/__tests__/fragmentation-coupling.test.ts +8 -2
- package/src/__tests__/fragmentation-log.test.ts +9 -9
- package/src/__tests__/scoring.test.ts +19 -7
- package/src/__tests__/structural-cohesion.test.ts +33 -21
- package/src/analyzer.ts +724 -376
- package/src/analyzers/python-context.ts +33 -10
- package/src/cli.ts +223 -59
- package/src/index.ts +112 -55
- package/src/scoring.ts +53 -43
- package/src/semantic-analysis.ts +73 -55
- package/src/types.ts +12 -13
package/dist/cli.js
CHANGED
|
@@ -43,7 +43,12 @@ async function analyzePythonContext(files, rootDir) {
|
|
|
43
43
|
return results;
|
|
44
44
|
}
|
|
45
45
|
const pythonFiles = files.filter((f) => f.toLowerCase().endsWith(".py"));
|
|
46
|
-
|
|
46
|
+
void import_path.relative;
|
|
47
|
+
void import_path.join;
|
|
48
|
+
const dependencyGraph = await buildPythonDependencyGraph(
|
|
49
|
+
pythonFiles,
|
|
50
|
+
rootDir
|
|
51
|
+
);
|
|
47
52
|
for (const file of pythonFiles) {
|
|
48
53
|
try {
|
|
49
54
|
const code = await import_fs.default.promises.readFile(file, "utf-8");
|
|
@@ -59,10 +64,21 @@ async function analyzePythonContext(files, rootDir) {
|
|
|
59
64
|
type: exp.type
|
|
60
65
|
}));
|
|
61
66
|
const linesOfCode = code.split("\n").length;
|
|
62
|
-
const importDepth = await calculatePythonImportDepth(
|
|
63
|
-
|
|
67
|
+
const importDepth = await calculatePythonImportDepth(
|
|
68
|
+
file,
|
|
69
|
+
dependencyGraph,
|
|
70
|
+
/* @__PURE__ */ new Set()
|
|
71
|
+
);
|
|
72
|
+
const contextBudget = estimateContextBudget(
|
|
73
|
+
code,
|
|
74
|
+
imports,
|
|
75
|
+
dependencyGraph
|
|
76
|
+
);
|
|
64
77
|
const cohesion = calculatePythonCohesion(exports2, imports);
|
|
65
|
-
const circularDependencies = detectCircularDependencies2(
|
|
78
|
+
const circularDependencies = detectCircularDependencies2(
|
|
79
|
+
file,
|
|
80
|
+
dependencyGraph
|
|
81
|
+
);
|
|
66
82
|
results.push({
|
|
67
83
|
file,
|
|
68
84
|
importDepth,
|
|
@@ -100,6 +116,7 @@ async function buildPythonDependencyGraph(files, rootDir) {
|
|
|
100
116
|
}
|
|
101
117
|
graph.set(file, dependencies);
|
|
102
118
|
} catch (error) {
|
|
119
|
+
void error;
|
|
103
120
|
}
|
|
104
121
|
}
|
|
105
122
|
return graph;
|
|
@@ -362,7 +379,26 @@ function extractDomainKeywordsFromPaths(files) {
|
|
|
362
379
|
const folderNames = /* @__PURE__ */ new Set();
|
|
363
380
|
for (const { file } of files) {
|
|
364
381
|
const segments = file.split("/");
|
|
365
|
-
const skipFolders = /* @__PURE__ */ new Set([
|
|
382
|
+
const skipFolders = /* @__PURE__ */ new Set([
|
|
383
|
+
"src",
|
|
384
|
+
"lib",
|
|
385
|
+
"dist",
|
|
386
|
+
"build",
|
|
387
|
+
"node_modules",
|
|
388
|
+
"test",
|
|
389
|
+
"tests",
|
|
390
|
+
"__tests__",
|
|
391
|
+
"spec",
|
|
392
|
+
"e2e",
|
|
393
|
+
"scripts",
|
|
394
|
+
"components",
|
|
395
|
+
"utils",
|
|
396
|
+
"helpers",
|
|
397
|
+
"util",
|
|
398
|
+
"helper",
|
|
399
|
+
"api",
|
|
400
|
+
"apis"
|
|
401
|
+
]);
|
|
366
402
|
for (const segment of segments) {
|
|
367
403
|
const normalized = segment.toLowerCase();
|
|
368
404
|
if (normalized && !skipFolders.has(normalized) && !normalized.includes(".")) {
|
|
@@ -398,9 +434,15 @@ function buildDependencyGraph(files) {
|
|
|
398
434
|
const nodes = /* @__PURE__ */ new Map();
|
|
399
435
|
const edges = /* @__PURE__ */ new Map();
|
|
400
436
|
const autoDetectedKeywords = extractDomainKeywordsFromPaths(files);
|
|
437
|
+
void import_core.calculateImportSimilarity;
|
|
401
438
|
for (const { file, content } of files) {
|
|
402
439
|
const imports = extractImportsFromContent(content);
|
|
403
|
-
const exports2 = extractExportsWithAST(
|
|
440
|
+
const exports2 = extractExportsWithAST(
|
|
441
|
+
content,
|
|
442
|
+
file,
|
|
443
|
+
{ domainKeywords: autoDetectedKeywords },
|
|
444
|
+
imports
|
|
445
|
+
);
|
|
404
446
|
const tokenCost = (0, import_core.estimateTokens)(content);
|
|
405
447
|
const linesOfCode = content.split("\n").length;
|
|
406
448
|
nodes.set(file, {
|
|
@@ -544,7 +586,9 @@ function isTestFile(filePath) {
|
|
|
544
586
|
}
|
|
545
587
|
function calculateFragmentation(files, domain, options) {
|
|
546
588
|
if (files.length <= 1) return 0;
|
|
547
|
-
const directories = new Set(
|
|
589
|
+
const directories = new Set(
|
|
590
|
+
files.map((f) => f.split("/").slice(0, -1).join("/"))
|
|
591
|
+
);
|
|
548
592
|
const uniqueDirs = directories.size;
|
|
549
593
|
if (options?.useLogScale) {
|
|
550
594
|
if (uniqueDirs <= 1) return 0;
|
|
@@ -617,7 +661,9 @@ function detectModuleClusters(graph, options) {
|
|
|
617
661
|
const node = graph.nodes.get(file);
|
|
618
662
|
return sum + (node?.tokenCost || 0);
|
|
619
663
|
}, 0);
|
|
620
|
-
const baseFragmentation = calculateFragmentation(files, domain, {
|
|
664
|
+
const baseFragmentation = calculateFragmentation(files, domain, {
|
|
665
|
+
useLogScale: !!options?.useLogScale
|
|
666
|
+
});
|
|
621
667
|
let importSimilarityTotal = 0;
|
|
622
668
|
let importComparisons = 0;
|
|
623
669
|
for (let i = 0; i < files.length; i++) {
|
|
@@ -638,7 +684,9 @@ function detectModuleClusters(graph, options) {
|
|
|
638
684
|
const directoryDistance = calculateDirectoryDistance(files);
|
|
639
685
|
const avgCohesion = files.reduce((sum, file) => {
|
|
640
686
|
const node = graph.nodes.get(file);
|
|
641
|
-
return sum + (node ? calculateCohesion(node.exports, file, {
|
|
687
|
+
return sum + (node ? calculateCohesion(node.exports, file, {
|
|
688
|
+
coUsageMatrix: graph.coUsageMatrix
|
|
689
|
+
}) : 0);
|
|
642
690
|
}, 0) / files.length;
|
|
643
691
|
const targetFiles = Math.max(1, Math.ceil(files.length / 3));
|
|
644
692
|
const consolidationPlan = generateConsolidationPlan(
|
|
@@ -686,7 +734,12 @@ function extractExports(content, filePath, domainOptions, fileImports) {
|
|
|
686
734
|
while ((match = pattern.exec(content)) !== null) {
|
|
687
735
|
const name = match[1] || "default";
|
|
688
736
|
const type = types[index];
|
|
689
|
-
const inferredDomain = inferDomain(
|
|
737
|
+
const inferredDomain = inferDomain(
|
|
738
|
+
name,
|
|
739
|
+
filePath,
|
|
740
|
+
domainOptions,
|
|
741
|
+
fileImports
|
|
742
|
+
);
|
|
690
743
|
exports2.push({ name, type, inferredDomain });
|
|
691
744
|
}
|
|
692
745
|
});
|
|
@@ -794,11 +847,17 @@ function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
|
|
|
794
847
|
return astExports.map((exp) => ({
|
|
795
848
|
name: exp.name,
|
|
796
849
|
type: exp.type,
|
|
797
|
-
inferredDomain: inferDomain(
|
|
850
|
+
inferredDomain: inferDomain(
|
|
851
|
+
exp.name,
|
|
852
|
+
filePath,
|
|
853
|
+
domainOptions,
|
|
854
|
+
fileImports
|
|
855
|
+
),
|
|
798
856
|
imports: exp.imports,
|
|
799
857
|
dependencies: exp.dependencies
|
|
800
858
|
}));
|
|
801
859
|
} catch (error) {
|
|
860
|
+
void error;
|
|
802
861
|
return extractExports(content, filePath, domainOptions, fileImports);
|
|
803
862
|
}
|
|
804
863
|
}
|
|
@@ -813,15 +872,24 @@ function calculateEnhancedCohesion(exports2, filePath, options) {
|
|
|
813
872
|
const importCohesion = hasImportData ? calculateImportBasedCohesion(exports2) : void 0;
|
|
814
873
|
const coUsageMatrix = options?.coUsageMatrix;
|
|
815
874
|
const structuralCohesion = filePath && coUsageMatrix ? calculateStructuralCohesionFromCoUsage(filePath, coUsageMatrix) : void 0;
|
|
816
|
-
const defaultWeights = {
|
|
875
|
+
const defaultWeights = {
|
|
876
|
+
importBased: 0.5,
|
|
877
|
+
structural: 0.3,
|
|
878
|
+
domainBased: 0.2
|
|
879
|
+
};
|
|
817
880
|
const weights = { ...defaultWeights, ...options?.weights || {} };
|
|
818
881
|
const signals = [];
|
|
819
|
-
if (importCohesion !== void 0)
|
|
820
|
-
|
|
882
|
+
if (importCohesion !== void 0)
|
|
883
|
+
signals.push({ score: importCohesion, weight: weights.importBased });
|
|
884
|
+
if (structuralCohesion !== void 0)
|
|
885
|
+
signals.push({ score: structuralCohesion, weight: weights.structural });
|
|
821
886
|
signals.push({ score: domainCohesion, weight: weights.domainBased });
|
|
822
887
|
const totalWeight = signals.reduce((s, el) => s + el.weight, 0);
|
|
823
888
|
if (totalWeight === 0) return domainCohesion;
|
|
824
|
-
const combined = signals.reduce(
|
|
889
|
+
const combined = signals.reduce(
|
|
890
|
+
(sum, el) => sum + el.score * (el.weight / totalWeight),
|
|
891
|
+
0
|
|
892
|
+
);
|
|
825
893
|
return combined;
|
|
826
894
|
}
|
|
827
895
|
function calculateStructuralCohesionFromCoUsage(file, coUsageMatrix) {
|
|
@@ -844,7 +912,9 @@ function calculateStructuralCohesionFromCoUsage(file, coUsageMatrix) {
|
|
|
844
912
|
return maxEntropy > 0 ? 1 - entropy / maxEntropy : 1;
|
|
845
913
|
}
|
|
846
914
|
function calculateImportBasedCohesion(exports2) {
|
|
847
|
-
const exportsWithImports = exports2.filter(
|
|
915
|
+
const exportsWithImports = exports2.filter(
|
|
916
|
+
(e) => e.imports && e.imports.length > 0
|
|
917
|
+
);
|
|
848
918
|
if (exportsWithImports.length < 2) {
|
|
849
919
|
return 1;
|
|
850
920
|
}
|
|
@@ -889,6 +959,8 @@ function calculateDomainCohesion(exports2) {
|
|
|
889
959
|
}
|
|
890
960
|
function classifyFile(node, cohesionScore, domains) {
|
|
891
961
|
const { exports: exports2, imports, linesOfCode, file } = node;
|
|
962
|
+
void imports;
|
|
963
|
+
void linesOfCode;
|
|
892
964
|
if (isBarrelExport(node)) {
|
|
893
965
|
return "barrel-export";
|
|
894
966
|
}
|
|
@@ -967,8 +1039,12 @@ function isTypeDefinitionFile(node) {
|
|
|
967
1039
|
const isTypesFile = fileName?.includes("types") || fileName?.includes(".d.ts") || fileName === "types.ts" || fileName === "interfaces.ts";
|
|
968
1040
|
const lowerPath = file.toLowerCase();
|
|
969
1041
|
const isTypesPath = lowerPath.includes("/types/") || lowerPath.includes("/typings/") || lowerPath.includes("/@types/") || lowerPath.startsWith("types/") || lowerPath.startsWith("typings/");
|
|
970
|
-
const typeExports = exports2.filter(
|
|
971
|
-
|
|
1042
|
+
const typeExports = exports2.filter(
|
|
1043
|
+
(e) => e.type === "type" || e.type === "interface"
|
|
1044
|
+
);
|
|
1045
|
+
const runtimeExports = exports2.filter(
|
|
1046
|
+
(e) => e.type === "function" || e.type === "class" || e.type === "const"
|
|
1047
|
+
);
|
|
972
1048
|
const mostlyTypes = exports2.length > 0 && typeExports.length > runtimeExports.length && typeExports.length / exports2.length > 0.7;
|
|
973
1049
|
const pureTypeFile = exports2.length > 0 && typeExports.length === exports2.length;
|
|
974
1050
|
const emptyOrReExportInTypesDir = isTypesPath && exports2.length === 0;
|
|
@@ -1149,12 +1225,7 @@ function isLambdaHandler(node) {
|
|
|
1149
1225
|
function isServiceFile(node) {
|
|
1150
1226
|
const { file, exports: exports2 } = node;
|
|
1151
1227
|
const fileName = file.split("/").pop()?.toLowerCase();
|
|
1152
|
-
const servicePatterns = [
|
|
1153
|
-
"service",
|
|
1154
|
-
".service.",
|
|
1155
|
-
"-service.",
|
|
1156
|
-
"_service."
|
|
1157
|
-
];
|
|
1228
|
+
const servicePatterns = ["service", ".service.", "-service.", "_service."];
|
|
1158
1229
|
const isServiceName = servicePatterns.some(
|
|
1159
1230
|
(pattern) => fileName?.includes(pattern)
|
|
1160
1231
|
);
|
|
@@ -1262,7 +1333,15 @@ function isNextJsPage(node) {
|
|
|
1262
1333
|
}
|
|
1263
1334
|
const exportNames = exports2.map((e) => e.name.toLowerCase());
|
|
1264
1335
|
const hasDefaultExport = exports2.some((e) => e.type === "default");
|
|
1265
|
-
const nextJsExports = [
|
|
1336
|
+
const nextJsExports = [
|
|
1337
|
+
"metadata",
|
|
1338
|
+
"generatemetadata",
|
|
1339
|
+
"faqjsonld",
|
|
1340
|
+
"jsonld",
|
|
1341
|
+
"icon",
|
|
1342
|
+
"viewport",
|
|
1343
|
+
"dynamic"
|
|
1344
|
+
];
|
|
1266
1345
|
const hasNextJsExports = exportNames.some(
|
|
1267
1346
|
(name) => nextJsExports.includes(name) || name.includes("jsonld")
|
|
1268
1347
|
);
|
|
@@ -1336,13 +1415,44 @@ function hasRelatedExportNames(exportNames) {
|
|
|
1336
1415
|
const stems = /* @__PURE__ */ new Set();
|
|
1337
1416
|
const domains = /* @__PURE__ */ new Set();
|
|
1338
1417
|
for (const name of exportNames) {
|
|
1339
|
-
const verbs = [
|
|
1418
|
+
const verbs = [
|
|
1419
|
+
"get",
|
|
1420
|
+
"set",
|
|
1421
|
+
"create",
|
|
1422
|
+
"update",
|
|
1423
|
+
"delete",
|
|
1424
|
+
"fetch",
|
|
1425
|
+
"save",
|
|
1426
|
+
"load",
|
|
1427
|
+
"parse",
|
|
1428
|
+
"format",
|
|
1429
|
+
"validate",
|
|
1430
|
+
"convert",
|
|
1431
|
+
"transform",
|
|
1432
|
+
"build",
|
|
1433
|
+
"generate",
|
|
1434
|
+
"render",
|
|
1435
|
+
"send",
|
|
1436
|
+
"receive"
|
|
1437
|
+
];
|
|
1340
1438
|
for (const verb of verbs) {
|
|
1341
1439
|
if (name.startsWith(verb) && name.length > verb.length) {
|
|
1342
1440
|
stems.add(name.slice(verb.length).toLowerCase());
|
|
1343
1441
|
}
|
|
1344
1442
|
}
|
|
1345
|
-
const domainPatterns = [
|
|
1443
|
+
const domainPatterns = [
|
|
1444
|
+
"user",
|
|
1445
|
+
"order",
|
|
1446
|
+
"product",
|
|
1447
|
+
"session",
|
|
1448
|
+
"email",
|
|
1449
|
+
"file",
|
|
1450
|
+
"db",
|
|
1451
|
+
"s3",
|
|
1452
|
+
"dynamo",
|
|
1453
|
+
"api",
|
|
1454
|
+
"config"
|
|
1455
|
+
];
|
|
1346
1456
|
for (const domain of domainPatterns) {
|
|
1347
1457
|
if (name.includes(domain)) {
|
|
1348
1458
|
domains.add(domain);
|
|
@@ -1400,11 +1510,15 @@ function hasRelatedExportNames(exportNames) {
|
|
|
1400
1510
|
"all"
|
|
1401
1511
|
]);
|
|
1402
1512
|
const singularize2 = (w) => w.endsWith("s") && w.length > 3 ? w.slice(0, -1) : w;
|
|
1403
|
-
return new Set(
|
|
1513
|
+
return new Set(
|
|
1514
|
+
tokens.filter((t) => !skip.has(t) && t.length > 2).map(singularize2)
|
|
1515
|
+
);
|
|
1404
1516
|
});
|
|
1405
1517
|
if (nounSets.length >= 2 && nounSets.every((s) => s.size > 0)) {
|
|
1406
1518
|
const [first, ...rest] = nounSets;
|
|
1407
|
-
const commonNouns = Array.from(first).filter(
|
|
1519
|
+
const commonNouns = Array.from(first).filter(
|
|
1520
|
+
(n) => rest.every((s) => s.has(n))
|
|
1521
|
+
);
|
|
1408
1522
|
if (commonNouns.length > 0) return true;
|
|
1409
1523
|
}
|
|
1410
1524
|
return false;
|
|
@@ -1507,21 +1621,29 @@ async function analyzeContext(options) {
|
|
|
1507
1621
|
// Only add node_modules to exclude if includeNodeModules is false
|
|
1508
1622
|
// The DEFAULT_EXCLUDE already includes node_modules, so this is only needed
|
|
1509
1623
|
// if user overrides the default exclude list
|
|
1510
|
-
exclude: includeNodeModules && scanOptions.exclude ? scanOptions.exclude.filter(
|
|
1624
|
+
exclude: includeNodeModules && scanOptions.exclude ? scanOptions.exclude.filter(
|
|
1625
|
+
(pattern) => pattern !== "**/node_modules/**"
|
|
1626
|
+
) : scanOptions.exclude
|
|
1511
1627
|
});
|
|
1512
1628
|
const pythonFiles = files.filter((f) => f.toLowerCase().endsWith(".py"));
|
|
1513
1629
|
const tsJsFiles = files.filter((f) => !f.toLowerCase().endsWith(".py"));
|
|
1630
|
+
void tsJsFiles;
|
|
1514
1631
|
const fileContents = await Promise.all(
|
|
1515
1632
|
files.map(async (file) => ({
|
|
1516
1633
|
file,
|
|
1517
1634
|
content: await (0, import_core4.readFileContent)(file)
|
|
1518
1635
|
}))
|
|
1519
1636
|
);
|
|
1520
|
-
const graph = buildDependencyGraph(
|
|
1637
|
+
const graph = buildDependencyGraph(
|
|
1638
|
+
fileContents.filter((f) => !f.file.toLowerCase().endsWith(".py"))
|
|
1639
|
+
);
|
|
1521
1640
|
let pythonResults = [];
|
|
1522
1641
|
if (pythonFiles.length > 0) {
|
|
1523
1642
|
const { analyzePythonContext: analyzePythonContext2 } = await Promise.resolve().then(() => (init_python_context(), python_context_exports));
|
|
1524
|
-
const pythonMetrics = await analyzePythonContext2(
|
|
1643
|
+
const pythonMetrics = await analyzePythonContext2(
|
|
1644
|
+
pythonFiles,
|
|
1645
|
+
scanOptions.rootDir || options.rootDir || "."
|
|
1646
|
+
);
|
|
1525
1647
|
pythonResults = pythonMetrics.map((metric) => {
|
|
1526
1648
|
const { severity, issues, recommendations, potentialSavings } = analyzeIssues({
|
|
1527
1649
|
file: metric.file,
|
|
@@ -1534,17 +1656,25 @@ async function analyzeContext(options) {
|
|
|
1534
1656
|
maxContextBudget,
|
|
1535
1657
|
minCohesion,
|
|
1536
1658
|
maxFragmentation,
|
|
1537
|
-
circularDeps: metric.metrics.circularDependencies.map(
|
|
1659
|
+
circularDeps: metric.metrics.circularDependencies.map(
|
|
1660
|
+
(cycle) => cycle.split(" \u2192 ")
|
|
1661
|
+
)
|
|
1538
1662
|
});
|
|
1539
1663
|
return {
|
|
1540
1664
|
file: metric.file,
|
|
1541
|
-
tokenCost: Math.floor(
|
|
1665
|
+
tokenCost: Math.floor(
|
|
1666
|
+
metric.contextBudget / (1 + metric.imports.length || 1)
|
|
1667
|
+
),
|
|
1542
1668
|
// Estimate
|
|
1543
1669
|
linesOfCode: metric.metrics.linesOfCode,
|
|
1544
1670
|
importDepth: metric.importDepth,
|
|
1545
1671
|
dependencyCount: metric.imports.length,
|
|
1546
|
-
dependencyList: metric.imports.map(
|
|
1547
|
-
|
|
1672
|
+
dependencyList: metric.imports.map(
|
|
1673
|
+
(imp) => imp.resolvedPath || imp.source
|
|
1674
|
+
),
|
|
1675
|
+
circularDeps: metric.metrics.circularDependencies.map(
|
|
1676
|
+
(cycle) => cycle.split(" \u2192 ")
|
|
1677
|
+
),
|
|
1548
1678
|
cohesionScore: metric.cohesion,
|
|
1549
1679
|
domains: ["python"],
|
|
1550
1680
|
// Generic for now
|
|
@@ -1577,7 +1707,9 @@ async function analyzeContext(options) {
|
|
|
1577
1707
|
const importDepth = focus === "depth" || focus === "all" ? calculateImportDepth(file, graph) : 0;
|
|
1578
1708
|
const dependencyList = focus === "depth" || focus === "all" ? getTransitiveDependencies(file, graph) : [];
|
|
1579
1709
|
const contextBudget = focus === "all" ? calculateContextBudget(file, graph) : node.tokenCost;
|
|
1580
|
-
const cohesionScore = focus === "cohesion" || focus === "all" ? calculateCohesion(node.exports, file, {
|
|
1710
|
+
const cohesionScore = focus === "cohesion" || focus === "all" ? calculateCohesion(node.exports, file, {
|
|
1711
|
+
coUsageMatrix: graph.coUsageMatrix
|
|
1712
|
+
}) : 1;
|
|
1581
1713
|
const fragmentationScore = fragmentationMap.get(file) || 0;
|
|
1582
1714
|
const relatedFiles = [];
|
|
1583
1715
|
for (const cluster of clusters) {
|
|
@@ -1598,6 +1730,10 @@ async function analyzeContext(options) {
|
|
|
1598
1730
|
maxFragmentation,
|
|
1599
1731
|
circularDeps
|
|
1600
1732
|
});
|
|
1733
|
+
void severity;
|
|
1734
|
+
void issues;
|
|
1735
|
+
void recommendations;
|
|
1736
|
+
void potentialSavings;
|
|
1601
1737
|
const domains = [
|
|
1602
1738
|
...new Set(node.exports.map((e) => e.inferredDomain || "unknown"))
|
|
1603
1739
|
];
|
|
@@ -1652,7 +1788,10 @@ async function analyzeContext(options) {
|
|
|
1652
1788
|
fileClassification,
|
|
1653
1789
|
severity: adjustedSeverity,
|
|
1654
1790
|
issues: adjustedIssues,
|
|
1655
|
-
recommendations: [
|
|
1791
|
+
recommendations: [
|
|
1792
|
+
...finalRecommendations,
|
|
1793
|
+
...classificationRecommendations.slice(0, 1)
|
|
1794
|
+
],
|
|
1656
1795
|
potentialSavings: adjustedSavings
|
|
1657
1796
|
});
|
|
1658
1797
|
}
|
|
@@ -1731,7 +1870,10 @@ function generateSummary(results) {
|
|
|
1731
1870
|
let importPairs = 0;
|
|
1732
1871
|
for (let i = 0; i < files.length; i++) {
|
|
1733
1872
|
for (let j = i + 1; j < files.length; j++) {
|
|
1734
|
-
importSimTotal += jaccard2(
|
|
1873
|
+
importSimTotal += jaccard2(
|
|
1874
|
+
files[i].dependencyList || [],
|
|
1875
|
+
files[j].dependencyList || []
|
|
1876
|
+
);
|
|
1735
1877
|
importPairs++;
|
|
1736
1878
|
}
|
|
1737
1879
|
}
|
|
@@ -1758,7 +1900,9 @@ function generateSummary(results) {
|
|
|
1758
1900
|
fragmentedModules.sort((a, b) => b.fragmentationScore - a.fragmentationScore);
|
|
1759
1901
|
const avgCohesion = results.reduce((sum, r) => sum + r.cohesionScore, 0) / totalFiles;
|
|
1760
1902
|
const lowCohesionFiles = results.filter((r) => r.cohesionScore < 0.6).map((r) => ({ file: r.file, score: r.cohesionScore })).sort((a, b) => a.score - b.score).slice(0, 10);
|
|
1761
|
-
const criticalIssues = results.filter(
|
|
1903
|
+
const criticalIssues = results.filter(
|
|
1904
|
+
(r) => r.severity === "critical"
|
|
1905
|
+
).length;
|
|
1762
1906
|
const majorIssues = results.filter((r) => r.severity === "major").length;
|
|
1763
1907
|
const minorIssues = results.filter((r) => r.severity === "minor").length;
|
|
1764
1908
|
const totalPotentialSavings = results.reduce(
|
|
@@ -1808,10 +1952,10 @@ function analyzeIssues(params) {
|
|
|
1808
1952
|
let potentialSavings = 0;
|
|
1809
1953
|
if (circularDeps.length > 0) {
|
|
1810
1954
|
severity = "critical";
|
|
1811
|
-
issues.push(
|
|
1812
|
-
|
|
1955
|
+
issues.push(`Part of ${circularDeps.length} circular dependency chain(s)`);
|
|
1956
|
+
recommendations.push(
|
|
1957
|
+
"Break circular dependencies by extracting interfaces or using dependency injection"
|
|
1813
1958
|
);
|
|
1814
|
-
recommendations.push("Break circular dependencies by extracting interfaces or using dependency injection");
|
|
1815
1959
|
potentialSavings += contextBudget * 0.2;
|
|
1816
1960
|
}
|
|
1817
1961
|
if (importDepth > maxDepth * 1.5) {
|
|
@@ -1821,25 +1965,37 @@ function analyzeIssues(params) {
|
|
|
1821
1965
|
potentialSavings += contextBudget * 0.3;
|
|
1822
1966
|
} else if (importDepth > maxDepth) {
|
|
1823
1967
|
severity = severity === "critical" ? "critical" : "major";
|
|
1824
|
-
issues.push(
|
|
1968
|
+
issues.push(
|
|
1969
|
+
`Import depth ${importDepth} exceeds recommended maximum ${maxDepth}`
|
|
1970
|
+
);
|
|
1825
1971
|
recommendations.push("Consider reducing dependency depth");
|
|
1826
1972
|
potentialSavings += contextBudget * 0.15;
|
|
1827
1973
|
}
|
|
1828
1974
|
if (contextBudget > maxContextBudget * 1.5) {
|
|
1829
1975
|
severity = severity === "critical" ? "critical" : "critical";
|
|
1830
|
-
issues.push(
|
|
1831
|
-
|
|
1976
|
+
issues.push(
|
|
1977
|
+
`Context budget ${contextBudget.toLocaleString()} tokens is 50% over limit`
|
|
1978
|
+
);
|
|
1979
|
+
recommendations.push(
|
|
1980
|
+
"Split into smaller modules or reduce dependency tree"
|
|
1981
|
+
);
|
|
1832
1982
|
potentialSavings += contextBudget * 0.4;
|
|
1833
1983
|
} else if (contextBudget > maxContextBudget) {
|
|
1834
1984
|
severity = severity === "critical" || severity === "major" ? severity : "major";
|
|
1835
|
-
issues.push(
|
|
1985
|
+
issues.push(
|
|
1986
|
+
`Context budget ${contextBudget.toLocaleString()} exceeds ${maxContextBudget.toLocaleString()}`
|
|
1987
|
+
);
|
|
1836
1988
|
recommendations.push("Reduce file size or dependencies");
|
|
1837
1989
|
potentialSavings += contextBudget * 0.2;
|
|
1838
1990
|
}
|
|
1839
1991
|
if (cohesionScore < minCohesion * 0.5) {
|
|
1840
1992
|
severity = severity === "critical" ? "critical" : "major";
|
|
1841
|
-
issues.push(
|
|
1842
|
-
|
|
1993
|
+
issues.push(
|
|
1994
|
+
`Very low cohesion (${(cohesionScore * 100).toFixed(0)}%) - mixed concerns`
|
|
1995
|
+
);
|
|
1996
|
+
recommendations.push(
|
|
1997
|
+
"Split file by domain - separate unrelated functionality"
|
|
1998
|
+
);
|
|
1843
1999
|
potentialSavings += contextBudget * 0.25;
|
|
1844
2000
|
} else if (cohesionScore < minCohesion) {
|
|
1845
2001
|
severity = severity === "critical" || severity === "major" ? severity : "minor";
|
|
@@ -1849,7 +2005,9 @@ function analyzeIssues(params) {
|
|
|
1849
2005
|
}
|
|
1850
2006
|
if (fragmentationScore > maxFragmentation) {
|
|
1851
2007
|
severity = severity === "critical" || severity === "major" ? severity : "minor";
|
|
1852
|
-
issues.push(
|
|
2008
|
+
issues.push(
|
|
2009
|
+
`High fragmentation (${(fragmentationScore * 100).toFixed(0)}%) - scattered implementation`
|
|
2010
|
+
);
|
|
1853
2011
|
recommendations.push("Consolidate with related files in same domain");
|
|
1854
2012
|
potentialSavings += contextBudget * 0.3;
|
|
1855
2013
|
}
|
|
@@ -1859,11 +2017,18 @@ function analyzeIssues(params) {
|
|
|
1859
2017
|
}
|
|
1860
2018
|
if (isBuildArtifact(file)) {
|
|
1861
2019
|
issues.push("Detected build artifact (bundled/output file)");
|
|
1862
|
-
recommendations.push(
|
|
2020
|
+
recommendations.push(
|
|
2021
|
+
"Exclude build outputs (e.g., cdk.out, dist, build, .next) from analysis"
|
|
2022
|
+
);
|
|
1863
2023
|
severity = downgradeSeverity(severity);
|
|
1864
2024
|
potentialSavings = 0;
|
|
1865
2025
|
}
|
|
1866
|
-
return {
|
|
2026
|
+
return {
|
|
2027
|
+
severity,
|
|
2028
|
+
issues,
|
|
2029
|
+
recommendations,
|
|
2030
|
+
potentialSavings: Math.floor(potentialSavings)
|
|
2031
|
+
};
|
|
1867
2032
|
}
|
|
1868
2033
|
function isBuildArtifact(filePath) {
|
|
1869
2034
|
const lower = filePath.toLowerCase();
|
|
@@ -1889,7 +2054,10 @@ var import_path2 = require("path");
|
|
|
1889
2054
|
var import_core5 = require("@aiready/core");
|
|
1890
2055
|
var import_prompts = __toESM(require("prompts"));
|
|
1891
2056
|
var program = new import_commander.Command();
|
|
1892
|
-
program.name("aiready-context").description("Analyze AI context window cost and code structure").version("0.1.0").addHelpText(
|
|
2057
|
+
program.name("aiready-context").description("Analyze AI context window cost and code structure").version("0.1.0").addHelpText(
|
|
2058
|
+
"after",
|
|
2059
|
+
"\nCONFIGURATION:\n Supports config files: aiready.json, aiready.config.json, .aiready.json, .aireadyrc.json, aiready.config.js, .aireadyrc.js\n CLI options override config file settings"
|
|
2060
|
+
).argument("<directory>", "Directory to analyze").option("--max-depth <number>", "Maximum acceptable import depth").option(
|
|
1893
2061
|
"--max-context <number>",
|
|
1894
2062
|
"Maximum acceptable context budget (tokens)"
|
|
1895
2063
|
).option("--min-cohesion <number>", "Minimum acceptable cohesion score (0-1)").option(
|
|
@@ -1898,11 +2066,17 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
1898
2066
|
).option(
|
|
1899
2067
|
"--focus <type>",
|
|
1900
2068
|
"Analysis focus: fragmentation, cohesion, depth, all"
|
|
1901
|
-
).option("--include-node-modules", "Include node_modules in analysis").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
|
|
2069
|
+
).option("--include-node-modules", "Include node_modules in analysis").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
|
|
2070
|
+
"--max-results <number>",
|
|
2071
|
+
"Maximum number of results to show in console output"
|
|
2072
|
+
).option(
|
|
1902
2073
|
"-o, --output <format>",
|
|
1903
2074
|
"Output format: console, json, html",
|
|
1904
2075
|
"console"
|
|
1905
|
-
).option("--output-file <path>", "Output file path (for json/html)").option(
|
|
2076
|
+
).option("--output-file <path>", "Output file path (for json/html)").option(
|
|
2077
|
+
"--interactive",
|
|
2078
|
+
"Run interactive setup to suggest excludes and focus areas"
|
|
2079
|
+
).action(async (directory, options) => {
|
|
1906
2080
|
console.log(import_chalk.default.blue("\u{1F50D} Analyzing context window costs...\n"));
|
|
1907
2081
|
const startTime = Date.now();
|
|
1908
2082
|
try {
|
|
@@ -1946,8 +2120,12 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
1946
2120
|
`context-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`,
|
|
1947
2121
|
directory
|
|
1948
2122
|
);
|
|
1949
|
-
(0, import_core5.handleJSONOutput)(
|
|
1950
|
-
|
|
2123
|
+
(0, import_core5.handleJSONOutput)(
|
|
2124
|
+
jsonOutput,
|
|
2125
|
+
outputPath,
|
|
2126
|
+
`
|
|
2127
|
+
\u2713 JSON report saved to ${outputPath}`
|
|
2128
|
+
);
|
|
1951
2129
|
return;
|
|
1952
2130
|
}
|
|
1953
2131
|
if (options.output === "html") {
|
|
@@ -1966,7 +2144,12 @@ program.name("aiready-context").description("Analyze AI context window cost and
|
|
|
1966
2144
|
\u2713 HTML report saved to ${outputPath}`));
|
|
1967
2145
|
return;
|
|
1968
2146
|
}
|
|
1969
|
-
displayConsoleReport(
|
|
2147
|
+
displayConsoleReport(
|
|
2148
|
+
summary,
|
|
2149
|
+
results,
|
|
2150
|
+
elapsedTime,
|
|
2151
|
+
finalOptions.maxResults
|
|
2152
|
+
);
|
|
1970
2153
|
displayTuningGuidance(results, finalOptions);
|
|
1971
2154
|
} catch (error) {
|
|
1972
2155
|
(0, import_core5.handleCLIError)(error, "Analysis");
|
|
@@ -1976,28 +2159,80 @@ program.parse();
|
|
|
1976
2159
|
function displayTuningGuidance(results, options) {
|
|
1977
2160
|
const issueCount = results.filter((r) => r.severity !== "info").length;
|
|
1978
2161
|
if (issueCount === 0) {
|
|
1979
|
-
console.log(
|
|
2162
|
+
console.log(
|
|
2163
|
+
import_chalk.default.green(
|
|
2164
|
+
"\n\u2728 No optimization opportunities found! Your code is well-structured for AI context usage.\n"
|
|
2165
|
+
)
|
|
2166
|
+
);
|
|
1980
2167
|
return;
|
|
1981
2168
|
}
|
|
1982
2169
|
console.log(import_chalk.default.cyan("\n\u2501".repeat(60)));
|
|
1983
2170
|
console.log(import_chalk.default.bold.white(" TUNING GUIDANCE"));
|
|
1984
2171
|
console.log(import_chalk.default.cyan("\u2501".repeat(60) + "\n"));
|
|
1985
2172
|
if (issueCount < 5) {
|
|
1986
|
-
console.log(
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
2173
|
+
console.log(
|
|
2174
|
+
import_chalk.default.yellow(
|
|
2175
|
+
"\u{1F4CA} Showing few optimization opportunities. To find more areas to improve:\n"
|
|
2176
|
+
)
|
|
2177
|
+
);
|
|
2178
|
+
console.log(
|
|
2179
|
+
import_chalk.default.dim(
|
|
2180
|
+
" \u2022 Lower --max-depth (currently: " + options.maxDepth + ") to catch shallower import chains"
|
|
2181
|
+
)
|
|
2182
|
+
);
|
|
2183
|
+
console.log(
|
|
2184
|
+
import_chalk.default.dim(
|
|
2185
|
+
" \u2022 Lower --max-context (currently: " + options.maxContextBudget.toLocaleString() + ") to catch smaller files"
|
|
2186
|
+
)
|
|
2187
|
+
);
|
|
2188
|
+
console.log(
|
|
2189
|
+
import_chalk.default.dim(
|
|
2190
|
+
" \u2022 Raise --min-cohesion (currently: " + (options.minCohesion * 100).toFixed(0) + "%) to be stricter about mixed concerns"
|
|
2191
|
+
)
|
|
2192
|
+
);
|
|
2193
|
+
console.log(
|
|
2194
|
+
import_chalk.default.dim(
|
|
2195
|
+
" \u2022 Lower --max-fragmentation (currently: " + (options.maxFragmentation * 100).toFixed(0) + "%) to catch scattered code\n"
|
|
2196
|
+
)
|
|
2197
|
+
);
|
|
1991
2198
|
} else if (issueCount > 20) {
|
|
1992
|
-
console.log(
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
2199
|
+
console.log(
|
|
2200
|
+
import_chalk.default.yellow(
|
|
2201
|
+
"\u{1F4CA} Showing many opportunities. To focus on highest-impact areas:\n"
|
|
2202
|
+
)
|
|
2203
|
+
);
|
|
2204
|
+
console.log(
|
|
2205
|
+
import_chalk.default.dim(
|
|
2206
|
+
" \u2022 Raise --max-depth (currently: " + options.maxDepth + ") to only catch very deep chains"
|
|
2207
|
+
)
|
|
2208
|
+
);
|
|
2209
|
+
console.log(
|
|
2210
|
+
import_chalk.default.dim(
|
|
2211
|
+
" \u2022 Raise --max-context (currently: " + options.maxContextBudget.toLocaleString() + ") to focus on largest files"
|
|
2212
|
+
)
|
|
2213
|
+
);
|
|
2214
|
+
console.log(
|
|
2215
|
+
import_chalk.default.dim(
|
|
2216
|
+
" \u2022 Lower --min-cohesion (currently: " + (options.minCohesion * 100).toFixed(0) + "%) to only flag severe mixed concerns"
|
|
2217
|
+
)
|
|
2218
|
+
);
|
|
2219
|
+
console.log(
|
|
2220
|
+
import_chalk.default.dim(
|
|
2221
|
+
" \u2022 Raise --max-fragmentation (currently: " + (options.maxFragmentation * 100).toFixed(0) + "%) to only flag highly scattered code\n"
|
|
2222
|
+
)
|
|
2223
|
+
);
|
|
1997
2224
|
} else {
|
|
1998
|
-
console.log(
|
|
2225
|
+
console.log(
|
|
2226
|
+
import_chalk.default.green(
|
|
2227
|
+
"\u{1F4CA} Good balance of optimization opportunities (showing " + issueCount + " areas)\n"
|
|
2228
|
+
)
|
|
2229
|
+
);
|
|
1999
2230
|
console.log(import_chalk.default.dim(" \u{1F4A1} Tip: Adjust thresholds if needed:"));
|
|
2000
|
-
console.log(
|
|
2231
|
+
console.log(
|
|
2232
|
+
import_chalk.default.dim(
|
|
2233
|
+
" aiready-context . --max-depth N --max-context N --min-cohesion 0.X\n"
|
|
2234
|
+
)
|
|
2235
|
+
);
|
|
2001
2236
|
}
|
|
2002
2237
|
console.log(import_chalk.default.dim(" \u{1F4D6} See README for detailed tuning guide\n"));
|
|
2003
2238
|
}
|
|
@@ -2008,9 +2243,13 @@ function displayConsoleReport(summary, results, elapsedTime, maxResults = 10) {
|
|
|
2008
2243
|
console.log(import_chalk.default.cyan(divider));
|
|
2009
2244
|
console.log(import_chalk.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
2010
2245
|
console.log(import_chalk.default.cyan(divider) + "\n");
|
|
2011
|
-
console.log(import_chalk.default.white(`\u{1F4C1} Files analyzed: ${import_chalk.default.bold(summary.totalFiles)}`));
|
|
2012
2246
|
console.log(
|
|
2013
|
-
import_chalk.default.white(`\u{
|
|
2247
|
+
import_chalk.default.white(`\u{1F4C1} Files analyzed: ${import_chalk.default.bold(summary.totalFiles)}`)
|
|
2248
|
+
);
|
|
2249
|
+
console.log(
|
|
2250
|
+
import_chalk.default.white(
|
|
2251
|
+
`\u{1F4CA} Total tokens: ${import_chalk.default.bold(summary.totalTokens.toLocaleString())}`
|
|
2252
|
+
)
|
|
2014
2253
|
);
|
|
2015
2254
|
console.log(
|
|
2016
2255
|
import_chalk.default.yellow(
|
|
@@ -2035,7 +2274,9 @@ function displayConsoleReport(summary, results, elapsedTime, maxResults = 10) {
|
|
|
2035
2274
|
);
|
|
2036
2275
|
}
|
|
2037
2276
|
if (summary.minorIssues > 0) {
|
|
2038
|
-
console.log(
|
|
2277
|
+
console.log(
|
|
2278
|
+
import_chalk.default.blue(` \u{1F535} Minor: ${import_chalk.default.bold(summary.minorIssues)}`)
|
|
2279
|
+
);
|
|
2039
2280
|
}
|
|
2040
2281
|
console.log(
|
|
2041
2282
|
import_chalk.default.green(
|
|
@@ -2130,11 +2371,14 @@ function displayConsoleReport(summary, results, elapsedTime, maxResults = 10) {
|
|
|
2130
2371
|
)
|
|
2131
2372
|
);
|
|
2132
2373
|
console.log(
|
|
2133
|
-
import_chalk.default.dim(
|
|
2374
|
+
import_chalk.default.dim(
|
|
2375
|
+
"\u{1F41B} Found a bug? Report it: https://github.com/caopengau/aiready-context-analyzer/issues\n"
|
|
2376
|
+
)
|
|
2134
2377
|
);
|
|
2135
2378
|
}
|
|
2136
2379
|
function generateHTMLReport(summary, results) {
|
|
2137
2380
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
2381
|
+
void results;
|
|
2138
2382
|
return `<!DOCTYPE html>
|
|
2139
2383
|
<html lang="en">
|
|
2140
2384
|
<head>
|
|
@@ -2262,14 +2506,16 @@ function generateHTMLReport(summary, results) {
|
|
|
2262
2506
|
</tr>
|
|
2263
2507
|
</thead>
|
|
2264
2508
|
<tbody>
|
|
2265
|
-
${summary.fragmentedModules.map(
|
|
2509
|
+
${summary.fragmentedModules.map(
|
|
2510
|
+
(m) => `
|
|
2266
2511
|
<tr>
|
|
2267
2512
|
<td>${m.domain}</td>
|
|
2268
2513
|
<td>${m.files.length}</td>
|
|
2269
2514
|
<td>${(m.fragmentationScore * 100).toFixed(0)}%</td>
|
|
2270
2515
|
<td>${m.totalTokens.toLocaleString()}</td>
|
|
2271
2516
|
</tr>
|
|
2272
|
-
`
|
|
2517
|
+
`
|
|
2518
|
+
).join("")}
|
|
2273
2519
|
</tbody>
|
|
2274
2520
|
</table>
|
|
2275
2521
|
</div>
|
|
@@ -2287,13 +2533,15 @@ function generateHTMLReport(summary, results) {
|
|
|
2287
2533
|
</tr>
|
|
2288
2534
|
</thead>
|
|
2289
2535
|
<tbody>
|
|
2290
|
-
${summary.topExpensiveFiles.map(
|
|
2536
|
+
${summary.topExpensiveFiles.map(
|
|
2537
|
+
(f) => `
|
|
2291
2538
|
<tr>
|
|
2292
2539
|
<td>${f.file}</td>
|
|
2293
2540
|
<td>${f.contextBudget.toLocaleString()} tokens</td>
|
|
2294
2541
|
<td class="issue-${f.severity}">${f.severity.toUpperCase()}</td>
|
|
2295
2542
|
</tr>
|
|
2296
|
-
`
|
|
2543
|
+
`
|
|
2544
|
+
).join("")}
|
|
2297
2545
|
</tbody>
|
|
2298
2546
|
</table>
|
|
2299
2547
|
</div>
|
|
@@ -2315,7 +2563,8 @@ async function runInteractiveSetup(directory, current) {
|
|
|
2315
2563
|
try {
|
|
2316
2564
|
const pkg = JSON.parse((0, import_fs2.readFileSync)(pkgPath, "utf-8"));
|
|
2317
2565
|
deps = { ...pkg.dependencies || {}, ...pkg.devDependencies || {} };
|
|
2318
|
-
} catch {
|
|
2566
|
+
} catch (e) {
|
|
2567
|
+
void e;
|
|
2319
2568
|
}
|
|
2320
2569
|
}
|
|
2321
2570
|
const hasNextJs = (0, import_fs2.existsSync)((0, import_path2.join)(directory, ".next")) || !!deps["next"];
|
|
@@ -2335,7 +2584,7 @@ async function runInteractiveSetup(directory, current) {
|
|
|
2335
2584
|
active: "yes",
|
|
2336
2585
|
inactive: "no"
|
|
2337
2586
|
});
|
|
2338
|
-
|
|
2587
|
+
const nextOptions = { ...current };
|
|
2339
2588
|
if (applyExcludes) {
|
|
2340
2589
|
nextOptions.exclude = Array.from(recommendedExcludes);
|
|
2341
2590
|
}
|
|
@@ -2352,9 +2601,23 @@ async function runInteractiveSetup(directory, current) {
|
|
|
2352
2601
|
});
|
|
2353
2602
|
if (focusArea === "frontend") {
|
|
2354
2603
|
nextOptions.include = ["**/*.{ts,tsx,js,jsx}"];
|
|
2355
|
-
nextOptions.exclude = Array.from(
|
|
2604
|
+
nextOptions.exclude = Array.from(
|
|
2605
|
+
/* @__PURE__ */ new Set([
|
|
2606
|
+
...nextOptions.exclude || [],
|
|
2607
|
+
"**/cdk.out/**",
|
|
2608
|
+
"**/infra/**",
|
|
2609
|
+
"**/server/**",
|
|
2610
|
+
"**/backend/**"
|
|
2611
|
+
])
|
|
2612
|
+
);
|
|
2356
2613
|
} else if (focusArea === "backend") {
|
|
2357
|
-
nextOptions.include = [
|
|
2614
|
+
nextOptions.include = [
|
|
2615
|
+
"**/api/**",
|
|
2616
|
+
"**/server/**",
|
|
2617
|
+
"**/backend/**",
|
|
2618
|
+
"**/infra/**",
|
|
2619
|
+
"**/*.{ts,js,py,java}"
|
|
2620
|
+
];
|
|
2358
2621
|
}
|
|
2359
2622
|
console.log(import_chalk.default.green("\u2713 Interactive configuration applied."));
|
|
2360
2623
|
return nextOptions;
|