@solongate/proxy 0.59.5 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -132,12 +132,12 @@ async function sendAuditLog(apiKey, apiUrl, entry) {
132
132
  `);
133
133
  try {
134
134
  const line = JSON.stringify({ ...entry, timestamp: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
135
- appendFile(AUDIT_LOG_BACKUP_PATH, line, "utf-8").catch((err) => {
136
- process.stderr.write(`[SolonGate] Audit backup write error: ${err instanceof Error ? err.message : String(err)}
135
+ appendFile(AUDIT_LOG_BACKUP_PATH, line, "utf-8").catch((err2) => {
136
+ process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
137
137
  `);
138
138
  });
139
- } catch (err) {
140
- process.stderr.write(`[SolonGate] Audit backup write error: ${err instanceof Error ? err.message : String(err)}
139
+ } catch (err2) {
140
+ process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
141
141
  `);
142
142
  }
143
143
  }
@@ -398,11 +398,11 @@ var require_json = __commonJS({
398
398
  try {
399
399
  JSON.parse(str);
400
400
  return true;
401
- } catch (err) {
402
- if (err instanceof SyntaxError) {
401
+ } catch (err2) {
402
+ if (err2 instanceof SyntaxError) {
403
403
  return false;
404
404
  }
405
- throw err;
405
+ throw err2;
406
406
  }
407
407
  }
408
408
  module.exports = {
@@ -765,9 +765,9 @@ var require_PlainValue_516d5bc2 = __commonJS({
765
765
  }
766
766
  }
767
767
  const offset = col > 1 ? " ".repeat(col - 1) : "";
768
- const err = "^".repeat(errLen);
768
+ const err2 = "^".repeat(errLen);
769
769
  return `${src}
770
- ${offset}${err}${errEnd}`;
770
+ ${offset}${err2}${errEnd}`;
771
771
  }
772
772
  var Range = class _Range {
773
773
  static copy(orig) {
@@ -2735,7 +2735,7 @@ var require_parse_cst = __commonJS({
2735
2735
  };
2736
2736
  }
2737
2737
  };
2738
- function parse(src) {
2738
+ function parse2(src) {
2739
2739
  const cr = [];
2740
2740
  if (src.indexOf("\r") !== -1) {
2741
2741
  src = src.replace(/\r\n?/g, (match, offset2) => {
@@ -2766,7 +2766,7 @@ var require_parse_cst = __commonJS({
2766
2766
  documents.toString = () => documents.join("...\n");
2767
2767
  return documents;
2768
2768
  }
2769
- exports.parse = parse;
2769
+ exports.parse = parse2;
2770
2770
  }
2771
2771
  });
2772
2772
 
@@ -3398,12 +3398,12 @@ ${ctx.indent}`;
3398
3398
  for (const {
3399
3399
  format,
3400
3400
  test,
3401
- resolve: resolve9
3401
+ resolve: resolve10
3402
3402
  } of tags) {
3403
3403
  if (test) {
3404
3404
  const match = str.match(test);
3405
3405
  if (match) {
3406
- let res = resolve9.apply(null, match);
3406
+ let res = resolve10.apply(null, match);
3407
3407
  if (!(res instanceof Scalar)) res = new Scalar(res);
3408
3408
  if (format) res.format = format;
3409
3409
  return res;
@@ -3817,15 +3817,15 @@ ${indent}`);
3817
3817
  }
3818
3818
  if (lastItem && lastItem.char !== char) {
3819
3819
  const msg = `Expected ${name} to end with ${char}`;
3820
- let err;
3820
+ let err2;
3821
3821
  if (typeof lastItem.offset === "number") {
3822
- err = new PlainValue.YAMLSemanticError(cst, msg);
3823
- err.offset = lastItem.offset + 1;
3822
+ err2 = new PlainValue.YAMLSemanticError(cst, msg);
3823
+ err2.offset = lastItem.offset + 1;
3824
3824
  } else {
3825
- err = new PlainValue.YAMLSemanticError(lastItem, msg);
3826
- if (lastItem.range && lastItem.range.end) err.offset = lastItem.range.end - lastItem.range.start;
3825
+ err2 = new PlainValue.YAMLSemanticError(lastItem, msg);
3826
+ if (lastItem.range && lastItem.range.end) err2.offset = lastItem.range.end - lastItem.range.start;
3827
3827
  }
3828
- errors.push(err);
3828
+ errors.push(err2);
3829
3829
  }
3830
3830
  }
3831
3831
  function checkFlowCommentSpace(errors, comment) {
@@ -4364,9 +4364,9 @@ ${ca}` : ca;
4364
4364
  continue;
4365
4365
  }
4366
4366
  const msg = `Flow map contains an unexpected ${char}`;
4367
- const err = new PlainValue.YAMLSyntaxError(cst, msg);
4368
- err.offset = offset;
4369
- doc.errors.push(err);
4367
+ const err2 = new PlainValue.YAMLSyntaxError(cst, msg);
4368
+ err2.offset = offset;
4369
+ doc.errors.push(err2);
4370
4370
  } else if (item.type === PlainValue.Type.BLANK_LINE) {
4371
4371
  comments.push({
4372
4372
  afterKey: !!key,
@@ -4482,9 +4482,9 @@ ${ca}` : ca;
4482
4482
  key = items.pop();
4483
4483
  if (key instanceof Pair) {
4484
4484
  const msg = "Chaining flow sequence pairs is invalid";
4485
- const err = new PlainValue.YAMLSemanticError(cst, msg);
4486
- err.offset = offset;
4487
- doc.errors.push(err);
4485
+ const err2 = new PlainValue.YAMLSemanticError(cst, msg);
4486
+ err2.offset = offset;
4487
+ doc.errors.push(err2);
4488
4488
  }
4489
4489
  if (!explicitKey && typeof keyStart === "number") {
4490
4490
  const keyEnd = item.range ? item.range.start : item.offset;
@@ -4506,9 +4506,9 @@ ${ca}` : ca;
4506
4506
  next = null;
4507
4507
  } else if (next === "[" || char !== "]" || i < cst.items.length - 1) {
4508
4508
  const msg = `Flow sequence contains an unexpected ${char}`;
4509
- const err = new PlainValue.YAMLSyntaxError(cst, msg);
4510
- err.offset = offset;
4511
- doc.errors.push(err);
4509
+ const err2 = new PlainValue.YAMLSyntaxError(cst, msg);
4510
+ err2.offset = offset;
4511
+ doc.errors.push(err2);
4512
4512
  }
4513
4513
  } else if (item.type === PlainValue.Type.BLANK_LINE) {
4514
4514
  comments.push({
@@ -6045,7 +6045,7 @@ var require_dist = __commonJS({
6045
6045
  }
6046
6046
  return doc;
6047
6047
  }
6048
- function parse(src, options) {
6048
+ function parse2(src, options) {
6049
6049
  const doc = parseDocument(src, options);
6050
6050
  doc.warnings.forEach((warning) => warnings.warn(warning));
6051
6051
  if (doc.errors.length > 0) throw doc.errors[0];
@@ -6060,7 +6060,7 @@ var require_dist = __commonJS({
6060
6060
  createNode,
6061
6061
  defaultOptions: Document$1.defaultOptions,
6062
6062
  Document,
6063
- parse,
6063
+ parse: parse2,
6064
6064
  parseAllDocuments,
6065
6065
  parseCST: parseCst.parse,
6066
6066
  parseDocument,
@@ -6090,7 +6090,7 @@ var require_yaml2 = __commonJS({
6090
6090
  "YAMLSyntaxError",
6091
6091
  "YAMLWarning"
6092
6092
  ]);
6093
- function parse(str) {
6093
+ function parse2(str) {
6094
6094
  if (typeof str !== "string") {
6095
6095
  return { ok: false, result: void 0 };
6096
6096
  }
@@ -6098,11 +6098,11 @@ var require_yaml2 = __commonJS({
6098
6098
  try {
6099
6099
  global.YAML_SILENCE_WARNINGS = true;
6100
6100
  return { ok: true, result: yaml.parse(str) };
6101
- } catch (err) {
6102
- if (err && errors.has(err.name)) {
6101
+ } catch (err2) {
6102
+ if (err2 && errors.has(err2.name)) {
6103
6103
  return { ok: false, result: void 0 };
6104
6104
  }
6105
- throw err;
6105
+ throw err2;
6106
6106
  } finally {
6107
6107
  global.YAML_SILENCE_WARNINGS = YAML_SILENCE_WARNINGS_CACHED;
6108
6108
  }
@@ -6110,9 +6110,9 @@ var require_yaml2 = __commonJS({
6110
6110
  module.exports = {
6111
6111
  // is_valid is expected to return nothing if input is invalid otherwise
6112
6112
  // true/false for it being valid YAML.
6113
- "yaml.is_valid": (str) => typeof str === "string" ? parse(str).ok : void 0,
6113
+ "yaml.is_valid": (str) => typeof str === "string" ? parse2(str).ok : void 0,
6114
6114
  "yaml.marshal": (data) => yaml.stringify(data),
6115
- "yaml.unmarshal": (str) => parse(str).result
6115
+ "yaml.unmarshal": (str) => parse2(str).result
6116
6116
  };
6117
6117
  }
6118
6118
  });
@@ -6554,6 +6554,1743 @@ var init_cli_utils = __esm({
6554
6554
  }
6555
6555
  });
6556
6556
 
6557
+ // src/api-client/client.ts
6558
+ var client_exports = {};
6559
+ __export(client_exports, {
6560
+ ApiError: () => ApiError,
6561
+ DEFAULT_API_URL: () => DEFAULT_API_URL2,
6562
+ NotAuthenticatedError: () => NotAuthenticatedError,
6563
+ isAuthenticated: () => isAuthenticated,
6564
+ request: () => request,
6565
+ resolveCredentials: () => resolveCredentials
6566
+ });
6567
+ import { readFileSync as readFileSync4, existsSync as existsSync3 } from "fs";
6568
+ import { resolve as resolve3, join as join4 } from "path";
6569
+ import { homedir as homedir2 } from "os";
6570
+ function loginCredentialFile() {
6571
+ try {
6572
+ const p = join4(homedir2(), ".solongate", "cloud-guard.json");
6573
+ if (!existsSync3(p)) return {};
6574
+ const c2 = JSON.parse(readFileSync4(p, "utf-8"));
6575
+ return c2 && typeof c2 === "object" ? c2 : {};
6576
+ } catch {
6577
+ return {};
6578
+ }
6579
+ }
6580
+ function dotenvApiKey() {
6581
+ try {
6582
+ const envPath = resolve3(".env");
6583
+ if (!existsSync3(envPath)) return void 0;
6584
+ for (const line of readFileSync4(envPath, "utf-8").split("\n")) {
6585
+ const trimmed = line.trim();
6586
+ if (!trimmed || trimmed.startsWith("#")) continue;
6587
+ const eq = trimmed.indexOf("=");
6588
+ if (eq === -1) continue;
6589
+ const key = trimmed.slice(0, eq).trim();
6590
+ if (key !== "SOLONGATE_API_KEY") continue;
6591
+ return trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
6592
+ }
6593
+ } catch {
6594
+ }
6595
+ return void 0;
6596
+ }
6597
+ function isAuthenticated() {
6598
+ try {
6599
+ resolveCredentials();
6600
+ return true;
6601
+ } catch {
6602
+ return false;
6603
+ }
6604
+ }
6605
+ function resolveCredentials(apiUrlOverride) {
6606
+ if (cached && !apiUrlOverride) return cached;
6607
+ const file = loginCredentialFile();
6608
+ const apiKey = process.env["SOLONGATE_API_KEY"] || file.apiKey || dotenvApiKey();
6609
+ if (!apiKey) throw new NotAuthenticatedError();
6610
+ const apiUrl = apiUrlOverride || process.env["SOLONGATE_API_URL"] || file.apiUrl || DEFAULT_API_URL2;
6611
+ const creds = { apiKey, apiUrl: apiUrl.replace(/\/$/, "") };
6612
+ if (!apiUrlOverride) cached = creds;
6613
+ return creds;
6614
+ }
6615
+ function buildUrl(base, path, query) {
6616
+ const url = new URL(`${base}/api/v1${path}`);
6617
+ if (query) {
6618
+ for (const [k, v] of Object.entries(query)) {
6619
+ if (v === void 0) continue;
6620
+ url.searchParams.set(k, String(v));
6621
+ }
6622
+ }
6623
+ return url.toString();
6624
+ }
6625
+ async function request(method, path, opts = {}) {
6626
+ const creds = resolveCredentials(opts.apiUrl);
6627
+ const url = buildUrl(creds.apiUrl, path, opts.query);
6628
+ const headers = {
6629
+ Authorization: `Bearer ${creds.apiKey}`
6630
+ };
6631
+ let bodyInit;
6632
+ if (opts.body !== void 0) {
6633
+ headers["Content-Type"] = "application/json";
6634
+ bodyInit = JSON.stringify(opts.body);
6635
+ }
6636
+ let res;
6637
+ try {
6638
+ res = await fetch(url, {
6639
+ method,
6640
+ headers,
6641
+ body: bodyInit,
6642
+ signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3)
6643
+ });
6644
+ } catch (err2) {
6645
+ const msg = err2 instanceof Error ? err2.message : String(err2);
6646
+ throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
6647
+ }
6648
+ const text = await res.text().catch(() => "");
6649
+ let json = void 0;
6650
+ if (text) {
6651
+ try {
6652
+ json = JSON.parse(text);
6653
+ } catch {
6654
+ }
6655
+ }
6656
+ if (!res.ok) {
6657
+ const envelope = json?.error;
6658
+ if (envelope && typeof envelope === "object") {
6659
+ throw new ApiError(res.status, envelope.code || "ERROR", envelope.message || res.statusText);
6660
+ }
6661
+ if (typeof envelope === "string") {
6662
+ throw new ApiError(res.status, "ERROR", envelope);
6663
+ }
6664
+ if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate login`.");
6665
+ if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
6666
+ throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
6667
+ }
6668
+ return json;
6669
+ }
6670
+ var DEFAULT_API_URL2, ApiError, NotAuthenticatedError, cached;
6671
+ var init_client = __esm({
6672
+ "src/api-client/client.ts"() {
6673
+ "use strict";
6674
+ DEFAULT_API_URL2 = "https://api.solongate.com";
6675
+ ApiError = class extends Error {
6676
+ status;
6677
+ code;
6678
+ constructor(status, code, message) {
6679
+ super(message);
6680
+ this.name = "ApiError";
6681
+ this.status = status;
6682
+ this.code = code;
6683
+ }
6684
+ };
6685
+ NotAuthenticatedError = class extends Error {
6686
+ constructor() {
6687
+ super("Not logged in. Run `solongate login` first.");
6688
+ this.name = "NotAuthenticatedError";
6689
+ }
6690
+ };
6691
+ cached = null;
6692
+ }
6693
+ });
6694
+
6695
+ // src/tui/theme.ts
6696
+ function decisionColor(decision) {
6697
+ const d = (decision || "").toUpperCase();
6698
+ if (d === "ALLOW") return theme.ok;
6699
+ if (d === "DENY" || d === "DENIED") return theme.bad;
6700
+ return theme.dim;
6701
+ }
6702
+ function modeColor(m) {
6703
+ if (m === "block" || m === "active" || m === "on") return theme.ok;
6704
+ if (m === "detect" || m === "idle") return theme.warn;
6705
+ return theme.dim;
6706
+ }
6707
+ function sparkline(values, width2) {
6708
+ let v = values;
6709
+ if (width2 && v.length > width2) v = v.slice(v.length - width2);
6710
+ if (v.length === 0) return "";
6711
+ const max = Math.max(...v, 0);
6712
+ if (max === 0) return BLOCKS[0].repeat(v.length);
6713
+ return v.map((n) => BLOCKS[Math.min(BLOCKS.length - 1, Math.round(n / max * (BLOCKS.length - 1)))]).join("");
6714
+ }
6715
+ function truncate2(s, n) {
6716
+ if (!s) return "";
6717
+ return s.length <= n ? s : s.slice(0, Math.max(0, n - 1)) + "\u2026";
6718
+ }
6719
+ function ago(ts) {
6720
+ const t = typeof ts === "number" ? ts : Date.parse(ts);
6721
+ if (Number.isNaN(t)) return String(ts ?? "");
6722
+ const s = Math.max(0, (Date.now() - t) / 1e3);
6723
+ if (s < 60) return `${Math.floor(s)}s`;
6724
+ if (s < 3600) return `${Math.floor(s / 60)}m`;
6725
+ if (s < 86400) return `${Math.floor(s / 3600)}h`;
6726
+ return `${Math.floor(s / 86400)}d`;
6727
+ }
6728
+ var theme, BLOCKS;
6729
+ var init_theme = __esm({
6730
+ "src/tui/theme.ts"() {
6731
+ "use strict";
6732
+ theme = {
6733
+ accent: "cyan",
6734
+ accentBright: "#5a8ce6",
6735
+ ok: "green",
6736
+ warn: "yellow",
6737
+ bad: "red",
6738
+ dim: "gray"
6739
+ };
6740
+ BLOCKS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
6741
+ }
6742
+ });
6743
+
6744
+ // src/tui/components.tsx
6745
+ import { Box, Text } from "ink";
6746
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6747
+ function DataView({
6748
+ loading,
6749
+ error,
6750
+ empty,
6751
+ emptyText,
6752
+ children
6753
+ }) {
6754
+ if (error) return /* @__PURE__ */ jsxs(Text, { color: theme.bad, children: [
6755
+ "\u2717 ",
6756
+ error
6757
+ ] });
6758
+ if (loading) return /* @__PURE__ */ jsx(Text, { color: theme.dim, children: "Loading\u2026" });
6759
+ if (empty) return /* @__PURE__ */ jsx(Text, { color: theme.dim, children: emptyText ?? "No data." });
6760
+ return /* @__PURE__ */ jsx(Fragment, { children });
6761
+ }
6762
+ function Table({ columns, rows }) {
6763
+ const fit = (s, w) => {
6764
+ const v = s ?? "";
6765
+ if (v.length > w) return v.slice(0, Math.max(0, w - 1)) + "\u2026";
6766
+ return v.padEnd(w);
6767
+ };
6768
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
6769
+ /* @__PURE__ */ jsx(Box, { children: columns.map((c2, i) => /* @__PURE__ */ jsx(Text, { color: theme.dim, children: fit(c2.header, c2.width) + " " }, i)) }),
6770
+ rows.map((row, ri) => /* @__PURE__ */ jsx(Box, { children: row.map((cell, ci) => /* @__PURE__ */ jsx(Text, { color: cell.color, dimColor: cell.dim, bold: cell.bold, children: fit(cell.value, columns[ci]?.width ?? 10) + " " }, ci)) }, ri))
6771
+ ] });
6772
+ }
6773
+ function KeyHints({ hints }) {
6774
+ return /* @__PURE__ */ jsx(Box, { children: hints.map(([key, label], i) => /* @__PURE__ */ jsxs(Text, { color: theme.dim, children: [
6775
+ /* @__PURE__ */ jsx(Text, { color: theme.accent, children: key }),
6776
+ " ",
6777
+ label,
6778
+ i < hints.length - 1 ? " " : ""
6779
+ ] }, i)) });
6780
+ }
6781
+ var init_components = __esm({
6782
+ "src/tui/components.tsx"() {
6783
+ "use strict";
6784
+ init_theme();
6785
+ }
6786
+ });
6787
+
6788
+ // src/api-client/types.ts
6789
+ var init_types = __esm({
6790
+ "src/api-client/types.ts"() {
6791
+ "use strict";
6792
+ }
6793
+ });
6794
+
6795
+ // src/api-client/policies.ts
6796
+ var policies_exports = {};
6797
+ __export(policies_exports, {
6798
+ active: () => active,
6799
+ addRule: () => addRule,
6800
+ create: () => create,
6801
+ dryRun: () => dryRun,
6802
+ get: () => get,
6803
+ list: () => list,
6804
+ remove: () => remove,
6805
+ revokeRule: () => revokeRule,
6806
+ rollback: () => rollback,
6807
+ setActive: () => setActive,
6808
+ update: () => update,
6809
+ versions: () => versions
6810
+ });
6811
+ function list() {
6812
+ return request("GET", "/policies");
6813
+ }
6814
+ function get(id, version) {
6815
+ return request("GET", `/policies/${encodeURIComponent(id)}`, {
6816
+ query: version !== void 0 ? { version } : void 0
6817
+ });
6818
+ }
6819
+ function create(policy) {
6820
+ return request("POST", "/policies", { body: policy });
6821
+ }
6822
+ function update(id, policy) {
6823
+ return request("PUT", `/policies/${encodeURIComponent(id)}`, { body: policy });
6824
+ }
6825
+ function remove(id) {
6826
+ return request("DELETE", `/policies/${encodeURIComponent(id)}`);
6827
+ }
6828
+ function addRule(id, spec) {
6829
+ return request("POST", `/policies/${encodeURIComponent(id)}/rules`, { body: spec });
6830
+ }
6831
+ function revokeRule(id, ruleId) {
6832
+ return request("DELETE", `/policies/${encodeURIComponent(id)}/rules/${encodeURIComponent(ruleId)}`);
6833
+ }
6834
+ function versions(id, opts = {}) {
6835
+ return request("GET", `/policies/${encodeURIComponent(id)}/versions`, { query: opts });
6836
+ }
6837
+ function rollback(id, version) {
6838
+ return request("POST", `/policies/${encodeURIComponent(id)}/rollback`, { body: { version } });
6839
+ }
6840
+ function active(agentId) {
6841
+ return request("GET", "/policies/active", { query: agentId ? { agent_id: agentId } : void 0 });
6842
+ }
6843
+ function setActive(policyId) {
6844
+ return request("POST", "/policies/active", { body: { policyId: policyId ?? "" } });
6845
+ }
6846
+ function dryRun(body) {
6847
+ return request("POST", "/policies/dry-run", { body });
6848
+ }
6849
+ var init_policies = __esm({
6850
+ "src/api-client/policies.ts"() {
6851
+ "use strict";
6852
+ init_client();
6853
+ }
6854
+ });
6855
+
6856
+ // src/api-client/settings.ts
6857
+ var settings_exports = {};
6858
+ __export(settings_exports, {
6859
+ clearRateLimitHistory: () => clearRateLimitHistory,
6860
+ getGuardStatus: () => getGuardStatus,
6861
+ getRateLimitHistory: () => getRateLimitHistory,
6862
+ getSecurityLayers: () => getSecurityLayers,
6863
+ setSecurityLayers: () => setSecurityLayers
6864
+ });
6865
+ function getSecurityLayers() {
6866
+ return request("GET", "/settings/security-layers");
6867
+ }
6868
+ function setSecurityLayers(layers) {
6869
+ return request("PUT", "/settings/security-layers", { body: { layers } });
6870
+ }
6871
+ function getRateLimitHistory() {
6872
+ return request("GET", "/settings/rate-limit-history");
6873
+ }
6874
+ function clearRateLimitHistory() {
6875
+ return request("DELETE", "/settings/rate-limit-history", { query: { all: 1 } });
6876
+ }
6877
+ function getGuardStatus() {
6878
+ return request("GET", "/settings/guard-status");
6879
+ }
6880
+ var init_settings = __esm({
6881
+ "src/api-client/settings.ts"() {
6882
+ "use strict";
6883
+ init_client();
6884
+ }
6885
+ });
6886
+
6887
+ // src/api-client/stats.ts
6888
+ var stats_exports = {};
6889
+ __export(stats_exports, {
6890
+ drift: () => drift,
6891
+ get: () => get2,
6892
+ securityInsights: () => securityInsights,
6893
+ timeseries: () => timeseries
6894
+ });
6895
+ function get2() {
6896
+ return request("GET", "/stats");
6897
+ }
6898
+ function timeseries(opts = {}) {
6899
+ return request("GET", "/stats/timeseries", { query: opts });
6900
+ }
6901
+ function drift(days) {
6902
+ return request("GET", "/stats/drift", { query: days !== void 0 ? { days } : void 0 });
6903
+ }
6904
+ function securityInsights(days) {
6905
+ return request("GET", "/stats/security-insights", { query: days !== void 0 ? { days } : void 0 });
6906
+ }
6907
+ var init_stats = __esm({
6908
+ "src/api-client/stats.ts"() {
6909
+ "use strict";
6910
+ init_client();
6911
+ }
6912
+ });
6913
+
6914
+ // src/api-client/audit.ts
6915
+ var audit_exports = {};
6916
+ __export(audit_exports, {
6917
+ list: () => list2,
6918
+ whitelist: () => whitelist
6919
+ });
6920
+ function list2(query = {}) {
6921
+ return request("GET", "/audit-logs", { query });
6922
+ }
6923
+ function whitelist(id, scope = "exact") {
6924
+ return request("POST", `/audit-logs/${encodeURIComponent(id)}/whitelist`, { body: { scope } });
6925
+ }
6926
+ var init_audit = __esm({
6927
+ "src/api-client/audit.ts"() {
6928
+ "use strict";
6929
+ init_client();
6930
+ }
6931
+ });
6932
+
6933
+ // src/api-client/agents.ts
6934
+ var agents_exports = {};
6935
+ __export(agents_exports, {
6936
+ anomalies: () => anomalies,
6937
+ get: () => get3,
6938
+ live: () => live
6939
+ });
6940
+ function live(opts = {}) {
6941
+ return request("GET", "/agents/live", {
6942
+ query: { limit: opts.limit, include_deactivated: opts.includeDeactivated ? 1 : void 0 }
6943
+ });
6944
+ }
6945
+ function get3(id, scan = false) {
6946
+ return request("GET", `/agents/${encodeURIComponent(id)}`, { query: scan ? { scan: 1 } : void 0 });
6947
+ }
6948
+ function anomalies(id, limit) {
6949
+ return request("GET", `/agents/${encodeURIComponent(id)}/anomalies`, {
6950
+ query: limit !== void 0 ? { limit } : void 0
6951
+ });
6952
+ }
6953
+ var init_agents = __esm({
6954
+ "src/api-client/agents.ts"() {
6955
+ "use strict";
6956
+ init_client();
6957
+ }
6958
+ });
6959
+
6960
+ // src/api-client/index.ts
6961
+ var api;
6962
+ var init_api_client = __esm({
6963
+ "src/api-client/index.ts"() {
6964
+ "use strict";
6965
+ init_client();
6966
+ init_types();
6967
+ init_policies();
6968
+ init_settings();
6969
+ init_stats();
6970
+ init_audit();
6971
+ init_agents();
6972
+ api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports };
6973
+ }
6974
+ });
6975
+
6976
+ // src/tui/hooks.ts
6977
+ import { useCallback, useEffect, useRef, useState } from "react";
6978
+ function useLoader(fn, deps = []) {
6979
+ const [data, setData] = useState(null);
6980
+ const [error, setError] = useState(null);
6981
+ const [loading, setLoading] = useState(true);
6982
+ const [nonce, setNonce] = useState(0);
6983
+ const alive = useRef(true);
6984
+ const fnRef = useRef(fn);
6985
+ fnRef.current = fn;
6986
+ useEffect(() => {
6987
+ alive.current = true;
6988
+ return () => {
6989
+ alive.current = false;
6990
+ };
6991
+ }, []);
6992
+ useEffect(() => {
6993
+ setLoading(true);
6994
+ fnRef.current().then((d) => {
6995
+ if (!alive.current) return;
6996
+ setData(d);
6997
+ setError(null);
6998
+ }).catch((e) => {
6999
+ if (!alive.current) return;
7000
+ setError(e instanceof Error ? e.message : String(e));
7001
+ }).finally(() => {
7002
+ if (alive.current) setLoading(false);
7003
+ });
7004
+ }, [nonce, ...deps]);
7005
+ const reload = useCallback(() => setNonce((n) => n + 1), []);
7006
+ return { data, error, loading, reload };
7007
+ }
7008
+ function usePoll(reload, intervalMs, enabled = true) {
7009
+ useEffect(() => {
7010
+ if (!enabled) return;
7011
+ const t = setInterval(reload, intervalMs);
7012
+ return () => clearInterval(t);
7013
+ }, [reload, intervalMs, enabled]);
7014
+ }
7015
+ var init_hooks = __esm({
7016
+ "src/tui/hooks.ts"() {
7017
+ "use strict";
7018
+ }
7019
+ });
7020
+
7021
+ // src/tui/panels/Policies.tsx
7022
+ import { Box as Box2, Text as Text2, useInput } from "ink";
7023
+ import { useState as useState2 } from "react";
7024
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7025
+ function PoliciesPanel({ focused }) {
7026
+ const [sel, setSel] = useState2(0);
7027
+ const list4 = useLoader(() => api.policies.list());
7028
+ const policies = list4.data?.policies ?? [];
7029
+ const selected = policies[Math.min(sel, Math.max(0, policies.length - 1))];
7030
+ const detail = useLoader(() => selected ? api.policies.get(selected.id) : Promise.resolve(null), [selected?.id]);
7031
+ useInput(
7032
+ (_input, key) => {
7033
+ if (key.upArrow) setSel((n) => Math.max(0, n - 1));
7034
+ if (key.downArrow) setSel((n) => Math.min(policies.length - 1, n + 1));
7035
+ },
7036
+ { isActive: focused }
7037
+ );
7038
+ return /* @__PURE__ */ jsx2(DataView, { loading: list4.loading && !list4.data, error: list4.error, empty: !!list4.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
7039
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: focused ? "\u2191\u2193 select policy" : "press \u2192 to browse" }),
7040
+ /* @__PURE__ */ jsx2(Box2, { marginTop: 1, flexDirection: "column", children: policies.map((p, i) => /* @__PURE__ */ jsxs2(Text2, { color: i === sel ? theme.accentBright : void 0, bold: i === sel, children: [
7041
+ (i === sel ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
7042
+ /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7043
+ p.mode.padEnd(10),
7044
+ " ",
7045
+ p.rules.length,
7046
+ " rules \xB7 v",
7047
+ p.version
7048
+ ] })
7049
+ ] }, p.id)) }),
7050
+ selected ? /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
7051
+ /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7052
+ "Rules of ",
7053
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: selected.id })
7054
+ ] }),
7055
+ /* @__PURE__ */ jsx2(
7056
+ Table,
7057
+ {
7058
+ columns: [
7059
+ { header: "EFFECT", width: 7 },
7060
+ { header: "PRIO", width: 4 },
7061
+ { header: "TOOL", width: 22 },
7062
+ { header: "DESCRIPTION", width: 34 }
7063
+ ],
7064
+ rows: (detail.data?.rules ?? []).slice(0, 10).map((r) => [
7065
+ { value: r.effect, color: r.effect === "ALLOW" ? theme.ok : theme.bad },
7066
+ { value: String(r.priority), dim: true },
7067
+ { value: truncate2(r.toolPattern, 22), color: theme.accent },
7068
+ { value: truncate2(r.description || "\u2014", 34) }
7069
+ ])
7070
+ }
7071
+ )
7072
+ ] }) : null
7073
+ ] }) });
7074
+ }
7075
+ var init_Policies = __esm({
7076
+ "src/tui/panels/Policies.tsx"() {
7077
+ "use strict";
7078
+ init_api_client();
7079
+ init_components();
7080
+ init_hooks();
7081
+ init_theme();
7082
+ }
7083
+ });
7084
+
7085
+ // src/tui/panels/RateLimit.tsx
7086
+ import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
7087
+ import { useEffect as useEffect2, useState as useState3 } from "react";
7088
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
7089
+ function RateLimitPanel({ focused }) {
7090
+ const layersQ = useLoader(() => api.settings.getSecurityLayers());
7091
+ const historyQ = useLoader(() => api.settings.getRateLimitHistory());
7092
+ const [draft, setDraft] = useState3(null);
7093
+ const [dirty, setDirty] = useState3(false);
7094
+ const [fi, setFi] = useState3(0);
7095
+ const [status, setStatus] = useState3(null);
7096
+ useEffect2(() => {
7097
+ if (layersQ.data && !draft) setDraft({ ...layersQ.data.layers.rateLimit });
7098
+ }, [layersQ.data, draft]);
7099
+ const adjust = (dir) => {
7100
+ if (!draft) return;
7101
+ const field = FIELDS[fi];
7102
+ if (field === "mode") {
7103
+ const idx = (MODES.indexOf(draft.mode) + dir + MODES.length) % MODES.length;
7104
+ setDraft({ ...draft, mode: MODES[idx] });
7105
+ } else {
7106
+ const step = 10;
7107
+ setDraft({ ...draft, [field]: Math.max(0, draft[field] + dir * step) });
7108
+ }
7109
+ setDirty(true);
7110
+ setStatus(null);
7111
+ };
7112
+ const save = async () => {
7113
+ if (!draft || !layersQ.data) return;
7114
+ setStatus("Saving\u2026");
7115
+ try {
7116
+ const next = { ...layersQ.data.layers, rateLimit: draft };
7117
+ const res = await api.settings.setSecurityLayers(next);
7118
+ setDraft({ ...res.layers.rateLimit });
7119
+ setDirty(false);
7120
+ setStatus("\u2713 Saved");
7121
+ historyQ.reload();
7122
+ } catch (e) {
7123
+ setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
7124
+ }
7125
+ };
7126
+ useInput2(
7127
+ (input, key) => {
7128
+ if (key.upArrow) setFi((n) => (n - 1 + FIELDS.length) % FIELDS.length);
7129
+ else if (key.downArrow) setFi((n) => (n + 1) % FIELDS.length);
7130
+ else if (key.leftArrow) adjust(-1);
7131
+ else if (key.rightArrow) adjust(1);
7132
+ else if (input === "s") void save();
7133
+ },
7134
+ { isActive: focused }
7135
+ );
7136
+ const history = historyQ.data?.history ?? [];
7137
+ return /* @__PURE__ */ jsx3(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
7138
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 field \u2190\u2192 change s save" : "press \u2192 to edit" }),
7139
+ /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
7140
+ /* @__PURE__ */ jsx3(Row, { label: "Mode", active: focused && fi === 0, children: /* @__PURE__ */ jsx3(Text3, { color: modeColor(draft.mode), children: draft.mode }) }),
7141
+ /* @__PURE__ */ jsx3(Row, { label: "Per minute", active: focused && fi === 1, children: /* @__PURE__ */ jsx3(Text3, { bold: true, children: draft.perMinute }) }),
7142
+ /* @__PURE__ */ jsx3(Row, { label: "Per hour", active: focused && fi === 2, children: /* @__PURE__ */ jsx3(Text3, { bold: true, children: draft.perHour === 0 ? "off" : draft.perHour }) }),
7143
+ /* @__PURE__ */ jsx3(Row, { label: "Per day", active: focused && fi === 3, children: /* @__PURE__ */ jsx3(Text3, { bold: true, children: draft.perDay === 0 ? "off" : draft.perDay }) })
7144
+ ] }),
7145
+ history.length ? /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, children: [
7146
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "history " }),
7147
+ /* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: sparkline(history.map((h) => h.minute), 40) }),
7148
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " " + history.length + " changes" })
7149
+ ] }) : null,
7150
+ /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, children: [
7151
+ dirty ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: "\u25CF unsaved \u2014 press s to apply " }) : null,
7152
+ status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
7153
+ ] })
7154
+ ] }) : null });
7155
+ }
7156
+ function Row({ label, active: active2, children }) {
7157
+ return /* @__PURE__ */ jsxs3(Box3, { children: [
7158
+ /* @__PURE__ */ jsx3(Text3, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + label.padEnd(12) }),
7159
+ children
7160
+ ] });
7161
+ }
7162
+ var MODES, FIELDS;
7163
+ var init_RateLimit = __esm({
7164
+ "src/tui/panels/RateLimit.tsx"() {
7165
+ "use strict";
7166
+ init_api_client();
7167
+ init_components();
7168
+ init_hooks();
7169
+ init_theme();
7170
+ MODES = ["off", "detect", "block"];
7171
+ FIELDS = ["mode", "perMinute", "perHour", "perDay"];
7172
+ }
7173
+ });
7174
+
7175
+ // src/tui/panels/Dlp.tsx
7176
+ import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
7177
+ import { useEffect as useEffect3, useState as useState4 } from "react";
7178
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
7179
+ function DlpPanel({ focused }) {
7180
+ const q = useLoader(() => api.settings.getSecurityLayers());
7181
+ const [dlp, setDlp] = useState4(null);
7182
+ const [available, setAvailable] = useState4([]);
7183
+ const [sel, setSel] = useState4(0);
7184
+ const [status, setStatus] = useState4(null);
7185
+ useEffect3(() => {
7186
+ if (q.data && !dlp) {
7187
+ setDlp({ ...q.data.layers.dlp, patterns: [...q.data.layers.dlp.patterns] });
7188
+ setAvailable(q.data.availablePatterns);
7189
+ }
7190
+ }, [q.data, dlp]);
7191
+ const persist = async (nextDlp) => {
7192
+ if (!q.data) return;
7193
+ setDlp(nextDlp);
7194
+ setStatus("Saving\u2026");
7195
+ try {
7196
+ const res = await api.settings.setSecurityLayers({ ...q.data.layers, dlp: nextDlp });
7197
+ setDlp({ ...res.layers.dlp, patterns: [...res.layers.dlp.patterns] });
7198
+ setStatus("\u2713 Saved");
7199
+ } catch (e) {
7200
+ setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
7201
+ }
7202
+ };
7203
+ useInput3(
7204
+ (input, key) => {
7205
+ if (!dlp) return;
7206
+ if (key.upArrow) setSel((n) => Math.max(0, n - 1));
7207
+ else if (key.downArrow) setSel((n) => Math.min(available.length - 1, n + 1));
7208
+ else if (input === " " || key.return) {
7209
+ const p = available[sel];
7210
+ if (!p) return;
7211
+ const set = new Set(dlp.patterns);
7212
+ if (set.has(p)) set.delete(p);
7213
+ else set.add(p);
7214
+ void persist({ ...dlp, patterns: [...set] });
7215
+ } else if (input === "m") {
7216
+ const idx = (MODES2.indexOf(dlp.mode) + 1) % MODES2.length;
7217
+ void persist({ ...dlp, mode: MODES2[idx] });
7218
+ }
7219
+ },
7220
+ { isActive: focused }
7221
+ );
7222
+ const enabled = new Set(dlp?.patterns ?? []);
7223
+ return /* @__PURE__ */ jsx4(DataView, { loading: q.loading && !dlp, error: q.error, children: dlp ? /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
7224
+ /* @__PURE__ */ jsxs4(Box4, { children: [
7225
+ /* @__PURE__ */ jsx4(Text4, { children: "mode: " }),
7226
+ /* @__PURE__ */ jsx4(Text4, { color: modeColor(dlp.mode), children: dlp.mode }),
7227
+ /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: focused ? " \u2191\u2193 move \xB7 space toggle \xB7 m mode" : " press \u2192 to edit" })
7228
+ ] }),
7229
+ /* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: available.map((p, i) => {
7230
+ const on = enabled.has(p);
7231
+ return /* @__PURE__ */ jsxs4(Text4, { color: focused && i === sel ? theme.accentBright : void 0, bold: focused && i === sel, children: [
7232
+ (focused && i === sel ? "\u25B8 " : " ") + (on ? "\u25CF " : "\u25CB "),
7233
+ /* @__PURE__ */ jsx4(Text4, { color: on ? theme.ok : theme.dim, children: p })
7234
+ ] }, p);
7235
+ }) }),
7236
+ dlp.custom.length ? /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
7237
+ /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "Custom:" }),
7238
+ dlp.custom.map((c2) => /* @__PURE__ */ jsxs4(Text4, { children: [
7239
+ " ",
7240
+ /* @__PURE__ */ jsx4(Text4, { color: theme.accent, children: c2.name }),
7241
+ " ",
7242
+ /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: c2.re })
7243
+ ] }, c2.name))
7244
+ ] }) : null,
7245
+ status ? /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) }) : null
7246
+ ] }) : null });
7247
+ }
7248
+ var MODES2;
7249
+ var init_Dlp = __esm({
7250
+ "src/tui/panels/Dlp.tsx"() {
7251
+ "use strict";
7252
+ init_api_client();
7253
+ init_components();
7254
+ init_hooks();
7255
+ init_theme();
7256
+ MODES2 = ["off", "detect", "block"];
7257
+ }
7258
+ });
7259
+
7260
+ // src/tui/panels/Stats.tsx
7261
+ import { Box as Box5, Text as Text5 } from "ink";
7262
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
7263
+ function StatsPanel({ active: active2 }) {
7264
+ const stats = useLoader(() => api.stats.get());
7265
+ const ts = useLoader(() => api.stats.timeseries({ period: "24h" }));
7266
+ usePoll(() => {
7267
+ stats.reload();
7268
+ ts.reload();
7269
+ }, 5e3, active2);
7270
+ const s = stats.data;
7271
+ const points = ts.data?.timeseries ?? [];
7272
+ return /* @__PURE__ */ jsx5(DataView, { loading: stats.loading && !s, error: stats.error, children: s ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
7273
+ /* @__PURE__ */ jsxs5(Box5, { children: [
7274
+ /* @__PURE__ */ jsxs5(Text5, { bold: true, children: [
7275
+ s.total_calls,
7276
+ " "
7277
+ ] }),
7278
+ /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: "calls " }),
7279
+ /* @__PURE__ */ jsxs5(Text5, { color: theme.ok, children: [
7280
+ s.allowed,
7281
+ " allowed"
7282
+ ] }),
7283
+ /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " " }),
7284
+ /* @__PURE__ */ jsxs5(Text5, { color: theme.bad, children: [
7285
+ s.denied,
7286
+ " denied"
7287
+ ] })
7288
+ ] }),
7289
+ /* @__PURE__ */ jsxs5(Text5, { color: theme.dim, children: [
7290
+ s.active_policies,
7291
+ " policies \xB7 ",
7292
+ s.registered_tools,
7293
+ " tools"
7294
+ ] }),
7295
+ /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
7296
+ /* @__PURE__ */ jsxs5(Text5, { color: theme.dim, children: [
7297
+ "Last 24h ",
7298
+ ts.data ? `(per ${ts.data.granularity})` : ""
7299
+ ] }),
7300
+ /* @__PURE__ */ jsxs5(Box5, { children: [
7301
+ /* @__PURE__ */ jsx5(Text5, { children: "total " }),
7302
+ /* @__PURE__ */ jsx5(Text5, { color: theme.accent, children: sparkline(points.map((p) => p.total), 64) })
7303
+ ] }),
7304
+ /* @__PURE__ */ jsxs5(Box5, { children: [
7305
+ /* @__PURE__ */ jsx5(Text5, { children: "allowed " }),
7306
+ /* @__PURE__ */ jsx5(Text5, { color: theme.ok, children: sparkline(points.map((p) => p.allowed), 64) })
7307
+ ] }),
7308
+ /* @__PURE__ */ jsxs5(Box5, { children: [
7309
+ /* @__PURE__ */ jsx5(Text5, { children: "denied " }),
7310
+ /* @__PURE__ */ jsx5(Text5, { color: theme.bad, children: sparkline(points.map((p) => p.denied), 64) })
7311
+ ] })
7312
+ ] }),
7313
+ /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
7314
+ /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: "Recent" }),
7315
+ /* @__PURE__ */ jsx5(
7316
+ Table,
7317
+ {
7318
+ columns: [
7319
+ { header: "DECISION", width: 9 },
7320
+ { header: "TOOL", width: 20 },
7321
+ { header: "MS", width: 5 },
7322
+ { header: "WHEN", width: 6 }
7323
+ ],
7324
+ rows: (s.recent_activity ?? []).slice(0, 8).map((a) => [
7325
+ { value: a.decision, color: decisionColor(a.decision) },
7326
+ { value: truncate2(a.tool_name, 20), color: theme.accent },
7327
+ { value: String(a.evaluation_time_ms ?? "\u2014"), dim: true },
7328
+ { value: ago(a.created_at), dim: true }
7329
+ ])
7330
+ }
7331
+ )
7332
+ ] })
7333
+ ] }) : null });
7334
+ }
7335
+ var init_Stats = __esm({
7336
+ "src/tui/panels/Stats.tsx"() {
7337
+ "use strict";
7338
+ init_api_client();
7339
+ init_components();
7340
+ init_hooks();
7341
+ init_theme();
7342
+ }
7343
+ });
7344
+
7345
+ // src/tui/panels/Audit.tsx
7346
+ import { Box as Box6, Text as Text6, useInput as useInput4 } from "ink";
7347
+ import { useState as useState5 } from "react";
7348
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
7349
+ function AuditPanel({ active: active2, focused }) {
7350
+ const [fi, setFi] = useState5(0);
7351
+ const filter = FILTERS[fi];
7352
+ const audit = useLoader(() => api.audit.list({ filter, limit: 14 }), [fi]);
7353
+ usePoll(audit.reload, 5e3, active2);
7354
+ useInput4(
7355
+ (input) => {
7356
+ if (input === "f") setFi((n) => (n + 1) % FILTERS.length);
7357
+ },
7358
+ { isActive: focused }
7359
+ );
7360
+ const entries = audit.data?.entries ?? [];
7361
+ return /* @__PURE__ */ jsx6(DataView, { loading: audit.loading && !audit.data, error: audit.error, empty: !!audit.data && entries.length === 0, emptyText: "No audit entries.", children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
7362
+ /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
7363
+ audit.data?.total ?? 0,
7364
+ " entries \xB7 filter: ",
7365
+ /* @__PURE__ */ jsx6(Text6, { color: theme.accent, children: filter ?? "all" }),
7366
+ " (press f)"
7367
+ ] }),
7368
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(
7369
+ Table,
7370
+ {
7371
+ columns: [
7372
+ { header: "DECISION", width: 9 },
7373
+ { header: "TOOL", width: 18 },
7374
+ { header: "AGENT", width: 14 },
7375
+ { header: "REASON", width: 26 },
7376
+ { header: "DLP", width: 4 },
7377
+ { header: "WHEN", width: 6 }
7378
+ ],
7379
+ rows: entries.map((e) => [
7380
+ { value: e.decision, color: decisionColor(e.decision) },
7381
+ { value: truncate2(e.tool_name, 18), color: theme.accent },
7382
+ { value: truncate2(e.agent_name ?? "\u2014", 14), dim: true },
7383
+ { value: truncate2(e.reason ?? "\u2014", 26) },
7384
+ { value: e.dlp_matches?.length ? String(e.dlp_matches.length) : "0", color: e.dlp_matches?.length ? theme.bad : void 0, dim: !e.dlp_matches?.length },
7385
+ { value: ago(e.created_at), dim: true }
7386
+ ])
7387
+ }
7388
+ ) })
7389
+ ] }) });
7390
+ }
7391
+ var FILTERS;
7392
+ var init_Audit = __esm({
7393
+ "src/tui/panels/Audit.tsx"() {
7394
+ "use strict";
7395
+ init_api_client();
7396
+ init_components();
7397
+ init_hooks();
7398
+ init_theme();
7399
+ FILTERS = [void 0, "DENY", "ALLOW"];
7400
+ }
7401
+ });
7402
+
7403
+ // src/tui/panels/Agents.tsx
7404
+ import { Box as Box7, Text as Text7 } from "ink";
7405
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
7406
+ function AgentsPanel({ active: active2 }) {
7407
+ const agents = useLoader(() => api.agents.live({ limit: 14 }));
7408
+ usePoll(agents.reload, 4e3, active2);
7409
+ const data = agents.data;
7410
+ const rows = data?.agents ?? [];
7411
+ return /* @__PURE__ */ jsx7(DataView, { loading: agents.loading && !data, error: agents.error, empty: !!data && rows.length === 0, emptyText: "No agent sessions.", children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
7412
+ data ? /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
7413
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.ok, children: [
7414
+ data.counts.active,
7415
+ " active"
7416
+ ] }),
7417
+ " \xB7 ",
7418
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.warn, children: [
7419
+ data.counts.idle,
7420
+ " idle"
7421
+ ] }),
7422
+ " \xB7 ",
7423
+ data.counts.deactivated,
7424
+ " off"
7425
+ ] }) : null,
7426
+ /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(
7427
+ Table,
7428
+ {
7429
+ columns: [
7430
+ { header: "STATUS", width: 7 },
7431
+ { header: "AGENT", width: 20 },
7432
+ { header: "CALLS", width: 6 },
7433
+ { header: "DENY", width: 5 },
7434
+ { header: "DLP", width: 4 },
7435
+ { header: "TRUST", width: 6 },
7436
+ { header: "CHARACTER", width: 20 }
7437
+ ],
7438
+ rows: rows.map((a) => [
7439
+ { value: a.status, color: modeColor(a.status) },
7440
+ { value: truncate2(a.agent_name ?? a.agent_id ?? a.session_id, 20), color: theme.accent },
7441
+ { value: String(a.total_calls) },
7442
+ { value: String(a.denied_calls), color: a.denied_calls ? theme.bad : void 0, dim: !a.denied_calls },
7443
+ { value: String(a.dlp_events), color: a.dlp_events ? theme.bad : void 0, dim: !a.dlp_events },
7444
+ { value: `${a.trust_score}` },
7445
+ { value: truncate2(a.character || "\u2014", 20), dim: true }
7446
+ ])
7447
+ }
7448
+ ) })
7449
+ ] }) });
7450
+ }
7451
+ var init_Agents = __esm({
7452
+ "src/tui/panels/Agents.tsx"() {
7453
+ "use strict";
7454
+ init_api_client();
7455
+ init_components();
7456
+ init_hooks();
7457
+ init_theme();
7458
+ }
7459
+ });
7460
+
7461
+ // src/tui/App.tsx
7462
+ import { Box as Box8, Text as Text8, useApp, useInput as useInput5 } from "ink";
7463
+ import { useState as useState6 } from "react";
7464
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
7465
+ function Banner() {
7466
+ const wide = (process.stdout.columns ?? 80) >= 82;
7467
+ if (!wide) {
7468
+ return /* @__PURE__ */ jsxs8(Box8, { children: [
7469
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate" }),
7470
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \u2014 security control center" })
7471
+ ] });
7472
+ }
7473
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
7474
+ BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx8(Text8, { bold: true, color: BANNER_HEX[i], children: line }, i)),
7475
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
7476
+ ] });
7477
+ }
7478
+ function App() {
7479
+ const { exit } = useApp();
7480
+ const [section, setSection] = useState6(0);
7481
+ const [focus, setFocus] = useState6("nav");
7482
+ useInput5((input, key) => {
7483
+ if (focus === "nav") {
7484
+ if (key.upArrow) setSection((n) => (n - 1 + SECTIONS.length) % SECTIONS.length);
7485
+ else if (key.downArrow) setSection((n) => (n + 1) % SECTIONS.length);
7486
+ else if (key.rightArrow || key.return || key.tab) setFocus("panel");
7487
+ else if (input === "q") exit();
7488
+ } else {
7489
+ if (key.escape || key.tab) setFocus("nav");
7490
+ }
7491
+ });
7492
+ const current = SECTIONS[section];
7493
+ const Panel = current.Panel;
7494
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
7495
+ /* @__PURE__ */ jsx8(Banner, {}),
7496
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
7497
+ /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => /* @__PURE__ */ jsx8(Text8, { color: i === section ? theme.accentBright : void 0, bold: i === section, children: (i === section ? "\u25B8 " : " ") + s.label }, s.label)) }),
7498
+ /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, minHeight: 16, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx8(Panel, { active: true, focused: focus === "panel" }) })
7499
+ ] }),
7500
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: focus === "nav" ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ["q", "quit"]] }) : /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2191\u2193", "move"], ["\u2190\u2192/space/s", "edit"], ["esc", "back to menu"]] }) })
7501
+ ] });
7502
+ }
7503
+ var SECTIONS, BANNER_HEX;
7504
+ var init_App = __esm({
7505
+ "src/tui/App.tsx"() {
7506
+ "use strict";
7507
+ init_cli_utils();
7508
+ init_components();
7509
+ init_theme();
7510
+ init_Policies();
7511
+ init_RateLimit();
7512
+ init_Dlp();
7513
+ init_Stats();
7514
+ init_Audit();
7515
+ init_Agents();
7516
+ SECTIONS = [
7517
+ { label: "Policies", Panel: PoliciesPanel },
7518
+ { label: "Rate Limit", Panel: RateLimitPanel },
7519
+ { label: "DLP", Panel: DlpPanel },
7520
+ { label: "Stats", Panel: StatsPanel },
7521
+ { label: "Audit", Panel: AuditPanel },
7522
+ { label: "Agents", Panel: AgentsPanel }
7523
+ ];
7524
+ BANNER_HEX = ["#1432A0", "#2850BE", "#3C6ED7", "#5A8CE6", "#82AAF0", "#AAC8FA"];
7525
+ }
7526
+ });
7527
+
7528
+ // src/tui/index.tsx
7529
+ var tui_exports = {};
7530
+ __export(tui_exports, {
7531
+ launchTui: () => launchTui
7532
+ });
7533
+ import { render } from "ink";
7534
+ import { jsx as jsx9 } from "react/jsx-runtime";
7535
+ async function launchTui() {
7536
+ if (!process.stdout.isTTY || !process.stdin.isTTY) {
7537
+ process.stderr.write(
7538
+ "The SolonGate TUI needs an interactive terminal.\nUse the scriptable commands instead, e.g. `solongate stats`, `solongate policy list`.\n"
7539
+ );
7540
+ return;
7541
+ }
7542
+ if (!isAuthenticated()) {
7543
+ process.stderr.write("Not logged in. Run `solongate login` first.\n");
7544
+ return;
7545
+ }
7546
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx9(App, {}));
7547
+ await waitUntilExit();
7548
+ }
7549
+ var init_tui = __esm({
7550
+ "src/tui/index.tsx"() {
7551
+ "use strict";
7552
+ init_App();
7553
+ init_client();
7554
+ }
7555
+ });
7556
+
7557
+ // src/commands/format.ts
7558
+ function printJson(value) {
7559
+ out(JSON.stringify(value, null, 2));
7560
+ }
7561
+ function decisionColor2(decision) {
7562
+ const d = decision.toUpperCase();
7563
+ if (d === "ALLOW") return green(d);
7564
+ if (d === "DENY" || d === "DENIED") return red(d);
7565
+ return dim(d);
7566
+ }
7567
+ function table(headers, rows) {
7568
+ const cols = headers.length;
7569
+ const w = new Array(cols).fill(0);
7570
+ for (let i = 0; i < cols; i++) w[i] = width(headers[i] ?? "");
7571
+ for (const row of rows) {
7572
+ for (let i = 0; i < cols; i++) w[i] = Math.max(w[i], width(row[i] ?? ""));
7573
+ }
7574
+ const pad = (s, i) => s + " ".repeat(Math.max(0, w[i] - width(s)));
7575
+ err(" " + headers.map((h, i) => dim(pad(h, i))).join(" "));
7576
+ for (const row of rows) {
7577
+ err(" " + row.map((cell, i) => pad(cell ?? "", i)).join(" "));
7578
+ }
7579
+ }
7580
+ function truncate3(s, n) {
7581
+ if (s.length <= n) return s;
7582
+ return s.slice(0, Math.max(0, n - 1)) + "\u2026";
7583
+ }
7584
+ function sparkline2(values) {
7585
+ if (values.length === 0) return "";
7586
+ const max = Math.max(...values, 0);
7587
+ if (max === 0) return BLOCKS2[0].repeat(values.length);
7588
+ return values.map((v) => BLOCKS2[Math.min(BLOCKS2.length - 1, Math.round(v / max * (BLOCKS2.length - 1)))]).join("");
7589
+ }
7590
+ var out, err, dim, bold, green, red, yellow, cyan, ANSI, width, BLOCKS2;
7591
+ var init_format = __esm({
7592
+ "src/commands/format.ts"() {
7593
+ "use strict";
7594
+ init_cli_utils();
7595
+ out = (s = "") => void process.stdout.write(s + "\n");
7596
+ err = (s = "") => void process.stderr.write(s + "\n");
7597
+ dim = (s) => `${c.dim}${s}${c.reset}`;
7598
+ bold = (s) => `${c.bold}${s}${c.reset}`;
7599
+ green = (s) => `${c.green}${s}${c.reset}`;
7600
+ red = (s) => `${c.red}${s}${c.reset}`;
7601
+ yellow = (s) => `${c.yellow}${s}${c.reset}`;
7602
+ cyan = (s) => `${c.cyan}${s}${c.reset}`;
7603
+ ANSI = /\x1b\[[0-9;]*m/g;
7604
+ width = (s) => s.replace(ANSI, "").length;
7605
+ BLOCKS2 = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
7606
+ }
7607
+ });
7608
+
7609
+ // src/commands/args.ts
7610
+ function parse(argv) {
7611
+ const positionals = [];
7612
+ const flags = {};
7613
+ for (let i = 0; i < argv.length; i++) {
7614
+ const tok = argv[i];
7615
+ if (tok.startsWith("--")) {
7616
+ const body = tok.slice(2);
7617
+ const eq = body.indexOf("=");
7618
+ if (eq !== -1) {
7619
+ flags[body.slice(0, eq)] = body.slice(eq + 1);
7620
+ continue;
7621
+ }
7622
+ const next = argv[i + 1];
7623
+ if (next !== void 0 && !next.startsWith("--")) {
7624
+ flags[body] = next;
7625
+ i++;
7626
+ } else {
7627
+ flags[body] = true;
7628
+ }
7629
+ } else {
7630
+ positionals.push(tok);
7631
+ }
7632
+ }
7633
+ return { positionals, flags };
7634
+ }
7635
+ function flagStr(flags, name) {
7636
+ const v = flags[name];
7637
+ return typeof v === "string" ? v : void 0;
7638
+ }
7639
+ function flagNum(flags, name) {
7640
+ const v = flagStr(flags, name);
7641
+ if (v === void 0) return void 0;
7642
+ const n = Number(v);
7643
+ return Number.isFinite(n) ? n : void 0;
7644
+ }
7645
+ function flagBool(flags, name) {
7646
+ return flags[name] === true || flags[name] === "true";
7647
+ }
7648
+ var init_args = __esm({
7649
+ "src/commands/args.ts"() {
7650
+ "use strict";
7651
+ }
7652
+ });
7653
+
7654
+ // src/commands/policy.ts
7655
+ import { readFileSync as readFileSync5 } from "fs";
7656
+ async function run(argv) {
7657
+ const { positionals, flags } = parse(argv);
7658
+ const sub = positionals[0];
7659
+ const json = flagBool(flags, "json");
7660
+ switch (sub) {
7661
+ case void 0:
7662
+ case "help":
7663
+ err(USAGE);
7664
+ return sub ? 0 : 1;
7665
+ case "list": {
7666
+ const { policies } = await api.policies.list();
7667
+ if (json) return printJson(policies), 0;
7668
+ if (policies.length === 0) {
7669
+ err(dim(" No policies. Create one at https://dashboard.solongate.com"));
7670
+ return 0;
7671
+ }
7672
+ table(
7673
+ ["ID", "NAME", "MODE", "RULES", "VER", "UPDATED BY"],
7674
+ policies.map((p) => [
7675
+ cyan(p.id),
7676
+ truncate3(p.name, 28),
7677
+ p.mode === "whitelist" ? green("whitelist") : "denylist",
7678
+ String(p.rules?.length ?? 0),
7679
+ `v${p.version}`,
7680
+ dim(truncate3(p.created_by || "\u2014", 20))
7681
+ ])
7682
+ );
7683
+ return 0;
7684
+ }
7685
+ case "show": {
7686
+ const id = positionals[1];
7687
+ if (!id) return err(" Usage: policy show <id> [--version N]"), 1;
7688
+ const p = await api.policies.get(id, flagNum(flags, "version"));
7689
+ if (json) return printJson(p), 0;
7690
+ err("");
7691
+ err(` ${bold(p.name)} ${dim(`(${p.id})`)} v${p._version}`);
7692
+ if (p.description) err(` ${dim(p.description)}`);
7693
+ err(` mode: ${p.mode === "whitelist" ? green("whitelist") : "denylist"} rules: ${p.rules.length}`);
7694
+ err("");
7695
+ printRules(p.rules);
7696
+ return 0;
7697
+ }
7698
+ case "rules": {
7699
+ const id = positionals[1];
7700
+ if (!id) return err(" Usage: policy rules <id>"), 1;
7701
+ const p = await api.policies.get(id);
7702
+ if (json) return printJson(p.rules), 0;
7703
+ printRules(p.rules);
7704
+ return 0;
7705
+ }
7706
+ case "allow": {
7707
+ const id = positionals[1];
7708
+ if (!id) return err(" Usage: policy allow <id> --tool <pattern> [--command|--path|--url <val>]"), 1;
7709
+ const toolPattern = flagStr(flags, "tool") ?? "*";
7710
+ let kind = "tool";
7711
+ let value;
7712
+ for (const k of ["command", "path", "url"]) {
7713
+ const v = flagStr(flags, k);
7714
+ if (v !== void 0) {
7715
+ kind = k;
7716
+ value = v;
7717
+ }
7718
+ }
7719
+ const res = await api.policies.addRule(id, { toolPattern, kind, value });
7720
+ if (json) return printJson(res), 0;
7721
+ if (res.deduped) err(green(" \u2713 ") + dim("Equivalent ALLOW rule already present."));
7722
+ else err(green(` \u2713 Rule added`) + dim(` (${res.rule?.id}) \u2192 v${res.policy_version}`));
7723
+ return 0;
7724
+ }
7725
+ case "revoke": {
7726
+ const id = positionals[1];
7727
+ const ruleId = positionals[2];
7728
+ if (!id || !ruleId) return err(" Usage: policy revoke <id> <ruleId>"), 1;
7729
+ const res = await api.policies.revokeRule(id, ruleId);
7730
+ if (json) return printJson(res), 0;
7731
+ err(green(` \u2713 Revoked ${ruleId}`) + dim(` \u2192 v${res.policy_version}`));
7732
+ return 0;
7733
+ }
7734
+ case "versions": {
7735
+ const id = positionals[1];
7736
+ if (!id) return err(" Usage: policy versions <id>"), 1;
7737
+ const { versions: versions2 } = await api.policies.versions(id, { limit: flagNum(flags, "limit") });
7738
+ if (json) return printJson(versions2), 0;
7739
+ table(
7740
+ ["VER", "RULES", "REASON", "BY", "WHEN"],
7741
+ versions2.map((v) => [
7742
+ `v${v.version}`,
7743
+ String(v.rules_count),
7744
+ truncate3(v.reason || "\u2014", 40),
7745
+ dim(truncate3(v.created_by || "\u2014", 18)),
7746
+ dim(v.created_at)
7747
+ ])
7748
+ );
7749
+ return 0;
7750
+ }
7751
+ case "rollback": {
7752
+ const id = positionals[1];
7753
+ const version = Number(positionals[2]);
7754
+ if (!id || !Number.isFinite(version)) return err(" Usage: policy rollback <id> <version>"), 1;
7755
+ const res = await api.policies.rollback(id, version);
7756
+ if (json) return printJson(res), 0;
7757
+ err(green(` \u2713 Rolled back ${res.policy_id} from v${res.rolled_back_from} \u2192 v${res.version}`));
7758
+ return 0;
7759
+ }
7760
+ case "active": {
7761
+ const a = await api.policies.active();
7762
+ if (json) return printJson(a), 0;
7763
+ if (!a.policy) {
7764
+ err(dim(" No active policy resolves for this project."));
7765
+ return 0;
7766
+ }
7767
+ err("");
7768
+ err(` Active: ${bold(a.policy.name)} ${dim(`(${a.policy.id})`)} v${a.version}`);
7769
+ err(` matched by: ${cyan(a.matched_by ?? "\u2014")} self-protection: ${a.self_protection_enabled ? green("on") : dim("off")}`);
7770
+ const rl = a.security?.rateLimit;
7771
+ if (rl) err(` rate limit: ${rl.perMinute}/min ${rl.perHour}/h ${rl.perDay}/day`);
7772
+ if (a.security?.dlpBlock) err(` DLP block: ${a.security.dlpBlock.patterns.length} patterns`);
7773
+ return 0;
7774
+ }
7775
+ case "activate": {
7776
+ if (flagBool(flags, "clear")) {
7777
+ const res2 = await api.policies.setActive(null);
7778
+ if (json) return printJson(res2), 0;
7779
+ return err(green(" \u2713 Cleared active-policy pin.")), 0;
7780
+ }
7781
+ const id = positionals[1];
7782
+ if (!id) return err(" Usage: policy activate <id> | policy activate --clear"), 1;
7783
+ const res = await api.policies.setActive(id);
7784
+ if (json) return printJson(res), 0;
7785
+ err(green(` \u2713 Pinned active policy \u2192 ${res.active}`));
7786
+ return 0;
7787
+ }
7788
+ case "dry-run": {
7789
+ const target = positionals[1];
7790
+ if (!target) return err(" Usage: policy dry-run <id|file.json> [--limit N]"), 1;
7791
+ const rules = await resolveRules(target);
7792
+ const res = await api.policies.dryRun({
7793
+ rules,
7794
+ mode: flagStr(flags, "mode") ?? void 0,
7795
+ limit: flagNum(flags, "limit")
7796
+ });
7797
+ if (json) return printJson(res), 0;
7798
+ err("");
7799
+ err(` Replayed ${bold(String(res.evaluated))} recent calls against ${rules.length} rule(s)`);
7800
+ err(` would allow: ${green(String(res.would_allow))} would deny: ${decisionColor2("DENY")} ${res.would_deny}`);
7801
+ err(` ${green("newly allowed")}: ${res.newly_allowed} ${decisionColor2("DENY")}${dim(" newly blocked")}: ${res.newly_blocked} unchanged: ${res.unchanged}`);
7802
+ if (res.sample_newly_blocked.length) {
7803
+ err(dim("\n Sample newly-blocked:"));
7804
+ for (const s of res.sample_newly_blocked.slice(0, 8)) err(` ${decisionColor2("DENY")} ${s.tool} ${dim(truncate3(s.preview, 50))}`);
7805
+ }
7806
+ return 0;
7807
+ }
7808
+ default:
7809
+ err(` Unknown: policy ${sub}
7810
+ `);
7811
+ err(USAGE);
7812
+ return 1;
7813
+ }
7814
+ }
7815
+ function printRules(rules) {
7816
+ if (rules.length === 0) return void err(dim(" (no rules)"));
7817
+ table(
7818
+ ["EFFECT", "PRIO", "TOOL", "ID", "DESCRIPTION"],
7819
+ rules.map((r) => [
7820
+ r.effect === "ALLOW" ? green("ALLOW") : decisionColor2("DENY"),
7821
+ String(r.priority),
7822
+ cyan(truncate3(r.toolPattern, 24)),
7823
+ dim(truncate3(r.id, 22)),
7824
+ truncate3(r.description || "\u2014", 40)
7825
+ ])
7826
+ );
7827
+ }
7828
+ async function resolveRules(target) {
7829
+ if (target.endsWith(".json")) {
7830
+ const parsed = JSON.parse(readFileSync5(target, "utf-8"));
7831
+ return parsed.rules ?? [];
7832
+ }
7833
+ const p = await api.policies.get(target);
7834
+ return p.rules;
7835
+ }
7836
+ var USAGE;
7837
+ var init_policy = __esm({
7838
+ "src/commands/policy.ts"() {
7839
+ "use strict";
7840
+ init_api_client();
7841
+ init_args();
7842
+ init_format();
7843
+ USAGE = `${bold("solongate policy")} \u2014 manage cloud policies
7844
+
7845
+ policy list List all policies
7846
+ policy show <id> [--version N] Show one policy (rules, mode)
7847
+ policy rules <id> List a policy's rules
7848
+ policy allow <id> --tool <p> [--command|--path|--url <val>]
7849
+ Append an ALLOW rule
7850
+ policy revoke <id> <ruleId> Remove a rule
7851
+ policy versions <id> List version history
7852
+ policy rollback <id> <version> Roll back to a version
7853
+ policy active Show the resolved active policy
7854
+ policy activate <id> | --clear Pin / unpin the active policy
7855
+ policy dry-run <id|file.json> [--limit N] [--mode denylist|whitelist]
7856
+ Replay recent traffic against a policy's rules
7857
+
7858
+ Add --json to any read command for machine-readable output.`;
7859
+ }
7860
+ });
7861
+
7862
+ // src/commands/ratelimit.ts
7863
+ async function run2(argv) {
7864
+ const { positionals, flags } = parse(argv);
7865
+ const sub = positionals[0] ?? "show";
7866
+ const json = flagBool(flags, "json");
7867
+ switch (sub) {
7868
+ case "help":
7869
+ return err(USAGE2), 0;
7870
+ case "show": {
7871
+ const [{ layers }, { history }] = await Promise.all([
7872
+ api.settings.getSecurityLayers(),
7873
+ api.settings.getRateLimitHistory()
7874
+ ]);
7875
+ if (json) return printJson({ rateLimit: layers.rateLimit, history }), 0;
7876
+ const rl = layers.rateLimit;
7877
+ err("");
7878
+ err(` Rate limit mode: ${modeColor2(rl.mode)}`);
7879
+ err(` ${bold(String(rl.perMinute))} ${dim("/min")} ${bold(String(rl.perHour))} ${dim("/hour")} ${bold(String(rl.perDay))} ${dim("/day")}`);
7880
+ if (history.length) {
7881
+ const spark = sparkline2(history.map((h) => h.minute));
7882
+ err(` history ${cyan(spark)} ${dim(`(${history.length} changes, per-min)`)}`);
7883
+ }
7884
+ return 0;
7885
+ }
7886
+ case "history": {
7887
+ const { history } = await api.settings.getRateLimitHistory();
7888
+ if (json) return printJson(history), 0;
7889
+ if (!history.length) return err(dim(" No rate-limit changes recorded.")), 0;
7890
+ table(
7891
+ ["WHEN", "MINUTE", "HOUR", "DAY"],
7892
+ history.map((h) => [dim(new Date(h.ts).toISOString()), String(h.minute), String(h.hour), String(h.day)])
7893
+ );
7894
+ return 0;
7895
+ }
7896
+ case "set": {
7897
+ const minute = flagNum(flags, "minute");
7898
+ const hour = flagNum(flags, "hour");
7899
+ const day = flagNum(flags, "day");
7900
+ const mode = flagStr(flags, "mode");
7901
+ if (minute === void 0 && hour === void 0 && day === void 0 && !mode) {
7902
+ return err(" Usage: ratelimit set --minute N [--hour N] [--day N] [--mode off|detect|block]"), 1;
7903
+ }
7904
+ const { layers } = await api.settings.getSecurityLayers();
7905
+ const next = {
7906
+ ...layers,
7907
+ rateLimit: {
7908
+ mode: mode ?? layers.rateLimit.mode,
7909
+ perMinute: minute ?? layers.rateLimit.perMinute,
7910
+ perHour: hour ?? layers.rateLimit.perHour,
7911
+ perDay: day ?? layers.rateLimit.perDay
7912
+ }
7913
+ };
7914
+ const res = await api.settings.setSecurityLayers(next);
7915
+ if (json) return printJson(res.layers.rateLimit), 0;
7916
+ const r = res.layers.rateLimit;
7917
+ err(green(" \u2713 Rate limit updated") + dim(` ${r.perMinute}/min ${r.perHour}/h ${r.perDay}/day (${r.mode})`));
7918
+ return 0;
7919
+ }
7920
+ default:
7921
+ return err(USAGE2), 1;
7922
+ }
7923
+ }
7924
+ var USAGE2, modeColor2;
7925
+ var init_ratelimit = __esm({
7926
+ "src/commands/ratelimit.ts"() {
7927
+ "use strict";
7928
+ init_api_client();
7929
+ init_args();
7930
+ init_format();
7931
+ USAGE2 = `${bold("solongate ratelimit")} \u2014 request throttling
7932
+
7933
+ ratelimit show Current limits + change history
7934
+ ratelimit set --minute N [--hour N] [--day N] [--mode off|detect|block]
7935
+ ratelimit history Recent limit changes
7936
+
7937
+ Add --json for machine-readable output.`;
7938
+ modeColor2 = (m) => m === "block" ? green(m) : m === "detect" ? yellow(m) : dim(m);
7939
+ }
7940
+ });
7941
+
7942
+ // src/commands/dlp.ts
7943
+ async function run3(argv) {
7944
+ const { positionals, flags } = parse(argv);
7945
+ const sub = positionals[0] ?? "show";
7946
+ const json = flagBool(flags, "json");
7947
+ const { layers, availablePatterns } = await api.settings.getSecurityLayers();
7948
+ const save = async (next) => (await api.settings.setSecurityLayers(next)).layers;
7949
+ switch (sub) {
7950
+ case "help":
7951
+ return err(USAGE3), 0;
7952
+ case "show": {
7953
+ if (json) return printJson({ dlp: layers.dlp, availablePatterns }), 0;
7954
+ err("");
7955
+ err(` DLP mode: ${modeColor3(layers.dlp.mode)}`);
7956
+ const enabled = new Set(layers.dlp.patterns);
7957
+ table(
7958
+ ["", "PATTERN"],
7959
+ availablePatterns.map((p) => [enabled.has(p) ? green("\u25CF") : dim("\u25CB"), enabled.has(p) ? p : dim(p)])
7960
+ );
7961
+ if (layers.dlp.custom.length) {
7962
+ err(dim("\n Custom:"));
7963
+ for (const c2 of layers.dlp.custom) err(` ${cyan(c2.name)} ${dim(c2.re)}`);
7964
+ }
7965
+ return 0;
7966
+ }
7967
+ case "mode": {
7968
+ const mode = positionals[1];
7969
+ if (!mode || !["off", "detect", "block"].includes(mode)) return err(" Usage: dlp mode <off|detect|block>"), 1;
7970
+ const saved = await save({ ...layers, dlp: { ...layers.dlp, mode } });
7971
+ if (json) return printJson(saved.dlp), 0;
7972
+ return err(green(` \u2713 DLP mode \u2192 ${saved.dlp.mode}`)), 0;
7973
+ }
7974
+ case "enable":
7975
+ case "disable": {
7976
+ const pattern = positionals.slice(1).join(" ");
7977
+ if (!pattern) return err(` Usage: dlp ${sub} <pattern>`), 1;
7978
+ if (!availablePatterns.includes(pattern)) {
7979
+ err(` Unknown pattern: "${pattern}". Available:`);
7980
+ for (const p of availablePatterns) err(` ${dim("\u2022")} ${p}`);
7981
+ return 1;
7982
+ }
7983
+ const set = new Set(layers.dlp.patterns);
7984
+ if (sub === "enable") set.add(pattern);
7985
+ else set.delete(pattern);
7986
+ const saved = await save({ ...layers, dlp: { ...layers.dlp, patterns: [...set] } });
7987
+ if (json) return printJson(saved.dlp), 0;
7988
+ return err(green(` \u2713 ${sub}d "${pattern}"`) + dim(` (${saved.dlp.patterns.length} active)`)), 0;
7989
+ }
7990
+ case "add-custom": {
7991
+ const name = flagStr(flags, "name");
7992
+ const re = flagStr(flags, "re");
7993
+ if (!name || !re) return err(" Usage: dlp add-custom --name <name> --re <regex>"), 1;
7994
+ const custom = [...layers.dlp.custom.filter((c2) => c2.name !== name), { name, re }];
7995
+ const saved = await save({ ...layers, dlp: { ...layers.dlp, custom } });
7996
+ if (json) return printJson(saved.dlp), 0;
7997
+ return err(green(` \u2713 Custom pattern "${name}" added`)), 0;
7998
+ }
7999
+ case "remove-custom": {
8000
+ const name = positionals.slice(1).join(" ");
8001
+ if (!name) return err(" Usage: dlp remove-custom <name>"), 1;
8002
+ const custom = layers.dlp.custom.filter((c2) => c2.name !== name);
8003
+ const saved = await save({ ...layers, dlp: { ...layers.dlp, custom } });
8004
+ if (json) return printJson(saved.dlp), 0;
8005
+ return err(green(` \u2713 Removed custom pattern "${name}"`)), 0;
8006
+ }
8007
+ default:
8008
+ return err(USAGE3), 1;
8009
+ }
8010
+ }
8011
+ var USAGE3, modeColor3;
8012
+ var init_dlp = __esm({
8013
+ "src/commands/dlp.ts"() {
8014
+ "use strict";
8015
+ init_api_client();
8016
+ init_args();
8017
+ init_format();
8018
+ USAGE3 = `${bold("solongate dlp")} \u2014 data-loss prevention
8019
+
8020
+ dlp show Current mode + enabled patterns
8021
+ dlp mode <off|detect|block> Set enforcement mode
8022
+ dlp enable <pattern> Enable a built-in pattern
8023
+ dlp disable <pattern> Disable a built-in pattern
8024
+ dlp add-custom --name X --re <regex> Add a custom pattern
8025
+ dlp remove-custom <name> Remove a custom pattern
8026
+
8027
+ Add --json for machine-readable output.`;
8028
+ modeColor3 = (m) => m === "block" ? green(m) : m === "detect" ? yellow(m) : dim(m);
8029
+ }
8030
+ });
8031
+
8032
+ // src/commands/stats.ts
8033
+ async function run4(argv) {
8034
+ const { positionals, flags } = parse(argv);
8035
+ const sub = positionals[0] ?? "overview";
8036
+ const json = flagBool(flags, "json");
8037
+ switch (sub) {
8038
+ case "help":
8039
+ return err(USAGE4), 0;
8040
+ case "overview": {
8041
+ const s = await api.stats.get();
8042
+ if (json) return printJson(s), 0;
8043
+ err("");
8044
+ err(` ${bold(String(s.total_calls))} calls ${green(String(s.allowed))} allowed ${red(String(s.denied))} denied`);
8045
+ err(` ${dim(`${s.active_policies} active policies \xB7 ${s.registered_tools} tools`)}`);
8046
+ if (s.recent_activity.length) {
8047
+ err(dim("\n Recent:"));
8048
+ table(
8049
+ ["DECISION", "TOOL", "TRUST", "MS", "WHEN"],
8050
+ s.recent_activity.map((a) => [
8051
+ decisionColor2(a.decision),
8052
+ cyan(truncate3(a.tool_name, 24)),
8053
+ dim(a.trust_level),
8054
+ String(a.evaluation_time_ms ?? "\u2014"),
8055
+ dim(a.created_at)
8056
+ ])
8057
+ );
8058
+ }
8059
+ return 0;
8060
+ }
8061
+ case "timeseries": {
8062
+ const period = flagStr(flags, "period") ?? "24h";
8063
+ const ts = await api.stats.timeseries({ period });
8064
+ if (json) return printJson(ts), 0;
8065
+ const pts = ts.timeseries;
8066
+ err("");
8067
+ err(` Timeseries ${dim(`(${ts.period}, per ${ts.granularity})`)}`);
8068
+ err(` total ${cyan(sparkline2(pts.map((p) => p.total)))} ${dim(`max ${Math.max(0, ...pts.map((p) => p.total))}`)}`);
8069
+ err(` allowed ${green(sparkline2(pts.map((p) => p.allowed)))}`);
8070
+ err(` denied ${red(sparkline2(pts.map((p) => p.denied)))}`);
8071
+ return 0;
8072
+ }
8073
+ case "drift": {
8074
+ const d = await api.stats.drift(flagNum(flags, "days"));
8075
+ if (json) return printJson(d), 0;
8076
+ err("");
8077
+ err(` Denial drift ${dim(`(${d.days}d: ${d.total_current} now vs ${d.total_previous} prev)`)}`);
8078
+ if (!d.rules.length) return err(dim(" No denials in window.")), 0;
8079
+ table(
8080
+ ["NOW", "PREV", "\u0394", "RULE", "REASON"],
8081
+ d.rules.slice(0, 20).map((r) => [
8082
+ bold(String(r.current)),
8083
+ dim(String(r.previous)),
8084
+ r.is_new ? green("NEW") : r.spike ? red(`+${r.delta}`) : String(r.delta),
8085
+ cyan(truncate3(r.rule_id ?? "\u2014", 22)),
8086
+ truncate3(r.reason ?? r.last_tool ?? "\u2014", 36)
8087
+ ])
8088
+ );
8089
+ return 0;
8090
+ }
8091
+ default:
8092
+ return err(USAGE4), 1;
8093
+ }
8094
+ }
8095
+ var USAGE4;
8096
+ var init_stats2 = __esm({
8097
+ "src/commands/stats.ts"() {
8098
+ "use strict";
8099
+ init_api_client();
8100
+ init_args();
8101
+ init_format();
8102
+ USAGE4 = `${bold("solongate stats")} \u2014 traffic & security stats
8103
+
8104
+ stats Overview (totals, recent activity)
8105
+ stats timeseries [--period 24h|7d|30d|all]
8106
+ stats drift [--days N] Denials rising/falling vs previous window
8107
+
8108
+ Add --json for machine-readable output.`;
8109
+ }
8110
+ });
8111
+
8112
+ // src/commands/audit.ts
8113
+ async function run5(argv) {
8114
+ const { positionals, flags } = parse(argv);
8115
+ const json = flagBool(flags, "json");
8116
+ if (positionals[0] === "help") return err(USAGE5), 0;
8117
+ if (positionals[0] === "whitelist") {
8118
+ const id = positionals[1];
8119
+ if (!id) return err(" Usage: audit whitelist <logId> [--scope exact|tool]"), 1;
8120
+ const scope = flagStr(flags, "scope") ?? "exact";
8121
+ const res2 = await api.audit.whitelist(id, scope);
8122
+ if (json) return printJson(res2), 0;
8123
+ if (res2.deduped) err(green(" \u2713 ") + dim("Equivalent ALLOW already present."));
8124
+ else err(green(` \u2713 Whitelisted (${res2.scope})`) + dim(` \u2192 ${res2.policy_id} v${res2.policy_version}`));
8125
+ return 0;
8126
+ }
8127
+ const query = {
8128
+ filter: flagStr(flags, "filter"),
8129
+ tool: flagStr(flags, "tool"),
8130
+ signal: flagStr(flags, "signal"),
8131
+ search: flagStr(flags, "search"),
8132
+ agent_name: flagStr(flags, "agent-name"),
8133
+ limit: flagNum(flags, "limit") ?? 30
8134
+ };
8135
+ const res = await api.audit.list(query);
8136
+ if (json) return printJson(res), 0;
8137
+ err("");
8138
+ err(` ${bold(String(res.total))} matching entries ${dim(`(showing ${res.entries.length})`)}`);
8139
+ if (!res.entries.length) return 0;
8140
+ table(
8141
+ ["DECISION", "TOOL", "AGENT", "REASON", "DLP", "WHEN", "ID"],
8142
+ res.entries.map((e) => [
8143
+ decisionColor2(e.decision),
8144
+ cyan(truncate3(e.tool_name, 22)),
8145
+ dim(truncate3(e.agent_name ?? "\u2014", 16)),
8146
+ truncate3(e.reason ?? "\u2014", 30),
8147
+ e.dlp_matches?.length ? red(String(e.dlp_matches.length)) : dim("0"),
8148
+ dim(e.created_at),
8149
+ dim(truncate3(e.id, 10))
8150
+ ])
8151
+ );
8152
+ return 0;
8153
+ }
8154
+ var USAGE5;
8155
+ var init_audit2 = __esm({
8156
+ "src/commands/audit.ts"() {
8157
+ "use strict";
8158
+ init_api_client();
8159
+ init_args();
8160
+ init_format();
8161
+ USAGE5 = `${bold("solongate audit")} \u2014 audit log
8162
+
8163
+ audit [--filter ALLOW|DENY] [--tool <substr>] [--signal dlp|ratelimit]
8164
+ [--search <text>] [--agent-name <name>] [--limit N]
8165
+ audit whitelist <logId> [--scope exact|tool]
8166
+ Turn a denied call into an ALLOW rule
8167
+
8168
+ Add --json for machine-readable output.`;
8169
+ }
8170
+ });
8171
+
8172
+ // src/commands/agents.ts
8173
+ async function runAgents(argv) {
8174
+ const { flags } = parse(argv);
8175
+ const json = flagBool(flags, "json");
8176
+ const res = await api.agents.live({ limit: flagNum(flags, "limit"), includeDeactivated: flagBool(flags, "all") });
8177
+ if (json) return printJson(res), 0;
8178
+ err("");
8179
+ err(` Agents ${green(String(res.counts.active))} active ${yellow(String(res.counts.idle))} idle ${dim(String(res.counts.deactivated) + " off")}`);
8180
+ if (!res.agents.length) return err(dim(" No agent sessions.")), 0;
8181
+ table(
8182
+ ["STATUS", "AGENT", "CALLS", "DENY", "DLP", "TRUST", "CHARACTER"],
8183
+ res.agents.map((a) => [
8184
+ statusColor(a.status),
8185
+ cyan(truncate3(a.agent_name ?? a.agent_id ?? a.session_id, 20)),
8186
+ String(a.total_calls),
8187
+ a.denied_calls ? red(String(a.denied_calls)) : dim("0"),
8188
+ a.dlp_events ? red(String(a.dlp_events)) : dim("0"),
8189
+ `${a.trust_score}`,
8190
+ dim(truncate3(a.character || "\u2014", 22))
8191
+ ])
8192
+ );
8193
+ return 0;
8194
+ }
8195
+ async function runAgent(argv) {
8196
+ const { positionals, flags } = parse(argv);
8197
+ const json = flagBool(flags, "json");
8198
+ const id = positionals[0];
8199
+ if (!id) return err(" Usage: solongate agent <agent_id> [--json]"), 1;
8200
+ const a = await api.agents.get(id);
8201
+ if (json) return printJson(a), 0;
8202
+ err("");
8203
+ err(` ${bold(a.agent_id)} status: ${statusColor(String(a.status))}`);
8204
+ const base = a.baseline;
8205
+ if (base) {
8206
+ err(` ${dim(base.character ?? "")} trust ${bold(String(base.trustScore ?? "\u2014"))}/100 deny-rate ${(Number(base.denyRate ?? 0) * 100).toFixed(0)}%`);
8207
+ }
8208
+ const feed = a.recent_feed ?? [];
8209
+ if (feed.length) {
8210
+ err(dim("\n Recent:"));
8211
+ table(
8212
+ ["DECISION", "TOOL", "REASON", "WHEN"],
8213
+ feed.slice(0, 15).map((f) => [
8214
+ f.decision === "ALLOW" ? green("ALLOW") : red(String(f.decision)),
8215
+ cyan(truncate3(String(f.tool), 22)),
8216
+ truncate3(String(f.reason ?? "\u2014"), 30),
8217
+ dim(String(f.created_at))
8218
+ ])
8219
+ );
8220
+ }
8221
+ return 0;
8222
+ }
8223
+ var statusColor;
8224
+ var init_agents2 = __esm({
8225
+ "src/commands/agents.ts"() {
8226
+ "use strict";
8227
+ init_api_client();
8228
+ init_args();
8229
+ init_format();
8230
+ statusColor = (s) => s === "active" ? green(s) : s === "idle" ? yellow(s) : dim(s);
8231
+ }
8232
+ });
8233
+
8234
+ // src/commands/index.ts
8235
+ var commands_exports = {};
8236
+ __export(commands_exports, {
8237
+ COMMAND_NAMES: () => COMMAND_NAMES,
8238
+ runCommand: () => runCommand
8239
+ });
8240
+ async function dispatch(command, argv) {
8241
+ switch (command) {
8242
+ case "policy":
8243
+ return run(argv);
8244
+ case "ratelimit":
8245
+ return run2(argv);
8246
+ case "dlp":
8247
+ return run3(argv);
8248
+ case "stats":
8249
+ return run4(argv);
8250
+ case "audit":
8251
+ return run5(argv);
8252
+ case "agents":
8253
+ return runAgents(argv);
8254
+ case "agent":
8255
+ return runAgent(argv);
8256
+ default:
8257
+ err(` Unknown command: ${command}`);
8258
+ return 1;
8259
+ }
8260
+ }
8261
+ async function runCommand(command, argv) {
8262
+ try {
8263
+ return await dispatch(command, argv);
8264
+ } catch (e) {
8265
+ if (e instanceof NotAuthenticatedError) {
8266
+ err(red(" \u2717 ") + e.message);
8267
+ return 1;
8268
+ }
8269
+ if (e instanceof ApiError) {
8270
+ err(red(" \u2717 ") + `${e.message}` + (e.status ? ` (${e.status})` : ""));
8271
+ return 1;
8272
+ }
8273
+ const msg = e instanceof Error ? e.message : String(e);
8274
+ err(red(" \u2717 ") + msg);
8275
+ return 1;
8276
+ }
8277
+ }
8278
+ var COMMAND_NAMES;
8279
+ var init_commands = __esm({
8280
+ "src/commands/index.ts"() {
8281
+ "use strict";
8282
+ init_api_client();
8283
+ init_format();
8284
+ init_policy();
8285
+ init_ratelimit();
8286
+ init_dlp();
8287
+ init_stats2();
8288
+ init_audit2();
8289
+ init_agents2();
8290
+ COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent"];
8291
+ }
8292
+ });
8293
+
6557
8294
  // src/global-install.ts
6558
8295
  var global_install_exports = {};
6559
8296
  __export(global_install_exports, {
@@ -6566,14 +8303,14 @@ __export(global_install_exports, {
6566
8303
  runGlobalRestore: () => runGlobalRestore,
6567
8304
  unlockProtected: () => unlockProtected
6568
8305
  });
6569
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
6570
- import { resolve as resolve3, join as join4, dirname } from "path";
6571
- import { homedir as homedir2 } from "os";
8306
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
8307
+ import { resolve as resolve4, join as join5, dirname } from "path";
8308
+ import { homedir as homedir3 } from "os";
6572
8309
  import { fileURLToPath } from "url";
6573
8310
  import { createInterface } from "readline";
6574
8311
  import { execFileSync as execFileSync2 } from "child_process";
6575
8312
  function lockFile(file) {
6576
- if (!existsSync3(file)) return;
8313
+ if (!existsSync4(file)) return;
6577
8314
  try {
6578
8315
  if (process.platform === "win32") {
6579
8316
  try {
@@ -6599,7 +8336,7 @@ function lockFile(file) {
6599
8336
  }
6600
8337
  }
6601
8338
  function unlockFile(file) {
6602
- if (!existsSync3(file)) return;
8339
+ if (!existsSync4(file)) return;
6603
8340
  try {
6604
8341
  if (process.platform === "win32") {
6605
8342
  try {
@@ -6631,10 +8368,10 @@ function unlockFile(file) {
6631
8368
  function protectedTargets() {
6632
8369
  const p = globalPaths();
6633
8370
  return [
6634
- join4(p.hooksDir, "guard.mjs"),
6635
- join4(p.hooksDir, "audit.mjs"),
6636
- join4(p.hooksDir, "stop.mjs"),
6637
- join4(p.hooksDir, "shield.mjs"),
8371
+ join5(p.hooksDir, "guard.mjs"),
8372
+ join5(p.hooksDir, "audit.mjs"),
8373
+ join5(p.hooksDir, "stop.mjs"),
8374
+ join5(p.hooksDir, "shield.mjs"),
6638
8375
  p.configPath,
6639
8376
  p.settingsPath
6640
8377
  ];
@@ -6646,26 +8383,26 @@ function unlockProtected() {
6646
8383
  for (const f of protectedTargets()) unlockFile(f);
6647
8384
  }
6648
8385
  function globalPaths() {
6649
- const home = homedir2();
6650
- const sgDir = join4(home, ".solongate");
6651
- const hooksDir = join4(sgDir, "hooks");
6652
- const claudeDir = join4(home, ".claude");
8386
+ const home = homedir3();
8387
+ const sgDir = join5(home, ".solongate");
8388
+ const hooksDir = join5(sgDir, "hooks");
8389
+ const claudeDir = join5(home, ".claude");
6653
8390
  return {
6654
8391
  home,
6655
8392
  sgDir,
6656
8393
  hooksDir,
6657
8394
  claudeDir,
6658
- settingsPath: join4(claudeDir, "settings.json"),
6659
- backupPath: join4(claudeDir, "settings.solongate.bak"),
6660
- configPath: join4(sgDir, "cloud-guard.json")
8395
+ settingsPath: join5(claudeDir, "settings.json"),
8396
+ backupPath: join5(claudeDir, "settings.solongate.bak"),
8397
+ configPath: join5(sgDir, "cloud-guard.json")
6661
8398
  };
6662
8399
  }
6663
8400
  function readHook(filename) {
6664
- return readFileSync4(join4(HOOKS_DIR, filename), "utf-8");
8401
+ return readFileSync6(join5(HOOKS_DIR, filename), "utf-8");
6665
8402
  }
6666
8403
  function readGuard() {
6667
- const bundled = join4(HOOKS_DIR, "guard.bundled.mjs");
6668
- return existsSync3(bundled) ? readFileSync4(bundled, "utf-8") : readHook("guard.mjs");
8404
+ const bundled = join5(HOOKS_DIR, "guard.bundled.mjs");
8405
+ return existsSync4(bundled) ? readFileSync6(bundled, "utf-8") : readHook("guard.mjs");
6669
8406
  }
6670
8407
  function ask(question) {
6671
8408
  const rl = createInterface({ input: process.stdin, output: process.stderr });
@@ -6678,12 +8415,12 @@ function runGlobalRestore() {
6678
8415
  const p = globalPaths();
6679
8416
  unlockProtected();
6680
8417
  removeClaudeShim();
6681
- if (existsSync3(p.backupPath)) {
6682
- writeFileSync3(p.settingsPath, readFileSync4(p.backupPath, "utf-8"));
8418
+ if (existsSync4(p.backupPath)) {
8419
+ writeFileSync3(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
6683
8420
  console.log(` Restored ${p.settingsPath} from backup.`);
6684
- } else if (existsSync3(p.settingsPath)) {
8421
+ } else if (existsSync4(p.settingsPath)) {
6685
8422
  try {
6686
- const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
8423
+ const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
6687
8424
  delete s.hooks;
6688
8425
  writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
6689
8426
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
@@ -6700,12 +8437,12 @@ function escapeRe(s) {
6700
8437
  function resolveRealClaude() {
6701
8438
  try {
6702
8439
  const finder = process.platform === "win32" ? "where" : "which";
6703
- const out = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
8440
+ const out2 = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
6704
8441
  if (process.platform === "win32") {
6705
8442
  const low = (s) => s.toLowerCase();
6706
- return out.find((l) => low(l).endsWith(".cmd")) || out.find((l) => low(l).endsWith(".exe")) || out.find((l) => low(l).endsWith(".bat")) || out[0] || null;
8443
+ return out2.find((l) => low(l).endsWith(".cmd")) || out2.find((l) => low(l).endsWith(".exe")) || out2.find((l) => low(l).endsWith(".bat")) || out2[0] || null;
6707
8444
  }
6708
- return out[0] || null;
8445
+ return out2[0] || null;
6709
8446
  } catch {
6710
8447
  return null;
6711
8448
  }
@@ -6719,11 +8456,11 @@ function shimTargets() {
6719
8456
  return [];
6720
8457
  }
6721
8458
  }
6722
- return [".bashrc", ".zshrc", ".profile"].map((f) => join4(homedir2(), f)).filter((f) => existsSync3(f));
8459
+ return [".bashrc", ".zshrc", ".profile"].map((f) => join5(homedir3(), f)).filter((f) => existsSync4(f));
6723
8460
  }
6724
8461
  function writeShimBlock(file, block) {
6725
8462
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
6726
- let content = existsSync3(file) ? readFileSync4(file, "utf-8") : "";
8463
+ let content = existsSync4(file) ? readFileSync6(file, "utf-8") : "";
6727
8464
  content = content.replace(re, "");
6728
8465
  if (block) {
6729
8466
  if (content.length && !content.endsWith("\n")) content += "\n";
@@ -6774,7 +8511,7 @@ async function runGlobalInstall(opts = {}) {
6774
8511
  let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
6775
8512
  if (!apiKey || apiKey === "sg_live_your_key_here") {
6776
8513
  try {
6777
- const cfg = JSON.parse(readFileSync4(p.configPath, "utf-8"));
8514
+ const cfg = JSON.parse(readFileSync6(p.configPath, "utf-8"));
6778
8515
  if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
6779
8516
  } catch {
6780
8517
  }
@@ -6790,18 +8527,18 @@ async function runGlobalInstall(opts = {}) {
6790
8527
  mkdirSync3(p.hooksDir, { recursive: true });
6791
8528
  mkdirSync3(p.claudeDir, { recursive: true });
6792
8529
  unlockProtected();
6793
- writeFileSync3(join4(p.hooksDir, "guard.mjs"), readGuard());
6794
- writeFileSync3(join4(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
6795
- writeFileSync3(join4(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
6796
- writeFileSync3(join4(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
8530
+ writeFileSync3(join5(p.hooksDir, "guard.mjs"), readGuard());
8531
+ writeFileSync3(join5(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
8532
+ writeFileSync3(join5(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
8533
+ writeFileSync3(join5(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
6797
8534
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
6798
8535
  removeClaudeShim();
6799
8536
  writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
6800
8537
  console.log(` Wrote ${p.configPath}`);
6801
8538
  let existing = {};
6802
- if (existsSync3(p.settingsPath)) {
6803
- const raw = readFileSync4(p.settingsPath, "utf-8");
6804
- if (!existsSync3(p.backupPath)) {
8539
+ if (existsSync4(p.settingsPath)) {
8540
+ const raw = readFileSync6(p.settingsPath, "utf-8");
8541
+ if (!existsSync4(p.backupPath)) {
6805
8542
  writeFileSync3(p.backupPath, raw);
6806
8543
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
6807
8544
  }
@@ -6811,9 +8548,9 @@ async function runGlobalInstall(opts = {}) {
6811
8548
  existing = {};
6812
8549
  }
6813
8550
  }
6814
- const guardAbs = join4(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
6815
- const auditAbs = join4(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
6816
- const stopAbs = join4(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
8551
+ const guardAbs = join5(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
8552
+ const auditAbs = join5(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
8553
+ const stopAbs = join5(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
6817
8554
  const nodeBin = process.execPath.replace(/\\/g, "/");
6818
8555
  const merged = {
6819
8556
  ...existing,
@@ -6838,7 +8575,7 @@ var init_global_install = __esm({
6838
8575
  "src/global-install.ts"() {
6839
8576
  "use strict";
6840
8577
  __dirname = dirname(fileURLToPath(import.meta.url));
6841
- HOOKS_DIR = resolve3(__dirname, "..", "hooks");
8578
+ HOOKS_DIR = resolve4(__dirname, "..", "hooks");
6842
8579
  SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
6843
8580
  SHIM_END = "# <<< SolonGate shield <<<";
6844
8581
  }
@@ -6987,8 +8724,8 @@ var init_login = __esm({
6987
8724
  init_global_install();
6988
8725
  sleep = (ms) => new Promise((r) => setTimeout(r, ms));
6989
8726
  SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
6990
- main().catch((err) => {
6991
- console.log(`Fatal: ${err instanceof Error ? err.message : String(err)}`);
8727
+ main().catch((err2) => {
8728
+ console.log(`Fatal: ${err2 instanceof Error ? err2.message : String(err2)}`);
6992
8729
  process.exit(1);
6993
8730
  });
6994
8731
  }
@@ -7003,21 +8740,21 @@ import { createServer, request as httpRequest } from "http";
7003
8740
  import { request as httpsRequest } from "https";
7004
8741
  import { spawn as spawn2 } from "child_process";
7005
8742
  import { URL as URL2 } from "url";
7006
- import { readFileSync as readFileSync5, existsSync as existsSync4, readdirSync, statSync } from "fs";
7007
- import { resolve as resolve4 } from "path";
7008
- import { homedir as homedir3 } from "os";
8743
+ import { readFileSync as readFileSync7, existsSync as existsSync5, readdirSync, statSync } from "fs";
8744
+ import { resolve as resolve5 } from "path";
8745
+ import { homedir as homedir4 } from "os";
7009
8746
  function findCacheFile() {
7010
- const dir = resolve4(homedir3(), ".solongate");
8747
+ const dir = resolve5(homedir4(), ".solongate");
7011
8748
  const envSel = process.env.SOLONGATE_AGENT_ID;
7012
8749
  if (envSel) {
7013
- const f = resolve4(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
7014
- if (existsSync4(f)) return f;
8750
+ const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
8751
+ if (existsSync5(f)) return f;
7015
8752
  }
7016
8753
  let best = null, bestTs = -1;
7017
8754
  try {
7018
8755
  for (const name of readdirSync(dir)) {
7019
8756
  if (name.startsWith(".policy-cache-") && name.endsWith(".json")) {
7020
- const full = resolve4(dir, name);
8757
+ const full = resolve5(dir, name);
7021
8758
  const ts = statSync(full).mtimeMs;
7022
8759
  if (ts > bestTs) {
7023
8760
  bestTs = ts;
@@ -7032,8 +8769,8 @@ function findCacheFile() {
7032
8769
  function loadCfg() {
7033
8770
  try {
7034
8771
  const f = findCacheFile();
7035
- if (f && existsSync4(f)) {
7036
- const c2 = JSON.parse(readFileSync5(f, "utf-8"));
8772
+ if (f && existsSync5(f)) {
8773
+ const c2 = JSON.parse(readFileSync7(f, "utf-8"));
7037
8774
  const d = c2?.security?.dlpRedact;
7038
8775
  const g = c2?.security?.ghost;
7039
8776
  const ghost = g && Array.isArray(g.patterns) ? g.patterns : [];
@@ -7146,31 +8883,31 @@ function dlpGlobToRe(glob, flags) {
7146
8883
  function redactString(s, cfg) {
7147
8884
  if (!cfg || typeof s !== "string" || !s) return s;
7148
8885
  const allow = new Set(cfg.patterns);
7149
- let out = s;
7150
- for (const p of DLP_PATTERNS) if (allow.has(p.name)) out = out.replace(p.re, `[REDACTED: ${p.name}]`);
8886
+ let out2 = s;
8887
+ for (const p of DLP_PATTERNS) if (allow.has(p.name)) out2 = out2.replace(p.re, `[REDACTED: ${p.name}]`);
7151
8888
  for (const c2 of cfg.custom) {
7152
8889
  try {
7153
- out = out.replace(dlpGlobToRe(c2.re, "g"), `[REDACTED: ${c2.name || "custom"}]`);
8890
+ out2 = out2.replace(dlpGlobToRe(c2.re, "g"), `[REDACTED: ${c2.name || "custom"}]`);
7154
8891
  } catch {
7155
8892
  }
7156
8893
  }
7157
- return out;
8894
+ return out2;
7158
8895
  }
7159
8896
  function redactDeep(value, cfg) {
7160
8897
  const ghost = cfg && Array.isArray(cfg.ghost) ? cfg.ghost : null;
7161
8898
  if (typeof value === "string") {
7162
- let out = redactString(value, cfg);
7163
- if (ghost && ghost.length) out = ghostStripLines(out, ghost);
7164
- return out;
8899
+ let out2 = redactString(value, cfg);
8900
+ if (ghost && ghost.length) out2 = ghostStripLines(out2, ghost);
8901
+ return out2;
7165
8902
  }
7166
8903
  if (Array.isArray(value)) {
7167
8904
  const arr = ghost && ghost.length ? value.filter((v) => !(typeof v === "string" && ghostMatch(v.trim(), ghost))) : value;
7168
8905
  return arr.map((v) => redactDeep(v, cfg));
7169
8906
  }
7170
8907
  if (value && typeof value === "object") {
7171
- const out = {};
7172
- for (const [k, v] of Object.entries(value)) out[k] = redactDeep(v, cfg);
7173
- return out;
8908
+ const out2 = {};
8909
+ for (const [k, v] of Object.entries(value)) out2[k] = redactDeep(v, cfg);
8910
+ return out2;
7174
8911
  }
7175
8912
  return value;
7176
8913
  }
@@ -7309,9 +9046,9 @@ __export(logs_server_exports, {
7309
9046
  runLogsServer: () => runLogsServer
7310
9047
  });
7311
9048
  import { createServer as createServer2 } from "http";
7312
- import { readFileSync as readFileSync6, statSync as statSync2 } from "fs";
7313
- import { resolve as resolve5, join as join5, isAbsolute } from "path";
7314
- import { homedir as homedir4 } from "os";
9049
+ import { readFileSync as readFileSync8, statSync as statSync2 } from "fs";
9050
+ import { resolve as resolve6, join as join6, isAbsolute } from "path";
9051
+ import { homedir as homedir5 } from "os";
7315
9052
  import { readdirSync as readdirSync2 } from "fs";
7316
9053
  function allowedOrigins() {
7317
9054
  const base = [
@@ -7328,15 +9065,15 @@ function resolveLocalLogDir(rawPath) {
7328
9065
  const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
7329
9066
  if (!dir) return null;
7330
9067
  if (isAbsolute(dir)) return dir;
7331
- return resolve5(homedir4(), ".solongate", "local-logs");
9068
+ return resolve6(homedir5(), ".solongate", "local-logs");
7332
9069
  }
7333
9070
  async function findLogDir() {
7334
- const base = resolve5(homedir4(), ".solongate");
9071
+ const base = resolve6(homedir5(), ".solongate");
7335
9072
  try {
7336
9073
  const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
7337
9074
  for (const f of files) {
7338
9075
  try {
7339
- const c2 = JSON.parse(readFileSync6(join5(base, f), "utf-8"));
9076
+ const c2 = JSON.parse(readFileSync8(join6(base, f), "utf-8"));
7340
9077
  const p = c2?.security?.localLogs?.path;
7341
9078
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
7342
9079
  } catch {
@@ -7345,7 +9082,7 @@ async function findLogDir() {
7345
9082
  } catch {
7346
9083
  }
7347
9084
  try {
7348
- const cfgRaw = readFileSync6(join5(base, "cloud-guard.json"), "utf-8");
9085
+ const cfgRaw = readFileSync8(join6(base, "cloud-guard.json"), "utf-8");
7349
9086
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
7350
9087
  if (apiKey) {
7351
9088
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -7374,7 +9111,7 @@ function setCors(req, res) {
7374
9111
  }
7375
9112
  function fileInfo(dir) {
7376
9113
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
7377
- const file = join5(dir, LOG_FILENAME);
9114
+ const file = join6(dir, LOG_FILENAME);
7378
9115
  try {
7379
9116
  const st = statSync2(file);
7380
9117
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
@@ -7435,7 +9172,7 @@ async function runLogsServer() {
7435
9172
  return;
7436
9173
  }
7437
9174
  try {
7438
- const text = readFileSync6(info.file, "utf-8");
9175
+ const text = readFileSync8(info.file, "utf-8");
7439
9176
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
7440
9177
  res.end(text);
7441
9178
  } catch {
@@ -7465,12 +9202,12 @@ async function runLogsServer() {
7465
9202
  process.stdout.write(`[SolonGate] Keep this running; the dashboard reads your logs live from here. Ctrl+C to stop.
7466
9203
  `);
7467
9204
  });
7468
- server.on("error", (err) => {
7469
- if (err.code === "EADDRINUSE") {
9205
+ server.on("error", (err2) => {
9206
+ if (err2.code === "EADDRINUSE") {
7470
9207
  process.stderr.write(`[SolonGate] Port ${port} is already in use. Pass --port <n> or set SOLONGATE_LOGS_PORT.
7471
9208
  `);
7472
9209
  } else {
7473
- process.stderr.write(`[SolonGate] Local logs agent error: ${err.message}
9210
+ process.stderr.write(`[SolonGate] Local logs agent error: ${err2.message}
7474
9211
  `);
7475
9212
  }
7476
9213
  process.exit(1);
@@ -7487,8 +9224,8 @@ var init_logs_server = __esm({
7487
9224
 
7488
9225
  // src/inject.ts
7489
9226
  var inject_exports = {};
7490
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync5, copyFileSync } from "fs";
7491
- import { resolve as resolve6 } from "path";
9227
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, existsSync as existsSync6, copyFileSync } from "fs";
9228
+ import { resolve as resolve7 } from "path";
7492
9229
  import { execSync } from "child_process";
7493
9230
  function parseInjectArgs(argv) {
7494
9231
  const args = argv.slice(2);
@@ -7545,9 +9282,9 @@ WHAT IT DOES
7545
9282
  `);
7546
9283
  }
7547
9284
  function detectProject() {
7548
- if (!existsSync5(resolve6("package.json"))) return false;
9285
+ if (!existsSync6(resolve7("package.json"))) return false;
7549
9286
  try {
7550
- const pkg = JSON.parse(readFileSync7(resolve6("package.json"), "utf-8"));
9287
+ const pkg = JSON.parse(readFileSync9(resolve7("package.json"), "utf-8"));
7551
9288
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
7552
9289
  return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
7553
9290
  } catch {
@@ -7556,18 +9293,18 @@ function detectProject() {
7556
9293
  }
7557
9294
  function findTsEntryFile() {
7558
9295
  try {
7559
- const pkg = JSON.parse(readFileSync7(resolve6("package.json"), "utf-8"));
9296
+ const pkg = JSON.parse(readFileSync9(resolve7("package.json"), "utf-8"));
7560
9297
  if (pkg.bin) {
7561
9298
  const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
7562
9299
  if (typeof binPath === "string") {
7563
9300
  const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
7564
- if (existsSync5(resolve6(srcPath))) return resolve6(srcPath);
7565
- if (existsSync5(resolve6(binPath))) return resolve6(binPath);
9301
+ if (existsSync6(resolve7(srcPath))) return resolve7(srcPath);
9302
+ if (existsSync6(resolve7(binPath))) return resolve7(binPath);
7566
9303
  }
7567
9304
  }
7568
9305
  if (pkg.main) {
7569
9306
  const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
7570
- if (existsSync5(resolve6(srcPath))) return resolve6(srcPath);
9307
+ if (existsSync6(resolve7(srcPath))) return resolve7(srcPath);
7571
9308
  }
7572
9309
  } catch {
7573
9310
  }
@@ -7580,10 +9317,10 @@ function findTsEntryFile() {
7580
9317
  "main.ts"
7581
9318
  ];
7582
9319
  for (const c2 of candidates) {
7583
- const full = resolve6(c2);
7584
- if (existsSync5(full)) {
9320
+ const full = resolve7(c2);
9321
+ if (existsSync6(full)) {
7585
9322
  try {
7586
- const content = readFileSync7(full, "utf-8");
9323
+ const content = readFileSync9(full, "utf-8");
7587
9324
  if (content.includes("McpServer") || content.includes("McpServer")) {
7588
9325
  return full;
7589
9326
  }
@@ -7592,18 +9329,18 @@ function findTsEntryFile() {
7592
9329
  }
7593
9330
  }
7594
9331
  for (const c2 of candidates) {
7595
- if (existsSync5(resolve6(c2))) return resolve6(c2);
9332
+ if (existsSync6(resolve7(c2))) return resolve7(c2);
7596
9333
  }
7597
9334
  return null;
7598
9335
  }
7599
9336
  function detectPackageManager() {
7600
- if (existsSync5(resolve6("pnpm-lock.yaml"))) return "pnpm";
7601
- if (existsSync5(resolve6("yarn.lock"))) return "yarn";
9337
+ if (existsSync6(resolve7("pnpm-lock.yaml"))) return "pnpm";
9338
+ if (existsSync6(resolve7("yarn.lock"))) return "yarn";
7602
9339
  return "npm";
7603
9340
  }
7604
9341
  function installSdk() {
7605
9342
  try {
7606
- const pkg = JSON.parse(readFileSync7(resolve6("package.json"), "utf-8"));
9343
+ const pkg = JSON.parse(readFileSync9(resolve7("package.json"), "utf-8"));
7607
9344
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
7608
9345
  if (allDeps["@solongate/proxy"]) {
7609
9346
  log3(" @solongate/proxy already installed");
@@ -7617,14 +9354,14 @@ function installSdk() {
7617
9354
  try {
7618
9355
  execSync(cmd, { stdio: "pipe", cwd: process.cwd() });
7619
9356
  return true;
7620
- } catch (err) {
7621
- log3(` Failed to install: ${err instanceof Error ? err.message : String(err)}`);
9357
+ } catch (err2) {
9358
+ log3(` Failed to install: ${err2 instanceof Error ? err2.message : String(err2)}`);
7622
9359
  log3(" You can install manually: npm install @solongate/proxy");
7623
9360
  return false;
7624
9361
  }
7625
9362
  }
7626
9363
  function injectTypeScript(filePath) {
7627
- const original = readFileSync7(filePath, "utf-8");
9364
+ const original = readFileSync9(filePath, "utf-8");
7628
9365
  const changes = [];
7629
9366
  let modified = original;
7630
9367
  if (modified.includes("SecureMcpServer")) {
@@ -7740,8 +9477,8 @@ async function main2() {
7740
9477
  process.exit(1);
7741
9478
  }
7742
9479
  log3(" Language: TypeScript");
7743
- const entryFile = opts.file ? resolve6(opts.file) : findTsEntryFile();
7744
- if (!entryFile || !existsSync5(entryFile)) {
9480
+ const entryFile = opts.file ? resolve7(opts.file) : findTsEntryFile();
9481
+ if (!entryFile || !existsSync6(entryFile)) {
7745
9482
  log3(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
7746
9483
  log3("");
7747
9484
  log3(" Specify it manually: --file <path>");
@@ -7754,7 +9491,7 @@ async function main2() {
7754
9491
  log3("");
7755
9492
  const backupPath = entryFile + ".solongate-backup";
7756
9493
  if (opts.restore) {
7757
- if (!existsSync5(backupPath)) {
9494
+ if (!existsSync6(backupPath)) {
7758
9495
  log3(" No backup found. Nothing to restore.");
7759
9496
  process.exit(1);
7760
9497
  }
@@ -7790,7 +9527,7 @@ async function main2() {
7790
9527
  log3(" To apply: npx @solongate/proxy inject");
7791
9528
  process.exit(0);
7792
9529
  }
7793
- if (!existsSync5(backupPath)) {
9530
+ if (!existsSync6(backupPath)) {
7794
9531
  copyFileSync(entryFile, backupPath);
7795
9532
  log3("");
7796
9533
  log3(` Backup: ${backupPath}`);
@@ -7815,8 +9552,8 @@ var init_inject = __esm({
7815
9552
  "src/inject.ts"() {
7816
9553
  "use strict";
7817
9554
  init_cli_utils();
7818
- main2().catch((err) => {
7819
- log3(`Fatal: ${err instanceof Error ? err.message : String(err)}`);
9555
+ main2().catch((err2) => {
9556
+ log3(`Fatal: ${err2 instanceof Error ? err2.message : String(err2)}`);
7820
9557
  process.exit(1);
7821
9558
  });
7822
9559
  }
@@ -7824,8 +9561,8 @@ var init_inject = __esm({
7824
9561
 
7825
9562
  // src/create.ts
7826
9563
  var create_exports = {};
7827
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as existsSync6 } from "fs";
7828
- import { resolve as resolve7, join as join6 } from "path";
9564
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
9565
+ import { resolve as resolve8, join as join7 } from "path";
7829
9566
  import { execSync as execSync2 } from "child_process";
7830
9567
  function withSpinner(message, fn) {
7831
9568
  const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
@@ -7840,11 +9577,11 @@ function withSpinner(message, fn) {
7840
9577
  process.stderr.write(`\r ${c.green}\u2713${c.reset} ${message}${" ".repeat(20)}
7841
9578
  `);
7842
9579
  return result;
7843
- } catch (err) {
9580
+ } catch (err2) {
7844
9581
  clearInterval(id);
7845
9582
  process.stderr.write(`\r ${c.red}\u2717${c.reset} ${message} \u2014 failed${" ".repeat(10)}
7846
9583
  `);
7847
- throw err;
9584
+ throw err2;
7848
9585
  }
7849
9586
  }
7850
9587
  function parseCreateArgs(argv) {
@@ -7905,7 +9642,7 @@ EXAMPLES
7905
9642
  }
7906
9643
  function createProject(dir, name, _policy) {
7907
9644
  writeFileSync5(
7908
- join6(dir, "package.json"),
9645
+ join7(dir, "package.json"),
7909
9646
  JSON.stringify(
7910
9647
  {
7911
9648
  name,
@@ -7935,7 +9672,7 @@ function createProject(dir, name, _policy) {
7935
9672
  ) + "\n"
7936
9673
  );
7937
9674
  writeFileSync5(
7938
- join6(dir, "tsconfig.json"),
9675
+ join7(dir, "tsconfig.json"),
7939
9676
  JSON.stringify(
7940
9677
  {
7941
9678
  compilerOptions: {
@@ -7955,9 +9692,9 @@ function createProject(dir, name, _policy) {
7955
9692
  2
7956
9693
  ) + "\n"
7957
9694
  );
7958
- mkdirSync4(join6(dir, "src"), { recursive: true });
9695
+ mkdirSync4(join7(dir, "src"), { recursive: true });
7959
9696
  writeFileSync5(
7960
- join6(dir, "src", "index.ts"),
9697
+ join7(dir, "src", "index.ts"),
7961
9698
  `#!/usr/bin/env node
7962
9699
 
7963
9700
  console.log = (...args: unknown[]) => {
@@ -7999,7 +9736,7 @@ console.log('Press Ctrl+C to stop.');
7999
9736
  `
8000
9737
  );
8001
9738
  writeFileSync5(
8002
- join6(dir, ".mcp.json"),
9739
+ join7(dir, ".mcp.json"),
8003
9740
  JSON.stringify(
8004
9741
  {
8005
9742
  mcpServers: {
@@ -8017,12 +9754,12 @@ console.log('Press Ctrl+C to stop.');
8017
9754
  ) + "\n"
8018
9755
  );
8019
9756
  writeFileSync5(
8020
- join6(dir, ".env"),
9757
+ join7(dir, ".env"),
8021
9758
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
8022
9759
  `
8023
9760
  );
8024
9761
  writeFileSync5(
8025
- join6(dir, ".gitignore"),
9762
+ join7(dir, ".gitignore"),
8026
9763
  `node_modules/
8027
9764
  dist/
8028
9765
  *.solongate-backup
@@ -8034,9 +9771,9 @@ dist/
8034
9771
  }
8035
9772
  async function main3() {
8036
9773
  const opts = parseCreateArgs(process.argv);
8037
- const dir = resolve7(opts.name);
9774
+ const dir = resolve8(opts.name);
8038
9775
  printBanner("Create MCP Server");
8039
- if (existsSync6(dir)) {
9776
+ if (existsSync7(dir)) {
8040
9777
  log3(` ${c.red}Error:${c.reset} Directory "${opts.name}" already exists.`);
8041
9778
  process.exit(1);
8042
9779
  }
@@ -8106,8 +9843,8 @@ var init_create = __esm({
8106
9843
  "src/create.ts"() {
8107
9844
  "use strict";
8108
9845
  init_cli_utils();
8109
- main3().catch((err) => {
8110
- log3(`Fatal: ${err instanceof Error ? err.message : String(err)}`);
9846
+ main3().catch((err2) => {
9847
+ log3(`Fatal: ${err2 instanceof Error ? err2.message : String(err2)}`);
8111
9848
  process.exit(1);
8112
9849
  });
8113
9850
  }
@@ -8115,14 +9852,14 @@ var init_create = __esm({
8115
9852
 
8116
9853
  // src/pull-push.ts
8117
9854
  var pull_push_exports = {};
8118
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync7 } from "fs";
8119
- import { resolve as resolve8 } from "path";
9855
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync8 } from "fs";
9856
+ import { resolve as resolve9 } from "path";
8120
9857
  function loadEnv() {
8121
9858
  if (process.env.SOLONGATE_API_KEY) return;
8122
- const envPath = resolve8(".env");
8123
- if (!existsSync7(envPath)) return;
9859
+ const envPath = resolve9(".env");
9860
+ if (!existsSync8(envPath)) return;
8124
9861
  try {
8125
- const content = readFileSync8(envPath, "utf-8");
9862
+ const content = readFileSync10(envPath, "utf-8");
8126
9863
  for (const line of content.split("\n")) {
8127
9864
  const trimmed = line.trim();
8128
9865
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -8164,7 +9901,7 @@ function parseCliArgs() {
8164
9901
  }
8165
9902
  }
8166
9903
  if (!apiKey) {
8167
- log5(red("ERROR: API key not found."));
9904
+ log5(red2("ERROR: API key not found."));
8168
9905
  log5("");
8169
9906
  log5("Set it in .env file:");
8170
9907
  log5(" SOLONGATE_API_KEY=sg_live_...");
@@ -8174,10 +9911,10 @@ function parseCliArgs() {
8174
9911
  process.exit(1);
8175
9912
  }
8176
9913
  if (!apiKey.startsWith("sg_live_")) {
8177
- log5(red("ERROR: Pull/push/list requires a live API key (sg_live_...)."));
9914
+ log5(red2("ERROR: Pull/push/list requires a live API key (sg_live_...)."));
8178
9915
  process.exit(1);
8179
9916
  }
8180
- return { command, apiKey, file: resolve8(file), policyId };
9917
+ return { command, apiKey, file: resolve9(file), policyId };
8181
9918
  }
8182
9919
  async function listPolicies(apiKey) {
8183
9920
  const res = await fetch(`${API_URL}/api/v1/policies`, {
@@ -8187,21 +9924,21 @@ async function listPolicies(apiKey) {
8187
9924
  const data = await res.json();
8188
9925
  return data.policies ?? [];
8189
9926
  }
8190
- async function list(apiKey, policyId) {
9927
+ async function list3(apiKey, policyId) {
8191
9928
  const policies = await listPolicies(apiKey);
8192
9929
  if (policies.length === 0) {
8193
- log5(yellow("No policies found. Create one in the dashboard first."));
8194
- log5(dim(" https://dashboard.solongate.com/policies"));
9930
+ log5(yellow2("No policies found. Create one in the dashboard first."));
9931
+ log5(dim2(" https://dashboard.solongate.com/policies"));
8195
9932
  return;
8196
9933
  }
8197
9934
  if (policyId) {
8198
9935
  const match = policies.find((p) => p.id === policyId);
8199
9936
  if (!match) {
8200
- log5(red(`Policy not found: ${policyId}`));
9937
+ log5(red2(`Policy not found: ${policyId}`));
8201
9938
  log5("");
8202
9939
  log5("Available policies:");
8203
9940
  for (const p of policies) {
8204
- log5(` ${dim("\u2022")} ${p.id}`);
9941
+ log5(` ${dim2("\u2022")} ${p.id}`);
8205
9942
  }
8206
9943
  process.exit(1);
8207
9944
  }
@@ -8210,8 +9947,8 @@ async function list(apiKey, policyId) {
8210
9947
  return;
8211
9948
  }
8212
9949
  log5("");
8213
- log5(bold(` Policies (${policies.length})`));
8214
- log5(dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
9950
+ log5(bold2(` Policies (${policies.length})`));
9951
+ log5(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8215
9952
  log5("");
8216
9953
  const fullPolicies = await Promise.all(
8217
9954
  policies.map(
@@ -8221,113 +9958,113 @@ async function list(apiKey, policyId) {
8221
9958
  for (const { policy, rules } of fullPolicies) {
8222
9959
  printPolicySummary(policy, [...rules]);
8223
9960
  }
8224
- log5(dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
9961
+ log5(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8225
9962
  log5("");
8226
- log5(` ${dim("View details:")} solongate-proxy list --policy-id <ID>`);
8227
- log5(` ${dim("Pull policy:")} solongate-proxy pull --policy-id <ID>`);
8228
- log5(` ${dim("Push policy:")} solongate-proxy push --policy-id <ID>`);
9963
+ log5(` ${dim2("View details:")} solongate-proxy list --policy-id <ID>`);
9964
+ log5(` ${dim2("Pull policy:")} solongate-proxy pull --policy-id <ID>`);
9965
+ log5(` ${dim2("Push policy:")} solongate-proxy push --policy-id <ID>`);
8229
9966
  log5("");
8230
9967
  }
8231
9968
  function printPolicySummary(p, rules) {
8232
9969
  const ruleCount = rules.length;
8233
9970
  const allowCount = rules.filter((r) => r.effect === "ALLOW").length;
8234
9971
  const denyCount = rules.filter((r) => r.effect === "DENY").length;
8235
- log5(` ${cyan(p.id)}`);
8236
- log5(` ${bold(p.name)} ${dim(`v${p.version ?? "?"}`)}`);
8237
- log5(` ${dim("Rules:")} ${ruleCount} ${green(`${allowCount} ALLOW`)} ${red(`${denyCount} DENY`)}`);
9972
+ log5(` ${cyan2(p.id)}`);
9973
+ log5(` ${bold2(p.name)} ${dim2(`v${p.version ?? "?"}`)}`);
9974
+ log5(` ${dim2("Rules:")} ${ruleCount} ${green2(`${allowCount} ALLOW`)} ${red2(`${denyCount} DENY`)}`);
8238
9975
  if (p.created_at) {
8239
- log5(` ${dim("Updated:")} ${new Date(p.created_at).toLocaleString()}`);
9976
+ log5(` ${dim2("Updated:")} ${new Date(p.created_at).toLocaleString()}`);
8240
9977
  }
8241
9978
  log5("");
8242
9979
  }
8243
9980
  function printPolicyDetail(policy) {
8244
9981
  log5("");
8245
- log5(bold(` ${policy.name}`));
8246
- log5(` ${dim("ID:")} ${cyan(policy.id)} ${dim("Version:")} ${policy.version} ${dim("Rules:")} ${policy.rules.length}`);
9982
+ log5(bold2(` ${policy.name}`));
9983
+ log5(` ${dim2("ID:")} ${cyan2(policy.id)} ${dim2("Version:")} ${policy.version} ${dim2("Rules:")} ${policy.rules.length}`);
8247
9984
  log5("");
8248
9985
  if (policy.rules.length === 0) {
8249
- log5(yellow(" No rules defined."));
9986
+ log5(yellow2(" No rules defined."));
8250
9987
  log5("");
8251
9988
  return;
8252
9989
  }
8253
- log5(dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
9990
+ log5(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8254
9991
  for (const rule of policy.rules) {
8255
- const effectColor = rule.effect === "ALLOW" ? green : red;
9992
+ const effectColor = rule.effect === "ALLOW" ? green2 : red2;
8256
9993
  log5("");
8257
- log5(` ${effectColor(rule.effect.padEnd(5))} ${bold(rule.toolPattern)} ${dim(`P:${rule.priority}`)}`);
9994
+ log5(` ${effectColor(rule.effect.padEnd(5))} ${bold2(rule.toolPattern)} ${dim2(`P:${rule.priority}`)}`);
8258
9995
  if (rule.description) {
8259
- log5(` ${dim(rule.description)}`);
9996
+ log5(` ${dim2(rule.description)}`);
8260
9997
  }
8261
- log5(` ${dim(`${rule.permission} trust:${rule.minimumTrustLevel || "UNTRUSTED"}`)}`);
9998
+ log5(` ${dim2(`${rule.permission} trust:${rule.minimumTrustLevel || "UNTRUSTED"}`)}`);
8262
9999
  if (rule.pathConstraints) {
8263
10000
  const pc = rule.pathConstraints;
8264
10001
  if (pc.rootDirectory) log5(` ${magenta("ROOT")} ${pc.rootDirectory}`);
8265
- if (pc.allowed?.length) log5(` ${green("PATHS")} ${pc.allowed.join(", ")}`);
8266
- if (pc.denied?.length) log5(` ${red("DENY")} ${pc.denied.join(", ")}`);
10002
+ if (pc.allowed?.length) log5(` ${green2("PATHS")} ${pc.allowed.join(", ")}`);
10003
+ if (pc.denied?.length) log5(` ${red2("DENY")} ${pc.denied.join(", ")}`);
8267
10004
  }
8268
10005
  if (rule.commandConstraints) {
8269
10006
  const cc = rule.commandConstraints;
8270
- if (cc.allowed?.length) log5(` ${green("CMDS")} ${cc.allowed.join(", ")}`);
8271
- if (cc.denied?.length) log5(` ${red("DENY")} ${cc.denied.join(", ")}`);
10007
+ if (cc.allowed?.length) log5(` ${green2("CMDS")} ${cc.allowed.join(", ")}`);
10008
+ if (cc.denied?.length) log5(` ${red2("DENY")} ${cc.denied.join(", ")}`);
8272
10009
  }
8273
10010
  if (rule.filenameConstraints) {
8274
10011
  const fc = rule.filenameConstraints;
8275
- if (fc.allowed?.length) log5(` ${green("FILES")} ${fc.allowed.join(", ")}`);
8276
- if (fc.denied?.length) log5(` ${red("DENY")} ${fc.denied.join(", ")}`);
10012
+ if (fc.allowed?.length) log5(` ${green2("FILES")} ${fc.allowed.join(", ")}`);
10013
+ if (fc.denied?.length) log5(` ${red2("DENY")} ${fc.denied.join(", ")}`);
8277
10014
  }
8278
10015
  if (rule.urlConstraints) {
8279
10016
  const uc = rule.urlConstraints;
8280
- if (uc.allowed?.length) log5(` ${green("URLS")} ${uc.allowed.join(", ")}`);
8281
- if (uc.denied?.length) log5(` ${red("DENY")} ${uc.denied.join(", ")}`);
10017
+ if (uc.allowed?.length) log5(` ${green2("URLS")} ${uc.allowed.join(", ")}`);
10018
+ if (uc.denied?.length) log5(` ${red2("DENY")} ${uc.denied.join(", ")}`);
8282
10019
  }
8283
10020
  }
8284
10021
  log5("");
8285
- log5(dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
10022
+ log5(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
8286
10023
  log5("");
8287
10024
  }
8288
10025
  async function pull(apiKey, file, policyId) {
8289
10026
  if (!policyId) {
8290
10027
  const policies = await listPolicies(apiKey);
8291
10028
  if (policies.length === 0) {
8292
- log5(red("No policies found. Create one in the dashboard first."));
10029
+ log5(red2("No policies found. Create one in the dashboard first."));
8293
10030
  process.exit(1);
8294
10031
  }
8295
10032
  if (policies.length === 1) {
8296
10033
  policyId = policies[0].id;
8297
- log5(dim(`Auto-selecting only policy: ${policyId}`));
10034
+ log5(dim2(`Auto-selecting only policy: ${policyId}`));
8298
10035
  } else {
8299
- log5(yellow(`Found ${policies.length} policies:`));
10036
+ log5(yellow2(`Found ${policies.length} policies:`));
8300
10037
  log5("");
8301
10038
  for (const p of policies) {
8302
- log5(` ${cyan(p.id)} ${p.name} ${dim(`v${p.version ?? "?"}`)}`);
10039
+ log5(` ${cyan2(p.id)} ${p.name} ${dim2(`v${p.version ?? "?"}`)}`);
8303
10040
  }
8304
10041
  log5("");
8305
10042
  log5("Use --policy-id <ID> to specify which one to pull.");
8306
10043
  process.exit(1);
8307
10044
  }
8308
10045
  }
8309
- log5(`Pulling ${cyan(policyId)} from dashboard...`);
10046
+ log5(`Pulling ${cyan2(policyId)} from dashboard...`);
8310
10047
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
8311
10048
  const { id: _id, ...policyWithoutId } = policy;
8312
10049
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
8313
10050
  writeFileSync6(file, json, "utf-8");
8314
10051
  log5("");
8315
- log5(green(" Saved to: ") + file);
8316
- log5(` ${dim("Name:")} ${policy.name}`);
8317
- log5(` ${dim("Version:")} ${policy.version}`);
8318
- log5(` ${dim("Rules:")} ${policy.rules.length}`);
10052
+ log5(green2(" Saved to: ") + file);
10053
+ log5(` ${dim2("Name:")} ${policy.name}`);
10054
+ log5(` ${dim2("Version:")} ${policy.version}`);
10055
+ log5(` ${dim2("Rules:")} ${policy.rules.length}`);
8319
10056
  log5("");
8320
- log5(dim("The policy file does not contain an ID."));
8321
- log5(dim("Use --policy-id to specify the target when pushing/pulling."));
10057
+ log5(dim2("The policy file does not contain an ID."));
10058
+ log5(dim2("Use --policy-id to specify the target when pushing/pulling."));
8322
10059
  log5("");
8323
10060
  }
8324
10061
  async function push(apiKey, file, policyId) {
8325
- if (!existsSync7(file)) {
8326
- log5(red(`ERROR: File not found: ${file}`));
10062
+ if (!existsSync8(file)) {
10063
+ log5(red2(`ERROR: File not found: ${file}`));
8327
10064
  process.exit(1);
8328
10065
  }
8329
10066
  if (!policyId) {
8330
- log5(red("ERROR: --policy-id is required for push."));
10067
+ log5(red2("ERROR: --policy-id is required for push."));
8331
10068
  log5("");
8332
10069
  log5("This determines which cloud policy to update.");
8333
10070
  log5("");
@@ -8339,18 +10076,18 @@ async function push(apiKey, file, policyId) {
8339
10076
  log5(" solongate-proxy list");
8340
10077
  process.exit(1);
8341
10078
  }
8342
- const content = readFileSync8(file, "utf-8");
10079
+ const content = readFileSync10(file, "utf-8");
8343
10080
  let policy;
8344
10081
  try {
8345
10082
  policy = JSON.parse(content);
8346
10083
  } catch {
8347
- log5(red(`ERROR: Invalid JSON in ${file}`));
10084
+ log5(red2(`ERROR: Invalid JSON in ${file}`));
8348
10085
  process.exit(1);
8349
10086
  }
8350
- log5(`Pushing to ${cyan(policyId)}...`);
8351
- log5(` ${dim("File:")} ${file}`);
8352
- log5(` ${dim("Name:")} ${policy.name || "Unnamed"}`);
8353
- log5(` ${dim("Rules:")} ${(policy.rules || []).length}`);
10087
+ log5(`Pushing to ${cyan2(policyId)}...`);
10088
+ log5(` ${dim2("File:")} ${file}`);
10089
+ log5(` ${dim2("Name:")} ${policy.name || "Unnamed"}`);
10090
+ log5(` ${dim2("Rules:")} ${(policy.rules || []).length}`);
8354
10091
  const checkRes = await fetch(`${API_URL}/api/v1/policies/${policyId}`, {
8355
10092
  headers: { "Authorization": `Bearer ${apiKey}` }
8356
10093
  });
@@ -8372,14 +10109,14 @@ async function push(apiKey, file, policyId) {
8372
10109
  });
8373
10110
  if (!res.ok) {
8374
10111
  const body = await res.text().catch(() => "");
8375
- log5(red(`ERROR: Push failed (${res.status}): ${body}`));
10112
+ log5(red2(`ERROR: Push failed (${res.status}): ${body}`));
8376
10113
  process.exit(1);
8377
10114
  }
8378
10115
  const data = await res.json();
8379
10116
  log5("");
8380
- log5(green(` Pushed to cloud: v${data._version ?? "created"}`));
8381
- log5(` ${dim("Policy ID:")} ${policyId}`);
8382
- log5(` ${dim("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
10117
+ log5(green2(` Pushed to cloud: v${data._version ?? "created"}`));
10118
+ log5(` ${dim2("Policy ID:")} ${policyId}`);
10119
+ log5(` ${dim2("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
8383
10120
  log5("");
8384
10121
  }
8385
10122
  async function main4() {
@@ -8390,41 +10127,41 @@ async function main4() {
8390
10127
  } else if (command === "push") {
8391
10128
  await push(apiKey, file, policyId);
8392
10129
  } else if (command === "list" || command === "ls") {
8393
- await list(apiKey, policyId);
10130
+ await list3(apiKey, policyId);
8394
10131
  } else {
8395
- log5(red(`Unknown command: ${command}`));
10132
+ log5(red2(`Unknown command: ${command}`));
8396
10133
  log5("");
8397
- log5(bold("Usage:"));
10134
+ log5(bold2("Usage:"));
8398
10135
  log5(" solongate-proxy list List all policies");
8399
10136
  log5(" solongate-proxy list --policy-id <ID> Show policy details");
8400
10137
  log5(" solongate-proxy pull --policy-id <ID> Pull policy to local file");
8401
10138
  log5(" solongate-proxy push --policy-id <ID> Push local file to cloud");
8402
10139
  log5("");
8403
- log5(bold("Flags:"));
10140
+ log5(bold2("Flags:"));
8404
10141
  log5(" --policy-id, --id <ID> Cloud policy ID (required for push)");
8405
10142
  log5(" --file, -f <path> Local file path (default: policy.json)");
8406
10143
  log5(" --api-key <key> API key (or set SOLONGATE_API_KEY)");
8407
10144
  log5("");
8408
10145
  process.exit(1);
8409
10146
  }
8410
- } catch (err) {
8411
- log5(red(`ERROR: ${err instanceof Error ? err.message : String(err)}`));
10147
+ } catch (err2) {
10148
+ log5(red2(`ERROR: ${err2 instanceof Error ? err2.message : String(err2)}`));
8412
10149
  process.exit(1);
8413
10150
  }
8414
10151
  }
8415
- var log5, dim, bold, green, red, yellow, cyan, magenta, API_URL;
10152
+ var log5, dim2, bold2, green2, red2, yellow2, cyan2, magenta, API_URL;
8416
10153
  var init_pull_push = __esm({
8417
10154
  "src/pull-push.ts"() {
8418
10155
  "use strict";
8419
10156
  init_config();
8420
10157
  log5 = (...args) => process.stderr.write(`${args.map(String).join(" ")}
8421
10158
  `);
8422
- dim = (s) => `\x1B[2m${s}\x1B[0m`;
8423
- bold = (s) => `\x1B[1m${s}\x1B[0m`;
8424
- green = (s) => `\x1B[32m${s}\x1B[0m`;
8425
- red = (s) => `\x1B[31m${s}\x1B[0m`;
8426
- yellow = (s) => `\x1B[33m${s}\x1B[0m`;
8427
- cyan = (s) => `\x1B[36m${s}\x1B[0m`;
10159
+ dim2 = (s) => `\x1B[2m${s}\x1B[0m`;
10160
+ bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
10161
+ green2 = (s) => `\x1B[32m${s}\x1B[0m`;
10162
+ red2 = (s) => `\x1B[31m${s}\x1B[0m`;
10163
+ yellow2 = (s) => `\x1B[33m${s}\x1B[0m`;
10164
+ cyan2 = (s) => `\x1B[36m${s}\x1B[0m`;
8428
10165
  magenta = (s) => `\x1B[35m${s}\x1B[0m`;
8429
10166
  API_URL = "https://api.solongate.com";
8430
10167
  main4();
@@ -9329,12 +11066,12 @@ function looksLikeFilename(s) {
9329
11066
  }
9330
11067
 
9331
11068
  // src/policy-engine/opa/request-adapter.ts
9332
- function toOpaInput(request) {
9333
- const args = request.arguments ?? {};
11069
+ function toOpaInput(request2) {
11070
+ const args = request2.arguments ?? {};
9334
11071
  return {
9335
- tool_name: request.toolName,
9336
- permission: request.requiredPermission ?? "",
9337
- trust_level: request.context.trustLevel,
11072
+ tool_name: request2.toolName,
11073
+ permission: request2.requiredPermission ?? "",
11074
+ trust_level: request2.context.trustLevel,
9338
11075
  arguments: args,
9339
11076
  paths: extractPathArguments(args),
9340
11077
  commands: extractCommandArguments(args),
@@ -9407,12 +11144,12 @@ var OpaEvaluator = class {
9407
11144
  // Evaluates an execution request against the loaded OPA policy.
9408
11145
  // Returns a PolicyDecision matching the same interface as the legacy evaluator,
9409
11146
  // ensuring full backward compatibility.
9410
- evaluate(request) {
11147
+ evaluate(request2) {
9411
11148
  if (!this.policy || !this.initialized) {
9412
11149
  throw new Error("OPA policy not loaded. Call loadBundle() or loadWasm() first.");
9413
11150
  }
9414
11151
  const startTime = performance.now();
9415
- const input = toOpaInput(request);
11152
+ const input = toOpaInput(request2);
9416
11153
  const results = this.policy.evaluate(input);
9417
11154
  const endTime = performance.now();
9418
11155
  const decision = results?.[0]?.result;
@@ -9482,11 +11219,11 @@ var PolicyEngine = class {
9482
11219
  // Never throws for denials - denial is a normal outcome, not an error.
9483
11220
  // OPA WASM is the only evaluator. If no WASM bundle is loaded, evaluation
9484
11221
  // fails CLOSED (default DENY) — there is no legacy fallback.
9485
- evaluate(request) {
11222
+ evaluate(request2) {
9486
11223
  const startTime = performance.now();
9487
11224
  let decision;
9488
11225
  if (this.opaEvaluator?.isReady()) {
9489
- decision = this.opaEvaluator.evaluate(request);
11226
+ decision = this.opaEvaluator.evaluate(request2);
9490
11227
  } else {
9491
11228
  decision = {
9492
11229
  effect: DEFAULT_POLICY_EFFECT,
@@ -9499,7 +11236,7 @@ var PolicyEngine = class {
9499
11236
  const elapsed = performance.now() - startTime;
9500
11237
  if (elapsed > this.timeoutMs) {
9501
11238
  console.warn(
9502
- `[SolonGate] Policy evaluation took ${elapsed.toFixed(1)}ms (limit: ${this.timeoutMs}ms) for tool "${request.toolName}"`
11239
+ `[SolonGate] Policy evaluation took ${elapsed.toFixed(1)}ms (limit: ${this.timeoutMs}ms) for tool "${request2.toolName}"`
9503
11240
  );
9504
11241
  }
9505
11242
  return decision;
@@ -9762,7 +11499,7 @@ async function interceptToolCall(params, upstreamCall, options) {
9762
11499
  const requestId = randomUUID2();
9763
11500
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
9764
11501
  const context = createSecurityContext({ requestId });
9765
- const request = {
11502
+ const request2 = {
9766
11503
  context,
9767
11504
  toolName: params.name,
9768
11505
  serverName: "default",
@@ -9779,7 +11516,7 @@ async function interceptToolCall(params, upstreamCall, options) {
9779
11516
  if (!toolLimit.allowed) {
9780
11517
  const result = {
9781
11518
  status: "ERROR",
9782
- request,
11519
+ request: request2,
9783
11520
  error: new RateLimitError(params.name, options.rateLimitPerTool),
9784
11521
  timestamp
9785
11522
  };
@@ -9796,7 +11533,7 @@ async function interceptToolCall(params, upstreamCall, options) {
9796
11533
  if (!globalLimit.allowed) {
9797
11534
  const result = {
9798
11535
  status: "ERROR",
9799
- request,
11536
+ request: request2,
9800
11537
  error: new RateLimitError("*", options.globalRateLimitPerMinute),
9801
11538
  timestamp
9802
11539
  };
@@ -9809,7 +11546,7 @@ async function interceptToolCall(params, upstreamCall, options) {
9809
11546
  if (options.exfiltrationTracker.detectChain(params.name)) {
9810
11547
  const result = {
9811
11548
  status: "DENIED",
9812
- request,
11549
+ request: request2,
9813
11550
  decision: {
9814
11551
  effect: "DENY",
9815
11552
  matchedRule: null,
@@ -9826,11 +11563,11 @@ async function interceptToolCall(params, upstreamCall, options) {
9826
11563
  }
9827
11564
  options.exfiltrationTracker.record(params.name);
9828
11565
  }
9829
- const decision = options.policyEngine.evaluate(request);
11566
+ const decision = options.policyEngine.evaluate(request2);
9830
11567
  if (decision.effect === "DENY") {
9831
11568
  const result = {
9832
11569
  status: "DENIED",
9833
- request,
11570
+ request: request2,
9834
11571
  decision,
9835
11572
  timestamp
9836
11573
  };
@@ -9880,7 +11617,7 @@ ${item.text}`;
9880
11617
  }
9881
11618
  const result = {
9882
11619
  status: "ALLOWED",
9883
- request,
11620
+ request: request2,
9884
11621
  decision,
9885
11622
  toolResult: finalResult,
9886
11623
  durationMs,
@@ -9891,7 +11628,7 @@ ${item.text}`;
9891
11628
  } catch (error) {
9892
11629
  const result = {
9893
11630
  status: "ERROR",
9894
- request,
11631
+ request: request2,
9895
11632
  error: error instanceof Error ? new PolicyDeniedError(params.name, error.message) : new PolicyDeniedError(params.name, "Unknown upstream error"),
9896
11633
  timestamp
9897
11634
  };
@@ -10156,8 +11893,8 @@ var ServerVerifier = class {
10156
11893
  /**
10157
11894
  * Validates a complete signed request including timestamp, nonce, and signature.
10158
11895
  */
10159
- validateSignedRequest(request) {
10160
- const requestTime = new Date(request.timestamp).getTime();
11896
+ validateSignedRequest(request2) {
11897
+ const requestTime = new Date(request2.timestamp).getTime();
10161
11898
  const now = Date.now();
10162
11899
  if (isNaN(requestTime)) {
10163
11900
  return { valid: false, reason: "Invalid timestamp" };
@@ -10168,13 +11905,13 @@ var ServerVerifier = class {
10168
11905
  if (requestTime > now + 3e4) {
10169
11906
  return { valid: false, reason: "Request timestamp in the future" };
10170
11907
  }
10171
- if (this.usedNonces.has(request.nonce)) {
11908
+ if (this.usedNonces.has(request2.nonce)) {
10172
11909
  return { valid: false, reason: "Duplicate nonce (replay detected)" };
10173
11910
  }
10174
- if (!this.verifySignature(request.params, request.capabilityToken, request.signature)) {
11911
+ if (!this.verifySignature(request2.params, request2.capabilityToken, request2.signature)) {
10175
11912
  return { valid: false, reason: "Invalid signature" };
10176
11913
  }
10177
- this.usedNonces.add(request.nonce);
11914
+ this.usedNonces.add(request2.nonce);
10178
11915
  return { valid: true };
10179
11916
  }
10180
11917
  };
@@ -10436,9 +12173,9 @@ var SolonGate = class {
10436
12173
  throw new LicenseError("Your subscription is inactive. Renew at https://solongate.com");
10437
12174
  }
10438
12175
  this.licenseValidated = true;
10439
- } catch (err) {
10440
- if (err instanceof LicenseError) throw err;
10441
- console.warn("[SolonGate] License validation failed (network error), allowing through:", err instanceof Error ? err.message : String(err));
12176
+ } catch (err2) {
12177
+ if (err2 instanceof LicenseError) throw err2;
12178
+ console.warn("[SolonGate] License validation failed (network error), allowing through:", err2 instanceof Error ? err2.message : String(err2));
10442
12179
  this.licenseValidated = true;
10443
12180
  }
10444
12181
  }
@@ -10487,10 +12224,10 @@ var SolonGate = class {
10487
12224
  }
10488
12225
  const wasmBytes = new Uint8Array(await res.arrayBuffer());
10489
12226
  await this.policyEngine.loadWasmBundle(wasmBytes);
10490
- } catch (err) {
12227
+ } catch (err2) {
10491
12228
  console.warn(
10492
12229
  "[SolonGate] Failed to load policy WASM bundle:",
10493
- err instanceof Error ? err.message : String(err)
12230
+ err2 instanceof Error ? err2.message : String(err2)
10494
12231
  );
10495
12232
  }
10496
12233
  }
@@ -10705,8 +12442,8 @@ var PolicySyncManager = class {
10705
12442
  this.debounceTimer = setTimeout(() => this.onFileChange(filePath), 300);
10706
12443
  });
10707
12444
  log(`Watching ${filePath} for changes`);
10708
- } catch (err) {
10709
- log(`File watch failed: ${err instanceof Error ? err.message : String(err)}`);
12445
+ } catch (err2) {
12446
+ log(`File watch failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
10710
12447
  }
10711
12448
  }
10712
12449
  /**
@@ -10737,12 +12474,12 @@ var PolicySyncManager = class {
10737
12474
  const result = await this.pushToCloud(newPolicy);
10738
12475
  this.cloudVersion = result.version;
10739
12476
  log(`Pushed to cloud: v${result.version}`);
10740
- } catch (err) {
10741
- log(`Cloud push failed: ${err instanceof Error ? err.message : String(err)}`);
12477
+ } catch (err2) {
12478
+ log(`Cloud push failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
10742
12479
  }
10743
12480
  }
10744
- } catch (err) {
10745
- log(`File read error: ${err instanceof Error ? err.message : String(err)}`);
12481
+ } catch (err2) {
12482
+ log(`File read error: ${err2 instanceof Error ? err2.message : String(err2)}`);
10746
12483
  }
10747
12484
  }
10748
12485
  /**
@@ -10831,8 +12568,8 @@ var PolicySyncManager = class {
10831
12568
  const { id: _id, ...rest } = policy;
10832
12569
  const json = JSON.stringify(rest, null, 2) + "\n";
10833
12570
  writeFileSync2(this.localPath, json, "utf-8");
10834
- } catch (err) {
10835
- log(`File write error: ${err instanceof Error ? err.message : String(err)}`);
12571
+ } catch (err2) {
12572
+ log(`File write error: ${err2 instanceof Error ? err2.message : String(err2)}`);
10836
12573
  }
10837
12574
  }
10838
12575
  /**
@@ -10856,7 +12593,7 @@ var Mutex = class {
10856
12593
  this.locked = true;
10857
12594
  return;
10858
12595
  }
10859
- return new Promise((resolve9, reject) => {
12596
+ return new Promise((resolve10, reject) => {
10860
12597
  const timer = setTimeout(() => {
10861
12598
  const idx = this.queue.indexOf(onReady);
10862
12599
  if (idx !== -1) this.queue.splice(idx, 1);
@@ -10864,7 +12601,7 @@ var Mutex = class {
10864
12601
  }, timeoutMs);
10865
12602
  const onReady = () => {
10866
12603
  clearTimeout(timer);
10867
- resolve9();
12604
+ resolve10();
10868
12605
  };
10869
12606
  this.queue.push(onReady);
10870
12607
  });
@@ -10933,8 +12670,8 @@ var SolonGateProxy = class {
10933
12670
  return { id: raw.toLowerCase().replace(/\s+/g, "-"), name: raw };
10934
12671
  }
10935
12672
  /** Extract sub-agent identity from MCP _meta field */
10936
- extractSubAgent(request) {
10937
- const meta = request?.params?._meta;
12673
+ extractSubAgent(request2) {
12674
+ const meta = request2?.params?._meta;
10938
12675
  if (meta && typeof meta === "object") {
10939
12676
  const solonMeta = meta["io.solongate/agent"];
10940
12677
  if (solonMeta && typeof solonMeta === "object") {
@@ -10978,9 +12715,9 @@ var SolonGateProxy = class {
10978
12715
  process.exit(1);
10979
12716
  }
10980
12717
  log2("License validated.");
10981
- } catch (err) {
12718
+ } catch (err2) {
10982
12719
  log2(`ERROR: Unable to reach SolonGate license server. Check your internet connection.`);
10983
- log2(`Details: ${err instanceof Error ? err.message : String(err)}`);
12720
+ log2(`Details: ${err2 instanceof Error ? err2.message : String(err2)}`);
10984
12721
  process.exit(1);
10985
12722
  }
10986
12723
  }
@@ -10989,8 +12726,8 @@ var SolonGateProxy = class {
10989
12726
  const cloudPolicy = await fetchCloudPolicy(this.config.apiKey, apiUrl, this.config.policyId);
10990
12727
  this.config.policy = cloudPolicy;
10991
12728
  log2(`Loaded cloud policy: ${cloudPolicy.name} (${cloudPolicy.rules.length} rules)`);
10992
- } catch (err) {
10993
- log2(`Cloud policy fetch failed, using local policy: ${err instanceof Error ? err.message : String(err)}`);
12729
+ } catch (err2) {
12730
+ log2(`Cloud policy fetch failed, using local policy: ${err2 instanceof Error ? err2.message : String(err2)}`);
10994
12731
  }
10995
12732
  }
10996
12733
  }
@@ -11124,9 +12861,9 @@ var SolonGateProxy = class {
11124
12861
  });
11125
12862
  const MAX_ARGUMENT_SIZE = 1024 * 1024;
11126
12863
  const MUTEX_TIMEOUT_MS = 3e4;
11127
- this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
11128
- const { name, arguments: args } = request.params;
11129
- const subAgent = this.extractSubAgent(request) || this.httpSubAgent;
12864
+ this.server.setRequestHandler(CallToolRequestSchema, async (request2) => {
12865
+ const { name, arguments: args } = request2.params;
12866
+ const subAgent = this.extractSubAgent(request2) || this.httpSubAgent;
11130
12867
  const argsSize = TEXT_ENCODER.encode(JSON.stringify(args ?? {})).length;
11131
12868
  if (argsSize > MAX_ARGUMENT_SIZE) {
11132
12869
  log2(`DENY: ${name} \u2014 payload size ${argsSize} exceeds limit ${MAX_ARGUMENT_SIZE}`);
@@ -11210,9 +12947,9 @@ var SolonGateProxy = class {
11210
12947
  return { resources: [] };
11211
12948
  }
11212
12949
  });
11213
- this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
12950
+ this.server.setRequestHandler(ReadResourceRequestSchema, async (request2) => {
11214
12951
  if (!this.client) throw new Error("Upstream client disconnected");
11215
- const uri = request.params.uri;
12952
+ const uri = request2.params.uri;
11216
12953
  log2(`Resource read: ${uri}`);
11217
12954
  const resourceResult = await this.client.readResource({ uri });
11218
12955
  if (resourceResult.contents) {
@@ -11247,12 +12984,12 @@ ${content.text}`;
11247
12984
  return { prompts: [] };
11248
12985
  }
11249
12986
  });
11250
- this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
12987
+ this.server.setRequestHandler(GetPromptRequestSchema, async (request2) => {
11251
12988
  if (!this.client) throw new Error("Upstream client disconnected");
11252
- const args = request.params.arguments;
11253
- log2(`Prompt get: ${request.params.name}`);
12989
+ const args = request2.params.arguments;
12990
+ log2(`Prompt get: ${request2.params.name}`);
11254
12991
  const promptResult = await this.client.getPrompt({
11255
- name: request.params.name,
12992
+ name: request2.params.name,
11256
12993
  arguments: args
11257
12994
  });
11258
12995
  if (promptResult.messages) {
@@ -11261,7 +12998,7 @@ ${content.text}`;
11261
12998
  const scan = scanResponse(msg.content.text);
11262
12999
  if (!scan.safe) {
11263
13000
  const threats = scan.threats.map((t) => t.type).join(", ");
11264
- log2(`WARNING prompt response: ${request.params.name} \u2014 ${threats}`);
13001
+ log2(`WARNING prompt response: ${request2.params.name} \u2014 ${threats}`);
11265
13002
  msg.content.text = `${RESPONSE_WARNING_MARKER}
11266
13003
 
11267
13004
  ${msg.content.text}`;
@@ -11367,8 +13104,8 @@ ${msg.content.text}`;
11367
13104
  const body = await res.text().catch(() => "");
11368
13105
  log2(`MCP server registration failed (${res.status}): ${body}`);
11369
13106
  }
11370
- }).catch((err) => {
11371
- log2(`MCP server registration error: ${err instanceof Error ? err.message : String(err)}`);
13107
+ }).catch((err2) => {
13108
+ log2(`MCP server registration error: ${err2 instanceof Error ? err2.message : String(err2)}`);
11372
13109
  });
11373
13110
  }
11374
13111
  /**
@@ -11455,7 +13192,7 @@ ${msg.content.text}`;
11455
13192
 
11456
13193
  // src/index.ts
11457
13194
  init_cli_utils();
11458
- var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["login", "logout", "shield", "create", "inject", "pull", "push", "list", "ls", "logs-server", "local-logs"]);
13195
+ var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["login", "logout", "shield", "create", "inject", "pull", "push", "list", "ls", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "ui", "dashboard", "tui"]);
11459
13196
  var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "");
11460
13197
  if (!IS_HUMAN_CLI) {
11461
13198
  console.log = (...args) => {
@@ -11490,9 +13227,26 @@ function printWelcome() {
11490
13227
  async function main5() {
11491
13228
  const subcommand = process.argv[2];
11492
13229
  if (process.argv.length <= 2) {
13230
+ const { isAuthenticated: isAuthenticated2 } = await Promise.resolve().then(() => (init_client(), client_exports));
13231
+ if (process.stdout.isTTY && isAuthenticated2()) {
13232
+ const { launchTui: launchTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
13233
+ await launchTui2();
13234
+ return;
13235
+ }
11493
13236
  printWelcome();
11494
13237
  return;
11495
13238
  }
13239
+ if (subcommand === "ui" || subcommand === "dashboard" || subcommand === "tui") {
13240
+ const { launchTui: launchTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
13241
+ await launchTui2();
13242
+ return;
13243
+ }
13244
+ const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent"]);
13245
+ if (MGMT_COMMANDS.has(subcommand ?? "")) {
13246
+ const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
13247
+ const code = await runCommand2(subcommand, process.argv.slice(3));
13248
+ process.exit(code);
13249
+ }
11496
13250
  if (subcommand === "login") {
11497
13251
  await Promise.resolve().then(() => (init_login(), login_exports));
11498
13252
  return;
@@ -11530,8 +13284,8 @@ async function main5() {
11530
13284
  const config = parseArgs(process.argv);
11531
13285
  const proxy = new SolonGateProxy(config);
11532
13286
  await proxy.start();
11533
- } catch (err) {
11534
- const message = err instanceof Error ? err.message : String(err);
13287
+ } catch (err2) {
13288
+ const message = err2 instanceof Error ? err2.message : String(err2);
11535
13289
  process.stderr.write(`[SolonGate] Fatal: ${message}
11536
13290
  `);
11537
13291
  process.exit(1);