calabasas 0.4.0 → 0.5.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/index.js +284 -85
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2236,7 +2236,8 @@ export default defineCalabasas({
|
|
|
2236
2236
|
`;
|
|
2237
2237
|
async function init() {
|
|
2238
2238
|
const convexDir = path.resolve(process.cwd(), "convex");
|
|
2239
|
-
const
|
|
2239
|
+
const calabasasDir = path.join(convexDir, "calabasas");
|
|
2240
|
+
const configPath = path.join(calabasasDir, "config.ts");
|
|
2240
2241
|
p3.intro("calabasas init");
|
|
2241
2242
|
if (!fs.existsSync(convexDir)) {
|
|
2242
2243
|
p3.cancel(`convex/ directory not found.
|
|
@@ -2246,15 +2247,18 @@ Run \`npx convex dev\` to initialize a new Convex project.`);
|
|
|
2246
2247
|
process.exit(1);
|
|
2247
2248
|
}
|
|
2248
2249
|
if (fs.existsSync(configPath)) {
|
|
2249
|
-
p3.cancel(`convex/calabasas
|
|
2250
|
+
p3.cancel(`convex/calabasas/config.ts already exists.
|
|
2250
2251
|
|
|
2251
2252
|
Delete the existing file if you want to start fresh:
|
|
2252
|
-
rm convex/calabasas
|
|
2253
|
+
rm convex/calabasas/config.ts`);
|
|
2253
2254
|
process.exit(1);
|
|
2254
2255
|
}
|
|
2256
|
+
if (!fs.existsSync(calabasasDir)) {
|
|
2257
|
+
fs.mkdirSync(calabasasDir, { recursive: true });
|
|
2258
|
+
}
|
|
2255
2259
|
fs.writeFileSync(configPath, CONFIG_TEMPLATE);
|
|
2256
|
-
p3.note("1. Edit convex/calabasas
|
|
2257
|
-
p3.outro("Created convex/calabasas
|
|
2260
|
+
p3.note("1. Edit convex/calabasas/config.ts to configure sync and events\n2. Run `calabasas generate` to generate type-safe handlers\n3. Run `calabasas push` to sync config with Calabasas", "Next steps");
|
|
2261
|
+
p3.outro("Created convex/calabasas/config.ts");
|
|
2258
2262
|
}
|
|
2259
2263
|
|
|
2260
2264
|
// src/commands/push.ts
|
|
@@ -2321,7 +2325,7 @@ async function push(options) {
|
|
|
2321
2325
|
const configPath = path3.resolve(process.cwd(), options.config);
|
|
2322
2326
|
if (!fs3.existsSync(configPath)) {
|
|
2323
2327
|
console.error(`Error: Config file not found: ${configPath}`);
|
|
2324
|
-
console.error("\nRun `calabasas init` to create a
|
|
2328
|
+
console.error("\nRun `calabasas init` to create a config file.");
|
|
2325
2329
|
process.exit(1);
|
|
2326
2330
|
}
|
|
2327
2331
|
if (!isAuthenticated(env)) {
|
|
@@ -2840,7 +2844,7 @@ export const syncGuildAdmins = mutation({
|
|
|
2840
2844
|
if (!expectedSecret || secret !== expectedSecret) {
|
|
2841
2845
|
throw new Error("Invalid secret");
|
|
2842
2846
|
}
|
|
2843
|
-
await ctx.runMutation(internal.calabasas.sync._syncGuildAdmins, { data });
|
|
2847
|
+
await ctx.runMutation(internal.calabasas._generated.sync._syncGuildAdmins, { data });
|
|
2844
2848
|
return null;
|
|
2845
2849
|
},
|
|
2846
2850
|
});`;
|
|
@@ -2864,7 +2868,7 @@ export const sync${capitalType} = mutation({
|
|
|
2864
2868
|
if (!expectedSecret || secret !== expectedSecret) {
|
|
2865
2869
|
throw new Error("Invalid secret");
|
|
2866
2870
|
}
|
|
2867
|
-
await ctx.runMutation(internal.calabasas.sync._sync${capitalType}, { data, operation });
|
|
2871
|
+
await ctx.runMutation(internal.calabasas._generated.sync._sync${capitalType}, { data, operation });
|
|
2868
2872
|
return null;
|
|
2869
2873
|
},
|
|
2870
2874
|
});`;
|
|
@@ -2920,7 +2924,7 @@ function generateSyncFile(sync) {
|
|
|
2920
2924
|
* updated, run \`calabasas generate\` to regenerate it from the config.
|
|
2921
2925
|
* Editing this file directly will cause your changes to be overwritten.
|
|
2922
2926
|
*
|
|
2923
|
-
* No sync handlers configured - enable sync options in calabasas
|
|
2927
|
+
* No sync handlers configured - enable sync options in convex/calabasas/config.ts
|
|
2924
2928
|
*/
|
|
2925
2929
|
|
|
2926
2930
|
export {};
|
|
@@ -2936,8 +2940,8 @@ export {};
|
|
|
2936
2940
|
* Editing this file directly will cause your changes to be overwritten.
|
|
2937
2941
|
*/
|
|
2938
2942
|
|
|
2939
|
-
import { mutation, internalMutation } from "
|
|
2940
|
-
import { internal } from "
|
|
2943
|
+
import { mutation, internalMutation } from "../../_generated/server";
|
|
2944
|
+
import { internal } from "../../_generated/api";
|
|
2941
2945
|
import { v } from "convex/values";
|
|
2942
2946
|
|
|
2943
2947
|
// ============================================================================
|
|
@@ -3273,9 +3277,9 @@ function generateHandlersCode(eventNames) {
|
|
|
3273
3277
|
* Editing this file directly will cause your changes to be overwritten.
|
|
3274
3278
|
*/
|
|
3275
3279
|
|
|
3276
|
-
import { mutation } from "
|
|
3280
|
+
import { mutation } from "../../_generated/server";
|
|
3277
3281
|
import { v } from "convex/values";
|
|
3278
|
-
import type { MutationCtx } from "
|
|
3282
|
+
import type { MutationCtx } from "../../_generated/server";
|
|
3279
3283
|
|
|
3280
3284
|
// Event type validators
|
|
3281
3285
|
${eventNames.map((name) => `const ${name}Validator = ${generateValidatorForEvent(name)};`).join(`
|
|
@@ -3496,17 +3500,27 @@ export const discord = {
|
|
|
3496
3500
|
}
|
|
3497
3501
|
async function generate(options) {
|
|
3498
3502
|
const convexDir = path4.resolve(process.cwd(), "convex");
|
|
3499
|
-
const
|
|
3503
|
+
const calabasasDir = path4.join(convexDir, "calabasas");
|
|
3504
|
+
const configPath = path4.join(calabasasDir, "config.ts");
|
|
3505
|
+
const legacyConfigPath = path4.join(convexDir, "calabasas.config.ts");
|
|
3500
3506
|
p5.intro("calabasas generate");
|
|
3501
3507
|
let config = { sync: {}, events: {} };
|
|
3502
3508
|
if (fs4.existsSync(configPath)) {
|
|
3503
3509
|
config = await parseConfigFile(configPath);
|
|
3510
|
+
} else if (fs4.existsSync(legacyConfigPath)) {
|
|
3511
|
+
p5.log.warn("Found config at legacy path convex/calabasas.config.ts");
|
|
3512
|
+
p5.log.info("Run `calabasas migrate dedicated-folder` to move files to the new layout.");
|
|
3513
|
+
config = await parseConfigFile(legacyConfigPath);
|
|
3504
3514
|
} else {
|
|
3505
|
-
p5.log.warn("No
|
|
3515
|
+
p5.log.warn("No config found, generating with default settings...");
|
|
3506
3516
|
p5.log.info("Run `calabasas init` to create a config file.");
|
|
3507
3517
|
}
|
|
3508
3518
|
const s = p5.spinner();
|
|
3509
3519
|
s.start("Generating files...");
|
|
3520
|
+
const generatedDir = path4.join(calabasasDir, "_generated");
|
|
3521
|
+
if (!fs4.existsSync(generatedDir)) {
|
|
3522
|
+
fs4.mkdirSync(generatedDir, { recursive: true });
|
|
3523
|
+
}
|
|
3510
3524
|
const eventHandlersPath = path4.resolve(process.cwd(), options.output);
|
|
3511
3525
|
const eventHandlersCode = generateEventHandlersFile(config.events ?? {});
|
|
3512
3526
|
fs4.writeFileSync(eventHandlersPath, eventHandlersCode);
|
|
@@ -3514,23 +3528,19 @@ async function generate(options) {
|
|
|
3514
3528
|
const syncConfig = config.sync ?? {};
|
|
3515
3529
|
const hasSyncEnabled = syncConfig.guilds || syncConfig.channels || syncConfig.roles || syncConfig.members;
|
|
3516
3530
|
if (hasSyncEnabled) {
|
|
3517
|
-
const
|
|
3518
|
-
if (!fs4.existsSync(calabasasDir)) {
|
|
3519
|
-
fs4.mkdirSync(calabasasDir, { recursive: true });
|
|
3520
|
-
}
|
|
3521
|
-
const schemaPath = path4.join(calabasasDir, "schema.ts");
|
|
3531
|
+
const schemaPath = path4.join(generatedDir, "schema.ts");
|
|
3522
3532
|
const schemaCode = generateSchemaFile(syncConfig);
|
|
3523
3533
|
fs4.writeFileSync(schemaPath, schemaCode);
|
|
3524
|
-
generated.push("convex/calabasas/schema.ts");
|
|
3525
|
-
const syncPath = path4.join(
|
|
3534
|
+
generated.push("convex/calabasas/_generated/schema.ts");
|
|
3535
|
+
const syncPath = path4.join(generatedDir, "sync.ts");
|
|
3526
3536
|
const syncCode = generateSyncFile(syncConfig);
|
|
3527
3537
|
fs4.writeFileSync(syncPath, syncCode);
|
|
3528
|
-
generated.push("convex/calabasas/sync.ts");
|
|
3538
|
+
generated.push("convex/calabasas/_generated/sync.ts");
|
|
3529
3539
|
}
|
|
3530
|
-
const actionsPath = path4.join(
|
|
3540
|
+
const actionsPath = path4.join(generatedDir, "discord.actions.ts");
|
|
3531
3541
|
const actionsCode = generateActionsFile();
|
|
3532
3542
|
fs4.writeFileSync(actionsPath, actionsCode);
|
|
3533
|
-
generated.push("convex/discord.actions.
|
|
3543
|
+
generated.push("convex/calabasas/_generated/discord.actions.ts");
|
|
3534
3544
|
s.stop(`Generated ${generated.length} file${generated.length > 1 ? "s" : ""}`);
|
|
3535
3545
|
p5.note(generated.join(`
|
|
3536
3546
|
`), "Generated files");
|
|
@@ -3547,14 +3557,14 @@ async function generate(options) {
|
|
|
3547
3557
|
if (syncConfig.members)
|
|
3548
3558
|
syncExports.push("syncMember");
|
|
3549
3559
|
p5.note(`1. Add tables to your convex/schema.ts:
|
|
3550
|
-
import { calabasasTables } from "./calabasas/schema";
|
|
3560
|
+
import { calabasasTables } from "./calabasas/_generated/schema";
|
|
3551
3561
|
|
|
3552
3562
|
export default defineSchema({
|
|
3553
3563
|
...calabasasTables,
|
|
3554
3564
|
});
|
|
3555
3565
|
|
|
3556
3566
|
2. Re-export sync mutations in convex/discord.ts:
|
|
3557
|
-
export { ${syncExports.join(", ")} } from "./calabasas/sync";
|
|
3567
|
+
export { ${syncExports.join(", ")} } from "./calabasas/_generated/sync";
|
|
3558
3568
|
|
|
3559
3569
|
3. Add CALABASAS_SECRET to your Convex environment variables
|
|
3560
3570
|
4. Create your event handler in convex/discord.ts
|
|
@@ -3563,7 +3573,7 @@ async function generate(options) {
|
|
|
3563
3573
|
p5.note(`1. Add CALABASAS_SECRET to your Convex environment variables
|
|
3564
3574
|
2. Create your handler in convex/discord.ts:
|
|
3565
3575
|
|
|
3566
|
-
import { handleDiscordEvent } from "./discord
|
|
3576
|
+
import { handleDiscordEvent } from "./calabasas/_generated/discord";
|
|
3567
3577
|
|
|
3568
3578
|
export const receive = handleDiscordEvent({
|
|
3569
3579
|
messageCreate: async (ctx, event) => {
|
|
@@ -5702,9 +5712,10 @@ async function add(componentNames) {
|
|
|
5702
5712
|
const cwd = process.cwd();
|
|
5703
5713
|
const convexDir = path6.resolve(cwd, "convex");
|
|
5704
5714
|
const calabasasDir = path6.join(convexDir, "calabasas");
|
|
5705
|
-
const configPath = path6.join(
|
|
5706
|
-
|
|
5707
|
-
|
|
5715
|
+
const configPath = path6.join(calabasasDir, "config.ts");
|
|
5716
|
+
const generatedDir = path6.join(calabasasDir, "_generated");
|
|
5717
|
+
if (!fs6.existsSync(generatedDir) || !fs6.existsSync(path6.join(generatedDir, "schema.ts"))) {
|
|
5718
|
+
console.log("Error: convex/calabasas/_generated/schema.ts not found.");
|
|
5708
5719
|
console.log("");
|
|
5709
5720
|
console.log("Run `calabasas init` and `calabasas generate` first to enable sync.");
|
|
5710
5721
|
return;
|
|
@@ -5755,7 +5766,7 @@ async function add(componentNames) {
|
|
|
5755
5766
|
const missingSyncTypes = comp.requiredSyncTypes.filter((t) => !enabledSync.has(t));
|
|
5756
5767
|
if (missingSyncTypes.length > 0) {
|
|
5757
5768
|
p7.log.warn(`Skipped ${comp.name} — requires sync types not enabled: ${missingSyncTypes.join(", ")}`);
|
|
5758
|
-
p7.log.info(`Enable them in calabasas
|
|
5769
|
+
p7.log.info(`Enable them in convex/calabasas/config.ts and re-run \`calabasas generate\`.`);
|
|
5759
5770
|
continue;
|
|
5760
5771
|
}
|
|
5761
5772
|
if (!fs6.existsSync(componentsDir)) {
|
|
@@ -5858,8 +5869,195 @@ ${props}
|
|
|
5858
5869
|
}
|
|
5859
5870
|
}
|
|
5860
5871
|
|
|
5861
|
-
// src/commands/
|
|
5872
|
+
// src/commands/migrate.ts
|
|
5873
|
+
import * as p9 from "@clack/prompts";
|
|
5874
|
+
|
|
5875
|
+
// src/migrations/dedicated-folder.ts
|
|
5876
|
+
import * as fs7 from "fs";
|
|
5877
|
+
import * as path7 from "path";
|
|
5862
5878
|
import * as p8 from "@clack/prompts";
|
|
5879
|
+
var FILE_MOVES = [
|
|
5880
|
+
["convex/calabasas.config.ts", "convex/calabasas/config.ts"],
|
|
5881
|
+
["convex/discord.generated.ts", "convex/calabasas/_generated/discord.ts"],
|
|
5882
|
+
[
|
|
5883
|
+
"convex/discord.actions.generated.ts",
|
|
5884
|
+
"convex/calabasas/_generated/discord.actions.ts"
|
|
5885
|
+
],
|
|
5886
|
+
["convex/calabasas/schema.ts", "convex/calabasas/_generated/schema.ts"],
|
|
5887
|
+
["convex/calabasas/sync.ts", "convex/calabasas/_generated/sync.ts"]
|
|
5888
|
+
];
|
|
5889
|
+
var IMPORT_REWRITES = [
|
|
5890
|
+
[
|
|
5891
|
+
/from\s+["']\.\/discord\.generated["']/g,
|
|
5892
|
+
`from "./calabasas/_generated/discord"`
|
|
5893
|
+
],
|
|
5894
|
+
[
|
|
5895
|
+
/from\s+["']\.\/discord\.actions\.generated["']/g,
|
|
5896
|
+
`from "./calabasas/_generated/discord.actions"`
|
|
5897
|
+
],
|
|
5898
|
+
[
|
|
5899
|
+
/from\s+["']\.\/calabasas\/schema["']/g,
|
|
5900
|
+
`from "./calabasas/_generated/schema"`
|
|
5901
|
+
],
|
|
5902
|
+
[
|
|
5903
|
+
/from\s+["']\.\/calabasas\/sync["']/g,
|
|
5904
|
+
`from "./calabasas/_generated/sync"`
|
|
5905
|
+
]
|
|
5906
|
+
];
|
|
5907
|
+
var GENERATED_IMPORT_REWRITES = {
|
|
5908
|
+
"convex/calabasas/_generated/discord.ts": [
|
|
5909
|
+
[
|
|
5910
|
+
/from\s+["']\.\/(_generated\/server)["']/g,
|
|
5911
|
+
`from "../../_generated/server"`
|
|
5912
|
+
],
|
|
5913
|
+
[
|
|
5914
|
+
/from\s+["']\.\/(_generated\/api)["']/g,
|
|
5915
|
+
`from "../../_generated/api"`
|
|
5916
|
+
]
|
|
5917
|
+
],
|
|
5918
|
+
"convex/calabasas/_generated/sync.ts": [
|
|
5919
|
+
[
|
|
5920
|
+
/from\s+["']\.\.\/(_generated\/server)["']/g,
|
|
5921
|
+
`from "../../_generated/server"`
|
|
5922
|
+
],
|
|
5923
|
+
[
|
|
5924
|
+
/from\s+["']\.\.\/(_generated\/api)["']/g,
|
|
5925
|
+
`from "../../_generated/api"`
|
|
5926
|
+
]
|
|
5927
|
+
]
|
|
5928
|
+
};
|
|
5929
|
+
function isUserFile(filePath) {
|
|
5930
|
+
const rel = path7.relative(path7.resolve(process.cwd(), "convex"), filePath);
|
|
5931
|
+
if (rel.startsWith("_generated"))
|
|
5932
|
+
return false;
|
|
5933
|
+
if (rel.includes("_generated"))
|
|
5934
|
+
return false;
|
|
5935
|
+
return /\.tsx?$/.test(filePath);
|
|
5936
|
+
}
|
|
5937
|
+
var dedicatedFolder = {
|
|
5938
|
+
name: "dedicated-folder",
|
|
5939
|
+
description: "Move all Calabasas files under convex/calabasas/ with _generated/ subdirectory",
|
|
5940
|
+
async run() {
|
|
5941
|
+
const cwd = process.cwd();
|
|
5942
|
+
const convexDir = path7.resolve(cwd, "convex");
|
|
5943
|
+
if (!fs7.existsSync(convexDir)) {
|
|
5944
|
+
p8.log.error("convex/ directory not found.");
|
|
5945
|
+
return;
|
|
5946
|
+
}
|
|
5947
|
+
const generatedDir = path7.join(convexDir, "calabasas", "_generated");
|
|
5948
|
+
if (!fs7.existsSync(generatedDir)) {
|
|
5949
|
+
fs7.mkdirSync(generatedDir, { recursive: true });
|
|
5950
|
+
}
|
|
5951
|
+
let movedCount = 0;
|
|
5952
|
+
for (const [oldRel, newRel] of FILE_MOVES) {
|
|
5953
|
+
const oldPath = path7.join(cwd, oldRel);
|
|
5954
|
+
const newPath = path7.join(cwd, newRel);
|
|
5955
|
+
if (!fs7.existsSync(oldPath))
|
|
5956
|
+
continue;
|
|
5957
|
+
if (fs7.existsSync(newPath)) {
|
|
5958
|
+
p8.log.warn(`Skipped ${oldRel} → ${newRel} (target already exists)`);
|
|
5959
|
+
continue;
|
|
5960
|
+
}
|
|
5961
|
+
fs7.renameSync(oldPath, newPath);
|
|
5962
|
+
p8.log.success(`Moved ${oldRel} → ${newRel}`);
|
|
5963
|
+
movedCount++;
|
|
5964
|
+
}
|
|
5965
|
+
let fixedGeneratedCount = 0;
|
|
5966
|
+
for (const [relPath, rewrites] of Object.entries(GENERATED_IMPORT_REWRITES)) {
|
|
5967
|
+
const absPath = path7.join(cwd, relPath);
|
|
5968
|
+
if (!fs7.existsSync(absPath))
|
|
5969
|
+
continue;
|
|
5970
|
+
let content = fs7.readFileSync(absPath, "utf-8");
|
|
5971
|
+
let changed = false;
|
|
5972
|
+
for (const [pattern, replacement] of rewrites) {
|
|
5973
|
+
const updated = content.replace(pattern, replacement);
|
|
5974
|
+
if (updated !== content) {
|
|
5975
|
+
content = updated;
|
|
5976
|
+
changed = true;
|
|
5977
|
+
}
|
|
5978
|
+
}
|
|
5979
|
+
if (changed) {
|
|
5980
|
+
fs7.writeFileSync(absPath, content);
|
|
5981
|
+
fixedGeneratedCount++;
|
|
5982
|
+
p8.log.success(`Fixed imports in ${relPath}`);
|
|
5983
|
+
}
|
|
5984
|
+
}
|
|
5985
|
+
let rewrittenCount = 0;
|
|
5986
|
+
const userFiles = collectTsFiles(convexDir).filter(isUserFile);
|
|
5987
|
+
for (const filePath of userFiles) {
|
|
5988
|
+
let content = fs7.readFileSync(filePath, "utf-8");
|
|
5989
|
+
let changed = false;
|
|
5990
|
+
for (const [pattern, replacement] of IMPORT_REWRITES) {
|
|
5991
|
+
const updated = content.replace(pattern, replacement);
|
|
5992
|
+
if (updated !== content) {
|
|
5993
|
+
content = updated;
|
|
5994
|
+
changed = true;
|
|
5995
|
+
}
|
|
5996
|
+
}
|
|
5997
|
+
if (changed) {
|
|
5998
|
+
fs7.writeFileSync(filePath, content);
|
|
5999
|
+
const rel = path7.relative(cwd, filePath);
|
|
6000
|
+
p8.log.success(`Rewrote imports in ${rel}`);
|
|
6001
|
+
rewrittenCount++;
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
6004
|
+
if (movedCount === 0 && rewrittenCount === 0 && fixedGeneratedCount === 0) {
|
|
6005
|
+
p8.log.info("Already up to date.");
|
|
6006
|
+
return;
|
|
6007
|
+
}
|
|
6008
|
+
p8.log.info(`
|
|
6009
|
+
Moved ${movedCount} file${movedCount !== 1 ? "s" : ""}, ` + `fixed imports in ${fixedGeneratedCount + rewrittenCount} file${fixedGeneratedCount + rewrittenCount !== 1 ? "s" : ""}.`);
|
|
6010
|
+
}
|
|
6011
|
+
};
|
|
6012
|
+
function collectTsFiles(dir) {
|
|
6013
|
+
const results = [];
|
|
6014
|
+
const entries = fs7.readdirSync(dir, { withFileTypes: true });
|
|
6015
|
+
for (const entry of entries) {
|
|
6016
|
+
const fullPath = path7.join(dir, entry.name);
|
|
6017
|
+
if (entry.isDirectory()) {
|
|
6018
|
+
results.push(...collectTsFiles(fullPath));
|
|
6019
|
+
} else if (/\.tsx?$/.test(entry.name)) {
|
|
6020
|
+
results.push(fullPath);
|
|
6021
|
+
}
|
|
6022
|
+
}
|
|
6023
|
+
return results;
|
|
6024
|
+
}
|
|
6025
|
+
|
|
6026
|
+
// src/migrations/index.ts
|
|
6027
|
+
var migrations = [dedicatedFolder];
|
|
6028
|
+
|
|
6029
|
+
// src/commands/migrate.ts
|
|
6030
|
+
async function migrate(name) {
|
|
6031
|
+
if (!name) {
|
|
6032
|
+
p9.intro("calabasas migrate");
|
|
6033
|
+
if (migrations.length === 0) {
|
|
6034
|
+
p9.log.info("No migrations available.");
|
|
6035
|
+
p9.outro("Done");
|
|
6036
|
+
return;
|
|
6037
|
+
}
|
|
6038
|
+
p9.log.info(`Available migrations:
|
|
6039
|
+
`);
|
|
6040
|
+
for (const m of migrations) {
|
|
6041
|
+
p9.log.message(` ${m.name} — ${m.description}`);
|
|
6042
|
+
}
|
|
6043
|
+
p9.log.info(`
|
|
6044
|
+
Run a migration with: calabasas migrate <name>`);
|
|
6045
|
+
p9.outro("Done");
|
|
6046
|
+
return;
|
|
6047
|
+
}
|
|
6048
|
+
const migration = migrations.find((m) => m.name === name);
|
|
6049
|
+
if (!migration) {
|
|
6050
|
+
p9.log.error(`Unknown migration: ${name}`);
|
|
6051
|
+
p9.log.info(`Available migrations: ${migrations.map((m) => m.name).join(", ")}`);
|
|
6052
|
+
return;
|
|
6053
|
+
}
|
|
6054
|
+
p9.intro(`calabasas migrate ${name}`);
|
|
6055
|
+
await migration.run();
|
|
6056
|
+
p9.outro("Migration complete!");
|
|
6057
|
+
}
|
|
6058
|
+
|
|
6059
|
+
// src/commands/bot.ts
|
|
6060
|
+
import * as p10 from "@clack/prompts";
|
|
5863
6061
|
import pc from "picocolors";
|
|
5864
6062
|
var INTENTS = [
|
|
5865
6063
|
{ name: "Guilds", value: 1 << 0, description: "Guild create/update/delete, roles, channels" },
|
|
@@ -5882,9 +6080,9 @@ var INTENTS = [
|
|
|
5882
6080
|
{ name: "Auto Moderation Config", value: 1 << 20, description: "Auto mod rule changes" },
|
|
5883
6081
|
{ name: "Auto Moderation Execution", value: 1 << 21, description: "Auto mod action execution" }
|
|
5884
6082
|
];
|
|
5885
|
-
async function apiRequest(method,
|
|
6083
|
+
async function apiRequest(method, path8, body, env) {
|
|
5886
6084
|
const config = getConfig(env);
|
|
5887
|
-
const url = `${getApiUrlForEnv(env)}${
|
|
6085
|
+
const url = `${getApiUrlForEnv(env)}${path8}`;
|
|
5888
6086
|
const response = await fetch(url, {
|
|
5889
6087
|
method,
|
|
5890
6088
|
headers: {
|
|
@@ -5910,43 +6108,43 @@ async function botAdd(options) {
|
|
|
5910
6108
|
console.log("Not logged in. Run `calabasas login` first.");
|
|
5911
6109
|
return;
|
|
5912
6110
|
}
|
|
5913
|
-
|
|
5914
|
-
const name = await
|
|
6111
|
+
p10.intro("calabasas bot add");
|
|
6112
|
+
const name = await p10.text({
|
|
5915
6113
|
message: "Bot name",
|
|
5916
6114
|
placeholder: "My Discord Bot",
|
|
5917
6115
|
validate: (v) => v.trim() ? undefined : "Bot name is required"
|
|
5918
6116
|
});
|
|
5919
|
-
if (
|
|
5920
|
-
|
|
6117
|
+
if (p10.isCancel(name)) {
|
|
6118
|
+
p10.cancel("Cancelled.");
|
|
5921
6119
|
return;
|
|
5922
6120
|
}
|
|
5923
|
-
const discordAppId = await
|
|
6121
|
+
const discordAppId = await p10.text({
|
|
5924
6122
|
message: "Discord Application ID",
|
|
5925
6123
|
placeholder: "123456789012345678",
|
|
5926
6124
|
validate: (v) => v.trim() ? undefined : "Discord Application ID is required"
|
|
5927
6125
|
});
|
|
5928
|
-
if (
|
|
5929
|
-
|
|
6126
|
+
if (p10.isCancel(discordAppId)) {
|
|
6127
|
+
p10.cancel("Cancelled.");
|
|
5930
6128
|
return;
|
|
5931
6129
|
}
|
|
5932
|
-
const token = await
|
|
6130
|
+
const token = await p10.password({
|
|
5933
6131
|
message: "Bot token",
|
|
5934
6132
|
validate: (v) => v.trim() ? undefined : "Bot token is required"
|
|
5935
6133
|
});
|
|
5936
|
-
if (
|
|
5937
|
-
|
|
6134
|
+
if (p10.isCancel(token)) {
|
|
6135
|
+
p10.cancel("Cancelled.");
|
|
5938
6136
|
return;
|
|
5939
6137
|
}
|
|
5940
|
-
const convexUrl = await
|
|
6138
|
+
const convexUrl = await p10.text({
|
|
5941
6139
|
message: "Your Convex URL",
|
|
5942
6140
|
placeholder: "https://your-project.convex.cloud",
|
|
5943
6141
|
validate: (v) => v.trim() ? undefined : "Convex URL is required"
|
|
5944
6142
|
});
|
|
5945
|
-
if (
|
|
5946
|
-
|
|
6143
|
+
if (p10.isCancel(convexUrl)) {
|
|
6144
|
+
p10.cancel("Cancelled.");
|
|
5947
6145
|
return;
|
|
5948
6146
|
}
|
|
5949
|
-
const selectedIntents = await
|
|
6147
|
+
const selectedIntents = await p10.multiselect({
|
|
5950
6148
|
message: "Select Gateway Intents",
|
|
5951
6149
|
options: INTENTS.map((intent, i) => ({
|
|
5952
6150
|
value: i,
|
|
@@ -5956,12 +6154,12 @@ async function botAdd(options) {
|
|
|
5956
6154
|
initialValues: [0, 9],
|
|
5957
6155
|
required: true
|
|
5958
6156
|
});
|
|
5959
|
-
if (
|
|
5960
|
-
|
|
6157
|
+
if (p10.isCancel(selectedIntents)) {
|
|
6158
|
+
p10.cancel("Cancelled.");
|
|
5961
6159
|
return;
|
|
5962
6160
|
}
|
|
5963
6161
|
const intents = selectedIntents.reduce((sum, i) => sum + INTENTS[i].value, 0);
|
|
5964
|
-
const s =
|
|
6162
|
+
const s = p10.spinner();
|
|
5965
6163
|
s.start("Creating bot...");
|
|
5966
6164
|
const { ok, data, status } = await apiRequest("POST", "/api/cli/bots", {
|
|
5967
6165
|
name: name.trim(),
|
|
@@ -5972,16 +6170,16 @@ async function botAdd(options) {
|
|
|
5972
6170
|
}, env);
|
|
5973
6171
|
if (!ok) {
|
|
5974
6172
|
s.stop("Failed to create bot");
|
|
5975
|
-
|
|
6173
|
+
p10.cancel(`${data.error || `HTTP ${status}`}`);
|
|
5976
6174
|
return;
|
|
5977
6175
|
}
|
|
5978
6176
|
s.stop("Bot created!");
|
|
5979
6177
|
const sharedSecret = data.sharedSecret;
|
|
5980
|
-
|
|
6178
|
+
p10.note(`${sharedSecret}
|
|
5981
6179
|
|
|
5982
6180
|
Add this to your Convex environment as CALABASAS_SECRET`, "Shared Secret");
|
|
5983
|
-
|
|
5984
|
-
|
|
6181
|
+
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");
|
|
6182
|
+
p10.outro("Bot created successfully!");
|
|
5985
6183
|
}
|
|
5986
6184
|
async function botList(options) {
|
|
5987
6185
|
if (options.dev && options.prod) {
|
|
@@ -6052,24 +6250,24 @@ async function botRemove(botId, options) {
|
|
|
6052
6250
|
console.log("Not logged in. Run `calabasas login` first.");
|
|
6053
6251
|
return;
|
|
6054
6252
|
}
|
|
6055
|
-
|
|
6056
|
-
const confirmed = await
|
|
6253
|
+
p10.intro("calabasas bot remove");
|
|
6254
|
+
const confirmed = await p10.confirm({
|
|
6057
6255
|
message: `Are you sure you want to remove bot ${botId}?`
|
|
6058
6256
|
});
|
|
6059
|
-
if (
|
|
6060
|
-
|
|
6257
|
+
if (p10.isCancel(confirmed) || !confirmed) {
|
|
6258
|
+
p10.cancel("Cancelled.");
|
|
6061
6259
|
return;
|
|
6062
6260
|
}
|
|
6063
|
-
const s =
|
|
6261
|
+
const s = p10.spinner();
|
|
6064
6262
|
s.start("Removing bot...");
|
|
6065
6263
|
const { ok, data, status } = await apiRequest("DELETE", `/api/cli/bots?id=${botId}`, undefined, env);
|
|
6066
6264
|
if (!ok) {
|
|
6067
6265
|
s.stop("Failed to remove bot");
|
|
6068
|
-
|
|
6266
|
+
p10.cancel(`${data.error || `HTTP ${status}`}`);
|
|
6069
6267
|
return;
|
|
6070
6268
|
}
|
|
6071
6269
|
s.stop("Done");
|
|
6072
|
-
|
|
6270
|
+
p10.outro("Bot removed successfully!");
|
|
6073
6271
|
}
|
|
6074
6272
|
async function botEdit(botId, options) {
|
|
6075
6273
|
if (options.dev && options.prod) {
|
|
@@ -6088,8 +6286,8 @@ async function botEdit(botId, options) {
|
|
|
6088
6286
|
const updates = { botId };
|
|
6089
6287
|
const hasFlags = options.name || options.url || options.token || options.intents;
|
|
6090
6288
|
if (!hasFlags) {
|
|
6091
|
-
|
|
6092
|
-
const field = await
|
|
6289
|
+
p10.intro("calabasas bot edit");
|
|
6290
|
+
const field = await p10.select({
|
|
6093
6291
|
message: "Which field do you want to edit?",
|
|
6094
6292
|
options: [
|
|
6095
6293
|
{ value: "name", label: "Bot name" },
|
|
@@ -6098,35 +6296,35 @@ async function botEdit(botId, options) {
|
|
|
6098
6296
|
{ value: "intents", label: "Intents value" }
|
|
6099
6297
|
]
|
|
6100
6298
|
});
|
|
6101
|
-
if (
|
|
6102
|
-
|
|
6299
|
+
if (p10.isCancel(field)) {
|
|
6300
|
+
p10.cancel("Cancelled.");
|
|
6103
6301
|
return;
|
|
6104
6302
|
}
|
|
6105
6303
|
if (field === "name") {
|
|
6106
|
-
const value = await
|
|
6107
|
-
if (
|
|
6108
|
-
|
|
6304
|
+
const value = await p10.text({ message: "New bot name" });
|
|
6305
|
+
if (p10.isCancel(value)) {
|
|
6306
|
+
p10.cancel("Cancelled.");
|
|
6109
6307
|
return;
|
|
6110
6308
|
}
|
|
6111
6309
|
updates.name = value;
|
|
6112
6310
|
} else if (field === "url") {
|
|
6113
|
-
const value = await
|
|
6114
|
-
if (
|
|
6115
|
-
|
|
6311
|
+
const value = await p10.text({ message: "New Convex URL" });
|
|
6312
|
+
if (p10.isCancel(value)) {
|
|
6313
|
+
p10.cancel("Cancelled.");
|
|
6116
6314
|
return;
|
|
6117
6315
|
}
|
|
6118
6316
|
updates.convexUrl = value;
|
|
6119
6317
|
} else if (field === "token") {
|
|
6120
|
-
const value = await
|
|
6121
|
-
if (
|
|
6122
|
-
|
|
6318
|
+
const value = await p10.password({ message: "New bot token" });
|
|
6319
|
+
if (p10.isCancel(value)) {
|
|
6320
|
+
p10.cancel("Cancelled.");
|
|
6123
6321
|
return;
|
|
6124
6322
|
}
|
|
6125
6323
|
updates.token = value;
|
|
6126
6324
|
} else if (field === "intents") {
|
|
6127
|
-
const value = await
|
|
6128
|
-
if (
|
|
6129
|
-
|
|
6325
|
+
const value = await p10.text({ message: "New intents value (number)" });
|
|
6326
|
+
if (p10.isCancel(value)) {
|
|
6327
|
+
p10.cancel("Cancelled.");
|
|
6130
6328
|
return;
|
|
6131
6329
|
}
|
|
6132
6330
|
updates.intents = parseInt(value, 10);
|
|
@@ -6146,17 +6344,17 @@ async function botEdit(botId, options) {
|
|
|
6146
6344
|
console.log("No updates specified.");
|
|
6147
6345
|
return;
|
|
6148
6346
|
}
|
|
6149
|
-
const s =
|
|
6347
|
+
const s = p10.spinner();
|
|
6150
6348
|
s.start("Updating bot...");
|
|
6151
6349
|
const { ok, data, status } = await apiRequest("PATCH", "/api/cli/bots", updates, env);
|
|
6152
6350
|
if (!ok) {
|
|
6153
6351
|
s.stop("Failed to update bot");
|
|
6154
|
-
|
|
6352
|
+
p10.cancel(`${data.error || `HTTP ${status}`}`);
|
|
6155
6353
|
return;
|
|
6156
6354
|
}
|
|
6157
6355
|
s.stop("Done");
|
|
6158
|
-
|
|
6159
|
-
|
|
6356
|
+
p10.note("The Gateway will automatically reconnect with the new settings.", "Note");
|
|
6357
|
+
p10.outro("Bot updated successfully!");
|
|
6160
6358
|
}
|
|
6161
6359
|
|
|
6162
6360
|
// src/index.ts
|
|
@@ -6173,10 +6371,11 @@ program2.name("calabasas").description("CLI for Calabasas - Discord Gateway as a
|
|
|
6173
6371
|
program2.command("login").description("Authenticate with Calabasas using your API key").option("--dev", "Use development environment").option("--prod", "Use production environment").action(login);
|
|
6174
6372
|
program2.command("logout").description("Clear stored credentials").option("--dev", "Use development environment").option("--prod", "Use production environment").action(logout);
|
|
6175
6373
|
program2.command("init").description("Initialize Calabasas config in your Convex project").action(init);
|
|
6176
|
-
program2.command("push").description("Push your
|
|
6177
|
-
program2.command("generate").description("Generate
|
|
6374
|
+
program2.command("push").description("Push your Calabasas config to the server").option("-c, --config <path>", "Path to config file", "convex/calabasas/config.ts").option("-b, --bot <botId>", "Bot ID to configure (prompts if not specified)").option("--dev", "Push to development environment").option("--prod", "Push to production environment").action(push);
|
|
6375
|
+
program2.command("generate").description("Generate type-safe Discord handlers and helpers").option("-o, --output <path>", "Output path", "convex/calabasas/_generated/discord.ts").action(generate);
|
|
6178
6376
|
program2.command("skill").description("Generate Calabasas documentation for AI assistants").option("--dev", "Use development environment").option("--prod", "Use production environment").action(skill);
|
|
6179
6377
|
program2.command("add [components...]").description("Add Discord UI components to your project").action(add);
|
|
6378
|
+
program2.command("migrate [name]").description("Run a codemod migration (list available if no name given)").action(migrate);
|
|
6180
6379
|
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);
|
|
6181
6380
|
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);
|
|
6182
6381
|
var bot = program2.command("bot").description("Manage Discord bots");
|