@reporting-bi/cli 0.0.15 → 0.0.17

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 +189 -110
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9803,9 +9803,9 @@ function saveCredentials(data) {
9803
9803
  function findLocalConfig(startDir) {
9804
9804
  let dir = path.resolve(startDir || process.cwd());
9805
9805
  while (true) {
9806
- const manifestPath = path.join(dir, ".rpbi", "manifest.json");
9806
+ const configPath = path.join(dir, ".rpbi", "config.json");
9807
9807
  try {
9808
- const data = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
9808
+ const data = JSON.parse(fs.readFileSync(configPath, "utf-8"));
9809
9809
  if (data.domain) return { domain: data.domain, accounting: data.accounting };
9810
9810
  } catch {
9811
9811
  }
@@ -10194,14 +10194,21 @@ async function logout(domain2) {
10194
10194
  // src/commands/status.ts
10195
10195
  function status() {
10196
10196
  const creds = loadCredentials();
10197
+ const local = findLocalConfig();
10197
10198
  const domains = Object.keys(creds.connections);
10199
+ if (local) {
10200
+ console.log(`Local config (.rpbi/config.json):`);
10201
+ console.log(` domain: ${local.domain}`);
10202
+ console.log(` accounting: ${local.accounting ?? "not set"}`);
10203
+ console.log();
10204
+ }
10198
10205
  if (domains.length === 0) {
10199
10206
  console.log("Not logged in.");
10200
10207
  return;
10201
10208
  }
10202
10209
  for (const domain2 of domains) {
10203
10210
  const tokens = creds.connections[domain2];
10204
- const isActive = creds.active === domain2;
10211
+ const isActive = local ? local.domain === domain2 : creds.active === domain2;
10205
10212
  const now = Math.floor(Date.now() / 1e3);
10206
10213
  const expiresIn = tokens.expires_at - now;
10207
10214
  let expiry;
@@ -10372,41 +10379,124 @@ var fs3 = __toESM(require("node:fs"));
10372
10379
  var path2 = __toESM(require("node:path"));
10373
10380
  var crypto = __toESM(require("node:crypto"));
10374
10381
  var RPBI_DIR = ".rpbi";
10375
- var MANIFEST_FILE = "manifest.json";
10382
+ var CONFIG_FILE = "config.json";
10383
+ var INDEX_FILE = "index.json";
10376
10384
  function computeHash(content2) {
10377
10385
  return crypto.createHash("sha256").update(content2, "utf-8").digest("hex");
10378
10386
  }
10379
- function getManifestPath(dir) {
10380
- return path2.join(dir, RPBI_DIR, MANIFEST_FILE);
10387
+ function getConfigPath(dir) {
10388
+ return path2.join(dir, RPBI_DIR, CONFIG_FILE);
10381
10389
  }
10382
- function readManifest(dir) {
10383
- const filePath = getManifestPath(dir);
10390
+ function getIndexPath(dir) {
10391
+ return path2.join(dir, RPBI_DIR, INDEX_FILE);
10392
+ }
10393
+ function readConfig(dir) {
10384
10394
  try {
10385
- const data = fs3.readFileSync(filePath, "utf-8");
10395
+ const data = fs3.readFileSync(getConfigPath(dir), "utf-8");
10386
10396
  return JSON.parse(data);
10387
10397
  } catch {
10388
10398
  return null;
10389
10399
  }
10390
10400
  }
10391
- function writeManifest(dir, manifest) {
10401
+ function writeConfig(dir, config2) {
10392
10402
  const rpbiDir = path2.join(dir, RPBI_DIR);
10393
10403
  fs3.mkdirSync(rpbiDir, { recursive: true });
10394
10404
  fs3.writeFileSync(
10395
- path2.join(rpbiDir, MANIFEST_FILE),
10396
- JSON.stringify(manifest, null, 2)
10405
+ path2.join(rpbiDir, CONFIG_FILE),
10406
+ JSON.stringify(config2, null, 2)
10407
+ );
10408
+ }
10409
+ function readIndex(dir) {
10410
+ try {
10411
+ const data = fs3.readFileSync(getIndexPath(dir), "utf-8");
10412
+ return JSON.parse(data);
10413
+ } catch {
10414
+ return [];
10415
+ }
10416
+ }
10417
+ function writeIndex(dir, index) {
10418
+ const rpbiDir = path2.join(dir, RPBI_DIR);
10419
+ fs3.mkdirSync(rpbiDir, { recursive: true });
10420
+ fs3.writeFileSync(
10421
+ path2.join(rpbiDir, INDEX_FILE),
10422
+ JSON.stringify(index, null, 2)
10397
10423
  );
10398
10424
  }
10399
10425
  function findEtlRoot(startDir) {
10400
10426
  let dir = path2.resolve(startDir);
10401
10427
  while (true) {
10402
- if (fs3.existsSync(getManifestPath(dir))) return dir;
10428
+ if (fs3.existsSync(getConfigPath(dir))) return dir;
10403
10429
  const parent = path2.dirname(dir);
10404
10430
  if (parent === dir) return null;
10405
10431
  dir = parent;
10406
10432
  }
10407
10433
  }
10408
10434
 
10435
+ // src/yaml.ts
10436
+ function toYaml(data, indent = 0) {
10437
+ if (data === null || data === void 0) return "null";
10438
+ if (typeof data === "boolean") return data ? "true" : "false";
10439
+ if (typeof data === "number") return String(data);
10440
+ if (typeof data === "string") {
10441
+ if (data.includes("\n")) {
10442
+ const prefix = " ".repeat(indent);
10443
+ const lines = data.split("\n").map((l) => prefix + " " + l).join("\n");
10444
+ return "|\n" + lines;
10445
+ }
10446
+ if (data === "" || /[:{}\[\],&*?|>!'"%@`#]/.test(data) || /^\s|\s$/.test(data)) {
10447
+ return JSON.stringify(data);
10448
+ }
10449
+ return data;
10450
+ }
10451
+ if (Array.isArray(data)) {
10452
+ if (data.length === 0) return "[]";
10453
+ const prefix = " ".repeat(indent);
10454
+ return data.map((item) => {
10455
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
10456
+ const entries = Object.entries(item);
10457
+ if (entries.length === 0) return `${prefix}- {}`;
10458
+ const [firstKey, firstVal] = entries[0];
10459
+ const firstLine = `${prefix}- ${firstKey}: ${toYaml(firstVal, indent + 2)}`;
10460
+ const rest = entries.slice(1).map(
10461
+ ([k, v]) => `${prefix} ${k}: ${toYaml(v, indent + 2)}`
10462
+ );
10463
+ return [firstLine, ...rest].join("\n");
10464
+ }
10465
+ return `${prefix}- ${toYaml(item, indent + 2)}`;
10466
+ }).join("\n");
10467
+ }
10468
+ if (typeof data === "object") {
10469
+ const entries = Object.entries(data);
10470
+ if (entries.length === 0) return "{}";
10471
+ const prefix = " ".repeat(indent);
10472
+ return entries.map(
10473
+ ([k, v]) => `${prefix}${k}: ${toYaml(v, indent)}`
10474
+ ).join("\n");
10475
+ }
10476
+ return String(data);
10477
+ }
10478
+
10409
10479
  // src/commands/etl-sync.ts
10480
+ var TYPE_DIR_NAMES = {
10481
+ "IA": "threads_import",
10482
+ "IM": "threads_import_manual",
10483
+ "O": "threads_export",
10484
+ "A": "agent_parameters",
10485
+ "AC": "agent_config",
10486
+ "EC": "excel_config",
10487
+ "D": "threads_delete",
10488
+ "L": "lists",
10489
+ "S": "scripts"
10490
+ };
10491
+ var DIR_NAME_TYPES = Object.fromEntries(
10492
+ Object.entries(TYPE_DIR_NAMES).map(([k, v]) => [v, k])
10493
+ );
10494
+ function typeToDirName(type) {
10495
+ return TYPE_DIR_NAMES[type] || "unknown";
10496
+ }
10497
+ function dirNameToType(dirName) {
10498
+ return DIR_NAME_TYPES[dirName] || null;
10499
+ }
10410
10500
  var PARAMETER_TYPES = ["IA", "IM", "O", "D"];
10411
10501
  var PARAMETER_EXCLUDE_FIELDS = ["accounting", "id_thread", "idz", "validate_flag", "date_created"];
10412
10502
  var THREAD_EXCLUDE_FIELDS = ["command_txt", "command_preview", "accounting", "id_thread", "type", "idz", "validate_flag", "date_created"];
@@ -10459,15 +10549,15 @@ function getFilePath(description, extension = ".sql") {
10459
10549
  }
10460
10550
  function threadToRelPath(thread) {
10461
10551
  const segments = getFilePath(thread.description || "");
10462
- return [thread.type, ...segments].join("/");
10552
+ return [typeToDirName(thread.type), ...segments].join("/");
10463
10553
  }
10464
10554
  function threadToParamPath(thread) {
10465
10555
  const segments = getFilePath(thread.description || "", ".yaml");
10466
- return [".parameters", thread.type, ...segments].join("/");
10556
+ return [".rpbi", "parameters", typeToDirName(thread.type), ...segments].join("/");
10467
10557
  }
10468
10558
  function threadToMetaPath(thread) {
10469
10559
  const segments = getFilePath(thread.description || "", ".yaml");
10470
- return [".threads", thread.type, ...segments].join("/");
10560
+ return [".rpbi", "threads", typeToDirName(thread.type), ...segments].join("/");
10471
10561
  }
10472
10562
  function writeFileSync4(filePath, content2) {
10473
10563
  fs4.mkdirSync(path3.dirname(filePath), { recursive: true });
@@ -10482,48 +10572,6 @@ function stripFields(obj, excludeFields) {
10482
10572
  }
10483
10573
  return result;
10484
10574
  }
10485
- function toYaml(data, indent = 0) {
10486
- if (data === null || data === void 0) return "null";
10487
- if (typeof data === "boolean") return data ? "true" : "false";
10488
- if (typeof data === "number") return String(data);
10489
- if (typeof data === "string") {
10490
- if (data.includes("\n")) {
10491
- const prefix = " ".repeat(indent);
10492
- const lines = data.split("\n").map((l) => prefix + " " + l).join("\n");
10493
- return "|\n" + lines;
10494
- }
10495
- if (data === "" || /[:{}\[\],&*?|>!'"%@`#]/.test(data) || /^\s|\s$/.test(data)) {
10496
- return JSON.stringify(data);
10497
- }
10498
- return data;
10499
- }
10500
- if (Array.isArray(data)) {
10501
- if (data.length === 0) return "[]";
10502
- const prefix = " ".repeat(indent);
10503
- return data.map((item) => {
10504
- if (typeof item === "object" && item !== null && !Array.isArray(item)) {
10505
- const entries = Object.entries(item);
10506
- if (entries.length === 0) return `${prefix}- {}`;
10507
- const [firstKey, firstVal] = entries[0];
10508
- const firstLine = `${prefix}- ${firstKey}: ${toYaml(firstVal, indent + 2)}`;
10509
- const rest = entries.slice(1).map(
10510
- ([k, v]) => `${prefix} ${k}: ${toYaml(v, indent + 2)}`
10511
- );
10512
- return [firstLine, ...rest].join("\n");
10513
- }
10514
- return `${prefix}- ${toYaml(item, indent + 2)}`;
10515
- }).join("\n");
10516
- }
10517
- if (typeof data === "object") {
10518
- const entries = Object.entries(data);
10519
- if (entries.length === 0) return "{}";
10520
- const prefix = " ".repeat(indent);
10521
- return entries.map(
10522
- ([k, v]) => `${prefix}${k}: ${toYaml(v, indent)}`
10523
- ).join("\n");
10524
- }
10525
- return String(data);
10526
- }
10527
10575
  async function pull(flags) {
10528
10576
  const dir = path3.resolve(flags.dir || ".");
10529
10577
  const conn = getActiveConnection();
@@ -10539,12 +10587,7 @@ async function pull(flags) {
10539
10587
  order: [["type", "asc"], ["description", "asc"]]
10540
10588
  }) || [];
10541
10589
  console.log(`Found ${threads.length} threads`);
10542
- const manifest = {
10543
- domain: conn.domain,
10544
- accounting: conn.tokens.accounting,
10545
- pulledAt: (/* @__PURE__ */ new Date()).toISOString(),
10546
- threads: {}
10547
- };
10590
+ const index = [];
10548
10591
  let pulled = 0;
10549
10592
  for (const thread of threads) {
10550
10593
  if (!thread.id_thread || !thread.type || !thread.description) continue;
@@ -10557,11 +10600,12 @@ async function pull(flags) {
10557
10600
  { parseResponse: false }
10558
10601
  ) || "";
10559
10602
  writeFileSync4(absPath, content2);
10560
- manifest.threads[relPath] = {
10603
+ index.push({
10604
+ path: relPath,
10561
10605
  id_thread: thread.id_thread,
10562
10606
  hash: computeHash(content2),
10563
10607
  type: thread.type
10564
- };
10608
+ });
10565
10609
  pulled++;
10566
10610
  if (pulled % 50 === 0) console.log(` ${pulled}/${threads.length} threads...`);
10567
10611
  } catch (err) {
@@ -10601,24 +10645,30 @@ async function pull(flags) {
10601
10645
  if (!flags["no-context"]) {
10602
10646
  await pullContext(dir, etlService, defService);
10603
10647
  }
10604
- writeManifest(dir, manifest);
10648
+ writeConfig(dir, {
10649
+ domain: conn.domain,
10650
+ accounting: conn.tokens.accounting,
10651
+ pulledAt: (/* @__PURE__ */ new Date()).toISOString()
10652
+ });
10653
+ writeIndex(dir, index);
10605
10654
  console.log(`Done. Pulled ${pulled} threads to ${dir}`);
10606
10655
  }
10607
10656
  async function push(flags, files) {
10608
10657
  const startDir = flags.dir || ".";
10609
10658
  const root = findEtlRoot(startDir);
10610
10659
  if (!root) {
10611
- console.error('No .rpbi/manifest.json found. Run "rpbi etl pull" first.');
10660
+ console.error('No .rpbi/config.json found. Run "rpbi etl pull" first.');
10612
10661
  process.exit(1);
10613
10662
  }
10614
- const manifest = readManifest(root);
10663
+ const index = readIndex(root);
10664
+ const indexMap = new Map(index.map((e) => [e.path, e]));
10615
10665
  const etlService = await createService("etl");
10616
10666
  const force = flags.force === "true";
10617
10667
  let filesToPush;
10618
10668
  if (files.length > 0) {
10619
10669
  filesToPush = files.map((f) => path3.relative(root, path3.resolve(f)));
10620
10670
  } else {
10621
- filesToPush = detectModifiedFiles(root, manifest);
10671
+ filesToPush = detectModifiedFiles(root, index);
10622
10672
  }
10623
10673
  if (filesToPush.length === 0) {
10624
10674
  console.log("Nothing to push.");
@@ -10632,7 +10682,7 @@ async function push(flags, files) {
10632
10682
  continue;
10633
10683
  }
10634
10684
  const localContent = fs4.readFileSync(absPath, "utf-8");
10635
- const entry = manifest.threads[relPath];
10685
+ const entry = indexMap.get(relPath);
10636
10686
  if (entry) {
10637
10687
  if (!force) {
10638
10688
  try {
@@ -10650,11 +10700,16 @@ async function push(flags, files) {
10650
10700
  }
10651
10701
  }
10652
10702
  await etlService.post(`threadContent/${entry.id_thread}`, localContent);
10653
- manifest.threads[relPath].hash = computeHash(localContent);
10703
+ entry.hash = computeHash(localContent);
10654
10704
  console.log(` Updated: ${relPath}`);
10655
10705
  } else {
10656
10706
  const parts = relPath.split("/");
10657
- const type = parts[0];
10707
+ const dirName = parts[0];
10708
+ const type = dirNameToType(dirName);
10709
+ if (!type) {
10710
+ console.error(` Unknown thread type directory: ${dirName}`);
10711
+ continue;
10712
+ }
10658
10713
  const description = parts.slice(1).join("/").replace(/\.sql$/, "");
10659
10714
  const newThread = await etlService.post("threads", {
10660
10715
  type,
@@ -10663,22 +10718,23 @@ async function push(flags, files) {
10663
10718
  });
10664
10719
  if (newThread?.id_thread) {
10665
10720
  await etlService.post(`threadContent/${newThread.id_thread}`, localContent);
10666
- manifest.threads[relPath] = {
10721
+ index.push({
10722
+ path: relPath,
10667
10723
  id_thread: newThread.id_thread,
10668
10724
  hash: computeHash(localContent),
10669
10725
  type
10670
- };
10726
+ });
10671
10727
  console.log(` Created: ${relPath} (thread #${newThread.id_thread})`);
10672
10728
  } else {
10673
10729
  console.error(` Failed to create thread for ${relPath}`);
10674
10730
  }
10675
10731
  }
10676
10732
  }
10677
- writeManifest(path3.resolve(root), manifest);
10733
+ writeIndex(path3.resolve(root), index);
10678
10734
  console.log("Push complete.");
10679
10735
  }
10680
10736
  async function pullContext(dir, etlService, defService) {
10681
- const contextDir = path3.join(dir, ".context");
10737
+ const contextDir = path3.join(dir, ".rpbi", "context");
10682
10738
  console.log("Pulling context (schema & modules)...");
10683
10739
  try {
10684
10740
  const modules2 = await defService.get("accountingModules");
@@ -10715,39 +10771,40 @@ async function context(flags) {
10715
10771
  await pullContext(dir, etlService, defService);
10716
10772
  console.log("Context pull complete.");
10717
10773
  }
10718
- function detectModifiedFiles(root, manifest) {
10774
+ function detectModifiedFiles(root, index) {
10719
10775
  const modified = [];
10720
- for (const [relPath, entry] of Object.entries(manifest.threads)) {
10721
- const absPath = path3.join(root, relPath);
10776
+ for (const entry of index) {
10777
+ const absPath = path3.join(root, entry.path);
10722
10778
  if (!fs4.existsSync(absPath)) {
10723
- modified.push(relPath);
10779
+ modified.push(entry.path);
10724
10780
  continue;
10725
10781
  }
10726
10782
  const content2 = fs4.readFileSync(absPath, "utf-8");
10727
10783
  if (computeHash(content2) !== entry.hash) {
10728
- modified.push(relPath);
10784
+ modified.push(entry.path);
10729
10785
  }
10730
10786
  }
10731
10787
  return modified;
10732
10788
  }
10733
- function detectNewFiles(root, manifest) {
10789
+ function detectNewFiles(root, index) {
10734
10790
  const newFiles = [];
10791
+ const knownPaths = new Set(index.map((e) => e.path));
10735
10792
  const entries = fs4.readdirSync(root, { withFileTypes: true });
10736
10793
  for (const entry of entries) {
10737
10794
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
10738
- walkDir(path3.join(root, entry.name), root, manifest, newFiles);
10795
+ walkDir(path3.join(root, entry.name), root, knownPaths, newFiles);
10739
10796
  }
10740
10797
  return newFiles;
10741
10798
  }
10742
- function walkDir(dir, root, manifest, result) {
10799
+ function walkDir(dir, root, knownPaths, result) {
10743
10800
  const entries = fs4.readdirSync(dir, { withFileTypes: true });
10744
10801
  for (const entry of entries) {
10745
10802
  const full = path3.join(dir, entry.name);
10746
10803
  if (entry.isDirectory()) {
10747
- walkDir(full, root, manifest, result);
10804
+ walkDir(full, root, knownPaths, result);
10748
10805
  } else if (entry.name.endsWith(".sql")) {
10749
10806
  const rel = path3.relative(root, full);
10750
- if (!manifest.threads[rel]) {
10807
+ if (!knownPaths.has(rel)) {
10751
10808
  result.push(rel);
10752
10809
  }
10753
10810
  }
@@ -10757,16 +10814,17 @@ async function status2(flags) {
10757
10814
  const startDir = flags.dir || ".";
10758
10815
  const root = findEtlRoot(startDir);
10759
10816
  if (!root) {
10760
- console.error('No .rpbi/manifest.json found. Run "rpbi etl pull" first.');
10817
+ console.error('No .rpbi/config.json found. Run "rpbi etl pull" first.');
10761
10818
  process.exit(1);
10762
10819
  }
10763
- const manifest = readManifest(root);
10820
+ const config2 = readConfig(root);
10821
+ const index = readIndex(root);
10764
10822
  console.log(`ETL workspace: ${root}`);
10765
- console.log(`Domain: ${manifest.domain} | Accounting: ${manifest.accounting}`);
10766
- console.log(`Pulled at: ${manifest.pulledAt}`);
10823
+ console.log(`Domain: ${config2?.domain} | Accounting: ${config2?.accounting}`);
10824
+ console.log(`Pulled at: ${config2?.pulledAt}`);
10767
10825
  console.log("");
10768
- const modified = detectModifiedFiles(root, manifest);
10769
- const newFiles = detectNewFiles(root, manifest);
10826
+ const modified = detectModifiedFiles(root, index);
10827
+ const newFiles = detectNewFiles(root, index);
10770
10828
  const deleted = modified.filter((f) => !fs4.existsSync(path3.join(root, f)));
10771
10829
  const changed = modified.filter((f) => fs4.existsSync(path3.join(root, f)));
10772
10830
  if (changed.length === 0 && newFiles.length === 0 && deleted.length === 0) {
@@ -34388,7 +34446,7 @@ function text(data) {
34388
34446
  async function mcp() {
34389
34447
  const server = new McpServer({
34390
34448
  name: "reporting-bi",
34391
- version: "0.0.15"
34449
+ version: "0.0.17"
34392
34450
  });
34393
34451
  server.tool(
34394
34452
  "status",
@@ -34838,17 +34896,16 @@ function init(args) {
34838
34896
  console.error(`Not logged in to "${domain2}". Run "rpbi login ${domain2}" first.`);
34839
34897
  process.exit(1);
34840
34898
  }
34841
- const existing = readManifest(process.cwd());
34842
- const manifest = {
34899
+ const existing = readConfig(process.cwd());
34900
+ const config2 = {
34843
34901
  domain: domain2,
34844
34902
  accounting: flags.accounting ? parseInt(flags.accounting) : existing?.accounting ?? creds.connections[domain2].accounting ?? 0,
34845
- ...existing?.pulledAt && { pulledAt: existing.pulledAt },
34846
- ...existing?.threads && { threads: existing.threads }
34903
+ ...existing?.pulledAt && { pulledAt: existing.pulledAt }
34847
34904
  };
34848
- writeManifest(process.cwd(), manifest);
34849
- console.log(`Initialized .rpbi/manifest.json`);
34850
- console.log(` domain: ${manifest.domain}`);
34851
- console.log(` accounting: ${manifest.accounting || "not set"}`);
34905
+ writeConfig(process.cwd(), config2);
34906
+ console.log(`Initialized .rpbi/config.json`);
34907
+ console.log(` domain: ${config2.domain}`);
34908
+ console.log(` accounting: ${config2.accounting || "not set"}`);
34852
34909
  }
34853
34910
 
34854
34911
  // src/autoupdate.ts
@@ -34861,6 +34918,20 @@ var CONFIG_DIR2 = path4.join(os2.homedir(), ".config", "reporting-bi");
34861
34918
  var UPDATE_CHECK_FILE = path4.join(CONFIG_DIR2, "update-check.json");
34862
34919
  var CHECK_INTERVAL = 60 * 60 * 1e3;
34863
34920
  var PACKAGE_NAME = "@reporting-bi/cli";
34921
+ var INSTALL_PREFIX = detectPrefix();
34922
+ function detectPrefix() {
34923
+ const binDir = path4.dirname(process.argv[1]);
34924
+ const libIndex = binDir.indexOf(path4.join("lib", "node_modules"));
34925
+ if (libIndex > 0) {
34926
+ const prefix = binDir.slice(0, libIndex - 1);
34927
+ if (prefix !== "/usr" && prefix !== "/usr/local") return prefix;
34928
+ }
34929
+ return null;
34930
+ }
34931
+ function npmInstallCmd(version2) {
34932
+ const prefix = INSTALL_PREFIX ? ` --prefix "${INSTALL_PREFIX}"` : "";
34933
+ return `npm install -g${prefix} ${PACKAGE_NAME}@${version2}`;
34934
+ }
34864
34935
  function loadUpdateCheck() {
34865
34936
  try {
34866
34937
  return JSON.parse(fs6.readFileSync(UPDATE_CHECK_FILE, "utf-8"));
@@ -34916,9 +34987,9 @@ async function checkForUpdate() {
34916
34987
  saveUpdateCheck({ lastCheck: now });
34917
34988
  const latest = await fetchLatestVersion();
34918
34989
  if (!latest) return;
34919
- if (!isNewer(latest, "0.0.15")) return;
34920
- console.log(`\x1B[33mUpdating ${PACKAGE_NAME} ${"0.0.15"} \u2192 ${latest}...\x1B[0m`);
34921
- (0, import_node_child_process2.execSync)(`npm install -g ${PACKAGE_NAME}@${latest}`, { stdio: "inherit" });
34990
+ if (!isNewer(latest, "0.0.17")) return;
34991
+ console.log(`\x1B[33mUpdating ${PACKAGE_NAME} ${"0.0.17"} \u2192 ${latest}...\x1B[0m`);
34992
+ (0, import_node_child_process2.execSync)(npmInstallCmd(latest), { stdio: "inherit" });
34922
34993
  console.log(`\x1B[32mUpdated to ${latest}.\x1B[0m`);
34923
34994
  } catch {
34924
34995
  }
@@ -34929,12 +35000,12 @@ async function forceUpdate() {
34929
35000
  console.error("Could not fetch latest version from npm.");
34930
35001
  process.exit(1);
34931
35002
  }
34932
- if (!isNewer(latest, "0.0.15")) {
34933
- console.log(`Already up to date (${"0.0.15"}).`);
35003
+ if (!isNewer(latest, "0.0.17")) {
35004
+ console.log(`Already up to date (${"0.0.17"}).`);
34934
35005
  return;
34935
35006
  }
34936
- console.log(`Updating ${PACKAGE_NAME} ${"0.0.15"} \u2192 ${latest}...`);
34937
- (0, import_node_child_process2.execSync)(`npm install -g ${PACKAGE_NAME}@${latest}`, { stdio: "inherit" });
35007
+ console.log(`Updating ${PACKAGE_NAME} ${"0.0.17"} \u2192 ${latest}...`);
35008
+ (0, import_node_child_process2.execSync)(npmInstallCmd(latest), { stdio: "inherit" });
34938
35009
  console.log(`\x1B[32mUpdated to ${latest}.\x1B[0m`);
34939
35010
  saveUpdateCheck({ lastCheck: Date.now() });
34940
35011
  }
@@ -34962,6 +35033,10 @@ ETL:
34962
35033
  etl content <id> Get thread SQL content (plain text)
34963
35034
  etl exec <id> [--sql "..."|--file f] Execute thread (optionally with custom SQL)
34964
35035
  etl search <query> Search threads
35036
+ etl pull [--dir <path>] [--no-context] Pull all ETL threads, parameters, metadata & schema to local files
35037
+ etl push [files...] [--dir <path>] [--force] Push modified/new .sql files back to server
35038
+ etl status [--dir <path>] Show local changes (modified, new, deleted)
35039
+ etl context [--dir <path>] Pull context only (schema & modules)
34965
35040
 
34966
35041
  Jobs:
34967
35042
  jobs list List available jobs
@@ -35031,6 +35106,10 @@ Examples:
35031
35106
  rpbi etl list
35032
35107
  rpbi etl exec 42
35033
35108
  rpbi etl content 42
35109
+ rpbi etl pull
35110
+ rpbi etl push
35111
+ rpbi etl push IA/folder/script.sql
35112
+ rpbi etl status
35034
35113
 
35035
35114
  rpbi jobs list
35036
35115
  rpbi jobs start "My Job"
@@ -35063,7 +35142,7 @@ Examples:
35063
35142
  (async () => {
35064
35143
  const [command, ...args] = process.argv.slice(2);
35065
35144
  if (command === "--version" || command === "-v") {
35066
- console.log("0.0.15");
35145
+ console.log("0.0.17");
35067
35146
  return;
35068
35147
  }
35069
35148
  await checkForUpdate();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reporting-bi/cli",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "license": "UNLICENSED",
5
5
  "description": "Reporting.bi CLI — command-line interface for the Reporting.bi platform",
6
6
  "main": "./dist/index.js",