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/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
|
|
@@ -14932,10 +14932,7 @@ function deduplicateFindings(findings) {
|
|
|
14932
14932
|
}
|
|
14933
14933
|
|
|
14934
14934
|
// src/engine/pruner.ts
|
|
14935
|
-
import { Project as Project2, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
14936
14935
|
import { readFile as readFile4 } from "fs/promises";
|
|
14937
|
-
import { existsSync as existsSync3 } from "fs";
|
|
14938
|
-
import { join as join5 } from "path";
|
|
14939
14936
|
var TS_EXTENSIONS2 = /* @__PURE__ */ new Set(["ts", "tsx", "js", "jsx", "mts", "mjs"]);
|
|
14940
14937
|
async function pruneFile(file2, level) {
|
|
14941
14938
|
if (level === "excluded") {
|
|
@@ -14958,23 +14955,7 @@ async function pruneTypeScript(file2, level) {
|
|
|
14958
14955
|
} catch {
|
|
14959
14956
|
return emptyResult(file2, level);
|
|
14960
14957
|
}
|
|
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);
|
|
14958
|
+
const prunedContent = level === "signatures" ? extractSignaturesRegex(content) : extractSkeletonRegex(content);
|
|
14978
14959
|
const prunedTokens = countTokensChars4(Buffer.byteLength(prunedContent, "utf-8"));
|
|
14979
14960
|
const savingsPercent = file2.tokens > 0 ? (file2.tokens - prunedTokens) / file2.tokens * 100 : 0;
|
|
14980
14961
|
return {
|
|
@@ -14986,131 +14967,281 @@ async function pruneTypeScript(file2, level) {
|
|
|
14986
14967
|
savingsPercent: Math.max(0, savingsPercent)
|
|
14987
14968
|
};
|
|
14988
14969
|
}
|
|
14989
|
-
function
|
|
14970
|
+
function extractSignaturesRegex(content) {
|
|
14971
|
+
const lines = content.split("\n");
|
|
14990
14972
|
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
|
-
|
|
14973
|
+
let i = 0;
|
|
14974
|
+
while (i < lines.length) {
|
|
14975
|
+
const line = lines[i];
|
|
14976
|
+
const trimmed = line.trim();
|
|
14977
|
+
if (trimmed === "") {
|
|
14978
|
+
i++;
|
|
14979
|
+
continue;
|
|
14980
|
+
}
|
|
14981
|
+
if (trimmed.startsWith("/**")) {
|
|
14982
|
+
const docLines = [];
|
|
14983
|
+
while (i < lines.length) {
|
|
14984
|
+
docLines.push(lines[i]);
|
|
14985
|
+
if (lines[i].includes("*/")) {
|
|
14986
|
+
i++;
|
|
14987
|
+
break;
|
|
14988
|
+
}
|
|
14989
|
+
i++;
|
|
14990
|
+
}
|
|
14991
|
+
parts.push(docLines.join("\n"));
|
|
14992
|
+
continue;
|
|
14993
|
+
}
|
|
14994
|
+
if (trimmed.startsWith("//")) {
|
|
14995
|
+
parts.push(line);
|
|
14996
|
+
i++;
|
|
14997
|
+
continue;
|
|
14998
|
+
}
|
|
14999
|
+
if (/^\s*(import|export)\s/.test(line) && (trimmed.includes(" from ") || trimmed.startsWith("import "))) {
|
|
15000
|
+
const block = collectBracedLine(lines, i);
|
|
15001
|
+
parts.push(block.text);
|
|
15002
|
+
i = block.nextIndex;
|
|
15003
|
+
continue;
|
|
15004
|
+
}
|
|
15005
|
+
if (/^\s*export\s*(\{|\*)/.test(trimmed)) {
|
|
15006
|
+
const block = collectBracedLine(lines, i);
|
|
15007
|
+
parts.push(block.text);
|
|
15008
|
+
i = block.nextIndex;
|
|
15009
|
+
continue;
|
|
15010
|
+
}
|
|
15011
|
+
if (/^\s*(export\s+)?type\s+\w/.test(trimmed) && !trimmed.startsWith("typeof")) {
|
|
15012
|
+
const block = collectBalanced(lines, i);
|
|
15013
|
+
parts.push(block.text);
|
|
15014
|
+
i = block.nextIndex;
|
|
15015
|
+
continue;
|
|
15016
|
+
}
|
|
15017
|
+
if (/^\s*(export\s+)?interface\s+\w/.test(trimmed)) {
|
|
15018
|
+
const block = collectBalanced(lines, i);
|
|
15019
|
+
parts.push(block.text);
|
|
15020
|
+
i = block.nextIndex;
|
|
15021
|
+
continue;
|
|
15022
|
+
}
|
|
15023
|
+
if (/^\s*(export\s+)?(const\s+)?enum\s+\w/.test(trimmed)) {
|
|
15024
|
+
const block = collectBalanced(lines, i);
|
|
15025
|
+
parts.push(block.text);
|
|
15026
|
+
i = block.nextIndex;
|
|
15027
|
+
continue;
|
|
15028
|
+
}
|
|
15029
|
+
const fnMatch = trimmed.match(/^(export\s+)?(async\s+)?function\s+(\w+)/);
|
|
15030
|
+
if (fnMatch) {
|
|
15031
|
+
const sig = extractFnSignature(lines, i);
|
|
15032
|
+
parts.push(`${sig} { /* ... */ }`);
|
|
15033
|
+
i = skipBlock(lines, i);
|
|
15034
|
+
continue;
|
|
15035
|
+
}
|
|
15036
|
+
const arrowMatch = trimmed.match(/^(export\s+)?(const|let|var)\s+(\w+)/);
|
|
15037
|
+
if (arrowMatch && looksLikeFunctionDecl(lines, i)) {
|
|
15038
|
+
const prefix = trimmed.match(/^((?:export\s+)?(?:const|let|var)\s+\w+[^=]*=)/)?.[1];
|
|
15039
|
+
if (prefix) {
|
|
15040
|
+
parts.push(`${prefix} /* ... */;`);
|
|
15041
|
+
}
|
|
15042
|
+
i = skipBlock(lines, i);
|
|
15043
|
+
continue;
|
|
15044
|
+
}
|
|
15045
|
+
if (arrowMatch) {
|
|
15046
|
+
const block = collectStatement(lines, i);
|
|
15047
|
+
parts.push(block.text);
|
|
15048
|
+
i = block.nextIndex;
|
|
15049
|
+
continue;
|
|
15050
|
+
}
|
|
15051
|
+
if (/^\s*(export\s+)?(abstract\s+)?class\s+\w/.test(trimmed)) {
|
|
15052
|
+
const classOutline = extractClassOutline(lines, i);
|
|
15053
|
+
parts.push(classOutline.text);
|
|
15054
|
+
i = classOutline.nextIndex;
|
|
15055
|
+
continue;
|
|
15056
|
+
}
|
|
15057
|
+
i++;
|
|
15075
15058
|
}
|
|
15076
15059
|
return parts.join("\n");
|
|
15077
15060
|
}
|
|
15078
|
-
function
|
|
15061
|
+
function extractSkeletonRegex(content) {
|
|
15062
|
+
const lines = content.split("\n");
|
|
15079
15063
|
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
|
-
|
|
15064
|
+
let i = 0;
|
|
15065
|
+
while (i < lines.length) {
|
|
15066
|
+
const trimmed = lines[i].trim();
|
|
15067
|
+
if (/^import\s/.test(trimmed)) {
|
|
15068
|
+
const block = collectBracedLine(lines, i);
|
|
15069
|
+
parts.push(block.text);
|
|
15070
|
+
i = block.nextIndex;
|
|
15071
|
+
continue;
|
|
15072
|
+
}
|
|
15073
|
+
if (/^export\s+(type|interface)\s+\w/.test(trimmed)) {
|
|
15074
|
+
const block = collectBalanced(lines, i);
|
|
15075
|
+
parts.push(block.text);
|
|
15076
|
+
i = block.nextIndex;
|
|
15077
|
+
continue;
|
|
15078
|
+
}
|
|
15079
|
+
if (/^export\s+(const\s+)?enum\s+\w/.test(trimmed)) {
|
|
15080
|
+
const block = collectBalanced(lines, i);
|
|
15081
|
+
parts.push(block.text);
|
|
15082
|
+
i = block.nextIndex;
|
|
15083
|
+
continue;
|
|
15084
|
+
}
|
|
15085
|
+
if (/^export\s+(async\s+)?function\s+\w/.test(trimmed)) {
|
|
15086
|
+
const sig = extractFnSignature(lines, i);
|
|
15087
|
+
parts.push(`${sig};`);
|
|
15088
|
+
i = skipBlock(lines, i);
|
|
15089
|
+
continue;
|
|
15090
|
+
}
|
|
15091
|
+
if (/^export\s+(abstract\s+)?class\s+/.test(trimmed)) {
|
|
15092
|
+
const nameMatch = trimmed.match(/class\s+(\w+)/);
|
|
15093
|
+
const name = nameMatch?.[1] ?? "Unknown";
|
|
15094
|
+
const end = skipBlock(lines, i);
|
|
15095
|
+
const methods = [];
|
|
15096
|
+
for (let j = i + 1; j < end; j++) {
|
|
15097
|
+
const mt = lines[j].trim();
|
|
15098
|
+
const mm = mt.match(/^(?:static\s+)?(?:async\s+)?(\w+)\s*\(/);
|
|
15099
|
+
if (mm && mm[1] !== "constructor") methods.push(mm[1]);
|
|
15100
|
+
}
|
|
15101
|
+
parts.push(`export class ${name} { /* methods: ${methods.join(", ")} */ }`);
|
|
15102
|
+
i = end;
|
|
15103
|
+
continue;
|
|
15104
|
+
}
|
|
15105
|
+
if (/^export\s*(\{|\*)/.test(trimmed)) {
|
|
15106
|
+
const block = collectBracedLine(lines, i);
|
|
15107
|
+
parts.push(block.text);
|
|
15108
|
+
i = block.nextIndex;
|
|
15109
|
+
continue;
|
|
15110
|
+
}
|
|
15111
|
+
i++;
|
|
15111
15112
|
}
|
|
15112
15113
|
return parts.join("\n");
|
|
15113
15114
|
}
|
|
15115
|
+
function collectBracedLine(lines, start) {
|
|
15116
|
+
let text = lines[start];
|
|
15117
|
+
let i = start + 1;
|
|
15118
|
+
while (i < lines.length && !text.includes(";") && !text.trimEnd().endsWith("'") && !text.trimEnd().endsWith('"')) {
|
|
15119
|
+
text += "\n" + lines[i];
|
|
15120
|
+
i++;
|
|
15121
|
+
}
|
|
15122
|
+
return { text, nextIndex: i };
|
|
15123
|
+
}
|
|
15124
|
+
function collectBalanced(lines, start) {
|
|
15125
|
+
let depth = 0;
|
|
15126
|
+
let text = "";
|
|
15127
|
+
let i = start;
|
|
15128
|
+
let started = false;
|
|
15129
|
+
while (i < lines.length) {
|
|
15130
|
+
const line = lines[i];
|
|
15131
|
+
text += (text ? "\n" : "") + line;
|
|
15132
|
+
for (const ch of line) {
|
|
15133
|
+
if (ch === "{" || ch === "(") {
|
|
15134
|
+
depth++;
|
|
15135
|
+
started = true;
|
|
15136
|
+
}
|
|
15137
|
+
if (ch === "}" || ch === ")") depth--;
|
|
15138
|
+
}
|
|
15139
|
+
i++;
|
|
15140
|
+
if (started && depth <= 0) break;
|
|
15141
|
+
if (!started && line.includes(";")) break;
|
|
15142
|
+
}
|
|
15143
|
+
return { text, nextIndex: i };
|
|
15144
|
+
}
|
|
15145
|
+
function collectStatement(lines, start) {
|
|
15146
|
+
let text = lines[start];
|
|
15147
|
+
let i = start + 1;
|
|
15148
|
+
if (text.includes(";")) return { text, nextIndex: i };
|
|
15149
|
+
let depth = 0;
|
|
15150
|
+
for (const ch of text) {
|
|
15151
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
15152
|
+
if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
15153
|
+
}
|
|
15154
|
+
while (i < lines.length && depth > 0) {
|
|
15155
|
+
text += "\n" + lines[i];
|
|
15156
|
+
for (const ch of lines[i]) {
|
|
15157
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
15158
|
+
if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
15159
|
+
}
|
|
15160
|
+
i++;
|
|
15161
|
+
}
|
|
15162
|
+
return { text, nextIndex: i };
|
|
15163
|
+
}
|
|
15164
|
+
function extractFnSignature(lines, start) {
|
|
15165
|
+
let sig = "";
|
|
15166
|
+
let i = start;
|
|
15167
|
+
while (i < lines.length) {
|
|
15168
|
+
const line = lines[i].trim();
|
|
15169
|
+
sig += (sig ? " " : "") + line;
|
|
15170
|
+
if (line.includes("{")) {
|
|
15171
|
+
sig = sig.replace(/\s*\{[^]*$/, "").trim();
|
|
15172
|
+
break;
|
|
15173
|
+
}
|
|
15174
|
+
i++;
|
|
15175
|
+
}
|
|
15176
|
+
return sig;
|
|
15177
|
+
}
|
|
15178
|
+
function skipBlock(lines, start) {
|
|
15179
|
+
let depth = 0;
|
|
15180
|
+
let i = start;
|
|
15181
|
+
let foundBrace = false;
|
|
15182
|
+
while (i < lines.length) {
|
|
15183
|
+
for (const ch of lines[i]) {
|
|
15184
|
+
if (ch === "{") {
|
|
15185
|
+
depth++;
|
|
15186
|
+
foundBrace = true;
|
|
15187
|
+
}
|
|
15188
|
+
if (ch === "}") depth--;
|
|
15189
|
+
}
|
|
15190
|
+
i++;
|
|
15191
|
+
if (foundBrace && depth <= 0) break;
|
|
15192
|
+
if (!foundBrace && lines[i - 1].includes(";")) break;
|
|
15193
|
+
}
|
|
15194
|
+
return i;
|
|
15195
|
+
}
|
|
15196
|
+
function looksLikeFunctionDecl(lines, start) {
|
|
15197
|
+
const chunk = lines.slice(start, Math.min(start + 5, lines.length)).join(" ");
|
|
15198
|
+
return /=>/.test(chunk) || /=\s*function/.test(chunk);
|
|
15199
|
+
}
|
|
15200
|
+
function extractClassOutline(lines, start) {
|
|
15201
|
+
const header = lines[start].trim();
|
|
15202
|
+
let headerText = header;
|
|
15203
|
+
let i = start + 1;
|
|
15204
|
+
if (!header.includes("{")) {
|
|
15205
|
+
while (i < lines.length) {
|
|
15206
|
+
headerText += " " + lines[i].trim();
|
|
15207
|
+
if (lines[i].includes("{")) {
|
|
15208
|
+
i++;
|
|
15209
|
+
break;
|
|
15210
|
+
}
|
|
15211
|
+
i++;
|
|
15212
|
+
}
|
|
15213
|
+
} else {
|
|
15214
|
+
i = start + 1;
|
|
15215
|
+
}
|
|
15216
|
+
const bodyParts = [headerText.replace(/\{[^]*$/, "{").trim()];
|
|
15217
|
+
let depth = 1;
|
|
15218
|
+
while (i < lines.length && depth > 0) {
|
|
15219
|
+
const line = lines[i];
|
|
15220
|
+
const trimmed = line.trim();
|
|
15221
|
+
for (const ch of line) {
|
|
15222
|
+
if (ch === "{") depth++;
|
|
15223
|
+
if (ch === "}") depth--;
|
|
15224
|
+
}
|
|
15225
|
+
if (depth <= 0) {
|
|
15226
|
+
i++;
|
|
15227
|
+
break;
|
|
15228
|
+
}
|
|
15229
|
+
if (depth === 1) {
|
|
15230
|
+
if (/^(private|protected|public|readonly|static|#)/.test(trimmed) && !trimmed.includes("(")) {
|
|
15231
|
+
bodyParts.push(` ${trimmed}`);
|
|
15232
|
+
} else if (/^constructor\s*\(/.test(trimmed)) {
|
|
15233
|
+
const sig = extractFnSignature(lines, i);
|
|
15234
|
+
bodyParts.push(` ${sig} { /* ... */ }`);
|
|
15235
|
+
} else if (/^(?:static\s+)?(?:async\s+)?(?:get\s+|set\s+)?\w+\s*[(<]/.test(trimmed) && !trimmed.startsWith("//")) {
|
|
15236
|
+
const sig = extractFnSignature(lines, i);
|
|
15237
|
+
bodyParts.push(` ${sig} { /* ... */ }`);
|
|
15238
|
+
}
|
|
15239
|
+
}
|
|
15240
|
+
i++;
|
|
15241
|
+
}
|
|
15242
|
+
bodyParts.push("}");
|
|
15243
|
+
return { text: bodyParts.join("\n"), nextIndex: i };
|
|
15244
|
+
}
|
|
15114
15245
|
async function pruneGeneric(file2, level) {
|
|
15115
15246
|
let content;
|
|
15116
15247
|
try {
|
|
@@ -15171,22 +15302,6 @@ function emptyResult(file2, level) {
|
|
|
15171
15302
|
savingsPercent: 100
|
|
15172
15303
|
};
|
|
15173
15304
|
}
|
|
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
15305
|
|
|
15191
15306
|
// src/engine/graph-utils.ts
|
|
15192
15307
|
function buildAdjacencyList(edges) {
|
|
@@ -16951,24 +17066,24 @@ function fmt2(n) {
|
|
|
16951
17066
|
|
|
16952
17067
|
// src/engine/config.ts
|
|
16953
17068
|
import { readFile as readFile6, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
16954
|
-
import { join as
|
|
16955
|
-
import { existsSync as
|
|
17069
|
+
import { join as join5 } from "path";
|
|
17070
|
+
import { existsSync as existsSync3 } from "fs";
|
|
16956
17071
|
import { parse as parseYAML, stringify as stringifyYAML } from "yaml";
|
|
16957
17072
|
var CONFIG_DIR = ".cto";
|
|
16958
17073
|
var CONFIG_FILE = "config.yml";
|
|
16959
17074
|
var POLICY_FILE = "policy.yml";
|
|
16960
17075
|
function getConfigPath(projectPath) {
|
|
16961
|
-
return
|
|
17076
|
+
return join5(projectPath, CONFIG_DIR, CONFIG_FILE);
|
|
16962
17077
|
}
|
|
16963
17078
|
function getPolicyPath(projectPath) {
|
|
16964
|
-
return
|
|
17079
|
+
return join5(projectPath, CONFIG_DIR, POLICY_FILE);
|
|
16965
17080
|
}
|
|
16966
17081
|
function getCTODir(projectPath) {
|
|
16967
|
-
return
|
|
17082
|
+
return join5(projectPath, CONFIG_DIR);
|
|
16968
17083
|
}
|
|
16969
17084
|
async function loadConfig(projectPath) {
|
|
16970
17085
|
const configPath = getConfigPath(projectPath);
|
|
16971
|
-
if (!
|
|
17086
|
+
if (!existsSync3(configPath)) {
|
|
16972
17087
|
return { ...DEFAULT_CONFIG };
|
|
16973
17088
|
}
|
|
16974
17089
|
try {
|
|
@@ -16989,15 +17104,15 @@ async function saveConfig(projectPath, config2) {
|
|
|
16989
17104
|
}
|
|
16990
17105
|
async function initProjectConfig(projectPath) {
|
|
16991
17106
|
const ctoDir = getCTODir(projectPath);
|
|
16992
|
-
await mkdir(
|
|
17107
|
+
await mkdir(join5(ctoDir, "snapshots"), { recursive: true });
|
|
16993
17108
|
const created = [];
|
|
16994
17109
|
const configPath = getConfigPath(projectPath);
|
|
16995
|
-
if (!
|
|
17110
|
+
if (!existsSync3(configPath)) {
|
|
16996
17111
|
await saveConfig(projectPath, DEFAULT_CONFIG);
|
|
16997
17112
|
created.push(configPath);
|
|
16998
17113
|
}
|
|
16999
17114
|
const policyPath = getPolicyPath(projectPath);
|
|
17000
|
-
if (!
|
|
17115
|
+
if (!existsSync3(policyPath)) {
|
|
17001
17116
|
const defaultPolicy = {
|
|
17002
17117
|
version: "1.0",
|
|
17003
17118
|
name: "default",
|
|
@@ -17047,7 +17162,7 @@ async function initProjectConfig(projectPath) {
|
|
|
17047
17162
|
}
|
|
17048
17163
|
async function loadPolicyFromYAML(projectPath) {
|
|
17049
17164
|
const policyPath = getPolicyPath(projectPath);
|
|
17050
|
-
if (!
|
|
17165
|
+
if (!existsSync3(policyPath)) return null;
|
|
17051
17166
|
try {
|
|
17052
17167
|
const raw = await readFile6(policyPath, "utf-8");
|
|
17053
17168
|
return parseYAML(raw);
|
|
@@ -17117,18 +17232,18 @@ function formatCost(cost) {
|
|
|
17117
17232
|
// src/govern/audit.ts
|
|
17118
17233
|
import { randomUUID, createHash as createHash5 } from "crypto";
|
|
17119
17234
|
import { readdir as readdir3, chmod } from "fs/promises";
|
|
17120
|
-
import { join as
|
|
17235
|
+
import { join as join6 } from "path";
|
|
17121
17236
|
import { userInfo } from "os";
|
|
17122
17237
|
import { homedir } from "os";
|
|
17123
17238
|
var CTO_DIR = ".cto-ai";
|
|
17124
17239
|
var AUDIT_DIR = "audit";
|
|
17125
17240
|
var MAX_ENTRIES_PER_FILE = 500;
|
|
17126
17241
|
function getAuditDir() {
|
|
17127
|
-
return
|
|
17242
|
+
return join6(homedir(), CTO_DIR, AUDIT_DIR);
|
|
17128
17243
|
}
|
|
17129
17244
|
function getCurrentAuditFile() {
|
|
17130
17245
|
const date5 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0].replace(/-/g, "");
|
|
17131
|
-
return
|
|
17246
|
+
return join6(getAuditDir(), `audit_${date5}.json`);
|
|
17132
17247
|
}
|
|
17133
17248
|
function computeIntegrityHash(entry) {
|
|
17134
17249
|
const payload = JSON.stringify({
|
|
@@ -17156,7 +17271,7 @@ async function readJSON(filePath) {
|
|
|
17156
17271
|
}
|
|
17157
17272
|
async function writeJSON(filePath, data) {
|
|
17158
17273
|
const { writeFile: writeFile4 } = await import("fs/promises");
|
|
17159
|
-
await ensureDir(
|
|
17274
|
+
await ensureDir(join6(filePath, ".."));
|
|
17160
17275
|
await writeFile4(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
17161
17276
|
}
|
|
17162
17277
|
async function logAudit(action, projectPath, details = {}) {
|
|
@@ -17206,7 +17321,7 @@ async function getAuditEntries(options = {}) {
|
|
|
17206
17321
|
const limit = options.limit ?? 100;
|
|
17207
17322
|
for (const file2 of auditFiles) {
|
|
17208
17323
|
if (allEntries.length >= limit) break;
|
|
17209
|
-
const entries = await readJSON(
|
|
17324
|
+
const entries = await readJSON(join6(auditDir, file2));
|
|
17210
17325
|
if (!entries) continue;
|
|
17211
17326
|
for (const entry of entries.reverse()) {
|
|
17212
17327
|
if (allEntries.length >= limit) break;
|
|
@@ -17556,7 +17671,7 @@ function hashString(input) {
|
|
|
17556
17671
|
// src/mcp/v2.ts
|
|
17557
17672
|
var SNAPSHOTS_DIR = ".cto/snapshots";
|
|
17558
17673
|
async function loadSnapshotFile(projectPath, name) {
|
|
17559
|
-
const filePath =
|
|
17674
|
+
const filePath = join7(projectPath, SNAPSHOTS_DIR, `${name}.json`);
|
|
17560
17675
|
const content = await readFile8(filePath, "utf-8");
|
|
17561
17676
|
return JSON.parse(content);
|
|
17562
17677
|
}
|
|
@@ -17960,9 +18075,9 @@ server.tool(
|
|
|
17960
18075
|
budget: budget ?? config2.interaction.defaultBudget,
|
|
17961
18076
|
createdBy: process.env.USER ?? "unknown"
|
|
17962
18077
|
});
|
|
17963
|
-
const dir =
|
|
18078
|
+
const dir = join7(absPath, SNAPSHOTS_DIR);
|
|
17964
18079
|
await mkdir2(dir, { recursive: true });
|
|
17965
|
-
const filePath =
|
|
18080
|
+
const filePath = join7(dir, `${name}.json`);
|
|
17966
18081
|
await writeFile3(filePath, JSON.stringify(snapshot, null, 2), "utf-8");
|
|
17967
18082
|
return {
|
|
17968
18083
|
content: [{
|