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.
@@ -935,7 +935,7 @@ var analyzeCommand = new Command2("analyze").description("Analyze project struct
935
935
  // src/cli/v2/interact.ts
936
936
  import { Command as Command3 } from "commander";
937
937
  import chalk3 from "chalk";
938
- import { resolve as resolve8, join as join9 } from "path";
938
+ import { resolve as resolve8, join as join8 } from "path";
939
939
  import { writeFile as writeFile4 } from "fs/promises";
940
940
 
941
941
  // src/engine/cache.ts
@@ -1512,10 +1512,7 @@ function deduplicateFindings(findings) {
1512
1512
  }
1513
1513
 
1514
1514
  // src/engine/pruner.ts
1515
- import { Project as Project2, SyntaxKind as SyntaxKind2 } from "ts-morph";
1516
1515
  import { readFile as readFile5 } from "fs/promises";
1517
- import { existsSync as existsSync4 } from "fs";
1518
- import { join as join7 } from "path";
1519
1516
  var TS_EXTENSIONS2 = /* @__PURE__ */ new Set(["ts", "tsx", "js", "jsx", "mts", "mjs"]);
1520
1517
  async function pruneFile(file, level) {
1521
1518
  if (level === "excluded") {
@@ -1538,23 +1535,7 @@ async function pruneTypeScript(file, level) {
1538
1535
  } catch {
1539
1536
  return emptyResult2(file, level);
1540
1537
  }
1541
- let project;
1542
- try {
1543
- const tsConfigPath = findTsConfig(file.path);
1544
- project = new Project2({
1545
- tsConfigFilePath: tsConfigPath,
1546
- skipAddingFilesFromTsConfig: true,
1547
- compilerOptions: tsConfigPath ? void 0 : { allowJs: true, esModuleInterop: true }
1548
- });
1549
- project.createSourceFile(file.path, content, { overwrite: true });
1550
- } catch {
1551
- return pruneGenericFromContent(file, content, level);
1552
- }
1553
- const sourceFile = project.getSourceFiles()[0];
1554
- if (!sourceFile) {
1555
- return pruneGenericFromContent(file, content, level);
1556
- }
1557
- const prunedContent = level === "signatures" ? extractSignaturesAST(sourceFile) : extractSkeletonAST(sourceFile);
1538
+ const prunedContent = level === "signatures" ? extractSignaturesRegex(content) : extractSkeletonRegex(content);
1558
1539
  const prunedTokens = countTokensChars4(Buffer.byteLength(prunedContent, "utf-8"));
1559
1540
  const savingsPercent = file.tokens > 0 ? (file.tokens - prunedTokens) / file.tokens * 100 : 0;
1560
1541
  return {
@@ -1566,131 +1547,281 @@ async function pruneTypeScript(file, level) {
1566
1547
  savingsPercent: Math.max(0, savingsPercent)
1567
1548
  };
1568
1549
  }
1569
- function extractSignaturesAST(sf) {
1550
+ function extractSignaturesRegex(content) {
1551
+ const lines = content.split("\n");
1570
1552
  const parts = [];
1571
- for (const imp of sf.getImportDeclarations()) {
1572
- parts.push(imp.getText());
1573
- }
1574
- if (parts.length > 0) parts.push("");
1575
- for (const ta of sf.getTypeAliases()) {
1576
- addJSDoc(ta, parts);
1577
- parts.push(ta.getText());
1578
- }
1579
- for (const iface of sf.getInterfaces()) {
1580
- addJSDoc(iface, parts);
1581
- parts.push(iface.getText());
1582
- }
1583
- for (const en of sf.getEnums()) {
1584
- addJSDoc(en, parts);
1585
- parts.push(en.getText());
1586
- }
1587
- for (const fn of sf.getFunctions()) {
1588
- addJSDoc(fn, parts);
1589
- const isExported = fn.isExported();
1590
- const isAsync = fn.isAsync();
1591
- const name = fn.getName() ?? "<anonymous>";
1592
- const params = fn.getParameters().map((p) => p.getText()).join(", ");
1593
- const returnType = fn.getReturnTypeNode()?.getText();
1594
- const returnStr = returnType ? `: ${returnType}` : "";
1595
- const prefix = isExported ? "export " : "";
1596
- const asyncStr = isAsync ? "async " : "";
1597
- parts.push(`${prefix}${asyncStr}function ${name}(${params})${returnStr} { /* ... */ }`);
1598
- }
1599
- for (const stmt of sf.getVariableStatements()) {
1600
- for (const decl of stmt.getDeclarations()) {
1601
- const init = decl.getInitializer();
1602
- if (init && (init.getKind() === SyntaxKind2.ArrowFunction || init.getKind() === SyntaxKind2.FunctionExpression)) {
1603
- addJSDoc(stmt, parts);
1604
- const isExported = stmt.isExported();
1605
- const prefix = isExported ? "export " : "";
1606
- const kind = stmt.getDeclarationKind();
1607
- const name = decl.getName();
1608
- const typeNode = decl.getTypeNode()?.getText();
1609
- const typeStr = typeNode ? `: ${typeNode}` : "";
1610
- parts.push(`${prefix}${kind} ${name}${typeStr} = /* ... */;`);
1611
- } else {
1612
- addJSDoc(stmt, parts);
1613
- parts.push(stmt.getText());
1614
- }
1615
- }
1616
- }
1617
- for (const cls of sf.getClasses()) {
1618
- addJSDoc(cls, parts);
1619
- const isExported = cls.isExported();
1620
- const prefix = isExported ? "export " : "";
1621
- const name = cls.getName() ?? "<anonymous>";
1622
- const ext = cls.getExtends()?.getText();
1623
- const impl = cls.getImplements().map((i) => i.getText()).join(", ");
1624
- let header = `${prefix}class ${name}`;
1625
- if (ext) header += ` extends ${ext}`;
1626
- if (impl) header += ` implements ${impl}`;
1627
- header += " {";
1628
- parts.push(header);
1629
- for (const prop of cls.getProperties()) {
1630
- parts.push(` ${prop.getText()}`);
1631
- }
1632
- const ctor = cls.getConstructors()[0];
1633
- if (ctor) {
1634
- const ctorParams = ctor.getParameters().map((p) => p.getText()).join(", ");
1635
- parts.push(` constructor(${ctorParams}) { /* ... */ }`);
1636
- }
1637
- for (const method of cls.getMethods()) {
1638
- const isStatic = method.isStatic();
1639
- const isAsync = method.isAsync();
1640
- const methodName = method.getName();
1641
- const methodParams = method.getParameters().map((p) => p.getText()).join(", ");
1642
- const returnType = method.getReturnTypeNode()?.getText();
1643
- const returnStr = returnType ? `: ${returnType}` : "";
1644
- const staticStr = isStatic ? "static " : "";
1645
- const asyncStr = isAsync ? "async " : "";
1646
- parts.push(` ${staticStr}${asyncStr}${methodName}(${methodParams})${returnStr} { /* ... */ }`);
1647
- }
1648
- parts.push("}");
1649
- }
1650
- for (const exp of sf.getExportDeclarations()) {
1651
- parts.push(exp.getText());
1652
- }
1653
- for (const exp of sf.getExportAssignments()) {
1654
- parts.push(exp.getText());
1553
+ let i = 0;
1554
+ while (i < lines.length) {
1555
+ const line = lines[i];
1556
+ const trimmed = line.trim();
1557
+ if (trimmed === "") {
1558
+ i++;
1559
+ continue;
1560
+ }
1561
+ if (trimmed.startsWith("/**")) {
1562
+ const docLines = [];
1563
+ while (i < lines.length) {
1564
+ docLines.push(lines[i]);
1565
+ if (lines[i].includes("*/")) {
1566
+ i++;
1567
+ break;
1568
+ }
1569
+ i++;
1570
+ }
1571
+ parts.push(docLines.join("\n"));
1572
+ continue;
1573
+ }
1574
+ if (trimmed.startsWith("//")) {
1575
+ parts.push(line);
1576
+ i++;
1577
+ continue;
1578
+ }
1579
+ if (/^\s*(import|export)\s/.test(line) && (trimmed.includes(" from ") || trimmed.startsWith("import "))) {
1580
+ const block = collectBracedLine(lines, i);
1581
+ parts.push(block.text);
1582
+ i = block.nextIndex;
1583
+ continue;
1584
+ }
1585
+ if (/^\s*export\s*(\{|\*)/.test(trimmed)) {
1586
+ const block = collectBracedLine(lines, i);
1587
+ parts.push(block.text);
1588
+ i = block.nextIndex;
1589
+ continue;
1590
+ }
1591
+ if (/^\s*(export\s+)?type\s+\w/.test(trimmed) && !trimmed.startsWith("typeof")) {
1592
+ const block = collectBalanced(lines, i);
1593
+ parts.push(block.text);
1594
+ i = block.nextIndex;
1595
+ continue;
1596
+ }
1597
+ if (/^\s*(export\s+)?interface\s+\w/.test(trimmed)) {
1598
+ const block = collectBalanced(lines, i);
1599
+ parts.push(block.text);
1600
+ i = block.nextIndex;
1601
+ continue;
1602
+ }
1603
+ if (/^\s*(export\s+)?(const\s+)?enum\s+\w/.test(trimmed)) {
1604
+ const block = collectBalanced(lines, i);
1605
+ parts.push(block.text);
1606
+ i = block.nextIndex;
1607
+ continue;
1608
+ }
1609
+ const fnMatch = trimmed.match(/^(export\s+)?(async\s+)?function\s+(\w+)/);
1610
+ if (fnMatch) {
1611
+ const sig = extractFnSignature(lines, i);
1612
+ parts.push(`${sig} { /* ... */ }`);
1613
+ i = skipBlock(lines, i);
1614
+ continue;
1615
+ }
1616
+ const arrowMatch = trimmed.match(/^(export\s+)?(const|let|var)\s+(\w+)/);
1617
+ if (arrowMatch && looksLikeFunctionDecl(lines, i)) {
1618
+ const prefix = trimmed.match(/^((?:export\s+)?(?:const|let|var)\s+\w+[^=]*=)/)?.[1];
1619
+ if (prefix) {
1620
+ parts.push(`${prefix} /* ... */;`);
1621
+ }
1622
+ i = skipBlock(lines, i);
1623
+ continue;
1624
+ }
1625
+ if (arrowMatch) {
1626
+ const block = collectStatement(lines, i);
1627
+ parts.push(block.text);
1628
+ i = block.nextIndex;
1629
+ continue;
1630
+ }
1631
+ if (/^\s*(export\s+)?(abstract\s+)?class\s+\w/.test(trimmed)) {
1632
+ const classOutline = extractClassOutline(lines, i);
1633
+ parts.push(classOutline.text);
1634
+ i = classOutline.nextIndex;
1635
+ continue;
1636
+ }
1637
+ i++;
1655
1638
  }
1656
1639
  return parts.join("\n");
1657
1640
  }
1658
- function extractSkeletonAST(sf) {
1641
+ function extractSkeletonRegex(content) {
1642
+ const lines = content.split("\n");
1659
1643
  const parts = [];
1660
- for (const imp of sf.getImportDeclarations()) {
1661
- parts.push(imp.getText());
1662
- }
1663
- if (parts.length > 0) parts.push("");
1664
- for (const ta of sf.getTypeAliases()) {
1665
- if (ta.isExported()) parts.push(ta.getText());
1666
- }
1667
- for (const iface of sf.getInterfaces()) {
1668
- if (!iface.isExported()) continue;
1669
- const ext = iface.getExtends().map((e) => e.getText());
1670
- const extStr = ext.length > 0 ? ` extends ${ext.join(", ")}` : "";
1671
- parts.push(`export interface ${iface.getName()}${extStr} { /* ${iface.getProperties().length} props */ }`);
1672
- }
1673
- for (const en of sf.getEnums()) {
1674
- if (!en.isExported()) continue;
1675
- const members = en.getMembers().map((m) => m.getName());
1676
- parts.push(`export enum ${en.getName()} { ${members.join(", ")} }`);
1677
- }
1678
- for (const fn of sf.getFunctions()) {
1679
- if (!fn.isExported()) continue;
1680
- const name = fn.getName() ?? "<anonymous>";
1681
- const params = fn.getParameters().map((p) => p.getText()).join(", ");
1682
- parts.push(`export function ${name}(${params});`);
1683
- }
1684
- for (const cls of sf.getClasses()) {
1685
- if (!cls.isExported()) continue;
1686
- const methods = cls.getMethods().map((m) => m.getName());
1687
- parts.push(`export class ${cls.getName()} { /* methods: ${methods.join(", ")} */ }`);
1688
- }
1689
- for (const exp of sf.getExportDeclarations()) {
1690
- parts.push(exp.getText());
1644
+ let i = 0;
1645
+ while (i < lines.length) {
1646
+ const trimmed = lines[i].trim();
1647
+ if (/^import\s/.test(trimmed)) {
1648
+ const block = collectBracedLine(lines, i);
1649
+ parts.push(block.text);
1650
+ i = block.nextIndex;
1651
+ continue;
1652
+ }
1653
+ if (/^export\s+(type|interface)\s+\w/.test(trimmed)) {
1654
+ const block = collectBalanced(lines, i);
1655
+ parts.push(block.text);
1656
+ i = block.nextIndex;
1657
+ continue;
1658
+ }
1659
+ if (/^export\s+(const\s+)?enum\s+\w/.test(trimmed)) {
1660
+ const block = collectBalanced(lines, i);
1661
+ parts.push(block.text);
1662
+ i = block.nextIndex;
1663
+ continue;
1664
+ }
1665
+ if (/^export\s+(async\s+)?function\s+\w/.test(trimmed)) {
1666
+ const sig = extractFnSignature(lines, i);
1667
+ parts.push(`${sig};`);
1668
+ i = skipBlock(lines, i);
1669
+ continue;
1670
+ }
1671
+ if (/^export\s+(abstract\s+)?class\s+/.test(trimmed)) {
1672
+ const nameMatch = trimmed.match(/class\s+(\w+)/);
1673
+ const name = nameMatch?.[1] ?? "Unknown";
1674
+ const end = skipBlock(lines, i);
1675
+ const methods = [];
1676
+ for (let j = i + 1; j < end; j++) {
1677
+ const mt = lines[j].trim();
1678
+ const mm = mt.match(/^(?:static\s+)?(?:async\s+)?(\w+)\s*\(/);
1679
+ if (mm && mm[1] !== "constructor") methods.push(mm[1]);
1680
+ }
1681
+ parts.push(`export class ${name} { /* methods: ${methods.join(", ")} */ }`);
1682
+ i = end;
1683
+ continue;
1684
+ }
1685
+ if (/^export\s*(\{|\*)/.test(trimmed)) {
1686
+ const block = collectBracedLine(lines, i);
1687
+ parts.push(block.text);
1688
+ i = block.nextIndex;
1689
+ continue;
1690
+ }
1691
+ i++;
1691
1692
  }
1692
1693
  return parts.join("\n");
1693
1694
  }
1695
+ function collectBracedLine(lines, start) {
1696
+ let text = lines[start];
1697
+ let i = start + 1;
1698
+ while (i < lines.length && !text.includes(";") && !text.trimEnd().endsWith("'") && !text.trimEnd().endsWith('"')) {
1699
+ text += "\n" + lines[i];
1700
+ i++;
1701
+ }
1702
+ return { text, nextIndex: i };
1703
+ }
1704
+ function collectBalanced(lines, start) {
1705
+ let depth = 0;
1706
+ let text = "";
1707
+ let i = start;
1708
+ let started = false;
1709
+ while (i < lines.length) {
1710
+ const line = lines[i];
1711
+ text += (text ? "\n" : "") + line;
1712
+ for (const ch of line) {
1713
+ if (ch === "{" || ch === "(") {
1714
+ depth++;
1715
+ started = true;
1716
+ }
1717
+ if (ch === "}" || ch === ")") depth--;
1718
+ }
1719
+ i++;
1720
+ if (started && depth <= 0) break;
1721
+ if (!started && line.includes(";")) break;
1722
+ }
1723
+ return { text, nextIndex: i };
1724
+ }
1725
+ function collectStatement(lines, start) {
1726
+ let text = lines[start];
1727
+ let i = start + 1;
1728
+ if (text.includes(";")) return { text, nextIndex: i };
1729
+ let depth = 0;
1730
+ for (const ch of text) {
1731
+ if (ch === "{" || ch === "(" || ch === "[") depth++;
1732
+ if (ch === "}" || ch === ")" || ch === "]") depth--;
1733
+ }
1734
+ while (i < lines.length && depth > 0) {
1735
+ text += "\n" + lines[i];
1736
+ for (const ch of lines[i]) {
1737
+ if (ch === "{" || ch === "(" || ch === "[") depth++;
1738
+ if (ch === "}" || ch === ")" || ch === "]") depth--;
1739
+ }
1740
+ i++;
1741
+ }
1742
+ return { text, nextIndex: i };
1743
+ }
1744
+ function extractFnSignature(lines, start) {
1745
+ let sig = "";
1746
+ let i = start;
1747
+ while (i < lines.length) {
1748
+ const line = lines[i].trim();
1749
+ sig += (sig ? " " : "") + line;
1750
+ if (line.includes("{")) {
1751
+ sig = sig.replace(/\s*\{[^]*$/, "").trim();
1752
+ break;
1753
+ }
1754
+ i++;
1755
+ }
1756
+ return sig;
1757
+ }
1758
+ function skipBlock(lines, start) {
1759
+ let depth = 0;
1760
+ let i = start;
1761
+ let foundBrace = false;
1762
+ while (i < lines.length) {
1763
+ for (const ch of lines[i]) {
1764
+ if (ch === "{") {
1765
+ depth++;
1766
+ foundBrace = true;
1767
+ }
1768
+ if (ch === "}") depth--;
1769
+ }
1770
+ i++;
1771
+ if (foundBrace && depth <= 0) break;
1772
+ if (!foundBrace && lines[i - 1].includes(";")) break;
1773
+ }
1774
+ return i;
1775
+ }
1776
+ function looksLikeFunctionDecl(lines, start) {
1777
+ const chunk = lines.slice(start, Math.min(start + 5, lines.length)).join(" ");
1778
+ return /=>/.test(chunk) || /=\s*function/.test(chunk);
1779
+ }
1780
+ function extractClassOutline(lines, start) {
1781
+ const header = lines[start].trim();
1782
+ let headerText = header;
1783
+ let i = start + 1;
1784
+ if (!header.includes("{")) {
1785
+ while (i < lines.length) {
1786
+ headerText += " " + lines[i].trim();
1787
+ if (lines[i].includes("{")) {
1788
+ i++;
1789
+ break;
1790
+ }
1791
+ i++;
1792
+ }
1793
+ } else {
1794
+ i = start + 1;
1795
+ }
1796
+ const bodyParts = [headerText.replace(/\{[^]*$/, "{").trim()];
1797
+ let depth = 1;
1798
+ while (i < lines.length && depth > 0) {
1799
+ const line = lines[i];
1800
+ const trimmed = line.trim();
1801
+ for (const ch of line) {
1802
+ if (ch === "{") depth++;
1803
+ if (ch === "}") depth--;
1804
+ }
1805
+ if (depth <= 0) {
1806
+ i++;
1807
+ break;
1808
+ }
1809
+ if (depth === 1) {
1810
+ if (/^(private|protected|public|readonly|static|#)/.test(trimmed) && !trimmed.includes("(")) {
1811
+ bodyParts.push(` ${trimmed}`);
1812
+ } else if (/^constructor\s*\(/.test(trimmed)) {
1813
+ const sig = extractFnSignature(lines, i);
1814
+ bodyParts.push(` ${sig} { /* ... */ }`);
1815
+ } else if (/^(?:static\s+)?(?:async\s+)?(?:get\s+|set\s+)?\w+\s*[(<]/.test(trimmed) && !trimmed.startsWith("//")) {
1816
+ const sig = extractFnSignature(lines, i);
1817
+ bodyParts.push(` ${sig} { /* ... */ }`);
1818
+ }
1819
+ }
1820
+ i++;
1821
+ }
1822
+ bodyParts.push("}");
1823
+ return { text: bodyParts.join("\n"), nextIndex: i };
1824
+ }
1694
1825
  async function pruneGeneric(file, level) {
1695
1826
  let content;
1696
1827
  try {
@@ -1751,22 +1882,6 @@ function emptyResult2(file, level) {
1751
1882
  savingsPercent: 100
1752
1883
  };
1753
1884
  }
1754
- function addJSDoc(node, parts) {
1755
- if (!node.getJsDocs) return;
1756
- const docs = node.getJsDocs();
1757
- if (docs.length > 0) {
1758
- parts.push(docs[0].getText());
1759
- }
1760
- }
1761
- function findTsConfig(filePath) {
1762
- let dir = filePath;
1763
- for (let i = 0; i < 10; i++) {
1764
- dir = join7(dir, "..");
1765
- const candidate = join7(dir, "tsconfig.json");
1766
- if (existsSync4(candidate)) return candidate;
1767
- }
1768
- return void 0;
1769
- }
1770
1885
 
1771
1886
  // src/engine/coverage.ts
1772
1887
  function calculateCoverage(targetPaths, includedPaths, allFiles, graph, depth = 2) {
@@ -2472,18 +2587,18 @@ function makeSection(id, role, content) {
2472
2587
  // src/govern/audit.ts
2473
2588
  import { randomUUID, createHash as createHash5 } from "crypto";
2474
2589
  import { readdir as readdir3, chmod } from "fs/promises";
2475
- import { join as join8 } from "path";
2590
+ import { join as join7 } from "path";
2476
2591
  import { userInfo } from "os";
2477
2592
  import { homedir } from "os";
2478
2593
  var CTO_DIR = ".cto-ai";
2479
2594
  var AUDIT_DIR = "audit";
2480
2595
  var MAX_ENTRIES_PER_FILE = 500;
2481
2596
  function getAuditDir() {
2482
- return join8(homedir(), CTO_DIR, AUDIT_DIR);
2597
+ return join7(homedir(), CTO_DIR, AUDIT_DIR);
2483
2598
  }
2484
2599
  function getCurrentAuditFile() {
2485
2600
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0].replace(/-/g, "");
2486
- return join8(getAuditDir(), `audit_${date}.json`);
2601
+ return join7(getAuditDir(), `audit_${date}.json`);
2487
2602
  }
2488
2603
  function computeIntegrityHash(entry) {
2489
2604
  const payload = JSON.stringify({
@@ -2511,7 +2626,7 @@ async function readJSON(filePath) {
2511
2626
  }
2512
2627
  async function writeJSON(filePath, data) {
2513
2628
  const { writeFile: writeFile7 } = await import("fs/promises");
2514
- await ensureDir(join8(filePath, ".."));
2629
+ await ensureDir(join7(filePath, ".."));
2515
2630
  await writeFile7(filePath, JSON.stringify(data, null, 2), "utf-8");
2516
2631
  }
2517
2632
  async function logAudit(action, projectPath, details = {}) {
@@ -2561,7 +2676,7 @@ async function getAuditEntries(options = {}) {
2561
2676
  const limit = options.limit ?? 100;
2562
2677
  for (const file of auditFiles) {
2563
2678
  if (allEntries.length >= limit) break;
2564
- const entries = await readJSON(join8(auditDir, file));
2679
+ const entries = await readJSON(join7(auditDir, file));
2565
2680
  if (!entries) continue;
2566
2681
  for (const entry of entries.reverse()) {
2567
2682
  if (allEntries.length >= limit) break;
@@ -2610,7 +2725,7 @@ async function purgeOldAuditEntries(retentionDays) {
2610
2725
  const dateStr = file.replace("audit_", "").replace(".json", "");
2611
2726
  if (dateStr < cutoffStr) {
2612
2727
  try {
2613
- await unlink(join8(auditDir, file));
2728
+ await unlink(join7(auditDir, file));
2614
2729
  purged++;
2615
2730
  } catch {
2616
2731
  }
@@ -2837,7 +2952,7 @@ var interactCommand = new Command3("interact").description("Build optimized AI c
2837
2952
  console.log("");
2838
2953
  }
2839
2954
  if (opts.output === "file") {
2840
- const outPath = join9(resolve8(opts.path ?? "."), ".cto", `prompt-${plan.id}.md`);
2955
+ const outPath = join8(resolve8(opts.path ?? "."), ".cto", `prompt-${plan.id}.md`);
2841
2956
  await writeFile4(outPath, plan.prompt.rendered, "utf-8");
2842
2957
  console.log(chalk3.green(` \u{1F4BE} Prompt saved to ${outPath}`));
2843
2958
  console.log("");
@@ -2867,7 +2982,7 @@ var interactCommand = new Command3("interact").description("Build optimized AI c
2867
2982
  // src/cli/v2/snapshot.ts
2868
2983
  import { Command as Command4 } from "commander";
2869
2984
  import chalk4 from "chalk";
2870
- import { resolve as resolve9, join as join10 } from "path";
2985
+ import { resolve as resolve9, join as join9 } from "path";
2871
2986
  import { readFile as readFile7, writeFile as writeFile5, readdir as readdir4, mkdir as mkdir3 } from "fs/promises";
2872
2987
 
2873
2988
  // src/govern/snapshot.ts
@@ -2970,7 +3085,7 @@ function hashString(input) {
2970
3085
  // src/cli/v2/snapshot.ts
2971
3086
  var SNAPSHOTS_DIR = ".cto/snapshots";
2972
3087
  async function ensureSnapshotsDir(projectPath) {
2973
- const dir = join10(projectPath, SNAPSHOTS_DIR);
3088
+ const dir = join9(projectPath, SNAPSHOTS_DIR);
2974
3089
  await mkdir3(dir, { recursive: true });
2975
3090
  return dir;
2976
3091
  }
@@ -2998,7 +3113,7 @@ var snapshotCommand = new Command4("snapshot").description("Create and manage re
2998
3113
  createdBy: process.env.USER ?? "unknown"
2999
3114
  });
3000
3115
  const dir = await ensureSnapshotsDir(projectPath);
3001
- const filePath = join10(dir, `${name}.json`);
3116
+ const filePath = join9(dir, `${name}.json`);
3002
3117
  await writeFile5(filePath, JSON.stringify(snap, null, 2), "utf-8");
3003
3118
  console.log("");
3004
3119
  console.log(chalk4.bold.cyan(` \u{1F4F8} Snapshot "${name}" created`));
@@ -3021,7 +3136,7 @@ var snapshotCommand = new Command4("snapshot").description("Create and manage re
3021
3136
  try {
3022
3137
  const projectPath = resolve9(opts.path ?? ".");
3023
3138
  const budget = parseInt(opts.budget ?? "50000", 10);
3024
- const snapPath = join10(projectPath, SNAPSHOTS_DIR, `${name}.json`);
3139
+ const snapPath = join9(projectPath, SNAPSHOTS_DIR, `${name}.json`);
3025
3140
  const snap = await loadSnapshot(snapPath);
3026
3141
  console.log(chalk4.dim(`
3027
3142
  Re-analyzing project...`));
@@ -3058,9 +3173,9 @@ var snapshotCommand = new Command4("snapshot").description("Create and manage re
3058
3173
  new Command4("compare").description("Compare two snapshots").argument("<older>", "Older snapshot name").argument("<newer>", "Newer snapshot name").option("-p, --path <path>", "Project path", ".").action(async (older, newer, opts) => {
3059
3174
  try {
3060
3175
  const projectPath = resolve9(opts.path ?? ".");
3061
- const dir = join10(projectPath, SNAPSHOTS_DIR);
3062
- const snap1 = await loadSnapshot(join10(dir, `${older}.json`));
3063
- const snap2 = await loadSnapshot(join10(dir, `${newer}.json`));
3176
+ const dir = join9(projectPath, SNAPSHOTS_DIR);
3177
+ const snap1 = await loadSnapshot(join9(dir, `${older}.json`));
3178
+ const snap2 = await loadSnapshot(join9(dir, `${newer}.json`));
3064
3179
  const diff = compareSnapshots(snap1, snap2);
3065
3180
  console.log("");
3066
3181
  console.log(chalk4.bold.cyan(` \u{1F4CA} Snapshot Comparison: ${older} \u2192 ${newer}`));
@@ -3093,7 +3208,7 @@ var snapshotCommand = new Command4("snapshot").description("Create and manage re
3093
3208
  new Command4("list").description("List saved snapshots").option("-p, --path <path>", "Project path", ".").action(async (opts) => {
3094
3209
  try {
3095
3210
  const projectPath = resolve9(opts.path ?? ".");
3096
- const dir = join10(projectPath, SNAPSHOTS_DIR);
3211
+ const dir = join9(projectPath, SNAPSHOTS_DIR);
3097
3212
  let files;
3098
3213
  try {
3099
3214
  files = await readdir4(dir);
@@ -3111,7 +3226,7 @@ var snapshotCommand = new Command4("snapshot").description("Create and manage re
3111
3226
  console.log("");
3112
3227
  for (const file of snapFiles) {
3113
3228
  try {
3114
- const snap = await loadSnapshot(join10(dir, file));
3229
+ const snap = await loadSnapshot(join9(dir, file));
3115
3230
  const date = new Date(snap.createdAt).toLocaleString();
3116
3231
  console.log(` ${chalk4.bold(snap.name)} \u2014 ${snap.files.length} files, ~${Math.round(snap.totalTokens / 1e3)}K tokens, coverage ${snap.coverageScore}%`);
3117
3232
  console.log(` ${chalk4.dim(`Created: ${date} | Hash: ${snap.hash}`)}`);
@@ -3222,7 +3337,7 @@ var auditCommand = new Command5("audit").description("View and manage the audit
3222
3337
  // src/cli/v2/policy.ts
3223
3338
  import { Command as Command6 } from "commander";
3224
3339
  import chalk6 from "chalk";
3225
- import { resolve as resolve10, join as join11 } from "path";
3340
+ import { resolve as resolve10, join as join10 } from "path";
3226
3341
  import { readFile as readFile8, writeFile as writeFile6, mkdir as mkdir4 } from "fs/promises";
3227
3342
 
3228
3343
  // src/govern/policy.ts
@@ -3377,16 +3492,16 @@ function fileMatchesCategory(path, category) {
3377
3492
  var POLICY_FILE2 = ".cto/policy.json";
3378
3493
  async function loadPolicy(projectPath) {
3379
3494
  try {
3380
- const content = await readFile8(join11(projectPath, POLICY_FILE2), "utf-8");
3495
+ const content = await readFile8(join10(projectPath, POLICY_FILE2), "utf-8");
3381
3496
  return JSON.parse(content);
3382
3497
  } catch {
3383
3498
  return DEFAULT_POLICY;
3384
3499
  }
3385
3500
  }
3386
3501
  async function savePolicy(projectPath, policy) {
3387
- const dir = join11(projectPath, ".cto");
3502
+ const dir = join10(projectPath, ".cto");
3388
3503
  await mkdir4(dir, { recursive: true });
3389
- await writeFile6(join11(projectPath, POLICY_FILE2), JSON.stringify(policy, null, 2), "utf-8");
3504
+ await writeFile6(join10(projectPath, POLICY_FILE2), JSON.stringify(policy, null, 2), "utf-8");
3390
3505
  }
3391
3506
  var policyCommand = new Command6("policy").description("Manage context selection policies").addCommand(
3392
3507
  new Command6("show").description("Show current policy rules").option("-p, --path <path>", "Project path", ".").option("--json", "Output as JSON").action(async (opts) => {
@@ -3530,7 +3645,7 @@ var policyCommand = new Command6("policy").description("Manage context selection
3530
3645
  const projectPath = resolve10(opts.path ?? ".");
3531
3646
  await savePolicy(projectPath, DEFAULT_POLICY);
3532
3647
  console.log(chalk6.green(`
3533
- \u2705 Default policy initialized at ${join11(projectPath, POLICY_FILE2)}
3648
+ \u2705 Default policy initialized at ${join10(projectPath, POLICY_FILE2)}
3534
3649
  `));
3535
3650
  } catch (err) {
3536
3651
  console.error(chalk6.red(`