create-memory-soda 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -4
  2. package/index.js +40 -58
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -19,8 +19,8 @@ what it can, and ends with a checklist of anything it could not do for you.
19
19
  confirms pgvector and enables the extension. Failures name the fix and let
20
20
  you retry, paste another URL, or skip.
21
21
  5. **Gemini key** — checked live. Blank allowed; goes on the checklist.
22
- 6. **Ports and admin login** — ports checked for use; blank password is
23
- generated at first boot.
22
+ 6. **Ports** — checked for use. Dashboard login starts as `admin` /
23
+ `open-sesame`; change it after signing in.
24
24
  7. **Clone, `.env`, `npm ci`, migrations** — migrations run now if the database
25
25
  passed.
26
26
 
@@ -31,8 +31,8 @@ cd memory-soda
31
31
  npm run dev
32
32
  ```
33
33
 
34
- Sign in to the dashboard (:3000) to create an API key. `npm run update` pulls
35
- and reinstalls later. Pass `--verbose` to stream clone/install output.
34
+ Sign in to the dashboard (:3000) to create an API key. The public repo is
35
+ remote `upstream`; `npm run update` pulls from it. Add your own repo as `origin`. Pass `--verbose` to stream clone/install output.
36
36
 
37
37
  ## Requirements
38
38
 
package/index.js CHANGED
@@ -83,15 +83,8 @@ function runWithSpinner(title, cmd, args, { cwd } = {}) {
83
83
  * explicitly — everything else stays on the defaults baked into config.ts, so
84
84
  * this file does not drift every time a new option is added there.
85
85
  */
86
- export function renderEnv({
87
- databaseUrl,
88
- geminiKey,
89
- adminUser,
90
- adminPassword,
91
- apiPort,
92
- dashboardPort,
93
- }) {
94
- const lines = [
86
+ export function renderEnv({ databaseUrl, geminiKey, apiPort, dashboardPort }) {
87
+ return [
95
88
  '# Generated by create-memory-soda.',
96
89
  '# Full reference: https://github.com/alagappan17/memory-soda',
97
90
  '',
@@ -108,15 +101,11 @@ export function renderEnv({
108
101
  `CORS_ORIGIN=http://localhost:${dashboardPort}`,
109
102
  `VITE_API_URL=http://localhost:${apiPort}`,
110
103
  '',
111
- '# Dashboard login, created once on first boot.',
112
- `ADMIN_USERNAME=${adminUser}`,
113
- ];
114
- // An unset ADMIN_PASSWORD makes the API generate one and print it once. That
115
- // is a better default than writing a weak chosen password to disk, so a blank
116
- // answer omits the key entirely rather than writing an empty one.
117
- if (adminPassword) lines.push(`ADMIN_PASSWORD=${adminPassword}`);
118
- lines.push('');
119
- return lines.join('\n');
104
+ '# Dashboard login. Defaults to admin / open-sesame — change it in the dashboard after first sign-in.',
105
+ '# ADMIN_USERNAME=admin',
106
+ '# ADMIN_PASSWORD=open-sesame',
107
+ '',
108
+ ].join('\n');
120
109
  }
121
110
 
122
111
  /** True if the path is safe to scaffold into: missing, or an empty directory. */
@@ -406,40 +395,35 @@ async function main() {
406
395
  }
