cto-ai-cli 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +201 -2
- package/README.md +216 -312
- package/dist/action/index.js +271 -156
- package/dist/api/dashboard.js +271 -156
- package/dist/api/dashboard.js.map +1 -1
- package/dist/api/server.js +276 -155
- package/dist/api/server.js.map +1 -1
- package/dist/cli/gateway.js +298 -183
- package/dist/cli/score.js +1396 -241
- package/dist/cli/v2/index.js +290 -175
- package/dist/cli/v2/index.js.map +1 -1
- package/dist/engine/index.d.ts +121 -1
- package/dist/engine/index.js +1035 -212
- package/dist/engine/index.js.map +1 -1
- package/dist/fsevents-X6WP4TKM.node +0 -0
- package/dist/gateway/index.js +298 -183
- package/dist/gateway/index.js.map +1 -1
- package/dist/interact/index.js +263 -148
- package/dist/interact/index.js.map +1 -1
- package/dist/mcp/v2.js +287 -172
- package/dist/mcp/v2.js.map +1 -1
- package/package.json +8 -22
package/dist/api/dashboard.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/api/dashboard.ts
|
|
4
|
-
import { resolve as resolve5, join as
|
|
4
|
+
import { resolve as resolve5, join as join5 } from "path";
|
|
5
5
|
import { writeFile as writeFile2, mkdir, readFile as readFile5 } from "fs/promises";
|
|
6
6
|
|
|
7
7
|
// src/engine/analyzer.ts
|
|
@@ -1005,10 +1005,7 @@ function deduplicateFindings(findings) {
|
|
|
1005
1005
|
}
|
|
1006
1006
|
|
|
1007
1007
|
// src/engine/pruner.ts
|
|
1008
|
-
import { Project as Project2, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
1009
1008
|
import { readFile as readFile4 } from "fs/promises";
|
|
1010
|
-
import { existsSync as existsSync3 } from "fs";
|
|
1011
|
-
import { join as join5 } from "path";
|
|
1012
1009
|
var TS_EXTENSIONS2 = /* @__PURE__ */ new Set(["ts", "tsx", "js", "jsx", "mts", "mjs"]);
|
|
1013
1010
|
async function pruneFile(file, level) {
|
|
1014
1011
|
if (level === "excluded") {
|
|
@@ -1031,23 +1028,7 @@ async function pruneTypeScript(file, level) {
|
|
|
1031
1028
|
} catch {
|
|
1032
1029
|
return emptyResult(file, level);
|
|
1033
1030
|
}
|
|
1034
|
-
|
|
1035
|
-
try {
|
|
1036
|
-
const tsConfigPath = findTsConfig(file.path);
|
|
1037
|
-
project = new Project2({
|
|
1038
|
-
tsConfigFilePath: tsConfigPath,
|
|
1039
|
-
skipAddingFilesFromTsConfig: true,
|
|
1040
|
-
compilerOptions: tsConfigPath ? void 0 : { allowJs: true, esModuleInterop: true }
|
|
1041
|
-
});
|
|
1042
|
-
project.createSourceFile(file.path, content, { overwrite: true });
|
|
1043
|
-
} catch {
|
|
1044
|
-
return pruneGenericFromContent(file, content, level);
|
|
1045
|
-
}
|
|
1046
|
-
const sourceFile = project.getSourceFiles()[0];
|
|
1047
|
-
if (!sourceFile) {
|
|
1048
|
-
return pruneGenericFromContent(file, content, level);
|
|
1049
|
-
}
|
|
1050
|
-
const prunedContent = level === "signatures" ? extractSignaturesAST(sourceFile) : extractSkeletonAST(sourceFile);
|
|
1031
|
+
const prunedContent = level === "signatures" ? extractSignaturesRegex(content) : extractSkeletonRegex(content);
|
|
1051
1032
|
const prunedTokens = countTokensChars4(Buffer.byteLength(prunedContent, "utf-8"));
|
|
1052
1033
|
const savingsPercent = file.tokens > 0 ? (file.tokens - prunedTokens) / file.tokens * 100 : 0;
|
|
1053
1034
|
return {
|
|
@@ -1059,131 +1040,281 @@ async function pruneTypeScript(file, level) {
|
|
|
1059
1040
|
savingsPercent: Math.max(0, savingsPercent)
|
|
1060
1041
|
};
|
|
1061
1042
|
}
|
|
1062
|
-
function
|
|
1043
|
+
function extractSignaturesRegex(content) {
|
|
1044
|
+
const lines = content.split("\n");
|
|
1063
1045
|
const parts = [];
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
addJSDoc(fn, parts);
|
|
1082
|
-
const isExported = fn.isExported();
|
|
1083
|
-
const isAsync = fn.isAsync();
|
|
1084
|
-
const name = fn.getName() ?? "<anonymous>";
|
|
1085
|
-
const params = fn.getParameters().map((p) => p.getText()).join(", ");
|
|
1086
|
-
const returnType = fn.getReturnTypeNode()?.getText();
|
|
1087
|
-
const returnStr = returnType ? `: ${returnType}` : "";
|
|
1088
|
-
const prefix = isExported ? "export " : "";
|
|
1089
|
-
const asyncStr = isAsync ? "async " : "";
|
|
1090
|
-
parts.push(`${prefix}${asyncStr}function ${name}(${params})${returnStr} { /* ... */ }`);
|
|
1091
|
-
}
|
|
1092
|
-
for (const stmt of sf.getVariableStatements()) {
|
|
1093
|
-
for (const decl of stmt.getDeclarations()) {
|
|
1094
|
-
const init = decl.getInitializer();
|
|
1095
|
-
if (init && (init.getKind() === SyntaxKind2.ArrowFunction || init.getKind() === SyntaxKind2.FunctionExpression)) {
|
|
1096
|
-
addJSDoc(stmt, parts);
|
|
1097
|
-
const isExported = stmt.isExported();
|
|
1098
|
-
const prefix = isExported ? "export " : "";
|
|
1099
|
-
const kind = stmt.getDeclarationKind();
|
|
1100
|
-
const name = decl.getName();
|
|
1101
|
-
const typeNode = decl.getTypeNode()?.getText();
|
|
1102
|
-
const typeStr = typeNode ? `: ${typeNode}` : "";
|
|
1103
|
-
parts.push(`${prefix}${kind} ${name}${typeStr} = /* ... */;`);
|
|
1104
|
-
} else {
|
|
1105
|
-
addJSDoc(stmt, parts);
|
|
1106
|
-
parts.push(stmt.getText());
|
|
1046
|
+
let i = 0;
|
|
1047
|
+
while (i < lines.length) {
|
|
1048
|
+
const line = lines[i];
|
|
1049
|
+
const trimmed = line.trim();
|
|
1050
|
+
if (trimmed === "") {
|
|
1051
|
+
i++;
|
|
1052
|
+
continue;
|
|
1053
|
+
}
|
|
1054
|
+
if (trimmed.startsWith("/**")) {
|
|
1055
|
+
const docLines = [];
|
|
1056
|
+
while (i < lines.length) {
|
|
1057
|
+
docLines.push(lines[i]);
|
|
1058
|
+
if (lines[i].includes("*/")) {
|
|
1059
|
+
i++;
|
|
1060
|
+
break;
|
|
1061
|
+
}
|
|
1062
|
+
i++;
|
|
1107
1063
|
}
|
|
1064
|
+
parts.push(docLines.join("\n"));
|
|
1065
|
+
continue;
|
|
1108
1066
|
}
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
if (
|
|
1127
|
-
const
|
|
1128
|
-
parts.push(
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
const
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1067
|
+
if (trimmed.startsWith("//")) {
|
|
1068
|
+
parts.push(line);
|
|
1069
|
+
i++;
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
if (/^\s*(import|export)\s/.test(line) && (trimmed.includes(" from ") || trimmed.startsWith("import "))) {
|
|
1073
|
+
const block = collectBracedLine(lines, i);
|
|
1074
|
+
parts.push(block.text);
|
|
1075
|
+
i = block.nextIndex;
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
if (/^\s*export\s*(\{|\*)/.test(trimmed)) {
|
|
1079
|
+
const block = collectBracedLine(lines, i);
|
|
1080
|
+
parts.push(block.text);
|
|
1081
|
+
i = block.nextIndex;
|
|
1082
|
+
continue;
|
|
1083
|
+
}
|
|
1084
|
+
if (/^\s*(export\s+)?type\s+\w/.test(trimmed) && !trimmed.startsWith("typeof")) {
|
|
1085
|
+
const block = collectBalanced(lines, i);
|
|
1086
|
+
parts.push(block.text);
|
|
1087
|
+
i = block.nextIndex;
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
if (/^\s*(export\s+)?interface\s+\w/.test(trimmed)) {
|
|
1091
|
+
const block = collectBalanced(lines, i);
|
|
1092
|
+
parts.push(block.text);
|
|
1093
|
+
i = block.nextIndex;
|
|
1094
|
+
continue;
|
|
1095
|
+
}
|
|
1096
|
+
if (/^\s*(export\s+)?(const\s+)?enum\s+\w/.test(trimmed)) {
|
|
1097
|
+
const block = collectBalanced(lines, i);
|
|
1098
|
+
parts.push(block.text);
|
|
1099
|
+
i = block.nextIndex;
|
|
1100
|
+
continue;
|
|
1101
|
+
}
|
|
1102
|
+
const fnMatch = trimmed.match(/^(export\s+)?(async\s+)?function\s+(\w+)/);
|
|
1103
|
+
if (fnMatch) {
|
|
1104
|
+
const sig = extractFnSignature(lines, i);
|
|
1105
|
+
parts.push(`${sig} { /* ... */ }`);
|
|
1106
|
+
i = skipBlock(lines, i);
|
|
1107
|
+
continue;
|
|
1108
|
+
}
|
|
1109
|
+
const arrowMatch = trimmed.match(/^(export\s+)?(const|let|var)\s+(\w+)/);
|
|
1110
|
+
if (arrowMatch && looksLikeFunctionDecl(lines, i)) {
|
|
1111
|
+
const prefix = trimmed.match(/^((?:export\s+)?(?:const|let|var)\s+\w+[^=]*=)/)?.[1];
|
|
1112
|
+
if (prefix) {
|
|
1113
|
+
parts.push(`${prefix} /* ... */;`);
|
|
1114
|
+
}
|
|
1115
|
+
i = skipBlock(lines, i);
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
if (arrowMatch) {
|
|
1119
|
+
const block = collectStatement(lines, i);
|
|
1120
|
+
parts.push(block.text);
|
|
1121
|
+
i = block.nextIndex;
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
if (/^\s*(export\s+)?(abstract\s+)?class\s+\w/.test(trimmed)) {
|
|
1125
|
+
const classOutline = extractClassOutline(lines, i);
|
|
1126
|
+
parts.push(classOutline.text);
|
|
1127
|
+
i = classOutline.nextIndex;
|
|
1128
|
+
continue;
|
|
1129
|
+
}
|
|
1130
|
+
i++;
|
|
1148
1131
|
}
|
|
1149
1132
|
return parts.join("\n");
|
|
1150
1133
|
}
|
|
1151
|
-
function
|
|
1134
|
+
function extractSkeletonRegex(content) {
|
|
1135
|
+
const lines = content.split("\n");
|
|
1152
1136
|
const parts = [];
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1137
|
+
let i = 0;
|
|
1138
|
+
while (i < lines.length) {
|
|
1139
|
+
const trimmed = lines[i].trim();
|
|
1140
|
+
if (/^import\s/.test(trimmed)) {
|
|
1141
|
+
const block = collectBracedLine(lines, i);
|
|
1142
|
+
parts.push(block.text);
|
|
1143
|
+
i = block.nextIndex;
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
if (/^export\s+(type|interface)\s+\w/.test(trimmed)) {
|
|
1147
|
+
const block = collectBalanced(lines, i);
|
|
1148
|
+
parts.push(block.text);
|
|
1149
|
+
i = block.nextIndex;
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
if (/^export\s+(const\s+)?enum\s+\w/.test(trimmed)) {
|
|
1153
|
+
const block = collectBalanced(lines, i);
|
|
1154
|
+
parts.push(block.text);
|
|
1155
|
+
i = block.nextIndex;
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1158
|
+
if (/^export\s+(async\s+)?function\s+\w/.test(trimmed)) {
|
|
1159
|
+
const sig = extractFnSignature(lines, i);
|
|
1160
|
+
parts.push(`${sig};`);
|
|
1161
|
+
i = skipBlock(lines, i);
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
if (/^export\s+(abstract\s+)?class\s+/.test(trimmed)) {
|
|
1165
|
+
const nameMatch = trimmed.match(/class\s+(\w+)/);
|
|
1166
|
+
const name = nameMatch?.[1] ?? "Unknown";
|
|
1167
|
+
const end = skipBlock(lines, i);
|
|
1168
|
+
const methods = [];
|
|
1169
|
+
for (let j = i + 1; j < end; j++) {
|
|
1170
|
+
const mt = lines[j].trim();
|
|
1171
|
+
const mm = mt.match(/^(?:static\s+)?(?:async\s+)?(\w+)\s*\(/);
|
|
1172
|
+
if (mm && mm[1] !== "constructor") methods.push(mm[1]);
|
|
1173
|
+
}
|
|
1174
|
+
parts.push(`export class ${name} { /* methods: ${methods.join(", ")} */ }`);
|
|
1175
|
+
i = end;
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
if (/^export\s*(\{|\*)/.test(trimmed)) {
|
|
1179
|
+
const block = collectBracedLine(lines, i);
|
|
1180
|
+
parts.push(block.text);
|
|
1181
|
+
i = block.nextIndex;
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
i++;
|
|
1184
1185
|
}
|
|
1185
1186
|
return parts.join("\n");
|
|
1186
1187
|
}
|
|
1188
|
+
function collectBracedLine(lines, start) {
|
|
1189
|
+
let text = lines[start];
|
|
1190
|
+
let i = start + 1;
|
|
1191
|
+
while (i < lines.length && !text.includes(";") && !text.trimEnd().endsWith("'") && !text.trimEnd().endsWith('"')) {
|
|
1192
|
+
text += "\n" + lines[i];
|
|
1193
|
+
i++;
|
|
1194
|
+
}
|
|
1195
|
+
return { text, nextIndex: i };
|
|
1196
|
+
}
|
|
1197
|
+
function collectBalanced(lines, start) {
|
|
1198
|
+
let depth = 0;
|
|
1199
|
+
let text = "";
|
|
1200
|
+
let i = start;
|
|
1201
|
+
let started = false;
|
|
1202
|
+
while (i < lines.length) {
|
|
1203
|
+
const line = lines[i];
|
|
1204
|
+
text += (text ? "\n" : "") + line;
|
|
1205
|
+
for (const ch of line) {
|
|
1206
|
+
if (ch === "{" || ch === "(") {
|
|
1207
|
+
depth++;
|
|
1208
|
+
started = true;
|
|
1209
|
+
}
|
|
1210
|
+
if (ch === "}" || ch === ")") depth--;
|
|
1211
|
+
}
|
|
1212
|
+
i++;
|
|
1213
|
+
if (started && depth <= 0) break;
|
|
1214
|
+
if (!started && line.includes(";")) break;
|
|
1215
|
+
}
|
|
1216
|
+
return { text, nextIndex: i };
|
|
1217
|
+
}
|
|
1218
|
+
function collectStatement(lines, start) {
|
|
1219
|
+
let text = lines[start];
|
|
1220
|
+
let i = start + 1;
|
|
1221
|
+
if (text.includes(";")) return { text, nextIndex: i };
|
|
1222
|
+
let depth = 0;
|
|
1223
|
+
for (const ch of text) {
|
|
1224
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
1225
|
+
if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
1226
|
+
}
|
|
1227
|
+
while (i < lines.length && depth > 0) {
|
|
1228
|
+
text += "\n" + lines[i];
|
|
1229
|
+
for (const ch of lines[i]) {
|
|
1230
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
1231
|
+
if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
1232
|
+
}
|
|
1233
|
+
i++;
|
|
1234
|
+
}
|
|
1235
|
+
return { text, nextIndex: i };
|
|
1236
|
+
}
|
|
1237
|
+
function extractFnSignature(lines, start) {
|
|
1238
|
+
let sig = "";
|
|
1239
|
+
let i = start;
|
|
1240
|
+
while (i < lines.length) {
|
|
1241
|
+
const line = lines[i].trim();
|
|
1242
|
+
sig += (sig ? " " : "") + line;
|
|
1243
|
+
if (line.includes("{")) {
|
|
1244
|
+
sig = sig.replace(/\s*\{[^]*$/, "").trim();
|
|
1245
|
+
break;
|
|
1246
|
+
}
|
|
1247
|
+
i++;
|
|
1248
|
+
}
|
|
1249
|
+
return sig;
|
|
1250
|
+
}
|
|
1251
|
+
function skipBlock(lines, start) {
|
|
1252
|
+
let depth = 0;
|
|
1253
|
+
let i = start;
|
|
1254
|
+
let foundBrace = false;
|
|
1255
|
+
while (i < lines.length) {
|
|
1256
|
+
for (const ch of lines[i]) {
|
|
1257
|
+
if (ch === "{") {
|
|
1258
|
+
depth++;
|
|
1259
|
+
foundBrace = true;
|
|
1260
|
+
}
|
|
1261
|
+
if (ch === "}") depth--;
|
|
1262
|
+
}
|
|
1263
|
+
i++;
|
|
1264
|
+
if (foundBrace && depth <= 0) break;
|
|
1265
|
+
if (!foundBrace && lines[i - 1].includes(";")) break;
|
|
1266
|
+
}
|
|
1267
|
+
return i;
|
|
1268
|
+
}
|
|
1269
|
+
function looksLikeFunctionDecl(lines, start) {
|
|
1270
|
+
const chunk = lines.slice(start, Math.min(start + 5, lines.length)).join(" ");
|
|
1271
|
+
return /=>/.test(chunk) || /=\s*function/.test(chunk);
|
|
1272
|
+
}
|
|
1273
|
+
function extractClassOutline(lines, start) {
|
|
1274
|
+
const header = lines[start].trim();
|
|
1275
|
+
let headerText = header;
|
|
1276
|
+
let i = start + 1;
|
|
1277
|
+
if (!header.includes("{")) {
|
|
1278
|
+
while (i < lines.length) {
|
|
1279
|
+
headerText += " " + lines[i].trim();
|
|
1280
|
+
if (lines[i].includes("{")) {
|
|
1281
|
+
i++;
|
|
1282
|
+
break;
|
|
1283
|
+
}
|
|
1284
|
+
i++;
|
|
1285
|
+
}
|
|
1286
|
+
} else {
|
|
1287
|
+
i = start + 1;
|
|
1288
|
+
}
|
|
1289
|
+
const bodyParts = [headerText.replace(/\{[^]*$/, "{").trim()];
|
|
1290
|
+
let depth = 1;
|
|
1291
|
+
while (i < lines.length && depth > 0) {
|
|
1292
|
+
const line = lines[i];
|
|
1293
|
+
const trimmed = line.trim();
|
|
1294
|
+
for (const ch of line) {
|
|
1295
|
+
if (ch === "{") depth++;
|
|
1296
|
+
if (ch === "}") depth--;
|
|
1297
|
+
}
|
|
1298
|
+
if (depth <= 0) {
|
|
1299
|
+
i++;
|
|
1300
|
+
break;
|
|
1301
|
+
}
|
|
1302
|
+
if (depth === 1) {
|
|
1303
|
+
if (/^(private|protected|public|readonly|static|#)/.test(trimmed) && !trimmed.includes("(")) {
|
|
1304
|
+
bodyParts.push(` ${trimmed}`);
|
|
1305
|
+
} else if (/^constructor\s*\(/.test(trimmed)) {
|
|
1306
|
+
const sig = extractFnSignature(lines, i);
|
|
1307
|
+
bodyParts.push(` ${sig} { /* ... */ }`);
|
|
1308
|
+
} else if (/^(?:static\s+)?(?:async\s+)?(?:get\s+|set\s+)?\w+\s*[(<]/.test(trimmed) && !trimmed.startsWith("//")) {
|
|
1309
|
+
const sig = extractFnSignature(lines, i);
|
|
1310
|
+
bodyParts.push(` ${sig} { /* ... */ }`);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
i++;
|
|
1314
|
+
}
|
|
1315
|
+
bodyParts.push("}");
|
|
1316
|
+
return { text: bodyParts.join("\n"), nextIndex: i };
|
|
1317
|
+
}
|
|
1187
1318
|
async function pruneGeneric(file, level) {
|
|
1188
1319
|
let content;
|
|
1189
1320
|
try {
|
|
@@ -1244,22 +1375,6 @@ function emptyResult(file, level) {
|
|
|
1244
1375
|
savingsPercent: 100
|
|
1245
1376
|
};
|
|
1246
1377
|
}
|
|
1247
|
-
function addJSDoc(node, parts) {
|
|
1248
|
-
if (!node.getJsDocs) return;
|
|
1249
|
-
const docs = node.getJsDocs();
|
|
1250
|
-
if (docs.length > 0) {
|
|
1251
|
-
parts.push(docs[0].getText());
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
function findTsConfig(filePath) {
|
|
1255
|
-
let dir = filePath;
|
|
1256
|
-
for (let i = 0; i < 10; i++) {
|
|
1257
|
-
dir = join5(dir, "..");
|
|
1258
|
-
const candidate = join5(dir, "tsconfig.json");
|
|
1259
|
-
if (existsSync3(candidate)) return candidate;
|
|
1260
|
-
}
|
|
1261
|
-
return void 0;
|
|
1262
|
-
}
|
|
1263
1378
|
|
|
1264
1379
|
// src/engine/graph-utils.ts
|
|
1265
1380
|
function buildAdjacencyList(edges) {
|
|
@@ -1952,7 +2067,7 @@ function computeStrategyScore(strategy, budget) {
|
|
|
1952
2067
|
// src/api/dashboard.ts
|
|
1953
2068
|
async function loadHistory(ctoDir) {
|
|
1954
2069
|
try {
|
|
1955
|
-
const raw = await readFile5(
|
|
2070
|
+
const raw = await readFile5(join5(ctoDir, "history.json"), "utf-8");
|
|
1956
2071
|
return JSON.parse(raw);
|
|
1957
2072
|
} catch {
|
|
1958
2073
|
return [];
|
|
@@ -1960,11 +2075,11 @@ async function loadHistory(ctoDir) {
|
|
|
1960
2075
|
}
|
|
1961
2076
|
async function saveHistory(ctoDir, history) {
|
|
1962
2077
|
await mkdir(ctoDir, { recursive: true });
|
|
1963
|
-
await writeFile2(
|
|
2078
|
+
await writeFile2(join5(ctoDir, "history.json"), JSON.stringify(history, null, 2));
|
|
1964
2079
|
}
|
|
1965
2080
|
async function generateDashboard(projectPath, task = "general code review and refactoring", budget = 5e4) {
|
|
1966
2081
|
const absPath = resolve5(projectPath);
|
|
1967
|
-
const ctoDir =
|
|
2082
|
+
const ctoDir = join5(absPath, ".cto");
|
|
1968
2083
|
const analysis = await getCachedAnalysis(absPath);
|
|
1969
2084
|
const score = await computeContextScore(analysis, task, budget);
|
|
1970
2085
|
const benchmark = await runBenchmark(analysis, task, budget);
|
|
@@ -1994,7 +2109,7 @@ async function generateDashboard(projectPath, task = "general code review and re
|
|
|
1994
2109
|
generatedAt: /* @__PURE__ */ new Date()
|
|
1995
2110
|
};
|
|
1996
2111
|
const html = renderDashboardHTML(data);
|
|
1997
|
-
const htmlPath =
|
|
2112
|
+
const htmlPath = join5(ctoDir, "dashboard.html");
|
|
1998
2113
|
await mkdir(ctoDir, { recursive: true });
|
|
1999
2114
|
await writeFile2(htmlPath, html, "utf-8");
|
|
2000
2115
|
return { htmlPath, data };
|