@launchsecure/launch-kit 0.0.19 → 0.0.21

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.
@@ -1694,51 +1694,149 @@ function pgTypeToPrisma(pgType) {
1694
1694
  const upper = pgType.toUpperCase().trim();
1695
1695
  return PG_TO_PRISMA[upper] ?? upper;
1696
1696
  }
1697
+ var ID = `(?:"[\\w$]+"|[\\w$]+)`;
1698
+ var QID = `(?:${ID}\\.)?${ID}`;
1699
+ function bareName(captured) {
1700
+ const parts = captured.split(".");
1701
+ const last = parts[parts.length - 1];
1702
+ return last.replace(/^"(.*)"$/, "$1").trim();
1703
+ }
1697
1704
  function parseCreateTable(sql, state) {
1698
- const re = /CREATE\s+TABLE\s+"(\w+)"\s*\(([\s\S]*?)\);/gi;
1705
+ const re = new RegExp(
1706
+ `CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s*\\(([\\s\\S]*?)\\);`,
1707
+ "gi"
1708
+ );
1699
1709
  let m;
1700
1710
  while ((m = re.exec(sql)) !== null) {
1701
- const tableName = m[1];
1711
+ const tableName = bareName(m[1]);
1702
1712
  const body = m[2];
1703
1713
  const columns = /* @__PURE__ */ new Map();
1704
1714
  let primaryCol = null;
1705
- for (const line of body.split("\n")) {
1706
- const trimmed = line.trim().replace(/,\s*$/, "");
1715
+ const inlineFks = [];
1716
+ const lines = splitTopLevelCommas(body);
1717
+ for (const raw of lines) {
1718
+ const trimmed = raw.trim().replace(/,\s*$/, "");
1707
1719
  if (!trimmed || trimmed.startsWith("--")) continue;
1708
- const pkMatch = trimmed.match(/CONSTRAINT\s+"[^"]+"\s+PRIMARY\s+KEY\s*\("(\w+)"\)/i);
1709
- if (pkMatch) {
1710
- primaryCol = pkMatch[1];
1720
+ const namedPk = trimmed.match(new RegExp(`^CONSTRAINT\\s+${ID}\\s+PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
1721
+ if (namedPk) {
1722
+ primaryCol = bareName(namedPk[1]);
1711
1723
  continue;
1712
1724
  }
1713
- if (/^\s*CONSTRAINT\s/i.test(trimmed)) continue;
1714
- const colMatch = trimmed.match(/^"(\w+)"\s+(.+)/);
1725
+ const tablePk = trimmed.match(new RegExp(`^PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
1726
+ if (tablePk) {
1727
+ primaryCol = bareName(tablePk[1]);
1728
+ continue;
1729
+ }
1730
+ if (/^UNIQUE\s*\(/i.test(trimmed)) continue;
1731
+ const namedFk = trimmed.match(new RegExp(
1732
+ `^CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1733
+ "i"
1734
+ ));
1735
+ if (namedFk) {
1736
+ inlineFks.push({
1737
+ constraintName: bareName(namedFk[1]),
1738
+ sourceTable: tableName,
1739
+ sourceColumn: bareName(namedFk[2]),
1740
+ targetTable: bareName(namedFk[3]),
1741
+ targetColumn: bareName(namedFk[4]),
1742
+ onDelete: namedFk[5] ?? null
1743
+ });
1744
+ continue;
1745
+ }
1746
+ const bareFk = trimmed.match(new RegExp(
1747
+ `^FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1748
+ "i"
1749
+ ));
1750
+ if (bareFk) {
1751
+ inlineFks.push({
1752
+ constraintName: `${tableName}_${bareName(bareFk[1])}_fkey`,
1753
+ sourceTable: tableName,
1754
+ sourceColumn: bareName(bareFk[1]),
1755
+ targetTable: bareName(bareFk[2]),
1756
+ targetColumn: bareName(bareFk[3]),
1757
+ onDelete: bareFk[4] ?? null
1758
+ });
1759
+ continue;
1760
+ }
1761
+ if (/^CONSTRAINT\s/i.test(trimmed)) continue;
1762
+ const colMatch = trimmed.match(new RegExp(`^(${ID})\\s+(.+)`, "i"));
1715
1763
  if (!colMatch) continue;
1716
- const colName = colMatch[1];
1764
+ const colName = bareName(colMatch[1]);
1717
1765
  let rest = colMatch[2];
1766
+ const inlineRefMatch = rest.match(new RegExp(
1767
+ `\\bREFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1768
+ "i"
1769
+ ));
1770
+ if (inlineRefMatch) {
1771
+ inlineFks.push({
1772
+ constraintName: `${tableName}_${colName}_fkey`,
1773
+ sourceTable: tableName,
1774
+ sourceColumn: colName,
1775
+ targetTable: bareName(inlineRefMatch[1]),
1776
+ targetColumn: bareName(inlineRefMatch[2]),
1777
+ onDelete: inlineRefMatch[3] ?? null
1778
+ });
1779
+ rest = rest.replace(inlineRefMatch[0], "").trim();
1780
+ }
1718
1781
  const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
1782
+ const isPrimaryKey = /\bPRIMARY\s+KEY\b/i.test(rest);
1783
+ const isUnique = /\bUNIQUE\b/i.test(rest);
1719
1784
  const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i);
1720
1785
  const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
1721
- let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
1786
+ let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bPRIMARY\s+KEY\b/gi, "").replace(/\bUNIQUE\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
1722
1787
  columns.set(colName, {
1723
1788
  name: colName,
1724
1789
  type: colType,
1725
- nullable: !isNotNull,
1726
- primary: false,
1727
- unique: false,
1790
+ nullable: !isNotNull && !isPrimaryKey,
1791
+ primary: isPrimaryKey,
1792
+ unique: isUnique,
1728
1793
  default: defaultVal
1729
1794
  });
1795
+ if (isPrimaryKey) primaryCol = colName;
1730
1796
  }
1731
1797
  if (primaryCol && columns.has(primaryCol)) {
1732
1798
  columns.get(primaryCol).primary = true;
1733
1799
  }
1734
1800
  state.tables.set(tableName, { name: tableName, columns });
1801
+ state.fks.push(...inlineFks);
1735
1802
  }
1736
1803
  }
1804
+ function splitTopLevelCommas(body) {
1805
+ const out = [];
1806
+ let depth = 0;
1807
+ let buf = "";
1808
+ let inString = null;
1809
+ for (const ch of body) {
1810
+ if (inString) {
1811
+ buf += ch;
1812
+ if (ch === inString) inString = null;
1813
+ continue;
1814
+ }
1815
+ if (ch === "'" || ch === '"') {
1816
+ inString = ch;
1817
+ buf += ch;
1818
+ continue;
1819
+ }
1820
+ if (ch === "(") depth++;
1821
+ else if (ch === ")") depth--;
1822
+ if (ch === "," && depth === 0) {
1823
+ out.push(buf);
1824
+ buf = "";
1825
+ continue;
1826
+ }
1827
+ buf += ch;
1828
+ }
1829
+ if (buf.trim()) out.push(buf);
1830
+ return out;
1831
+ }
1737
1832
  function parseCreateEnum(sql, state) {
1738
- const re = /CREATE\s+TYPE\s+"(\w+)"\s+AS\s+ENUM\s*\(([^)]+)\)/gi;
1833
+ const re = new RegExp(
1834
+ `CREATE\\s+TYPE\\s+(${QID})\\s+AS\\s+ENUM\\s*\\(([^)]+)\\)`,
1835
+ "gi"
1836
+ );
1739
1837
  let m;
1740
1838
  while ((m = re.exec(sql)) !== null) {
1741
- const enumName = m[1];
1839
+ const enumName = bareName(m[1]);
1742
1840
  const valuesStr = m[2];
1743
1841
  const values = new Set(
1744
1842
  valuesStr.split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1")).filter(Boolean)
@@ -1747,11 +1845,14 @@ function parseCreateEnum(sql, state) {
1747
1845
  }
1748
1846
  }
1749
1847
  function parseAlterTable(sql, state) {
1750
- const addColRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+COLUMN\s+"(\w+)"\s+(.+?);/gi;
1848
+ const addColRe = new RegExp(
1849
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+COLUMN\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s+(.+?);`,
1850
+ "gi"
1851
+ );
1751
1852
  let m;
1752
1853
  while ((m = addColRe.exec(sql)) !== null) {
1753
- const tableName = m[1];
1754
- const colName = m[2];
1854
+ const tableName = bareName(m[1]);
1855
+ const colName = bareName(m[2]);
1755
1856
  let rest = m[3];
1756
1857
  const table = state.tables.get(tableName);
1757
1858
  if (!table) continue;
@@ -1768,48 +1869,66 @@ function parseAlterTable(sql, state) {
1768
1869
  default: defaultVal
1769
1870
  });
1770
1871
  }
1771
- const dropColRe = /ALTER\s+TABLE\s+"(\w+)"\s+DROP\s+COLUMN\s+"(\w+)"/gi;
1872
+ const dropColRe = new RegExp(
1873
+ `ALTER\\s+TABLE\\s+(${QID})\\s+DROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
1874
+ "gi"
1875
+ );
1772
1876
  while ((m = dropColRe.exec(sql)) !== null) {
1773
- const table = state.tables.get(m[1]);
1774
- if (table) table.columns.delete(m[2]);
1877
+ const table = state.tables.get(bareName(m[1]));
1878
+ if (table) table.columns.delete(bareName(m[2]));
1775
1879
  }
1776
- const fkRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+CONSTRAINT\s+"([^"]+)"\s+FOREIGN\s+KEY\s*\("(\w+)"\)\s+REFERENCES\s+"(\w+)"\("(\w+)"\)(?:\s+ON\s+DELETE\s+(\w+(?:\s+\w+)?))?/gi;
1880
+ const fkRe = new RegExp(
1881
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1882
+ "gi"
1883
+ );
1777
1884
  while ((m = fkRe.exec(sql)) !== null) {
1778
1885
  state.fks.push({
1779
- constraintName: m[2],
1780
- sourceTable: m[1],
1781
- sourceColumn: m[3],
1782
- targetTable: m[4],
1783
- targetColumn: m[5],
1886
+ constraintName: bareName(m[2]),
1887
+ sourceTable: bareName(m[1]),
1888
+ sourceColumn: bareName(m[3]),
1889
+ targetTable: bareName(m[4]),
1890
+ targetColumn: bareName(m[5]),
1784
1891
  onDelete: m[6] ?? null
1785
1892
  });
1786
1893
  }
1787
1894
  }
1788
1895
  function parseAlterEnum(sql, state) {
1789
- const re = /ALTER\s+TYPE\s+"(\w+)"\s+ADD\s+VALUE\s+'([^']+)'/gi;
1896
+ const re = new RegExp(
1897
+ `ALTER\\s+TYPE\\s+(${QID})\\s+ADD\\s+VALUE\\s+'([^']+)'`,
1898
+ "gi"
1899
+ );
1790
1900
  let m;
1791
1901
  while ((m = re.exec(sql)) !== null) {
1792
- const en = state.enums.get(m[1]);
1902
+ const en = state.enums.get(bareName(m[1]));
1793
1903
  if (en) en.values.add(m[2]);
1794
1904
  }
1795
1905
  }
1796
1906
  function parseDropTable(sql, state) {
1797
- const re = /DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?"(\w+)"/gi;
1907
+ const re = new RegExp(
1908
+ `DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
1909
+ "gi"
1910
+ );
1798
1911
  let m;
1799
1912
  while ((m = re.exec(sql)) !== null) {
1800
- state.tables.delete(m[1]);
1801
- state.fks = state.fks.filter((fk) => fk.sourceTable !== m[1] && fk.targetTable !== m[1]);
1913
+ const dropped = bareName(m[1]);
1914
+ state.tables.delete(dropped);
1915
+ state.fks = state.fks.filter((fk) => fk.sourceTable !== dropped && fk.targetTable !== dropped);
1802
1916
  }
1803
1917
  }
1804
1918
  function parseUniqueIndex(sql, state) {
1805
- const re = /CREATE\s+UNIQUE\s+INDEX\s+"[^"]+"\s+ON\s+"(\w+)"\("(\w+)"\)/gi;
1919
+ const re = new RegExp(
1920
+ `CREATE\\s+UNIQUE\\s+INDEX\\s+(?:(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:${ID}\\s+)?)?ON\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)`,
1921
+ "gi"
1922
+ );
1806
1923
  let m;
1807
1924
  while ((m = re.exec(sql)) !== null) {
1808
- const table = state.tables.get(m[1]);
1809
- const col = table?.columns.get(m[2]);
1925
+ const tableName = bareName(m[1]);
1926
+ const colName = bareName(m[2]);
1927
+ const table = state.tables.get(tableName);
1928
+ const col = table?.columns.get(colName);
1810
1929
  if (col) col.unique = true;
1811
- if (!state.uniqueIndexes.has(m[1])) state.uniqueIndexes.set(m[1], /* @__PURE__ */ new Set());
1812
- state.uniqueIndexes.get(m[1]).add(m[2]);
1930
+ if (!state.uniqueIndexes.has(tableName)) state.uniqueIndexes.set(tableName, /* @__PURE__ */ new Set());
1931
+ state.uniqueIndexes.get(tableName).add(colName);
1813
1932
  }
1814
1933
  }
1815
1934
  function discoverMigrationFiles(migrationsDir) {
@@ -8051,51 +8051,149 @@ function pgTypeToPrisma(pgType) {
8051
8051
  const upper = pgType.toUpperCase().trim();
8052
8052
  return PG_TO_PRISMA[upper] ?? upper;
8053
8053
  }
8054
+ var ID = `(?:"[\\w$]+"|[\\w$]+)`;
8055
+ var QID = `(?:${ID}\\.)?${ID}`;
8056
+ function bareName(captured) {
8057
+ const parts = captured.split(".");
8058
+ const last = parts[parts.length - 1];
8059
+ return last.replace(/^"(.*)"$/, "$1").trim();
8060
+ }
8054
8061
  function parseCreateTable(sql, state) {
8055
- const re = /CREATE\s+TABLE\s+"(\w+)"\s*\(([\s\S]*?)\);/gi;
8062
+ const re = new RegExp(
8063
+ `CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s*\\(([\\s\\S]*?)\\);`,
8064
+ "gi"
8065
+ );
8056
8066
  let m;
8057
8067
  while ((m = re.exec(sql)) !== null) {
8058
- const tableName = m[1];
8068
+ const tableName = bareName(m[1]);
8059
8069
  const body = m[2];
8060
8070
  const columns = /* @__PURE__ */ new Map();
8061
8071
  let primaryCol = null;
8062
- for (const line of body.split("\n")) {
8063
- const trimmed = line.trim().replace(/,\s*$/, "");
8072
+ const inlineFks = [];
8073
+ const lines = splitTopLevelCommas(body);
8074
+ for (const raw of lines) {
8075
+ const trimmed = raw.trim().replace(/,\s*$/, "");
8064
8076
  if (!trimmed || trimmed.startsWith("--")) continue;
8065
- const pkMatch = trimmed.match(/CONSTRAINT\s+"[^"]+"\s+PRIMARY\s+KEY\s*\("(\w+)"\)/i);
8066
- if (pkMatch) {
8067
- primaryCol = pkMatch[1];
8077
+ const namedPk = trimmed.match(new RegExp(`^CONSTRAINT\\s+${ID}\\s+PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
8078
+ if (namedPk) {
8079
+ primaryCol = bareName(namedPk[1]);
8068
8080
  continue;
8069
8081
  }
8070
- if (/^\s*CONSTRAINT\s/i.test(trimmed)) continue;
8071
- const colMatch = trimmed.match(/^"(\w+)"\s+(.+)/);
8082
+ const tablePk = trimmed.match(new RegExp(`^PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
8083
+ if (tablePk) {
8084
+ primaryCol = bareName(tablePk[1]);
8085
+ continue;
8086
+ }
8087
+ if (/^UNIQUE\s*\(/i.test(trimmed)) continue;
8088
+ const namedFk = trimmed.match(new RegExp(
8089
+ `^CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
8090
+ "i"
8091
+ ));
8092
+ if (namedFk) {
8093
+ inlineFks.push({
8094
+ constraintName: bareName(namedFk[1]),
8095
+ sourceTable: tableName,
8096
+ sourceColumn: bareName(namedFk[2]),
8097
+ targetTable: bareName(namedFk[3]),
8098
+ targetColumn: bareName(namedFk[4]),
8099
+ onDelete: namedFk[5] ?? null
8100
+ });
8101
+ continue;
8102
+ }
8103
+ const bareFk = trimmed.match(new RegExp(
8104
+ `^FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
8105
+ "i"
8106
+ ));
8107
+ if (bareFk) {
8108
+ inlineFks.push({
8109
+ constraintName: `${tableName}_${bareName(bareFk[1])}_fkey`,
8110
+ sourceTable: tableName,
8111
+ sourceColumn: bareName(bareFk[1]),
8112
+ targetTable: bareName(bareFk[2]),
8113
+ targetColumn: bareName(bareFk[3]),
8114
+ onDelete: bareFk[4] ?? null
8115
+ });
8116
+ continue;
8117
+ }
8118
+ if (/^CONSTRAINT\s/i.test(trimmed)) continue;
8119
+ const colMatch = trimmed.match(new RegExp(`^(${ID})\\s+(.+)`, "i"));
8072
8120
  if (!colMatch) continue;
8073
- const colName = colMatch[1];
8121
+ const colName = bareName(colMatch[1]);
8074
8122
  let rest = colMatch[2];
8123
+ const inlineRefMatch = rest.match(new RegExp(
8124
+ `\\bREFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
8125
+ "i"
8126
+ ));
8127
+ if (inlineRefMatch) {
8128
+ inlineFks.push({
8129
+ constraintName: `${tableName}_${colName}_fkey`,
8130
+ sourceTable: tableName,
8131
+ sourceColumn: colName,
8132
+ targetTable: bareName(inlineRefMatch[1]),
8133
+ targetColumn: bareName(inlineRefMatch[2]),
8134
+ onDelete: inlineRefMatch[3] ?? null
8135
+ });
8136
+ rest = rest.replace(inlineRefMatch[0], "").trim();
8137
+ }
8075
8138
  const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
8139
+ const isPrimaryKey = /\bPRIMARY\s+KEY\b/i.test(rest);
8140
+ const isUnique = /\bUNIQUE\b/i.test(rest);
8076
8141
  const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i);
8077
8142
  const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
8078
- let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
8143
+ let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bPRIMARY\s+KEY\b/gi, "").replace(/\bUNIQUE\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
8079
8144
  columns.set(colName, {
8080
8145
  name: colName,
8081
8146
  type: colType,
8082
- nullable: !isNotNull,
8083
- primary: false,
8084
- unique: false,
8147
+ nullable: !isNotNull && !isPrimaryKey,
8148
+ primary: isPrimaryKey,
8149
+ unique: isUnique,
8085
8150
  default: defaultVal
8086
8151
  });
8152
+ if (isPrimaryKey) primaryCol = colName;
8087
8153
  }
8088
8154
  if (primaryCol && columns.has(primaryCol)) {
8089
8155
  columns.get(primaryCol).primary = true;
8090
8156
  }
8091
8157
  state.tables.set(tableName, { name: tableName, columns });
8158
+ state.fks.push(...inlineFks);
8092
8159
  }
8093
8160
  }
8161
+ function splitTopLevelCommas(body) {
8162
+ const out = [];
8163
+ let depth = 0;
8164
+ let buf = "";
8165
+ let inString = null;
8166
+ for (const ch of body) {
8167
+ if (inString) {
8168
+ buf += ch;
8169
+ if (ch === inString) inString = null;
8170
+ continue;
8171
+ }
8172
+ if (ch === "'" || ch === '"') {
8173
+ inString = ch;
8174
+ buf += ch;
8175
+ continue;
8176
+ }
8177
+ if (ch === "(") depth++;
8178
+ else if (ch === ")") depth--;
8179
+ if (ch === "," && depth === 0) {
8180
+ out.push(buf);
8181
+ buf = "";
8182
+ continue;
8183
+ }
8184
+ buf += ch;
8185
+ }
8186
+ if (buf.trim()) out.push(buf);
8187
+ return out;
8188
+ }
8094
8189
  function parseCreateEnum(sql, state) {
8095
- const re = /CREATE\s+TYPE\s+"(\w+)"\s+AS\s+ENUM\s*\(([^)]+)\)/gi;
8190
+ const re = new RegExp(
8191
+ `CREATE\\s+TYPE\\s+(${QID})\\s+AS\\s+ENUM\\s*\\(([^)]+)\\)`,
8192
+ "gi"
8193
+ );
8096
8194
  let m;
8097
8195
  while ((m = re.exec(sql)) !== null) {
8098
- const enumName = m[1];
8196
+ const enumName = bareName(m[1]);
8099
8197
  const valuesStr = m[2];
8100
8198
  const values = new Set(
8101
8199
  valuesStr.split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1")).filter(Boolean)
@@ -8104,11 +8202,14 @@ function parseCreateEnum(sql, state) {
8104
8202
  }
8105
8203
  }
8106
8204
  function parseAlterTable(sql, state) {
8107
- const addColRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+COLUMN\s+"(\w+)"\s+(.+?);/gi;
8205
+ const addColRe = new RegExp(
8206
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+COLUMN\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s+(.+?);`,
8207
+ "gi"
8208
+ );
8108
8209
  let m;
8109
8210
  while ((m = addColRe.exec(sql)) !== null) {
8110
- const tableName = m[1];
8111
- const colName = m[2];
8211
+ const tableName = bareName(m[1]);
8212
+ const colName = bareName(m[2]);
8112
8213
  let rest = m[3];
8113
8214
  const table = state.tables.get(tableName);
8114
8215
  if (!table) continue;
@@ -8125,48 +8226,66 @@ function parseAlterTable(sql, state) {
8125
8226
  default: defaultVal
8126
8227
  });
8127
8228
  }
8128
- const dropColRe = /ALTER\s+TABLE\s+"(\w+)"\s+DROP\s+COLUMN\s+"(\w+)"/gi;
8229
+ const dropColRe = new RegExp(
8230
+ `ALTER\\s+TABLE\\s+(${QID})\\s+DROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
8231
+ "gi"
8232
+ );
8129
8233
  while ((m = dropColRe.exec(sql)) !== null) {
8130
- const table = state.tables.get(m[1]);
8131
- if (table) table.columns.delete(m[2]);
8234
+ const table = state.tables.get(bareName(m[1]));
8235
+ if (table) table.columns.delete(bareName(m[2]));
8132
8236
  }
8133
- const fkRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+CONSTRAINT\s+"([^"]+)"\s+FOREIGN\s+KEY\s*\("(\w+)"\)\s+REFERENCES\s+"(\w+)"\("(\w+)"\)(?:\s+ON\s+DELETE\s+(\w+(?:\s+\w+)?))?/gi;
8237
+ const fkRe = new RegExp(
8238
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
8239
+ "gi"
8240
+ );
8134
8241
  while ((m = fkRe.exec(sql)) !== null) {
8135
8242
  state.fks.push({
8136
- constraintName: m[2],
8137
- sourceTable: m[1],
8138
- sourceColumn: m[3],
8139
- targetTable: m[4],
8140
- targetColumn: m[5],
8243
+ constraintName: bareName(m[2]),
8244
+ sourceTable: bareName(m[1]),
8245
+ sourceColumn: bareName(m[3]),
8246
+ targetTable: bareName(m[4]),
8247
+ targetColumn: bareName(m[5]),
8141
8248
  onDelete: m[6] ?? null
8142
8249
  });
8143
8250
  }
8144
8251
  }
