calabasas 0.18.0 → 0.19.1

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,160 @@
1
+ import {
2
+ build_default,
3
+ relativeTime
4
+ } from "./index-8gymgyxd.js";
5
+ import"./index-tre7d3f1.js";
6
+ import {
7
+ __toESM
8
+ } from "./index-sdksp5px.js";
9
+ import {
10
+ Box_default,
11
+ Text
12
+ } from "./index-4rn9k8et.js";
13
+ import {
14
+ cliApi,
15
+ require_jsx_dev_runtime,
16
+ useQuery
17
+ } from "./convex-1z1jsz1n.js";
18
+ import"./index-vmy4gfe1.js";
19
+
20
+ // src/components/StatusBadge.tsx
21
+ var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
22
+ var STATUS_CONFIG = {
23
+ connected: { color: "green", dot: "●" },
24
+ connecting: { color: "yellow", dot: "●" },
25
+ error: { color: "red", dot: "●" },
26
+ disconnected: { color: "gray", dot: "●" }
27
+ };
28
+ function StatusBadge({ status, width = 0 }) {
29
+ const config = STATUS_CONFIG[status];
30
+ const label = `${config.dot} ${status}`;
31
+ const padded = width > 0 ? label.padEnd(width) : label;
32
+ return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
33
+ children: [
34
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
35
+ color: config.color,
36
+ children: config.dot
37
+ }, undefined, false, undefined, this),
38
+ /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
39
+ children: padded.slice(1)
40
+ }, undefined, false, undefined, this)
41
+ ]
42
+ }, undefined, true, undefined, this);
43
+ }
44
+
45
+ // src/components/BotList.tsx
46
+ var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
47
+ function BotList({
48
+ apiKey,
49
+ selectedIndex,
50
+ onSelect
51
+ }) {
52
+ const bots = useQuery(cliApi.listBots, { apiKey });
53
+ if (bots === undefined) {
54
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
55
+ children: [
56
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
57
+ color: "cyan",
58
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(build_default, {
59
+ type: "dots"
60
+ }, undefined, false, undefined, this)
61
+ }, undefined, false, undefined, this),
62
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
63
+ children: " Loading bots..."
64
+ }, undefined, false, undefined, this)
65
+ ]
66
+ }, undefined, true, undefined, this);
67
+ }
68
+ if (bots.length === 0) {
69
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
70
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
71
+ dimColor: true,
72
+ children: "No bots found. Run `calabasas bot add` to create one."
73
+ }, undefined, false, undefined, this)
74
+ }, undefined, false, undefined, this);
75
+ }
76
+ const COL = { name: 30, status: 16, appId: 22, last: 16 };
77
+ function truncate(str, max) {
78
+ if (str.length <= max)
79
+ return str.padEnd(max);
80
+ return str.slice(0, max - 1) + "…";
81
+ }
82
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
83
+ flexDirection: "column",
84
+ children: [
85
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
86
+ marginBottom: 1,
87
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
88
+ bold: true,
89
+ children: [
90
+ " ",
91
+ "Name".padEnd(COL.name),
92
+ "Status".padEnd(COL.status),
93
+ "Discord App ID".padEnd(COL.appId),
94
+ "Last Connected"
95
+ ]
96
+ }, undefined, true, undefined, this)
97
+ }, undefined, false, undefined, this),
98
+ bots.map((bot, i) => {
99
+ const isSelected = selectedIndex === i;
100
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
101
+ flexDirection: "column",
102
+ children: [
103
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
104
+ children: [
105
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
106
+ color: isSelected ? "cyan" : undefined,
107
+ children: isSelected ? "→ " : " "
108
+ }, undefined, false, undefined, this),
109
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
110
+ bold: isSelected,
111
+ children: truncate(bot.name, COL.name)
112
+ }, undefined, false, undefined, this),
113
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(StatusBadge, {
114
+ status: bot.status,
115
+ width: COL.status
116
+ }, undefined, false, undefined, this),
117
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
118
+ dimColor: true,
119
+ children: bot.discordAppId.padEnd(COL.appId)
120
+ }, undefined, false, undefined, this),
121
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
122
+ dimColor: true,
123
+ children: relativeTime(bot.lastConnectedAt)
124
+ }, undefined, false, undefined, this)
125
+ ]
126
+ }, undefined, true, undefined, this),
127
+ bot.errorMessage && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
128
+ marginLeft: 4,
129
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
130
+ color: "red",
131
+ dimColor: true,
132
+ children: [
133
+ "└",
134
+ " ",
135
+ bot.errorMessage
136
+ ]
137
+ }, undefined, true, undefined, this)
138
+ }, undefined, false, undefined, this),
139
+ !bot.errorMessage && bot.disconnectReason && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
140
+ marginLeft: 4,
141
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
142
+ dimColor: true,
143
+ children: [
144
+ "└",
145
+ " ",
146
+ bot.disconnectReason
147
+ ]
148
+ }, undefined, true, undefined, this)
149
+ }, undefined, false, undefined, this)
150
+ ]
151
+ }, bot._id, true, undefined, this);
152
+ })
153
+ ]
154
+ }, undefined, true, undefined, this);
155
+ }
156
+ export {
157
+ BotList
158
+ };
159
+
160
+ ;
@@ -0,0 +1,221 @@
1
+ import {
2
+ LogViewer
3
+ } from "./index-b0cp0nch.js";
4
+ import {
5
+ getConvexUrl,
6
+ resolvePlatformApiKey
7
+ } from "./index-p7v1hq7k.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,192 @@
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 response = await fetch(`${apiUrl}/api/cli/bots`, {
84
+ method: "GET",
85
+ headers: {
86
+ "Content-Type": "application/json",
87
+ Authorization: `Bearer ${apiKey}`
88
+ }
89
+ });
90
+ if (!response.ok) {
91
+ console.error("Error fetching bots: " + await response.text());
92
+ process.exit(1);
93
+ }
94
+ const { bots } = await response.json();
95
+ if (!bots || bots.length === 0) {
96
+ console.error("No bots found. Add a bot first with `calabasas bot add`.");
97
+ process.exit(1);
98
+ }
99
+ if (bots.length === 1) {
100
+ return bots[0]._id;
101
+ }
102
+ const p = await import("@clack/prompts");
103
+ const selected = await p.select({
104
+ message: "Select a bot",
105
+ options: bots.map((bot) => ({
106
+ value: bot._id,
107
+ label: bot.name
108
+ }))
109
+ });
110
+ if (p.isCancel(selected)) {
111
+ p.cancel("Cancelled.");
112
+ process.exit(1);
113
+ }
114
+ return selected;
115
+ }
116
+ function resolvePlatformApiKey(options) {
117
+ if (options.platformKey) {
118
+ return { key: options.platformKey, source: "flag", isPlatformKey: true };
119
+ }
120
+ const envLocal = parseEnvLocal();
121
+ const platformKey = envLocal["CALABASAS_PLATFORM_API_KEY"];
122
+ if (platformKey) {
123
+ return { key: platformKey, source: "env", isPlatformKey: true };
124
+ }
125
+ const config = getConfig();
126
+ if (config.apiKey) {
127
+ return { key: config.apiKey, source: "user", isPlatformKey: false };
128
+ }
129
+ return null;
130
+ }
131
+ async function platformApiRequest(method, path2, platformApiKey, body, extraHeaders) {
132
+ const url = `${getApiUrl()}${path2}`;
133
+ const response = await fetch(url, {
134
+ method,
135
+ headers: {
136
+ "Content-Type": "application/json",
137
+ Authorization: `Bearer ${platformApiKey}`,
138
+ ...extraHeaders
139
+ },
140
+ body: body ? JSON.stringify(body) : undefined
141
+ });
142
+ const data = await response.json();
143
+ return { ok: response.ok, data, status: response.status };
144
+ }
145
+ function appendToEnvLocal(entries) {
146
+ const envPath = path.join(process.cwd(), ".env.local");
147
+ let lines = [];
148
+ if (fs.existsSync(envPath)) {
149
+ lines = fs.readFileSync(envPath, "utf-8").split(`
150
+ `);
151
+ }
152
+ for (const [key, value] of Object.entries(entries)) {
153
+ const lineIndex = lines.findIndex((l) => {
154
+ const trimmed = l.trim();
155
+ return trimmed.startsWith(`${key}=`) || trimmed.startsWith(`${key} =`);
156
+ });
157
+ if (lineIndex !== -1) {
158
+ lines[lineIndex] = `${key}=${value}`;
159
+ } else {
160
+ if (!lines.some((l) => l.trim() === "# Calabasas")) {
161
+ if (lines.length > 0 && lines[lines.length - 1].trim() !== "") {
162
+ lines.push("");
163
+ }
164
+ lines.push("# Calabasas");
165
+ }
166
+ lines.push(`${key}=${value}`);
167
+ }
168
+ }
169
+ fs.writeFileSync(envPath, lines.join(`
170
+ `));
171
+ }
172
+ async function showPlatformContext(apiKey) {
173
+ try {
174
+ const url = `${getApiUrl()}/api/cli/platform`;
175
+ const response = await fetch(url, {
176
+ method: "GET",
177
+ headers: {
178
+ "Content-Type": "application/json",
179
+ Authorization: `Bearer ${apiKey}`
180
+ }
181
+ });
182
+ if (!response.ok)
183
+ return;
184
+ const data = await response.json();
185
+ if (data.name) {
186
+ const pc = await import("picocolors");
187
+ console.log(`${pc.default.magenta("◆")} Platform: ${pc.default.bold(data.name)}`);
188
+ }
189
+ } catch {}
190
+ }
191
+
192
+ export { getConfig, saveConfig, clearConfig, isAuthenticated, getApiUrl, getWebUrl, getConvexUrl, resolveBot, resolvePlatformApiKey, platformApiRequest, appendToEnvLocal, showPlatformContext };