calabasas 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +288 -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,199 @@ ${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
|
+
/internal\.calabasas\.sync\./g,
|
|
5929
|
+
`internal.calabasas._generated.sync.`
|
|
5930
|
+
]
|
|
5931
|
+
]
|
|
5932
|
+
};
|
|
5933
|
+
function isUserFile(filePath) {
|
|
5934
|
+
const rel = path7.relative(path7.resolve(process.cwd(), "convex"), filePath);
|
|
5935
|
+
if (rel.startsWith("_generated"))
|
|
5936
|
+
return false;
|
|
5937
|
+
if (rel.includes("_generated"))
|
|
5938
|
+
return false;
|
|
5939
|
+
return /\.tsx?$/.test(filePath);
|
|
5940
|
+
}
|
|
5941
|
+
var dedicatedFolder = {
|
|
5942
|
+
name: "dedicated-folder",
|
|
5943
|
+
description: "Move all Calabasas files under convex/calabasas/ with _generated/ subdirectory",
|
|
5944
|
+
async run() {
|
|
5945
|
+
const cwd = process.cwd();
|
|
5946
|
+
const convexDir = path7.resolve(cwd, "convex");
|
|
5947
|
+
if (!fs7.existsSync(convexDir)) {
|
|
5948
|
+
p8.log.error("convex/ directory not found.");
|
|
5949
|
+
return;
|
|
5950
|
+
}
|
|
5951
|
+
const generatedDir = path7.join(convexDir, "calabasas", "_generated");
|
|
5952
|
+
if (!fs7.existsSync(generatedDir)) {
|
|
5953
|
+
fs7.mkdirSync(generatedDir, { recursive: true });
|
|
5954
|
+
}
|
|
5955
|
+
let movedCount = 0;
|
|
5956
|
+
for (const [oldRel, newRel] of FILE_MOVES) {
|
|
5957
|
+
const oldPath = path7.join(cwd, oldRel);
|
|
5958
|
+
const newPath = path7.join(cwd, newRel);
|
|
5959
|
+
if (!fs7.existsSync(oldPath))
|
|
5960
|
+
continue;
|
|
5961
|
+
if (fs7.existsSync(newPath)) {
|
|
5962
|
+
p8.log.warn(`Skipped ${oldRel} → ${newRel} (target already exists)`);
|
|
5963
|
+
continue;
|
|
5964
|
+
}
|
|
5965
|
+
fs7.renameSync(oldPath, newPath);
|
|
5966
|
+
p8.log.success(`Moved ${oldRel} → ${newRel}`);
|
|
5967
|
+
movedCount++;
|
|
5968
|
+
}
|
|
5969
|
+
let fixedGeneratedCount = 0;
|
|
5970
|
+
for (const [relPath, rewrites] of Object.entries(GENERATED_IMPORT_REWRITES)) {
|
|
5971
|
+
const absPath = path7.join(cwd, relPath);
|
|
5972
|
+
if (!fs7.existsSync(absPath))
|
|
5973
|
+
continue;
|
|
5974
|
+
let content = fs7.readFileSync(absPath, "utf-8");
|
|
5975
|
+
let changed = false;
|
|
5976
|
+
for (const [pattern, replacement] of rewrites) {
|
|
5977
|
+
const updated = content.replace(pattern, replacement);
|
|
5978
|
+
if (updated !== content) {
|
|
5979
|
+
content = updated;
|
|
5980
|
+
changed = true;
|
|
5981
|
+
}
|
|
5982
|
+
}
|
|
5983
|
+
if (changed) {
|
|
5984
|
+
fs7.writeFileSync(absPath, content);
|
|
5985
|
+
fixedGeneratedCount++;
|
|
5986
|
+
p8.log.success(`Fixed imports in ${relPath}`);
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5989
|
+
let rewrittenCount = 0;
|
|
5990
|
+
const userFiles = collectTsFiles(convexDir).filter(isUserFile);
|
|
5991
|
+
for (const filePath of userFiles) {
|
|
5992
|
+
let content = fs7.readFileSync(filePath, "utf-8");
|
|
5993
|
+
let changed = false;
|
|
5994
|
+
for (const [pattern, replacement] of IMPORT_REWRITES) {
|
|
5995
|
+
const updated = content.replace(pattern, replacement);
|
|
5996
|
+
if (updated !== content) {
|
|
5997
|
+
content = updated;
|
|
5998
|
+
changed = true;
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
6001
|
+
if (changed) {
|
|
6002
|
+
fs7.writeFileSync(filePath, content);
|
|
6003
|
+
const rel = path7.relative(cwd, filePath);
|
|
6004
|
+
p8.log.success(`Rewrote imports in ${rel}`);
|
|
6005
|
+
rewrittenCount++;
|
|
6006
|
+
}
|
|
6007
|
+
}
|
|
6008
|
+
if (movedCount === 0 && rewrittenCount === 0 && fixedGeneratedCount === 0) {
|
|
6009
|
+
p8.log.info("Already up to date.");
|
|
6010
|
+
return;
|
|
6011
|
+
}
|
|
6012
|
+
p8.log.info(`
|
|
6013
|
+
Moved ${movedCount} file${movedCount !== 1 ? "s" : ""}, ` + `fixed imports in ${fixedGeneratedCount + rewrittenCount} file${fixedGeneratedCount + rewrittenCount !== 1 ? "s" : ""}.`);
|
|
6014
|
+
}
|
|
6015
|
+
};
|
|
6016
|
+
function collectTsFiles(dir) {
|
|
6017
|
+
const results = [];
|
|
6018
|
+
const entries = fs7.readdirSync(dir, { withFileTypes: true });
|
|
6019
|
+
for (const entry of entries) {
|
|
6020
|
+
const fullPath = path7.join(dir, entry.name);
|
|
6021
|
+
if (entry.isDirectory()) {
|
|
6022
|
+
results.push(...collectTsFiles(fullPath));
|
|
6023
|
+
} else if (/\.tsx?$/.test(entry.name)) {
|
|
6024
|
+
results.push(fullPath);
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
return results;
|
|
6028
|
+
}
|
|
6029
|
+
|
|
6030
|
+
// src/migrations/index.ts
|
|
6031
|
+
var migrations = [dedicatedFolder];
|
|
6032
|
+
|
|
6033
|
+
// src/commands/migrate.ts
|
|
6034
|
+
async function migrate(name) {
|
|
6035
|
+
if (!name) {
|
|
6036
|
+
p9.intro("calabasas migrate");
|
|
6037
|
+
if (migrations.length === 0) {
|
|
6038
|
+
p9.log.info("No migrations available.");
|
|
6039
|
+
p9.outro("Done");
|
|
6040
|
+
return;
|
|
6041
|
+
}
|
|
6042
|
+
p9.log.info(`Available migrations:
|
|
6043
|
+
`);
|
|
6044
|
+
for (const m of migrations) {
|
|
6045
|
+
p9.log.message(` ${m.name} — ${m.description}`);
|
|
6046
|
+
}
|
|
6047
|
+
p9.log.info(`
|
|
6048
|
+
Run a migration with: calabasas migrate <name>`);
|
|
6049
|
+
p9.outro("Done");
|
|
6050
|
+
return;
|
|
6051
|
+
}
|
|
6052
|
+
const migration = migrations.find((m) => m.name === name);
|
|
6053
|
+
if (!migration) {
|
|
6054
|
+
p9.log.error(`Unknown migration: ${name}`);
|
|
6055
|
+
p9.log.info(`Available migrations: ${migrations.map((m) => m.name).join(", ")}`);
|
|
6056
|
+
return;
|
|
6057
|
+
}
|
|
6058
|
+
p9.intro(`calabasas migrate ${name}`);
|
|
6059
|
+
await migration.run();
|
|
6060
|
+
p9.outro("Migration complete!");
|
|
6061
|
+
}
|
|
6062
|
+
|
|
6063
|
+
// src/commands/bot.ts
|
|
6064
|
+
import * as p10 from "@clack/prompts";
|
|
5863
6065
|
import pc from "picocolors";
|
|
5864
6066
|
var INTENTS = [
|
|
5865
6067
|
{ name: "Guilds", value: 1 << 0, description: "Guild create/update/delete, roles, channels" },
|
|
@@ -5882,9 +6084,9 @@ var INTENTS = [
|
|
|
5882
6084
|
{ name: "Auto Moderation Config", value: 1 << 20, description: "Auto mod rule changes" },
|
|
5883
6085
|
{ name: "Auto Moderation Execution", value: 1 << 21, description: "Auto mod action execution" }
|
|
5884
6086
|
];
|
|
5885
|
-
async function apiRequest(method,
|
|
6087
|
+
async function apiRequest(method, path8, body, env) {
|
|
5886
6088
|
const config = getConfig(env);
|
|
5887
|
-
const url = `${getApiUrlForEnv(env)}${
|
|
6089
|
+
const url = `${getApiUrlForEnv(env)}${path8}`;
|
|
5888
6090
|
const response = await fetch(url, {
|
|
5889
6091
|
method,
|
|
5890
6092
|
headers: {
|
|
@@ -5910,43 +6112,43 @@ async function botAdd(options) {
|
|
|
5910
6112
|
console.log("Not logged in. Run `calabasas login` first.");
|
|
5911
6113
|
return;
|
|
5912
6114
|
}
|
|
5913
|
-
|
|
5914
|
-
const name = await
|
|
6115
|
+
p10.intro("calabasas bot add");
|
|
6116
|
+
const name = await p10.text({
|
|
5915
6117
|
message: "Bot name",
|
|
5916
6118
|
placeholder: "My Discord Bot",
|
|
5917
6119
|
validate: (v) => v.trim() ? undefined : "Bot name is required"
|
|
5918
6120
|
});
|
|
5919
|
-
if (
|
|
5920
|
-
|
|
6121
|
+
if (p10.isCancel(name)) {
|
|
6122
|
+
p10.cancel("Cancelled.");
|
|
5921
6123
|
return;
|
|
5922
6124
|
}
|
|
5923
|
-
const discordAppId = await
|
|
6125
|
+
const discordAppId = await p10.text({
|
|
5924
6126
|
message: "Discord Application ID",
|
|
5925
6127
|
placeholder: "123456789012345678",
|
|
5926
6128
|
validate: (v) => v.trim() ? undefined : "Discord Application ID is required"
|
|
5927
6129
|
});
|
|
5928
|
-
if (
|
|
5929
|
-
|
|
6130
|
+
if (p10.isCancel(discordAppId)) {
|
|
6131
|
+
p10.cancel("Cancelled.");
|
|
5930
6132
|
return;
|
|
5931
6133
|
}
|
|
5932
|
-
const token = await
|
|
6134
|
+
const token = await p10.password({
|
|
5933
6135
|
message: "Bot token",
|
|
5934
6136
|
validate: (v) => v.trim() ? undefined : "Bot token is required"
|
|
5935
6137
|
});
|
|
5936
|
-
if (
|
|
5937
|
-
|
|
6138
|
+
if (p10.isCancel(token)) {
|
|
6139
|
+
p10.cancel("Cancelled.");
|
|
5938
6140
|
return;
|
|
5939
6141
|
}
|
|
5940
|
-
const convexUrl = await
|
|
6142
|
+
const convexUrl = await p10.text({
|
|
5941
6143
|
message: "Your Convex URL",
|
|
5942
6144
|
placeholder: "https://your-project.convex.cloud",
|
|
5943
6145
|
validate: (v) => v.trim() ? undefined : "Convex URL is required"
|
|
5944
6146
|
});
|
|
5945
|
-
if (
|
|
5946
|
-
|
|
6147
|
+
if (p10.isCancel(convexUrl)) {
|
|
6148
|
+
p10.cancel("Cancelled.");
|
|
5947
6149
|
return;
|
|
5948
6150
|
}
|
|
5949
|
-
const selectedIntents = await
|
|
6151
|
+
const selectedIntents = await p10.multiselect({
|
|
5950
6152
|
message: "Select Gateway Intents",
|
|
5951
6153
|
options: INTENTS.map((intent, i) => ({
|
|
5952
6154
|
value: i,
|
|
@@ -5956,12 +6158,12 @@ async function botAdd(options) {
|
|
|
5956
6158
|
initialValues: [0, 9],
|
|
5957
6159
|
required: true
|
|
5958
6160
|
});
|
|
5959
|
-
if (
|
|
5960
|
-
|
|
6161
|
+
if (p10.isCancel(selectedIntents)) {
|
|
6162
|
+
p10.cancel("Cancelled.");
|
|
5961
6163
|
return;
|
|
5962
6164
|
}
|
|
5963
6165
|
const intents = selectedIntents.reduce((sum, i) => sum + INTENTS[i].value, 0);
|
|
5964
|
-
const s =
|
|
6166
|
+
const s = p10.spinner();
|
|
5965
6167
|
s.start("Creating bot...");
|
|
5966
6168
|
const { ok, data, status } = await apiRequest("POST", "/api/cli/bots", {
|
|
5967
6169
|
name: name.trim(),
|
|
@@ -5972,16 +6174,16 @@ async function botAdd(options) {
|
|
|
5972
6174
|
}, env);
|
|
5973
6175
|
if (!ok) {
|
|
5974
6176
|
s.stop("Failed to create bot");
|
|
5975
|
-
|
|
6177
|
+
p10.cancel(`${data.error || `HTTP ${status}`}`);
|
|
5976
6178
|
return;
|
|
5977
6179
|
}
|
|
5978
6180
|
s.stop("Bot created!");
|
|
5979
6181
|
const sharedSecret = data.sharedSecret;
|
|
5980
|
-
|
|
6182
|
+
p10.note(`${sharedSecret}
|
|
5981
6183
|
|
|
5982
6184
|
Add this to your Convex environment as CALABASAS_SECRET`, "Shared Secret");
|
|
5983
|
-
|
|
5984
|
-
|
|
6185
|
+
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");
|
|
6186
|
+
p10.outro("Bot created successfully!");
|
|
5985
6187
|
}
|
|
5986
6188
|
async function botList(options) {
|
|
5987
6189
|
if (options.dev && options.prod) {
|
|
@@ -6052,24 +6254,24 @@ async function botRemove(botId, options) {
|
|
|
6052
6254
|
console.log("Not logged in. Run `calabasas login` first.");
|
|
6053
6255
|
return;
|
|
6054
6256
|
}
|
|
6055
|
-
|
|
6056
|
-
const confirmed = await
|
|
6257
|
+
p10.intro("calabasas bot remove");
|
|
6258
|
+
const confirmed = await p10.confirm({
|
|
6057
6259
|
message: `Are you sure you want to remove bot ${botId}?`
|
|
6058
6260
|
});
|
|
6059
|
-
if (
|
|
6060
|
-
|
|
6261
|
+
if (p10.isCancel(confirmed) || !confirmed) {
|
|
6262
|
+
p10.cancel("Cancelled.");
|
|
6061
6263
|
return;
|
|
6062
6264
|
}
|
|
6063
|
-
const s =
|
|
6265
|
+
const s = p10.spinner();
|
|
6064
6266
|
s.start("Removing bot...");
|
|
6065
6267
|
const { ok, data, status } = await apiRequest("DELETE", `/api/cli/bots?id=${botId}`, undefined, env);
|
|
6066
6268
|
if (!ok) {
|
|
6067
6269
|
s.stop("Failed to remove bot");
|
|
6068
|
-
|
|
6270
|
+
p10.cancel(`${data.error || `HTTP ${status}`}`);
|
|
6069
6271
|
return;
|
|
6070
6272
|
}
|
|
6071
6273
|
s.stop("Done");
|
|
6072
|
-
|
|
6274
|
+
p10.outro("Bot removed successfully!");
|
|
6073
6275
|
}
|
|
6074
6276
|
async function botEdit(botId, options) {
|
|
6075
6277
|
if (options.dev && options.prod) {
|
|
@@ -6088,8 +6290,8 @@ async function botEdit(botId, options) {
|
|
|
6088
6290
|
const updates = { botId };
|
|
6089
6291
|
const hasFlags = options.name || options.url || options.token || options.intents;
|
|
6090
6292
|
if (!hasFlags) {
|
|
6091
|
-
|
|
6092
|
-
const field = await
|
|
6293
|
+
p10.intro("calabasas bot edit");
|
|
6294
|
+
const field = await p10.select({
|
|
6093
6295
|
message: "Which field do you want to edit?",
|
|
6094
6296
|
options: [
|
|
6095
6297
|
{ value: "name", label: "Bot name" },
|
|
@@ -6098,35 +6300,35 @@ async function botEdit(botId, options) {
|
|
|
6098
6300
|
{ value: "intents", label: "Intents value" }
|
|
6099
6301
|
]
|
|
6100
6302
|
});
|
|
6101
|
-
if (
|
|
6102
|
-
|
|
6303
|
+
if (p10.isCancel(field)) {
|
|
6304
|
+
p10.cancel("Cancelled.");
|
|
6103
6305
|
return;
|
|
6104
6306
|
}
|
|
6105
6307
|
if (field === "name") {
|
|
6106
|
-
const value = await
|
|
6107
|
-
if (
|
|
6108
|
-
|
|
6308
|
+
const value = await p10.text({ message: "New bot name" });
|
|
6309
|
+
if (p10.isCancel(value)) {
|
|
6310
|
+
p10.cancel("Cancelled.");
|
|
6109
6311
|
return;
|
|
6110
6312
|
}
|
|
6111
6313
|
updates.name = value;
|
|
6112
6314
|
} else if (field === "url") {
|
|
6113
|
-
const value = await
|
|
6114
|
-
if (
|
|
6115
|
-
|
|
6315
|
+
const value = await p10.text({ message: "New Convex URL" });
|
|
6316
|
+
if (p10.isCancel(value)) {
|
|
6317
|
+
p10.cancel("Cancelled.");
|
|
6116
6318
|
return;
|
|
6117
6319
|
}
|
|
6118
6320
|
updates.convexUrl = value;
|
|
6119
6321
|
} else if (field === "token") {
|
|
6120
|
-
const value = await
|
|
6121
|
-
if (
|
|
6122
|
-
|
|
6322
|
+
const value = await p10.password({ message: "New bot token" });
|
|
6323
|
+
if (p10.isCancel(value)) {
|
|
6324
|
+
p10.cancel("Cancelled.");
|
|
6123
6325
|
return;
|
|
6124
6326
|
}
|
|
6125
6327
|
updates.token = value;
|
|
6126
6328
|
} else if (field === "intents") {
|
|
6127
|
-
const value = await
|
|
6128
|
-
if (
|
|
6129
|
-
|
|
6329
|
+
const value = await p10.text({ message: "New intents value (number)" });
|
|
6330
|
+
if (p10.isCancel(value)) {
|
|
6331
|
+
p10.cancel("Cancelled.");
|
|
6130
6332
|
return;
|
|
6131
6333
|
}
|
|
6132
6334
|
updates.intents = parseInt(value, 10);
|
|
@@ -6146,17 +6348,17 @@ async function botEdit(botId, options) {
|
|
|
6146
6348
|
console.log("No updates specified.");
|
|
6147
6349
|
return;
|
|
6148
6350
|
}
|
|
6149
|
-
const s =
|
|
6351
|
+
const s = p10.spinner();
|
|
6150
6352
|
s.start("Updating bot...");
|
|
6151
6353
|
const { ok, data, status } = await apiRequest("PATCH", "/api/cli/bots", updates, env);
|
|
6152
6354
|
if (!ok) {
|
|
6153
6355
|
s.stop("Failed to update bot");
|
|
6154
|
-
|
|
6356
|
+
p10.cancel(`${data.error || `HTTP ${status}`}`);
|
|
6155
6357
|
return;
|
|
6156
6358
|
}
|
|
6157
6359
|
s.stop("Done");
|
|
6158
|
-
|
|
6159
|
-
|
|
6360
|
+
p10.note("The Gateway will automatically reconnect with the new settings.", "Note");
|
|
6361
|
+
p10.outro("Bot updated successfully!");
|
|
6160
6362
|
}
|
|
6161
6363
|
|
|
6162
6364
|
// src/index.ts
|
|
@@ -6173,10 +6375,11 @@ program2.name("calabasas").description("CLI for Calabasas - Discord Gateway as a
|
|
|
6173
6375
|
program2.command("login").description("Authenticate with Calabasas using your API key").option("--dev", "Use development environment").option("--prod", "Use production environment").action(login);
|
|
6174
6376
|
program2.command("logout").description("Clear stored credentials").option("--dev", "Use development environment").option("--prod", "Use production environment").action(logout);
|
|
6175
6377
|
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
|
|
6378
|
+
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);
|
|
6379
|
+
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
6380
|
program2.command("skill").description("Generate Calabasas documentation for AI assistants").option("--dev", "Use development environment").option("--prod", "Use production environment").action(skill);
|
|
6179
6381
|
program2.command("add [components...]").description("Add Discord UI components to your project").action(add);
|
|
6382
|
+
program2.command("migrate [name]").description("Run a codemod migration (list available if no name given)").action(migrate);
|
|
6180
6383
|
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
6384
|
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
6385
|
var bot = program2.command("bot").description("Manage Discord bots");
|