@solongate/proxy 0.82.82 → 0.82.84
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/commands/doctor.d.ts +12 -0
- package/dist/commands/index.js +7 -3
- package/dist/global-install.d.ts +19 -0
- package/dist/global-install.js +38 -24
- package/dist/index.js +390 -255
- package/dist/tui/index.js +262 -42
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6203,6 +6203,7 @@ __export(global_install_exports, {
|
|
|
6203
6203
|
isGuardInstalled: () => isGuardInstalled,
|
|
6204
6204
|
lockProtected: () => lockProtected,
|
|
6205
6205
|
removeClaudeShim: () => removeClaudeShim,
|
|
6206
|
+
repairQuiet: () => repairQuiet,
|
|
6206
6207
|
runGlobalInstall: () => runGlobalInstall,
|
|
6207
6208
|
runGlobalRestore: () => runGlobalRestore,
|
|
6208
6209
|
runRepair: () => runRepair,
|
|
@@ -6579,44 +6580,57 @@ function runGlobalRestore() {
|
|
|
6579
6580
|
}
|
|
6580
6581
|
console.log(" Global SolonGate enforcement uninstalled. Restart Claude Code.");
|
|
6581
6582
|
}
|
|
6582
|
-
|
|
6583
|
+
function repairQuiet() {
|
|
6583
6584
|
const p = globalPaths();
|
|
6584
|
-
const out2 = (s) => void process.stderr.write(s + "\n");
|
|
6585
6585
|
const has = (f) => existsSync3(f);
|
|
6586
6586
|
const guardFile = join4(p.hooksDir, "guard.mjs");
|
|
6587
|
+
const line = (label, ok, yes, no) => ({ label, ok, detail: ok ? yes : no });
|
|
6588
|
+
const before = [
|
|
6589
|
+
line("guard hook file", has(guardFile), "present", "MISSING"),
|
|
6590
|
+
line("cloud credential", has(p.configPath), "present", "MISSING"),
|
|
6591
|
+
line("Claude Code settings", isGuardInstalled(), "guard registered", "guard NOT registered"),
|
|
6592
|
+
line("Antigravity hooks", has(p.antigravityHooksPath), "present", "MISSING"),
|
|
6593
|
+
line("Codex hooks", isCodexGuardInstalled(), "guard registered", "guard NOT registered")
|
|
6594
|
+
];
|
|
6595
|
+
const r = installGlobalQuiet();
|
|
6596
|
+
if (!r.ok) return { ok: false, message: r.message, before, after: [], notes: [] };
|
|
6597
|
+
const after = [
|
|
6598
|
+
{ label: "guard hook file", ok: true, detail: `present (v${installedGuardVersion() ?? "?"})` },
|
|
6599
|
+
line("Claude Code settings", isGuardInstalled(), "guard registered", "NOT registered"),
|
|
6600
|
+
line("Antigravity hooks", has(p.antigravityHooksPath), "present", "MISSING"),
|
|
6601
|
+
line("Codex hooks", isCodexGuardInstalled(), "guard registered", "NOT registered")
|
|
6602
|
+
];
|
|
6603
|
+
const notes = [];
|
|
6604
|
+
const cx = codexHooksStatus();
|
|
6605
|
+
if (cx.registered && !cx.trusted) {
|
|
6606
|
+
notes.push("Codex only: run `/hooks` inside Codex once and trust the SolonGate hooks (Codex skips any hook it has not been told to trust).");
|
|
6607
|
+
}
|
|
6608
|
+
if (cx.disabled) {
|
|
6609
|
+
notes.push("Codex only: hooks are turned OFF in ~/.codex/config.toml ([features] hooks = false) - the guard cannot run there until that line is removed.");
|
|
6610
|
+
}
|
|
6611
|
+
return { ok: true, message: "guard repaired. Open a new AI session for it to take effect.", before, after, notes };
|
|
6612
|
+
}
|
|
6613
|
+
async function runRepair() {
|
|
6614
|
+
const out2 = (s) => void process.stderr.write(s + "\n");
|
|
6615
|
+
const rep = repairQuiet();
|
|
6587
6616
|
out2("");
|
|
6588
6617
|
out2(" SolonGate repair");
|
|
6589
6618
|
out2("");
|
|
6590
6619
|
out2(" before:");
|
|
6591
|
-
out2(`
|
|
6592
|
-
out2(` cloud credential ${has(p.configPath) ? "present" : "MISSING"}`);
|
|
6593
|
-
out2(` Claude Code settings ${isGuardInstalled() ? "guard registered" : "guard NOT registered"}`);
|
|
6594
|
-
out2(` Antigravity hooks ${has(p.antigravityHooksPath) ? "present" : "MISSING"}`);
|
|
6595
|
-
out2(` Codex hooks ${isCodexGuardInstalled() ? "guard registered" : "guard NOT registered"}`);
|
|
6620
|
+
for (const l of rep.before) out2(` ${l.label.padEnd(20)} ${l.detail}`);
|
|
6596
6621
|
out2("");
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
out2(` \u2717 ${r.message}`);
|
|
6622
|
+
if (!rep.ok) {
|
|
6623
|
+
out2(` \u2717 ${rep.message}`);
|
|
6600
6624
|
return 1;
|
|
6601
6625
|
}
|
|
6602
6626
|
out2(" restored:");
|
|
6603
|
-
|
|
6604
|
-
out2(` Claude Code settings ${isGuardInstalled() ? "guard registered" : "NOT registered"}`);
|
|
6605
|
-
out2(` Antigravity hooks ${has(p.antigravityHooksPath) ? "present" : "MISSING"}`);
|
|
6606
|
-
out2(` Codex hooks ${isCodexGuardInstalled() ? "guard registered" : "NOT registered"}`);
|
|
6627
|
+
for (const l of rep.after) out2(` ${l.label.padEnd(20)} ${l.detail}`);
|
|
6607
6628
|
out2("");
|
|
6608
|
-
const
|
|
6609
|
-
|
|
6610
|
-
out2(" Codex only: run `/hooks` inside Codex once and trust the SolonGate hooks");
|
|
6611
|
-
out2(" (Codex skips any hook it has not been told to trust).");
|
|
6629
|
+
for (const n of rep.notes) {
|
|
6630
|
+
out2(` ${n}`);
|
|
6612
6631
|
out2("");
|
|
6613
6632
|
}
|
|
6614
|
-
|
|
6615
|
-
out2(" Codex only: hooks are turned OFF in ~/.codex/config.toml ([features] hooks = false)");
|
|
6616
|
-
out2(" \u2014 the guard cannot run there until that line is removed.");
|
|
6617
|
-
out2("");
|
|
6618
|
-
}
|
|
6619
|
-
out2(" \u2713 guard repaired. Open a new AI session for it to take effect.");
|
|
6633
|
+
out2(` \u2713 ${rep.message}`);
|
|
6620
6634
|
out2("");
|
|
6621
6635
|
return 0;
|
|
6622
6636
|
}
|
|
@@ -11095,6 +11109,220 @@ var init_Audit = __esm({
|
|
|
11095
11109
|
}
|
|
11096
11110
|
});
|
|
11097
11111
|
|
|
11112
|
+
// src/commands/format.ts
|
|
11113
|
+
function printJson(value) {
|
|
11114
|
+
out(JSON.stringify(value, null, 2));
|
|
11115
|
+
}
|
|
11116
|
+
function usage(title, tagline, rows, footer = "Add --json for machine-readable output.") {
|
|
11117
|
+
const W = 40;
|
|
11118
|
+
const lines = ["", ` ${c.bold}${c.blue4}${title}${c.reset} ${c.dim}${tagline}${c.reset}`, ""];
|
|
11119
|
+
for (const [syntax, desc] of rows) {
|
|
11120
|
+
if (!syntax) {
|
|
11121
|
+
lines.push("");
|
|
11122
|
+
continue;
|
|
11123
|
+
}
|
|
11124
|
+
if (desc === void 0) {
|
|
11125
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}`);
|
|
11126
|
+
continue;
|
|
11127
|
+
}
|
|
11128
|
+
if (syntax.length <= W) {
|
|
11129
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}${" ".repeat(W - syntax.length)}${c.dim}${desc}${c.reset}`);
|
|
11130
|
+
} else {
|
|
11131
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}`);
|
|
11132
|
+
lines.push(` ${" ".repeat(W)}${c.dim}${desc}${c.reset}`);
|
|
11133
|
+
}
|
|
11134
|
+
}
|
|
11135
|
+
if (footer) lines.push("", ` ${c.dim}${footer}${c.reset}`);
|
|
11136
|
+
return lines.join("\n");
|
|
11137
|
+
}
|
|
11138
|
+
function decisionColor2(decision) {
|
|
11139
|
+
const d = decision.toUpperCase();
|
|
11140
|
+
if (d === "ALLOW") return green(d);
|
|
11141
|
+
if (d === "DENY" || d === "DENIED") return red(d);
|
|
11142
|
+
return dim(d);
|
|
11143
|
+
}
|
|
11144
|
+
function table(headers, rows) {
|
|
11145
|
+
const cols = headers.length;
|
|
11146
|
+
const w = new Array(cols).fill(0);
|
|
11147
|
+
for (let i = 0; i < cols; i++) w[i] = width(headers[i] ?? "");
|
|
11148
|
+
for (const row of rows) {
|
|
11149
|
+
for (let i = 0; i < cols; i++) w[i] = Math.max(w[i], width(row[i] ?? ""));
|
|
11150
|
+
}
|
|
11151
|
+
const pad = (s, i) => s + " ".repeat(Math.max(0, w[i] - width(s)));
|
|
11152
|
+
err(" " + headers.map((h, i) => dim(pad(h, i))).join(" "));
|
|
11153
|
+
for (const row of rows) {
|
|
11154
|
+
err(" " + row.map((cell, i) => pad(cell ?? "", i)).join(" "));
|
|
11155
|
+
}
|
|
11156
|
+
}
|
|
11157
|
+
function truncate3(s, n) {
|
|
11158
|
+
if (s.length <= n) return s;
|
|
11159
|
+
return s.slice(0, Math.max(0, n - 1)) + "\u2026";
|
|
11160
|
+
}
|
|
11161
|
+
function sparkline(values) {
|
|
11162
|
+
if (values.length === 0) return "";
|
|
11163
|
+
const max = Math.max(...values, 0);
|
|
11164
|
+
if (max === 0) return BLOCKS[0].repeat(values.length);
|
|
11165
|
+
return values.map((v) => BLOCKS[Math.min(BLOCKS.length - 1, Math.round(v / max * (BLOCKS.length - 1)))]).join("");
|
|
11166
|
+
}
|
|
11167
|
+
var out, err, dim, bold, green, red, yellow, cyan, ANSI, width, BLOCKS;
|
|
11168
|
+
var init_format = __esm({
|
|
11169
|
+
"src/commands/format.ts"() {
|
|
11170
|
+
"use strict";
|
|
11171
|
+
init_cli_utils();
|
|
11172
|
+
out = (s = "") => void process.stdout.write(s + "\n");
|
|
11173
|
+
err = (s = "") => void process.stderr.write(s + "\n");
|
|
11174
|
+
dim = (s) => `${c.dim}${s}${c.reset}`;
|
|
11175
|
+
bold = (s) => `${c.bold}${s}${c.reset}`;
|
|
11176
|
+
green = (s) => `${c.green}${s}${c.reset}`;
|
|
11177
|
+
red = (s) => `${c.red}${s}${c.reset}`;
|
|
11178
|
+
yellow = (s) => `${c.yellow}${s}${c.reset}`;
|
|
11179
|
+
cyan = (s) => `${c.cyan}${s}${c.reset}`;
|
|
11180
|
+
ANSI = /\x1b\[[0-9;]*m/g;
|
|
11181
|
+
width = (s) => s.replace(ANSI, "").length;
|
|
11182
|
+
BLOCKS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
|
|
11183
|
+
}
|
|
11184
|
+
});
|
|
11185
|
+
|
|
11186
|
+
// src/commands/args.ts
|
|
11187
|
+
function parse(argv) {
|
|
11188
|
+
const positionals = [];
|
|
11189
|
+
const flags = {};
|
|
11190
|
+
for (let i = 0; i < argv.length; i++) {
|
|
11191
|
+
const tok = argv[i];
|
|
11192
|
+
if (tok.startsWith("--")) {
|
|
11193
|
+
const body = tok.slice(2);
|
|
11194
|
+
const eq = body.indexOf("=");
|
|
11195
|
+
if (eq !== -1) {
|
|
11196
|
+
flags[body.slice(0, eq)] = body.slice(eq + 1);
|
|
11197
|
+
continue;
|
|
11198
|
+
}
|
|
11199
|
+
const next = argv[i + 1];
|
|
11200
|
+
if (next !== void 0 && !next.startsWith("--")) {
|
|
11201
|
+
flags[body] = next;
|
|
11202
|
+
i++;
|
|
11203
|
+
} else {
|
|
11204
|
+
flags[body] = true;
|
|
11205
|
+
}
|
|
11206
|
+
} else {
|
|
11207
|
+
positionals.push(tok);
|
|
11208
|
+
}
|
|
11209
|
+
}
|
|
11210
|
+
return { positionals, flags };
|
|
11211
|
+
}
|
|
11212
|
+
function flagStr(flags, name) {
|
|
11213
|
+
const v = flags[name];
|
|
11214
|
+
return typeof v === "string" ? v : void 0;
|
|
11215
|
+
}
|
|
11216
|
+
function flagNum(flags, name) {
|
|
11217
|
+
const v = flagStr(flags, name);
|
|
11218
|
+
if (v === void 0) return void 0;
|
|
11219
|
+
const n = Number(v);
|
|
11220
|
+
return Number.isFinite(n) ? n : void 0;
|
|
11221
|
+
}
|
|
11222
|
+
function flagBool(flags, name) {
|
|
11223
|
+
return flags[name] === true || flags[name] === "true";
|
|
11224
|
+
}
|
|
11225
|
+
var init_args = __esm({
|
|
11226
|
+
"src/commands/args.ts"() {
|
|
11227
|
+
"use strict";
|
|
11228
|
+
}
|
|
11229
|
+
});
|
|
11230
|
+
|
|
11231
|
+
// src/commands/doctor.ts
|
|
11232
|
+
import { existsSync as existsSync6, readFileSync as readFileSync10, statSync as statSync2 } from "fs";
|
|
11233
|
+
import { homedir as homedir10 } from "os";
|
|
11234
|
+
import { join as join12 } from "path";
|
|
11235
|
+
async function collectChecks() {
|
|
11236
|
+
const checks = [];
|
|
11237
|
+
if (!isAuthenticated()) {
|
|
11238
|
+
checks.push({ name: "login", ok: false, detail: "not logged in - run `solongate`, add your account in the Accounts panel" });
|
|
11239
|
+
} else {
|
|
11240
|
+
const { apiUrl } = resolveCredentials();
|
|
11241
|
+
checks.push({ name: "login", ok: true, detail: `paired \xB7 ${apiUrl}` });
|
|
11242
|
+
try {
|
|
11243
|
+
const active2 = await api.policies.active();
|
|
11244
|
+
if (active2.policy) {
|
|
11245
|
+
checks.push({ name: "active policy", ok: true, detail: `${active2.policy.name} v${active2.version} \xB7 ${active2.policy.mode ?? "denylist"} \xB7 matched by ${active2.matched_by}` });
|
|
11246
|
+
} else {
|
|
11247
|
+
checks.push({ name: "active policy", ok: "warn", detail: "no policy resolves - every call falls back to default" });
|
|
11248
|
+
}
|
|
11249
|
+
const sec = active2.security;
|
|
11250
|
+
checks.push({ name: "rate limit", ok: sec?.rateLimit ? true : "warn", detail: sec?.rateLimit ? `${sec.rateLimit.perMinute}/min` : "off" });
|
|
11251
|
+
checks.push({ name: "dlp", ok: sec?.dlpBlock ? true : "warn", detail: sec?.dlpBlock ? `block \xB7 ${sec.dlpBlock.patterns.length} patterns` : sec?.dlpRedact ? "redact" : "off" });
|
|
11252
|
+
checks.push({ name: "self-protection", ok: active2.self_protection_enabled ? true : "warn", detail: active2.self_protection_enabled ? "on" : "off" });
|
|
11253
|
+
} catch (e) {
|
|
11254
|
+
checks.push({ name: "api", ok: false, detail: "unreachable: " + (e instanceof Error ? e.message : String(e)) });
|
|
11255
|
+
}
|
|
11256
|
+
try {
|
|
11257
|
+
const g = await api.settings.getGuardStatus();
|
|
11258
|
+
checks.push({ name: "guard hook", ok: g.up_to_date ? true : "warn", detail: g.up_to_date ? `v${g.installed} (latest) \xB7 ${g.device_count} device(s)` : `v${g.installed} \u2192 v${g.latest} available \xB7 update from \`solongate\` \u2192 Settings \u2192 guard` });
|
|
11259
|
+
} catch {
|
|
11260
|
+
}
|
|
11261
|
+
}
|
|
11262
|
+
if (codexDetected()) {
|
|
11263
|
+
const cx = codexHooksStatus();
|
|
11264
|
+
if (!cx.registered) {
|
|
11265
|
+
checks.push({ name: "codex hooks", ok: false, detail: "guard not registered - run `solongate repair`" });
|
|
11266
|
+
} else if (cx.disabled) {
|
|
11267
|
+
checks.push({ name: "codex hooks", ok: false, detail: "hooks disabled in ~/.codex/config.toml ([features] hooks = false)" });
|
|
11268
|
+
} else if (!cx.trusted) {
|
|
11269
|
+
checks.push({ name: "codex hooks", ok: "warn", detail: "registered - run `/hooks` in Codex once and trust them (Codex skips untrusted hooks)" });
|
|
11270
|
+
} else {
|
|
11271
|
+
checks.push({ name: "codex hooks", ok: true, detail: "registered + trusted" });
|
|
11272
|
+
}
|
|
11273
|
+
}
|
|
11274
|
+
try {
|
|
11275
|
+
const raw = readFileSync10(join12(homedir10(), ".solongate", ".key-rejected.json"), "utf-8");
|
|
11276
|
+
const m = JSON.parse(raw);
|
|
11277
|
+
const ageMin = m.ts ? Math.round((Date.now() - m.ts) / 6e4) : null;
|
|
11278
|
+
checks.push({
|
|
11279
|
+
name: "hook credential",
|
|
11280
|
+
ok: false,
|
|
11281
|
+
detail: `rejected by ${m.apiUrl ?? "the API"}${ageMin != null ? ` ${ageMin}m ago` : ""} \xB7 key from ${m.keySource ?? "?"}${m.cwd ? ` (agent cwd ${m.cwd})` : ""} - nothing is being logged from there`
|
|
11282
|
+
});
|
|
11283
|
+
} catch {
|
|
11284
|
+
}
|
|
11285
|
+
const LOCAL_LOG2 = localLogFile();
|
|
11286
|
+
if (existsSync6(LOCAL_LOG2)) {
|
|
11287
|
+
const st = statSync2(LOCAL_LOG2);
|
|
11288
|
+
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
11289
|
+
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"}` });
|
|
11290
|
+
} else {
|
|
11291
|
+
checks.push({ name: "local logs", ok: "warn", detail: "off (logs go to cloud) - enable in dashboard \u2192 Settings" });
|
|
11292
|
+
}
|
|
11293
|
+
return checks;
|
|
11294
|
+
}
|
|
11295
|
+
async function run(argv) {
|
|
11296
|
+
const { flags } = parse(argv);
|
|
11297
|
+
const json = flagBool(flags, "json");
|
|
11298
|
+
const checks = await collectChecks();
|
|
11299
|
+
if (json) return printJson(checks), checks.some((c2) => c2.ok === false) ? 1 : 0;
|
|
11300
|
+
err("");
|
|
11301
|
+
err(` ${bold("SolonGate doctor")}`);
|
|
11302
|
+
err("");
|
|
11303
|
+
for (const c2 of checks) {
|
|
11304
|
+
const mark = c2.ok === true ? green("\u2713") : c2.ok === "warn" ? yellow("!") : red("\u2717");
|
|
11305
|
+
err(` ${mark} ${c2.name.padEnd(16)} ${dim(c2.detail)}`);
|
|
11306
|
+
}
|
|
11307
|
+
err("");
|
|
11308
|
+
const bad = checks.filter((c2) => c2.ok === false).length;
|
|
11309
|
+
const warn = checks.filter((c2) => c2.ok === "warn").length;
|
|
11310
|
+
if (bad) err(` ${red(`${bad} problem(s)`)}${warn ? dim(` \xB7 ${warn} warning(s)`) : ""}`);
|
|
11311
|
+
else if (warn) err(` ${yellow(`${warn} warning(s)`)} ${dim("- guard is working")}`);
|
|
11312
|
+
else err(` ${green("all good")}`);
|
|
11313
|
+
return bad ? 1 : 0;
|
|
11314
|
+
}
|
|
11315
|
+
var init_doctor = __esm({
|
|
11316
|
+
"src/commands/doctor.ts"() {
|
|
11317
|
+
"use strict";
|
|
11318
|
+
init_api_client();
|
|
11319
|
+
init_global_install();
|
|
11320
|
+
init_local_log();
|
|
11321
|
+
init_format();
|
|
11322
|
+
init_args();
|
|
11323
|
+
}
|
|
11324
|
+
});
|
|
11325
|
+
|
|
11098
11326
|
// src/tui/panels/Settings.tsx
|
|
11099
11327
|
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
11100
11328
|
import TextInput6 from "ink-text-input";
|
|
@@ -11117,6 +11345,24 @@ function SettingsPanel({
|
|
|
11117
11345
|
const [busy, setBusy] = useState8(false);
|
|
11118
11346
|
const [editor, setEditor] = useState8(null);
|
|
11119
11347
|
const [latest, setLatest] = useState8(null);
|
|
11348
|
+
const [diagBusy, setDiagBusy] = useState8(null);
|
|
11349
|
+
const [diag, setDiag] = useState8(null);
|
|
11350
|
+
const [diagStep, setDiagStep] = useState8(0);
|
|
11351
|
+
const DIAG_STEPS = {
|
|
11352
|
+
doctor: ["login", "active policy", "guard hook", "agent hooks", "local logs"],
|
|
11353
|
+
repair: ["inspecting protection files", "rewriting hook files", "registering with agents", "re-locking"]
|
|
11354
|
+
};
|
|
11355
|
+
const settle = async (started, of) => {
|
|
11356
|
+
const min = DIAG_STEPS[of].length * 220 + 160;
|
|
11357
|
+
const left = min - (Date.now() - started);
|
|
11358
|
+
if (left > 0) await new Promise((res) => setTimeout(res, left));
|
|
11359
|
+
};
|
|
11360
|
+
useEffect7(() => {
|
|
11361
|
+
if (!diagBusy) return;
|
|
11362
|
+
const total = DIAG_STEPS[diagBusy].length;
|
|
11363
|
+
const step = setInterval(() => setDiagStep((s) => Math.min(s + 1, total - 1)), 220);
|
|
11364
|
+
return () => clearInterval(step);
|
|
11365
|
+
}, [diagBusy]);
|
|
11120
11366
|
const ver = currentVersion();
|
|
11121
11367
|
useEffect7(() => {
|
|
11122
11368
|
let live2 = true;
|
|
@@ -11155,10 +11401,11 @@ function SettingsPanel({
|
|
|
11155
11401
|
return () => clearInterval(t);
|
|
11156
11402
|
}, []);
|
|
11157
11403
|
useEffect7(() => {
|
|
11158
|
-
|
|
11404
|
+
const loggingIn = login && login.phase !== "done" && login.phase !== "error";
|
|
11405
|
+
if (!loggingIn && !diagBusy) return;
|
|
11159
11406
|
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
11160
11407
|
return () => clearInterval(t);
|
|
11161
|
-
}, [login]);
|
|
11408
|
+
}, [login, diagBusy]);
|
|
11162
11409
|
const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
|
|
11163
11410
|
const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
|
|
11164
11411
|
const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
|
|
@@ -11190,6 +11437,8 @@ function SettingsPanel({
|
|
|
11190
11437
|
...locked ? [] : [
|
|
11191
11438
|
{ kind: "guard" },
|
|
11192
11439
|
{ kind: "self" },
|
|
11440
|
+
{ kind: "doctor" },
|
|
11441
|
+
{ kind: "repair" },
|
|
11193
11442
|
{ kind: "ll-enabled" },
|
|
11194
11443
|
{ kind: "ll-path" },
|
|
11195
11444
|
{ kind: "ll-server" },
|
|
@@ -11308,6 +11557,64 @@ function SettingsPanel({
|
|
|
11308
11557
|
setMsg({ text: (res.ok ? "\u2713 " : "\u2717 ") + res.message, level: res.ok ? "ok" : "bad" });
|
|
11309
11558
|
refreshGuard();
|
|
11310
11559
|
guardQ.reload();
|
|
11560
|
+
} else if (r.kind === "doctor") {
|
|
11561
|
+
if (diagBusy) return;
|
|
11562
|
+
setDiagBusy("doctor");
|
|
11563
|
+
setDiagStep(0);
|
|
11564
|
+
setDiag(null);
|
|
11565
|
+
void (async () => {
|
|
11566
|
+
const started = Date.now();
|
|
11567
|
+
try {
|
|
11568
|
+
const checks = await collectChecks();
|
|
11569
|
+
await settle(started, "doctor");
|
|
11570
|
+
const bad = checks.filter((c2) => c2.ok === false).length;
|
|
11571
|
+
const warn = checks.filter((c2) => c2.ok === "warn").length;
|
|
11572
|
+
setDiag({
|
|
11573
|
+
of: "doctor",
|
|
11574
|
+
lines: checks.map((c2) => ({
|
|
11575
|
+
text: `${c2.ok === true ? "\u2713" : c2.ok === "warn" ? "!" : "\u2717"} ${c2.name.padEnd(16)} ${c2.detail}`,
|
|
11576
|
+
level: c2.ok === true ? "ok" : c2.ok === "warn" ? "warn" : "bad"
|
|
11577
|
+
}))
|
|
11578
|
+
});
|
|
11579
|
+
setMsg(
|
|
11580
|
+
bad ? { text: `\u2717 ${bad} problem(s)${warn ? ` \xB7 ${warn} warning(s)` : ""}`, level: "bad" } : { text: warn ? `\u2713 guard is working \xB7 ${warn} warning(s)` : "\u2713 all good", level: "ok" }
|
|
11581
|
+
);
|
|
11582
|
+
} catch (e) {
|
|
11583
|
+
setMsg({ text: "\u2717 doctor failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" });
|
|
11584
|
+
} finally {
|
|
11585
|
+
setDiagBusy(null);
|
|
11586
|
+
}
|
|
11587
|
+
})();
|
|
11588
|
+
} else if (r.kind === "repair") {
|
|
11589
|
+
if (diagBusy) return;
|
|
11590
|
+
setDiagBusy("repair");
|
|
11591
|
+
setDiagStep(0);
|
|
11592
|
+
setDiag(null);
|
|
11593
|
+
void (async () => {
|
|
11594
|
+
try {
|
|
11595
|
+
const started = Date.now();
|
|
11596
|
+
await new Promise((res) => setTimeout(res, 60));
|
|
11597
|
+
const rep = repairQuiet();
|
|
11598
|
+
await settle(started, "repair");
|
|
11599
|
+
setDiag({
|
|
11600
|
+
of: "repair",
|
|
11601
|
+
lines: [
|
|
11602
|
+
...(rep.ok ? rep.after : rep.before).map((l) => ({
|
|
11603
|
+
text: `${l.ok ? "\u2713" : "\u2717"} ${l.label.padEnd(20)} ${l.detail}`,
|
|
11604
|
+
level: l.ok ? "ok" : "bad"
|
|
11605
|
+
})),
|
|
11606
|
+
...rep.notes.map((n) => ({ text: n, level: "warn" }))
|
|
11607
|
+
]
|
|
11608
|
+
});
|
|
11609
|
+
setMsg({ text: (rep.ok ? "\u2713 " : "\u2717 ") + rep.message, level: rep.ok ? "ok" : "bad" });
|
|
11610
|
+
refreshGuard();
|
|
11611
|
+
guardQ.reload();
|
|
11612
|
+
} catch (e) {
|
|
11613
|
+
setMsg({ text: "\u2717 repair failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" });
|
|
11614
|
+
} finally {
|
|
11615
|
+
setDiagBusy(null);
|
|
11616
|
+
}
|
|
11617
|
+
})();
|
|
11311
11618
|
} else if (r.kind === "self") {
|
|
11312
11619
|
if (!selfProt) return;
|
|
11313
11620
|
run10(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
@@ -11597,6 +11904,18 @@ function SettingsPanel({
|
|
|
11597
11904
|
selfProt ? onOff(selfProt.enabled) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u2026" }),
|
|
11598
11905
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " blocks agents editing SolonGate\u2019s own hooks/config \xB7 enter toggles" })
|
|
11599
11906
|
] });
|
|
11907
|
+
case "doctor":
|
|
11908
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11909
|
+
cursor(r),
|
|
11910
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "doctor".padEnd(11) }),
|
|
11911
|
+
diagBusy === "doctor" ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: `${spin} running health check\u2026` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "health check: login, policy, guard, hooks, local logs \xB7 enter runs it" })
|
|
11912
|
+
] });
|
|
11913
|
+
case "repair":
|
|
11914
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11915
|
+
cursor(r),
|
|
11916
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "repair".padEnd(11) }),
|
|
11917
|
+
diagBusy === "repair" ? /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: `${spin} restoring protection\u2026` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "restore every protection file after tampering or deletion \xB7 enter runs it" })
|
|
11918
|
+
] });
|
|
11600
11919
|
case "ll-enabled":
|
|
11601
11920
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11602
11921
|
cursor(r),
|
|
@@ -11649,10 +11968,10 @@ function SettingsPanel({
|
|
|
11649
11968
|
] });
|
|
11650
11969
|
}
|
|
11651
11970
|
};
|
|
11652
|
-
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";
|
|
11971
|
+
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" ? "ACCOUNTS" : r.kind === "guard" || r.kind === "self" || r.kind === "doctor" || r.kind === "repair" ? "PROTECTION" : r.kind === "ll-enabled" || r.kind === "ll-path" || r.kind === "ll-server" ? "LOCAL LOGS" : r.kind === "wh" || r.kind === "wh-add" ? "WEBHOOKS" : "ALERTS";
|
|
11653
11972
|
const SECTION_DESC = {
|
|
11654
11973
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
11655
|
-
PROTECTION: "guard hook: enter install/update
|
|
11974
|
+
PROTECTION: "guard hook: enter install/update \xB7 d remove \xB7 self-protection \xB7 doctor + repair",
|
|
11656
11975
|
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
11657
11976
|
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
11658
11977
|
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 m on/off`
|
|
@@ -11684,6 +12003,31 @@ function SettingsPanel({
|
|
|
11684
12003
|
}
|
|
11685
12004
|
lineEls.push(/* @__PURE__ */ jsx8(Box8, { children: rowLine(r) }, keyOf(r)));
|
|
11686
12005
|
lineKey.push(keyOf(r));
|
|
12006
|
+
if ((r.kind === "doctor" || r.kind === "repair") && diagBusy === r.kind) {
|
|
12007
|
+
DIAG_STEPS[r.kind].forEach((label, i) => {
|
|
12008
|
+
const done = i < diagStep;
|
|
12009
|
+
lineEls.push(
|
|
12010
|
+
/* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: done ? theme.ok : i === diagStep ? theme.accentBright : theme.dim, children: ` ${done ? "\u2713" : i === diagStep ? spin : " "} ${label}` }, `step:${r.kind}:${i}`)
|
|
12011
|
+
);
|
|
12012
|
+
lineKey.push("");
|
|
12013
|
+
});
|
|
12014
|
+
}
|
|
12015
|
+
if (diag && (r.kind === "doctor" && diag.of === "doctor" || r.kind === "repair" && diag.of === "repair")) {
|
|
12016
|
+
diag.lines.forEach((l, i) => {
|
|
12017
|
+
lineEls.push(
|
|
12018
|
+
/* @__PURE__ */ jsx8(
|
|
12019
|
+
Text8,
|
|
12020
|
+
{
|
|
12021
|
+
wrap: "truncate",
|
|
12022
|
+
color: l.level === "ok" ? theme.ok : l.level === "warn" ? theme.warn : l.level === "bad" ? theme.bad : theme.dim,
|
|
12023
|
+
children: " " + l.text
|
|
12024
|
+
},
|
|
12025
|
+
`diag:${diag.of}:${i}`
|
|
12026
|
+
)
|
|
12027
|
+
);
|
|
12028
|
+
lineKey.push("");
|
|
12029
|
+
});
|
|
12030
|
+
}
|
|
11687
12031
|
});
|
|
11688
12032
|
if (hasEmailAlert && hasTgAlert) {
|
|
11689
12033
|
lineEls.push(
|
|
@@ -11725,6 +12069,7 @@ var init_Settings = __esm({
|
|
|
11725
12069
|
init_client();
|
|
11726
12070
|
init_device_login();
|
|
11727
12071
|
init_global_install();
|
|
12072
|
+
init_doctor();
|
|
11728
12073
|
init_logs_server_daemon();
|
|
11729
12074
|
init_self_update();
|
|
11730
12075
|
init_components();
|
|
@@ -11968,8 +12313,8 @@ __export(tui_exports, {
|
|
|
11968
12313
|
launchTui: () => launchTui
|
|
11969
12314
|
});
|
|
11970
12315
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
11971
|
-
import { homedir as
|
|
11972
|
-
import { join as
|
|
12316
|
+
import { homedir as homedir11 } from "os";
|
|
12317
|
+
import { join as join13 } from "path";
|
|
11973
12318
|
import { render } from "ink";
|
|
11974
12319
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
11975
12320
|
async function launchTui() {
|
|
@@ -11980,11 +12325,11 @@ async function launchTui() {
|
|
|
11980
12325
|
return;
|
|
11981
12326
|
}
|
|
11982
12327
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
11983
|
-
const debugLog =
|
|
12328
|
+
const debugLog = join13(homedir11(), ".solongate", "dataroom-debug.log");
|
|
11984
12329
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
11985
12330
|
const toFile = (level) => (...args) => {
|
|
11986
12331
|
try {
|
|
11987
|
-
mkdirSync9(
|
|
12332
|
+
mkdirSync9(join13(homedir11(), ".solongate"), { recursive: true });
|
|
11988
12333
|
appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
11989
12334
|
`);
|
|
11990
12335
|
} catch {
|
|
@@ -12010,128 +12355,9 @@ var init_tui = __esm({
|
|
|
12010
12355
|
}
|
|
12011
12356
|
});
|
|
12012
12357
|
|
|
12013
|
-
// src/commands/format.ts
|
|
12014
|
-
function printJson(value) {
|
|
12015
|
-
out(JSON.stringify(value, null, 2));
|
|
12016
|
-
}
|
|
12017
|
-
function usage(title, tagline, rows, footer = "Add --json for machine-readable output.") {
|
|
12018
|
-
const W = 40;
|
|
12019
|
-
const lines = ["", ` ${c.bold}${c.blue4}${title}${c.reset} ${c.dim}${tagline}${c.reset}`, ""];
|
|
12020
|
-
for (const [syntax, desc] of rows) {
|
|
12021
|
-
if (!syntax) {
|
|
12022
|
-
lines.push("");
|
|
12023
|
-
continue;
|
|
12024
|
-
}
|
|
12025
|
-
if (desc === void 0) {
|
|
12026
|
-
lines.push(` ${c.cyan}${syntax}${c.reset}`);
|
|
12027
|
-
continue;
|
|
12028
|
-
}
|
|
12029
|
-
if (syntax.length <= W) {
|
|
12030
|
-
lines.push(` ${c.cyan}${syntax}${c.reset}${" ".repeat(W - syntax.length)}${c.dim}${desc}${c.reset}`);
|
|
12031
|
-
} else {
|
|
12032
|
-
lines.push(` ${c.cyan}${syntax}${c.reset}`);
|
|
12033
|
-
lines.push(` ${" ".repeat(W)}${c.dim}${desc}${c.reset}`);
|
|
12034
|
-
}
|
|
12035
|
-
}
|
|
12036
|
-
if (footer) lines.push("", ` ${c.dim}${footer}${c.reset}`);
|
|
12037
|
-
return lines.join("\n");
|
|
12038
|
-
}
|
|
12039
|
-
function decisionColor2(decision) {
|
|
12040
|
-
const d = decision.toUpperCase();
|
|
12041
|
-
if (d === "ALLOW") return green(d);
|
|
12042
|
-
if (d === "DENY" || d === "DENIED") return red(d);
|
|
12043
|
-
return dim(d);
|
|
12044
|
-
}
|
|
12045
|
-
function table(headers, rows) {
|
|
12046
|
-
const cols = headers.length;
|
|
12047
|
-
const w = new Array(cols).fill(0);
|
|
12048
|
-
for (let i = 0; i < cols; i++) w[i] = width(headers[i] ?? "");
|
|
12049
|
-
for (const row of rows) {
|
|
12050
|
-
for (let i = 0; i < cols; i++) w[i] = Math.max(w[i], width(row[i] ?? ""));
|
|
12051
|
-
}
|
|
12052
|
-
const pad = (s, i) => s + " ".repeat(Math.max(0, w[i] - width(s)));
|
|
12053
|
-
err(" " + headers.map((h, i) => dim(pad(h, i))).join(" "));
|
|
12054
|
-
for (const row of rows) {
|
|
12055
|
-
err(" " + row.map((cell, i) => pad(cell ?? "", i)).join(" "));
|
|
12056
|
-
}
|
|
12057
|
-
}
|
|
12058
|
-
function truncate3(s, n) {
|
|
12059
|
-
if (s.length <= n) return s;
|
|
12060
|
-
return s.slice(0, Math.max(0, n - 1)) + "\u2026";
|
|
12061
|
-
}
|
|
12062
|
-
function sparkline(values) {
|
|
12063
|
-
if (values.length === 0) return "";
|
|
12064
|
-
const max = Math.max(...values, 0);
|
|
12065
|
-
if (max === 0) return BLOCKS[0].repeat(values.length);
|
|
12066
|
-
return values.map((v) => BLOCKS[Math.min(BLOCKS.length - 1, Math.round(v / max * (BLOCKS.length - 1)))]).join("");
|
|
12067
|
-
}
|
|
12068
|
-
var out, err, dim, bold, green, red, yellow, cyan, ANSI, width, BLOCKS;
|
|
12069
|
-
var init_format = __esm({
|
|
12070
|
-
"src/commands/format.ts"() {
|
|
12071
|
-
"use strict";
|
|
12072
|
-
init_cli_utils();
|
|
12073
|
-
out = (s = "") => void process.stdout.write(s + "\n");
|
|
12074
|
-
err = (s = "") => void process.stderr.write(s + "\n");
|
|
12075
|
-
dim = (s) => `${c.dim}${s}${c.reset}`;
|
|
12076
|
-
bold = (s) => `${c.bold}${s}${c.reset}`;
|
|
12077
|
-
green = (s) => `${c.green}${s}${c.reset}`;
|
|
12078
|
-
red = (s) => `${c.red}${s}${c.reset}`;
|
|
12079
|
-
yellow = (s) => `${c.yellow}${s}${c.reset}`;
|
|
12080
|
-
cyan = (s) => `${c.cyan}${s}${c.reset}`;
|
|
12081
|
-
ANSI = /\x1b\[[0-9;]*m/g;
|
|
12082
|
-
width = (s) => s.replace(ANSI, "").length;
|
|
12083
|
-
BLOCKS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
|
|
12084
|
-
}
|
|
12085
|
-
});
|
|
12086
|
-
|
|
12087
|
-
// src/commands/args.ts
|
|
12088
|
-
function parse(argv) {
|
|
12089
|
-
const positionals = [];
|
|
12090
|
-
const flags = {};
|
|
12091
|
-
for (let i = 0; i < argv.length; i++) {
|
|
12092
|
-
const tok = argv[i];
|
|
12093
|
-
if (tok.startsWith("--")) {
|
|
12094
|
-
const body = tok.slice(2);
|
|
12095
|
-
const eq = body.indexOf("=");
|
|
12096
|
-
if (eq !== -1) {
|
|
12097
|
-
flags[body.slice(0, eq)] = body.slice(eq + 1);
|
|
12098
|
-
continue;
|
|
12099
|
-
}
|
|
12100
|
-
const next = argv[i + 1];
|
|
12101
|
-
if (next !== void 0 && !next.startsWith("--")) {
|
|
12102
|
-
flags[body] = next;
|
|
12103
|
-
i++;
|
|
12104
|
-
} else {
|
|
12105
|
-
flags[body] = true;
|
|
12106
|
-
}
|
|
12107
|
-
} else {
|
|
12108
|
-
positionals.push(tok);
|
|
12109
|
-
}
|
|
12110
|
-
}
|
|
12111
|
-
return { positionals, flags };
|
|
12112
|
-
}
|
|
12113
|
-
function flagStr(flags, name) {
|
|
12114
|
-
const v = flags[name];
|
|
12115
|
-
return typeof v === "string" ? v : void 0;
|
|
12116
|
-
}
|
|
12117
|
-
function flagNum(flags, name) {
|
|
12118
|
-
const v = flagStr(flags, name);
|
|
12119
|
-
if (v === void 0) return void 0;
|
|
12120
|
-
const n = Number(v);
|
|
12121
|
-
return Number.isFinite(n) ? n : void 0;
|
|
12122
|
-
}
|
|
12123
|
-
function flagBool(flags, name) {
|
|
12124
|
-
return flags[name] === true || flags[name] === "true";
|
|
12125
|
-
}
|
|
12126
|
-
var init_args = __esm({
|
|
12127
|
-
"src/commands/args.ts"() {
|
|
12128
|
-
"use strict";
|
|
12129
|
-
}
|
|
12130
|
-
});
|
|
12131
|
-
|
|
12132
12358
|
// src/commands/policy.ts
|
|
12133
|
-
import { readFileSync as
|
|
12134
|
-
async function
|
|
12359
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
12360
|
+
async function run2(argv) {
|
|
12135
12361
|
const { positionals, flags } = parse(argv);
|
|
12136
12362
|
const sub = positionals[0];
|
|
12137
12363
|
const json = flagBool(flags, "json");
|
|
@@ -12287,7 +12513,7 @@ function printRules(rules) {
|
|
|
12287
12513
|
}
|
|
12288
12514
|
async function resolveRules(target) {
|
|
12289
12515
|
if (target.endsWith(".json")) {
|
|
12290
|
-
const parsed = JSON.parse(
|
|
12516
|
+
const parsed = JSON.parse(readFileSync11(target, "utf-8"));
|
|
12291
12517
|
return parsed.rules ?? [];
|
|
12292
12518
|
}
|
|
12293
12519
|
const p = await api.policies.get(target);
|
|
@@ -12316,7 +12542,7 @@ var init_policy = __esm({
|
|
|
12316
12542
|
});
|
|
12317
12543
|
|
|
12318
12544
|
// src/commands/ratelimit.ts
|
|
12319
|
-
async function
|
|
12545
|
+
async function run3(argv) {
|
|
12320
12546
|
const { positionals, flags } = parse(argv);
|
|
12321
12547
|
const sub = positionals[0] ?? "show";
|
|
12322
12548
|
const json = flagBool(flags, "json");
|
|
@@ -12394,7 +12620,7 @@ var init_ratelimit = __esm({
|
|
|
12394
12620
|
});
|
|
12395
12621
|
|
|
12396
12622
|
// src/commands/dlp.ts
|
|
12397
|
-
async function
|
|
12623
|
+
async function run4(argv) {
|
|
12398
12624
|
const { positionals, flags } = parse(argv);
|
|
12399
12625
|
const sub = positionals[0] ?? "show";
|
|
12400
12626
|
const json = flagBool(flags, "json");
|
|
@@ -12482,7 +12708,7 @@ var init_dlp = __esm({
|
|
|
12482
12708
|
});
|
|
12483
12709
|
|
|
12484
12710
|
// src/commands/stats.ts
|
|
12485
|
-
async function
|
|
12711
|
+
async function run5(argv) {
|
|
12486
12712
|
const { positionals, flags } = parse(argv);
|
|
12487
12713
|
const sub = positionals[0] ?? "overview";
|
|
12488
12714
|
const json = flagBool(flags, "json");
|
|
@@ -12560,7 +12786,7 @@ var init_stats2 = __esm({
|
|
|
12560
12786
|
});
|
|
12561
12787
|
|
|
12562
12788
|
// src/commands/audit.ts
|
|
12563
|
-
async function
|
|
12789
|
+
async function run6(argv) {
|
|
12564
12790
|
const { positionals, flags } = parse(argv);
|
|
12565
12791
|
const json = flagBool(flags, "json");
|
|
12566
12792
|
if (positionals[0] === "help") return err(USAGE5), 0;
|
|
@@ -12689,97 +12915,6 @@ var init_agents2 = __esm({
|
|
|
12689
12915
|
}
|
|
12690
12916
|
});
|
|
12691
12917
|
|
|
12692
|
-
// src/commands/doctor.ts
|
|
12693
|
-
import { existsSync as existsSync6, readFileSync as readFileSync11, statSync as statSync2 } from "fs";
|
|
12694
|
-
import { homedir as homedir11 } from "os";
|
|
12695
|
-
import { join as join13 } from "path";
|
|
12696
|
-
async function run6(argv) {
|
|
12697
|
-
const { flags } = parse(argv);
|
|
12698
|
-
const json = flagBool(flags, "json");
|
|
12699
|
-
const checks = [];
|
|
12700
|
-
if (!isAuthenticated()) {
|
|
12701
|
-
checks.push({ name: "login", ok: false, detail: "not logged in - run `solongate`, add your account in the Accounts panel" });
|
|
12702
|
-
} else {
|
|
12703
|
-
const { apiUrl } = resolveCredentials();
|
|
12704
|
-
checks.push({ name: "login", ok: true, detail: `paired \xB7 ${apiUrl}` });
|
|
12705
|
-
try {
|
|
12706
|
-
const active2 = await api.policies.active();
|
|
12707
|
-
if (active2.policy) {
|
|
12708
|
-
checks.push({ name: "active policy", ok: true, detail: `${active2.policy.name} v${active2.version} \xB7 ${active2.policy.mode ?? "denylist"} \xB7 matched by ${active2.matched_by}` });
|
|
12709
|
-
} else {
|
|
12710
|
-
checks.push({ name: "active policy", ok: "warn", detail: "no policy resolves - every call falls back to default" });
|
|
12711
|
-
}
|
|
12712
|
-
const sec = active2.security;
|
|
12713
|
-
checks.push({ name: "rate limit", ok: sec?.rateLimit ? true : "warn", detail: sec?.rateLimit ? `${sec.rateLimit.perMinute}/min` : "off" });
|
|
12714
|
-
checks.push({ name: "dlp", ok: sec?.dlpBlock ? true : "warn", detail: sec?.dlpBlock ? `block \xB7 ${sec.dlpBlock.patterns.length} patterns` : sec?.dlpRedact ? "redact" : "off" });
|
|
12715
|
-
checks.push({ name: "self-protection", ok: active2.self_protection_enabled ? true : "warn", detail: active2.self_protection_enabled ? "on" : "off" });
|
|
12716
|
-
} catch (e) {
|
|
12717
|
-
checks.push({ name: "api", ok: false, detail: "unreachable: " + (e instanceof Error ? e.message : String(e)) });
|
|
12718
|
-
}
|
|
12719
|
-
try {
|
|
12720
|
-
const g = await api.settings.getGuardStatus();
|
|
12721
|
-
checks.push({ name: "guard hook", ok: g.up_to_date ? true : "warn", detail: g.up_to_date ? `v${g.installed} (latest) \xB7 ${g.device_count} device(s)` : `v${g.installed} \u2192 v${g.latest} available \xB7 update from \`solongate\` \u2192 Settings \u2192 guard` });
|
|
12722
|
-
} catch {
|
|
12723
|
-
}
|
|
12724
|
-
}
|
|
12725
|
-
if (codexDetected()) {
|
|
12726
|
-
const cx = codexHooksStatus();
|
|
12727
|
-
if (!cx.registered) {
|
|
12728
|
-
checks.push({ name: "codex hooks", ok: false, detail: "guard not registered - run `solongate repair`" });
|
|
12729
|
-
} else if (cx.disabled) {
|
|
12730
|
-
checks.push({ name: "codex hooks", ok: false, detail: "hooks disabled in ~/.codex/config.toml ([features] hooks = false)" });
|
|
12731
|
-
} else if (!cx.trusted) {
|
|
12732
|
-
checks.push({ name: "codex hooks", ok: "warn", detail: "registered - run `/hooks` in Codex once and trust them (Codex skips untrusted hooks)" });
|
|
12733
|
-
} else {
|
|
12734
|
-
checks.push({ name: "codex hooks", ok: true, detail: "registered + trusted" });
|
|
12735
|
-
}
|
|
12736
|
-
}
|
|
12737
|
-
try {
|
|
12738
|
-
const raw = readFileSync11(join13(homedir11(), ".solongate", ".key-rejected.json"), "utf-8");
|
|
12739
|
-
const m = JSON.parse(raw);
|
|
12740
|
-
const ageMin = m.ts ? Math.round((Date.now() - m.ts) / 6e4) : null;
|
|
12741
|
-
checks.push({
|
|
12742
|
-
name: "hook credential",
|
|
12743
|
-
ok: false,
|
|
12744
|
-
detail: `rejected by ${m.apiUrl ?? "the API"}${ageMin != null ? ` ${ageMin}m ago` : ""} \xB7 key from ${m.keySource ?? "?"}${m.cwd ? ` (agent cwd ${m.cwd})` : ""} - nothing is being logged from there`
|
|
12745
|
-
});
|
|
12746
|
-
} catch {
|
|
12747
|
-
}
|
|
12748
|
-
const LOCAL_LOG2 = localLogFile();
|
|
12749
|
-
if (existsSync6(LOCAL_LOG2)) {
|
|
12750
|
-
const st = statSync2(LOCAL_LOG2);
|
|
12751
|
-
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
12752
|
-
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"}` });
|
|
12753
|
-
} else {
|
|
12754
|
-
checks.push({ name: "local logs", ok: "warn", detail: "off (logs go to cloud) - enable in dashboard \u2192 Settings" });
|
|
12755
|
-
}
|
|
12756
|
-
if (json) return printJson(checks), checks.some((c2) => c2.ok === false) ? 1 : 0;
|
|
12757
|
-
err("");
|
|
12758
|
-
err(` ${bold("SolonGate doctor")}`);
|
|
12759
|
-
err("");
|
|
12760
|
-
for (const c2 of checks) {
|
|
12761
|
-
const mark = c2.ok === true ? green("\u2713") : c2.ok === "warn" ? yellow("!") : red("\u2717");
|
|
12762
|
-
err(` ${mark} ${c2.name.padEnd(16)} ${dim(c2.detail)}`);
|
|
12763
|
-
}
|
|
12764
|
-
err("");
|
|
12765
|
-
const bad = checks.filter((c2) => c2.ok === false).length;
|
|
12766
|
-
const warn = checks.filter((c2) => c2.ok === "warn").length;
|
|
12767
|
-
if (bad) err(` ${red(`${bad} problem(s)`)}${warn ? dim(` \xB7 ${warn} warning(s)`) : ""}`);
|
|
12768
|
-
else if (warn) err(` ${yellow(`${warn} warning(s)`)} ${dim("- guard is working")}`);
|
|
12769
|
-
else err(` ${green("all good")}`);
|
|
12770
|
-
return bad ? 1 : 0;
|
|
12771
|
-
}
|
|
12772
|
-
var init_doctor = __esm({
|
|
12773
|
-
"src/commands/doctor.ts"() {
|
|
12774
|
-
"use strict";
|
|
12775
|
-
init_api_client();
|
|
12776
|
-
init_global_install();
|
|
12777
|
-
init_local_log();
|
|
12778
|
-
init_format();
|
|
12779
|
-
init_args();
|
|
12780
|
-
}
|
|
12781
|
-
});
|
|
12782
|
-
|
|
12783
12918
|
// src/commands/watch.ts
|
|
12784
12919
|
import { closeSync as closeSync2, existsSync as existsSync7, openSync as openSync4, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
12785
12920
|
function tailLocal(file, maxBytes = 131072) {
|
|
@@ -13023,21 +13158,21 @@ __export(commands_exports, {
|
|
|
13023
13158
|
async function dispatch(command, argv) {
|
|
13024
13159
|
switch (command) {
|
|
13025
13160
|
case "policy":
|
|
13026
|
-
return run(argv);
|
|
13027
|
-
case "ratelimit":
|
|
13028
13161
|
return run2(argv);
|
|
13029
|
-
case "
|
|
13162
|
+
case "ratelimit":
|
|
13030
13163
|
return run3(argv);
|
|
13031
|
-
case "
|
|
13164
|
+
case "dlp":
|
|
13032
13165
|
return run4(argv);
|
|
13033
|
-
case "
|
|
13166
|
+
case "stats":
|
|
13034
13167
|
return run5(argv);
|
|
13168
|
+
case "audit":
|
|
13169
|
+
return run6(argv);
|
|
13035
13170
|
case "sessions":
|
|
13036
13171
|
return runAgents(argv);
|
|
13037
13172
|
case "session":
|
|
13038
13173
|
return runAgent(argv);
|
|
13039
13174
|
case "doctor":
|
|
13040
|
-
return
|
|
13175
|
+
return run(argv);
|
|
13041
13176
|
case "watch":
|
|
13042
13177
|
return run7(argv);
|
|
13043
13178
|
case "alerts":
|