8145
8252
  function parseAlterEnum(sql, state) {
8146
- const re = /ALTER\s+TYPE\s+"(\w+)"\s+ADD\s+VALUE\s+'([^']+)'/gi;
8253
+ const re = new RegExp(
8254
+ `ALTER\\s+TYPE\\s+(${QID})\\s+ADD\\s+VALUE\\s+'([^']+)'`,
8255
+ "gi"
8256
+ );
8147
8257
  let m;
8148
8258
  while ((m = re.exec(sql)) !== null) {
8149
- const en = state.enums.get(m[1]);
8259
+ const en = state.enums.get(bareName(m[1]));
8150
8260
  if (en) en.values.add(m[2]);
8151
8261
  }
8152
8262
  }
8153
8263
  function parseDropTable(sql, state) {
8154
- const re = /DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?"(\w+)"/gi;
8264
+ const re = new RegExp(
8265
+ `DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
8266
+ "gi"
8267
+ );
8155
8268
  let m;
8156
8269
  while ((m = re.exec(sql)) !== null) {
8157
- state.tables.delete(m[1]);
8158
- state.fks = state.fks.filter((fk) => fk.sourceTable !== m[1] && fk.targetTable !== m[1]);
8270
+ const dropped = bareName(m[1]);
8271
+ state.tables.delete(dropped);
8272
+ state.fks = state.fks.filter((fk) => fk.sourceTable !== dropped && fk.targetTable !== dropped);
8159
8273
  }
8160
8274
  }
8161
8275
  function parseUniqueIndex(sql, state) {
8162
- const re = /CREATE\s+UNIQUE\s+INDEX\s+"[^"]+"\s+ON\s+"(\w+)"\("(\w+)"\)/gi;
8276
+ const re = new RegExp(
8277
+ `CREATE\\s+UNIQUE\\s+INDEX\\s+(?:(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:${ID}\\s+)?)?ON\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)`,
8278
+ "gi"
8279
+ );
8163
8280
  let m;
8164
8281
  while ((m = re.exec(sql)) !== null) {
8165
- const table = state.tables.get(m[1]);
8166
- const col = table?.columns.get(m[2]);
8282
+ const tableName = bareName(m[1]);
8283
+ const colName = bareName(m[2]);
8284
+ const table = state.tables.get(tableName);
8285
+ const col = table?.columns.get(colName);
8167
8286
  if (col) col.unique = true;
8168
- if (!state.uniqueIndexes.has(m[1])) state.uniqueIndexes.set(m[1], /* @__PURE__ */ new Set());
8169
- state.uniqueIndexes.get(m[1]).add(m[2]);
8287
+ if (!state.uniqueIndexes.has(tableName)) state.uniqueIndexes.set(tableName, /* @__PURE__ */ new Set());
8288
+ state.uniqueIndexes.get(tableName).add(colName);
8170
8289
  }
8171
8290
  }
8172
8291
  function discoverMigrationFiles(migrationsDir) {
@@ -12016,7 +12135,7 @@ function handleAuditLayer(args) {
12016
12135
  }
12017
12136
  lines.push("");
12018
12137
  }
12019
- return okText(lines.join("\n"));
12138
+ return ok(lines.join("\n"));
12020
12139
  }
12021
12140
  function handleDetectProjectStack() {
12022
12141
  const rootDir = process.cwd();
@@ -1767,51 +1767,147 @@ function pgTypeToPrisma(pgType) {
1767
1767
  const upper = pgType.toUpperCase().trim();
1768
1768
  return PG_TO_PRISMA[upper] ?? upper;
1769
1769
  }
1770
+ function bareName(captured) {
1771
+ const parts = captured.split(".");
1772
+ const last = parts[parts.length - 1];
1773
+ return last.replace(/^"(.*)"$/, "$1").trim();
1774
+ }
1770
1775
  function parseCreateTable(sql, state) {
1771
- const re = /CREATE\s+TABLE\s+"(\w+)"\s*\(([\s\S]*?)\);/gi;
1776
+ const re = new RegExp(
1777
+ `CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s*\\(([\\s\\S]*?)\\);`,
1778
+ "gi"
1779
+ );
1772
1780
  let m;
1773
1781
  while ((m = re.exec(sql)) !== null) {
1774
- const tableName = m[1];
1782
+ const tableName = bareName(m[1]);
1775
1783
  const body = m[2];
1776
1784
  const columns = /* @__PURE__ */ new Map();
1777
1785
  let primaryCol = null;
1778
- for (const line of body.split("\n")) {
1779
- const trimmed = line.trim().replace(/,\s*$/, "");
1786
+ const inlineFks = [];
1787
+ const lines = splitTopLevelCommas(body);
1788
+ for (const raw of lines) {
1789
+ const trimmed = raw.trim().replace(/,\s*$/, "");
1780
1790
  if (!trimmed || trimmed.startsWith("--")) continue;
1781
- const pkMatch = trimmed.match(/CONSTRAINT\s+"[^"]+"\s+PRIMARY\s+KEY\s*\("(\w+)"\)/i);
1782
- if (pkMatch) {
1783
- primaryCol = pkMatch[1];
1791
+ const namedPk = trimmed.match(new RegExp(`^CONSTRAINT\\s+${ID}\\s+PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
1792
+ if (namedPk) {
1793
+ primaryCol = bareName(namedPk[1]);
1784
1794
  continue;
1785
1795
  }
1786
- if (/^\s*CONSTRAINT\s/i.test(trimmed)) continue;
1787
- const colMatch = trimmed.match(/^"(\w+)"\s+(.+)/);
1796
+ const tablePk = trimmed.match(new RegExp(`^PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
1797
+ if (tablePk) {
1798
+ primaryCol = bareName(tablePk[1]);
1799
+ continue;
1800
+ }
1801
+ if (/^UNIQUE\s*\(/i.test(trimmed)) continue;
1802
+ const namedFk = trimmed.match(new RegExp(
1803
+ `^CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1804
+ "i"
1805
+ ));
1806
+ if (namedFk) {
1807
+ inlineFks.push({
1808
+ constraintName: bareName(namedFk[1]),
1809
+ sourceTable: tableName,
1810
+ sourceColumn: bareName(namedFk[2]),
1811
+ targetTable: bareName(namedFk[3]),
1812
+ targetColumn: bareName(namedFk[4]),
1813
+ onDelete: namedFk[5] ?? null
1814
+ });
1815
+ continue;
1816
+ }
1817
+ const bareFk = trimmed.match(new RegExp(
1818
+ `^FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1819
+ "i"
1820
+ ));
1821
+ if (bareFk) {
1822
+ inlineFks.push({
1823
+ constraintName: `${tableName}_${bareName(bareFk[1])}_fkey`,
1824
+ sourceTable: tableName,
1825
+ sourceColumn: bareName(bareFk[1]),
1826
+ targetTable: bareName(bareFk[2]),
1827
+ targetColumn: bareName(bareFk[3]),
1828
+ onDelete: bareFk[4] ?? null
1829
+ });
1830
+ continue;
1831
+ }
1832
+ if (/^CONSTRAINT\s/i.test(trimmed)) continue;
1833
+ const colMatch = trimmed.match(new RegExp(`^(${ID})\\s+(.+)`, "i"));
1788
1834
  if (!colMatch) continue;
1789
- const colName = colMatch[1];
1835
+ const colName = bareName(colMatch[1]);
1790
1836
  let rest = colMatch[2];
1837
+ const inlineRefMatch = rest.match(new RegExp(
1838
+ `\\bREFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1839
+ "i"
1840
+ ));
1841
+ if (inlineRefMatch) {
1842
+ inlineFks.push({
1843
+ constraintName: `${tableName}_${colName}_fkey`,
1844
+ sourceTable: tableName,
1845
+ sourceColumn: colName,
1846
+ targetTable: bareName(inlineRefMatch[1]),
1847
+ targetColumn: bareName(inlineRefMatch[2]),
1848
+ onDelete: inlineRefMatch[3] ?? null
1849
+ });
1850
+ rest = rest.replace(inlineRefMatch[0], "").trim();
1851
+ }
1791
1852
  const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
1853
+ const isPrimaryKey = /\bPRIMARY\s+KEY\b/i.test(rest);
1854
+ const isUnique = /\bUNIQUE\b/i.test(rest);
1792
1855
  const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i);
