@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/index.js
CHANGED
|
@@ -6934,6 +6934,39 @@ var init_theme = __esm({
|
|
|
6934
6934
|
// src/tui/components.tsx
|
|
6935
6935
|
import { Box, Text } from "ink";
|
|
6936
6936
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6937
|
+
function PaneTitle({ label, extra, width: width2 }) {
|
|
6938
|
+
const tail = extra ? ` ${extra} ` : " ";
|
|
6939
|
+
const used = 2 + 1 + label.length + tail.length;
|
|
6940
|
+
return /* @__PURE__ */ jsxs(Text, { wrap: "truncate", children: [
|
|
6941
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: "\u2500 " }),
|
|
6942
|
+
/* @__PURE__ */ jsxs(Text, { color: theme.accentBright, bold: true, children: [
|
|
6943
|
+
"\u258E",
|
|
6944
|
+
label
|
|
6945
|
+
] }),
|
|
6946
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width2 - used)) })
|
|
6947
|
+
] });
|
|
6948
|
+
}
|
|
6949
|
+
function StreamLine({ e, loc, selected }) {
|
|
6950
|
+
return /* @__PURE__ */ jsxs(Text, { wrap: "truncate", backgroundColor: selected ? "#1c2f63" : void 0, children: [
|
|
6951
|
+
/* @__PURE__ */ jsx(Text, { color: selected ? theme.accentBright : theme.dim, children: selected ? "\u25B8" : " " }),
|
|
6952
|
+
/* @__PURE__ */ jsxs(Text, { color: theme.dim, children: [
|
|
6953
|
+
"[",
|
|
6954
|
+
hhmmss(e.at),
|
|
6955
|
+
" "
|
|
6956
|
+
] }),
|
|
6957
|
+
/* @__PURE__ */ jsx(Text, { color: loc ? theme.ok : "white", children: loc ? "LOC" : "CLD" }),
|
|
6958
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: "] " }),
|
|
6959
|
+
/* @__PURE__ */ jsx(Text, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
6960
|
+
/* @__PURE__ */ jsx(Text, { color: theme.accent, children: truncate2(e.tool, 12).padEnd(13) }),
|
|
6961
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: (e.permission ?? "").padEnd(5) }),
|
|
6962
|
+
/* @__PURE__ */ jsx(Text, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
|
|
6963
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: truncate2(e.agent ?? "-", 11).padEnd(12) }),
|
|
6964
|
+
/* @__PURE__ */ jsx(Text, { color: e.dlp ? theme.bad : theme.dim, bold: e.dlp, children: ("dlp:" + (e.dlp ? "yes" : "no")).padEnd(8) }),
|
|
6965
|
+
/* @__PURE__ */ jsx(Text, { color: e.burst ? theme.warn : theme.dim, bold: e.burst, children: ("rl:" + (e.burst ? "yes" : "no")).padEnd(7) }),
|
|
6966
|
+
e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx(Text, { color: theme.bad, children: truncate2(e.rule, 14) + " " }) : null,
|
|
6967
|
+
/* @__PURE__ */ jsx(Text, { color: theme.dim, children: e.detail })
|
|
6968
|
+
] });
|
|
6969
|
+
}
|
|
6937
6970
|
function DataView({
|
|
6938
6971
|
loading,
|
|
6939
6972
|
error,
|
|
@@ -6968,10 +7001,15 @@ function KeyHints({ hints }) {
|
|
|
6968
7001
|
i < hints.length - 1 ? " " : ""
|
|
6969
7002
|
] }, i)) });
|
|
6970
7003
|
}
|
|
7004
|
+
var hhmmss;
|
|
6971
7005
|
var init_components = __esm({
|
|
6972
7006
|
"src/tui/components.tsx"() {
|
|
6973
7007
|
"use strict";
|
|
6974
7008
|
init_theme();
|
|
7009
|
+
hhmmss = (ts) => {
|
|
7010
|
+
const d = new Date(ts);
|
|
7011
|
+
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
7012
|
+
};
|
|
6975
7013
|
}
|
|
6976
7014
|
});
|
|
6977
7015
|
|
|
@@ -7130,6 +7168,28 @@ function setActiveAccount(creds) {
|
|
|
7130
7168
|
return false;
|
|
7131
7169
|
}
|
|
7132
7170
|
}
|
|
7171
|
+
function clearActiveCredential() {
|
|
7172
|
+
try {
|
|
7173
|
+
const p = join8(homedir6(), ".solongate", ["cloud", "guard.json"].join("-"));
|
|
7174
|
+
if (!existsSync3(p)) {
|
|
7175
|
+
cached2 = null;
|
|
7176
|
+
return true;
|
|
7177
|
+
}
|
|
7178
|
+
let existing = {};
|
|
7179
|
+
try {
|
|
7180
|
+
existing = JSON.parse(readFileSync8(p, "utf-8"));
|
|
7181
|
+
} catch {
|
|
7182
|
+
}
|
|
7183
|
+
delete existing.apiKey;
|
|
7184
|
+
delete existing.apiUrl;
|
|
7185
|
+
writeFileSync6(p, JSON.stringify(existing, null, 2));
|
|
7186
|
+
cached2 = null;
|
|
7187
|
+
viewOverride = null;
|
|
7188
|
+
return true;
|
|
7189
|
+
} catch {
|
|
7190
|
+
return false;
|
|
7191
|
+
}
|
|
7192
|
+
}
|
|
7133
7193
|
function loginCredentialFile() {
|
|
7134
7194
|
try {
|
|
7135
7195
|
const p = join8(homedir6(), ".solongate", "cloud-guard.json");
|
|
@@ -7804,39 +7864,6 @@ function HBar({ label, value, max, width: width2, color }) {
|
|
|
7804
7864
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + value })
|
|
7805
7865
|
] });
|
|
7806
7866
|
}
|
|
7807
|
-
function PaneTitle({ label, extra, width: width2 }) {
|
|
7808
|
-
const tail = extra ? ` ${extra} ` : " ";
|
|
7809
|
-
const used = 2 + 1 + label.length + tail.length;
|
|
7810
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7811
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2500 " }),
|
|
7812
|
-
/* @__PURE__ */ jsxs2(Text2, { color: theme.accentBright, bold: true, children: [
|
|
7813
|
-
"\u258E",
|
|
7814
|
-
label
|
|
7815
|
-
] }),
|
|
7816
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width2 - used)) })
|
|
7817
|
-
] });
|
|
7818
|
-
}
|
|
7819
|
-
function StreamLine({ e, loc, selected }) {
|
|
7820
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: selected ? "#1c2f63" : void 0, children: [
|
|
7821
|
-
/* @__PURE__ */ jsx2(Text2, { color: selected ? theme.accentBright : theme.dim, children: selected ? "\u25B8" : " " }),
|
|
7822
|
-
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7823
|
-
"[",
|
|
7824
|
-
hhmmss(e.at),
|
|
7825
|
-
" "
|
|
7826
|
-
] }),
|
|
7827
|
-
/* @__PURE__ */ jsx2(Text2, { color: loc ? theme.ok : "white", children: loc ? "LOC" : "CLD" }),
|
|
7828
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
|
|
7829
|
-
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
7830
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(e.tool, 12).padEnd(13) }),
|
|
7831
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
|
|
7832
|
-
/* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
|
|
7833
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate2(e.agent ?? "-", 11).padEnd(12) }),
|
|
7834
|
-
/* @__PURE__ */ jsx2(Text2, { color: e.dlp ? theme.bad : theme.dim, bold: e.dlp, children: ("dlp:" + (e.dlp ? "yes" : "no")).padEnd(8) }),
|
|
7835
|
-
/* @__PURE__ */ jsx2(Text2, { color: e.burst ? theme.warn : theme.dim, bold: e.burst, children: ("rl:" + (e.burst ? "yes" : "no")).padEnd(7) }),
|
|
7836
|
-
e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: truncate2(e.rule, 14) + " " }) : null,
|
|
7837
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
|
|
7838
|
-
] });
|
|
7839
|
-
}
|
|
7840
7867
|
function LivePanel({ active: active2 }) {
|
|
7841
7868
|
const [s, setS] = useState2(null);
|
|
7842
7869
|
const [lat, setLat] = useState2([]);
|
|
@@ -8725,7 +8752,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8725
8752
|
] })
|
|
8726
8753
|
] });
|
|
8727
8754
|
}
|
|
8728
|
-
var CONFIG, SPIN, BG, DIM_FLOOR, RING,
|
|
8755
|
+
var CONFIG, SPIN, BG, DIM_FLOOR, RING, fmtUp, FILTERS, sessStatus, STATUS_STYLE, LIVE_HELP;
|
|
8729
8756
|
var init_Live = __esm({
|
|
8730
8757
|
"src/tui/panels/Live.tsx"() {
|
|
8731
8758
|
"use strict";
|
|
@@ -8734,16 +8761,13 @@ var init_Live = __esm({
|
|
|
8734
8761
|
init_config2();
|
|
8735
8762
|
init_notify();
|
|
8736
8763
|
init_hooks();
|
|
8764
|
+
init_components();
|
|
8737
8765
|
init_theme();
|
|
8738
8766
|
CONFIG = loadConfig();
|
|
8739
8767
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8740
8768
|
BG = "#12234f";
|
|
8741
8769
|
DIM_FLOOR = "#233457";
|
|
8742
8770
|
RING = join9(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
8743
|
-
hhmmss = (ts) => {
|
|
8744
|
-
const d = new Date(ts);
|
|
8745
|
-
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
8746
|
-
};
|
|
8747
8771
|
fmtUp = (ms) => {
|
|
8748
8772
|
const s = Math.floor(ms / 1e3);
|
|
8749
8773
|
const p = (n) => String(n).padStart(2, "0");
|
|
@@ -9433,7 +9457,7 @@ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
|
9433
9457
|
import { homedir as homedir8 } from "os";
|
|
9434
9458
|
import { join as join10 } from "path";
|
|
9435
9459
|
import { useState as useState6 } from "react";
|
|
9436
|
-
import {
|
|
9460
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
9437
9461
|
function loadLocalRows() {
|
|
9438
9462
|
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) => {
|
|
9439
9463
|
const rs = reasonSignals(j.reason);
|
|
@@ -9553,10 +9577,6 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9553
9577
|
const sq = sessSearch.trim().toLowerCase();
|
|
9554
9578
|
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);
|
|
9555
9579
|
const currentSess = sessionsFiltered[Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1))];
|
|
9556
|
-
const sessionQ = useLoader(
|
|
9557
|
-
() => view === "detail" && current?.session && source === "cloud" ? api.audit.list({ session_id: current.session, limit: 40 }) : Promise.resolve(null),
|
|
9558
|
-
[view, current?.session, source]
|
|
9559
|
-
);
|
|
9560
9580
|
const logsLoading = (source === "cloud" ? cloudQ.loading : localQ.loading) && !editing;
|
|
9561
9581
|
const sessLoading = source === "cloud" ? agentsQ.loading : localQ.loading;
|
|
9562
9582
|
const doDelete = (kind) => {
|
|
@@ -9782,61 +9802,56 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9782
9802
|
] });
|
|
9783
9803
|
}
|
|
9784
9804
|
if (view === "detail" && current) {
|
|
9785
|
-
const
|
|
9786
|
-
const
|
|
9787
|
-
const
|
|
9788
|
-
const
|
|
9789
|
-
const
|
|
9790
|
-
|
|
9791
|
-
const
|
|
9792
|
-
|
|
9805
|
+
const e = current;
|
|
9806
|
+
const loc = source === "local";
|
|
9807
|
+
const bodyW = Math.max(20, cols - 4);
|
|
9808
|
+
const innerW = cols - 2;
|
|
9809
|
+
const contentLines = [];
|
|
9810
|
+
if (e.reason && e.decision !== "ALLOW") contentLines.push(...wrapLines("reason: " + e.reason, bodyW), "");
|
|
9811
|
+
const argsText = e.args ? prettyJson(e.args) : e.reason && e.decision === "ALLOW" ? e.reason : "(no arguments recorded)";
|
|
9812
|
+
contentLines.push(...wrapLines(argsText, bodyW));
|
|
9813
|
+
const bodyRows = Math.max(4, rows - 7 - (frozen ? 1 : 0));
|
|
9814
|
+
const maxScroll = Math.max(0, contentLines.length - bodyRows);
|
|
9793
9815
|
const off = Math.min(detailScroll, maxScroll);
|
|
9794
|
-
const
|
|
9816
|
+
const win = contentLines.slice(off, off + bodyRows);
|
|
9795
9817
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9796
9818
|
copyBanner,
|
|
9797
|
-
/* @__PURE__ */ jsxs6(
|
|
9798
|
-
/* @__PURE__ */ jsx6(Text6, { color:
|
|
9799
|
-
/* @__PURE__ */ jsx6(Text6, { color:
|
|
9800
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.
|
|
9801
|
-
|
|
9819
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9820
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
|
|
9821
|
+
/* @__PURE__ */ jsx6(Text6, { color: decisionColor(e.decision), bold: true, children: " " + e.decision }),
|
|
9822
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, bold: true, children: " " + e.tool }),
|
|
9823
|
+
/* @__PURE__ */ jsx6(Text6, { color: loc ? theme.ok : "white", children: " " + (loc ? "LOC" : "CLD") }),
|
|
9824
|
+
e.dlp.length ? /* @__PURE__ */ jsx6(Text6, { color: theme.bad, children: " DLP!" }) : null,
|
|
9825
|
+
e.burst ? /* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: " BURST" }) : null,
|
|
9826
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2190 back" })
|
|
9802
9827
|
] }),
|
|
9803
|
-
|
|
9804
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "
|
|
9805
|
-
/* @__PURE__ */ jsx6(Text6, { children:
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
/* @__PURE__ */ jsx6(
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
|
|
9827
|
-
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
rows: sessionCalls.slice(0, Math.max(1, sessionRows - 2)).map((e) => [
|
|
9831
|
-
{ value: e.decision, color: decisionColor(e.decision) },
|
|
9832
|
-
{ value: truncate2(e.tool, 20), color: theme.accent },
|
|
9833
|
-
{ value: truncate2(e.reason ?? "\u2014", Math.max(16, cols - 48)) },
|
|
9834
|
-
{ value: ago(e.at), dim: true }
|
|
9835
|
-
])
|
|
9836
|
-
}
|
|
9837
|
-
)
|
|
9838
|
-
] }) : /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "(no session id)" }),
|
|
9839
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2191\u2193 scroll arguments \xB7 \u2190/esc back to logs" })
|
|
9828
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9829
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2502 when " }),
|
|
9830
|
+
/* @__PURE__ */ jsx6(Text6, { children: new Date(e.at).toLocaleString() }),
|
|
9831
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 perm " }),
|
|
9832
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.permission || "\u2014" }),
|
|
9833
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 trust " }),
|
|
9834
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.trust || "\u2014" }),
|
|
9835
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 eval " }),
|
|
9836
|
+
/* @__PURE__ */ jsx6(Text6, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : void 0, children: e.evalMs != null ? `${e.evalMs}ms` : "\u2014" }),
|
|
9837
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 agent " }),
|
|
9838
|
+
/* @__PURE__ */ jsx6(Text6, { children: e.agent ?? "\u2014" }),
|
|
9839
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502" })
|
|
9840
|
+
] }),
|
|
9841
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9842
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2502 session " }),
|
|
9843
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: e.session ?? "\u2014" }),
|
|
9844
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 rule " }),
|
|
9845
|
+
/* @__PURE__ */ jsx6(Text6, { color: e.rule && e.decision !== "ALLOW" ? theme.bad : theme.dim, children: e.rule ?? "\u2014" }),
|
|
9846
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502" })
|
|
9847
|
+
] }),
|
|
9848
|
+
/* @__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 }),
|
|
9849
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win.map((l, i) => /* @__PURE__ */ jsx6(Text6, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
9850
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9851
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
|
|
9852
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: "#0b1530", color: "white", children: ` ${e.id} ` }),
|
|
9853
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", children: " \u2191\u2193 scroll \xB7 space copy \xB7 ? all keys \xB7 \u2190 back \xB7 esc menu " })
|
|
9854
|
+
] })
|
|
9840
9855
|
] });
|
|
9841
9856
|
}
|
|
9842
9857
|
const chip = (label, val, on) => /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
@@ -9923,7 +9938,6 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9923
9938
|
const maxStart = Math.max(0, pageRows.length - listRows);
|
|
9924
9939
|
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
9925
9940
|
const windowed = pageRows.slice(start, start + listRows);
|
|
9926
|
-
const reasonW = Math.min(58, Math.max(12, cols - 71));
|
|
9927
9941
|
return /* @__PURE__ */ jsx6(DataView, { loading: logsLoading && !frozen, error: source === "cloud" ? cloudQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9928
9942
|
strip,
|
|
9929
9943
|
copyBanner,
|
|
@@ -9959,21 +9973,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9959
9973
|
)
|
|
9960
9974
|
] }) : null,
|
|
9961
9975
|
/* @__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` : ""}` }),
|
|
9962
|
-
/* @__PURE__ */ jsx6(
|
|
9963
|
-
Table,
|
|
9964
|
-
{
|
|
9965
|
-
columns: [
|
|
9966
|
-
{ header: "", width: 2 },
|
|
9967
|
-
{ header: "DECISION", width: 9 },
|
|
9968
|
-
{ header: "TOOL", width: 18 },
|
|
9969
|
-
{ header: "AGENT", width: 14 },
|
|
9970
|
-
{ header: "REASON", width: reasonW },
|
|
9971
|
-
{ header: "SIGNAL", width: 8 },
|
|
9972
|
-
{ header: "WHEN", width: 6 }
|
|
9973
|
-
],
|
|
9974
|
-
rows: windowed.map((e, i) => rowFor(e, start + i === selClamped && focused, reasonW))
|
|
9975
|
-
}
|
|
9976
|
-
),
|
|
9976
|
+
/* @__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)) }),
|
|
9977
9977
|
pageRows.length === 0 ? /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9978
9978
|
"(no entries",
|
|
9979
9979
|
source === "local" ? " in the local file" : "",
|
|
@@ -9981,25 +9981,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9981
9981
|
] }) : null
|
|
9982
9982
|
] }) });
|
|
9983
9983
|
}
|
|
9984
|
-
|
|
9985
|
-
const sig = [e.dlp.length ? `DLP${e.dlp.length > 1 ? e.dlp.length : ""}` : "", e.burst ? "RL" : ""].filter(Boolean).join(" ");
|
|
9986
|
-
return [
|
|
9987
|
-
{ value: active2 ? "\u25B8" : "", color: theme.accentBright },
|
|
9988
|
-
{ value: e.decision, color: decisionColor(e.decision) },
|
|
9989
|
-
{ value: truncate2(e.tool, 18), color: theme.accent },
|
|
9990
|
-
{ value: truncate2(e.agent ?? "\u2014", 14), dim: true },
|
|
9991
|
-
{ value: truncate2(e.reason ?? e.args ?? "\u2014", reasonW) },
|
|
9992
|
-
{ value: sig || "\xB7", color: sig ? theme.bad : void 0, dim: !sig },
|
|
9993
|
-
{ value: ago(e.at), dim: true }
|
|
9994
|
-
];
|
|
9995
|
-
}
|
|
9996
|
-
function Detail({ label, value, color }) {
|
|
9997
|
-
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9998
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: label.padEnd(9) }),
|
|
9999
|
-
/* @__PURE__ */ jsx6(Text6, { color, wrap: "truncate", children: value })
|
|
10000
|
-
] });
|
|
10001
|
-
}
|
|
10002
|
-
var DECISIONS, SIGNALS, SESS_STATUS, PAGE, LOCAL_MAX_BYTES, cloudRow, AUDIT_HELP, sessStatus2, STATUS_DOT;
|
|
9984
|
+
var DECISIONS, SIGNALS, SESS_STATUS, PAGE, LOCAL_MAX_BYTES, BG2, toStream, cloudRow, AUDIT_HELP, sessStatus2, STATUS_DOT;
|
|
10003
9985
|
var init_Audit = __esm({
|
|
10004
9986
|
"src/tui/panels/Audit.tsx"() {
|
|
10005
9987
|
"use strict";
|
|
@@ -10013,6 +9995,19 @@ var init_Audit = __esm({
|
|
|
10013
9995
|
SESS_STATUS = [void 0, "active", "idle", "ended"];
|
|
10014
9996
|
PAGE = 500;
|
|
10015
9997
|
LOCAL_MAX_BYTES = 16 * 1024 * 1024;
|
|
9998
|
+
BG2 = "#12234f";
|
|
9999
|
+
toStream = (e) => ({
|
|
10000
|
+
at: e.at,
|
|
10001
|
+
tool: e.tool,
|
|
10002
|
+
decision: e.decision,
|
|
10003
|
+
permission: (e.permission ?? "").slice(0, 4),
|
|
10004
|
+
detail: (e.args ?? e.reason ?? "").replace(/\s+/g, " "),
|
|
10005
|
+
dlp: e.dlp.length > 0,
|
|
10006
|
+
burst: e.burst,
|
|
10007
|
+
agent: e.agent,
|
|
10008
|
+
evalMs: e.evalMs,
|
|
10009
|
+
rule: e.rule
|
|
10010
|
+
});
|
|
10016
10011
|
cloudRow = (e) => {
|
|
10017
10012
|
const rs = reasonSignals(e.reason);
|
|
10018
10013
|
return {
|
|
@@ -10070,7 +10065,7 @@ var init_Audit = __esm({
|
|
|
10070
10065
|
["esc", "back to the menu"]
|
|
10071
10066
|
]
|
|
10072
10067
|
],
|
|
10073
|
-
["Entry
|
|
10068
|
+
["Entry (full content)", [["\u2191\u2193 / PgUp PgDn", "scroll the reason + arguments"], ["space", "copy mode (freeze, then select)"], ["\u2190 / esc", "back to the list"]]]
|
|
10074
10069
|
];
|
|
10075
10070
|
sessStatus2 = (lastAt) => Date.now() - lastAt < 6e4 ? "active" : Date.now() - lastAt < 3e5 ? "idle" : "ended";
|
|
10076
10071
|
STATUS_DOT = {
|
|
@@ -10081,174 +10076,437 @@ var init_Audit = __esm({
|
|
|
10081
10076
|
}
|
|
10082
10077
|
});
|
|
10083
10078
|
|
|
10084
|
-
// src/
|
|
10085
|
-
import {
|
|
10086
|
-
import
|
|
10087
|
-
import {
|
|
10088
|
-
import {
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
void active2;
|
|
10096
|
-
const { cols, rows } = usePanelSize();
|
|
10097
|
-
const [sel, setSel] = useState7(0);
|
|
10098
|
-
const [editing, setEditing] = useState7(null);
|
|
10099
|
-
const [input, setInput] = useState7("");
|
|
10100
|
-
const [confirmDel, setConfirmDel] = useState7(null);
|
|
10101
|
-
const [msg, setMsg] = useState7(null);
|
|
10102
|
-
const [busy, setBusy] = useState7(false);
|
|
10103
|
-
const [editor, setEditor] = useState7(null);
|
|
10104
|
-
const [accounts, setAccounts] = useState7(() => listAccounts());
|
|
10105
|
-
const [login, setLogin] = useState7(null);
|
|
10106
|
-
const [tick, setTick] = useState7(0);
|
|
10107
|
-
const abort = useRef3(false);
|
|
10108
|
-
const refreshAccounts = () => setAccounts(listAccounts());
|
|
10109
|
-
const locked = accounts.length === 0;
|
|
10110
|
-
const [srv, setSrv] = useState7(() => logsServerStatus());
|
|
10111
|
-
useEffect6(() => {
|
|
10112
|
-
const t = setInterval(() => setSrv(logsServerStatus()), 3e3);
|
|
10113
|
-
return () => clearInterval(t);
|
|
10114
|
-
}, []);
|
|
10115
|
-
useEffect6(() => {
|
|
10116
|
-
if (!login || login.phase === "done" || login.phase === "error") return;
|
|
10117
|
-
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
10118
|
-
return () => clearInterval(t);
|
|
10119
|
-
}, [login]);
|
|
10120
|
-
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
10121
|
-
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
10122
|
-
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
10123
|
-
const guardQ = useLoader(() => listAccounts().length ? api.settings.getGuardStatus() : Promise.resolve(null));
|
|
10124
|
-
const selfQ = useLoader(() => listAccounts().length ? api.settings.getSelfProtection() : Promise.resolve(null));
|
|
10125
|
-
const local = localQ.data;
|
|
10126
|
-
const guard = guardQ.data;
|
|
10127
|
-
const selfProt = selfQ.data;
|
|
10128
|
-
const [hidden, setHidden] = useState7(/* @__PURE__ */ new Set());
|
|
10129
|
-
const webhooks = (whQ.data?.webhooks ?? []).filter((w) => !hidden.has("wh:" + w.id));
|
|
10130
|
-
const alerts = (alertQ.data?.rules ?? []).filter((r) => !hidden.has("alert:" + r.id));
|
|
10131
|
-
const hasEmailAlert = alerts.some((r) => alertChannel(r) === "email");
|
|
10132
|
-
const hasTgAlert = alerts.some((r) => alertChannel(r) === "telegram");
|
|
10133
|
-
const rowsAll = [
|
|
10134
|
-
...accounts.map((acc) => ({ kind: "acct", acc })),
|
|
10135
|
-
{ kind: "acct-add" },
|
|
10136
|
-
...locked ? [] : [
|
|
10137
|
-
{ kind: "guard" },
|
|
10138
|
-
{ kind: "self" },
|
|
10139
|
-
{ kind: "ll-enabled" },
|
|
10140
|
-
{ kind: "ll-path" },
|
|
10141
|
-
{ kind: "ll-server" },
|
|
10142
|
-
...webhooks.map((wh) => ({ kind: "wh", wh })),
|
|
10143
|
-
{ kind: "wh-add" },
|
|
10144
|
-
...alerts.map((rule) => ({ kind: "alert", rule })),
|
|
10145
|
-
...hasEmailAlert ? [] : [{ kind: "alert-add-email" }],
|
|
10146
|
-
...hasTgAlert ? [] : [{ kind: "alert-add-tg" }]
|
|
10147
|
-
]
|
|
10148
|
-
];
|
|
10149
|
-
const selClamped = Math.min(sel, rowsAll.length - 1);
|
|
10150
|
-
const cur = rowsAll[selClamped];
|
|
10151
|
-
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;
|
|
10152
|
-
const reloadAll = () => {
|
|
10153
|
-
refreshAccounts();
|
|
10154
|
-
localQ.reload();
|
|
10155
|
-
whQ.reload();
|
|
10156
|
-
alertQ.reload();
|
|
10157
|
-
guardQ.reload();
|
|
10158
|
-
selfQ.reload();
|
|
10159
|
-
};
|
|
10160
|
-
const run12 = (label, fn, reload) => {
|
|
10161
|
-
if (busy) return;
|
|
10162
|
-
setBusy(true);
|
|
10163
|
-
setMsg({ text: label + "\u2026", level: "ok" });
|
|
10164
|
-
fn().then(() => {
|
|
10165
|
-
setMsg({ text: "\u2713 " + label, level: "ok" });
|
|
10166
|
-
reload();
|
|
10167
|
-
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" })).finally(() => setBusy(false));
|
|
10168
|
-
};
|
|
10169
|
-
const beginLogin = () => {
|
|
10170
|
-
if (login && (login.phase === "starting" || login.phase === "waiting")) return;
|
|
10171
|
-
abort.current = false;
|
|
10172
|
-
setLogin({ phase: "starting" });
|
|
10173
|
-
void (async () => {
|
|
10174
|
-
let start;
|
|
10079
|
+
// src/global-install.ts
|
|
10080
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync9, existsSync as existsSync4, mkdirSync as mkdirSync8, rmSync as rmSync2 } from "fs";
|
|
10081
|
+
import { resolve as resolve4, join as join11, dirname as dirname3 } from "path";
|
|
10082
|
+
import { homedir as homedir9 } from "os";
|
|
10083
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
10084
|
+
import { createInterface } from "readline";
|
|
10085
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
10086
|
+
function lockFile(file) {
|
|
10087
|
+
if (!existsSync4(file)) return;
|
|
10088
|
+
try {
|
|
10089
|
+
if (process.platform === "win32") {
|
|
10175
10090
|
try {
|
|
10176
|
-
|
|
10177
|
-
} catch
|
|
10178
|
-
setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
|
|
10179
|
-
return;
|
|
10091
|
+
execFileSync2("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
|
|
10092
|
+
} catch {
|
|
10180
10093
|
}
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
|
|
10191
|
-
|
|
10192
|
-
|
|
10193
|
-
|
|
10194
|
-
}
|
|
10195
|
-
if (res.status === "expired" || res.status === "not_found") {
|
|
10196
|
-
setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
|
|
10197
|
-
return;
|
|
10198
|
-
}
|
|
10094
|
+
try {
|
|
10095
|
+
execFileSync2("attrib", ["+R", file], { stdio: "ignore" });
|
|
10096
|
+
} catch {
|
|
10097
|
+
}
|
|
10098
|
+
} else if (process.platform === "darwin") {
|
|
10099
|
+
try {
|
|
10100
|
+
execFileSync2("chflags", ["uchg", file], { stdio: "ignore" });
|
|
10101
|
+
} catch {
|
|
10102
|
+
}
|
|
10103
|
+
} else {
|
|
10104
|
+
try {
|
|
10105
|
+
execFileSync2("chattr", ["+i", file], { stdio: "ignore" });
|
|
10106
|
+
} catch {
|
|
10199
10107
|
}
|
|
10200
|
-
if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
|
|
10201
|
-
})();
|
|
10202
|
-
};
|
|
10203
|
-
const openAlertEditor = (channel, rule) => {
|
|
10204
|
-
setEditor({
|
|
10205
|
-
id: rule?.id,
|
|
10206
|
-
channel,
|
|
10207
|
-
target: (channel === "email" ? rule?.emails?.[0] : rule?.telegram?.[0]) ?? "",
|
|
10208
|
-
signal: rule?.signal ?? "any",
|
|
10209
|
-
threshold: rule?.threshold ?? THRESH_MIN,
|
|
10210
|
-
windowSeconds: rule?.windowSeconds ?? 300,
|
|
10211
|
-
enabled: rule?.enabled ?? true,
|
|
10212
|
-
field: rule ? 1 : 0
|
|
10213
|
-
// new rule starts on the target; existing on signal
|
|
10214
|
-
});
|
|
10215
|
-
if (!rule) {
|
|
10216
|
-
setInput("");
|
|
10217
|
-
setEditing("alert-target");
|
|
10218
|
-
}
|
|
10219
|
-
};
|
|
10220
|
-
const normTarget = (channel, raw) => {
|
|
10221
|
-
const v = raw.trim();
|
|
10222
|
-
if (channel === "email") {
|
|
10223
|
-
const email = v.replace(/^mailto:/i, "").replace(/^["'<]+|["'>]+$/g, "").replace(/[.,;:]+$/, "").replace(/\s+/g, "");
|
|
10224
|
-
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return { value: email, error: "that does not look like an e-mail address" };
|
|
10225
|
-
return { value: email };
|
|
10226
|
-
}
|
|
10227
|
-
const tg = v.replace(/^@/, "").replace(/^(chat[\s_-]*)?id[:=\s]*/i, "").replace(/\s+/g, "");
|
|
10228
|
-
if (!/^-?\d{5,}$/.test(tg)) return { value: tg, error: "a telegram chat id is a number \u2014 get yours from @userinfobot" };
|
|
10229
|
-
return { value: tg };
|
|
10230
|
-
};
|
|
10231
|
-
const saveEditor = () => {
|
|
10232
|
-
if (!editor) return;
|
|
10233
|
-
const t = normTarget(editor.channel, editor.target);
|
|
10234
|
-
if (t.error) {
|
|
10235
|
-
setMsg({ text: "\u2717 " + t.error, level: "bad" });
|
|
10236
|
-
return;
|
|
10237
10108
|
}
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10109
|
+
} catch {
|
|
10110
|
+
}
|
|
10111
|
+
}
|
|
10112
|
+
function unlockFile(file) {
|
|
10113
|
+
if (!existsSync4(file)) return;
|
|
10114
|
+
try {
|
|
10115
|
+
if (process.platform === "win32") {
|
|
10116
|
+
try {
|
|
10117
|
+
execFileSync2("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
|
|
10118
|
+
} catch {
|
|
10119
|
+
}
|
|
10120
|
+
try {
|
|
10121
|
+
execFileSync2("icacls", [file, "/reset"], { stdio: "ignore" });
|
|
10122
|
+
} catch {
|
|
10123
|
+
}
|
|
10124
|
+
try {
|
|
10125
|
+
execFileSync2("attrib", ["-R", file], { stdio: "ignore" });
|
|
10126
|
+
} catch {
|
|
10127
|
+
}
|
|
10128
|
+
} else if (process.platform === "darwin") {
|
|
10129
|
+
try {
|
|
10130
|
+
execFileSync2("chflags", ["nouchg", file], { stdio: "ignore" });
|
|
10131
|
+
} catch {
|
|
10132
|
+
}
|
|
10133
|
+
} else {
|
|
10134
|
+
try {
|
|
10135
|
+
execFileSync2("chattr", ["-i", file], { stdio: "ignore" });
|
|
10136
|
+
} catch {
|
|
10137
|
+
}
|
|
10138
|
+
}
|
|
10139
|
+
} catch {
|
|
10140
|
+
}
|
|
10141
|
+
}
|
|
10142
|
+
function protectedTargets() {
|
|
10143
|
+
const p = globalPaths();
|
|
10144
|
+
return [
|
|
10145
|
+
join11(p.hooksDir, "guard.mjs"),
|
|
10146
|
+
join11(p.hooksDir, "audit.mjs"),
|
|
10147
|
+
join11(p.hooksDir, "stop.mjs"),
|
|
10148
|
+
join11(p.hooksDir, "shield.mjs"),
|
|
10149
|
+
p.configPath,
|
|
10150
|
+
p.settingsPath
|
|
10151
|
+
];
|
|
10152
|
+
}
|
|
10153
|
+
function lockProtected() {
|
|
10154
|
+
for (const f of protectedTargets()) lockFile(f);
|
|
10155
|
+
}
|
|
10156
|
+
function unlockProtected() {
|
|
10157
|
+
for (const f of protectedTargets()) unlockFile(f);
|
|
10158
|
+
}
|
|
10159
|
+
function globalPaths() {
|
|
10160
|
+
const home = homedir9();
|
|
10161
|
+
const sgDir = join11(home, ".solongate");
|
|
10162
|
+
const hooksDir = join11(sgDir, "hooks");
|
|
10163
|
+
const claudeDir = join11(home, ".claude");
|
|
10164
|
+
return {
|
|
10165
|
+
home,
|
|
10166
|
+
sgDir,
|
|
10167
|
+
hooksDir,
|
|
10168
|
+
claudeDir,
|
|
10169
|
+
settingsPath: join11(claudeDir, "settings.json"),
|
|
10170
|
+
backupPath: join11(claudeDir, "settings.solongate.bak"),
|
|
10171
|
+
configPath: join11(sgDir, "cloud-guard.json")
|
|
10172
|
+
};
|
|
10173
|
+
}
|
|
10174
|
+
function clearGuardUpdateCheck() {
|
|
10175
|
+
try {
|
|
10176
|
+
rmSync2(join11(globalPaths().sgDir, ".hook-update-check"), { force: true });
|
|
10177
|
+
return true;
|
|
10178
|
+
} catch {
|
|
10179
|
+
return false;
|
|
10180
|
+
}
|
|
10181
|
+
}
|
|
10182
|
+
function readHook(filename) {
|
|
10183
|
+
return readFileSync9(join11(HOOKS_DIR, filename), "utf-8");
|
|
10184
|
+
}
|
|
10185
|
+
function readGuard() {
|
|
10186
|
+
const bundled = join11(HOOKS_DIR, "guard.bundled.mjs");
|
|
10187
|
+
return existsSync4(bundled) ? readFileSync9(bundled, "utf-8") : readHook("guard.mjs");
|
|
10188
|
+
}
|
|
10189
|
+
function ask(question) {
|
|
10190
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
10191
|
+
return new Promise((res) => rl.question(question, (a) => {
|
|
10192
|
+
rl.close();
|
|
10193
|
+
res(a.trim());
|
|
10194
|
+
}));
|
|
10195
|
+
}
|
|
10196
|
+
function escapeRe(s) {
|
|
10197
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10198
|
+
}
|
|
10199
|
+
function resolveRealClaude() {
|
|
10200
|
+
try {
|
|
10201
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
10202
|
+
const out2 = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
10203
|
+
if (process.platform === "win32") {
|
|
10204
|
+
const low = (s) => s.toLowerCase();
|
|
10205
|
+
return out2.find((l) => low(l).endsWith(".cmd")) || out2.find((l) => low(l).endsWith(".exe")) || out2.find((l) => low(l).endsWith(".bat")) || out2[0] || null;
|
|
10206
|
+
}
|
|
10207
|
+
return out2[0] || null;
|
|
10208
|
+
} catch {
|
|
10209
|
+
return null;
|
|
10210
|
+
}
|
|
10211
|
+
}
|
|
10212
|
+
function shimTargets() {
|
|
10213
|
+
if (process.platform === "win32") {
|
|
10214
|
+
try {
|
|
10215
|
+
const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
10216
|
+
return prof ? [prof] : [];
|
|
10217
|
+
} catch {
|
|
10218
|
+
return [];
|
|
10219
|
+
}
|
|
10220
|
+
}
|
|
10221
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join11(homedir9(), f)).filter((f) => existsSync4(f));
|
|
10222
|
+
}
|
|
10223
|
+
function writeShimBlock(file, block2) {
|
|
10224
|
+
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
10225
|
+
let content = existsSync4(file) ? readFileSync9(file, "utf-8") : "";
|
|
10226
|
+
content = content.replace(re, "");
|
|
10227
|
+
if (block2) {
|
|
10228
|
+
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
10229
|
+
content += block2 + "\n";
|
|
10230
|
+
}
|
|
10231
|
+
mkdirSync8(dirname3(file), { recursive: true });
|
|
10232
|
+
writeFileSync9(file, content);
|
|
10233
|
+
}
|
|
10234
|
+
function installClaudeShim(shieldPath) {
|
|
10235
|
+
const real = resolveRealClaude();
|
|
10236
|
+
if (!real) {
|
|
10237
|
+
console.log(" (Claude Code not found on PATH \u2014 skipped auto-shield. Install it, then re-run `login`.)");
|
|
10238
|
+
return;
|
|
10239
|
+
}
|
|
10240
|
+
const node = process.execPath.replace(/\\/g, "/");
|
|
10241
|
+
const shield = shieldPath.replace(/\\/g, "/");
|
|
10242
|
+
const win = process.platform === "win32";
|
|
10243
|
+
const block2 = win ? `${SHIM_BEGIN}
|
|
10244
|
+
function claude { & "${node}" "${shield}" -- "${real}" @args }
|
|
10245
|
+
${SHIM_END}` : `${SHIM_BEGIN}
|
|
10246
|
+
claude() { "${node}" "${shield}" -- "${real}" "$@"; }
|
|
10247
|
+
${SHIM_END}`;
|
|
10248
|
+
const targets = shimTargets();
|
|
10249
|
+
if (targets.length === 0) return;
|
|
10250
|
+
for (const file of targets) {
|
|
10251
|
+
try {
|
|
10252
|
+
writeShimBlock(file, block2);
|
|
10253
|
+
} catch {
|
|
10254
|
+
}
|
|
10255
|
+
}
|
|
10256
|
+
}
|
|
10257
|
+
async function runGlobalInstall2(opts = {}) {
|
|
10258
|
+
const p = globalPaths();
|
|
10259
|
+
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
10260
|
+
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
10261
|
+
try {
|
|
10262
|
+
const cfg = JSON.parse(readFileSync9(p.configPath, "utf-8"));
|
|
10263
|
+
if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
|
|
10264
|
+
} catch {
|
|
10265
|
+
}
|
|
10266
|
+
}
|
|
10267
|
+
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
10268
|
+
apiKey = await ask(" Enter your SolonGate API key (sg_live_\u2026 from https://dashboard.solongate.com): ");
|
|
10269
|
+
}
|
|
10270
|
+
if (!apiKey.startsWith("sg_live_") && !apiKey.startsWith("sg_test_")) {
|
|
10271
|
+
console.log(" Invalid API key. Must start with sg_live_ or sg_test_");
|
|
10272
|
+
process.exit(1);
|
|
10273
|
+
}
|
|
10274
|
+
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
10275
|
+
mkdirSync8(p.hooksDir, { recursive: true });
|
|
10276
|
+
mkdirSync8(p.claudeDir, { recursive: true });
|
|
10277
|
+
unlockProtected();
|
|
10278
|
+
writeFileSync9(join11(p.hooksDir, "guard.mjs"), readGuard());
|
|
10279
|
+
writeFileSync9(join11(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
10280
|
+
writeFileSync9(join11(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
10281
|
+
writeFileSync9(join11(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
10282
|
+
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
10283
|
+
installClaudeShim(join11(p.hooksDir, "shield.mjs"));
|
|
10284
|
+
writeFileSync9(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
10285
|
+
console.log(` Wrote ${p.configPath}`);
|
|
10286
|
+
let existing = {};
|
|
10287
|
+
if (existsSync4(p.settingsPath)) {
|
|
10288
|
+
const raw = readFileSync9(p.settingsPath, "utf-8");
|
|
10289
|
+
if (!existsSync4(p.backupPath)) {
|
|
10290
|
+
writeFileSync9(p.backupPath, raw);
|
|
10291
|
+
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
10292
|
+
}
|
|
10293
|
+
try {
|
|
10294
|
+
existing = JSON.parse(raw);
|
|
10295
|
+
} catch {
|
|
10296
|
+
existing = {};
|
|
10297
|
+
}
|
|
10298
|
+
}
|
|
10299
|
+
const guardAbs = join11(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
10300
|
+
const auditAbs = join11(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
10301
|
+
const stopAbs = join11(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
10302
|
+
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
10303
|
+
const call = process.platform === "win32" ? "& " : "";
|
|
10304
|
+
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
10305
|
+
const merged = {
|
|
10306
|
+
...existing,
|
|
10307
|
+
hooks: {
|
|
10308
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(guardAbs) }] }],
|
|
10309
|
+
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(auditAbs) }] }],
|
|
10310
|
+
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
10311
|
+
}
|
|
10312
|
+
};
|
|
10313
|
+
writeFileSync9(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10314
|
+
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
10315
|
+
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
10316
|
+
lockProtected();
|
|
10317
|
+
console.log(" Locked protection files (OS-level read-only/immutable).");
|
|
10318
|
+
}
|
|
10319
|
+
}
|
|
10320
|
+
var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
10321
|
+
var init_global_install = __esm({
|
|
10322
|
+
"src/global-install.ts"() {
|
|
10323
|
+
"use strict";
|
|
10324
|
+
__dirname = dirname3(fileURLToPath3(import.meta.url));
|
|
10325
|
+
HOOKS_DIR = resolve4(__dirname, "..", "hooks");
|
|
10326
|
+
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
10327
|
+
SHIM_END = "# <<< SolonGate shield <<<";
|
|
10328
|
+
}
|
|
10329
|
+
});
|
|
10330
|
+
|
|
10331
|
+
// src/tui/panels/Settings.tsx
|
|
10332
|
+
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
10333
|
+
import TextInput5 from "ink-text-input";
|
|
10334
|
+
import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
|
|
10335
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
10336
|
+
function SettingsPanel({
|
|
10337
|
+
active: active2,
|
|
10338
|
+
focused,
|
|
10339
|
+
viewApiKey,
|
|
10340
|
+
onView,
|
|
10341
|
+
onAccountsChanged
|
|
10342
|
+
}) {
|
|
10343
|
+
void active2;
|
|
10344
|
+
const { cols, rows } = usePanelSize();
|
|
10345
|
+
const [sel, setSel] = useState7(0);
|
|
10346
|
+
const [editing, setEditing] = useState7(null);
|
|
10347
|
+
const [input, setInput] = useState7("");
|
|
10348
|
+
const [confirmDel, setConfirmDel] = useState7(null);
|
|
10349
|
+
const [msg, setMsg] = useState7(null);
|
|
10350
|
+
const [busy, setBusy] = useState7(false);
|
|
10351
|
+
const [editor, setEditor] = useState7(null);
|
|
10352
|
+
const [accounts, setAccounts] = useState7(() => listAccounts());
|
|
10353
|
+
const [login, setLogin] = useState7(null);
|
|
10354
|
+
const [tick, setTick] = useState7(0);
|
|
10355
|
+
const abort = useRef3(false);
|
|
10356
|
+
const refreshAccounts = () => setAccounts(listAccounts());
|
|
10357
|
+
const locked = accounts.length === 0;
|
|
10358
|
+
const [srv, setSrv] = useState7(() => logsServerStatus());
|
|
10359
|
+
useEffect6(() => {
|
|
10360
|
+
const t = setInterval(() => setSrv(logsServerStatus()), 3e3);
|
|
10361
|
+
return () => clearInterval(t);
|
|
10362
|
+
}, []);
|
|
10363
|
+
useEffect6(() => {
|
|
10364
|
+
if (!login || login.phase === "done" || login.phase === "error") return;
|
|
10365
|
+
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
10366
|
+
return () => clearInterval(t);
|
|
10367
|
+
}, [login]);
|
|
10368
|
+
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
10369
|
+
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
10370
|
+
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
10371
|
+
const guardQ = useLoader(() => listAccounts().length ? api.settings.getGuardStatus() : Promise.resolve(null));
|
|
10372
|
+
const selfQ = useLoader(() => listAccounts().length ? api.settings.getSelfProtection() : Promise.resolve(null));
|
|
10373
|
+
const local = localQ.data;
|
|
10374
|
+
const guard = guardQ.data;
|
|
10375
|
+
const selfProt = selfQ.data;
|
|
10376
|
+
const [hidden, setHidden] = useState7(/* @__PURE__ */ new Set());
|
|
10377
|
+
const webhooks = (whQ.data?.webhooks ?? []).filter((w) => !hidden.has("wh:" + w.id));
|
|
10378
|
+
const alerts = (alertQ.data?.rules ?? []).filter((r) => !hidden.has("alert:" + r.id));
|
|
10379
|
+
const hasEmailAlert = alerts.some((r) => alertChannel(r) === "email");
|
|
10380
|
+
const hasTgAlert = alerts.some((r) => alertChannel(r) === "telegram");
|
|
10381
|
+
const rowsAll = [
|
|
10382
|
+
...accounts.map((acc) => ({ kind: "acct", acc })),
|
|
10383
|
+
{ kind: "acct-add" },
|
|
10384
|
+
...locked ? [] : [
|
|
10385
|
+
{ kind: "guard" },
|
|
10386
|
+
{ kind: "self" },
|
|
10387
|
+
{ kind: "ll-enabled" },
|
|
10388
|
+
{ kind: "ll-path" },
|
|
10389
|
+
{ kind: "ll-server" },
|
|
10390
|
+
...webhooks.map((wh) => ({ kind: "wh", wh })),
|
|
10391
|
+
{ kind: "wh-add" },
|
|
10392
|
+
...alerts.map((rule) => ({ kind: "alert", rule })),
|
|
10393
|
+
...hasEmailAlert ? [] : [{ kind: "alert-add-email" }],
|
|
10394
|
+
...hasTgAlert ? [] : [{ kind: "alert-add-tg" }]
|
|
10395
|
+
]
|
|
10396
|
+
];
|
|
10397
|
+
const selClamped = Math.min(sel, rowsAll.length - 1);
|
|
10398
|
+
const cur = rowsAll[selClamped];
|
|
10399
|
+
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;
|
|
10400
|
+
const reloadAll = () => {
|
|
10401
|
+
refreshAccounts();
|
|
10402
|
+
localQ.reload();
|
|
10403
|
+
whQ.reload();
|
|
10404
|
+
alertQ.reload();
|
|
10405
|
+
guardQ.reload();
|
|
10406
|
+
selfQ.reload();
|
|
10407
|
+
};
|
|
10408
|
+
const run12 = (label, fn, reload) => {
|
|
10409
|
+
if (busy) return;
|
|
10410
|
+
setBusy(true);
|
|
10411
|
+
setMsg({ text: label + "\u2026", level: "ok" });
|
|
10412
|
+
fn().then(() => {
|
|
10413
|
+
setMsg({ text: "\u2713 " + label, level: "ok" });
|
|
10414
|
+
reload();
|
|
10415
|
+
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" })).finally(() => setBusy(false));
|
|
10416
|
+
};
|
|
10417
|
+
const beginLogin = () => {
|
|
10418
|
+
if (login && (login.phase === "starting" || login.phase === "waiting")) return;
|
|
10419
|
+
abort.current = false;
|
|
10420
|
+
setLogin({ phase: "starting" });
|
|
10421
|
+
void (async () => {
|
|
10422
|
+
let start;
|
|
10423
|
+
try {
|
|
10424
|
+
start = await startDeviceLogin(DEFAULT_API_URL2);
|
|
10425
|
+
} catch (e) {
|
|
10426
|
+
setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
|
|
10427
|
+
return;
|
|
10428
|
+
}
|
|
10429
|
+
setLogin({ phase: "waiting", url: start.verifyUrl });
|
|
10430
|
+
openBrowser(start.verifyUrl);
|
|
10431
|
+
while (Date.now() < start.expiresAt && !abort.current) {
|
|
10432
|
+
await new Promise((r) => setTimeout(r, start.intervalMs));
|
|
10433
|
+
if (abort.current) return;
|
|
10434
|
+
const res = await pollDeviceLogin(DEFAULT_API_URL2, start.deviceCode);
|
|
10435
|
+
if (res.status === "approved" && res.apiKey) {
|
|
10436
|
+
saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
|
|
10437
|
+
setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
|
|
10438
|
+
setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2 });
|
|
10439
|
+
onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
|
|
10440
|
+
reloadAll();
|
|
10441
|
+
return;
|
|
10442
|
+
}
|
|
10443
|
+
if (res.status === "expired" || res.status === "not_found") {
|
|
10444
|
+
setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
|
|
10445
|
+
return;
|
|
10446
|
+
}
|
|
10447
|
+
}
|
|
10448
|
+
if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
|
|
10449
|
+
})();
|
|
10450
|
+
};
|
|
10451
|
+
const openAlertEditor = (channel, rule) => {
|
|
10452
|
+
setEditor({
|
|
10453
|
+
id: rule?.id,
|
|
10454
|
+
channel,
|
|
10455
|
+
target: (channel === "email" ? rule?.emails?.[0] : rule?.telegram?.[0]) ?? "",
|
|
10456
|
+
signal: rule?.signal ?? "any",
|
|
10457
|
+
threshold: rule?.threshold ?? THRESH_MIN,
|
|
10458
|
+
windowSeconds: rule?.windowSeconds ?? 300,
|
|
10459
|
+
enabled: rule?.enabled ?? true,
|
|
10460
|
+
field: rule ? 1 : 0
|
|
10461
|
+
// new rule starts on the target; existing on signal
|
|
10462
|
+
});
|
|
10463
|
+
if (!rule) {
|
|
10464
|
+
setInput("");
|
|
10465
|
+
setEditing("alert-target");
|
|
10466
|
+
}
|
|
10467
|
+
};
|
|
10468
|
+
const normTarget = (channel, raw) => {
|
|
10469
|
+
const v = raw.trim();
|
|
10470
|
+
if (channel === "email") {
|
|
10471
|
+
const email = v.replace(/^mailto:/i, "").replace(/^["'<]+|["'>]+$/g, "").replace(/[.,;:]+$/, "").replace(/\s+/g, "");
|
|
10472
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return { value: email, error: "that does not look like an e-mail address" };
|
|
10473
|
+
return { value: email };
|
|
10474
|
+
}
|
|
10475
|
+
const tg = v.replace(/^@/, "").replace(/^(chat[\s_-]*)?id[:=\s]*/i, "").replace(/\s+/g, "");
|
|
10476
|
+
if (!/^-?\d{5,}$/.test(tg)) return { value: tg, error: "a telegram chat id is a number \u2014 get yours from @userinfobot" };
|
|
10477
|
+
return { value: tg };
|
|
10478
|
+
};
|
|
10479
|
+
const saveEditor = () => {
|
|
10480
|
+
if (!editor) return;
|
|
10481
|
+
const t = normTarget(editor.channel, editor.target);
|
|
10482
|
+
if (t.error) {
|
|
10483
|
+
setMsg({ text: "\u2717 " + t.error, level: "bad" });
|
|
10484
|
+
return;
|
|
10485
|
+
}
|
|
10486
|
+
const channels = editor.channel === "email" ? { emails: [t.value], telegram: [] } : { telegram: [t.value], emails: [] };
|
|
10487
|
+
const body = { signal: editor.signal, threshold: editor.threshold, windowSeconds: editor.windowSeconds, enabled: editor.enabled, ...channels };
|
|
10488
|
+
const id = editor.id;
|
|
10489
|
+
setEditor(null);
|
|
10490
|
+
if (id) run12("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
10491
|
+
else run12(`${editor.channel} alert added`, () => api.settings.createAlert({ name: "SolonGate alert", ...body }), alertQ.reload);
|
|
10492
|
+
};
|
|
10493
|
+
const activate = (r) => {
|
|
10494
|
+
if (r.kind === "acct") {
|
|
10495
|
+
setViewCredentials({ apiKey: r.acc.apiKey, apiUrl: r.acc.apiUrl });
|
|
10248
10496
|
onView?.(r.acc);
|
|
10249
10497
|
setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
|
|
10250
10498
|
} else if (r.kind === "acct-add") {
|
|
10251
10499
|
beginLogin();
|
|
10500
|
+
} else if (r.kind === "guard") {
|
|
10501
|
+
if (!guard) return;
|
|
10502
|
+
if (guard.up_to_date) {
|
|
10503
|
+
setMsg({ text: `guard already on the latest hook (v${guard.latest})`, level: "ok" });
|
|
10504
|
+
return;
|
|
10505
|
+
}
|
|
10506
|
+
const armed = clearGuardUpdateCheck();
|
|
10507
|
+
setMsg(
|
|
10508
|
+
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" }
|
|
10509
|
+
);
|
|
10252
10510
|
} else if (r.kind === "self") {
|
|
10253
10511
|
if (!selfProt) return;
|
|
10254
10512
|
run12(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
@@ -10354,16 +10612,31 @@ function SettingsPanel({
|
|
|
10354
10612
|
else activate(cur);
|
|
10355
10613
|
}
|
|
10356
10614
|
} else if (inp === "x" && cur.kind === "acct") {
|
|
10357
|
-
const
|
|
10615
|
+
const target = cur.acc;
|
|
10616
|
+
const k = "acct:" + target.apiKey;
|
|
10617
|
+
const wasActive = isActiveAccount(target.apiKey);
|
|
10618
|
+
const others = accounts.filter((a) => a.apiKey !== target.apiKey);
|
|
10358
10619
|
if (confirmDel !== k) {
|
|
10359
10620
|
setConfirmDel(k);
|
|
10360
|
-
|
|
10621
|
+
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)";
|
|
10622
|
+
setMsg({ text: `press x again to remove ${acctLabel(target)} from this device${note}`, level: "bad" });
|
|
10361
10623
|
return;
|
|
10362
10624
|
}
|
|
10363
10625
|
setConfirmDel(null);
|
|
10364
|
-
removeAccount(
|
|
10365
|
-
|
|
10626
|
+
removeAccount(target.apiKey);
|
|
10627
|
+
let extra = " from this device";
|
|
10628
|
+
if (wasActive) {
|
|
10629
|
+
if (others.length) {
|
|
10630
|
+
setActiveAccount({ apiKey: others[0].apiKey, apiUrl: others[0].apiUrl });
|
|
10631
|
+
extra = ` \xB7 ${acctLabel(others[0])} is now the active key`;
|
|
10632
|
+
} else {
|
|
10633
|
+
clearActiveCredential();
|
|
10634
|
+
extra = " \xB7 signed out of this device";
|
|
10635
|
+
}
|
|
10636
|
+
}
|
|
10637
|
+
setMsg({ text: `\u2713 removed ${acctLabel(target)}${extra}`, level: "ok" });
|
|
10366
10638
|
refreshAccounts();
|
|
10639
|
+
onAccountsChanged?.();
|
|
10367
10640
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
10368
10641
|
run12("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
10369
10642
|
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
@@ -10487,9 +10760,9 @@ function SettingsPanel({
|
|
|
10487
10760
|
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10488
10761
|
cursor(r),
|
|
10489
10762
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
10490
|
-
guard ? /* @__PURE__ */ jsxs7(
|
|
10763
|
+
guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
10491
10764
|
/* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
|
|
10492
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available` }),
|
|
10765
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter to update` }),
|
|
10493
10766
|
/* @__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` : ""}` })
|
|
10494
10767
|
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading\u2026" })
|
|
10495
10768
|
] });
|
|
@@ -10555,7 +10828,7 @@ function SettingsPanel({
|
|
|
10555
10828
|
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";
|
|
10556
10829
|
const SECTION_DESC = {
|
|
10557
10830
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
10558
|
-
PROTECTION: "guard hook version + self-protection toggle",
|
|
10831
|
+
PROTECTION: "guard hook version (enter to update) + self-protection toggle",
|
|
10559
10832
|
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
10560
10833
|
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
10561
10834
|
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 m on/off`
|
|
@@ -10617,6 +10890,7 @@ var init_Settings = __esm({
|
|
|
10617
10890
|
init_api_client();
|
|
10618
10891
|
init_client();
|
|
10619
10892
|
init_device_login();
|
|
10893
|
+
init_global_install();
|
|
10620
10894
|
init_logs_server_daemon();
|
|
10621
10895
|
init_components();
|
|
10622
10896
|
init_hooks();
|
|
@@ -10717,6 +10991,14 @@ function App() {
|
|
|
10717
10991
|
if (accounts.length < 2) return;
|
|
10718
10992
|
viewAccount(accounts[(acctIdx + 1) % accounts.length]);
|
|
10719
10993
|
};
|
|
10994
|
+
const syncAccounts = () => {
|
|
10995
|
+
const list6 = listAccounts();
|
|
10996
|
+
setAccounts(list6);
|
|
10997
|
+
const next = list6.find((a) => a.apiKey === viewKey) ?? list6[0];
|
|
10998
|
+
setViewCredentials(next ? { apiKey: next.apiKey, apiUrl: next.apiUrl } : null);
|
|
10999
|
+
setViewKey(next?.apiKey);
|
|
11000
|
+
setViewNonce((n) => n + 1);
|
|
11001
|
+
};
|
|
10720
11002
|
const locked = accounts.length === 0;
|
|
10721
11003
|
const effectiveSection = locked ? SETTINGS_SECTION : section;
|
|
10722
11004
|
useInput7((input, key) => {
|
|
@@ -10752,7 +11034,7 @@ function App() {
|
|
|
10752
11034
|
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx8(LivePanel, { active: true, focused: true }, viewNonce) });
|
|
10753
11035
|
}
|
|
10754
11036
|
const Panel = current.Panel;
|
|
10755
|
-
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" });
|
|
11037
|
+
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" });
|
|
10756
11038
|
return (
|
|
10757
11039
|
// height rows-1 (not rows): once total output reaches stdout.rows ink stops
|
|
10758
11040
|
// diffing and clearTerminal-repaints every frame, which slides the banner.
|
|
@@ -10834,9 +11116,9 @@ var tui_exports = {};
|
|
|
10834
11116
|
__export(tui_exports, {
|
|
10835
11117
|
launchTui: () => launchTui
|
|
10836
11118
|
});
|
|
10837
|
-
import { appendFileSync as appendFileSync2, mkdirSync as
|
|
10838
|
-
import { homedir as
|
|
10839
|
-
import { join as
|
|
11119
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
11120
|
+
import { homedir as homedir10 } from "os";
|
|
11121
|
+
import { join as join12 } from "path";
|
|
10840
11122
|
import { render } from "ink";
|
|
10841
11123
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
10842
11124
|
async function launchTui() {
|
|
@@ -10847,11 +11129,11 @@ async function launchTui() {
|
|
|
10847
11129
|
return;
|
|
10848
11130
|
}
|
|
10849
11131
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
10850
|
-
const debugLog =
|
|
11132
|
+
const debugLog = join12(homedir10(), ".solongate", "dataroom-debug.log");
|
|
10851
11133
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
10852
11134
|
const toFile = (level) => (...args) => {
|
|
10853
11135
|
try {
|
|
10854
|
-
|
|
11136
|
+
mkdirSync9(join12(homedir10(), ".solongate"), { recursive: true });
|
|
10855
11137
|
appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
10856
11138
|
`);
|
|
10857
11139
|
} catch {
|
|
@@ -10975,7 +11257,7 @@ var init_args = __esm({
|
|
|
10975
11257
|
});
|
|
10976
11258
|
|
|
10977
11259
|
// src/commands/policy.ts
|
|
10978
|
-
import { readFileSync as
|
|
11260
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
10979
11261
|
async function run(argv) {
|
|
10980
11262
|
const { positionals, flags } = parse(argv);
|
|
10981
11263
|
const sub = positionals[0];
|
|
@@ -11150,7 +11432,7 @@ function printRules(rules) {
|
|
|
11150
11432
|
}
|
|
11151
11433
|
async function resolveRules(target) {
|
|
11152
11434
|
if (target.endsWith(".json")) {
|
|
11153
|
-
const parsed = JSON.parse(
|
|
11435
|
+
const parsed = JSON.parse(readFileSync10(target, "utf-8"));
|
|
11154
11436
|
return parsed.rules ?? [];
|
|
11155
11437
|
}
|
|
11156
11438
|
const p = await api.policies.get(target);
|
|
@@ -11565,9 +11847,9 @@ var init_agents2 = __esm({
|
|
|
11565
11847
|
});
|
|
11566
11848
|
|
|
11567
11849
|
// src/commands/doctor.ts
|
|
11568
|
-
import { existsSync as
|
|
11569
|
-
import { homedir as
|
|
11570
|
-
import { join as
|
|
11850
|
+
import { existsSync as existsSync5, statSync as statSync2 } from "fs";
|
|
11851
|
+
import { homedir as homedir11 } from "os";
|
|
11852
|
+
import { join as join13 } from "path";
|
|
11571
11853
|
async function run6(argv) {
|
|
11572
11854
|
const { flags } = parse(argv);
|
|
11573
11855
|
const json = flagBool(flags, "json");
|
|
@@ -11597,7 +11879,7 @@ async function run6(argv) {
|
|
|
11597
11879
|
} catch {
|
|
11598
11880
|
}
|
|
11599
11881
|
}
|
|
11600
|
-
if (
|
|
11882
|
+
if (existsSync5(LOCAL_LOG2)) {
|
|
11601
11883
|
const st = statSync2(LOCAL_LOG2);
|
|
11602
11884
|
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
11603
11885
|
checks.push({ name: "local logs", ok: true, detail: `on \xB7 ${(st.size / 1024).toFixed(0)}KB \xB7 last write ${ageMin < 1 ? "just now" : Math.round(ageMin) + "m ago"}` });
|
|
@@ -11627,14 +11909,14 @@ var init_doctor = __esm({
|
|
|
11627
11909
|
init_api_client();
|
|
11628
11910
|
init_format();
|
|
11629
11911
|
init_args();
|
|
11630
|
-
LOCAL_LOG2 =
|
|
11912
|
+
LOCAL_LOG2 = join13(homedir11(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
11631
11913
|
}
|
|
11632
11914
|
});
|
|
11633
11915
|
|
|
11634
11916
|
// src/commands/watch.ts
|
|
11635
|
-
import { closeSync as closeSync2, existsSync as
|
|
11636
|
-
import { homedir as
|
|
11637
|
-
import { join as
|
|
11917
|
+
import { closeSync as closeSync2, existsSync as existsSync6, openSync as openSync4, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
11918
|
+
import { homedir as homedir12 } from "os";
|
|
11919
|
+
import { join as join14 } from "path";
|
|
11638
11920
|
function tailLocal(file, maxBytes = 131072) {
|
|
11639
11921
|
try {
|
|
11640
11922
|
const size = statSync3(file).size;
|
|
@@ -11678,7 +11960,7 @@ async function run7(argv) {
|
|
|
11678
11960
|
for (const r of rows) if (keep(r)) print(r, json);
|
|
11679
11961
|
};
|
|
11680
11962
|
const pollLocal = () => {
|
|
11681
|
-
if (cloudOnly || !
|
|
11963
|
+
if (cloudOnly || !existsSync6(LOCAL_LOG3)) return;
|
|
11682
11964
|
const rows = [];
|
|
11683
11965
|
for (const line of tailLocal(LOCAL_LOG3)) {
|
|
11684
11966
|
try {
|
|
@@ -11741,7 +12023,7 @@ var init_watch = __esm({
|
|
|
11741
12023
|
init_cli_utils();
|
|
11742
12024
|
init_args();
|
|
11743
12025
|
init_format();
|
|
11744
|
-
LOCAL_LOG3 =
|
|
12026
|
+
LOCAL_LOG3 = join14(homedir12(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
11745
12027
|
trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
11746
12028
|
time = (ms) => new Date(ms).toTimeString().slice(0, 8);
|
|
11747
12029
|
}
|
|
@@ -12031,250 +12313,6 @@ var init_commands = __esm({
|
|
|
12031
12313
|
}
|
|
12032
12314
|
});
|
|
12033
12315
|
|
|
12034
|
-
// src/global-install.ts
|
|
12035
|
-
import { readFileSync as readFileSync10, writeFileSync as writeFileSync9, existsSync as existsSync6, mkdirSync as mkdirSync9 } from "fs";
|
|
12036
|
-
import { resolve as resolve4, join as join14, dirname as dirname3 } from "path";
|
|
12037
|
-
import { homedir as homedir12 } from "os";
|
|
12038
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
12039
|
-
import { createInterface } from "readline";
|
|
12040
|
-
import { execFileSync as execFileSync2 } from "child_process";
|
|
12041
|
-
function lockFile(file) {
|
|
12042
|
-
if (!existsSync6(file)) return;
|
|
12043
|
-
try {
|
|
12044
|
-
if (process.platform === "win32") {
|
|
12045
|
-
try {
|
|
12046
|
-
execFileSync2("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
|
|
12047
|
-
} catch {
|
|
12048
|
-
}
|
|
12049
|
-
try {
|
|
12050
|
-
execFileSync2("attrib", ["+R", file], { stdio: "ignore" });
|
|
12051
|
-
} catch {
|
|
12052
|
-
}
|
|
12053
|
-
} else if (process.platform === "darwin") {
|
|
12054
|
-
try {
|
|
12055
|
-
execFileSync2("chflags", ["uchg", file], { stdio: "ignore" });
|
|
12056
|
-
} catch {
|
|
12057
|
-
}
|
|
12058
|
-
} else {
|
|
12059
|
-
try {
|
|
12060
|
-
execFileSync2("chattr", ["+i", file], { stdio: "ignore" });
|
|
12061
|
-
} catch {
|
|
12062
|
-
}
|
|
12063
|
-
}
|
|
12064
|
-
} catch {
|
|
12065
|
-
}
|
|
12066
|
-
}
|
|
12067
|
-
function unlockFile(file) {
|
|
12068
|
-
if (!existsSync6(file)) return;
|
|
12069
|
-
try {
|
|
12070
|
-
if (process.platform === "win32") {
|
|
12071
|
-
try {
|
|
12072
|
-
execFileSync2("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
|
|
12073
|
-
} catch {
|
|
12074
|
-
}
|
|
12075
|
-
try {
|
|
12076
|
-
execFileSync2("icacls", [file, "/reset"], { stdio: "ignore" });
|
|
12077
|
-
} catch {
|
|
12078
|
-
}
|
|
12079
|
-
try {
|
|
12080
|
-
execFileSync2("attrib", ["-R", file], { stdio: "ignore" });
|
|
12081
|
-
} catch {
|
|
12082
|
-
}
|
|
12083
|
-
} else if (process.platform === "darwin") {
|
|
12084
|
-
try {
|
|
12085
|
-
execFileSync2("chflags", ["nouchg", file], { stdio: "ignore" });
|
|
12086
|
-
} catch {
|
|
12087
|
-
}
|
|
12088
|
-
} else {
|
|
12089
|
-
try {
|
|
12090
|
-
execFileSync2("chattr", ["-i", file], { stdio: "ignore" });
|
|
12091
|
-
} catch {
|
|
12092
|
-
}
|
|
12093
|
-
}
|
|
12094
|
-
} catch {
|
|
12095
|
-
}
|
|
12096
|
-
}
|
|
12097
|
-
function protectedTargets() {
|
|
12098
|
-
const p = globalPaths();
|
|
12099
|
-
return [
|
|
12100
|
-
join14(p.hooksDir, "guard.mjs"),
|
|
12101
|
-
join14(p.hooksDir, "audit.mjs"),
|
|
12102
|
-
join14(p.hooksDir, "stop.mjs"),
|
|
12103
|
-
join14(p.hooksDir, "shield.mjs"),
|
|
12104
|
-
p.configPath,
|
|
12105
|
-
p.settingsPath
|
|
12106
|
-
];
|
|
12107
|
-
}
|
|
12108
|
-
function lockProtected() {
|
|
12109
|
-
for (const f of protectedTargets()) lockFile(f);
|
|
12110
|
-
}
|
|
12111
|
-
function unlockProtected() {
|
|
12112
|
-
for (const f of protectedTargets()) unlockFile(f);
|
|
12113
|
-
}
|
|
12114
|
-
function globalPaths() {
|
|
12115
|
-
const home = homedir12();
|
|
12116
|
-
const sgDir = join14(home, ".solongate");
|
|
12117
|
-
const hooksDir = join14(sgDir, "hooks");
|
|
12118
|
-
const claudeDir = join14(home, ".claude");
|
|
12119
|
-
return {
|
|
12120
|
-
home,
|
|
12121
|
-
sgDir,
|
|
12122
|
-
hooksDir,
|
|
12123
|
-
claudeDir,
|
|
12124
|
-
settingsPath: join14(claudeDir, "settings.json"),
|
|
12125
|
-
backupPath: join14(claudeDir, "settings.solongate.bak"),
|
|
12126
|
-
configPath: join14(sgDir, "cloud-guard.json")
|
|
12127
|
-
};
|
|
12128
|
-
}
|
|
12129
|
-
function readHook(filename) {
|
|
12130
|
-
return readFileSync10(join14(HOOKS_DIR, filename), "utf-8");
|
|
12131
|
-
}
|
|
12132
|
-
function readGuard() {
|
|
12133
|
-
const bundled = join14(HOOKS_DIR, "guard.bundled.mjs");
|
|
12134
|
-
return existsSync6(bundled) ? readFileSync10(bundled, "utf-8") : readHook("guard.mjs");
|
|
12135
|
-
}
|
|
12136
|
-
function ask(question) {
|
|
12137
|
-
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
12138
|
-
return new Promise((res) => rl.question(question, (a) => {
|
|
12139
|
-
rl.close();
|
|
12140
|
-
res(a.trim());
|
|
12141
|
-
}));
|
|
12142
|
-
}
|
|
12143
|
-
function escapeRe(s) {
|
|
12144
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12145
|
-
}
|
|
12146
|
-
function resolveRealClaude() {
|
|
12147
|
-
try {
|
|
12148
|
-
const finder = process.platform === "win32" ? "where" : "which";
|
|
12149
|
-
const out2 = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
12150
|
-
if (process.platform === "win32") {
|
|
12151
|
-
const low = (s) => s.toLowerCase();
|
|
12152
|
-
return out2.find((l) => low(l).endsWith(".cmd")) || out2.find((l) => low(l).endsWith(".exe")) || out2.find((l) => low(l).endsWith(".bat")) || out2[0] || null;
|
|
12153
|
-
}
|
|
12154
|
-
return out2[0] || null;
|
|
12155
|
-
} catch {
|
|
12156
|
-
return null;
|
|
12157
|
-
}
|
|
12158
|
-
}
|
|
12159
|
-
function shimTargets() {
|
|
12160
|
-
if (process.platform === "win32") {
|
|
12161
|
-
try {
|
|
12162
|
-
const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
12163
|
-
return prof ? [prof] : [];
|
|
12164
|
-
} catch {
|
|
12165
|
-
return [];
|
|
12166
|
-
}
|
|
12167
|
-
}
|
|
12168
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) => join14(homedir12(), f)).filter((f) => existsSync6(f));
|
|
12169
|
-
}
|
|
12170
|
-
function writeShimBlock(file, block2) {
|
|
12171
|
-
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
12172
|
-
let content = existsSync6(file) ? readFileSync10(file, "utf-8") : "";
|
|
12173
|
-
content = content.replace(re, "");
|
|
12174
|
-
if (block2) {
|
|
12175
|
-
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
12176
|
-
content += block2 + "\n";
|
|
12177
|
-
}
|
|
12178
|
-
mkdirSync9(dirname3(file), { recursive: true });
|
|
12179
|
-
writeFileSync9(file, content);
|
|
12180
|
-
}
|
|
12181
|
-
function installClaudeShim(shieldPath) {
|
|
12182
|
-
const real = resolveRealClaude();
|
|
12183
|
-
if (!real) {
|
|
12184
|
-
console.log(" (Claude Code not found on PATH \u2014 skipped auto-shield. Install it, then re-run `login`.)");
|
|
12185
|
-
return;
|
|
12186
|
-
}
|
|
12187
|
-
const node = process.execPath.replace(/\\/g, "/");
|
|
12188
|
-
const shield = shieldPath.replace(/\\/g, "/");
|
|
12189
|
-
const win = process.platform === "win32";
|
|
12190
|
-
const block2 = win ? `${SHIM_BEGIN}
|
|
12191
|
-
function claude { & "${node}" "${shield}" -- "${real}" @args }
|
|
12192
|
-
${SHIM_END}` : `${SHIM_BEGIN}
|
|
12193
|
-
claude() { "${node}" "${shield}" -- "${real}" "$@"; }
|
|
12194
|
-
${SHIM_END}`;
|
|
12195
|
-
const targets = shimTargets();
|
|
12196
|
-
if (targets.length === 0) return;
|
|
12197
|
-
for (const file of targets) {
|
|
12198
|
-
try {
|
|
12199
|
-
writeShimBlock(file, block2);
|
|
12200
|
-
} catch {
|
|
12201
|
-
}
|
|
12202
|
-
}
|
|
12203
|
-
}
|
|
12204
|
-
async function runGlobalInstall2(opts = {}) {
|
|
12205
|
-
const p = globalPaths();
|
|
12206
|
-
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
12207
|
-
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
12208
|
-
try {
|
|
12209
|
-
const cfg = JSON.parse(readFileSync10(p.configPath, "utf-8"));
|
|
12210
|
-
if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
|
|
12211
|
-
} catch {
|
|
12212
|
-
}
|
|
12213
|
-
}
|
|
12214
|
-
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
12215
|
-
apiKey = await ask(" Enter your SolonGate API key (sg_live_\u2026 from https://dashboard.solongate.com): ");
|
|
12216
|
-
}
|
|
12217
|
-
if (!apiKey.startsWith("sg_live_") && !apiKey.startsWith("sg_test_")) {
|
|
12218
|
-
console.log(" Invalid API key. Must start with sg_live_ or sg_test_");
|
|
12219
|
-
process.exit(1);
|
|
12220
|
-
}
|
|
12221
|
-
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
12222
|
-
mkdirSync9(p.hooksDir, { recursive: true });
|
|
12223
|
-
mkdirSync9(p.claudeDir, { recursive: true });
|
|
12224
|
-
unlockProtected();
|
|
12225
|
-
writeFileSync9(join14(p.hooksDir, "guard.mjs"), readGuard());
|
|
12226
|
-
writeFileSync9(join14(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
12227
|
-
writeFileSync9(join14(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
12228
|
-
writeFileSync9(join14(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
12229
|
-
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
12230
|
-
installClaudeShim(join14(p.hooksDir, "shield.mjs"));
|
|
12231
|
-
writeFileSync9(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
12232
|
-
console.log(` Wrote ${p.configPath}`);
|
|
12233
|
-
let existing = {};
|
|
12234
|
-
if (existsSync6(p.settingsPath)) {
|
|
12235
|
-
const raw = readFileSync10(p.settingsPath, "utf-8");
|
|
12236
|
-
if (!existsSync6(p.backupPath)) {
|
|
12237
|
-
writeFileSync9(p.backupPath, raw);
|
|
12238
|
-
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
12239
|
-
}
|
|
12240
|
-
try {
|
|
12241
|
-
existing = JSON.parse(raw);
|
|
12242
|
-
} catch {
|
|
12243
|
-
existing = {};
|
|
12244
|
-
}
|
|
12245
|
-
}
|
|
12246
|
-
const guardAbs = join14(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
12247
|
-
const auditAbs = join14(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
12248
|
-
const stopAbs = join14(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
12249
|
-
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
12250
|
-
const call = process.platform === "win32" ? "& " : "";
|
|
12251
|
-
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
12252
|
-
const merged = {
|
|
12253
|
-
...existing,
|
|
12254
|
-
hooks: {
|
|
12255
|
-
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(guardAbs) }] }],
|
|
12256
|
-
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(auditAbs) }] }],
|
|
12257
|
-
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
12258
|
-
}
|
|
12259
|
-
};
|
|
12260
|
-
writeFileSync9(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
12261
|
-
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
12262
|
-
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
12263
|
-
lockProtected();
|
|
12264
|
-
console.log(" Locked protection files (OS-level read-only/immutable).");
|
|
12265
|
-
}
|
|
12266
|
-
}
|
|
12267
|
-
var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
12268
|
-
var init_global_install = __esm({
|
|
12269
|
-
"src/global-install.ts"() {
|
|
12270
|
-
"use strict";
|
|
12271
|
-
__dirname = dirname3(fileURLToPath3(import.meta.url));
|
|
12272
|
-
HOOKS_DIR = resolve4(__dirname, "..", "hooks");
|
|
12273
|
-
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
12274
|
-
SHIM_END = "# <<< SolonGate shield <<<";
|
|
12275
|
-
}
|
|
12276
|
-
});
|
|
12277
|
-
|
|
12278
12316
|
// src/login.ts
|
|
12279
12317
|
var login_exports = {};
|
|
12280
12318
|
import { spawn as spawn5 } from "child_process";
|