@solongate/proxy 0.81.68 → 0.81.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/global-install.d.ts +1 -0
- package/dist/global-install.js +10 -1
- package/dist/index.js +395 -397
- package/dist/login.js +1 -1
- package/dist/tui/components.d.ts +31 -0
- package/dist/tui/index.js +189 -169
- package/package.json +1 -1
package/dist/login.js
CHANGED
|
@@ -26,7 +26,7 @@ var c = {
|
|
|
26
26
|
var BANNER_COLORS = [c.blue1, c.blue2, c.blue3, c.blue4, c.blue5, c.blue6];
|
|
27
27
|
|
|
28
28
|
// src/global-install.ts
|
|
29
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
29
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync } from "fs";
|
|
30
30
|
import { resolve, join, dirname } from "path";
|
|
31
31
|
import { homedir } from "os";
|
|
32
32
|
import { fileURLToPath } from "url";
|
package/dist/tui/components.d.ts
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
/** HH:MM:SS for a timestamp (ms or ISO); `--:--:--` when unparseable. */
|
|
3
|
+
export declare const hhmmss: (ts: string | number) => string;
|
|
4
|
+
/** Section divider title used across the Live/Audit consoles. */
|
|
5
|
+
export declare function PaneTitle({ label, extra, width }: {
|
|
6
|
+
label: string;
|
|
7
|
+
extra?: string;
|
|
8
|
+
width: number;
|
|
9
|
+
}): JSX.Element;
|
|
10
|
+
/**
|
|
11
|
+
* One tool-stream row, shared verbatim by Live (rolling buffer) and Audit (full
|
|
12
|
+
* history). `loc` tags LOC vs CLD; `selected` highlights + shows the ▸ cursor.
|
|
13
|
+
* Columns are fixed-width and NEVER conditional so scrolling can't reshuffle the
|
|
14
|
+
* line and glitch the frame.
|
|
15
|
+
*/
|
|
16
|
+
export interface StreamRow {
|
|
17
|
+
at: number;
|
|
18
|
+
tool: string;
|
|
19
|
+
decision: string;
|
|
20
|
+
permission: string;
|
|
21
|
+
detail: string;
|
|
22
|
+
dlp: boolean;
|
|
23
|
+
burst: boolean;
|
|
24
|
+
agent?: string | null;
|
|
25
|
+
evalMs?: number | null;
|
|
26
|
+
rule?: string | null;
|
|
27
|
+
}
|
|
28
|
+
export declare function StreamLine({ e, loc, selected }: {
|
|
29
|
+
e: StreamRow;
|
|
30
|
+
loc: boolean;
|
|
31
|
+
selected?: boolean;
|
|
32
|
+
}): JSX.Element;
|
|
2
33
|
export declare function Panel({ title, subtitle, children }: {
|
|
3
34
|
title: string;
|
|
4
35
|
subtitle?: string;
|
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,
|
|
@@ -824,10 +861,6 @@ var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826"
|
|
|
824
861
|
var BG = "#12234f";
|
|
825
862
|
var DIM_FLOOR = "#233457";
|
|
826
863
|
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
864
|
var fmtUp = (ms) => {
|
|
832
865
|
const s = Math.floor(ms / 1e3);
|
|
833
866
|
const p = (n) => String(n).padStart(2, "0");
|
|
@@ -899,39 +932,6 @@ function HBar({ label, value, max, width, color }) {
|
|
|
899
932
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + value })
|
|
900
933
|
] });
|
|
901
934
|
}
|
|
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
935
|
var FILTERS = ["all", "local", "cloud"];
|
|
936
936
|
var sessStatus = (lastAt, now) => now - lastAt < 6e4 ? "active" : now - lastAt < 3e5 ? "idle" : "ended";
|
|
937
937
|
var STATUS_STYLE = {
|
|
@@ -2472,12 +2472,25 @@ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
|
2472
2472
|
import { homedir as homedir5 } from "os";
|
|
2473
2473
|
import { join as join5 } from "path";
|
|
2474
2474
|
import { useState as useState6 } from "react";
|
|
2475
|
-
import {
|
|
2475
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2476
2476
|
var DECISIONS = [void 0, "DENY", "ALLOW"];
|
|
2477
2477
|
var SIGNALS = [void 0, "dlp", "ratelimit"];
|
|
2478
2478
|
var SESS_STATUS = [void 0, "active", "idle", "ended"];
|
|
2479
2479
|
var PAGE = 500;
|
|
2480
2480
|
var LOCAL_MAX_BYTES = 16 * 1024 * 1024;
|
|
2481
|
+
var BG2 = "#12234f";
|
|
2482
|
+
var toStream = (e) => ({
|
|
2483
|
+
at: e.at,
|
|
2484
|
+
tool: e.tool,
|
|
2485
|
+
decision: e.decision,
|
|
2486
|
+
permission: (e.permission ?? "").slice(0, 4),
|
|
2487
|
+
detail: (e.args ?? e.reason ?? "").replace(/\s+/g, " "),
|
|
2488
|
+
dlp: e.dlp.length > 0,
|
|
2489
|
+
burst: e.burst,
|
|
2490
|
+
agent: e.agent,
|
|
2491
|
+
evalMs: e.evalMs,
|
|
2492
|
+
rule: e.rule
|
|
2493
|
+
});
|
|
2481
2494
|
var cloudRow = (e) => {
|
|
2482
2495
|
const rs = reasonSignals(e.reason);
|
|
2483
2496
|
return {
|
|
@@ -2557,7 +2570,7 @@ var AUDIT_HELP = [
|
|
|
2557
2570
|
["esc", "back to the menu"]
|
|
2558
2571
|
]
|
|
2559
2572
|
],
|
|
2560
|
-
["Entry
|
|
2573
|
+
["Entry (full content)", [["\u2191\u2193 / PgUp PgDn", "scroll the reason + arguments"], ["space", "copy mode (freeze, then select)"], ["\u2190 / esc", "back to the list"]]]
|
|
2561
2574
|
];
|
|
2562
2575
|
var sessStatus2 = (lastAt) => Date.now() - lastAt < 6e4 ? "active" : Date.now() - lastAt < 3e5 ? "idle" : "ended";
|
|
2563
2576
|
var STATUS_DOT = {
|
|
@@ -2662,10 +2675,6 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2662
2675
|
const sq = sessSearch.trim().toLowerCase();
|
|
2663
2676
|
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
2677
|
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
2678
|
const logsLoading = (source === "cloud" ? cloudQ.loading : localQ.loading) && !editing;
|
|
2670
2679
|
const sessLoading = source === "cloud" ? agentsQ.loading : localQ.loading;
|
|
2671
2680
|
const doDelete = (kind) => {
|
|
@@ -2891,61 +2900,56 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2891
2900
|
] });
|
|
2892
2901
|
}
|
|
2893
2902
|
if (view === "detail" && current) {
|
|
2894
|
-
const
|
|
2895
|
-
const
|
|
2896
|
-
const
|
|
2897
|
-
const
|
|
2898
|
-
const
|
|
2899
|
-
|
|
2900
|
-
const
|
|
2901
|
-
|
|
2903
|
+
const e = current;
|
|
2904
|
+
const loc = source === "local";
|
|
2905
|
+
const bodyW = Math.max(20, cols - 4);
|
|
2906
|
+
const innerW = cols - 2;
|
|
2907
|
+
const contentLines = [];
|
|
2908
|
+
if (e.reason && e.decision !== "ALLOW") contentLines.push(...wrapLines("reason: " + e.reason, bodyW), "");
|
|
2909
|
+
const argsText = e.args ? prettyJson(e.args) : e.reason && e.decision === "ALLOW" ? e.reason : "(no arguments recorded)";
|
|
2910
|
+
contentLines.push(...wrapLines(argsText, bodyW));
|
|
2911
|
+
const bodyRows = Math.max(4, rows - 7 - (frozen ? 1 : 0));
|
|
2912
|
+
const maxScroll = Math.max(0, contentLines.length - bodyRows);
|
|
2902
2913
|
const off = Math.min(detailScroll, maxScroll);
|
|
2903
|
-
const
|
|
2914
|
+
const win = contentLines.slice(off, off + bodyRows);
|
|
2904
2915
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
2905
2916
|
copyBanner,
|
|
2906
|
-
/* @__PURE__ */ jsxs6(
|
|
2907
|
-
/* @__PURE__ */ jsx6(Text6, { color:
|
|
2908
|
-
/* @__PURE__ */ jsx6(Text6, { color:
|
|
2909
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.
|
|
2910
|
-
|
|
2917
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
2918
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
|
|
2919
|
+
/* @__PURE__ */ jsx6(Text6, { color: decisionColor(e.decision), bold: true, children: " " + e.decision }),
|
|
2920
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, bold: true, children: " " + e.tool }),
|
|
2921
|
+
/* @__PURE__ */ jsx6(Text6, { color: loc ? theme.ok : "white", children: " " + (loc ? "LOC" : "CLD") }),
|
|
2922
|
+
e.dlp.length ? /* @__PURE__ */ jsx6(Text6, { color: theme.bad, children: " DLP!" }) : null,
|
|
2923
|
+
e.burst ? /* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: " BURST" }) : null,
|
|
2924
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2190 back" })
|
|
2911
2925
|
] }),
|
|
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" })
|
|
2926
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
2927
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2502 when " }),
|
|
2928
|
+
/* @__PURE__ */ jsx6(Text6, { children: new Date(e.at).toLocaleString() }),
|
|
2929
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 perm " }),
|
|
2930
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.permission || "\u2014" }),
|
|
2931
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 trust " }),
|
|
2932
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.trust || "\u2014" }),
|
|
2933
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 eval " }),
|
|
2934
|
+
/* @__PURE__ */ jsx6(Text6, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : void 0, children: e.evalMs != null ? `${e.evalMs}ms` : "\u2014" }),
|
|
2935
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 agent " }),
|
|
2936
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.agent ?? "\u2014" }),
|
|
2937
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502" })
|
|
2938
|
+
] }),
|
|
2939
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
2940
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2502 session " }),
|
|
2941
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: e.session ?? "\u2014" }),
|
|
2942
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 rule " }),
|
|
2943
|
+
/* @__PURE__ */ jsx6(Text6, { color: e.rule && e.decision !== "ALLOW" ? theme.bad : theme.dim, children: e.rule ?? "\u2014" }),
|
|
2944
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502" })
|
|
2945
|
+
] }),
|
|
2946
|
+
/* @__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 }),
|
|
2947
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win.map((l, i) => /* @__PURE__ */ jsx6(Text6, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
2948
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
2949
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
|
|
2950
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: "#0b1530", color: "white", children: ` ${e.id} ` }),
|
|
2951
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", children: " \u2191\u2193 scroll \xB7 space copy \xB7 ? all keys \xB7 \u2190 back \xB7 esc menu " })
|
|
2952
|
+
] })
|
|
2949
2953
|
] });
|
|
2950
2954
|
}
|
|
2951
2955
|
const chip = (label, val, on) => /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
@@ -3032,7 +3036,6 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3032
3036
|
const maxStart = Math.max(0, pageRows.length - listRows);
|
|
3033
3037
|
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
3034
3038
|
const windowed = pageRows.slice(start, start + listRows);
|
|
3035
|
-
const reasonW = Math.min(58, Math.max(12, cols - 71));
|
|
3036
3039
|
return /* @__PURE__ */ jsx6(DataView, { loading: logsLoading && !frozen, error: source === "cloud" ? cloudQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
3037
3040
|
strip,
|
|
3038
3041
|
copyBanner,
|
|
@@ -3068,21 +3071,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3068
3071
|
)
|
|
3069
3072
|
] }) : null,
|
|
3070
3073
|
/* @__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
|
-
),
|
|
3074
|
+
/* @__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
3075
|
pageRows.length === 0 ? /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
3087
3076
|
"(no entries",
|
|
3088
3077
|
source === "local" ? " in the local file" : "",
|
|
@@ -3090,43 +3079,58 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3090
3079
|
] }) : null
|
|
3091
3080
|
] }) });
|
|
3092
3081
|
}
|
|
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
3082
|
|
|
3112
3083
|
// src/tui/panels/Settings.tsx
|
|
3113
3084
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
3114
3085
|
import TextInput5 from "ink-text-input";
|
|
3115
3086
|
import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
|
|
3116
3087
|
|
|
3117
|
-
// src/
|
|
3118
|
-
import {
|
|
3119
|
-
import {
|
|
3088
|
+
// src/global-install.ts
|
|
3089
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync2, mkdirSync as mkdirSync4, rmSync } from "fs";
|
|
3090
|
+
import { resolve as resolve2, join as join6, dirname } from "path";
|
|
3120
3091
|
import { homedir as homedir6 } from "os";
|
|
3121
|
-
import { dirname, join as join6 } from "path";
|
|
3122
3092
|
import { fileURLToPath } from "url";
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
var
|
|
3093
|
+
import { createInterface } from "readline";
|
|
3094
|
+
import { execFileSync } from "child_process";
|
|
3095
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
3096
|
+
var HOOKS_DIR = resolve2(__dirname, "..", "hooks");
|
|
3097
|
+
function globalPaths() {
|
|
3098
|
+
const home = homedir6();
|
|
3099
|
+
const sgDir = join6(home, ".solongate");
|
|
3100
|
+
const hooksDir = join6(sgDir, "hooks");
|
|
3101
|
+
const claudeDir = join6(home, ".claude");
|
|
3102
|
+
return {
|
|
3103
|
+
home,
|
|
3104
|
+
sgDir,
|
|
3105
|
+
hooksDir,
|
|
3106
|
+
claudeDir,
|
|
3107
|
+
settingsPath: join6(claudeDir, "settings.json"),
|
|
3108
|
+
backupPath: join6(claudeDir, "settings.solongate.bak"),
|
|
3109
|
+
configPath: join6(sgDir, "cloud-guard.json")
|
|
3110
|
+
};
|
|
3111
|
+
}
|
|
3112
|
+
function clearGuardUpdateCheck() {
|
|
3113
|
+
try {
|
|
3114
|
+
rmSync(join6(globalPaths().sgDir, ".hook-update-check"), { force: true });
|
|
3115
|
+
return true;
|
|
3116
|
+
} catch {
|
|
3117
|
+
return false;
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
// src/logs-server-daemon.ts
|
|
3122
|
+
import { spawn as spawn3 } from "child_process";
|
|
3123
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
3124
|
+
import { homedir as homedir7 } from "os";
|
|
3125
|
+
import { dirname as dirname2, join as join7 } from "path";
|
|
3126
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3127
|
+
var DIR = join7(homedir7(), ".solongate");
|
|
3128
|
+
var STATE_FILE = join7(DIR, ".logs-server.json");
|
|
3129
|
+
var LOG_FILE = join7(DIR, "logs-server.log");
|
|
3126
3130
|
var LOGS_SERVER_PORT = 8788;
|
|
3127
3131
|
function readState() {
|
|
3128
3132
|
try {
|
|
3129
|
-
const s = JSON.parse(
|
|
3133
|
+
const s = JSON.parse(readFileSync5(STATE_FILE, "utf-8"));
|
|
3130
3134
|
return s && typeof s === "object" ? s : {};
|
|
3131
3135
|
} catch {
|
|
3132
3136
|
return {};
|
|
@@ -3134,8 +3138,8 @@ function readState() {
|
|
|
3134
3138
|
}
|
|
3135
3139
|
function writeState(s) {
|
|
3136
3140
|
try {
|
|
3137
|
-
|
|
3138
|
-
|
|
3141
|
+
mkdirSync5(DIR, { recursive: true });
|
|
3142
|
+
writeFileSync6(STATE_FILE, JSON.stringify(s));
|
|
3139
3143
|
} catch {
|
|
3140
3144
|
}
|
|
3141
3145
|
}
|
|
@@ -3160,9 +3164,9 @@ function startLogsServerDaemon() {
|
|
|
3160
3164
|
return { ...cur, desired: "on" };
|
|
3161
3165
|
}
|
|
3162
3166
|
try {
|
|
3163
|
-
|
|
3167
|
+
mkdirSync5(DIR, { recursive: true });
|
|
3164
3168
|
const log = openSync2(LOG_FILE, "a");
|
|
3165
|
-
const cli =
|
|
3169
|
+
const cli = join7(dirname2(fileURLToPath2(import.meta.url)), "index.js");
|
|
3166
3170
|
const p = spawn3(process.execPath, [cli, "logs-server"], {
|
|
3167
3171
|
detached: true,
|
|
3168
3172
|
stdio: ["ignore", log, log],
|
|
@@ -3190,7 +3194,7 @@ function stopLogsServerDaemon() {
|
|
|
3190
3194
|
}
|
|
3191
3195
|
|
|
3192
3196
|
// src/tui/panels/Settings.tsx
|
|
3193
|
-
import { Fragment as
|
|
3197
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3194
3198
|
var EVENTS = ["denials", "allowed", "all"];
|
|
3195
3199
|
var SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3196
3200
|
var SIGNALS2 = ["any", "deny", "dlp", "ratelimit"];
|
|
@@ -3370,6 +3374,16 @@ function SettingsPanel({
|
|
|
3370
3374
|
setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
|
|
3371
3375
|
} else if (r.kind === "acct-add") {
|
|
3372
3376
|
beginLogin();
|
|
3377
|
+
} else if (r.kind === "guard") {
|
|
3378
|
+
if (!guard) return;
|
|
3379
|
+
if (guard.up_to_date) {
|
|
3380
|
+
setMsg({ text: `guard already on the latest hook (v${guard.latest})`, level: "ok" });
|
|
3381
|
+
return;
|
|
3382
|
+
}
|
|
3383
|
+
const armed = clearGuardUpdateCheck();
|
|
3384
|
+
setMsg(
|
|
3385
|
+
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" }
|
|
3386
|
+
);
|
|
3373
3387
|
} else if (r.kind === "self") {
|
|
3374
3388
|
if (!selfProt) return;
|
|
3375
3389
|
run(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
@@ -3608,9 +3622,9 @@ function SettingsPanel({
|
|
|
3608
3622
|
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
3609
3623
|
cursor(r),
|
|
3610
3624
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
3611
|
-
guard ? /* @__PURE__ */ jsxs7(
|
|
3625
|
+
guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
3612
3626
|
/* @__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` }),
|
|
3627
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter to update` }),
|
|
3614
3628
|
/* @__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
3629
|
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading\u2026" })
|
|
3616
3630
|
] });
|
|
@@ -3676,7 +3690,7 @@ function SettingsPanel({
|
|
|
3676
3690
|
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
3691
|
const SECTION_DESC = {
|
|
3678
3692
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
3679
|
-
PROTECTION: "guard hook version + self-protection toggle",
|
|
3693
|
+
PROTECTION: "guard hook version (enter to update) + self-protection toggle",
|
|
3680
3694
|
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
3681
3695
|
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
3682
3696
|
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 m on/off`
|
|
@@ -3734,18 +3748,18 @@ function SettingsPanel({
|
|
|
3734
3748
|
|
|
3735
3749
|
// src/self-update.ts
|
|
3736
3750
|
import { execFile, spawn as spawn4 } from "child_process";
|
|
3737
|
-
import { mkdirSync as
|
|
3738
|
-
import { homedir as
|
|
3739
|
-
import { dirname as
|
|
3740
|
-
import { fileURLToPath as
|
|
3751
|
+
import { mkdirSync as mkdirSync6, openSync as openSync3, readFileSync as readFileSync6, realpathSync, writeFileSync as writeFileSync7 } from "fs";
|
|
3752
|
+
import { homedir as homedir8 } from "os";
|
|
3753
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
3754
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3741
3755
|
var PKG = "@solongate/proxy";
|
|
3742
3756
|
var CHECK_EVERY_MS = 30 * 60 * 1e3;
|
|
3743
3757
|
var ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
3744
|
-
var STATE_FILE2 =
|
|
3745
|
-
var LOG_FILE2 =
|
|
3758
|
+
var STATE_FILE2 = join8(homedir8(), ".solongate", ".self-update.json");
|
|
3759
|
+
var LOG_FILE2 = join8(homedir8(), ".solongate", "self-update.log");
|
|
3746
3760
|
function readState2() {
|
|
3747
3761
|
try {
|
|
3748
|
-
const s = JSON.parse(
|
|
3762
|
+
const s = JSON.parse(readFileSync6(STATE_FILE2, "utf-8"));
|
|
3749
3763
|
return s && typeof s === "object" ? s : {};
|
|
3750
3764
|
} catch {
|
|
3751
3765
|
return {};
|
|
@@ -3753,14 +3767,14 @@ function readState2() {
|
|
|
3753
3767
|
}
|
|
3754
3768
|
function writeState2(s) {
|
|
3755
3769
|
try {
|
|
3756
|
-
|
|
3757
|
-
|
|
3770
|
+
mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
|
|
3771
|
+
writeFileSync7(STATE_FILE2, JSON.stringify(s));
|
|
3758
3772
|
} catch {
|
|
3759
3773
|
}
|
|
3760
3774
|
}
|
|
3761
3775
|
function currentVersion() {
|
|
3762
3776
|
try {
|
|
3763
|
-
const pkg = JSON.parse(
|
|
3777
|
+
const pkg = JSON.parse(readFileSync6(join8(dirname3(fileURLToPath3(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
3764
3778
|
return pkg.version ?? "0.0.0";
|
|
3765
3779
|
} catch {
|
|
3766
3780
|
return "0.0.0";
|
|
@@ -3777,22 +3791,28 @@ function newerThan(b, a) {
|
|
|
3777
3791
|
}
|
|
3778
3792
|
async function fetchLatest() {
|
|
3779
3793
|
try {
|
|
3780
|
-
const res = await fetch(`https://registry.npmjs.org/${PKG}
|
|
3794
|
+
const res = await fetch(`https://registry.npmjs.org/${PKG}`, {
|
|
3795
|
+
headers: { accept: "application/vnd.npm.install-v1+json" },
|
|
3796
|
+
signal: AbortSignal.timeout(3e3)
|
|
3797
|
+
});
|
|
3781
3798
|
if (!res.ok) return null;
|
|
3782
3799
|
const j = await res.json();
|
|
3783
|
-
|
|
3800
|
+
const latest = j["dist-tags"]?.latest;
|
|
3801
|
+
if (typeof latest !== "string") return null;
|
|
3802
|
+
if (!j.versions || !(latest in j.versions)) return null;
|
|
3803
|
+
return latest;
|
|
3784
3804
|
} catch {
|
|
3785
3805
|
return null;
|
|
3786
3806
|
}
|
|
3787
3807
|
}
|
|
3788
3808
|
function npmGlobalRoot() {
|
|
3789
|
-
return new Promise((
|
|
3809
|
+
return new Promise((resolve3) => {
|
|
3790
3810
|
try {
|
|
3791
3811
|
execFile("npm", ["root", "-g"], { timeout: 5e3, windowsHide: true, shell: process.platform === "win32" }, (err, stdout) => {
|
|
3792
|
-
|
|
3812
|
+
resolve3(err ? null : stdout.trim() || null);
|
|
3793
3813
|
});
|
|
3794
3814
|
} catch {
|
|
3795
|
-
|
|
3815
|
+
resolve3(null);
|
|
3796
3816
|
}
|
|
3797
3817
|
});
|
|
3798
3818
|
}
|
|
@@ -3808,26 +3828,26 @@ async function isGlobalInstall() {
|
|
|
3808
3828
|
}
|
|
3809
3829
|
}
|
|
3810
3830
|
function runGlobalInstall(version) {
|
|
3811
|
-
return new Promise((
|
|
3831
|
+
return new Promise((resolve3) => {
|
|
3812
3832
|
try {
|
|
3813
|
-
|
|
3833
|
+
mkdirSync6(join8(homedir8(), ".solongate"), { recursive: true });
|
|
3814
3834
|
execFile(
|
|
3815
3835
|
"npm",
|
|
3816
3836
|
["install", "-g", `${PKG}@${version}`],
|
|
3817
3837
|
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
3818
3838
|
(err, stdout, stderr) => {
|
|
3819
3839
|
try {
|
|
3820
|
-
|
|
3840
|
+
writeFileSync7(LOG_FILE2, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err ? "FAILED" : "ok"}
|
|
3821
3841
|
${stdout}
|
|
3822
3842
|
${stderr}
|
|
3823
3843
|
`, { flag: "a" });
|
|
3824
3844
|
} catch {
|
|
3825
3845
|
}
|
|
3826
|
-
|
|
3846
|
+
resolve3(!err);
|
|
3827
3847
|
}
|
|
3828
3848
|
);
|
|
3829
3849
|
} catch {
|
|
3830
|
-
|
|
3850
|
+
resolve3(false);
|
|
3831
3851
|
}
|
|
3832
3852
|
});
|
|
3833
3853
|
}
|
|
@@ -4031,11 +4051,11 @@ async function launchTui() {
|
|
|
4031
4051
|
return;
|
|
4032
4052
|
}
|
|
4033
4053
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
4034
|
-
const debugLog =
|
|
4054
|
+
const debugLog = join9(homedir9(), ".solongate", "dataroom-debug.log");
|
|
4035
4055
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
4036
4056
|
const toFile = (level) => (...args) => {
|
|
4037
4057
|
try {
|
|
4038
|
-
|
|
4058
|
+
mkdirSync7(join9(homedir9(), ".solongate"), { recursive: true });
|
|
4039
4059
|
appendFileSync(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
4040
4060
|
`);
|
|
4041
4061
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.70",
|
|
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": {
|