1793
1856
  const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
1794
- let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
1857
+ let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bPRIMARY\s+KEY\b/gi, "").replace(/\bUNIQUE\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
1795
1858
  columns.set(colName, {
1796
1859
  name: colName,
1797
1860
  type: colType,
1798
- nullable: !isNotNull,
1799
- primary: false,
1800
- unique: false,
1861
+ nullable: !isNotNull && !isPrimaryKey,
1862
+ primary: isPrimaryKey,
1863
+ unique: isUnique,
1801
1864
  default: defaultVal
1802
1865
  });
1866
+ if (isPrimaryKey) primaryCol = colName;
1803
1867
  }
1804
1868
  if (primaryCol && columns.has(primaryCol)) {
1805
1869
  columns.get(primaryCol).primary = true;
1806
1870
  }
1807
1871
  state.tables.set(tableName, { name: tableName, columns });
1872
+ state.fks.push(...inlineFks);
1808
1873
  }
1809
1874
  }
1875
+ function splitTopLevelCommas(body) {
1876
+ const out = [];
1877
+ let depth = 0;
1878
+ let buf = "";
1879
+ let inString = null;
1880
+ for (const ch of body) {
1881
+ if (inString) {
1882
+ buf += ch;
1883
+ if (ch === inString) inString = null;
1884
+ continue;
1885
+ }
1886
+ if (ch === "'" || ch === '"') {
1887
+ inString = ch;
1888
+ buf += ch;
1889
+ continue;
1890
+ }
1891
+ if (ch === "(") depth++;
1892
+ else if (ch === ")") depth--;
1893
+ if (ch === "," && depth === 0) {
1894
+ out.push(buf);
1895
+ buf = "";
1896
+ continue;
1897
+ }
1898
+ buf += ch;
1899
+ }
1900
+ if (buf.trim()) out.push(buf);
1901
+ return out;
1902
+ }
1810
1903
  function parseCreateEnum(sql, state) {
1811
- const re = /CREATE\s+TYPE\s+"(\w+)"\s+AS\s+ENUM\s*\(([^)]+)\)/gi;
1904
+ const re = new RegExp(
1905
+ `CREATE\\s+TYPE\\s+(${QID})\\s+AS\\s+ENUM\\s*\\(([^)]+)\\)`,
1906
+ "gi"
1907
+ );
1812
1908
  let m;
