calabasas 0.10.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +15 -3
- package/dist/dashboard-r2cptf7m.js +236 -0
- package/dist/index-qnd4rw0e.js +191 -0
- package/dist/index.js +363 -9
- package/dist/logs-452qgkw7.js +70 -0
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -9,9 +9,21 @@ export type SyncConfig = {
|
|
|
9
9
|
presence?: boolean;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
export type
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
export type DiscordEventName =
|
|
13
|
+
| "messageCreate"
|
|
14
|
+
| "messageUpdate"
|
|
15
|
+
| "messageDelete"
|
|
16
|
+
| "guildMemberAdd"
|
|
17
|
+
| "guildMemberRemove"
|
|
18
|
+
| "guildMemberUpdate"
|
|
19
|
+
| "interactionCreate"
|
|
20
|
+
| "voiceStateUpdate"
|
|
21
|
+
| "presenceUpdate"
|
|
22
|
+
| "typingStart"
|
|
23
|
+
| "messageReactionAdd"
|
|
24
|
+
| "messageReactionRemove";
|
|
25
|
+
|
|
26
|
+
export type EventConfig = { [K in DiscordEventName]?: true };
|
|
15
27
|
|
|
16
28
|
export type CommandOptionType = "string" | "integer" | "number" | "boolean" | "user" | "channel" | "role" | "mentionable" | "attachment";
|
|
17
29
|
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LogViewer
|
|
3
|
+
} from "./index-f8td7thj.js";
|
|
4
|
+
import {
|
|
5
|
+
getConfig,
|
|
6
|
+
getConvexUrl,
|
|
7
|
+
isAuthenticated,
|
|
8
|
+
resolveEnv
|
|
9
|
+
} from "./index-qnd4rw0e.js";
|
|
10
|
+
import {
|
|
11
|
+
build_default,
|
|
12
|
+
formatLatency,
|
|
13
|
+
formatNumber
|
|
14
|
+
} from "./index-8gymgyxd.js";
|
|
15
|
+
import"./index-tre7d3f1.js";
|
|
16
|
+
import {
|
|
17
|
+
__toESM
|
|
18
|
+
} from "./index-sdksp5px.js";
|
|
19
|
+
import {
|
|
20
|
+
BotList
|
|
21
|
+
} from "./BotList-jqxxq32e.js";
|
|
22
|
+
import {
|
|
23
|
+
Box_default,
|
|
24
|
+
Text,
|
|
25
|
+
render_default,
|
|
26
|
+
use_app_default,
|
|
27
|
+
use_input_default
|
|
28
|
+
} from "./index-4rn9k8et.js";
|
|
29
|
+
import {
|
|
30
|
+
ConvexProvider,
|
|
31
|
+
cliApi,
|
|
32
|
+
createConvexClient,
|
|
33
|
+
require_jsx_dev_runtime,
|
|
34
|
+
useQuery
|
|
35
|
+
} from "./convex-1z1jsz1n.js";
|
|
36
|
+
import {
|
|
37
|
+
require_react
|
|
38
|
+
} from "./index-vmy4gfe1.js";
|
|
39
|
+
|
|
40
|
+
// src/components/Dashboard.tsx
|
|
41
|
+
var import_react2 = __toESM(require_react(), 1);
|
|
42
|
+
|
|
43
|
+
// src/components/Header.tsx
|
|
44
|
+
var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
|
|
45
|
+
function Header({
|
|
46
|
+
botCount,
|
|
47
|
+
env
|
|
48
|
+
}) {
|
|
49
|
+
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
50
|
+
marginBottom: 1,
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
53
|
+
bold: true,
|
|
54
|
+
color: "magenta",
|
|
55
|
+
children: "calabasas"
|
|
56
|
+
}, undefined, false, undefined, this),
|
|
57
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
58
|
+
dimColor: true,
|
|
59
|
+
children: " v0.1.12"
|
|
60
|
+
}, undefined, false, undefined, this),
|
|
61
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
62
|
+
dimColor: true,
|
|
63
|
+
children: " · "
|
|
64
|
+
}, undefined, false, undefined, this),
|
|
65
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
66
|
+
children: [
|
|
67
|
+
botCount,
|
|
68
|
+
" bot",
|
|
69
|
+
botCount !== 1 ? "s" : ""
|
|
70
|
+
]
|
|
71
|
+
}, undefined, true, undefined, this),
|
|
72
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
73
|
+
dimColor: true,
|
|
74
|
+
children: " · "
|
|
75
|
+
}, undefined, false, undefined, this),
|
|
76
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
77
|
+
color: env === "dev" ? "yellow" : "green",
|
|
78
|
+
children: env
|
|
79
|
+
}, undefined, false, undefined, this),
|
|
80
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
81
|
+
dimColor: true,
|
|
82
|
+
children: " · Press "
|
|
83
|
+
}, undefined, false, undefined, this),
|
|
84
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
85
|
+
bold: true,
|
|
86
|
+
children: "q"
|
|
87
|
+
}, undefined, false, undefined, this),
|
|
88
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
89
|
+
dimColor: true,
|
|
90
|
+
children: " to quit"
|
|
91
|
+
}, undefined, false, undefined, this)
|
|
92
|
+
]
|
|
93
|
+
}, undefined, true, undefined, this);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/components/StatsPanel.tsx
|
|
97
|
+
var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
|
|
98
|
+
var ONE_HOUR = 60 * 60 * 1000;
|
|
99
|
+
function StatsPanel({
|
|
100
|
+
apiKey,
|
|
101
|
+
botId
|
|
102
|
+
}) {
|
|
103
|
+
const stats = useQuery(cliApi.botStats, {
|
|
104
|
+
apiKey,
|
|
105
|
+
botId,
|
|
106
|
+
since: Date.now() - ONE_HOUR
|
|
107
|
+
});
|
|
108
|
+
if (stats === undefined) {
|
|
109
|
+
return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
|
|
112
|
+
color: "cyan",
|
|
113
|
+
children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(build_default, {
|
|
114
|
+
type: "dots"
|
|
115
|
+
}, undefined, false, undefined, this)
|
|
116
|
+
}, undefined, false, undefined, this),
|
|
117
|
+
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
|
|
118
|
+
children: " Loading stats..."
|
|
119
|
+
}, undefined, false, undefined, this)
|
|
120
|
+
]
|
|
121
|
+
}, undefined, true, undefined, this);
|
|
122
|
+
}
|
|
123
|
+
return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
|
|
124
|
+
gap: 2,
|
|
125
|
+
marginBottom: 1,
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
|
|
128
|
+
dimColor: true,
|
|
129
|
+
children: "Events (1h):"
|
|
130
|
+
}, undefined, false, undefined, this),
|
|
131
|
+
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
|
|
132
|
+
bold: true,
|
|
133
|
+
children: formatNumber(stats.total)
|
|
134
|
+
}, undefined, false, undefined, this),
|
|
135
|
+
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
|
|
136
|
+
color: "green",
|
|
137
|
+
children: [
|
|
138
|
+
formatNumber(stats.success),
|
|
139
|
+
" ok"
|
|
140
|
+
]
|
|
141
|
+
}, undefined, true, undefined, this),
|
|
142
|
+
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
|
|
143
|
+
color: "red",
|
|
144
|
+
children: [
|
|
145
|
+
formatNumber(stats.failed),
|
|
146
|
+
" failed"
|
|
147
|
+
]
|
|
148
|
+
}, undefined, true, undefined, this),
|
|
149
|
+
/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
|
|
150
|
+
dimColor: true,
|
|
151
|
+
children: [
|
|
152
|
+
"avg ",
|
|
153
|
+
formatLatency(stats.avgLatencyMs)
|
|
154
|
+
]
|
|
155
|
+
}, undefined, true, undefined, this)
|
|
156
|
+
]
|
|
157
|
+
}, undefined, true, undefined, this);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/components/Dashboard.tsx
|
|
161
|
+
var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
|
|
162
|
+
function Dashboard({
|
|
163
|
+
apiKey,
|
|
164
|
+
env
|
|
165
|
+
}) {
|
|
166
|
+
const { exit } = use_app_default();
|
|
167
|
+
const [selectedIndex, setSelectedIndex] = import_react2.useState(0);
|
|
168
|
+
const bots = useQuery(cliApi.listBots, { apiKey });
|
|
169
|
+
const botCount = bots?.length ?? 0;
|
|
170
|
+
const selectedBot = bots?.[selectedIndex];
|
|
171
|
+
use_input_default(import_react2.useCallback((input, key) => {
|
|
172
|
+
if (input === "q") {
|
|
173
|
+
exit();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if ((input === "j" || key.downArrow) && botCount > 0) {
|
|
177
|
+
setSelectedIndex((i) => Math.min(i, botCount - 1) === botCount - 1 ? 0 : i + 1);
|
|
178
|
+
}
|
|
179
|
+
if ((input === "k" || key.upArrow) && botCount > 0) {
|
|
180
|
+
setSelectedIndex((i) => i === 0 ? botCount - 1 : i - 1);
|
|
181
|
+
}
|
|
182
|
+
}, [botCount, exit]));
|
|
183
|
+
return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
184
|
+
flexDirection: "column",
|
|
185
|
+
children: [
|
|
186
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Header, {
|
|
187
|
+
botCount,
|
|
188
|
+
env
|
|
189
|
+
}, undefined, false, undefined, this),
|
|
190
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(BotList, {
|
|
191
|
+
apiKey,
|
|
192
|
+
selectedIndex
|
|
193
|
+
}, undefined, false, undefined, this),
|
|
194
|
+
selectedBot && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
|
|
195
|
+
flexDirection: "column",
|
|
196
|
+
marginTop: 1,
|
|
197
|
+
children: [
|
|
198
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(StatsPanel, {
|
|
199
|
+
apiKey,
|
|
200
|
+
botId: selectedBot._id
|
|
201
|
+
}, undefined, false, undefined, this),
|
|
202
|
+
/* @__PURE__ */ jsx_dev_runtime3.jsxDEV(LogViewer, {
|
|
203
|
+
apiKey,
|
|
204
|
+
botId: selectedBot._id
|
|
205
|
+
}, undefined, false, undefined, this)
|
|
206
|
+
]
|
|
207
|
+
}, undefined, true, undefined, this)
|
|
208
|
+
]
|
|
209
|
+
}, undefined, true, undefined, this);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/commands/dashboard.tsx
|
|
213
|
+
var jsx_dev_runtime4 = __toESM(require_jsx_dev_runtime(), 1);
|
|
214
|
+
async function dashboard(options) {
|
|
215
|
+
const env = resolveEnv(options);
|
|
216
|
+
if (!isAuthenticated(env)) {
|
|
217
|
+
console.log("Not logged in. Run `calabasas login` first.");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const config = getConfig(env);
|
|
221
|
+
const apiKey = config.apiKey;
|
|
222
|
+
const convexUrl = getConvexUrl(env);
|
|
223
|
+
const client = createConvexClient(convexUrl);
|
|
224
|
+
const { waitUntilExit } = render_default(/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(ConvexProvider, {
|
|
225
|
+
client,
|
|
226
|
+
children: /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Dashboard, {
|
|
227
|
+
apiKey,
|
|
228
|
+
env
|
|
229
|
+
}, undefined, false, undefined, this)
|
|
230
|
+
}, undefined, false, undefined, this));
|
|
231
|
+
await waitUntilExit();
|
|
232
|
+
await client.close();
|
|
233
|
+
}
|
|
234
|
+
export {
|
|
235
|
+
dashboard
|
|
236
|
+
};
|
|
@@ -0,0 +1,191 @@
|
|
|
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
|
+
function getConfigFile(env) {
|
|
12
|
+
if (env === "dev")
|
|
13
|
+
return path.join(CONFIG_DIR, "config.dev.json");
|
|
14
|
+
return path.join(CONFIG_DIR, "config.json");
|
|
15
|
+
}
|
|
16
|
+
var PROD_API_URL = "https://sensible-starfish-338.convex.site";
|
|
17
|
+
var DEV_API_URL = "https://diligent-swordfish-752.convex.site";
|
|
18
|
+
var PROD_CONVEX_URL = "https://sensible-starfish-338.convex.cloud";
|
|
19
|
+
var DEV_CONVEX_URL = "https://diligent-swordfish-752.convex.cloud";
|
|
20
|
+
var PROD_WEB_URL = "https://calabasas-web.vercel.app";
|
|
21
|
+
var DEV_WEB_URL = "http://localhost:3000";
|
|
22
|
+
function getConfig(env) {
|
|
23
|
+
try {
|
|
24
|
+
const configFile = getConfigFile(env);
|
|
25
|
+
if (!fs.existsSync(configFile)) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
const content = fs.readFileSync(configFile, "utf-8");
|
|
29
|
+
return JSON.parse(content);
|
|
30
|
+
} catch {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function saveConfig(config, env) {
|
|
35
|
+
const existing = getConfig(env);
|
|
36
|
+
const merged = { ...existing, ...config };
|
|
37
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
38
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
fs.writeFileSync(getConfigFile(env), JSON.stringify(merged, null, 2));
|
|
41
|
+
}
|
|
42
|
+
function clearConfig(env) {
|
|
43
|
+
const configFile = getConfigFile(env);
|
|
44
|
+
if (fs.existsSync(configFile)) {
|
|
45
|
+
fs.unlinkSync(configFile);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function isAuthenticated(env) {
|
|
49
|
+
const config = getConfig(env);
|
|
50
|
+
return !!config.apiKey;
|
|
51
|
+
}
|
|
52
|
+
function getApiUrl(env) {
|
|
53
|
+
const config = getConfig(env);
|
|
54
|
+
return config.apiUrl || PROD_API_URL;
|
|
55
|
+
}
|
|
56
|
+
function getApiUrlForEnv(env) {
|
|
57
|
+
if (env === "dev")
|
|
58
|
+
return DEV_API_URL;
|
|
59
|
+
if (env === "prod")
|
|
60
|
+
return PROD_API_URL;
|
|
61
|
+
return getApiUrl();
|
|
62
|
+
}
|
|
63
|
+
function getWebUrlForEnv(env) {
|
|
64
|
+
if (env === "dev")
|
|
65
|
+
return DEV_WEB_URL;
|
|
66
|
+
return PROD_WEB_URL;
|
|
67
|
+
}
|
|
68
|
+
function getConvexUrl(env) {
|
|
69
|
+
if (env === "dev")
|
|
70
|
+
return DEV_CONVEX_URL;
|
|
71
|
+
return PROD_CONVEX_URL;
|
|
72
|
+
}
|
|
73
|
+
function parseEnvLocal() {
|
|
74
|
+
const envPath = path.join(process.cwd(), ".env.local");
|
|
75
|
+
if (!fs.existsSync(envPath))
|
|
76
|
+
return {};
|
|
77
|
+
const content = fs.readFileSync(envPath, "utf-8");
|
|
78
|
+
const result = {};
|
|
79
|
+
for (const line of content.split(`
|
|
80
|
+
`)) {
|
|
81
|
+
const trimmed = line.trim();
|
|
82
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
83
|
+
continue;
|
|
84
|
+
const eqIndex = trimmed.indexOf("=");
|
|
85
|
+
if (eqIndex === -1)
|
|
86
|
+
continue;
|
|
87
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
88
|
+
let value = trimmed.slice(eqIndex + 1).trim();
|
|
89
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
90
|
+
value = value.slice(1, -1);
|
|
91
|
+
}
|
|
92
|
+
result[key] = value;
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
function resolveEnv(options) {
|
|
97
|
+
if (options.dev && options.prod) {
|
|
98
|
+
console.error("Error: Cannot use both --dev and --prod flags.");
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
if (options.dev)
|
|
102
|
+
return "dev";
|
|
103
|
+
if (options.prod)
|
|
104
|
+
return "prod";
|
|
105
|
+
const envLocal = parseEnvLocal();
|
|
106
|
+
const calabasasEnv = envLocal["CALABASAS_ENV"];
|
|
107
|
+
if (calabasasEnv === "dev" || calabasasEnv === "prod") {
|
|
108
|
+
return calabasasEnv;
|
|
109
|
+
}
|
|
110
|
+
if (calabasasEnv) {
|
|
111
|
+
console.error(`Error: CALABASAS_ENV in .env.local must be "dev" or "prod", got "${calabasasEnv}".`);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
console.error("Error: Specify --dev or --prod, or set CALABASAS_ENV in .env.local");
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
async function resolveBot(options, apiKey, apiUrl, env) {
|
|
118
|
+
if (options.bot)
|
|
119
|
+
return options.bot;
|
|
120
|
+
const envLocal = parseEnvLocal();
|
|
121
|
+
const scopedKey = env === "dev" ? "CALABASAS_BOT_ID_DEV" : "CALABASAS_BOT_ID_PROD";
|
|
122
|
+
const scopedBotId = envLocal[scopedKey];
|
|
123
|
+
if (scopedBotId)
|
|
124
|
+
return scopedBotId;
|
|
125
|
+
const legacyBotId = envLocal["CALABASAS_BOT_ID"];
|
|
126
|
+
if (legacyBotId) {
|
|
127
|
+
console.warn("Warning: CALABASAS_BOT_ID is deprecated. Use CALABASAS_BOT_ID_DEV and CALABASAS_BOT_ID_PROD instead.");
|
|
128
|
+
return legacyBotId;
|
|
129
|
+
}
|
|
130
|
+
const response = await fetch(`${apiUrl}/api/cli/bots`, {
|
|
131
|
+
method: "GET",
|
|
132
|
+
headers: {
|
|
133
|
+
"Content-Type": "application/json",
|
|
134
|
+
Authorization: `Bearer ${apiKey}`
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
console.error("Error fetching bots: " + await response.text());
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
const { bots } = await response.json();
|
|
142
|
+
if (!bots || bots.length === 0) {
|
|
143
|
+
console.error("No bots found. Add a bot first with `calabasas bot add`.");
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
if (bots.length === 1) {
|
|
147
|
+
return bots[0]._id;
|
|
148
|
+
}
|
|
149
|
+
const p = await import("@clack/prompts");
|
|
150
|
+
const selected = await p.select({
|
|
151
|
+
message: "Select a bot",
|
|
152
|
+
options: bots.map((bot) => ({
|
|
153
|
+
value: bot._id,
|
|
154
|
+
label: bot.name
|
|
155
|
+
}))
|
|
156
|
+
});
|
|
157
|
+
if (p.isCancel(selected)) {
|
|
158
|
+
p.cancel("Cancelled.");
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
return selected;
|
|
162
|
+
}
|
|
163
|
+
function appendToEnvLocal(entries) {
|
|
164
|
+
const envPath = path.join(process.cwd(), ".env.local");
|
|
165
|
+
let lines = [];
|
|
166
|
+
if (fs.existsSync(envPath)) {
|
|
167
|
+
lines = fs.readFileSync(envPath, "utf-8").split(`
|
|
168
|
+
`);
|
|
169
|
+
}
|
|
170
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
171
|
+
const lineIndex = lines.findIndex((l) => {
|
|
172
|
+
const trimmed = l.trim();
|
|
173
|
+
return trimmed.startsWith(`${key}=`) || trimmed.startsWith(`${key} =`);
|
|
174
|
+
});
|
|
175
|
+
if (lineIndex !== -1) {
|
|
176
|
+
lines[lineIndex] = `${key}=${value}`;
|
|
177
|
+
} else {
|
|
178
|
+
if (!lines.some((l) => l.trim() === "# Calabasas")) {
|
|
179
|
+
if (lines.length > 0 && lines[lines.length - 1].trim() !== "") {
|
|
180
|
+
lines.push("");
|
|
181
|
+
}
|
|
182
|
+
lines.push("# Calabasas");
|
|
183
|
+
}
|
|
184
|
+
lines.push(`${key}=${value}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
fs.writeFileSync(envPath, lines.join(`
|
|
188
|
+
`));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { getConfig, saveConfig, clearConfig, isAuthenticated, getApiUrlForEnv, getWebUrlForEnv, getConvexUrl, resolveEnv, resolveBot, appendToEnvLocal };
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
resolveBot,
|
|
11
11
|
resolveEnv,
|
|
12
12
|
saveConfig
|
|
13
|
-
} from "./index-
|
|
13
|
+
} from "./index-qnd4rw0e.js";
|
|
14
14
|
import {
|
|
15
15
|
__commonJS,
|
|
16
16
|
__require,
|
|
@@ -2336,7 +2336,7 @@ async function push(options) {
|
|
|
2336
2336
|
const config = getConfig(env);
|
|
2337
2337
|
const apiKey = config.apiKey;
|
|
2338
2338
|
p4.intro("calabasas push");
|
|
2339
|
-
const botId = await resolveBot(options, apiKey, apiUrl);
|
|
2339
|
+
const botId = await resolveBot(options, apiKey, apiUrl, env);
|
|
2340
2340
|
const calabasasConfig = await parseConfigFile(configPath);
|
|
2341
2341
|
const eventConfigs = Object.keys(calabasasConfig.events ?? {}).map((eventType) => ({ eventType }));
|
|
2342
2342
|
const s = p4.spinner();
|
|
@@ -5253,18 +5253,19 @@ async function botAdd(options) {
|
|
|
5253
5253
|
p10.note(`${sharedSecret}
|
|
5254
5254
|
|
|
5255
5255
|
Add this to your Convex environment as CALABASAS_SECRET`, "Shared Secret");
|
|
5256
|
+
const botIdKey = env === "dev" ? "CALABASAS_BOT_ID_DEV" : "CALABASAS_BOT_ID_PROD";
|
|
5256
5257
|
if (nonInteractive) {
|
|
5257
|
-
appendToEnvLocal({ CALABASAS_ENV: env,
|
|
5258
|
+
appendToEnvLocal({ CALABASAS_ENV: env, [botIdKey]: botId });
|
|
5258
5259
|
p10.note(`CALABASAS_ENV=${env}
|
|
5259
|
-
|
|
5260
|
+
${botIdKey}=${botId}`, "Saved to .env.local");
|
|
5260
5261
|
} else {
|
|
5261
5262
|
const saveEnv = await p10.confirm({
|
|
5262
|
-
message:
|
|
5263
|
+
message: `Save defaults to .env.local? (CALABASAS_ENV + ${botIdKey})`
|
|
5263
5264
|
});
|
|
5264
5265
|
if (!p10.isCancel(saveEnv) && saveEnv) {
|
|
5265
|
-
appendToEnvLocal({ CALABASAS_ENV: env,
|
|
5266
|
+
appendToEnvLocal({ CALABASAS_ENV: env, [botIdKey]: botId });
|
|
5266
5267
|
p10.note(`CALABASAS_ENV=${env}
|
|
5267
|
-
|
|
5268
|
+
${botIdKey}=${botId}`, "Saved to .env.local");
|
|
5268
5269
|
}
|
|
5269
5270
|
}
|
|
5270
5271
|
p10.note("1. Run `calabasas generate` to generate the event handler\n2. Create your handler in convex/discord.ts\n3. Add CALABASAS_SECRET to your Convex environment variables", "Next steps");
|
|
@@ -5424,13 +5425,365 @@ async function botEdit(botId, options) {
|
|
|
5424
5425
|
p10.outro("Bot updated successfully!");
|
|
5425
5426
|
}
|
|
5426
5427
|
|
|
5428
|
+
// src/commands/config.ts
|
|
5429
|
+
import * as fs8 from "fs";
|
|
5430
|
+
import * as path8 from "path";
|
|
5431
|
+
import * as p11 from "@clack/prompts";
|
|
5432
|
+
import pc2 from "picocolors";
|
|
5433
|
+
|
|
5434
|
+
// src/lib/configSerializer.ts
|
|
5435
|
+
function indent(str, level) {
|
|
5436
|
+
return str.split(`
|
|
5437
|
+
`).map((line) => line.trim() === "" ? "" : " ".repeat(level) + line).join(`
|
|
5438
|
+
`);
|
|
5439
|
+
}
|
|
5440
|
+
function serializeValue(value, depth) {
|
|
5441
|
+
if (value === null || value === undefined)
|
|
5442
|
+
return "null";
|
|
5443
|
+
if (typeof value === "boolean")
|
|
5444
|
+
return String(value);
|
|
5445
|
+
if (typeof value === "number")
|
|
5446
|
+
return String(value);
|
|
5447
|
+
if (typeof value === "string")
|
|
5448
|
+
return JSON.stringify(value);
|
|
5449
|
+
if (Array.isArray(value)) {
|
|
5450
|
+
if (value.length === 0)
|
|
5451
|
+
return "[]";
|
|
5452
|
+
const allPrimitive = value.every((v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean");
|
|
5453
|
+
if (allPrimitive && value.length <= 5) {
|
|
5454
|
+
return `[${value.map((v) => serializeValue(v, depth + 1)).join(", ")}]`;
|
|
5455
|
+
}
|
|
5456
|
+
const items = value.map((v) => indent(serializeValue(v, depth + 1), depth + 1));
|
|
5457
|
+
return `[
|
|
5458
|
+
${items.join(`,
|
|
5459
|
+
`)}
|
|
5460
|
+
${" ".repeat(depth)}]`;
|
|
5461
|
+
}
|
|
5462
|
+
if (typeof value === "object") {
|
|
5463
|
+
const entries = Object.entries(value);
|
|
5464
|
+
if (entries.length === 0)
|
|
5465
|
+
return "{}";
|
|
5466
|
+
const lines = entries.map(([key, val]) => {
|
|
5467
|
+
const safeKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
|
|
5468
|
+
return `${" ".repeat(depth + 1)}${safeKey}: ${serializeValue(val, depth + 1)},`;
|
|
5469
|
+
});
|
|
5470
|
+
return `{
|
|
5471
|
+
${lines.join(`
|
|
5472
|
+
`)}
|
|
5473
|
+
${" ".repeat(depth)}}`;
|
|
5474
|
+
}
|
|
5475
|
+
return String(value);
|
|
5476
|
+
}
|
|
5477
|
+
function serializeConfig(config) {
|
|
5478
|
+
const sections = [];
|
|
5479
|
+
if (config.intents && config.intents.length > 0) {
|
|
5480
|
+
const items = config.intents.map((name) => JSON.stringify(name)).join(", ");
|
|
5481
|
+
sections.push(` intents: [${items}],`);
|
|
5482
|
+
}
|
|
5483
|
+
if (config.sync) {
|
|
5484
|
+
const syncLines = Object.entries(config.sync).map(([key, val]) => ` ${key}: ${val},`);
|
|
5485
|
+
sections.push(` sync: {
|
|
5486
|
+
${syncLines.join(`
|
|
5487
|
+
`)}
|
|
5488
|
+
},`);
|
|
5489
|
+
}
|
|
5490
|
+
if (config.events) {
|
|
5491
|
+
const eventKeys = Object.keys(config.events);
|
|
5492
|
+
if (eventKeys.length > 0) {
|
|
5493
|
+
const eventLines = eventKeys.map((key) => ` ${key}: true,`);
|
|
5494
|
+
sections.push(` events: {
|
|
5495
|
+
${eventLines.join(`
|
|
5496
|
+
`)}
|
|
5497
|
+
},`);
|
|
5498
|
+
}
|
|
5499
|
+
}
|
|
5500
|
+
if (config.commands) {
|
|
5501
|
+
const commandKeys = Object.keys(config.commands);
|
|
5502
|
+
if (commandKeys.length > 0) {
|
|
5503
|
+
const commandLines = commandKeys.map((name) => {
|
|
5504
|
+
const def = config.commands[name];
|
|
5505
|
+
const serialized = serializeValue(def, 2);
|
|
5506
|
+
return ` ${name}: ${serialized},`;
|
|
5507
|
+
});
|
|
5508
|
+
sections.push(` commands: {
|
|
5509
|
+
${commandLines.join(`
|
|
5510
|
+
`)}
|
|
5511
|
+
},`);
|
|
5512
|
+
}
|
|
5513
|
+
}
|
|
5514
|
+
return [
|
|
5515
|
+
`import { defineCalabasas } from "calabasas";`,
|
|
5516
|
+
``,
|
|
5517
|
+
`export default defineCalabasas({`,
|
|
5518
|
+
sections.join(`
|
|
5519
|
+
`),
|
|
5520
|
+
`});`,
|
|
5521
|
+
``
|
|
5522
|
+
].join(`
|
|
5523
|
+
`);
|
|
5524
|
+
}
|
|
5525
|
+
|
|
5526
|
+
// src/lib/events.ts
|
|
5527
|
+
var DISCORD_EVENTS_META = {
|
|
5528
|
+
messageCreate: { intent: "GuildMessages", privileged: false },
|
|
5529
|
+
messageUpdate: { intent: "GuildMessages", privileged: false },
|
|
5530
|
+
messageDelete: { intent: "GuildMessages", privileged: false },
|
|
5531
|
+
guildMemberAdd: { intent: "GuildMembers", privileged: true },
|
|
5532
|
+
guildMemberRemove: { intent: "GuildMembers", privileged: true },
|
|
5533
|
+
guildMemberUpdate: { intent: "GuildMembers", privileged: true },
|
|
5534
|
+
interactionCreate: { intent: null, privileged: false },
|
|
5535
|
+
voiceStateUpdate: { intent: "GuildVoiceStates", privileged: false },
|
|
5536
|
+
presenceUpdate: { intent: "GuildPresences", privileged: true },
|
|
5537
|
+
typingStart: { intent: "GuildMessageTyping", privileged: false },
|
|
5538
|
+
messageReactionAdd: { intent: "GuildMessageReactions", privileged: false },
|
|
5539
|
+
messageReactionRemove: { intent: "GuildMessageReactions", privileged: false }
|
|
5540
|
+
};
|
|
5541
|
+
|
|
5542
|
+
// src/lib/sync.ts
|
|
5543
|
+
var SYNC_PROPERTIES_META = {
|
|
5544
|
+
guilds: { intent: null, privileged: false, description: "Sync guild/server info" },
|
|
5545
|
+
channels: { intent: null, privileged: false, description: "Sync channels" },
|
|
5546
|
+
roles: { intent: null, privileged: false, description: "Sync roles" },
|
|
5547
|
+
members: { intent: "GuildMembers", privileged: true, description: "Sync members" },
|
|
5548
|
+
presence: { intent: "GuildPresences", privileged: true, description: "Sync online status" }
|
|
5549
|
+
};
|
|
5550
|
+
|
|
5551
|
+
// src/commands/config.ts
|
|
5552
|
+
var ALL_EVENTS = Object.keys(DISCORD_EVENTS_META);
|
|
5553
|
+
var ALL_SYNC = Object.keys(SYNC_PROPERTIES_META);
|
|
5554
|
+
function resolveConfigPath(configOption) {
|
|
5555
|
+
return path8.resolve(process.cwd(), configOption);
|
|
5556
|
+
}
|
|
5557
|
+
function validateEventNames(names) {
|
|
5558
|
+
const valid = [];
|
|
5559
|
+
const invalid = [];
|
|
5560
|
+
for (const name of names) {
|
|
5561
|
+
if (ALL_EVENTS.includes(name)) {
|
|
5562
|
+
valid.push(name);
|
|
5563
|
+
} else {
|
|
5564
|
+
invalid.push(name);
|
|
5565
|
+
}
|
|
5566
|
+
}
|
|
5567
|
+
return { valid, invalid };
|
|
5568
|
+
}
|
|
5569
|
+
function validateSyncNames(names) {
|
|
5570
|
+
const valid = [];
|
|
5571
|
+
const invalid = [];
|
|
5572
|
+
for (const name of names) {
|
|
5573
|
+
if (ALL_SYNC.includes(name)) {
|
|
5574
|
+
valid.push(name);
|
|
5575
|
+
} else {
|
|
5576
|
+
invalid.push(name);
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5579
|
+
return { valid, invalid };
|
|
5580
|
+
}
|
|
5581
|
+
function intentHint(intent, privileged) {
|
|
5582
|
+
if (!intent)
|
|
5583
|
+
return "";
|
|
5584
|
+
const tag = privileged ? pc2.yellow(`requires ${intent} privileged intent`) : pc2.dim(`requires ${intent} intent`);
|
|
5585
|
+
return ` ${tag}`;
|
|
5586
|
+
}
|
|
5587
|
+
function listConfig(config, configPath) {
|
|
5588
|
+
const relPath = path8.relative(process.cwd(), configPath);
|
|
5589
|
+
console.log(`
|
|
5590
|
+
${pc2.bold("Calabasas Config")} ${pc2.dim(`(${relPath})`)}
|
|
5591
|
+
`);
|
|
5592
|
+
console.log(pc2.bold("Sync:"));
|
|
5593
|
+
for (const key of ALL_SYNC) {
|
|
5594
|
+
const meta = SYNC_PROPERTIES_META[key];
|
|
5595
|
+
const enabled = config.sync?.[key] === true;
|
|
5596
|
+
const dot = enabled ? pc2.green(" ●") : pc2.dim(" ○");
|
|
5597
|
+
const hint = !enabled ? intentHint(meta.intent, meta.privileged) : "";
|
|
5598
|
+
console.log(`${dot} ${key}${hint}`);
|
|
5599
|
+
}
|
|
5600
|
+
console.log(`
|
|
5601
|
+
${pc2.bold("Events:")}`);
|
|
5602
|
+
const enabledEvents = new Set(Object.keys(config.events ?? {}));
|
|
5603
|
+
for (const key of ALL_EVENTS) {
|
|
5604
|
+
const meta = DISCORD_EVENTS_META[key];
|
|
5605
|
+
const enabled = enabledEvents.has(key);
|
|
5606
|
+
const dot = enabled ? pc2.green(" ●") : pc2.dim(" ○");
|
|
5607
|
+
const hint = !enabled ? intentHint(meta.intent, meta.privileged) : "";
|
|
5608
|
+
console.log(`${dot} ${key}${hint}`);
|
|
5609
|
+
}
|
|
5610
|
+
const commandNames = Object.keys(config.commands ?? {});
|
|
5611
|
+
if (commandNames.length > 0) {
|
|
5612
|
+
console.log(`
|
|
5613
|
+
${pc2.bold("Commands:")}`);
|
|
5614
|
+
for (const name of commandNames) {
|
|
5615
|
+
console.log(` /${name} — ${config.commands[name].description}`);
|
|
5616
|
+
}
|
|
5617
|
+
}
|
|
5618
|
+
console.log("");
|
|
5619
|
+
}
|
|
5620
|
+
async function interactiveConfig(config, configPath) {
|
|
5621
|
+
p11.intro("calabasas config");
|
|
5622
|
+
const syncSelection = await p11.multiselect({
|
|
5623
|
+
message: "Select sync properties to enable",
|
|
5624
|
+
options: ALL_SYNC.map((key) => {
|
|
5625
|
+
const meta = SYNC_PROPERTIES_META[key];
|
|
5626
|
+
const hint = meta.privileged ? `${meta.description} (Privileged)` : meta.description;
|
|
5627
|
+
return {
|
|
5628
|
+
value: key,
|
|
5629
|
+
label: meta.privileged ? pc2.yellow(key) : key,
|
|
5630
|
+
hint
|
|
5631
|
+
};
|
|
5632
|
+
}),
|
|
5633
|
+
initialValues: ALL_SYNC.filter((key) => config.sync?.[key] === true),
|
|
5634
|
+
required: false
|
|
5635
|
+
});
|
|
5636
|
+
if (p11.isCancel(syncSelection)) {
|
|
5637
|
+
p11.cancel("Cancelled.");
|
|
5638
|
+
return;
|
|
5639
|
+
}
|
|
5640
|
+
const eventSelection = await p11.multiselect({
|
|
5641
|
+
message: "Select events to enable",
|
|
5642
|
+
options: ALL_EVENTS.map((key) => {
|
|
5643
|
+
const meta = DISCORD_EVENTS_META[key];
|
|
5644
|
+
const hint = meta.intent ? meta.privileged ? `${meta.intent} (Privileged)` : meta.intent : "No intent required";
|
|
5645
|
+
return {
|
|
5646
|
+
value: key,
|
|
5647
|
+
label: meta.privileged ? pc2.yellow(key) : key,
|
|
5648
|
+
hint
|
|
5649
|
+
};
|
|
5650
|
+
}),
|
|
5651
|
+
initialValues: Object.keys(config.events ?? {}),
|
|
5652
|
+
required: false
|
|
5653
|
+
});
|
|
5654
|
+
if (p11.isCancel(eventSelection)) {
|
|
5655
|
+
p11.cancel("Cancelled.");
|
|
5656
|
+
return;
|
|
5657
|
+
}
|
|
5658
|
+
const selectedSync = new Set(syncSelection);
|
|
5659
|
+
const selectedEvents = new Set(eventSelection);
|
|
5660
|
+
const newConfig = { ...config };
|
|
5661
|
+
const newSync = {};
|
|
5662
|
+
for (const key of ALL_SYNC) {
|
|
5663
|
+
newSync[key] = selectedSync.has(key);
|
|
5664
|
+
}
|
|
5665
|
+
newConfig.sync = newSync;
|
|
5666
|
+
const newEvents = {};
|
|
5667
|
+
for (const key of selectedEvents) {
|
|
5668
|
+
newEvents[key] = true;
|
|
5669
|
+
}
|
|
5670
|
+
newConfig.events = newEvents;
|
|
5671
|
+
const oldSync = config.sync ?? {};
|
|
5672
|
+
const oldEvents = new Set(Object.keys(config.events ?? {}));
|
|
5673
|
+
const syncChanged = ALL_SYNC.some((key) => oldSync[key] === true !== selectedSync.has(key));
|
|
5674
|
+
const eventsChanged = selectedEvents.size !== oldEvents.size || [...selectedEvents].some((e) => !oldEvents.has(e));
|
|
5675
|
+
if (!syncChanged && !eventsChanged) {
|
|
5676
|
+
p11.outro("No changes.");
|
|
5677
|
+
return;
|
|
5678
|
+
}
|
|
5679
|
+
const changes = [];
|
|
5680
|
+
for (const key of ALL_SYNC) {
|
|
5681
|
+
const was = oldSync[key] === true;
|
|
5682
|
+
const now = selectedSync.has(key);
|
|
5683
|
+
if (was && !now)
|
|
5684
|
+
changes.push(`sync.${key}: ${pc2.red("enabled → disabled")}`);
|
|
5685
|
+
if (!was && now)
|
|
5686
|
+
changes.push(`sync.${key}: ${pc2.green("disabled → enabled")}`);
|
|
5687
|
+
}
|
|
5688
|
+
for (const key of ALL_EVENTS) {
|
|
5689
|
+
const was = oldEvents.has(key);
|
|
5690
|
+
const now = selectedEvents.has(key);
|
|
5691
|
+
if (was && !now)
|
|
5692
|
+
changes.push(`events.${key}: ${pc2.red("enabled → disabled")}`);
|
|
5693
|
+
if (!was && now)
|
|
5694
|
+
changes.push(`events.${key}: ${pc2.green("disabled → enabled")}`);
|
|
5695
|
+
}
|
|
5696
|
+
p11.note(changes.join(`
|
|
5697
|
+
`), "Changes");
|
|
5698
|
+
const source = serializeConfig(newConfig);
|
|
5699
|
+
fs8.writeFileSync(configPath, source);
|
|
5700
|
+
p11.log.info(pc2.dim("Note: Comments in the original file are not preserved."));
|
|
5701
|
+
p11.outro(`Updated ${path8.relative(process.cwd(), configPath)}. Run ${pc2.cyan("`calabasas generate`")} to regenerate code.`);
|
|
5702
|
+
}
|
|
5703
|
+
async function config(options) {
|
|
5704
|
+
const configPath = resolveConfigPath(options.config);
|
|
5705
|
+
if (!fs8.existsSync(configPath)) {
|
|
5706
|
+
console.error(`Error: Config file not found: ${configPath}`);
|
|
5707
|
+
console.error(`
|
|
5708
|
+
Run ${pc2.cyan("`calabasas init`")} first.`);
|
|
5709
|
+
process.exit(1);
|
|
5710
|
+
}
|
|
5711
|
+
const currentConfig = await parseConfigFile(configPath);
|
|
5712
|
+
if (options.list) {
|
|
5713
|
+
listConfig(currentConfig, configPath);
|
|
5714
|
+
return;
|
|
5715
|
+
}
|
|
5716
|
+
const hasFlags = options.addEvent?.length || options.removeEvent?.length || options.addSync?.length || options.removeSync?.length;
|
|
5717
|
+
if (hasFlags) {
|
|
5718
|
+
if (options.addEvent?.length) {
|
|
5719
|
+
const { invalid } = validateEventNames(options.addEvent);
|
|
5720
|
+
if (invalid.length > 0) {
|
|
5721
|
+
console.error(`Error: Unknown event names: ${invalid.join(", ")}`);
|
|
5722
|
+
console.error(`Valid events: ${ALL_EVENTS.join(", ")}`);
|
|
5723
|
+
process.exit(1);
|
|
5724
|
+
}
|
|
5725
|
+
}
|
|
5726
|
+
if (options.removeEvent?.length) {
|
|
5727
|
+
const { invalid } = validateEventNames(options.removeEvent);
|
|
5728
|
+
if (invalid.length > 0) {
|
|
5729
|
+
console.error(`Error: Unknown event names: ${invalid.join(", ")}`);
|
|
5730
|
+
console.error(`Valid events: ${ALL_EVENTS.join(", ")}`);
|
|
5731
|
+
process.exit(1);
|
|
5732
|
+
}
|
|
5733
|
+
}
|
|
5734
|
+
if (options.addSync?.length) {
|
|
5735
|
+
const { invalid } = validateSyncNames(options.addSync);
|
|
5736
|
+
if (invalid.length > 0) {
|
|
5737
|
+
console.error(`Error: Unknown sync properties: ${invalid.join(", ")}`);
|
|
5738
|
+
console.error(`Valid properties: ${ALL_SYNC.join(", ")}`);
|
|
5739
|
+
process.exit(1);
|
|
5740
|
+
}
|
|
5741
|
+
}
|
|
5742
|
+
if (options.removeSync?.length) {
|
|
5743
|
+
const { invalid } = validateSyncNames(options.removeSync);
|
|
5744
|
+
if (invalid.length > 0) {
|
|
5745
|
+
console.error(`Error: Unknown sync properties: ${invalid.join(", ")}`);
|
|
5746
|
+
console.error(`Valid properties: ${ALL_SYNC.join(", ")}`);
|
|
5747
|
+
process.exit(1);
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5750
|
+
const newConfig = { ...currentConfig };
|
|
5751
|
+
if (options.addSync?.length || options.removeSync?.length) {
|
|
5752
|
+
const sync = { ...currentConfig.sync };
|
|
5753
|
+
for (const name of options.addSync ?? []) {
|
|
5754
|
+
sync[name] = true;
|
|
5755
|
+
}
|
|
5756
|
+
for (const name of options.removeSync ?? []) {
|
|
5757
|
+
sync[name] = false;
|
|
5758
|
+
}
|
|
5759
|
+
newConfig.sync = sync;
|
|
5760
|
+
}
|
|
5761
|
+
if (options.addEvent?.length || options.removeEvent?.length) {
|
|
5762
|
+
const events = { ...currentConfig.events };
|
|
5763
|
+
for (const name of options.addEvent ?? []) {
|
|
5764
|
+
events[name] = true;
|
|
5765
|
+
}
|
|
5766
|
+
for (const name of options.removeEvent ?? []) {
|
|
5767
|
+
delete events[name];
|
|
5768
|
+
}
|
|
5769
|
+
newConfig.events = events;
|
|
5770
|
+
}
|
|
5771
|
+
const source = serializeConfig(newConfig);
|
|
5772
|
+
fs8.writeFileSync(configPath, source);
|
|
5773
|
+
console.log(`Updated ${path8.relative(process.cwd(), configPath)}.`);
|
|
5774
|
+
console.log(`Run ${pc2.cyan("`calabasas generate`")} to regenerate code.`);
|
|
5775
|
+
return;
|
|
5776
|
+
}
|
|
5777
|
+
await interactiveConfig(currentConfig, configPath);
|
|
5778
|
+
}
|
|
5779
|
+
|
|
5427
5780
|
// src/index.ts
|
|
5428
5781
|
var dashboard = async (...args) => {
|
|
5429
|
-
const mod = await import("./dashboard-
|
|
5782
|
+
const mod = await import("./dashboard-r2cptf7m.js");
|
|
5430
5783
|
return mod.dashboard(args[0]);
|
|
5431
5784
|
};
|
|
5432
5785
|
var logs = async (...args) => {
|
|
5433
|
-
const mod = await import("./logs-
|
|
5786
|
+
const mod = await import("./logs-452qgkw7.js");
|
|
5434
5787
|
return mod.logs(args[0], args[1]);
|
|
5435
5788
|
};
|
|
5436
5789
|
var program2 = new Command;
|
|
@@ -5443,6 +5796,7 @@ program2.command("generate").description("Generate type-safe Discord handlers an
|
|
|
5443
5796
|
program2.command("skill").description("Generate Calabasas documentation for AI assistants").option("--dev", "Use development environment").option("--prod", "Use production environment").option("-f, --file <path>", "Target file path (e.g. CLAUDE.md)").option("-y, --yes", "Auto-confirm replacing existing guidelines").action(skill);
|
|
5444
5797
|
program2.command("add [components...]").description("Add Discord UI components to your project").action(add);
|
|
5445
5798
|
program2.command("migrate [name]").description("Run a codemod migration (list available if no name given)").action(migrate);
|
|
5799
|
+
program2.command("config").description("View and modify your Calabasas config").option("-c, --config <path>", "Path to config file", "convex/calabasas/config.ts").option("-l, --list", "List current and available config options").option("--add-event <events...>", "Enable event handlers").option("--remove-event <events...>", "Disable event handlers").option("--add-sync <properties...>", "Enable sync properties").option("--remove-sync <properties...>", "Disable sync properties").action(config);
|
|
5446
5800
|
program2.command("status").alias("dashboard").description("Real-time dashboard showing bot status, events, and stats").option("--dev", "Use development environment").option("--prod", "Use production environment").action(dashboard);
|
|
5447
5801
|
program2.command("logs [botId]").description("Live event log viewer for a bot").option("-n, --limit <number>", "Number of log entries to show", "50").option("--dev", "Use development environment").option("--prod", "Use production environment").action(logs);
|
|
5448
5802
|
var bot = program2.command("bot").description("Manage Discord bots");
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LogViewer
|
|
3
|
+
} from "./index-f8td7thj.js";
|
|
4
|
+
import {
|
|
5
|
+
getApiUrlForEnv,
|
|
6
|
+
getConfig,
|
|
7
|
+
getConvexUrl,
|
|
8
|
+
isAuthenticated,
|
|
9
|
+
resolveBot,
|
|
10
|
+
resolveEnv
|
|
11
|
+
} from "./index-qnd4rw0e.js";
|
|
12
|
+
import"./index-8gymgyxd.js";
|
|
13
|
+
import"./index-tre7d3f1.js";
|
|
14
|
+
import {
|
|
15
|
+
__toESM
|
|
16
|
+
} from "./index-sdksp5px.js";
|
|
17
|
+
import {
|
|
18
|
+
render_default,
|
|
19
|
+
use_app_default,
|
|
20
|
+
use_input_default
|
|
21
|
+
} from "./index-4rn9k8et.js";
|
|
22
|
+
import {
|
|
23
|
+
ConvexProvider,
|
|
24
|
+
createConvexClient,
|
|
25
|
+
require_jsx_dev_runtime
|
|
26
|
+
} from "./convex-1z1jsz1n.js";
|
|
27
|
+
import"./index-vmy4gfe1.js";
|
|
28
|
+
|
|
29
|
+
// src/commands/logs.tsx
|
|
30
|
+
var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
|
|
31
|
+
function LogsApp({ apiKey, botId, limit }) {
|
|
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
|
+
}, undefined, false, undefined, this);
|
|
43
|
+
}
|
|
44
|
+
async function logs(botId, options) {
|
|
45
|
+
const env = resolveEnv(options);
|
|
46
|
+
if (!isAuthenticated(env)) {
|
|
47
|
+
console.log("Not logged in. Run `calabasas login` first.");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const config = getConfig(env);
|
|
51
|
+
const apiKey = config.apiKey;
|
|
52
|
+
const apiUrl = getApiUrlForEnv(env);
|
|
53
|
+
botId = await resolveBot({ bot: botId }, apiKey, apiUrl, env);
|
|
54
|
+
const limit = options.limit ? parseInt(options.limit, 10) : 50;
|
|
55
|
+
const convexUrl = getConvexUrl(env);
|
|
56
|
+
const client = createConvexClient(convexUrl);
|
|
57
|
+
const { waitUntilExit } = render_default(/* @__PURE__ */ jsx_dev_runtime.jsxDEV(ConvexProvider, {
|
|
58
|
+
client,
|
|
59
|
+
children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(LogsApp, {
|
|
60
|
+
apiKey,
|
|
61
|
+
botId,
|
|
62
|
+
limit
|
|
63
|
+
}, undefined, false, undefined, this)
|
|
64
|
+
}, undefined, false, undefined, this));
|
|
65
|
+
await waitUntilExit();
|
|
66
|
+
await client.close();
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
logs
|
|
70
|
+
};
|