calabasas 0.3.6 → 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.
Files changed (2) hide show
  1. package/dist/index.js +289 -112
  2. 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 configPath = path.join(convexDir, "calabasas.config.ts");
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.config.ts already exists.
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.config.ts`);
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.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");
2257
- p3.outro("Created convex/calabasas.config.ts");
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 calabasas.config.ts file.");
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.config.ts
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 "../_generated/server";
2940
- import { internal } from "../_generated/api";
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 "./_generated/server";
3280
+ import { mutation } from "../../_generated/server";
3277
3281
  import { v } from "convex/values";
3278
- import type { MutationCtx } from "./_generated/server";
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 configPath = path4.join(convexDir, "calabasas.config.ts");
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 calabasas.config.ts found, generating with default settings...");
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 calabasasDir = path4.join(convexDir, "calabasas");
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(calabasasDir, "sync.ts");
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(convexDir, "discord.actions.generated.ts");
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.generated.ts");
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.generated";
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(convexDir, "calabasas.config.ts");
5706
- if (!fs6.existsSync(calabasasDir) || !fs6.existsSync(path6.join(calabasasDir, "schema.ts"))) {
5707
- console.log("Error: convex/calabasas/schema.ts not found.");
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.config.ts and re-run \`calabasas generate\`.`);
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/bot.ts
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,26 +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
- function encrypt(text2, key) {
5886
- const keyBytes = new TextEncoder().encode(key);
5887
- const textBytes = new TextEncoder().encode(text2);
5888
- const encrypted = new Uint8Array(textBytes.length);
5889
- for (let i = 0;i < textBytes.length; i++) {
5890
- encrypted[i] = textBytes[i] ^ keyBytes[i % keyBytes.length];
5891
- }
5892
- return btoa(String.fromCharCode(...encrypted));
5893
- }
5894
- function generateSecret() {
5895
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
5896
- let result = "";
5897
- for (let i = 0;i < 32; i++) {
5898
- result += chars.charAt(Math.floor(Math.random() * chars.length));
5899
- }
5900
- return result;
5901
- }
5902
- async function apiRequest(method, path7, body, env) {
6083
+ async function apiRequest(method, path8, body, env) {
5903
6084
  const config = getConfig(env);
5904
- const url = `${getApiUrlForEnv(env)}${path7}`;
6085
+ const url = `${getApiUrlForEnv(env)}${path8}`;
5905
6086
  const response = await fetch(url, {
5906
6087
  method,
5907
6088
  headers: {
@@ -5927,43 +6108,43 @@ async function botAdd(options) {
5927
6108
  console.log("Not logged in. Run `calabasas login` first.");
5928
6109
  return;
5929
6110
  }
5930
- p8.intro("calabasas bot add");
5931
- const name = await p8.text({
6111
+ p10.intro("calabasas bot add");
6112
+ const name = await p10.text({
5932
6113
  message: "Bot name",
5933
6114
  placeholder: "My Discord Bot",
5934
6115
  validate: (v) => v.trim() ? undefined : "Bot name is required"
5935
6116
  });
5936
- if (p8.isCancel(name)) {
5937
- p8.cancel("Cancelled.");
6117
+ if (p10.isCancel(name)) {
6118
+ p10.cancel("Cancelled.");
5938
6119
  return;
5939
6120
  }
5940
- const discordAppId = await p8.text({
6121
+ const discordAppId = await p10.text({
5941
6122
  message: "Discord Application ID",
5942
6123
  placeholder: "123456789012345678",
5943
6124
  validate: (v) => v.trim() ? undefined : "Discord Application ID is required"
5944
6125
  });
5945
- if (p8.isCancel(discordAppId)) {
5946
- p8.cancel("Cancelled.");
6126
+ if (p10.isCancel(discordAppId)) {
6127
+ p10.cancel("Cancelled.");
5947
6128
  return;
5948
6129
  }
5949
- const token = await p8.password({
6130
+ const token = await p10.password({
5950
6131
  message: "Bot token",
5951
6132
  validate: (v) => v.trim() ? undefined : "Bot token is required"
5952
6133
  });
5953
- if (p8.isCancel(token)) {
5954
- p8.cancel("Cancelled.");
6134
+ if (p10.isCancel(token)) {
6135
+ p10.cancel("Cancelled.");
5955
6136
  return;
5956
6137
  }
5957
- const convexUrl = await p8.text({
6138
+ const convexUrl = await p10.text({
5958
6139
  message: "Your Convex URL",
5959
6140
  placeholder: "https://your-project.convex.cloud",
5960
6141
  validate: (v) => v.trim() ? undefined : "Convex URL is required"
5961
6142
  });
5962
- if (p8.isCancel(convexUrl)) {
5963
- p8.cancel("Cancelled.");
6143
+ if (p10.isCancel(convexUrl)) {
6144
+ p10.cancel("Cancelled.");
5964
6145
  return;
5965
6146
  }
5966
- const selectedIntents = await p8.multiselect({
6147
+ const selectedIntents = await p10.multiselect({
5967
6148
  message: "Select Gateway Intents",
5968
6149
  options: INTENTS.map((intent, i) => ({
5969
6150
  value: i,
@@ -5973,35 +6154,32 @@ async function botAdd(options) {
5973
6154
  initialValues: [0, 9],
5974
6155
  required: true
5975
6156
  });
5976
- if (p8.isCancel(selectedIntents)) {
5977
- p8.cancel("Cancelled.");
6157
+ if (p10.isCancel(selectedIntents)) {
6158
+ p10.cancel("Cancelled.");
5978
6159
  return;
5979
6160
  }
5980
6161
  const intents = selectedIntents.reduce((sum, i) => sum + INTENTS[i].value, 0);
5981
- const s = p8.spinner();
6162
+ const s = p10.spinner();
5982
6163
  s.start("Creating bot...");
5983
- const encryptionKey = "calabasas-dev-key-change-in-production";
5984
- const encryptedToken = encrypt(token, encryptionKey);
5985
- const sharedSecret = generateSecret();
5986
6164
  const { ok, data, status } = await apiRequest("POST", "/api/cli/bots", {
5987
6165
  name: name.trim(),
5988
6166
  discordAppId: discordAppId.trim(),
5989
- encryptedToken,
6167
+ token,
5990
6168
  intents,
5991
- convexUrl: convexUrl.trim(),
5992
- sharedSecret
6169
+ convexUrl: convexUrl.trim()
5993
6170
  }, env);
5994
6171
  if (!ok) {
5995
6172
  s.stop("Failed to create bot");
5996
- p8.cancel(`${data.error || `HTTP ${status}`}`);
6173
+ p10.cancel(`${data.error || `HTTP ${status}`}`);
5997
6174
  return;
5998
6175
  }
5999
6176
  s.stop("Bot created!");
6000
- p8.note(`${sharedSecret}
6177
+ const sharedSecret = data.sharedSecret;
6178
+ p10.note(`${sharedSecret}
6001
6179
 
6002
6180
  Add this to your Convex environment as CALABASAS_SECRET`, "Shared Secret");
6003
- p8.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");
6004
- p8.outro("Bot created successfully!");
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!");
6005
6183
  }
6006
6184
  async function botList(options) {
6007
6185
  if (options.dev && options.prod) {
@@ -6072,24 +6250,24 @@ async function botRemove(botId, options) {
6072
6250
  console.log("Not logged in. Run `calabasas login` first.");
6073
6251
  return;
6074
6252
  }
6075
- p8.intro("calabasas bot remove");
6076
- const confirmed = await p8.confirm({
6253
+ p10.intro("calabasas bot remove");
6254
+ const confirmed = await p10.confirm({
6077
6255
  message: `Are you sure you want to remove bot ${botId}?`
6078
6256
  });
6079
- if (p8.isCancel(confirmed) || !confirmed) {
6080
- p8.cancel("Cancelled.");
6257
+ if (p10.isCancel(confirmed) || !confirmed) {
6258
+ p10.cancel("Cancelled.");
6081
6259
  return;
6082
6260
  }
6083
- const s = p8.spinner();
6261
+ const s = p10.spinner();
6084
6262
  s.start("Removing bot...");
6085
6263
  const { ok, data, status } = await apiRequest("DELETE", `/api/cli/bots?id=${botId}`, undefined, env);
6086
6264
  if (!ok) {
6087
6265
  s.stop("Failed to remove bot");
6088
- p8.cancel(`${data.error || `HTTP ${status}`}`);
6266
+ p10.cancel(`${data.error || `HTTP ${status}`}`);
6089
6267
  return;
6090
6268
  }
6091
6269
  s.stop("Done");
6092
- p8.outro("Bot removed successfully!");
6270
+ p10.outro("Bot removed successfully!");
6093
6271
  }
6094
6272
  async function botEdit(botId, options) {
6095
6273
  if (options.dev && options.prod) {
@@ -6108,8 +6286,8 @@ async function botEdit(botId, options) {
6108
6286
  const updates = { botId };
6109
6287
  const hasFlags = options.name || options.url || options.token || options.intents;
6110
6288
  if (!hasFlags) {
6111
- p8.intro("calabasas bot edit");
6112
- const field = await p8.select({
6289
+ p10.intro("calabasas bot edit");
6290
+ const field = await p10.select({
6113
6291
  message: "Which field do you want to edit?",
6114
6292
  options: [
6115
6293
  { value: "name", label: "Bot name" },
@@ -6118,36 +6296,35 @@ async function botEdit(botId, options) {
6118
6296
  { value: "intents", label: "Intents value" }
6119
6297
  ]
6120
6298
  });
6121
- if (p8.isCancel(field)) {
6122
- p8.cancel("Cancelled.");
6299
+ if (p10.isCancel(field)) {
6300
+ p10.cancel("Cancelled.");
6123
6301
  return;
6124
6302
  }
6125
6303
  if (field === "name") {
6126
- const value = await p8.text({ message: "New bot name" });
6127
- if (p8.isCancel(value)) {
6128
- p8.cancel("Cancelled.");
6304
+ const value = await p10.text({ message: "New bot name" });
6305
+ if (p10.isCancel(value)) {
6306
+ p10.cancel("Cancelled.");
6129
6307
  return;
6130
6308
  }
6131
6309
  updates.name = value;
6132
6310
  } else if (field === "url") {
6133
- const value = await p8.text({ message: "New Convex URL" });
6134
- if (p8.isCancel(value)) {
6135
- p8.cancel("Cancelled.");
6311
+ const value = await p10.text({ message: "New Convex URL" });
6312
+ if (p10.isCancel(value)) {
6313
+ p10.cancel("Cancelled.");
6136
6314
  return;
6137
6315
  }
6138
6316
  updates.convexUrl = value;
6139
6317
  } else if (field === "token") {
6140
- const value = await p8.password({ message: "New bot token" });
6141
- if (p8.isCancel(value)) {
6142
- p8.cancel("Cancelled.");
6318
+ const value = await p10.password({ message: "New bot token" });
6319
+ if (p10.isCancel(value)) {
6320
+ p10.cancel("Cancelled.");
6143
6321
  return;
6144
6322
  }
6145
- const encryptionKey = "calabasas-dev-key-change-in-production";
6146
- updates.encryptedToken = encrypt(value, encryptionKey);
6323
+ updates.token = value;
6147
6324
  } else if (field === "intents") {
6148
- const value = await p8.text({ message: "New intents value (number)" });
6149
- if (p8.isCancel(value)) {
6150
- p8.cancel("Cancelled.");
6325
+ const value = await p10.text({ message: "New intents value (number)" });
6326
+ if (p10.isCancel(value)) {
6327
+ p10.cancel("Cancelled.");
6151
6328
  return;
6152
6329
  }
6153
6330
  updates.intents = parseInt(value, 10);
@@ -6158,8 +6335,7 @@ async function botEdit(botId, options) {
6158
6335
  if (options.url)
6159
6336
  updates.convexUrl = options.url;
6160
6337
  if (options.token) {
6161
- const encryptionKey = "calabasas-dev-key-change-in-production";
6162
- updates.encryptedToken = encrypt(options.token, encryptionKey);
6338
+ updates.token = options.token;
6163
6339
  }
6164
6340
  if (options.intents)
6165
6341
  updates.intents = parseInt(options.intents, 10);
@@ -6168,17 +6344,17 @@ async function botEdit(botId, options) {
6168
6344
  console.log("No updates specified.");
6169
6345
  return;
6170
6346
  }
6171
- const s = p8.spinner();
6347
+ const s = p10.spinner();
6172
6348
  s.start("Updating bot...");
6173
6349
  const { ok, data, status } = await apiRequest("PATCH", "/api/cli/bots", updates, env);
6174
6350
  if (!ok) {
6175
6351
  s.stop("Failed to update bot");
6176
- p8.cancel(`${data.error || `HTTP ${status}`}`);
6352
+ p10.cancel(`${data.error || `HTTP ${status}`}`);
6177
6353
  return;
6178
6354
  }
6179
6355
  s.stop("Done");
6180
- p8.note("The Gateway will automatically reconnect with the new settings.", "Note");
6181
- p8.outro("Bot updated successfully!");
6356
+ p10.note("The Gateway will automatically reconnect with the new settings.", "Note");
6357
+ p10.outro("Bot updated successfully!");
6182
6358
  }
6183
6359
 
6184
6360
  // src/index.ts
@@ -6195,10 +6371,11 @@ program2.name("calabasas").description("CLI for Calabasas - Discord Gateway as a
6195
6371
  program2.command("login").description("Authenticate with Calabasas using your API key").option("--dev", "Use development environment").option("--prod", "Use production environment").action(login);
6196
6372
  program2.command("logout").description("Clear stored credentials").option("--dev", "Use development environment").option("--prod", "Use production environment").action(logout);
6197
6373
  program2.command("init").description("Initialize Calabasas config in your Convex project").action(init);
6198
- program2.command("push").description("Push your calabasas.config.ts to Calabasas").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);
6199
- program2.command("generate").description("Generate discord.generated.ts with type-safe handlers").option("-o, --output <path>", "Output path", "convex/discord.generated.ts").action(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);
6200
6376
  program2.command("skill").description("Generate Calabasas documentation for AI assistants").option("--dev", "Use development environment").option("--prod", "Use production environment").action(skill);
6201
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);
6202
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);
6203
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);
6204
6381
  var bot = program2.command("bot").description("Manage Discord bots");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "calabasas",
3
- "version": "0.3.6",
3
+ "version": "0.5.0",
4
4
  "description": "CLI for Calabasas - Discord Gateway as a Service for Convex",
5
5
  "type": "module",
6
6
  "bin": {