@solongate/proxy 0.81.48 → 0.81.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-client/client.d.ts +2 -0
- package/dist/api-client/device-login.d.ts +1 -0
- package/dist/index.js +258 -270
- package/dist/login.js +1 -1
- package/dist/tui/index.js +254 -258
- package/dist/tui/panels/Settings.d.ts +4 -1
- package/package.json +1 -1
- package/dist/tui/panels/Accounts.d.ts +0 -7
package/dist/tui/index.js
CHANGED
|
@@ -11,8 +11,8 @@ import { join as join7 } from "path";
|
|
|
11
11
|
import { render } from "ink";
|
|
12
12
|
|
|
13
13
|
// src/tui/App.tsx
|
|
14
|
-
import { Box as
|
|
15
|
-
import { useEffect as useEffect7, useState as
|
|
14
|
+
import { Box as Box8, Text as Text8, useApp, useInput as useInput7 } from "ink";
|
|
15
|
+
import { useEffect as useEffect7, useState as useState8 } from "react";
|
|
16
16
|
|
|
17
17
|
// src/cli-utils.ts
|
|
18
18
|
var c = {
|
|
@@ -462,7 +462,7 @@ async function pollDeviceLogin(apiUrl, deviceCode) {
|
|
|
462
462
|
});
|
|
463
463
|
const j = await res.json().catch(() => ({}));
|
|
464
464
|
if (j.status === "approved" && j.api_key) {
|
|
465
|
-
return { status: "approved", apiKey: j.api_key, project: j.project?.name, user: j.user?.name || j.user?.email };
|
|
465
|
+
return { status: "approved", apiKey: j.api_key, project: j.project?.name, user: j.user?.name || j.user?.email, email: j.user?.email };
|
|
466
466
|
}
|
|
467
467
|
if (j.status === "expired" || j.status === "not_found") return { status: j.status };
|
|
468
468
|
return { status: "pending" };
|
|
@@ -3090,9 +3090,10 @@ function Detail({ label, value, color }) {
|
|
|
3090
3090
|
// src/tui/panels/Settings.tsx
|
|
3091
3091
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
3092
3092
|
import TextInput5 from "ink-text-input";
|
|
3093
|
-
import { useState as useState7 } from "react";
|
|
3094
|
-
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3093
|
+
import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
|
|
3094
|
+
import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3095
3095
|
var EVENTS = ["denials", "allowed", "all"];
|
|
3096
|
+
var SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3096
3097
|
function alertBodyFor(channel) {
|
|
3097
3098
|
const c2 = channel.trim();
|
|
3098
3099
|
const base = { name: "dataroom alert", threshold: 5, windowSeconds: 60, signal: "any" };
|
|
@@ -3100,7 +3101,13 @@ function alertBodyFor(channel) {
|
|
|
3100
3101
|
if (c2.includes("@")) return { ...base, emails: [c2] };
|
|
3101
3102
|
return { ...base, telegram: [c2] };
|
|
3102
3103
|
}
|
|
3103
|
-
|
|
3104
|
+
var acctLabel = (a) => a.email || a.user || "account \u2026" + a.apiKey.slice(-4);
|
|
3105
|
+
function SettingsPanel({
|
|
3106
|
+
active: active2,
|
|
3107
|
+
focused,
|
|
3108
|
+
viewApiKey,
|
|
3109
|
+
onView
|
|
3110
|
+
}) {
|
|
3104
3111
|
void active2;
|
|
3105
3112
|
const { cols, rows } = usePanelSize();
|
|
3106
3113
|
const [sel, setSel] = useState7(0);
|
|
@@ -3109,24 +3116,40 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
3109
3116
|
const [confirmDel, setConfirmDel] = useState7(null);
|
|
3110
3117
|
const [msg, setMsg] = useState7(null);
|
|
3111
3118
|
const [busy, setBusy] = useState7(false);
|
|
3112
|
-
const
|
|
3113
|
-
const
|
|
3114
|
-
const
|
|
3119
|
+
const [accounts, setAccounts] = useState7(() => listAccounts());
|
|
3120
|
+
const [login, setLogin] = useState7(null);
|
|
3121
|
+
const [tick, setTick] = useState7(0);
|
|
3122
|
+
const abort = useRef3(false);
|
|
3123
|
+
const refreshAccounts = () => setAccounts(listAccounts());
|
|
3124
|
+
const locked = accounts.length === 0;
|
|
3125
|
+
useEffect6(() => {
|
|
3126
|
+
if (!login || login.phase === "done" || login.phase === "error") return;
|
|
3127
|
+
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
3128
|
+
return () => clearInterval(t);
|
|
3129
|
+
}, [login]);
|
|
3130
|
+
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
3131
|
+
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
3132
|
+
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
3115
3133
|
const local = localQ.data;
|
|
3116
3134
|
const webhooks = whQ.data?.webhooks ?? [];
|
|
3117
3135
|
const alerts = alertQ.data?.rules ?? [];
|
|
3118
3136
|
const rowsAll = [
|
|
3119
|
-
{ kind: "
|
|
3120
|
-
{ kind: "
|
|
3121
|
-
...
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3137
|
+
...accounts.map((acc) => ({ kind: "acct", acc })),
|
|
3138
|
+
{ kind: "acct-add" },
|
|
3139
|
+
...locked ? [] : [
|
|
3140
|
+
{ kind: "ll-enabled" },
|
|
3141
|
+
{ kind: "ll-path" },
|
|
3142
|
+
...webhooks.map((wh) => ({ kind: "wh", wh })),
|
|
3143
|
+
{ kind: "wh-add" },
|
|
3144
|
+
...alerts.map((rule) => ({ kind: "alert", rule })),
|
|
3145
|
+
{ kind: "alert-add" }
|
|
3146
|
+
]
|
|
3125
3147
|
];
|
|
3126
3148
|
const selClamped = Math.min(sel, rowsAll.length - 1);
|
|
3127
3149
|
const cur = rowsAll[selClamped];
|
|
3128
|
-
const keyOf = (r) => r.kind === "wh" ? "wh:" + r.wh.id : r.kind === "alert" ? "alert:" + r.rule.id : r.kind;
|
|
3150
|
+
const keyOf = (r) => r.kind === "acct" ? "acct:" + r.acc.apiKey : r.kind === "wh" ? "wh:" + r.wh.id : r.kind === "alert" ? "alert:" + r.rule.id : r.kind;
|
|
3129
3151
|
const reloadAll = () => {
|
|
3152
|
+
refreshAccounts();
|
|
3130
3153
|
localQ.reload();
|
|
3131
3154
|
whQ.reload();
|
|
3132
3155
|
alertQ.reload();
|
|
@@ -3140,8 +3163,48 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
3140
3163
|
reload();
|
|
3141
3164
|
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" })).finally(() => setBusy(false));
|
|
3142
3165
|
};
|
|
3166
|
+
const beginLogin = () => {
|
|
3167
|
+
if (login && (login.phase === "starting" || login.phase === "waiting")) return;
|
|
3168
|
+
abort.current = false;
|
|
3169
|
+
setLogin({ phase: "starting" });
|
|
3170
|
+
void (async () => {
|
|
3171
|
+
let start2;
|
|
3172
|
+
try {
|
|
3173
|
+
start2 = await startDeviceLogin(DEFAULT_API_URL);
|
|
3174
|
+
} catch (e) {
|
|
3175
|
+
setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
3178
|
+
setLogin({ phase: "waiting", url: start2.verifyUrl });
|
|
3179
|
+
openBrowser(start2.verifyUrl);
|
|
3180
|
+
while (Date.now() < start2.expiresAt && !abort.current) {
|
|
3181
|
+
await new Promise((r) => setTimeout(r, start2.intervalMs));
|
|
3182
|
+
if (abort.current) return;
|
|
3183
|
+
const res = await pollDeviceLogin(DEFAULT_API_URL, start2.deviceCode);
|
|
3184
|
+
if (res.status === "approved" && res.apiKey) {
|
|
3185
|
+
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user, email: res.email });
|
|
3186
|
+
setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
|
|
3187
|
+
setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL });
|
|
3188
|
+
onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user, email: res.email });
|
|
3189
|
+
reloadAll();
|
|
3190
|
+
return;
|
|
3191
|
+
}
|
|
3192
|
+
if (res.status === "expired" || res.status === "not_found") {
|
|
3193
|
+
setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
|
|
3198
|
+
})();
|
|
3199
|
+
};
|
|
3143
3200
|
const activate = (r) => {
|
|
3144
|
-
if (r.kind === "
|
|
3201
|
+
if (r.kind === "acct") {
|
|
3202
|
+
setViewCredentials({ apiKey: r.acc.apiKey, apiUrl: r.acc.apiUrl });
|
|
3203
|
+
onView?.(r.acc);
|
|
3204
|
+
setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
|
|
3205
|
+
} else if (r.kind === "acct-add") {
|
|
3206
|
+
beginLogin();
|
|
3207
|
+
} else if (r.kind === "ll-enabled") {
|
|
3145
3208
|
if (!local) return;
|
|
3146
3209
|
if (!local.enabled && !local.path.trim()) {
|
|
3147
3210
|
setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
|
|
@@ -3180,6 +3243,13 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
3180
3243
|
};
|
|
3181
3244
|
useInput6(
|
|
3182
3245
|
(inp, key) => {
|
|
3246
|
+
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
3247
|
+
if (key.escape) {
|
|
3248
|
+
abort.current = true;
|
|
3249
|
+
setLogin(null);
|
|
3250
|
+
}
|
|
3251
|
+
return;
|
|
3252
|
+
}
|
|
3183
3253
|
setMsg(null);
|
|
3184
3254
|
if (key.upArrow) {
|
|
3185
3255
|
setSel((n) => Math.max(0, n - 1));
|
|
@@ -3188,6 +3258,11 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
3188
3258
|
setSel((n) => Math.min(rowsAll.length - 1, n + 1));
|
|
3189
3259
|
setConfirmDel(null);
|
|
3190
3260
|
} else if (key.return || inp === " ") activate(cur);
|
|
3261
|
+
else if (inp === "m" && cur.kind === "acct") {
|
|
3262
|
+
const ok = setActiveAccount({ apiKey: cur.acc.apiKey, apiUrl: cur.acc.apiUrl });
|
|
3263
|
+
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
3264
|
+
refreshAccounts();
|
|
3265
|
+
} else if (inp === "n") beginLogin();
|
|
3191
3266
|
else if (inp === "e" && cur.kind === "wh") {
|
|
3192
3267
|
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
3193
3268
|
run(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
@@ -3214,215 +3289,136 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
3214
3289
|
},
|
|
3215
3290
|
{ isActive: focused && !editing }
|
|
3216
3291
|
);
|
|
3217
|
-
const
|
|
3218
|
-
|
|
3292
|
+
const spin = SPIN2[tick % SPIN2.length];
|
|
3293
|
+
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
3294
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
3295
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, color: theme.accentBright, children: "Add an account" }),
|
|
3296
|
+
login.phase === "starting" ? /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3297
|
+
spin,
|
|
3298
|
+
" starting device pairing\u2026"
|
|
3299
|
+
] }) : /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
3300
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
|
|
3301
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
|
|
3302
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
|
|
3303
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.warn, children: [
|
|
3304
|
+
spin,
|
|
3305
|
+
" waiting for authorization\u2026 "
|
|
3306
|
+
] }),
|
|
3307
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "esc to cancel" })
|
|
3308
|
+
] })
|
|
3309
|
+
] })
|
|
3310
|
+
] });
|
|
3311
|
+
}
|
|
3312
|
+
const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data);
|
|
3313
|
+
const error = locked ? null : localQ.error ?? whQ.error ?? alertQ.error;
|
|
3219
3314
|
const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
|
|
3220
3315
|
const onOff = (on) => on ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" });
|
|
3221
3316
|
const chanOf = (rule) => [...(rule.slackUrls ?? []).map((u) => "slack " + u), ...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
3222
|
-
const listBudget = Math.max(4, rows -
|
|
3317
|
+
const listBudget = Math.max(4, rows - 10);
|
|
3223
3318
|
const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
|
|
3224
3319
|
const inWindow = (r) => {
|
|
3225
3320
|
const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
|
|
3226
3321
|
return i >= start && i < start + listBudget;
|
|
3227
3322
|
};
|
|
3228
3323
|
return /* @__PURE__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
3229
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter
|
|
3324
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter view-toggle-edit \xB7 m make active \xB7 n add account \xB7 e events \xB7 d delete \xB7 r refresh" : "press \u2192 to configure" }),
|
|
3230
3325
|
editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
3231
3326
|
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : editing === "wh-url" ? "webhook url: " : "channel (slack url / email / telegram id): " }),
|
|
3232
3327
|
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
3233
|
-
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
3234
|
-
inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3235
|
-
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3236
|
-
"LOCAL LOGS ",
|
|
3237
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
|
|
3238
|
-
] }),
|
|
3239
|
-
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3240
|
-
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[0]) }),
|
|
3241
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(10) }),
|
|
3242
|
-
onOff(!!local?.enabled),
|
|
3243
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
|
|
3244
|
-
] }),
|
|
3245
|
-
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3246
|
-
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[1]) }),
|
|
3247
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(10) }),
|
|
3248
|
-
local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
3249
|
-
] })
|
|
3250
|
-
] }) : null,
|
|
3328
|
+
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
3251
3329
|
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3252
3330
|
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3253
|
-
"
|
|
3331
|
+
"ACCOUNTS ",
|
|
3254
3332
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3255
|
-
"\u2014
|
|
3256
|
-
|
|
3257
|
-
")"
|
|
3333
|
+
"\u2014 logged in on this device (",
|
|
3334
|
+
accounts.length,
|
|
3335
|
+
") \xB7 \u25CF viewing = shown here \xB7 ACTIVE = key the guard uses"
|
|
3258
3336
|
] })
|
|
3259
3337
|
] }),
|
|
3260
|
-
|
|
3261
|
-
/* @__PURE__ */ jsx7(Text7, { color:
|
|
3262
|
-
|
|
3263
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
/* @__PURE__ */
|
|
3338
|
+
accounts.length === 0 ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
3339
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " no accounts yet \u2014 " }),
|
|
3340
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: "n" }),
|
|
3341
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " (or enter) logs in, pairs this device and unlocks the dataroom" })
|
|
3342
|
+
] }) : null,
|
|
3343
|
+
accounts.filter((acc) => inWindow({ kind: "acct", acc })).map((a) => {
|
|
3344
|
+
const isView = viewApiKey ? a.apiKey === viewApiKey : accounts[0]?.apiKey === a.apiKey;
|
|
3345
|
+
const isActive = isActiveAccount(a.apiKey);
|
|
3346
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3347
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "acct:" + a.apiKey && focused ? theme.accentBright : theme.dim, children: mark({ kind: "acct", acc: a }) }),
|
|
3348
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(acctLabel(a), 30).padEnd(31) }),
|
|
3349
|
+
isView ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
|
|
3350
|
+
isActive ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
|
|
3351
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate(a.project, 24) : "" })
|
|
3352
|
+
] }, a.apiKey);
|
|
3353
|
+
}),
|
|
3354
|
+
inWindow({ kind: "acct-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
3355
|
+
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "acct-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "acct-add" }) }),
|
|
3356
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add account (enter \u2014 device login in the browser)" })
|
|
3269
3357
|
] }) : null
|
|
3270
3358
|
] }),
|
|
3271
|
-
/* @__PURE__ */ jsxs7(
|
|
3272
|
-
/* @__PURE__ */ jsxs7(
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
"\u2014
|
|
3276
|
-
|
|
3277
|
-
|
|
3359
|
+
locked ? null : /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
3360
|
+
inWindow({ kind: "ll-enabled" }) || inWindow({ kind: "ll-path" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3361
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3362
|
+
"LOCAL LOGS ",
|
|
3363
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
|
|
3364
|
+
] }),
|
|
3365
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3366
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-enabled" }) }),
|
|
3367
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(10) }),
|
|
3368
|
+
onOff(!!local?.enabled),
|
|
3369
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
|
|
3370
|
+
] }),
|
|
3371
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3372
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-path" }) }),
|
|
3373
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(10) }),
|
|
3374
|
+
local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
3278
3375
|
] })
|
|
3376
|
+
] }) : null,
|
|
3377
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3378
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3379
|
+
"WEBHOOKS ",
|
|
3380
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3381
|
+
"\u2014 POST every matching event to your endpoint (",
|
|
3382
|
+
webhooks.length,
|
|
3383
|
+
")"
|
|
3384
|
+
] })
|
|
3385
|
+
] }),
|
|
3386
|
+
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3387
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
|
|
3388
|
+
onOff(wh.enabled),
|
|
3389
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
|
|
3390
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(wh.url, cols - 16) })
|
|
3391
|
+
] }, wh.id)),
|
|
3392
|
+
inWindow({ kind: "wh-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
3393
|
+
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
|
|
3394
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add webhook (enter)" })
|
|
3395
|
+
] }) : null
|
|
3279
3396
|
] }),
|
|
3280
|
-
|
|
3281
|
-
/* @__PURE__ */
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3397
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
3398
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
3399
|
+
"ALERTS ",
|
|
3400
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
3401
|
+
"\u2014 notify on a signal spike (",
|
|
3402
|
+
alerts.length,
|
|
3403
|
+
")"
|
|
3404
|
+
] })
|
|
3405
|
+
] }),
|
|
3406
|
+
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3407
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
|
|
3408
|
+
onOff(rule.enabled),
|
|
3409
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
|
|
3410
|
+
/* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
|
|
3411
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate(chanOf(rule), cols - 26) })
|
|
3412
|
+
] }, rule.id)),
|
|
3413
|
+
inWindow({ kind: "alert-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
3414
|
+
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
|
|
3415
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
|
|
3416
|
+
] }) : null
|
|
3417
|
+
] })
|
|
3291
3418
|
] })
|
|
3292
3419
|
] }) });
|
|
3293
3420
|
}
|
|
3294
3421
|
|
|
3295
|
-
// src/tui/panels/Accounts.tsx
|
|
3296
|
-
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
3297
|
-
import { useEffect as useEffect6, useRef as useRef3, useState as useState8 } from "react";
|
|
3298
|
-
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3299
|
-
var SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3300
|
-
function AccountsPanel({
|
|
3301
|
-
focused,
|
|
3302
|
-
viewApiKey,
|
|
3303
|
-
onView
|
|
3304
|
-
}) {
|
|
3305
|
-
const [accounts, setAccounts] = useState8(() => listAccounts());
|
|
3306
|
-
const [sel, setSel] = useState8(0);
|
|
3307
|
-
const [msg, setMsg] = useState8(null);
|
|
3308
|
-
const [login, setLogin] = useState8(null);
|
|
3309
|
-
const [tick, setTick] = useState8(0);
|
|
3310
|
-
const abort = useRef3(false);
|
|
3311
|
-
const refresh = () => setAccounts(listAccounts());
|
|
3312
|
-
useEffect6(() => {
|
|
3313
|
-
if (!login || login.phase === "done" || login.phase === "error") return;
|
|
3314
|
-
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
3315
|
-
return () => clearInterval(t);
|
|
3316
|
-
}, [login]);
|
|
3317
|
-
const beginLogin = () => {
|
|
3318
|
-
if (login && (login.phase === "starting" || login.phase === "waiting")) return;
|
|
3319
|
-
abort.current = false;
|
|
3320
|
-
setLogin({ phase: "starting" });
|
|
3321
|
-
void (async () => {
|
|
3322
|
-
let start;
|
|
3323
|
-
try {
|
|
3324
|
-
start = await startDeviceLogin(DEFAULT_API_URL);
|
|
3325
|
-
} catch (e) {
|
|
3326
|
-
setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
|
|
3327
|
-
return;
|
|
3328
|
-
}
|
|
3329
|
-
setLogin({ phase: "waiting", url: start.verifyUrl });
|
|
3330
|
-
openBrowser(start.verifyUrl);
|
|
3331
|
-
while (Date.now() < start.expiresAt && !abort.current) {
|
|
3332
|
-
await new Promise((r) => setTimeout(r, start.intervalMs));
|
|
3333
|
-
if (abort.current) return;
|
|
3334
|
-
const res = await pollDeviceLogin(DEFAULT_API_URL, start.deviceCode);
|
|
3335
|
-
if (res.status === "approved" && res.apiKey) {
|
|
3336
|
-
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user });
|
|
3337
|
-
setLogin({ phase: "done", msg: `\u2713 added ${res.project || res.user || "account"}` });
|
|
3338
|
-
refresh();
|
|
3339
|
-
setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL });
|
|
3340
|
-
onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL, project: res.project, user: res.user });
|
|
3341
|
-
return;
|
|
3342
|
-
}
|
|
3343
|
-
if (res.status === "expired" || res.status === "not_found") {
|
|
3344
|
-
setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
|
|
3345
|
-
return;
|
|
3346
|
-
}
|
|
3347
|
-
}
|
|
3348
|
-
if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
|
|
3349
|
-
})();
|
|
3350
|
-
};
|
|
3351
|
-
useInput7(
|
|
3352
|
-
(input, key) => {
|
|
3353
|
-
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
3354
|
-
if (key.escape) {
|
|
3355
|
-
abort.current = true;
|
|
3356
|
-
setLogin(null);
|
|
3357
|
-
}
|
|
3358
|
-
return;
|
|
3359
|
-
}
|
|
3360
|
-
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
3361
|
-
else if (key.downArrow) setSel((n) => Math.min(accounts.length - 1, n + 1));
|
|
3362
|
-
else if (key.return) {
|
|
3363
|
-
const a = accounts[sel];
|
|
3364
|
-
if (a) {
|
|
3365
|
-
setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
3366
|
-
onView?.(a);
|
|
3367
|
-
setMsg({ text: `viewing ${a.project || a.user || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
|
|
3368
|
-
}
|
|
3369
|
-
} else if (input === "m") {
|
|
3370
|
-
const a = accounts[sel];
|
|
3371
|
-
if (a) {
|
|
3372
|
-
const ok = setActiveAccount({ apiKey: a.apiKey, apiUrl: a.apiUrl });
|
|
3373
|
-
setMsg(ok ? { text: `\u2713 ${a.project || a.user || "account"} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
3374
|
-
refresh();
|
|
3375
|
-
}
|
|
3376
|
-
} else if (input === "n") beginLogin();
|
|
3377
|
-
else if (input === "r") refresh();
|
|
3378
|
-
},
|
|
3379
|
-
{ isActive: focused }
|
|
3380
|
-
);
|
|
3381
|
-
const spin = SPIN2[tick % SPIN2.length];
|
|
3382
|
-
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
3383
|
-
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
3384
|
-
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "Add an account" }),
|
|
3385
|
-
login.phase === "starting" ? /* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
|
|
3386
|
-
spin,
|
|
3387
|
-
" starting device pairing\u2026"
|
|
3388
|
-
] }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
3389
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
|
|
3390
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
|
|
3391
|
-
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
3392
|
-
/* @__PURE__ */ jsxs8(Text8, { color: theme.warn, children: [
|
|
3393
|
-
spin,
|
|
3394
|
-
" waiting for authorization\u2026 "
|
|
3395
|
-
] }),
|
|
3396
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "esc to cancel" })
|
|
3397
|
-
] })
|
|
3398
|
-
] })
|
|
3399
|
-
] });
|
|
3400
|
-
}
|
|
3401
|
-
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
3402
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter view \xB7 m make active \xB7 n add account \xB7 r refresh" : "press \u2192 to manage accounts" }),
|
|
3403
|
-
msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, 70) }) : login?.msg ? /* @__PURE__ */ jsx8(Text8, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
3404
|
-
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: accounts.length === 0 ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
3405
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "No accounts on this device yet." }),
|
|
3406
|
-
/* @__PURE__ */ jsxs8(Text8, { children: [
|
|
3407
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "n" }),
|
|
3408
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " to log in \u2014 pairs this device and starts protecting your Claude Code sessions." })
|
|
3409
|
-
] })
|
|
3410
|
-
] }) : accounts.map((a, i) => {
|
|
3411
|
-
const isSel = i === sel && focused;
|
|
3412
|
-
const isView = viewApiKey ? a.apiKey === viewApiKey : i === 0;
|
|
3413
|
-
const isActive = isActiveAccount(a.apiKey);
|
|
3414
|
-
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
|
|
3415
|
-
/* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
|
|
3416
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate(a.project || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
|
|
3417
|
-
isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
3418
|
-
isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
3419
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.user && a.project ? truncate(a.user, 24) : "" })
|
|
3420
|
-
] }, a.apiKey);
|
|
3421
|
-
}) }),
|
|
3422
|
-
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u25CF viewing = the account the dataroom is showing \xB7 ACTIVE = the key the guard hooks + logging use" }) })
|
|
3423
|
-
] });
|
|
3424
|
-
}
|
|
3425
|
-
|
|
3426
3422
|
// src/self-update.ts
|
|
3427
3423
|
import { execFile, spawn as spawn3 } from "child_process";
|
|
3428
3424
|
import { mkdirSync as mkdirSync4, openSync as openSync2, readFileSync as readFileSync4, realpathSync, writeFileSync as writeFileSync5 } from "fs";
|
|
@@ -3545,15 +3541,15 @@ async function tuiUpdateFlow(onStatus) {
|
|
|
3545
3541
|
}
|
|
3546
3542
|
|
|
3547
3543
|
// src/tui/App.tsx
|
|
3548
|
-
import { jsx as
|
|
3544
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3549
3545
|
function LiveHint() {
|
|
3550
|
-
return /* @__PURE__ */
|
|
3551
|
-
/* @__PURE__ */
|
|
3552
|
-
/* @__PURE__ */
|
|
3553
|
-
/* @__PURE__ */
|
|
3554
|
-
/* @__PURE__ */
|
|
3546
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
3547
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
|
|
3548
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
|
|
3549
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
|
|
3550
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
3555
3551
|
"press ",
|
|
3556
|
-
/* @__PURE__ */
|
|
3552
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "enter" }),
|
|
3557
3553
|
" to go live"
|
|
3558
3554
|
] }) })
|
|
3559
3555
|
] });
|
|
@@ -3564,33 +3560,32 @@ var SECTIONS = [
|
|
|
3564
3560
|
{ label: "Rate Limit", Panel: RateLimitPanel },
|
|
3565
3561
|
{ label: "DLP", Panel: DlpPanel },
|
|
3566
3562
|
{ label: "Audit", Panel: AuditPanel },
|
|
3567
|
-
{ label: "Settings", Panel: SettingsPanel }
|
|
3568
|
-
{ label: "Accounts", Panel: AccountsPanel }
|
|
3563
|
+
{ label: "Settings", Panel: SettingsPanel }
|
|
3569
3564
|
];
|
|
3570
3565
|
var BANNER_HEX = ["white", "white", "white", "white", "white", "white"];
|
|
3571
3566
|
function Banner({ cols }) {
|
|
3572
3567
|
const wide = cols >= 82;
|
|
3573
3568
|
if (!wide) {
|
|
3574
|
-
return /* @__PURE__ */
|
|
3575
|
-
/* @__PURE__ */
|
|
3576
|
-
/* @__PURE__ */
|
|
3569
|
+
return /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
3570
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate" }),
|
|
3571
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \u2014 security control center" })
|
|
3577
3572
|
] });
|
|
3578
3573
|
}
|
|
3579
|
-
return /* @__PURE__ */
|
|
3580
|
-
BANNER_FULL.map((line, i) => /* @__PURE__ */
|
|
3581
|
-
/* @__PURE__ */
|
|
3574
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
3575
|
+
BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx8(Text8, { bold: true, color: BANNER_HEX[i], children: line }, i)),
|
|
3576
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
|
|
3582
3577
|
] });
|
|
3583
3578
|
}
|
|
3584
|
-
var
|
|
3579
|
+
var SETTINGS_SECTION = SECTIONS.findIndex((s) => s.label === "Settings");
|
|
3585
3580
|
function App() {
|
|
3586
3581
|
const { exit } = useApp();
|
|
3587
|
-
const [accounts, setAccounts] =
|
|
3588
|
-
const [viewKey, setViewKey] =
|
|
3589
|
-
const [viewNonce, setViewNonce] =
|
|
3590
|
-
const [section, setSection] =
|
|
3591
|
-
const [focus, setFocus] =
|
|
3592
|
-
const [help, setHelp] =
|
|
3593
|
-
const [update2, setUpdate] =
|
|
3582
|
+
const [accounts, setAccounts] = useState8(() => listAccounts());
|
|
3583
|
+
const [viewKey, setViewKey] = useState8(() => accounts[0]?.apiKey);
|
|
3584
|
+
const [viewNonce, setViewNonce] = useState8(0);
|
|
3585
|
+
const [section, setSection] = useState8(accounts.length === 0 ? SETTINGS_SECTION : 0);
|
|
3586
|
+
const [focus, setFocus] = useState8("nav");
|
|
3587
|
+
const [help, setHelp] = useState8(false);
|
|
3588
|
+
const [update2, setUpdate] = useState8({ kind: "idle" });
|
|
3594
3589
|
useEffect7(() => {
|
|
3595
3590
|
let alive = true;
|
|
3596
3591
|
const run = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
@@ -3603,15 +3598,16 @@ function App() {
|
|
|
3603
3598
|
}, []);
|
|
3604
3599
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
3605
3600
|
const cur = accounts[acctIdx];
|
|
3606
|
-
const
|
|
3601
|
+
const acctLabel2 = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
|
|
3607
3602
|
useEffect7(() => {
|
|
3608
|
-
if (!cur || cur.
|
|
3603
|
+
if (!cur || cur.email) return;
|
|
3609
3604
|
let alive = true;
|
|
3610
3605
|
api.auth.me().then((r) => {
|
|
3611
|
-
const project = r.project?.name ||
|
|
3612
|
-
const user = r.user?.name ||
|
|
3613
|
-
|
|
3614
|
-
|
|
3606
|
+
const project = r.project?.name || cur.project;
|
|
3607
|
+
const user = r.user?.name || cur.user;
|
|
3608
|
+
const email = r.user?.email || void 0;
|
|
3609
|
+
if (!alive || !project && !user && !email) return;
|
|
3610
|
+
saveAccount({ ...cur, project, user, email });
|
|
3615
3611
|
setAccounts(listAccounts());
|
|
3616
3612
|
}).catch(() => {
|
|
3617
3613
|
});
|
|
@@ -3630,8 +3626,8 @@ function App() {
|
|
|
3630
3626
|
viewAccount(accounts[(acctIdx + 1) % accounts.length]);
|
|
3631
3627
|
};
|
|
3632
3628
|
const locked = accounts.length === 0;
|
|
3633
|
-
const effectiveSection = locked ?
|
|
3634
|
-
|
|
3629
|
+
const effectiveSection = locked ? SETTINGS_SECTION : section;
|
|
3630
|
+
useInput7((input, key) => {
|
|
3635
3631
|
if (help) {
|
|
3636
3632
|
setHelp(false);
|
|
3637
3633
|
return;
|
|
@@ -3659,29 +3655,29 @@ function App() {
|
|
|
3659
3655
|
});
|
|
3660
3656
|
const { cols, rows } = useTermSize();
|
|
3661
3657
|
const current = SECTIONS[effectiveSection];
|
|
3662
|
-
if (help) return /* @__PURE__ */
|
|
3658
|
+
if (help) return /* @__PURE__ */ jsx8(HelpOverlay, { cols, rows });
|
|
3663
3659
|
if (current.label === "Live" && focus === "panel") {
|
|
3664
|
-
return /* @__PURE__ */
|
|
3660
|
+
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx8(LivePanel, { active: true, focused: true }, viewNonce) });
|
|
3665
3661
|
}
|
|
3666
3662
|
const Panel = current.Panel;
|
|
3667
|
-
const panelBody = current.label === "
|
|
3668
|
-
return /* @__PURE__ */
|
|
3669
|
-
/* @__PURE__ */
|
|
3670
|
-
/* @__PURE__ */
|
|
3671
|
-
/* @__PURE__ */
|
|
3672
|
-
/* @__PURE__ */
|
|
3673
|
-
locked ? /* @__PURE__ */
|
|
3674
|
-
update2.kind === "updating" ? /* @__PURE__ */
|
|
3663
|
+
const panelBody = current.label === "Settings" ? /* @__PURE__ */ jsx8(SettingsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount }) : /* @__PURE__ */ jsx8(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
|
|
3664
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
|
|
3665
|
+
/* @__PURE__ */ jsx8(Banner, { cols }),
|
|
3666
|
+
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
3667
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "account: " }),
|
|
3668
|
+
/* @__PURE__ */ jsx8(Text8, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel2 }),
|
|
3669
|
+
locked ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 log in from Settings to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Settings to manage)` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 Settings to add another" }),
|
|
3670
|
+
update2.kind === "updating" ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \u2014 restart (q, then solongate) to apply` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
|
|
3675
3671
|
] }),
|
|
3676
|
-
/* @__PURE__ */
|
|
3677
|
-
/* @__PURE__ */
|
|
3672
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexGrow: 1, children: [
|
|
3673
|
+
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
|
3678
3674
|
const isCur = i === effectiveSection;
|
|
3679
|
-
const disabled = locked && s.label !== "
|
|
3680
|
-
return /* @__PURE__ */
|
|
3675
|
+
const disabled = locked && s.label !== "Settings";
|
|
3676
|
+
return /* @__PURE__ */ jsx8(Text8, { color: isCur ? theme.accentBright : disabled ? theme.dim : void 0, bold: isCur, dimColor: disabled, children: (isCur ? "\u25B8 " : disabled ? "\u2298 " : " ") + s.label }, s.label);
|
|
3681
3677
|
}) }),
|
|
3682
|
-
/* @__PURE__ */
|
|
3678
|
+
/* @__PURE__ */ jsx8(Box8, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: panelBody })
|
|
3683
3679
|
] }, viewNonce),
|
|
3684
|
-
/* @__PURE__ */
|
|
3680
|
+
/* @__PURE__ */ jsx8(Box8, { children: locked ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2192/enter", "open Settings"], ["n", "log in"], ["q", "quit"]] }) : focus === "nav" ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ...accounts.length > 1 ? [["a", "account"]] : [], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
|
|
3685
3681
|
] });
|
|
3686
3682
|
}
|
|
3687
3683
|
var HELP = [
|
|
@@ -3694,21 +3690,21 @@ var HELP = [
|
|
|
3694
3690
|
["Accounts", [["a", "switch account (view another account logged in on this device)"], ["", "the header shows which account you are viewing; guard/logging keep the active key"]]]
|
|
3695
3691
|
];
|
|
3696
3692
|
function HelpOverlay({ cols, rows }) {
|
|
3697
|
-
return /* @__PURE__ */
|
|
3698
|
-
/* @__PURE__ */
|
|
3699
|
-
/* @__PURE__ */
|
|
3700
|
-
/* @__PURE__ */
|
|
3701
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
3702
|
-
/* @__PURE__ */
|
|
3703
|
-
/* @__PURE__ */
|
|
3693
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
|
|
3694
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
|
|
3695
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
|
|
3696
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accent, children: group }),
|
|
3697
|
+
keys.map(([k, desc]) => /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
3698
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
|
|
3699
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: desc })
|
|
3704
3700
|
] }, k))
|
|
3705
3701
|
] }, group)) }),
|
|
3706
|
-
/* @__PURE__ */
|
|
3702
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "press any key to close" })
|
|
3707
3703
|
] });
|
|
3708
3704
|
}
|
|
3709
3705
|
|
|
3710
3706
|
// src/tui/index.tsx
|
|
3711
|
-
import { jsx as
|
|
3707
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
3712
3708
|
async function launchTui() {
|
|
3713
3709
|
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
3714
3710
|
process.stderr.write(
|
|
@@ -3733,7 +3729,7 @@ async function launchTui() {
|
|
|
3733
3729
|
console.info = toFile("info");
|
|
3734
3730
|
console.debug = toFile("debug");
|
|
3735
3731
|
try {
|
|
3736
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
3732
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx9(App, {}), { patchConsole: false });
|
|
3737
3733
|
await waitUntilExit();
|
|
3738
3734
|
} finally {
|
|
3739
3735
|
Object.assign(console, saved);
|