@solongate/proxy 0.83.3 → 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 +138 -28
- package/dist/self-update.d.ts +14 -1
- package/dist/tui/index.js +64 -8
- 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");
|
|
@@ -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
|
|
|
@@ -11543,6 +11627,17 @@ function SettingsPanel({
|
|
|
11543
11627
|
const [diagBusy, setDiagBusy] = useState8(null);
|
|
11544
11628
|
const [autoUp, setAutoUp] = useState8(() => autoUpdateEnabled());
|
|
11545
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
|
+
}, []);
|
|
11546
11641
|
const [diag, setDiag] = useState8(null);
|
|
11547
11642
|
const [diagStep, setDiagStep] = useState8(0);
|
|
11548
11643
|
const DIAG_STEPS = {
|
|
@@ -11822,15 +11917,27 @@ function SettingsPanel({
|
|
|
11822
11917
|
if (updBusy) return;
|
|
11823
11918
|
setUpdBusy(true);
|
|
11824
11919
|
setMsg({ text: "updating\u2026", level: "ok" });
|
|
11920
|
+
setDiag(null);
|
|
11825
11921
|
void (async () => {
|
|
11826
11922
|
try {
|
|
11827
11923
|
const res = await updateNow();
|
|
11828
11924
|
if (res.status === "updated") setMsg({ text: `\u2713 v${res.version} installed \xB7 restart (q, then solongate) to apply`, level: "ok" });
|
|
11829
11925
|
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
|
-
|
|
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" });
|
|
11832
11938
|
else setMsg({ text: `\u2717 update to v${res.version} failed \u2014 see ~/.solongate/self-update.log`, level: "bad" });
|
|
11833
11939
|
setLatest(await latestVersion());
|
|
11940
|
+
setCanInstall((await globalInstallCheck()).writable);
|
|
11834
11941
|
} finally {
|
|
11835
11942
|
setUpdBusy(false);
|
|
11836
11943
|
}
|
|
@@ -11844,7 +11951,7 @@ function SettingsPanel({
|
|
|
11844
11951
|
setAutoUpdate(next);
|
|
11845
11952
|
setAutoUp(next);
|
|
11846
11953
|
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" }
|
|
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" }
|
|
11848
11955
|
);
|
|
11849
11956
|
} else if (r.kind === "ll-enabled") {
|
|
11850
11957
|
if (!local) return;
|
|
@@ -12162,7 +12269,10 @@ function SettingsPanel({
|
|
|
12162
12269
|
cursor(r),
|
|
12163
12270
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "version".padEnd(11) }),
|
|
12164
12271
|
/* @__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
|
|
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" })
|
|
12166
12276
|
] });
|
|
12167
12277
|
}
|
|
12168
12278
|
case "auto-update":
|
|
@@ -12170,7 +12280,7 @@ function SettingsPanel({
|
|
|
12170
12280
|
cursor(r),
|
|
12171
12281
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "auto".padEnd(11) }),
|
|
12172
12282
|
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" })
|
|
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" })
|
|
12174
12284
|
] });
|
|
12175
12285
|
case "ll-enabled":
|
|
12176
12286
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
@@ -12269,7 +12379,7 @@ function SettingsPanel({
|
|
|
12269
12379
|
lineKey.push("");
|
|
12270
12380
|
});
|
|
12271
12381
|
}
|
|
12272
|
-
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")) {
|
|
12273
12383
|
diag.lines.forEach((l, i) => {
|
|
12274
12384
|
lineEls.push(
|
|
12275
12385
|
/* @__PURE__ */ jsx8(
|
|
@@ -17157,7 +17267,7 @@ function printHelp() {
|
|
|
17157
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}`);
|
|
17158
17268
|
head("Setup & status");
|
|
17159
17269
|
cmd("solongate", "open the dataroom UI (login, policies, audit, settings)");
|
|
17160
|
-
cmd("update", "update SolonGate
|
|
17270
|
+
cmd("update", "update SolonGate and refresh the guard (tells you if it needs sudo)");
|
|
17161
17271
|
cmd("update auto on|off", "background auto-update (default off \u2014 on macOS npm -g often needs sudo)");
|
|
17162
17272
|
cmd("repair", "restore the guard + hook + settings files if they were deleted or disarmed");
|
|
17163
17273
|
cmd("doctor", "health check: login, policy, guard, local logs");
|
|
@@ -17308,7 +17418,7 @@ async function main() {
|
|
|
17308
17418
|
if (subcommand === "update") {
|
|
17309
17419
|
if (process.argv[3] === "auto") {
|
|
17310
17420
|
const { runAutoUpdateCommand: runAutoUpdateCommand2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
17311
|
-
process.exit(runAutoUpdateCommand2(process.argv[4]));
|
|
17421
|
+
process.exit(await runAutoUpdateCommand2(process.argv[4]));
|
|
17312
17422
|
}
|
|
17313
17423
|
const { runUpdateCommand: runUpdateCommand2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
17314
17424
|
process.exit(await runUpdateCommand2());
|
package/dist/self-update.d.ts
CHANGED
|
@@ -23,6 +23,19 @@ export declare function latestVersion(): Promise<string | null>;
|
|
|
23
23
|
export declare function runUpdateCommand(): Promise<number>;
|
|
24
24
|
/** The exact command that fixes a root-owned global prefix. */
|
|
25
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[];
|
|
26
39
|
/**
|
|
27
40
|
* Install the newest version NOW, whatever the auto-update setting says — the
|
|
28
41
|
* dataroom's UPDATES row and `solongate update` both run through here.
|
|
@@ -36,7 +49,7 @@ export declare function updateNow(): Promise<{
|
|
|
36
49
|
* Kept separate from `runUpdateCommand` so `solongate update` stays "update me
|
|
37
50
|
* now" and never changes a setting as a side effect.
|
|
38
51
|
*/
|
|
39
|
-
export declare function runAutoUpdateCommand(arg?: string): number
|
|
52
|
+
export declare function runAutoUpdateCommand(arg?: string): Promise<number>;
|
|
40
53
|
/** What the dataroom shows about the updater. */
|
|
41
54
|
export type UpdateStatus = {
|
|
42
55
|
kind: 'idle';
|
package/dist/tui/index.js
CHANGED
|
@@ -4495,9 +4495,9 @@ 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;
|
|
@@ -4598,11 +4598,41 @@ ${output}
|
|
|
4598
4598
|
function adminInstallCommand() {
|
|
4599
4599
|
return process.platform === "win32" ? `npm i -g ${PKG}@latest (in an Administrator terminal)` : `sudo npm i -g ${PKG}@latest`;
|
|
4600
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 });
|
|
4620
|
+
}
|
|
4621
|
+
});
|
|
4622
|
+
return prefixCheck;
|
|
4623
|
+
}
|
|
4624
|
+
function adminUpdateSteps() {
|
|
4625
|
+
return [` ${adminInstallCommand()}`, ` solongate repair${process.platform === "win32" ? "" : " (this one WITHOUT sudo)"}`];
|
|
4626
|
+
}
|
|
4601
4627
|
async function updateNow() {
|
|
4602
4628
|
const cur = currentVersion();
|
|
4603
4629
|
const latest = await fetchLatest();
|
|
4604
4630
|
if (!latest) return { status: "unreachable", version: cur };
|
|
4605
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
|
+
}
|
|
4606
4636
|
const r = await runGlobalInstall(latest);
|
|
4607
4637
|
if (r.ok) {
|
|
4608
4638
|
writeState2({ ...readState2(), installed: latest, needsAdmin: void 0 });
|
|
@@ -4703,6 +4733,17 @@ function SettingsPanel({
|
|
|
4703
4733
|
const [diagBusy, setDiagBusy] = useState8(null);
|
|
4704
4734
|
const [autoUp, setAutoUp] = useState8(() => autoUpdateEnabled());
|
|
4705
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
|
+
}, []);
|
|
4706
4747
|
const [diag, setDiag] = useState8(null);
|
|
4707
4748
|
const [diagStep, setDiagStep] = useState8(0);
|
|
4708
4749
|
const DIAG_STEPS = {
|
|
@@ -4982,15 +5023,27 @@ function SettingsPanel({
|
|
|
4982
5023
|
if (updBusy) return;
|
|
4983
5024
|
setUpdBusy(true);
|
|
4984
5025
|
setMsg({ text: "updating\u2026", level: "ok" });
|
|
5026
|
+
setDiag(null);
|
|
4985
5027
|
void (async () => {
|
|
4986
5028
|
try {
|
|
4987
5029
|
const res = await updateNow();
|
|
4988
5030
|
if (res.status === "updated") setMsg({ text: `\u2713 v${res.version} installed \xB7 restart (q, then solongate) to apply`, level: "ok" });
|
|
4989
5031
|
else if (res.status === "current") setMsg({ text: `\u2713 already on the latest version (v${res.version})`, level: "ok" });
|
|
4990
|
-
else if (res.status === "needs-admin")
|
|
4991
|
-
|
|
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" });
|
|
4992
5044
|
else setMsg({ text: `\u2717 update to v${res.version} failed \u2014 see ~/.solongate/self-update.log`, level: "bad" });
|
|
4993
5045
|
setLatest(await latestVersion());
|
|
5046
|
+
setCanInstall((await globalInstallCheck()).writable);
|
|
4994
5047
|
} finally {
|
|
4995
5048
|
setUpdBusy(false);
|
|
4996
5049
|
}
|
|
@@ -5004,7 +5057,7 @@ function SettingsPanel({
|
|
|
5004
5057
|
setAutoUpdate(next);
|
|
5005
5058
|
setAutoUp(next);
|
|
5006
5059
|
setMsg(
|
|
5007
|
-
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" }
|
|
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" }
|
|
5008
5061
|
);
|
|
5009
5062
|
} else if (r.kind === "ll-enabled") {
|
|
5010
5063
|
if (!local) return;
|
|
@@ -5322,7 +5375,10 @@ function SettingsPanel({
|
|
|
5322
5375
|
cursor(r),
|
|
5323
5376
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "version".padEnd(11) }),
|
|
5324
5377
|
/* @__PURE__ */ jsx8(Text8, { color: behind ? theme.warn : theme.ok, children: `v${ver}` }),
|
|
5325
|
-
updBusy ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: ` ${spin} updating\u2026` }) : behind
|
|
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" })
|
|
5326
5382
|
] });
|
|
5327
5383
|
}
|
|
5328
5384
|
case "auto-update":
|
|
@@ -5330,7 +5386,7 @@ function SettingsPanel({
|
|
|
5330
5386
|
cursor(r),
|
|
5331
5387
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "auto".padEnd(11) }),
|
|
5332
5388
|
onOff(autoUp),
|
|
5333
|
-
/* @__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" })
|
|
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" })
|
|
5334
5390
|
] });
|
|
5335
5391
|
case "ll-enabled":
|
|
5336
5392
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
@@ -5429,7 +5485,7 @@ function SettingsPanel({
|
|
|
5429
5485
|
lineKey.push("");
|
|
5430
5486
|
});
|
|
5431
5487
|
}
|
|
5432
|
-
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")) {
|
|
5433
5489
|
diag.lines.forEach((l, i) => {
|
|
5434
5490
|
lineEls.push(
|
|
5435
5491
|
/* @__PURE__ */ jsx8(
|
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": {
|