@solongate/proxy 0.82.39 → 0.82.40

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
@@ -32,361 +32,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  mod
33
33
  ));
34
34
 
35
- // src/config.ts
36
- import { readFileSync, existsSync } from "fs";
37
- import { appendFile } from "fs/promises";
38
- import { resolve, join } from "path";
39
- import { homedir } from "os";
40
- function loginCredential() {
41
- try {
42
- const p = join(homedir(), ".solongate", "cloud-guard.json");
43
- if (!existsSync(p)) return {};
44
- const c2 = JSON.parse(readFileSync(p, "utf-8"));
45
- return c2 && typeof c2 === "object" ? c2 : {};
46
- } catch {
47
- return {};
48
- }
49
- }
50
- async function fetchCloudPolicy(apiKey, apiUrl, policyId) {
51
- let resolvedId = policyId;
52
- if (!resolvedId) {
53
- const listRes = await fetch(`${apiUrl}/api/v1/policies`, {
54
- headers: { "Authorization": `Bearer ${apiKey}` },
55
- signal: AbortSignal.timeout(1e4)
56
- });
57
- if (!listRes.ok) {
58
- const body = await listRes.text().catch(() => "");
59
- throw new Error(`Failed to list policies from cloud (${listRes.status}): ${body}`);
60
- }
61
- const listData = await listRes.json();
62
- const policies = listData.policies ?? [];
63
- if (policies.length === 0) {
64
- throw new Error("No policies found in cloud. Create one in the dashboard first.");
65
- }
66
- resolvedId = policies[0].id;
67
- }
68
- const url = `${apiUrl}/api/v1/policies/${resolvedId}`;
69
- const res = await fetch(url, {
70
- headers: { "Authorization": `Bearer ${apiKey}` },
71
- signal: AbortSignal.timeout(1e4)
72
- });
73
- if (!res.ok) {
74
- const body = await res.text().catch(() => "");
75
- throw new Error(`Failed to fetch policy from cloud (${res.status}): ${body}`);
76
- }
77
- const data = await res.json();
78
- return {
79
- id: String(data.id ?? "cloud"),
80
- name: String(data.name ?? "Cloud Policy"),
81
- description: String(data.description ?? ""),
82
- version: Number(data._version ?? 1),
83
- rules: data.rules ?? [],
84
- createdAt: String(data._created_at ?? ""),
85
- updatedAt: ""
86
- };
87
- }
88
- async function fetchCloudPolicyWasm(apiKey, apiUrl, policyId) {
89
- try {
90
- const res = await fetch(`${apiUrl}/api/v1/policies/${policyId}/wasm`, {
91
- headers: { "Authorization": `Bearer ${apiKey}` },
92
- signal: AbortSignal.timeout(1e4)
93
- });
94
- if (!res.ok) return null;
95
- return new Uint8Array(await res.arrayBuffer());
96
- } catch {
97
- return null;
98
- }
99
- }
100
- async function sendAuditLog(apiKey, apiUrl, entry) {
101
- const url = `${apiUrl}/api/v1/audit-logs`;
102
- const body = JSON.stringify({
103
- ...entry,
104
- agent_id: entry.agent_id,
105
- agent_name: entry.agent_name
106
- });
107
- for (let attempt = 0; attempt < AUDIT_MAX_RETRIES; attempt++) {
108
- try {
109
- const res = await fetch(url, {
110
- method: "POST",
111
- headers: {
112
- "Authorization": `Bearer ${apiKey}`,
113
- "Content-Type": "application/json"
114
- },
115
- body,
116
- signal: AbortSignal.timeout(5e3)
117
- });
118
- if (res.ok) return;
119
- if (res.status >= 400 && res.status < 500) {
120
- const resBody = await res.text().catch(() => "");
121
- process.stderr.write(`[SolonGate] Audit log rejected (${res.status}): ${resBody}
122
- `);
123
- return;
124
- }
125
- } catch {
126
- }
127
- if (attempt < AUDIT_MAX_RETRIES - 1) {
128
- await new Promise((r) => setTimeout(r, 500 * Math.pow(2, attempt)));
129
- }
130
- }
131
- process.stderr.write(`[SolonGate] Audit log failed after ${AUDIT_MAX_RETRIES} retries, saving to local backup.
132
- `);
133
- try {
134
- const line = JSON.stringify({ ...entry, timestamp: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
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
- `);
138
- });
139
- } catch (err2) {
140
- process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
141
- `);
142
- }
143
- }
144
- function ensureCatchAllAllow(policy) {
145
- const hasCatchAllAllow = policy.rules.some(
146
- (r) => r.effect === "ALLOW" && r.toolPattern === "*" && r.enabled !== false
147
- );
148
- if (hasCatchAllAllow) return policy;
149
- const now = (/* @__PURE__ */ new Date()).toISOString();
150
- return {
151
- ...policy,
152
- rules: [
153
- ...policy.rules,
154
- {
155
- id: "_solongate-catch-all-allow",
156
- description: "Auto-added: allow everything not explicitly denied",
157
- effect: "ALLOW",
158
- priority: 9999,
159
- toolPattern: "*",
160
- minimumTrustLevel: "UNTRUSTED",
161
- enabled: true,
162
- createdAt: now,
163
- updatedAt: now
164
- }
165
- ]
166
- };
167
- }
168
- function loadPolicy(source) {
169
- let policy;
170
- if (typeof source === "object") {
171
- policy = source;
172
- } else {
173
- const filePath = resolve(source);
174
- if (existsSync(filePath)) {
175
- const content = readFileSync(filePath, "utf-8");
176
- policy = JSON.parse(content);
177
- } else {
178
- return DEFAULT_POLICY;
179
- }
180
- }
181
- return ensureCatchAllAllow(policy);
182
- }
183
- function parseArgs(argv) {
184
- const args = argv.slice(2);
185
- let policySource;
186
- let name = "solongate-proxy";
187
- let verbose = false;
188
- let rateLimitPerTool;
189
- let globalRateLimit;
190
- let configFile;
191
- let apiKey;
192
- let apiUrl;
193
- let upstreamUrl;
194
- let upstreamTransport;
195
- let port;
196
- let policyId;
197
- let agentName;
198
- let separatorIndex = args.indexOf("--");
199
- const flags = separatorIndex >= 0 ? args.slice(0, separatorIndex) : args;
200
- let upstreamArgs = separatorIndex >= 0 ? args.slice(separatorIndex + 1) : [];
201
- for (let i = 0; i < flags.length; i++) {
202
- if (!flags[i].startsWith("--")) {
203
- if (upstreamArgs.length === 0) {
204
- upstreamArgs.push(...flags.slice(i));
205
- }
206
- break;
207
- }
208
- switch (flags[i]) {
209
- case "--policy":
210
- policySource = flags[++i];
211
- break;
212
- case "--name":
213
- name = flags[++i];
214
- break;
215
- case "--verbose":
216
- verbose = true;
217
- break;
218
- case "--rate-limit":
219
- rateLimitPerTool = parseInt(flags[++i], 10);
220
- break;
221
- case "--global-rate-limit":
222
- globalRateLimit = parseInt(flags[++i], 10);
223
- break;
224
- case "--config":
225
- configFile = flags[++i];
226
- break;
227
- case "--api-key":
228
- apiKey = flags[++i];
229
- break;
230
- case "--api-url":
231
- apiUrl = flags[++i];
232
- break;
233
- case "--upstream-url":
234
- upstreamUrl = flags[++i];
235
- break;
236
- case "--upstream-transport":
237
- upstreamTransport = flags[++i];
238
- break;
239
- case "--port":
240
- port = parseInt(flags[++i], 10);
241
- break;
242
- case "--policy-id":
243
- case "--id":
244
- policyId = flags[++i];
245
- break;
246
- case "--agent-name":
247
- agentName = flags[++i];
248
- break;
249
- }
250
- }
251
- if (apiKey && /^\$\{.+\}$/.test(apiKey)) {
252
- apiKey = void 0;
253
- }
254
- if (!apiKey) {
255
- const dotenvPath = resolve(".env");
256
- if (existsSync(dotenvPath)) {
257
- const dotenvContent = readFileSync(dotenvPath, "utf-8");
258
- const match = dotenvContent.match(/^SOLONGATE_API_KEY=(sg_(?:live|test)_\w+)/m);
259
- if (match) apiKey = match[1];
260
- }
261
- }
262
- if (!apiKey) {
263
- const envKey = process.env.SOLONGATE_API_KEY;
264
- if (envKey && !/^\$\{.+\}$/.test(envKey)) {
265
- apiKey = envKey;
266
- }
267
- }
268
- if (!apiKey) {
269
- const cred = loginCredential();
270
- if (cred.apiKey) apiKey = cred.apiKey;
271
- }
272
- if (!apiKey) {
273
- throw new Error(
274
- "Not logged in. Run this once to get started:\n\n solongate\n\n then add your account from the Accounts panel.\n"
275
- );
276
- }
277
- if (!apiKey.startsWith("sg_live_") && !apiKey.startsWith("sg_test_")) {
278
- throw new Error(
279
- "Invalid API key format. Keys must start with 'sg_live_' or 'sg_test_'.\nGet your API key at https://solongate.com\n"
280
- );
281
- }
282
- const resolvedPolicyPath = policySource ? resolvePolicyPath(policySource) : null;
283
- if (configFile) {
284
- const filePath = resolve(configFile);
285
- const content = readFileSync(filePath, "utf-8");
286
- const fileConfig = JSON.parse(content);
287
- if (!fileConfig.upstream) {
288
- throw new Error('Config file must include "upstream" with at least "command" or "url"');
289
- }
290
- const cfgPolicySource = fileConfig.policy ?? policySource ?? "policy.json";
291
- return {
292
- upstream: fileConfig.upstream,
293
- policy: loadPolicy(cfgPolicySource),
294
- name: fileConfig.name ?? name,
295
- verbose: fileConfig.verbose ?? verbose,
296
- rateLimitPerTool: fileConfig.rateLimitPerTool ?? rateLimitPerTool,
297
- globalRateLimit: fileConfig.globalRateLimit ?? globalRateLimit,
298
- apiKey: apiKey ?? fileConfig.apiKey,
299
- apiUrl: apiUrl ?? fileConfig.apiUrl,
300
- port: port ?? fileConfig.port,
301
- policyPath: resolvePolicyPath(cfgPolicySource) ?? void 0,
302
- policyId: policyId ?? fileConfig.policyId,
303
- agentName
304
- };
305
- }
306
- if (upstreamUrl) {
307
- const transport = upstreamTransport ?? (upstreamUrl.includes("/sse") ? "sse" : "http");
308
- return {
309
- upstream: {
310
- transport,
311
- command: "",
312
- // not used for URL-based transports
313
- url: upstreamUrl
314
- },
315
- policy: loadPolicy(policySource ?? "policy.json"),
316
- name,
317
- verbose,
318
- rateLimitPerTool,
319
- globalRateLimit,
320
- apiKey,
321
- apiUrl,
322
- port,
323
- policyPath: resolvedPolicyPath ?? void 0,
324
- policyId,
325
- agentName
326
- };
327
- }
328
- if (upstreamArgs.length === 0) {
329
- throw new Error(
330
- "No upstream server command provided.\n\nIf you just want to get started, run:\n solongate\n"
331
- );
332
- }
333
- const [command, ...commandArgs] = upstreamArgs;
334
- return {
335
- upstream: {
336
- transport: upstreamTransport ?? "stdio",
337
- command,
338
- args: commandArgs,
339
- env: { PATH: process.env.PATH ?? "", HOME: process.env.HOME ?? "", USERPROFILE: process.env.USERPROFILE ?? "" }
340
- },
341
- policy: loadPolicy(policySource ?? "policy.json"),
342
- name,
343
- verbose,
344
- rateLimitPerTool,
345
- globalRateLimit,
346
- apiKey,
347
- apiUrl,
348
- port,
349
- policyPath: resolvedPolicyPath ?? void 0,
350
- policyId,
351
- agentName
352
- };
353
- }
354
- function resolvePolicyPath(source) {
355
- const filePath = resolve(source);
356
- if (existsSync(filePath)) return filePath;
357
- return null;
358
- }
359
- var DEFAULT_API_URL, AUDIT_MAX_RETRIES, AUDIT_LOG_BACKUP_PATH, DEFAULT_POLICY;
360
- var init_config = __esm({
361
- "src/config.ts"() {
362
- "use strict";
363
- DEFAULT_API_URL = "https://api.solongate.com";
364
- AUDIT_MAX_RETRIES = 3;
365
- AUDIT_LOG_BACKUP_PATH = resolve(".solongate-audit-backup.jsonl");
366
- DEFAULT_POLICY = {
367
- id: "default",
368
- name: "Default (Allow All)",
369
- description: "Allows all tools by default. Add DENY rules from the dashboard to restrict.",
370
- version: 1,
371
- rules: [
372
- {
373
- id: "_default-allow-all",
374
- description: "Allow all tools by default",
375
- effect: "ALLOW",
376
- priority: 9999,
377
- toolPattern: "*",
378
- minimumTrustLevel: "UNTRUSTED",
379
- enabled: true,
380
- createdAt: "",
381
- updatedAt: ""
382
- }
383
- ],
384
- createdAt: "",
385
- updatedAt: ""
386
- };
387
- }
388
- });
389
-
390
35
  // ../../node_modules/.pnpm/@open-policy-agent+opa-wasm@1.10.0/node_modules/@open-policy-agent/opa-wasm/src/builtins/json.js
391
36
  var require_json = __commonJS({
392
37
  "../../node_modules/.pnpm/@open-policy-agent+opa-wasm@1.10.0/node_modules/@open-policy-agent/opa-wasm/src/builtins/json.js"(exports, module) {
@@ -3398,12 +3043,12 @@ ${ctx.indent}`;
3398
3043
  for (const {
3399
3044
  format,
3400
3045
  test,
3401
- resolve: resolve7
3046
+ resolve: resolve6
3402
3047
  } of tags) {
3403
3048
  if (test) {
3404
3049
  const match = str.match(test);
3405
3050
  if (match) {
3406
- let res = resolve7.apply(null, match);
3051
+ let res = resolve6.apply(null, match);
3407
3052
  if (!(res instanceof Scalar)) res = new Scalar(res);
3408
3053
  if (format) res.format = format;
3409
3054
  return res;
@@ -6610,9 +6255,9 @@ async function fetchLatest() {
6610
6255
  function spawnGlobalInstall(version) {
6611
6256
  try {
6612
6257
  mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
6613
- const log4 = openSync(LOG_FILE, "a");
6258
+ const log3 = openSync(LOG_FILE, "a");
6614
6259
  const p = spawn("npm", ["install", "-g", `${PKG}@${version}`], {
6615
- stdio: ["ignore", log4, log4],
6260
+ stdio: ["ignore", log3, log3],
6616
6261
  detached: true,
6617
6262
  windowsHide: true,
6618
6263
  shell: process.platform === "win32"
@@ -6626,7 +6271,7 @@ function spawnGlobalInstall(version) {
6626
6271
  }
6627
6272
  }
6628
6273
  function runGlobalInstall(version) {
6629
- return new Promise((resolve7) => {
6274
+ return new Promise((resolve6) => {
6630
6275
  try {
6631
6276
  mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
6632
6277
  execFile(
@@ -6641,11 +6286,11 @@ ${stderr}
6641
6286
  `, { flag: "a" });
6642
6287
  } catch {
6643
6288
  }
6644
- resolve7(!err2);
6289
+ resolve6(!err2);
6645
6290
  }
6646
6291
  );
