@solongate/proxy 0.81.69 → 0.81.71
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 +8 -0
- package/dist/global-install.d.ts +1 -0
- package/dist/global-install.js +10 -1
- package/dist/index.js +597 -559
- package/dist/login.js +1 -1
- package/dist/tui/components.d.ts +31 -0
- package/dist/tui/index.js +233 -173
- package/dist/tui/panels/Settings.d.ts +4 -1
- package/package.json +1 -1
package/dist/tui/index.js
CHANGED
|
@@ -5,9 +5,9 @@ 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 mkdirSync7 } from "fs";
|
|
9
|
+
import { homedir as homedir9 } from "os";
|
|
10
|
+
import { join as join9 } from "path";
|
|
11
11
|
import { render } from "ink";
|
|
12
12
|
|
|
13
13
|
// src/tui/App.tsx
|
|
@@ -125,6 +125,43 @@ function ago(ts) {
|
|
|
125
125
|
|
|
126
126
|
// src/tui/components.tsx
|
|
127
127
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
128
|
+
var hhmmss = (ts) => {
|
|
129
|
+
const d = new Date(ts);
|
|
130
|
+
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
131
|
+
};
|
|
132
|
+
function PaneTitle({ label, extra, width }) {
|
|
133
|
+
const tail = extra ? ` ${extra} ` : " ";
|
|
134
|
+
const used = 2 + 1 + label.length + tail.length;
|
|
135
|
+
return /* @__PURE__ */ jsxs(Text, { wrap: "truncate", children: [
|
|
136
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: "\u2500 " }),
|
|
137
|
+
/* @__PURE__ */ jsxs(Text, { color: theme.accentBright, bold: true, children: [
|
|
138
|
+
"\u258E",
|
|
139
|
+
label
|
|
140
|
+
] }),
|
|
141
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width - used)) })
|
|
142
|
+
] });
|
|
143
|
+
}
|
|
144
|
+
function StreamLine({ e, loc, selected }) {
|
|
145
|
+
return /* @__PURE__ */ jsxs(Text, { wrap: "truncate", backgroundColor: selected ? "#1c2f63" : void 0, children: [
|
|
146
|
+
/* @__PURE__ */ jsx(Text, { color: selected ? theme.accentBright : theme.dim, children: selected ? "\u25B8" : " " }),
|
|
147
|
+
/* @__PURE__ */ jsxs(Text, { color: theme.dim, children: [
|
|
148
|
+
"[",
|
|
149
|
+
hhmmss(e.at),
|
|
150
|
+
" "
|
|
151
|
+
] }),
|
|
152
|
+
/* @__PURE__ */ jsx(Text, { color: loc ? theme.ok : "white", children: loc ? "LOC" : "CLD" }),
|
|
153
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: "] " }),
|
|
154
|
+
/* @__PURE__ */ jsx(Text, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
155
|
+
/* @__PURE__ */ jsx(Text, { color: theme.accent, children: truncate(e.tool, 12).padEnd(13) }),
|
|
156
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: (e.permission ?? "").padEnd(5) }),
|
|
157
|
+
/* @__PURE__ */ jsx(Text, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
|
|
158
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncate(e.agent ?? "-", 11).padEnd(12) }),
|
|
159
|
+
/* @__PURE__ */ jsx(Text, { color: e.dlp ? theme.bad : theme.dim, bold: e.dlp, children: ("dlp:" + (e.dlp ? "yes" : "no")).padEnd(8) }),
|
|
160
|
+
/* @__PURE__ */ jsx(Text, { color: e.burst ? theme.warn : theme.dim, bold: e.burst, children: ("rl:" + (e.burst ? "yes" : "no")).padEnd(7) }),
|
|
161
|
+
e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx(Text, { color: theme.bad, children: truncate(e.rule, 14) + " " }) : null,
|
|
162
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: e.detail })
|
|
163
|
+
] });
|
|
164
|
+
}
|
|
128
165
|
function DataView({
|
|
129
166
|
loading,
|
|
130
167
|
error,
|
|
@@ -322,6 +359,28 @@ function setActiveAccount(creds) {
|
|
|
322
359
|
return false;
|
|
323
360
|
}
|
|
324
361
|
}
|
|
362
|
+
function clearActiveCredential() {
|
|
363
|
+
try {
|
|
364
|
+
const p = join3(homedir3(), ".solongate", ["cloud", "guard.json"].join("-"));
|
|
365
|
+
if (!existsSync(p)) {
|
|
366
|
+
cached2 = null;
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
let existing = {};
|
|
370
|
+
try {
|
|
371
|
+
existing = JSON.parse(readFileSync3(p, "utf-8"));
|
|
372
|
+
} catch {
|
|
373
|
+
}
|
|
374
|
+
delete existing.apiKey;
|
|
375
|
+
delete existing.apiUrl;
|
|
376
|
+
writeFileSync2(p, JSON.stringify(existing, null, 2));
|
|
377
|
+
cached2 = null;
|
|
378
|
+
viewOverride = null;
|
|
379
|
+
return true;
|
|
380
|
+
} catch {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
325
384
|
var ApiError = class extends Error {
|
|
326
385
|
status;
|
|
327
386
|
code;
|
|
@@ -824,10 +883,6 @@ var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826"
|
|
|
824
883
|
var BG = "#12234f";
|
|
825
884
|
var DIM_FLOOR = "#233457";
|
|
826
885
|
var RING = join4(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
827
|
-
var hhmmss = (ts) => {
|
|
828
|
-
const d = new Date(ts);
|
|
829
|
-
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
830
|
-
};
|
|
831
886
|
var fmtUp = (ms) => {
|
|
832
887
|
const s = Math.floor(ms / 1e3);
|
|
833
888
|
const p = (n) => String(n).padStart(2, "0");
|
|
@@ -899,39 +954,6 @@ function HBar({ label, value, max, width, color }) {
|
|
|
899
954
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + value })
|
|
900
955
|
] });
|
|
901
956
|
}
|
|
902
|
-
function PaneTitle({ label, extra, width }) {
|
|
903
|
-
const tail = extra ? ` ${extra} ` : " ";
|
|
904
|
-
const used = 2 + 1 + label.length + tail.length;
|
|
905
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
906
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2500 " }),
|
|
907
|
-
/* @__PURE__ */ jsxs2(Text2, { color: theme.accentBright, bold: true, children: [
|
|
908
|
-
"\u258E",
|
|
909
|
-
label
|
|
910
|
-
] }),
|
|
911
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width - used)) })
|
|
912
|
-
] });
|
|
913
|
-
}
|
|
914
|
-
function StreamLine({ e, loc, selected }) {
|
|
915
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: selected ? "#1c2f63" : void 0, children: [
|
|
916
|
-
/* @__PURE__ */ jsx2(Text2, { color: selected ? theme.accentBright : theme.dim, children: selected ? "\u25B8" : " " }),
|
|
917
|
-
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
918
|
-
"[",
|
|
919
|
-
hhmmss(e.at),
|
|
920
|
-
" "
|
|
921
|
-
] }),
|
|
922
|
-
/* @__PURE__ */ jsx2(Text2, { color: loc ? theme.ok : "white", children: loc ? "LOC" : "CLD" }),
|
|
923
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
|
|
924
|
-
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
925
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate(e.tool, 12).padEnd(13) }),
|
|
926
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
|
|
927
|
-
/* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
|
|
928
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate(e.agent ?? "-", 11).padEnd(12) }),
|
|
929
|
-
/* @__PURE__ */ jsx2(Text2, { color: e.dlp ? theme.bad : theme.dim, bold: e.dlp, children: ("dlp:" + (e.dlp ? "yes" : "no")).padEnd(8) }),
|
|
930
|
-
/* @__PURE__ */ jsx2(Text2, { color: e.burst ? theme.warn : theme.dim, bold: e.burst, children: ("rl:" + (e.burst ? "yes" : "no")).padEnd(7) }),
|
|
931
|
-
e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: truncate(e.rule, 14) + " " }) : null,
|
|
932
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
|
|
933
|
-
] });
|
|
934
|
-
}
|
|
935
957
|
var FILTERS = ["all", "local", "cloud"];
|
|
936
958
|
var sessStatus = (lastAt, now) => now - lastAt < 6e4 ? "active" : now - lastAt < 3e5 ? "idle" : "ended";
|
|
937
959
|
var STATUS_STYLE = {
|
|
@@ -2472,12 +2494,25 @@ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
|
2472
2494
|
import { homedir as homedir5 } from "os";
|
|
2473
2495
|
import { join as join5 } from "path";
|
|
2474
2496
|
import { useState as useState6 } from "react";
|
|
2475
|
-
import {
|
|
2497
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2476
2498
|
var DECISIONS = [void 0, "DENY", "ALLOW"];
|
|
2477
2499
|
var SIGNALS = [void 0, "dlp", "ratelimit"];
|
|
2478
2500
|
var SESS_STATUS = [void 0, "active", "idle", "ended"];
|
|
2479
2501
|
var PAGE = 500;
|
|
2480
2502
|
var LOCAL_MAX_BYTES = 16 * 1024 * 1024;
|
|
2503
|
+
var BG2 = "#12234f";
|
|
2504
|
+
var toStream = (e) => ({
|
|
2505
|
+
at: e.at,
|
|
2506
|
+
tool: e.tool,
|
|
2507
|
+
decision: e.decision,
|
|
2508
|
+
permission: (e.permission ?? "").slice(0, 4),
|
|
2509
|
+
detail: (e.args ?? e.reason ?? "").replace(/\s+/g, " "),
|
|
2510
|
+
dlp: e.dlp.length > 0,
|
|
2511
|
+
burst: e.burst,
|
|
2512
|
+
agent: e.agent,
|
|
2513
|
+
evalMs: e.evalMs,
|
|
2514
|
+
rule: e.rule
|
|
2515
|
+
});
|
|
2481
2516
|
var cloudRow = (e) => {
|
|
2482
2517
|
const rs = reasonSignals(e.reason);
|
|
2483
2518
|
return {
|
|
@@ -2557,7 +2592,7 @@ var AUDIT_HELP = [
|
|
|
2557
2592
|
["esc", "back to the menu"]
|
|
2558
2593
|
]
|
|
2559
2594
|
],
|
|
2560
|
-
["Entry
|
|
2595
|
+
["Entry (full content)", [["\u2191\u2193 / PgUp PgDn", "scroll the reason + arguments"], ["space", "copy mode (freeze, then select)"], ["\u2190 / esc", "back to the list"]]]
|
|
2561
2596
|
];
|
|
2562
2597
|
var sessStatus2 = (lastAt) => Date.now() - lastAt < 6e4 ? "active" : Date.now() - lastAt < 3e5 ? "idle" : "ended";
|
|
2563
2598
|
var STATUS_DOT = {
|
|
@@ -2662,10 +2697,6 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2662
2697
|
const sq = sessSearch.trim().toLowerCase();
|
|
2663
2698
|
const sessionsFiltered = sessions.map((s) => ({ ...s, status: source === "cloud" ? s.status : sessStatus2(s.lastAt) })).filter((s) => SESS_STATUS[si] ? s.status === SESS_STATUS[si] : true).filter((s) => !sq || `${s.agent} ${s.id}`.toLowerCase().includes(sq)).sort((a, b) => b.lastAt - a.lastAt);
|
|
2664
2699
|
const currentSess = sessionsFiltered[Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1))];
|
|
2665
|
-
const sessionQ = useLoader(
|
|
2666
|
-
() => view === "detail" && current?.session && source === "cloud" ? api.audit.list({ session_id: current.session, limit: 40 }) : Promise.resolve(null),
|
|
2667
|
-
[view, current?.session, source]
|
|
2668
|
-
);
|
|
2669
2700
|
const logsLoading = (source === "cloud" ? cloudQ.loading : localQ.loading) && !editing;
|
|
2670
2701
|
const sessLoading = source === "cloud" ? agentsQ.loading : localQ.loading;
|
|
2671
2702
|
const doDelete = (kind) => {
|
|
@@ -2891,61 +2922,56 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2891
2922
|
] });
|
|
2892
2923
|
}
|
|
2893
2924
|
if (view === "detail" && current) {
|
|
2894
|
-
const
|
|
2895
|
-
const
|
|
2896
|
-
const
|
|
2897
|
-
const
|
|
2898
|
-
const
|
|
2899
|
-
|
|
2900
|
-
const
|
|
2901
|
-
|
|
2925
|
+
const e = current;
|
|
2926
|
+
const loc = source === "local";
|
|
2927
|
+
const bodyW = Math.max(20, cols - 4);
|
|
2928
|
+
const innerW = cols - 2;
|
|
2929
|
+
const contentLines = [];
|
|
2930
|
+
if (e.reason && e.decision !== "ALLOW") contentLines.push(...wrapLines("reason: " + e.reason, bodyW), "");
|
|
2931
|
+
const argsText = e.args ? prettyJson(e.args) : e.reason && e.decision === "ALLOW" ? e.reason : "(no arguments recorded)";
|
|
2932
|
+
contentLines.push(...wrapLines(argsText, bodyW));
|
|
2933
|
+
const bodyRows = Math.max(4, rows - 7 - (frozen ? 1 : 0));
|
|
2934
|
+
const maxScroll = Math.max(0, contentLines.length - bodyRows);
|
|
2902
2935
|
const off = Math.min(detailScroll, maxScroll);
|
|
2903
|
-
const
|
|
2936
|
+
const win = contentLines.slice(off, off + bodyRows);
|
|
2904
2937
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
2905
2938
|
copyBanner,
|
|
2906
|
-
/* @__PURE__ */ jsxs6(
|
|
2907
|
-
/* @__PURE__ */ jsx6(Text6, { color:
|
|
2908
|
-
/* @__PURE__ */ jsx6(Text6, { color:
|
|
2909
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.
|
|
2910
|
-
|
|
2939
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
2940
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
|
|
2941
|
+
/* @__PURE__ */ jsx6(Text6, { color: decisionColor(e.decision), bold: true, children: " " + e.decision }),
|
|
2942
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, bold: true, children: " " + e.tool }),
|
|
2943
|
+
/* @__PURE__ */ jsx6(Text6, { color: loc ? theme.ok : "white", children: " " + (loc ? "LOC" : "CLD") }),
|
|
2944
|
+
e.dlp.length ? /* @__PURE__ */ jsx6(Text6, { color: theme.bad, children: " DLP!" }) : null,
|
|
2945
|
+
e.burst ? /* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: " BURST" }) : null,
|
|
2946
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2190 back" })
|
|
2911
2947
|
] }),
|
|
2912
|
-
|
|
2913
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "
|
|
2914
|
-
/* @__PURE__ */ jsx6(Text6, { children:
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
/* @__PURE__ */ jsx6(
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
rows: sessionCalls.slice(0, Math.max(1, sessionRows - 2)).map((e) => [
|
|
2940
|
-
{ value: e.decision, color: decisionColor(e.decision) },
|
|
2941
|
-
{ value: truncate(e.tool, 20), color: theme.accent },
|
|
2942
|
-
{ value: truncate(e.reason ?? "\u2014", Math.max(16, cols - 48)) },
|
|
2943
|
-
{ value: ago(e.at), dim: true }
|
|
2944
|
-
])
|
|
2945
|
-
}
|
|
2946
|
-
)
|
|
2947
|
-
] }) : /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "(no session id)" }),
|
|
2948
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2191\u2193 scroll arguments \xB7 \u2190/esc back to logs" })
|
|
2948
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
2949
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2502 when " }),
|
|
2950
|
+
/* @__PURE__ */ jsx6(Text6, { children: new Date(e.at).toLocaleString() }),
|
|
2951
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 perm " }),
|
|
2952
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.permission || "\u2014" }),
|
|
2953
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 trust " }),
|
|
2954
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.trust || "\u2014" }),
|
|
2955
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 eval " }),
|
|
2956
|
+
/* @__PURE__ */ jsx6(Text6, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : void 0, children: e.evalMs != null ? `${e.evalMs}ms` : "\u2014" }),
|
|
2957
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 agent " }),
|
|
2958
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.agent ?? "\u2014" }),
|
|
2959
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502" })
|
|
2960
|
+
] }),
|
|
2961
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
2962
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2502 session " }),
|
|
2963
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: e.session ?? "\u2014" }),
|
|
2964
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 rule " }),
|
|
2965
|
+
/* @__PURE__ */ jsx6(Text6, { color: e.rule && e.decision !== "ALLOW" ? theme.bad : theme.dim, children: e.rule ?? "\u2014" }),
|
|
2966
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502" })
|
|
2967
|
+
] }),
|
|
2968
|
+
/* @__PURE__ */ jsx6(PaneTitle, { label: "FULL CONTENT", extra: `${contentLines.length} lines${maxScroll ? ` \xB7 \u25BC${maxScroll - off} more \xB7 \u2191\u2193 scroll` : ""} \xB7 space copy \xB7 \u2190 back`, width: innerW }),
|
|
2969
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win.map((l, i) => /* @__PURE__ */ jsx6(Text6, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
2970
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
2971
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
|
|
2972
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: "#0b1530", color: "white", children: ` ${e.id} ` }),
|
|
2973
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", children: " \u2191\u2193 scroll \xB7 space copy \xB7 ? all keys \xB7 \u2190 back \xB7 esc menu " })
|
|
2974
|
+
] })
|
|
2949
2975
|
] });
|
|
2950
2976
|
}
|
|
2951
2977
|
const chip = (label, val, on) => /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
@@ -3032,7 +3058,6 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3032
3058
|
const maxStart = Math.max(0, pageRows.length - listRows);
|
|
3033
3059
|
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
3034
3060
|
const windowed = pageRows.slice(start, start + listRows);
|
|
3035
|
-
const reasonW = Math.min(58, Math.max(12, cols - 71));
|
|
3036
3061
|
return /* @__PURE__ */ jsx6(DataView, { loading: logsLoading && !frozen, error: source === "cloud" ? cloudQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
3037
3062
|
strip,
|
|
3038
3063
|
copyBanner,
|
|
@@ -3068,21 +3093,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3068
3093
|
)
|
|
3069
3094
|
] }) : null,
|
|
3070
3095
|
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, wrap: "truncate", children: `${total} matched \xB7 page ${Math.min(page + 1, pages)}/${pages} \xB7 ${PAGE}/page \xB7 ${pageRows.length ? selClamped + 1 : 0}/${pageRows.length}${start ? ` \xB7 \u25B2${start} newer` : ""}${start + listRows < pageRows.length ? ` \xB7 \u25BC${pageRows.length - start - listRows} older` : ""}` }),
|
|
3071
|
-
/* @__PURE__ */ jsx6(
|
|
3072
|
-
Table,
|
|
3073
|
-
{
|
|
3074
|
-
columns: [
|
|
3075
|
-
{ header: "", width: 2 },
|
|
3076
|
-
{ header: "DECISION", width: 9 },
|
|
3077
|
-
{ header: "TOOL", width: 18 },
|
|
3078
|
-
{ header: "AGENT", width: 14 },
|
|
3079
|
-
{ header: "REASON", width: reasonW },
|
|
3080
|
-
{ header: "SIGNAL", width: 8 },
|
|
3081
|
-
{ header: "WHEN", width: 6 }
|
|
3082
|
-
],
|
|
3083
|
-
rows: windowed.map((e, i) => rowFor(e, start + i === selClamped && focused, reasonW))
|
|
3084
|
-
}
|
|
3085
|
-
),
|
|
3096
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", overflow: "hidden", children: windowed.map((e, i) => /* @__PURE__ */ jsx6(StreamLine, { e: toStream(e), loc: source === "local", selected: start + i === selClamped && focused }, e.id)) }),
|
|
3086
3097
|
pageRows.length === 0 ? /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
3087
3098
|
"(no entries",
|
|
3088
3099
|
source === "local" ? " in the local file" : "",
|
|
@@ -3090,43 +3101,58 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3090
3101
|
] }) : null
|
|
3091
3102
|
] }) });
|
|
3092
3103
|
}
|
|
3093
|
-
function rowFor(e, active2, reasonW) {
|
|
3094
|
-
const sig = [e.dlp.length ? `DLP${e.dlp.length > 1 ? e.dlp.length : ""}` : "", e.burst ? "RL" : ""].filter(Boolean).join(" ");
|
|
3095
|
-
return [
|
|
3096
|
-
{ value: active2 ? "\u25B8" : "", color: theme.accentBright },
|
|
3097
|
-
{ value: e.decision, color: decisionColor(e.decision) },
|
|
3098
|
-
{ value: truncate(e.tool, 18), color: theme.accent },
|
|
3099
|
-
{ value: truncate(e.agent ?? "\u2014", 14), dim: true },
|
|
3100
|
-
{ value: truncate(e.reason ?? e.args ?? "\u2014", reasonW) },
|
|
3101
|
-
{ value: sig || "\xB7", color: sig ? theme.bad : void 0, dim: !sig },
|
|
3102
|
-
{ value: ago(e.at), dim: true }
|
|
3103
|
-
];
|
|
3104
|
-
}
|
|
3105
|
-
function Detail({ label, value, color }) {
|
|
3106
|
-
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
3107
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: label.padEnd(9) }),
|
|
3108
|
-
/* @__PURE__ */ jsx6(Text6, { color, wrap: "truncate", children: value })
|
|
3109
|
-
] });
|
|
3110
|
-
}
|
|
3111
3104
|
|
|
3112
3105
|
// src/tui/panels/Settings.tsx
|
|
3113
3106
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
3114
3107
|
import TextInput5 from "ink-text-input";
|
|
3115
3108
|
import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
|
|
3116
3109
|
|
|
3117
|
-
// src/
|
|
3118
|
-
import {
|
|
3119
|
-
import {
|
|
3110
|
+
// src/global-install.ts
|
|
3111
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync2, mkdirSync as mkdirSync4, rmSync } from "fs";
|
|
3112
|
+
import { resolve as resolve2, join as join6, dirname } from "path";
|
|
3120
3113
|
import { homedir as homedir6 } from "os";
|
|
3121
|
-
import { dirname, join as join6 } from "path";
|
|
3122
3114
|
import { fileURLToPath } from "url";
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
var
|
|
3115
|
+
import { createInterface } from "readline";
|
|
3116
|
+
import { execFileSync } from "child_process";
|
|
3117
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
3118
|
+
var HOOKS_DIR = resolve2(__dirname, "..", "hooks");
|
|
3119
|
+
function globalPaths() {
|
|
3120
|
+
const home = homedir6();
|
|
3121
|
+
const sgDir = join6(home, ".solongate");
|
|
3122
|
+
const hooksDir = join6(sgDir, "hooks");
|
|
3123
|
+
const claudeDir = join6(home, ".claude");
|
|
3124
|
+
return {
|
|
3125
|
+
home,
|
|
3126
|
+
sgDir,
|
|
3127
|
+
hooksDir,
|
|
3128
|
+
claudeDir,
|
|
3129
|
+
settingsPath: join6(claudeDir, "settings.json"),
|
|
3130
|
+
backupPath: join6(claudeDir, "settings.solongate.bak"),
|
|
3131
|
+
configPath: join6(sgDir, "cloud-guard.json")
|
|
3132
|
+
};
|
|
3133
|
+
}
|
|
3134
|
+
function clearGuardUpdateCheck() {
|
|
3135
|
+
try {
|
|
3136
|
+
rmSync(join6(globalPaths().sgDir, ".hook-update-check"), { force: true });
|
|
3137
|
+
return true;
|
|
3138
|
+
} catch {
|
|
3139
|
+
return false;
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
// src/logs-server-daemon.ts
|
|
3144
|
+
import { spawn as spawn3 } from "child_process";
|
|
3145
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
3146
|
+
import { homedir as homedir7 } from "os";
|
|
3147
|
+
import { dirname as dirname2, join as join7 } from "path";
|
|
3148
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3149
|
+
var DIR = join7(homedir7(), ".solongate");
|
|
3150
|
+
var STATE_FILE = join7(DIR, ".logs-server.json");
|
|
3151
|
+
var LOG_FILE = join7(DIR, "logs-server.log");
|
|
3126
3152
|
var LOGS_SERVER_PORT = 8788;
|
|
3127
3153
|
function readState() {
|
|
3128
3154
|
try {
|
|
3129
|
-
const s = JSON.parse(
|
|
3155
|
+
const s = JSON.parse(readFileSync5(STATE_FILE, "utf-8"));
|
|
3130
3156
|
return s && typeof s === "object" ? s : {};
|
|
3131
3157
|
} catch {
|
|
3132
3158
|
return {};
|
|
@@ -3134,8 +3160,8 @@ function readState() {
|
|
|
3134
3160
|
}
|
|
3135
3161
|
function writeState(s) {
|
|
3136
3162
|
try {
|
|
3137
|
-
|
|
3138
|
-
|
|
3163
|
+
mkdirSync5(DIR, { recursive: true });
|
|
3164
|
+
writeFileSync6(STATE_FILE, JSON.stringify(s));
|
|
3139
3165
|
} catch {
|
|
3140
3166
|
}
|
|
3141
3167
|
}
|
|
@@ -3160,9 +3186,9 @@ function startLogsServerDaemon() {
|
|
|
3160
3186
|
return { ...cur, desired: "on" };
|
|
3161
3187
|
}
|
|
3162
3188
|
try {
|
|
3163
|
-
|
|
3189
|
+
mkdirSync5(DIR, { recursive: true });
|
|
3164
3190
|
const log = openSync2(LOG_FILE, "a");
|
|
3165
|
-
const cli =
|
|
3191
|
+
const cli = join7(dirname2(fileURLToPath2(import.meta.url)), "index.js");
|
|
3166
3192
|
const p = spawn3(process.execPath, [cli, "logs-server"], {
|
|
3167
3193
|
detached: true,
|
|
3168
3194
|
stdio: ["ignore", log, log],
|
|
@@ -3190,7 +3216,7 @@ function stopLogsServerDaemon() {
|
|
|
3190
3216
|
}
|
|
3191
3217
|
|
|
3192
3218
|
// src/tui/panels/Settings.tsx
|
|
3193
|
-
import { Fragment as
|
|
3219
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3194
3220
|
var EVENTS = ["denials", "allowed", "all"];
|
|
3195
3221
|
var SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3196
3222
|
var SIGNALS2 = ["any", "deny", "dlp", "ratelimit"];
|
|
@@ -3211,7 +3237,8 @@ function SettingsPanel({
|
|
|
3211
3237
|
active: active2,
|
|
3212
3238
|
focused,
|
|
3213
3239
|
viewApiKey,
|
|
3214
|
-
onView
|
|
3240
|
+
onView,
|
|
3241
|
+
onAccountsChanged
|
|
3215
3242
|
}) {
|
|
3216
3243
|
void active2;
|
|
3217
3244
|
const { cols, rows } = usePanelSize();
|
|
@@ -3370,6 +3397,16 @@ function SettingsPanel({
|
|
|
3370
3397
|
setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
|
|
3371
3398
|
} else if (r.kind === "acct-add") {
|
|
3372
3399
|
beginLogin();
|
|
3400
|
+
} else if (r.kind === "guard") {
|
|
3401
|
+
if (!guard) return;
|
|
3402
|
+
if (guard.up_to_date) {
|
|
3403
|
+
setMsg({ text: `guard already on the latest hook (v${guard.latest})`, level: "ok" });
|
|
3404
|
+
return;
|
|
3405
|
+
}
|
|
3406
|
+
const armed = clearGuardUpdateCheck();
|
|
3407
|
+
setMsg(
|
|
3408
|
+
armed ? { text: `\u2713 update armed. now make your agent RUN any command (e.g. "echo ok"), not just chat; the guard installs v${guard.latest} on the next executed command`, level: "ok" } : { text: "\u2717 could not arm the update (check ~/.solongate permissions)", level: "bad" }
|
|
3409
|
+
);
|
|
3373
3410
|
} else if (r.kind === "self") {
|
|
3374
3411
|
if (!selfProt) return;
|
|
3375
3412
|
run(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
@@ -3475,16 +3512,31 @@ function SettingsPanel({
|
|
|
3475
3512
|
else activate(cur);
|
|
3476
3513
|
}
|
|
3477
3514
|
} else if (inp === "x" && cur.kind === "acct") {
|
|
3478
|
-
const
|
|
3515
|
+
const target = cur.acc;
|
|
3516
|
+
const k = "acct:" + target.apiKey;
|
|
3517
|
+
const wasActive = isActiveAccount(target.apiKey);
|
|
3518
|
+
const others = accounts.filter((a) => a.apiKey !== target.apiKey);
|
|
3479
3519
|
if (confirmDel !== k) {
|
|
3480
3520
|
setConfirmDel(k);
|
|
3481
|
-
|
|
3521
|
+
const note = wasActive ? others.length ? ` \u2014 the ACTIVE guard key; ${acctLabel(others[0])} takes over` : " \u2014 your ONLY account & the active guard key; this signs the device out (guard has no key until you log in again)" : " (the cloud account is untouched)";
|
|
3522
|
+
setMsg({ text: `press x again to remove ${acctLabel(target)} from this device${note}`, level: "bad" });
|
|
3482
3523
|
return;
|
|
3483
3524
|
}
|
|
3484
3525
|
setConfirmDel(null);
|
|
3485
|
-
removeAccount(
|
|
3486
|
-
|
|
3526
|
+
removeAccount(target.apiKey);
|
|
3527
|
+
let extra = " from this device";
|
|
3528
|
+
if (wasActive) {
|
|
3529
|
+
if (others.length) {
|
|
3530
|
+
setActiveAccount({ apiKey: others[0].apiKey, apiUrl: others[0].apiUrl });
|
|
3531
|
+
extra = ` \xB7 ${acctLabel(others[0])} is now the active key`;
|
|
3532
|
+
} else {
|
|
3533
|
+
clearActiveCredential();
|
|
3534
|
+
extra = " \xB7 signed out of this device";
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
setMsg({ text: `\u2713 removed ${acctLabel(target)}${extra}`, level: "ok" });
|
|
3487
3538
|
refreshAccounts();
|
|
3539
|
+
onAccountsChanged?.();
|
|
3488
3540
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
3489
3541
|
run("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
3490
3542
|
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
@@ -3608,9 +3660,9 @@ function SettingsPanel({
|
|
|
3608
3660
|
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3609
3661
|
cursor(r),
|
|
3610
3662
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
3611
|
-
guard ? /* @__PURE__ */ jsxs7(
|
|
3663
|
+
guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
3612
3664
|
/* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
|
|
3613
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available` }),
|
|
3665
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter to update` }),
|
|
3614
3666
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${guard.device_count} device${guard.device_count === 1 ? "" : "s"}${guard.outdated_count ? ` \xB7 ${guard.outdated_count} outdated` : ""}` })
|
|
3615
3667
|
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading\u2026" })
|
|
3616
3668
|
] });
|
|
@@ -3676,7 +3728,7 @@ function SettingsPanel({
|
|
|
3676
3728
|
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" ? "ACCOUNTS" : r.kind === "guard" || r.kind === "self" ? "PROTECTION" : r.kind === "ll-enabled" || r.kind === "ll-path" || r.kind === "ll-server" ? "LOCAL LOGS" : r.kind === "wh" || r.kind === "wh-add" ? "WEBHOOKS" : "ALERTS";
|
|
3677
3729
|
const SECTION_DESC = {
|
|
3678
3730
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
3679
|
-
PROTECTION: "guard hook version + self-protection toggle",
|
|
3731
|
+
PROTECTION: "guard hook version (enter to update) + self-protection toggle",
|
|
3680
3732
|
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
3681
3733
|
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
3682
3734
|
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 m on/off`
|
|
@@ -3734,18 +3786,18 @@ function SettingsPanel({
|
|
|
3734
3786
|
|
|
3735
3787
|
// src/self-update.ts
|
|
3736
3788
|
import { execFile, spawn as spawn4 } from "child_process";
|
|
3737
|
-
import { mkdirSync as
|
|
3738
|
-
import { homedir as
|
|
3739
|
-
import { dirname as
|
|
3740
|
-
import { fileURLToPath as
|
|
3789
|
+
import { mkdirSync as mkdirSync6, openSync as openSync3, readFileSync as readFileSync6, realpathSync, writeFileSync as writeFileSync7 } from "fs";
|
|
3790
|
+
import { homedir as homedir8 } from "os";
|
|
3791
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
3792
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3741
3793
|
var PKG = "@solongate/proxy";
|
|
3742
3794
|
var CHECK_EVERY_MS = 30 * 60 * 1e3;
|
|
3743
3795
|
var ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
3744
|
-
var STATE_FILE2 =
|
|
3745
|
-
var LOG_FILE2 =
|
|
3796
|
+
var STATE_FILE2 = join8(homedir8(), ".solongate", ".self-update.json");
|
|
3797
|
+
var LOG_FILE2 = join8(homedir8(), ".solongate", "self-update.log");
|
|
3746
3798
|
function readState2() {
|
|
3747
3799
|
try {
|
|
3748
|
-
const s = JSON.parse(
|
|
3800
|
+
const s = JSON.parse(readFileSync6(STATE_FILE2, "utf-8"));
|
|
3749
3801
|
return s && typeof s === "object" ? s : {};
|
|
3750
3802
|
} catch {
|
|
3751
3803
|
return {};
|
|
@@ -3753,14 +3805,14 @@ function readState2() {
|
|
|
3753
3805
|
}
|
|
3754
3806
|
function writeState2(s) {
|
|
3755
3807
|
try {
|
|
3756
|
-
|
|
3757
|
-
|
|
3808
|
+
mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
|
|
3809
|
+
writeFileSync7(STATE_FILE2, JSON.stringify(s));
|
|
3758
3810
|
} catch {
|
|
3759
3811
|
}
|
|
3760
3812
|
}
|
|
3761
3813
|
function currentVersion() {
|
|
3762
3814
|
try {
|
|
3763
|
-
const pkg = JSON.parse(
|
|
3815
|
+
const pkg = JSON.parse(readFileSync6(join8(dirname3(fileURLToPath3(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
3764
3816
|
return pkg.version ?? "0.0.0";
|
|
3765
3817
|
} catch {
|
|
3766
3818
|
return "0.0.0";
|
|
@@ -3792,13 +3844,13 @@ async function fetchLatest() {
|
|
|
3792
3844
|
}
|
|
3793
3845
|
}
|
|
3794
3846
|
function npmGlobalRoot() {
|
|
3795
|
-
return new Promise((
|
|
3847
|
+
return new Promise((resolve3) => {
|
|
3796
3848
|
try {
|
|
3797
3849
|
execFile("npm", ["root", "-g"], { timeout: 5e3, windowsHide: true, shell: process.platform === "win32" }, (err, stdout) => {
|
|
3798
|
-
|
|
3850
|
+
resolve3(err ? null : stdout.trim() || null);
|
|
3799
3851
|
});
|
|
3800
3852
|
} catch {
|
|
3801
|
-
|
|
3853
|
+
resolve3(null);
|
|
3802
3854
|
}
|
|
3803
3855
|
});
|
|
3804
3856
|
}
|
|
@@ -3814,26 +3866,26 @@ async function isGlobalInstall() {
|
|
|
3814
3866
|
}
|
|
3815
3867
|
}
|
|
3816
3868
|
function runGlobalInstall(version) {
|
|
3817
|
-
return new Promise((
|
|
3869
|
+
return new Promise((resolve3) => {
|
|
3818
3870
|
try {
|
|
3819
|
-
|
|
3871
|
+
mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
|
|
3820
3872
|
execFile(
|
|
3821
3873
|
"npm",
|
|
3822
3874
|
["install", "-g", `${PKG}@${version}`],
|
|
3823
3875
|
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
3824
3876
|
(err, stdout, stderr) => {
|
|
3825
3877
|
try {
|
|
3826
|
-
|
|
3878
|
+
writeFileSync7(LOG_FILE2, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err ? "FAILED" : "ok"}
|
|
3827
3879
|
${stdout}
|
|
3828
3880
|
${stderr}
|
|
3829
3881
|
`, { flag: "a" });
|
|
3830
3882
|
} catch {
|
|
3831
3883
|
}
|
|
3832
|
-
|
|
3884
|
+
resolve3(!err);
|
|
3833
3885
|
}
|
|
3834
3886
|
);
|
|
3835
3887
|
} catch {
|
|
3836
|
-
|
|
3888
|
+
resolve3(false);
|
|
3837
3889
|
}
|
|
3838
3890
|
});
|
|
3839
3891
|
}
|
|
@@ -3944,6 +3996,14 @@ function App() {
|
|
|
3944
3996
|
if (accounts.length < 2) return;
|
|
3945
3997
|
viewAccount(accounts[(acctIdx + 1) % accounts.length]);
|
|
3946
3998
|
};
|
|
3999
|
+
const syncAccounts = () => {
|
|
4000
|
+
const list5 = listAccounts();
|
|
4001
|
+
setAccounts(list5);
|
|
4002
|
+
const next = list5.find((a) => a.apiKey === viewKey) ?? list5[0];
|
|
4003
|
+
setViewCredentials(next ? { apiKey: next.apiKey, apiUrl: next.apiUrl } : null);
|
|
4004
|
+
setViewKey(next?.apiKey);
|
|
4005
|
+
setViewNonce((n) => n + 1);
|
|
4006
|
+
};
|
|
3947
4007
|
const locked = accounts.length === 0;
|
|
3948
4008
|
const effectiveSection = locked ? SETTINGS_SECTION : section;
|
|
3949
4009
|
useInput7((input, key) => {
|
|
@@ -3979,7 +4039,7 @@ function App() {
|
|
|
3979
4039
|
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx8(LivePanel, { active: true, focused: true }, viewNonce) });
|
|
3980
4040
|
}
|
|
3981
4041
|
const Panel = current.Panel;
|
|
3982
|
-
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" });
|
|
4042
|
+
const panelBody = current.label === "Settings" ? /* @__PURE__ */ jsx8(SettingsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount, onAccountsChanged: syncAccounts }) : /* @__PURE__ */ jsx8(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
|
|
3983
4043
|
return (
|
|
3984
4044
|
// height rows-1 (not rows): once total output reaches stdout.rows ink stops
|
|
3985
4045
|
// diffing and clearTerminal-repaints every frame, which slides the banner.
|
|
@@ -4037,11 +4097,11 @@ async function launchTui() {
|
|
|
4037
4097
|
return;
|
|
4038
4098
|
}
|
|
4039
4099
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
4040
|
-
const debugLog =
|
|
4100
|
+
const debugLog = join9(homedir9(), ".solongate", "dataroom-debug.log");
|
|
4041
4101
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
4042
4102
|
const toFile = (level) => (...args) => {
|
|
4043
4103
|
try {
|
|
4044
|
-
|
|
4104
|
+
mkdirSync7(join9(homedir9(), ".solongate"), { recursive: true });
|
|
4045
4105
|
appendFileSync(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
4046
4106
|
`);
|
|
4047
4107
|
} catch {
|