@solongate/proxy 0.83.2 → 0.83.4
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/global-install.js +10 -0
- package/dist/index.js +285 -38
- package/dist/self-update.d.ts +55 -8
- package/dist/tui/index.js +167 -15
- package/package.json +1 -1
package/dist/global-install.js
CHANGED
|
@@ -405,6 +405,16 @@ function repairQuiet() {
|
|
|
405
405
|
}
|
|
406
406
|
async function runRepair() {
|
|
407
407
|
const out = (s) => void process.stderr.write(s + "\n");
|
|
408
|
+
if (process.platform !== "win32" && typeof process.getuid === "function" && process.getuid() === 0 && process.env["SOLONGATE_INTERNAL"] !== "1") {
|
|
409
|
+
out("");
|
|
410
|
+
out(" Do not run `solongate repair` with sudo.");
|
|
411
|
+
out(" It installs the guard into your home directory, and as root it would");
|
|
412
|
+
out(` arm root\u2019s home instead${process.env["SUDO_USER"] ? ` of ${process.env["SUDO_USER"]}\u2019s` : ""} \u2014 reporting success while nothing changed for you.`);
|
|
413
|
+
out("");
|
|
414
|
+
out(" Run it as yourself: solongate repair");
|
|
415
|
+
out("");
|
|
416
|
+
return 1;
|
|
417
|
+
}
|
|
408
418
|
const rep = repairQuiet();
|
|
409
419
|
out("");
|
|
410
420
|
out(" SolonGate repair");
|
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");
|
|
@@ -6923,17 +6933,26 @@ var init_global_install = __esm({
|
|
|
6923
6933
|
// src/self-update.ts
|
|
6924
6934
|
var self_update_exports = {};
|
|
6925
6935
|
__export(self_update_exports, {
|
|
6936
|
+
adminInstallCommand: () => adminInstallCommand,
|
|
6937
|
+
adminUpdateSteps: () => adminUpdateSteps,
|
|
6938
|
+
autoUpdateEnabled: () => autoUpdateEnabled,
|
|
6939
|
+
autoUpdateForcedByEnv: () => autoUpdateForcedByEnv,
|
|
6926
6940
|
currentVersion: () => currentVersion,
|
|
6941
|
+
globalInstallCheck: () => globalInstallCheck,
|
|
6927
6942
|
latestVersion: () => latestVersion,
|
|
6928
6943
|
maybeSelfUpdate: () => maybeSelfUpdate,
|
|
6929
6944
|
newerThan: () => newerThan,
|
|
6945
|
+
runAutoUpdateCommand: () => runAutoUpdateCommand,
|
|
6930
6946
|
runUpdateCommand: () => runUpdateCommand,
|
|
6931
|
-
|
|
6947
|
+
runningAsRoot: () => runningAsRoot,
|
|
6948
|
+
setAutoUpdate: () => setAutoUpdate,
|
|
6949
|
+
tuiUpdateFlow: () => tuiUpdateFlow,
|
|
6950
|
+
updateNow: () => updateNow
|
|
6932
6951
|
});
|
|
6933
6952
|
import { execFile, execFileSync as execFileSync3, spawn } from "child_process";
|
|
6934
|
-
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";
|
|
6935
6954
|
import { homedir as homedir3 } from "os";
|
|
6936
|
-
import { dirname as dirname2, join as join5 } from "path";
|
|
6955
|
+
import { dirname as dirname2, join as join5, sep } from "path";
|
|
6937
6956
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6938
6957
|
function readState() {
|
|
6939
6958
|
try {
|
|
@@ -6950,6 +6969,20 @@ function writeState(s) {
|
|
|
6950
6969
|
} catch {
|
|
6951
6970
|
}
|
|
6952
6971
|
}
|
|
6972
|
+
function autoUpdateEnabled() {
|
|
6973
|
+
const env = (process.env.SOLONGATE_AUTO_UPDATE ?? "").trim().toLowerCase();
|
|
6974
|
+
if (env === "1" || env === "true" || env === "on" || env === "yes") return true;
|
|
6975
|
+
if (env === "0" || env === "false" || env === "off" || env === "no") return false;
|
|
6976
|
+
return readState().auto === true;
|
|
6977
|
+
}
|
|
6978
|
+
function autoUpdateForcedByEnv() {
|
|
6979
|
+
const env = (process.env.SOLONGATE_AUTO_UPDATE ?? "").trim().toLowerCase();
|
|
6980
|
+
return ["1", "true", "on", "yes", "0", "false", "off", "no"].includes(env);
|
|
6981
|
+
}
|
|
6982
|
+
function setAutoUpdate(on) {
|
|
6983
|
+
const s = readState();
|
|
6984
|
+
writeState(on ? { ...s, auto: true, needsAdmin: void 0 } : { ...s, auto: false });
|
|
6985
|
+
}
|
|
6953
6986
|
function currentVersion() {
|
|
6954
6987
|
try {
|
|
6955
6988
|
const pkg = JSON.parse(readFileSync5(join5(dirname2(fileURLToPath2(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
@@ -7006,6 +7039,17 @@ function spawnGlobalInstall(version) {
|
|
|
7006
7039
|
}
|
|
7007
7040
|
async function runUpdateCommand() {
|
|
7008
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
|
+
}
|
|
7009
7053
|
const cur = currentVersion();
|
|
7010
7054
|
out2(` current ${cur}`);
|
|
7011
7055
|
const latest = await latestVersion();
|
|
@@ -7014,12 +7058,32 @@ async function runUpdateCommand() {
|
|
|
7014
7058
|
return 1;
|
|
7015
7059
|
}
|
|
7016
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
|
+
}
|
|
7017
7073
|
out2(` updating ${cur} -> ${latest} ...`);
|
|
7018
|
-
const
|
|
7019
|
-
if (!ok) {
|
|
7020
|
-
|
|
7074
|
+
const r = await runGlobalInstall2(latest);
|
|
7075
|
+
if (!r.ok) {
|
|
7076
|
+
if (r.needsAdmin) {
|
|
7077
|
+
writeState({ ...readState(), needsAdmin: latest });
|
|
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);
|
|
7081
|
+
} else {
|
|
7082
|
+
out2(" update failed. Try: npm i -g @solongate/proxy@latest");
|
|
7083
|
+
}
|
|
7021
7084
|
return 1;
|
|
7022
7085
|
}
|
|
7086
|
+
writeState({ ...readState(), needsAdmin: void 0 });
|
|
7023
7087
|
out2(` \u2713 updated to ${latest} (open a new session to use it)`);
|
|
7024
7088
|
} else {
|
|
7025
7089
|
out2(` \u2713 already up to date`);
|
|
@@ -7049,20 +7113,99 @@ function runGlobalInstall2(version) {
|
|
|
7049
7113
|
["install", "-g", `${PKG}@${version}`],
|
|
7050
7114
|
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
7051
7115
|
(err2, stdout, stderr) => {
|
|
7116
|
+
const output = `${stdout}
|
|
7117
|
+
${stderr}`;
|
|
7052
7118
|
try {
|
|
7053
7119
|
writeFileSync4(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err2 ? "FAILED" : "ok"}
|
|
7054
|
-
${
|
|
7055
|
-
${stderr}
|
|
7120
|
+
${output}
|
|
7056
7121
|
`, { flag: "a" });
|
|
7057
7122
|
} catch {
|
|
7058
7123
|
}
|
|
7059
|
-
resolve6(!err2);
|
|
7124
|
+
resolve6({ ok: !err2, needsAdmin: !!err2 && NEEDS_ADMIN_RE.test(output) });
|
|
7060
7125
|
}
|
|
7061
7126
|
);
|
|
7062
7127
|
} catch {
|
|
7063
|
-
resolve6(false);
|
|
7128
|
+
resolve6({ ok: false, needsAdmin: false });
|
|
7129
|
+
}
|
|
7130
|
+
});
|
|
7131
|
+
}
|
|
7132
|
+
function adminInstallCommand() {
|
|
7133
|
+
return process.platform === "win32" ? `npm i -g ${PKG}@latest (in an Administrator terminal)` : `sudo npm i -g ${PKG}@latest`;
|
|
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 });
|
|
7064
7156
|
}
|
|
7065
7157
|
});
|
|
7158
|
+
return prefixCheck;
|
|
7159
|
+
}
|
|
7160
|
+
function adminUpdateSteps() {
|
|
7161
|
+
return [` ${adminInstallCommand()}`, ` solongate repair${process.platform === "win32" ? "" : " (this one WITHOUT sudo)"}`];
|
|
7162
|
+
}
|
|
7163
|
+
async function updateNow() {
|
|
7164
|
+
const cur = currentVersion();
|
|
7165
|
+
const latest = await fetchLatest();
|
|
7166
|
+
if (!latest) return { status: "unreachable", version: cur };
|
|
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
|
+
}
|
|
7172
|
+
const r = await runGlobalInstall2(latest);
|
|
7173
|
+
if (r.ok) {
|
|
7174
|
+
writeState({ ...readState(), installed: latest, needsAdmin: void 0 });
|
|
7175
|
+
return { status: "updated", version: latest };
|
|
7176
|
+
}
|
|
7177
|
+
if (r.needsAdmin) {
|
|
7178
|
+
writeState({ ...readState(), needsAdmin: latest });
|
|
7179
|
+
return { status: "needs-admin", version: latest };
|
|
7180
|
+
}
|
|
7181
|
+
return { status: "failed", version: latest };
|
|
7182
|
+
}
|
|
7183
|
+
async function runAutoUpdateCommand(arg) {
|
|
7184
|
+
const out2 = (s) => void process.stderr.write(s + "\n");
|
|
7185
|
+
const envForced = autoUpdateForcedByEnv();
|
|
7186
|
+
if (arg === void 0) {
|
|
7187
|
+
out2(` auto-update is ${autoUpdateEnabled() ? "on" : "off"}${envForced ? " (forced by SOLONGATE_AUTO_UPDATE)" : ""}`);
|
|
7188
|
+
out2(" change it with: solongate update auto on|off");
|
|
7189
|
+
return 0;
|
|
7190
|
+
}
|
|
7191
|
+
const v = arg.trim().toLowerCase();
|
|
7192
|
+
const on = ["on", "1", "true", "yes", "enable", "enabled"].includes(v);
|
|
7193
|
+
const off = ["off", "0", "false", "no", "disable", "disabled"].includes(v);
|
|
7194
|
+
if (!on && !off) {
|
|
7195
|
+
out2(` unknown value "${arg}" \u2014 use: solongate update auto on|off`);
|
|
7196
|
+
return 1;
|
|
7197
|
+
}
|
|
7198
|
+
setAutoUpdate(on);
|
|
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
|
+
}
|
|
7207
|
+
if (envForced) out2(` note: SOLONGATE_AUTO_UPDATE is set and overrides this while it stays set`);
|
|
7208
|
+
return 0;
|
|
7066
7209
|
}
|
|
7067
7210
|
async function tuiUpdateFlow(onStatus) {
|
|
7068
7211
|
try {
|
|
@@ -7075,10 +7218,22 @@ async function tuiUpdateFlow(onStatus) {
|
|
|
7075
7218
|
onStatus({ kind: "updated", version: latest });
|
|
7076
7219
|
return;
|
|
7077
7220
|
}
|
|
7221
|
+
if (!autoUpdateEnabled()) {
|
|
7222
|
+
onStatus({ kind: "available", version: latest });
|
|
7223
|
+
return;
|
|
7224
|
+
}
|
|
7225
|
+
if (readState().needsAdmin === latest) {
|
|
7226
|
+
onStatus({ kind: "needs-admin", version: latest });
|
|
7227
|
+
return;
|
|
7228
|
+
}
|
|
7078
7229
|
onStatus({ kind: "updating", version: latest });
|
|
7079
|
-
|
|
7080
|
-
|
|
7230
|
+
const r = await runGlobalInstall2(latest);
|
|
7231
|
+
if (r.ok) {
|
|
7232
|
+
writeState({ ...readState(), installed: latest, needsAdmin: void 0 });
|
|
7081
7233
|
onStatus({ kind: "updated", version: latest });
|
|
7234
|
+
} else if (r.needsAdmin) {
|
|
7235
|
+
writeState({ ...readState(), needsAdmin: latest });
|
|
7236
|
+
onStatus({ kind: "needs-admin", version: latest });
|
|
7082
7237
|
}
|
|
7083
7238
|
} catch {
|
|
7084
7239
|
}
|
|
@@ -7097,17 +7252,27 @@ function maybeSelfUpdate(notify = (l) => process.stderr.write(l + "\n")) {
|
|
|
7097
7252
|
}
|
|
7098
7253
|
if (!latest || !newerThan(latest, current)) return;
|
|
7099
7254
|
const attempts = readState().attempts ?? {};
|
|
7100
|
-
if (now - (attempts[latest] ?? 0)
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7255
|
+
if (now - (attempts[latest] ?? 0) < ATTEMPT_EVERY_MS) return;
|
|
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
|
+
}
|
|
7264
|
+
if (!autoUpdateEnabled()) {
|
|
7265
|
+
notify(`${head} \u2014 run ${c.reset}${c.cyan}solongate update${c.reset}`);
|
|
7266
|
+
return;
|
|
7267
|
+
}
|
|
7268
|
+
if (spawnGlobalInstall(latest)) {
|
|
7269
|
+
notify(`${head} \u2014 updating in the background, next run uses it${c.reset}`);
|
|
7105
7270
|
}
|
|
7106
7271
|
} catch {
|
|
7107
7272
|
}
|
|
7108
7273
|
})();
|
|
7109
7274
|
}
|
|
7110
|
-
var PKG, CHECK_EVERY_MS, ATTEMPT_EVERY_MS, STATE_FILE, LOG_FILE;
|
|
7275
|
+
var PKG, CHECK_EVERY_MS, ATTEMPT_EVERY_MS, STATE_FILE, LOG_FILE, NEEDS_ADMIN_RE, prefixCheck;
|
|
7111
7276
|
var init_self_update = __esm({
|
|
7112
7277
|
"src/self-update.ts"() {
|
|
7113
7278
|
"use strict";
|
|
@@ -7117,6 +7282,8 @@ var init_self_update = __esm({
|
|
|
7117
7282
|
ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
7118
7283
|
STATE_FILE = join5(homedir3(), ".solongate", ".self-update.json");
|
|
7119
7284
|
LOG_FILE = join5(homedir3(), ".solongate", "self-update.log");
|
|
7285
|
+
NEEDS_ADMIN_RE = /\bEACCES\b|\bEPERM\b|permission denied|operation not permitted/i;
|
|
7286
|
+
prefixCheck = null;
|
|
7120
7287
|
}
|
|
7121
7288
|
});
|
|
7122
7289
|
|
|
@@ -11458,6 +11625,19 @@ function SettingsPanel({
|
|
|
11458
11625
|
const [editor, setEditor] = useState8(null);
|
|
11459
11626
|
const [latest, setLatest] = useState8(null);
|
|
11460
11627
|
const [diagBusy, setDiagBusy] = useState8(null);
|
|
11628
|
+
const [autoUp, setAutoUp] = useState8(() => autoUpdateEnabled());
|
|
11629
|
+
const [updBusy, setUpdBusy] = useState8(false);
|
|
11630
|
+
const [canInstall, setCanInstall] = useState8(null);
|
|
11631
|
+
useEffect7(() => {
|
|
11632
|
+
let live2 = true;
|
|
11633
|
+
globalInstallCheck().then((r) => {
|
|
11634
|
+
if (live2) setCanInstall(r.writable);
|
|
11635
|
+
}).catch(() => {
|
|
11636
|
+
});
|
|
11637
|
+
return () => {
|
|
11638
|
+
live2 = false;
|
|
11639
|
+
};
|
|
11640
|
+
}, []);
|
|
11461
11641
|
const [diag, setDiag] = useState8(null);
|
|
11462
11642
|
const [diagStep, setDiagStep] = useState8(0);
|
|
11463
11643
|
const DIAG_STEPS = {
|
|
@@ -11515,10 +11695,10 @@ function SettingsPanel({
|
|
|
11515
11695
|
}, []);
|
|
11516
11696
|
useEffect7(() => {
|
|
11517
11697
|
const loggingIn = login && login.phase !== "done" && login.phase !== "error";
|
|
11518
|
-
if (!loggingIn && !diagBusy) return;
|
|
11698
|
+
if (!loggingIn && !diagBusy && !updBusy) return;
|
|
11519
11699
|
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
11520
11700
|
return () => clearInterval(t);
|
|
11521
|
-
}, [login, diagBusy]);
|
|
11701
|
+
}, [login, diagBusy, updBusy]);
|
|
11522
11702
|
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
11523
11703
|
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
11524
11704
|
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
@@ -11552,6 +11732,8 @@ function SettingsPanel({
|
|
|
11552
11732
|
{ kind: "self" },
|
|
11553
11733
|
{ kind: "doctor" },
|
|
11554
11734
|
{ kind: "repair" },
|
|
11735
|
+
{ kind: "cli-update" },
|
|
11736
|
+
{ kind: "auto-update" },
|
|
11555
11737
|
{ kind: "ll-enabled" },
|
|
11556
11738
|
{ kind: "ll-path" },
|
|
11557
11739
|
{ kind: "ll-server" },
|
|
@@ -11731,6 +11913,46 @@ function SettingsPanel({
|
|
|
11731
11913
|
} else if (r.kind === "self") {
|
|
11732
11914
|
if (!selfProt) return;
|
|
11733
11915
|
run10(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
11916
|
+
} else if (r.kind === "cli-update") {
|
|
11917
|
+
if (updBusy) return;
|
|
11918
|
+
setUpdBusy(true);
|
|
11919
|
+
setMsg({ text: "updating\u2026", level: "ok" });
|
|
11920
|
+
setDiag(null);
|
|
11921
|
+
void (async () => {
|
|
11922
|
+
try {
|
|
11923
|
+
const res = await updateNow();
|
|
11924
|
+
if (res.status === "updated") setMsg({ text: `\u2713 v${res.version} installed \xB7 restart (q, then solongate) to apply`, level: "ok" });
|
|
11925
|
+
else if (res.status === "current") setMsg({ text: `\u2713 already on the latest version (v${res.version})`, level: "ok" });
|
|
11926
|
+
else if (res.status === "needs-admin") {
|
|
11927
|
+
setMsg({ text: `\u2717 v${res.version} needs admin rights \u2014 run the two commands below`, level: "bad" });
|
|
11928
|
+
setDiag({
|
|
11929
|
+
of: "cli-update",
|
|
11930
|
+
lines: [
|
|
11931
|
+
{ text: "npm\u2019s global folder belongs to root on this machine (the usual macOS", level: "warn" },
|
|
11932
|
+
{ text: "setup), so SolonGate cannot install there by itself. In a terminal:", level: "warn" },
|
|
11933
|
+
...adminUpdateSteps().map((s) => ({ text: s.trim(), level: "ok" })),
|
|
11934
|
+
{ text: "run repair WITHOUT sudo, or the guard hooks land in root\u2019s home", level: "dim" }
|
|
11935
|
+
]
|
|
11936
|
+
});
|
|
11937
|
+
} else if (res.status === "unreachable") setMsg({ text: "\u2717 could not reach the npm registry", level: "bad" });
|
|
11938
|
+
else setMsg({ text: `\u2717 update to v${res.version} failed \u2014 see ~/.solongate/self-update.log`, level: "bad" });
|
|
11939
|
+
setLatest(await latestVersion());
|
|
11940
|
+
setCanInstall((await globalInstallCheck()).writable);
|
|
11941
|
+
} finally {
|
|
11942
|
+
setUpdBusy(false);
|
|
11943
|
+
}
|
|
11944
|
+
})();
|
|
11945
|
+
} else if (r.kind === "auto-update") {
|
|
11946
|
+
if (autoUpdateForcedByEnv()) {
|
|
11947
|
+
setMsg({ text: "SOLONGATE_AUTO_UPDATE is set \u2014 unset it to change this here", level: "bad" });
|
|
11948
|
+
return;
|
|
11949
|
+
}
|
|
11950
|
+
const next = !autoUp;
|
|
11951
|
+
setAutoUpdate(next);
|
|
11952
|
+
setAutoUp(next);
|
|
11953
|
+
setMsg(
|
|
11954
|
+
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" }
|
|
11955
|
+
);
|
|
11734
11956
|
} else if (r.kind === "ll-enabled") {
|
|
11735
11957
|
if (!local) return;
|
|
11736
11958
|
if (!local.enabled && !local.path.trim()) {
|
|
@@ -11829,7 +12051,7 @@ function SettingsPanel({
|
|
|
11829
12051
|
if (ok) clearLocalLog();
|
|
11830
12052
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
11831
12053
|
refreshAccounts();
|
|
11832
|
-
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
12054
|
+
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "auto-update" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
11833
12055
|
if (cur.kind === "alert") run10(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
11834
12056
|
else activate(cur);
|
|
11835
12057
|
}
|
|
@@ -12041,6 +12263,25 @@ function SettingsPanel({
|
|
|
12041
12263
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "repair".padEnd(11) }),
|
|
12042
12264
|
diagBusy === "repair" ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: `${spin} restoring protection\u2026` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "restore every protection file after tampering or deletion \xB7 enter runs it" })
|
|
12043
12265
|
] });
|
|
12266
|
+
case "cli-update": {
|
|
12267
|
+
const behind = latest ? newerThan(latest, ver) : false;
|
|
12268
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
12269
|
+
cursor(r),
|
|
12270
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "version".padEnd(11) }),
|
|
12271
|
+
/* @__PURE__ */ jsx8(Text8, { color: behind ? theme.warn : theme.ok, children: `v${ver}` }),
|
|
12272
|
+
updBusy ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: ` ${spin} updating\u2026` }) : behind && canInstall === false ? (
|
|
12273
|
+
// Said before they press enter, not after a minute of npm noise.
|
|
12274
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` v${latest} on npm \xB7 needs sudo here \xB7 enter shows how` })
|
|
12275
|
+
) : 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" })
|
|
12276
|
+
] });
|
|
12277
|
+
}
|
|
12278
|
+
case "auto-update":
|
|
12279
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
12280
|
+
cursor(r),
|
|
12281
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "auto".padEnd(11) }),
|
|
12282
|
+
onOff(autoUp),
|
|
12283
|
+
/* @__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" })
|
|
12284
|
+
] });
|
|
12044
12285
|
case "ll-enabled":
|
|
12045
12286
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
12046
12287
|
cursor(r),
|
|
@@ -12093,10 +12334,11 @@ function SettingsPanel({
|
|
|
12093
12334
|
] });
|
|
12094
12335
|
}
|
|
12095
12336
|
};
|
|
12096
|
-
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" || r.kind === "allowance" ? "ACCOUNTS" : r.kind === "guard" || r.kind === "self" || r.kind === "doctor" || r.kind === "repair" ? "PROTECTION" : r.kind === "ll-enabled" || r.kind === "ll-path" || r.kind === "ll-server" ? "LOCAL LOGS" : r.kind === "wh" || r.kind === "wh-add" ? "WEBHOOKS" : "ALERTS";
|
|
12337
|
+
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" || r.kind === "allowance" ? "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";
|
|
12097
12338
|
const SECTION_DESC = {
|
|
12098
12339
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
12099
12340
|
PROTECTION: "guard hook: enter install/update \xB7 d remove \xB7 self-protection \xB7 doctor + repair",
|
|
12341
|
+
UPDATES: "the solongate CLI itself \xB7 background auto-update is off unless you turn it on",
|
|
12100
12342
|
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
12101
12343
|
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
12102
12344
|
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 m on/off`
|
|
@@ -12137,7 +12379,7 @@ function SettingsPanel({
|
|
|
12137
12379
|
lineKey.push("");
|
|
12138
12380
|
});
|
|
12139
12381
|
}
|
|
12140
|
-
if (diag && (r.kind === "doctor" && diag.of === "doctor" || r.kind === "repair" && diag.of === "repair")) {
|
|
12382
|
+
if (diag && (r.kind === "doctor" && diag.of === "doctor" || r.kind === "repair" && diag.of === "repair" || r.kind === "cli-update" && diag.of === "cli-update")) {
|
|
12141
12383
|
diag.lines.forEach((l, i) => {
|
|
12142
12384
|
lineEls.push(
|
|
12143
12385
|
/* @__PURE__ */ jsx8(
|
|
@@ -12165,7 +12407,7 @@ function SettingsPanel({
|
|
|
12165
12407
|
lineEls.push(
|
|
12166
12408
|
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", color: theme.dim, children: [
|
|
12167
12409
|
`solongate v${ver}`,
|
|
12168
|
-
latest ? newerThan(latest, ver) ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \xB7 v${latest} on npm \u2014 auto-updating` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: " \xB7 latest" }) : null
|
|
12410
|
+
latest ? newerThan(latest, ver) ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \xB7 v${latest} on npm \u2014 ${autoUp ? "auto-updating" : "UPDATES above"}` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: " \xB7 latest" }) : null
|
|
12169
12411
|
] }, "ver")
|
|
12170
12412
|
);
|
|
12171
12413
|
lineKey.push("");
|
|
@@ -12394,7 +12636,7 @@ function App() {
|
|
|
12394
12636
|
// a row off whichever panel is open.
|
|
12395
12637
|
/* @__PURE__ */ jsx9(Text9, { color: theme.bad, bold: true, children: " \xB7 allowance used up \xB7 every call denied \xB7 create an account to carry on" })
|
|
12396
12638
|
) : 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" }),
|
|
12397
|
-
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` }) : null
|
|
12639
|
+
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
|
|
12398
12640
|
] }),
|
|
12399
12641
|
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
12400
12642
|
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", flexShrink: 0, width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
|
@@ -17025,7 +17267,8 @@ function printHelp() {
|
|
|
17025
17267
|
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}`);
|
|
17026
17268
|
head("Setup & status");
|
|
17027
17269
|
cmd("solongate", "open the dataroom UI (login, policies, audit, settings)");
|
|
17028
|
-
cmd("update", "update SolonGate
|
|
17270
|
+
cmd("update", "update SolonGate and refresh the guard (tells you if it needs sudo)");
|
|
17271
|
+
cmd("update auto on|off", "background auto-update (default off \u2014 on macOS npm -g often needs sudo)");
|
|
17029
17272
|
cmd("repair", "restore the guard + hook + settings files if they were deleted or disarmed");
|
|
17030
17273
|
cmd("doctor", "health check: login, policy, guard, local logs");
|
|
17031
17274
|
cmd("doctor --json", "the same health check as machine-readable JSON");
|
|
@@ -17173,6 +17416,10 @@ async function main() {
|
|
|
17173
17416
|
return;
|
|
17174
17417
|
}
|
|
17175
17418
|
if (subcommand === "update") {
|
|
17419
|
+
if (process.argv[3] === "auto") {
|
|
17420
|
+
const { runAutoUpdateCommand: runAutoUpdateCommand2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
17421
|
+
process.exit(await runAutoUpdateCommand2(process.argv[4]));
|
|
17422
|
+
}
|
|
17176
17423
|
const { runUpdateCommand: runUpdateCommand2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
17177
17424
|
process.exit(await runUpdateCommand2());
|
|
17178
17425
|
}
|
package/dist/self-update.d.ts
CHANGED
|
@@ -1,30 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is the background updater turned on? Default: NO — see the file header.
|
|
3
|
+
* SOLONGATE_AUTO_UPDATE=on|off (1/0, true/false) overrides the stored setting
|
|
4
|
+
* for one run, so a CI image or a managed fleet can force either way without
|
|
5
|
+
* writing to the user's home directory.
|
|
6
|
+
*/
|
|
7
|
+
export declare function autoUpdateEnabled(): boolean;
|
|
8
|
+
/** True when the env var is deciding, so the UI can say the row is overridden. */
|
|
9
|
+
export declare function autoUpdateForcedByEnv(): boolean;
|
|
10
|
+
/** Turn the background updater on/off. Clears the "npm refused" memo on enable. */
|
|
11
|
+
export declare function setAutoUpdate(on: boolean): void;
|
|
1
12
|
export declare function currentVersion(): string;
|
|
2
13
|
/** true when `b` is a strictly newer semver than `a` (numeric triples only). */
|
|
3
14
|
export declare function newerThan(b: string, a: string): boolean;
|
|
4
15
|
/** The latest version published to npm, or null if it can't be reached. */
|
|
5
16
|
export declare function latestVersion(): Promise<string | null>;
|
|
6
|
-
/** Foreground global install — resolves true on success, output → update log. */
|
|
7
17
|
/**
|
|
8
|
-
* `solongate update` —
|
|
9
|
-
* background
|
|
10
|
-
* installed guard hooks. Returns a process exit
|
|
18
|
+
* `solongate update` — the normal way to update, and the ONLY way when the
|
|
19
|
+
* background updater is off (which is the default): installs the newest CLI
|
|
20
|
+
* globally, then refreshes the installed guard hooks. Returns a process exit
|
|
21
|
+
* code.
|
|
11
22
|
*/
|
|
12
23
|
export declare function runUpdateCommand(): Promise<number>;
|
|
24
|
+
/** The exact command that fixes a root-owned global prefix. */
|
|
25
|
+
export declare function adminInstallCommand(): string;
|
|
26
|
+
/** Are we root — i.e. did someone run this under sudo? */
|
|
27
|
+
export declare function runningAsRoot(): boolean;
|
|
28
|
+
export declare function globalInstallCheck(): Promise<{
|
|
29
|
+
writable: boolean | null;
|
|
30
|
+
dir: string | null;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* The two commands that update SolonGate on a machine whose global npm folder
|
|
34
|
+
* belongs to root. `repair` is deliberately NOT under sudo: it writes the guard
|
|
35
|
+
* hooks into the invoking user's home, so as root it would arm root's home and
|
|
36
|
+
* leave the actual user unguarded.
|
|
37
|
+
*/
|
|
38
|
+
export declare function adminUpdateSteps(): string[];
|
|
39
|
+
/**
|
|
40
|
+
* Install the newest version NOW, whatever the auto-update setting says — the
|
|
41
|
+
* dataroom's UPDATES row and `solongate update` both run through here.
|
|
42
|
+
*/
|
|
43
|
+
export declare function updateNow(): Promise<{
|
|
44
|
+
status: 'updated' | 'current' | 'needs-admin' | 'unreachable' | 'failed';
|
|
45
|
+
version: string;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* `solongate update auto [on|off]` — show or change the background updater.
|
|
49
|
+
* Kept separate from `runUpdateCommand` so `solongate update` stays "update me
|
|
50
|
+
* now" and never changes a setting as a side effect.
|
|
51
|
+
*/
|
|
52
|
+
export declare function runAutoUpdateCommand(arg?: string): Promise<number>;
|
|
13
53
|
/** What the dataroom shows about the updater. */
|
|
14
54
|
export type UpdateStatus = {
|
|
15
55
|
kind: 'idle';
|
|
56
|
+
} | {
|
|
57
|
+
kind: 'available';
|
|
58
|
+
version: string;
|
|
16
59
|
} | {
|
|
17
60
|
kind: 'updating';
|
|
18
61
|
version: string;
|
|
19
62
|
} | {
|
|
20
63
|
kind: 'updated';
|
|
21
64
|
version: string;
|
|
65
|
+
} | {
|
|
66
|
+
kind: 'needs-admin';
|
|
67
|
+
version: string;
|
|
22
68
|
};
|
|
23
69
|
/**
|
|
24
|
-
* The dataroom's updater
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
70
|
+
* The dataroom's updater: check the registry EVERY time the TUI opens (and
|
|
71
|
+
* periodically while it stays open). With auto-update ON, install in the
|
|
72
|
+
* background and ask for a restart; with it OFF (the default), only report that
|
|
73
|
+
* a version is available. `onStatus` drives the in-app status line; nothing is
|
|
74
|
+
* ever written to the terminal directly.
|
|
28
75
|
*/
|
|
29
76
|
export declare function tuiUpdateFlow(onStatus: (s: UpdateStatus) => void): Promise<void>;
|
|
30
77
|
/**
|
package/dist/tui/index.js
CHANGED
|
@@ -4495,15 +4495,16 @@ function stopLogsServerDaemon() {
|
|
|
4495
4495
|
|
|
4496
4496
|
// src/self-update.ts
|
|
4497
4497
|
import { execFile, execFileSync as execFileSync2, spawn as spawn4 } from "child_process";
|
|
4498
|
-
import { mkdirSync as mkdirSync6, openSync as openSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
4498
|
+
import { access, mkdirSync as mkdirSync6, openSync as openSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync7, constants as FS } from "fs";
|
|
4499
4499
|
import { homedir as homedir9 } from "os";
|
|
4500
|
-
import { dirname as dirname3, join as join9 } from "path";
|
|
4500
|
+
import { dirname as dirname3, join as join9, sep } from "path";
|
|
4501
4501
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4502
4502
|
var PKG = "@solongate/proxy";
|
|
4503
4503
|
var CHECK_EVERY_MS = 30 * 60 * 1e3;
|
|
4504
4504
|
var ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
4505
4505
|
var STATE_FILE2 = join9(homedir9(), ".solongate", ".self-update.json");
|
|
4506
4506
|
var LOG_FILE2 = join9(homedir9(), ".solongate", "self-update.log");
|
|
4507
|
+
var NEEDS_ADMIN_RE = /\bEACCES\b|\bEPERM\b|permission denied|operation not permitted/i;
|
|
4507
4508
|
function readState2() {
|
|
4508
4509
|
try {
|
|
4509
4510
|
const s = JSON.parse(readFileSync7(STATE_FILE2, "utf-8"));
|
|
@@ -4519,6 +4520,20 @@ function writeState2(s) {
|
|
|
4519
4520
|
} catch {
|
|
4520
4521
|
}
|
|
4521
4522
|
}
|
|
4523
|
+
function autoUpdateEnabled() {
|
|
4524
|
+
const env = (process.env.SOLONGATE_AUTO_UPDATE ?? "").trim().toLowerCase();
|
|
4525
|
+
if (env === "1" || env === "true" || env === "on" || env === "yes") return true;
|
|
4526
|
+
if (env === "0" || env === "false" || env === "off" || env === "no") return false;
|
|
4527
|
+
return readState2().auto === true;
|
|
4528
|
+
}
|
|
4529
|
+
function autoUpdateForcedByEnv() {
|
|
4530
|
+
const env = (process.env.SOLONGATE_AUTO_UPDATE ?? "").trim().toLowerCase();
|
|
4531
|
+
return ["1", "true", "on", "yes", "0", "false", "off", "no"].includes(env);
|
|
4532
|
+
}
|
|
4533
|
+
function setAutoUpdate(on) {
|
|
4534
|
+
const s = readState2();
|
|
4535
|
+
writeState2(on ? { ...s, auto: true, needsAdmin: void 0 } : { ...s, auto: false });
|
|
4536
|
+
}
|
|
4522
4537
|
function currentVersion() {
|
|
4523
4538
|
try {
|
|
4524
4539
|
const pkg = JSON.parse(readFileSync7(join9(dirname3(fileURLToPath3(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
@@ -4564,20 +4579,70 @@ function runGlobalInstall(version) {
|
|
|
4564
4579
|
["install", "-g", `${PKG}@${version}`],
|
|
4565
4580
|
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
4566
4581
|
(err2, stdout, stderr) => {
|
|
4582
|
+
const output = `${stdout}
|
|
4583
|
+
${stderr}`;
|
|
4567
4584
|
try {
|
|
4568
4585
|
writeFileSync7(LOG_FILE2, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err2 ? "FAILED" : "ok"}
|
|
4569
|
-
${
|
|
4570
|
-
${stderr}
|
|
4586
|
+
${output}
|
|
4571
4587
|
`, { flag: "a" });
|
|
4572
4588
|
} catch {
|
|
4573
4589
|
}
|
|
4574
|
-
resolve3(!err2);
|
|
4590
|
+
resolve3({ ok: !err2, needsAdmin: !!err2 && NEEDS_ADMIN_RE.test(output) });
|
|
4575
4591
|
}
|
|
4576
4592
|
);
|
|
4577
4593
|
} catch {
|
|
4578
|
-
resolve3(false);
|
|
4594
|
+
resolve3({ ok: false, needsAdmin: false });
|
|
4595
|
+
}
|
|
4596
|
+
});
|
|
4597
|
+
}
|
|
4598
|
+
function adminInstallCommand() {
|
|
4599
|
+
return process.platform === "win32" ? `npm i -g ${PKG}@latest (in an Administrator terminal)` : `sudo npm i -g ${PKG}@latest`;
|
|
4600
|
+
}
|
|
4601
|
+
function ownNodeModules() {
|
|
4602
|
+
let dir = dirname3(fileURLToPath3(import.meta.url));
|
|
4603
|
+
for (let i = 0; i < 12; i++) {
|
|
4604
|
+
const parent = dirname3(dir);
|
|
4605
|
+
if (parent === dir) break;
|
|
4606
|
+
if (dir.endsWith(`${sep}node_modules`)) return dir;
|
|
4607
|
+
dir = parent;
|
|
4608
|
+
}
|
|
4609
|
+
return null;
|
|
4610
|
+
}
|
|
4611
|
+
var prefixCheck = null;
|
|
4612
|
+
function globalInstallCheck() {
|
|
4613
|
+
prefixCheck ??= new Promise((resolve3) => {
|
|
4614
|
+
try {
|
|
4615
|
+
const dir = ownNodeModules();
|
|
4616
|
+
if (!dir) return resolve3({ writable: null, dir: null });
|
|
4617
|
+
access(dir, FS.W_OK, (e) => resolve3({ writable: !e, dir }));
|
|
4618
|
+
} catch {
|
|
4619
|
+
resolve3({ writable: null, dir: null });
|
|
4579
4620
|
}
|
|
4580
4621
|
});
|
|
4622
|
+
return prefixCheck;
|
|
4623
|
+
}
|
|
4624
|
+
function adminUpdateSteps() {
|
|
4625
|
+
return [` ${adminInstallCommand()}`, ` solongate repair${process.platform === "win32" ? "" : " (this one WITHOUT sudo)"}`];
|
|
4626
|
+
}
|
|
4627
|
+
async function updateNow() {
|
|
4628
|
+
const cur = currentVersion();
|
|
4629
|
+
const latest = await fetchLatest();
|
|
4630
|
+
if (!latest) return { status: "unreachable", version: cur };
|
|
4631
|
+
if (!newerThan(latest, cur)) return { status: "current", version: cur };
|
|
4632
|
+
if ((await globalInstallCheck()).writable === false) {
|
|
4633
|
+
writeState2({ ...readState2(), needsAdmin: latest });
|
|
4634
|
+
return { status: "needs-admin", version: latest };
|
|
4635
|
+
}
|
|
4636
|
+
const r = await runGlobalInstall(latest);
|
|
4637
|
+
if (r.ok) {
|
|
4638
|
+
writeState2({ ...readState2(), installed: latest, needsAdmin: void 0 });
|
|
4639
|
+
return { status: "updated", version: latest };
|
|
4640
|
+
}
|
|
4641
|
+
if (r.needsAdmin) {
|
|
4642
|
+
writeState2({ ...readState2(), needsAdmin: latest });
|
|
4643
|
+
return { status: "needs-admin", version: latest };
|
|
4644
|
+
}
|
|
4645
|
+
return { status: "failed", version: latest };
|
|
4581
4646
|
}
|
|
4582
4647
|
async function tuiUpdateFlow(onStatus) {
|
|
4583
4648
|
try {
|
|
@@ -4590,10 +4655,22 @@ async function tuiUpdateFlow(onStatus) {
|
|
|
4590
4655
|
onStatus({ kind: "updated", version: latest });
|
|
4591
4656
|
return;
|
|
4592
4657
|
}
|
|
4658
|
+
if (!autoUpdateEnabled()) {
|
|
4659
|
+
onStatus({ kind: "available", version: latest });
|
|
4660
|
+
return;
|
|
4661
|
+
}
|
|
4662
|
+
if (readState2().needsAdmin === latest) {
|
|
4663
|
+
onStatus({ kind: "needs-admin", version: latest });
|
|
4664
|
+
return;
|
|
4665
|
+
}
|
|
4593
4666
|
onStatus({ kind: "updating", version: latest });
|
|
4594
|
-
|
|
4595
|
-
|
|
4667
|
+
const r = await runGlobalInstall(latest);
|
|
4668
|
+
if (r.ok) {
|
|
4669
|
+
writeState2({ ...readState2(), installed: latest, needsAdmin: void 0 });
|
|
4596
4670
|
onStatus({ kind: "updated", version: latest });
|
|
4671
|
+
} else if (r.needsAdmin) {
|
|
4672
|
+
writeState2({ ...readState2(), needsAdmin: latest });
|
|
4673
|
+
onStatus({ kind: "needs-admin", version: latest });
|
|
4597
4674
|
}
|
|
4598
4675
|
} catch {
|
|
4599
4676
|
}
|
|
@@ -4654,6 +4731,19 @@ function SettingsPanel({
|
|
|
4654
4731
|
const [editor, setEditor] = useState8(null);
|
|
4655
4732
|
const [latest, setLatest] = useState8(null);
|
|
4656
4733
|
const [diagBusy, setDiagBusy] = useState8(null);
|
|
4734
|
+
const [autoUp, setAutoUp] = useState8(() => autoUpdateEnabled());
|
|
4735
|
+
const [updBusy, setUpdBusy] = useState8(false);
|
|
4736
|
+
const [canInstall, setCanInstall] = useState8(null);
|
|
4737
|
+
useEffect7(() => {
|
|
4738
|
+
let live2 = true;
|
|
4739
|
+
globalInstallCheck().then((r) => {
|
|
4740
|
+
if (live2) setCanInstall(r.writable);
|
|
4741
|
+
}).catch(() => {
|
|
4742
|
+
});
|
|
4743
|
+
return () => {
|
|
4744
|
+
live2 = false;
|
|
4745
|
+
};
|
|
4746
|
+
}, []);
|
|
4657
4747
|
const [diag, setDiag] = useState8(null);
|
|
4658
4748
|
const [diagStep, setDiagStep] = useState8(0);
|
|
4659
4749
|
const DIAG_STEPS = {
|
|
@@ -4711,10 +4801,10 @@ function SettingsPanel({
|
|
|
4711
4801
|
}, []);
|
|
4712
4802
|
useEffect7(() => {
|
|
4713
4803
|
const loggingIn = login && login.phase !== "done" && login.phase !== "error";
|
|
4714
|
-
if (!loggingIn && !diagBusy) return;
|
|
4804
|
+
if (!loggingIn && !diagBusy && !updBusy) return;
|
|
4715
4805
|
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
4716
4806
|
return () => clearInterval(t);
|
|
4717
|
-
}, [login, diagBusy]);
|
|
4807
|
+
}, [login, diagBusy, updBusy]);
|
|
4718
4808
|
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
4719
4809
|
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
4720
4810
|
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
@@ -4748,6 +4838,8 @@ function SettingsPanel({
|
|
|
4748
4838
|
{ kind: "self" },
|
|
4749
4839
|
{ kind: "doctor" },
|
|
4750
4840
|
{ kind: "repair" },
|
|
4841
|
+
{ kind: "cli-update" },
|
|
4842
|
+
{ kind: "auto-update" },
|
|
4751
4843
|
{ kind: "ll-enabled" },
|
|
4752
4844
|
{ kind: "ll-path" },
|
|
4753
4845
|
{ kind: "ll-server" },
|
|
@@ -4927,6 +5019,46 @@ function SettingsPanel({
|
|
|
4927
5019
|
} else if (r.kind === "self") {
|
|
4928
5020
|
if (!selfProt) return;
|
|
4929
5021
|
run(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
5022
|
+
} else if (r.kind === "cli-update") {
|
|
5023
|
+
if (updBusy) return;
|
|
5024
|
+
setUpdBusy(true);
|
|
5025
|
+
setMsg({ text: "updating\u2026", level: "ok" });
|
|
5026
|
+
setDiag(null);
|
|
5027
|
+
void (async () => {
|
|
5028
|
+
try {
|
|
5029
|
+
const res = await updateNow();
|
|
5030
|
+
if (res.status === "updated") setMsg({ text: `\u2713 v${res.version} installed \xB7 restart (q, then solongate) to apply`, level: "ok" });
|
|
5031
|
+
else if (res.status === "current") setMsg({ text: `\u2713 already on the latest version (v${res.version})`, level: "ok" });
|
|
5032
|
+
else if (res.status === "needs-admin") {
|
|
5033
|
+
setMsg({ text: `\u2717 v${res.version} needs admin rights \u2014 run the two commands below`, level: "bad" });
|
|
5034
|
+
setDiag({
|
|
5035
|
+
of: "cli-update",
|
|
5036
|
+
lines: [
|
|
5037
|
+
{ text: "npm\u2019s global folder belongs to root on this machine (the usual macOS", level: "warn" },
|
|
5038
|
+
{ text: "setup), so SolonGate cannot install there by itself. In a terminal:", level: "warn" },
|
|
5039
|
+
...adminUpdateSteps().map((s) => ({ text: s.trim(), level: "ok" })),
|
|
5040
|
+
{ text: "run repair WITHOUT sudo, or the guard hooks land in root\u2019s home", level: "dim" }
|
|
5041
|
+
]
|
|
5042
|
+
});
|
|
5043
|
+
} else if (res.status === "unreachable") setMsg({ text: "\u2717 could not reach the npm registry", level: "bad" });
|
|
5044
|
+
else setMsg({ text: `\u2717 update to v${res.version} failed \u2014 see ~/.solongate/self-update.log`, level: "bad" });
|
|
5045
|
+
setLatest(await latestVersion());
|
|
5046
|
+
setCanInstall((await globalInstallCheck()).writable);
|
|
5047
|
+
} finally {
|
|
5048
|
+
setUpdBusy(false);
|
|
5049
|
+
}
|
|
5050
|
+
})();
|
|
5051
|
+
} else if (r.kind === "auto-update") {
|
|
5052
|
+
if (autoUpdateForcedByEnv()) {
|
|
5053
|
+
setMsg({ text: "SOLONGATE_AUTO_UPDATE is set \u2014 unset it to change this here", level: "bad" });
|
|
5054
|
+
return;
|
|
5055
|
+
}
|
|
5056
|
+
const next = !autoUp;
|
|
5057
|
+
setAutoUpdate(next);
|
|
5058
|
+
setAutoUp(next);
|
|
5059
|
+
setMsg(
|
|
5060
|
+
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" }
|
|
5061
|
+
);
|
|
4930
5062
|
} else if (r.kind === "ll-enabled") {
|
|
4931
5063
|
if (!local) return;
|
|
4932
5064
|
if (!local.enabled && !local.path.trim()) {
|
|
@@ -5025,7 +5157,7 @@ function SettingsPanel({
|
|
|
5025
5157
|
if (ok) clearLocalLog();
|
|
5026
5158
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
5027
5159
|
refreshAccounts();
|
|
5028
|
-
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
5160
|
+
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "auto-update" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
5029
5161
|
if (cur.kind === "alert") run(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
5030
5162
|
else activate(cur);
|
|
5031
5163
|
}
|
|
@@ -5237,6 +5369,25 @@ function SettingsPanel({
|
|
|
5237
5369
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "repair".padEnd(11) }),
|
|
5238
5370
|
diagBusy === "repair" ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: `${spin} restoring protection\u2026` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "restore every protection file after tampering or deletion \xB7 enter runs it" })
|
|
5239
5371
|
] });
|
|
5372
|
+
case "cli-update": {
|
|
5373
|
+
const behind = latest ? newerThan(latest, ver) : false;
|
|
5374
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
5375
|
+
cursor(r),
|
|
5376
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "version".padEnd(11) }),
|
|
5377
|
+
/* @__PURE__ */ jsx8(Text8, { color: behind ? theme.warn : theme.ok, children: `v${ver}` }),
|
|
5378
|
+
updBusy ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: ` ${spin} updating\u2026` }) : behind && canInstall === false ? (
|
|
5379
|
+
// Said before they press enter, not after a minute of npm noise.
|
|
5380
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` v${latest} on npm \xB7 needs sudo here \xB7 enter shows how` })
|
|
5381
|
+
) : 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" })
|
|
5382
|
+
] });
|
|
5383
|
+
}
|
|
5384
|
+
case "auto-update":
|
|
5385
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
5386
|
+
cursor(r),
|
|
5387
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "auto".padEnd(11) }),
|
|
5388
|
+
onOff(autoUp),
|
|
5389
|
+
/* @__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" })
|
|
5390
|
+
] });
|
|
5240
5391
|
case "ll-enabled":
|
|
5241
5392
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
5242
5393
|
cursor(r),
|
|
@@ -5289,10 +5440,11 @@ function SettingsPanel({
|
|
|
5289
5440
|
] });
|
|
5290
5441
|
}
|
|
5291
5442
|
};
|
|
5292
|
-
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" || r.kind === "allowance" ? "ACCOUNTS" : r.kind === "guard" || r.kind === "self" || r.kind === "doctor" || r.kind === "repair" ? "PROTECTION" : r.kind === "ll-enabled" || r.kind === "ll-path" || r.kind === "ll-server" ? "LOCAL LOGS" : r.kind === "wh" || r.kind === "wh-add" ? "WEBHOOKS" : "ALERTS";
|
|
5443
|
+
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" || r.kind === "allowance" ? "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";
|
|
5293
5444
|
const SECTION_DESC = {
|
|
5294
5445
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
5295
5446
|
PROTECTION: "guard hook: enter install/update \xB7 d remove \xB7 self-protection \xB7 doctor + repair",
|
|
5447
|
+
UPDATES: "the solongate CLI itself \xB7 background auto-update is off unless you turn it on",
|
|
5296
5448
|
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
5297
5449
|
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
5298
5450
|
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 m on/off`
|
|
@@ -5333,7 +5485,7 @@ function SettingsPanel({
|
|
|
5333
5485
|
lineKey.push("");
|
|
5334
5486
|
});
|
|
5335
5487
|
}
|
|
5336
|
-
if (diag && (r.kind === "doctor" && diag.of === "doctor" || r.kind === "repair" && diag.of === "repair")) {
|
|
5488
|
+
if (diag && (r.kind === "doctor" && diag.of === "doctor" || r.kind === "repair" && diag.of === "repair" || r.kind === "cli-update" && diag.of === "cli-update")) {
|
|
5337
5489
|
diag.lines.forEach((l, i) => {
|
|
5338
5490
|
lineEls.push(
|
|
5339
5491
|
/* @__PURE__ */ jsx8(
|
|
@@ -5361,7 +5513,7 @@ function SettingsPanel({
|
|
|
5361
5513
|
lineEls.push(
|
|
5362
5514
|
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", color: theme.dim, children: [
|
|
5363
5515
|
`solongate v${ver}`,
|
|
5364
|
-
latest ? newerThan(latest, ver) ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \xB7 v${latest} on npm \u2014 auto-updating` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: " \xB7 latest" }) : null
|
|
5516
|
+
latest ? newerThan(latest, ver) ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \xB7 v${latest} on npm \u2014 ${autoUp ? "auto-updating" : "UPDATES above"}` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: " \xB7 latest" }) : null
|
|
5365
5517
|
] }, "ver")
|
|
5366
5518
|
);
|
|
5367
5519
|
lineKey.push("");
|
|
@@ -5566,7 +5718,7 @@ function App() {
|
|
|
5566
5718
|
// a row off whichever panel is open.
|
|
5567
5719
|
/* @__PURE__ */ jsx9(Text9, { color: theme.bad, bold: true, children: " \xB7 allowance used up \xB7 every call denied \xB7 create an account to carry on" })
|
|
5568
5720
|
) : 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" }),
|
|
5569
|
-
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` }) : null
|
|
5721
|
+
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
|
|
5570
5722
|
] }),
|
|
5571
5723
|
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
5572
5724
|
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", flexShrink: 0, width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.83.
|
|
3
|
+
"version": "0.83.4",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|