1813
1909
  while ((m = re.exec(sql)) !== null) {
1814
- const enumName = m[1];
1910
+ const enumName = bareName(m[1]);
1815
1911
  const valuesStr = m[2];
1816
1912
  const values = new Set(
1817
1913
  valuesStr.split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1")).filter(Boolean)
@@ -1820,11 +1916,14 @@ function parseCreateEnum(sql, state) {
1820
1916
  }
1821
1917
  }
1822
1918
  function parseAlterTable(sql, state) {
1823
- const addColRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+COLUMN\s+"(\w+)"\s+(.+?);/gi;
1919
+ const addColRe = new RegExp(
1920
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+COLUMN\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s+(.+?);`,
1921
+ "gi"
1922
+ );
1824
1923
  let m;
1825
1924
  while ((m = addColRe.exec(sql)) !== null) {
1826
- const tableName = m[1];
1827
- const colName = m[2];
1925
+ const tableName = bareName(m[1]);
1926
+ const colName = bareName(m[2]);
1828
1927
  let rest = m[3];
1829
1928
  const table = state.tables.get(tableName);
1830
1929
  if (!table) continue;
@@ -1841,48 +1940,66 @@ function parseAlterTable(sql, state) {
1841
1940
  default: defaultVal
1842
1941
  });
1843
1942
  }
1844
- const dropColRe = /ALTER\s+TABLE\s+"(\w+)"\s+DROP\s+COLUMN\s+"(\w+)"/gi;
1943
+ const dropColRe = new RegExp(
1944
+ `ALTER\\s+TABLE\\s+(${QID})\\s+DROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
1945
+ "gi"
1946
+ );
1845
1947
  while ((m = dropColRe.exec(sql)) !== null) {
1846
- const table = state.tables.get(m[1]);
1847
- if (table) table.columns.delete(m[2]);
1948
+ const table = state.tables.get(bareName(m[1]));
1949
+ if (table) table.columns.delete(bareName(m[2]));
1848
1950
  }
1849
- const fkRe = /ALTER\s+TABLE\s+"(\w+)"\s+ADD\s+CONSTRAINT\s+"([^"]+)"\s+FOREIGN\s+KEY\s*\("(\w+)"\)\s+REFERENCES\s+"(\w+)"\("(\w+)"\)(?:\s+ON\s+DELETE\s+(\w+(?:\s+\w+)?))?/gi;
1951
+ const fkRe = new RegExp(
1952
+ `ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
1953
+ "gi"
1954
+ );
1850
1955
  while ((m = fkRe.exec(sql)) !== null) {
1851
1956
  state.fks.push({
1852
- constraintName: m[2],
1853
- sourceTable: m[1],
1854
- sourceColumn: m[3],
1855
- targetTable: m[4],
1856
- targetColumn: m[5],
1957
+ constraintName: bareName(m[2]),
1958
+ sourceTable: bareName(m[1]),
1959
+ sourceColumn: bareName(m[3]),
1960
+ targetTable: bareName(m[4]),
1961
+ targetColumn: bareName(m[5]),
1857
1962
  onDelete: m[6] ?? null
1858
1963
  });
1859
1964
  }
1860
1965
  }
1861
1966
  function parseAlterEnum(sql, state) {
1862
- const re = /ALTER\s+TYPE\s+"(\w+)"\s+ADD\s+VALUE\s+'([^']+)'/gi;
1967
+ const re = new RegExp(
1968
+ `ALTER\\s+TYPE\\s+(${QID})\\s+ADD\\s+VALUE\\s+'([^']+)'`,
1969
+ "gi"
1970
+ );
1863
1971
  let m;
