realitydb 1.4.3 → 1.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 (2) hide show
  1. package/dist/index.js +479 -227
  2. package/package.json +1 -2
package/dist/index.js CHANGED
@@ -3476,83 +3476,10 @@ var {
3476
3476
  Help
3477
3477
  } = import_index.default;
3478
3478
 
3479
- // ../../packages/config/dist/loadConfig.js
3480
- var import_promises = require("fs/promises");
3481
- var import_node_path = require("path");
3482
-
3483
- // ../../packages/config/dist/defaults.js
3484
- var DEFAULT_CONFIG = {
3485
- seed: {
3486
- defaultRecords: 5e3,
3487
- batchSize: 1e3,
3488
- environment: "dev"
3489
- },
3490
- export: {
3491
- defaultFormat: "json",
3492
- outputDir: "./.databox"
3493
- }
3494
- };
3495
-
3496
- // ../../packages/config/dist/loadConfig.js
3497
- var CONFIG_FILES = ["realitydb.config.json", "seedforge.config.json", "databox.config.json"];
3498
- async function findConfigFile(basePath) {
3499
- for (const name of CONFIG_FILES) {
3500
- const fullPath = (0, import_node_path.resolve)(basePath, name);
3501
- try {
3502
- await (0, import_promises.access)(fullPath);
3503
- return fullPath;
3504
- } catch {
3505
- continue;
3506
- }
3507
- }
3508
- return null;
3509
- }
3510
- async function loadConfig(filePath) {
3511
- let resolvedPath;
3512
- if (filePath) {
3513
- resolvedPath = (0, import_node_path.resolve)(filePath);
3514
- } else {
3515
- const found = await findConfigFile(".");
3516
- if (!found) {
3517
- throw new Error(`[realitydb] Config file not found.
3518
- Create a realitydb.config.json or specify a path with --config.`);
3519
- }
3520
- resolvedPath = found;
3521
- }
3522
- let raw;
3523
- try {
3524
- raw = await (0, import_promises.readFile)(resolvedPath, "utf-8");
3525
- } catch {
3526
- throw new Error(`[realitydb] Config file not found: ${resolvedPath}
3527
- Create a realitydb.config.json or specify a path with --config.`);
3528
- }
3529
- let parsed;
3530
- try {
3531
- parsed = JSON.parse(raw);
3532
- } catch {
3533
- throw new Error(`[realitydb] Invalid JSON in config file: ${resolvedPath}`);
3534
- }
3535
- const config = parsed;
3536
- const database = config["database"];
3537
- if (!database || typeof database["connectionString"] !== "string") {
3538
- throw new Error("[realitydb] Config validation failed: database.connectionString is required.");
3539
- }
3540
- return {
3541
- database: {
3542
- client: "postgres",
3543
- connectionString: database["connectionString"]
3544
- },
3545
- seed: {
3546
- ...DEFAULT_CONFIG.seed,
3547
- ...config["seed"] ?? {}
3548
- },
3549
- template: config["template"],
3550
- export: {
3551
- ...DEFAULT_CONFIG.export,
3552
- ...config["export"] ?? {}
3553
- }
3554
- };
3555
- }
3479
+ // src/commands/init.ts
3480
+ var import_node_readline = require("readline");
3481
+ var import_node_process = require("process");
3482
+ var import_node_fs7 = require("fs");
3556
3483
 
3557
3484
  // ../../packages/core/dist/planning/dependencyGraph.js
