calabasas 0.19.0 → 0.19.2

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.
@@ -0,0 +1,221 @@
1
+ import {
2
+ LogViewer
3
+ } from "./index-b0cp0nch.js";
4
+ import {
5
+ getConvexUrl,
6
+ resolvePlatformApiKey
7
+ } from "./index-rb2tds4a.js";
8
+ import {
9
+ build_default,
10
+ formatLatency,
11
+ formatNumber
12
+ } from "./index-8gymgyxd.js";
13
+ import"./index-tre7d3f1.js";
14
+ import {
15
+ __toESM
16
+ } from "./index-sdksp5px.js";
17
+ import {
18
+ BotList
19
+ } from "./BotList-metq47qv.js";
20
+ import {
21
+ Box_default,
22
+ Text,
23
+ render_default,
24
+ use_app_default,
25
+ use_input_default
26
+ } from "./index-4rn9k8et.js";
27
+ import {
28
+ ConvexProvider,
29
+ cliApi,
30
+ createConvexClient,
31
+ require_jsx_dev_runtime,
32
+ useQuery
33
+ } from "./convex-1z1jsz1n.js";
34
+ import {
35
+ require_react
36
+ } from "./index-vmy4gfe1.js";
37
+
38
+ // src/components/Dashboard.tsx
39
+ var import_react2 = __toESM(require_react(), 1);
40
+
41
+ // src/components/Header.tsx
42
+ var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
43
+ function Header({
44
+ botCount
45
+ }) {
46
+ return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
47
+ marginBottom: 1,
48
+ children: [
49
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
50
+ bold: true,
51
+ color: "magenta",
52
+ children: "calabasas"
53
+ }, undefined, false, undefined, this),
54
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
55
+ dimColor: true,
56
+ children: " v0.1.12"
57
+ }, undefined, false, undefined, this),
58
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
59
+ dimColor: true,
60
+ children: " · "
61
+ }, undefined, false, undefined, this),
62
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
63
+ children: [
64
+ botCount,
65
+ " bot",
66
+ botCount !== 1 ? "s" : ""
67
+ ]
68
+ }, undefined, true, undefined, this),
69
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
70
+ dimColor: true,
71
+ children: " · Press "
72
+ }, undefined, false, undefined, this),
73
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
74
+ bold: true,
75
+ children: "q"
76
+ }, undefined, false, undefined, this),
77
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
78
+ dimColor: true,
79
+ children: " to quit"
80
+ }, undefined, false, undefined, this)
81
+ ]
82
+ }, undefined, true, undefined, this);
83
+ }
84
+
85
+ // src/components/StatsPanel.tsx
86
+ var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
87
+ var ONE_HOUR = 60 * 60 * 1000;
88
+ function StatsPanel({
89
+ apiKey,
90
+ botId
91
+ }) {
92
+ const stats = useQuery(cliApi.botStats, {
93
+ apiKey,
94
+ botId,
95
+ since: Date.now() - ONE_HOUR
96
+ });
97
+ if (stats === undefined) {
98
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
99
+ children: [
100
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
101
+ color: "cyan",
102
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(build_default, {
103
+ type: "dots"
104
+ }, undefined, false, undefined, this)
105
+ }, undefined, false, undefined, this),
106
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
107
+ children: " Loading stats..."
108
+ }, undefined, false, undefined, this)
109
+ ]
110
+ }, undefined, true, undefined, this);
111
+ }
112
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
113
+ gap: 2,
114
+ marginBottom: 1,
115
+ children: [
116
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
117
+ dimColor: true,
118
+ children: "Events (1h):"
119
+ }, undefined, false, undefined, this),
120
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
121
+ bold: true,
122
+ children: formatNumber(stats.total)
123
+ }, undefined, false, undefined, this),
124
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
125
+ color: "green",
126
+ children: [
127
+ formatNumber(stats.success),
128
+ " ok"
129
+ ]
130
+ }, undefined, true, undefined, this),
131
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
132
+ color: "red",
133
+ children: [
134
+ formatNumber(stats.failed),
135
+ " failed"
136
+ ]
137
+ }, undefined, true, undefined, this),
138
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
139
+ dimColor: true,
140
+ children: [
141
+ "avg ",
142
+ formatLatency(stats.avgLatencyMs)
143
+ ]
144
+ }, undefined, true, undefined, this)
145
+ ]
146
+ }, undefined, true, undefined, this);
147
+ }
148
+
149
+ // src/components/Dashboard.tsx
150
+ var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
151
+ function Dashboard({
152
+ apiKey
153
+ }) {
154
+ const { exit } = use_app_default();
155
+ const [selectedIndex, setSelectedIndex] = import_react2.useState(0);
156
+ const bots = useQuery(cliApi.listBots, { apiKey });
157
+ const botCount = bots?.length ?? 0;
158
+ const selectedBot = bots?.[selectedIndex];
159
+ use_input_default(import_react2.useCallback((input, key) => {
160
+ if (input === "q") {
161
+ exit();
162
+ return;
163
+ }
164
+ if ((input === "j" || key.downArrow) && botCount > 0) {
165
+ setSelectedIndex((i) => Math.min(i, botCount - 1) === botCount - 1 ? 0 : i + 1);
166
+ }
167
+ if ((input === "k" || key.upArrow) && botCount > 0) {
168
+ setSelectedIndex((i) => i === 0 ? botCount - 1 : i - 1);
169
+ }
170
+ }, [botCount, exit]));
171
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
172
+ flexDirection: "column",
173
+ children: [
174
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Header, {
175
+ botCount
176
+ }, undefined, false, undefined, this),
177
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(BotList, {
178
+ apiKey,
179
+ selectedIndex
180
+ }, undefined, false, undefined, this),
181
+ selectedBot && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
182
+ flexDirection: "column",
183
+ marginTop: 1,
184
+ children: [
185
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(StatsPanel, {
186
+ apiKey,
187
+ botId: selectedBot._id
188
+ }, undefined, false, undefined, this),
189
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(LogViewer, {
190
+ apiKey,
191
+ botId: selectedBot._id
192
+ }, undefined, false, undefined, this)
193
+ ]
194
+ }, undefined, true, undefined, this)
195
+ ]
196
+ }, undefined, true, undefined, this);
197
+ }
198
+
199
+ // src/commands/dashboard.tsx
200
+ var jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
201
+ async function dashboard() {
202
+ const resolved = resolvePlatformApiKey({});
203
+ if (!resolved) {
204
+ console.log("Not logged in. Run `calabasas login` first.");
205
+ return;
206
+ }
207
+ const apiKey = resolved.key;
208
+ const convexUrl = getConvexUrl();
209
+ const client = createConvexClient(convexUrl);
210
+ const { waitUntilExit } = render_default(/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(ConvexProvider, {
211
+ client,
212
+ children: /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Dashboard, {
213
+ apiKey
214
+ }, undefined, false, undefined, this)
215
+ }, undefined, false, undefined, this));
216
+ await waitUntilExit();
217
+ await client.close();
218
+ }
219
+ export {
220
+ dashboard
221
+ };
@@ -0,0 +1,196 @@
1
+ import {
2
+ __require,
3
+ __toESM
4
+ } from "./index-sdksp5px.js";
5
+
6
+ // src/lib/config.ts
7
+ import * as fs from "fs";
8
+ import * as path from "path";
9
+ import * as os from "os";
10
+ var CONFIG_DIR = path.join(os.homedir(), ".calabasas");
11
+ var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
12
+ var API_URL = "https://sensible-starfish-338.convex.site";
13
+ var CONVEX_URL = "https://sensible-starfish-338.convex.cloud";
14
+ var WEB_URL = "https://calabasas-web.vercel.app";
15
+ function getConfig() {
16
+ try {
17
+ if (!fs.existsSync(CONFIG_FILE)) {
18
+ return {};
19
+ }
20
+ const content = fs.readFileSync(CONFIG_FILE, "utf-8");
21
+ return JSON.parse(content);
22
+ } catch {
23
+ return {};
24
+ }
25
+ }
26
+ function saveConfig(config) {
27
+ const existing = getConfig();
28
+ const merged = { ...existing, ...config };
29
+ if (!fs.existsSync(CONFIG_DIR)) {
30
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
31
+ }
32
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2));
33
+ }
34
+ function clearConfig() {
35
+ if (fs.existsSync(CONFIG_FILE)) {
36
+ fs.unlinkSync(CONFIG_FILE);
37
+ }
38
+ }
39
+ function isAuthenticated() {
40
+ const config = getConfig();
41
+ return !!config.apiKey;
42
+ }
43
+ function getApiUrl() {
44
+ const config = getConfig();
45
+ return config.apiUrl || API_URL;
46
+ }
47
+ function getWebUrl() {
48
+ return WEB_URL;
49
+ }
50
+ function getConvexUrl() {
51
+ return CONVEX_URL;
52
+ }
53
+ function parseEnvLocal() {
54
+ const envPath = path.join(process.cwd(), ".env.local");
55
+ if (!fs.existsSync(envPath))
56
+ return {};
57
+ const content = fs.readFileSync(envPath, "utf-8");
58
+ const result = {};
59
+ for (const line of content.split(`
60
+ `)) {
61
+ const trimmed = line.trim();
62
+ if (!trimmed || trimmed.startsWith("#"))
63
+ continue;
64
+ const eqIndex = trimmed.indexOf("=");
65
+ if (eqIndex === -1)
66
+ continue;
67
+ const key = trimmed.slice(0, eqIndex).trim();
68
+ let value = trimmed.slice(eqIndex + 1).trim();
69
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
70
+ value = value.slice(1, -1);
71
+ }
72
+ result[key] = value;
73
+ }
74
+ return result;
75
+ }
76
+ async function resolveBot(options, apiKey, apiUrl) {
77
+ if (options.bot)
78
+ return options.bot;
79
+ const envLocal = parseEnvLocal();
80
+ const botId = envLocal["CALABASAS_BOT_ID"];
81
+ if (botId)
82
+ return botId;
83
+ const isPlatformKey = apiKey.startsWith("cpk_");
84
+ const endpoint = isPlatformKey ? "/api/sdk/bots" : "/api/cli/bots";
85
+ const response = await fetch(`${apiUrl}${endpoint}`, {
86
+ method: "GET",
87
+ headers: {
88
+ "Content-Type": "application/json",
89
+ Authorization: `Bearer ${apiKey}`
90
+ }
91
+ });
92
+ if (!response.ok) {
93
+ console.error("Error fetching bots: " + await response.text());
94
+ process.exit(1);
95
+ }
96
+ const { bots } = await response.json();
97
+ if (!bots || bots.length === 0) {
98
+ console.error("No bots found. Add a bot first with `calabasas bot add`.");
99
+ process.exit(1);
100
+ }
101
+ if (bots.length === 1) {
102
+ return bots[0]._id;
103
+ }
104
+ const p = await import("@clack/prompts");
105
+ const selected = await p.select({
106
+ message: "Select a bot",
107
+ options: bots.map((bot) => ({
108
+ value: bot._id,
109
+ label: bot.name
110
+ }))
111
+ });
112
+ if (p.isCancel(selected)) {
113
+ p.cancel("Cancelled.");
114
+ process.exit(1);
115
+ }
116
+ return selected;
117
+ }
118
+ function resolvePlatformApiKey(options) {
119
+ if (options.platformKey) {
120
+ return { key: options.platformKey, source: "flag", isPlatformKey: true };
121
+ }
122
+ const envLocal = parseEnvLocal();
123
+ const platformKey = envLocal["CALABASAS_PLATFORM_API_KEY"];
124
+ if (platformKey) {
125
+ return { key: platformKey, source: "env", isPlatformKey: true };
126
+ }
127
+ const config = getConfig();
128
+ if (config.apiKey) {
129
+ return { key: config.apiKey, source: "user", isPlatformKey: false };
130
+ }
131
+ return null;
132
+ }
133
+ async function platformApiRequest(method, path2, platformApiKey, body, extraHeaders) {
134
+ const url = `${getApiUrl()}${path2}`;
135
+ const response = await fetch(url, {
136
+ method,
137
+ headers: {
138
+ "Content-Type": "application/json",
139
+ Authorization: `Bearer ${platformApiKey}`,
140
+ ...extraHeaders
141
+ },
142
+ body: body ? JSON.stringify(body) : undefined
143
+ });
144
+ const data = await response.json();
145
+ return { ok: response.ok, data, status: response.status };
146
+ }
147
+ function appendToEnvLocal(entries) {
148
+ const envPath = path.join(process.cwd(), ".env.local");
149
+ let lines = [];
150
+ if (fs.existsSync(envPath)) {
151
+ lines = fs.readFileSync(envPath, "utf-8").split(`
152
+ `);
153
+ }
154
+ for (const [key, value] of Object.entries(entries)) {
155
+ const lineIndex = lines.findIndex((l) => {
156
+ const trimmed = l.trim();
157
+ return trimmed.startsWith(`${key}=`) || trimmed.startsWith(`${key} =`);
158
+ });
159
+ if (lineIndex !== -1) {
160
+ lines[lineIndex] = `${key}=${value}`;
161
+ } else {
162
+ if (!lines.some((l) => l.trim() === "# Calabasas")) {
163
+ if (lines.length > 0 && lines[lines.length - 1].trim() !== "") {
164
+ lines.push("");
165
+ }
166
+ lines.push("# Calabasas");
167
+ }
168
+ lines.push(`${key}=${value}`);
169
+ }
170
+ }
171
+ fs.writeFileSync(envPath, lines.join(`
172
+ `));
173
+ }
174
+ async function showPlatformContext(apiKey) {
175
+ try {
176
+ const isPlatformKey = apiKey.startsWith("cpk_");
177
+ const endpoint = isPlatformKey ? "/api/sdk/platform" : "/api/cli/platform";
178
+ const url = `${getApiUrl()}${endpoint}`;
179
+ const response = await fetch(url, {
180
+ method: "GET",
181
+ headers: {
182
+ "Content-Type": "application/json",
183
+ Authorization: `Bearer ${apiKey}`
184
+ }
185
+ });
186
+ if (!response.ok)
187
+ return;
188
+ const data = await response.json();
189
+ if (data.name) {
190
+ const pc = await import("picocolors");
191
+ console.log(`${pc.default.magenta("◆")} Platform: ${pc.default.bold(data.name)}`);
192
+ }
193
+ } catch {}
194
+ }
195
+
196
+ export { getConfig, saveConfig, clearConfig, isAuthenticated, getApiUrl, getWebUrl, getConvexUrl, resolveBot, resolvePlatformApiKey, platformApiRequest, appendToEnvLocal, showPlatformContext };
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  resolvePlatformApiKey,
13
13
  saveConfig,
