@rivora/cli 0.1.2 → 0.1.3

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 +861 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -180050,6 +180050,18 @@ class RestClient {
180050
180050
  }
180051
180051
  return { data: response.data, status: response.statusCode || 200 };
180052
180052
  }
180053
+ async sendAgentMessage(body) {
180054
+ const response = await this.makeRequest({
180055
+ method: "POST",
180056
+ path: "/api/agent/message",
180057
+ body
180058
+ });
180059
+ if (!response.success) {
180060
+ const errorMsg = typeof response.error === "string" ? response.error : response.error?.message || "Agent request failed";
180061
+ throw new Error(errorMsg);
180062
+ }
180063
+ return response.data;
180064
+ }
180053
180065
  async put(path52, body, options) {
180054
180066
  const response = await this.makeRequest({
180055
180067
  method: "PUT",
@@ -186412,7 +186424,7 @@ function createTestCommand() {
186412
186424
  });
186413
186425
  }
186414
186426
  init_source();
186415
- var version = "0.0.2";
186427
+ var version = "0.1.3";
186416
186428
  var execAsync = promisify(exec);
186417
186429
  var CLI_BASE_URL = process.env.RIVORA_CLI_URL || "https://cli.rivora.dev/releases/latest";
186418
186430
  async function fetchLatestVersion() {
@@ -186838,7 +186850,7 @@ trainingCommand.command("config").description("Show training configuration [INTE
186838
186850
  init_source();
186839
186851
  var import_cli_table34 = __toESM2(require_table(), 1);
186840
186852
  init_auth_service();
186841
- var modelsCommand = new Command2("models").description("Manage metrics contribution for Rivora ML models");
186853
+ var modelsCommand = new Command2("models").description("Manage Rivora ML models and metrics contribution");
186842
186854
  async function ensureAuth6() {
186843
186855
  const isAuthenticated = await authService.isAuthenticated();
186844
186856
  if (!isAuthenticated) {
@@ -186848,6 +186860,149 @@ async function ensureAuth6() {
186848
186860
  }
186849
186861
  return authService.getAccessToken();
186850
186862
  }
186863
+ function renderModelStatus(model) {
186864
+ if (model.update_policy === "pinned") {
186865
+ return source_default.blue("Pinned");
186866
+ }
186867
+ if (model.update_available) {
186868
+ return source_default.yellow("Update available");
186869
+ }
186870
+ return source_default.green("Up to date");
186871
+ }
186872
+ modelsCommand.command("status").description("Show model status and versions").option("--json", "Output as JSON").action(async (options) => {
186873
+ try {
186874
+ await ensureAuth6();
186875
+ const spinner = ora("Fetching model status...").start();
186876
+ try {
186877
+ const response = await restClient.get("/api/models/status");
186878
+ spinner.succeed("Model status retrieved");
186879
+ if (options.json) {
186880
+ console.log(JSON.stringify(response.data, null, 2));
186881
+ return;
186882
+ }
186883
+ const data = response.data;
186884
+ console.log();
186885
+ console.log(source_default.bold("Model Status"));
186886
+ const table = new import_cli_table34.default({
186887
+ head: [
186888
+ source_default.bold("Family"),
186889
+ source_default.bold("Global"),
186890
+ source_default.bold("Tenant"),
186891
+ source_default.bold("Policy"),
186892
+ source_default.bold("Status")
186893
+ ],
186894
+ style: { head: [], border: [] },
186895
+ chars: {
186896
+ top: "\u2500",
186897
+ "top-mid": "\u252C",
186898
+ "top-left": "\u250C",
186899
+ "top-right": "\u2510",
186900
+ bottom: "\u2500",
186901
+ "bottom-mid": "\u2534",
186902
+ "bottom-left": "\u2514",
186903
+ "bottom-right": "\u2518",
186904
+ left: "\u2502",
186905
+ "left-mid": "\u251C",
186906
+ mid: "\u2500",
186907
+ "mid-mid": "\u253C",
186908
+ right: "\u2502",
186909
+ "right-mid": "\u2524",
186910
+ middle: "\u2502"
186911
+ }
186912
+ });
186913
+ for (const model of data.models) {
186914
+ table.push([
186915
+ model.family,
186916
+ model.global_version,
186917
+ model.tenant_version,
186918
+ model.update_policy,
186919
+ renderModelStatus(model)
186920
+ ]);
186921
+ }
186922
+ console.log(table.toString());
186923
+ console.log();
186924
+ console.log(`Metrics contribution: ${data.contribute_metrics ? source_default.green("Enabled") : source_default.dim("Disabled")}`);
186925
+ if (data.consent_timestamp) {
186926
+ console.log(`Consent timestamp: ${source_default.dim(new Date(data.consent_timestamp).toLocaleString())}`);
186927
+ }
186928
+ console.log();
186929
+ } catch (error) {
186930
+ spinner.fail("Failed to fetch model status");
186931
+ console.error(source_default.red(error.message));
186932
+ process.exit(1);
186933
+ }
186934
+ } catch (error) {
186935
+ console.error(source_default.red("Error:"), error.message);
186936
+ process.exit(1);
186937
+ }
186938
+ });
186939
+ modelsCommand.command("update").description("Update model families to the latest stable versions").option("--family <name>", "Update specific model family (prioritizer, anomaly)").option("--json", "Output as JSON").action(async (options) => {
186940
+ try {
186941
+ await ensureAuth6();
186942
+ const spinner = ora("Updating models...").start();
186943
+ try {
186944
+ const body = {};
186945
+ if (options.family) {
186946
+ body.family = options.family;
186947
+ }
186948
+ const response = await restClient.post("/api/models/update", body);
186949
+ spinner.succeed("Models checked");
186950
+ if (options.json) {
186951
+ console.log(JSON.stringify(response.data, null, 2));
186952
+ return;
186953
+ }
186954
+ const data = response.data;
186955
+ console.log();
186956
+ if (!data.updated || data.updates.length === 0) {
186957
+ console.log(source_default.green("\u2713 All models are up to date"));
186958
+ console.log();
186959
+ return;
186960
+ }
186961
+ console.log(source_default.bold("Updated Models"));
186962
+ for (const update of data.updates) {
186963
+ console.log(` ${source_default.cyan(update.family)}: ${source_default.dim(update.from_version)} -> ${source_default.green(update.to_version)}`);
186964
+ }
186965
+ console.log();
186966
+ } catch (error) {
186967
+ spinner.fail("Failed to update models");
186968
+ console.error(source_default.red(error.message));
186969
+ process.exit(1);
186970
+ }
186971
+ } catch (error) {
186972
+ console.error(source_default.red("Error:"), error.message);
186973
+ process.exit(1);
186974
+ }
186975
+ });
186976
+ modelsCommand.command("pin").description("Pin a model family to a specific version").argument("<family>", "Model family to pin (prioritizer, anomaly)").argument("<version>", "Version to pin (e.g. 1.0.0)").option("--json", "Output as JSON").action(async (family, version2, options) => {
186977
+ try {
186978
+ await ensureAuth6();
186979
+ const spinner = ora(`Pinning ${family} to ${version2}...`).start();
186980
+ try {
186981
+ const response = await restClient.post("/api/models/pin", {
186982
+ family,
186983
+ version: version2
186984
+ });
186985
+ spinner.succeed("Model pinned");
186986
+ if (options.json) {
186987
+ console.log(JSON.stringify(response.data, null, 2));
186988
+ return;
186989
+ }
186990
+ console.log();
186991
+ console.log(source_default.green(`\u2713 ${family} pinned to ${version2}`));
186992
+ if (response.data.message) {
186993
+ console.log(source_default.dim(` ${response.data.message}`));
186994
+ }
186995
+ console.log();
186996
+ } catch (error) {
186997
+ spinner.fail("Failed to pin model");
186998
+ console.error(source_default.red(error.message));
186999
+ process.exit(1);
187000
+ }
187001
+ } catch (error) {
187002
+ console.error(source_default.red("Error:"), error.message);
187003
+ process.exit(1);
187004
+ }
187005
+ });
186851
187006
  modelsCommand.command("contribute").description("Enable or disable metrics contribution").option("--enable", "Enable metrics contribution").option("--disable", "Disable metrics contribution").option("--json", "Output as JSON").action(async (options) => {
186852
187007
  try {
186853
187008
  await ensureAuth6();
@@ -186892,9 +187047,7 @@ modelsCommand.command("contribute").description("Enable or disable metrics contr
186892
187047
  }
186893
187048
  const spinner = ora("Enabling metrics contribution...").start();
186894
187049
  try {
186895
- const response = await restClient.post("/api/models/consent", {
186896
- consent: true
186897
- });
187050
+ const response = await restClient.post("/api/models/consent", {});
186898
187051
  spinner.succeed("Metrics contribution enabled");
186899
187052
  if (options.json) {
186900
187053
  console.log(JSON.stringify(response.data, null, 2));
@@ -186902,6 +187055,9 @@ modelsCommand.command("contribute").description("Enable or disable metrics contr
186902
187055
  }
186903
187056
  console.log();
186904
187057
  console.log(source_default.green("\u2713 Thank you for contributing to Rivora!"));
187058
+ if (response.data?.consent_timestamp) {
187059
+ console.log(source_default.dim(` Consent recorded: ${new Date(response.data.consent_timestamp).toLocaleString()}`));
187060
+ }
186905
187061
  console.log(source_default.dim(" Preview what's shared: rivora models metrics-preview"));
186906
187062
  console.log();
186907
187063
  } catch (error) {
@@ -186920,8 +187076,8 @@ modelsCommand.command("contribute").description("Enable or disable metrics contr
186920
187076
  }
186921
187077
  console.log();
186922
187078
  console.log(source_default.green("\u2713 Metrics contribution disabled"));
186923
- if (response.data.data_deleted) {
186924
- console.log(source_default.dim(" Previously shared data has been deleted."));
187079
+ if (response.data?.metrics_deleted) {
187080
+ console.log(source_default.dim(` Deleted ${response.data.deleted_count} metrics file(s).`));
186925
187081
  }
186926
187082
  console.log();
186927
187083
  } catch (error) {
@@ -186947,11 +187103,16 @@ modelsCommand.command("metrics-preview").description("Preview metrics that would
186947
187103
  return;
186948
187104
  }
186949
187105
  const data = response.data;
187106
+ const rows = data.rule_stats ?? data.rules ?? [];
187107
+ const periodStart = data.period_start ?? data.date_range?.start;
187108
+ const periodEnd = data.period_end ?? data.date_range?.end;
186950
187109
  console.log();
186951
187110
  console.log(source_default.bold("Metrics Preview"));
186952
- console.log(source_default.dim(`Date range: ${data.date_range.start} to ${data.date_range.end}`));
187111
+ if (periodStart && periodEnd) {
187112
+ console.log(source_default.dim(`Date range: ${periodStart} to ${periodEnd}`));
187113
+ }
186953
187114
  console.log();
186954
- if (data.rules.length === 0) {
187115
+ if (rows.length === 0) {
186955
187116
  console.log(source_default.dim("No metrics available yet."));
186956
187117
  console.log(source_default.dim("Metrics are collected after running scans and reviewing findings."));
186957
187118
  console.log();
@@ -186960,9 +187121,9 @@ modelsCommand.command("metrics-preview").description("Preview metrics that would
186960
187121
  const table = new import_cli_table34.default({
186961
187122
  head: [
186962
187123
  source_default.bold("Rule ID"),
186963
- source_default.bold("Invocations"),
186964
- source_default.bold("True Positives"),
186965
- source_default.bold("False Positives")
187124
+ source_default.bold("Triggers"),
187125
+ source_default.bold("Severity"),
187126
+ source_default.bold("Avg Priority")
186966
187127
  ],
186967
187128
  style: { head: [], border: [] },
186968
187129
  chars: {
@@ -186983,20 +187144,25 @@ modelsCommand.command("metrics-preview").description("Preview metrics that would
186983
187144
  middle: "\u2502"
186984
187145
  }
186985
187146
  });
186986
- for (const rule of data.rules) {
187147
+ for (const row of rows) {
187148
+ const triggerCount = row.trigger_count ?? row.invocations ?? 0;
187149
+ const severity = row.severity_distribution ? Object.entries(row.severity_distribution).map(([key, value]) => `${key}:${value}`).join(", ") : "-";
187150
+ const avgPriority = row.avg_priority_score == null ? "-" : row.avg_priority_score.toFixed(3);
186987
187151
  table.push([
186988
- rule.rule_id,
186989
- rule.invocations.toString(),
186990
- source_default.green(rule.true_positives.toString()),
186991
- source_default.red(rule.false_positives.toString())
187152
+ row.rule_id,
187153
+ triggerCount.toString(),
187154
+ severity,
187155
+ avgPriority
186992
187156
  ]);
186993
187157
  }
186994
187158
  console.log(table.toString());
186995
187159
  console.log();
186996
187160
  console.log(`Total findings: ${source_default.bold(data.total_findings)}`);
186997
187161
  console.log();
186998
- console.log(source_default.dim("This data helps improve model accuracy for all users."));
186999
- console.log(source_default.dim("Enable contribution: rivora models contribute --enable"));
187162
+ if (data.would_share !== undefined) {
187163
+ console.log(`Would share now: ${data.would_share ? source_default.green("Yes") : source_default.yellow("No")}`);
187164
+ console.log();
187165
+ }
187000
187166
  console.log();
187001
187167
  } catch (error) {
187002
187168
  spinner.fail("Failed to fetch metrics preview");
@@ -187699,7 +187865,7 @@ async function manageConfig(options) {
187699
187865
  }
187700
187866
  }
187701
187867
  var argocdCommand = createArgocdCommand();
187702
- var version2 = "0.0.2";
187868
+ var version2 = "0.1.3";
187703
187869
  var rcaCommand = new Command2("rca").description("Root cause analysis (5 Whys)");
187704
187870
  function displayRCAReport(report) {
187705
187871
  console.log();
@@ -187839,8 +188005,682 @@ rcaCommand.command("feedback").description("Accept or reject an RCA root cause")
187839
188005
  process.exit(1);
187840
188006
  }
187841
188007
  });
188008
+ function extractOptimizationService(ruleId) {
188009
+ if (!ruleId)
188010
+ return "unknown";
188011
+ const parts = ruleId.split("-");
188012
+ if (parts.length >= 3 && parts[0] === "opt")
188013
+ return parts[1];
188014
+ return "unknown";
188015
+ }
188016
+ async function resolveOptimizationFindingId(token, idOrRuleId) {
188017
+ if (!idOrRuleId.startsWith("opt-")) {
188018
+ return idOrRuleId;
188019
+ }
188020
+ const response = await restClient.get("/findings?category=optimization", { headers: { Authorization: `Bearer ${token}` } });
188021
+ const match = (response.data || []).find((f) => f.rule_id === idOrRuleId);
188022
+ if (!match) {
188023
+ throw new Error(`No open optimization finding found for rule ${idOrRuleId}`);
188024
+ }
188025
+ return match.id;
188026
+ }
188027
+ var optimizeCommand = new Command2("optimize").description("Configuration optimization recommendations");
188028
+ optimizeCommand.command("aws").description("List optimization recommendations for AWS resources").option("--impact <level>", "Filter by impact (high, medium, low)").option("--service <service>", "Filter by service (eks, s3, ec2, ecs, iam)").option("--json", "Output as JSON").action(async (options) => {
188029
+ try {
188030
+ const token = await ensureAuthDrift();
188031
+ const spinner = ora("Fetching optimization recommendations...").start();
188032
+ try {
188033
+ const params = new URLSearchParams;
188034
+ params.set("category", "optimization");
188035
+ if (options.impact)
188036
+ params.set("severity", options.impact.toLowerCase());
188037
+ const summaryParams = new URLSearchParams;
188038
+ summaryParams.set("notify", "true");
188039
+ if (options.service)
188040
+ summaryParams.set("service", options.service.toLowerCase());
188041
+ const findingsResponse = await restClient.get(`/findings?${params.toString()}`, { headers: { Authorization: `Bearer ${token}` } });
188042
+ try {
188043
+ await restClient.get(`/findings/optimize/summary?${summaryParams.toString()}`, { headers: { Authorization: `Bearer ${token}` } });
188044
+ } catch (_err) {}
188045
+ const allFindings = findingsResponse.data || [];
188046
+ const serviceFilter = options.service ? options.service.toLowerCase() : null;
188047
+ const findings = allFindings.filter((f) => {
188048
+ const service = extractOptimizationService(f.rule_id);
188049
+ return !serviceFilter || service === serviceFilter;
188050
+ });
188051
+ spinner.succeed(`Found ${findings.length} recommendation(s)`);
188052
+ if (options.json) {
188053
+ console.log(JSON.stringify(findings, null, 2));
188054
+ return;
188055
+ }
188056
+ if (findings.length === 0) {
188057
+ console.log();
188058
+ console.log(source_default.green("\u2713 No optimization recommendations match your filters"));
188059
+ console.log();
188060
+ return;
188061
+ }
188062
+ console.log();
188063
+ console.log(source_default.bold("\u26A1 Configuration Optimization \u2014 AWS"));
188064
+ console.log();
188065
+ const table = new Table3({
188066
+ head: [
188067
+ source_default.bold("ID"),
188068
+ source_default.bold("Recommendation"),
188069
+ source_default.bold("Impact"),
188070
+ source_default.bold("Resource")
188071
+ ],
188072
+ style: { head: [], border: [] }
188073
+ });
188074
+ let high = 0;
188075
+ let medium = 0;
188076
+ let low = 0;
188077
+ for (const finding of findings) {
188078
+ const sev = (finding.severity || "").toLowerCase();
188079
+ if (sev === "high" || sev === "critical")
188080
+ high++;
188081
+ else if (sev === "medium")
188082
+ medium++;
188083
+ else
188084
+ low++;
188085
+ table.push([
188086
+ finding.id,
188087
+ `${finding.title} (${finding.rule_id})`,
188088
+ sev.toUpperCase(),
188089
+ finding.resource_id || "n/a"
188090
+ ]);
188091
+ }
188092
+ console.log(table.toString());
188093
+ console.log();
188094
+ console.log(`${findings.length} recommendations (${high} High, ${medium} Medium, ${low} Low)`);
188095
+ console.log(source_default.dim("Run `rivora optimize get <id>` for details or `rivora optimize plan <id>` for remediation steps."));
188096
+ console.log();
188097
+ } catch (error) {
188098
+ spinner.fail("Failed to fetch optimization recommendations");
188099
+ console.error(source_default.red(error.message));
188100
+ process.exit(1);
188101
+ }
188102
+ } catch (error) {
188103
+ if (error instanceof Error) {
188104
+ console.error(source_default.red("Error:"), error.message);
188105
+ }
188106
+ process.exit(1);
188107
+ }
188108
+ });
188109
+ optimizeCommand.command("get").description("Get optimization recommendation details").argument("<id>", "Finding ID").option("--json", "Output as JSON").action(async (id, options) => {
188110
+ try {
188111
+ const token = await ensureAuthDrift();
188112
+ const findingId = await resolveOptimizationFindingId(token, id);
188113
+ const spinner = ora("Fetching recommendation details...").start();
188114
+ try {
188115
+ const response = await restClient.get(`/findings/${findingId}`, { headers: { Authorization: `Bearer ${token}` } });
188116
+ spinner.succeed("Recommendation loaded");
188117
+ if (options.json) {
188118
+ console.log(JSON.stringify(response.data, null, 2));
188119
+ return;
188120
+ }
188121
+ const finding = response.data;
188122
+ console.log();
188123
+ console.log(source_default.bold(`\u26A1 ${finding.title}`));
188124
+ console.log(source_default.dim(`ID: ${finding.id}`));
188125
+ console.log(source_default.dim(`Rule: ${finding.rule_id}`));
188126
+ console.log(source_default.dim(`Impact: ${(finding.severity || "").toUpperCase()}`));
188127
+ console.log(source_default.dim(`Resource: ${finding.resource_type || "unknown"}/${finding.resource_id || "unknown"}`));
188128
+ console.log();
188129
+ console.log(finding.description);
188130
+ if (finding.recommendation) {
188131
+ console.log();
188132
+ console.log(source_default.bold("Recommendation"));
188133
+ console.log(finding.recommendation);
188134
+ }
188135
+ console.log();
188136
+ } catch (error) {
188137
+ spinner.fail("Failed to fetch recommendation");
188138
+ console.error(source_default.red(error.message));
188139
+ process.exit(1);
188140
+ }
188141
+ } catch (error) {
188142
+ if (error instanceof Error) {
188143
+ console.error(source_default.red("Error:"), error.message);
188144
+ }
188145
+ process.exit(1);
188146
+ }
188147
+ });
188148
+ optimizeCommand.command("plan").description("Generate remediation plan for an optimization recommendation").argument("<id>", "Finding ID").option("--format <format>", "Output format (cli, terraform, json)", "cli").option("--json", "Output as JSON").action(async (id, options) => {
188149
+ try {
188150
+ const token = await ensureAuthDrift();
188151
+ const findingId = await resolveOptimizationFindingId(token, id);
188152
+ const spinner = ora("Generating optimization plan...").start();
188153
+ try {
188154
+ const response = await restClient.post(`/findings/${findingId}/plan`, { format: options.format }, { headers: { Authorization: `Bearer ${token}` } });
188155
+ spinner.succeed("Plan generated");
188156
+ if (options.json) {
188157
+ console.log(JSON.stringify(response.data, null, 2));
188158
+ return;
188159
+ }
188160
+ const plan = response.data;
188161
+ console.log();
188162
+ console.log(source_default.bold(`Plan ${plan.id}`));
188163
+ console.log(source_default.dim(`Finding: ${plan.finding_id}`));
188164
+ console.log();
188165
+ if (plan.steps && plan.steps.length > 0) {
188166
+ for (const [idx, step] of plan.steps.entries()) {
188167
+ console.log(`${idx + 1}. ${step}`);
188168
+ }
188169
+ } else {
188170
+ console.log(source_default.dim("No plan steps returned."));
188171
+ }
188172
+ console.log();
188173
+ } catch (error) {
188174
+ spinner.fail("Failed to generate plan");
188175
+ console.error(source_default.red(error.message));
188176
+ process.exit(1);
188177
+ }
188178
+ } catch (error) {
188179
+ if (error instanceof Error) {
188180
+ console.error(source_default.red("Error:"), error.message);
188181
+ }
188182
+ process.exit(1);
188183
+ }
188184
+ });
188185
+ optimizeCommand.command("dismiss").description("Dismiss an optimization recommendation").argument("<id>", "Finding ID").requiredOption("--reason <reason>", "Reason for dismissing").action(async (id, options) => {
188186
+ try {
188187
+ const token = await ensureAuthDrift();
188188
+ const findingId = await resolveOptimizationFindingId(token, id);
188189
+ const spinner = ora("Dismissing recommendation...").start();
188190
+ try {
188191
+ await restClient.post(`/findings/${findingId}/status?status=ignored`, {}, { headers: { Authorization: `Bearer ${token}` } });
188192
+ spinner.succeed("Recommendation dismissed");
188193
+ console.log(source_default.dim(`Reason: ${options.reason}`));
188194
+ } catch (error) {
188195
+ spinner.fail("Failed to dismiss recommendation");
188196
+ console.error(source_default.red(error.message));
188197
+ process.exit(1);
188198
+ }
188199
+ } catch (error) {
188200
+ if (error instanceof Error) {
188201
+ console.error(source_default.red("Error:"), error.message);
188202
+ }
188203
+ process.exit(1);
188204
+ }
188205
+ });
188206
+ var ConnectedProvider = /* @__PURE__ */ (() => {
188207
+ return function ConnectedProvider(name, type, connected) {
188208
+ this.name = name;
188209
+ this.type = type;
188210
+ this.connected = connected;
188211
+ };
188212
+ })();
188213
+ var AgentMessage = /* @__PURE__ */ (() => {
188214
+ return function AgentMessage(role, content, name) {
188215
+ this.role = role;
188216
+ this.content = content;
188217
+ if (name !== undefined) {
188218
+ this.name = name;
188219
+ }
188220
+ };
188221
+ })();
188222
+ var AgentSession = /* @__PURE__ */ (() => {
188223
+ function AgentSession2() {
188224
+ this.messages = [];
188225
+ this.recentFindings = [];
188226
+ this.connectedProviders = [];
188227
+ this.loadConnectedProviders();
188228
+ }
188229
+ AgentSession2.prototype.loadConnectedProviders = function() {
188230
+ var providers = [];
188231
+ var config = configManager.getConfig();
188232
+ if (config.cloud && config.cloud.aws) {
188233
+ providers.push(new ConnectedProvider("AWS", "aws", true));
188234
+ }
188235
+ if (config.cloud && config.cloud.k8s) {
188236
+ providers.push(new ConnectedProvider("Kubernetes", "k8s", true));
188237
+ }
188238
+ if (config.cloud && config.cloud.slack) {
188239
+ providers.push(new ConnectedProvider("Slack", "slack", configManager.isSlackConnected()));
188240
+ }
188241
+ if (config.cloud && config.cloud.linear) {
188242
+ providers.push(new ConnectedProvider("Linear", "linear", configManager.isLinearConnected()));
188243
+ }
188244
+ if (config.cloud && config.cloud.github) {
188245
+ providers.push(new ConnectedProvider("GitHub", "github", configManager.isGitHubConnected()));
188246
+ }
188247
+ if (config.cloud && config.cloud.agent) {
188248
+ providers.push(new ConnectedProvider("Agent", "agent", configManager.isAgentDeployed()));
188249
+ }
188250
+ this.connectedProviders = providers;
188251
+ };
188252
+ AgentSession2.prototype.addMessage = function(role, content, name) {
188253
+ var message2 = new AgentMessage(role, content);
188254
+ if (name !== undefined) {
188255
+ message2.name = name;
188256
+ }
188257
+ this.messages.push(message2);
188258
+ };
188259
+ AgentSession2.prototype.getMessages = function() {
188260
+ return this.messages.slice(0);
188261
+ };
188262
+ AgentSession2.prototype.truncate = function(maxMessages) {
188263
+ var systemMessages = this.messages.filter(function(m) {
188264
+ return m.role === "system";
188265
+ });
188266
+ var nonSystemMessages = this.messages.filter(function(m) {
188267
+ return m.role !== "system";
188268
+ });
188269
+ var keepCount = Math.min(maxMessages - systemMessages.length, nonSystemMessages.length);
188270
+ var recentNonSystem = nonSystemMessages.slice(-keepCount);
188271
+ this.messages = systemMessages.concat(recentNonSystem);
188272
+ };
188273
+ AgentSession2.prototype.reset = function() {
188274
+ this.messages = [];
188275
+ this.recentFindings = [];
188276
+ this.loadConnectedProviders();
188277
+ };
188278
+ AgentSession2.prototype.addFinding = function(findingId) {
188279
+ if (!this.recentFindings.includes(findingId)) {
188280
+ this.recentFindings.push(findingId);
188281
+ }
188282
+ };
188283
+ AgentSession2.prototype.getRecentFindings = function() {
188284
+ return this.recentFindings.slice(0);
188285
+ };
188286
+ AgentSession2.prototype.getConnectedProviders = function() {
188287
+ return this.connectedProviders.slice(0);
188288
+ };
188289
+ AgentSession2.prototype.getSystemPrompt = function() {
188290
+ var connectedList = this.connectedProviders.filter(function(p) {
188291
+ return p.connected;
188292
+ }).map(function(p) {
188293
+ return p.name;
188294
+ }).join(", ");
188295
+ var findingsContext = this.recentFindings.length > 0 ? `
188296
+
188297
+ Recent finding IDs in session: ` + this.recentFindings.join(", ") : "";
188298
+ return `You are Rivora, an AI assistant that helps manage cloud security and infrastructure.
188299
+
188300
+ Connected providers: ` + (connectedList || "None") + findingsContext;
188301
+ };
188302
+ return AgentSession2;
188303
+ })();
188304
+ var AgentRenderer = /* @__PURE__ */ (() => {
188305
+ function AgentRenderer2() {
188306
+ this.spinner = null;
188307
+ }
188308
+ AgentRenderer2.prototype.renderResponse = function(result) {
188309
+ switch (result.status) {
188310
+ case "completed":
188311
+ this.renderCompleted(result.message || "", result.iterations);
188312
+ break;
188313
+ case "approval_required":
188314
+ this.renderApprovalRequired(result.pending_tool, result.message || "");
188315
+ break;
188316
+ case "failed":
188317
+ this.renderError(result.message || "Unknown error", result.iterations);
188318
+ break;
188319
+ case "message":
188320
+ if (result.message) {
188321
+ console.log(result.message);
188322
+ }
188323
+ break;
188324
+ }
188325
+ };
188326
+ AgentRenderer2.prototype.renderCompleted = function(message2, iterations) {
188327
+ console.log();
188328
+ console.log(source_default.bold.green("\u2713 Agent Completed"));
188329
+ console.log(source_default.dim("\u2500".repeat(60)));
188330
+ console.log();
188331
+ console.log(message2);
188332
+ console.log();
188333
+ if (iterations !== undefined) {
188334
+ console.log(source_default.dim("Iterations: " + iterations));
188335
+ }
188336
+ };
188337
+ AgentRenderer2.prototype.renderApprovalRequired = function(pendingTool, message2) {
188338
+ console.log();
188339
+ console.log(source_default.bold.yellow("\u26A0\uFE0F Approval Required"));
188340
+ console.log(source_default.dim("\u2500".repeat(60)));
188341
+ console.log();
188342
+ console.log(source_default.bold("Skill:") + " " + pendingTool.skill);
188343
+ console.log(source_default.bold("Risk Level:") + " " + this.getRiskColor(pendingTool.risk));
188344
+ console.log(source_default.bold("Call ID:") + " " + source_default.cyan(pendingTool.call_id));
188345
+ console.log();
188346
+ console.log(source_default.bold("Arguments:"));
188347
+ var __loop = function(key2) {
188348
+ console.log(" " + source_default.dim(key2) + ": " + JSON.stringify(pendingTool.args[key2]));
188349
+ };
188350
+ for (var key in pendingTool.args) {
188351
+ __loop(key);
188352
+ }
188353
+ console.log();
188354
+ if (message2) {
188355
+ console.log(source_default.bold("Message:"));
188356
+ console.log(" " + message2);
188357
+ console.log();
188358
+ }
188359
+ console.log(source_default.dim("\u2500".repeat(60)));
188360
+ console.log(source_default.yellow("To approve this action, use the approval endpoint"));
188361
+ console.log();
188362
+ };
188363
+ AgentRenderer2.prototype.renderError = function(message2, iterations) {
188364
+ console.log();
188365
+ console.log(source_default.bold.red("\u2717 Agent Failed"));
188366
+ console.log(source_default.dim("\u2500".repeat(60)));
188367
+ console.log();
188368
+ console.log(source_default.red(message2));
188369
+ console.log();
188370
+ if (iterations !== undefined) {
188371
+ console.log(source_default.dim("Iterations: " + iterations));
188372
+ }
188373
+ };
188374
+ AgentRenderer2.prototype.getRiskColor = function(risk) {
188375
+ switch (risk) {
188376
+ case "low":
188377
+ return source_default.blue("LOW");
188378
+ case "medium":
188379
+ return source_default.yellow("MEDIUM");
188380
+ case "high":
188381
+ return source_default.red.bold("HIGH");
188382
+ default:
188383
+ return risk;
188384
+ }
188385
+ };
188386
+ return AgentRenderer2;
188387
+ })();
188388
+ var AVAILABLE_PRESETS = ["security-sweep", "reliability-audit", "drift-detection"];
188389
+ var AgentREPL = /* @__PURE__ */ (() => {
188390
+ function AgentREPL2(session, renderer) {
188391
+ this.rl = null;
188392
+ this.spinner = null;
188393
+ this.running = false;
188394
+ this.session = session;
188395
+ this.renderer = renderer;
188396
+ }
188397
+ AgentREPL2.prototype.start = async function() {
188398
+ await this.ensureAuthenticated();
188399
+ this.running = true;
188400
+ console.log();
188401
+ console.log(source_default.bold.cyan("\uD83E\uDD16 Rivora Agent REPL"));
188402
+ console.log(source_default.dim("\u2500".repeat(60)));
188403
+ console.log();
188404
+ console.log(source_default.dim("Type /help for available commands"));
188405
+ console.log();
188406
+ var rl = readline.createInterface({
188407
+ input: process.stdin,
188408
+ output: process.stdout
188409
+ });
188410
+ this.rl = rl;
188411
+ await this.replLoop();
188412
+ };
188413
+ AgentREPL2.prototype.replLoop = async function() {
188414
+ while (this.running) {
188415
+ try {
188416
+ var input = await this.prompt();
188417
+ if (!input) {
188418
+ continue;
188419
+ }
188420
+ var trimmed = input.trim();
188421
+ if (this.isExitCommand(trimmed)) {
188422
+ this.exit();
188423
+ break;
188424
+ }
188425
+ if (trimmed.startsWith("/")) {
188426
+ await this.handleCommand(trimmed);
188427
+ } else {
188428
+ await this.runOneShot(trimmed);
188429
+ }
188430
+ } catch (error) {
188431
+ if (error.message === "EXIT") {
188432
+ this.exit();
188433
+ break;
188434
+ }
188435
+ console.error(source_default.red("Error: " + error.message));
188436
+ }
188437
+ }
188438
+ };
188439
+ AgentREPL2.prototype.prompt = function() {
188440
+ var self2 = this;
188441
+ return new Promise(function(resolve2) {
188442
+ self2.rl.question("rivora> ", function(answer) {
188443
+ resolve2(answer);
188444
+ });
188445
+ });
188446
+ };
188447
+ AgentREPL2.prototype.isExitCommand = function(input) {
188448
+ var cmd = input.toLowerCase();
188449
+ return cmd === "/exit" || cmd === "/quit";
188450
+ };
188451
+ AgentREPL2.prototype.exit = function() {
188452
+ this.running = false;
188453
+ console.log(source_default.dim(`
188454
+ Goodbye!`));
188455
+ if (this.rl) {
188456
+ this.rl.close();
188457
+ }
188458
+ process.exit(0);
188459
+ };
188460
+ AgentREPL2.prototype.handleCommand = async function(input) {
188461
+ var parts = input.split(/\s+/);
188462
+ var command = (parts[0] || "").toLowerCase();
188463
+ var args = parts.slice(1).join(" ");
188464
+ switch (command) {
188465
+ case "/help":
188466
+ this.showHelp();
188467
+ break;
188468
+ case "/preset":
188469
+ if (!args) {
188470
+ console.log(source_default.yellow("Usage: /preset <name>"));
188471
+ console.log(source_default.dim("Available presets: " + AVAILABLE_PRESETS.join(", ")));
188472
+ } else {
188473
+ await this.runPreset(args);
188474
+ }
188475
+ break;
188476
+ case "/clear":
188477
+ this.session.reset();
188478
+ console.log(source_default.green("Session cleared"));
188479
+ break;
188480
+ case "/exit":
188481
+ case "/quit":
188482
+ this.exit();
188483
+ break;
188484
+ default:
188485
+ console.log(source_default.yellow("Unknown command: " + command));
188486
+ console.log(source_default.dim("Type /help for available commands"));
188487
+ }
188488
+ };
188489
+ AgentREPL2.prototype.showHelp = function() {
188490
+ console.log();
188491
+ console.log(source_default.bold("Available Commands:"));
188492
+ console.log(source_default.dim("\u2500".repeat(40)));
188493
+ console.log(" " + source_default.cyan("/help") + " Show this help message");
188494
+ console.log(" " + source_default.cyan("/preset <name>") + " Run a preset (" + AVAILABLE_PRESETS.join(", ") + ")");
188495
+ console.log(" " + source_default.cyan("/clear") + " Clear the session");
188496
+ console.log(" " + source_default.cyan("/exit") + " Exit the REPL");
188497
+ console.log(" " + source_default.cyan("/quit") + " Exit the REPL");
188498
+ console.log();
188499
+ };
188500
+ AgentREPL2.prototype.runOneShot = async function(query) {
188501
+ await this.ensureAuthenticated();
188502
+ var spinner = ora("Thinking...").start();
188503
+ try {
188504
+ var result = await this.sendMessage(query);
188505
+ spinner.stop();
188506
+ await this.handleAgentResponse(result);
188507
+ } catch (error) {
188508
+ spinner.fail("Request failed");
188509
+ throw error;
188510
+ }
188511
+ };
188512
+ AgentREPL2.prototype.runPreset = async function(presetName) {
188513
+ await this.ensureAuthenticated();
188514
+ if (!AVAILABLE_PRESETS.includes(presetName)) {
188515
+ console.log(source_default.yellow("Unknown preset: " + presetName));
188516
+ console.log(source_default.dim("Available presets: " + AVAILABLE_PRESETS.join(", ")));
188517
+ return;
188518
+ }
188519
+ var spinner = ora("Running preset: " + presetName + "...").start();
188520
+ try {
188521
+ var result = await restClient.sendAgentMessage({
188522
+ message: "Run the " + presetName + " preset",
188523
+ preset: presetName,
188524
+ messages: [{ role: "system", content: this.session.getSystemPrompt() }]
188525
+ });
188526
+ spinner.stop();
188527
+ await this.handleAgentResponse(result);
188528
+ } catch (error) {
188529
+ spinner.fail("Preset execution failed");
188530
+ throw error;
188531
+ }
188532
+ };
188533
+ AgentREPL2.prototype.sendMessage = async function(message2, approvals) {
188534
+ var messages = this.session.getMessages();
188535
+ if (messages.length === 0) {
188536
+ this.session.addMessage("system", this.session.getSystemPrompt());
188537
+ }
188538
+ this.session.addMessage("user", message2);
188539
+ var result = await restClient.sendAgentMessage({
188540
+ message: message2,
188541
+ messages: this.session.getMessages(),
188542
+ approvals
188543
+ });
188544
+ if (result.messages) {
188545
+ var __loop2 = function(msg) {
188546
+ if (msg.role !== "user" && msg.role !== "system") {
188547
+ this2.session.addMessage(msg.role, msg.content, msg.name);
188548
+ }
188549
+ };
188550
+ var this2 = this;
188551
+ for (var __i2 = 0;__i2 < result.messages.length; __i2++) {
188552
+ __loop2(result.messages[__i2]);
188553
+ }
188554
+ }
188555
+ return result;
188556
+ };
188557
+ AgentREPL2.prototype.handleAgentResponse = async function(result) {
188558
+ switch (result.status) {
188559
+ case "completed":
188560
+ this.renderer.renderCompleted(result.message, result.iterations);
188561
+ break;
188562
+ case "approval_required":
188563
+ await this.handleApprovalRequired(result.pending_tool, result.message);
188564
+ break;
188565
+ case "failed":
188566
+ this.renderer.renderError(result.message, result.iterations);
188567
+ break;
188568
+ default:
188569
+ if (result.message) {
188570
+ console.log(result.message);
188571
+ }
188572
+ }
188573
+ };
188574
+ AgentREPL2.prototype.handleApprovalRequired = async function(pendingTool, message2) {
188575
+ this.renderer.renderApprovalRequired(pendingTool, message2);
188576
+ var approvalRetries = 0;
188577
+ var maxRetries = 3;
188578
+ while (approvalRetries < maxRetries) {
188579
+ var approved = await this.promptApproval(pendingTool);
188580
+ var spinner = ora("Submitting " + (approved ? "approval" : "denial") + "...").start();
188581
+ try {
188582
+ var result = await this.sendMessage("", [
188583
+ { call_id: pendingTool.call_id, approved }
188584
+ ]);
188585
+ spinner.stop();
188586
+ if (result.status === "completed") {
188587
+ this.renderer.renderCompleted(result.message, result.iterations);
188588
+ return;
188589
+ } else if (result.status === "approval_required") {
188590
+ approvalRetries++;
188591
+ if (approvalRetries >= maxRetries) {
188592
+ console.log(source_default.yellow("Max approval retries reached"));
188593
+ return;
188594
+ }
188595
+ await this.handleApprovalRequired(result.pending_tool, result.message);
188596
+ return;
188597
+ } else if (result.status === "failed") {
188598
+ this.renderer.renderError(result.message, result.iterations);
188599
+ return;
188600
+ }
188601
+ } catch (error) {
188602
+ spinner.fail("Failed to submit approval");
188603
+ throw error;
188604
+ }
188605
+ }
188606
+ };
188607
+ AgentREPL2.prototype.promptApproval = function(pendingTool) {
188608
+ var self2 = this;
188609
+ return new Promise(function(resolve2) {
188610
+ var riskColor = pendingTool.risk === "high" ? source_default.red : pendingTool.risk === "medium" ? source_default.yellow : source_default.blue;
188611
+ process.stdout.write(source_default.bold("Skill:") + " " + pendingTool.skill + " " + source_default.dim("|") + " " + source_default.bold("Risk:") + riskColor(pendingTool.risk.toUpperCase()) + `
188612
+ `);
188613
+ process.stdout.write(source_default.bold("Approve? (y/n) "));
188614
+ self2.rl.question("", function(answer) {
188615
+ var trimmed = answer.trim().toLowerCase();
188616
+ if (trimmed === "y" || trimmed === "yes") {
188617
+ resolve2(true);
188618
+ } else {
188619
+ resolve2(false);
188620
+ }
188621
+ });
188622
+ });
188623
+ };
188624
+ AgentREPL2.prototype.ensureAuthenticated = async function() {
188625
+ var isAuth = await authService.isAuthenticated();
188626
+ if (!isAuth) {
188627
+ console.log(source_default.yellow("\u26A0\uFE0F Authentication required"));
188628
+ console.log(source_default.dim(" Run: rivora auth login"));
188629
+ throw new Error("EXIT");
188630
+ }
188631
+ };
188632
+ return AgentREPL2;
188633
+ })();
188634
+ var VALID_PRESETS = ["security-sweep", "reliability-audit", "drift-detection"];
188635
+ var VALID_MODELS = ["qwen3-30b", "glm-flash", "llama-70b"];
188636
+ var agentCommand = new Command2("agent").description("Start an interactive AI agent or run a query/preset").argument("[query]", "One-shot query to run").option("-p, --preset <name>", `Run a preset (${VALID_PRESETS.join(", ")})`).option("-m, --model <model>", `Model to use (${VALID_MODELS.join(", ")})`).option("--json", "Output as JSON (for one-shot mode)").action(async (query, options) => {
188637
+ try {
188638
+ if (!authService.isAuthenticated()) {
188639
+ console.log(source_default.yellow("\u26A0\uFE0F Authentication required"));
188640
+ console.log(source_default.dim(" Run: rivora auth login"));
188641
+ process.exit(1);
188642
+ }
188643
+ const session = new AgentSession;
188644
+ const renderer = new AgentRenderer;
188645
+ const repl = new AgentREPL(session, renderer);
188646
+ if (query && query.trim()) {
188647
+ const spinner = ora("Processing query...").start();
188648
+ try {
188649
+ await repl.runOneShot(query);
188650
+ spinner.succeed("Query completed");
188651
+ } catch (error) {
188652
+ spinner.fail("Query failed");
188653
+ console.error(source_default.red(error.message));
188654
+ process.exit(1);
188655
+ }
188656
+ } else if (options.preset) {
188657
+ const presetName = options.preset;
188658
+ if (!VALID_PRESETS.includes(presetName)) {
188659
+ console.error(source_default.red(`Invalid preset: ${presetName}`));
188660
+ console.log(source_default.dim(`Valid presets: ${VALID_PRESETS.join(", ")}`));
188661
+ process.exit(1);
188662
+ }
188663
+ const spinner = ora(`Running preset: ${presetName}...`).start();
188664
+ try {
188665
+ await repl.runPreset(presetName);
188666
+ spinner.succeed("Preset completed");
188667
+ } catch (error) {
188668
+ spinner.fail("Preset execution failed");
188669
+ console.error(source_default.red(error.message));
188670
+ process.exit(1);
188671
+ }
188672
+ } else {
188673
+ await repl.start();
188674
+ }
188675
+ } catch (error) {
188676
+ if (error instanceof Error) {
188677
+ console.error(source_default.red("Error:"), error.message);
188678
+ }
188679
+ process.exit(1);
188680
+ }
188681
+ });
187842
188682
  var program3 = new Command;
187843
- program3.name("rivora").description("Rivora - Infrastructure Intelligence Layer").version(version2).addCommand(authCommand).addCommand(connectCommand).addCommand(inventoryCommand).addCommand(findingsCommand).addCommand(planCommand).addCommand(remediateCommand).addCommand(helpCommand).addCommand(regionsCommand).addCommand(slackCommand).addCommand(ciCommand).addCommand(updateCommand).addCommand(modelsCommand).addCommand(adminCommand).addCommand(argocdCommand).addCommand(driftCommand).addCommand(backlogCommand).addCommand(rcaCommand);
188683
+ program3.name("rivora").description("Rivora - Infrastructure Intelligence Layer").version(version2).addCommand(authCommand).addCommand(connectCommand).addCommand(inventoryCommand).addCommand(findingsCommand).addCommand(planCommand).addCommand(remediateCommand).addCommand(helpCommand).addCommand(regionsCommand).addCommand(slackCommand).addCommand(ciCommand).addCommand(updateCommand).addCommand(modelsCommand).addCommand(adminCommand).addCommand(argocdCommand).addCommand(driftCommand).addCommand(backlogCommand).addCommand(rcaCommand).addCommand(optimizeCommand).addCommand(agentCommand);
187844
188684
  if (process.env.RIVORA_INTERNAL === "1") {
187845
188685
  program3.addCommand(trainingCommand);
187846
188686
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivora/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Rivora CLI - Infrastructure Intelligence Layer",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",