1864
1972
  while ((m = re.exec(sql)) !== null) {
1865
- const en = state.enums.get(m[1]);
1973
+ const en = state.enums.get(bareName(m[1]));
1866
1974
  if (en) en.values.add(m[2]);
1867
1975
  }
1868
1976
  }
1869
1977
  function parseDropTable(sql, state) {
1870
- const re = /DROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?"(\w+)"/gi;
1978
+ const re = new RegExp(
1979
+ `DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
1980
+ "gi"
1981
+ );
1871
1982
  let m;
1872
1983
  while ((m = re.exec(sql)) !== null) {
1873
- state.tables.delete(m[1]);
1874
- state.fks = state.fks.filter((fk) => fk.sourceTable !== m[1] && fk.targetTable !== m[1]);
1984
+ const dropped = bareName(m[1]);
1985
+ state.tables.delete(dropped);
1986
+ state.fks = state.fks.filter((fk) => fk.sourceTable !== dropped && fk.targetTable !== dropped);
1875
1987
  }
1876
1988
  }
1877
1989
  function parseUniqueIndex(sql, state) {
1878
- const re = /CREATE\s+UNIQUE\s+INDEX\s+"[^"]+"\s+ON\s+"(\w+)"\("(\w+)"\)/gi;
1990
+ const re = new RegExp(
1991
+ `CREATE\\s+UNIQUE\\s+INDEX\\s+(?:(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:${ID}\\s+)?)?ON\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)`,
1992
+ "gi"
1993
+ );
1879
1994
  let m;
1880
1995
  while ((m = re.exec(sql)) !== null) {
1881
- const table = state.tables.get(m[1]);
1882
- const col = table?.columns.get(m[2]);
1996
+ const tableName = bareName(m[1]);
1997
+ const colName = bareName(m[2]);
1998
+ const table = state.tables.get(tableName);
1999
+ const col = table?.columns.get(colName);
1883
2000
  if (col) col.unique = true;
1884
- if (!state.uniqueIndexes.has(m[1])) state.uniqueIndexes.set(m[1], /* @__PURE__ */ new Set());
1885
- state.uniqueIndexes.get(m[1]).add(m[2]);
2001
+ if (!state.uniqueIndexes.has(tableName)) state.uniqueIndexes.set(tableName, /* @__PURE__ */ new Set());
2002
+ state.uniqueIndexes.get(tableName).add(colName);
1886
2003
  }
1887
2004
  }
1888
2005
  function discoverMigrationFiles(migrationsDir) {
@@ -2168,7 +2285,7 @@ function generate3(rootDir) {
2168
2285
  flagged_edges: flaggedEdges
2169
2286
  };
2170
2287
  }
2171
- var import_node_fs8, import_node_path7, PG_TO_PRISMA, sqlMigrationsParser;
2288
+ var import_node_fs8, import_node_path7, PG_TO_PRISMA, ID, QID, sqlMigrationsParser;
2172
2289
  var init_sql_migrations = __esm({
2173
2290
  "src/server/graph/parsers/db/sql-migrations.ts"() {
2174
2291
  "use strict";
@@ -2202,6 +2319,8 @@ var init_sql_migrations = __esm({
2202
2319
  "UUID": "String",
2203
2320
  "TEXT[]": "String[]"
2204
2321
  };
2322
+ ID = `(?:"[\\w$]+"|[\\w$]+)`;
2323
+ QID = `(?:${ID}\\.)?${ID}`;
2205
2324
  sqlMigrationsParser = {
2206
2325
  id: "sql-migrations",
2207
2326
  layer: "db",
@@ -5923,7 +6042,7 @@ function handleAuditLayer(args) {
5923
6042
  }
5924
6043
  lines.push("");
5925
6044
  }
5926
- return okText(lines.join("\n"));
6045
+ return ok(lines.join("\n"));
5927
6046
  }
5928
6047
  function handleDetectProjectStack() {
5929
6048
  const rootDir = process.cwd();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchsecure/launch-kit",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "LaunchSecure toolkit — launch-pod (pipeline), launch-chart (project graph MCP), launch-deck (visual playground MCP).",
5
5
  "license": "MIT",
6
6
  "author": "LaunchSecure - AutomateWithUs",