shiva-code 0.7.8 → 0.7.10

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.
@@ -1,6 +1,7 @@
1
1
  import {
2
+ colors,
2
3
  log
3
- } from "./chunk-Z6NXFC4Q.js";
4
+ } from "./chunk-UABU5VVI.js";
4
5
  import {
5
6
  formatContextAsMarkdown,
6
7
  generateGitHubContext,
@@ -1318,7 +1319,7 @@ function removeShivaHooks(eventHooks) {
1318
1319
  );
1319
1320
  }
1320
1321
  var hookCommand = new Command("hook").description("Claude Code Hook Integration verwalten");
1321
- hookCommand.command("install").description("SHIVA Hooks in Claude Code installieren").option("--github", "GitHub Context Injection aktivieren").option("--sync", "Cloud Sync Hooks aktivieren (Standard)").option("--scan", "Package Security Scanning aktivieren").option("--all", "Alle Hooks aktivieren").action((options) => {
1322
+ hookCommand.command("install").description("SHIVA Hooks in Claude Code installieren").option("--github", "GitHub Context Injection aktivieren").option("--sync", "Cloud Sync Hooks aktivieren (Standard)").option("--scan", "Package Security Scanning aktivieren").option("--token-protection", "Token-Schutz aktivieren (erkennt & sch\xFCtzt Secrets)").option("--all", "Alle Hooks aktivieren").action((options) => {
1322
1323
  log.brand();
1323
1324
  const claudePath = join(homedir(), ".claude");
1324
1325
  if (!existsSync(claudePath)) {
@@ -1334,12 +1335,14 @@ hookCommand.command("install").description("SHIVA Hooks in Claude Code installie
1334
1335
  if (!settings.hooks) {
1335
1336
  settings.hooks = {};
1336
1337
  }
1337
- const installSync = options.sync || options.all || !options.github && !options.scan;
1338
+ const installSync = options.sync || options.all || !options.github && !options.scan && !options.tokenProtection;
1338
1339
  const installGithub = options.github || options.all;
1339
1340
  const installScan = options.scan || options.all;
1341
+ const installTokenProtection = options.tokenProtection || options.all;
1340
1342
  const hasSyncHooks = hasShivaHook(settings.hooks, "SessionStart") || hasShivaHook(settings.hooks, "Stop");
1341
1343
  const hasGithubHook = hasShivaContextHook(settings.hooks);
1342
1344
  const hasScanHook = hasShivaScanHook(settings.hooks);
1345
+ const hasTokenHook = hasShivaTokenHook(settings.hooks);
1343
1346
  if (hasSyncHooks && installSync && !installGithub && !installScan) {
1344
1347
  log.warn("SHIVA Sync Hooks sind bereits installiert");
1345
1348
  log.newline();
@@ -1412,6 +1415,21 @@ hookCommand.command("install").description("SHIVA Hooks in Claude Code installie
1412
1415
  });
1413
1416
  installedSomething = true;
1414
1417
  }
1418
+ if (installTokenProtection && !hasTokenHook) {
1419
+ if (!settings.hooks.Stop) {
1420
+ settings.hooks.Stop = [];
1421
+ }
1422
+ settings.hooks.Stop.push({
1423
+ hooks: [
1424
+ {
1425
+ type: "command",
1426
+ command: "shiva hook scan-session --quiet",
1427
+ timeout: 30
1428
+ }
1429
+ ]
1430
+ });
1431
+ installedSomething = true;
1432
+ }
1415
1433
  if (!installedSomething) {
1416
1434
  log.warn("Alle ausgew\xE4hlten Hooks sind bereits installiert");
1417
1435
  log.newline();
@@ -1432,6 +1450,9 @@ hookCommand.command("install").description("SHIVA Hooks in Claude Code installie
1432
1450
  if (installScan || hasScanHook) {
1433
1451
  log.tree.item("PreToolUse: Package Security Scanning");
1434
1452
  }
1453
+ if (installTokenProtection || hasTokenHook) {
1454
+ log.tree.item("Stop: Token-Schutz (Secrets erkennen & sch\xFCtzen)");
1455
+ }
1435
1456
  log.newline();
1436
1457
  log.dim("Claude Code wird nun automatisch mit SHIVA integriert.");
1437
1458
  log.newline();
@@ -1452,6 +1473,13 @@ function hasShivaScanHook(hooks) {
1452
1473
  (entry) => entry.matcher === "Bash" && entry.hooks?.some((h) => h.command?.includes("shiva hook scan-command"))
1453
1474
  );
1454
1475
  }
1476
+ function hasShivaTokenHook(hooks) {
1477
+ if (!hooks || !hooks.Stop) return false;
1478
+ const eventHooks = hooks.Stop;
1479
+ return eventHooks.some(
1480
+ (entry) => entry.hooks?.some((h) => h.command?.includes("shiva hook scan-session"))
1481
+ );
1482
+ }
1455
1483
  hookCommand.command("uninstall").description("SHIVA Hooks aus Claude Code entfernen").action(() => {
1456
1484
  log.brand();
1457
1485
  const settings = getClaudeSettings();
@@ -1503,6 +1531,7 @@ hookCommand.command("status").description("Hook-Status anzeigen").action(() => {
1503
1531
  const hasStop = hasShivaHook(settings.hooks, "Stop");
1504
1532
  const hasGithub = hasShivaContextHook(settings.hooks);
1505
1533
  const hasScan = hasShivaScanHook(settings.hooks);
1534
+ const hasToken = hasShivaTokenHook(settings.hooks);
1506
1535
  log.plain("Cloud Sync:");
1507
1536
  if (hasSessionStart) {
1508
1537
  log.listItem("SessionStart: Memories laden", "synced");
@@ -1528,8 +1557,13 @@ hookCommand.command("status").description("Hook-Status anzeigen").action(() => {
1528
1557
  } else {
1529
1558
  log.listItem("Package Scanning: nicht aktiv", "pending");
1530
1559
  }
1560
+ if (hasToken) {
1561
+ log.listItem("Stop: Token-Schutz (Secrets erkennen)", "synced");
1562
+ } else {
1563
+ log.listItem("Token-Schutz: nicht aktiv", "pending");
1564
+ }
1531
1565
  log.newline();
1532
- const allInstalled = hasSessionStart && hasStop && hasGithub && hasScan;
1566
+ const allInstalled = hasSessionStart && hasStop && hasGithub && hasScan && hasToken;
1533
1567
  const syncInstalled = hasSessionStart && hasStop;
1534
1568
  const anyInstalled = hasSessionStart || hasStop || hasGithub || hasScan;
1535
1569
  if (allInstalled) {
@@ -1740,7 +1774,7 @@ hookCommand.command("sync").description("Hooks mit Cloud synchronisieren").actio
1740
1774
  hookCommand.command("cloud-list").description("Cloud-Hooks auflisten").option("--event <type>", "Nach Event-Typ filtern").option("--json", "JSON Output").action(async (options) => {
1741
1775
  const { api } = await import("./client-H3JXPT5B.js");
1742
1776
  const { isAuthenticated } = await import("./config-FGMZONWV.js");
1743
- const { colors } = await import("./logger-E7SC5KUO.js");
1777
+ const { colors: colors2 } = await import("./logger-VVWOD6AA.js");
1744
1778
  if (!isAuthenticated()) {
1745
1779
  log.error("Nicht angemeldet");
1746
1780
  log.info("Anmelden mit: shiva login");
@@ -1762,8 +1796,8 @@ hookCommand.command("cloud-list").description("Cloud-Hooks auflisten").option("-
1762
1796
  return;
1763
1797
  }
1764
1798
  log.newline();
1765
- console.log(colors.orange.bold("Cloud Hooks"));
1766
- console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1799
+ console.log(colors2.orange.bold("Cloud Hooks"));
1800
+ console.log(colors2.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1767
1801
  log.newline();
1768
1802
  if (!hooks || Array.isArray(hooks) && hooks.length === 0) {
1769
1803
  log.dim("Keine Cloud-Hooks konfiguriert");
@@ -1771,14 +1805,14 @@ hookCommand.command("cloud-list").description("Cloud-Hooks auflisten").option("-
1771
1805
  }
1772
1806
  const hooksArray = Array.isArray(hooks) ? hooks : Object.values(hooks).flat();
1773
1807
  for (const hook of hooksArray) {
1774
- const enabledIcon = hook.enabled !== false ? colors.green("\u25CF") : colors.dim("\u25CB");
1775
- console.log(` ${enabledIcon} ${colors.bold(hook.id || hook.event)}`);
1776
- console.log(` ${colors.dim("Event:")} ${hook.event}`);
1808
+ const enabledIcon = hook.enabled !== false ? colors2.green("\u25CF") : colors2.dim("\u25CB");
1809
+ console.log(` ${enabledIcon} ${colors2.bold(hook.id || hook.event)}`);
1810
+ console.log(` ${colors2.dim("Event:")} ${hook.event}`);
1777
1811
  if (hook.matcher) {
1778
- console.log(` ${colors.dim("Matcher:")} ${hook.matcher}`);
1812
+ console.log(` ${colors2.dim("Matcher:")} ${hook.matcher}`);
1779
1813
  }
1780
- console.log(` ${colors.dim("Type:")} ${hook.type}`);
1781
- console.log(` ${colors.dim("Command:")} ${hook.command}`);
1814
+ console.log(` ${colors2.dim("Type:")} ${hook.type}`);
1815
+ console.log(` ${colors2.dim("Command:")} ${hook.command}`);
1782
1816
  log.newline();
1783
1817
  }
1784
1818
  } catch (error) {
@@ -1817,7 +1851,7 @@ hookCommand.command("cloud-create").description("Neuen Cloud-Hook erstellen").re
1817
1851
  hookCommand.command("cloud-test").description("Cloud-Hook testen").argument("<hook-id>", "Hook ID").action(async (hookId) => {
1818
1852
  const { api } = await import("./client-H3JXPT5B.js");
1819
1853
  const { isAuthenticated } = await import("./config-FGMZONWV.js");
1820
- const { colors } = await import("./logger-E7SC5KUO.js");
1854
+ const { colors: colors2 } = await import("./logger-VVWOD6AA.js");
1821
1855
  if (!isAuthenticated()) {
1822
1856
  log.error("Nicht angemeldet");
1823
1857
  log.info("Anmelden mit: shiva login");
@@ -1833,15 +1867,15 @@ hookCommand.command("cloud-test").description("Cloud-Hook testen").argument("<ho
1833
1867
  log.success(`Hook erfolgreich (${result.duration}ms)`);
1834
1868
  if (result.output) {
1835
1869
  log.newline();
1836
- console.log(colors.dim("Output:"));
1870
+ console.log(colors2.dim("Output:"));
1837
1871
  console.log(result.output);
1838
1872
  }
1839
1873
  } else {
1840
1874
  log.error(`Hook fehlgeschlagen (${result.duration}ms)`);
1841
1875
  if (result.error) {
1842
1876
  log.newline();
1843
- console.log(colors.dim("Error:"));
1844
- console.log(colors.red(result.error));
1877
+ console.log(colors2.dim("Error:"));
1878
+ console.log(colors2.red(result.error));
1845
1879
  }
1846
1880
  }
1847
1881
  } catch (error) {
@@ -1911,6 +1945,122 @@ hookCommand.command("cloud-toggle").description("Cloud-Hook aktivieren/deaktivie
1911
1945
  log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
1912
1946
  }
1913
1947
  });
1948
+ hookCommand.command("scan-session").description("Session nach sensiblen Tokens scannen (f\xFCr Stop Hook)").option("--quiet", "Keine Ausgabe (f\xFCr Hook)").option("--redact", "Tokens in Session-History maskieren").option("--path <path>", "Session-Datei Pfad").action(async (options) => {
1949
+ const { detectTokens, redactTokens, maskToken } = await import("./token-detection-K6KCIWAU.js");
1950
+ const { api } = await import("./client-H3JXPT5B.js");
1951
+ const { isAuthenticated } = await import("./config-FGMZONWV.js");
1952
+ const { existsSync: existsSync2, readFileSync: readFileSync2, writeFileSync: writeFileSync2, readdirSync, statSync } = await import("fs");
1953
+ const { join: join2 } = await import("path");
1954
+ const { homedir: homedir2 } = await import("os");
1955
+ const quiet = options.quiet;
1956
+ try {
1957
+ let autoRedact = options.redact || false;
1958
+ let autoStore = false;
1959
+ if (isAuthenticated()) {
1960
+ try {
1961
+ const settings = await api.getUserSettings();
1962
+ if (settings.settings?.tokenProtection) {
1963
+ autoRedact = settings.settings.tokenProtection.autoRedact ?? autoRedact;
1964
+ autoStore = settings.settings.tokenProtection.autoStore ?? false;
1965
+ }
1966
+ } catch {
1967
+ }
1968
+ }
1969
+ const claudeProjectsPath = join2(homedir2(), ".claude", "projects");
1970
+ let sessionFiles = [];
1971
+ if (options.path) {
1972
+ sessionFiles = [options.path];
1973
+ } else if (existsSync2(claudeProjectsPath)) {
1974
+ const oneHourAgo = Date.now() - 60 * 60 * 1e3;
1975
+ try {
1976
+ const projects = readdirSync(claudeProjectsPath);
1977
+ for (const project of projects) {
1978
+ const projectPath = join2(claudeProjectsPath, project);
1979
+ const stat = statSync(projectPath);
1980
+ if (!stat.isDirectory()) continue;
1981
+ const files = readdirSync(projectPath);
1982
+ for (const file of files) {
1983
+ if (!file.endsWith(".jsonl")) continue;
1984
+ const filePath = join2(projectPath, file);
1985
+ const fileStat = statSync(filePath);
1986
+ if (fileStat.mtime.getTime() > oneHourAgo) {
1987
+ sessionFiles.push(filePath);
1988
+ }
1989
+ }
1990
+ }
1991
+ } catch {
1992
+ }
1993
+ }
1994
+ let totalTokensFound = 0;
1995
+ let totalFilesScanned = 0;
1996
+ let totalTokensRedacted = 0;
1997
+ const detectedTokens = [];
1998
+ for (const sessionFile of sessionFiles) {
1999
+ if (!existsSync2(sessionFile)) continue;
2000
+ try {
2001
+ const content = readFileSync2(sessionFile, "utf-8");
2002
+ const tokens = detectTokens(content);
2003
+ if (tokens.length > 0) {
2004
+ totalTokensFound += tokens.length;
2005
+ for (const t of tokens) {
2006
+ detectedTokens.push({
2007
+ file: sessionFile,
2008
+ token: t.token,
2009
+ service: t.pattern.service
2010
+ });
2011
+ if (autoStore && isAuthenticated()) {
2012
+ try {
2013
+ const secretKey = `${t.pattern.name.toUpperCase()}_TOKEN`;
2014
+ await api.addSecret({
2015
+ key: secretKey,
2016
+ value: t.token,
2017
+ description: `Auto-detected ${t.pattern.description}`
2018
+ });
2019
+ } catch {
2020
+ }
2021
+ }
2022
+ }
2023
+ if (autoRedact) {
2024
+ const redactedContent = redactTokens(content);
2025
+ writeFileSync2(sessionFile, redactedContent);
2026
+ totalTokensRedacted += tokens.length;
2027
+ }
2028
+ }
2029
+ totalFilesScanned++;
2030
+ } catch {
2031
+ }
2032
+ }
2033
+ if (quiet) {
2034
+ process.exit(0);
2035
+ } else {
2036
+ log.newline();
2037
+ if (totalTokensFound === 0) {
2038
+ log.success(`Keine sensiblen Tokens gefunden (${totalFilesScanned} Dateien gescannt)`);
2039
+ } else {
2040
+ console.log(colors.red.bold(`\u26A0\uFE0F ${totalTokensFound} sensible Tokens gefunden!`));
2041
+ log.newline();
2042
+ for (const t of detectedTokens) {
2043
+ console.log(` ${colors.red("!")} ${t.service}: ${colors.dim(maskToken(t.token))}`);
2044
+ }
2045
+ log.newline();
2046
+ if (totalTokensRedacted > 0) {
2047
+ log.success(`${totalTokensRedacted} Tokens in Session-History maskiert`);
2048
+ } else {
2049
+ log.warn("Tokens NICHT maskiert. Verwende --redact oder aktiviere auto-redact in Einstellungen.");
2050
+ }
2051
+ log.newline();
2052
+ log.info("Sichere Tokens mit: shiva secure-token");
2053
+ }
2054
+ log.newline();
2055
+ }
2056
+ } catch (error) {
2057
+ if (quiet) {
2058
+ process.exit(0);
2059
+ } else {
2060
+ log.error(error instanceof Error ? error.message : "Fehler beim Scannen");
2061
+ }
2062
+ }
2063
+ });
1914
2064
 
1915
2065
  export {
1916
2066
  packageScanner,
@@ -0,0 +1,195 @@
1
+ // src/utils/token-detection.ts
2
+ var TOKEN_PATTERNS = [
3
+ // NPM
4
+ {
5
+ name: "npm",
6
+ service: "NPM Registry",
7
+ pattern: /npm_[A-Za-z0-9]{36}/g,
8
+ configCommand: (token) => ["npm", "config", "set", "//registry.npmjs.org/:_authToken", token],
9
+ description: "NPM Access Token"
10
+ },
11
+ // GitHub
12
+ {
13
+ name: "github",
14
+ service: "GitHub",
15
+ pattern: /ghp_[A-Za-z0-9]{36}/g,
16
+ description: "GitHub Personal Access Token"
17
+ },
18
+ {
19
+ name: "github_pat",
20
+ service: "GitHub",
21
+ pattern: /github_pat_[A-Za-z0-9_]{80,}/g,
22
+ description: "GitHub Fine-grained Personal Access Token"
23
+ },
24
+ // OpenAI
25
+ {
26
+ name: "openai",
27
+ service: "OpenAI",
28
+ pattern: /sk-[A-Za-z0-9]{48}/g,
29
+ description: "OpenAI API Key"
30
+ },
31
+ {
32
+ name: "openai_proj",
33
+ service: "OpenAI",
34
+ pattern: /sk-proj-[A-Za-z0-9_-]{80,}/g,
35
+ description: "OpenAI Project API Key"
36
+ },
37
+ // Anthropic
38
+ {
39
+ name: "anthropic",
40
+ service: "Anthropic",
41
+ pattern: /sk-ant-[A-Za-z0-9_-]{80,}/g,
42
+ description: "Anthropic API Key"
43
+ },
44
+ // AWS
45
+ {
46
+ name: "aws_access_key",
47
+ service: "AWS",
48
+ pattern: /AKIA[A-Z0-9]{16}/g,
49
+ description: "AWS Access Key ID"
50
+ },
51
+ {
52
+ name: "aws_secret",
53
+ service: "AWS",
54
+ pattern: /(?<![A-Za-z0-9\/+])[A-Za-z0-9\/+=]{40}(?![A-Za-z0-9\/+=])/g,
55
+ description: "AWS Secret Access Key (potential)"
56
+ },
57
+ // Google Cloud
58
+ {
59
+ name: "gcp",
60
+ service: "Google Cloud",
61
+ pattern: /AIza[A-Za-z0-9_-]{35}/g,
62
+ description: "Google Cloud API Key"
63
+ },
64
+ // Stripe
65
+ {
66
+ name: "stripe_secret",
67
+ service: "Stripe",
68
+ pattern: /sk_live_[A-Za-z0-9]{24,}/g,
69
+ description: "Stripe Secret Key (Live)"
70
+ },
71
+ {
72
+ name: "stripe_test",
73
+ service: "Stripe",
74
+ pattern: /sk_test_[A-Za-z0-9]{24,}/g,
75
+ description: "Stripe Secret Key (Test)"
76
+ },
77
+ // Slack
78
+ {
79
+ name: "slack_bot",
80
+ service: "Slack",
81
+ pattern: /xoxb-[A-Za-z0-9-]{50,}/g,
82
+ description: "Slack Bot Token"
83
+ },
84
+ {
85
+ name: "slack_user",
86
+ service: "Slack",
87
+ pattern: /xoxp-[A-Za-z0-9-]{50,}/g,
88
+ description: "Slack User Token"
89
+ },
90
+ // Discord
91
+ {
92
+ name: "discord",
93
+ service: "Discord",
94
+ pattern: /[MN][A-Za-z0-9]{23,}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27,}/g,
95
+ description: "Discord Bot Token"
96
+ },
97
+ // Twilio
98
+ {
99
+ name: "twilio",
100
+ service: "Twilio",
101
+ pattern: /SK[a-f0-9]{32}/g,
102
+ description: "Twilio API Key"
103
+ },
104
+ // SendGrid
105
+ {
106
+ name: "sendgrid",
107
+ service: "SendGrid",
108
+ pattern: /SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}/g,
109
+ description: "SendGrid API Key"
110
+ },
111
+ // Mailchimp
112
+ {
113
+ name: "mailchimp",
114
+ service: "Mailchimp",
115
+ pattern: /[a-f0-9]{32}-us[0-9]{1,2}/g,
116
+ description: "Mailchimp API Key"
117
+ },
118
+ // Heroku
119
+ {
120
+ name: "heroku",
121
+ service: "Heroku",
122
+ pattern: /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/g,
123
+ description: "Heroku API Key (UUID format)"
124
+ },
125
+ // Generic JWT (potential sensitive)
126
+ {
127
+ name: "jwt",
128
+ service: "JWT",
129
+ pattern: /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g,
130
+ description: "JSON Web Token"
131
+ },
132
+ // Private Keys
133
+ {
134
+ name: "private_key",
135
+ service: "Private Key",
136
+ pattern: /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g,
137
+ description: "Private Key Header"
138
+ }
139
+ ];
140
+ function detectTokens(text) {
141
+ const detected = [];
142
+ for (const pattern of TOKEN_PATTERNS) {
143
+ pattern.pattern.lastIndex = 0;
144
+ let match;
145
+ while ((match = pattern.pattern.exec(text)) !== null) {
146
+ detected.push({
147
+ token: match[0],
148
+ pattern,
149
+ startIndex: match.index,
150
+ endIndex: match.index + match[0].length
151
+ });
152
+ }
153
+ }
154
+ return detected.sort((a, b) => a.startIndex - b.startIndex).filter((item, index, array) => {
155
+ if (index === 0) return true;
156
+ const prev = array[index - 1];
157
+ return item.startIndex >= prev.endIndex;
158
+ });
159
+ }
160
+ function containsTokens(text) {
161
+ return detectTokens(text).length > 0;
162
+ }
163
+ function redactTokens(text, replacement = "****REDACTED****") {
164
+ const tokens = detectTokens(text);
165
+ if (tokens.length === 0) return text;
166
+ let result = text;
167
+ for (let i = tokens.length - 1; i >= 0; i--) {
168
+ const { startIndex, endIndex, pattern } = tokens[i];
169
+ const redacted = `[${pattern.service}:${replacement}]`;
170
+ result = result.slice(0, startIndex) + redacted + result.slice(endIndex);
171
+ }
172
+ return result;
173
+ }
174
+ function maskToken(token) {
175
+ if (token.length <= 12) {
176
+ return "****";
177
+ }
178
+ return `${token.slice(0, 6)}...${token.slice(-4)}`;
179
+ }
180
+ function getPatternByName(name) {
181
+ return TOKEN_PATTERNS.find((p) => p.name === name);
182
+ }
183
+ function getSupportedServices() {
184
+ return [...new Set(TOKEN_PATTERNS.map((p) => p.name))];
185
+ }
186
+
187
+ export {
188
+ TOKEN_PATTERNS,
189
+ detectTokens,
190
+ containsTokens,
191
+ redactTokens,
192
+ maskToken,
193
+ getPatternByName,
194
+ getSupportedServices
195
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  colors,
3
3
  log
4
- } from "./chunk-Z6NXFC4Q.js";
4
+ } from "./chunk-UABU5VVI.js";
5
5
  import {
6
6
  api
7
7
  } from "./chunk-KB6M24M3.js";