spindb 0.35.4 → 0.36.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/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  **One CLI for all your local databases.**
9
9
 
10
- SpinDB is a universal database management tool that combines a package manager, a unified API, and native client tooling for 18 different database engines—all from a single command-line interface. No Docker, no VMs, no platform-specific installers. Just databases, running natively on your machine.
10
+ SpinDB is a universal database management tool that combines a package manager, a unified API, and native client tooling for 19 different database engines—all from a single command-line interface. No Docker, no VMs, no platform-specific installers. Just databases, running natively on your machine.
11
11
 
12
12
  ```bash
13
13
  npm install -g spindb
@@ -28,7 +28,7 @@ spindb create cache --engine redis
28
28
 
29
29
  ## Supported Engines & Platforms
30
30
 
31
- SpinDB supports **18 database engines** across **5 platform architectures**—all with a consistent API.
31
+ SpinDB supports **19 database engines** across **5 platform architectures**—all with a consistent API.
32
32
 
33
33
  | Engine | Type | macOS ARM | macOS Intel | Linux x64 | Linux ARM | Windows |
34
34
  |--------|------|:---------:|:-----------:|:---------:|:---------:|:-------:|
@@ -50,8 +50,9 @@ SpinDB supports **18 database engines** across **5 platform architectures**—al
50
50
  | ⏱️ **QuestDB** | Time-Series | ✅ | ✅ | ✅ | ✅ | ✅ |
51
51
  | 🤖 **TypeDB** | Knowledge Graph | ✅ | ✅ | ✅ | ✅ | ✅ |
52
52
  | 📈 **InfluxDB** | Time-Series | ✅ | ✅ | ✅ | ✅ | ✅ |
53
+ | 🔮 **Weaviate** | Vector Database | ✅ | ✅ | ✅ | ✅ | ✅ |
53
54
 
54
- **89 combinations. One CLI. Zero configuration.**
55
+ **95 combinations. One CLI. Zero configuration.**
55
56
 
56
57
  > ClickHouse is available on Windows via WSL. FerretDB v1 is natively supported on Windows (uses plain PostgreSQL backend); v2 requires macOS/Linux.
57
58
 
@@ -117,6 +118,16 @@ spindb connect tsdata # Interactive SQL console
117
118
 
118
119
  > InfluxDB supports two file formats: `.lp` (line protocol) for writing data, `.sql` for queries.
119
120
 
121
+ ### Weaviate
122
+
123
+ ```bash
124
+ spindb create vectors --engine weaviate --start
125
+ spindb query vectors "GET /v1/schema" # Query via REST API
126
+ spindb connect vectors # Open web dashboard
127
+ ```
128
+
129
+ > Weaviate is an AI-native vector database. REST API on default port 8080, gRPC on port+1. Uses classes/collections.
130
+
120
131
  ### Enhanced Shells & Visual Tools
121
132
 
122
133
  ```bash
@@ -129,7 +140,7 @@ spindb connect mydb --ui # Built-in Web UI (DuckDB)
129
140
  ### Any Engine
130
141
 
