@cortexmemory/cli 0.1.0 → 0.22.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/README.md +8 -0
- package/dist/commands/conversations.d.ts +1 -1
- package/dist/commands/conversations.d.ts.map +1 -1
- package/dist/commands/conversations.js +58 -28
- package/dist/commands/conversations.js.map +1 -1
- package/dist/commands/convex.d.ts +1 -1
- package/dist/commands/convex.d.ts.map +1 -1
- package/dist/commands/convex.js +237 -64
- package/dist/commands/convex.js.map +1 -1
- package/dist/commands/db.d.ts +1 -1
- package/dist/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +511 -113
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/dev.d.ts +8 -8
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +734 -513
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/facts.d.ts +1 -1
- package/dist/commands/facts.d.ts.map +1 -1
- package/dist/commands/facts.js +79 -49
- package/dist/commands/facts.js.map +1 -1
- package/dist/commands/init.d.ts +28 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +895 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/memory.d.ts +1 -1
- package/dist/commands/memory.d.ts.map +1 -1
- package/dist/commands/memory.js +84 -48
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/setup.d.ts +4 -5
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +613 -265
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/spaces.d.ts +1 -1
- package/dist/commands/spaces.d.ts.map +1 -1
- package/dist/commands/spaces.js +100 -43
- package/dist/commands/spaces.js.map +1 -1
- package/dist/commands/status.d.ts +17 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +314 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/users.d.ts +1 -1
- package/dist/commands/users.d.ts.map +1 -1
- package/dist/commands/users.js +152 -45
- package/dist/commands/users.js.map +1 -1
- package/dist/index.js +61 -19
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/__tests__/client.test.d.ts +5 -0
- package/dist/utils/__tests__/client.test.d.ts.map +1 -0
- package/dist/utils/__tests__/client.test.js +88 -0
- package/dist/utils/__tests__/client.test.js.map +1 -0
- package/dist/utils/__tests__/env-file.test.d.ts +7 -0
- package/dist/utils/__tests__/env-file.test.d.ts.map +1 -0
- package/dist/utils/__tests__/env-file.test.js +196 -0
- package/dist/utils/__tests__/env-file.test.js.map +1 -0
- package/dist/utils/__tests__/shell.test.d.ts +7 -0
- package/dist/utils/__tests__/shell.test.d.ts.map +1 -0
- package/dist/utils/__tests__/shell.test.js +89 -0
- package/dist/utils/__tests__/shell.test.js.map +1 -0
- package/dist/utils/client.d.ts +1 -0
- package/dist/utils/client.d.ts.map +1 -1
- package/dist/utils/client.js +7 -1
- package/dist/utils/client.js.map +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +12 -39
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/deployment-selector.d.ts +50 -0
- package/dist/utils/deployment-selector.d.ts.map +1 -0
- package/dist/utils/deployment-selector.js +129 -0
- package/dist/utils/deployment-selector.js.map +1 -0
- package/dist/utils/env-file.d.ts +48 -0
- package/dist/utils/env-file.d.ts.map +1 -0
- package/dist/utils/env-file.js +152 -0
- package/dist/utils/env-file.js.map +1 -0
- package/dist/utils/formatting.d.ts.map +1 -1
- package/dist/utils/formatting.js +4 -0
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/init/convex-setup.d.ts +30 -0
- package/dist/utils/init/convex-setup.d.ts.map +1 -0
- package/dist/utils/init/convex-setup.js +225 -0
- package/dist/utils/init/convex-setup.js.map +1 -0
- package/dist/utils/init/env-generator.d.ts +32 -0
- package/dist/utils/init/env-generator.d.ts.map +1 -0
- package/dist/utils/init/env-generator.js +210 -0
- package/dist/utils/init/env-generator.js.map +1 -0
- package/dist/utils/init/file-operations.d.ts +22 -0
- package/dist/utils/init/file-operations.d.ts.map +1 -0
- package/dist/utils/init/file-operations.js +211 -0
- package/dist/utils/init/file-operations.js.map +1 -0
- package/dist/utils/init/graph-setup.d.ts +35 -0
- package/dist/utils/init/graph-setup.d.ts.map +1 -0
- package/dist/utils/init/graph-setup.js +413 -0
- package/dist/utils/init/graph-setup.js.map +1 -0
- package/dist/utils/init/index.d.ts +11 -0
- package/dist/utils/init/index.d.ts.map +1 -0
- package/dist/utils/init/index.js +11 -0
- package/dist/utils/init/index.js.map +1 -0
- package/dist/utils/init/types.d.ts +73 -0
- package/dist/utils/init/types.d.ts.map +1 -0
- package/dist/utils/init/types.js +5 -0
- package/dist/utils/init/types.js.map +1 -0
- package/dist/utils/shell.d.ts +60 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +188 -0
- package/dist/utils/shell.js.map +1 -0
- package/package.json +30 -19
- package/templates/basic/README.md +105 -0
- package/templates/basic/dev-runner.mjs +215 -0
- package/templates/basic/package-lock.json +1263 -0
- package/templates/basic/package.json +22 -0
- package/templates/basic/src/index.ts +85 -0
- package/templates/basic/tsconfig.json +17 -0
package/dist/commands/setup.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Configuration Commands
|
|
3
3
|
*
|
|
4
|
-
* Commands for
|
|
5
|
-
* - setup: Interactive setup wizard
|
|
4
|
+
* Commands for managing CLI configuration:
|
|
6
5
|
* - config: Configuration management
|
|
7
6
|
*/
|
|
8
7
|
import prompts from "prompts";
|
|
@@ -12,141 +11,20 @@ import { loadConfig, saveUserConfig, getUserConfigPath, getProjectConfigPath, li
|
|
|
12
11
|
import { testConnection } from "../utils/client.js";
|
|
13
12
|
import { printSuccess, printError, printWarning, printInfo, printSection, formatOutput, } from "../utils/formatting.js";
|
|
14
13
|
import { validateUrl } from "../utils/validation.js";
|
|
14
|
+
import { addDeploymentToEnv, removeDeploymentFromEnv, getDeploymentEnvKeys, } from "../utils/env-file.js";
|
|
15
|
+
import { getCurrentDeployment, setCurrentDeployment, clearCurrentDeployment, } from "../utils/deployment-selector.js";
|
|
15
16
|
import { existsSync } from "fs";
|
|
17
|
+
import { join, resolve } from "path";
|
|
16
18
|
/**
|
|
17
|
-
* Register
|
|
19
|
+
* Register config commands
|
|
18
20
|
*/
|
|
19
|
-
export function
|
|
20
|
-
// setup command
|
|
21
|
-
program
|
|
22
|
-
.command("setup")
|
|
23
|
-
.description("Interactive setup wizard")
|
|
24
|
-
.option("--auto", "Auto-configure from environment variables", false)
|
|
25
|
-
.option("--local", "Set up local Convex development", false)
|
|
26
|
-
.option("--cloud", "Set up cloud Convex deployment", false)
|
|
27
|
-
.action(async (options) => {
|
|
28
|
-
console.log();
|
|
29
|
-
console.log(pc.bold(pc.cyan("🧠 Cortex CLI Setup")));
|
|
30
|
-
console.log(pc.dim("Configure your Cortex Memory deployment\n"));
|
|
31
|
-
try {
|
|
32
|
-
let config = await loadConfig();
|
|
33
|
-
if (options.auto) {
|
|
34
|
-
// Auto mode: configure from environment variables
|
|
35
|
-
await autoSetup(config);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
// Interactive setup
|
|
39
|
-
const setupMode = await prompts({
|
|
40
|
-
type: "select",
|
|
41
|
-
name: "mode",
|
|
42
|
-
message: "What would you like to set up?",
|
|
43
|
-
choices: [
|
|
44
|
-
{
|
|
45
|
-
title: "Local development",
|
|
46
|
-
description: "Configure local Convex instance",
|
|
47
|
-
value: "local",
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
title: "Cloud deployment",
|
|
51
|
-
description: "Configure Convex cloud deployment",
|
|
52
|
-
value: "cloud",
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
title: "Both",
|
|
56
|
-
description: "Configure local and cloud deployments",
|
|
57
|
-
value: "both",
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
title: "View current configuration",
|
|
61
|
-
description: "Show existing configuration",
|
|
62
|
-
value: "view",
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
initial: options.local ? 0 : options.cloud ? 1 : 2,
|
|
66
|
-
});
|
|
67
|
-
if (!setupMode.mode) {
|
|
68
|
-
printWarning("Setup cancelled");
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (setupMode.mode === "view") {
|
|
72
|
-
await showConfiguration(config);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
// Set up local deployment
|
|
76
|
-
if (setupMode.mode === "local" || setupMode.mode === "both") {
|
|
77
|
-
config = await setupLocalDeployment(config);
|
|
78
|
-
}
|
|
79
|
-
// Set up cloud deployment
|
|
80
|
-
if (setupMode.mode === "cloud" || setupMode.mode === "both") {
|
|
81
|
-
config = await setupCloudDeployment(config);
|
|
82
|
-
}
|
|
83
|
-
// Set default deployment
|
|
84
|
-
if (setupMode.mode === "both") {
|
|
85
|
-
const defaultChoice = await prompts({
|
|
86
|
-
type: "select",
|
|
87
|
-
name: "default",
|
|
88
|
-
message: "Which deployment should be the default?",
|
|
89
|
-
choices: [
|
|
90
|
-
{ title: "Local", value: "local" },
|
|
91
|
-
{ title: "Cloud", value: "cloud" },
|
|
92
|
-
],
|
|
93
|
-
});
|
|
94
|
-
if (defaultChoice.default) {
|
|
95
|
-
config.default = defaultChoice.default;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
config.default = setupMode.mode;
|
|
100
|
-
}
|
|
101
|
-
// Set output format
|
|
102
|
-
const formatChoice = await prompts({
|
|
103
|
-
type: "select",
|
|
104
|
-
name: "format",
|
|
105
|
-
message: "Preferred output format?",
|
|
106
|
-
choices: [
|
|
107
|
-
{ title: "Table (human-readable)", value: "table" },
|
|
108
|
-
{ title: "JSON (machine-readable)", value: "json" },
|
|
109
|
-
],
|
|
110
|
-
initial: 0,
|
|
111
|
-
});
|
|
112
|
-
if (formatChoice.format) {
|
|
113
|
-
config.format = formatChoice.format;
|
|
114
|
-
}
|
|
115
|
-
// Confirm dangerous operations
|
|
116
|
-
const confirmChoice = await prompts({
|
|
117
|
-
type: "confirm",
|
|
118
|
-
name: "confirm",
|
|
119
|
-
message: "Require confirmation for dangerous operations (delete, clear)?",
|
|
120
|
-
initial: true,
|
|
121
|
-
});
|
|
122
|
-
config.confirmDangerous = confirmChoice.confirm ?? true;
|
|
123
|
-
// Save configuration
|
|
124
|
-
await saveUserConfig(config);
|
|
125
|
-
console.log();
|
|
126
|
-
printSuccess(`Configuration saved to ${getUserConfigPath()}`);
|
|
127
|
-
// Test connection
|
|
128
|
-
const testChoice = await prompts({
|
|
129
|
-
type: "confirm",
|
|
130
|
-
name: "test",
|
|
131
|
-
message: "Would you like to test the connection?",
|
|
132
|
-
initial: true,
|
|
133
|
-
});
|
|
134
|
-
if (testChoice.test) {
|
|
135
|
-
await testAndShowConnection(config, config.default);
|
|
136
|
-
}
|
|
137
|
-
console.log();
|
|
138
|
-
printSuccess("Setup complete! 🎉");
|
|
139
|
-
printInfo("Run 'cortex --help' to see available commands");
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
printError(error instanceof Error ? error.message : "Setup failed");
|
|
143
|
-
process.exit(1);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
21
|
+
export function registerConfigCommands(program, _config) {
|
|
146
22
|
// config command group
|
|
147
23
|
const configCmd = program
|
|
148
24
|
.command("config")
|
|
149
|
-
.description("Manage CLI configuration")
|
|
25
|
+
.description("Manage CLI configuration")
|
|
26
|
+
.enablePositionalOptions()
|
|
27
|
+
.passThroughOptions();
|
|
150
28
|
// config show
|
|
151
29
|
configCmd
|
|
152
30
|
.command("show")
|
|
@@ -162,6 +40,75 @@ export function registerSetupCommands(program, _config) {
|
|
|
162
40
|
process.exit(1);
|
|
163
41
|
}
|
|
164
42
|
});
|
|
43
|
+
// config list - Table view of deployments
|
|
44
|
+
configCmd
|
|
45
|
+
.command("list")
|
|
46
|
+
.description("List all deployments in table format")
|
|
47
|
+
.action(async () => {
|
|
48
|
+
try {
|
|
49
|
+
const config = await loadConfig();
|
|
50
|
+
const deployments = Object.entries(config.deployments);
|
|
51
|
+
if (deployments.length === 0) {
|
|
52
|
+
console.log(pc.yellow("\n No deployments configured\n"));
|
|
53
|
+
printInfo("To get started:");
|
|
54
|
+
console.log(pc.dim(" • Run 'cortex init' to create a new project"));
|
|
55
|
+
console.log(pc.dim(" • Run 'cortex config add-deployment' to add an existing deployment"));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
console.log();
|
|
59
|
+
// Table header
|
|
60
|
+
const nameWidth = 20;
|
|
61
|
+
const statusWidth = 10;
|
|
62
|
+
const urlWidth = 40;
|
|
63
|
+
const keyWidth = 6;
|
|
64
|
+
const pathWidth = 35;
|
|
65
|
+
console.log(pc.bold(" " +
|
|
66
|
+
"NAME".padEnd(nameWidth) +
|
|
67
|
+
"STATUS".padEnd(statusWidth) +
|
|
68
|
+
"URL".padEnd(urlWidth) +
|
|
69
|
+
"KEY".padEnd(keyWidth) +
|
|
70
|
+
"PROJECT PATH"));
|
|
71
|
+
console.log(pc.dim(" " + "─".repeat(nameWidth + statusWidth + urlWidth + keyWidth + pathWidth)));
|
|
72
|
+
for (const [name, deployment] of deployments) {
|
|
73
|
+
const isDefault = name === config.default;
|
|
74
|
+
// Default deployment is implicitly enabled; others check enabled field
|
|
75
|
+
const isEnabled = deployment.enabled === true || (deployment.enabled === undefined && isDefault);
|
|
76
|
+
const prefix = isDefault ? pc.green("→ ") : " ";
|
|
77
|
+
// Pad BEFORE applying color to avoid ANSI escape code length issues
|
|
78
|
+
const namePadded = name.padEnd(nameWidth - 2);
|
|
79
|
+
const nameDisplay = isDefault ? pc.cyan(namePadded) : namePadded;
|
|
80
|
+
const statusText = isEnabled ? "enabled" : "disabled";
|
|
81
|
+
const statusPadded = statusText.padEnd(statusWidth);
|
|
82
|
+
const statusDisplay = isEnabled ? pc.green(statusPadded) : pc.dim(statusPadded);
|
|
83
|
+
const keyText = deployment.key ? "yes" : "no";
|
|
84
|
+
const keyPadded = keyText.padEnd(keyWidth);
|
|
85
|
+
const keyStatus = deployment.key ? pc.green(keyPadded) : pc.dim(keyPadded);
|
|
86
|
+
const urlDisplay = (deployment.url.length > urlWidth - 2
|
|
87
|
+
? deployment.url.substring(0, urlWidth - 5) + "..."
|
|
88
|
+
: deployment.url).padEnd(urlWidth);
|
|
89
|
+
const pathDisplay = deployment.projectPath
|
|
90
|
+
? (deployment.projectPath.length > pathWidth - 2
|
|
91
|
+
? "..." + deployment.projectPath.slice(-(pathWidth - 5))
|
|
92
|
+
: deployment.projectPath)
|
|
93
|
+
: pc.dim("--");
|
|
94
|
+
console.log(prefix +
|
|
95
|
+
nameDisplay +
|
|
96
|
+
statusDisplay +
|
|
97
|
+
urlDisplay +
|
|
98
|
+
keyStatus +
|
|
99
|
+
pathDisplay);
|
|
100
|
+
}
|
|
101
|
+
console.log();
|
|
102
|
+
if (config.default) {
|
|
103
|
+
console.log(pc.dim(` Default: ${config.default} (→) • Enabled deployments started with 'cortex start'`));
|
|
104
|
+
}
|
|
105
|
+
console.log();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
printError(error instanceof Error ? error.message : "Failed to load config");
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
165
112
|
// config set
|
|
166
113
|
configCmd
|
|
167
114
|
.command("set <key> <value>")
|
|
@@ -192,6 +139,101 @@ export function registerSetupCommands(program, _config) {
|
|
|
192
139
|
process.exit(1);
|
|
193
140
|
}
|
|
194
141
|
});
|
|
142
|
+
// config set-path - Set project path for a deployment
|
|
143
|
+
configCmd
|
|
144
|
+
.command("set-path <deployment> [path]")
|
|
145
|
+
.description("Set project path for a deployment (enables 'cortex start -d <name>' from anywhere)")
|
|
146
|
+
.action(async (deploymentName, pathArg) => {
|
|
147
|
+
try {
|
|
148
|
+
const config = await loadConfig();
|
|
149
|
+
if (!config.deployments[deploymentName]) {
|
|
150
|
+
printError(`Deployment "${deploymentName}" not found`);
|
|
151
|
+
const names = Object.keys(config.deployments);
|
|
152
|
+
if (names.length > 0) {
|
|
153
|
+
printInfo(`Available deployments: ${names.join(", ")}`);
|
|
154
|
+
}
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
// If no path provided, use current directory
|
|
158
|
+
const projectPath = pathArg ? resolve(pathArg) : process.cwd();
|
|
159
|
+
// Verify path exists
|
|
160
|
+
if (!existsSync(projectPath)) {
|
|
161
|
+
printError(`Path does not exist: ${projectPath}`);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
// Update deployment with projectPath
|
|
165
|
+
config.deployments[deploymentName] = {
|
|
166
|
+
...config.deployments[deploymentName],
|
|
167
|
+
projectPath,
|
|
168
|
+
};
|
|
169
|
+
await saveUserConfig(config);
|
|
170
|
+
printSuccess(`Set project path for "${deploymentName}"`);
|
|
171
|
+
console.log(pc.dim(` Path: ${projectPath}`));
|
|
172
|
+
console.log();
|
|
173
|
+
printInfo(`You can now run: cortex start -d ${deploymentName}`);
|
|
174
|
+
console.log(pc.dim(" This will work from any directory"));
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
printError(error instanceof Error ? error.message : "Failed to set project path");
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
// config enable - Enable a deployment for `cortex start`
|
|
182
|
+
configCmd
|
|
183
|
+
.command("enable <deployment>")
|
|
184
|
+
.description("Enable a deployment (will be started with 'cortex start')")
|
|
185
|
+
.action(async (deploymentName) => {
|
|
186
|
+
try {
|
|
187
|
+
const config = await loadConfig();
|
|
188
|
+
if (!config.deployments[deploymentName]) {
|
|
189
|
+
printError(`Deployment "${deploymentName}" not found`);
|
|
190
|
+
const names = Object.keys(config.deployments);
|
|
191
|
+
if (names.length > 0) {
|
|
192
|
+
printInfo(`Available deployments: ${names.join(", ")}`);
|
|
193
|
+
}
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
config.deployments[deploymentName] = {
|
|
197
|
+
...config.deployments[deploymentName],
|
|
198
|
+
enabled: true,
|
|
199
|
+
};
|
|
200
|
+
await saveUserConfig(config);
|
|
201
|
+
printSuccess(`Enabled deployment "${deploymentName}"`);
|
|
202
|
+
console.log(pc.dim(" Will be started with 'cortex start'"));
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
printError(error instanceof Error ? error.message : "Failed to enable deployment");
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
// config disable - Disable a deployment
|
|
210
|
+
configCmd
|
|
211
|
+
.command("disable <deployment>")
|
|
212
|
+
.description("Disable a deployment (will not be started with 'cortex start')")
|
|
213
|
+
.action(async (deploymentName) => {
|
|
214
|
+
try {
|
|
215
|
+
const config = await loadConfig();
|
|
216
|
+
if (!config.deployments[deploymentName]) {
|
|
217
|
+
printError(`Deployment "${deploymentName}" not found`);
|
|
218
|
+
const names = Object.keys(config.deployments);
|
|
219
|
+
if (names.length > 0) {
|
|
220
|
+
printInfo(`Available deployments: ${names.join(", ")}`);
|
|
221
|
+
}
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
config.deployments[deploymentName] = {
|
|
225
|
+
...config.deployments[deploymentName],
|
|
226
|
+
enabled: false,
|
|
227
|
+
};
|
|
228
|
+
await saveUserConfig(config);
|
|
229
|
+
printSuccess(`Disabled deployment "${deploymentName}"`);
|
|
230
|
+
console.log(pc.dim(" Will NOT be started with 'cortex start'"));
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
printError(error instanceof Error ? error.message : "Failed to disable deployment");
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
195
237
|
// config deployments
|
|
196
238
|
configCmd
|
|
197
239
|
.command("deployments")
|
|
@@ -226,24 +268,126 @@ export function registerSetupCommands(program, _config) {
|
|
|
226
268
|
});
|
|
227
269
|
// config add-deployment
|
|
228
270
|
configCmd
|
|
229
|
-
.command("add-deployment
|
|
230
|
-
.description("Add a new deployment configuration")
|
|
231
|
-
.
|
|
271
|
+
.command("add-deployment [name]")
|
|
272
|
+
.description("Add a new deployment configuration\n\nExample: cortex config add-deployment cloud -u https://my-app.convex.cloud")
|
|
273
|
+
.option("-u, --url <url>", "Convex deployment URL")
|
|
232
274
|
.option("-k, --key <key>", "Convex deploy key")
|
|
233
275
|
.option("--default", "Set as default deployment", false)
|
|
234
|
-
.
|
|
276
|
+
.option("--json-only", "Only save to ~/.cortexrc (skip .env.local)", false)
|
|
277
|
+
.action(async (nameArg, options) => {
|
|
235
278
|
try {
|
|
236
|
-
|
|
279
|
+
// Prompt for missing values interactively
|
|
280
|
+
let name = nameArg;
|
|
281
|
+
let url = options.url;
|
|
282
|
+
let key = options.key;
|
|
283
|
+
if (!name) {
|
|
284
|
+
const response = await prompts({
|
|
285
|
+
type: "select",
|
|
286
|
+
name: "name",
|
|
287
|
+
message: "Deployment name:",
|
|
288
|
+
choices: [
|
|
289
|
+
{
|
|
290
|
+
title: "local",
|
|
291
|
+
description: "Local development",
|
|
292
|
+
value: "local",
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
title: "cloud",
|
|
296
|
+
description: "Cloud/production",
|
|
297
|
+
value: "cloud",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
title: "staging",
|
|
301
|
+
description: "Staging environment",
|
|
302
|
+
value: "staging",
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
title: "custom",
|
|
306
|
+
description: "Enter custom name",
|
|
307
|
+
value: "__custom__",
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
});
|
|
311
|
+
if (!response.name) {
|
|
312
|
+
printWarning("Cancelled");
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (response.name === "__custom__") {
|
|
316
|
+
const customResponse = await prompts({
|
|
317
|
+
type: "text",
|
|
318
|
+
name: "name",
|
|
319
|
+
message: "Custom deployment name:",
|
|
320
|
+
validate: (v) => v.length > 0 || "Name is required",
|
|
321
|
+
});
|
|
322
|
+
if (!customResponse.name) {
|
|
323
|
+
printWarning("Cancelled");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
name = customResponse.name;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
name = response.name;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (!url) {
|
|
333
|
+
const isLocal = name.toLowerCase() === "local";
|
|
334
|
+
const response = await prompts({
|
|
335
|
+
type: "text",
|
|
336
|
+
name: "url",
|
|
337
|
+
message: "Convex deployment URL:",
|
|
338
|
+
initial: isLocal
|
|
339
|
+
? "http://127.0.0.1:3210"
|
|
340
|
+
: "https://your-app.convex.cloud",
|
|
341
|
+
validate: (v) => {
|
|
342
|
+
try {
|
|
343
|
+
new URL(v);
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
return "Please enter a valid URL";
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
if (!response.url) {
|
|
352
|
+
printWarning("Cancelled");
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
url = response.url;
|
|
356
|
+
}
|
|
357
|
+
validateUrl(url);
|
|
358
|
+
// Only prompt for key if not local and not already provided
|
|
359
|
+
const isLocal = name.toLowerCase() === "local";
|
|
360
|
+
if (!key && !isLocal) {
|
|
361
|
+
const response = await prompts({
|
|
362
|
+
type: "password",
|
|
363
|
+
name: "key",
|
|
364
|
+
message: "Convex deploy key (optional, press Enter to skip):",
|
|
365
|
+
});
|
|
366
|
+
key = response.key || undefined;
|
|
367
|
+
}
|
|
237
368
|
const deployment = {
|
|
238
|
-
url
|
|
239
|
-
key
|
|
369
|
+
url,
|
|
370
|
+
key,
|
|
240
371
|
};
|
|
372
|
+
// Save to user config (~/.cortexrc)
|
|
241
373
|
const config = await updateDeployment(name, deployment);
|
|
242
374
|
if (options.default) {
|
|
243
375
|
config.default = name;
|
|
244
376
|
await saveUserConfig(config);
|
|
245
377
|
}
|
|
246
|
-
|
|
378
|
+
// Also save to .env.local (unless --json-only)
|
|
379
|
+
if (!options.jsonOnly) {
|
|
380
|
+
await addDeploymentToEnv(name, url, key);
|
|
381
|
+
const envKeys = getDeploymentEnvKeys(name);
|
|
382
|
+
printSuccess(`Added deployment "${name}"`);
|
|
383
|
+
printInfo(`Updated .env.local: ${envKeys.urlKey}=${url}`);
|
|
384
|
+
if (key) {
|
|
385
|
+
printInfo(`Updated .env.local: ${envKeys.keyKey}=***`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
printSuccess(`Added deployment "${name}" to ~/.cortexrc`);
|
|
390
|
+
}
|
|
247
391
|
if (options.default) {
|
|
248
392
|
printInfo(`Set as default deployment`);
|
|
249
393
|
}
|
|
@@ -255,11 +399,36 @@ export function registerSetupCommands(program, _config) {
|
|
|
255
399
|
});
|
|
256
400
|
// config remove-deployment
|
|
257
401
|
configCmd
|
|
258
|
-
.command("remove-deployment
|
|
402
|
+
.command("remove-deployment [name]")
|
|
259
403
|
.description("Remove a deployment configuration")
|
|
260
|
-
.
|
|
404
|
+
.option("--json-only", "Only remove from ~/.cortexrc (skip .env.local)", false)
|
|
405
|
+
.action(async (nameArg, options) => {
|
|
261
406
|
try {
|
|
262
407
|
const config = await loadConfig();
|
|
408
|
+
let name = nameArg;
|
|
409
|
+
// If no name provided, show interactive selection
|
|
410
|
+
if (!name) {
|
|
411
|
+
const deploymentNames = Object.keys(config.deployments).filter((n) => n !== config.default);
|
|
412
|
+
if (deploymentNames.length === 0) {
|
|
413
|
+
printWarning("No removable deployments found (cannot remove default)");
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
const response = await prompts({
|
|
417
|
+
type: "select",
|
|
418
|
+
name: "name",
|
|
419
|
+
message: "Select deployment to remove:",
|
|
420
|
+
choices: deploymentNames.map((n) => ({
|
|
421
|
+
title: n,
|
|
422
|
+
description: config.deployments[n].url,
|
|
423
|
+
value: n,
|
|
424
|
+
})),
|
|
425
|
+
});
|
|
426
|
+
if (!response.name) {
|
|
427
|
+
printWarning("Cancelled");
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
name = response.name;
|
|
431
|
+
}
|
|
263
432
|
if (!config.deployments[name]) {
|
|
264
433
|
printError(`Deployment "${name}" not found`);
|
|
265
434
|
process.exit(1);
|
|
@@ -268,9 +437,30 @@ export function registerSetupCommands(program, _config) {
|
|
|
268
437
|
printError(`Cannot remove default deployment. Set a different default first.`);
|
|
269
438
|
process.exit(1);
|
|
270
439
|
}
|
|
440
|
+
// Confirm removal
|
|
441
|
+
const confirm = await prompts({
|
|
442
|
+
type: "confirm",
|
|
443
|
+
name: "value",
|
|
444
|
+
message: `Remove deployment "${name}" (${config.deployments[name].url})?`,
|
|
445
|
+
initial: false,
|
|
446
|
+
});
|
|
447
|
+
if (!confirm.value) {
|
|
448
|
+
printWarning("Cancelled");
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
// Remove from user config (~/.cortexrc)
|
|
271
452
|
delete config.deployments[name];
|
|
272
453
|
await saveUserConfig(config);
|
|
273
|
-
|
|
454
|
+
// Also remove from .env.local (unless --json-only)
|
|
455
|
+
if (!options.jsonOnly) {
|
|
456
|
+
const envKeys = getDeploymentEnvKeys(name);
|
|
457
|
+
await removeDeploymentFromEnv(name);
|
|
458
|
+
printSuccess(`Removed deployment "${name}"`);
|
|
459
|
+
printInfo(`Removed from .env.local: ${envKeys.urlKey}, ${envKeys.keyKey}`);
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
printSuccess(`Removed deployment "${name}" from ~/.cortexrc`);
|
|
463
|
+
}
|
|
274
464
|
}
|
|
275
465
|
catch (error) {
|
|
276
466
|
printError(error instanceof Error
|
|
@@ -279,20 +469,208 @@ export function registerSetupCommands(program, _config) {
|
|
|
279
469
|
process.exit(1);
|
|
280
470
|
}
|
|
281
471
|
});
|
|
472
|
+
// config set-key
|
|
473
|
+
configCmd
|
|
474
|
+
.command("set-key [deployment]")
|
|
475
|
+
.description("Set or update the deploy key for a deployment")
|
|
476
|
+
.option("-k, --key <key>", "Deploy key (will prompt if not provided)")
|
|
477
|
+
.option("--json-only", "Only update ~/.cortexrc (skip .env.local)", false)
|
|
478
|
+
.action(async (deploymentArg, options) => {
|
|
479
|
+
try {
|
|
480
|
+
const config = await loadConfig();
|
|
481
|
+
let name = deploymentArg;
|
|
482
|
+
// If no name provided, show interactive selection
|
|
483
|
+
if (!name) {
|
|
484
|
+
const deploymentNames = Object.keys(config.deployments);
|
|
485
|
+
if (deploymentNames.length === 0) {
|
|
486
|
+
printWarning("No deployments configured");
|
|
487
|
+
console.log(pc.dim(" Run 'cortex config add-deployment' to add one\n"));
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const response = await prompts({
|
|
491
|
+
type: "select",
|
|
492
|
+
name: "name",
|
|
493
|
+
message: "Select deployment to set key for:",
|
|
494
|
+
choices: deploymentNames.map((n) => {
|
|
495
|
+
const dep = config.deployments[n];
|
|
496
|
+
const keyStatus = dep.key ? pc.green("(key set)") : pc.dim("(no key)");
|
|
497
|
+
return {
|
|
498
|
+
title: `${n} ${keyStatus}`,
|
|
499
|
+
description: dep.url,
|
|
500
|
+
value: n,
|
|
501
|
+
};
|
|
502
|
+
}),
|
|
503
|
+
});
|
|
504
|
+
if (!response.name) {
|
|
505
|
+
printWarning("Cancelled");
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
name = response.name;
|
|
509
|
+
}
|
|
510
|
+
if (!config.deployments[name]) {
|
|
511
|
+
printError(`Deployment "${name}" not found`);
|
|
512
|
+
console.log(pc.dim(" Run 'cortex config list' to see available deployments\n"));
|
|
513
|
+
process.exit(1);
|
|
514
|
+
}
|
|
515
|
+
// Get key from option or prompt
|
|
516
|
+
let key = options.key;
|
|
517
|
+
if (!key) {
|
|
518
|
+
const response = await prompts({
|
|
519
|
+
type: "password",
|
|
520
|
+
name: "key",
|
|
521
|
+
message: `Enter deploy key for "${name}":`,
|
|
522
|
+
validate: (v) => v.length > 0 || "Key cannot be empty",
|
|
523
|
+
});
|
|
524
|
+
if (!response.key) {
|
|
525
|
+
printWarning("Cancelled");
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
key = response.key;
|
|
529
|
+
}
|
|
530
|
+
// Update the deployment with the new key
|
|
531
|
+
const deployment = config.deployments[name];
|
|
532
|
+
deployment.key = key;
|
|
533
|
+
await updateDeployment(name, deployment);
|
|
534
|
+
// Also update .env.local (unless --json-only)
|
|
535
|
+
if (!options.jsonOnly) {
|
|
536
|
+
await addDeploymentToEnv(name, deployment.url, key);
|
|
537
|
+
const envKeys = getDeploymentEnvKeys(name);
|
|
538
|
+
printSuccess(`Set deploy key for "${name}"`);
|
|
539
|
+
printInfo(`Updated .env.local: ${envKeys.keyKey}=***`);
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
printSuccess(`Set deploy key for "${name}" in ~/.cortexrc`);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
catch (error) {
|
|
546
|
+
printError(error instanceof Error ? error.message : "Failed to set key");
|
|
547
|
+
process.exit(1);
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
// config set-url
|
|
551
|
+
configCmd
|
|
552
|
+
.command("set-url [deployment]")
|
|
553
|
+
.description("Set or update the URL for a deployment")
|
|
554
|
+
.option("-u, --url <url>", "Deployment URL (will prompt if not provided)")
|
|
555
|
+
.option("--json-only", "Only update ~/.cortexrc (skip .env.local)", false)
|
|
556
|
+
.action(async (deploymentArg, options) => {
|
|
557
|
+
try {
|
|
558
|
+
const config = await loadConfig();
|
|
559
|
+
let name = deploymentArg;
|
|
560
|
+
// If no name provided, show interactive selection
|
|
561
|
+
if (!name) {
|
|
562
|
+
const deploymentNames = Object.keys(config.deployments);
|
|
563
|
+
if (deploymentNames.length === 0) {
|
|
564
|
+
printWarning("No deployments configured");
|
|
565
|
+
console.log(pc.dim(" Run 'cortex config add-deployment' to add one\n"));
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
const response = await prompts({
|
|
569
|
+
type: "select",
|
|
570
|
+
name: "name",
|
|
571
|
+
message: "Select deployment to set URL for:",
|
|
572
|
+
choices: deploymentNames.map((n) => {
|
|
573
|
+
const dep = config.deployments[n];
|
|
574
|
+
return {
|
|
575
|
+
title: n,
|
|
576
|
+
description: dep.url,
|
|
577
|
+
value: n,
|
|
578
|
+
};
|
|
579
|
+
}),
|
|
580
|
+
});
|
|
581
|
+
if (!response.name) {
|
|
582
|
+
printWarning("Cancelled");
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
name = response.name;
|
|
586
|
+
}
|
|
587
|
+
if (!config.deployments[name]) {
|
|
588
|
+
printError(`Deployment "${name}" not found`);
|
|
589
|
+
console.log(pc.dim(" Run 'cortex config list' to see available deployments\n"));
|
|
590
|
+
process.exit(1);
|
|
591
|
+
}
|
|
592
|
+
// Get URL from option or prompt
|
|
593
|
+
let url = options.url;
|
|
594
|
+
if (!url) {
|
|
595
|
+
const currentUrl = config.deployments[name].url;
|
|
596
|
+
const response = await prompts({
|
|
597
|
+
type: "text",
|
|
598
|
+
name: "url",
|
|
599
|
+
message: `Enter URL for "${name}":`,
|
|
600
|
+
initial: currentUrl,
|
|
601
|
+
validate: (v) => {
|
|
602
|
+
try {
|
|
603
|
+
new URL(v);
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
catch {
|
|
607
|
+
return "Please enter a valid URL";
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
});
|
|
611
|
+
if (!response.url) {
|
|
612
|
+
printWarning("Cancelled");
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
url = response.url;
|
|
616
|
+
}
|
|
617
|
+
// Validate URL
|
|
618
|
+
validateUrl(url);
|
|
619
|
+
// Update the deployment with the new URL
|
|
620
|
+
const deployment = config.deployments[name];
|
|
621
|
+
const oldUrl = deployment.url;
|
|
622
|
+
deployment.url = url;
|
|
623
|
+
await updateDeployment(name, deployment);
|
|
624
|
+
// Also update .env.local (unless --json-only)
|
|
625
|
+
if (!options.jsonOnly) {
|
|
626
|
+
await addDeploymentToEnv(name, url, deployment.key);
|
|
627
|
+
const envKeys = getDeploymentEnvKeys(name);
|
|
628
|
+
printSuccess(`Updated URL for "${name}"`);
|
|
629
|
+
printInfo(`${oldUrl} → ${url}`);
|
|
630
|
+
printInfo(`Updated .env.local: ${envKeys.urlKey}=${url}`);
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
printSuccess(`Updated URL for "${name}" in ~/.cortexrc`);
|
|
634
|
+
printInfo(`${oldUrl} → ${url}`);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
catch (error) {
|
|
638
|
+
printError(error instanceof Error ? error.message : "Failed to set URL");
|
|
639
|
+
process.exit(1);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
282
642
|
// config path
|
|
283
643
|
configCmd
|
|
284
644
|
.command("path")
|
|
285
645
|
.description("Show configuration file paths")
|
|
286
646
|
.action(async () => {
|
|
287
647
|
const userPath = getUserConfigPath();
|
|
288
|
-
const
|
|
648
|
+
const projectJsonPath = getProjectConfigPath();
|
|
649
|
+
const projectEnvPath = join(process.cwd(), ".env.local");
|
|
289
650
|
console.log();
|
|
290
651
|
printSection("Configuration Paths", {
|
|
291
|
-
"User config": userPath,
|
|
652
|
+
"User config (~/.cortexrc)": userPath,
|
|
292
653
|
"User config exists": existsSync(userPath) ? "Yes" : "No",
|
|
293
|
-
"Project config":
|
|
294
|
-
"Project
|
|
654
|
+
"Project JSON config": projectJsonPath,
|
|
655
|
+
"Project JSON exists": existsSync(projectJsonPath) ? "Yes" : "No",
|
|
656
|
+
"Project env config": projectEnvPath,
|
|
657
|
+
"Project env exists": existsSync(projectEnvPath) ? "Yes" : "No",
|
|
295
658
|
});
|
|
659
|
+
// Show which env vars are currently set
|
|
660
|
+
const envVars = {
|
|
661
|
+
LOCAL_CONVEX_URL: process.env.LOCAL_CONVEX_URL,
|
|
662
|
+
LOCAL_CONVEX_DEPLOYMENT: process.env.LOCAL_CONVEX_DEPLOYMENT,
|
|
663
|
+
CLOUD_CONVEX_URL: process.env.CLOUD_CONVEX_URL,
|
|
664
|
+
CLOUD_CONVEX_DEPLOY_KEY: process.env.CLOUD_CONVEX_DEPLOY_KEY
|
|
665
|
+
? "***"
|
|
666
|
+
: undefined,
|
|
667
|
+
CONVEX_URL: process.env.CONVEX_URL,
|
|
668
|
+
CONVEX_DEPLOY_KEY: process.env.CONVEX_DEPLOY_KEY ? "***" : undefined,
|
|
669
|
+
};
|
|
670
|
+
const setVars = Object.entries(envVars).filter(([, v]) => v);
|
|
671
|
+
if (setVars.length > 0) {
|
|
672
|
+
printSection("Environment Variables", Object.fromEntries(setVars));
|
|
673
|
+
}
|
|
296
674
|
});
|
|
297
675
|
// config reset
|
|
298
676
|
configCmd
|
|
@@ -314,134 +692,88 @@ export function registerSetupCommands(program, _config) {
|
|
|
314
692
|
}
|
|
315
693
|
}
|
|
316
694
|
const defaultConfig = {
|
|
317
|
-
deployments: {
|
|
318
|
-
|
|
319
|
-
url: "http://127.0.0.1:3210",
|
|
320
|
-
deployment: "anonymous:anonymous-cortex-sdk-local",
|
|
321
|
-
},
|
|
322
|
-
},
|
|
323
|
-
default: "local",
|
|
695
|
+
deployments: {},
|
|
696
|
+
default: "",
|
|
324
697
|
format: "table",
|
|
325
698
|
confirmDangerous: true,
|
|
326
699
|
};
|
|
327
700
|
await saveUserConfig(defaultConfig);
|
|
328
701
|
printSuccess("Configuration reset to defaults");
|
|
702
|
+
console.log();
|
|
703
|
+
printInfo("No deployments configured. To get started:");
|
|
704
|
+
console.log(pc.dim(" • Run 'cortex init' to create a new project"));
|
|
705
|
+
console.log(pc.dim(" • Run 'cortex config add-deployment' to add an existing deployment"));
|
|
329
706
|
}
|
|
330
707
|
catch (error) {
|
|
331
708
|
printError(error instanceof Error ? error.message : "Reset failed");
|
|
332
709
|
process.exit(1);
|
|
333
710
|
}
|
|
334
711
|
});
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
async function setupLocalDeployment(config) {
|
|
378
|
-
console.log();
|
|
379
|
-
console.log(pc.bold("Local Development Setup"));
|
|
380
|
-
console.log(pc.dim("Configure connection to local Convex instance\n"));
|
|
381
|
-
const urlPrompt = await prompts({
|
|
382
|
-
type: "text",
|
|
383
|
-
name: "url",
|
|
384
|
-
message: "Local Convex URL:",
|
|
385
|
-
initial: config.deployments.local?.url ?? "http://127.0.0.1:3210",
|
|
386
|
-
validate: (value) => {
|
|
387
|
-
try {
|
|
388
|
-
new URL(value);
|
|
389
|
-
return true;
|
|
390
|
-
}
|
|
391
|
-
catch {
|
|
392
|
-
return "Please enter a valid URL";
|
|
393
|
-
}
|
|
394
|
-
},
|
|
395
|
-
});
|
|
396
|
-
const deploymentPrompt = await prompts({
|
|
397
|
-
type: "text",
|
|
398
|
-
name: "deployment",
|
|
399
|
-
message: "Local deployment name (optional):",
|
|
400
|
-
initial: config.deployments.local?.deployment ??
|
|
401
|
-
"anonymous:anonymous-cortex-sdk-local",
|
|
402
|
-
});
|
|
403
|
-
config.deployments.local = {
|
|
404
|
-
url: urlPrompt.url,
|
|
405
|
-
deployment: deploymentPrompt.deployment || undefined,
|
|
406
|
-
};
|
|
407
|
-
return config;
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* Set up cloud deployment
|
|
411
|
-
*/
|
|
412
|
-
async function setupCloudDeployment(config) {
|
|
413
|
-
console.log();
|
|
414
|
-
console.log(pc.bold("Cloud Deployment Setup"));
|
|
415
|
-
console.log(pc.dim("Configure connection to Convex cloud\n"));
|
|
416
|
-
const urlPrompt = await prompts({
|
|
417
|
-
type: "text",
|
|
418
|
-
name: "url",
|
|
419
|
-
message: "Convex cloud URL:",
|
|
420
|
-
initial: config.deployments.cloud?.url ?? "https://your-deployment.convex.cloud",
|
|
421
|
-
validate: (value) => {
|
|
422
|
-
try {
|
|
423
|
-
const url = new URL(value);
|
|
424
|
-
if (!url.hostname.includes("convex")) {
|
|
425
|
-
return "URL should be a Convex cloud URL";
|
|
712
|
+
// Top-level 'use' command for quick deployment switching
|
|
713
|
+
program
|
|
714
|
+
.command("use [deployment]")
|
|
715
|
+
.description("Set current deployment for all commands (session context)")
|
|
716
|
+
.option("--clear", "Clear the current deployment setting")
|
|
717
|
+
.action(async (deploymentName, options) => {
|
|
718
|
+
try {
|
|
719
|
+
const config = await loadConfig();
|
|
720
|
+
const deployments = Object.keys(config.deployments);
|
|
721
|
+
// Handle --clear flag
|
|
722
|
+
if (options.clear) {
|
|
723
|
+
await clearCurrentDeployment();
|
|
724
|
+
printSuccess("Cleared current deployment");
|
|
725
|
+
console.log(pc.dim(" Commands will now prompt for deployment selection\n"));
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
// If no deployment specified, show current and list available
|
|
729
|
+
if (!deploymentName) {
|
|
730
|
+
const current = await getCurrentDeployment();
|
|
731
|
+
console.log();
|
|
732
|
+
if (current && config.deployments[current]) {
|
|
733
|
+
console.log(pc.bold(" Current deployment: ") + pc.cyan(current));
|
|
734
|
+
}
|
|
735
|
+
else if (current) {
|
|
736
|
+
console.log(pc.yellow(` Current deployment "${current}" no longer exists`));
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
console.log(pc.dim(" No current deployment set"));
|
|
740
|
+
}
|
|
741
|
+
console.log();
|
|
742
|
+
console.log(pc.bold(" Available deployments:"));
|
|
743
|
+
if (deployments.length === 0) {
|
|
744
|
+
console.log(pc.yellow(" No deployments configured"));
|
|
745
|
+
}
|
|
746
|
+
else {
|
|
747
|
+
for (const name of deployments) {
|
|
748
|
+
const isCurrent = name === current;
|
|
749
|
+
const isDefault = name === config.default;
|
|
750
|
+
const prefix = isCurrent ? pc.green("→") : " ";
|
|
751
|
+
const suffix = isDefault ? pc.dim(" (default)") : "";
|
|
752
|
+
console.log(` ${prefix} ${pc.cyan(name)}${suffix}`);
|
|
753
|
+
}
|
|
426
754
|
}
|
|
427
|
-
|
|
755
|
+
console.log();
|
|
756
|
+
console.log(pc.dim(" Usage: cortex use <deployment>"));
|
|
757
|
+
console.log(pc.dim(" cortex use --clear"));
|
|
758
|
+
console.log();
|
|
759
|
+
return;
|
|
428
760
|
}
|
|
429
|
-
|
|
430
|
-
|
|
761
|
+
// Validate deployment exists
|
|
762
|
+
if (!config.deployments[deploymentName]) {
|
|
763
|
+
printError(`Deployment "${deploymentName}" not found`);
|
|
764
|
+
console.log(pc.dim(` Available: ${deployments.join(", ")}\n`));
|
|
765
|
+
process.exit(1);
|
|
431
766
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
767
|
+
// Set the current deployment
|
|
768
|
+
await setCurrentDeployment(deploymentName);
|
|
769
|
+
printSuccess(`Now using: ${deploymentName}`);
|
|
770
|
+
console.log(pc.dim(` All commands will target this deployment until changed\n`));
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
printError(error instanceof Error ? error.message : "Failed to set deployment");
|
|
774
|
+
process.exit(1);
|
|
775
|
+
}
|
|
439
776
|
});
|
|
440
|
-
config.deployments.cloud = {
|
|
441
|
-
url: urlPrompt.url,
|
|
442
|
-
key: keyPrompt.key || undefined,
|
|
443
|
-
};
|
|
444
|
-
return config;
|
|
445
777
|
}
|
|
446
778
|
/**
|
|
447
779
|
* Show current configuration
|
|
@@ -467,11 +799,27 @@ async function showConfiguration(config, format) {
|
|
|
467
799
|
"Confirm dangerous ops": config.confirmDangerous ? "Yes" : "No",
|
|
468
800
|
});
|
|
469
801
|
console.log(" Deployments:");
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
802
|
+
const deploymentEntries = Object.entries(config.deployments);
|
|
803
|
+
if (deploymentEntries.length === 0) {
|
|
804
|
+
console.log(pc.yellow(" No deployments configured"));
|
|
805
|
+
console.log();
|
|
806
|
+
printInfo("To get started:");
|
|
807
|
+
console.log(pc.dim(" • Run 'cortex init' to create a new project"));
|
|
808
|
+
console.log(pc.dim(" • Run 'cortex config add-deployment' to add an existing deployment"));
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
for (const [name, deployment] of deploymentEntries) {
|
|
812
|
+
const isDefault = name === config.default;
|
|
813
|
+
// Default deployment is implicitly enabled; others check enabled field
|
|
814
|
+
const isEnabled = deployment.enabled === true || (deployment.enabled === undefined && isDefault);
|
|
815
|
+
const prefix = isDefault ? pc.green("→") : " ";
|
|
816
|
+
const statusBadge = isEnabled ? pc.green("[enabled]") : pc.dim("[disabled]");
|
|
817
|
+
const keyStatus = deployment.key ? pc.green("(key set)") : "";
|
|
818
|
+
console.log(` ${prefix} ${pc.cyan(name)}: ${deployment.url} ${statusBadge} ${keyStatus}`);
|
|
819
|
+
if (deployment.projectPath) {
|
|
820
|
+
console.log(pc.dim(` Project: ${deployment.projectPath}`));
|
|
821
|
+
}
|
|
822
|
+
}
|
|
475
823
|
}
|
|
476
824
|
console.log();
|
|
477
825
|
}
|