cto-ai-cli 4.0.0 → 5.1.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 +217 -312
- package/dist/action/index.js +281 -162
- package/dist/api/dashboard.js +281 -162
- package/dist/api/dashboard.js.map +1 -1
- package/dist/api/server.js +362 -184
- package/dist/api/server.js.map +1 -1
- package/dist/cli/gateway.js +358 -229
- package/dist/cli/score.js +2426 -1225
- package/dist/cli/v2/index.js +290 -175
- package/dist/cli/v2/index.js.map +1 -1
- package/dist/engine/index.d.ts +150 -1
- package/dist/engine/index.js +1130 -219
- package/dist/engine/index.js.map +1 -1
- package/dist/fsevents-X6WP4TKM.node +0 -0
- package/dist/gateway/index.d.ts +2 -2
- package/dist/gateway/index.js +358 -229
- 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 +297 -178
- package/dist/mcp/v2.js.map +1 -1
- package/package.json +8 -22
- package/dist/core/index.d.ts +0 -717
- package/dist/core/index.js +0 -4446
- package/dist/core/index.js.map +0 -1
package/dist/mcp/v2.js
CHANGED
|
@@ -13778,7 +13778,7 @@ function date4(params) {
|
|
|
13778
13778
|
config(en_default());
|
|
13779
13779
|
|
|
13780
13780
|
// src/mcp/v2.ts
|
|
13781
|
-
import { resolve as resolve8, join as
|
|
13781
|
+
import { resolve as resolve8, join as join7 } from "path";
|
|
13782
13782
|
import { readFile as readFile8, writeFile as writeFile3, mkdir as mkdir2 } from "fs/promises";
|
|
13783
13783
|
|
|
13784
13784
|
// src/engine/analyzer.ts
|
|
@@ -14369,8 +14369,8 @@ async function analyzeProject(projectPath, config2) {
|
|
|
14369
14369
|
maxDepth: mergedConfig.analysis.maxDepth
|
|
14370
14370
|
});
|
|
14371
14371
|
const tokenMethod = mergedConfig.tokens.method;
|
|
14372
|
-
const
|
|
14373
|
-
|
|
14372
|
+
const BATCH_SIZE = 50;
|
|
14373
|
+
async function estimateFileTokens(entry) {
|
|
14374
14374
|
let tokens;
|
|
14375
14375
|
if (tokenMethod === "tiktoken") {
|
|
14376
14376
|
try {
|
|
@@ -14382,7 +14382,7 @@ async function analyzeProject(projectPath, config2) {
|
|
|
14382
14382
|
} else {
|
|
14383
14383
|
tokens = countTokensChars4(entry.size);
|
|
14384
14384
|
}
|
|
14385
|
-
|
|
14385
|
+
return {
|
|
14386
14386
|
path: entry.path,
|
|
14387
14387
|
relativePath: entry.relativePath,
|
|
14388
14388
|
extension: entry.extension,
|
|
@@ -14391,16 +14391,20 @@ async function analyzeProject(projectPath, config2) {
|
|
|
14391
14391
|
lines: entry.lines,
|
|
14392
14392
|
lastModified: entry.lastModified,
|
|
14393
14393
|
kind: classifyFileKind(entry.relativePath),
|
|
14394
|
-
// Graph data — populated by graph analysis
|
|
14395
14394
|
imports: [],
|
|
14396
14395
|
importedBy: [],
|
|
14397
14396
|
isHub: false,
|
|
14398
14397
|
complexity: 0,
|
|
14399
|
-
// Risk data — populated by risk analysis
|
|
14400
14398
|
riskScore: 0,
|
|
14401
14399
|
riskFactors: [],
|
|
14402
14400
|
exclusionImpact: "none"
|
|
14403
|
-
}
|
|
14401
|
+
};
|
|
14402
|
+
}
|
|
14403
|
+
const files = [];
|
|
14404
|
+
for (let i = 0; i < walkEntries.length; i += BATCH_SIZE) {
|
|
14405
|
+
const batch = walkEntries.slice(i, i + BATCH_SIZE);
|
|
14406
|
+
const results = await Promise.all(batch.map(estimateFileTokens));
|
|
14407
|
+
files.push(...results);
|
|
14404
14408
|
}
|
|
14405
14409
|
const graph = buildProjectGraph(absPath, files);
|
|
14406
14410
|
for (const file2 of files) {
|
|
@@ -14932,10 +14936,7 @@ function deduplicateFindings(findings) {
|
|
|
14932
14936
|
}
|
|
14933
14937
|
|
|
14934
14938
|
// src/engine/pruner.ts
|
|
14935
|
-
import { Project as Project2, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
14936
14939
|
import { readFile as readFile4 } from "fs/promises";
|
|
14937
|
-
import { existsSync as existsSync3 } from "fs";
|
|
14938
|
-
import { join as join5 } from "path";
|
|
14939
14940
|
var TS_EXTENSIONS2 = /* @__PURE__ */ new Set(["ts", "tsx", "js", "jsx", "mts", "mjs"]);
|
|
14940
14941
|
async function pruneFile(file2, level) {
|
|
14941
14942
|
if (level === "excluded") {
|
|
@@ -14958,23 +14959,7 @@ async function pruneTypeScript(file2, level) {
|
|
|
14958
14959
|
} catch {
|
|
14959
14960
|
return emptyResult(file2, level);
|
|
14960
14961
|
}
|
|
14961
|
-
|
|
14962
|
-
try {
|
|
14963
|
-
const tsConfigPath = findTsConfig(file2.path);
|
|
14964
|
-
project = new Project2({
|
|
14965
|
-
tsConfigFilePath: tsConfigPath,
|
|
14966
|
-
skipAddingFilesFromTsConfig: true,
|
|
14967
|
-
compilerOptions: tsConfigPath ? void 0 : { allowJs: true, esModuleInterop: true }
|
|
14968
|
-
});
|
|
14969
|
-
project.createSourceFile(file2.path, content, { overwrite: true });
|
|
14970
|
-
} catch {
|
|
14971
|
-
return pruneGenericFromContent(file2, content, level);
|
|
14972
|
-
}
|
|
14973
|
-
const sourceFile = project.getSourceFiles()[0];
|
|
14974
|
-
if (!sourceFile) {
|
|
14975
|
-
return pruneGenericFromContent(file2, content, level);
|
|
14976
|
-
}
|
|
14977
|
-
const prunedContent = level === "signatures" ? extractSignaturesAST(sourceFile) : extractSkeletonAST(sourceFile);
|
|
14962
|
+
const prunedContent = level === "signatures" ? extractSignaturesRegex(content) : extractSkeletonRegex(content);
|
|
14978
14963
|
const prunedTokens = countTokensChars4(Buffer.byteLength(prunedContent, "utf-8"));
|
|
14979
14964
|
const savingsPercent = file2.tokens > 0 ? (file2.tokens - prunedTokens) / file2.tokens * 100 : 0;
|
|
14980
14965
|
return {
|
|
@@ -14986,131 +14971,281 @@ async function pruneTypeScript(file2, level) {
|
|
|
14986
14971
|
savingsPercent: Math.max(0, savingsPercent)
|
|
14987
14972
|
};
|
|
14988
14973
|
}
|
|
14989
|
-
function
|
|
14974
|
+
function extractSignaturesRegex(content) {
|
|
14975
|
+
const lines = content.split("\n");
|
|
14990
14976
|
const parts = [];
|
|
14991
|
-
|
|
14992
|
-
|
|
14993
|
-
|
|
14994
|
-
|
|
14995
|
-
|
|
14996
|
-
|
|
14997
|
-
|
|
14998
|
-
|
|
14999
|
-
|
|
15000
|
-
|
|
15001
|
-
|
|
15002
|
-
|
|
15003
|
-
|
|
15004
|
-
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
15020
|
-
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
|
|
15024
|
-
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
|
|
15028
|
-
|
|
15029
|
-
|
|
15030
|
-
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15041
|
-
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
parts.push(
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
const
|
|
15065
|
-
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
|
|
15069
|
-
|
|
15070
|
-
|
|
15071
|
-
|
|
15072
|
-
|
|
15073
|
-
|
|
15074
|
-
|
|
14977
|
+
let i = 0;
|
|
14978
|
+
while (i < lines.length) {
|
|
14979
|
+
const line = lines[i];
|
|
14980
|
+
const trimmed = line.trim();
|
|
14981
|
+
if (trimmed === "") {
|
|
14982
|
+
i++;
|
|
14983
|
+
continue;
|
|
14984
|
+
}
|
|
14985
|
+
if (trimmed.startsWith("/**")) {
|
|
14986
|
+
const docLines = [];
|
|
14987
|
+
while (i < lines.length) {
|
|
14988
|
+
docLines.push(lines[i]);
|
|
14989
|
+
if (lines[i].includes("*/")) {
|
|
14990
|
+
i++;
|
|
14991
|
+
break;
|
|
14992
|
+
}
|
|
14993
|
+
i++;
|
|
14994
|
+
}
|
|
14995
|
+
parts.push(docLines.join("\n"));
|
|
14996
|
+
continue;
|
|
14997
|
+
}
|
|
14998
|
+
if (trimmed.startsWith("//")) {
|
|
14999
|
+
parts.push(line);
|
|
15000
|
+
i++;
|
|
15001
|
+
continue;
|
|
15002
|
+
}
|
|
15003
|
+
if (/^\s*(import|export)\s/.test(line) && (trimmed.includes(" from ") || trimmed.startsWith("import "))) {
|
|
15004
|
+
const block = collectBracedLine(lines, i);
|
|
15005
|
+
parts.push(block.text);
|
|
15006
|
+
i = block.nextIndex;
|
|
15007
|
+
continue;
|
|
15008
|
+
}
|
|
15009
|
+
if (/^\s*export\s*(\{|\*)/.test(trimmed)) {
|
|
15010
|
+
const block = collectBracedLine(lines, i);
|
|
15011
|
+
parts.push(block.text);
|
|
15012
|
+
i = block.nextIndex;
|
|
15013
|
+
continue;
|
|
15014
|
+
}
|
|
15015
|
+
if (/^\s*(export\s+)?type\s+\w/.test(trimmed) && !trimmed.startsWith("typeof")) {
|
|
15016
|
+
const block = collectBalanced(lines, i);
|
|
15017
|
+
parts.push(block.text);
|
|
15018
|
+
i = block.nextIndex;
|
|
15019
|
+
continue;
|
|
15020
|
+
}
|
|
15021
|
+
if (/^\s*(export\s+)?interface\s+\w/.test(trimmed)) {
|
|
15022
|
+
const block = collectBalanced(lines, i);
|
|
15023
|
+
parts.push(block.text);
|
|
15024
|
+
i = block.nextIndex;
|
|
15025
|
+
continue;
|
|
15026
|
+
}
|
|
15027
|
+
if (/^\s*(export\s+)?(const\s+)?enum\s+\w/.test(trimmed)) {
|
|
15028
|
+
const block = collectBalanced(lines, i);
|
|
15029
|
+
parts.push(block.text);
|
|
15030
|
+
i = block.nextIndex;
|
|
15031
|
+
continue;
|
|
15032
|
+
}
|
|
15033
|
+
const fnMatch = trimmed.match(/^(export\s+)?(async\s+)?function\s+(\w+)/);
|
|
15034
|
+
if (fnMatch) {
|
|
15035
|
+
const sig = extractFnSignature(lines, i);
|
|
15036
|
+
parts.push(`${sig} { /* ... */ }`);
|
|
15037
|
+
i = skipBlock(lines, i);
|
|
15038
|
+
continue;
|
|
15039
|
+
}
|
|
15040
|
+
const arrowMatch = trimmed.match(/^(export\s+)?(const|let|var)\s+(\w+)/);
|
|
15041
|
+
if (arrowMatch && looksLikeFunctionDecl(lines, i)) {
|
|
15042
|
+
const prefix = trimmed.match(/^((?:export\s+)?(?:const|let|var)\s+\w+[^=]*=)/)?.[1];
|
|
15043
|
+
if (prefix) {
|
|
15044
|
+
parts.push(`${prefix} /* ... */;`);
|
|
15045
|
+
}
|
|
15046
|
+
i = skipBlock(lines, i);
|
|
15047
|
+
continue;
|
|
15048
|
+
}
|
|
15049
|
+
if (arrowMatch) {
|
|
15050
|
+
const block = collectStatement(lines, i);
|
|
15051
|
+
parts.push(block.text);
|
|
15052
|
+
i = block.nextIndex;
|
|
15053
|
+
continue;
|
|
15054
|
+
}
|
|
15055
|
+
if (/^\s*(export\s+)?(abstract\s+)?class\s+\w/.test(trimmed)) {
|
|
15056
|
+
const classOutline = extractClassOutline(lines, i);
|
|
15057
|
+
parts.push(classOutline.text);
|
|
15058
|
+
i = classOutline.nextIndex;
|
|
15059
|
+
continue;
|
|
15060
|
+
}
|
|
15061
|
+
i++;
|
|
15075
15062
|
}
|
|
15076
15063
|
return parts.join("\n");
|
|
15077
15064
|
}
|
|
15078
|
-
function
|
|
15065
|
+
function extractSkeletonRegex(content) {
|
|
15066
|
+
const lines = content.split("\n");
|
|
15079
15067
|
const parts = [];
|
|
15080
|
-
|
|
15081
|
-
|
|
15082
|
-
|
|
15083
|
-
|
|
15084
|
-
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
|
|
15089
|
-
|
|
15090
|
-
|
|
15091
|
-
|
|
15092
|
-
|
|
15093
|
-
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15097
|
-
|
|
15098
|
-
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15068
|
+
let i = 0;
|
|
15069
|
+
while (i < lines.length) {
|
|
15070
|
+
const trimmed = lines[i].trim();
|
|
15071
|
+
if (/^import\s/.test(trimmed)) {
|
|
15072
|
+
const block = collectBracedLine(lines, i);
|
|
15073
|
+
parts.push(block.text);
|
|
15074
|
+
i = block.nextIndex;
|
|
15075
|
+
continue;
|
|
15076
|
+
}
|
|
15077
|
+
if (/^export\s+(type|interface)\s+\w/.test(trimmed)) {
|
|
15078
|
+
const block = collectBalanced(lines, i);
|
|
15079
|
+
parts.push(block.text);
|
|
15080
|
+
i = block.nextIndex;
|
|
15081
|
+
continue;
|
|
15082
|
+
}
|
|
15083
|
+
if (/^export\s+(const\s+)?enum\s+\w/.test(trimmed)) {
|
|
15084
|
+
const block = collectBalanced(lines, i);
|
|
15085
|
+
parts.push(block.text);
|
|
15086
|
+
i = block.nextIndex;
|
|
15087
|
+
continue;
|
|
15088
|
+
}
|
|
15089
|
+
if (/^export\s+(async\s+)?function\s+\w/.test(trimmed)) {
|
|
15090
|
+
const sig = extractFnSignature(lines, i);
|
|
15091
|
+
parts.push(`${sig};`);
|
|
15092
|
+
i = skipBlock(lines, i);
|
|
15093
|
+
continue;
|
|
15094
|
+
}
|
|
15095
|
+
if (/^export\s+(abstract\s+)?class\s+/.test(trimmed)) {
|
|
15096
|
+
const nameMatch = trimmed.match(/class\s+(\w+)/);
|
|
15097
|
+
const name = nameMatch?.[1] ?? "Unknown";
|
|
15098
|
+
const end = skipBlock(lines, i);
|
|
15099
|
+
const methods = [];
|
|
15100
|
+
for (let j = i + 1; j < end; j++) {
|
|
15101
|
+
const mt = lines[j].trim();
|
|
15102
|
+
const mm = mt.match(/^(?:static\s+)?(?:async\s+)?(\w+)\s*\(/);
|
|
15103
|
+
if (mm && mm[1] !== "constructor") methods.push(mm[1]);
|
|
15104
|
+
}
|
|
15105
|
+
parts.push(`export class ${name} { /* methods: ${methods.join(", ")} */ }`);
|
|
15106
|
+
i = end;
|
|
15107
|
+
continue;
|
|
15108
|
+
}
|
|
15109
|
+
if (/^export\s*(\{|\*)/.test(trimmed)) {
|
|
15110
|
+
const block = collectBracedLine(lines, i);
|
|
15111
|
+
parts.push(block.text);
|
|
15112
|
+
i = block.nextIndex;
|
|
15113
|
+
continue;
|
|
15114
|
+
}
|
|
15115
|
+
i++;
|
|
15111
15116
|
}
|
|
15112
15117
|
return parts.join("\n");
|
|
15113
15118
|
}
|
|
15119
|
+
function collectBracedLine(lines, start) {
|
|
15120
|
+
let text = lines[start];
|
|
15121
|
+
let i = start + 1;
|
|
15122
|
+
while (i < lines.length && !text.includes(";") && !text.trimEnd().endsWith("'") && !text.trimEnd().endsWith('"')) {
|
|
15123
|
+
text += "\n" + lines[i];
|
|
15124
|
+
i++;
|
|
15125
|
+
}
|
|
15126
|
+
return { text, nextIndex: i };
|
|
15127
|
+
}
|
|
15128
|
+
function collectBalanced(lines, start) {
|
|
15129
|
+
let depth = 0;
|
|
15130
|
+
let text = "";
|
|
15131
|
+
let i = start;
|
|
15132
|
+
let started = false;
|
|
15133
|
+
while (i < lines.length) {
|
|
15134
|
+
const line = lines[i];
|
|
15135
|
+
text += (text ? "\n" : "") + line;
|
|
15136
|
+
for (const ch of line) {
|
|
15137
|
+
if (ch === "{" || ch === "(") {
|
|
15138
|
+
depth++;
|
|
15139
|
+
started = true;
|
|
15140
|
+
}
|
|
15141
|
+
if (ch === "}" || ch === ")") depth--;
|
|
15142
|
+
}
|
|
15143
|
+
i++;
|
|
15144
|
+
if (started && depth <= 0) break;
|
|
15145
|
+
if (!started && line.includes(";")) break;
|
|
15146
|
+
}
|
|
15147
|
+
return { text, nextIndex: i };
|
|
15148
|
+
}
|
|
15149
|
+
function collectStatement(lines, start) {
|
|
15150
|
+
let text = lines[start];
|
|
15151
|
+
let i = start + 1;
|
|
15152
|
+
if (text.includes(";")) return { text, nextIndex: i };
|
|
15153
|
+
let depth = 0;
|
|
15154
|
+
for (const ch of text) {
|
|
15155
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
15156
|
+
if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
15157
|
+
}
|
|
15158
|
+
while (i < lines.length && depth > 0) {
|
|
15159
|
+
text += "\n" + lines[i];
|
|
15160
|
+
for (const ch of lines[i]) {
|
|
15161
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
15162
|
+
if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
15163
|
+
}
|
|
15164
|
+
i++;
|
|
15165
|
+
}
|
|
15166
|
+
return { text, nextIndex: i };
|
|
15167
|
+
}
|
|
15168
|
+
function extractFnSignature(lines, start) {
|
|
15169
|
+
let sig = "";
|
|
15170
|
+
let i = start;
|
|
15171
|
+
while (i < lines.length) {
|
|
15172
|
+
const line = lines[i].trim();
|
|
15173
|
+
sig += (sig ? " " : "") + line;
|
|
15174
|
+
if (line.includes("{")) {
|
|
15175
|
+
sig = sig.replace(/\s*\{[^]*$/, "").trim();
|
|
15176
|
+
break;
|
|
15177
|
+
}
|
|
15178
|
+
i++;
|
|
15179
|
+
}
|
|
15180
|
+
return sig;
|
|
15181
|
+
}
|
|
15182
|
+
function skipBlock(lines, start) {
|
|
15183
|
+
let depth = 0;
|
|
15184
|
+
let i = start;
|
|
15185
|
+
let foundBrace = false;
|
|
15186
|
+
while (i < lines.length) {
|
|
15187
|
+
for (const ch of lines[i]) {
|
|
15188
|
+
if (ch === "{") {
|
|
15189
|
+
depth++;
|
|
15190
|
+
foundBrace = true;
|
|
15191
|
+
}
|
|
15192
|
+
if (ch === "}") depth--;
|
|
15193
|
+
}
|
|
15194
|
+
i++;
|
|
15195
|
+
if (foundBrace && depth <= 0) break;
|
|
15196
|
+
if (!foundBrace && lines[i - 1].includes(";")) break;
|
|
15197
|
+
}
|
|
15198
|
+
return i;
|
|
15199
|
+
}
|
|
15200
|
+
function looksLikeFunctionDecl(lines, start) {
|
|
15201
|
+
const chunk = lines.slice(start, Math.min(start + 5, lines.length)).join(" ");
|
|
15202
|
+
return /=>/.test(chunk) || /=\s*function/.test(chunk);
|
|
15203
|
+
}
|
|
15204
|
+
function extractClassOutline(lines, start) {
|
|
15205
|
+
const header = lines[start].trim();
|
|
15206
|
+
let headerText = header;
|
|
15207
|
+
let i = start + 1;
|
|
15208
|
+
if (!header.includes("{")) {
|
|
15209
|
+
while (i < lines.length) {
|
|
15210
|
+
headerText += " " + lines[i].trim();
|
|
15211
|
+
if (lines[i].includes("{")) {
|
|
15212
|
+
i++;
|
|
15213
|
+
break;
|
|
15214
|
+
}
|
|
15215
|
+
i++;
|
|
15216
|
+
}
|
|
15217
|
+
} else {
|
|
15218
|
+
i = start + 1;
|
|
15219
|
+
}
|
|
15220
|
+
const bodyParts = [headerText.replace(/\{[^]*$/, "{").trim()];
|
|
15221
|
+
let depth = 1;
|
|
15222
|
+
while (i < lines.length && depth > 0) {
|
|
15223
|
+
const line = lines[i];
|
|
15224
|
+
const trimmed = line.trim();
|
|
15225
|
+
for (const ch of line) {
|
|
15226
|
+
if (ch === "{") depth++;
|
|
15227
|
+
if (ch === "}") depth--;
|
|
15228
|
+
}
|
|
15229
|
+
if (depth <= 0) {
|
|
15230
|
+
i++;
|
|
15231
|
+
break;
|
|
15232
|
+
}
|
|
15233
|
+
if (depth === 1) {
|
|
15234
|
+
if (/^(private|protected|public|readonly|static|#)/.test(trimmed) && !trimmed.includes("(")) {
|
|
15235
|
+
bodyParts.push(` ${trimmed}`);
|
|
15236
|
+
} else if (/^constructor\s*\(/.test(trimmed)) {
|
|
15237
|
+
const sig = extractFnSignature(lines, i);
|
|
15238
|
+
bodyParts.push(` ${sig} { /* ... */ }`);
|
|
15239
|
+
} else if (/^(?:static\s+)?(?:async\s+)?(?:get\s+|set\s+)?\w+\s*[(<]/.test(trimmed) && !trimmed.startsWith("//")) {
|
|
15240
|
+
const sig = extractFnSignature(lines, i);
|
|
15241
|
+
bodyParts.push(` ${sig} { /* ... */ }`);
|
|
15242
|
+
}
|
|
15243
|
+
}
|
|
15244
|
+
i++;
|
|
15245
|
+
}
|
|
15246
|
+
bodyParts.push("}");
|
|
15247
|
+
return { text: bodyParts.join("\n"), nextIndex: i };
|
|
15248
|
+
}
|
|
15114
15249
|
async function pruneGeneric(file2, level) {
|
|
15115
15250
|
let content;
|
|
15116
15251
|
try {
|
|
@@ -15171,22 +15306,6 @@ function emptyResult(file2, level) {
|
|
|
15171
15306
|
savingsPercent: 100
|
|
15172
15307
|
};
|
|
15173
15308
|
}
|
|
15174
|
-
function addJSDoc(node, parts) {
|
|
15175
|
-
if (!node.getJsDocs) return;
|
|
15176
|
-
const docs = node.getJsDocs();
|
|
15177
|
-
if (docs.length > 0) {
|
|
15178
|
-
parts.push(docs[0].getText());
|
|
15179
|
-
}
|
|
15180
|
-
}
|
|
15181
|
-
function findTsConfig(filePath) {
|
|
15182
|
-
let dir = filePath;
|
|
15183
|
-
for (let i = 0; i < 10; i++) {
|
|
15184
|
-
dir = join5(dir, "..");
|
|
15185
|
-
const candidate = join5(dir, "tsconfig.json");
|
|
15186
|
-
if (existsSync3(candidate)) return candidate;
|
|
15187
|
-
}
|
|
15188
|
-
return void 0;
|
|
15189
|
-
}
|
|
15190
15309
|
|
|
15191
15310
|
// src/engine/graph-utils.ts
|
|
15192
15311
|
function buildAdjacencyList(edges) {
|
|
@@ -16951,24 +17070,24 @@ function fmt2(n) {
|
|
|
16951
17070
|
|
|
16952
17071
|
// src/engine/config.ts
|
|
16953
17072
|
import { readFile as readFile6, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
16954
|
-
import { join as
|
|
16955
|
-
import { existsSync as
|
|
17073
|
+
import { join as join5 } from "path";
|
|
17074
|
+
import { existsSync as existsSync3 } from "fs";
|
|
16956
17075
|
import { parse as parseYAML, stringify as stringifyYAML } from "yaml";
|
|
16957
17076
|
var CONFIG_DIR = ".cto";
|
|
16958
17077
|
var CONFIG_FILE = "config.yml";
|
|
16959
17078
|
var POLICY_FILE = "policy.yml";
|
|
16960
17079
|
function getConfigPath(projectPath) {
|
|
16961
|
-
return
|
|
17080
|
+
return join5(projectPath, CONFIG_DIR, CONFIG_FILE);
|
|
16962
17081
|
}
|
|
16963
17082
|
function getPolicyPath(projectPath) {
|
|
16964
|
-
return
|
|
17083
|
+
return join5(projectPath, CONFIG_DIR, POLICY_FILE);
|
|
16965
17084
|
}
|
|
16966
17085
|
function getCTODir(projectPath) {
|
|
16967
|
-
return
|
|
17086
|
+
return join5(projectPath, CONFIG_DIR);
|
|
16968
17087
|
}
|
|
16969
17088
|
async function loadConfig(projectPath) {
|
|
16970
17089
|
const configPath = getConfigPath(projectPath);
|
|
16971
|
-
if (!
|
|
17090
|
+
if (!existsSync3(configPath)) {
|
|
16972
17091
|
return { ...DEFAULT_CONFIG };
|
|
16973
17092
|
}
|
|
16974
17093
|
try {
|
|
@@ -16989,15 +17108,15 @@ async function saveConfig(projectPath, config2) {
|
|
|
16989
17108
|
}
|
|
16990
17109
|
async function initProjectConfig(projectPath) {
|
|
16991
17110
|
const ctoDir = getCTODir(projectPath);
|
|
16992
|
-
await mkdir(
|
|
17111
|
+
await mkdir(join5(ctoDir, "snapshots"), { recursive: true });
|
|
16993
17112
|
const created = [];
|
|
16994
17113
|
const configPath = getConfigPath(projectPath);
|
|
16995
|
-
if (!
|
|
17114
|
+
if (!existsSync3(configPath)) {
|
|
16996
17115
|
await saveConfig(projectPath, DEFAULT_CONFIG);
|
|
16997
17116
|
created.push(configPath);
|
|
16998
17117
|
}
|
|
16999
17118
|
const policyPath = getPolicyPath(projectPath);
|
|
17000
|
-
if (!
|
|
17119
|
+
if (!existsSync3(policyPath)) {
|
|
17001
17120
|
const defaultPolicy = {
|
|
17002
17121
|
version: "1.0",
|
|
17003
17122
|
name: "default",
|
|
@@ -17047,7 +17166,7 @@ async function initProjectConfig(projectPath) {
|
|
|
17047
17166
|
}
|
|
17048
17167
|
async function loadPolicyFromYAML(projectPath) {
|
|
17049
17168
|
const policyPath = getPolicyPath(projectPath);
|
|
17050
|
-
if (!
|
|
17169
|
+
if (!existsSync3(policyPath)) return null;
|
|
17051
17170
|
try {
|
|
17052
17171
|
const raw = await readFile6(policyPath, "utf-8");
|
|
17053
17172
|
return parseYAML(raw);
|
|
@@ -17117,18 +17236,18 @@ function formatCost(cost) {
|
|
|
17117
17236
|
// src/govern/audit.ts
|
|
17118
17237
|
import { randomUUID, createHash as createHash5 } from "crypto";
|
|
17119
17238
|
import { readdir as readdir3, chmod } from "fs/promises";
|
|
17120
|
-
import { join as
|
|
17239
|
+
import { join as join6 } from "path";
|
|
17121
17240
|
import { userInfo } from "os";
|
|
17122
17241
|
import { homedir } from "os";
|
|
17123
17242
|
var CTO_DIR = ".cto-ai";
|
|
17124
17243
|
var AUDIT_DIR = "audit";
|
|
17125
17244
|
var MAX_ENTRIES_PER_FILE = 500;
|
|
17126
17245
|
function getAuditDir() {
|
|
17127
|
-
return
|
|
17246
|
+
return join6(homedir(), CTO_DIR, AUDIT_DIR);
|
|
17128
17247
|
}
|
|
17129
17248
|
function getCurrentAuditFile() {
|
|
17130
17249
|
const date5 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0].replace(/-/g, "");
|
|
17131
|
-
return
|
|
17250
|
+
return join6(getAuditDir(), `audit_${date5}.json`);
|
|
17132
17251
|
}
|
|
17133
17252
|
function computeIntegrityHash(entry) {
|
|
17134
17253
|
const payload = JSON.stringify({
|
|
@@ -17156,7 +17275,7 @@ async function readJSON(filePath) {
|
|
|
17156
17275
|
}
|
|
17157
17276
|
async function writeJSON(filePath, data) {
|
|
17158
17277
|
const { writeFile: writeFile4 } = await import("fs/promises");
|
|
17159
|
-
await ensureDir(
|
|
17278
|
+
await ensureDir(join6(filePath, ".."));
|
|
17160
17279
|
await writeFile4(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
17161
17280
|
}
|
|
17162
17281
|
async function logAudit(action, projectPath, details = {}) {
|
|
@@ -17206,7 +17325,7 @@ async function getAuditEntries(options = {}) {
|
|
|
17206
17325
|
const limit = options.limit ?? 100;
|
|
17207
17326
|
for (const file2 of auditFiles) {
|
|
17208
17327
|
if (allEntries.length >= limit) break;
|
|
17209
|
-
const entries = await readJSON(
|
|
17328
|
+
const entries = await readJSON(join6(auditDir, file2));
|
|
17210
17329
|
if (!entries) continue;
|
|
17211
17330
|
for (const entry of entries.reverse()) {
|
|
17212
17331
|
if (allEntries.length >= limit) break;
|
|
@@ -17556,7 +17675,7 @@ function hashString(input) {
|
|
|
17556
17675
|
// src/mcp/v2.ts
|
|
17557
17676
|
var SNAPSHOTS_DIR = ".cto/snapshots";
|
|
17558
17677
|
async function loadSnapshotFile(projectPath, name) {
|
|
17559
|
-
const filePath =
|
|
17678
|
+
const filePath = join7(projectPath, SNAPSHOTS_DIR, `${name}.json`);
|
|
17560
17679
|
const content = await readFile8(filePath, "utf-8");
|
|
17561
17680
|
return JSON.parse(content);
|
|
17562
17681
|
}
|
|
@@ -17960,9 +18079,9 @@ server.tool(
|
|
|
17960
18079
|
budget: budget ?? config2.interaction.defaultBudget,
|
|
17961
18080
|
createdBy: process.env.USER ?? "unknown"
|
|
17962
18081
|
});
|
|
17963
|
-
const dir =
|
|
18082
|
+
const dir = join7(absPath, SNAPSHOTS_DIR);
|
|
17964
18083
|
await mkdir2(dir, { recursive: true });
|
|
17965
|
-
const filePath =
|
|
18084
|
+
const filePath = join7(dir, `${name}.json`);
|
|
17966
18085
|
await writeFile3(filePath, JSON.stringify(snapshot, null, 2), "utf-8");
|
|
17967
18086
|
return {
|
|
17968
18087
|
content: [{
|