14
14
  showPlatformContext
15
- } from "./index-p7v1hq7k.js";
15
+ } from "./index-rb2tds4a.js";
16
16
  import {
17
17
  __commonJS,
18
18
  __require,
@@ -2422,19 +2422,31 @@ async function push(options) {
2422
2422
  p4.log.warn(`Privileged intents: ${privilegedUsed.join(", ")} — make sure these are enabled in the Discord Developer Portal.`);
2423
2423
  }
2424
2424
  const bitfield = intentsToBitfield(intents);
2425
- const intentsResponse = await fetch(`${apiUrl}/api/cli/bots`, {
2426
- method: "PATCH",
2427
- headers: {
2428
- "Content-Type": "application/json",
2429
- Authorization: `Bearer ${apiKey}`
2430
- },
2431
- body: JSON.stringify({ botId, intents: bitfield })
2432
- });
2433
- if (!intentsResponse.ok) {
2434
- const error = await intentsResponse.text();
2435
- s.stop("Intents push failed");
2436
- p4.cancel(`Error: ${error}`);
2437
- process.exit(1);
2425
+ if (resolved.isPlatformKey) {
2426
+ const { ok: intentsOk, data: intentsData } = await platformApiRequest("PATCH", "/api/sdk/bots/config", apiKey, {
2427
+ botId,
2428
+ intents: bitfield
2429
+ });
2430
+ if (!intentsOk) {
2431
+ s.stop("Intents push failed");
2432
+ p4.cancel(`Error: ${JSON.stringify(intentsData)}`);
2433
+ process.exit(1);
2434
+ }
2435
+ } else {
2436
+ const intentsResponse = await fetch(`${apiUrl}/api/cli/bots`, {
2437
+ method: "PATCH",
2438
+ headers: {
2439
+ "Content-Type": "application/json",
2440
+ Authorization: `Bearer ${apiKey}`
2441
+ },
2442
+ body: JSON.stringify({ botId, intents: bitfield })
2443
+ });
2444
+ if (!intentsResponse.ok) {
2445
+ const error = await intentsResponse.text();
2446
+ s.stop("Intents push failed");
2447
+ p4.cancel(`Error: ${error}`);
2448
+ process.exit(1);
2449
+ }
2438
2450
  }
2439
2451
  }
2440
2452
  s.stop("Config pushed!");
@@ -6997,7 +7009,7 @@ async function botEdit(botId, options) {
6997
7009
  }
6998
7010
  const s = p10.spinner();
6999
7011
  s.start("Updating bot...");
7000
- const { ok, data, status } = await apiRequest("PATCH", "/api/cli/bots", updates);
7012
+ const { ok, data, status } = auth.isPlatformKey ? await platformApiRequest("PATCH", "/api/cli/bots", auth.key, updates) : await apiRequest("PATCH", "/api/cli/bots", updates);
7001
7013
  if (!ok) {
7002
7014
  s.stop("Failed to update bot");
7003
7015
  p10.cancel(`${data.error || `HTTP ${status}`}`);
@@ -7103,6 +7115,62 @@ Add this as CALABASAS_SECRET in your Convex environment.`, "Platform Secret");
7103
7115
  }
7104
7116
  p11.outro("Platform created successfully!");
7105
7117
  }
7118
+ async function platformConnect() {
7119
+ if (!isAuthenticated()) {
7120
+ console.log("Not logged in. Run `calabasas login` first.");
7121
+ return;
7122
+ }
7123
+ p11.intro("calabasas platform connect");
7124
+ const s = p11.spinner();
7125
+ s.start("Fetching platforms...");
7126
+ const { ok, data, status } = await apiRequest2("GET", "/api/cli/platforms");
7127
+ if (!ok) {
7128
+ s.stop("Failed to fetch platforms");
7129
+ p11.cancel(`${data.error || `HTTP ${status}`}`);
7130
+ return;
7131
+ }
7132
+ const { platforms } = data;
7133
+ s.stop("Fetched platforms");
7134
+ if (platforms.length === 0) {
7135
+ p11.cancel("No platforms found. Run `calabasas platform create` to create one.");
7136
+ return;
7137
+ }
7138
+ let selectedPlatform;
7139
+ if (platforms.length === 1) {
7140
+ selectedPlatform = platforms[0];
7141
+ p11.log.info(`Using platform: ${pc2.bold(selectedPlatform.name)}`);
7142
+ } else {
7143
+ const choice = await p11.select({
7144
+ message: "Select a platform to connect to",
7145
+ options: platforms.map((platform) => ({
7146
+ value: platform._id,
7147
+ label: platform.name,
7148
+ hint: platform.convexProject ?? undefined
7149
+ }))
7150
+ });
7151
+ if (p11.isCancel(choice)) {
7152
+ p11.cancel("Cancelled.");
7153
+ return;
7154
+ }
7155
+ selectedPlatform = platforms.find((pl) => pl._id === choice);
7156
+ }
7157
+ const keySpinner = p11.spinner();
7158
+ keySpinner.start("Generating API key...");
7159
+ const { ok: rotateOk, data: rotateData, status: rotateStatus } = await apiRequest2("PATCH", "/api/cli/platform", { platformId: selectedPlatform._id, rotateApiKey: true });
7160
+ if (!rotateOk) {
7161
+ keySpinner.stop("Failed to generate API key");
7162
+ p11.cancel(`${rotateData.error || `HTTP ${rotateStatus}`}`);
7163
+ return;
7164
+ }
7165
+ keySpinner.stop("API key generated");
7166
+ const { platformApiKey } = rotateData;
7167
+ if (selectedPlatform.hasApiKey) {
7168
+ p11.log.warn("This replaces the previous API key for this platform.");
7169
+ }
7170
+ appendToEnvLocal({ CALABASAS_PLATFORM_API_KEY: platformApiKey });
7171
+ p11.note(`CALABASAS_PLATFORM_API_KEY=${platformApiKey}`, "Saved to .env.local");
7172
+ p11.outro(`Connected to ${pc2.bold(selectedPlatform.name)}!`);
7173
+ }
7106
7174
  async function platformList() {
7107
7175
  if (!isAuthenticated()) {
7108
7176
  console.log("Not logged in. Run `calabasas login` first.");
@@ -7626,11 +7694,11 @@ Run ${pc3.cyan("`calabasas init`")} first.`);
7626
7694
 
7627
7695
  // src/index.ts
7628
7696
  var dashboard = async () => {
7629
- const mod = await import("./dashboard-bb11jwa7.js");
7697
+ const mod = await import("./dashboard-hebbbc6d.js");
7630
7698
  return mod.dashboard();
7631
7699
  };
7632
7700
  var logs = async (...args) => {
7633
- const mod = await import("./logs-qtkh50rh.js");
7701
+ const mod = await import("./logs-v149b3tb.js");
7634
7702
  return mod.logs(args[0]);
7635
7703
  };
7636
7704
  var program2 = new Command;
@@ -7653,6 +7721,7 @@ bot.command("remove <botId>").alias("rm").description("Remove a Discord bot").op
7653
7721
  bot.command("edit <botId>").description("Edit a Discord bot").option("-n, --name <name>", "New bot name").option("-t, --token <token>", "New bot token").option("-i, --intents <intents>", "New intents value").action(botEdit);
7654
7722
  var platformCmd = program2.command("platform").description("Manage your Calabasas platform");
7655
7723
  platformCmd.command("create").description("Create a new platform with Convex project configuration").option("-n, --name <name>", "Platform name").option("-p, --project <project>", "Convex project name (e.g. diligent-swordfish-752)").action(platformCreate);
7724
+ platformCmd.command("connect").description("Connect this project to an existing platform (saves API key to .env.local)").action(platformConnect);
7656
7725
  platformCmd.command("list").alias("ls").description("List all your platforms").action(platformList);
7657
7726
  platformCmd.command("info").description("Show platform info (secret, URL, API key status)").action(platformInfo);
7658
7727
  platformCmd.command("set-url").description("Set Convex URL for your platform").action(platformSetUrl);
@@ -0,0 +1,111 @@
1
+ import {
2
+ LogViewer
3
+ } from "./index-b0cp0nch.js";
4
+ import {
5
+ getConvexUrl,
6
+ platformApiRequest,
7
+ resolvePlatformApiKey
8
+ } from "./index-rb2tds4a.js";
9
+ import {
10
+ formatLatency
11
+ } from "./index-8gymgyxd.js";
12
+ import"./index-tre7d3f1.js";
13
+ import {
14
+ __toESM
15
+ } from "./index-sdksp5px.js";
16
+ import {
17
+ render_default,
18
+ use_app_default,
19
+ use_input_default
20
+ } from "./index-4rn9k8et.js";
21
+ import {
22
+ ConvexProvider,
23
+ createConvexClient,
24
+ require_jsx_dev_runtime
25
+ } from "./convex-1z1jsz1n.js";
26
+ import"./index-vmy4gfe1.js";
27
+
28
+ // src/commands/logs.tsx
29
+ import pc from "picocolors";
30
+ var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
31
+ function LogsApp({ apiKey, botId, limit, successFilter }) {
32
+ const { exit } = use_app_default();
33
+ use_input_default((input) => {
34
+ if (input === "q") {
35
+ exit();
36
+ }
37
+ });
38
+ return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(LogViewer, {
39
+ apiKey,
40
+ botId,
41
+ limit,
42
+ successFilter
43
+ }, undefined, false, undefined, this);
44
+ }
45
+ function formatTimestamp(ts) {
46
+ const d = new Date(ts);
47
+ return d.toLocaleTimeString("en-US", { hour12: false });
48
+ }
49
+ async function logs(options) {
50
+ if (options.errors && options.success) {
51
+ console.error("Error: Cannot use both --errors and --success flags.");
52
+ process.exit(1);
53
+ }
54
+ const resolved = resolvePlatformApiKey({});
55
+ if (!resolved) {
56
+ console.log("Not logged in. Run `calabasas login` first.");
57
+ return;
58
+ }
59
+ const apiKey = resolved.key;
60
+ const limit = options.limit ? parseInt(options.limit, 10) : 50;
61
+ const successFilter = options.errors ? false : options.success ? true : undefined;
62
+ const botId = options.bot;
63
+ if (options.once || !process.stdin.isTTY) {
64
+ const params = new URLSearchParams;
65
+ if (botId)
66
+ params.set("botId", botId);
67
+ params.set("limit", String(limit));
68
+ if (successFilter !== undefined)
69
+ params.set("success", String(successFilter));
70
+ const queryString = params.toString();
71
+ const path = `/api/sdk/logs${queryString ? `?${queryString}` : ""}`;
72
+ const { ok, data, status } = await platformApiRequest("GET", path, apiKey);
73
+ if (!ok) {
74
+ console.error(`Failed to fetch logs: ${data.error || `HTTP ${status}`}`);
75
+ process.exit(1);
76
+ }
77
+ const { logs: entries } = data;
78
+ if (entries.length === 0) {
79
+ console.log("No events found.");
80
+ return;
81
+ }
82
+ const uniqueBots = new Set(entries.map((l) => l.botName));
83
+ const multiBot = uniqueBots.size > 1 || !botId;
84
+ for (const log of entries) {
85
+ const time = pc.dim(formatTimestamp(log.timestamp));
86
+ const status2 = log.success ? pc.green("✓") : pc.red("✗");
87
+ const event = pc.bold(log.eventType);
88
+ const latency = pc.dim(formatLatency(log.latencyMs));
89
+ const botLabel = multiBot ? pc.cyan(`[${log.botName}]`) + " " : "";
90
+ const error = log.error ? ` ${pc.red(log.error)}` : "";
91
+ console.log(`${time} ${status2} ${botLabel}${event} ${latency}${error}`);
92
+ }
93
+ return;
94
+ }
95
+ const convexUrl = getConvexUrl();
96
+ const client = createConvexClient(convexUrl);
97
+ const { waitUntilExit } = render_default(/* @__PURE__ */ jsx_dev_runtime.jsxDEV(ConvexProvider, {
98
+ client,
99
+ children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(LogsApp, {
100
+ apiKey,
101
+ botId,
102
+ limit,
103
+ successFilter
104
+ }, undefined, false, undefined, this)
105
+ }, undefined, false, undefined, this));
106
+ await waitUntilExit();
107
+ await client.close();
108
+ }
109
+ export {
110
+ logs
111
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "calabasas",
3
- "version": "0.19.0",
3
+ "version": "0.19.2",
4
4
  "description": "CLI for Calabasas - Discord Gateway as a Service for Convex",
5
5
  "type": "module",
6
6
  "bin": {