@solongate/proxy 0.81.36 → 0.81.38
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/api-client/client.d.ts +19 -0
- package/dist/api-client/device-login.d.ts +16 -0
- package/dist/api-client/index.d.ts +1 -0
- package/dist/commands/index.js +6 -1
- package/dist/index.js +515 -254
- package/dist/login.js +24 -0
- package/dist/tui/index.js +306 -62
- package/dist/tui/panels/Accounts.d.ts +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6554,179 +6554,31 @@ 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
|
-
const attempt = () => fetch(url, {
|
|
6637
|
-
method,
|
|
6638
|
-
headers: { ...headers, Connection: "close" },
|
|
6639
|
-
body: bodyInit,
|
|
6640
|
-
signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3)
|
|
6641
|
-
});
|
|
6642
|
-
const maxTries = method === "GET" ? 3 : 1;
|
|
6643
|
-
let res;
|
|
6644
|
-
let lastErr;
|
|
6645
|
-
for (let i = 0; i < maxTries; i++) {
|
|
6646
|
-
try {
|
|
6647
|
-
res = await attempt();
|
|
6648
|
-
break;
|
|
6649
|
-
} catch (err2) {
|
|
6650
|
-
lastErr = err2;
|
|
6651
|
-
if (i < maxTries - 1) await new Promise((r) => setTimeout(r, 600 * (i + 1)));
|
|
6652
|
-
}
|
|
6653
|
-
}
|
|
6654
|
-
if (!res) {
|
|
6655
|
-
const msg = lastErr instanceof Error ? lastErr.message : String(lastErr);
|
|
6656
|
-
throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
|
|
6657
|
-
}
|
|
6658
|
-
const text = await res.text().catch(() => "");
|
|
6659
|
-
let json = void 0;
|
|
6660
|
-
if (text) {
|
|
6661
|
-
try {
|
|
6662
|
-
json = JSON.parse(text);
|
|
6663
|
-
} catch {
|
|
6664
|
-
}
|
|
6665
|
-
}
|
|
6666
|
-
if (!res.ok) {
|
|
6667
|
-
const envelope = json?.error;
|
|
6668
|
-
if (envelope && typeof envelope === "object") {
|
|
6669
|
-
throw new ApiError(res.status, envelope.code || "ERROR", envelope.message || res.statusText);
|
|
6670
|
-
}
|
|
6671
|
-
if (typeof envelope === "string") {
|
|
6672
|
-
throw new ApiError(res.status, "ERROR", envelope);
|
|
6673
|
-
}
|
|
6674
|
-
if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate login`.");
|
|
6675
|
-
if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
|
|
6676
|
-
throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
|
|
6677
|
-
}
|
|
6678
|
-
return json;
|
|
6679
|
-
}
|
|
6680
|
-
var DEFAULT_API_URL2, ApiError, NotAuthenticatedError, cached;
|
|
6681
|
-
var init_client = __esm({
|
|
6682
|
-
"src/api-client/client.ts"() {
|
|
6683
|
-
"use strict";
|
|
6684
|
-
DEFAULT_API_URL2 = "https://api.solongate.com";
|
|
6685
|
-
ApiError = class extends Error {
|
|
6686
|
-
status;
|
|
6687
|
-
code;
|
|
6688
|
-
constructor(status, code, message) {
|
|
6689
|
-
super(message);
|
|
6690
|
-
this.name = "ApiError";
|
|
6691
|
-
this.status = status;
|
|
6692
|
-
this.code = code;
|
|
6693
|
-
}
|
|
6694
|
-
};
|
|
6695
|
-
NotAuthenticatedError = class extends Error {
|
|
6696
|
-
constructor() {
|
|
6697
|
-
super("Not logged in. Run `solongate login` first.");
|
|
6698
|
-
this.name = "NotAuthenticatedError";
|
|
6699
|
-
}
|
|
6700
|
-
};
|
|
6701
|
-
cached = null;
|
|
6702
|
-
}
|
|
6703
|
-
});
|
|
6704
|
-
|
|
6705
6557
|
// src/tui/config.ts
|
|
6706
|
-
import { readFileSync as
|
|
6707
|
-
import { homedir as
|
|
6708
|
-
import { join as
|
|
6558
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
6559
|
+
import { homedir as homedir2 } from "os";
|
|
6560
|
+
import { join as join4 } from "path";
|
|
6709
6561
|
function loadConfig() {
|
|
6710
|
-
if (
|
|
6562
|
+
if (cached) return cached;
|
|
6711
6563
|
const defaults = { notifications: true };
|
|
6712
6564
|
try {
|
|
6713
|
-
const raw =
|
|
6565
|
+
const raw = readFileSync4(join4(homedir2(), ".solongate", "tui-config.json"), "utf-8");
|
|
6714
6566
|
const j = JSON.parse(raw);
|
|
6715
|
-
|
|
6567
|
+
cached = {
|
|
6716
6568
|
notifications: j.notifications !== false,
|
|
6717
6569
|
accent: typeof j.accent === "string" ? j.accent : void 0,
|
|
6718
6570
|
pollMs: typeof j.pollMs === "number" ? j.pollMs : void 0
|
|
6719
6571
|
};
|
|
6720
6572
|
} catch {
|
|
6721
|
-
|
|
6573
|
+
cached = defaults;
|
|
6722
6574
|
}
|
|
6723
|
-
return
|
|
6575
|
+
return cached;
|
|
6724
6576
|
}
|
|
6725
|
-
var
|
|
6577
|
+
var cached;
|
|
6726
6578
|
var init_config2 = __esm({
|
|
6727
6579
|
"src/tui/config.ts"() {
|
|
6728
6580
|
"use strict";
|
|
6729
|
-
|
|
6581
|
+
cached = null;
|
|
6730
6582
|
}
|
|
6731
6583
|
});
|
|
6732
6584
|
|
|
@@ -6836,9 +6688,9 @@ var init_components = __esm({
|
|
|
6836
6688
|
});
|
|
6837
6689
|
|
|
6838
6690
|
// src/tui/local-log.ts
|
|
6839
|
-
import { closeSync, openSync, readFileSync as
|
|
6840
|
-
import { homedir as
|
|
6841
|
-
import { join as
|
|
6691
|
+
import { closeSync, openSync, readFileSync as readFileSync5, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
6692
|
+
import { homedir as homedir3 } from "os";
|
|
6693
|
+
import { join as join5 } from "path";
|
|
6842
6694
|
function tailLines(file, maxBytes = 131072) {
|
|
6843
6695
|
try {
|
|
6844
6696
|
const size = statSync(file).size;
|
|
@@ -6856,7 +6708,7 @@ function tailLines(file, maxBytes = 131072) {
|
|
|
6856
6708
|
}
|
|
6857
6709
|
function deleteLocalEntry(at, tool, session) {
|
|
6858
6710
|
try {
|
|
6859
|
-
const lines =
|
|
6711
|
+
const lines = readFileSync5(LOCAL_LOG, "utf-8").split("\n");
|
|
6860
6712
|
let removed = 0;
|
|
6861
6713
|
const kept = lines.filter((line) => {
|
|
6862
6714
|
if (!line.trim()) return false;
|
|
@@ -6880,7 +6732,7 @@ function deleteLocalEntry(at, tool, session) {
|
|
|
6880
6732
|
}
|
|
6881
6733
|
function clearLocalLog() {
|
|
6882
6734
|
try {
|
|
6883
|
-
const n =
|
|
6735
|
+
const n = readFileSync5(LOCAL_LOG, "utf-8").split("\n").filter(Boolean).length;
|
|
6884
6736
|
writeFileSync3(LOCAL_LOG, "");
|
|
6885
6737
|
return n;
|
|
6886
6738
|
} catch {
|
|
@@ -6912,12 +6764,208 @@ var LOCAL_LOG, DLP_REASON, RL_REASON;
|
|
|
6912
6764
|
var init_local_log = __esm({
|
|
6913
6765
|
"src/tui/local-log.ts"() {
|
|
6914
6766
|
"use strict";
|
|
6915
|
-
LOCAL_LOG =
|
|
6767
|
+
LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
6916
6768
|
DLP_REASON = /security layer \(dlp\)/i;
|
|
6917
6769
|
RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
|
|
6918
6770
|
}
|
|
6919
6771
|
});
|
|
6920
6772
|
|
|
6773
|
+
// src/api-client/client.ts
|
|
6774
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync3 } from "fs";
|
|
6775
|
+
import { resolve as resolve3, join as join6 } from "path";
|
|
6776
|
+
import { homedir as homedir4 } from "os";
|
|
6777
|
+
function listAccounts() {
|
|
6778
|
+
let list6 = [];
|
|
6779
|
+
try {
|
|
6780
|
+
const raw = JSON.parse(readFileSync6(accountsFile(), "utf-8"));
|
|
6781
|
+
if (Array.isArray(raw)) list6 = raw.filter((a) => a && typeof a.apiKey === "string");
|
|
6782
|
+
} catch {
|
|
6783
|
+
}
|
|
6784
|
+
const active2 = loginCredentialFile();
|
|
6785
|
+
if (active2.apiKey && !list6.some((a) => a.apiKey === active2.apiKey)) {
|
|
6786
|
+
list6.unshift({ apiKey: active2.apiKey, apiUrl: active2.apiUrl || DEFAULT_API_URL2 });
|
|
6787
|
+
}
|
|
6788
|
+
return list6;
|
|
6789
|
+
}
|
|
6790
|
+
function saveAccount(acc) {
|
|
6791
|
+
try {
|
|
6792
|
+
const list6 = (() => {
|
|
6793
|
+
try {
|
|
6794
|
+
const raw = JSON.parse(readFileSync6(accountsFile(), "utf-8"));
|
|
6795
|
+
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
6796
|
+
} catch {
|
|
6797
|
+
return [];
|
|
6798
|
+
}
|
|
6799
|
+
})();
|
|
6800
|
+
const next = list6.filter((a) => a.apiKey !== acc.apiKey);
|
|
6801
|
+
next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
|
|
6802
|
+
mkdirSync3(join6(homedir4(), ".solongate"), { recursive: true });
|
|
6803
|
+
writeFileSync4(accountsFile(), JSON.stringify(next, null, 2));
|
|
6804
|
+
} catch {
|
|
6805
|
+
}
|
|
6806
|
+
}
|
|
6807
|
+
function setViewCredentials(creds) {
|
|
6808
|
+
viewOverride = creds;
|
|
6809
|
+
cached2 = null;
|
|
6810
|
+
}
|
|
6811
|
+
function isActiveAccount(apiKey) {
|
|
6812
|
+
return loginCredentialFile().apiKey === apiKey;
|
|
6813
|
+
}
|
|
6814
|
+
function setActiveAccount(creds) {
|
|
6815
|
+
try {
|
|
6816
|
+
const dir = join6(homedir4(), ".solongate");
|
|
6817
|
+
mkdirSync3(dir, { recursive: true });
|
|
6818
|
+
const p = join6(dir, ["cloud", "guard.json"].join("-"));
|
|
6819
|
+
let existing = {};
|
|
6820
|
+
try {
|
|
6821
|
+
existing = JSON.parse(readFileSync6(p, "utf-8"));
|
|
6822
|
+
} catch {
|
|
6823
|
+
}
|
|
6824
|
+
writeFileSync4(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2));
|
|
6825
|
+
cached2 = null;
|
|
6826
|
+
return true;
|
|
6827
|
+
} catch {
|
|
6828
|
+
return false;
|
|
6829
|
+
}
|
|
6830
|
+
}
|
|
6831
|
+
function loginCredentialFile() {
|
|
6832
|
+
try {
|
|
6833
|
+
const p = join6(homedir4(), ".solongate", "cloud-guard.json");
|
|
6834
|
+
if (!existsSync3(p)) return {};
|
|
6835
|
+
const c2 = JSON.parse(readFileSync6(p, "utf-8"));
|
|
6836
|
+
return c2 && typeof c2 === "object" ? c2 : {};
|
|
6837
|
+
} catch {
|
|
6838
|
+
return {};
|
|
6839
|
+
}
|
|
6840
|
+
}
|
|
6841
|
+
function dotenvApiKey() {
|
|
6842
|
+
try {
|
|
6843
|
+
const envPath = resolve3(".env");
|
|
6844
|
+
if (!existsSync3(envPath)) return void 0;
|
|
6845
|
+
for (const line of readFileSync6(envPath, "utf-8").split("\n")) {
|
|
6846
|
+
const trimmed = line.trim();
|
|
6847
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
6848
|
+
const eq = trimmed.indexOf("=");
|
|
6849
|
+
if (eq === -1) continue;
|
|
6850
|
+
const key = trimmed.slice(0, eq).trim();
|
|
6851
|
+
if (key !== "SOLONGATE_API_KEY") continue;
|
|
6852
|
+
return trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
6853
|
+
}
|
|
6854
|
+
} catch {
|
|
6855
|
+
}
|
|
6856
|
+
return void 0;
|
|
6857
|
+
}
|
|
6858
|
+
function isAuthenticated() {
|
|
6859
|
+
try {
|
|
6860
|
+
resolveCredentials();
|
|
6861
|
+
return true;
|
|
6862
|
+
} catch {
|
|
6863
|
+
return false;
|
|
6864
|
+
}
|
|
6865
|
+
}
|
|
6866
|
+
function resolveCredentials(apiUrlOverride) {
|
|
6867
|
+
if (viewOverride && !apiUrlOverride) return viewOverride;
|
|
6868
|
+
if (cached2 && !apiUrlOverride) return cached2;
|
|
6869
|
+
const file = loginCredentialFile();
|
|
6870
|
+
const apiKey = process.env["SOLONGATE_API_KEY"] || file.apiKey || dotenvApiKey();
|
|
6871
|
+
if (!apiKey) throw new NotAuthenticatedError();
|
|
6872
|
+
const apiUrl = apiUrlOverride || process.env["SOLONGATE_API_URL"] || file.apiUrl || DEFAULT_API_URL2;
|
|
6873
|
+
const creds = { apiKey, apiUrl: apiUrl.replace(/\/$/, "") };
|
|
6874
|
+
if (!apiUrlOverride) cached2 = creds;
|
|
6875
|
+
return creds;
|
|
6876
|
+
}
|
|
6877
|
+
function buildUrl(base, path, query) {
|
|
6878
|
+
const url = new URL(`${base}/api/v1${path}`);
|
|
6879
|
+
if (query) {
|
|
6880
|
+
for (const [k, v] of Object.entries(query)) {
|
|
6881
|
+
if (v === void 0) continue;
|
|
6882
|
+
url.searchParams.set(k, String(v));
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6885
|
+
return url.toString();
|
|
6886
|
+
}
|
|
6887
|
+
async function request(method, path, opts = {}) {
|
|
6888
|
+
const creds = resolveCredentials(opts.apiUrl);
|
|
6889
|
+
const url = buildUrl(creds.apiUrl, path, opts.query);
|
|
6890
|
+
const headers = {
|
|
6891
|
+
Authorization: `Bearer ${creds.apiKey}`
|
|
6892
|
+
};
|
|
6893
|
+
let bodyInit;
|
|
6894
|
+
if (opts.body !== void 0) {
|
|
6895
|
+
headers["Content-Type"] = "application/json";
|
|
6896
|
+
bodyInit = JSON.stringify(opts.body);
|
|
6897
|
+
}
|
|
6898
|
+
const attempt = () => fetch(url, {
|
|
6899
|
+
method,
|
|
6900
|
+
headers: { ...headers, Connection: "close" },
|
|
6901
|
+
body: bodyInit,
|
|
6902
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3)
|
|
6903
|
+
});
|
|
6904
|
+
const maxTries = method === "GET" ? 3 : 1;
|
|
6905
|
+
let res;
|
|
6906
|
+
let lastErr;
|
|
6907
|
+
for (let i = 0; i < maxTries; i++) {
|
|
6908
|
+
try {
|
|
6909
|
+
res = await attempt();
|
|
6910
|
+
break;
|
|
6911
|
+
} catch (err2) {
|
|
6912
|
+
lastErr = err2;
|
|
6913
|
+
if (i < maxTries - 1) await new Promise((r) => setTimeout(r, 600 * (i + 1)));
|
|
6914
|
+
}
|
|
6915
|
+
}
|
|
6916
|
+
if (!res) {
|
|
6917
|
+
const msg = lastErr instanceof Error ? lastErr.message : String(lastErr);
|
|
6918
|
+
throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
|
|
6919
|
+
}
|
|
6920
|
+
const text = await res.text().catch(() => "");
|
|
6921
|
+
let json = void 0;
|
|
6922
|
+
if (text) {
|
|
6923
|
+
try {
|
|
6924
|
+
json = JSON.parse(text);
|
|
6925
|
+
} catch {
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6928
|
+
if (!res.ok) {
|
|
6929
|
+
const envelope = json?.error;
|
|
6930
|
+
if (envelope && typeof envelope === "object") {
|
|
6931
|
+
throw new ApiError(res.status, envelope.code || "ERROR", envelope.message || res.statusText);
|
|
6932
|
+
}
|
|
6933
|
+
if (typeof envelope === "string") {
|
|
6934
|
+
throw new ApiError(res.status, "ERROR", envelope);
|
|
6935
|
+
}
|
|
6936
|
+
if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate login`.");
|
|
6937
|
+
if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
|
|
6938
|
+
throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
|
|
6939
|
+
}
|
|
6940
|
+
return json;
|
|
6941
|
+
}
|
|
6942
|
+
var DEFAULT_API_URL2, accountsFile, viewOverride, ApiError, NotAuthenticatedError, cached2;
|
|
6943
|
+
var init_client = __esm({
|
|
6944
|
+
"src/api-client/client.ts"() {
|
|
6945
|
+
"use strict";
|
|
6946
|
+
DEFAULT_API_URL2 = "https://api.solongate.com";
|
|
6947
|
+
accountsFile = () => join6(homedir4(), ".solongate", "accounts.json");
|
|
6948
|
+
viewOverride = null;
|
|
6949
|
+
ApiError = class extends Error {
|
|
6950
|
+
status;
|
|
6951
|
+
code;
|
|
6952
|
+
constructor(status, code, message) {
|
|
6953
|
+
super(message);
|
|
6954
|
+
this.name = "ApiError";
|
|
6955
|
+
this.status = status;
|
|
6956
|
+
this.code = code;
|
|
6957
|
+
}
|
|
6958
|
+
};
|
|
6959
|
+
NotAuthenticatedError = class extends Error {
|
|
6960
|
+
constructor() {
|
|
6961
|
+
super("Not logged in. Run `solongate login` first.");
|
|
6962
|
+
this.name = "NotAuthenticatedError";
|
|
6963
|
+
}
|
|
6964
|
+
};
|
|
6965
|
+
cached2 = null;
|
|
6966
|
+
}
|
|
6967
|
+
});
|
|
6968
|
+
|
|
6921
6969
|
// src/api-client/types.ts
|
|
6922
6970
|
var init_types = __esm({
|
|
6923
6971
|
"src/api-client/types.ts"() {
|
|
@@ -6925,6 +6973,54 @@ var init_types = __esm({
|
|
|
6925
6973
|
}
|
|
6926
6974
|
});
|
|
6927
6975
|
|
|
6976
|
+
// src/api-client/device-login.ts
|
|
6977
|
+
import { spawn } from "child_process";
|
|
6978
|
+
function openBrowser(url) {
|
|
6979
|
+
try {
|
|
6980
|
+
const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
6981
|
+
const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
|
|
6982
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
6983
|
+
child.on("error", () => {
|
|
6984
|
+
});
|
|
6985
|
+
child.unref();
|
|
6986
|
+
} catch {
|
|
6987
|
+
}
|
|
6988
|
+
}
|
|
6989
|
+
async function startDeviceLogin(apiUrl = DEFAULT_API_URL2) {
|
|
6990
|
+
const res = await fetch(`${apiUrl}/api/v1/auth/device/start`, { method: "POST" });
|
|
6991
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
6992
|
+
const j = await res.json();
|
|
6993
|
+
return {
|
|
6994
|
+
deviceCode: j.device_code,
|
|
6995
|
+
verifyUrl: j.verification_uri_complete || j.verification_uri || "",
|
|
6996
|
+
intervalMs: Math.max(2, Number(j.interval) || 3) * 1e3,
|
|
6997
|
+
expiresAt: Date.now() + (Number(j.expires_in) || 600) * 1e3
|
|
6998
|
+
};
|
|
6999
|
+
}
|
|
7000
|
+
async function pollDeviceLogin(apiUrl, deviceCode) {
|
|
7001
|
+
try {
|
|
7002
|
+
const res = await fetch(`${apiUrl}/api/v1/auth/device/poll`, {
|
|
7003
|
+
method: "POST",
|
|
7004
|
+
headers: { "Content-Type": "application/json" },
|
|
7005
|
+
body: JSON.stringify({ device_code: deviceCode })
|
|
7006
|
+
});
|
|
7007
|
+
const j = await res.json().catch(() => ({}));
|
|
7008
|
+
if (j.status === "approved" && j.api_key) {
|
|
7009
|
+
return { status: "approved", apiKey: j.api_key, project: j.project?.name, user: j.user?.name || j.user?.email };
|
|
7010
|
+
}
|
|
7011
|
+
if (j.status === "expired" || j.status === "not_found") return { status: j.status };
|
|
7012
|
+
return { status: "pending" };
|
|
7013
|
+
} catch {
|
|
7014
|
+
return { status: "pending" };
|
|
7015
|
+
}
|
|
7016
|
+
}
|
|
7017
|
+
var init_device_login = __esm({
|
|
7018
|
+
"src/api-client/device-login.ts"() {
|
|
7019
|
+
"use strict";
|
|
7020
|
+
init_client();
|
|
7021
|
+
}
|
|
7022
|
+
});
|
|
7023
|
+
|
|
6928
7024
|
// src/api-client/policies.ts
|
|
6929
7025
|
var policies_exports = {};
|
|
6930
7026
|
__export(policies_exports, {
|
|
@@ -7195,6 +7291,7 @@ var init_api_client = __esm({
|
|
|
7195
7291
|
"use strict";
|
|
7196
7292
|
init_client();
|
|
7197
7293
|
init_types();
|
|
7294
|
+
init_device_login();
|
|
7198
7295
|
init_policies();
|
|
7199
7296
|
init_settings();
|
|
7200
7297
|
init_stats();
|
|
@@ -7207,24 +7304,24 @@ var init_api_client = __esm({
|
|
|
7207
7304
|
});
|
|
7208
7305
|
|
|
7209
7306
|
// src/tui/notify.ts
|
|
7210
|
-
import { spawn } from "child_process";
|
|
7307
|
+
import { spawn as spawn2 } from "child_process";
|
|
7211
7308
|
function desktopNotify(title, msg) {
|
|
7212
7309
|
try {
|
|
7213
7310
|
if (process.platform === "linux") {
|
|
7214
|
-
const p =
|
|
7311
|
+
const p = spawn2("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
|
|
7215
7312
|
p.on("error", () => {
|
|
7216
7313
|
});
|
|
7217
7314
|
p.unref();
|
|
7218
7315
|
} else if (process.platform === "win32") {
|
|
7219
7316
|
const q = (s) => s.replace(/'/g, "''");
|
|
7220
7317
|
const ps = `Add-Type -AssemblyName System.Windows.Forms;Add-Type -AssemblyName System.Drawing;$n=New-Object System.Windows.Forms.NotifyIcon;$n.Icon=[System.Drawing.SystemIcons]::Information;$n.Visible=$true;$n.ShowBalloonTip(6000,'${q(title)}','${q(msg)}',[System.Windows.Forms.ToolTipIcon]::Warning);Start-Sleep -Milliseconds 6500;$n.Dispose()`;
|
|
7221
|
-
const p =
|
|
7318
|
+
const p = spawn2("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "ignore", detached: true, windowsHide: true });
|
|
7222
7319
|
p.on("error", () => {
|
|
7223
7320
|
});
|
|
7224
7321
|
p.unref();
|
|
7225
7322
|
} else if (process.platform === "darwin") {
|
|
7226
7323
|
const esc = (s) => s.replace(/"/g, '\\"');
|
|
7227
|
-
const p =
|
|
7324
|
+
const p = spawn2("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
|
|
7228
7325
|
p.on("error", () => {
|
|
7229
7326
|
});
|
|
7230
7327
|
p.unref();
|
|
@@ -7310,7 +7407,7 @@ var init_hooks = __esm({
|
|
|
7310
7407
|
// src/tui/panels/Live.tsx
|
|
7311
7408
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7312
7409
|
import TextInput from "ink-text-input";
|
|
7313
|
-
import { mkdirSync as
|
|
7410
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
7314
7411
|
import { homedir as homedir5 } from "os";
|
|
7315
7412
|
import { join as join7 } from "path";
|
|
7316
7413
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
@@ -7861,8 +7958,8 @@ function LivePanel({ active: active2 }) {
|
|
|
7861
7958
|
else if (input === "e") {
|
|
7862
7959
|
const file = join7(homedir5(), ".solongate", "live-export.jsonl");
|
|
7863
7960
|
try {
|
|
7864
|
-
|
|
7865
|
-
|
|
7961
|
+
mkdirSync4(join7(homedir5(), ".solongate"), { recursive: true });
|
|
7962
|
+
writeFileSync5(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
7866
7963
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
7867
7964
|
} catch (err2) {
|
|
7868
7965
|
setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
|
|
@@ -8880,7 +8977,7 @@ var init_Dlp = __esm({
|
|
|
8880
8977
|
// src/tui/panels/Audit.tsx
|
|
8881
8978
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
8882
8979
|
import TextInput4 from "ink-text-input";
|
|
8883
|
-
import { mkdirSync as
|
|
8980
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
8884
8981
|
import { homedir as homedir6 } from "os";
|
|
8885
8982
|
import { join as join8 } from "path";
|
|
8886
8983
|
import { useState as useState6 } from "react";
|
|
@@ -9044,8 +9141,8 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9044
9141
|
const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
|
|
9045
9142
|
rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
|
|
9046
9143
|
} else rows2 = localFiltered;
|
|
9047
|
-
|
|
9048
|
-
|
|
9144
|
+
mkdirSync5(dir, { recursive: true });
|
|
9145
|
+
writeFileSync6(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
|
|
9049
9146
|
return { n: rows2.length, file };
|
|
9050
9147
|
};
|
|
9051
9148
|
run12().then(({ n, file }) => setMsg({ text: `\u2713 exported ${n} rows \u2192 ${file}`, level: "ok" })).catch((e) => setMsg({ text: "\u2717 export failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
@@ -9747,18 +9844,158 @@ var init_Settings = __esm({
|
|
|
9747
9844
|
}
|
|
9748
9845
|
});
|
|
9749
9846
|
|
|
9750
|
-
// src/tui/
|
|
9751
|
-
import { Box as Box8, Text as Text8,
|
|
9752
|
-
import { useState as useState8 } from "react";
|
|
9847
|
+
// src/tui/panels/Accounts.tsx
|
|
9848
|
+
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
9849
|
+
import { useEffect as useEffect6, useRef as useRef3, useState as useState8 } from "react";
|
|
9753
9850
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
9754
|
-
function
|
|
9851
|
+
function AccountsPanel({
|
|
9852
|
+
focused,
|
|
9853
|
+
viewApiKey,
|
|
9854
|
+
onView
|
|
9855
|
+
}) {
|
|
9856
|
+
const [accounts, setAccounts] = useState8(() => listAccounts());
|
|
9857
|
+
const [sel, setSel] = useState8(0);
|
|
9858
|
+
const [msg, setMsg] = useState8(null);
|
|
9859
|
+
const [login, setLogin] = useState8(null);
|
|
9860
|
+
const [tick, setTick] = useState8(0);
|
|
9861
|
+
const abort = useRef3(false);
|
|
9862
|
+
const refresh = () => setAccounts(listAccounts());
|
|
9863
|
+
useEffect6(() => {
|
|
9864
|
+
if (!login || login.phase === "done" || login.phase === "error") return;
|
|
9865
|
+
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
9866
|
+
return () => clearInterval(t);
|
|
9867
|
+
}, [login]);
|
|
9868
|
+
const beginLogin = () => {
|
|
9869
|
+
if (login && (login.phase === "starting" || login.phase === "waiting")) return;
|
|
9870
|
+
abort.current = false;
|
|
9871
|
+
setLogin({ phase: "starting" });
|
|
9872
|
+
void (async () => {
|
|
9873
|
+
let start;
|
|
9874
|
+
try {
|
|
9875
|
+
start = await startDeviceLogin(DEFAULT_API_URL2);
|
|
9876
|
+
} catch (e) {
|
|
9877
|
+
setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
|
|
9878
|
+
return;
|
|
9879
|
+
}
|
|
9880
|
+
setLogin({ phase: "waiting", url: start.verifyUrl });
|
|
9881
|
+
openBrowser(start.verifyUrl);
|
|
9882
|
+
while (Date.now() < start.expiresAt && !abort.current) {
|
|
9883
|
+
await new Promise((r) => setTimeout(r, start.intervalMs));
|
|
9884
|
+
if (abort.current) return;
|
|
9885
|
+
const res = await pollDeviceLogin(DEFAULT_API_URL2, start.deviceCode);
|
|
9886
|
+
if (res.status === "approved" && res.apiKey) {
|
|
9887
|
+
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user });
|
|
9888
|
+
setLogin({ phase: "done", msg: `\u2713 added ${res.project || res.user || "account"}` });
|
|
9889
|
+
refresh();
|
|
9890
|
+
setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2 });
|
|
9891
|
+
onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user });
|
|
9892
|
+
return;
|
|
9893
|
+
}
|
|
9894
|
+
if (res.status === "expired" || res.status === "not_found") {
|
|
9895
|
+
setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
|
|
9896
|
+
return;
|
|
9897
|
+
}
|
|
9898
|
+
}
|
|
9899
|
+
if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
|
|
9900
|
+
})();
|
|
9901
|
+
};
|
|
9902
|
+
useInput7(
|
|
9903
|
+
(input, key) => {
|
|
9904
|
+
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
9905
|
+
if (key.escape) {
|
|
9906
|
+
abort.current = true;
|
|
9907
|
+
setLogin(null);
|
|
9908
|
+
}
|
|
9909
|
+
return;
|
|
9910
|
+
}
|
|
9911
|
+
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
9912
|
+
else if (key.downArrow) setSel((n) => Math.min(accounts.length - 1, n + 1));
|
|
9913
|
+
else if (key.return) {
|
|
9914
|
+
const a = accounts[sel];
|
|
9915
|
+
if (a) {
|
|
9916
|
+
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
9917
|
+
onView?.(a);
|
|
9918
|
+
setMsg({ text: `viewing ${a.project || a.user || a.apiKey.slice(0, 8)}`, level: "ok" });
|
|
9919
|
+
}
|
|
9920
|
+
} else if (input === "m") {
|
|
9921
|
+
const a = accounts[sel];
|
|
9922
|
+
if (a) {
|
|
9923
|
+
const ok = setActiveAccount({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
9924
|
+
setMsg(ok ? { text: `\u2713 ${a.project || a.user || "account"} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
9925
|
+
refresh();
|
|
9926
|
+
}
|
|
9927
|
+
} else if (input === "n") beginLogin();
|
|
9928
|
+
else if (input === "r") refresh();
|
|
9929
|
+
},
|
|
9930
|
+
{ isActive: focused }
|
|
9931
|
+
);
|
|
9932
|
+
const spin = SPIN2[tick % SPIN2.length];
|
|
9933
|
+
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
9934
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
9935
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "Add an account" }),
|
|
9936
|
+
login.phase === "starting" ? /* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
|
|
9937
|
+
spin,
|
|
9938
|
+
" starting device pairing\u2026"
|
|
9939
|
+
] }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
9940
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
|
|
9941
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
|
|
9942
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
9943
|
+
/* @__PURE__ */ jsxs8(Text8, { color: theme.warn, children: [
|
|
9944
|
+
spin,
|
|
9945
|
+
" waiting for authorization\u2026 "
|
|
9946
|
+
] }),
|
|
9947
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "esc to cancel" })
|
|
9948
|
+
] })
|
|
9949
|
+
] })
|
|
9950
|
+
] });
|
|
9951
|
+
}
|
|
9755
9952
|
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
9756
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.
|
|
9757
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.
|
|
9758
|
-
/* @__PURE__ */ jsx8(
|
|
9759
|
-
|
|
9953
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter view \xB7 m make active \xB7 n add account \xB7 r refresh" : "press \u2192 to manage accounts" }),
|
|
9954
|
+
msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, 70) }) : login?.msg ? /* @__PURE__ */ jsx8(Text8, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
9955
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: accounts.length === 0 ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
9956
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "No accounts on this device yet." }),
|
|
9957
|
+
/* @__PURE__ */ jsxs8(Text8, { children: [
|
|
9958
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "n" }),
|
|
9959
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " to log in \u2014 pairs this device and starts protecting your Claude Code sessions." })
|
|
9960
|
+
] })
|
|
9961
|
+
] }) : accounts.map((a, i) => {
|
|
9962
|
+
const isSel = i === sel && focused;
|
|
9963
|
+
const isView = viewApiKey ? a.apiKey === viewApiKey : i === 0;
|
|
9964
|
+
const isActive = isActiveAccount(a.apiKey);
|
|
9965
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
|
|
9966
|
+
/* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
|
|
9967
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.project || a.user || a.apiKey.slice(0, 12), 30).padEnd(31) }),
|
|
9968
|
+
isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
9969
|
+
isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
9970
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.user && a.project ? truncate2(a.user, 24) : "" })
|
|
9971
|
+
] }, a.apiKey);
|
|
9972
|
+
}) }),
|
|
9973
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u25CF viewing = the account the dataroom is showing \xB7 ACTIVE = the key the guard hooks + logging use" }) })
|
|
9974
|
+
] });
|
|
9975
|
+
}
|
|
9976
|
+
var SPIN2;
|
|
9977
|
+
var init_Accounts = __esm({
|
|
9978
|
+
"src/tui/panels/Accounts.tsx"() {
|
|
9979
|
+
"use strict";
|
|
9980
|
+
init_client();
|
|
9981
|
+
init_device_login();
|
|
9982
|
+
init_theme();
|
|
9983
|
+
SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
9984
|
+
}
|
|
9985
|
+
});
|
|
9986
|
+
|
|
9987
|
+
// src/tui/App.tsx
|
|
9988
|
+
import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
|
|
9989
|
+
import { useState as useState9 } from "react";
|
|
9990
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
9991
|
+
function LiveHint() {
|
|
9992
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
9993
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
|
|
9994
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
|
|
9995
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
|
|
9996
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
9760
9997
|
"press ",
|
|
9761
|
-
/* @__PURE__ */
|
|
9998
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: "enter" }),
|
|
9762
9999
|
" to go live"
|
|
9763
10000
|
] }) })
|
|
9764
10001
|
] });
|
|
@@ -9766,22 +10003,38 @@ function LiveHint() {
|
|
|
9766
10003
|
function Banner({ cols }) {
|
|
9767
10004
|
const wide = cols >= 82;
|
|
9768
10005
|
if (!wide) {
|
|
9769
|
-
return /* @__PURE__ */
|
|
9770
|
-
/* @__PURE__ */
|
|
9771
|
-
/* @__PURE__ */
|
|
10006
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
10007
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate" }),
|
|
10008
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \u2014 security control center" })
|
|
9772
10009
|
] });
|
|
9773
10010
|
}
|
|
9774
|
-
return /* @__PURE__ */
|
|
9775
|
-
BANNER_FULL.map((line, i) => /* @__PURE__ */
|
|
9776
|
-
/* @__PURE__ */
|
|
10011
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
10012
|
+
BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx9(Text9, { bold: true, color: BANNER_HEX[i], children: line }, i)),
|
|
10013
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
|
|
9777
10014
|
] });
|
|
9778
10015
|
}
|
|
9779
10016
|
function App() {
|
|
9780
10017
|
const { exit } = useApp();
|
|
9781
|
-
const [
|
|
9782
|
-
const [
|
|
9783
|
-
const [
|
|
9784
|
-
|
|
10018
|
+
const [accounts, setAccounts] = useState9(() => listAccounts());
|
|
10019
|
+
const [viewKey, setViewKey] = useState9(() => accounts[0]?.apiKey);
|
|
10020
|
+
const [viewNonce, setViewNonce] = useState9(0);
|
|
10021
|
+
const [section, setSection] = useState9(accounts.length === 0 ? ACCOUNTS_SECTION : 0);
|
|
10022
|
+
const [focus, setFocus] = useState9("nav");
|
|
10023
|
+
const [help, setHelp] = useState9(false);
|
|
10024
|
+
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
10025
|
+
const cur = accounts[acctIdx];
|
|
10026
|
+
const acctLabel = cur ? cur.project || cur.user || cur.apiKey.slice(0, 8) : "not logged in";
|
|
10027
|
+
const viewAccount = (a) => {
|
|
10028
|
+
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
10029
|
+
setAccounts(listAccounts());
|
|
10030
|
+
setViewKey(a.apiKey);
|
|
10031
|
+
setViewNonce((n) => n + 1);
|
|
10032
|
+
};
|
|
10033
|
+
const switchAccount = () => {
|
|
10034
|
+
if (accounts.length < 2) return;
|
|
10035
|
+
viewAccount(accounts[(acctIdx + 1) % accounts.length]);
|
|
10036
|
+
};
|
|
10037
|
+
useInput8((input, key) => {
|
|
9785
10038
|
if (help) {
|
|
9786
10039
|
setHelp(false);
|
|
9787
10040
|
return;
|
|
@@ -9794,6 +10047,7 @@ function App() {
|
|
|
9794
10047
|
if (key.upArrow) setSection((n) => (n - 1 + SECTIONS.length) % SECTIONS.length);
|
|
9795
10048
|
else if (key.downArrow) setSection((n) => (n + 1) % SECTIONS.length);
|
|
9796
10049
|
else if (key.rightArrow || key.return || key.tab) setFocus("panel");
|
|
10050
|
+
else if (input === "a") switchAccount();
|
|
9797
10051
|
else if (input === "q") exit();
|
|
9798
10052
|
} else {
|
|
9799
10053
|
if (key.escape || key.tab) setFocus("nav");
|
|
@@ -9802,34 +10056,40 @@ function App() {
|
|
|
9802
10056
|
});
|
|
9803
10057
|
const { cols, rows } = useTermSize();
|
|
9804
10058
|
const current = SECTIONS[section];
|
|
9805
|
-
if (help) return /* @__PURE__ */
|
|
10059
|
+
if (help) return /* @__PURE__ */ jsx9(HelpOverlay, { cols, rows });
|
|
9806
10060
|
if (current.label === "Live" && focus === "panel") {
|
|
9807
|
-
return /* @__PURE__ */
|
|
10061
|
+
return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: cols, height: rows, children: /* @__PURE__ */ jsx9(LivePanel, { active: true, focused: true }, viewNonce) });
|
|
9808
10062
|
}
|
|
9809
10063
|
const Panel = current.Panel;
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
/* @__PURE__ */
|
|
9813
|
-
|
|
9814
|
-
/* @__PURE__ */
|
|
10064
|
+
const panelBody = current.label === "Accounts" ? /* @__PURE__ */ jsx9(AccountsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount }) : /* @__PURE__ */ jsx9(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
|
|
10065
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
|
|
10066
|
+
/* @__PURE__ */ jsx9(Banner, { cols }),
|
|
10067
|
+
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
10068
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
|
|
10069
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, bold: true, children: acctLabel }),
|
|
10070
|
+
accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : accounts.length === 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" }) : null
|
|
9815
10071
|
] }),
|
|
9816
|
-
/* @__PURE__ */
|
|
10072
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
10073
|
+
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => /* @__PURE__ */ jsx9(Text9, { color: i === section ? theme.accentBright : void 0, bold: i === section, children: (i === section ? "\u25B8 " : " ") + s.label }, s.label)) }),
|
|
10074
|
+
/* @__PURE__ */ jsx9(Box9, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: panelBody })
|
|
10075
|
+
] }, viewNonce),
|
|
10076
|
+
/* @__PURE__ */ jsx9(Box9, { children: focus === "nav" ? /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ...accounts.length > 1 ? [["a", "account"]] : [], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
|
|
9817
10077
|
] });
|
|
9818
10078
|
}
|
|
9819
10079
|
function HelpOverlay({ cols, rows }) {
|
|
9820
|
-
return /* @__PURE__ */
|
|
9821
|
-
/* @__PURE__ */
|
|
9822
|
-
/* @__PURE__ */
|
|
9823
|
-
/* @__PURE__ */
|
|
9824
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
9825
|
-
/* @__PURE__ */
|
|
9826
|
-
/* @__PURE__ */
|
|
10080
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
|
|
10081
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
|
|
10082
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
|
|
10083
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accent, children: group }),
|
|
10084
|
+
keys.map(([k, desc]) => /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
10085
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
|
|
10086
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: desc })
|
|
9827
10087
|
] }, k))
|
|
9828
10088
|
] }, group)) }),
|
|
9829
|
-
/* @__PURE__ */
|
|
10089
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "press any key to close" })
|
|
9830
10090
|
] });
|
|
9831
10091
|
}
|
|
9832
|
-
var SECTIONS, BANNER_HEX, HELP;
|
|
10092
|
+
var SECTIONS, BANNER_HEX, ACCOUNTS_SECTION, HELP;
|
|
9833
10093
|
var init_App = __esm({
|
|
9834
10094
|
"src/tui/App.tsx"() {
|
|
9835
10095
|
"use strict";
|
|
@@ -9842,23 +10102,28 @@ var init_App = __esm({
|
|
|
9842
10102
|
init_Dlp();
|
|
9843
10103
|
init_Audit();
|
|
9844
10104
|
init_Settings();
|
|
10105
|
+
init_Accounts();
|
|
9845
10106
|
init_hooks();
|
|
10107
|
+
init_client();
|
|
9846
10108
|
SECTIONS = [
|
|
9847
10109
|
{ label: "Live", Panel: LiveHint },
|
|
9848
10110
|
{ label: "Policies", Panel: PoliciesPanel },
|
|
9849
10111
|
{ label: "Rate Limit", Panel: RateLimitPanel },
|
|
9850
10112
|
{ label: "DLP", Panel: DlpPanel },
|
|
9851
10113
|
{ label: "Audit", Panel: AuditPanel },
|
|
9852
|
-
{ label: "Settings", Panel: SettingsPanel }
|
|
10114
|
+
{ label: "Settings", Panel: SettingsPanel },
|
|
10115
|
+
{ label: "Accounts", Panel: AccountsPanel }
|
|
9853
10116
|
];
|
|
9854
10117
|
BANNER_HEX = ["white", "white", "white", "white", "white", "white"];
|
|
10118
|
+
ACCOUNTS_SECTION = SECTIONS.findIndex((s) => s.label === "Accounts");
|
|
9855
10119
|
HELP = [
|
|
9856
10120
|
["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
|
|
9857
10121
|
["Live", [["\u2191\u2193", "select a stream row"], ["enter", "full entry content"], ["w", "whitelist the selected DENY"], ["b", "block the selected ALLOW"], ["d / x / r", "filter denies / dlp / rate-limit"], ["f", "local / cloud filter"], ["/", "search"], ["s", "sessions (\u2191\u2193 pick, enter open)"], ["space", "copy mode (freeze)"]]],
|
|
9858
10122
|
["Policies", [["\u2191\u2193", "browse / select"], ["a", "activate (pin) selected policy"], ["x", "deactivate \u2014 no active policy"], ["enter", "open rules \u2192 open a rule"], ["space", "toggle a rule on/off"], ["e", "flip effect"], ["n", "new rule"], ["d", "delete rule"], ["m", "flip mode"], ["D", "dry-run the draft"], ["s", "save"], ["x", "discard"]]],
|
|
9859
10123
|
["Rate limit / DLP", [["\u2191\u2193", "field / pattern"], ["\u2190\u2192", "adjust (shift = \xB110)"], ["space", "toggle pattern"], ["m", "mode"], ["a / d", "add / remove custom"], ["g", "ghost mode"], ["P", "self-protection"], ["s", "save"]]],
|
|
9860
10124
|
["Audit", [["v", "logs \u2194 sessions"], ["s", "source: cloud \u2194 local"], ["\u2190 \u2192", "prev / next page (500 each)"], ["\u2191\u2193", "select (list scrolls)"], ["enter", "full entry / session logs"], ["f / g", "decision / signal filter"], ["t / n / /", "tool / agent / search"], ["x / X", "delete entry / ALL (press twice)"], ["c", "clear filters"]]],
|
|
9861
|
-
["Settings", [["\u2191\u2193", "move"], ["enter / space", "toggle \xB7 edit \xB7 add"], ["e", "webhook events"], ["d d", "delete"], ["r", "refresh"]]]
|
|
10125
|
+
["Settings", [["\u2191\u2193", "move"], ["enter / space", "toggle \xB7 edit \xB7 add"], ["e", "webhook events"], ["d d", "delete"], ["r", "refresh"]]],
|
|
10126
|
+
["Accounts", [["a", "switch account (view another account logged in on this device)"], ["", "the header shows which account you are viewing; guard/logging keep the active key"]]]
|
|
9862
10127
|
];
|
|
9863
10128
|
}
|
|
9864
10129
|
});
|
|
@@ -9869,7 +10134,7 @@ __export(tui_exports, {
|
|
|
9869
10134
|
launchTui: () => launchTui
|
|
9870
10135
|
});
|
|
9871
10136
|
import { render } from "ink";
|
|
9872
|
-
import { jsx as
|
|
10137
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
9873
10138
|
async function launchTui() {
|
|
9874
10139
|
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
9875
10140
|
process.stderr.write(
|
|
@@ -9877,13 +10142,9 @@ async function launchTui() {
|
|
|
9877
10142
|
);
|
|
9878
10143
|
return;
|
|
9879
10144
|
}
|
|
9880
|
-
if (!isAuthenticated()) {
|
|
9881
|
-
process.stderr.write("Not logged in. Run `solongate login` first.\n");
|
|
9882
|
-
return;
|
|
9883
|
-
}
|
|
9884
10145
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
9885
10146
|
try {
|
|
9886
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
10147
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}));
|
|
9887
10148
|
await waitUntilExit();
|
|
9888
10149
|
} finally {
|
|
9889
10150
|
process.stdout.write("\x1B[?1049l");
|
|
@@ -9893,7 +10154,6 @@ var init_tui = __esm({
|
|
|
9893
10154
|
"src/tui/index.tsx"() {
|
|
9894
10155
|
"use strict";
|
|
9895
10156
|
init_App();
|
|
9896
|
-
init_client();
|
|
9897
10157
|
}
|
|
9898
10158
|
});
|
|
9899
10159
|
|
|
@@ -11063,7 +11323,7 @@ __export(global_install_exports, {
|
|
|
11063
11323
|
runGlobalRestore: () => runGlobalRestore,
|
|
11064
11324
|
unlockProtected: () => unlockProtected
|
|
11065
11325
|
});
|
|
11066
|
-
import { readFileSync as readFileSync8, writeFileSync as
|
|
11326
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, existsSync as existsSync6, mkdirSync as mkdirSync6 } from "fs";
|
|
11067
11327
|
import { resolve as resolve4, join as join11, dirname } from "path";
|
|
11068
11328
|
import { homedir as homedir9 } from "os";
|
|
11069
11329
|
import { fileURLToPath } from "url";
|
|
@@ -11176,13 +11436,13 @@ function runGlobalRestore() {
|
|
|
11176
11436
|
unlockProtected();
|
|
11177
11437
|
removeClaudeShim();
|
|
11178
11438
|
if (existsSync6(p.backupPath)) {
|
|
11179
|
-
|
|
11439
|
+
writeFileSync7(p.settingsPath, readFileSync8(p.backupPath, "utf-8"));
|
|
11180
11440
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
11181
11441
|
} else if (existsSync6(p.settingsPath)) {
|
|
11182
11442
|
try {
|
|
11183
11443
|
const s = JSON.parse(readFileSync8(p.settingsPath, "utf-8"));
|
|
11184
11444
|
delete s.hooks;
|
|
11185
|
-
|
|
11445
|
+
writeFileSync7(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
11186
11446
|
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
11187
11447
|
} catch {
|
|
11188
11448
|
}
|
|
@@ -11226,8 +11486,8 @@ function writeShimBlock(file, block2) {
|
|
|
11226
11486
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
11227
11487
|
content += block2 + "\n";
|
|
11228
11488
|
}
|
|
11229
|
-
|
|
11230
|
-
|
|
11489
|
+
mkdirSync6(dirname(file), { recursive: true });
|
|
11490
|
+
writeFileSync7(file, content);
|
|
11231
11491
|
}
|
|
11232
11492
|
function installClaudeShim(shieldPath) {
|
|
11233
11493
|
const real = resolveRealClaude();
|
|
@@ -11278,22 +11538,22 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11278
11538
|
process.exit(1);
|
|
11279
11539
|
}
|
|
11280
11540
|
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
11281
|
-
|
|
11282
|
-
|
|
11541
|
+
mkdirSync6(p.hooksDir, { recursive: true });
|
|
11542
|
+
mkdirSync6(p.claudeDir, { recursive: true });
|
|
11283
11543
|
unlockProtected();
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11544
|
+
writeFileSync7(join11(p.hooksDir, "guard.mjs"), readGuard());
|
|
11545
|
+
writeFileSync7(join11(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
11546
|
+
writeFileSync7(join11(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
11547
|
+
writeFileSync7(join11(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
11288
11548
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
11289
11549
|
installClaudeShim(join11(p.hooksDir, "shield.mjs"));
|
|
11290
|
-
|
|
11550
|
+
writeFileSync7(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
11291
11551
|
console.log(` Wrote ${p.configPath}`);
|
|
11292
11552
|
let existing = {};
|
|
11293
11553
|
if (existsSync6(p.settingsPath)) {
|
|
11294
11554
|
const raw = readFileSync8(p.settingsPath, "utf-8");
|
|
11295
11555
|
if (!existsSync6(p.backupPath)) {
|
|
11296
|
-
|
|
11556
|
+
writeFileSync7(p.backupPath, raw);
|
|
11297
11557
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
11298
11558
|
}
|
|
11299
11559
|
try {
|
|
@@ -11316,7 +11576,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11316
11576
|
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
11317
11577
|
}
|
|
11318
11578
|
};
|
|
11319
|
-
|
|
11579
|
+
writeFileSync7(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
11320
11580
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
11321
11581
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
11322
11582
|
lockProtected();
|
|
@@ -11339,7 +11599,7 @@ var init_global_install = __esm({
|
|
|
11339
11599
|
|
|
11340
11600
|
// src/login.ts
|
|
11341
11601
|
var login_exports = {};
|
|
11342
|
-
import { spawn as
|
|
11602
|
+
import { spawn as spawn3 } from "child_process";
|
|
11343
11603
|
function startSpinner(text) {
|
|
11344
11604
|
if (!process.stderr.isTTY) {
|
|
11345
11605
|
process.stderr.write(` ${text}
|
|
@@ -11371,11 +11631,11 @@ function parseArgs2(argv) {
|
|
|
11371
11631
|
}
|
|
11372
11632
|
return { apiUrl, install };
|
|
11373
11633
|
}
|
|
11374
|
-
function
|
|
11634
|
+
function openBrowser2(url) {
|
|
11375
11635
|
try {
|
|
11376
11636
|
const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
11377
11637
|
const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
|
|
11378
|
-
const child =
|
|
11638
|
+
const child = spawn3(cmd, args, { stdio: "ignore", detached: true });
|
|
11379
11639
|
child.on("error", () => {
|
|
11380
11640
|
});
|
|
11381
11641
|
child.unref();
|
|
@@ -11405,7 +11665,7 @@ async function main() {
|
|
|
11405
11665
|
console.log(` ${c.cyan}${verifyUrl}${c.reset}`);
|
|
11406
11666
|
console.log("");
|
|
11407
11667
|
void user_code;
|
|
11408
|
-
|
|
11668
|
+
openBrowser2(verifyUrl);
|
|
11409
11669
|
const pollMs = Math.max(2, Number(interval) || 3) * 1e3;
|
|
11410
11670
|
const deadline = Date.now() + (Number(expires_in) || 600) * 1e3;
|
|
11411
11671
|
let apiKey = "";
|
|
@@ -11434,6 +11694,7 @@ async function main() {
|
|
|
11434
11694
|
if (data?.project?.name) {
|
|
11435
11695
|
console.log(` ${c.dim}Project:${c.reset} ${c.cyan}${data.project.name}${c.reset}`);
|
|
11436
11696
|
}
|
|
11697
|
+
saveAccount({ apiKey, apiUrl, project: data?.project?.name, user: data?.user?.name || data?.user?.email });
|
|
11437
11698
|
break;
|
|
11438
11699
|
}
|
|
11439
11700
|
if (data?.status === "expired" || data?.status === "not_found") {
|
|
@@ -11478,6 +11739,7 @@ var init_login = __esm({
|
|
|
11478
11739
|
"use strict";
|
|
11479
11740
|
init_cli_utils();
|
|
11480
11741
|
init_global_install();
|
|
11742
|
+
init_client();
|
|
11481
11743
|
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
11482
11744
|
SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
11483
11745
|
main().catch((err2) => {
|
|
@@ -11494,7 +11756,7 @@ __export(shield_exports, {
|
|
|
11494
11756
|
});
|
|
11495
11757
|
import { createServer, request as httpRequest } from "http";
|
|
11496
11758
|
import { request as httpsRequest } from "https";
|
|
11497
|
-
import { spawn as
|
|
11759
|
+
import { spawn as spawn4 } from "child_process";
|
|
11498
11760
|
import { URL as URL2 } from "url";
|
|
11499
11761
|
import { readFileSync as readFileSync9, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
11500
11762
|
import { resolve as resolve5 } from "path";
|
|
@@ -11754,7 +12016,7 @@ async function runShield() {
|
|
|
11754
12016
|
const upstream = pickUpstream();
|
|
11755
12017
|
const { port, close } = await startProxy(upstream);
|
|
11756
12018
|
log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
|
|
11757
|
-
const child =
|
|
12019
|
+
const child = spawn4(cmd[0], cmd.slice(1), {
|
|
11758
12020
|
stdio: "inherit",
|
|
11759
12021
|
env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
|
|
11760
12022
|
shell: process.platform === "win32"
|
|
@@ -11992,7 +12254,7 @@ var init_logs_server = __esm({
|
|
|
11992
12254
|
|
|
11993
12255
|
// src/inject.ts
|
|
11994
12256
|
var inject_exports = {};
|
|
11995
|
-
import { readFileSync as readFileSync11, writeFileSync as
|
|
12257
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, existsSync as existsSync8, copyFileSync } from "fs";
|
|
11996
12258
|
import { resolve as resolve7 } from "path";
|
|
11997
12259
|
import { execSync } from "child_process";
|
|
11998
12260
|
function parseInjectArgs(argv) {
|
|
@@ -12300,7 +12562,7 @@ async function main2() {
|
|
|
12300
12562
|
log3("");
|
|
12301
12563
|
log3(` Backup: ${backupPath}`);
|
|
12302
12564
|
}
|
|
12303
|
-
|
|
12565
|
+
writeFileSync8(entryFile, result.modified);
|
|
12304
12566
|
log3("");
|
|
12305
12567
|
log3(" \u250C\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\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
12306
12568
|
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
@@ -12329,7 +12591,7 @@ var init_inject = __esm({
|
|
|
12329
12591
|
|
|
12330
12592
|
// src/create.ts
|
|
12331
12593
|
var create_exports = {};
|
|
12332
|
-
import { mkdirSync as
|
|
12594
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync9, existsSync as existsSync9 } from "fs";
|
|
12333
12595
|
import { resolve as resolve8, join as join13 } from "path";
|
|
12334
12596
|
import { execSync as execSync2 } from "child_process";
|
|
12335
12597
|
function withSpinner(message, fn) {
|
|
@@ -12409,7 +12671,7 @@ EXAMPLES
|
|
|
12409
12671
|
`);
|
|
12410
12672
|
}
|
|
12411
12673
|
function createProject(dir, name, _policy) {
|
|
12412
|
-
|
|
12674
|
+
writeFileSync9(
|
|
12413
12675
|
join13(dir, "package.json"),
|
|
12414
12676
|
JSON.stringify(
|
|
12415
12677
|
{
|
|
@@ -12439,7 +12701,7 @@ function createProject(dir, name, _policy) {
|
|
|
12439
12701
|
2
|
|
12440
12702
|
) + "\n"
|
|
12441
12703
|
);
|
|
12442
|
-
|
|
12704
|
+
writeFileSync9(
|
|
12443
12705
|
join13(dir, "tsconfig.json"),
|
|
12444
12706
|
JSON.stringify(
|
|
12445
12707
|
{
|
|
@@ -12460,8 +12722,8 @@ function createProject(dir, name, _policy) {
|
|
|
12460
12722
|
2
|
|
12461
12723
|
) + "\n"
|
|
12462
12724
|
);
|
|
12463
|
-
|
|
12464
|
-
|
|
12725
|
+
mkdirSync7(join13(dir, "src"), { recursive: true });
|
|
12726
|
+
writeFileSync9(
|
|
12465
12727
|
join13(dir, "src", "index.ts"),
|
|
12466
12728
|
`#!/usr/bin/env node
|
|
12467
12729
|
|
|
@@ -12503,7 +12765,7 @@ console.log('');
|
|
|
12503
12765
|
console.log('Press Ctrl+C to stop.');
|
|
12504
12766
|
`
|
|
12505
12767
|
);
|
|
12506
|
-
|
|
12768
|
+
writeFileSync9(
|
|
12507
12769
|
join13(dir, ".mcp.json"),
|
|
12508
12770
|
JSON.stringify(
|
|
12509
12771
|
{
|
|
@@ -12521,12 +12783,12 @@ console.log('Press Ctrl+C to stop.');
|
|
|
12521
12783
|
2
|
|
12522
12784
|
) + "\n"
|
|
12523
12785
|
);
|
|
12524
|
-
|
|
12786
|
+
writeFileSync9(
|
|
12525
12787
|
join13(dir, ".env"),
|
|
12526
12788
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
12527
12789
|
`
|
|
12528
12790
|
);
|
|
12529
|
-
|
|
12791
|
+
writeFileSync9(
|
|
12530
12792
|
join13(dir, ".gitignore"),
|
|
12531
12793
|
`node_modules/
|
|
12532
12794
|
dist/
|
|
@@ -12546,7 +12808,7 @@ async function main3() {
|
|
|
12546
12808
|
process.exit(1);
|
|
12547
12809
|
}
|
|
12548
12810
|
withSpinner(`Setting up ${opts.name}...`, () => {
|
|
12549
|
-
|
|
12811
|
+
mkdirSync7(dir, { recursive: true });
|
|
12550
12812
|
createProject(dir, opts.name, opts.policy);
|
|
12551
12813
|
});
|
|
12552
12814
|
if (!opts.noInstall) {
|
|
@@ -12620,7 +12882,7 @@ var init_create = __esm({
|
|
|
12620
12882
|
|
|
12621
12883
|
// src/pull-push.ts
|
|
12622
12884
|
var pull_push_exports = {};
|
|
12623
|
-
import { readFileSync as readFileSync12, writeFileSync as
|
|
12885
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync10, existsSync as existsSync10 } from "fs";
|
|
12624
12886
|
import { resolve as resolve9 } from "path";
|
|
12625
12887
|
function loadEnv() {
|
|
12626
12888
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
@@ -12815,7 +13077,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
12815
13077
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
12816
13078
|
const { id: _id, ...policyWithoutId } = policy;
|
|
12817
13079
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
12818
|
-
|
|
13080
|
+
writeFileSync10(file, json, "utf-8");
|
|
12819
13081
|
log5("");
|
|
12820
13082
|
log5(green2(" Saved to: ") + file);
|
|
12821
13083
|
log5(` ${dim2("Name:")} ${policy.name}`);
|
|
@@ -15995,8 +16257,7 @@ function printWelcome() {
|
|
|
15995
16257
|
async function main5() {
|
|
15996
16258
|
const subcommand = process.argv[2];
|
|
15997
16259
|
if (process.argv.length <= 2) {
|
|
15998
|
-
|
|
15999
|
-
if (process.stdout.isTTY && isAuthenticated2()) {
|
|
16260
|
+
if (process.stdout.isTTY && process.stdin.isTTY) {
|
|
16000
16261
|
const { launchTui: launchTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
|
|
16001
16262
|
await launchTui2();
|
|
16002
16263
|
return;
|