@cortexmemory/cli 0.26.2 → 0.27.3
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/commands/convex.js +1 -1
- package/dist/commands/convex.js.map +1 -1
- package/dist/commands/deploy.d.ts +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +771 -144
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +210 -36
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +273 -43
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +102 -46
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +94 -7
- package/dist/commands/status.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/app-template-sync.d.ts +95 -0
- package/dist/utils/app-template-sync.d.ts.map +1 -0
- package/dist/utils/app-template-sync.js +425 -0
- package/dist/utils/app-template-sync.js.map +1 -0
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +20 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/deployment-selector.d.ts +21 -0
- package/dist/utils/deployment-selector.d.ts.map +1 -1
- package/dist/utils/deployment-selector.js +32 -0
- package/dist/utils/deployment-selector.js.map +1 -1
- package/dist/utils/init/graph-setup.d.ts.map +1 -1
- package/dist/utils/init/graph-setup.js +25 -2
- package/dist/utils/init/graph-setup.js.map +1 -1
- package/dist/utils/init/quickstart-setup.d.ts +87 -0
- package/dist/utils/init/quickstart-setup.d.ts.map +1 -0
- package/dist/utils/init/quickstart-setup.js +462 -0
- package/dist/utils/init/quickstart-setup.js.map +1 -0
- package/dist/utils/schema-sync.d.ts.map +1 -1
- package/dist/utils/schema-sync.js +27 -21
- package/dist/utils/schema-sync.js.map +1 -1
- package/package.json +3 -2
- package/templates/vercel-ai-quickstart/.env.local.example +45 -0
- package/templates/vercel-ai-quickstart/README.md +280 -0
- package/templates/vercel-ai-quickstart/app/api/auth/check/route.ts +30 -0
- package/templates/vercel-ai-quickstart/app/api/auth/login/route.ts +83 -0
- package/templates/vercel-ai-quickstart/app/api/auth/register/route.ts +94 -0
- package/templates/vercel-ai-quickstart/app/api/auth/setup/route.ts +59 -0
- package/templates/vercel-ai-quickstart/app/api/chat/route.ts +277 -0
- package/templates/vercel-ai-quickstart/app/api/conversations/route.ts +179 -0
- package/templates/vercel-ai-quickstart/app/api/facts/route.ts +39 -0
- package/templates/vercel-ai-quickstart/app/api/health/route.ts +99 -0
- package/templates/vercel-ai-quickstart/app/api/memories/route.ts +37 -0
- package/templates/vercel-ai-quickstart/app/globals.css +275 -0
- package/templates/vercel-ai-quickstart/app/layout.tsx +19 -0
- package/templates/vercel-ai-quickstart/app/page.tsx +216 -0
- package/templates/vercel-ai-quickstart/components/AdminSetup.tsx +139 -0
- package/templates/vercel-ai-quickstart/components/AuthProvider.tsx +283 -0
- package/templates/vercel-ai-quickstart/components/ChatHistorySidebar.tsx +323 -0
- package/templates/vercel-ai-quickstart/components/ChatInterface.tsx +334 -0
- package/templates/vercel-ai-quickstart/components/ConvexClientProvider.tsx +21 -0
- package/templates/vercel-ai-quickstart/components/DataPreview.tsx +57 -0
- package/templates/vercel-ai-quickstart/components/HealthStatus.tsx +214 -0
- package/templates/vercel-ai-quickstart/components/LayerCard.tsx +263 -0
- package/templates/vercel-ai-quickstart/components/LayerFlowDiagram.tsx +195 -0
- package/templates/vercel-ai-quickstart/components/LoginScreen.tsx +202 -0
- package/templates/vercel-ai-quickstart/components/MemorySpaceSwitcher.tsx +93 -0
- package/templates/vercel-ai-quickstart/convex/conversations.ts +67 -0
- package/templates/vercel-ai-quickstart/convex/facts.ts +131 -0
- package/templates/vercel-ai-quickstart/convex/health.ts +15 -0
- package/templates/vercel-ai-quickstart/convex/memories.ts +104 -0
- package/templates/vercel-ai-quickstart/convex/schema.ts +20 -0
- package/templates/vercel-ai-quickstart/convex/users.ts +105 -0
- package/templates/vercel-ai-quickstart/jest.config.js +45 -0
- package/templates/vercel-ai-quickstart/lib/animations.ts +146 -0
- package/templates/vercel-ai-quickstart/lib/cortex.ts +27 -0
- package/templates/vercel-ai-quickstart/lib/layer-tracking.ts +214 -0
- package/templates/vercel-ai-quickstart/lib/password.ts +120 -0
- package/templates/vercel-ai-quickstart/next.config.js +27 -0
- package/templates/vercel-ai-quickstart/package.json +46 -0
- package/templates/vercel-ai-quickstart/postcss.config.js +5 -0
- package/templates/vercel-ai-quickstart/tailwind.config.js +37 -0
- package/templates/vercel-ai-quickstart/tests/helpers/mock-cortex.ts +263 -0
- package/templates/vercel-ai-quickstart/tests/helpers/setup.ts +48 -0
- package/templates/vercel-ai-quickstart/tests/integration/auth.test.ts +455 -0
- package/templates/vercel-ai-quickstart/tests/integration/conversations.test.ts +461 -0
- package/templates/vercel-ai-quickstart/tests/unit/password.test.ts +228 -0
- package/templates/vercel-ai-quickstart/tsconfig.json +33 -0
package/dist/commands/init.js
CHANGED
|
@@ -13,6 +13,7 @@ import { spawn } from "child_process";
|
|
|
13
13
|
import { loadConfig, saveUserConfig } from "../utils/config.js";
|
|
14
14
|
import { isValidProjectName, isDirectoryEmpty, fetchLatestSDKMetadata, execCommand, commandExists, } from "../utils/shell.js";
|
|
15
15
|
import { setupNewConvex, setupExistingConvex, deployToConvex, ensureConvexAuth, sanitizeProjectName, } from "../utils/init/convex-setup.js";
|
|
16
|
+
import { installVercelAIQuickstart, startApp, stopApp, findAppPidFiles, isAppRunning, findProcessByPort, stopProcessByPort, } from "../utils/init/quickstart-setup.js";
|
|
16
17
|
import { getGraphConfig, setupGraphFiles, addGraphDependencies, createGraphExample, startGraphContainers, stopGraphContainers, } from "../utils/init/graph-setup.js";
|
|
17
18
|
import { copyTemplate, deployCortexBackend, createConvexJson, ensureGitignore, } from "../utils/init/file-operations.js";
|
|
18
19
|
import { createEnvFile, appendGraphEnvVars, } from "../utils/init/env-generator.js";
|
|
@@ -101,12 +102,24 @@ export function registerLifecycleCommands(program, _config) {
|
|
|
101
102
|
console.log(pc.dim(" Use 'cortex start -d <name> -f' for foreground mode"));
|
|
102
103
|
process.exit(1);
|
|
103
104
|
}
|
|
104
|
-
|
|
105
|
+
// Collect enabled apps for summary
|
|
106
|
+
const apps = Object.entries(config.apps || {});
|
|
107
|
+
const enabledApps = apps.filter(([, app]) => app.enabled);
|
|
108
|
+
// Show summary header
|
|
109
|
+
console.log();
|
|
110
|
+
console.log(pc.bold(" ═══════════════════════════════════════════════════════════"));
|
|
111
|
+
console.log(pc.bold(" Cortex Start"));
|
|
112
|
+
console.log(pc.bold(" ═══════════════════════════════════════════════════════════"));
|
|
113
|
+
console.log();
|
|
114
|
+
// Deployments section
|
|
115
|
+
console.log(pc.bold(pc.cyan(` Deployments (${deploymentsToStart.length})`)));
|
|
116
|
+
console.log(pc.dim(" ───────────────────────────────────────────────────────────"));
|
|
105
117
|
// Start each deployment
|
|
106
118
|
for (const dep of deploymentsToStart) {
|
|
107
|
-
console.log(pc.
|
|
108
|
-
console.log(pc.dim(`
|
|
109
|
-
console.log(pc.dim(`
|
|
119
|
+
console.log(` ${pc.green("●")} ${pc.cyan(dep.name)}`);
|
|
120
|
+
console.log(pc.dim(` Project: ${dep.projectPath}`));
|
|
121
|
+
console.log(pc.dim(` URL: ${dep.url}`));
|
|
122
|
+
console.log();
|
|
110
123
|
// Start graph database if configured and not convex-only
|
|
111
124
|
if (!options.convexOnly) {
|
|
112
125
|
const dockerComposePath = path.join(dep.projectPath, "docker-compose.graph.yml");
|
|
@@ -185,28 +198,86 @@ export function registerLifecycleCommands(program, _config) {
|
|
|
185
198
|
}
|
|
186
199
|
}
|
|
187
200
|
}
|
|
201
|
+
// Start enabled apps (unless convex-only or graph-only)
|
|
202
|
+
if (!options.convexOnly && !options.graphOnly && !options.foreground) {
|
|
203
|
+
if (enabledApps.length > 0) {
|
|
204
|
+
console.log(pc.bold(pc.cyan(` Apps (${enabledApps.length})`)));
|
|
205
|
+
console.log(pc.dim(" ───────────────────────────────────────────────────────────"));
|
|
206
|
+
for (const [name, app] of enabledApps) {
|
|
207
|
+
console.log(` ${pc.green("●")} ${pc.cyan(name)}`);
|
|
208
|
+
console.log(pc.dim(` Type: ${app.type}`));
|
|
209
|
+
console.log(pc.dim(` Path: ${path.join(app.projectPath, app.path)}`));
|
|
210
|
+
console.log(pc.dim(` Port: ${app.port || 3000}`));
|
|
211
|
+
console.log();
|
|
212
|
+
await startApp(name, app);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
188
216
|
// Show summary
|
|
189
217
|
if (!options.foreground) {
|
|
190
|
-
|
|
191
|
-
console.log(pc.
|
|
192
|
-
console.log(pc.
|
|
218
|
+
const totalStarted = deploymentsToStart.length + (enabledApps.length || 0);
|
|
219
|
+
console.log(pc.bold(" ═══════════════════════════════════════════════════════════"));
|
|
220
|
+
console.log(pc.green(` ✓ Started ${totalStarted} service(s)`));
|
|
221
|
+
console.log(pc.bold(" ═══════════════════════════════════════════════════════════"));
|
|
222
|
+
console.log();
|
|
223
|
+
console.log(pc.dim(" Use 'cortex stop' to stop all services"));
|
|
224
|
+
console.log(pc.dim(" Use 'cortex config list' to see deployment status"));
|
|
225
|
+
console.log();
|
|
193
226
|
}
|
|
194
227
|
});
|
|
195
228
|
// Stop command
|
|
196
229
|
program
|
|
197
230
|
.command("stop")
|
|
198
|
-
.description("Stop background services (Convex
|
|
231
|
+
.description("Stop background services (Convex, graph database, and apps)")
|
|
199
232
|
.option("-d, --deployment <name>", "Stop specific deployment only")
|
|
233
|
+
.option("-a, --app <name>", "Stop specific app only")
|
|
200
234
|
.option("--convex-only", "Only stop Convex server", false)
|
|
201
235
|
.option("--graph-only", "Only stop graph database", false)
|
|
236
|
+
.option("--apps-only", "Only stop template apps", false)
|
|
202
237
|
.action(async (options) => {
|
|
238
|
+
// Load fresh config to get current state
|
|
239
|
+
const config = await loadConfig();
|
|
203
240
|
let stoppedSomething = false;
|
|
204
241
|
let stoppedCount = 0;
|
|
205
|
-
|
|
242
|
+
let stoppedAppsCount = 0;
|
|
243
|
+
// If stopping specific app only
|
|
244
|
+
if (options.app) {
|
|
245
|
+
const appConfig = config.apps?.[options.app];
|
|
246
|
+
if (!appConfig) {
|
|
247
|
+
// Try to find app in current directory
|
|
248
|
+
const cwd = process.cwd();
|
|
249
|
+
const appPidFiles = await findAppPidFiles(cwd);
|
|
250
|
+
const matchingApp = appPidFiles.find((a) => a.name === options.app);
|
|
251
|
+
if (!matchingApp) {
|
|
252
|
+
console.error(pc.red(`\n Error: App "${options.app}" not found`));
|
|
253
|
+
console.log(pc.dim(" Run 'cortex config list' to see available apps\n"));
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
// Stop from current directory
|
|
257
|
+
const stopped = await stopApp(options.app, cwd);
|
|
258
|
+
if (stopped) {
|
|
259
|
+
console.log(pc.green(`\n ✓ App "${options.app}" stopped\n`));
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
console.log(pc.yellow(`\n App "${options.app}" was not running\n`));
|
|
263
|
+
}
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// Stop specific configured app
|
|
267
|
+
const stopped = await stopApp(options.app, appConfig.projectPath);
|
|
268
|
+
if (stopped) {
|
|
269
|
+
console.log(pc.green(`\n ✓ App "${options.app}" stopped\n`));
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
console.log(pc.yellow(`\n App "${options.app}" was not running\n`));
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
// Determine which deployments/project paths to stop
|
|
206
277
|
const deploymentsToStop = [];
|
|
207
278
|
if (options.deployment) {
|
|
208
279
|
// Stop specific deployment
|
|
209
|
-
const deployment =
|
|
280
|
+
const deployment = config.deployments?.[options.deployment];
|
|
210
281
|
if (!deployment) {
|
|
211
282
|
console.error(pc.red(`\n Error: Deployment "${options.deployment}" not found`));
|
|
212
283
|
console.log(pc.dim(" Run 'cortex config list' to see available deployments\n"));
|
|
@@ -224,36 +295,52 @@ export function registerLifecycleCommands(program, _config) {
|
|
|
224
295
|
}
|
|
225
296
|
else {
|
|
226
297
|
// Stop all deployments that have running processes
|
|
227
|
-
const deploymentEntries = Object.entries(
|
|
228
|
-
|
|
298
|
+
const deploymentEntries = Object.entries(config.deployments || {});
|
|
299
|
+
// Collect project paths from both deployments and apps
|
|
300
|
+
const projectPaths = new Map(); // path -> name
|
|
301
|
+
if (deploymentEntries.length === 0 && !config.apps) {
|
|
229
302
|
// Fallback to current directory
|
|
230
303
|
const cwd = process.cwd();
|
|
231
|
-
|
|
232
|
-
name: "current directory",
|
|
233
|
-
projectPath: cwd,
|
|
234
|
-
});
|
|
304
|
+
projectPaths.set(cwd, "current directory");
|
|
235
305
|
}
|
|
236
306
|
else {
|
|
307
|
+
// Add deployment project paths
|
|
237
308
|
for (const [name, deployment] of deploymentEntries) {
|
|
238
309
|
if (deployment.projectPath &&
|
|
239
310
|
fs.existsSync(deployment.projectPath)) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
311
|
+
projectPaths.set(deployment.projectPath, name);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Add app project paths (may overlap with deployments)
|
|
315
|
+
if (config.apps) {
|
|
316
|
+
for (const [appName, app] of Object.entries(config.apps)) {
|
|
317
|
+
if (app.projectPath && fs.existsSync(app.projectPath)) {
|
|
318
|
+
// Use app name if no deployment for this path
|
|
319
|
+
if (!projectPaths.has(app.projectPath)) {
|
|
320
|
+
projectPaths.set(app.projectPath, `app:${appName}`);
|
|
321
|
+
}
|
|
250
322
|
}
|
|
251
323
|
}
|
|
252
324
|
}
|
|
253
325
|
}
|
|
326
|
+
// Check each project path for running services
|
|
327
|
+
for (const [projectPath, name] of projectPaths) {
|
|
328
|
+
// Check if anything is running for this deployment
|
|
329
|
+
const pidFile = path.join(projectPath, ".convex-dev.pid");
|
|
330
|
+
const dockerCompose = path.join(projectPath, "docker-compose.graph.yml");
|
|
331
|
+
const appPidFiles = await findAppPidFiles(projectPath);
|
|
332
|
+
const hasPidFile = fs.existsSync(pidFile);
|
|
333
|
+
const hasDockerCompose = fs.existsSync(dockerCompose);
|
|
334
|
+
const hasApps = appPidFiles.length > 0;
|
|
335
|
+
if (hasPidFile || hasDockerCompose || hasApps) {
|
|
336
|
+
deploymentsToStop.push({ name, projectPath });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
254
339
|
}
|
|
255
340
|
if (deploymentsToStop.length === 0) {
|
|
256
|
-
console.log(pc.yellow("\n No deployments with running services found
|
|
341
|
+
console.log(pc.yellow("\n No deployments with running services found"));
|
|
342
|
+
console.log(pc.dim(" Note: Services started without PID files cannot be auto-detected.\n" +
|
|
343
|
+
" Use 'ps aux | grep convex' or 'ps aux | grep next' to find running processes.\n"));
|
|
257
344
|
return;
|
|
258
345
|
}
|
|
259
346
|
console.log(pc.cyan(`\n Stopping ${deploymentsToStop.length} deployment(s)...\n`));
|
|
@@ -261,8 +348,9 @@ export function registerLifecycleCommands(program, _config) {
|
|
|
261
348
|
console.log(pc.bold(` ${name}`));
|
|
262
349
|
console.log(pc.dim(` ${projectPath}`));
|
|
263
350
|
let deploymentStopped = false;
|
|
264
|
-
|
|
265
|
-
if
|
|
351
|
+
let convexStopped = false;
|
|
352
|
+
// Stop Convex if not graph-only and not apps-only
|
|
353
|
+
if (!options.graphOnly && !options.appsOnly) {
|
|
266
354
|
const pidFile = path.join(projectPath, ".convex-dev.pid");
|
|
267
355
|
try {
|
|
268
356
|
const pid = await fs.readFile(pidFile, "utf-8");
|
|
@@ -272,11 +360,13 @@ export function registerLifecycleCommands(program, _config) {
|
|
|
272
360
|
console.log(pc.green(` ✓ Convex stopped (PID: ${pidNum})`));
|
|
273
361
|
stoppedSomething = true;
|
|
274
362
|
deploymentStopped = true;
|
|
363
|
+
convexStopped = true;
|
|
275
364
|
}
|
|
276
365
|
catch (e) {
|
|
277
366
|
const err = e;
|
|
278
367
|
if (err.code === "ESRCH") {
|
|
279
368
|
console.log(pc.yellow(" Convex was already stopped"));
|
|
369
|
+
convexStopped = true; // Consider it handled
|
|
280
370
|
}
|
|
281
371
|
else {
|
|
282
372
|
throw e;
|
|
@@ -290,13 +380,37 @@ export function registerLifecycleCommands(program, _config) {
|
|
|
290
380
|
if (err.code !== "ENOENT") {
|
|
291
381
|
console.error(pc.red(" Error stopping Convex:"), e);
|
|
292
382
|
}
|
|
293
|
-
|
|
294
|
-
|
|
383
|
+
// No PID file - will try port-based detection below
|
|
384
|
+
}
|
|
385
|
+
// Fallback: try to stop by port if no PID file and deployment is local
|
|
386
|
+
if (!convexStopped) {
|
|
387
|
+
// Check if this is a local deployment (port 3210)
|
|
388
|
+
const deploymentConfig = Object.values(config.deployments || {}).find((d) => d.projectPath === projectPath);
|
|
389
|
+
const isLocal = deploymentConfig?.url?.includes("127.0.0.1:3210") ||
|
|
390
|
+
deploymentConfig?.url?.includes("localhost:3210");
|
|
391
|
+
if (isLocal) {
|
|
392
|
+
const convexPid = await findProcessByPort(3210);
|
|
393
|
+
if (convexPid) {
|
|
394
|
+
console.log(pc.yellow(` Found Convex on port 3210 (no PID file)`));
|
|
395
|
+
const stopped = await stopProcessByPort(3210);
|
|
396
|
+
if (stopped) {
|
|
397
|
+
console.log(pc.green(` ✓ Convex stopped (port 3210, PID: ${convexPid})`));
|
|
398
|
+
stoppedSomething = true;
|
|
399
|
+
deploymentStopped = true;
|
|
400
|
+
convexStopped = true;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
console.log(pc.dim(" No Convex process running"));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
else if (!options.graphOnly && !options.appsOnly) {
|
|
408
|
+
console.log(pc.dim(" No Convex process running (PID file not found)"));
|
|
295
409
|
}
|
|
296
410
|
}
|
|
297
411
|
}
|
|
298
|
-
// Stop graph containers if not convex-only
|
|
299
|
-
if (!options.convexOnly) {
|
|
412
|
+
// Stop graph containers if not convex-only and not apps-only
|
|
413
|
+
if (!options.convexOnly && !options.appsOnly) {
|
|
300
414
|
const dockerComposePath = path.join(projectPath, "docker-compose.graph.yml");
|
|
301
415
|
if (fs.existsSync(dockerComposePath)) {
|
|
302
416
|
const stopped = await stopGraphContainers(projectPath);
|
|
@@ -309,17 +423,76 @@ export function registerLifecycleCommands(program, _config) {
|
|
|
309
423
|
console.log(pc.dim(" No graph container running"));
|
|
310
424
|
}
|
|
311
425
|
}
|
|
312
|
-
else if (!options.convexOnly) {
|
|
426
|
+
else if (!options.convexOnly && !options.appsOnly) {
|
|
313
427
|
console.log(pc.dim(" No graph database configured"));
|
|
314
428
|
}
|
|
315
429
|
}
|
|
430
|
+
// Stop apps if not convex-only and not graph-only
|
|
431
|
+
if (!options.convexOnly && !options.graphOnly) {
|
|
432
|
+
const appPidFiles = await findAppPidFiles(projectPath);
|
|
433
|
+
const stoppedAppNames = new Set();
|
|
434
|
+
// First, try to stop apps with PID files
|
|
435
|
+
if (appPidFiles.length > 0) {
|
|
436
|
+
for (const { name: appName } of appPidFiles) {
|
|
437
|
+
const appStatus = await isAppRunning(appName, projectPath);
|
|
438
|
+
if (appStatus.running) {
|
|
439
|
+
const stopped = await stopApp(appName, projectPath);
|
|
440
|
+
if (stopped) {
|
|
441
|
+
console.log(pc.green(` ✓ App "${appName}" stopped (PID: ${appStatus.pid})`));
|
|
442
|
+
stoppedSomething = true;
|
|
443
|
+
stoppedAppsCount++;
|
|
444
|
+
deploymentStopped = true;
|
|
445
|
+
stoppedAppNames.add(appName);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
// Clean up stale PID file (already handled by isAppRunning)
|
|
450
|
+
console.log(pc.dim(` App "${appName}" was not running`));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// Also check configured apps that might not have PID files
|
|
455
|
+
// (started before PID tracking was added)
|
|
456
|
+
if (config.apps) {
|
|
457
|
+
for (const [appName, appConfig] of Object.entries(config.apps)) {
|
|
458
|
+
// Skip if already stopped via PID file or not matching this project
|
|
459
|
+
if (stoppedAppNames.has(appName))
|
|
460
|
+
continue;
|
|
461
|
+
if (appConfig.projectPath !== projectPath)
|
|
462
|
+
continue;
|
|
463
|
+
const port = appConfig.port || 3000;
|
|
464
|
+
const pid = await findProcessByPort(port);
|
|
465
|
+
if (pid) {
|
|
466
|
+
console.log(pc.yellow(` Found app "${appName}" on port ${port} (no PID file)`));
|
|
467
|
+
const stopped = await stopProcessByPort(port);
|
|
468
|
+
if (stopped) {
|
|
469
|
+
console.log(pc.green(` ✓ App "${appName}" stopped (port ${port}, PID: ${pid})`));
|
|
470
|
+
stoppedSomething = true;
|
|
471
|
+
stoppedAppsCount++;
|
|
472
|
+
deploymentStopped = true;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (appPidFiles.length === 0 && !config.apps && options.appsOnly) {
|
|
478
|
+
console.log(pc.dim(" No apps configured"));
|
|
479
|
+
}
|
|
480
|
+
}
|
|
316
481
|
if (deploymentStopped) {
|
|
317
482
|
stoppedCount++;
|
|
318
483
|
}
|
|
319
484
|
console.log();
|
|
320
485
|
}
|
|
486
|
+
// Summary
|
|
321
487
|
if (stoppedSomething) {
|
|
322
|
-
|
|
488
|
+
const parts = [];
|
|
489
|
+
if (stoppedCount > 0 && !options.appsOnly) {
|
|
490
|
+
parts.push(`${stoppedCount} deployment(s)`);
|
|
491
|
+
}
|
|
492
|
+
if (stoppedAppsCount > 0) {
|
|
493
|
+
parts.push(`${stoppedAppsCount} app(s)`);
|
|
494
|
+
}
|
|
495
|
+
console.log(pc.green(` ✓ Stopped ${parts.join(" and ")}\n`));
|
|
323
496
|
}
|
|
324
497
|
else {
|
|
325
498
|
console.log(pc.yellow(" No services were running\n"));
|
|
@@ -401,26 +574,64 @@ export async function runInitWizard(targetDir, options = {}) {
|
|
|
401
574
|
if (!options.yes) {
|
|
402
575
|
await showConfirmation(config);
|
|
403
576
|
}
|
|
404
|
-
// Execute setup
|
|
405
|
-
await executeSetup(config);
|
|
406
|
-
// Ask
|
|
577
|
+
// Execute setup (returns SDK metadata for post-setup steps)
|
|
578
|
+
const sdkMetadata = await executeSetup(config);
|
|
579
|
+
// Ask about Vercel AI quickstart (optional demo app)
|
|
580
|
+
let installedQuickstart = false;
|
|
581
|
+
let quickstartAppConfig = null;
|
|
582
|
+
if (!options.yes) {
|
|
583
|
+
const { installQuickstart } = await prompts({
|
|
584
|
+
type: "confirm",
|
|
585
|
+
name: "installQuickstart",
|
|
586
|
+
message: "Install Vercel AI quickstart demo?",
|
|
587
|
+
initial: false,
|
|
588
|
+
});
|
|
589
|
+
if (installQuickstart) {
|
|
590
|
+
// Need the actual Convex URL from the config that was just set up
|
|
591
|
+
const convexUrl = config.convexUrl || "";
|
|
592
|
+
// Pass graph config if it was enabled during init
|
|
593
|
+
const graphConfig = config.graphEnabled
|
|
594
|
+
? {
|
|
595
|
+
enabled: true,
|
|
596
|
+
uri: config.graphUri,
|
|
597
|
+
username: config.graphUsername,
|
|
598
|
+
password: config.graphPassword,
|
|
599
|
+
}
|
|
600
|
+
: undefined;
|
|
601
|
+
quickstartAppConfig = await installVercelAIQuickstart(config.projectPath, sdkMetadata.sdkVersion, convexUrl, config.openaiApiKey, graphConfig);
|
|
602
|
+
// Save app to CLI config
|
|
603
|
+
const cliConfig = await loadConfig();
|
|
604
|
+
cliConfig.apps = cliConfig.apps || {};
|
|
605
|
+
cliConfig.apps["quickstart"] = quickstartAppConfig;
|
|
606
|
+
await saveUserConfig(cliConfig);
|
|
607
|
+
installedQuickstart = true;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
// Context-aware start prompt
|
|
407
611
|
let shouldStart = options.start;
|
|
408
612
|
if (!shouldStart && !options.yes) {
|
|
613
|
+
const message = installedQuickstart
|
|
614
|
+
? "Start Convex backend and quickstart app now?"
|
|
615
|
+
: "Start Convex development server now?";
|
|
409
616
|
const response = await prompts({
|
|
410
617
|
type: "confirm",
|
|
411
618
|
name: "startNow",
|
|
412
|
-
message
|
|
619
|
+
message,
|
|
413
620
|
initial: true,
|
|
414
621
|
});
|
|
415
622
|
shouldStart = response.startNow;
|
|
416
623
|
}
|
|
417
|
-
// Start
|
|
624
|
+
// Start services if requested
|
|
418
625
|
if (shouldStart) {
|
|
419
626
|
const isLocal = config.convexSetupType === "local";
|
|
420
627
|
await startConvexInBackground(config.projectPath, isLocal);
|
|
628
|
+
// Start quickstart app if installed
|
|
629
|
+
if (installedQuickstart && quickstartAppConfig) {
|
|
630
|
+
await startApp("quickstart", quickstartAppConfig);
|
|
631
|
+
}
|
|
421
632
|
// Show running status dashboard
|
|
422
633
|
console.log();
|
|
423
|
-
await showRunningStatus(config.projectPath, isLocal);
|
|
634
|
+
await showRunningStatus(config.projectPath, isLocal, installedQuickstart);
|
|
424
635
|
}
|
|
425
636
|
}
|
|
426
637
|
/**
|
|
@@ -643,6 +854,7 @@ async function showConfirmation(config) {
|
|
|
643
854
|
}
|
|
644
855
|
/**
|
|
645
856
|
* Execute the setup
|
|
857
|
+
* Returns SDK metadata for use in post-setup steps (like quickstart installation)
|
|
646
858
|
*/
|
|
647
859
|
async function executeSetup(config) {
|
|
648
860
|
console.log(pc.cyan("\n Setting up Cortex...\n"));
|
|
@@ -788,6 +1000,11 @@ async function executeSetup(config) {
|
|
|
788
1000
|
await saveDeploymentToConfig(config);
|
|
789
1001
|
// Success!
|
|
790
1002
|
showSuccessMessage(config);
|
|
1003
|
+
// Return SDK metadata for use in post-setup steps
|
|
1004
|
+
return {
|
|
1005
|
+
sdkVersion: sdkMetadata.sdkVersion,
|
|
1006
|
+
convexVersion: sdkMetadata.convexVersion,
|
|
1007
|
+
};
|
|
791
1008
|
}
|
|
792
1009
|
catch (error) {
|
|
793
1010
|
console.error(pc.red("\n Setup failed:"), error);
|
|
@@ -809,11 +1026,12 @@ async function saveDeploymentToConfig(config) {
|
|
|
809
1026
|
const deploymentName = config.projectName
|
|
810
1027
|
.toLowerCase()
|
|
811
1028
|
.replace(/[^a-z0-9-]/g, "-");
|
|
812
|
-
// Add the deployment
|
|
1029
|
+
// Add the deployment (enabled by default when created by init)
|
|
813
1030
|
userConfig.deployments[deploymentName] = {
|
|
814
1031
|
url: config.convexUrl,
|
|
815
1032
|
key: config.deployKey,
|
|
816
1033
|
projectPath: config.projectPath,
|
|
1034
|
+
enabled: true,
|
|
817
1035
|
};
|
|
818
1036
|
// Set as default if no default exists
|
|
819
1037
|
if (!userConfig.default) {
|
|
@@ -934,7 +1152,7 @@ async function startConvexInBackground(projectPath, isLocal, deploymentUrl, depl
|
|
|
934
1152
|
/**
|
|
935
1153
|
* Show running services status dashboard
|
|
936
1154
|
*/
|
|
937
|
-
async function showRunningStatus(projectPath, isLocal) {
|
|
1155
|
+
async function showRunningStatus(projectPath, isLocal, hasQuickstart = false) {
|
|
938
1156
|
const width = 56;
|
|
939
1157
|
const line = "═".repeat(width);
|
|
940
1158
|
const thinLine = "─".repeat(width);
|
|
@@ -1006,6 +1224,15 @@ async function showRunningStatus(projectPath, isLocal) {
|
|
|
1006
1224
|
console.log(` ${pc.dim("○")} Not configured`);
|
|
1007
1225
|
}
|
|
1008
1226
|
console.log();
|
|
1227
|
+
// Quickstart App Status (if installed)
|
|
1228
|
+
if (hasQuickstart) {
|
|
1229
|
+
console.log(pc.bold(pc.white(" Vercel AI Quickstart")));
|
|
1230
|
+
console.log(pc.dim(" " + thinLine));
|
|
1231
|
+
console.log(` ${pc.green("●")} Running`);
|
|
1232
|
+
console.log(pc.dim(" URL: http://localhost:3000"));
|
|
1233
|
+
console.log(pc.dim(" Interactive chat demo with memory visualization"));
|
|
1234
|
+
console.log();
|
|
1235
|
+
}
|
|
1009
1236
|
// Quick Actions
|
|
1010
1237
|
console.log(pc.bold(pc.white(" Quick Actions")));
|
|
1011
1238
|
console.log(pc.dim(" " + thinLine));
|
|
@@ -1014,6 +1241,9 @@ async function showRunningStatus(projectPath, isLocal) {
|
|
|
1014
1241
|
pc.dim(" # Foreground mode (see logs)"));
|
|
1015
1242
|
console.log(pc.dim(" cortex stop") +
|
|
1016
1243
|
pc.dim(" # Stop background services"));
|
|
1244
|
+
if (hasQuickstart) {
|
|
1245
|
+
console.log(pc.dim(" npm run quickstart") + pc.dim(" # Start quickstart demo"));
|
|
1246
|
+
}
|
|
1017
1247
|
console.log(pc.dim(" npm start") + pc.dim(" # Run your AI agent"));
|
|
1018
1248
|
console.log();
|
|
1019
1249
|
// Log file hint
|