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/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 join8 } from "path";
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 files = [];
14373
- for (const entry of walkEntries) {
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
- files.push({
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
- let project;
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 extractSignaturesAST(sf) {
14974
+ function extractSignaturesRegex(content) {
14975
+ const lines = content.split("\n");
14990
14976
  const parts = [];
14991
- for (const imp of sf.getImportDeclarations()) {
14992
- parts.push(imp.getText());
14993
- }
14994
- if (parts.length > 0) parts.push("");
14995
- for (const ta of sf.getTypeAliases()) {
14996
- addJSDoc(ta, parts);
14997
- parts.push(ta.getText());
14998
- }
14999
- for (const iface of sf.getInterfaces()) {
15000
- addJSDoc(iface, parts);
15001
- parts.push(iface.getText());
15002
- }
15003
- for (const en of sf.getEnums()) {
15004
- addJSDoc(en, parts);
15005
- parts.push(en.getText());
15006
- }
15007
- for (const fn of sf.getFunctions()) {
15008
- addJSDoc(fn, parts);
15009
- const isExported = fn.isExported();
15010
- const isAsync = fn.isAsync();
15011
- const name = fn.getName() ?? "<anonymous>";
15012
- const params = fn.getParameters().map((p) => p.getText()).join(", ");
15013
- const returnType = fn.getReturnTypeNode()?.getText();
15014
- const returnStr = returnType ? `: ${returnType}` : "";
15015
- const prefix = isExported ? "export " : "";
15016
- const asyncStr = isAsync ? "async " : "";
15017
- parts.push(`${prefix}${asyncStr}function ${name}(${params})${returnStr} { /* ... */ }`);
15018
- }
15019
- for (const stmt of sf.getVariableStatements()) {
15020
- for (const decl of stmt.getDeclarations()) {
15021
- const init = decl.getInitializer();
15022
- if (init && (init.getKind() === SyntaxKind2.ArrowFunction || init.getKind() === SyntaxKind2.FunctionExpression)) {
15023
- addJSDoc(stmt, parts);
15024
- const isExported = stmt.isExported();
15025
- const prefix = isExported ? "export " : "";
15026
- const kind = stmt.getDeclarationKind();
15027
- const name = decl.getName();
15028
- const typeNode = decl.getTypeNode()?.getText();
15029
- const typeStr = typeNode ? `: ${typeNode}` : "";
15030
- parts.push(`${prefix}${kind} ${name}${typeStr} = /* ... */;`);
15031
- } else {
15032
- addJSDoc(stmt, parts);
15033
- parts.push(stmt.getText());
15034
- }
15035
- }
15036
- }
15037
- for (const cls of sf.getClasses()) {
15038
- addJSDoc(cls, parts);
15039
- const isExported = cls.isExported();
15040
- const prefix = isExported ? "export " : "";
15041
- const name = cls.getName() ?? "<anonymous>";
15042
- const ext = cls.getExtends()?.getText();
15043
- const impl = cls.getImplements().map((i) => i.getText()).join(", ");
15044
- let header = `${prefix}class ${name}`;
15045
- if (ext) header += ` extends ${ext}`;
15046
- if (impl) header += ` implements ${impl}`;
15047
- header += " {";
15048
- parts.push(header);
15049
- for (const prop of cls.getProperties()) {
15050
- parts.push(` ${prop.getText()}`);
15051
- }
15052
- const ctor = cls.getConstructors()[0];
15053
- if (ctor) {
15054
- const ctorParams = ctor.getParameters().map((p) => p.getText()).join(", ");
15055
- parts.push(` constructor(${ctorParams}) { /* ... */ }`);
15056
- }
15057
- for (const method of cls.getMethods()) {
15058
- const isStatic = method.isStatic();
15059
- const isAsync = method.isAsync();
15060
- const methodName = method.getName();
15061
- const methodParams = method.getParameters().map((p) => p.getText()).join(", ");
15062
- const returnType = method.getReturnTypeNode()?.getText();
15063
- const returnStr = returnType ? `: ${returnType}` : "";
15064
- const staticStr = isStatic ? "static " : "";
15065
- const asyncStr = isAsync ? "async " : "";
15066
- parts.push(` ${staticStr}${asyncStr}${methodName}(${methodParams})${returnStr} { /* ... */ }`);
15067
- }
15068
- parts.push("}");
15069
- }
15070
- for (const exp of sf.getExportDeclarations()) {
15071
- parts.push(exp.getText());
15072
- }
15073
- for (const exp of sf.getExportAssignments()) {
15074
- parts.push(exp.getText());
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 extractSkeletonAST(sf) {
15065
+ function extractSkeletonRegex(content) {
15066
+ const lines = content.split("\n");
15079
15067
  const parts = [];
15080
- for (const imp of sf.getImportDeclarations()) {
15081
- parts.push(imp.getText());
15082
- }
15083
- if (parts.length > 0) parts.push("");
15084
- for (const ta of sf.getTypeAliases()) {
15085
- if (ta.isExported()) parts.push(ta.getText());
15086
- }
15087
- for (const iface of sf.getInterfaces()) {
15088
- if (!iface.isExported()) continue;
15089
- const ext = iface.getExtends().map((e) => e.getText());
15090
- const extStr = ext.length > 0 ? ` extends ${ext.join(", ")}` : "";
15091
- parts.push(`export interface ${iface.getName()}${extStr} { /* ${iface.getProperties().length} props */ }`);
15092
- }
15093
- for (const en of sf.getEnums()) {
15094
- if (!en.isExported()) continue;
15095
- const members = en.getMembers().map((m) => m.getName());
15096
- parts.push(`export enum ${en.getName()} { ${members.join(", ")} }`);
15097
- }
15098
- for (const fn of sf.getFunctions()) {
15099
- if (!fn.isExported()) continue;
15100
- const name = fn.getName() ?? "<anonymous>";
15101
- const params = fn.getParameters().map((p) => p.getText()).join(", ");
15102
- parts.push(`export function ${name}(${params});`);
15103
- }
15104
- for (const cls of sf.getClasses()) {
15105
- if (!cls.isExported()) continue;
15106
- const methods = cls.getMethods().map((m) => m.getName());
15107
- parts.push(`export class ${cls.getName()} { /* methods: ${methods.join(", ")} */ }`);
15108
- }
15109
- for (const exp of sf.getExportDeclarations()) {
15110
- parts.push(exp.getText());
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 join6 } from "path";
16955
- import { existsSync as existsSync4 } from "fs";
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 join6(projectPath, CONFIG_DIR, CONFIG_FILE);
17080
+ return join5(projectPath, CONFIG_DIR, CONFIG_FILE);
16962
17081
  }
16963
17082
  function getPolicyPath(projectPath) {
16964
- return join6(projectPath, CONFIG_DIR, POLICY_FILE);
17083
+ return join5(projectPath, CONFIG_DIR, POLICY_FILE);
16965
17084
  }
16966
17085
  function getCTODir(projectPath) {
16967
- return join6(projectPath, CONFIG_DIR);
17086
+ return join5(projectPath, CONFIG_DIR);
16968
17087
  }
16969
17088
  async function loadConfig(projectPath) {
16970
17089
  const configPath = getConfigPath(projectPath);
16971
- if (!existsSync4(configPath)) {
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(join6(ctoDir, "snapshots"), { recursive: true });
17111
+ await mkdir(join5(ctoDir, "snapshots"), { recursive: true });
16993
17112
  const created = [];
16994
17113
  const configPath = getConfigPath(projectPath);
16995
- if (!existsSync4(configPath)) {
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 (!existsSync4(policyPath)) {
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 (!existsSync4(policyPath)) return null;
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 join7 } from "path";
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 join7(homedir(), CTO_DIR, AUDIT_DIR);
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 join7(getAuditDir(), `audit_${date5}.json`);
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(join7(filePath, ".."));
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(join7(auditDir, file2));
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 = join8(projectPath, SNAPSHOTS_DIR, `${name}.json`);
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 = join8(absPath, SNAPSHOTS_DIR);
18082
+ const dir = join7(absPath, SNAPSHOTS_DIR);
17964
18083
  await mkdir2(dir, { recursive: true });
17965
- const filePath = join8(dir, `${name}.json`);
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: [{