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/interact/index.js
CHANGED
|
@@ -207,10 +207,7 @@ function deduplicateFindings(findings) {
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
// src/engine/pruner.ts
|
|
210
|
-
import { Project, SyntaxKind } from "ts-morph";
|
|
211
210
|
import { readFile as readFile3 } from "fs/promises";
|
|
212
|
-
import { existsSync as existsSync2 } from "fs";
|
|
213
|
-
import { join as join2 } from "path";
|
|
214
211
|
|
|
215
212
|
// src/engine/tokenizer.ts
|
|
216
213
|
import { encodingForModel } from "js-tiktoken";
|
|
@@ -243,23 +240,7 @@ async function pruneTypeScript(file, level) {
|
|
|
243
240
|
} catch {
|
|
244
241
|
return emptyResult(file, level);
|
|
245
242
|
}
|
|
246
|
-
|
|
247
|
-
try {
|
|
248
|
-
const tsConfigPath = findTsConfig(file.path);
|
|
249
|
-
project = new Project({
|
|
250
|
-
tsConfigFilePath: tsConfigPath,
|
|
251
|
-
skipAddingFilesFromTsConfig: true,
|
|
252
|
-
compilerOptions: tsConfigPath ? void 0 : { allowJs: true, esModuleInterop: true }
|
|
253
|
-
});
|
|
254
|
-
project.createSourceFile(file.path, content, { overwrite: true });
|
|
255
|
-
} catch {
|
|
256
|
-
return pruneGenericFromContent(file, content, level);
|
|
257
|
-
}
|
|
258
|
-
const sourceFile = project.getSourceFiles()[0];
|
|
259
|
-
if (!sourceFile) {
|
|
260
|
-
return pruneGenericFromContent(file, content, level);
|
|
261
|
-
}
|
|
262
|
-
const prunedContent = level === "signatures" ? extractSignaturesAST(sourceFile) : extractSkeletonAST(sourceFile);
|
|
243
|
+
const prunedContent = level === "signatures" ? extractSignaturesRegex(content) : extractSkeletonRegex(content);
|
|
263
244
|
const prunedTokens = countTokensChars4(Buffer.byteLength(prunedContent, "utf-8"));
|
|
264
245
|
const savingsPercent = file.tokens > 0 ? (file.tokens - prunedTokens) / file.tokens * 100 : 0;
|
|
265
246
|
return {
|
|
@@ -271,130 +252,280 @@ async function pruneTypeScript(file, level) {
|
|
|
271
252
|
savingsPercent: Math.max(0, savingsPercent)
|
|
272
253
|
};
|
|
273
254
|
}
|
|
274
|
-
function
|
|
255
|
+
function extractSignaturesRegex(content) {
|
|
256
|
+
const lines = content.split("\n");
|
|
275
257
|
const parts = [];
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
addJSDoc(fn, parts);
|
|
294
|
-
const isExported = fn.isExported();
|
|
295
|
-
const isAsync = fn.isAsync();
|
|
296
|
-
const name = fn.getName() ?? "<anonymous>";
|
|
297
|
-
const params = fn.getParameters().map((p) => p.getText()).join(", ");
|
|
298
|
-
const returnType = fn.getReturnTypeNode()?.getText();
|
|
299
|
-
const returnStr = returnType ? `: ${returnType}` : "";
|
|
300
|
-
const prefix = isExported ? "export " : "";
|
|
301
|
-
const asyncStr = isAsync ? "async " : "";
|
|
302
|
-
parts.push(`${prefix}${asyncStr}function ${name}(${params})${returnStr} { /* ... */ }`);
|
|
303
|
-
}
|
|
304
|
-
for (const stmt of sf.getVariableStatements()) {
|
|
305
|
-
for (const decl of stmt.getDeclarations()) {
|
|
306
|
-
const init = decl.getInitializer();
|
|
307
|
-
if (init && (init.getKind() === SyntaxKind.ArrowFunction || init.getKind() === SyntaxKind.FunctionExpression)) {
|
|
308
|
-
addJSDoc(stmt, parts);
|
|
309
|
-
const isExported = stmt.isExported();
|
|
310
|
-
const prefix = isExported ? "export " : "";
|
|
311
|
-
const kind = stmt.getDeclarationKind();
|
|
312
|
-
const name = decl.getName();
|
|
313
|
-
const typeNode = decl.getTypeNode()?.getText();
|
|
314
|
-
const typeStr = typeNode ? `: ${typeNode}` : "";
|
|
315
|
-
parts.push(`${prefix}${kind} ${name}${typeStr} = /* ... */;`);
|
|
316
|
-
} else {
|
|
317
|
-
addJSDoc(stmt, parts);
|
|
318
|
-
parts.push(stmt.getText());
|
|
258
|
+
let i = 0;
|
|
259
|
+
while (i < lines.length) {
|
|
260
|
+
const line = lines[i];
|
|
261
|
+
const trimmed = line.trim();
|
|
262
|
+
if (trimmed === "") {
|
|
263
|
+
i++;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (trimmed.startsWith("/**")) {
|
|
267
|
+
const docLines = [];
|
|
268
|
+
while (i < lines.length) {
|
|
269
|
+
docLines.push(lines[i]);
|
|
270
|
+
if (lines[i].includes("*/")) {
|
|
271
|
+
i++;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
i++;
|
|
319
275
|
}
|
|
276
|
+
parts.push(docLines.join("\n"));
|
|
277
|
+
continue;
|
|
320
278
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const prefix = isExported ? "export " : "";
|
|
326
|
-
const name = cls.getName() ?? "<anonymous>";
|
|
327
|
-
const ext = cls.getExtends()?.getText();
|
|
328
|
-
const impl = cls.getImplements().map((i) => i.getText()).join(", ");
|
|
329
|
-
let header = `${prefix}class ${name}`;
|
|
330
|
-
if (ext) header += ` extends ${ext}`;
|
|
331
|
-
if (impl) header += ` implements ${impl}`;
|
|
332
|
-
header += " {";
|
|
333
|
-
parts.push(header);
|
|
334
|
-
for (const prop of cls.getProperties()) {
|
|
335
|
-
parts.push(` ${prop.getText()}`);
|
|
279
|
+
if (trimmed.startsWith("//")) {
|
|
280
|
+
parts.push(line);
|
|
281
|
+
i++;
|
|
282
|
+
continue;
|
|
336
283
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
284
|
+
if (/^\s*(import|export)\s/.test(line) && (trimmed.includes(" from ") || trimmed.startsWith("import "))) {
|
|
285
|
+
const block = collectBracedLine(lines, i);
|
|
286
|
+
parts.push(block.text);
|
|
287
|
+
i = block.nextIndex;
|
|
288
|
+
continue;
|
|
341
289
|
}
|
|
342
|
-
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const returnType = method.getReturnTypeNode()?.getText();
|
|
348
|
-
const returnStr = returnType ? `: ${returnType}` : "";
|
|
349
|
-
const staticStr = isStatic ? "static " : "";
|
|
350
|
-
const asyncStr = isAsync ? "async " : "";
|
|
351
|
-
parts.push(` ${staticStr}${asyncStr}${methodName}(${methodParams})${returnStr} { /* ... */ }`);
|
|
290
|
+
if (/^\s*export\s*(\{|\*)/.test(trimmed)) {
|
|
291
|
+
const block = collectBracedLine(lines, i);
|
|
292
|
+
parts.push(block.text);
|
|
293
|
+
i = block.nextIndex;
|
|
294
|
+
continue;
|
|
352
295
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
296
|
+
if (/^\s*(export\s+)?type\s+\w/.test(trimmed) && !trimmed.startsWith("typeof")) {
|
|
297
|
+
const block = collectBalanced(lines, i);
|
|
298
|
+
parts.push(block.text);
|
|
299
|
+
i = block.nextIndex;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (/^\s*(export\s+)?interface\s+\w/.test(trimmed)) {
|
|
303
|
+
const block = collectBalanced(lines, i);
|
|
304
|
+
parts.push(block.text);
|
|
305
|
+
i = block.nextIndex;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (/^\s*(export\s+)?(const\s+)?enum\s+\w/.test(trimmed)) {
|
|
309
|
+
const block = collectBalanced(lines, i);
|
|
310
|
+
parts.push(block.text);
|
|
311
|
+
i = block.nextIndex;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
const fnMatch = trimmed.match(/^(export\s+)?(async\s+)?function\s+(\w+)/);
|
|
315
|
+
if (fnMatch) {
|
|
316
|
+
const sig = extractFnSignature(lines, i);
|
|
317
|
+
parts.push(`${sig} { /* ... */ }`);
|
|
318
|
+
i = skipBlock(lines, i);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
const arrowMatch = trimmed.match(/^(export\s+)?(const|let|var)\s+(\w+)/);
|
|
322
|
+
if (arrowMatch && looksLikeFunctionDecl(lines, i)) {
|
|
323
|
+
const prefix = trimmed.match(/^((?:export\s+)?(?:const|let|var)\s+\w+[^=]*=)/)?.[1];
|
|
324
|
+
if (prefix) {
|
|
325
|
+
parts.push(`${prefix} /* ... */;`);
|
|
326
|
+
}
|
|
327
|
+
i = skipBlock(lines, i);
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (arrowMatch) {
|
|
331
|
+
const block = collectStatement(lines, i);
|
|
332
|
+
parts.push(block.text);
|
|
333
|
+
i = block.nextIndex;
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (/^\s*(export\s+)?(abstract\s+)?class\s+\w/.test(trimmed)) {
|
|
337
|
+
const classOutline = extractClassOutline(lines, i);
|
|
338
|
+
parts.push(classOutline.text);
|
|
339
|
+
i = classOutline.nextIndex;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
i++;
|
|
360
343
|
}
|
|
361
344
|
return parts.join("\n");
|
|
362
345
|
}
|
|
363
|
-
function
|
|
346
|
+
function extractSkeletonRegex(content) {
|
|
347
|
+
const lines = content.split("\n");
|
|
364
348
|
const parts = [];
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
349
|
+
let i = 0;
|
|
350
|
+
while (i < lines.length) {
|
|
351
|
+
const trimmed = lines[i].trim();
|
|
352
|
+
if (/^import\s/.test(trimmed)) {
|
|
353
|
+
const block = collectBracedLine(lines, i);
|
|
354
|
+
parts.push(block.text);
|
|
355
|
+
i = block.nextIndex;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (/^export\s+(type|interface)\s+\w/.test(trimmed)) {
|
|
359
|
+
const block = collectBalanced(lines, i);
|
|
360
|
+
parts.push(block.text);
|
|
361
|
+
i = block.nextIndex;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (/^export\s+(const\s+)?enum\s+\w/.test(trimmed)) {
|
|
365
|
+
const block = collectBalanced(lines, i);
|
|
366
|
+
parts.push(block.text);
|
|
367
|
+
i = block.nextIndex;
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
if (/^export\s+(async\s+)?function\s+\w/.test(trimmed)) {
|
|
371
|
+
const sig = extractFnSignature(lines, i);
|
|
372
|
+
parts.push(`${sig};`);
|
|
373
|
+
i = skipBlock(lines, i);
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
if (/^export\s+(abstract\s+)?class\s+/.test(trimmed)) {
|
|
377
|
+
const nameMatch = trimmed.match(/class\s+(\w+)/);
|
|
378
|
+
const name = nameMatch?.[1] ?? "Unknown";
|
|
379
|
+
const end = skipBlock(lines, i);
|
|
380
|
+
const methods = [];
|
|
381
|
+
for (let j = i + 1; j < end; j++) {
|
|
382
|
+
const mt = lines[j].trim();
|
|
383
|
+
const mm = mt.match(/^(?:static\s+)?(?:async\s+)?(\w+)\s*\(/);
|
|
384
|
+
if (mm && mm[1] !== "constructor") methods.push(mm[1]);
|
|
385
|
+
}
|
|
386
|
+
parts.push(`export class ${name} { /* methods: ${methods.join(", ")} */ }`);
|
|
387
|
+
i = end;
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
if (/^export\s*(\{|\*)/.test(trimmed)) {
|
|
391
|
+
const block = collectBracedLine(lines, i);
|
|
392
|
+
parts.push(block.text);
|
|
393
|
+
i = block.nextIndex;
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
i++;
|
|
371
397
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
398
|
+
return parts.join("\n");
|
|
399
|
+
}
|
|
400
|
+
function collectBracedLine(lines, start) {
|
|
401
|
+
let text = lines[start];
|
|
402
|
+
let i = start + 1;
|
|
403
|
+
while (i < lines.length && !text.includes(";") && !text.trimEnd().endsWith("'") && !text.trimEnd().endsWith('"')) {
|
|
404
|
+
text += "\n" + lines[i];
|
|
405
|
+
i++;
|
|
406
|
+
}
|
|
407
|
+
return { text, nextIndex: i };
|
|
408
|
+
}
|
|
409
|
+
function collectBalanced(lines, start) {
|
|
410
|
+
let depth = 0;
|
|
411
|
+
let text = "";
|
|
412
|
+
let i = start;
|
|
413
|
+
let started = false;
|
|
414
|
+
while (i < lines.length) {
|
|
415
|
+
const line = lines[i];
|
|
416
|
+
text += (text ? "\n" : "") + line;
|
|
417
|
+
for (const ch of line) {
|
|
418
|
+
if (ch === "{" || ch === "(") {
|
|
419
|
+
depth++;
|
|
420
|
+
started = true;
|
|
421
|
+
}
|
|
422
|
+
if (ch === "}" || ch === ")") depth--;
|
|
423
|
+
}
|
|
424
|
+
i++;
|
|
425
|
+
if (started && depth <= 0) break;
|
|
426
|
+
if (!started && line.includes(";")) break;
|
|
377
427
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
428
|
+
return { text, nextIndex: i };
|
|
429
|
+
}
|
|
430
|
+
function collectStatement(lines, start) {
|
|
431
|
+
let text = lines[start];
|
|
432
|
+
let i = start + 1;
|
|
433
|
+
if (text.includes(";")) return { text, nextIndex: i };
|
|
434
|
+
let depth = 0;
|
|
435
|
+
for (const ch of text) {
|
|
436
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
437
|
+
if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
438
|
+
}
|
|
439
|
+
while (i < lines.length && depth > 0) {
|
|
440
|
+
text += "\n" + lines[i];
|
|
441
|
+
for (const ch of lines[i]) {
|
|
442
|
+
if (ch === "{" || ch === "(" || ch === "[") depth++;
|
|
443
|
+
if (ch === "}" || ch === ")" || ch === "]") depth--;
|
|
444
|
+
}
|
|
445
|
+
i++;
|
|
382
446
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
447
|
+
return { text, nextIndex: i };
|
|
448
|
+
}
|
|
449
|
+
function extractFnSignature(lines, start) {
|
|
450
|
+
let sig = "";
|
|
451
|
+
let i = start;
|
|
452
|
+
while (i < lines.length) {
|
|
453
|
+
const line = lines[i].trim();
|
|
454
|
+
sig += (sig ? " " : "") + line;
|
|
455
|
+
if (line.includes("{")) {
|
|
456
|
+
sig = sig.replace(/\s*\{[^]*$/, "").trim();
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
i++;
|
|
388
460
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
461
|
+
return sig;
|
|
462
|
+
}
|
|
463
|
+
function skipBlock(lines, start) {
|
|
464
|
+
let depth = 0;
|
|
465
|
+
let i = start;
|
|
466
|
+
let foundBrace = false;
|
|
467
|
+
while (i < lines.length) {
|
|
468
|
+
for (const ch of lines[i]) {
|
|
469
|
+
if (ch === "{") {
|
|
470
|
+
depth++;
|
|
471
|
+
foundBrace = true;
|
|
472
|
+
}
|
|
473
|
+
if (ch === "}") depth--;
|
|
474
|
+
}
|
|
475
|
+
i++;
|
|
476
|
+
if (foundBrace && depth <= 0) break;
|
|
477
|
+
if (!foundBrace && lines[i - 1].includes(";")) break;
|
|
393
478
|
}
|
|
394
|
-
|
|
395
|
-
|
|
479
|
+
return i;
|
|
480
|
+
}
|
|
481
|
+
function looksLikeFunctionDecl(lines, start) {
|
|
482
|
+
const chunk = lines.slice(start, Math.min(start + 5, lines.length)).join(" ");
|
|
483
|
+
return /=>/.test(chunk) || /=\s*function/.test(chunk);
|
|
484
|
+
}
|
|
485
|
+
function extractClassOutline(lines, start) {
|
|
486
|
+
const header = lines[start].trim();
|
|
487
|
+
let headerText = header;
|
|
488
|
+
let i = start + 1;
|
|
489
|
+
if (!header.includes("{")) {
|
|
490
|
+
while (i < lines.length) {
|
|
491
|
+
headerText += " " + lines[i].trim();
|
|
492
|
+
if (lines[i].includes("{")) {
|
|
493
|
+
i++;
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
i++;
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
499
|
+
i = start + 1;
|
|
500
|
+
}
|
|
501
|
+
const bodyParts = [headerText.replace(/\{[^]*$/, "{").trim()];
|
|
502
|
+
let depth = 1;
|
|
503
|
+
while (i < lines.length && depth > 0) {
|
|
504
|
+
const line = lines[i];
|
|
505
|
+
const trimmed = line.trim();
|
|
506
|
+
for (const ch of line) {
|
|
507
|
+
if (ch === "{") depth++;
|
|
508
|
+
if (ch === "}") depth--;
|
|
509
|
+
}
|
|
510
|
+
if (depth <= 0) {
|
|
511
|
+
i++;
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
if (depth === 1) {
|
|
515
|
+
if (/^(private|protected|public|readonly|static|#)/.test(trimmed) && !trimmed.includes("(")) {
|
|
516
|
+
bodyParts.push(` ${trimmed}`);
|
|
517
|
+
} else if (/^constructor\s*\(/.test(trimmed)) {
|
|
518
|
+
const sig = extractFnSignature(lines, i);
|
|
519
|
+
bodyParts.push(` ${sig} { /* ... */ }`);
|
|
520
|
+
} else if (/^(?:static\s+)?(?:async\s+)?(?:get\s+|set\s+)?\w+\s*[(<]/.test(trimmed) && !trimmed.startsWith("//")) {
|
|
521
|
+
const sig = extractFnSignature(lines, i);
|
|
522
|
+
bodyParts.push(` ${sig} { /* ... */ }`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
i++;
|
|
396
526
|
}
|
|
397
|
-
|
|
527
|
+
bodyParts.push("}");
|
|
528
|
+
return { text: bodyParts.join("\n"), nextIndex: i };
|
|
398
529
|
}
|
|
399
530
|
async function pruneGeneric(file, level) {
|
|
400
531
|
let content;
|
|
@@ -456,22 +587,6 @@ function emptyResult(file, level) {
|
|
|
456
587
|
savingsPercent: 100
|
|
457
588
|
};
|
|
458
589
|
}
|
|
459
|
-
function addJSDoc(node, parts) {
|
|
460
|
-
if (!node.getJsDocs) return;
|
|
461
|
-
const docs = node.getJsDocs();
|
|
462
|
-
if (docs.length > 0) {
|
|
463
|
-
parts.push(docs[0].getText());
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
function findTsConfig(filePath) {
|
|
467
|
-
let dir = filePath;
|
|
468
|
-
for (let i = 0; i < 10; i++) {
|
|
469
|
-
dir = join2(dir, "..");
|
|
470
|
-
const candidate = join2(dir, "tsconfig.json");
|
|
471
|
-
if (existsSync2(candidate)) return candidate;
|
|
472
|
-
}
|
|
473
|
-
return void 0;
|
|
474
|
-
}
|
|
475
590
|
|
|
476
591
|
// src/engine/graph-utils.ts
|
|
477
592
|
function buildAdjacencyList(edges) {
|
|
@@ -1230,18 +1345,18 @@ function makeSection(id, role, content) {
|
|
|
1230
1345
|
// src/govern/audit.ts
|
|
1231
1346
|
import { randomUUID, createHash as createHash3 } from "crypto";
|
|
1232
1347
|
import { readdir, chmod } from "fs/promises";
|
|
1233
|
-
import { join as
|
|
1348
|
+
import { join as join2 } from "path";
|
|
1234
1349
|
import { userInfo } from "os";
|
|
1235
1350
|
import { homedir } from "os";
|
|
1236
1351
|
var CTO_DIR = ".cto-ai";
|
|
1237
1352
|
var AUDIT_DIR = "audit";
|
|
1238
1353
|
var MAX_ENTRIES_PER_FILE = 500;
|
|
1239
1354
|
function getAuditDir() {
|
|
1240
|
-
return
|
|
1355
|
+
return join2(homedir(), CTO_DIR, AUDIT_DIR);
|
|
1241
1356
|
}
|
|
1242
1357
|
function getCurrentAuditFile() {
|
|
1243
1358
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0].replace(/-/g, "");
|
|
1244
|
-
return
|
|
1359
|
+
return join2(getAuditDir(), `audit_${date}.json`);
|
|
1245
1360
|
}
|
|
1246
1361
|
function computeIntegrityHash(entry) {
|
|
1247
1362
|
const payload = JSON.stringify({
|
|
@@ -1269,7 +1384,7 @@ async function readJSON(filePath) {
|
|
|
1269
1384
|
}
|
|
1270
1385
|
async function writeJSON(filePath, data) {
|
|
1271
1386
|
const { writeFile: writeFile2 } = await import("fs/promises");
|
|
1272
|
-
await ensureDir(
|
|
1387
|
+
await ensureDir(join2(filePath, ".."));
|
|
1273
1388
|
await writeFile2(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
1274
1389
|
}
|
|
1275
1390
|
async function logAudit(action, projectPath, details = {}) {
|