@solongate/proxy 0.81.46 → 0.81.48
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 +12 -0
- package/dist/api-client/index.d.ts +2 -0
- package/dist/commands/index.js +10 -1
- package/dist/index.js +104 -12
- package/dist/self-update.d.ts +20 -0
- package/dist/tui/index.js +168 -11
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export * from './client.js';
|
|
6
6
|
export * from './types.js';
|
|
7
7
|
export * from './device-login.js';
|
|
8
|
+
import * as auth from './auth.js';
|
|
8
9
|
import * as policies from './policies.js';
|
|
9
10
|
import * as settings from './settings.js';
|
|
10
11
|
import * as stats from './stats.js';
|
|
@@ -13,6 +14,7 @@ import * as agents from './agents.js';
|
|
|
13
14
|
import * as keys from './keys.js';
|
|
14
15
|
import * as mcp from './mcp.js';
|
|
15
16
|
export declare const api: {
|
|
17
|
+
auth: typeof auth;
|
|
16
18
|
policies: typeof policies;
|
|
17
19
|
settings: typeof settings;
|
|
18
20
|
stats: typeof stats;
|
package/dist/commands/index.js
CHANGED
|
@@ -142,6 +142,15 @@ async function request(method, path, opts = {}) {
|
|
|
142
142
|
// src/api-client/device-login.ts
|
|
143
143
|
import { spawn } from "child_process";
|
|
144
144
|
|
|
145
|
+
// src/api-client/auth.ts
|
|
146
|
+
var auth_exports = {};
|
|
147
|
+
__export(auth_exports, {
|
|
148
|
+
me: () => me
|
|
149
|
+
});
|
|
150
|
+
function me() {
|
|
151
|
+
return request("GET", "/auth/me");
|
|
152
|
+
}
|
|
153
|
+
|
|
145
154
|
// src/api-client/policies.ts
|
|
146
155
|
var policies_exports = {};
|
|
147
156
|
__export(policies_exports, {
|
|
@@ -364,7 +373,7 @@ function list4() {
|
|
|
364
373
|
}
|
|
365
374
|
|
|
366
375
|
// src/api-client/index.ts
|
|
367
|
-
var api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
376
|
+
var api = { auth: auth_exports, policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
368
377
|
|
|
369
378
|
// src/cli-utils.ts
|
|
370
379
|
var c = {
|
package/dist/index.js
CHANGED
|
@@ -6558,7 +6558,8 @@ var init_cli_utils = __esm({
|
|
|
6558
6558
|
var self_update_exports = {};
|
|
6559
6559
|
__export(self_update_exports, {
|
|
6560
6560
|
currentVersion: () => currentVersion,
|
|
6561
|
-
maybeSelfUpdate: () => maybeSelfUpdate
|
|
6561
|
+
maybeSelfUpdate: () => maybeSelfUpdate,
|
|
6562
|
+
tuiUpdateFlow: () => tuiUpdateFlow
|
|
6562
6563
|
});
|
|
6563
6564
|
import { execFile, spawn } from "child_process";
|
|
6564
6565
|
import { mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync4, realpathSync, writeFileSync as writeFileSync3 } from "fs";
|
|
@@ -6647,6 +6648,51 @@ function spawnGlobalInstall(version) {
|
|
|
6647
6648
|
return false;
|
|
6648
6649
|
}
|
|
6649
6650
|
}
|
|
6651
|
+
function runGlobalInstall(version) {
|
|
6652
|
+
return new Promise((resolve10) => {
|
|
6653
|
+
try {
|
|
6654
|
+
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6655
|
+
execFile(
|
|
6656
|
+
"npm",
|
|
6657
|
+
["install", "-g", `${PKG}@${version}`],
|
|
6658
|
+
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
6659
|
+
(err2, stdout, stderr) => {
|
|
6660
|
+
try {
|
|
6661
|
+
writeFileSync3(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err2 ? "FAILED" : "ok"}
|
|
6662
|
+
${stdout}
|
|
6663
|
+
${stderr}
|
|
6664
|
+
`, { flag: "a" });
|
|
6665
|
+
} catch {
|
|
6666
|
+
}
|
|
6667
|
+
resolve10(!err2);
|
|
6668
|
+
}
|
|
6669
|
+
);
|
|
6670
|
+
} catch {
|
|
6671
|
+
resolve10(false);
|
|
6672
|
+
}
|
|
6673
|
+
});
|
|
6674
|
+
}
|
|
6675
|
+
async function tuiUpdateFlow(onStatus) {
|
|
6676
|
+
try {
|
|
6677
|
+
const current = currentVersion();
|
|
6678
|
+
const latest = await fetchLatest();
|
|
6679
|
+
const state = readState();
|
|
6680
|
+
if (latest) writeState({ ...state, lastCheckAt: Date.now(), latestSeen: latest });
|
|
6681
|
+
if (!latest || !newerThan(latest, current)) return;
|
|
6682
|
+
const attempts = readState().attempts ?? {};
|
|
6683
|
+
const canRetry = Date.now() - (attempts[latest] ?? 0) >= ATTEMPT_EVERY_MS;
|
|
6684
|
+
if (await isGlobalInstall() && canRetry) {
|
|
6685
|
+
writeState({ ...readState(), attempts: { [latest]: Date.now() } });
|
|
6686
|
+
onStatus({ kind: "updating", version: latest });
|
|
6687
|
+
if (await runGlobalInstall(latest)) {
|
|
6688
|
+
onStatus({ kind: "updated", version: latest });
|
|
6689
|
+
return;
|
|
6690
|
+
}
|
|
6691
|
+
}
|
|
6692
|
+
onStatus({ kind: "manual", version: latest });
|
|
6693
|
+
} catch {
|
|
6694
|
+
}
|
|
6695
|
+
}
|
|
6650
6696
|
function maybeSelfUpdate(notify = (l) => process.stderr.write(l + "\n")) {
|
|
6651
6697
|
void (async () => {
|
|
6652
6698
|
try {
|
|
@@ -7157,6 +7203,21 @@ var init_device_login = __esm({
|
|
|
7157
7203
|
}
|
|
7158
7204
|
});
|
|
7159
7205
|
|
|
7206
|
+
// src/api-client/auth.ts
|
|
7207
|
+
var auth_exports = {};
|
|
7208
|
+
__export(auth_exports, {
|
|
7209
|
+
me: () => me
|
|
7210
|
+
});
|
|
7211
|
+
function me() {
|
|
7212
|
+
return request("GET", "/auth/me");
|
|
7213
|
+
}
|
|
7214
|
+
var init_auth = __esm({
|
|
7215
|
+
"src/api-client/auth.ts"() {
|
|
7216
|
+
"use strict";
|
|
7217
|
+
init_client();
|
|
7218
|
+
}
|
|
7219
|
+
});
|
|
7220
|
+
|
|
7160
7221
|
// src/api-client/policies.ts
|
|
7161
7222
|
var policies_exports = {};
|
|
7162
7223
|
__export(policies_exports, {
|
|
@@ -7428,6 +7489,7 @@ var init_api_client = __esm({
|
|
|
7428
7489
|
init_client();
|
|
7429
7490
|
init_types();
|
|
7430
7491
|
init_device_login();
|
|
7492
|
+
init_auth();
|
|
7431
7493
|
init_policies();
|
|
7432
7494
|
init_settings();
|
|
7433
7495
|
init_stats();
|
|
@@ -7435,7 +7497,7 @@ var init_api_client = __esm({
|
|
|
7435
7497
|
init_agents();
|
|
7436
7498
|
init_keys();
|
|
7437
7499
|
init_mcp();
|
|
7438
|
-
api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
7500
|
+
api = { auth: auth_exports, policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
7439
7501
|
}
|
|
7440
7502
|
});
|
|
7441
7503
|
|
|
@@ -10177,7 +10239,7 @@ function AccountsPanel({
|
|
|
10177
10239
|
if (a) {
|
|
10178
10240
|
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
10179
10241
|
onView?.(a);
|
|
10180
|
-
setMsg({ text: `viewing ${a.project || a.user || a.apiKey.slice(
|
|
10242
|
+
setMsg({ text: `viewing ${a.project || a.user || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
|
|
10181
10243
|
}
|
|
10182
10244
|
} else if (input === "m") {
|
|
10183
10245
|
const a = accounts[sel];
|
|
@@ -10226,7 +10288,7 @@ function AccountsPanel({
|
|
|
10226
10288
|
const isActive = isActiveAccount(a.apiKey);
|
|
10227
10289
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
|
|
10228
10290
|
/* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
|
|
10229
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.project || a.user || a.apiKey.slice(
|
|
10291
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.project || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
|
|
10230
10292
|
isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
10231
10293
|
isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
10232
10294
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.user && a.project ? truncate2(a.user, 24) : "" })
|
|
@@ -10248,7 +10310,7 @@ var init_Accounts = __esm({
|
|
|
10248
10310
|
|
|
10249
10311
|
// src/tui/App.tsx
|
|
10250
10312
|
import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
|
|
10251
|
-
import { useState as useState9 } from "react";
|
|
10313
|
+
import { useEffect as useEffect7, useState as useState9 } from "react";
|
|
10252
10314
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
10253
10315
|
function LiveHint() {
|
|
10254
10316
|
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
@@ -10283,9 +10345,35 @@ function App() {
|
|
|
10283
10345
|
const [section, setSection] = useState9(accounts.length === 0 ? ACCOUNTS_SECTION : 0);
|
|
10284
10346
|
const [focus, setFocus] = useState9("nav");
|
|
10285
10347
|
const [help, setHelp] = useState9(false);
|
|
10348
|
+
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
10349
|
+
useEffect7(() => {
|
|
10350
|
+
let alive = true;
|
|
10351
|
+
const run12 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
10352
|
+
run12();
|
|
10353
|
+
const t = setInterval(run12, 30 * 6e4);
|
|
10354
|
+
return () => {
|
|
10355
|
+
alive = false;
|
|
10356
|
+
clearInterval(t);
|
|
10357
|
+
};
|
|
10358
|
+
}, []);
|
|
10286
10359
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
10287
10360
|
const cur = accounts[acctIdx];
|
|
10288
|
-
const acctLabel = cur ? cur.project || cur.user || cur.apiKey.slice(
|
|
10361
|
+
const acctLabel = cur ? cur.project || cur.user || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
|
|
10362
|
+
useEffect7(() => {
|
|
10363
|
+
if (!cur || cur.project || cur.user) return;
|
|
10364
|
+
let alive = true;
|
|
10365
|
+
api.auth.me().then((r) => {
|
|
10366
|
+
const project = r.project?.name || void 0;
|
|
10367
|
+
const user = r.user?.name || r.user?.email || void 0;
|
|
10368
|
+
if (!alive || !project && !user) return;
|
|
10369
|
+
saveAccount({ ...cur, project, user });
|
|
10370
|
+
setAccounts(listAccounts());
|
|
10371
|
+
}).catch(() => {
|
|
10372
|
+
});
|
|
10373
|
+
return () => {
|
|
10374
|
+
alive = false;
|
|
10375
|
+
};
|
|
10376
|
+
}, [cur]);
|
|
10289
10377
|
const viewAccount = (a) => {
|
|
10290
10378
|
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
10291
10379
|
setAccounts(listAccounts());
|
|
@@ -10337,7 +10425,8 @@ function App() {
|
|
|
10337
10425
|
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
10338
10426
|
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
|
|
10339
10427
|
/* @__PURE__ */ jsx9(Text9, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel }),
|
|
10340
|
-
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" })
|
|
10428
|
+
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" }),
|
|
10429
|
+
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 \u2014 restart (q, then solongate) to apply` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
|
|
10341
10430
|
] }),
|
|
10342
10431
|
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
10343
10432
|
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
|
@@ -10379,6 +10468,8 @@ var init_App = __esm({
|
|
|
10379
10468
|
init_Accounts();
|
|
10380
10469
|
init_hooks();
|
|
10381
10470
|
init_client();
|
|
10471
|
+
init_api_client();
|
|
10472
|
+
init_self_update();
|
|
10382
10473
|
SECTIONS = [
|
|
10383
10474
|
{ label: "Live", Panel: LiveHint },
|
|
10384
10475
|
{ label: "Policies", Panel: PoliciesPanel },
|
|
@@ -11774,7 +11865,7 @@ ${SHIM_END}`;
|
|
|
11774
11865
|
}
|
|
11775
11866
|
}
|
|
11776
11867
|
}
|
|
11777
|
-
async function
|
|
11868
|
+
async function runGlobalInstall2(opts = {}) {
|
|
11778
11869
|
const p = globalPaths();
|
|
11779
11870
|
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
11780
11871
|
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
@@ -11965,7 +12056,7 @@ async function main() {
|
|
|
11965
12056
|
return;
|
|
11966
12057
|
}
|
|
11967
12058
|
console.log("");
|
|
11968
|
-
await
|
|
12059
|
+
await runGlobalInstall2({ apiKey, apiUrl });
|
|
11969
12060
|
console.log("");
|
|
11970
12061
|
console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
11971
12062
|
console.log(" \u2502 You are logged in and protected. \u2502");
|
|
@@ -16508,9 +16599,10 @@ async function main5() {
|
|
|
16508
16599
|
const subcommand = process.argv[2];
|
|
16509
16600
|
if (IS_HUMAN_CLI) {
|
|
16510
16601
|
const tuiBound = subcommand === "dataroom" || process.argv.length <= 2 && process.stdout.isTTY && process.stdin.isTTY;
|
|
16511
|
-
|
|
16512
|
-
|
|
16513
|
-
|
|
16602
|
+
if (!tuiBound) {
|
|
16603
|
+
const { maybeSelfUpdate: maybeSelfUpdate2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
16604
|
+
maybeSelfUpdate2();
|
|
16605
|
+
}
|
|
16514
16606
|
}
|
|
16515
16607
|
if (process.argv.length <= 2) {
|
|
16516
16608
|
if (process.stdout.isTTY && process.stdin.isTTY) {
|
package/dist/self-update.d.ts
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
export declare function currentVersion(): string;
|
|
2
|
+
/** What the dataroom shows about the updater. */
|
|
3
|
+
export type UpdateStatus = {
|
|
4
|
+
kind: 'idle';
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'updating';
|
|
7
|
+
version: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'updated';
|
|
10
|
+
version: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'manual';
|
|
13
|
+
version: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The dataroom's updater (Claude Code-style): check the registry EVERY time the
|
|
17
|
+
* TUI opens (and periodically while it stays open), install the new version in
|
|
18
|
+
* the background, then tell the user to restart. `onStatus` drives the in-app
|
|
19
|
+
* status line; nothing is ever written to the terminal directly.
|
|
20
|
+
*/
|
|
21
|
+
export declare function tuiUpdateFlow(onStatus: (s: UpdateStatus) => void): Promise<void>;
|
|
2
22
|
/**
|
|
3
23
|
* Fire-and-forget startup hook. `notify` writes the human-facing one-liner —
|
|
4
24
|
* callers pass a stderr writer so the notice never lands in piped stdout.
|
package/dist/tui/index.js
CHANGED
|
@@ -5,14 +5,14 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/tui/index.tsx
|
|
8
|
-
import { appendFileSync, mkdirSync as
|
|
9
|
-
import { homedir as
|
|
10
|
-
import { join as
|
|
8
|
+
import { appendFileSync, mkdirSync as mkdirSync5 } from "fs";
|
|
9
|
+
import { homedir as homedir7 } from "os";
|
|
10
|
+
import { join as join7 } from "path";
|
|
11
11
|
import { render } from "ink";
|
|
12
12
|
|
|
13
13
|
// src/tui/App.tsx
|
|
14
14
|
import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
|
|
15
|
-
import { useState as useState9 } from "react";
|
|
15
|
+
import { useEffect as useEffect7, useState as useState9 } from "react";
|
|
16
16
|
|
|
17
17
|
// src/cli-utils.ts
|
|
18
18
|
var c = {
|
|
@@ -471,6 +471,15 @@ async function pollDeviceLogin(apiUrl, deviceCode) {
|
|
|
471
471
|
}
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
+
// src/api-client/auth.ts
|
|
475
|
+
var auth_exports = {};
|
|
476
|
+
__export(auth_exports, {
|
|
477
|
+
me: () => me
|
|
478
|
+
});
|
|
479
|
+
function me() {
|
|
480
|
+
return request("GET", "/auth/me");
|
|
481
|
+
}
|
|
482
|
+
|
|
474
483
|
// src/api-client/policies.ts
|
|
475
484
|
var policies_exports = {};
|
|
476
485
|
__export(policies_exports, {
|
|
@@ -693,7 +702,7 @@ function list4() {
|
|
|
693
702
|
}
|
|
694
703
|
|
|
695
704
|
// src/api-client/index.ts
|
|
696
|
-
var api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
705
|
+
var api = { auth: auth_exports, policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
697
706
|
|
|
698
707
|
// src/tui/notify.ts
|
|
699
708
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -3355,7 +3364,7 @@ function AccountsPanel({
|
|
|
3355
3364
|
if (a) {
|
|
3356
3365
|
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
3357
3366
|
onView?.(a);
|
|
3358
|
-
setMsg({ text: `viewing ${a.project || a.user || a.apiKey.slice(
|
|
3367
|
+
setMsg({ text: `viewing ${a.project || a.user || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
|
|
3359
3368
|
}
|
|
3360
3369
|
} else if (input === "m") {
|
|
3361
3370
|
const a = accounts[sel];
|
|
@@ -3404,7 +3413,7 @@ function AccountsPanel({
|
|
|
3404
3413
|
const isActive = isActiveAccount(a.apiKey);
|
|
3405
3414
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
|
|
3406
3415
|
/* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
|
|
3407
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate(a.project || a.user || a.apiKey.slice(
|
|
3416
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate(a.project || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
|
|
3408
3417
|
isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
3409
3418
|
isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
3410
3419
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.user && a.project ? truncate(a.user, 24) : "" })
|
|
@@ -3414,6 +3423,127 @@ function AccountsPanel({
|
|
|
3414
3423
|
] });
|
|
3415
3424
|
}
|
|
3416
3425
|
|
|
3426
|
+
// src/self-update.ts
|
|
3427
|
+
import { execFile, spawn as spawn3 } from "child_process";
|
|
3428
|
+
import { mkdirSync as mkdirSync4, openSync as openSync2, readFileSync as readFileSync4, realpathSync, writeFileSync as writeFileSync5 } from "fs";
|
|
3429
|
+
import { homedir as homedir6 } from "os";
|
|
3430
|
+
import { dirname, join as join6 } from "path";
|
|
3431
|
+
import { fileURLToPath } from "url";
|
|
3432
|
+
var PKG = "@solongate/proxy";
|
|
3433
|
+
var CHECK_EVERY_MS = 30 * 60 * 1e3;
|
|
3434
|
+
var ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
3435
|
+
var STATE_FILE = join6(homedir6(), ".solongate", ".self-update.json");
|
|
3436
|
+
var LOG_FILE = join6(homedir6(), ".solongate", "self-update.log");
|
|
3437
|
+
function readState() {
|
|
3438
|
+
try {
|
|
3439
|
+
const s = JSON.parse(readFileSync4(STATE_FILE, "utf-8"));
|
|
3440
|
+
return s && typeof s === "object" ? s : {};
|
|
3441
|
+
} catch {
|
|
3442
|
+
return {};
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
function writeState(s) {
|
|
3446
|
+
try {
|
|
3447
|
+
mkdirSync4(join6(homedir6(), ".solongate"), { recursive: true });
|
|
3448
|
+
writeFileSync5(STATE_FILE, JSON.stringify(s));
|
|
3449
|
+
} catch {
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
function currentVersion() {
|
|
3453
|
+
try {
|
|
3454
|
+
const pkg = JSON.parse(readFileSync4(join6(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
3455
|
+
return pkg.version ?? "0.0.0";
|
|
3456
|
+
} catch {
|
|
3457
|
+
return "0.0.0";
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
function newerThan(b, a) {
|
|
3461
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
3462
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
3463
|
+
for (let i = 0; i < 3; i++) {
|
|
3464
|
+
if ((pb[i] ?? 0) > (pa[i] ?? 0)) return true;
|
|
3465
|
+
if ((pb[i] ?? 0) < (pa[i] ?? 0)) return false;
|
|
3466
|
+
}
|
|
3467
|
+
return false;
|
|
3468
|
+
}
|
|
3469
|
+
async function fetchLatest() {
|
|
3470
|
+
try {
|
|
3471
|
+
const res = await fetch(`https://registry.npmjs.org/${PKG}/latest`, { signal: AbortSignal.timeout(2e3) });
|
|
3472
|
+
if (!res.ok) return null;
|
|
3473
|
+
const j = await res.json();
|
|
3474
|
+
return typeof j.version === "string" ? j.version : null;
|
|
3475
|
+
} catch {
|
|
3476
|
+
return null;
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
function npmGlobalRoot() {
|
|
3480
|
+
return new Promise((resolve2) => {
|
|
3481
|
+
try {
|
|
3482
|
+
execFile("npm", ["root", "-g"], { timeout: 5e3, windowsHide: true, shell: process.platform === "win32" }, (err, stdout) => {
|
|
3483
|
+
resolve2(err ? null : stdout.trim() || null);
|
|
3484
|
+
});
|
|
3485
|
+
} catch {
|
|
3486
|
+
resolve2(null);
|
|
3487
|
+
}
|
|
3488
|
+
});
|
|
3489
|
+
}
|
|
3490
|
+
async function isGlobalInstall() {
|
|
3491
|
+
try {
|
|
3492
|
+
const script = realpathSync(process.argv[1] ?? "");
|
|
3493
|
+
if (!script) return false;
|
|
3494
|
+
const root = await npmGlobalRoot();
|
|
3495
|
+
if (!root) return false;
|
|
3496
|
+
return script.startsWith(realpathSync(root));
|
|
3497
|
+
} catch {
|
|
3498
|
+
return false;
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
function runGlobalInstall(version) {
|
|
3502
|
+
return new Promise((resolve2) => {
|
|
3503
|
+
try {
|
|
3504
|
+
mkdirSync4(join6(homedir6(), ".solongate"), { recursive: true });
|
|
3505
|
+
execFile(
|
|
3506
|
+
"npm",
|
|
3507
|
+
["install", "-g", `${PKG}@${version}`],
|
|
3508
|
+
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
3509
|
+
(err, stdout, stderr) => {
|
|
3510
|
+
try {
|
|
3511
|
+
writeFileSync5(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err ? "FAILED" : "ok"}
|
|
3512
|
+
${stdout}
|
|
3513
|
+
${stderr}
|
|
3514
|
+
`, { flag: "a" });
|
|
3515
|
+
} catch {
|
|
3516
|
+
}
|
|
3517
|
+
resolve2(!err);
|
|
3518
|
+
}
|
|
3519
|
+
);
|
|
3520
|
+
} catch {
|
|
3521
|
+
resolve2(false);
|
|
3522
|
+
}
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
async function tuiUpdateFlow(onStatus) {
|
|
3526
|
+
try {
|
|
3527
|
+
const current = currentVersion();
|
|
3528
|
+
const latest = await fetchLatest();
|
|
3529
|
+
const state = readState();
|
|
3530
|
+
if (latest) writeState({ ...state, lastCheckAt: Date.now(), latestSeen: latest });
|
|
3531
|
+
if (!latest || !newerThan(latest, current)) return;
|
|
3532
|
+
const attempts = readState().attempts ?? {};
|
|
3533
|
+
const canRetry = Date.now() - (attempts[latest] ?? 0) >= ATTEMPT_EVERY_MS;
|
|
3534
|
+
if (await isGlobalInstall() && canRetry) {
|
|
3535
|
+
writeState({ ...readState(), attempts: { [latest]: Date.now() } });
|
|
3536
|
+
onStatus({ kind: "updating", version: latest });
|
|
3537
|
+
if (await runGlobalInstall(latest)) {
|
|
3538
|
+
onStatus({ kind: "updated", version: latest });
|
|
3539
|
+
return;
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
onStatus({ kind: "manual", version: latest });
|
|
3543
|
+
} catch {
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
|
|
3417
3547
|
// src/tui/App.tsx
|
|
3418
3548
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3419
3549
|
function LiveHint() {
|
|
@@ -3460,9 +3590,35 @@ function App() {
|
|
|
3460
3590
|
const [section, setSection] = useState9(accounts.length === 0 ? ACCOUNTS_SECTION : 0);
|
|
3461
3591
|
const [focus, setFocus] = useState9("nav");
|
|
3462
3592
|
const [help, setHelp] = useState9(false);
|
|
3593
|
+
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
3594
|
+
useEffect7(() => {
|
|
3595
|
+
let alive = true;
|
|
3596
|
+
const run = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
3597
|
+
run();
|
|
3598
|
+
const t = setInterval(run, 30 * 6e4);
|
|
3599
|
+
return () => {
|
|
3600
|
+
alive = false;
|
|
3601
|
+
clearInterval(t);
|
|
3602
|
+
};
|
|
3603
|
+
}, []);
|
|
3463
3604
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
3464
3605
|
const cur = accounts[acctIdx];
|
|
3465
|
-
const acctLabel = cur ? cur.project || cur.user || cur.apiKey.slice(
|
|
3606
|
+
const acctLabel = cur ? cur.project || cur.user || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
|
|
3607
|
+
useEffect7(() => {
|
|
3608
|
+
if (!cur || cur.project || cur.user) return;
|
|
3609
|
+
let alive = true;
|
|
3610
|
+
api.auth.me().then((r) => {
|
|
3611
|
+
const project = r.project?.name || void 0;
|
|
3612
|
+
const user = r.user?.name || r.user?.email || void 0;
|
|
3613
|
+
if (!alive || !project && !user) return;
|
|
3614
|
+
saveAccount({ ...cur, project, user });
|
|
3615
|
+
setAccounts(listAccounts());
|
|
3616
|
+
}).catch(() => {
|
|
3617
|
+
});
|
|
3618
|
+
return () => {
|
|
3619
|
+
alive = false;
|
|
3620
|
+
};
|
|
3621
|
+
}, [cur]);
|
|
3466
3622
|
const viewAccount = (a) => {
|
|
3467
3623
|
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
3468
3624
|
setAccounts(listAccounts());
|
|
@@ -3514,7 +3670,8 @@ function App() {
|
|
|
3514
3670
|
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
3515
3671
|
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
|
|
3516
3672
|
/* @__PURE__ */ jsx9(Text9, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel }),
|
|
3517
|
-
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" })
|
|
3673
|
+
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" }),
|
|
3674
|
+
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 \u2014 restart (q, then solongate) to apply` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
|
|
3518
3675
|
] }),
|
|
3519
3676
|
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
3520
3677
|
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
|
@@ -3560,11 +3717,11 @@ async function launchTui() {
|
|
|
3560
3717
|
return;
|
|
3561
3718
|
}
|
|
3562
3719
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
3563
|
-
const debugLog =
|
|
3720
|
+
const debugLog = join7(homedir7(), ".solongate", "dataroom-debug.log");
|
|
3564
3721
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
3565
3722
|
const toFile = (level) => (...args) => {
|
|
3566
3723
|
try {
|
|
3567
|
-
|
|
3724
|
+
mkdirSync5(join7(homedir7(), ".solongate"), { recursive: true });
|
|
3568
3725
|
appendFileSync(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
3569
3726
|
`);
|
|
3570
3727
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.48",
|
|
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": {
|