6647
6292
  } catch {
6648
- resolve7(false);
6293
+ resolve6(false);
6649
6294
  }
6650
6295
  });
6651
6296
  }
@@ -6760,11 +6405,11 @@ function startLogsServerDaemon() {
6760
6405
  }
6761
6406
  try {
6762
6407
  mkdirSync4(DIR, { recursive: true });
6763
- const log4 = openSync2(LOG_FILE2, "a");
6408
+ const log3 = openSync2(LOG_FILE2, "a");
6764
6409
  const cli = join5(dirname2(fileURLToPath2(import.meta.url)), "index.js");
6765
6410
  const p = spawn2(process.execPath, [cli, "logs-server"], {
6766
6411
  detached: true,
6767
- stdio: ["ignore", log4, log4],
6412
+ stdio: ["ignore", log3, log3],
6768
6413
  windowsHide: true
6769
6414
  });
6770
6415
  p.on("error", () => {
@@ -6826,7 +6471,7 @@ function loadConfig() {
6826
6471
  return cached;
6827
6472
  }
6828
6473
  var cached;
6829
- var init_config2 = __esm({
6474
+ var init_config = __esm({
6830
6475
  "src/tui/config.ts"() {
6831
6476
  "use strict";
6832
6477
  cached = null;
@@ -6881,7 +6526,7 @@ var accent, theme;
6881
6526
  var init_theme = __esm({
6882
6527
  "src/tui/theme.ts"() {
6883
6528
  "use strict";
6884
- init_config2();
6529
+ init_config();
6885
6530
  accent = loadConfig().accent;
6886
6531
  theme = {
6887
6532
  accent: accent || "white",
@@ -7071,21 +6716,21 @@ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSy
7071
6716
  import { resolve as resolve3, join as join8 } from "path";
7072
6717
  import { homedir as homedir6 } from "os";
7073
6718
  function listAccounts() {
7074
- let list6 = [];
6719
+ let list5 = [];
7075
6720
  try {
7076
6721
  const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
7077
- if (Array.isArray(raw)) list6 = raw.filter((a) => a && typeof a.apiKey === "string");
6722
+ if (Array.isArray(raw)) list5 = raw.filter((a) => a && typeof a.apiKey === "string");
7078
6723
  } catch {
7079
6724
  }
7080
6725
  const active2 = loginCredentialFile();
7081
- if (active2.apiKey && !list6.some((a) => a.apiKey === active2.apiKey)) {
7082
- list6.unshift({ apiKey: active2.apiKey, apiUrl: active2.apiUrl || DEFAULT_API_URL2 });
6726
+ if (active2.apiKey && !list5.some((a) => a.apiKey === active2.apiKey)) {
6727
+ list5.unshift({ apiKey: active2.apiKey, apiUrl: active2.apiUrl || DEFAULT_API_URL2 });
7083
6728
  }
7084
- return list6;
6729
+ return list5;
7085
6730
  }
7086
6731
  function saveAccount(acc) {
7087
6732
  try {
7088
- const list6 = (() => {
6733
+ const list5 = (() => {
7089
6734
  try {
7090
6735
  const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
7091
6736
  return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
@@ -7093,7 +6738,7 @@ function saveAccount(acc) {
7093
6738
  return [];
7094
6739
  }
7095
6740
  })();
7096
- const next = list6.filter((a) => a.apiKey !== acc.apiKey);
6741
+ const next = list5.filter((a) => a.apiKey !== acc.apiKey);
7097
6742
  next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
7098
6743
  mkdirSync5(join8(homedir6(), ".solongate"), { recursive: true });
7099
6744
  writeFileSync6(accountsFile(), JSON.stringify(next, null, 2));
@@ -7102,7 +6747,7 @@ function saveAccount(acc) {
7102
6747
  }
7103
6748
  function removeAccount(apiKey) {
7104
6749
  try {
7105
- const list6 = (() => {
6750
+ const list5 = (() => {
7106
6751
  try {
7107
6752
  const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
7108
6753
  return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
@@ -7110,7 +6755,7 @@ function removeAccount(apiKey) {
7110
6755
  return [];
7111
6756
  }
7112
6757
  })();
7113
- writeFileSync6(accountsFile(), JSON.stringify(list6.filter((a) => a.apiKey !== apiKey), null, 2));
6758
+ writeFileSync6(accountsFile(), JSON.stringify(list5.filter((a) => a.apiKey !== apiKey), null, 2));
7114
6759
  } catch {
7115
6760
  }
7116
6761
  }
@@ -7846,7 +7491,7 @@ function LivePanel({ active: active2 }) {
7846
7491
  const [localBuf, setLocalBuf] = useState2([]);
7847
7492
  const [localOn, setLocalOn] = useState2(null);
7848
7493
  const [ring, setRing] = useState2(null);
7849
- const [log4, setLog] = useState2([]);
7494
+ const [log3, setLog] = useState2([]);
7850
7495
  const [filter, setFilter] = useState2("all");
7851
7496
  const [signal, setSignal] = useState2("none");
7852
7497
  const [search, setSearch] = useState2("");
@@ -8449,9 +8094,9 @@ function LivePanel({ active: active2 }) {
8449
8094
  const allHits = ins.dlpByPattern ?? [];
8450
8095
  const maxHit = allHits[0]?.count ?? 1;
8451
8096
  const L = [];
8452
- const push2 = (el) => L.push(/* @__PURE__ */ jsx2(Box2, { children: el }, L.length));
8453
- const blank = () => push2(/* @__PURE__ */ jsx2(Text2, { children: " " }));
8454
- const section = (label, m, note) => push2(
8097
+ const push = (el) => L.push(/* @__PURE__ */ jsx2(Box2, { children: el }, L.length));
8098
+ const blank = () => push(/* @__PURE__ */ jsx2(Text2, { children: " " }));
8099
+ const section = (label, m, note) => push(
8455
8100
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
8456
8101
  /* @__PURE__ */ jsxs2(Text2, { bold: true, color: theme.accentBright, children: [
8457
8102
  "\u258E",
@@ -8461,7 +8106,7 @@ function LivePanel({ active: active2 }) {
8461
8106
  note ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: note }) : null
8462
8107
  ] })
8463
8108
  );
8464
- const kv = (k, v) => push2(
8109
+ const kv = (k, v) => push(
8465
8110
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
8466
8111
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (" " + k).padEnd(16) }),
8467
8112
  v
@@ -8470,18 +8115,18 @@ function LivePanel({ active: active2 }) {
8470
8115
  section("RATELIMIT", rl?.mode, rl?.mode === "block" ? "over-limit calls are DENIED" : rl?.mode === "detect" ? "over-limit calls are observed & flagged rl:yes" : "no limit enforcement");
8471
8116
  kv("limits", /* @__PURE__ */ jsx2(Text2, { children: rl?.perMinute || rl?.perHour || rl?.perDay ? `${rl?.perMinute || "\u2014"}/min \xB7 ${rl?.perHour || "\u2014"}/hour \xB7 ${rl?.perDay || "\u2014"}/day` : "none configured" }));
8472
8117
  kv("load now", /* @__PURE__ */ jsx2(Text2, { children: `${minuteNow} calls in the last 60s` }));
8473
- if (rl?.perMinute) push2(/* @__PURE__ */ jsx2(HBar, { label: " load/min", value: minuteNow, max: rl.perMinute, width: barW, color: minuteNow > rl.perMinute ? theme.bad : theme.accent }));
8118
+ if (rl?.perMinute) push(/* @__PURE__ */ jsx2(HBar, { label: " load/min", value: minuteNow, max: rl.perMinute, width: barW, color: minuteNow > rl.perMinute ? theme.bad : theme.accent }));
8474
8119
  kv("bursts", /* @__PURE__ */ jsx2(Text2, { color: burstsInBuf ? theme.warn : theme.dim, children: `${burstsInBuf} flagged in the live buffer` }));
8475
8120
  blank();
8476
8121
  section("DLP", dl?.mode, dl?.mode === "block" ? "secrets in arguments are DENIED + redacted" : dl?.mode === "detect" ? "secrets observed & flagged dlp:yes, output redacted" : "no secret scanning");
8477
8122
  kv("hits", /* @__PURE__ */ jsx2(Text2, { color: dlpInBuf ? theme.bad : theme.dim, children: `${dlpInBuf} flagged in the live buffer` }));
8478
8123
  const builtin = dl?.patterns ?? [];
8479
8124
  kv("builtin", /* @__PURE__ */ jsx2(Text2, { children: builtin.length ? `${builtin.length} patterns enabled` : "none enabled" }));
8480
- for (const line of wrapLines(builtin.join(" \xB7 "), Math.max(20, innerW - 18))) push2(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
8125
+ for (const line of wrapLines(builtin.join(" \xB7 "), Math.max(20, innerW - 18))) push(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
8481
8126
  const custom = dl?.custom ?? [];
8482
8127
  kv("custom", /* @__PURE__ */ jsx2(Text2, { children: custom.length ? `${custom.length} patterns` : "none" }));
8483
8128
  for (const c2 of custom)
8484
- push2(
8129
+ push(
8485
8130
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
8486
8131
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " }),
8487
8132
  /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(c2.name ?? "custom", 24).padEnd(25) }),
@@ -8489,12 +8134,12 @@ function LivePanel({ active: active2 }) {
8489
8134
  ] })
8490
8135
  );
8491
8136
  kv("pattern hits", /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: allHits.length ? "last 7 days" : "none in the last 7 days" }));
8492
- for (const h of allHits) push2(/* @__PURE__ */ jsx2(HBar, { label: " " + truncate2(h.pattern, 10), value: h.count, max: maxHit, width: barW, color: theme.bad }));
8137
+ for (const h of allHits) push(/* @__PURE__ */ jsx2(HBar, { label: " " + truncate2(h.pattern, 10), value: h.count, max: maxHit, width: barW, color: theme.bad }));
8493
8138
  blank();
8494
8139
  section("GHOST", gh?.mode, gh?.mode === "on" ? "matching paths are hidden from agents" : "no hidden paths");
8495
8140
  const ghostPats = gh?.patterns ?? [];
8496
8141
  kv("patterns", /* @__PURE__ */ jsx2(Text2, { children: ghostPats.length ? `${ghostPats.length}` : "none" }));
8497
- for (const line of wrapLines(ghostPats.join(" \xB7 "), Math.max(20, innerW - 18))) push2(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
8142
+ for (const line of wrapLines(ghostPats.join(" \xB7 "), Math.max(20, innerW - 18))) push(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
8498
8143
  blank();
8499
8144
  section("GUARD", guard.data ? guard.data.up_to_date ? "ok" : "stale" : "?", "the PreToolUse hook enforcing all of the above");
8500
8145
  kv(
@@ -8690,7 +8335,7 @@ function LivePanel({ active: active2 }) {
8690
8335
  ] }),
8691
8336
  /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
8692
8337
  /* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
8693
- log4.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
8338
+ log3.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
8694
8339
  /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
8695
8340
  hhmmss(l.ts),
8696
8341
  " "
@@ -8733,7 +8378,7 @@ var init_Live = __esm({
8733
8378
  "use strict";
8734
8379
  init_local_log();
8735
8380
  init_api_client();
8736
- init_config2();
8381
+ init_config();
8737
8382
  init_notify();
8738
8383
  init_hooks();
8739
8384
  init_components();
@@ -8807,8 +8452,8 @@ function requestDryRun(policyId) {
8807
8452
  pendingPolicyId = policyId;
8808
8453
  }
8809
8454
  function DryRunPanel({ focused }) {
8810
- const list6 = useLoader(() => api.policies.list());
8811
- const policies = list6.data?.policies ?? [];
8455
+ const list5 = useLoader(() => api.policies.list());
8456
+ const policies = list5.data?.policies ?? [];
8812
8457
  const [pi, setPi] = useState3(0);
8813
8458
  const [limit, setLimit] = useState3(DEFAULT_LIMIT);
8814
8459
  const [editLogs, setEditLogs] = useState3(null);
@@ -8863,7 +8508,7 @@ function DryRunPanel({ focused }) {
8863
8508
  const w = Math.max(40, cols);
8864
8509
  const lines = [];
8865
8510
  const head = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: t }, `h${lines.length}`));
8866
- const dim3 = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: t }, `d${lines.length}`));
8511
+ const dim2 = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: t }, `d${lines.length}`));
8867
8512
  const row = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { wrap: "truncate", children: t }, `r${lines.length}`));
8868
8513
  const blank = () => lines.push(/* @__PURE__ */ jsx3(Text3, { children: " " }, `b${lines.length}`));
8869
8514
  if (res) {
@@ -8889,7 +8534,7 @@ function DryRunPanel({ focused }) {
8889
8534
  blank();
8890
8535
  if (res.per_rule.length) {
8891
8536
  head("Per-rule impact");
8892
- dim3(` ${"RULE".padEnd(38)}${"MATCHED".padEnd(9)}${"%".padEnd(8)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
8537
+ dim2(` ${"RULE".padEnd(38)}${"MATCHED".padEnd(9)}${"%".padEnd(8)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
8893
8538
  for (const r of res.per_rule.slice(0, 30)) {
8894
8539
  row(` ${truncate2(r.rule_id, 36).padEnd(38)}${String(r.matched).padEnd(9)}${pct(r.matched, s.evaluated).padEnd(8)}${String(r.newly_blocked).padEnd(9)}${r.newly_allowed}`);
8895
8540
  }
@@ -8897,7 +8542,7 @@ function DryRunPanel({ focused }) {
8897
8542
  }
8898
8543
  if (res.per_agent.length) {
8899
8544
  head("Per-agent impact");
8900
- dim3(` ${"AGENT".padEnd(24)}${"EVALUATED".padEnd(11)}${"CHANGED".padEnd(9)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
8545
+ dim2(` ${"AGENT".padEnd(24)}${"EVALUATED".padEnd(11)}${"CHANGED".padEnd(9)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
8901
8546
  for (const a of res.per_agent) {
8902
8547
  row(` ${truncate2(a.agent || "-", 22).padEnd(24)}${String(a.evaluated).padEnd(11)}${String(a.changed).padEnd(9)}${String(a.newly_blocked).padEnd(9)}${a.newly_allowed}`);
8903
8548
  }
@@ -8905,7 +8550,7 @@ function DryRunPanel({ focused }) {
8905
8550
  }
8906
8551
  if (res.per_tool.length) {
8907
8552
  head("Per-tool breakdown");
8908
- dim3(` ${"TOOL".padEnd(24)}${"EVALUATED".padEnd(11)}${"CHANGED".padEnd(9)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
8553
+ dim2(` ${"TOOL".padEnd(24)}${"EVALUATED".padEnd(11)}${"CHANGED".padEnd(9)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
8909
8554
  for (const t of res.per_tool) {
8910
8555
  row(` ${truncate2(t.tool || "-", 22).padEnd(24)}${String(t.evaluated).padEnd(11)}${String(t.changed).padEnd(9)}${String(t.newly_blocked).padEnd(9)}${t.newly_allowed}`);
8911
8556
  }
@@ -8935,7 +8580,7 @@ function DryRunPanel({ focused }) {
8935
8580
  const win = lines.slice(start, start + budget);
8936
8581
  const above = start;
8937
8582
  const below = Math.max(0, lines.length - (start + budget));
8938
- return /* @__PURE__ */ jsx3(DataView, { loading: list6.loading && !list6.data, error: list6.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
8583
+ return /* @__PURE__ */ jsx3(DataView, { loading: list5.loading && !list5.data, error: list5.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
8939
8584
  /* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: "Policy Dry Run" }),
8940
8585
  /* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
8941
8586
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " policy " }),
@@ -9014,8 +8659,8 @@ function ruleSummary(r) {
9014
8659
  return bits.join(" ");
9015
8660
  }
9016
8661
  function PoliciesPanel({ focused }) {
9017
- const list6 = useLoader(() => api.policies.list());
9018
- const policies = list6.data?.policies ?? [];
8662
+ const list5 = useLoader(() => api.policies.list());
8663
+ const policies = list5.data?.policies ?? [];
9019
8664
  const activeQ = useLoader(() => api.policies.active());
9020
8665
  const activeId = activeQ.data?.policy?.id ?? null;
9021
8666
  const activeBy = activeQ.data?.matched_by;
@@ -9041,7 +8686,7 @@ function PoliciesPanel({ focused }) {
9041
8686
  }
9042
8687
  }, [detail.data]);
9043
8688
  usePoll(() => {
9044
- list6.reloadQuiet();
8689
+ list5.reloadQuiet();
9045
8690
  activeQ.reloadQuiet();
9046
8691
  }, 3e3);
9047
8692
  const mutate = (nextRules, nextMode = mode) => {
@@ -9065,7 +8710,7 @@ function PoliciesPanel({ focused }) {
9065
8710
  setRules(res.rules);
9066
8711
  setDirty(false);
9067
8712
  setStatus("\u2713 Saved");
9068
- list6.reload();
8713
+ list5.reload();
9069
8714
  } catch (e) {
9070
8715
  setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
9071
8716
  }
@@ -9086,14 +8731,14 @@ function PoliciesPanel({ focused }) {
9086
8731
  setStatus("Creating\u2026");
9087
8732
  void api.policies.create({ id: `policy-${Date.now()}`, name: n, rules: [], mode: "denylist" }).then(() => {
9088
8733
  setStatus(`\u2713 created "${n}" - open it and press n to add rules`);
9089
- list6.reload();
8734
+ list5.reload();
9090
8735
  }).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
9091
8736
  }
9092
8737
  useInput3(
9093
8738
  (input, key) => {
9094
8739
  if (creating !== null) return;
9095
8740
  if (key.ctrl && input === "r" && !editing) {
9096
- list6.reload();
8741
+ list5.reload();
9097
8742
  activeQ.reload();
9098
8743
  detail.reload();
9099
8744
  setStatus(`\u27F3 refreshed ${(/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })}`);
@@ -9189,7 +8834,7 @@ function PoliciesPanel({ focused }) {
9189
8834
  const lWin = policies.slice(lStart, lStart + lBudget);
9190
8835
  const lAbove = lStart;
9191
8836
  const lBelow = Math.max(0, policies.length - (lStart + lBudget));
9192
- return /* @__PURE__ */ jsx4(DataView, { loading: list6.loading && !list6.data, error: list6.error, empty: !!list6.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
8837
+ return /* @__PURE__ */ jsx4(DataView, { loading: list5.loading && !list5.data, error: list5.error, empty: !!list5.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
9193
8838
  /* @__PURE__ */ jsxs4(Box4, { children: [
9194
8839
  /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "active: " }),
9195
8840
  activeQ.loading && !activeQ.data ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "\u2026" }) : activeName ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
@@ -11418,9 +11063,9 @@ function App() {
11418
11063
  viewAccount(accounts[(acctIdx + 1) % accounts.length]);
11419
11064
  };
11420
11065
  const syncAccounts = () => {
11421
- const list6 = listAccounts();
11422
- setAccounts(list6);
11423
- const next = list6.find((a) => a.apiKey === viewKey) ?? list6[0];
11066
+ const list5 = listAccounts();
11067
+ setAccounts(list5);
11068
+ const next = list5.find((a) => a.apiKey === viewKey) ?? list5[0];
11424
11069
  setViewCredentials(next ? { apiKey: next.apiKey, apiUrl: next.apiUrl } : null);
11425
11070
  setViewKey(next?.apiKey);
11426
11071
  setViewNonce((n) => n + 1);
@@ -12196,7 +11841,7 @@ async function runAgents(argv) {
12196
11841
  const res = await api.agents.live({ limit: flagNum(flags, "limit"), includeDeactivated: flagBool(flags, "all") });
12197
11842
  if (json) return printJson(res), 0;
12198
11843
  err("");
12199
- err(` Agents ${green(String(res.counts.active))} active ${yellow(String(res.counts.idle))} idle ${dim(String(res.counts.deactivated) + " off")}`);
11844
+ err(` Sessions ${green(String(res.counts.active))} active ${yellow(String(res.counts.idle))} idle ${dim(String(res.counts.deactivated) + " off")}`);
12200
11845
  if (!res.agents.length) return err(dim(" No agent sessions.")), 0;
12201
11846
  table(
12202
11847
  ["STATUS", "AGENT", "CALLS", "DENY", "DLP", "TRUST", "CHARACTER"],
@@ -12216,7 +11861,7 @@ async function runAgent(argv) {
12216
11861
  const { positionals, flags } = parse(argv);
12217
11862
  const json = flagBool(flags, "json");
12218
11863
  const id = positionals[0];
12219
- if (!id) return err(" Usage: solongate agent <agent_id> [--json]"), 1;
11864
+ if (!id) return err(" Usage: solongate session <id> [--json]"), 1;
12220
11865
  const a = await api.agents.get(id);
12221
11866
  if (json) return printJson(a), 0;
12222
11867
  err("");
@@ -12571,9 +12216,9 @@ async function dispatch(command, argv) {
12571
12216
  return run4(argv);
12572
12217
  case "audit":
12573
12218
  return run5(argv);
12574
- case "agents":
12219
+ case "sessions":
12575
12220
  return runAgents(argv);
12576
- case "agent":
12221
+ case "session":
12577
12222
  return runAgent(argv);
12578
12223
  case "doctor":
12579
12224
  return run6(argv);
@@ -12621,7 +12266,7 @@ var init_commands = __esm({
12621
12266
  init_watch();
12622
12267
  init_alerts();
12623
12268
  init_webhooks();
12624
- COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks"];
12269
+ COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"];
12625
12270
  }
12626
12271
  });
12627
12272
 
@@ -12829,331 +12474,361 @@ var init_logs_server = __esm({
12829
12474
  LOG_FILENAME = "solongate-audit.jsonl";
12830
12475
  DEFAULT_PORT = 8788;
12831
12476
  }
12832
- });
12833
-
12834
- // src/pull-push.ts
12835
- var pull_push_exports = {};
12836
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync10, existsSync as existsSync7 } from "fs";
12837
- import { resolve as resolve6 } from "path";
12838
- function loadEnv() {
12839
- if (process.env.SOLONGATE_API_KEY) return;
12840
- const envPath = resolve6(".env");
12841
- if (!existsSync7(envPath)) return;
12842
- try {
12843
- const content = readFileSync12(envPath, "utf-8");
12844
- for (const line of content.split("\n")) {
12845
- const trimmed = line.trim();
12846
- if (!trimmed || trimmed.startsWith("#")) continue;
12847
- const eq = trimmed.indexOf("=");
12848
- if (eq === -1) continue;
12849
- const key = trimmed.slice(0, eq).trim();
12850
- const val = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
12851
- if (key === "SOLONGATE_API_KEY") {
12852
- process.env.SOLONGATE_API_KEY = val;
12853
- return;
12477
+ });
12478
+
12479
+ // src/index.ts
12480
+ import { readFileSync as readFileSync12 } from "fs";
12481
+ import { fileURLToPath as fileURLToPath4 } from "url";
12482
+ import { dirname as dirname4, join as join16 } from "path";
12483
+
12484
+ // src/config.ts
12485
+ import { readFileSync, existsSync } from "fs";
12486
+ import { appendFile } from "fs/promises";
12487
+ import { resolve, join } from "path";
12488
+ import { homedir } from "os";
12489
+ function loginCredential() {
12490
+ try {
12491
+ const p = join(homedir(), ".solongate", "cloud-guard.json");
12492
+ if (!existsSync(p)) return {};
12493
+ const c2 = JSON.parse(readFileSync(p, "utf-8"));
12494
+ return c2 && typeof c2 === "object" ? c2 : {};
12495
+ } catch {
12496
+ return {};
12497
+ }
12498
+ }
12499
+ var DEFAULT_API_URL = "https://api.solongate.com";
12500
+ async function fetchCloudPolicy(apiKey, apiUrl, policyId) {
12501
+ let resolvedId = policyId;
12502
+ if (!resolvedId) {
12503
+ const listRes = await fetch(`${apiUrl}/api/v1/policies`, {
12504
+ headers: { "Authorization": `Bearer ${apiKey}` },
12505
+ signal: AbortSignal.timeout(1e4)
12506
+ });
12507
+ if (!listRes.ok) {
12508
+ const body = await listRes.text().catch(() => "");
12509
+ throw new Error(`Failed to list policies from cloud (${listRes.status}): ${body}`);
12510
+ }
12511
+ const listData = await listRes.json();
12512
+ const policies = listData.policies ?? [];
12513
+ if (policies.length === 0) {
12514
+ throw new Error("No policies found in cloud. Create one in the dashboard first.");
12515
+ }
12516
+ resolvedId = policies[0].id;
12517
+ }
12518
+ const url = `${apiUrl}/api/v1/policies/${resolvedId}`;
12519
+ const res = await fetch(url, {
12520
+ headers: { "Authorization": `Bearer ${apiKey}` },
12521
+ signal: AbortSignal.timeout(1e4)
12522
+ });
12523
+ if (!res.ok) {
12524
+ const body = await res.text().catch(() => "");
12525
+ throw new Error(`Failed to fetch policy from cloud (${res.status}): ${body}`);
12526
+ }
12527
+ const data = await res.json();
12528
+ return {
12529
+ id: String(data.id ?? "cloud"),
12530
+ name: String(data.name ?? "Cloud Policy"),
12531
+ description: String(data.description ?? ""),
12532
+ version: Number(data._version ?? 1),
12533
+ rules: data.rules ?? [],
12534
+ createdAt: String(data._created_at ?? ""),
12535
+ updatedAt: ""
12536
+ };
12537
+ }
12538
+ async function fetchCloudPolicyWasm(apiKey, apiUrl, policyId) {
12539
+ try {
12540
+ const res = await fetch(`${apiUrl}/api/v1/policies/${policyId}/wasm`, {
12541
+ headers: { "Authorization": `Bearer ${apiKey}` },
12542
+ signal: AbortSignal.timeout(1e4)
12543
+ });
12544
+ if (!res.ok) return null;
12545
+ return new Uint8Array(await res.arrayBuffer());
12546
+ } catch {
12547
+ return null;
12548
+ }
12549
+ }
12550
+ var AUDIT_MAX_RETRIES = 3;
12551
+ var AUDIT_LOG_BACKUP_PATH = resolve(".solongate-audit-backup.jsonl");
12552
+ async function sendAuditLog(apiKey, apiUrl, entry) {
12553
+ const url = `${apiUrl}/api/v1/audit-logs`;
12554
+ const body = JSON.stringify({
12555
+ ...entry,
12556
+ agent_id: entry.agent_id,
12557
+ agent_name: entry.agent_name
12558
+ });
12559
+ for (let attempt = 0; attempt < AUDIT_MAX_RETRIES; attempt++) {
12560
+ try {
12561
+ const res = await fetch(url, {
12562
+ method: "POST",
12563
+ headers: {
12564
+ "Authorization": `Bearer ${apiKey}`,
12565
+ "Content-Type": "application/json"
12566
+ },
12567
+ body,
12568
+ signal: AbortSignal.timeout(5e3)
12569
+ });
12570
+ if (res.ok) return;
12571
+ if (res.status >= 400 && res.status < 500) {
12572
+ const resBody = await res.text().catch(() => "");
12573
+ process.stderr.write(`[SolonGate] Audit log rejected (${res.status}): ${resBody}
12574
+ `);
12575
+ return;
12576
+ }
12577
+ } catch {
12578
+ }
12579
+ if (attempt < AUDIT_MAX_RETRIES - 1) {
12580
+ await new Promise((r) => setTimeout(r, 500 * Math.pow(2, attempt)));
12581
+ }
12582
+ }
12583
+ process.stderr.write(`[SolonGate] Audit log failed after ${AUDIT_MAX_RETRIES} retries, saving to local backup.
12584
+ `);
12585
+ try {
12586
+ const line = JSON.stringify({ ...entry, timestamp: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
12587
+ appendFile(AUDIT_LOG_BACKUP_PATH, line, "utf-8").catch((err2) => {
12588
+ process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
12589
+ `);
12590
+ });
12591
+ } catch (err2) {
12592
+ process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
12593
+ `);
12594
+ }
12595
+ }
12596
+ var DEFAULT_POLICY = {
12597
+ id: "default",
12598
+ name: "Default (Allow All)",
12599
+ description: "Allows all tools by default. Add DENY rules from the dashboard to restrict.",
12600
+ version: 1,
12601
+ rules: [
12602
+ {
12603
+ id: "_default-allow-all",
12604
+ description: "Allow all tools by default",
12605
+ effect: "ALLOW",
12606
+ priority: 9999,
12607
+ toolPattern: "*",
12608
+ minimumTrustLevel: "UNTRUSTED",
12609
+ enabled: true,
12610
+ createdAt: "",
12611
+ updatedAt: ""
12612
+ }
12613
+ ],
12614
+ createdAt: "",
12615
+ updatedAt: ""
12616
+ };
12617
+ function ensureCatchAllAllow(policy) {
12618
+ const hasCatchAllAllow = policy.rules.some(
12619
+ (r) => r.effect === "ALLOW" && r.toolPattern === "*" && r.enabled !== false
12620
+ );
12621
+ if (hasCatchAllAllow) return policy;
12622
+ const now = (/* @__PURE__ */ new Date()).toISOString();
12623
+ return {
12624
+ ...policy,
12625
+ rules: [
12626
+ ...policy.rules,
12627
+ {
12628
+ id: "_solongate-catch-all-allow",
12629
+ description: "Auto-added: allow everything not explicitly denied",
12630
+ effect: "ALLOW",
12631
+ priority: 9999,
12632
+ toolPattern: "*",
12633
+ minimumTrustLevel: "UNTRUSTED",
12634
+ enabled: true,
12635
+ createdAt: now,
12636
+ updatedAt: now
12854
12637
  }
12638
+ ]
12639
+ };
12640
+ }
12641
+ function loadPolicy(source) {
12642
+ let policy;
12643
+ if (typeof source === "object") {
12644
+ policy = source;
12645
+ } else {
12646
+ const filePath = resolve(source);
12647
+ if (existsSync(filePath)) {
12648
+ const content = readFileSync(filePath, "utf-8");
12649
+ policy = JSON.parse(content);
12650
+ } else {
12651
+ return DEFAULT_POLICY;
12855
12652
  }
12856
- } catch {
12857
12653
  }
12654
+ return ensureCatchAllAllow(policy);
12858
12655
  }
12859
- function parseCliArgs() {
12860
- loadEnv();
12861
- const args = process.argv.slice(2);
12862
- const command = args[0];
12863
- let apiKey = process.env.SOLONGATE_API_KEY || "";
12864
- let file = "policy.json";
12656
+ function parseArgs(argv) {
12657
+ const args = argv.slice(2);
12658
+ let policySource;
12659
+ let name = "solongate-proxy";
12660
+ let verbose = false;
12661
+ let rateLimitPerTool;
12662
+ let globalRateLimit;
12663
+ let configFile;
12664
+ let apiKey;
12665
+ let apiUrl;
12666
+ let upstreamUrl;
12667
+ let upstreamTransport;
12668
+ let port;
12865
12669
  let policyId;
12866
- for (let i = 1; i < args.length; i++) {
12867
- switch (args[i]) {
12670
+ let agentName;
12671
+ let separatorIndex = args.indexOf("--");
12672
+ const flags = separatorIndex >= 0 ? args.slice(0, separatorIndex) : args;
12673
+ let upstreamArgs = separatorIndex >= 0 ? args.slice(separatorIndex + 1) : [];
12674
+ for (let i = 0; i < flags.length; i++) {
12675
+ if (!flags[i].startsWith("--")) {
12676
+ if (upstreamArgs.length === 0) {
12677
+ upstreamArgs.push(...flags.slice(i));
12678
+ }
12679
+ break;
12680
+ }
12681
+ switch (flags[i]) {
12682
+ case "--policy":
12683
+ policySource = flags[++i];
12684
+ break;
12685
+ case "--name":
12686
+ name = flags[++i];
12687
+ break;
12688
+ case "--verbose":
12689
+ verbose = true;
12690
+ break;
12691
+ case "--rate-limit":
12692
+ rateLimitPerTool = parseInt(flags[++i], 10);
12693
+ break;
12694
+ case "--global-rate-limit":
12695
+ globalRateLimit = parseInt(flags[++i], 10);
12696
+ break;
12697
+ case "--config":
12698
+ configFile = flags[++i];
12699
+ break;
12868
12700
  case "--api-key":
12869
- apiKey = args[++i];
12701
+ apiKey = flags[++i];
12870
12702
  break;
12871
- case "--policy":
12872
- case "--output":
12873
- case "--file":
12874
- case "-f":
12875
- case "-o":
12876
- file = args[++i];
12703
+ case "--api-url":
12704
+ apiUrl = flags[++i];
12705
+ break;
12706
+ case "--upstream-url":
12707
+ upstreamUrl = flags[++i];
12708
+ break;
12709
+ case "--upstream-transport":
12710
+ upstreamTransport = flags[++i];
12711
+ break;
12712
+ case "--port":
12713
+ port = parseInt(flags[++i], 10);
12877
12714
  break;
12878
12715
  case "--policy-id":
12879
12716
  case "--id":
12880
- policyId = args[++i];
12717
+ policyId = flags[++i];
12718
+ break;
12719
+ case "--agent-name":
12720
+ agentName = flags[++i];
12881
12721
  break;
12882
12722
  }
12883
12723
  }
12724
+ if (apiKey && /^\$\{.+\}$/.test(apiKey)) {
12725
+ apiKey = void 0;
12726
+ }
12884
12727
  if (!apiKey) {
12885
- log3(red2("ERROR: API key not found."));
12886
- log3("");
12887
- log3("Set it in .env file:");
12888
- log3(" SOLONGATE_API_KEY=sg_live_...");
12889
- log3("");
12890
- log3("Or pass via environment:");
12891
- log3(` SOLONGATE_API_KEY=sg_live_... solongate-proxy ${command}`);
12892
- process.exit(1);
12728
+ const dotenvPath = resolve(".env");
12729
+ if (existsSync(dotenvPath)) {
12730
+ const dotenvContent = readFileSync(dotenvPath, "utf-8");
12731
+ const match = dotenvContent.match(/^SOLONGATE_API_KEY=(sg_(?:live|test)_\w+)/m);
12732
+ if (match) apiKey = match[1];
12733
+ }
12893
12734
  }
12894
- if (!apiKey.startsWith("sg_live_")) {
12895
- log3(red2("ERROR: Pull/push/list requires a live API key (sg_live_...)."));
12896
- process.exit(1);
12735
+ if (!apiKey) {
12736
+ const envKey = process.env.SOLONGATE_API_KEY;
12737
+ if (envKey && !/^\$\{.+\}$/.test(envKey)) {
12738
+ apiKey = envKey;
12739
+ }
12897
12740
  }
12898
- return { command, apiKey, file: resolve6(file), policyId };
12899
- }
12900
- async function listPolicies(apiKey) {
12901
- const res = await fetch(`${API_URL}/api/v1/policies`, {
12902
- headers: { "Authorization": `Bearer ${apiKey}` }
12903
- });
12904
- if (!res.ok) throw new Error(`Failed to list policies (${res.status})`);
12905
- const data = await res.json();
12906
- return data.policies ?? [];
12907
- }
12908
- async function list5(apiKey, policyId) {
12909
- const policies = await listPolicies(apiKey);
12910
- if (policies.length === 0) {
12911
- log3(yellow2("No policies found. Create one in the dashboard first."));
12912
- log3(dim2(" https://dashboard.solongate.com/policies"));
12913
- return;
12741
+ if (!apiKey) {
12742
+ const cred = loginCredential();
12743
+ if (cred.apiKey) apiKey = cred.apiKey;
12914
12744
  }
12915
- if (policyId) {
12916
- const match = policies.find((p) => p.id === policyId);
12917
- if (!match) {
12918
- log3(red2(`Policy not found: ${policyId}`));
12919
- log3("");
12920
- log3("Available policies:");
12921
- for (const p of policies) {
12922
- log3(` ${dim2("\u2022")} ${p.id}`);
12923
- }
12924
- process.exit(1);
12925
- }
12926
- const full = await fetchCloudPolicy(apiKey, API_URL, policyId);
12927
- printPolicyDetail(full);
12928
- return;
12745
+ if (!apiKey) {
12746
+ throw new Error(
12747
+ "Not logged in. Run this once to get started:\n\n solongate\n\n then add your account from the Accounts panel.\n"
12748
+ );
12929
12749
  }
12930
- log3("");
12931
- log3(bold2(` Policies (${policies.length})`));
12932
- log3(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"));
12933
- log3("");
12934
- const fullPolicies = await Promise.all(
12935
- policies.map(
12936
- (p) => fetchCloudPolicy(apiKey, API_URL, p.id).then((full) => ({ policy: p, rules: full.rules })).catch(() => ({ policy: p, rules: [] }))
12937
- )
12938
- );
12939
- for (const { policy, rules } of fullPolicies) {
12940
- printPolicySummary(policy, [...rules]);
12941
- }
12942
- log3(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"));
12943
- log3("");
12944
- log3(` ${dim2("View details:")} solongate-proxy list --policy-id <ID>`);
12945
- log3(` ${dim2("Pull policy:")} solongate-proxy pull --policy-id <ID>`);
12946
- log3(` ${dim2("Push policy:")} solongate-proxy push --policy-id <ID>`);
12947
- log3("");
12948
- }
12949
- function printPolicySummary(p, rules) {
12950
- const ruleCount = rules.length;
12951
- const allowCount = rules.filter((r) => r.effect === "ALLOW").length;
12952
- const denyCount = rules.filter((r) => r.effect === "DENY").length;
12953
- log3(` ${cyan2(p.id)}`);
12954
- log3(` ${bold2(p.name)} ${dim2(`v${p.version ?? "?"}`)}`);
12955
- log3(` ${dim2("Rules:")} ${ruleCount} ${green2(`${allowCount} ALLOW`)} ${red2(`${denyCount} DENY`)}`);
12956
- if (p.created_at) {
12957
- log3(` ${dim2("Updated:")} ${new Date(p.created_at).toLocaleString()}`);
12958
- }
12959
- log3("");
12960
- }
12961
- function printPolicyDetail(policy) {
12962
- log3("");
12963
- log3(bold2(` ${policy.name}`));
12964
- log3(` ${dim2("ID:")} ${cyan2(policy.id)} ${dim2("Version:")} ${policy.version} ${dim2("Rules:")} ${policy.rules.length}`);
12965
- log3("");
12966
- if (policy.rules.length === 0) {
12967
- log3(yellow2(" No rules defined."));
12968
- log3("");
12969
- return;
12750
+ if (!apiKey.startsWith("sg_live_") && !apiKey.startsWith("sg_test_")) {
12751
+ throw new Error(
12752
+ "Invalid API key format. Keys must start with 'sg_live_' or 'sg_test_'.\nGet your API key at https://solongate.com\n"
12753
+ );
12970
12754
  }
12971
- log3(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"));
12972
- for (const rule of policy.rules) {
12973
- const effectColor = rule.effect === "ALLOW" ? green2 : red2;
12974
- log3("");
12975
- log3(` ${effectColor(rule.effect.padEnd(5))} ${bold2(rule.toolPattern)} ${dim2(`P:${rule.priority}`)}`);
12976
- if (rule.description) {
12977
- log3(` ${dim2(rule.description)}`);
12978
- }
12979
- log3(` ${dim2(`${rule.permission} trust:${rule.minimumTrustLevel || "UNTRUSTED"}`)}`);
12980
- if (rule.pathConstraints) {
12981
- const pc = rule.pathConstraints;
12982
- if (pc.rootDirectory) log3(` ${magenta("ROOT")} ${pc.rootDirectory}`);
12983
- if (pc.allowed?.length) log3(` ${green2("PATHS")} ${pc.allowed.join(", ")}`);
12984
- if (pc.denied?.length) log3(` ${red2("DENY")} ${pc.denied.join(", ")}`);
12985
- }
12986
- if (rule.commandConstraints) {
12987
- const cc = rule.commandConstraints;
12988
- if (cc.allowed?.length) log3(` ${green2("CMDS")} ${cc.allowed.join(", ")}`);
12989
- if (cc.denied?.length) log3(` ${red2("DENY")} ${cc.denied.join(", ")}`);
12990
- }
12991
- if (rule.filenameConstraints) {
12992
- const fc = rule.filenameConstraints;
12993
- if (fc.allowed?.length) log3(` ${green2("FILES")} ${fc.allowed.join(", ")}`);
12994
- if (fc.denied?.length) log3(` ${red2("DENY")} ${fc.denied.join(", ")}`);
12995
- }
12996
- if (rule.urlConstraints) {
12997
- const uc = rule.urlConstraints;
12998
- if (uc.allowed?.length) log3(` ${green2("URLS")} ${uc.allowed.join(", ")}`);
12999
- if (uc.denied?.length) log3(` ${red2("DENY")} ${uc.denied.join(", ")}`);
13000
- }
13001
- }
13002
- log3("");
13003
- log3(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"));
13004
- log3("");
13005
- }
13006
- async function pull(apiKey, file, policyId) {
13007
- if (!policyId) {
13008
- const policies = await listPolicies(apiKey);
13009
- if (policies.length === 0) {
13010
- log3(red2("No policies found. Create one in the dashboard first."));
13011
- process.exit(1);
12755
+ const resolvedPolicyPath = policySource ? resolvePolicyPath(policySource) : null;
12756
+ if (configFile) {
12757
+ const filePath = resolve(configFile);
12758
+ const content = readFileSync(filePath, "utf-8");
12759
+ const fileConfig = JSON.parse(content);
12760
+ if (!fileConfig.upstream) {
12761
+ throw new Error('Config file must include "upstream" with at least "command" or "url"');
13012
12762
  }
13013
- if (policies.length === 1) {
13014
- policyId = policies[0].id;
13015
- log3(dim2(`Auto-selecting only policy: ${policyId}`));
13016
- } else {
13017
- log3(yellow2(`Found ${policies.length} policies:`));
13018
- log3("");
13019
- for (const p of policies) {
13020
- log3(` ${cyan2(p.id)} ${p.name} ${dim2(`v${p.version ?? "?"}`)}`);
13021
- }
13022
- log3("");
13023
- log3("Use --policy-id <ID> to specify which one to pull.");
13024
- process.exit(1);
13025
- }
13026
- }
13027
- log3(`Pulling ${cyan2(policyId)} from dashboard...`);
13028
- const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
13029
- const { id: _id, ...policyWithoutId } = policy;
13030
- const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
13031
- writeFileSync10(file, json, "utf-8");
13032
- log3("");
13033
- log3(green2(" Saved to: ") + file);
13034
- log3(` ${dim2("Name:")} ${policy.name}`);
13035
- log3(` ${dim2("Version:")} ${policy.version}`);
13036
- log3(` ${dim2("Rules:")} ${policy.rules.length}`);
13037
- log3("");
13038
- log3(dim2("The policy file does not contain an ID."));
13039
- log3(dim2("Use --policy-id to specify the target when pushing/pulling."));
13040
- log3("");
13041
- }
13042
- async function push(apiKey, file, policyId) {
13043
- if (!existsSync7(file)) {
13044
- log3(red2(`ERROR: File not found: ${file}`));
13045
- process.exit(1);
12763
+ const cfgPolicySource = fileConfig.policy ?? policySource ?? "policy.json";
12764
+ return {
12765
+ upstream: fileConfig.upstream,
12766
+ policy: loadPolicy(cfgPolicySource),
12767
+ name: fileConfig.name ?? name,
12768
+ verbose: fileConfig.verbose ?? verbose,
12769
+ rateLimitPerTool: fileConfig.rateLimitPerTool ?? rateLimitPerTool,
12770
+ globalRateLimit: fileConfig.globalRateLimit ?? globalRateLimit,
12771
+ apiKey: apiKey ?? fileConfig.apiKey,
12772
+ apiUrl: apiUrl ?? fileConfig.apiUrl,
12773
+ port: port ?? fileConfig.port,
12774
+ policyPath: resolvePolicyPath(cfgPolicySource) ?? void 0,
12775
+ policyId: policyId ?? fileConfig.policyId,
12776
+ agentName
12777
+ };
13046
12778
  }
13047
- if (!policyId) {
13048
- log3(red2("ERROR: --policy-id is required for push."));
13049
- log3("");
13050
- log3("This determines which cloud policy to update.");
13051
- log3("");
13052
- log3("Usage:");
13053
- log3(" solongate-proxy push --policy-id my-policy");
13054
- log3(" solongate-proxy push --policy-id my-policy --file custom.json");
13055
- log3("");
13056
- log3("List your policies:");
13057
- log3(" solongate-proxy list");
13058
- process.exit(1);
12779
+ if (upstreamUrl) {
12780
+ const transport = upstreamTransport ?? (upstreamUrl.includes("/sse") ? "sse" : "http");
12781
+ return {
12782
+ upstream: {
12783
+ transport,
12784
+ command: "",
12785
+ // not used for URL-based transports
12786
+ url: upstreamUrl
12787
+ },
12788
+ policy: loadPolicy(policySource ?? "policy.json"),
12789
+ name,
12790
+ verbose,
12791
+ rateLimitPerTool,
12792
+ globalRateLimit,
12793
+ apiKey,
12794
+ apiUrl,
12795
+ port,
12796
+ policyPath: resolvedPolicyPath ?? void 0,
12797
+ policyId,
12798
+ agentName
12799
+ };
13059
12800
  }
13060
- const content = readFileSync12(file, "utf-8");
13061
- let policy;
13062
- try {
13063
- policy = JSON.parse(content);
13064
- } catch {
13065
- log3(red2(`ERROR: Invalid JSON in ${file}`));
13066
- process.exit(1);
12801
+ if (upstreamArgs.length === 0) {
12802
+ throw new Error(
12803
+ "No upstream server command provided.\n\nIf you just want to get started, run:\n solongate\n"
12804
+ );
13067
12805
  }
13068
- log3(`Pushing to ${cyan2(policyId)}...`);
13069
- log3(` ${dim2("File:")} ${file}`);
13070
- log3(` ${dim2("Name:")} ${policy.name || "Unnamed"}`);
13071
- log3(` ${dim2("Rules:")} ${(policy.rules || []).length}`);
13072
- const checkRes = await fetch(`${API_URL}/api/v1/policies/${policyId}`, {
13073
- headers: { "Authorization": `Bearer ${apiKey}` }
13074
- });
13075
- const method = checkRes.ok ? "PUT" : "POST";
13076
- const url = checkRes.ok ? `${API_URL}/api/v1/policies/${policyId}` : `${API_URL}/api/v1/policies`;
13077
- const res = await fetch(url, {
13078
- method,
13079
- headers: {
13080
- "Authorization": `Bearer ${apiKey}`,
13081
- "Content-Type": "application/json"
12806
+ const [command, ...commandArgs] = upstreamArgs;
12807
+ return {
12808
+ upstream: {
12809
+ transport: upstreamTransport ?? "stdio",
12810
+ command,
12811
+ args: commandArgs,
12812
+ env: { PATH: process.env.PATH ?? "", HOME: process.env.HOME ?? "", USERPROFILE: process.env.USERPROFILE ?? "" }
13082
12813
  },
13083
- body: JSON.stringify({
13084
- id: policyId,
13085
- name: policy.name || "Local Policy",
13086
- description: policy.description || "Pushed from local file",
13087
- version: policy.version || 1,
13088
- rules: policy.rules || []
13089
- })
13090
- });
13091
- if (!res.ok) {
13092
- const body = await res.text().catch(() => "");
13093
- log3(red2(`ERROR: Push failed (${res.status}): ${body}`));
13094
- process.exit(1);
13095
- }
13096
- const data = await res.json();
13097
- log3("");
13098
- log3(green2(` Pushed to cloud: v${data._version ?? "created"}`));
13099
- log3(` ${dim2("Policy ID:")} ${policyId}`);
13100
- log3(` ${dim2("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
13101
- log3("");
12814
+ policy: loadPolicy(policySource ?? "policy.json"),
12815
+ name,
12816
+ verbose,
12817
+ rateLimitPerTool,
12818
+ globalRateLimit,
12819
+ apiKey,
12820
+ apiUrl,
12821
+ port,
12822
+ policyPath: resolvedPolicyPath ?? void 0,
12823
+ policyId,
12824
+ agentName
12825
+ };
13102
12826
  }
13103
- async function main() {
13104
- const { command, apiKey, file, policyId } = parseCliArgs();
13105
- try {
13106
- if (command === "pull") {
13107
- await pull(apiKey, file, policyId);
13108
- } else if (command === "push") {
13109
- await push(apiKey, file, policyId);
13110
- } else if (command === "list" || command === "ls") {
13111
- await list5(apiKey, policyId);
13112
- } else {
13113
- log3(red2(`Unknown command: ${command}`));
13114
- log3("");
13115
- log3(bold2("Usage:"));
13116
- log3(" solongate-proxy list List all policies");
13117
- log3(" solongate-proxy list --policy-id <ID> Show policy details");
13118
- log3(" solongate-proxy pull --policy-id <ID> Pull policy to local file");
13119
- log3(" solongate-proxy push --policy-id <ID> Push local file to cloud");
13120
- log3("");
13121
- log3(bold2("Flags:"));
13122
- log3(" --policy-id, --id <ID> Cloud policy ID (required for push)");
13123
- log3(" --file, -f <path> Local file path (default: policy.json)");
13124
- log3(" --api-key <key> API key (or set SOLONGATE_API_KEY)");
13125
- log3("");
13126
- process.exit(1);
13127
- }
13128
- } catch (err2) {
13129
- log3(red2(`ERROR: ${err2 instanceof Error ? err2.message : String(err2)}`));
13130
- process.exit(1);
13131
- }
12827
+ function resolvePolicyPath(source) {
12828
+ const filePath = resolve(source);
12829
+ if (existsSync(filePath)) return filePath;
12830
+ return null;
13132
12831
  }
13133
- var log3, dim2, bold2, green2, red2, yellow2, cyan2, magenta, API_URL;
13134
- var init_pull_push = __esm({
13135
- "src/pull-push.ts"() {
13136
- "use strict";
13137
- init_config();
13138
- log3 = (...args) => process.stderr.write(`${args.map(String).join(" ")}
13139
- `);
13140
- dim2 = (s) => `\x1B[2m${s}\x1B[0m`;
13141
- bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
13142
- green2 = (s) => `\x1B[32m${s}\x1B[0m`;
13143
- red2 = (s) => `\x1B[31m${s}\x1B[0m`;
13144
- yellow2 = (s) => `\x1B[33m${s}\x1B[0m`;
13145
- cyan2 = (s) => `\x1B[36m${s}\x1B[0m`;
13146
- magenta = (s) => `\x1B[35m${s}\x1B[0m`;
13147
- API_URL = "https://api.solongate.com";
13148
- main();
13149
- }
13150
- });
13151
-
13152
- // src/index.ts
13153
- init_config();
13154
- import { readFileSync as readFileSync13 } from "fs";
13155
- import { fileURLToPath as fileURLToPath4 } from "url";
13156
- import { dirname as dirname4, join as join16 } from "path";
13157
12832
 
13158
12833
  // src/proxy.ts
13159
12834
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -15348,11 +15023,7 @@ var SolonGate = class {
15348
15023
  }
15349
15024
  };
15350
15025
 
15351
- // src/proxy.ts
15352
- init_config();
15353
-
15354
15026
  // src/sync.ts
15355
- init_config();
15356
15027
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, watch, existsSync as existsSync2 } from "fs";
15357
15028
  var log = (...args) => process.stderr.write(`[SolonGate Sync] ${args.map(String).join(" ")}
15358
15029
  `);
@@ -15577,7 +15248,7 @@ var Mutex = class {
15577
15248
  this.locked = true;
15578
15249
  return;
15579
15250
  }
15580
- return new Promise((resolve7, reject) => {
15251
+ return new Promise((resolve6, reject) => {
15581
15252
  const timer = setTimeout(() => {
15582
15253
  const idx = this.queue.indexOf(onReady);
15583
15254
  if (idx !== -1) this.queue.splice(idx, 1);
@@ -15585,7 +15256,7 @@ var Mutex = class {
15585
15256
  }, timeoutMs);
15586
15257
  const onReady = () => {
15587
15258
  clearTimeout(timer);
15588
- resolve7();
15259
+ resolve6();
15589
15260
  };
15590
15261
  this.queue.push(onReady);
15591
15262
  });
@@ -16176,7 +15847,7 @@ ${msg.content.text}`;
16176
15847
 
16177
15848
  // src/index.ts
16178
15849
  init_cli_utils();
16179
- var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["pull", "push", "list", "ls", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
15850
+ var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
16180
15851
  var CLI_INFO_ARGS = /* @__PURE__ */ new Set(["login", "help", "--help", "-h", "--version", "-v", "version"]);
16181
15852
  var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "") || CLI_INFO_ARGS.has(process.argv[2] ?? "");
16182
15853
  if (!IS_HUMAN_CLI) {
@@ -16196,7 +15867,7 @@ if (!IS_HUMAN_CLI) {
16196
15867
  var PKG_VERSION = (() => {
16197
15868
  try {
16198
15869
  const p = join16(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
16199
- return JSON.parse(readFileSync13(p, "utf-8")).version || "unknown";
15870
+ return JSON.parse(readFileSync12(p, "utf-8")).version || "unknown";
16200
15871
  } catch {
16201
15872
  return "unknown";
16202
15873
  }
@@ -16268,8 +15939,8 @@ function printHelp() {
16268
15939
  cmd("audit block <logId> [--scope exact|tool]", "turn a call into a DENY rule");
16269
15940
  cmd("stats [timeseries|drift]", "traffic & security statistics");
16270
15941
  cmd("watch [--filter DENY] [--tool <s>]", "live-tail tool calls (Ctrl+C to stop)");
16271
- cmd("agents [--all]", "live agent feed");
16272
- cmd("agent <agent_id>", "one-agent detail");
15942
+ cmd("sessions [--all]", "live agent-session feed (calls, denies, trust)");
15943
+ cmd("session <id>", "one session's detail");
16273
15944
  head("Alerts & webhooks");
16274
15945
  cmd("alerts list");
16275
15946
  cmd("alerts add --signal deny|dlp|ratelimit|any --threshold N --window S (--email <a> | --telegram <id> | --slack <url>)", "spike alert");
@@ -16277,16 +15948,12 @@ function printHelp() {
16277
15948
  cmd("webhooks list");
16278
15949
  cmd("webhooks add --url <https://\u2026> [--events denials|allowed|all]", "event webhook");
16279
15950
  cmd("webhooks remove <id>");
16280
- head("Policy sync");
16281
- cmd("list [--policy-id <ID>]", "list cloud policies (or show one)");
16282
- cmd("pull --policy-id <ID> [--file f]", "pull a cloud policy to a local file");
16283
- cmd("push --policy-id <ID> [--file f]", "push a local policy file to the cloud");
16284
15951
  console.log("");
16285
15952
  console.log(` ${c.dim}Add ${c.reset}${c.cyan}--json${c.reset}${c.dim} to most read commands for machine output.${c.reset}`);
16286
15953
  console.log(` ${c.dim}Details for a command: ${c.reset}${c.cyan}solongate <command> help${c.reset}${c.dim} \xB7 Dashboard: ${c.reset}${c.cyan}https://dashboard.solongate.com${c.reset}`);
16287
15954
  console.log("");
16288
15955
  }
16289
- async function main2() {
15956
+ async function main() {
16290
15957
  const subcommand = process.argv[2];
16291
15958
  if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
16292
15959
  printHelp();
@@ -16321,7 +15988,7 @@ async function main2() {
16321
15988
  await launchTui2();
16322
15989
  return;
16323
15990
  }
16324
- const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks"]);
15991
+ const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
16325
15992
  if (MGMT_COMMANDS.has(subcommand ?? "")) {
16326
15993
  const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
16327
15994
  const code = await runCommand2(subcommand, process.argv.slice(3));
@@ -16339,10 +16006,6 @@ async function main2() {
16339
16006
  await runLogsServer2();
16340
16007
  return;
16341
16008
  }
16342
- if (subcommand === "pull" || subcommand === "push" || subcommand === "list" || subcommand === "ls") {
16343
- await Promise.resolve().then(() => (init_pull_push(), pull_push_exports));
16344
- return;
16345
- }
16346
16009
  const hasProxySeparator = process.argv.includes("--");
16347
16010
  const looksLikeProxyFlag = (subcommand ?? "").startsWith("-");
16348
16011
  if (subcommand && !hasProxySeparator && !looksLikeProxyFlag) {
@@ -16365,4 +16028,4 @@ async function main2() {
16365
16028
  process.exit(1);
16366
16029
  }
16367
16030
  }
16368
- main2();
16031
+ main();