@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.
- package/dist/index.js +189 -110
- 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
|
|
9806
|
+
const configPath = path.join(dir, ".rpbi", "config.json");
|
|
9807
9807
|
try {
|
|
9808
|
-
const data = JSON.parse(fs.readFileSync(
|
|
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
|
|
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
|
|
10380
|
-
return path2.join(dir, RPBI_DIR,
|
|
10387
|
+
function getConfigPath(dir) {
|
|
10388
|
+
return path2.join(dir, RPBI_DIR, CONFIG_FILE);
|
|
10381
10389
|
}
|
|
10382
|
-
function
|
|
10383
|
-
|
|
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(
|
|
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
|
|
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,
|
|
10396
|
-
JSON.stringify(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
10660
|
+
console.error('No .rpbi/config.json found. Run "rpbi etl pull" first.');
|
|
10612
10661
|
process.exit(1);
|
|
10613
10662
|
}
|
|
10614
|
-
const
|
|
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,
|
|
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 =
|
|
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
|
-
|
|
10703
|
+
entry.hash = computeHash(localContent);
|
|
10654
10704
|
console.log(` Updated: ${relPath}`);
|
|
10655
10705
|
} else {
|
|
10656
10706
|
const parts = relPath.split("/");
|
|
10657
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
10774
|
+
function detectModifiedFiles(root, index) {
|
|
10719
10775
|
const modified = [];
|
|
10720
|
-
for (const
|
|
10721
|
-
const absPath = path3.join(root,
|
|
10776
|
+
for (const entry of index) {
|
|
10777
|
+
const absPath = path3.join(root, entry.path);
|
|
10722
10778
|
if (!fs4.existsSync(absPath)) {
|
|
10723
|
-
modified.push(
|
|
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(
|
|
10784
|
+
modified.push(entry.path);
|
|
10729
10785
|
}
|
|
10730
10786
|
}
|
|
10731
10787
|
return modified;
|
|
10732
10788
|
}
|
|
10733
|
-
function detectNewFiles(root,
|
|
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,
|
|
10795
|
+
walkDir(path3.join(root, entry.name), root, knownPaths, newFiles);
|
|
10739
10796
|
}
|
|
10740
10797
|
return newFiles;
|
|
10741
10798
|
}
|
|
10742
|
-
function walkDir(dir, root,
|
|
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,
|
|
10804
|
+
walkDir(full, root, knownPaths, result);
|
|
10748
10805
|
} else if (entry.name.endsWith(".sql")) {
|
|
10749
10806
|
const rel = path3.relative(root, full);
|
|
10750
|
-
if (!
|
|
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/
|
|
10817
|
+
console.error('No .rpbi/config.json found. Run "rpbi etl pull" first.');
|
|
10761
10818
|
process.exit(1);
|
|
10762
10819
|
}
|
|
10763
|
-
const
|
|
10820
|
+
const config2 = readConfig(root);
|
|
10821
|
+
const index = readIndex(root);
|
|
10764
10822
|
console.log(`ETL workspace: ${root}`);
|
|
10765
|
-
console.log(`Domain: ${
|
|
10766
|
-
console.log(`Pulled at: ${
|
|
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,
|
|
10769
|
-
const newFiles = detectNewFiles(root,
|
|
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.
|
|
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 =
|
|
34842
|
-
const
|
|
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
|
-
|
|
34849
|
-
console.log(`Initialized .rpbi/
|
|
34850
|
-
console.log(` domain: ${
|
|
34851
|
-
console.log(` accounting: ${
|
|
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.
|
|
34920
|
-
console.log(`\x1B[33mUpdating ${PACKAGE_NAME} ${"0.0.
|
|
34921
|
-
(0, import_node_child_process2.execSync)(
|
|
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.
|
|
34933
|
-
console.log(`Already up to date (${"0.0.
|
|
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.
|
|
34937
|
-
(0, import_node_child_process2.execSync)(
|
|
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.
|
|
35145
|
+
console.log("0.0.17");
|
|
35067
35146
|
return;
|
|
35068
35147
|
}
|
|
35069
35148
|
await checkForUpdate();
|