@solongate/proxy 0.83.3 → 0.83.5
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/auth.d.ts +0 -8
- package/dist/api-client/client.d.ts +0 -14
- package/dist/commands/index.js +0 -33
- package/dist/global-install.js +10 -0
- package/dist/index.js +175 -157
- package/dist/self-update.d.ts +14 -1
- package/dist/tui/index.js +83 -92
- package/hooks/guard.bundled.mjs +1 -44
- package/hooks/guard.mjs +1 -53
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -465,13 +465,13 @@ ${offset}${err2}${errEnd}`;
|
|
|
465
465
|
return next >= src.length || src[next] === "\n" ? str + "\n" : str;
|
|
466
466
|
}
|
|
467
467
|
// ^(---|...)
|
|
468
|
-
static atDocumentBoundary(src, offset,
|
|
468
|
+
static atDocumentBoundary(src, offset, sep2) {
|
|
469
469
|
const ch0 = src[offset];
|
|
470
470
|
if (!ch0) return true;
|
|
471
471
|
const prev = src[offset - 1];
|
|
472
472
|
if (prev && prev !== "\n") return false;
|
|
473
|
-
if (
|
|
474
|
-
if (ch0 !==
|
|
473
|
+
if (sep2) {
|
|
474
|
+
if (ch0 !== sep2) return false;
|
|
475
475
|
} else {
|
|
476
476
|
if (ch0 !== Char.DIRECTIVES_END && ch0 !== Char.DOCUMENT_END) return false;
|
|
477
477
|
}
|
|
@@ -1647,7 +1647,7 @@ var require_parse_cst = __commonJS({
|
|
|
1647
1647
|
const folded = this.type === PlainValue.Type.BLOCK_FOLDED;
|
|
1648
1648
|
let atStart = true;
|
|
1649
1649
|
let str = "";
|
|
1650
|
-
let
|
|
1650
|
+
let sep2 = "";
|
|
1651
1651
|
let prevMoreIndented = false;
|
|
1652
1652
|
for (let i = start; i < end; ++i) {
|
|
1653
1653
|
for (let j = 0; j < bi; ++j) {
|
|
@@ -1656,21 +1656,21 @@ var require_parse_cst = __commonJS({
|
|
|
1656
1656
|
}
|
|
1657
1657
|
const ch2 = src[i];
|
|
1658
1658
|
if (ch2 === "\n") {
|
|
1659
|
-
if (
|
|
1660
|
-
else
|
|
1659
|
+
if (sep2 === "\n") str += "\n";
|
|
1660
|
+
else sep2 = "\n";
|
|
1661
1661
|
} else {
|
|
1662
1662
|
const lineEnd = PlainValue.Node.endOfLine(src, i);
|
|
1663
1663
|
const line = src.slice(i, lineEnd);
|
|
1664
1664
|
i = lineEnd;
|
|
1665
1665
|
if (folded && (ch2 === " " || ch2 === " ") && i < keepStart) {
|
|
1666
|
-
if (
|
|
1667
|
-
else if (!prevMoreIndented && !atStart &&
|
|
1668
|
-
str +=
|
|
1669
|
-
|
|
1666
|
+
if (sep2 === " ") sep2 = "\n";
|
|
1667
|
+
else if (!prevMoreIndented && !atStart && sep2 === "\n") sep2 = "\n\n";
|
|
1668
|
+
str += sep2 + line;
|
|
1669
|
+
sep2 = lineEnd < end && src[lineEnd] || "";
|
|
1670
1670
|
prevMoreIndented = true;
|
|
1671
1671
|
} else {
|
|
1672
|
-
str +=
|
|
1673
|
-
|
|
1672
|
+
str += sep2 + line;
|
|
1673
|
+
sep2 = folded && i < keepStart ? " " : "\n";
|
|
1674
1674
|
prevMoreIndented = false;
|
|
1675
1675
|
}
|
|
1676
1676
|
if (atStart && line !== "") atStart = false;
|
|
@@ -6612,6 +6612,16 @@ function repairQuiet() {
|
|
|
6612
6612
|
}
|
|
6613
6613
|
async function runRepair() {
|
|
6614
6614
|
const out2 = (s) => void process.stderr.write(s + "\n");
|
|
6615
|
+
if (process.platform !== "win32" && typeof process.getuid === "function" && process.getuid() === 0 && process.env["SOLONGATE_INTERNAL"] !== "1") {
|
|
6616
|
+
out2("");
|
|
6617
|
+
out2(" Do not run `solongate repair` with sudo.");
|
|
6618
|
+
out2(" It installs the guard into your home directory, and as root it would");
|
|
6619
|
+
out2(` arm root\u2019s home instead${process.env["SUDO_USER"] ? ` of ${process.env["SUDO_USER"]}\u2019s` : ""} \u2014 reporting success while nothing changed for you.`);
|
|
6620
|
+
out2("");
|
|
6621
|
+
out2(" Run it as yourself: solongate repair");
|
|
6622
|
+
out2("");
|
|
6623
|
+
return 1;
|
|
6624
|
+
}
|
|
6615
6625
|
const rep = repairQuiet();
|
|
6616
6626
|
out2("");
|
|
6617
6627
|
out2(" SolonGate repair");
|
|
@@ -6924,22 +6934,25 @@ var init_global_install = __esm({
|
|
|
6924
6934
|
var self_update_exports = {};
|
|
6925
6935
|
__export(self_update_exports, {
|
|
6926
6936
|
adminInstallCommand: () => adminInstallCommand,
|
|
6937
|
+
adminUpdateSteps: () => adminUpdateSteps,
|
|
6927
6938
|
autoUpdateEnabled: () => autoUpdateEnabled,
|
|
6928
6939
|
autoUpdateForcedByEnv: () => autoUpdateForcedByEnv,
|
|
6929
6940
|
currentVersion: () => currentVersion,
|
|
6941
|
+
globalInstallCheck: () => globalInstallCheck,
|
|
6930
6942
|
latestVersion: () => latestVersion,
|
|
6931
6943
|
maybeSelfUpdate: () => maybeSelfUpdate,
|
|
6932
6944
|
newerThan: () => newerThan,
|
|
6933
6945
|
runAutoUpdateCommand: () => runAutoUpdateCommand,
|
|
6934
6946
|
runUpdateCommand: () => runUpdateCommand,
|
|
6947
|
+
runningAsRoot: () => runningAsRoot,
|
|
6935
6948
|
setAutoUpdate: () => setAutoUpdate,
|
|
6936
6949
|
tuiUpdateFlow: () => tuiUpdateFlow,
|
|
6937
6950
|
updateNow: () => updateNow
|
|
6938
6951
|
});
|
|
6939
6952
|
import { execFile, execFileSync as execFileSync3, spawn } from "child_process";
|
|
6940
|
-
import { mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
6953
|
+
import { access, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4, constants as FS } from "fs";
|
|
6941
6954
|
import { homedir as homedir3 } from "os";
|
|
6942
|
-
import { dirname as dirname2, join as join5 } from "path";
|
|
6955
|
+
import { dirname as dirname2, join as join5, sep } from "path";
|
|
6943
6956
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6944
6957
|
function readState() {
|
|
6945
6958
|
try {
|
|
@@ -7026,6 +7039,17 @@ function spawnGlobalInstall(version) {
|
|
|
7026
7039
|
}
|
|
7027
7040
|
async function runUpdateCommand() {
|
|
7028
7041
|
const out2 = (s) => void process.stderr.write(s + "\n");
|
|
7042
|
+
if (runningAsRoot()) {
|
|
7043
|
+
out2("");
|
|
7044
|
+
out2(" Do not run `solongate update` with sudo.");
|
|
7045
|
+
out2(" npm would install fine, but the guard hooks would be written into root\u2019s");
|
|
7046
|
+
out2(" home instead of yours, and your agents would stop being guarded.");
|
|
7047
|
+
out2("");
|
|
7048
|
+
out2(" Run these two instead:");
|
|
7049
|
+
for (const s of adminUpdateSteps()) out2(" " + s);
|
|
7050
|
+
out2("");
|
|
7051
|
+
return 1;
|
|
7052
|
+
}
|
|
7029
7053
|
const cur = currentVersion();
|
|
7030
7054
|
out2(` current ${cur}`);
|
|
7031
7055
|
const latest = await latestVersion();
|
|
@@ -7034,13 +7058,26 @@ async function runUpdateCommand() {
|
|
|
7034
7058
|
return 1;
|
|
7035
7059
|
}
|
|
7036
7060
|
if (newerThan(latest, cur)) {
|
|
7061
|
+
const pre = await globalInstallCheck();
|
|
7062
|
+
if (pre.writable === false) {
|
|
7063
|
+
writeState({ ...readState(), needsAdmin: latest });
|
|
7064
|
+
out2(` v${latest} is out, but npm\u2019s global folder needs admin rights on this machine:`);
|
|
7065
|
+
out2(` ${pre.dir}`);
|
|
7066
|
+
out2(" That is the normal macOS setup \u2014 SolonGate cannot install there on its own.");
|
|
7067
|
+
out2("");
|
|
7068
|
+
out2(" Run these two:");
|
|
7069
|
+
for (const s of adminUpdateSteps()) out2(" " + s);
|
|
7070
|
+
out2("");
|
|
7071
|
+
return 1;
|
|
7072
|
+
}
|
|
7037
7073
|
out2(` updating ${cur} -> ${latest} ...`);
|
|
7038
7074
|
const r = await runGlobalInstall2(latest);
|
|
7039
7075
|
if (!r.ok) {
|
|
7040
7076
|
if (r.needsAdmin) {
|
|
7041
7077
|
writeState({ ...readState(), needsAdmin: latest });
|
|
7042
|
-
out2(
|
|
7043
|
-
out2(
|
|
7078
|
+
out2(" npm could not write to the global folder (it needs admin rights).");
|
|
7079
|
+
out2(" Run these two:");
|
|
7080
|
+
for (const s of adminUpdateSteps()) out2(" " + s);
|
|
7044
7081
|
} else {
|
|
7045
7082
|
out2(" update failed. Try: npm i -g @solongate/proxy@latest");
|
|
7046
7083
|
}
|
|
@@ -7095,11 +7132,43 @@ ${output}
|
|
|
7095
7132
|
function adminInstallCommand() {
|
|
7096
7133
|
return process.platform === "win32" ? `npm i -g ${PKG}@latest (in an Administrator terminal)` : `sudo npm i -g ${PKG}@latest`;
|
|
7097
7134
|
}
|
|
7135
|
+
function runningAsRoot() {
|
|
7136
|
+
return process.platform !== "win32" && typeof process.getuid === "function" && process.getuid() === 0;
|
|
7137
|
+
}
|
|
7138
|
+
function ownNodeModules() {
|
|
7139
|
+
let dir = dirname2(fileURLToPath2(import.meta.url));
|
|
7140
|
+
for (let i = 0; i < 12; i++) {
|
|
7141
|
+
const parent = dirname2(dir);
|
|
7142
|
+
if (parent === dir) break;
|
|
7143
|
+
if (dir.endsWith(`${sep}node_modules`)) return dir;
|
|
7144
|
+
dir = parent;
|
|
7145
|
+
}
|
|
7146
|
+
return null;
|
|
7147
|
+
}
|
|
7148
|
+
function globalInstallCheck() {
|
|
7149
|
+
prefixCheck ??= new Promise((resolve6) => {
|
|
7150
|
+
try {
|
|
7151
|
+
const dir = ownNodeModules();
|
|
7152
|
+
if (!dir) return resolve6({ writable: null, dir: null });
|
|
7153
|
+
access(dir, FS.W_OK, (e) => resolve6({ writable: !e, dir }));
|
|
7154
|
+
} catch {
|
|
7155
|
+
resolve6({ writable: null, dir: null });
|
|
7156
|
+
}
|
|
7157
|
+
});
|
|
7158
|
+
return prefixCheck;
|
|
7159
|
+
}
|
|
7160
|
+
function adminUpdateSteps() {
|
|
7161
|
+
return [` ${adminInstallCommand()}`, ` solongate repair${process.platform === "win32" ? "" : " (this one WITHOUT sudo)"}`];
|
|
7162
|
+
}
|
|
7098
7163
|
async function updateNow() {
|
|
7099
7164
|
const cur = currentVersion();
|
|
7100
7165
|
const latest = await fetchLatest();
|
|
7101
7166
|
if (!latest) return { status: "unreachable", version: cur };
|
|
7102
7167
|
if (!newerThan(latest, cur)) return { status: "current", version: cur };
|
|
7168
|
+
if ((await globalInstallCheck()).writable === false) {
|
|
7169
|
+
writeState({ ...readState(), needsAdmin: latest });
|
|
7170
|
+
return { status: "needs-admin", version: latest };
|
|
7171
|
+
}
|
|
7103
7172
|
const r = await runGlobalInstall2(latest);
|
|
7104
7173
|
if (r.ok) {
|
|
7105
7174
|
writeState({ ...readState(), installed: latest, needsAdmin: void 0 });
|
|
@@ -7111,7 +7180,7 @@ async function updateNow() {
|
|
|
7111
7180
|
}
|
|
7112
7181
|
return { status: "failed", version: latest };
|
|
7113
7182
|
}
|
|
7114
|
-
function runAutoUpdateCommand(arg) {
|
|
7183
|
+
async function runAutoUpdateCommand(arg) {
|
|
7115
7184
|
const out2 = (s) => void process.stderr.write(s + "\n");
|
|
7116
7185
|
const envForced = autoUpdateForcedByEnv();
|
|
7117
7186
|
if (arg === void 0) {
|
|
@@ -7128,6 +7197,13 @@ function runAutoUpdateCommand(arg) {
|
|
|
7128
7197
|
}
|
|
7129
7198
|
setAutoUpdate(on);
|
|
7130
7199
|
out2(on ? " \u2713 auto-update on \u2014 new versions install in the background" : " \u2713 auto-update off \u2014 update with: solongate update");
|
|
7200
|
+
if (on && (await globalInstallCheck()).writable === false) {
|
|
7201
|
+
out2("");
|
|
7202
|
+
out2(" Heads up: npm\u2019s global folder needs admin rights on this machine, so a");
|
|
7203
|
+
out2(" background install cannot succeed here. Updates will still be announced,");
|
|
7204
|
+
out2(" and installing them takes:");
|
|
7205
|
+
for (const s of adminUpdateSteps()) out2(" " + s);
|
|
7206
|
+
}
|
|
7131
7207
|
if (envForced) out2(` note: SOLONGATE_AUTO_UPDATE is set and overrides this while it stays set`);
|
|
7132
7208
|
return 0;
|
|
7133
7209
|
}
|
|
@@ -7178,18 +7254,25 @@ function maybeSelfUpdate(notify = (l) => process.stderr.write(l + "\n")) {
|
|
|
7178
7254
|
const attempts = readState().attempts ?? {};
|
|
7179
7255
|
if (now - (attempts[latest] ?? 0) < ATTEMPT_EVERY_MS) return;
|
|
7180
7256
|
writeState({ ...readState(), attempts: { [latest]: now } });
|
|
7257
|
+
const needsAdmin = (await globalInstallCheck()).writable === false;
|
|
7258
|
+
const head = `${c.dim}\u2191 solongate v${latest} available (running v${current})`;
|
|
7259
|
+
if (needsAdmin) {
|
|
7260
|
+
notify(`${head} \u2014 needs admin rights on this machine:${c.reset}`);
|
|
7261
|
+
for (const s of adminUpdateSteps()) notify(`${c.cyan} ${s.trim()}${c.reset}`);
|
|
7262
|
+
return;
|
|
7263
|
+
}
|
|
7181
7264
|
if (!autoUpdateEnabled()) {
|
|
7182
|
-
notify(`${
|
|
7265
|
+
notify(`${head} \u2014 run ${c.reset}${c.cyan}solongate update${c.reset}`);
|
|
7183
7266
|
return;
|
|
7184
7267
|
}
|
|
7185
7268
|
if (spawnGlobalInstall(latest)) {
|
|
7186
|
-
notify(`${
|
|
7269
|
+
notify(`${head} \u2014 updating in the background, next run uses it${c.reset}`);
|
|
7187
7270
|
}
|
|
7188
7271
|
} catch {
|
|
7189
7272
|
}
|
|
7190
7273
|
})();
|
|
7191
7274
|
}
|
|
7192
|
-
var PKG, CHECK_EVERY_MS, ATTEMPT_EVERY_MS, STATE_FILE, LOG_FILE, NEEDS_ADMIN_RE;
|
|
7275
|
+
var PKG, CHECK_EVERY_MS, ATTEMPT_EVERY_MS, STATE_FILE, LOG_FILE, NEEDS_ADMIN_RE, prefixCheck;
|
|
7193
7276
|
var init_self_update = __esm({
|
|
7194
7277
|
"src/self-update.ts"() {
|
|
7195
7278
|
"use strict";
|
|
@@ -7200,6 +7283,7 @@ var init_self_update = __esm({
|
|
|
7200
7283
|
STATE_FILE = join5(homedir3(), ".solongate", ".self-update.json");
|
|
7201
7284
|
LOG_FILE = join5(homedir3(), ".solongate", "self-update.log");
|
|
7202
7285
|
NEEDS_ADMIN_RE = /\bEACCES\b|\bEPERM\b|permission denied|operation not permitted/i;
|
|
7286
|
+
prefixCheck = null;
|
|
7203
7287
|
}
|
|
7204
7288
|
});
|
|
7205
7289
|
|
|
@@ -7632,26 +7716,6 @@ var init_local_log = __esm({
|
|
|
7632
7716
|
});
|
|
7633
7717
|
|
|
7634
7718
|
// src/api-client/client.ts
|
|
7635
|
-
var client_exports = {};
|
|
7636
|
-
__export(client_exports, {
|
|
7637
|
-
ApiError: () => ApiError,
|
|
7638
|
-
DEFAULT_API_URL: () => DEFAULT_API_URL2,
|
|
7639
|
-
GUEST_EMAIL_SUFFIX: () => GUEST_EMAIL_SUFFIX,
|
|
7640
|
-
GuestReadOnlyError: () => GuestReadOnlyError,
|
|
7641
|
-
NotAuthenticatedError: () => NotAuthenticatedError,
|
|
7642
|
-
clearActiveCredential: () => clearActiveCredential,
|
|
7643
|
-
enforcingKey: () => enforcingKey,
|
|
7644
|
-
isActiveAccount: () => isActiveAccount,
|
|
7645
|
-
isAuthenticated: () => isAuthenticated,
|
|
7646
|
-
isGuestAccount: () => isGuestAccount,
|
|
7647
|
-
listAccounts: () => listAccounts,
|
|
7648
|
-
removeAccount: () => removeAccount,
|
|
7649
|
-
request: () => request,
|
|
7650
|
-
resolveCredentials: () => resolveCredentials,
|
|
7651
|
-
saveAccount: () => saveAccount,
|
|
7652
|
-
setActiveAccount: () => setActiveAccount,
|
|
7653
|
-
setViewCredentials: () => setViewCredentials
|
|
7654
|
-
});
|
|
7655
7719
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync5 } from "fs";
|
|
7656
7720
|
import { resolve as resolve4, join as join9 } from "path";
|
|
7657
7721
|
import { homedir as homedir7 } from "os";
|
|
@@ -7703,15 +7767,6 @@ function setViewCredentials(creds) {
|
|
|
7703
7767
|
viewOverride = creds;
|
|
7704
7768
|
cached2 = null;
|
|
7705
7769
|
}
|
|
7706
|
-
function isGuestAccount() {
|
|
7707
|
-
try {
|
|
7708
|
-
const active2 = loginCredentialFile().apiKey;
|
|
7709
|
-
if (!active2) return false;
|
|
7710
|
-
return listAccounts().some((a) => a.apiKey === active2 && (a.email ?? "").endsWith(GUEST_EMAIL_SUFFIX));
|
|
7711
|
-
} catch {
|
|
7712
|
-
return false;
|
|
7713
|
-
}
|
|
7714
|
-
}
|
|
7715
7770
|
function enforcingKey() {
|
|
7716
7771
|
return loginCredentialFile().apiKey ?? null;
|
|
7717
7772
|
}
|
|
@@ -7814,9 +7869,6 @@ function buildUrl(base, path, query) {
|
|
|
7814
7869
|
return url.toString();
|
|
7815
7870
|
}
|
|
7816
7871
|
async function request(method, path, opts = {}) {
|
|
7817
|
-
if (method !== "GET" && isGuestAccount()) {
|
|
7818
|
-
throw new GuestReadOnlyError();
|
|
7819
|
-
}
|
|
7820
7872
|
const creds = resolveCredentials(opts.apiUrl);
|
|
7821
7873
|
const url = buildUrl(creds.apiUrl, path, opts.query);
|
|
7822
7874
|
const headers = {
|
|
@@ -7872,7 +7924,7 @@ async function request(method, path, opts = {}) {
|
|
|
7872
7924
|
}
|
|
7873
7925
|
return json;
|
|
7874
7926
|
}
|
|
7875
|
-
var DEFAULT_API_URL2, accountsFile, viewOverride,
|
|
7927
|
+
var DEFAULT_API_URL2, accountsFile, viewOverride, ApiError, NotAuthenticatedError, cached2;
|
|
7876
7928
|
var init_client = __esm({
|
|
7877
7929
|
"src/api-client/client.ts"() {
|
|
7878
7930
|
"use strict";
|
|
@@ -7880,7 +7932,6 @@ var init_client = __esm({
|
|
|
7880
7932
|
DEFAULT_API_URL2 = "https://api.solongate.com";
|
|
7881
7933
|
accountsFile = () => join9(homedir7(), ".solongate", "accounts.json");
|
|
7882
7934
|
viewOverride = null;
|
|
7883
|
-
GUEST_EMAIL_SUFFIX = "@anonymous.solongate.invalid";
|
|
7884
7935
|
ApiError = class extends Error {
|
|
7885
7936
|
status;
|
|
7886
7937
|
code;
|
|
@@ -7891,12 +7942,6 @@ var init_client = __esm({
|
|
|
7891
7942
|
this.code = code;
|
|
7892
7943
|
}
|
|
7893
7944
|
};
|
|
7894
|
-
GuestReadOnlyError = class extends Error {
|
|
7895
|
-
constructor() {
|
|
7896
|
-
super("Guest account: sign up at auth.solongate.com to change anything. Your project, its policy and everything recorded carry over.");
|
|
7897
|
-
this.name = "GuestReadOnlyError";
|
|
7898
|
-
}
|
|
7899
|
-
};
|
|
7900
7945
|
NotAuthenticatedError = class extends Error {
|
|
7901
7946
|
constructor() {
|
|
7902
7947
|
super("Not logged in. Run `solongate` and log in from the Accounts panel.");
|
|
@@ -9237,18 +9282,18 @@ function LivePanel({ active: active2 }) {
|
|
|
9237
9282
|
}
|
|
9238
9283
|
) : null,
|
|
9239
9284
|
activeAction ? /* @__PURE__ */ jsx2(Text2, { wrap: "truncate", backgroundColor: activeAction.level === "bad" ? "#3d1220" : "#123d1f", color: activeAction.level === "bad" ? "#ff6b6b" : "#7bd88f", bold: true, children: ` ${truncate2(activeAction.text, innerW - 4)} ` }) : null,
|
|
9240
|
-
/* @__PURE__ */ jsxs2(Box2, { height: 1 + chartH, children: [
|
|
9241
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: leftW, marginRight: 2, children: [
|
|
9285
|
+
/* @__PURE__ */ jsxs2(Box2, { height: 1 + chartH, overflow: "hidden", children: [
|
|
9286
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: leftW, height: 1 + chartH, marginRight: 2, overflow: "hidden", children: [
|
|
9242
9287
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "TRAFFIC", extra: `${trafficLabel} \xB7 peak ${Math.max(0, ...traffic)} \xB7 red = denials`, width: leftW }),
|
|
9243
9288
|
/* @__PURE__ */ jsx2(ColumnChart, { series: traffic, hot: trafficHot, height: chartH, width: leftW, color: theme.accent })
|
|
9244
9289
|
] }),
|
|
9245
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: rightW, children: [
|
|
9290
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: rightW, height: 1 + chartH, overflow: "hidden", children: [
|
|
9246
9291
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "API LATENCY", extra: `now ${latNow}ms \xB7 med ${latMed}ms \xB7 amber >${Math.round(latHotAt)}ms`, width: rightW }),
|
|
9247
9292
|
/* @__PURE__ */ jsx2(ColumnChart, { series: lat, hot: lat.map((v) => v > latHotAt), height: chartH, width: rightW, color: "white", hotColor: "#ffb454" })
|
|
9248
9293
|
] })
|
|
9249
9294
|
] }),
|
|
9250
|
-
/* @__PURE__ */ jsxs2(Box2, { height: colH, children: [
|
|
9251
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
9295
|
+
/* @__PURE__ */ jsxs2(Box2, { height: colH, overflow: "hidden", children: [
|
|
9296
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, height: colH, marginRight: 2, overflow: "hidden", children: [
|
|
9252
9297
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", extra: "l = inspect", width: colW }),
|
|
9253
9298
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
9254
9299
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "RATELIMIT ".padEnd(10) }),
|
|
@@ -9261,7 +9306,11 @@ function LivePanel({ active: active2 }) {
|
|
|
9261
9306
|
/* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: (dl?.mode ?? "?").padEnd(7) }),
|
|
9262
9307
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `${(dl?.patterns ?? []).length} builtin \xB7 ${(dl?.custom ?? []).length} custom` })
|
|
9263
9308
|
] }),
|
|
9264
|
-
dlpBars.length ? dlpBars.map((d2) => /* @__PURE__ */ jsx2(HBar, { label: truncate2(d2.pattern, 10), value: d2.count, max: maxDlpBar, width: Math.max(6, colW - 16), color: theme.bad }, d2.pattern)) :
|
|
9309
|
+
dlpBars.length ? dlpBars.map((d2) => /* @__PURE__ */ jsx2(HBar, { label: truncate2(d2.pattern, 10), value: d2.count, max: maxDlpBar, width: Math.max(6, colW - 16), color: theme.bad }, d2.pattern)) : (
|
|
9310
|
+
// 36 chars against a colW that is ~31 at cols=100: without truncate
|
|
9311
|
+
// this wrapped onto a second line and pushed the column over colH.
|
|
9312
|
+
/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " no dlp hits in last 7 days" })
|
|
9313
|
+
),
|
|
9265
9314
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
9266
9315
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "GUARD".padEnd(10) }),
|
|
9267
9316
|
ring ? /* @__PURE__ */ jsxs2(Text2, { color: theme.ok, children: [
|
|
@@ -9270,7 +9319,7 @@ function LivePanel({ active: active2 }) {
|
|
|
9270
9319
|
] }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no local ring in cwd" })
|
|
9271
9320
|
] })
|
|
9272
9321
|
] }),
|
|
9273
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
9322
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, height: colH, marginRight: 2, overflow: "hidden", children: [
|
|
9274
9323
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: mode === "pick" ? "\u2191\u2193 pick \xB7 enter open" : `${combinedSess.length} \xB7 s = inspect`, width: colW }),
|
|
9275
9324
|
pickable.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
|
|
9276
9325
|
pickable.map((r, i) => {
|
|
@@ -9296,7 +9345,7 @@ function LivePanel({ active: active2 }) {
|
|
|
9296
9345
|
] }, r.id);
|
|
9297
9346
|
})
|
|
9298
9347
|
] }),
|
|
9299
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
|
|
9348
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, height: colH, overflow: "hidden", children: [
|
|
9300
9349
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
|
|
9301
9350
|
log3.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
9302
9351
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
@@ -11503,26 +11552,7 @@ var init_doctor = __esm({
|
|
|
11503
11552
|
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
11504
11553
|
import TextInput6 from "ink-text-input";
|
|
11505
11554
|
import { useEffect as useEffect7, useRef as useRef3, useState as useState8 } from "react";
|
|
11506
|
-
import { readFileSync as readFileSync11, readdirSync as readdirSync2 } from "fs";
|
|
11507
|
-
import { homedir as homedir11 } from "os";
|
|
11508
|
-
import { join as join13 } from "path";
|
|
11509
11555
|
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
11510
|
-
function guestAllowance() {
|
|
11511
|
-
try {
|
|
11512
|
-
const dir = join13(homedir11(), ".solongate");
|
|
11513
|
-
for (const f of readdirSync2(dir)) {
|
|
11514
|
-
if (!f.startsWith(".policy-cache-") || !f.endsWith(".json")) continue;
|
|
11515
|
-
try {
|
|
11516
|
-
const c2 = JSON.parse(readFileSync11(join13(dir, f), "utf-8"));
|
|
11517
|
-
const q = c2?.security?.guestQuota;
|
|
11518
|
-
if (q && typeof q.limit === "number") return { used: q.used ?? 0, limit: q.limit };
|
|
11519
|
-
} catch {
|
|
11520
|
-
}
|
|
11521
|
-
}
|
|
11522
|
-
} catch {
|
|
11523
|
-
}
|
|
11524
|
-
return null;
|
|
11525
|
-
}
|
|
11526
11556
|
function SettingsPanel({
|
|
11527
11557
|
active: active2,
|
|
11528
11558
|
focused,
|
|
@@ -11543,6 +11573,17 @@ function SettingsPanel({
|
|
|
11543
11573
|
const [diagBusy, setDiagBusy] = useState8(null);
|
|
11544
11574
|
const [autoUp, setAutoUp] = useState8(() => autoUpdateEnabled());
|
|
11545
11575
|
const [updBusy, setUpdBusy] = useState8(false);
|
|
11576
|
+
const [canInstall, setCanInstall] = useState8(null);
|
|
11577
|
+
useEffect7(() => {
|
|
11578
|
+
let live2 = true;
|
|
11579
|
+
globalInstallCheck().then((r) => {
|
|
11580
|
+
if (live2) setCanInstall(r.writable);
|
|
11581
|
+
}).catch(() => {
|
|
11582
|
+
});
|
|
11583
|
+
return () => {
|
|
11584
|
+
live2 = false;
|
|
11585
|
+
};
|
|
11586
|
+
}, []);
|
|
11546
11587
|
const [diag, setDiag] = useState8(null);
|
|
11547
11588
|
const [diagStep, setDiagStep] = useState8(0);
|
|
11548
11589
|
const DIAG_STEPS = {
|
|
@@ -11560,7 +11601,6 @@ function SettingsPanel({
|
|
|
11560
11601
|
const step = setInterval(() => setDiagStep((s) => Math.min(s + 1, total - 1)), 220);
|
|
11561
11602
|
return () => clearInterval(step);
|
|
11562
11603
|
}, [diagBusy]);
|
|
11563
|
-
void guestAllowance;
|
|
11564
11604
|
const ver = currentVersion();
|
|
11565
11605
|
useEffect7(() => {
|
|
11566
11606
|
let live2 = true;
|
|
@@ -11822,15 +11862,27 @@ function SettingsPanel({
|
|
|
11822
11862
|
if (updBusy) return;
|
|
11823
11863
|
setUpdBusy(true);
|
|
11824
11864
|
setMsg({ text: "updating\u2026", level: "ok" });
|
|
11865
|
+
setDiag(null);
|
|
11825
11866
|
void (async () => {
|
|
11826
11867
|
try {
|
|
11827
11868
|
const res = await updateNow();
|
|
11828
11869
|
if (res.status === "updated") setMsg({ text: `\u2713 v${res.version} installed \xB7 restart (q, then solongate) to apply`, level: "ok" });
|
|
11829
11870
|
else if (res.status === "current") setMsg({ text: `\u2713 already on the latest version (v${res.version})`, level: "ok" });
|
|
11830
|
-
else if (res.status === "needs-admin")
|
|
11831
|
-
|
|
11871
|
+
else if (res.status === "needs-admin") {
|
|
11872
|
+
setMsg({ text: `\u2717 v${res.version} needs admin rights \u2014 run the two commands below`, level: "bad" });
|
|
11873
|
+
setDiag({
|
|
11874
|
+
of: "cli-update",
|
|
11875
|
+
lines: [
|
|
11876
|
+
{ text: "npm\u2019s global folder belongs to root on this machine (the usual macOS", level: "warn" },
|
|
11877
|
+
{ text: "setup), so SolonGate cannot install there by itself. In a terminal:", level: "warn" },
|
|
11878
|
+
...adminUpdateSteps().map((s) => ({ text: s.trim(), level: "ok" })),
|
|
11879
|
+
{ text: "run repair WITHOUT sudo, or the guard hooks land in root\u2019s home", level: "dim" }
|
|
11880
|
+
]
|
|
11881
|
+
});
|
|
11882
|
+
} else if (res.status === "unreachable") setMsg({ text: "\u2717 could not reach the npm registry", level: "bad" });
|
|
11832
11883
|
else setMsg({ text: `\u2717 update to v${res.version} failed \u2014 see ~/.solongate/self-update.log`, level: "bad" });
|
|
11833
11884
|
setLatest(await latestVersion());
|
|
11885
|
+
setCanInstall((await globalInstallCheck()).writable);
|
|
11834
11886
|
} finally {
|
|
11835
11887
|
setUpdBusy(false);
|
|
11836
11888
|
}
|
|
@@ -11844,7 +11896,7 @@ function SettingsPanel({
|
|
|
11844
11896
|
setAutoUpdate(next);
|
|
11845
11897
|
setAutoUp(next);
|
|
11846
11898
|
setMsg(
|
|
11847
|
-
next ? { text: "\u2713 auto-update on \u2014 new versions install in the background", level: "ok" } : { text: "\u2713 auto-update off \u2014 update from this row or with: solongate update", level: "ok" }
|
|
11899
|
+
next ? canInstall === false ? { text: "\u2713 auto-update on \u2014 but npm needs sudo here, so it still cannot install on its own", level: "bad" } : { text: "\u2713 auto-update on \u2014 new versions install in the background", level: "ok" } : { text: "\u2713 auto-update off \u2014 update from this row or with: solongate update", level: "ok" }
|
|
11848
11900
|
);
|
|
11849
11901
|
} else if (r.kind === "ll-enabled") {
|
|
11850
11902
|
if (!local) return;
|
|
@@ -12113,15 +12165,6 @@ function SettingsPanel({
|
|
|
12113
12165
|
cursor(r),
|
|
12114
12166
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add account (enter \u2014 device login in the browser)" })
|
|
12115
12167
|
] });
|
|
12116
|
-
case "allowance": {
|
|
12117
|
-
const left = Math.max(0, r.limit - r.used);
|
|
12118
|
-
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
12119
|
-
cursor(r),
|
|
12120
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "allowance".padEnd(11) }),
|
|
12121
|
-
/* @__PURE__ */ jsx8(Text8, { color: left === 0 ? theme.bad : left <= 20 ? theme.warn : theme.ok, bold: true, children: `${r.used}/${r.limit} tool calls` }),
|
|
12122
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: left === 0 ? " used up \u2014 every call is denied \xB7 create an account to carry on" : ` ${left} left on this guest account \xB7 create an account for no limit` })
|
|
12123
|
-
] });
|
|
12124
|
-
}
|
|
12125
12168
|
case "guard":
|
|
12126
12169
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
12127
12170
|
cursor(r),
|
|
@@ -12162,7 +12205,10 @@ function SettingsPanel({
|
|
|
12162
12205
|
cursor(r),
|
|
12163
12206
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "version".padEnd(11) }),
|
|
12164
12207
|
/* @__PURE__ */ jsx8(Text8, { color: behind ? theme.warn : theme.ok, children: `v${ver}` }),
|
|
12165
|
-
updBusy ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: ` ${spin} updating\u2026` }) : behind
|
|
12208
|
+
updBusy ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: ` ${spin} updating\u2026` }) : behind && canInstall === false ? (
|
|
12209
|
+
// Said before they press enter, not after a minute of npm noise.
|
|
12210
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` v${latest} on npm \xB7 needs sudo here \xB7 enter shows how` })
|
|
12211
|
+
) : behind ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` v${latest} on npm \xB7 enter updates now` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: latest ? " latest \xB7 enter checks again" : " enter checks npm and updates" })
|
|
12166
12212
|
] });
|
|
12167
12213
|
}
|
|
12168
12214
|
case "auto-update":
|
|
@@ -12170,7 +12216,7 @@ function SettingsPanel({
|
|
|
12170
12216
|
cursor(r),
|
|
12171
12217
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "auto".padEnd(11) }),
|
|
12172
12218
|
onOff(autoUp),
|
|
12173
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: autoUpdateForcedByEnv() ? " set by SOLONGATE_AUTO_UPDATE" : autoUp ? " installs new versions in the background \xB7 enter toggles" : " off: nothing installs on its own (npm -g may need sudo) \xB7 enter toggles" })
|
|
12219
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: autoUpdateForcedByEnv() ? " set by SOLONGATE_AUTO_UPDATE" : canInstall === false ? " cannot work here: npm needs sudo, so updates stay manual \xB7 enter toggles" : autoUp ? " installs new versions in the background \xB7 enter toggles" : " off: nothing installs on its own (npm -g may need sudo) \xB7 enter toggles" })
|
|
12174
12220
|
] });
|
|
12175
12221
|
case "ll-enabled":
|
|
12176
12222
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
@@ -12224,7 +12270,7 @@ function SettingsPanel({
|
|
|
12224
12270
|
] });
|
|
12225
12271
|
}
|
|
12226
12272
|
};
|
|
12227
|
-
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add"
|
|
12273
|
+
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" ? "ACCOUNTS" : r.kind === "guard" || r.kind === "self" || r.kind === "doctor" || r.kind === "repair" ? "PROTECTION" : r.kind === "cli-update" || r.kind === "auto-update" ? "UPDATES" : r.kind === "ll-enabled" || r.kind === "ll-path" || r.kind === "ll-server" ? "LOCAL LOGS" : r.kind === "wh" || r.kind === "wh-add" ? "WEBHOOKS" : "ALERTS";
|
|
12228
12274
|
const SECTION_DESC = {
|
|
12229
12275
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
12230
12276
|
PROTECTION: "guard hook: enter install/update \xB7 d remove \xB7 self-protection \xB7 doctor + repair",
|
|
@@ -12269,7 +12315,7 @@ function SettingsPanel({
|
|
|
12269
12315
|
lineKey.push("");
|
|
12270
12316
|
});
|
|
12271
12317
|
}
|
|
12272
|
-
if (diag && (r.kind === "doctor" && diag.of === "doctor" || r.kind === "repair" && diag.of === "repair")) {
|
|
12318
|
+
if (diag && (r.kind === "doctor" && diag.of === "doctor" || r.kind === "repair" && diag.of === "repair" || r.kind === "cli-update" && diag.of === "cli-update")) {
|
|
12273
12319
|
diag.lines.forEach((l, i) => {
|
|
12274
12320
|
lineEls.push(
|
|
12275
12321
|
/* @__PURE__ */ jsx8(
|
|
@@ -12418,23 +12464,7 @@ function App() {
|
|
|
12418
12464
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
12419
12465
|
const cur = accounts[acctIdx];
|
|
12420
12466
|
const rawEmail = cur?.email ?? "";
|
|
12421
|
-
const
|
|
12422
|
-
const acctLabel2 = !cur ? "not logged in" : isGuestAccount2 ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}`;
|
|
12423
|
-
const [guestSpent, setGuestSpent] = useState9(false);
|
|
12424
|
-
useEffect8(() => {
|
|
12425
|
-
if (!isGuestAccount2) {
|
|
12426
|
-
setGuestSpent(false);
|
|
12427
|
-
return;
|
|
12428
|
-
}
|
|
12429
|
-
let alive = true;
|
|
12430
|
-
api.auth.me().then((r) => {
|
|
12431
|
-
if (alive) setGuestSpent(r.guest?.exhausted === true);
|
|
12432
|
-
}).catch(() => {
|
|
12433
|
-
});
|
|
12434
|
-
return () => {
|
|
12435
|
-
alive = false;
|
|
12436
|
-
};
|
|
12437
|
-
}, [isGuestAccount2, cur?.apiKey]);
|
|
12467
|
+
const acctLabel2 = !cur ? "not logged in" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}`;
|
|
12438
12468
|
useEffect8(() => {
|
|
12439
12469
|
if (!cur || cur.email) return;
|
|
12440
12470
|
let alive = true;
|
|
@@ -12520,12 +12550,7 @@ function App() {
|
|
|
12520
12550
|
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
12521
12551
|
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
|
|
12522
12552
|
/* @__PURE__ */ jsx9(Text9, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel2 }),
|
|
12523
|
-
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Settings to unlock the dataroom" }) :
|
|
12524
|
-
// Said on this line rather than on a new one: every panel budgets its
|
|
12525
|
-
// height against a fixed shell, so one more line up here silently clips
|
|
12526
|
-
// a row off whichever panel is open.
|
|
12527
|
-
/* @__PURE__ */ jsx9(Text9, { color: theme.bad, bold: true, children: " \xB7 allowance used up \xB7 every call denied \xB7 create an account to carry on" })
|
|
12528
|
-
) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Settings to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Settings to add another" }),
|
|
12553
|
+
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Settings to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Settings to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Settings to add another" }),
|
|
12529
12554
|
update2.kind === "updating" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx9(Text9, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \xB7 restart (q, then solongate) to apply` }) : update2.kind === "available" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 v${update2.version} out \xB7 Settings \u2192 UPDATES` }) : update2.kind === "needs-admin" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 v${update2.version} needs admin rights \xB7 Settings \u2192 UPDATES` }) : null
|
|
12530
12555
|
] }),
|
|
12531
12556
|
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
@@ -12603,8 +12628,8 @@ __export(tui_exports, {
|
|
|
12603
12628
|
launchTui: () => launchTui
|
|
12604
12629
|
});
|
|
12605
12630
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
12606
|
-
import { homedir as
|
|
12607
|
-
import { join as
|
|
12631
|
+
import { homedir as homedir11 } from "os";
|
|
12632
|
+
import { join as join13 } from "path";
|
|
12608
12633
|
import { render } from "ink";
|
|
12609
12634
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
12610
12635
|
async function launchTui() {
|
|
@@ -12615,11 +12640,11 @@ async function launchTui() {
|
|
|
12615
12640
|
return;
|
|
12616
12641
|
}
|
|
12617
12642
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
12618
|
-
const debugLog =
|
|
12643
|
+
const debugLog = join13(homedir11(), ".solongate", "dataroom-debug.log");
|
|
12619
12644
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
12620
12645
|
const toFile = (level) => (...args) => {
|
|
12621
12646
|
try {
|
|
12622
|
-
mkdirSync9(
|
|
12647
|
+
mkdirSync9(join13(homedir11(), ".solongate"), { recursive: true });
|
|
12623
12648
|
appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
12624
12649
|
`);
|
|
12625
12650
|
} catch {
|
|
@@ -12646,7 +12671,7 @@ var init_tui = __esm({
|
|
|
12646
12671
|
});
|
|
12647
12672
|
|
|
12648
12673
|
// src/commands/policy.ts
|
|
12649
|
-
import { readFileSync as
|
|
12674
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
12650
12675
|
async function run2(argv) {
|
|
12651
12676
|
const { positionals, flags } = parse(argv);
|
|
12652
12677
|
const sub = positionals[0];
|
|
@@ -12803,7 +12828,7 @@ function printRules(rules) {
|
|
|
12803
12828
|
}
|
|
12804
12829
|
async function resolveRules(target) {
|
|
12805
12830
|
if (target.endsWith(".json")) {
|
|
12806
|
-
const parsed = JSON.parse(
|
|
12831
|
+
const parsed = JSON.parse(readFileSync11(target, "utf-8"));
|
|
12807
12832
|
return parsed.rules ?? [];
|
|
12808
12833
|
}
|
|
12809
12834
|
const p = await api.policies.get(target);
|
|
@@ -13517,10 +13542,10 @@ __export(logs_server_exports, {
|
|
|
13517
13542
|
runLogsServer: () => runLogsServer
|
|
13518
13543
|
});
|
|
13519
13544
|
import { createServer } from "http";
|
|
13520
|
-
import { readFileSync as
|
|
13521
|
-
import { resolve as resolve5, join as
|
|
13522
|
-
import { homedir as
|
|
13523
|
-
import { readdirSync as
|
|
13545
|
+
import { readFileSync as readFileSync12, statSync as statSync4 } from "fs";
|
|
13546
|
+
import { resolve as resolve5, join as join14, isAbsolute as isAbsolute2 } from "path";
|
|
13547
|
+
import { homedir as homedir12 } from "os";
|
|
13548
|
+
import { readdirSync as readdirSync2 } from "fs";
|
|
13524
13549
|
function allowedOrigins() {
|
|
13525
13550
|
const base = [
|
|
13526
13551
|
"https://dashboard.solongate.com",
|
|
@@ -13536,15 +13561,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
13536
13561
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
13537
13562
|
if (!dir) return null;
|
|
13538
13563
|
if (isAbsolute2(dir)) return dir;
|
|
13539
|
-
return resolve5(
|
|
13564
|
+
return resolve5(homedir12(), ".solongate", "local-logs");
|
|
13540
13565
|
}
|
|
13541
13566
|
async function findLogDir() {
|
|
13542
|
-
const base = resolve5(
|
|
13567
|
+
const base = resolve5(homedir12(), ".solongate");
|
|
13543
13568
|
try {
|
|
13544
|
-
const files =
|
|
13569
|
+
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
13545
13570
|
for (const f of files) {
|
|
13546
13571
|
try {
|
|
13547
|
-
const c2 = JSON.parse(
|
|
13572
|
+
const c2 = JSON.parse(readFileSync12(join14(base, f), "utf-8"));
|
|
13548
13573
|
const p = c2?.security?.localLogs?.path;
|
|
13549
13574
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
13550
13575
|
} catch {
|
|
@@ -13553,7 +13578,7 @@ async function findLogDir() {
|
|
|
13553
13578
|
} catch {
|
|
13554
13579
|
}
|
|
13555
13580
|
try {
|
|
13556
|
-
const cfgRaw =
|
|
13581
|
+
const cfgRaw = readFileSync12(join14(base, "cloud-guard.json"), "utf-8");
|
|
13557
13582
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
13558
13583
|
if (apiKey) {
|
|
13559
13584
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -13582,7 +13607,7 @@ function setCors(req, res) {
|
|
|
13582
13607
|
}
|
|
13583
13608
|
function fileInfo(dir) {
|
|
13584
13609
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
13585
|
-
const file =
|
|
13610
|
+
const file = join14(dir, LOG_FILENAME);
|
|
13586
13611
|
try {
|
|
13587
13612
|
const st = statSync4(file);
|
|
13588
13613
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
@@ -13665,7 +13690,7 @@ async function runLogsServer() {
|
|
|
13665
13690
|
return;
|
|
13666
13691
|
}
|
|
13667
13692
|
try {
|
|
13668
|
-
const text =
|
|
13693
|
+
const text = readFileSync12(info.file, "utf-8");
|
|
13669
13694
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
|
|
13670
13695
|
res.end(text);
|
|
13671
13696
|
} catch {
|
|
@@ -13718,9 +13743,9 @@ var init_logs_server = __esm({
|
|
|
13718
13743
|
});
|
|
13719
13744
|
|
|
13720
13745
|
// src/index.ts
|
|
13721
|
-
import { readFileSync as
|
|
13746
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
13722
13747
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13723
|
-
import { dirname as dirname4, join as
|
|
13748
|
+
import { dirname as dirname4, join as join15 } from "path";
|
|
13724
13749
|
|
|
13725
13750
|
// src/config.ts
|
|
13726
13751
|
import { readFileSync, existsSync } from "fs";
|
|
@@ -17115,8 +17140,8 @@ if (!IS_HUMAN_CLI) {
|
|
|
17115
17140
|
}
|
|
17116
17141
|
var PKG_VERSION = (() => {
|
|
17117
17142
|
try {
|
|
17118
|
-
const p =
|
|
17119
|
-
return JSON.parse(
|
|
17143
|
+
const p = join15(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
17144
|
+
return JSON.parse(readFileSync13(p, "utf-8")).version || "unknown";
|
|
17120
17145
|
} catch {
|
|
17121
17146
|
return "unknown";
|
|
17122
17147
|
}
|
|
@@ -17157,7 +17182,7 @@ function printHelp() {
|
|
|
17157
17182
|
console.log(` ${c.dim}Usage:${c.reset} ${c.cyan}solongate${c.reset} ${c.dim}[command]${c.reset} ${c.dim}(no command opens the dataroom: all of this in a terminal UI)${c.reset}`);
|
|
17158
17183
|
head("Setup & status");
|
|
17159
17184
|
cmd("solongate", "open the dataroom UI (login, policies, audit, settings)");
|
|
17160
|
-
cmd("update", "update SolonGate
|
|
17185
|
+
cmd("update", "update SolonGate and refresh the guard (tells you if it needs sudo)");
|
|
17161
17186
|
cmd("update auto on|off", "background auto-update (default off \u2014 on macOS npm -g often needs sudo)");
|
|
17162
17187
|
cmd("repair", "restore the guard + hook + settings files if they were deleted or disarmed");
|
|
17163
17188
|
cmd("doctor", "health check: login, policy, guard, local logs");
|
|
@@ -17287,13 +17312,6 @@ async function main() {
|
|
|
17287
17312
|
}
|
|
17288
17313
|
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
|
|
17289
17314
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
17290
|
-
const { isGuestAccount: isGuestAccount2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
17291
|
-
if (subcommand !== "doctor" && isGuestAccount2()) {
|
|
17292
|
-
process.stderr.write(
|
|
17293
|
-
"\n This is a guest account, which can look but not change.\n Create an account to use the management commands:\n https://auth.solongate.com\n\n Your project, its policy and everything already recorded carry over,\n and this device keeps working without being paired again.\n\n"
|
|
17294
|
-
);
|
|
17295
|
-
process.exit(1);
|
|
17296
|
-
}
|
|
17297
17315
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
17298
17316
|
const code = await runCommand2(subcommand, process.argv.slice(3));
|
|
17299
17317
|
process.exit(code);
|
|
@@ -17308,7 +17326,7 @@ async function main() {
|
|
|
17308
17326
|
if (subcommand === "update") {
|
|
17309
17327
|
if (process.argv[3] === "auto") {
|
|
17310
17328
|
const { runAutoUpdateCommand: runAutoUpdateCommand2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
17311
|
-
process.exit(runAutoUpdateCommand2(process.argv[4]));
|
|
17329
|
+
process.exit(await runAutoUpdateCommand2(process.argv[4]));
|
|
17312
17330
|
}
|
|
17313
17331
|
const { runUpdateCommand: runUpdateCommand2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
17314
17332
|
process.exit(await runUpdateCommand2());
|