407
396
  if (where !== 'skip') {
408
397
  for (;;) {
409
- const s = p.spinner();
398
+ // A clack spinner cannot be restarted once stopped (its timer leaks and
399
+ // the process never exits), so every phase gets a fresh one.
400
+ let s = p.spinner();
410
401
  s.start('Checking the database');
411
402
  let result = await checkDatabase(databaseUrl);
412
403
  if (result?.missingDb) {
413
404
  s.stop(`Database "${result.missingDb}" does not exist`);
414
405
  if (
415
- guard(
406
+ !guard(
416
407
  await p.confirm({
417
408
  message: `Create database "${result.missingDb}"?`,
418
409
  initialValue: true,
419
410
  }),
420
411
  )
421
412
  ) {
422
- s.start(`Creating database ${result.missingDb}`);
423
- try {
424
- await createDatabase(databaseUrl);
425
- result = await checkDatabase(databaseUrl);
426
- } catch (err) {
427
- result = {
428
- problem: `could not create database "${result.missingDb}": ${err.message}`,
429
- fix: `createdb ${result.missingDb} (as a role with CREATEDB)`,
430
- };
431
- }
432
- } else {
433
413
  todo.push(`createdb ${result.missingDb}`);
434
414
  break;
435
415
  }
436
- if (result?.missingDb)
416
+ s = p.spinner();
417
+ s.start(`Creating database ${result.missingDb}`);
418
+ try {
419
+ await createDatabase(databaseUrl);
420
+ result = await checkDatabase(databaseUrl);
421
+ } catch (err) {
437
422
  result = {
438
- problem: `database "${result.missingDb}" still does not exist`,
439
- fix: null,
423
+ problem: `could not create database "${result.missingDb}": ${err.message}`,
424
+ fix: `createdb ${result.missingDb} (as a role with CREATEDB)`,
440
425
  };
441
- if (result === null || result?.extensionTodo)
442
- s.start('Checking the database');
426
+ }
443
427
  }
444
428
  if (result === null) {
445
429
  s.stop('Database ready — connected, pgvector enabled');
@@ -504,39 +488,27 @@ async function main() {
504
488
  'Set GOOGLE_GENERATIVE_AI_API_KEY in .env — the API refuses to start without it',
505
489
  );
506
490
 
507
- // ── 5 + 6. Ports and login
491
+ // ── 5. Ports
508
492
  const apiPort = await askPort('API port', '3004');
509
493
  const dashboardPort = await askPort('Dashboard port', '3000');
510
- const adminUser = guard(
511
- await p.text({
512
- message: 'Dashboard admin username',
513
- placeholder: 'admin',
514
- defaultValue: 'admin',
515
- }),
516
- );
517
- const adminPassword =
518
- guard(
519
- await p.password({
520
- message: `Dashboard admin password ${chalk.dim('(leave blank to generate one at first boot)')}`,
521
- mask: '•',
522
- }),
523
- ) ?? '';
524
-
525
494
  // ── 7. Install
526
495
  await runWithSpinner(`Cloning into ${chalk.bold(dirName)}`, 'git', [
527
496
  'clone',
528
- '--depth',
529
- '1',
530
497
  REPO,
531
498
  target,
532
499
  ]);
500
+ // The clone points at the public repo, which the user cannot push to.
501
+ // Name it `upstream` so `git pull upstream main` fetches fixes and `origin`
502
+ // stays free for the repo they deploy from.
503
+ execFileSync('git', ['remote', 'rename', 'origin', 'upstream'], {
504
+ cwd: target,
505
+ stdio: 'ignore',
506
+ });
533
507
  writeFileSync(
534
508
  resolve(target, '.env'),
535
509
  renderEnv({
536
510
  databaseUrl,
537
511
  geminiKey,
538
- adminUser,
539
- adminPassword,
540
512
  apiPort,
541
513
  dashboardPort,
542
514
  }),
@@ -596,13 +568,23 @@ async function main() {
596
568
  '',
597
569
  `Dashboard ${chalk.underline(`http://localhost:${dashboardPort}`)}`,
598
570
  `API ${chalk.underline(`http://localhost:${apiPort}`)}`,
599
- `Login ${adminUser} / ${adminPassword ? 'the password you chose' : 'password printed at first boot'}`,
571
+ `Login ${chalk.bold('admin')} / ${chalk.bold('open-sesame')} ${chalk.dim('← change it under Settings after signing in')}`,
600
572
  '',
601
573
  'Then sign in, create an API key, and: npm install @memory-soda/sdk',
602
574
  ].join('\n'),
603
575
  'Run',
604
576
  );
605
- p.outro(`${chalk.bold(basename(target))} is ready.`);
577
+ p.note(
578
+ [
579
+ 'Updates npm run update (git pull upstream main && npm install)',
580
+ 'Your repo git remote add origin <url> && git push -u origin main',
581
+ ].join('\n'),
582
+ 'Git',
583
+ );
584
+ p.outro(
585
+ `Thanks for trying Memory Soda — ${chalk.bold(basename(target))} is ready.`,
586
+ );
587
+ exit(0);
606
588
  }
607
589
 
608
590
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-memory-soda",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Scaffold a self-hosted Memory Soda instance — API, dashboard, and Postgres",
5
5
  "keywords": [
6
6
  "ai",