131
142
  ```bash
132
- spindb create mydb --engine [postgresql|mysql|mariadb|mongodb|ferretdb|redis|valkey|clickhouse|sqlite|duckdb|qdrant|meilisearch|couchdb|cockroachdb|surrealdb|questdb|typedb|influxdb]
143
+ spindb create mydb --engine [postgresql|mysql|mariadb|mongodb|ferretdb|redis|valkey|clickhouse|sqlite|duckdb|qdrant|meilisearch|couchdb|cockroachdb|surrealdb|questdb|typedb|influxdb|weaviate]
133
144
  spindb start mydb
134
145
  spindb connect mydb
135
146
  spindb backup mydb
@@ -171,7 +182,7 @@ SpinDB runs databases as **native processes** with **isolated data directories**
171
182
 
172
183
  | Feature | SpinDB | DBngin | Postgres.app | Laragon |
173
184
  |---------|--------|--------|--------------|---------|
174
- | **Engines supported** | 18 | 3 (PG/MySQL/Redis) | 1 (PostgreSQL) | 4 (PG/MySQL/MariaDB/MongoDB) |
185
+ | **Engines supported** | 19 | 3 (PG/MySQL/Redis) | 1 (PostgreSQL) | 4 (PG/MySQL/MariaDB/MongoDB) |
175
186
  | CLI-first | ✅ | ❌ GUI-only | ❌ GUI-only | ⚠️ Limited CLI |
176
187
  | Multi-version support | ✅ | ✅ | ✅ | ✅ |
177
188
  | Built-in backup/restore | ✅ | ✅ | ❌ | ⚠️ Manual |
@@ -187,7 +198,7 @@ SpinDB runs databases as **native processes** with **isolated data directories**
187
198
 
188
199
  | Feature | SpinDB | Docker Desktop | Podman | OrbStack |
189
200
  |---------|--------|----------------|--------|----------|
190
- | **Engines supported** | 18 unified | Any (manual setup) | Any (manual setup) | Any (manual setup) |
201
+ | **Engines supported** | 19 unified | Any (manual setup) | Any (manual setup) | Any (manual setup) |
191
202
  | Daemon required | ❌ | ✅ | ❌ (rootless) | ✅ |
192
203
  | Resource overhead | Native | VM + containers | VM + containers | VM + containers |
193
204
  | Built-in backup/restore | ✅ | ❌ Manual | ❌ Manual | ❌ Manual |
@@ -203,7 +214,7 @@ SpinDB runs databases as **native processes** with **isolated data directories**
203
214
 
204
215
  | Feature | SpinDB | Homebrew | apt/winget | asdf-vm |
205
216
  |---------|--------|----------|------------|---------|
206
- | **Engines supported** | 18 unified | Many (separate formulas) | Many (separate packages) | Many (plugins) |
217
+ | **Engines supported** | 19 unified | Many (separate formulas) | Many (separate packages) | Many (plugins) |
207
218
  | Multi-version side-by-side | ✅ | ⚠️ Complex | ❌ | ✅ |
208
219
  | Isolated data directories | ✅ | ❌ System-wide | ❌ System-wide | ❌ |
209
220
  | Built-in backup/restore | ✅ | ❌ | ❌ | ❌ |
@@ -273,7 +284,7 @@ See [DEPLOY.md](DEPLOY.md) for comprehensive deployment documentation.
273
284
  - **Local only** - Databases bind to `127.0.0.1`. Remote connection support planned for v1.1.
274
285
  - **ClickHouse Windows** - Not supported (hostdb doesn't build for Windows).
275
286
  - **FerretDB Windows** - v1 supported natively (plain PostgreSQL backend). v2 not supported (postgresql-documentdb has startup issues); use WSL for v2.
276
- - **Qdrant, Meilisearch, CouchDB** - Use REST API instead of CLI shell. Access via HTTP at the configured port.
287
+ - **Qdrant, Meilisearch, CouchDB, Weaviate** - Use REST API instead of CLI shell. Access via HTTP at the configured port.
277
288
 
278
289
  ---
279
290
 
@@ -394,7 +405,7 @@ See [ENGINE_CHECKLIST.md](ENGINE_CHECKLIST.md) for adding new database engines.
394
405
 
395
406
  SpinDB is powered by:
396
407
 
397
- - **[hostdb](https://github.com/robertjbass/hostdb)** - Pre-compiled database binaries for 18 engines across all major platforms. Makes Docker-free multi-version database support possible.
408
+ - **[hostdb](https://github.com/robertjbass/hostdb)** - Pre-compiled database binaries for 19 engines across all major platforms. Makes Docker-free multi-version database support possible.
398
409
 
399
410
  ---
400
411
 
@@ -30,26 +30,7 @@ import { promptConfirm } from '../ui/prompts'
30
30
  import { createSpinner } from '../ui/spinner'
31
31
  import { uiError, uiWarning, uiInfo, uiSuccess, formatBytes } from '../ui/theme'
32
32
  import { getEngineIcon } from '../constants'
33
- import {
34
- getInstalledEngines,
35
- getInstalledPostgresEngines,
36
- type InstalledPostgresEngine,
37
- type InstalledMysqlEngine,
38
- type InstalledSqliteEngine,
39
- type InstalledDuckDBEngine,
40
- type InstalledMongodbEngine,
41
- type InstalledFerretDBEngine,
42
- type InstalledRedisEngine,
43
- type InstalledValkeyEngine,
44
- type InstalledQdrantEngine,
45
- type InstalledMeilisearchEngine,
46
- type InstalledCouchDBEngine,
47
- type InstalledCockroachDBEngine,
48
- type InstalledSurrealDBEngine,
49
- type InstalledQuestDBEngine,
50
- type InstalledTypeDBEngine,
51
- type InstalledInfluxDBEngine,
52
- } from '../helpers'
33
+ import { getInstalledEngines, getInstalledPostgresEngines } from '../helpers'
53
34
  import { Engine, Platform } from '../../types'
54
35
  import {
55
36
  loadEnginesJson,
@@ -73,6 +54,7 @@ import { surrealdbBinaryManager } from '../../engines/surrealdb/binary-manager'
73
54
  import { questdbBinaryManager } from '../../engines/questdb/binary-manager'
74
55
  import { typedbBinaryManager } from '../../engines/typedb/binary-manager'
75
56
  import { influxdbBinaryManager } from '../../engines/influxdb/binary-manager'
57
+ import { weaviateBinaryManager } from '../../engines/weaviate/binary-manager'
76
58
  import {
77
59
  DEFAULT_DOCUMENTDB_VERSION,
78
60
  DEFAULT_V1_POSTGRESQL_VERSION,
@@ -434,59 +416,11 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
434
416
  return
435
417
  }
436
418
 
437
- // Separate engines by type
438
- const pgEngines = engines.filter(
439
- (e): e is InstalledPostgresEngine => e.engine === 'postgresql',
440
- )
441
- const mysqlEngines = engines.filter(
442
- (e): e is InstalledMysqlEngine => e.engine === 'mysql',
443
- )
444
- const sqliteEngine = engines.find(
445
- (e): e is InstalledSqliteEngine => e.engine === 'sqlite',
446
- )
447
- const duckdbEngines = engines.filter(
448
- (e): e is InstalledDuckDBEngine => e.engine === 'duckdb',
449
- )
450
- const mongodbEngines = engines.filter(
451
- (e): e is InstalledMongodbEngine => e.engine === 'mongodb',
452
- )
453
- const ferretdbEngines = engines.filter(
454
- (e): e is InstalledFerretDBEngine => e.engine === 'ferretdb',
455
- )
456
- const redisEngines = engines.filter(
457
- (e): e is InstalledRedisEngine => e.engine === 'redis',
458
- )
459
- const valkeyEngines = engines.filter(
460
- (e): e is InstalledValkeyEngine => e.engine === 'valkey',
461
- )
462
- const qdrantEngines = engines.filter(
463
- (e): e is InstalledQdrantEngine => e.engine === 'qdrant',
464
- )
465
- const meilisearchEngines = engines.filter(
466
- (e): e is InstalledMeilisearchEngine => e.engine === 'meilisearch',
467
- )
468
- const couchdbEngines = engines.filter(
469
- (e): e is InstalledCouchDBEngine => e.engine === 'couchdb',
470
- )
471
- const cockroachdbEngines = engines.filter(
472
- (e): e is InstalledCockroachDBEngine => e.engine === 'cockroachdb',
473
- )
474
- const surrealdbEngines = engines.filter(
475
- (e): e is InstalledSurrealDBEngine => e.engine === 'surrealdb',
476
- )
477
- const questdbEngines = engines.filter(
478
- (e): e is InstalledQuestDBEngine => e.engine === 'questdb',
479
- )
480
- const typedbEngines = engines.filter(
481
- (e): e is InstalledTypeDBEngine => e.engine === 'typedb',
482
- )
483
- const influxdbEngines = engines.filter(
484
- (e): e is InstalledInfluxDBEngine => e.engine === 'influxdb',
419
+ // Sort engines alphabetically by engine name
420
+ const sortedEngines = [...engines].sort((a, b) =>
421
+ a.engine.localeCompare(b.engine),
485
422
  )
486
423
 
487
- // Calculate total size for PostgreSQL
488
- const totalPgSize = pgEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
489
-
490
424
  // Table header
491
425
  // Icon is 5 chars, longest engine name is 11 (meilisearch/cockroachdb), so 18 total for ENGINE column
492
426
  console.log()
@@ -499,8 +433,8 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
499
433
  )
500
434
  console.log(chalk.gray(' ' + '─'.repeat(59)))
501
435
 
502
- // PostgreSQL rows
503
- for (const engine of pgEngines) {
436
+ // Display all engines in alphabetical order
437
+ for (const engine of sortedEngines) {
504
438
  const platformInfo = `${engine.platform}-${engine.arch}`
505
439
 
506
440
  console.log(
@@ -513,375 +447,48 @@ async function listEngines(options: { json?: boolean }): Promise<void> {
513
447
  )
514
448
  }
515
449
 
516
- // MySQL rows
517
- for (const mysqlEngine of mysqlEngines) {
518
- const platformInfo = `${mysqlEngine.platform}-${mysqlEngine.arch}`
519
-
520
- console.log(
521
- chalk.gray(' ') +
522
- getEngineIcon('mysql') +
523
- chalk.cyan('mysql'.padEnd(13)) +
524
- chalk.yellow(mysqlEngine.version.padEnd(12)) +
525
- chalk.gray(platformInfo.padEnd(18)) +
526
- chalk.white(formatBytes(mysqlEngine.sizeBytes)),
527
- )
528
- }
529
-
530
- // SQLite row
531
- if (sqliteEngine) {
532
- console.log(
533
- chalk.gray(' ') +
534
- getEngineIcon('sqlite') +
535
- chalk.cyan('sqlite'.padEnd(13)) +
536
- chalk.yellow(sqliteEngine.version.padEnd(12)) +
537
- chalk.gray('system'.padEnd(18)) +
538
- chalk.gray('(system-installed)'),
539
- )
540
- }
541
-
542
- // DuckDB rows
543
- for (const engine of duckdbEngines) {
544
- const platformInfo = `${engine.platform}-${engine.arch}`
545
-
546
- console.log(
547
- chalk.gray(' ') +
548
- getEngineIcon('duckdb') +
549
- chalk.cyan('duckdb'.padEnd(13)) +
550
- chalk.yellow(engine.version.padEnd(12)) +
551
- chalk.gray(platformInfo.padEnd(18)) +
552
- chalk.white(formatBytes(engine.sizeBytes)),
553
- )
554
- }
555
-
556
- // MongoDB rows
557
- for (const engine of mongodbEngines) {
558
- const platformInfo = `${engine.platform}-${engine.arch}`
559
-
560
- console.log(
561
- chalk.gray(' ') +
562
- getEngineIcon('mongodb') +
563
- chalk.cyan('mongodb'.padEnd(13)) +
564
- chalk.yellow(engine.version.padEnd(12)) +
565
- chalk.gray(platformInfo.padEnd(18)) +
566
- chalk.white(formatBytes(engine.sizeBytes)),
567
- )
568
- }
569
-
570
- // FerretDB rows
571
- for (const engine of ferretdbEngines) {
572
- const platformInfo = `${engine.platform}-${engine.arch}`
573
-
574
- console.log(
575
- chalk.gray(' ') +
576
- getEngineIcon('ferretdb') +
577
- chalk.cyan('ferretdb'.padEnd(13)) +
578
- chalk.yellow(engine.version.padEnd(12)) +
579
- chalk.gray(platformInfo.padEnd(18)) +
580
- chalk.white(formatBytes(engine.sizeBytes)),
581
- )
582
- }
583
-
584
- // Redis rows
585
- for (const engine of redisEngines) {
586
- const platformInfo = `${engine.platform}-${engine.arch}`
587
-
588
- console.log(
589
- chalk.gray(' ') +
590
- getEngineIcon('redis') +
591
- chalk.cyan('redis'.padEnd(13)) +
592
- chalk.yellow(engine.version.padEnd(12)) +
593
- chalk.gray(platformInfo.padEnd(18)) +
594
- chalk.white(formatBytes(engine.sizeBytes)),
595
- )
596
- }
597
-
598
- // Valkey rows
599
- for (const engine of valkeyEngines) {
600
- const platformInfo = `${engine.platform}-${engine.arch}`
601
-
602
- console.log(
603
- chalk.gray(' ') +
604
- getEngineIcon('valkey') +
605
- chalk.cyan('valkey'.padEnd(13)) +
606
- chalk.yellow(engine.version.padEnd(12)) +
607
- chalk.gray(platformInfo.padEnd(18)) +
608
- chalk.white(formatBytes(engine.sizeBytes)),
609
- )
610
- }
611
-
612
- // Qdrant rows
613
- for (const engine of qdrantEngines) {
614
- const platformInfo = `${engine.platform}-${engine.arch}`
615
-
616
- console.log(
617
- chalk.gray(' ') +
618
- getEngineIcon('qdrant') +
619
- chalk.cyan('qdrant'.padEnd(13)) +
620
- chalk.yellow(engine.version.padEnd(12)) +
621
- chalk.gray(platformInfo.padEnd(18)) +
622
- chalk.white(formatBytes(engine.sizeBytes)),
623
- )
624
- }
625
-
626
- // Meilisearch rows
627
- for (const engine of meilisearchEngines) {
628
- const platformInfo = `${engine.platform}-${engine.arch}`
629
-
630
- console.log(
631
- chalk.gray(' ') +
632
- getEngineIcon('meilisearch') +
633
- chalk.cyan('meilisearch'.padEnd(13)) +
634
- chalk.yellow(engine.version.padEnd(12)) +
635
- chalk.gray(platformInfo.padEnd(18)) +
636
- chalk.white(formatBytes(engine.sizeBytes)),
637
- )
638
- }
639
-
640
- // CouchDB rows
641
- for (const engine of couchdbEngines) {
642
- const platformInfo = `${engine.platform}-${engine.arch}`
643
-
644
- console.log(
645
- chalk.gray(' ') +
646
- getEngineIcon('couchdb') +
647
- chalk.cyan('couchdb'.padEnd(13)) +
648
- chalk.yellow(engine.version.padEnd(12)) +
649
- chalk.gray(platformInfo.padEnd(18)) +
650
- chalk.white(formatBytes(engine.sizeBytes)),
651
- )
652
- }
653
-
654
- // CockroachDB rows
655
- for (const engine of cockroachdbEngines) {
656
- const platformInfo = `${engine.platform}-${engine.arch}`
657
-
658
- console.log(
659
- chalk.gray(' ') +
660
- getEngineIcon('cockroachdb') +
661
- chalk.cyan('cockroachdb'.padEnd(13)) +
662
- chalk.yellow(engine.version.padEnd(12)) +
663
- chalk.gray(platformInfo.padEnd(18)) +
664
- chalk.white(formatBytes(engine.sizeBytes)),
665
- )
666
- }
667
-
668
- // SurrealDB rows
669
- for (const engine of surrealdbEngines) {
670
- const platformInfo = `${engine.platform}-${engine.arch}`
671
-
672
- console.log(
673
- chalk.gray(' ') +
674
- getEngineIcon('surrealdb') +
675
- chalk.cyan('surrealdb'.padEnd(13)) +
676
- chalk.yellow(engine.version.padEnd(12)) +
677
- chalk.gray(platformInfo.padEnd(18)) +
678
- chalk.white(formatBytes(engine.sizeBytes)),
679
- )
680
- }
681
-
682
- // QuestDB rows
683
- for (const engine of questdbEngines) {
684
- const platformInfo = `${engine.platform}-${engine.arch}`
685
-
686
- console.log(
687
- chalk.gray(' ') +
688
- getEngineIcon('questdb') +
689
- chalk.cyan('questdb'.padEnd(13)) +
690
- chalk.yellow(engine.version.padEnd(12)) +
691
- chalk.gray(platformInfo.padEnd(18)) +
692
- chalk.white(formatBytes(engine.sizeBytes)),
693
- )
694
- }
450
+ console.log(chalk.gray(' ' + '─'.repeat(59)))
695
451
 
696
- // TypeDB rows
697
- for (const engine of typedbEngines) {
698
- const platformInfo = `${engine.platform}-${engine.arch}`
452
+ // Summary - group by engine name (already sorted)
453
+ console.log()
699
454
 
700
- console.log(
701
- chalk.gray(' ') +
702
- getEngineIcon('typedb') +
703
- chalk.cyan('typedb'.padEnd(13)) +
704
- chalk.yellow(engine.version.padEnd(12)) +
705
- chalk.gray(platformInfo.padEnd(18)) +
706
- chalk.white(formatBytes(engine.sizeBytes)),
707
- )
455
+ // Engine display name map for summary
456
+ const ENGINE_DISPLAY_NAMES: Record<string, string> = {
457
+ clickhouse: 'ClickHouse',
458
+ cockroachdb: 'CockroachDB',
459
+ couchdb: 'CouchDB',
460
+ duckdb: 'DuckDB',
461
+ ferretdb: 'FerretDB',
462
+ influxdb: 'InfluxDB',
463
+ mariadb: 'MariaDB',
464
+ meilisearch: 'Meilisearch',
465
+ mongodb: 'MongoDB',
466
+ mysql: 'MySQL',
467
+ postgresql: 'PostgreSQL',
468
+ qdrant: 'Qdrant',
469
+ questdb: 'QuestDB',
470
+ redis: 'Redis',
471
+ sqlite: 'SQLite',
472
+ surrealdb: 'SurrealDB',
473
+ typedb: 'TypeDB',
474
+ valkey: 'Valkey',
475
+ weaviate: 'Weaviate',
708
476
  }
709
477
 
710
- // InfluxDB rows
711
- for (const engine of influxdbEngines) {
712
- const platformInfo = `${engine.platform}-${engine.arch}`
713
-
714
- console.log(
715
- chalk.gray(' ') +
716
- getEngineIcon('influxdb') +
717
- chalk.cyan('influxdb'.padEnd(13)) +
718
- chalk.yellow(engine.version.padEnd(12)) +
719
- chalk.gray(platformInfo.padEnd(18)) +
720
- chalk.white(formatBytes(engine.sizeBytes)),
721
- )
478
+ // Group engines by name for summary
479
+ const engineGroups = new Map<string, typeof sortedEngines>()
480
+ for (const engine of sortedEngines) {
481
+ const group = engineGroups.get(engine.engine) || []
482
+ group.push(engine)
483
+ engineGroups.set(engine.engine, group)
722
484
  }
723
485
 
724
- console.log(chalk.gray(' ' + '─'.repeat(59)))
725
-
726
- // Summary
727
- console.log()
728
- if (pgEngines.length > 0) {
729
- console.log(
730
- chalk.gray(
731
- ` PostgreSQL: ${pgEngines.length} version(s), ${formatBytes(totalPgSize)}`,
732
- ),
733
- )
734
- }
735
- if (mysqlEngines.length > 0) {
736
- const totalMysqlSize = mysqlEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
737
- console.log(
738
- chalk.gray(
739
- ` MySQL: ${mysqlEngines.length} version(s), ${formatBytes(totalMysqlSize)}`,
740
- ),
741
- )
742
- }
743
- if (sqliteEngine) {
744
- console.log(
745
- chalk.gray(` SQLite: system-installed at ${sqliteEngine.path}`),
746
- )
747
- }
748
- if (duckdbEngines.length > 0) {
749
- const totalDuckdbSize = duckdbEngines.reduce(
750
- (acc, e) => acc + e.sizeBytes,
751
- 0,
752
- )
753
- console.log(
754
- chalk.gray(
755
- ` DuckDB: ${duckdbEngines.length} version(s), ${formatBytes(totalDuckdbSize)}`,
756
- ),
757
- )
758
- }
759
- if (mongodbEngines.length > 0) {
760
- const totalMongodbSize = mongodbEngines.reduce(
761
- (acc, e) => acc + e.sizeBytes,
762
- 0,
763
- )
764
- console.log(
765
- chalk.gray(
766
- ` MongoDB: ${mongodbEngines.length} version(s), ${formatBytes(totalMongodbSize)}`,
767
- ),
768
- )
769
- }
770
- if (ferretdbEngines.length > 0) {
771
- const totalFerretdbSize = ferretdbEngines.reduce(
772
- (acc, e) => acc + e.sizeBytes,
773
- 0,
774
- )
775
- console.log(
776
- chalk.gray(
777
- ` FerretDB: ${ferretdbEngines.length} version(s), ${formatBytes(totalFerretdbSize)}`,
778
- ),
779
- )
780
- }
781
- if (redisEngines.length > 0) {
782
- const totalRedisSize = redisEngines.reduce((acc, e) => acc + e.sizeBytes, 0)
783
- console.log(
784
- chalk.gray(
785
- ` Redis: ${redisEngines.length} version(s), ${formatBytes(totalRedisSize)}`,
786
- ),
787
- )
788
- }
789
- if (valkeyEngines.length > 0) {
790
- const totalValkeySize = valkeyEngines.reduce(
791
- (acc, e) => acc + e.sizeBytes,
792
- 0,
793
- )
794
- console.log(
795
- chalk.gray(
796
- ` Valkey: ${valkeyEngines.length} version(s), ${formatBytes(totalValkeySize)}`,
797
- ),
798
- )
799
- }
800
- if (qdrantEngines.length > 0) {
801
- const totalQdrantSize = qdrantEngines.reduce(
802
- (acc, e) => acc + e.sizeBytes,
803
- 0,
804
- )
805
- console.log(
806
- chalk.gray(
807
- ` Qdrant: ${qdrantEngines.length} version(s), ${formatBytes(totalQdrantSize)}`,
808
- ),
809
- )
810
- }
811
- if (meilisearchEngines.length > 0) {
812
- const totalMeilisearchSize = meilisearchEngines.reduce(
813
- (acc, e) => acc + e.sizeBytes,
814
- 0,
815
- )
486
+ for (const [engineName, group] of engineGroups) {
487
+ const displayName = ENGINE_DISPLAY_NAMES[engineName] || engineName
488
+ const totalSize = group.reduce((acc, e) => acc + e.sizeBytes, 0)
816
489
  console.log(
817
490
  chalk.gray(
818
- ` Meilisearch: ${meilisearchEngines.length} version(s), ${formatBytes(totalMeilisearchSize)}`,
819
- ),
820
- )
821
- }
822
- if (couchdbEngines.length > 0) {
823
- const totalCouchDBSize = couchdbEngines.reduce(
824
- (acc, e) => acc + e.sizeBytes,
825
- 0,
826
- )
827
- console.log(
828
- chalk.gray(
829
- ` CouchDB: ${couchdbEngines.length} version(s), ${formatBytes(totalCouchDBSize)}`,
830
- ),
831
- )
832
- }
833
- if (cockroachdbEngines.length > 0) {
834
- const totalCockroachDBSize = cockroachdbEngines.reduce(
835
- (acc, e) => acc + e.sizeBytes,
836
- 0,
837
- )
838
- console.log(
839
- chalk.gray(
840
- ` CockroachDB: ${cockroachdbEngines.length} version(s), ${formatBytes(totalCockroachDBSize)}`,
841
- ),
842
- )
843
- }
844
- if (surrealdbEngines.length > 0) {
845
- const totalSurrealDBSize = surrealdbEngines.reduce(
846
- (acc, e) => acc + e.sizeBytes,
847
- 0,
848
- )
849
- console.log(
850
- chalk.gray(
851
- ` SurrealDB: ${surrealdbEngines.length} version(s), ${formatBytes(totalSurrealDBSize)}`,
852
- ),
853
- )
854
- }
855
- if (questdbEngines.length > 0) {
856
- const totalQuestDBSize = questdbEngines.reduce(
857
- (acc, e) => acc + e.sizeBytes,
858
- 0,
859
- )
860
- console.log(
861
- chalk.gray(
862
- ` QuestDB: ${questdbEngines.length} version(s), ${formatBytes(totalQuestDBSize)}`,
863
- ),
864
- )
865
- }
866
- if (typedbEngines.length > 0) {
867
- const totalTypeDBSize = typedbEngines.reduce(
868
- (acc, e) => acc + e.sizeBytes,
869
- 0,
870
- )
871
- console.log(
872
- chalk.gray(
873
- ` TypeDB: ${typedbEngines.length} version(s), ${formatBytes(totalTypeDBSize)}`,
874
- ),
875
- )
876
- }
877
- if (influxdbEngines.length > 0) {
878
- const totalInfluxDBSize = influxdbEngines.reduce(
879
- (acc, e) => acc + e.sizeBytes,
880
- 0,
881
- )
882
- console.log(
883
- chalk.gray(
884
- ` InfluxDB: ${influxdbEngines.length} version(s), ${formatBytes(totalInfluxDBSize)}`,
491
+ ` ${displayName}: ${group.length} version(s), ${formatBytes(totalSize)}`,
885
492
  ),
886
493
  )
887
494
  }
@@ -2121,9 +1728,56 @@ enginesCommand
2121
1728
  return
2122
1729
  }
2123
1730
 
1731
+ if (['weaviate', 'wv'].includes(normalizedEngine)) {
1732
+ if (!version) {
1733
+ console.error(uiError('Weaviate requires a version (e.g., 1)'))
1734
+ process.exit(1)
1735
+ }
1736
+
1737
+ const engine = getEngine(Engine.Weaviate)
1738
+
1739
+ const spinner = createSpinner(
1740
+ `Checking Weaviate ${version} binaries...`,
1741
+ )
1742
+ spinner.start()
1743
+
1744
+ let wasCached = false
1745
+ await engine.ensureBinaries(version, ({ stage, message }) => {
1746
+ if (stage === 'cached') {
1747
+ wasCached = true
1748
+ spinner.text = `Weaviate ${version} binaries ready (cached)`
1749
+ } else {
1750
+ spinner.text = message
1751
+ }
1752
+ })
1753
+
1754
+ if (wasCached) {
1755
+ spinner.succeed(`Weaviate ${version} binaries already installed`)
1756
+ } else {
1757
+ spinner.succeed(`Weaviate ${version} binaries downloaded`)
1758
+ }
1759
+
1760
+ // Show the path for reference
1761
+ const { platform: weaviatePlatform, arch: weaviateArch } =
1762
+ platformService.getPlatformInfo()
1763
+ const weaviateFullVersion =
1764
+ weaviateBinaryManager.getFullVersion(version)
1765
+ const binPath = paths.getBinaryPath({
1766
+ engine: 'weaviate',
1767
+ version: weaviateFullVersion,
1768
+ platform: weaviatePlatform,
1769
+ arch: weaviateArch,
1770
+ })
1771
+ console.log(chalk.gray(` Location: ${binPath}`))
1772
+
1773
+ // Skip client tools check for Weaviate - it's a REST API server
1774
+ // with no CLI client tools (uses HTTP protocols instead)
1775
+ return
1776
+ }
1777
+
2124
1778
  console.error(
2125
1779
  uiError(
2126
- `Unknown engine "${engineName}". Supported: postgresql, mysql, mariadb, sqlite, duckdb, mongodb, ferretdb, redis, valkey, clickhouse, qdrant, meilisearch, couchdb, cockroachdb, surrealdb, questdb, typedb, influxdb`,
1780
+ `Unknown engine "${engineName}". Supported: postgresql, mysql, mariadb, sqlite, duckdb, mongodb, ferretdb, redis, valkey, clickhouse, qdrant, meilisearch, couchdb, cockroachdb, surrealdb, questdb, typedb, influxdb, weaviate`,
2127
1781
  ),
2128
1782
  )
2129
1783
  process.exit(1)
@@ -223,6 +223,11 @@ function validateConnectionString(
223
223
  return 'Connection string must start with influxdb://, http://, or https://'
224
224
  }
225
225
  break
226
+ case Engine.Weaviate:
227
+ if (!input.startsWith('http://') && !input.startsWith('https://')) {
228
+ return 'Connection string must start with http:// or https://'
229
+ }
230
+ break
226
231
  case Engine.SQLite:
227
232
  case Engine.DuckDB:
228
233
  return 'File-based engines do not support remote connection strings'