@reporting-bi/cli 0.0.10 → 0.0.11

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 +488 -49
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2028,9 +2028,9 @@ var require_stringify = __commonJS({
2028
2028
  }
2029
2029
  };
2030
2030
  var isArray = Array.isArray;
2031
- var push = Array.prototype.push;
2031
+ var push2 = Array.prototype.push;
2032
2032
  var pushToArray = function(arr, valueOrArray) {
2033
- push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
2033
+ push2.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
2034
2034
  };
2035
2035
  var toISO = Date.prototype.toISOString;
2036
2036
  var defaultFormat = formats["default"];
@@ -2650,7 +2650,7 @@ var require_service = __commonJS({
2650
2650
  this.options.baseUrl = `https://${this.options.baseUrl}`;
2651
2651
  }
2652
2652
  }
2653
- createUrl(path3 = "", params) {
2653
+ createUrl(path5 = "", params) {
2654
2654
  if (this.options.xdebugSession) {
2655
2655
  params = params || {};
2656
2656
  params.XDEBUG_SESSION = this.options.xdebugSession === true ? "1" : this.options.xdebugSession.toString();
@@ -2660,8 +2660,8 @@ var require_service = __commonJS({
2660
2660
  }
2661
2661
  const queryString = params ? "?" + serializeRequestParams(params) : "";
2662
2662
  const a = params && params.accounting ? params.accounting.toString() : this.a ? this.a.toString() : null;
2663
- path3 = path3.replace(/^\//, "");
2664
- const parts = [this.options.baseUrl, a, this.options.name, path3];
2663
+ path5 = path5.replace(/^\//, "");
2664
+ const parts = [this.options.baseUrl, a, this.options.name, path5];
2665
2665
  return parts.filter((p) => p != null && p !== "").join("/") + queryString;
2666
2666
  }
2667
2667
  async createHeaders(headers) {
@@ -2702,28 +2702,28 @@ var require_service = __commonJS({
2702
2702
  return await response.text();
2703
2703
  }
2704
2704
  }
2705
- async getRaw(path3, params, options) {
2706
- return fetch(this.createUrl(path3, params), {
2705
+ async getRaw(path5, params, options) {
2706
+ return fetch(this.createUrl(path5, params), {
2707
2707
  headers: await this.createHeaders(options?.headers),
2708
2708
  credentials: this.credentials
2709
2709
  });
2710
2710
  }
2711
- async get(path3, params, options) {
2711
+ async get(path5, params, options) {
2712
2712
  if (options?.cache) {
2713
- const cachedData = this.cache.get({ path: path3, params });
2713
+ const cachedData = this.cache.get({ path: path5, params });
2714
2714
  if (cachedData)
2715
2715
  return cachedData;
2716
2716
  }
2717
- const response = await this.getRaw(path3, params, options);
2717
+ const response = await this.getRaw(path5, params, options);
2718
2718
  const responseData = await this.handleResponse(response, options?.parseResponse);
2719
2719
  if (options?.cache && responseData) {
2720
- this.cache.set({ path: path3, params }, responseData);
2720
+ this.cache.set({ path: path5, params }, responseData);
2721
2721
  }
2722
2722
  return responseData;
2723
2723
  }
2724
- async postRaw(path3, data, params, options) {
2724
+ async postRaw(path5, data, params, options) {
2725
2725
  const json = isObject(data) || Array.isArray(data);
2726
- return fetch(this.createUrl(path3, params), {
2726
+ return fetch(this.createUrl(path5, params), {
2727
2727
  method: "POST",
2728
2728
  body: json ? JSON.stringify(data) : data,
2729
2729
  headers: await this.createHeaders({
@@ -2733,24 +2733,24 @@ var require_service = __commonJS({
2733
2733
  credentials: this.credentials
2734
2734
  });
2735
2735
  }
2736
- async post(path3, data, params, options) {
2737
- const response = await this.postRaw(path3, data, params, options);
2736
+ async post(path5, data, params, options) {
2737
+ const response = await this.postRaw(path5, data, params, options);
2738
2738
  return this.handleResponse(response);
2739
2739
  }
2740
- async deleteRaw(path3, params, options) {
2741
- return fetch(this.createUrl(path3, params), {
2740
+ async deleteRaw(path5, params, options) {
2741
+ return fetch(this.createUrl(path5, params), {
2742
2742
  method: "DELETE",
2743
2743
  headers: await this.createHeaders(options?.headers),
2744
2744
  credentials: this.credentials
2745
2745
  });
2746
2746
  }
2747
- async delete(path3, params, options) {
2748
- const response = await this.deleteRaw(path3, params, options);
2747
+ async delete(path5, params, options) {
2748
+ const response = await this.deleteRaw(path5, params, options);
2749
2749
  return this.handleResponse(response);
2750
2750
  }
2751
- async putRaw(path3, data, params, options) {
2751
+ async putRaw(path5, data, params, options) {
2752
2752
  const json = isObject(data) || Array.isArray(data);
2753
- return fetch(this.createUrl(path3, params), {
2753
+ return fetch(this.createUrl(path5, params), {
2754
2754
  method: "PUT",
2755
2755
  body: json ? JSON.stringify(data) : data,
2756
2756
  headers: await this.createHeaders({
@@ -2760,8 +2760,8 @@ var require_service = __commonJS({
2760
2760
  credentials: this.credentials
2761
2761
  });
2762
2762
  }
2763
- async put(path3, data, params, options) {
2764
- const response = await this.putRaw(path3, data, params, options);
2763
+ async put(path5, data, params, options) {
2764
+ const response = await this.putRaw(path5, data, params, options);
2765
2765
  return this.handleResponse(response);
2766
2766
  }
2767
2767
  };
@@ -3286,8 +3286,8 @@ var callback_default = `<!DOCTYPE html>
3286
3286
  `;
3287
3287
 
3288
3288
  // src/commands/login.ts
3289
- function renderCallback(status2, title, message) {
3290
- return callback_default.replace("{{status}}", status2).replace("{{title}}", title).replace("{{message}}", message);
3289
+ function renderCallback(status3, title, message) {
3290
+ return callback_default.replace("{{status}}", status3).replace("{{title}}", title).replace("{{message}}", message);
3291
3291
  }
3292
3292
  function openBrowser(url) {
3293
3293
  const platform = process.platform;
@@ -3331,12 +3331,12 @@ async function login(args) {
3331
3331
  }
3332
3332
  }
3333
3333
  function getAuthorizationCode(domain) {
3334
- return new Promise((resolve) => {
3334
+ return new Promise((resolve3) => {
3335
3335
  let timeout;
3336
3336
  const done = (result) => {
3337
3337
  clearTimeout(timeout);
3338
3338
  server.close();
3339
- resolve(result);
3339
+ resolve3(result);
3340
3340
  };
3341
3341
  const server = http.createServer((req, res) => {
3342
3342
  const url = new URL(req.url || "", "http://localhost");
@@ -3496,11 +3496,11 @@ async function readContent(flags) {
3496
3496
  return flags.content;
3497
3497
  }
3498
3498
  if (!process.stdin.isTTY) {
3499
- return new Promise((resolve) => {
3499
+ return new Promise((resolve3) => {
3500
3500
  let data = "";
3501
3501
  process.stdin.setEncoding("utf-8");
3502
3502
  process.stdin.on("data", (chunk) => data += chunk);
3503
- process.stdin.on("end", () => resolve(data));
3503
+ process.stdin.on("end", () => resolve3(data));
3504
3504
  });
3505
3505
  }
3506
3506
  console.error("No content provided. Use --file, --content, or pipe to stdin.");
@@ -3564,7 +3564,433 @@ async function wiki(args) {
3564
3564
  }
3565
3565
 
3566
3566
  // src/commands/etl.ts
3567
+ var fs5 = __toESM(require("node:fs"));
3568
+
3569
+ // src/commands/etl-sync.ts
3570
+ var fs4 = __toESM(require("node:fs"));
3571
+ var path3 = __toESM(require("node:path"));
3572
+
3573
+ // src/manifest.ts
3567
3574
  var fs3 = __toESM(require("node:fs"));
3575
+ var path2 = __toESM(require("node:path"));
3576
+ var crypto = __toESM(require("node:crypto"));
3577
+ var RPBI_DIR = ".rpbi";
3578
+ var MANIFEST_FILE = "manifest.json";
3579
+ function computeHash(content2) {
3580
+ return crypto.createHash("sha256").update(content2, "utf-8").digest("hex");
3581
+ }
3582
+ function getManifestPath(dir) {
3583
+ return path2.join(dir, RPBI_DIR, MANIFEST_FILE);
3584
+ }
3585
+ function readManifest(dir) {
3586
+ const filePath = getManifestPath(dir);
3587
+ try {
3588
+ const data = fs3.readFileSync(filePath, "utf-8");
3589
+ return JSON.parse(data);
3590
+ } catch {
3591
+ return null;
3592
+ }
3593
+ }
3594
+ function writeManifest(dir, manifest) {
3595
+ const rpbiDir = path2.join(dir, RPBI_DIR);
3596
+ fs3.mkdirSync(rpbiDir, { recursive: true });
3597
+ fs3.writeFileSync(
3598
+ path2.join(rpbiDir, MANIFEST_FILE),
3599
+ JSON.stringify(manifest, null, 2)
3600
+ );
3601
+ }
3602
+ function findEtlRoot(startDir) {
3603
+ let dir = path2.resolve(startDir);
3604
+ while (true) {
3605
+ if (fs3.existsSync(getManifestPath(dir))) return dir;
3606
+ const parent = path2.dirname(dir);
3607
+ if (parent === dir) return null;
3608
+ dir = parent;
3609
+ }
3610
+ }
3611
+
3612
+ // src/commands/etl-sync.ts
3613
+ var PARAMETER_TYPES = ["IA", "IM", "O", "D"];
3614
+ var PARAMETER_EXCLUDE_FIELDS = ["accounting", "id_thread", "idz", "validate_flag", "date_created"];
3615
+ var THREAD_EXCLUDE_FIELDS = ["command_txt", "command_preview", "accounting", "id_thread", "type", "idz", "validate_flag", "date_created"];
3616
+ var CONTEXT_SCHEMA_DIRS = {
3617
+ "schema/db_data/tables": { db: "db_data", objectType: "tables" },
3618
+ "schema/db_data/procedures": { db: "db_data", objectType: "procedures" },
3619
+ "schema/db_data/functions": { db: "db_data", objectType: "functions" },
3620
+ "schema/db_master/views": { db: "db_master", objectType: "views" },
3621
+ "schema/db_master/procedures": { db: "db_master", objectType: "procedures" },
3622
+ "schema/db_master/functions": { db: "db_master", objectType: "functions" },
3623
+ "schema/db_super/views": { db: "db_super", objectType: "views" },
3624
+ "schema/db_super/procedures": { db: "db_super", objectType: "procedures" },
3625
+ "schema/db_super/functions": { db: "db_super", objectType: "functions" }
3626
+ };
3627
+ function optimizeForLlm(data) {
3628
+ if (data === null || data === void 0) return void 0;
3629
+ if (Array.isArray(data)) {
3630
+ const result = data.map((item) => optimizeForLlm(item)).filter((item) => item !== void 0);
3631
+ return result.length > 0 ? result : void 0;
3632
+ }
3633
+ if (typeof data === "object") {
3634
+ const result = {};
3635
+ let hasKeys = false;
3636
+ for (const [key, value] of Object.entries(data)) {
3637
+ const optimized = optimizeForLlm(value);
3638
+ if (optimized !== void 0) {
3639
+ result[key] = optimized;
3640
+ hasKeys = true;
3641
+ }
3642
+ }
3643
+ return hasKeys ? result : void 0;
3644
+ }
3645
+ return data;
3646
+ }
3647
+ function getFilePath(description, extension = ".sql") {
3648
+ const parts = description.split("/");
3649
+ const name = parts.pop();
3650
+ let fileName;
3651
+ if (!name.includes(".")) {
3652
+ fileName = name + extension;
3653
+ } else if (name.endsWith(".sql") && extension !== ".sql") {
3654
+ fileName = name.slice(0, -4) + extension;
3655
+ } else if (extension !== ".sql") {
3656
+ const dotIndex = name.lastIndexOf(".");
3657
+ fileName = name.slice(0, dotIndex) + extension;
3658
+ } else {
3659
+ fileName = name;
3660
+ }
3661
+ return [...parts, fileName];
3662
+ }
3663
+ function threadToRelPath(thread) {
3664
+ const segments = getFilePath(thread.description || "");
3665
+ return [thread.type, ...segments].join("/");
3666
+ }
3667
+ function threadToParamPath(thread) {
3668
+ const segments = getFilePath(thread.description || "", ".yaml");
3669
+ return [".parameters", thread.type, ...segments].join("/");
3670
+ }
3671
+ function threadToMetaPath(thread) {
3672
+ const segments = getFilePath(thread.description || "", ".yaml");
3673
+ return [".threads", thread.type, ...segments].join("/");
3674
+ }
3675
+ function writeFileSync4(filePath, content2) {
3676
+ fs4.mkdirSync(path3.dirname(filePath), { recursive: true });
3677
+ fs4.writeFileSync(filePath, content2, "utf-8");
3678
+ }
3679
+ function stripFields(obj, excludeFields) {
3680
+ const result = {};
3681
+ for (const [key, value] of Object.entries(obj)) {
3682
+ if (!excludeFields.includes(key)) {
3683
+ result[key] = value;
3684
+ }
3685
+ }
3686
+ return result;
3687
+ }
3688
+ function toYaml(data, indent = 0) {
3689
+ if (data === null || data === void 0) return "null";
3690
+ if (typeof data === "boolean") return data ? "true" : "false";
3691
+ if (typeof data === "number") return String(data);
3692
+ if (typeof data === "string") {
3693
+ if (data.includes("\n")) {
3694
+ const prefix = " ".repeat(indent);
3695
+ const lines = data.split("\n").map((l) => prefix + " " + l).join("\n");
3696
+ return "|\n" + lines;
3697
+ }
3698
+ if (data === "" || /[:{}\[\],&*?|>!'"%@`#]/.test(data) || /^\s|\s$/.test(data)) {
3699
+ return JSON.stringify(data);
3700
+ }
3701
+ return data;
3702
+ }
3703
+ if (Array.isArray(data)) {
3704
+ if (data.length === 0) return "[]";
3705
+ const prefix = " ".repeat(indent);
3706
+ return data.map((item) => {
3707
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
3708
+ const entries = Object.entries(item);
3709
+ if (entries.length === 0) return `${prefix}- {}`;
3710
+ const [firstKey, firstVal] = entries[0];
3711
+ const firstLine = `${prefix}- ${firstKey}: ${toYaml(firstVal, indent + 2)}`;
3712
+ const rest = entries.slice(1).map(
3713
+ ([k, v]) => `${prefix} ${k}: ${toYaml(v, indent + 2)}`
3714
+ );
3715
+ return [firstLine, ...rest].join("\n");
3716
+ }
3717
+ return `${prefix}- ${toYaml(item, indent + 2)}`;
3718
+ }).join("\n");
3719
+ }
3720
+ if (typeof data === "object") {
3721
+ const entries = Object.entries(data);
3722
+ if (entries.length === 0) return "{}";
3723
+ const prefix = " ".repeat(indent);
3724
+ return entries.map(
3725
+ ([k, v]) => `${prefix}${k}: ${toYaml(v, indent)}`
3726
+ ).join("\n");
3727
+ }
3728
+ return String(data);
3729
+ }
3730
+ async function pull(flags) {
3731
+ const dir = path3.resolve(flags.dir || ".");
3732
+ const conn = getActiveConnection();
3733
+ if (!conn) {
3734
+ console.error('Not logged in. Run "rpbi login" first.');
3735
+ process.exit(1);
3736
+ }
3737
+ const etlService = await createService("etl");
3738
+ const defService = await createService("definition");
3739
+ console.log(`Pulling ETL threads to ${dir}...`);
3740
+ const threads = await etlService.get("threads", {
3741
+ fields: ["id_thread", "description", "type", "enabled", "ord_num", "module"],
3742
+ order: [["type", "asc"], ["description", "asc"]]
3743
+ }) || [];
3744
+ console.log(`Found ${threads.length} threads`);
3745
+ const manifest = {
3746
+ domain: conn.domain,
3747
+ accounting: conn.tokens.accounting,
3748
+ pulledAt: (/* @__PURE__ */ new Date()).toISOString(),
3749
+ threads: {}
3750
+ };
3751
+ let pulled = 0;
3752
+ for (const thread of threads) {
3753
+ if (!thread.id_thread || !thread.type || !thread.description) continue;
3754
+ const relPath = threadToRelPath(thread);
3755
+ const absPath = path3.join(dir, relPath);
3756
+ try {
3757
+ const content2 = await etlService.get(
3758
+ `threadContent/${thread.id_thread}`,
3759
+ void 0,
3760
+ { parseResponse: false }
3761
+ ) || "";
3762
+ writeFileSync4(absPath, content2);
3763
+ manifest.threads[relPath] = {
3764
+ id_thread: thread.id_thread,
3765
+ hash: computeHash(content2),
3766
+ type: thread.type
3767
+ };
3768
+ pulled++;
3769
+ if (pulled % 50 === 0) console.log(` ${pulled}/${threads.length} threads...`);
3770
+ } catch (err) {
3771
+ console.error(` Failed to pull ${relPath}: ${err instanceof Error ? err.message : err}`);
3772
+ }
3773
+ }
3774
+ console.log("Pulling parameters...");
3775
+ for (const thread of threads) {
3776
+ if (!thread.id_thread || !PARAMETER_TYPES.includes(thread.type || "")) continue;
3777
+ try {
3778
+ const params = await etlService.get(
3779
+ `threads/${thread.id_thread}/parameters`
3780
+ ) || [];
3781
+ if (params.length === 0) continue;
3782
+ const cleaned = params.map((p) => stripFields(p, PARAMETER_EXCLUDE_FIELDS));
3783
+ const optimized = optimizeForLlm(cleaned);
3784
+ if (!optimized || !Array.isArray(optimized) || optimized.length === 0) continue;
3785
+ const paramPath = path3.join(dir, threadToParamPath(thread));
3786
+ writeFileSync4(paramPath, toYaml(optimized) + "\n");
3787
+ } catch {
3788
+ }
3789
+ }
3790
+ console.log("Pulling thread metadata...");
3791
+ for (const thread of threads) {
3792
+ if (!thread.id_thread) continue;
3793
+ try {
3794
+ const full = await etlService.get(`threads/${thread.id_thread}`);
3795
+ if (!full) continue;
3796
+ const cleaned = stripFields(full, THREAD_EXCLUDE_FIELDS);
3797
+ const optimized = optimizeForLlm(cleaned);
3798
+ if (!optimized || Object.keys(optimized).length === 0) continue;
3799
+ const metaPath = path3.join(dir, threadToMetaPath(thread));
3800
+ writeFileSync4(metaPath, toYaml(optimized) + "\n");
3801
+ } catch {
3802
+ }
3803
+ }
3804
+ if (!flags["no-context"]) {
3805
+ await pullContext(dir, etlService, defService);
3806
+ }
3807
+ writeManifest(dir, manifest);
3808
+ console.log(`Done. Pulled ${pulled} threads to ${dir}`);
3809
+ }
3810
+ async function push(flags, files) {
3811
+ const startDir = flags.dir || ".";
3812
+ const root = findEtlRoot(startDir);
3813
+ if (!root) {
3814
+ console.error('No .rpbi/manifest.json found. Run "rpbi etl pull" first.');
3815
+ process.exit(1);
3816
+ }
3817
+ const manifest = readManifest(root);
3818
+ const etlService = await createService("etl");
3819
+ const force = flags.force === "true";
3820
+ let filesToPush;
3821
+ if (files.length > 0) {
3822
+ filesToPush = files.map((f) => path3.relative(root, path3.resolve(f)));
3823
+ } else {
3824
+ filesToPush = detectModifiedFiles(root, manifest);
3825
+ }
3826
+ if (filesToPush.length === 0) {
3827
+ console.log("Nothing to push.");
3828
+ return;
3829
+ }
3830
+ console.log(`Pushing ${filesToPush.length} file(s)...`);
3831
+ for (const relPath of filesToPush) {
3832
+ const absPath = path3.join(root, relPath);
3833
+ if (!fs4.existsSync(absPath)) {
3834
+ console.log(` Skipping ${relPath} (file not found)`);
3835
+ continue;
3836
+ }
3837
+ const localContent = fs4.readFileSync(absPath, "utf-8");
3838
+ const entry = manifest.threads[relPath];
3839
+ if (entry) {
3840
+ if (!force) {
3841
+ try {
3842
+ const serverContent = await etlService.get(
3843
+ `threadContent/${entry.id_thread}`,
3844
+ void 0,
3845
+ { parseResponse: false }
3846
+ ) || "";
3847
+ const serverHash = computeHash(serverContent);
3848
+ if (serverHash !== entry.hash) {
3849
+ console.error(` CONFLICT: ${relPath} was modified on server. Use --force to overwrite.`);
3850
+ continue;
3851
+ }
3852
+ } catch {
3853
+ }
3854
+ }
3855
+ await etlService.post(`threadContent/${entry.id_thread}`, localContent);
3856
+ manifest.threads[relPath].hash = computeHash(localContent);
3857
+ console.log(` Updated: ${relPath}`);
3858
+ } else {
3859
+ const parts = relPath.split("/");
3860
+ const type = parts[0];
3861
+ const description = parts.slice(1).join("/").replace(/\.sql$/, "");
3862
+ const newThread = await etlService.post("threads", {
3863
+ type,
3864
+ description,
3865
+ enabled: 1
3866
+ });
3867
+ if (newThread?.id_thread) {
3868
+ await etlService.post(`threadContent/${newThread.id_thread}`, localContent);
3869
+ manifest.threads[relPath] = {
3870
+ id_thread: newThread.id_thread,
3871
+ hash: computeHash(localContent),
3872
+ type
3873
+ };
3874
+ console.log(` Created: ${relPath} (thread #${newThread.id_thread})`);
3875
+ } else {
3876
+ console.error(` Failed to create thread for ${relPath}`);
3877
+ }
3878
+ }
3879
+ }
3880
+ writeManifest(path3.resolve(root), manifest);
3881
+ console.log("Push complete.");
3882
+ }
3883
+ async function pullContext(dir, etlService, defService) {
3884
+ const contextDir = path3.join(dir, ".context");
3885
+ console.log("Pulling context (schema & modules)...");
3886
+ try {
3887
+ const modules2 = await defService.get("accountingModules");
3888
+ if (modules2) {
3889
+ const optimized = optimizeForLlm(modules2);
3890
+ writeFileSync4(
3891
+ path3.join(contextDir, "modules.json"),
3892
+ JSON.stringify(optimized, null, 2)
3893
+ );
3894
+ }
3895
+ } catch (err) {
3896
+ console.error(` Failed to pull modules: ${err instanceof Error ? err.message : err}`);
3897
+ }
3898
+ for (const [dirPath, { db, objectType }] of Object.entries(CONTEXT_SCHEMA_DIRS)) {
3899
+ try {
3900
+ const items = await etlService.get(`schema/${db}/${objectType}`) || [];
3901
+ for (const item of items) {
3902
+ const name = item?.name;
3903
+ if (!name) continue;
3904
+ const optimized = optimizeForLlm(item);
3905
+ writeFileSync4(
3906
+ path3.join(contextDir, dirPath, `${name}.json`),
3907
+ JSON.stringify(optimized, null, 2)
3908
+ );
3909
+ }
3910
+ } catch {
3911
+ }
3912
+ }
3913
+ }
3914
+ async function context(flags) {
3915
+ const dir = path3.resolve(flags.dir || ".");
3916
+ const etlService = await createService("etl");
3917
+ const defService = await createService("definition");
3918
+ await pullContext(dir, etlService, defService);
3919
+ console.log("Context pull complete.");
3920
+ }
3921
+ function detectModifiedFiles(root, manifest) {
3922
+ const modified = [];
3923
+ for (const [relPath, entry] of Object.entries(manifest.threads)) {
3924
+ const absPath = path3.join(root, relPath);
3925
+ if (!fs4.existsSync(absPath)) {
3926
+ modified.push(relPath);
3927
+ continue;
3928
+ }
3929
+ const content2 = fs4.readFileSync(absPath, "utf-8");
3930
+ if (computeHash(content2) !== entry.hash) {
3931
+ modified.push(relPath);
3932
+ }
3933
+ }
3934
+ return modified;
3935
+ }
3936
+ function detectNewFiles(root, manifest) {
3937
+ const newFiles = [];
3938
+ const entries = fs4.readdirSync(root, { withFileTypes: true });
3939
+ for (const entry of entries) {
3940
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
3941
+ walkDir(path3.join(root, entry.name), root, manifest, newFiles);
3942
+ }
3943
+ return newFiles;
3944
+ }
3945
+ function walkDir(dir, root, manifest, result) {
3946
+ const entries = fs4.readdirSync(dir, { withFileTypes: true });
3947
+ for (const entry of entries) {
3948
+ const full = path3.join(dir, entry.name);
3949
+ if (entry.isDirectory()) {
3950
+ walkDir(full, root, manifest, result);
3951
+ } else if (entry.name.endsWith(".sql")) {
3952
+ const rel = path3.relative(root, full);
3953
+ if (!manifest.threads[rel]) {
3954
+ result.push(rel);
3955
+ }
3956
+ }
3957
+ }
3958
+ }
3959
+ async function status2(flags) {
3960
+ const startDir = flags.dir || ".";
3961
+ const root = findEtlRoot(startDir);
3962
+ if (!root) {
3963
+ console.error('No .rpbi/manifest.json found. Run "rpbi etl pull" first.');
3964
+ process.exit(1);
3965
+ }
3966
+ const manifest = readManifest(root);
3967
+ console.log(`ETL workspace: ${root}`);
3968
+ console.log(`Domain: ${manifest.domain} | Accounting: ${manifest.accounting}`);
3969
+ console.log(`Pulled at: ${manifest.pulledAt}`);
3970
+ console.log("");
3971
+ const modified = detectModifiedFiles(root, manifest);
3972
+ const newFiles = detectNewFiles(root, manifest);
3973
+ const deleted = modified.filter((f) => !fs4.existsSync(path3.join(root, f)));
3974
+ const changed = modified.filter((f) => fs4.existsSync(path3.join(root, f)));
3975
+ if (changed.length === 0 && newFiles.length === 0 && deleted.length === 0) {
3976
+ console.log("No changes.");
3977
+ return;
3978
+ }
3979
+ if (changed.length > 0) {
3980
+ console.log("Modified:");
3981
+ for (const f of changed) console.log(` M ${f}`);
3982
+ }
3983
+ if (newFiles.length > 0) {
3984
+ console.log("New (untracked):");
3985
+ for (const f of newFiles) console.log(` + ${f}`);
3986
+ }
3987
+ if (deleted.length > 0) {
3988
+ console.log("Deleted locally:");
3989
+ for (const f of deleted) console.log(` - ${f}`);
3990
+ }
3991
+ }
3992
+
3993
+ // src/commands/etl.ts
3568
3994
  var DEFAULT_FIELDS = ["id_thread", "description", "module", "type", "enabled", "ord_num"];
3569
3995
  async function list3(flags) {
3570
3996
  const service = await createService("etl");
@@ -3585,7 +4011,7 @@ async function exec2(id, flags) {
3585
4011
  const service = await createService("etl");
3586
4012
  let body = void 0;
3587
4013
  if (flags.file) {
3588
- body = fs3.readFileSync(flags.file, "utf-8");
4014
+ body = fs5.readFileSync(flags.file, "utf-8");
3589
4015
  } else if (flags.sql) {
3590
4016
  body = flags.sql;
3591
4017
  }
@@ -3627,8 +4053,16 @@ async function etl(args) {
3627
4053
  process.exit(1);
3628
4054
  }
3629
4055
  return search2(rest[0], flags);
4056
+ case "pull":
4057
+ return pull(flags);
4058
+ case "push":
4059
+ return push(flags, rest);
4060
+ case "context":
4061
+ return context(flags);
4062
+ case "status":
4063
+ return status2(flags);
3630
4064
  default:
3631
- console.log("Usage: rpbi etl <list|get|content|exec|search> [options]");
4065
+ console.log("Usage: rpbi etl <list|get|content|exec|search|pull|push|context|status> [options]");
3632
4066
  break;
3633
4067
  }
3634
4068
  }
@@ -3684,7 +4118,7 @@ async function jobs(args) {
3684
4118
 
3685
4119
  // src/commands/analytics.ts
3686
4120
  var DEFAULT_CONTEXT_FIELDS = ["id_context", "name", "module", "user_name"];
3687
- async function context(args) {
4121
+ async function context2(args) {
3688
4122
  const { positional, flags } = parseArgs(args);
3689
4123
  const [subcommand, ...rest] = positional;
3690
4124
  switch (subcommand) {
@@ -3974,47 +4408,47 @@ async function helpdesk(args) {
3974
4408
  }
3975
4409
 
3976
4410
  // src/autoupdate.ts
3977
- var fs4 = __toESM(require("node:fs"));
3978
- var path2 = __toESM(require("node:path"));
4411
+ var fs6 = __toESM(require("node:fs"));
4412
+ var path4 = __toESM(require("node:path"));
3979
4413
  var os2 = __toESM(require("node:os"));
3980
4414
  var https = __toESM(require("node:https"));
3981
4415
  var import_node_child_process2 = require("node:child_process");
3982
- var CONFIG_DIR2 = path2.join(os2.homedir(), ".config", "reporting-bi");
3983
- var UPDATE_CHECK_FILE = path2.join(CONFIG_DIR2, "update-check.json");
4416
+ var CONFIG_DIR2 = path4.join(os2.homedir(), ".config", "reporting-bi");
4417
+ var UPDATE_CHECK_FILE = path4.join(CONFIG_DIR2, "update-check.json");
3984
4418
  var CHECK_INTERVAL = 60 * 60 * 1e3;
3985
4419
  var PACKAGE_NAME = "@reporting-bi/cli";
3986
4420
  function loadUpdateCheck() {
3987
4421
  try {
3988
- return JSON.parse(fs4.readFileSync(UPDATE_CHECK_FILE, "utf-8"));
4422
+ return JSON.parse(fs6.readFileSync(UPDATE_CHECK_FILE, "utf-8"));
3989
4423
  } catch {
3990
4424
  return { lastCheck: 0 };
3991
4425
  }
3992
4426
  }
3993
4427
  function saveUpdateCheck(data) {
3994
- fs4.mkdirSync(CONFIG_DIR2, { recursive: true });
3995
- fs4.writeFileSync(UPDATE_CHECK_FILE, JSON.stringify(data, null, 2));
4428
+ fs6.mkdirSync(CONFIG_DIR2, { recursive: true });
4429
+ fs6.writeFileSync(UPDATE_CHECK_FILE, JSON.stringify(data, null, 2));
3996
4430
  }
3997
4431
  function fetchLatestVersion() {
3998
- return new Promise((resolve) => {
4432
+ return new Promise((resolve3) => {
3999
4433
  const req = https.get(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, { timeout: 5e3 }, (res) => {
4000
4434
  if (res.statusCode !== 200) {
4001
4435
  res.resume();
4002
- return resolve(null);
4436
+ return resolve3(null);
4003
4437
  }
4004
4438
  let body = "";
4005
4439
  res.on("data", (chunk) => body += chunk);
4006
4440
  res.on("end", () => {
4007
4441
  try {
4008
- resolve(JSON.parse(body).version ?? null);
4442
+ resolve3(JSON.parse(body).version ?? null);
4009
4443
  } catch {
4010
- resolve(null);
4444
+ resolve3(null);
4011
4445
  }
4012
4446
  });
4013
4447
  });
4014
- req.on("error", () => resolve(null));
4448
+ req.on("error", () => resolve3(null));
4015
4449
  req.on("timeout", () => {
4016
4450
  req.destroy();
4017
- resolve(null);
4451
+ resolve3(null);
4018
4452
  });
4019
4453
  });
4020
4454
  }
@@ -4030,6 +4464,7 @@ function isNewer(remote, local) {
4030
4464
  return false;
4031
4465
  }
4032
4466
  async function checkForUpdate() {
4467
+ if (process.env.RPBI_EMBEDDED) return;
4033
4468
  try {
4034
4469
  const data = loadUpdateCheck();
4035
4470
  const now = Date.now();
@@ -4037,8 +4472,8 @@ async function checkForUpdate() {
4037
4472
  saveUpdateCheck({ lastCheck: now });
4038
4473
  const latest = await fetchLatestVersion();
4039
4474
  if (!latest) return;
4040
- if (!isNewer(latest, "0.0.10")) return;
4041
- console.log(`\x1B[33mUpdating ${PACKAGE_NAME} ${"0.0.10"} \u2192 ${latest}...\x1B[0m`);
4475
+ if (!isNewer(latest, "0.0.11")) return;
4476
+ console.log(`\x1B[33mUpdating ${PACKAGE_NAME} ${"0.0.11"} \u2192 ${latest}...\x1B[0m`);
4042
4477
  (0, import_node_child_process2.execSync)(`npm install -g ${PACKAGE_NAME}@${latest}`, { stdio: "inherit" });
4043
4478
  console.log(`\x1B[32mUpdated to ${latest}.\x1B[0m`);
4044
4479
  } catch {
@@ -4164,8 +4599,12 @@ Examples:
4164
4599
 
4165
4600
  // src/index.ts
4166
4601
  (async () => {
4167
- await checkForUpdate();
4168
4602
  const [command, ...args] = process.argv.slice(2);
4603
+ if (command === "--version" || command === "-v") {
4604
+ console.log("0.0.11");
4605
+ return;
4606
+ }
4607
+ await checkForUpdate();
4169
4608
  switch (command) {
4170
4609
  case "login":
4171
4610
  login(args);
@@ -4189,7 +4628,7 @@ Examples:
4189
4628
  jobs(args);
4190
4629
  break;
4191
4630
  case "context":
4192
- context(args);
4631
+ context2(args);
4193
4632
  break;
4194
4633
  case "report":
4195
4634
  report(args);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reporting-bi/cli",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "license": "UNLICENSED",
5
5
  "description": "Reporting.bi CLI — command-line interface for the Reporting.bi platform",
6
6
  "main": "./dist/index.js",