3558
3485
  function buildDependencyGraph(foreignKeys) {
@@ -4390,32 +4317,32 @@ function generateDataset(plan) {
4390
4317
  }
4391
4318
 
4392
4319
  // ../../packages/generators/dist/exporters/json.js
4393
- var import_promises2 = require("fs/promises");
4394
- var import_node_path2 = require("path");
4320
+ var import_promises = require("fs/promises");
4321
+ var import_node_path = require("path");
4395
4322
  async function exportToJson(dataset, outputDir) {
4396
- await (0, import_promises2.mkdir)(outputDir, { recursive: true });
4323
+ await (0, import_promises.mkdir)(outputDir, { recursive: true });
4397
4324
  const files = [];
4398
4325
  for (const [tableName, table] of dataset.tables) {
4399
- const filePath = (0, import_node_path2.join)(outputDir, `${tableName}.json`);
4326
+ const filePath = (0, import_node_path.join)(outputDir, `${tableName}.json`);
4400
4327
  const content = JSON.stringify(table.rows, null, 2);
4401
- await (0, import_promises2.writeFile)(filePath, content, "utf-8");
4328
+ await (0, import_promises.writeFile)(filePath, content, "utf-8");
4402
4329
  files.push(filePath);
4403
4330
  }
4404
4331
  return files;
4405
4332
  }
4406
4333
 
4407
4334
  // ../../packages/generators/dist/exporters/csv.js
4408
- var import_promises3 = require("fs/promises");
4409
- var import_node_path3 = require("path");
4335
+ var import_promises2 = require("fs/promises");
4336
+ var import_node_path2 = require("path");
4410
4337
  async function exportToCsv(dataset, outputDir) {
4411
- await (0, import_promises3.mkdir)(outputDir, { recursive: true });
4338
+ await (0, import_promises2.mkdir)(outputDir, { recursive: true });
4412
4339
  const files = [];
4413
4340
  for (const [tableName, table] of dataset.tables) {
4414
- const filePath = (0, import_node_path3.join)(outputDir, `${tableName}.csv`);
4341
+ const filePath = (0, import_node_path2.join)(outputDir, `${tableName}.csv`);
4415
4342
  const header = table.columns.map(escapeCsvField).join(",");
4416
4343
  const rows = table.rows.map((row) => table.columns.map((col) => escapeCsvField(String(row[col] ?? ""))).join(","));
4417
4344
  const content = [header, ...rows].join("\n");
4418
- await (0, import_promises3.writeFile)(filePath, content, "utf-8");
4345
+ await (0, import_promises2.writeFile)(filePath, content, "utf-8");
4419
4346
  files.push(filePath);
4420
4347
  }
4421
4348
  return files;
@@ -4428,10 +4355,10 @@ function escapeCsvField(value) {
4428
4355
  }
4429
4356
 
4430
4357
  // ../../packages/generators/dist/exporters/sql.js
4431
- var import_promises4 = require("fs/promises");
4432
- var import_node_path4 = require("path");
4358
+ var import_promises3 = require("fs/promises");
4359
+ var import_node_path3 = require("path");
4433
4360
  async function exportToSql(dataset, outputDir, tableOrder) {
4434
- await (0, import_promises4.mkdir)(outputDir, { recursive: true });
4361
+ await (0, import_promises3.mkdir)(outputDir, { recursive: true });
4435
4362
  const lines = [];
4436
4363
  lines.push("-- Generated by DataBox");
4437
4364
  lines.push(`-- Seed: ${dataset.seed}`);
@@ -4448,8 +4375,8 @@ async function exportToSql(dataset, outputDir, tableOrder) {
4448
4375
  }
4449
4376
  lines.push("");
4450
4377
  }
4451
- const filePath = (0, import_node_path4.join)(outputDir, "seed.sql");
4452
- await (0, import_promises4.writeFile)(filePath, lines.join("\n"), "utf-8");
4378
+ const filePath = (0, import_node_path3.join)(outputDir, "seed.sql");
4379
+ await (0, import_promises3.writeFile)(filePath, lines.join("\n"), "utf-8");
4453
4380
  return [filePath];
4454
4381
  }
4455
4382
  function escapeSqlValue(value) {
@@ -5731,7 +5658,7 @@ function countRows2(dataset) {
5731
5658
 
5732
5659
  // ../../packages/generators/dist/scenarios/loadScenario.js
5733
5660
  var import_node_fs = require("fs");
5734
- var import_node_path5 = require("path");
5661
+ var import_node_path4 = require("path");
5735
5662
  function scaffoldCustomScenario(name) {
5736
5663
  return {
5737
5664
  name,
@@ -5802,8 +5729,8 @@ function extractTablesFromModifications(modifications) {
5802
5729
  }
5803
5730
 
5804
5731
  // ../../packages/generators/dist/packExporter.js
5805
- var import_promises5 = require("fs/promises");
5806
- var import_node_path6 = require("path");
5732
+ var import_promises4 = require("fs/promises");
5733
+ var import_node_path5 = require("path");
5807
5734
  function exportRealityPack(dataset, plan, schema, options) {
5808
5735
  const name = options?.name ?? plan.config.templateName ?? "realitydb-pack";
5809
5736
  const packSchema = {
@@ -5851,14 +5778,14 @@ function exportRealityPack(dataset, plan, schema, options) {
5851
5778
  }
5852
5779
  async function saveRealityPack(pack, outputPath) {
5853
5780
  const filePath = outputPath.endsWith(".realitydb-pack.json") || outputPath.endsWith(".databox-pack.json") ? outputPath : `${outputPath}/${pack.metadata.name}.realitydb-pack.json`;
5854
- await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(filePath), { recursive: true });
5855
- await (0, import_promises5.writeFile)(filePath, JSON.stringify(pack, null, 2), "utf-8");
5781
+ await (0, import_promises4.mkdir)((0, import_node_path5.dirname)(filePath), { recursive: true });
5782
+ await (0, import_promises4.writeFile)(filePath, JSON.stringify(pack, null, 2), "utf-8");
5856
5783
  return filePath;
5857
5784
  }
5858
5785
  async function loadRealityPack(filePath) {
5859
5786
  let raw;
5860
5787
  try {
5861
- raw = await (0, import_promises5.readFile)(filePath, "utf-8");
5788
+ raw = await (0, import_promises4.readFile)(filePath, "utf-8");
5862
5789
  } catch (err) {
5863
5790
  const message = err instanceof Error ? err.message : String(err);
5864
5791
  throw new Error(`Failed to read Reality Pack file: ${message}`);
@@ -6414,7 +6341,7 @@ function isIntLike(value) {
6414
6341
  }
6415
6342
 
6416
6343
  // ../../packages/generators/dist/writers/parquet.js
6417
- var import_promises6 = require("fs/promises");
6344
+ var import_promises5 = require("fs/promises");
6418
6345
  async function appendParquetBatch(rows, filePath) {
6419
6346
  const { appendFile: appendFile3 } = await import("fs/promises");
6420
6347
  const lines = rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
@@ -6422,14 +6349,14 @@ async function appendParquetBatch(rows, filePath) {
6422
6349
  }
6423
6350
 
6424
6351
  // ../../packages/generators/dist/writers/csv.js
6425
- var import_promises7 = require("fs/promises");
6352
+ var import_promises6 = require("fs/promises");
6426
6353
  async function writeCsvHeader(columns, filePath) {
6427
6354
  const header = columns.map(escapeCsvField2).join(",") + "\n";
6428
- await (0, import_promises7.writeFile)(filePath, header, "utf-8");
6355
+ await (0, import_promises6.writeFile)(filePath, header, "utf-8");
6429
6356
  }
6430
6357
  async function appendCsvBatch(rows, columns, filePath) {
6431
6358
  const lines = rows.map((row) => columns.map((col) => escapeCsvField2(String(row[col] ?? ""))).join(",")).join("\n") + "\n";
6432
- await (0, import_promises7.appendFile)(filePath, lines, "utf-8");
6359
+ await (0, import_promises6.appendFile)(filePath, lines, "utf-8");
6433
6360
  }
6434
6361
  function escapeCsvField2(value) {
6435
6362
  if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
@@ -6439,13 +6366,13 @@ function escapeCsvField2(value) {
6439
6366
  }
6440
6367
 
6441
6368
  // ../../packages/generators/dist/writers/json.js
6442
- var import_promises8 = require("fs/promises");
6369
+ var import_promises7 = require("fs/promises");
6443
6370
  async function writeJsonHeader(filePath) {
6444
- await (0, import_promises8.writeFile)(filePath, "", "utf-8");
6371
+ await (0, import_promises7.writeFile)(filePath, "", "utf-8");
6445
6372
  }
6446
6373
  async function appendJsonBatch(rows, filePath) {
6447
6374
  const lines = rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
6448
- await (0, import_promises8.appendFile)(filePath, lines, "utf-8");
6375
+ await (0, import_promises7.appendFile)(filePath, lines, "utf-8");
6449
6376
  }
6450
6377
 
6451
6378
  // ../../packages/generators/dist/analyze/columnDetector.js
@@ -7309,13 +7236,13 @@ var CourseRegistry = class {
7309
7236
 
7310
7237
  // ../../packages/generators/dist/classroom/progressTracker.js
7311
7238
  var import_node_fs2 = require("fs");
7312
- var import_node_path7 = require("path");
7239
+ var import_node_path6 = require("path");
7313
7240
  var import_node_os = require("os");
7314
7241
  function getProgressDir() {
7315
- return (0, import_node_path7.join)((0, import_node_os.homedir)(), ".realitydb");
7242
+ return (0, import_node_path6.join)((0, import_node_os.homedir)(), ".realitydb");
7316
7243
  }
7317
7244
  function getProgressPath() {
7318
- return (0, import_node_path7.join)(getProgressDir(), "progress.json");
7245
+ return (0, import_node_path6.join)(getProgressDir(), "progress.json");
7319
7246
  }
7320
7247
  function loadProgress() {
7321
7248
  const filePath = getProgressPath();
@@ -10304,7 +10231,7 @@ var VALID_STRATEGY_KINDS = [
10304
10231
 
10305
10232
  // ../../packages/templates/dist/loadTemplate.js
10306
10233
  var import_node_fs3 = require("fs");
10307
- var import_node_path8 = require("path");
10234
+ var import_node_path7 = require("path");
10308
10235
 
10309
10236
  // ../../packages/templates/dist/validateTemplate.js
10310
10237
  function validateTemplateJSON(json) {
@@ -10388,7 +10315,7 @@ function assertValidTemplate(json) {
10388
10315
 
10389
10316
  // ../../packages/templates/dist/loadTemplate.js
10390
10317
  function loadTemplateFromJSON(filePath) {
10391
- const resolvedPath = (0, import_node_path8.resolve)(filePath);
10318
+ const resolvedPath = (0, import_node_path7.resolve)(filePath);
10392
10319
  let raw;
10393
10320
  try {
10394
10321
  raw = (0, import_node_fs3.readFileSync)(resolvedPath, "utf-8");
@@ -10441,11 +10368,11 @@ function convertToDomainTemplate(json) {
10441
10368
 
10442
10369
  // ../../packages/templates/dist/userTemplates.js
10443
10370
  var import_node_os2 = require("os");
10444
- var import_node_path9 = require("path");
10371
+ var import_node_path8 = require("path");
10445
10372
  var import_node_fs4 = require("fs");
10446
10373
  var USER_TEMPLATE_DIR_NAME = ".realitydb/templates";
10447
10374
  function getUserTemplateDir() {
10448
- return (0, import_node_path9.join)((0, import_node_os2.homedir)(), USER_TEMPLATE_DIR_NAME);
10375
+ return (0, import_node_path8.join)((0, import_node_os2.homedir)(), USER_TEMPLATE_DIR_NAME);
10449
10376
  }
10450
10377
  function listUserTemplates() {
10451
10378
  const dir = getUserTemplateDir();
@@ -10456,14 +10383,14 @@ function listUserTemplates() {
10456
10383
  const files = (0, import_node_fs4.readdirSync)(dir);
10457
10384
  return files.filter((f) => f.endsWith(".json")).map((f) => ({
10458
10385
  name: f.replace(/\.json$/, ""),
10459
- filePath: (0, import_node_path9.join)(dir, f)
10386
+ filePath: (0, import_node_path8.join)(dir, f)
10460
10387
  }));
10461
10388
  } catch {
10462
10389
  return [];
10463
10390
  }
10464
10391
  }
10465
10392
  function resolveUserTemplate(name) {
10466
- const filePath = (0, import_node_path9.join)(getUserTemplateDir(), `${name}.json`);
10393
+ const filePath = (0, import_node_path8.join)(getUserTemplateDir(), `${name}.json`);
10467
10394
  if ((0, import_node_fs4.existsSync)(filePath)) {
10468
10395
  return filePath;
10469
10396
  }
@@ -10478,27 +10405,27 @@ var saasLifecycle = {
10478
10405
  {
10479
10406
  name: "trial",
10480
10407
  weight: 0.12,
10481
- columnValues: {}
10408
+ columnValues: { status: "active" }
10482
10409
  },
10483
10410
  {
10484
10411
  name: "active",
10485
10412
  weight: 0.65,
10486
- columnValues: {}
10413
+ columnValues: { status: "active" }
10487
10414
  },
10488
10415
  {
10489
10416
  name: "churned",
10490
10417
  weight: 0.1,
10491
- columnValues: {}
10418
+ columnValues: { status: "inactive" }
10492
10419
  },
10493
10420
  {
10494
10421
  name: "past_due",
10495
10422
  weight: 0.08,
10496
- columnValues: {}
10423
+ columnValues: { status: "active" }
10497
10424
  },
10498
10425
  {
10499
10426
  name: "paused",
10500
10427
  weight: 0.05,
10501
- columnValues: {}
10428
+ columnValues: { status: "inactive" }
10502
10429
  }
10503
10430
  ],
10504
10431
  transitions: [
@@ -10510,7 +10437,7 @@ var saasLifecycle = {
10510
10437
  {
10511
10438
  table: "subscriptions",
10512
10439
  action: "create",
10513
- values: { status: "active", plan: "Professional" }
10440
+ values: { status: "active" }
10514
10441
  },
10515
10442
  {
10516
10443
  table: "payments",
@@ -10613,20 +10540,6 @@ var saasLifecycle = {
10613
10540
  }
10614
10541
  ],
10615
10542
  correlations: [
10616
- {
10617
- description: "Enterprise plan users have 2x more payments (longer tenure)",
10618
- condition: {
10619
- table: "subscriptions",
10620
- column: "plan",
10621
- operator: "eq",
10622
- value: "Enterprise"
10623
- },
10624
- effect: {
10625
- table: "payments",
10626
- column: "amount_cents",
10627
- multiplier: 2
10628
- }
10629
- },
10630
10543
  {
10631
10544
  description: "Churned users always have a failed payment before cancel",
10632
10545
  condition: {
@@ -11731,53 +11644,13 @@ async function seedDatabase(config, options) {
11731
11644
  throw new Error(`Generation plan validation failed:
11732
11645
  ${validation.errors.join("\n")}`);
11733
11646
  }
11734
- let dataset;
11735
11647
  const lifecycleUsed = !!options?.lifecycle;
11648
+ let dataset = timelineConfig ? generateTimelineDataset(plan, timelineConfig) : generateDataset(plan);
11736
11649
  if (options?.lifecycle && options?.template) {
11737
11650
  const lifecycle = resolveLifecycle(options.template);
11738
11651
  if (lifecycle) {
11739
- const random = createSeededRandom(plan.reproducibility.randomSeed);
11740
- const entityCount = effectiveConfig.seed.defaultRecords;
11741
- const simResult = simulateLifecycles(lifecycle, entityCount, random);
11742
- const correlatedResult = applyCorrelations(simResult, lifecycle.correlations, random);
11743
- const schemaColumnLookup = /* @__PURE__ */ new Map();
11744
- for (const table of schema.tables) {
11745
- schemaColumnLookup.set(table.name, new Set(table.columns.map((c) => c.name)));
11746
- }
11747
- const tables = /* @__PURE__ */ new Map();
11748
- let totalRows = 0;
11749
- for (const [tableName, rows] of correlatedResult.tables) {
11750
- const validColumns = schemaColumnLookup.get(tableName);
11751
- const filteredRows = validColumns ? rows.map((row) => {
11752
- const filtered = {};
11753
- for (const [col, val] of Object.entries(row)) {
11754
- if (validColumns.has(col)) {
11755
- filtered[col] = val;
11756
- } else {
11757
- console.warn(`[lifecycle] Skipping column '${col}' on table '${tableName}' \u2014 column does not exist`);
11758
- }
11759
- }
11760
- return filtered;
11761
- }) : rows;
11762
- tables.set(tableName, {
11763
- tableName,
11764
- columns: filteredRows.length > 0 ? Object.keys(filteredRows[0]) : [],
11765
- rows: filteredRows,
11766
- rowCount: filteredRows.length
11767
- });
11768
- totalRows += filteredRows.length;
11769
- }
11770
- dataset = {
11771
- tables,
11772
- generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11773
- seed: plan.reproducibility.randomSeed,
11774
- totalRows
11775
- };
11776
- } else {
11777
- dataset = timelineConfig ? generateTimelineDataset(plan, timelineConfig) : generateDataset(plan);
11652
+ dataset = applyLifecycleOverlay(dataset, lifecycle, plan, schema);
11778
11653
  }
11779
- } else {
11780
- dataset = timelineConfig ? generateTimelineDataset(plan, timelineConfig) : generateDataset(plan);
11781
11654
  }
11782
11655
  let scenariosApplied;
11783
11656
  let scenarioReportData;
@@ -11819,6 +11692,66 @@ ${validation.errors.join("\n")}`);
11819
11692
  await closeConnection(pool);
11820
11693
  }
11821
11694
  }
11695
+ function applyLifecycleOverlay(dataset, lifecycle, plan, schema) {
11696
+ const random = createSeededRandom(plan.reproducibility.randomSeed);
11697
+ const rootTable = dataset.tables.get(lifecycle.rootTable);
11698
+ const entityCount = rootTable?.rowCount ?? plan.tables[0]?.rowCount ?? 0;
11699
+ const simResult = simulateLifecycles(lifecycle, entityCount, random);
11700
+ const correlatedResult = applyCorrelations(simResult, lifecycle.correlations, random);
11701
+ const schemaColumnLookup = /* @__PURE__ */ new Map();
11702
+ for (const table of schema.tables) {
11703
+ schemaColumnLookup.set(table.name, new Set(table.columns.map((c) => c.name)));
11704
+ }
11705
+ const warnedColumns = /* @__PURE__ */ new Set();
11706
+ if (rootTable) {
11707
+ const lifecycleRootRows = correlatedResult.tables.get(lifecycle.rootTable);
11708
+ if (lifecycleRootRows) {
11709
+ const validColumns = schemaColumnLookup.get(lifecycle.rootTable);
11710
+ const count = Math.min(rootTable.rows.length, lifecycleRootRows.length);
11711
+ for (let i = 0; i < count; i++) {
11712
+ for (const [col, val] of Object.entries(lifecycleRootRows[i])) {
11713
+ if (col === "id")
11714
+ continue;
11715
+ if (validColumns && !validColumns.has(col)) {
11716
+ const key = `${lifecycle.rootTable}.${col}`;
11717
+ if (!warnedColumns.has(key)) {
11718
+ console.warn(`[lifecycle] Skipping column '${col}' on table '${lifecycle.rootTable}' \u2014 does not exist in schema`);
11719
+ warnedColumns.add(key);
11720
+ }
11721
+ continue;
11722
+ }
11723
+ rootTable.rows[i][col] = val;
11724
+ }
11725
+ }
11726
+ }
11727
+ }
11728
+ for (const [tableName, lifecycleRows] of correlatedResult.tables) {
11729
+ if (tableName === lifecycle.rootTable)
11730
+ continue;
11731
+ const existingTable = dataset.tables.get(tableName);
11732
+ if (!existingTable || lifecycleRows.length === 0)
11733
+ continue;
11734
+ const validColumns = schemaColumnLookup.get(tableName);
11735
+ const entityIdCol = `${lifecycle.entityName}_id`;
11736
+ const count = Math.min(lifecycleRows.length, existingTable.rows.length);
11737
+ for (let i = 0; i < count; i++) {
11738
+ for (const [col, val] of Object.entries(lifecycleRows[i])) {
11739
+ if (col === "id" || col === entityIdCol)
11740
+ continue;
11741
+ if (validColumns && !validColumns.has(col)) {
11742
+ const key = `${tableName}.${col}`;
11743
+ if (!warnedColumns.has(key)) {
11744
+ console.warn(`[lifecycle] Skipping column '${col}' on table '${tableName}' \u2014 does not exist in schema`);
11745
+ warnedColumns.add(key);
11746
+ }
11747
+ continue;
11748
+ }
11749
+ existingTable.rows[i][col] = val;
11750
+ }
11751
+ }
11752
+ }
11753
+ return dataset;
11754
+ }
11822
11755
  function computeTotalMonths(tc) {
11823
11756
  const start = new Date(tc.startDate);
11824
11757
  const end = new Date(tc.endDate);
@@ -12194,7 +12127,7 @@ async function captureDatabase(config, options) {
12194
12127
  }
12195
12128
 
12196
12129
  // ../../packages/core/dist/sharePipeline.js
12197
- var import_promises9 = require("fs/promises");
12130
+ var import_promises8 = require("fs/promises");
12198
12131
 
12199
12132
  // ../../packages/core/dist/sharing/gistUpload.js
12200
12133
  var import_node_https = __toESM(require("https"), 1);
@@ -12282,11 +12215,11 @@ function formatSize(bytes) {
12282
12215
  }
12283
12216
  async function shareRealityPack(filePath, options) {
12284
12217
  const pack = await loadRealityPack(filePath);
12285
- const fileStat = await (0, import_promises9.stat)(filePath);
12218
+ const fileStat = await (0, import_promises8.stat)(filePath);
12286
12219
  const size = formatSize(fileStat.size);
12287
12220
  const method = options?.method ?? "file";
12288
12221
  if (method === "gist") {
12289
- const content = await (0, import_promises9.readFile)(filePath, "utf-8");
12222
+ const content = await (0, import_promises8.readFile)(filePath, "utf-8");
12290
12223
  const compressed = await compressPack(content);
12291
12224
  const compressedSize = formatSize(compressed.length);
12292
12225
  const filename = `${pack.metadata.name}.realitydb-pack.json`;
@@ -12758,12 +12691,322 @@ function maskConnectionString(connectionString) {
12758
12691
  }
12759
12692
  }
12760
12693
 
12694
+ // src/commands/init.ts
12695
+ var CONFIG_FILE = "realitydb.config.json";
12696
+ var DEFAULT_CONNECTION = "postgres://postgres:postgres@localhost:5432/myapp_dev";
12697
+ function ask(rl, prompt) {
12698
+ return new Promise((resolve12) => {
12699
+ rl.question(prompt, (answer) => {
12700
+ resolve12(answer);
12701
+ });
12702
+ });
12703
+ }
12704
+ async function initCommand() {
12705
+ const rl = (0, import_node_readline.createInterface)({ input: import_node_process.stdin, output: import_node_process.stdout });
12706
+ rl.on("close", () => {
12707
+ if (!wizardComplete) {
12708
+ console.log("");
12709
+ console.log("");
12710
+ console.log("Init cancelled.");
12711
+ console.log("");
12712
+ process.exit(0);
12713
+ }
12714
+ });
12715
+ let wizardComplete = false;
12716
+ try {
12717
+ console.log("");
12718
+ console.log("Welcome to RealityDB");
12719
+ console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
12720
+ console.log("");
12721
+ console.log("Let's connect to your database and fill it with realistic data.");
12722
+ console.log("");
12723
+ if ((0, import_node_fs7.existsSync)(CONFIG_FILE)) {
12724
+ const overwrite = await ask(rl, `${CONFIG_FILE} already exists. Overwrite? (y/N) `);
12725
+ if (overwrite.toLowerCase() !== "y") {
12726
+ wizardComplete = true;
12727
+ console.log("");
12728
+ console.log("Init cancelled. Existing config preserved.");
12729
+ console.log("");
12730
+ return;
12731
+ }
12732
+ console.log("");
12733
+ }
12734
+ let connectionString;
12735
+ let scanResult;
12736
+ let masked;
12737
+ while (true) {
12738
+ console.log("Step 1: Database Connection");
12739
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12740
+ connectionString = await promptWithDefault(
12741
+ rl,
12742
+ "PostgreSQL connection string",
12743
+ DEFAULT_CONNECTION
12744
+ );
12745
+ console.log("");
12746
+ console.log("Step 2: Connecting & Scanning");
12747
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12748
+ masked = maskConnectionString(connectionString);
12749
+ console.log(` Connecting to ${masked}...`);
12750
+ const scanConfig = {
12751
+ database: { client: "postgres", connectionString },
12752
+ seed: { defaultRecords: 50, batchSize: 1e3, environment: "dev" }
12753
+ };
12754
+ try {
12755
+ scanResult = await scanDatabase(scanConfig);
12756
+ break;
12757
+ } catch (err) {
12758
+ const msg = err instanceof Error ? err.message : String(err);
12759
+ console.error("");
12760
+ console.error(` Connection failed: ${msg}`);
12761
+ console.error("");
12762
+ console.error("Hints:");
12763
+ console.error(" - Is PostgreSQL running? (docker ps, pg_isready)");
12764
+ console.error(" - Check host, port, username, password, and database name");
12765
+ console.error(" - Ensure the database exists (createdb myapp_dev)");
12766
+ console.error("");
12767
+ const retry = await ask(rl, "Try a different connection string? (Y/n) ");
12768
+ if (retry.toLowerCase() === "n") {
12769
+ wizardComplete = true;
12770
+ process.exit(1);
12771
+ }
12772
+ console.log("");
12773
+ }
12774
+ }
12775
+ const { schema } = scanResult;
12776
+ console.log(" Connected successfully.");
12777
+ console.log("");
12778
+ if (schema.tables.length === 0) {
12779
+ wizardComplete = true;
12780
+ console.log(" No tables found in the public schema.");
12781
+ console.log("");
12782
+ console.log(" Run your migrations first, then try again:");
12783
+ console.log(" npx prisma migrate dev");
12784
+ console.log(" npx knex migrate:latest");
12785
+ console.log(" rails db:migrate");
12786
+ console.log("");
12787
+ process.exit(1);
12788
+ }
12789
+ console.log("Step 3: Schema");
12790
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12791
+ console.log(` Found ${schema.tables.length} tables, ${schema.foreignKeys.length} foreign keys`);
12792
+ console.log("");
12793
+ console.log(" Tables:");
12794
+ for (const table of schema.tables) {
12795
+ const colCount = table.columns.length;
12796
+ const pkLabel = table.primaryKey ? ` PK: ${table.primaryKey.columnName}` : "";
12797
+ console.log(` ${table.name} (${colCount} cols${pkLabel})`);
12798
+ }
12799
+ console.log("");
12800
+ console.log("Step 4: Template Selection");
12801
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12802
+ const registry = getDefaultRegistry();
12803
+ const allTemplates = registry.list();
12804
+ const detected = detectTemplate(schema.tables.map((t) => t.name), allTemplates);
12805
+ let templateName;
12806
+ if (detected) {
12807
+ console.log(` Auto-detected domain: ${detected.name}`);
12808
+ console.log(` ${detected.description}`);
12809
+ console.log("");
12810
+ const useDetected = await ask(rl, ` Use "${detected.name}" template? (Y/n) `);
12811
+ if (useDetected.toLowerCase() !== "n") {
12812
+ templateName = detected.name;
12813
+ }
12814
+ }
12815
+ if (!templateName) {
12816
+ console.log("");
12817
+ console.log(" Available templates:");
12818
+ for (let i = 0; i < allTemplates.length; i++) {
12819
+ console.log(` ${i + 1}. ${allTemplates[i].name} \u2014 ${allTemplates[i].description}`);
12820
+ }
12821
+ console.log(` ${allTemplates.length + 1}. none \u2014 use schema-only generation`);
12822
+ console.log("");
12823
+ const choice = await ask(rl, ` Choose template (1-${allTemplates.length + 1}): `);
12824
+ const choiceNum = parseInt(choice, 10);
12825
+ if (choiceNum >= 1 && choiceNum <= allTemplates.length) {
12826
+ templateName = allTemplates[choiceNum - 1].name;
12827
+ }
12828
+ }
12829
+ console.log("");
12830
+ console.log("Step 5: Configuration");
12831
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12832
+ const recordsStr = await promptWithDefault(rl, "Records per table", "50");
12833
+ const records = parseInt(recordsStr, 10) || 50;
12834
+ console.log("");
12835
+ console.log("Step 6: Writing Config");
12836
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
12837
+ const config = {
12838
+ database: {
12839
+ client: "postgres",
12840
+ connectionString
12841
+ },
12842
+ seed: {
12843
+ defaultRecords: records,
12844
+ batchSize: 1e3,
12845
+ environment: "dev",
12846
+ randomSeed: 42
12847
+ },
12848
+ ...templateName ? { template: templateName } : {}
12849
+ };
12850
+ (0, import_node_fs7.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
12851
+ console.log(` Created ${CONFIG_FILE}`);
12852
+ console.log("");
12853
+ const runSeed = await ask(rl, "Run initial seed now? (Y/n) ");
12854
+ if (runSeed.toLowerCase() !== "n") {
12855
+ console.log("");
12856
+ console.log("Seeding...");
12857
+ try {
12858
+ const result = await seedDatabase(config, {
12859
+ records,
12860
+ seed: 42,
12861
+ template: templateName
12862
+ });
12863
+ console.log("");
12864
+ for (const tableResult of result.insertResult.tables) {
12865
+ console.log(
12866
+ ` ${tableResult.tableName}: ${tableResult.rowsInserted} rows`
12867
+ );
12868
+ }
12869
+ const totalTime = (result.durationMs / 1e3).toFixed(1);
12870
+ console.log("");
12871
+ console.log(` Seed complete. ${result.totalRows} rows in ${totalTime}s`);
12872
+ } catch (err) {
12873
+ const msg = err instanceof Error ? err.message : String(err);
12874
+ console.error("");
12875
+ console.error(` Seed failed: ${msg}`);
12876
+ console.error(" You can retry later with: realitydb seed");
12877
+ }
12878
+ }
12879
+ wizardComplete = true;
12880
+ console.log("");
12881
+ console.log("RealityDB initialized!");
12882
+ console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
12883
+ console.log(` Config: ./${CONFIG_FILE}`);
12884
+ console.log(` Database: ${masked}`);
12885
+ if (templateName) {
12886
+ console.log(` Template: ${templateName}`);
12887
+ }
12888
+ console.log(` Records: ${records} per table`);
12889
+ console.log("");
12890
+ console.log("Next steps:");
12891
+ console.log(" realitydb scan Inspect your schema");
12892
+ console.log(" realitydb seed Generate data");
12893
+ console.log(" realitydb export Export without writing to DB");
12894
+ console.log(" realitydb analyze Generate a custom template");
12895
+ console.log(" realitydb --help See all commands");
12896
+ console.log("");
12897
+ } finally {
12898
+ rl.close();
12899
+ }
12900
+ }
12901
+ async function promptWithDefault(rl, label, defaultValue) {
12902
+ console.log(` ${label}`);
12903
+ console.log(` Default: ${defaultValue}`);
12904
+ const answer = await ask(rl, " > ");
12905
+ return answer.trim() || defaultValue;
12906
+ }
12907
+ function detectTemplate(tableNames, templates) {
12908
+ const lower = new Set(tableNames.map((t) => t.toLowerCase()));
12909
+ let bestMatch = null;
12910
+ let bestScore = 0;
12911
+ for (const template of templates) {
12912
+ let matches = 0;
12913
+ for (const target of template.targetTables) {
12914
+ if (lower.has(target.toLowerCase())) {
12915
+ matches++;
12916
+ }
12917
+ }
12918
+ if (matches >= 2 && matches > bestScore) {
12919
+ bestScore = matches;
12920
+ bestMatch = template;
12921
+ }
12922
+ }
12923
+ return bestMatch;
12924
+ }
12925
+
12926
+ // ../../packages/config/dist/loadConfig.js
12927
+ var import_promises9 = require("fs/promises");
12928
+ var import_node_path9 = require("path");
12929
+
12930
+ // ../../packages/config/dist/defaults.js
12931
+ var DEFAULT_CONFIG = {
12932
+ seed: {
12933
+ defaultRecords: 5e3,
12934
+ batchSize: 1e3,
12935
+ environment: "dev"
12936
+ },
12937
+ export: {
12938
+ defaultFormat: "json",
12939
+ outputDir: "./.databox"
12940
+ }
12941
+ };
12942
+
12943
+ // ../../packages/config/dist/loadConfig.js
12944
+ var CONFIG_FILES = ["realitydb.config.json", "seedforge.config.json", "databox.config.json"];
12945
+ async function findConfigFile(basePath) {
12946
+ for (const name of CONFIG_FILES) {
12947
+ const fullPath = (0, import_node_path9.resolve)(basePath, name);
12948
+ try {
12949
+ await (0, import_promises9.access)(fullPath);
12950
+ return fullPath;
12951
+ } catch {
12952
+ continue;
12953
+ }
12954
+ }
12955
+ return null;
12956
+ }
12957
+ async function loadConfig(filePath) {
12958
+ let resolvedPath;
12959
+ if (filePath) {
12960
+ resolvedPath = (0, import_node_path9.resolve)(filePath);
12961
+ } else {
12962
+ const found = await findConfigFile(".");
12963
+ if (!found) {
12964
+ throw new Error(`[realitydb] Config file not found.
12965
+ Create a realitydb.config.json or specify a path with --config.`);
12966
+ }
12967
+ resolvedPath = found;
12968
+ }
12969
+ let raw;
12970
+ try {
12971
+ raw = await (0, import_promises9.readFile)(resolvedPath, "utf-8");
12972
+ } catch {
12973
+ throw new Error(`[realitydb] Config file not found: ${resolvedPath}
12974
+ Create a realitydb.config.json or specify a path with --config.`);
12975
+ }
12976
+ let parsed;
12977
+ try {
12978
+ parsed = JSON.parse(raw);
12979
+ } catch {
12980
+ throw new Error(`[realitydb] Invalid JSON in config file: ${resolvedPath}`);
12981
+ }
12982
+ const config = parsed;
12983
+ const database = config["database"];
12984
+ if (!database || typeof database["connectionString"] !== "string") {
12985
+ throw new Error("[realitydb] Config validation failed: database.connectionString is required.");
12986
+ }
12987
+ return {
12988
+ database: {
12989
+ client: "postgres",
12990
+ connectionString: database["connectionString"]
12991
+ },
12992
+ seed: {
12993
+ ...DEFAULT_CONFIG.seed,
12994
+ ...config["seed"] ?? {}
12995
+ },
12996
+ template: config["template"],
12997
+ export: {
12998
+ ...DEFAULT_CONFIG.export,
12999
+ ...config["export"] ?? {}
13000
+ }
13001
+ };
13002
+ }
13003
+
12761
13004
  // src/commands/scan.ts
12762
13005
  var VERSION2 = "0.10.0";
12763
13006
  async function scanCommand(options) {
12764
13007
  const start = performance.now();
12765
13008
  try {
12766
- const config = await loadConfig();
13009
+ const config = await loadConfig(options.configPath);
12767
13010
  const result = await scanDatabase(config);
12768
13011
  const { schema } = result;
12769
13012
  const masked = maskConnectionString(config.database.connectionString);
@@ -12883,7 +13126,7 @@ var VERSION3 = "1.3.1";
12883
13126
  async function seedCommand(options) {
12884
13127
  const start = performance.now();
12885
13128
  try {
12886
- const config = await loadConfig();
13129
+ const config = await loadConfig(options.configPath);
12887
13130
  const records = options.records ? parseInt(options.records, 10) : void 0;
12888
13131
  const seed = options.seed ? parseInt(options.seed, 10) : void 0;
12889
13132
  const rawTemplateName = options.template ?? config.template;
@@ -13093,7 +13336,7 @@ async function resetCommand(options) {
13093
13336
  process.exit(0);
13094
13337
  }
13095
13338
  try {
13096
- const config = await loadConfig();
13339
+ const config = await loadConfig(options.configPath);
13097
13340
  const masked = maskConnectionString(config.database.connectionString);
13098
13341
  if (!options.ci) {
13099
13342
  console.log("");
@@ -13158,7 +13401,7 @@ var VERSION5 = "1.3.1";
13158
13401
  async function exportCommand(options) {
13159
13402
  const start = performance.now();
13160
13403
  try {
13161
- const config = await loadConfig();
13404
+ const config = await loadConfig(options.configPath);
13162
13405
  const format = options.format ?? config.export?.defaultFormat ?? "json";
13163
13406
  const outputDir = options.output ?? config.export?.outputDir ?? "./.realitydb";
13164
13407
  const records = options.records ? parseInt(options.records, 10) : void 0;
@@ -13311,7 +13554,7 @@ async function exportCommand(options) {
13311
13554
  }
13312
13555
 
13313
13556
  // src/commands/templates.ts
13314
- var import_node_fs7 = require("fs");
13557
+ var import_node_fs8 = require("fs");
13315
13558
  var VERSION6 = "0.10.0";
13316
13559
  function templatesCommand() {
13317
13560
  const registry = getDefaultRegistry();
@@ -13338,7 +13581,7 @@ function templatesCommand() {
13338
13581
  }
13339
13582
  function templatesInitCommand() {
13340
13583
  const fileName = "realitydb.template.json";
13341
- if ((0, import_node_fs7.existsSync)(fileName)) {
13584
+ if ((0, import_node_fs8.existsSync)(fileName)) {
13342
13585
  console.error(`[realitydb] ${fileName} already exists in this directory.`);
13343
13586
  process.exit(1);
13344
13587
  }
@@ -13372,7 +13615,7 @@ function templatesInitCommand() {
13372
13615
  }
13373
13616
  }
13374
13617
  };
13375
- (0, import_node_fs7.writeFileSync)(fileName, JSON.stringify(scaffold, null, 2) + "\n");
13618
+ (0, import_node_fs8.writeFileSync)(fileName, JSON.stringify(scaffold, null, 2) + "\n");
13376
13619
  console.log("");
13377
13620
  console.log(`Created ${fileName}`);
13378
13621
  console.log("Edit this file to define your custom template.");
@@ -13383,7 +13626,7 @@ function templatesInitCommand() {
13383
13626
  }
13384
13627
  function templatesValidateCommand(filePath, options) {
13385
13628
  const start = performance.now();
13386
- if (!(0, import_node_fs7.existsSync)(filePath)) {
13629
+ if (!(0, import_node_fs8.existsSync)(filePath)) {
13387
13630
  if (options.ci) {
13388
13631
  console.log(formatCIOutput({
13389
13632
  success: false,
@@ -13400,7 +13643,7 @@ function templatesValidateCommand(filePath, options) {
13400
13643
  }
13401
13644
  let json;
13402
13645
  try {
13403
- const raw = (0, import_node_fs7.readFileSync)(filePath, "utf-8");
13646
+ const raw = (0, import_node_fs8.readFileSync)(filePath, "utf-8");
13404
13647
  json = JSON.parse(raw);
13405
13648
  } catch {
13406
13649
  if (options.ci) {
@@ -13463,7 +13706,7 @@ function templatesValidateCommand(filePath, options) {
13463
13706
  }
13464
13707
 
13465
13708
  // src/commands/scenarios.ts
13466
- var import_node_fs8 = require("fs");
13709
+ var import_node_fs9 = require("fs");
13467
13710
  var import_node_path12 = require("path");
13468
13711
  function scenariosCommand() {
13469
13712
  const registry = getDefaultScenarioRegistry();
@@ -13488,12 +13731,12 @@ function scenariosCreateCommand(name) {
13488
13731
  const sanitized = name.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-");
13489
13732
  const fileName = `${sanitized}.scenario.json`;
13490
13733
  const filePath = (0, import_node_path12.resolve)(fileName);
13491
- if ((0, import_node_fs8.existsSync)(filePath)) {
13734
+ if ((0, import_node_fs9.existsSync)(filePath)) {
13492
13735
  console.error(`[realitydb] File already exists: ${fileName}`);
13493
13736
  process.exit(1);
13494
13737
  }
13495
13738
  const scaffold = scaffoldCustomScenario(sanitized);
13496
- (0, import_node_fs8.writeFileSync)(filePath, JSON.stringify(scaffold, null, 2) + "\n", "utf-8");
13739
+ (0, import_node_fs9.writeFileSync)(filePath, JSON.stringify(scaffold, null, 2) + "\n", "utf-8");
13497
13740
  console.log("");
13498
13741
  console.log(`Created custom scenario: ${fileName}`);
13499
13742
  console.log("");
@@ -13518,7 +13761,7 @@ var import_node_path13 = require("path");
13518
13761
  var import_promises10 = require("fs/promises");
13519
13762
  async function packExportCommand(options) {
13520
13763
  try {
13521
- const config = await loadConfig();
13764
+ const config = await loadConfig(options.configPath);
13522
13765
  const records = options.records ? parseInt(options.records, 10) : void 0;
13523
13766
  const seed = options.seed ? parseInt(options.seed, 10) : void 0;
13524
13767
  const rawTemplateName = options.template ?? config.template;
@@ -13620,7 +13863,7 @@ async function packImportCommand(filePath, options) {
13620
13863
  console.error("Usage: realitydb pack import <file> --confirm");
13621
13864
  process.exit(1);
13622
13865
  }
13623
- const config = await loadConfig();
13866
+ const config = await loadConfig(options.configPath);
13624
13867
  const masked = maskConnectionString(config.database.connectionString);
13625
13868
  const pack = await loadRealityPack(filePath);
13626
13869
  console.log("");
@@ -13689,7 +13932,7 @@ async function captureCommand(options) {
13689
13932
  console.error("Usage: realitydb capture --name <name>");
13690
13933
  process.exit(1);
13691
13934
  }
13692
- const config = await loadConfig();
13935
+ const config = await loadConfig(options.configPath);
13693
13936
  const masked = maskConnectionString(config.database.connectionString);
13694
13937
  const tables = options.tables ? options.tables.split(",").map((t) => t.trim()).filter((t) => t.length > 0) : void 0;
13695
13938
  if (!options.ci) {
@@ -13935,7 +14178,7 @@ async function loadCommand(filePath, options) {
13935
14178
  }
13936
14179
  return;
13937
14180
  }
13938
- const config = await loadConfig();
14181
+ const config = await loadConfig(options.configPath);
13939
14182
  const masked = maskConnectionString(config.database.connectionString);
13940
14183
  if (!options.ci) {
13941
14184
  console.log("");
@@ -14248,13 +14491,13 @@ function getDefaultSchema() {
14248
14491
  }
14249
14492
 
14250
14493
  // src/commands/analyze.ts
14251
- var import_node_fs9 = require("fs");
14494
+ var import_node_fs10 = require("fs");
14252
14495
  var import_node_path16 = require("path");
14253
14496
  var VERSION12 = "1.3.1";
14254
14497
  async function analyzeCommand(options) {
14255
14498
  const start = performance.now();
14256
14499
  try {
14257
- const config = await loadConfig();
14500
+ const config = await loadConfig(options.configPath);
14258
14501
  const sampleSize = options.sampleSize ? parseInt(options.sampleSize, 10) : 1e3;
14259
14502
  const masked = maskConnectionString(config.database.connectionString);
14260
14503
  if (!options.ci) {
@@ -14290,14 +14533,14 @@ async function analyzeCommand(options) {
14290
14533
  }));
14291
14534
  if (result.templateJson && options.output) {
14292
14535
  const filePath = (0, import_node_path16.resolve)(options.output);
14293
- (0, import_node_fs9.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
14536
+ (0, import_node_fs10.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
14294
14537
  }
14295
14538
  return;
14296
14539
  }
14297
14540
  console.log(formatAnalysisReport(result.report));
14298
14541
  if (result.templateJson && options.output) {
14299
14542
  const filePath = (0, import_node_path16.resolve)(options.output);
14300
- (0, import_node_fs9.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
14543
+ (0, import_node_fs10.writeFileSync)(filePath, result.templateJson + "\n", "utf-8");
14301
14544
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
14302
14545
  console.log(`Template generated: ${filePath}`);
14303
14546
  console.log("");
@@ -14342,13 +14585,13 @@ async function analyzeCommand(options) {
14342
14585
  }
14343
14586
 
14344
14587
  // src/commands/mask.ts
14345
- var import_node_fs10 = require("fs");
14588
+ var import_node_fs11 = require("fs");
14346
14589
  var import_node_path17 = require("path");
14347
14590
  var VERSION13 = "1.3.1";
14348
14591
  async function maskCommand(options) {
14349
14592
  const start = performance.now();
14350
14593
  try {
14351
- const config = await loadConfig();
14594
+ const config = await loadConfig(options.configPath);
14352
14595
  const mode = options.mode ?? "gdpr";
14353
14596
  const seed = options.seed ? parseInt(options.seed, 10) : void 0;
14354
14597
  const dryRun = options.dryRun ?? false;
@@ -14420,7 +14663,7 @@ async function maskCommand(options) {
14420
14663
  const durationMs = Math.round(performance.now() - start);
14421
14664
  if (options.auditLog) {
14422
14665
  const auditPath = (0, import_node_path17.resolve)(options.auditLog);
14423
- (0, import_node_fs10.writeFileSync)(auditPath, serializeAuditLog(result.auditLog) + "\n", "utf-8");
14666
+ (0, import_node_fs11.writeFileSync)(auditPath, serializeAuditLog(result.auditLog) + "\n", "utf-8");
14424
14667
  }
14425
14668
  if (options.ci) {
14426
14669
  console.log(formatCIOutput({
@@ -14495,7 +14738,7 @@ async function maskCommand(options) {
14495
14738
  }
14496
14739
 
14497
14740
  // src/commands/classroom.ts
14498
- var import_node_fs11 = require("fs");
14741
+ var import_node_fs12 = require("fs");
14499
14742
  var import_node_path18 = require("path");
14500
14743
  var VERSION14 = "1.3.1";
14501
14744
  async function classroomListCommand(options) {
@@ -14557,7 +14800,7 @@ async function classroomListCommand(options) {
14557
14800
  async function classroomStartCommand(courseName, options) {
14558
14801
  const start = performance.now();
14559
14802
  try {
14560
- const config = await loadConfig();
14803
+ const config = await loadConfig(options.configPath);
14561
14804
  const masked = maskConnectionString(config.database.connectionString);
14562
14805
  if (!options.ci) {
14563
14806
  console.log("");
@@ -14760,7 +15003,7 @@ async function classroomCreateCommand(name, options) {
14760
15003
  const content = classroomCreate(name);
14761
15004
  const filename = `${name}.course.json`;
14762
15005
  const filePath = (0, import_node_path18.resolve)(filename);
14763
- (0, import_node_fs11.writeFileSync)(filePath, content + "\n", "utf-8");
15006
+ (0, import_node_fs12.writeFileSync)(filePath, content + "\n", "utf-8");
14764
15007
  const durationMs = Math.round(performance.now() - start);
14765
15008
  if (options.ci) {
14766
15009
  console.log(formatCIOutput({
@@ -15010,33 +15253,36 @@ async function simulateWebhooksCommand(options) {
15010
15253
  }
15011
15254
 
15012
15255
  // src/cli.ts
15013
- var VERSION16 = "1.3.1";
15256
+ var VERSION16 = "1.5.0";
15014
15257
  function run(argv) {
15015
15258
  const program2 = new Command();
15016
15259
  program2.name("realitydb").description("RealityDB \u2014 Developer Reality Platform").version(VERSION16).option("--config <path>", "Path to config file").option("--ci", "CI mode: JSON output, no prompts, proper exit codes", false).option("--verbose", "Enable verbose output", false);
15260
+ program2.command("init").description("Interactive setup wizard \u2014 connect, scan, and seed in one step").action(async () => {
15261
+ await initCommand();
15262
+ });
15017
15263
  program2.command("scan").description("Scan database schema").action(async () => {
15018
15264
  const opts = program2.opts();
15019
- await scanCommand({ ci: opts.ci });
15265
+ await scanCommand({ ci: opts.ci, configPath: opts.config });
15020
15266
  });
15021
15267
  program2.command("analyze").description("Analyze database schema and suggest column strategies").option("--output <file>", "Generate a template JSON file from analysis").option("--sample-size <count>", "Number of rows to sample per table", "1000").action(async (cmdOpts) => {
15022
15268
  const opts = program2.opts();
15023
- await analyzeCommand({ ...cmdOpts, ci: opts.ci });
15269
+ await analyzeCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15024
15270
  });
15025
15271
  program2.command("seed").description("Seed database with generated data").option("--records <count>", "Number of records per table").option("--template <name|path>", "Template name or path to custom .json file").option("--seed <number>", "Random seed for reproducibility").option("--timeline <duration>", 'Timeline duration (e.g., "12-months", "1-year")').option("--scenario <names>", "Scenarios to apply (comma-separated)").option("--scenario-intensity <level>", "Scenario intensity (low|medium|high)", "medium").option("--scenario-schedule <schedule>", 'Timeline-scheduled scenarios (e.g., "fraud-spike:month-6,churn-spike:month-9")').option("--lifecycle", "Enable lifecycle simulation for causally-connected data").action(async (cmdOpts) => {
15026
15272
  const opts = program2.opts();
15027
- await seedCommand({ ...cmdOpts, ci: opts.ci });
15273
+ await seedCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15028
15274
  });
15029
15275
  program2.command("reset").description("Reset seeded data").option("--confirm", "Confirm destructive operation").action(async (cmdOpts) => {
15030
15276
  const opts = program2.opts();
15031
- await resetCommand({ ...cmdOpts, ci: opts.ci });
15277
+ await resetCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15032
15278
  });
15033
15279
  program2.command("export").description("Export generated data").option("--format <format>", "Output format (json|csv|sql)", "json").option("--output <dir>", "Output directory", "./.realitydb").option("--records <count>", "Number of records per table").option("--seed <number>", "Random seed for reproducibility").option("--template <name>", "Template to use").option("--timeline <duration>", 'Timeline duration (e.g., "12-months", "1-year")').option("--scenario <names>", "Scenarios to apply (comma-separated)").option("--scenario-intensity <level>", "Scenario intensity (low|medium|high)", "medium").option("--scenario-schedule <schedule>", 'Timeline-scheduled scenarios (e.g., "fraud-spike:month-6,churn-spike:month-9")').action(async (cmdOpts) => {
15034
15280
  const opts = program2.opts();
15035
- await exportCommand({ ...cmdOpts, ci: opts.ci });
15281
+ await exportCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15036
15282
  });
15037
15283
  program2.command("generate").description("Generate large-scale datasets for data science (no database required)").option("--records <count>", "Number of records to generate", "1000").option("--schema <file>", "Schema definition file (.sql or .json)").option("--format <format>", "Output format (json|csv|parquet)", "json").option("--output <dir>", "Output directory", "./.realitydb/generated").option("--seed <number>", "Random seed for reproducibility").option("--table <name>", "Generate only a specific table").option("--correlations", "Enable cross-column correlations from schema").action(async (cmdOpts) => {
15038
15284
  const opts = program2.opts();
15039
- await generateCommand({ ...cmdOpts, ci: opts.ci });
15285
+ await generateCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15040
15286
  });
15041
15287
  const templates = program2.command("templates").description("Template management");
15042
15288
  templates.command("list", { isDefault: true }).description("List available domain templates").action(templatesCommand);
@@ -15052,61 +15298,67 @@ function run(argv) {
15052
15298
  });
15053
15299
  program2.command("mask").description("Detect and mask PII in your database").option("--mode <mode>", "Compliance mode (hipaa|gdpr|strict)", "gdpr").option("--seed <number>", "Random seed for deterministic masking").option("--dry-run", "Preview PII detection without modifying data").option("--output <dir>", "Export masked data to files instead of writing to DB").option("--output-format <format>", "Output format (json|csv|sql)", "json").option("--audit-log <file>", "Write audit log to file").option("--confirm", "Confirm writing masked data back to database").action(async (cmdOpts) => {
15054
15300
  const opts = program2.opts();
15055
- await maskCommand({ ...cmdOpts, ci: opts.ci });
15301
+ await maskCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15056
15302
  });
15057
15303
  const classroom = program2.command("classroom").description("Education and classroom mode");
15058
15304
  classroom.command("list", { isDefault: true }).description("List available courses").action(async () => {
15059
15305
  const opts = program2.opts();
15060
- await classroomListCommand({ ci: opts.ci });
15306
+ await classroomListCommand({ ci: opts.ci, configPath: opts.config });
15061
15307
  });
15062
15308
  classroom.command("start <course>").description("Load a course into your database").action(async (course) => {
15063
15309
  const opts = program2.opts();
15064
- await classroomStartCommand(course, { ci: opts.ci });
15310
+ await classroomStartCommand(course, { ci: opts.ci, configPath: opts.config });
15065
15311
  });
15066
15312
  classroom.command("status [course]").description("Show progress for all courses or a specific course").action(async (course) => {
15067
15313
  const opts = program2.opts();
15068
- await classroomStatusCommand(course, { ci: opts.ci });
15314
+ await classroomStatusCommand(course, { ci: opts.ci, configPath: opts.config });
15069
15315
  });
15070
15316
  classroom.command("complete <course> <exercise>").description("Mark an exercise as completed").action(async (course, exercise) => {
15071
15317
  const opts = program2.opts();
15072
- await classroomCompleteCommand(course, exercise, { ci: opts.ci });
15318
+ await classroomCompleteCommand(course, exercise, { ci: opts.ci, configPath: opts.config });
15073
15319
  });
15074
15320
  classroom.command("reset <course>").description("Reset progress for a course").action(async (course) => {
15075
15321
  const opts = program2.opts();
15076
- await classroomResetCommand(course, { ci: opts.ci });
15322
+ await classroomResetCommand(course, { ci: opts.ci, configPath: opts.config });
15077
15323
  });
15078
15324
  classroom.command("create <name>").description("Scaffold a custom course JSON file").action(async (name) => {
15079
15325
  const opts = program2.opts();
15080
- await classroomCreateCommand(name, { ci: opts.ci });
15326
+ await classroomCreateCommand(name, { ci: opts.ci, configPath: opts.config });
15081
15327
  });
15082
15328
  const simulate = program2.command("simulate").description("System behavior simulation");
15083
15329
  simulate.command("run", { isDefault: true }).description("Run a simulation with a profile").option("--profile <name>", "Simulation profile (saas-startup|ecommerce-peak|api-service)", "saas-startup").option("--duration <duration>", "Override profile duration (e.g., 1-hour, 1-day, 1-week)").option("--events <count>", "Number of events to generate", "1000").option("--seed <number>", "Random seed for reproducibility").option("--output <file>", "Output file path").option("--format <format>", "Output format (json|ndjson)", "json").action(async (cmdOpts) => {
15084
15330
  const opts = program2.opts();
15085
- await simulateRunCommand({ ...cmdOpts, ci: opts.ci });
15331
+ await simulateRunCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15086
15332
  });
15087
15333
  simulate.command("profiles").description("List available simulation profiles").action(async () => {
15088
15334
  const opts = program2.opts();
15089
- await simulateProfilesCommand({ ci: opts.ci });
15335
+ await simulateProfilesCommand({ ci: opts.ci, configPath: opts.config });
15090
15336
  });
15091
15337
  simulate.command("webhooks").description("Generate webhook events from a specific source").option("--source <source>", "Webhook source (stripe|github)", "stripe").option("--events <count>", "Number of events to generate", "100").option("--seed <number>", "Random seed for reproducibility").option("--output <file>", "Output file path").option("--format <format>", "Output format (json|ndjson)", "json").action(async (cmdOpts) => {
15092
15338
  const opts = program2.opts();
15093
- await simulateWebhooksCommand({ ...cmdOpts, ci: opts.ci });
15339
+ await simulateWebhooksCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15094
15340
  });
15095
15341
  program2.command("capture").description("Capture live database state into a Reality Pack").requiredOption("--name <name>", "Name for the captured pack").option("--description <desc>", "Pack description").option("--tables <tables>", "Comma-separated list of tables to capture").option("--output <dir>", "Output directory", ".").action(async (cmdOpts) => {
15096
15342
  const opts = program2.opts();
15097
- await captureCommand({ ...cmdOpts, ci: opts.ci });
15343
+ await captureCommand({ ...cmdOpts, ci: opts.ci, configPath: opts.config });
15098
15344
  });
15099
15345
  program2.command("share <file>").description("Share a Reality Pack file").option("--gist", "Upload to GitHub Gist").option("--description <desc>", "Gist description").action(async (filePath, cmdOpts) => {
15100
15346
  const opts = program2.opts();
15101
- await shareCommand(filePath, { ...cmdOpts, ci: opts.ci });
15347
+ await shareCommand(filePath, { ...cmdOpts, ci: opts.ci, configPath: opts.config });
15102
15348
  });
15103
15349
  program2.command("load <file>").description("Load a Reality Pack into the database (file path or URL)").option("--confirm", "Confirm import operation").option("--show-ddl", "Show schema DDL without importing").action(async (filePath, cmdOpts) => {
15104
15350
  const opts = program2.opts();
15105
- await loadCommand(filePath, { ...cmdOpts, ci: opts.ci });
15351
+ await loadCommand(filePath, { ...cmdOpts, ci: opts.ci, configPath: opts.config });
15106
15352
  });
15107
15353
  const pack = program2.command("pack").description("Reality Pack operations");
15108
- pack.command("export").description("Export environment as Reality Pack").option("--name <name>", "Pack name").option("--description <desc>", "Pack description").option("--output <dir>", "Output directory", ".").option("--records <count>", "Number of records per table").option("--seed <number>", "Random seed for reproducibility").option("--template <name>", "Template to use").option("--timeline <duration>", 'Timeline duration (e.g., "12-months", "1-year")').option("--scenario <names>", "Scenarios to apply (comma-separated)").option("--scenario-intensity <level>", "Scenario intensity (low|medium|high)", "medium").option("--scenario-schedule <schedule>", 'Timeline-scheduled scenarios (e.g., "fraud-spike:month-6,churn-spike:month-9")').action(packExportCommand);
15109
- pack.command("import <file>").description("Import Reality Pack into database").option("--confirm", "Confirm import operation").action(packImportCommand);
15354
+ pack.command("export").description("Export environment as Reality Pack").option("--name <name>", "Pack name").option("--description <desc>", "Pack description").option("--output <dir>", "Output directory", ".").option("--records <count>", "Number of records per table").option("--seed <number>", "Random seed for reproducibility").option("--template <name>", "Template to use").option("--timeline <duration>", 'Timeline duration (e.g., "12-months", "1-year")').option("--scenario <names>", "Scenarios to apply (comma-separated)").option("--scenario-intensity <level>", "Scenario intensity (low|medium|high)", "medium").option("--scenario-schedule <schedule>", 'Timeline-scheduled scenarios (e.g., "fraud-spike:month-6,churn-spike:month-9")').action(async (cmdOpts) => {
15355
+ const opts = program2.opts();
15356
+ await packExportCommand({ ...cmdOpts, configPath: opts.config });
15357
+ });
15358
+ pack.command("import <file>").description("Import Reality Pack into database").option("--confirm", "Confirm import operation").action(async (filePath, cmdOpts) => {
15359
+ const opts = program2.opts();
15360
+ await packImportCommand(filePath, { ...cmdOpts, configPath: opts.config });
15361
+ });
15110
15362
  const packs = program2.command("packs").description("Browse available Reality Packs");
15111
15363
  packs.command("list", { isDefault: true }).description("List available demo packs").action(() => {
15112
15364
  const opts = program2.opts();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "realitydb",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Developer Reality Platform - realistic database environments from your schema",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -59,4 +59,3 @@
59
59
  "pg": "^8.20.0"
60
60
  }
61
61
  }
62
-