@solongate/proxy 0.82.20 → 0.82.22
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/index.d.ts +1 -1
- package/dist/commands/index.js +11 -81
- package/dist/index.js +187 -1259
- package/package.json +1 -1
- package/dist/commands/keys.d.ts +0 -1
- package/dist/commands/mcp.d.ts +0 -1
- package/dist/create.d.ts +0 -13
- package/dist/create.js +0 -329
- package/dist/inject.d.ts +0 -19
- package/dist/inject.js +0 -375
- package/dist/shield.d.ts +0 -1
- package/dist/shield.js +0 -314
package/dist/index.js
CHANGED
|
@@ -3398,12 +3398,12 @@ ${ctx.indent}`;
|
|
|
3398
3398
|
for (const {
|
|
3399
3399
|
format,
|
|
3400
3400
|
test,
|
|
3401
|
-
resolve:
|
|
3401
|
+
resolve: resolve7
|
|
3402
3402
|
} of tags) {
|
|
3403
3403
|
if (test) {
|
|
3404
3404
|
const match = str.match(test);
|
|
3405
3405
|
if (match) {
|
|
3406
|
-
let res =
|
|
3406
|
+
let res = resolve7.apply(null, match);
|
|
3407
3407
|
if (!(res instanceof Scalar)) res = new Scalar(res);
|
|
3408
3408
|
if (format) res.format = format;
|
|
3409
3409
|
return res;
|
|
@@ -6507,18 +6507,6 @@ var init_src = __esm({
|
|
|
6507
6507
|
});
|
|
6508
6508
|
|
|
6509
6509
|
// src/cli-utils.ts
|
|
6510
|
-
function log3(msg) {
|
|
6511
|
-
process.stderr.write(msg + "\n");
|
|
6512
|
-
}
|
|
6513
|
-
function printBanner(subtitle) {
|
|
6514
|
-
log3("");
|
|
6515
|
-
for (let i = 0; i < BANNER_FULL.length; i++) {
|
|
6516
|
-
log3(`${c.bold}${BANNER_COLORS[i]}${BANNER_FULL[i]}${c.reset}`);
|
|
6517
|
-
}
|
|
6518
|
-
log3("");
|
|
6519
|
-
log3(` ${c.dim}${c.italic}${subtitle}${c.reset}`);
|
|
6520
|
-
log3("");
|
|
6521
|
-
}
|
|
6522
6510
|
var c, BANNER_FULL, BANNER_COLORS;
|
|
6523
6511
|
var init_cli_utils = __esm({
|
|
6524
6512
|
"src/cli-utils.ts"() {
|
|
@@ -6622,9 +6610,9 @@ async function fetchLatest() {
|
|
|
6622
6610
|
function spawnGlobalInstall(version) {
|
|
6623
6611
|
try {
|
|
6624
6612
|
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6625
|
-
const
|
|
6613
|
+
const log4 = openSync(LOG_FILE, "a");
|
|
6626
6614
|
const p = spawn("npm", ["install", "-g", `${PKG}@${version}`], {
|
|
6627
|
-
stdio: ["ignore",
|
|
6615
|
+
stdio: ["ignore", log4, log4],
|
|
6628
6616
|
detached: true,
|
|
6629
6617
|
windowsHide: true,
|
|
6630
6618
|
shell: process.platform === "win32"
|
|
@@ -6638,7 +6626,7 @@ function spawnGlobalInstall(version) {
|
|
|
6638
6626
|
}
|
|
6639
6627
|
}
|
|
6640
6628
|
function runGlobalInstall(version) {
|
|
6641
|
-
return new Promise((
|
|
6629
|
+
return new Promise((resolve7) => {
|
|
6642
6630
|
try {
|
|
6643
6631
|
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6644
6632
|
execFile(
|
|
@@ -6653,11 +6641,11 @@ ${stderr}
|
|
|
6653
6641
|
`, { flag: "a" });
|
|
6654
6642
|
} catch {
|
|
6655
6643
|
}
|
|
6656
|
-
|
|
6644
|
+
resolve7(!err2);
|
|
6657
6645
|
}
|
|
6658
6646
|
);
|
|
6659
6647
|
} catch {
|
|
6660
|
-
|
|
6648
|
+
resolve7(false);
|
|
6661
6649
|
}
|
|
6662
6650
|
});
|
|
6663
6651
|
}
|
|
@@ -6772,11 +6760,11 @@ function startLogsServerDaemon() {
|
|
|
6772
6760
|
}
|
|
6773
6761
|
try {
|
|
6774
6762
|
mkdirSync4(DIR, { recursive: true });
|
|
6775
|
-
const
|
|
6763
|
+
const log4 = openSync2(LOG_FILE2, "a");
|
|
6776
6764
|
const cli = join5(dirname2(fileURLToPath2(import.meta.url)), "index.js");
|
|
6777
6765
|
const p = spawn2(process.execPath, [cli, "logs-server"], {
|
|
6778
6766
|
detached: true,
|
|
6779
|
-
stdio: ["ignore",
|
|
6767
|
+
stdio: ["ignore", log4, log4],
|
|
6780
6768
|
windowsHide: true
|
|
6781
6769
|
});
|
|
6782
6770
|
p.on("error", () => {
|
|
@@ -7854,7 +7842,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7854
7842
|
const [localBuf, setLocalBuf] = useState2([]);
|
|
7855
7843
|
const [localOn, setLocalOn] = useState2(null);
|
|
7856
7844
|
const [ring, setRing] = useState2(null);
|
|
7857
|
-
const [
|
|
7845
|
+
const [log4, setLog] = useState2([]);
|
|
7858
7846
|
const [filter, setFilter] = useState2("all");
|
|
7859
7847
|
const [signal, setSignal] = useState2("none");
|
|
7860
7848
|
const [search, setSearch] = useState2("");
|
|
@@ -8698,7 +8686,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8698
8686
|
] }),
|
|
8699
8687
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
|
|
8700
8688
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
|
|
8701
|
-
|
|
8689
|
+
log4.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8702
8690
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
8703
8691
|
hhmmss(l.ts),
|
|
8704
8692
|
" "
|
|
@@ -9635,7 +9623,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9635
9623
|
const sessLoading = source === "cloud" ? agentsQ.loading : localQ.loading;
|
|
9636
9624
|
const doDelete = (kind) => {
|
|
9637
9625
|
setMsg({ text: "deleting\u2026", level: "ok" });
|
|
9638
|
-
const
|
|
9626
|
+
const run10 = async () => {
|
|
9639
9627
|
if (source === "cloud") {
|
|
9640
9628
|
if (kind === "one") {
|
|
9641
9629
|
if (!current) throw new Error("nothing selected");
|
|
@@ -9651,14 +9639,14 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9651
9639
|
localQ.reload();
|
|
9652
9640
|
}
|
|
9653
9641
|
};
|
|
9654
|
-
|
|
9642
|
+
run10().then(() => {
|
|
9655
9643
|
setMsg({ text: kind === "one" ? "\u2713 entry deleted" : `\u2713 ALL ${source} logs deleted`, level: "ok" });
|
|
9656
9644
|
toTop();
|
|
9657
9645
|
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
9658
9646
|
};
|
|
9659
9647
|
const doExport = (kind) => {
|
|
9660
9648
|
setMsg({ text: "exporting\u2026", level: "ok" });
|
|
9661
|
-
const
|
|
9649
|
+
const run10 = async () => {
|
|
9662
9650
|
const dir = join10(homedir8(), ".solongate");
|
|
9663
9651
|
const file = join10(dir, `audit-export-${source}.jsonl`);
|
|
9664
9652
|
let rows2;
|
|
@@ -9671,7 +9659,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9671
9659
|
writeFileSync8(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
|
|
9672
9660
|
return { n: rows2.length, file };
|
|
9673
9661
|
};
|
|
9674
|
-
|
|
9662
|
+
run10().then(({ n, file }) => setMsg({ text: `\u2713 exported ${n} rows \u2192 ${file}`, level: "ok" })).catch((e) => setMsg({ text: "\u2717 export failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
9675
9663
|
};
|
|
9676
9664
|
useInput5(
|
|
9677
9665
|
(input, key) => {
|
|
@@ -10554,7 +10542,7 @@ function SettingsPanel({
|
|
|
10554
10542
|
guardQ.reload();
|
|
10555
10543
|
selfQ.reload();
|
|
10556
10544
|
};
|
|
10557
|
-
const
|
|
10545
|
+
const run10 = (label, fn, reload) => {
|
|
10558
10546
|
if (busy) return;
|
|
10559
10547
|
setBusy(true);
|
|
10560
10548
|
setMsg({ text: label + "\u2026", level: "ok" });
|
|
@@ -10636,8 +10624,8 @@ function SettingsPanel({
|
|
|
10636
10624
|
const body = { signal: editor.signal, threshold: editor.threshold, windowSeconds: editor.windowSeconds, enabled: editor.enabled, ...channels };
|
|
10637
10625
|
const id = editor.id;
|
|
10638
10626
|
setEditor(null);
|
|
10639
|
-
if (id)
|
|
10640
|
-
else
|
|
10627
|
+
if (id) run10("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
10628
|
+
else run10(`${editor.channel} alert added`, () => api.settings.createAlert({ name: "SolonGate alert", ...body }), alertQ.reload);
|
|
10641
10629
|
};
|
|
10642
10630
|
const activate = (r) => {
|
|
10643
10631
|
if (r.kind === "acct") {
|
|
@@ -10653,14 +10641,14 @@ function SettingsPanel({
|
|
|
10653
10641
|
guardQ.reload();
|
|
10654
10642
|
} else if (r.kind === "self") {
|
|
10655
10643
|
if (!selfProt) return;
|
|
10656
|
-
|
|
10644
|
+
run10(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
10657
10645
|
} else if (r.kind === "ll-enabled") {
|
|
10658
10646
|
if (!local) return;
|
|
10659
10647
|
if (!local.enabled && !local.path.trim()) {
|
|
10660
10648
|
setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
|
|
10661
10649
|
return;
|
|
10662
10650
|
}
|
|
10663
|
-
|
|
10651
|
+
run10(local.enabled ? "local logs disabled" : "local logs enabled", () => api.settings.setLocalLogs({ enabled: !local.enabled, path: local.path }), localQ.reload);
|
|
10664
10652
|
} else if (r.kind === "ll-path") {
|
|
10665
10653
|
setInput(local?.path ?? "");
|
|
10666
10654
|
setEditing("path");
|
|
@@ -10671,7 +10659,7 @@ function SettingsPanel({
|
|
|
10671
10659
|
next.running ? { text: `\u2713 dashboard link running on 127.0.0.1:${next.port} \u2014 keeps running after you close the dataroom`, level: "ok" } : { text: "\u2713 dashboard link stopped (disabled until you start it again)", level: "ok" }
|
|
10672
10660
|
);
|
|
10673
10661
|
} else if (r.kind === "wh") {
|
|
10674
|
-
|
|
10662
|
+
run10(r.wh.enabled ? "webhook disabled" : "webhook enabled", () => api.settings.updateWebhook(r.wh.id, { enabled: !r.wh.enabled }), whQ.reload);
|
|
10675
10663
|
} else if (r.kind === "wh-add") {
|
|
10676
10664
|
setInput("");
|
|
10677
10665
|
setEditing("wh-url");
|
|
@@ -10690,7 +10678,7 @@ function SettingsPanel({
|
|
|
10690
10678
|
setEditing(null);
|
|
10691
10679
|
if (which === "path") {
|
|
10692
10680
|
const enabled = (local?.enabled ?? false) && v.length > 0;
|
|
10693
|
-
|
|
10681
|
+
run10(v ? `path saved${enabled ? "" : " (press enter on enabled to turn on)"}` : "path cleared (local logs off)", () => api.settings.setLocalLogs({ enabled, path: v }), localQ.reload);
|
|
10694
10682
|
} else if (which === "wh-url") {
|
|
10695
10683
|
const url = v.replace(/^["'<]+|["'>]+$/g, "").trim();
|
|
10696
10684
|
if (!url) return;
|
|
@@ -10698,7 +10686,7 @@ function SettingsPanel({
|
|
|
10698
10686
|
setMsg({ text: "\u2717 webhook url must start with http:// or https://", level: "bad" });
|
|
10699
10687
|
return;
|
|
10700
10688
|
}
|
|
10701
|
-
|
|
10689
|
+
run10("webhook added", () => api.settings.createWebhook({ url, events: "denials" }), whQ.reload);
|
|
10702
10690
|
} else if (which === "alert-target" && editor) {
|
|
10703
10691
|
setEditor({ ...editor, target: v, field: 1 });
|
|
10704
10692
|
}
|
|
@@ -10752,7 +10740,7 @@ function SettingsPanel({
|
|
|
10752
10740
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
10753
10741
|
refreshAccounts();
|
|
10754
10742
|
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
10755
|
-
if (cur.kind === "alert")
|
|
10743
|
+
if (cur.kind === "alert") run10(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
10756
10744
|
else activate(cur);
|
|
10757
10745
|
}
|
|
10758
10746
|
} else if (inp === "x" && cur.kind === "acct") {
|
|
@@ -10782,13 +10770,13 @@ function SettingsPanel({
|
|
|
10782
10770
|
refreshAccounts();
|
|
10783
10771
|
onAccountsChanged?.();
|
|
10784
10772
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
10785
|
-
|
|
10773
|
+
run10("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
10786
10774
|
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
10787
10775
|
}), whQ.reload);
|
|
10788
10776
|
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
10789
10777
|
else if (inp === "e" && cur.kind === "wh") {
|
|
10790
10778
|
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
10791
|
-
|
|
10779
|
+
run10(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
10792
10780
|
} else if (inp === "e" && cur.kind === "alert") {
|
|
10793
10781
|
const ch = alertChannel(cur.rule);
|
|
10794
10782
|
if (ch) openAlertEditor(ch, cur.rule);
|
|
@@ -10825,10 +10813,10 @@ function SettingsPanel({
|
|
|
10825
10813
|
setConfirmDel(null);
|
|
10826
10814
|
if (cur.kind === "wh") {
|
|
10827
10815
|
const id = cur.wh.id;
|
|
10828
|
-
|
|
10816
|
+
run10("webhook deleted", () => api.settings.deleteWebhook(id).then(() => setHidden((h) => new Set(h).add("wh:" + id))), whQ.reload);
|
|
10829
10817
|
} else {
|
|
10830
10818
|
const id = cur.rule.id;
|
|
10831
|
-
|
|
10819
|
+
run10("alert deleted", () => api.settings.deleteAlert(id).then(() => setHidden((h) => new Set(h).add("alert:" + id))), alertQ.reload);
|
|
10832
10820
|
}
|
|
10833
10821
|
} else if (inp === "r") reloadAll();
|
|
10834
10822
|
},
|
|
@@ -11128,9 +11116,9 @@ function App() {
|
|
|
11128
11116
|
const [update2, setUpdate] = useState8({ kind: "idle" });
|
|
11129
11117
|
useEffect7(() => {
|
|
11130
11118
|
let alive = true;
|
|
11131
|
-
const
|
|
11132
|
-
|
|
11133
|
-
const t = setInterval(
|
|
11119
|
+
const run10 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
11120
|
+
run10();
|
|
11121
|
+
const t = setInterval(run10, 30 * 6e4);
|
|
11134
11122
|
return () => {
|
|
11135
11123
|
alive = false;
|
|
11136
11124
|
clearInterval(t);
|
|
@@ -12204,7 +12192,7 @@ var init_watch = __esm({
|
|
|
12204
12192
|
}
|
|
12205
12193
|
});
|
|
12206
12194
|
|
|
12207
|
-
// src/commands/
|
|
12195
|
+
// src/commands/alerts.ts
|
|
12208
12196
|
async function run8(argv) {
|
|
12209
12197
|
const { positionals, flags } = parse(argv);
|
|
12210
12198
|
const sub = positionals[0] ?? "list";
|
|
@@ -12212,89 +12200,6 @@ async function run8(argv) {
|
|
|
12212
12200
|
switch (sub) {
|
|
12213
12201
|
case "help":
|
|
12214
12202
|
return err(USAGE6), 0;
|
|
12215
|
-
case "list": {
|
|
12216
|
-
const { keys } = await api.keys.list();
|
|
12217
|
-
if (json) return printJson(keys), 0;
|
|
12218
|
-
if (!keys.length) return err(dim(" No API keys.")), 0;
|
|
12219
|
-
table(
|
|
12220
|
-
["ID", "NAME", "PREFIX", "CREATED"],
|
|
12221
|
-
keys.map((k) => [dim(truncate3(k.id, 10)), truncate3(k.name, 24), cyan(k.key_prefix), dim(k.created_at)])
|
|
12222
|
-
);
|
|
12223
|
-
return 0;
|
|
12224
|
-
}
|
|
12225
|
-
case "create": {
|
|
12226
|
-
const name = flagStr(flags, "name");
|
|
12227
|
-
if (!name) return err(" Usage: keys create --name <name>"), 1;
|
|
12228
|
-
const res = await api.keys.create(name, !flagBool(flags, "test"));
|
|
12229
|
-
if (json) return printJson(res), 0;
|
|
12230
|
-
err(green(` \u2713 Created "${res.name}"`));
|
|
12231
|
-
err("");
|
|
12232
|
-
err(" " + bold(res.key));
|
|
12233
|
-
err(dim(" \u2191 shown only once \u2014 copy it now."));
|
|
12234
|
-
return 0;
|
|
12235
|
-
}
|
|
12236
|
-
case "revoke": {
|
|
12237
|
-
const id = positionals[1];
|
|
12238
|
-
if (!id) return err(" Usage: keys revoke <id>"), 1;
|
|
12239
|
-
await api.keys.revoke(id);
|
|
12240
|
-
if (json) return printJson({ ok: true, id }), 0;
|
|
12241
|
-
return err(green(` \u2713 Revoked ${id}`)), 0;
|
|
12242
|
-
}
|
|
12243
|
-
default:
|
|
12244
|
-
return err(USAGE6), 1;
|
|
12245
|
-
}
|
|
12246
|
-
}
|
|
12247
|
-
var USAGE6;
|
|
12248
|
-
var init_keys2 = __esm({
|
|
12249
|
-
"src/commands/keys.ts"() {
|
|
12250
|
-
"use strict";
|
|
12251
|
-
init_api_client();
|
|
12252
|
-
init_args();
|
|
12253
|
-
init_format();
|
|
12254
|
-
USAGE6 = `${bold("solongate keys")} \u2014 API keys
|
|
12255
|
-
|
|
12256
|
-
keys list List keys (prefix only)
|
|
12257
|
-
keys create --name <n> Create a key (secret shown once)
|
|
12258
|
-
keys revoke <id> Revoke a key
|
|
12259
|
-
|
|
12260
|
-
Add --json for machine-readable output.`;
|
|
12261
|
-
}
|
|
12262
|
-
});
|
|
12263
|
-
|
|
12264
|
-
// src/commands/mcp.ts
|
|
12265
|
-
async function run9(argv) {
|
|
12266
|
-
const { flags } = parse(argv);
|
|
12267
|
-
const json = flagBool(flags, "json");
|
|
12268
|
-
const { servers } = await api.mcp.list();
|
|
12269
|
-
if (json) return printJson(servers), 0;
|
|
12270
|
-
if (!servers.length) return err(dim(" No MCP servers registered.")), 0;
|
|
12271
|
-
table(
|
|
12272
|
-
["STATUS", "NAME", "TARGET"],
|
|
12273
|
-
servers.map((s) => [
|
|
12274
|
-
s.status === "active" ? green(s.status) : yellow(s.status),
|
|
12275
|
-
cyan(truncate3(s.name, 24)),
|
|
12276
|
-
dim(truncate3(s.url || s.command || "\u2014", 46))
|
|
12277
|
-
])
|
|
12278
|
-
);
|
|
12279
|
-
return 0;
|
|
12280
|
-
}
|
|
12281
|
-
var init_mcp2 = __esm({
|
|
12282
|
-
"src/commands/mcp.ts"() {
|
|
12283
|
-
"use strict";
|
|
12284
|
-
init_api_client();
|
|
12285
|
-
init_args();
|
|
12286
|
-
init_format();
|
|
12287
|
-
}
|
|
12288
|
-
});
|
|
12289
|
-
|
|
12290
|
-
// src/commands/alerts.ts
|
|
12291
|
-
async function run10(argv) {
|
|
12292
|
-
const { positionals, flags } = parse(argv);
|
|
12293
|
-
const sub = positionals[0] ?? "list";
|
|
12294
|
-
const json = flagBool(flags, "json");
|
|
12295
|
-
switch (sub) {
|
|
12296
|
-
case "help":
|
|
12297
|
-
return err(USAGE7), 0;
|
|
12298
12203
|
case "list": {
|
|
12299
12204
|
const { rules } = await api.settings.getAlerts();
|
|
12300
12205
|
if (json) return printJson(rules), 0;
|
|
@@ -12336,17 +12241,17 @@ async function run10(argv) {
|
|
|
12336
12241
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
12337
12242
|
}
|
|
12338
12243
|
default:
|
|
12339
|
-
return err(
|
|
12244
|
+
return err(USAGE6), 1;
|
|
12340
12245
|
}
|
|
12341
12246
|
}
|
|
12342
|
-
var
|
|
12247
|
+
var USAGE6;
|
|
12343
12248
|
var init_alerts = __esm({
|
|
12344
12249
|
"src/commands/alerts.ts"() {
|
|
12345
12250
|
"use strict";
|
|
12346
12251
|
init_api_client();
|
|
12347
12252
|
init_args();
|
|
12348
12253
|
init_format();
|
|
12349
|
-
|
|
12254
|
+
USAGE6 = `${bold("solongate alerts")} \u2014 spike alerts (Telegram / email)
|
|
12350
12255
|
|
|
12351
12256
|
alerts list
|
|
12352
12257
|
alerts add --signal deny|dlp|ratelimit|any --threshold N --window S
|
|
@@ -12358,13 +12263,13 @@ var init_alerts = __esm({
|
|
|
12358
12263
|
});
|
|
12359
12264
|
|
|
12360
12265
|
// src/commands/webhooks.ts
|
|
12361
|
-
async function
|
|
12266
|
+
async function run9(argv) {
|
|
12362
12267
|
const { positionals, flags } = parse(argv);
|
|
12363
12268
|
const sub = positionals[0] ?? "list";
|
|
12364
12269
|
const json = flagBool(flags, "json");
|
|
12365
12270
|
switch (sub) {
|
|
12366
12271
|
case "help":
|
|
12367
|
-
return err(
|
|
12272
|
+
return err(USAGE7), 0;
|
|
12368
12273
|
case "list": {
|
|
12369
12274
|
const { webhooks } = await api.settings.getWebhooks();
|
|
12370
12275
|
if (json) return printJson(webhooks), 0;
|
|
@@ -12390,17 +12295,17 @@ async function run11(argv) {
|
|
|
12390
12295
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
12391
12296
|
}
|
|
12392
12297
|
default:
|
|
12393
|
-
return err(
|
|
12298
|
+
return err(USAGE7), 1;
|
|
12394
12299
|
}
|
|
12395
12300
|
}
|
|
12396
|
-
var
|
|
12301
|
+
var USAGE7;
|
|
12397
12302
|
var init_webhooks = __esm({
|
|
12398
12303
|
"src/commands/webhooks.ts"() {
|
|
12399
12304
|
"use strict";
|
|
12400
12305
|
init_api_client();
|
|
12401
12306
|
init_args();
|
|
12402
12307
|
init_format();
|
|
12403
|
-
|
|
12308
|
+
USAGE7 = `${bold("solongate webhooks")} \u2014 event webhooks
|
|
12404
12309
|
|
|
12405
12310
|
webhooks list
|
|
12406
12311
|
webhooks add --url <https://\u2026> [--events denials|allowed|all]
|
|
@@ -12436,14 +12341,10 @@ async function dispatch(command, argv) {
|
|
|
12436
12341
|
return run6(argv);
|
|
12437
12342
|
case "watch":
|
|
12438
12343
|
return run7(argv);
|
|
12439
|
-
case "keys":
|
|
12440
|
-
return run8(argv);
|
|
12441
|
-
case "mcp":
|
|
12442
|
-
return run9(argv);
|
|
12443
12344
|
case "alerts":
|
|
12444
|
-
return
|
|
12345
|
+
return run8(argv);
|
|
12445
12346
|
case "webhooks":
|
|
12446
|
-
return
|
|
12347
|
+
return run9(argv);
|
|
12447
12348
|
default:
|
|
12448
12349
|
err(` Unknown command: ${command}`);
|
|
12449
12350
|
return 1;
|
|
@@ -12480,333 +12381,9 @@ var init_commands = __esm({
|
|
|
12480
12381
|
init_agents2();
|
|
12481
12382
|
init_doctor();
|
|
12482
12383
|
init_watch();
|
|
12483
|
-
init_keys2();
|
|
12484
|
-
init_mcp2();
|
|
12485
12384
|
init_alerts();
|
|
12486
12385
|
init_webhooks();
|
|
12487
|
-
COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "
|
|
12488
|
-
}
|
|
12489
|
-
});
|
|
12490
|
-
|
|
12491
|
-
// src/shield.ts
|
|
12492
|
-
var shield_exports = {};
|
|
12493
|
-
__export(shield_exports, {
|
|
12494
|
-
runShield: () => runShield
|
|
12495
|
-
});
|
|
12496
|
-
import { createServer, request as httpRequest } from "http";
|
|
12497
|
-
import { request as httpsRequest } from "https";
|
|
12498
|
-
import { spawn as spawn5 } from "child_process";
|
|
12499
|
-
import { URL as URL2 } from "url";
|
|
12500
|
-
import { readFileSync as readFileSync11, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
12501
|
-
import { resolve as resolve5 } from "path";
|
|
12502
|
-
import { homedir as homedir13 } from "os";
|
|
12503
|
-
function findCacheFile() {
|
|
12504
|
-
const dir = resolve5(homedir13(), ".solongate");
|
|
12505
|
-
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
12506
|
-
if (envSel) {
|
|
12507
|
-
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
12508
|
-
if (existsSync7(f)) return f;
|
|
12509
|
-
}
|
|
12510
|
-
let best = null, bestTs = -1;
|
|
12511
|
-
try {
|
|
12512
|
-
for (const name of readdirSync(dir)) {
|
|
12513
|
-
if (name.startsWith(".policy-cache-") && name.endsWith(".json")) {
|
|
12514
|
-
const full = resolve5(dir, name);
|
|
12515
|
-
const ts = statSync4(full).mtimeMs;
|
|
12516
|
-
if (ts > bestTs) {
|
|
12517
|
-
bestTs = ts;
|
|
12518
|
-
best = full;
|
|
12519
|
-
}
|
|
12520
|
-
}
|
|
12521
|
-
}
|
|
12522
|
-
} catch {
|
|
12523
|
-
}
|
|
12524
|
-
return best;
|
|
12525
|
-
}
|
|
12526
|
-
function loadCfg() {
|
|
12527
|
-
try {
|
|
12528
|
-
const f = findCacheFile();
|
|
12529
|
-
if (f && existsSync7(f)) {
|
|
12530
|
-
const c2 = JSON.parse(readFileSync11(f, "utf-8"));
|
|
12531
|
-
const d = c2?.security?.dlpRedact;
|
|
12532
|
-
const g = c2?.security?.ghost;
|
|
12533
|
-
const ghost = g && Array.isArray(g.patterns) ? g.patterns : [];
|
|
12534
|
-
if (d && Array.isArray(d.patterns)) return { patterns: d.patterns, custom: Array.isArray(d.custom) ? d.custom : [], ghost };
|
|
12535
|
-
return { patterns: DLP_PATTERNS.map((p) => p.name), custom: [], ghost };
|
|
12536
|
-
}
|
|
12537
|
-
} catch {
|
|
12538
|
-
}
|
|
12539
|
-
return { patterns: DLP_PATTERNS.map((p) => p.name), custom: [], ghost: [] };
|
|
12540
|
-
}
|
|
12541
|
-
function ghostGlobToRegExp(glob) {
|
|
12542
|
-
let re = "";
|
|
12543
|
-
for (let i = 0; i < glob.length; i++) {
|
|
12544
|
-
const c2 = glob[i];
|
|
12545
|
-
if (c2 === "*") {
|
|
12546
|
-
if (glob[i + 1] === "*") {
|
|
12547
|
-
re += ".*";
|
|
12548
|
-
i++;
|
|
12549
|
-
} else re += "[^/]*";
|
|
12550
|
-
} else if (c2 === "?") re += "[^/]";
|
|
12551
|
-
else if ("\\^$.|+()[]{}".indexOf(c2) !== -1) re += "\\" + c2;
|
|
12552
|
-
else re += c2;
|
|
12553
|
-
}
|
|
12554
|
-
try {
|
|
12555
|
-
return new RegExp("^" + re + "$");
|
|
12556
|
-
} catch {
|
|
12557
|
-
return null;
|
|
12558
|
-
}
|
|
12559
|
-
}
|
|
12560
|
-
function ghostMatch(targetPath, patterns) {
|
|
12561
|
-
if (!targetPath || !Array.isArray(patterns) || patterns.length === 0) return false;
|
|
12562
|
-
const norm = String(targetPath).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
12563
|
-
if (!norm) return false;
|
|
12564
|
-
const segments = norm.split("/").filter(Boolean);
|
|
12565
|
-
const base = segments.length ? segments[segments.length - 1] : norm;
|
|
12566
|
-
for (let pat of patterns) {
|
|
12567
|
-
pat = String(pat || "").trim();
|
|
12568
|
-
if (!pat) continue;
|
|
12569
|
-
let dirOnly = false;
|
|
12570
|
-
if (pat.endsWith("/")) {
|
|
12571
|
-
dirOnly = true;
|
|
12572
|
-
pat = pat.slice(0, -1);
|
|
12573
|
-
}
|
|
12574
|
-
if (!pat) continue;
|
|
12575
|
-
const hasSlash = pat.indexOf("/") !== -1;
|
|
12576
|
-
const hasWild = /[*?]/.test(pat);
|
|
12577
|
-
const re = ghostGlobToRegExp(pat);
|
|
12578
|
-
if (!re) continue;
|
|
12579
|
-
if (dirOnly) {
|
|
12580
|
-
if (!hasSlash && !hasWild) {
|
|
12581
|
-
if (segments.indexOf(pat) !== -1) return true;
|
|
12582
|
-
continue;
|
|
12583
|
-
}
|
|
12584
|
-
let acc = "";
|
|
12585
|
-
for (const s of segments) {
|
|
12586
|
-
acc = acc ? acc + "/" + s : s;
|
|
12587
|
-
if (re.test(acc) || re.test(s)) return true;
|
|
12588
|
-
}
|
|
12589
|
-
continue;
|
|
12590
|
-
}
|
|
12591
|
-
if (!hasSlash) {
|
|
12592
|
-
if (re.test(base)) return true;
|
|
12593
|
-
if (segments.some((s) => re.test(s))) return true;
|
|
12594
|
-
continue;
|
|
12595
|
-
}
|
|
12596
|
-
if (re.test(norm)) return true;
|
|
12597
|
-
}
|
|
12598
|
-
return false;
|
|
12599
|
-
}
|
|
12600
|
-
function ghostCleanToken(tok) {
|
|
12601
|
-
let t = String(tok || "").trim();
|
|
12602
|
-
t = t.replace(/^[<>|;&(]+/, "").replace(/[);&|]+$/, "");
|
|
12603
|
-
t = t.replace(/^['"]+/, "").replace(/['"]+$/, "");
|
|
12604
|
-
t = t.replace(/^\d*>>?/, "");
|
|
12605
|
-
return t.trim();
|
|
12606
|
-
}
|
|
12607
|
-
function ghostStripLines(text, pats) {
|
|
12608
|
-
if (!Array.isArray(pats) || pats.length === 0) return text;
|
|
12609
|
-
const lines = String(text).split("\n");
|
|
12610
|
-
const kept = [];
|
|
12611
|
-
for (const line of lines) {
|
|
12612
|
-
const trimmed = line.trim();
|
|
12613
|
-
if (!trimmed) {
|
|
12614
|
-
kept.push(line);
|
|
12615
|
-
continue;
|
|
12616
|
-
}
|
|
12617
|
-
if (ghostMatch(trimmed, pats)) continue;
|
|
12618
|
-
const toks = trimmed.split(/\s+/);
|
|
12619
|
-
const anyHit = toks.some((t) => ghostMatch(ghostCleanToken(t), pats));
|
|
12620
|
-
if (!anyHit) {
|
|
12621
|
-
kept.push(line);
|
|
12622
|
-
continue;
|
|
12623
|
-
}
|
|
12624
|
-
if (toks.length > 3) continue;
|
|
12625
|
-
const remaining = toks.filter((t) => !ghostMatch(ghostCleanToken(t), pats));
|
|
12626
|
-
if (remaining.length === 0) continue;
|
|
12627
|
-
kept.push(remaining.join(" "));
|
|
12628
|
-
}
|
|
12629
|
-
return kept.join("\n");
|
|
12630
|
-
}
|
|
12631
|
-
function dlpGlobToRe(glob, flags) {
|
|
12632
|
-
let re = "";
|
|
12633
|
-
for (const ch of String(glob || "")) {
|
|
12634
|
-
if (ch === "*") re += "[^\\s]*";
|
|
12635
|
-
else if (".+?^${}()|[]\\".indexOf(ch) !== -1) re += "\\" + ch;
|
|
12636
|
-
else re += ch;
|
|
12637
|
-
}
|
|
12638
|
-
return new RegExp(re, flags);
|
|
12639
|
-
}
|
|
12640
|
-
function redactString(s, cfg) {
|
|
12641
|
-
if (!cfg || typeof s !== "string" || !s) return s;
|
|
12642
|
-
const allow = new Set(cfg.patterns);
|
|
12643
|
-
const NUL = String.fromCharCode(0);
|
|
12644
|
-
const labels = [];
|
|
12645
|
-
const stash = (label) => NUL + (labels.push(label) - 1) + NUL;
|
|
12646
|
-
let out2 = s;
|
|
12647
|
-
for (const p of DLP_PATTERNS) if (allow.has(p.name)) out2 = out2.replace(p.re, () => stash(`[REDACTED: ${p.name}]`));
|
|
12648
|
-
for (const c2 of cfg.custom) {
|
|
12649
|
-
try {
|
|
12650
|
-
out2 = out2.replace(dlpGlobToRe(c2.re, "gi"), () => stash(`[REDACTED: ${c2.name || "custom"}]`));
|
|
12651
|
-
} catch {
|
|
12652
|
-
}
|
|
12653
|
-
}
|
|
12654
|
-
return out2.replace(new RegExp(NUL + "(\\d+)" + NUL, "g"), (_, i) => labels[+i] || "");
|
|
12655
|
-
}
|
|
12656
|
-
function redactDeep(value, cfg) {
|
|
12657
|
-
const ghost = cfg && Array.isArray(cfg.ghost) ? cfg.ghost : null;
|
|
12658
|
-
if (typeof value === "string") {
|
|
12659
|
-
let out2 = redactString(value, cfg);
|
|
12660
|
-
if (ghost && ghost.length) out2 = ghostStripLines(out2, ghost);
|
|
12661
|
-
if (out2 === "" && value !== "") out2 = "\n";
|
|
12662
|
-
return out2;
|
|
12663
|
-
}
|
|
12664
|
-
if (Array.isArray(value)) {
|
|
12665
|
-
const arr = ghost && ghost.length ? value.filter((v) => !(typeof v === "string" && ghostMatch(v.trim(), ghost))) : value;
|
|
12666
|
-
return arr.map((v) => redactDeep(v, cfg));
|
|
12667
|
-
}
|
|
12668
|
-
if (value && typeof value === "object") {
|
|
12669
|
-
const out2 = {};
|
|
12670
|
-
for (const [k, v] of Object.entries(value)) out2[k] = redactDeep(v, cfg);
|
|
12671
|
-
return out2;
|
|
12672
|
-
}
|
|
12673
|
-
return value;
|
|
12674
|
-
}
|
|
12675
|
-
function pickUpstream() {
|
|
12676
|
-
const raw = process.env.SOLONGATE_SHIELD_UPSTREAM || process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
|
|
12677
|
-
try {
|
|
12678
|
-
return new URL2(raw);
|
|
12679
|
-
} catch {
|
|
12680
|
-
return new URL2("https://api.anthropic.com");
|
|
12681
|
-
}
|
|
12682
|
-
}
|
|
12683
|
-
function startProxy(upstream) {
|
|
12684
|
-
const forward = upstream.protocol === "https:" ? httpsRequest : httpRequest;
|
|
12685
|
-
const server = createServer((req, res) => {
|
|
12686
|
-
const cfg = loadCfg();
|
|
12687
|
-
const chunks = [];
|
|
12688
|
-
req.on("data", (c2) => chunks.push(c2));
|
|
12689
|
-
req.on("end", () => {
|
|
12690
|
-
let body = Buffer.concat(chunks);
|
|
12691
|
-
try {
|
|
12692
|
-
if (body.length && (req.headers["content-type"] || "").includes("json")) {
|
|
12693
|
-
const parsed = JSON.parse(body.toString("utf-8"));
|
|
12694
|
-
if (parsed && typeof parsed === "object" && Array.isArray(parsed["messages"])) {
|
|
12695
|
-
if (parsed["system"] !== void 0) parsed["system"] = redactDeep(parsed["system"], cfg);
|
|
12696
|
-
const msgs = parsed["messages"];
|
|
12697
|
-
for (let i = 0; i < msgs.length; i++) {
|
|
12698
|
-
const m = msgs[i];
|
|
12699
|
-
if (m && m["role"] !== "assistant") msgs[i] = redactDeep(m, cfg);
|
|
12700
|
-
}
|
|
12701
|
-
body = Buffer.from(JSON.stringify(parsed), "utf-8");
|
|
12702
|
-
} else {
|
|
12703
|
-
body = Buffer.from(JSON.stringify(redactDeep(parsed, cfg)), "utf-8");
|
|
12704
|
-
}
|
|
12705
|
-
}
|
|
12706
|
-
} catch {
|
|
12707
|
-
}
|
|
12708
|
-
const headers = { ...req.headers };
|
|
12709
|
-
delete headers["host"];
|
|
12710
|
-
delete headers["content-length"];
|
|
12711
|
-
delete headers["accept-encoding"];
|
|
12712
|
-
headers["content-length"] = String(body.length);
|
|
12713
|
-
const upstreamReq = forward(
|
|
12714
|
-
{
|
|
12715
|
-
protocol: upstream.protocol,
|
|
12716
|
-
hostname: upstream.hostname,
|
|
12717
|
-
port: upstream.port || (upstream.protocol === "https:" ? 443 : 80),
|
|
12718
|
-
method: req.method,
|
|
12719
|
-
path: req.url,
|
|
12720
|
-
headers: { ...headers, host: upstream.host }
|
|
12721
|
-
},
|
|
12722
|
-
(upRes) => {
|
|
12723
|
-
res.writeHead(upRes.statusCode || 502, upRes.headers);
|
|
12724
|
-
upRes.pipe(res);
|
|
12725
|
-
}
|
|
12726
|
-
);
|
|
12727
|
-
upstreamReq.on("error", (e) => {
|
|
12728
|
-
log4("upstream error:", e.message);
|
|
12729
|
-
if (!res.headersSent) res.writeHead(502, { "content-type": "text/plain" });
|
|
12730
|
-
res.end("shield upstream error");
|
|
12731
|
-
});
|
|
12732
|
-
upstreamReq.end(body);
|
|
12733
|
-
});
|
|
12734
|
-
req.on("error", () => {
|
|
12735
|
-
try {
|
|
12736
|
-
res.destroy();
|
|
12737
|
-
} catch {
|
|
12738
|
-
}
|
|
12739
|
-
});
|
|
12740
|
-
});
|
|
12741
|
-
return new Promise((resolveP) => {
|
|
12742
|
-
server.listen(0, "127.0.0.1", () => {
|
|
12743
|
-
const addr = server.address();
|
|
12744
|
-
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
12745
|
-
resolveP({ port, close: () => server.close() });
|
|
12746
|
-
});
|
|
12747
|
-
});
|
|
12748
|
-
}
|
|
12749
|
-
async function runShield() {
|
|
12750
|
-
const sep = process.argv.indexOf("--");
|
|
12751
|
-
const cmd = sep !== -1 ? process.argv.slice(sep + 1) : [];
|
|
12752
|
-
if (cmd.length === 0) {
|
|
12753
|
-
log4("usage: npx @solongate/proxy shield -- <command> [args...] (e.g. shield -- claude)");
|
|
12754
|
-
process.exit(1);
|
|
12755
|
-
}
|
|
12756
|
-
const upstream = pickUpstream();
|
|
12757
|
-
const { port, close } = await startProxy(upstream);
|
|
12758
|
-
log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
|
|
12759
|
-
const child = spawn5(cmd[0], cmd.slice(1), {
|
|
12760
|
-
stdio: "inherit",
|
|
12761
|
-
env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
|
|
12762
|
-
shell: process.platform === "win32"
|
|
12763
|
-
// resolve `claude.cmd` etc. on Windows
|
|
12764
|
-
});
|
|
12765
|
-
const shutdown = () => {
|
|
12766
|
-
try {
|
|
12767
|
-
close();
|
|
12768
|
-
} catch {
|
|
12769
|
-
}
|
|
12770
|
-
};
|
|
12771
|
-
child.on("exit", (code, signal) => {
|
|
12772
|
-
shutdown();
|
|
12773
|
-
if (signal) process.kill(process.pid, signal);
|
|
12774
|
-
else process.exit(code ?? 0);
|
|
12775
|
-
});
|
|
12776
|
-
child.on("error", (e) => {
|
|
12777
|
-
log4("failed to launch command:", e.message);
|
|
12778
|
-
shutdown();
|
|
12779
|
-
process.exit(1);
|
|
12780
|
-
});
|
|
12781
|
-
for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => {
|
|
12782
|
-
try {
|
|
12783
|
-
child.kill(sig);
|
|
12784
|
-
} catch {
|
|
12785
|
-
}
|
|
12786
|
-
});
|
|
12787
|
-
}
|
|
12788
|
-
var log4, DLP_PATTERNS;
|
|
12789
|
-
var init_shield = __esm({
|
|
12790
|
-
"src/shield.ts"() {
|
|
12791
|
-
"use strict";
|
|
12792
|
-
log4 = (...a) => process.stderr.write(`[SolonGate shield] ${a.map(String).join(" ")}
|
|
12793
|
-
`);
|
|
12794
|
-
DLP_PATTERNS = [
|
|
12795
|
-
{ name: "AWS access key", re: /AKIA[0-9A-Z]{16}/g },
|
|
12796
|
-
{ name: "Private key block", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----|-----BEGIN [A-Z ]*PRIVATE KEY-----/g },
|
|
12797
|
-
{ name: "Anthropic key", re: /sk-ant-[A-Za-z0-9_-]{20,}/g },
|
|
12798
|
-
{ name: "OpenAI key", re: /sk-(proj-)?[A-Za-z0-9_-]{20,}/g },
|
|
12799
|
-
{ name: "GitHub token", re: /gh[pousr]_[A-Za-z0-9]{20,}/g },
|
|
12800
|
-
{ name: "GitHub fine-grained PAT", re: /github_pat_[A-Za-z0-9_]{20,}/g },
|
|
12801
|
-
{ name: "GitLab token", re: /glpat-[A-Za-z0-9_-]{20,}/g },
|
|
12802
|
-
{ name: "Slack token", re: /xox[baprs]-[A-Za-z0-9-]{10,}/g },
|
|
12803
|
-
{ name: "Stripe key", re: /[sr]k_(live|test)_[A-Za-z0-9]{20,}/g },
|
|
12804
|
-
{ name: "SendGrid key", re: /SG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}/g },
|
|
12805
|
-
{ name: "Twilio key", re: /SK[0-9a-fA-F]{32}/g },
|
|
12806
|
-
{ name: "npm token", re: /npm_[A-Za-z0-9]{36}/g },
|
|
12807
|
-
{ name: "JWT", re: /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g },
|
|
12808
|
-
{ name: "Bearer token", re: /bearer\s+[A-Za-z0-9._-]{20,}/gi }
|
|
12809
|
-
];
|
|
12386
|
+
COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks"];
|
|
12810
12387
|
}
|
|
12811
12388
|
});
|
|
12812
12389
|
|
|
@@ -12815,11 +12392,11 @@ var logs_server_exports = {};
|
|
|
12815
12392
|
__export(logs_server_exports, {
|
|
12816
12393
|
runLogsServer: () => runLogsServer
|
|
12817
12394
|
});
|
|
12818
|
-
import { createServer
|
|
12819
|
-
import { readFileSync as
|
|
12820
|
-
import { resolve as
|
|
12821
|
-
import { homedir as
|
|
12822
|
-
import { readdirSync
|
|
12395
|
+
import { createServer } from "http";
|
|
12396
|
+
import { readFileSync as readFileSync11, statSync as statSync4 } from "fs";
|
|
12397
|
+
import { resolve as resolve5, join as join15, isAbsolute } from "path";
|
|
12398
|
+
import { homedir as homedir13 } from "os";
|
|
12399
|
+
import { readdirSync } from "fs";
|
|
12823
12400
|
function allowedOrigins() {
|
|
12824
12401
|
const base = [
|
|
12825
12402
|
"https://dashboard.solongate.com",
|
|
@@ -12835,15 +12412,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
12835
12412
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
12836
12413
|
if (!dir) return null;
|
|
12837
12414
|
if (isAbsolute(dir)) return dir;
|
|
12838
|
-
return
|
|
12415
|
+
return resolve5(homedir13(), ".solongate", "local-logs");
|
|
12839
12416
|
}
|
|
12840
12417
|
async function findLogDir() {
|
|
12841
|
-
const base =
|
|
12418
|
+
const base = resolve5(homedir13(), ".solongate");
|
|
12842
12419
|
try {
|
|
12843
|
-
const files =
|
|
12420
|
+
const files = readdirSync(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
12844
12421
|
for (const f of files) {
|
|
12845
12422
|
try {
|
|
12846
|
-
const c2 = JSON.parse(
|
|
12423
|
+
const c2 = JSON.parse(readFileSync11(join15(base, f), "utf-8"));
|
|
12847
12424
|
const p = c2?.security?.localLogs?.path;
|
|
12848
12425
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
12849
12426
|
} catch {
|
|
@@ -12852,7 +12429,7 @@ async function findLogDir() {
|
|
|
12852
12429
|
} catch {
|
|
12853
12430
|
}
|
|
12854
12431
|
try {
|
|
12855
|
-
const cfgRaw =
|
|
12432
|
+
const cfgRaw = readFileSync11(join15(base, "cloud-guard.json"), "utf-8");
|
|
12856
12433
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
12857
12434
|
if (apiKey) {
|
|
12858
12435
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -12883,7 +12460,7 @@ function fileInfo(dir) {
|
|
|
12883
12460
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
12884
12461
|
const file = join15(dir, LOG_FILENAME);
|
|
12885
12462
|
try {
|
|
12886
|
-
const st =
|
|
12463
|
+
const st = statSync4(file);
|
|
12887
12464
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
12888
12465
|
} catch {
|
|
12889
12466
|
return { file, exists: false, size: 0, mtimeMs: 0 };
|
|
@@ -12915,7 +12492,7 @@ async function runLogsServer() {
|
|
|
12915
12492
|
}
|
|
12916
12493
|
const portArg = argv[argv.indexOf("--port") + 1];
|
|
12917
12494
|
const port = Number(process.env.SOLONGATE_LOGS_PORT || (argv.includes("--port") ? portArg : "") || DEFAULT_PORT) || DEFAULT_PORT;
|
|
12918
|
-
const server =
|
|
12495
|
+
const server = createServer(async (req, res) => {
|
|
12919
12496
|
setCors(req, res);
|
|
12920
12497
|
if (req.method === "OPTIONS") {
|
|
12921
12498
|
res.writeHead(204);
|
|
@@ -12964,7 +12541,7 @@ async function runLogsServer() {
|
|
|
12964
12541
|
return;
|
|
12965
12542
|
}
|
|
12966
12543
|
try {
|
|
12967
|
-
const text =
|
|
12544
|
+
const text = readFileSync11(info.file, "utf-8");
|
|
12968
12545
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
|
|
12969
12546
|
res.end(text);
|
|
12970
12547
|
} catch {
|
|
@@ -13016,644 +12593,16 @@ var init_logs_server = __esm({
|
|
|
13016
12593
|
}
|
|
13017
12594
|
});
|
|
13018
12595
|
|
|
13019
|
-
// src/inject.ts
|
|
13020
|
-
var inject_exports = {};
|
|
13021
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, existsSync as existsSync8, copyFileSync } from "fs";
|
|
13022
|
-
import { resolve as resolve7 } from "path";
|
|
13023
|
-
import { execSync } from "child_process";
|
|
13024
|
-
function parseInjectArgs(argv) {
|
|
13025
|
-
const args = argv.slice(2);
|
|
13026
|
-
const opts = {
|
|
13027
|
-
dryRun: false,
|
|
13028
|
-
restore: false,
|
|
13029
|
-
skipInstall: false
|
|
13030
|
-
};
|
|
13031
|
-
for (let i = 0; i < args.length; i++) {
|
|
13032
|
-
switch (args[i]) {
|
|
13033
|
-
case "--file":
|
|
13034
|
-
opts.file = args[++i];
|
|
13035
|
-
break;
|
|
13036
|
-
case "--dry-run":
|
|
13037
|
-
opts.dryRun = true;
|
|
13038
|
-
break;
|
|
13039
|
-
case "--restore":
|
|
13040
|
-
opts.restore = true;
|
|
13041
|
-
break;
|
|
13042
|
-
case "--skip-install":
|
|
13043
|
-
opts.skipInstall = true;
|
|
13044
|
-
break;
|
|
13045
|
-
case "--help":
|
|
13046
|
-
case "-h":
|
|
13047
|
-
printHelp();
|
|
13048
|
-
process.exit(0);
|
|
13049
|
-
}
|
|
13050
|
-
}
|
|
13051
|
-
return opts;
|
|
13052
|
-
}
|
|
13053
|
-
function printHelp() {
|
|
13054
|
-
log3(`
|
|
13055
|
-
SolonGate Inject \u2014 Add security to your MCP server in seconds
|
|
13056
|
-
|
|
13057
|
-
USAGE
|
|
13058
|
-
npx @solongate/proxy inject [options]
|
|
13059
|
-
|
|
13060
|
-
OPTIONS
|
|
13061
|
-
--file <path> Entry file to modify (default: auto-detect)
|
|
13062
|
-
--dry-run Preview changes without writing
|
|
13063
|
-
--restore Restore original file from backup
|
|
13064
|
-
--skip-install Don't install SDK package
|
|
13065
|
-
-h, --help Show this help message
|
|
13066
|
-
|
|
13067
|
-
EXAMPLES
|
|
13068
|
-
npx @solongate/proxy inject # Auto-detect and inject
|
|
13069
|
-
npx @solongate/proxy inject --file src/main.ts # Specify entry file
|
|
13070
|
-
npx @solongate/proxy inject --dry-run # Preview changes
|
|
13071
|
-
npx @solongate/proxy inject --restore # Undo injection
|
|
13072
|
-
|
|
13073
|
-
WHAT IT DOES
|
|
13074
|
-
Replaces McpServer with SecureMcpServer (2 lines changed)
|
|
13075
|
-
All tool() calls are automatically protected by SolonGate.
|
|
13076
|
-
`);
|
|
13077
|
-
}
|
|
13078
|
-
function detectProject() {
|
|
13079
|
-
if (!existsSync8(resolve7("package.json"))) return false;
|
|
13080
|
-
try {
|
|
13081
|
-
const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
|
|
13082
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13083
|
-
return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
|
|
13084
|
-
} catch {
|
|
13085
|
-
return false;
|
|
13086
|
-
}
|
|
13087
|
-
}
|
|
13088
|
-
function findTsEntryFile() {
|
|
13089
|
-
try {
|
|
13090
|
-
const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
|
|
13091
|
-
if (pkg.bin) {
|
|
13092
|
-
const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
|
|
13093
|
-
if (typeof binPath === "string") {
|
|
13094
|
-
const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
13095
|
-
if (existsSync8(resolve7(srcPath))) return resolve7(srcPath);
|
|
13096
|
-
if (existsSync8(resolve7(binPath))) return resolve7(binPath);
|
|
13097
|
-
}
|
|
13098
|
-
}
|
|
13099
|
-
if (pkg.main) {
|
|
13100
|
-
const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
13101
|
-
if (existsSync8(resolve7(srcPath))) return resolve7(srcPath);
|
|
13102
|
-
}
|
|
13103
|
-
} catch {
|
|
13104
|
-
}
|
|
13105
|
-
const candidates = [
|
|
13106
|
-
"src/index.ts",
|
|
13107
|
-
"src/server.ts",
|
|
13108
|
-
"src/main.ts",
|
|
13109
|
-
"index.ts",
|
|
13110
|
-
"server.ts",
|
|
13111
|
-
"main.ts"
|
|
13112
|
-
];
|
|
13113
|
-
for (const c2 of candidates) {
|
|
13114
|
-
const full = resolve7(c2);
|
|
13115
|
-
if (existsSync8(full)) {
|
|
13116
|
-
try {
|
|
13117
|
-
const content = readFileSync13(full, "utf-8");
|
|
13118
|
-
if (content.includes("McpServer") || content.includes("McpServer")) {
|
|
13119
|
-
return full;
|
|
13120
|
-
}
|
|
13121
|
-
} catch {
|
|
13122
|
-
}
|
|
13123
|
-
}
|
|
13124
|
-
}
|
|
13125
|
-
for (const c2 of candidates) {
|
|
13126
|
-
if (existsSync8(resolve7(c2))) return resolve7(c2);
|
|
13127
|
-
}
|
|
13128
|
-
return null;
|
|
13129
|
-
}
|
|
13130
|
-
function detectPackageManager() {
|
|
13131
|
-
if (existsSync8(resolve7("pnpm-lock.yaml"))) return "pnpm";
|
|
13132
|
-
if (existsSync8(resolve7("yarn.lock"))) return "yarn";
|
|
13133
|
-
return "npm";
|
|
13134
|
-
}
|
|
13135
|
-
function installSdk() {
|
|
13136
|
-
try {
|
|
13137
|
-
const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
|
|
13138
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13139
|
-
if (allDeps["@solongate/proxy"]) {
|
|
13140
|
-
log3(" @solongate/proxy already installed");
|
|
13141
|
-
return true;
|
|
13142
|
-
}
|
|
13143
|
-
} catch {
|
|
13144
|
-
}
|
|
13145
|
-
const pm = detectPackageManager();
|
|
13146
|
-
const cmd = pm === "yarn" ? "yarn add @solongate/proxy" : `${pm} install @solongate/proxy`;
|
|
13147
|
-
log3(` Installing @solongate/proxy via ${pm}...`);
|
|
13148
|
-
try {
|
|
13149
|
-
execSync(cmd, { stdio: "pipe", cwd: process.cwd() });
|
|
13150
|
-
return true;
|
|
13151
|
-
} catch (err2) {
|
|
13152
|
-
log3(` Failed to install: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
13153
|
-
log3(" You can install manually: npm install @solongate/proxy");
|
|
13154
|
-
return false;
|
|
13155
|
-
}
|
|
13156
|
-
}
|
|
13157
|
-
function injectTypeScript(filePath) {
|
|
13158
|
-
const original = readFileSync13(filePath, "utf-8");
|
|
13159
|
-
const changes = [];
|
|
13160
|
-
let modified = original;
|
|
13161
|
-
if (modified.includes("SecureMcpServer")) {
|
|
13162
|
-
return { file: filePath, changes: ["Already injected \u2014 skipping"], original, modified };
|
|
13163
|
-
}
|
|
13164
|
-
const mcpImportPatterns = [
|
|
13165
|
-
// Solo import: import { McpServer } from '...'
|
|
13166
|
-
/import\s*\{\s*McpServer\s*\}\s*from\s*['"][^'"]+['"]/,
|
|
13167
|
-
// Import with others: import { McpServer, ... } from '...'
|
|
13168
|
-
/import\s*\{[^}]*McpServer[^}]*\}\s*from\s*['"][^'"]+['"]/
|
|
13169
|
-
];
|
|
13170
|
-
let importReplaced = false;
|
|
13171
|
-
for (const pattern of mcpImportPatterns) {
|
|
13172
|
-
const match = modified.match(pattern);
|
|
13173
|
-
if (match) {
|
|
13174
|
-
const importLine = match[0];
|
|
13175
|
-
const namedImports = importLine.match(/\{([^}]+)\}/)?.[1] ?? "";
|
|
13176
|
-
const importNames = namedImports.split(",").map((s) => s.trim()).filter(Boolean);
|
|
13177
|
-
if (importNames.length === 1 && importNames[0] === "McpServer") {
|
|
13178
|
-
modified = modified.replace(
|
|
13179
|
-
importLine,
|
|
13180
|
-
`import { SecureMcpServer } from '@solongate/proxy'`
|
|
13181
|
-
);
|
|
13182
|
-
changes.push("Replaced McpServer import with SecureMcpServer from @solongate/proxy");
|
|
13183
|
-
} else {
|
|
13184
|
-
const otherImports = importNames.filter((n) => n !== "McpServer");
|
|
13185
|
-
const fromModule = importLine.match(/from\s*['"]([^'"]+)['"]/)?.[1] ?? "";
|
|
13186
|
-
modified = modified.replace(
|
|
13187
|
-
importLine,
|
|
13188
|
-
`import { ${otherImports.join(", ")} } from '${fromModule}';
|
|
13189
|
-
import { SecureMcpServer } from '@solongate/proxy'`
|
|
13190
|
-
);
|
|
13191
|
-
changes.push("Removed McpServer from existing import, added SecureMcpServer import from @solongate/proxy");
|
|
13192
|
-
}
|
|
13193
|
-
importReplaced = true;
|
|
13194
|
-
break;
|
|
13195
|
-
}
|
|
13196
|
-
}
|
|
13197
|
-
if (!importReplaced) {
|
|
13198
|
-
const insertPos = findImportInsertPosition(modified);
|
|
13199
|
-
modified = modified.slice(0, insertPos) + `import { SecureMcpServer } from '@solongate/proxy';
|
|
13200
|
-
` + modified.slice(insertPos);
|
|
13201
|
-
changes.push("Added SecureMcpServer import from @solongate/proxy");
|
|
13202
|
-
}
|
|
13203
|
-
const constructorPattern = /new\s+McpServer\s*\(/g;
|
|
13204
|
-
const constructorCount = (modified.match(constructorPattern) || []).length;
|
|
13205
|
-
if (constructorCount > 0) {
|
|
13206
|
-
modified = modified.replace(constructorPattern, "new SecureMcpServer(");
|
|
13207
|
-
changes.push(`Replaced ${constructorCount} McpServer constructor(s) with SecureMcpServer`);
|
|
13208
|
-
}
|
|
13209
|
-
return { file: filePath, changes, original, modified };
|
|
13210
|
-
}
|
|
13211
|
-
function findImportInsertPosition(content) {
|
|
13212
|
-
let pos = 0;
|
|
13213
|
-
if (content.startsWith("#!")) {
|
|
13214
|
-
pos = content.indexOf("\n") + 1;
|
|
13215
|
-
}
|
|
13216
|
-
const lines = content.slice(pos).split("\n");
|
|
13217
|
-
let offset = pos;
|
|
13218
|
-
for (const line of lines) {
|
|
13219
|
-
const trimmed = line.trim();
|
|
13220
|
-
if (trimmed === "" || trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*") || trimmed.startsWith("*/")) {
|
|
13221
|
-
offset += line.length + 1;
|
|
13222
|
-
} else {
|
|
13223
|
-
break;
|
|
13224
|
-
}
|
|
13225
|
-
}
|
|
13226
|
-
const importRegex = /^import\s+.+$/gm;
|
|
13227
|
-
let lastImportEnd = offset;
|
|
13228
|
-
let importMatch;
|
|
13229
|
-
while ((importMatch = importRegex.exec(content)) !== null) {
|
|
13230
|
-
lastImportEnd = importMatch.index + importMatch[0].length + 1;
|
|
13231
|
-
}
|
|
13232
|
-
return lastImportEnd > offset ? lastImportEnd : offset;
|
|
13233
|
-
}
|
|
13234
|
-
function showDiff(result) {
|
|
13235
|
-
if (result.original === result.modified) {
|
|
13236
|
-
log3(" No changes needed.");
|
|
13237
|
-
return;
|
|
13238
|
-
}
|
|
13239
|
-
const origLines = result.original.split("\n");
|
|
13240
|
-
const modLines = result.modified.split("\n");
|
|
13241
|
-
log3("");
|
|
13242
|
-
log3(` File: ${result.file}`);
|
|
13243
|
-
log3(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
13244
|
-
const maxLines = Math.max(origLines.length, modLines.length);
|
|
13245
|
-
let diffCount = 0;
|
|
13246
|
-
for (let i = 0; i < maxLines; i++) {
|
|
13247
|
-
const orig = origLines[i];
|
|
13248
|
-
const mod = modLines[i];
|
|
13249
|
-
if (orig !== mod) {
|
|
13250
|
-
if (diffCount < 30) {
|
|
13251
|
-
if (orig !== void 0) log3(` - ${orig}`);
|
|
13252
|
-
if (mod !== void 0) log3(` + ${mod}`);
|
|
13253
|
-
}
|
|
13254
|
-
diffCount++;
|
|
13255
|
-
}
|
|
13256
|
-
}
|
|
13257
|
-
if (diffCount > 30) {
|
|
13258
|
-
log3(` ... and ${diffCount - 30} more line changes`);
|
|
13259
|
-
}
|
|
13260
|
-
log3("");
|
|
13261
|
-
}
|
|
13262
|
-
async function main() {
|
|
13263
|
-
const opts = parseInjectArgs(process.argv);
|
|
13264
|
-
printBanner("Inject SDK");
|
|
13265
|
-
if (!detectProject()) {
|
|
13266
|
-
log3(" Could not detect a TypeScript MCP server project.");
|
|
13267
|
-
log3(" Make sure you are in a project directory with:");
|
|
13268
|
-
log3(" package.json + @modelcontextprotocol/sdk in dependencies");
|
|
13269
|
-
log3("");
|
|
13270
|
-
log3(" To create a new MCP server: npx @solongate/proxy create <name>");
|
|
13271
|
-
process.exit(1);
|
|
13272
|
-
}
|
|
13273
|
-
log3(" Language: TypeScript");
|
|
13274
|
-
const entryFile = opts.file ? resolve7(opts.file) : findTsEntryFile();
|
|
13275
|
-
if (!entryFile || !existsSync8(entryFile)) {
|
|
13276
|
-
log3(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
|
|
13277
|
-
log3("");
|
|
13278
|
-
log3(" Specify it manually: --file <path>");
|
|
13279
|
-
log3("");
|
|
13280
|
-
log3(" Common entry points:");
|
|
13281
|
-
log3(" src/index.ts, src/server.ts, index.ts");
|
|
13282
|
-
process.exit(1);
|
|
13283
|
-
}
|
|
13284
|
-
log3(` Entry: ${entryFile}`);
|
|
13285
|
-
log3("");
|
|
13286
|
-
const backupPath = entryFile + ".solongate-backup";
|
|
13287
|
-
if (opts.restore) {
|
|
13288
|
-
if (!existsSync8(backupPath)) {
|
|
13289
|
-
log3(" No backup found. Nothing to restore.");
|
|
13290
|
-
process.exit(1);
|
|
13291
|
-
}
|
|
13292
|
-
copyFileSync(backupPath, entryFile);
|
|
13293
|
-
log3(` Restored original file from backup.`);
|
|
13294
|
-
log3(` Backup: ${backupPath}`);
|
|
13295
|
-
process.exit(0);
|
|
13296
|
-
}
|
|
13297
|
-
if (!opts.skipInstall && !opts.dryRun) {
|
|
13298
|
-
installSdk();
|
|
13299
|
-
log3("");
|
|
13300
|
-
}
|
|
13301
|
-
const result = injectTypeScript(entryFile);
|
|
13302
|
-
log3(` Changes (${result.changes.length}):`);
|
|
13303
|
-
for (const change of result.changes) {
|
|
13304
|
-
log3(` - ${change}`);
|
|
13305
|
-
}
|
|
13306
|
-
if (result.changes.length === 1 && result.changes[0].includes("Already injected")) {
|
|
13307
|
-
log3("");
|
|
13308
|
-
log3(" Your MCP server is already protected by SolonGate!");
|
|
13309
|
-
process.exit(0);
|
|
13310
|
-
}
|
|
13311
|
-
if (result.original === result.modified) {
|
|
13312
|
-
log3("");
|
|
13313
|
-
log3(" No changes were made. The file may not contain recognizable MCP patterns.");
|
|
13314
|
-
log3(" See docs: https://solongate.com/docs/integration");
|
|
13315
|
-
process.exit(0);
|
|
13316
|
-
}
|
|
13317
|
-
if (opts.dryRun) {
|
|
13318
|
-
log3("");
|
|
13319
|
-
log3(" --- DRY RUN (no changes written) ---");
|
|
13320
|
-
showDiff(result);
|
|
13321
|
-
log3(" To apply: npx @solongate/proxy inject");
|
|
13322
|
-
process.exit(0);
|
|
13323
|
-
}
|
|
13324
|
-
if (!existsSync8(backupPath)) {
|
|
13325
|
-
copyFileSync(entryFile, backupPath);
|
|
13326
|
-
log3("");
|
|
13327
|
-
log3(` Backup: ${backupPath}`);
|
|
13328
|
-
}
|
|
13329
|
-
writeFileSync10(entryFile, result.modified);
|
|
13330
|
-
log3("");
|
|
13331
|
-
log3(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
13332
|
-
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
13333
|
-
log3(" \u2502 \u2502");
|
|
13334
|
-
log3(" \u2502 McpServer \u2192 SecureMcpServer \u2502");
|
|
13335
|
-
log3(" \u2502 All tool() calls are now auto-protected. \u2502");
|
|
13336
|
-
log3(" \u2502 \u2502");
|
|
13337
|
-
log3(" \u2502 Set your API key: \u2502");
|
|
13338
|
-
log3(" \u2502 export SOLONGATE_API_KEY=sg_live_xxx \u2502");
|
|
13339
|
-
log3(" \u2502 \u2502");
|
|
13340
|
-
log3(" \u2502 To undo: \u2502");
|
|
13341
|
-
log3(" \u2502 npx @solongate/proxy inject --restore \u2502");
|
|
13342
|
-
log3(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
13343
|
-
log3("");
|
|
13344
|
-
}
|
|
13345
|
-
var init_inject = __esm({
|
|
13346
|
-
"src/inject.ts"() {
|
|
13347
|
-
"use strict";
|
|
13348
|
-
init_cli_utils();
|
|
13349
|
-
main().catch((err2) => {
|
|
13350
|
-
log3(`Fatal: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
13351
|
-
process.exit(1);
|
|
13352
|
-
});
|
|
13353
|
-
}
|
|
13354
|
-
});
|
|
13355
|
-
|
|
13356
|
-
// src/create.ts
|
|
13357
|
-
var create_exports = {};
|
|
13358
|
-
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, existsSync as existsSync9 } from "fs";
|
|
13359
|
-
import { resolve as resolve8, join as join16 } from "path";
|
|
13360
|
-
import { execSync as execSync2 } from "child_process";
|
|
13361
|
-
function withSpinner(message, fn) {
|
|
13362
|
-
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
13363
|
-
let i = 0;
|
|
13364
|
-
const id = setInterval(() => {
|
|
13365
|
-
const color = i % 2 === 0 ? c.blue3 : c.blue5;
|
|
13366
|
-
process.stderr.write(`\r ${color}${frames[i++ % frames.length]}${c.reset} ${c.dim}${message}${c.reset}`);
|
|
13367
|
-
}, 80);
|
|
13368
|
-
try {
|
|
13369
|
-
const result = fn();
|
|
13370
|
-
clearInterval(id);
|
|
13371
|
-
process.stderr.write(`\r ${c.green}\u2713${c.reset} ${message}${" ".repeat(20)}
|
|
13372
|
-
`);
|
|
13373
|
-
return result;
|
|
13374
|
-
} catch (err2) {
|
|
13375
|
-
clearInterval(id);
|
|
13376
|
-
process.stderr.write(`\r ${c.red}\u2717${c.reset} ${message} \u2014 failed${" ".repeat(10)}
|
|
13377
|
-
`);
|
|
13378
|
-
throw err2;
|
|
13379
|
-
}
|
|
13380
|
-
}
|
|
13381
|
-
function parseCreateArgs(argv) {
|
|
13382
|
-
const args = argv.slice(2);
|
|
13383
|
-
const opts = {
|
|
13384
|
-
name: "",
|
|
13385
|
-
policy: "",
|
|
13386
|
-
noInstall: false
|
|
13387
|
-
};
|
|
13388
|
-
for (let i = 0; i < args.length; i++) {
|
|
13389
|
-
switch (args[i]) {
|
|
13390
|
-
case "--policy":
|
|
13391
|
-
opts.policy = args[++i];
|
|
13392
|
-
break;
|
|
13393
|
-
case "--no-install":
|
|
13394
|
-
opts.noInstall = true;
|
|
13395
|
-
break;
|
|
13396
|
-
case "--help":
|
|
13397
|
-
case "-h":
|
|
13398
|
-
printHelp2();
|
|
13399
|
-
process.exit(0);
|
|
13400
|
-
break;
|
|
13401
|
-
default:
|
|
13402
|
-
if (!args[i].startsWith("-") && !opts.name) {
|
|
13403
|
-
opts.name = args[i];
|
|
13404
|
-
}
|
|
13405
|
-
}
|
|
13406
|
-
}
|
|
13407
|
-
if (!opts.name) {
|
|
13408
|
-
log3("");
|
|
13409
|
-
log3(" Error: Project name required.");
|
|
13410
|
-
log3("");
|
|
13411
|
-
log3(" Usage: npx @solongate/proxy create <name>");
|
|
13412
|
-
log3("");
|
|
13413
|
-
log3(" Examples:");
|
|
13414
|
-
log3(" npx @solongate/proxy create my-mcp-server");
|
|
13415
|
-
log3(" npx @solongate/proxy create weather-api");
|
|
13416
|
-
process.exit(1);
|
|
13417
|
-
}
|
|
13418
|
-
return opts;
|
|
13419
|
-
}
|
|
13420
|
-
function printHelp2() {
|
|
13421
|
-
log3(`
|
|
13422
|
-
SolonGate Create \u2014 Scaffold a secure MCP server in seconds
|
|
13423
|
-
|
|
13424
|
-
USAGE
|
|
13425
|
-
npx @solongate/proxy create <name> [options]
|
|
13426
|
-
|
|
13427
|
-
OPTIONS
|
|
13428
|
-
--policy <file> Policy JSON file (default: cloud-managed)
|
|
13429
|
-
--no-install Skip dependency installation
|
|
13430
|
-
-h, --help Show this help message
|
|
13431
|
-
|
|
13432
|
-
EXAMPLES
|
|
13433
|
-
npx @solongate/proxy create my-server
|
|
13434
|
-
npx @solongate/proxy create db-tools --policy ./policy.json
|
|
13435
|
-
`);
|
|
13436
|
-
}
|
|
13437
|
-
function createProject(dir, name, _policy) {
|
|
13438
|
-
writeFileSync11(
|
|
13439
|
-
join16(dir, "package.json"),
|
|
13440
|
-
JSON.stringify(
|
|
13441
|
-
{
|
|
13442
|
-
name,
|
|
13443
|
-
version: "0.1.0",
|
|
13444
|
-
type: "module",
|
|
13445
|
-
private: true,
|
|
13446
|
-
bin: { [name]: "./dist/index.js" },
|
|
13447
|
-
scripts: {
|
|
13448
|
-
build: "tsup src/index.ts --format esm",
|
|
13449
|
-
dev: "tsx --env-file=.env src/index.ts",
|
|
13450
|
-
start: "node --env-file=.env dist/index.js"
|
|
13451
|
-
},
|
|
13452
|
-
dependencies: {
|
|
13453
|
-
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
13454
|
-
"@solongate/proxy": "latest",
|
|
13455
|
-
zod: "^3.25.0"
|
|
13456
|
-
},
|
|
13457
|
-
devDependencies: {
|
|
13458
|
-
"@types/node": "^22.0.0",
|
|
13459
|
-
tsup: "^8.3.0",
|
|
13460
|
-
tsx: "^4.19.0",
|
|
13461
|
-
typescript: "^5.7.0"
|
|
13462
|
-
}
|
|
13463
|
-
},
|
|
13464
|
-
null,
|
|
13465
|
-
2
|
|
13466
|
-
) + "\n"
|
|
13467
|
-
);
|
|
13468
|
-
writeFileSync11(
|
|
13469
|
-
join16(dir, "tsconfig.json"),
|
|
13470
|
-
JSON.stringify(
|
|
13471
|
-
{
|
|
13472
|
-
compilerOptions: {
|
|
13473
|
-
target: "ES2022",
|
|
13474
|
-
module: "ESNext",
|
|
13475
|
-
moduleResolution: "bundler",
|
|
13476
|
-
esModuleInterop: true,
|
|
13477
|
-
strict: true,
|
|
13478
|
-
outDir: "dist",
|
|
13479
|
-
rootDir: "src",
|
|
13480
|
-
declaration: true,
|
|
13481
|
-
skipLibCheck: true
|
|
13482
|
-
},
|
|
13483
|
-
include: ["src"]
|
|
13484
|
-
},
|
|
13485
|
-
null,
|
|
13486
|
-
2
|
|
13487
|
-
) + "\n"
|
|
13488
|
-
);
|
|
13489
|
-
mkdirSync10(join16(dir, "src"), { recursive: true });
|
|
13490
|
-
writeFileSync11(
|
|
13491
|
-
join16(dir, "src", "index.ts"),
|
|
13492
|
-
`#!/usr/bin/env node
|
|
13493
|
-
|
|
13494
|
-
console.log = (...args: unknown[]) => {
|
|
13495
|
-
process.stderr.write(args.map(String).join(' ') + '\\n');
|
|
13496
|
-
};
|
|
13497
|
-
|
|
13498
|
-
import { SecureMcpServer } from '@solongate/proxy';
|
|
13499
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13500
|
-
import { z } from 'zod';
|
|
13501
|
-
|
|
13502
|
-
// Policy is managed from the SolonGate Dashboard (https://solongate.com)
|
|
13503
|
-
// No local policySet needed \u2014 it's fetched from the cloud via your API key.
|
|
13504
|
-
const server = new SecureMcpServer(
|
|
13505
|
-
{ name: '${name}', version: '0.1.0' },
|
|
13506
|
-
);
|
|
13507
|
-
|
|
13508
|
-
server.tool(
|
|
13509
|
-
'hello',
|
|
13510
|
-
'Say hello to someone',
|
|
13511
|
-
{ name: z.string().describe('Name of the person to greet') },
|
|
13512
|
-
async ({ name }: { name: string }) => ({
|
|
13513
|
-
content: [{ type: 'text', text: \`Hello, \${name}! Welcome to ${name}.\` }],
|
|
13514
|
-
}),
|
|
13515
|
-
);
|
|
13516
|
-
|
|
13517
|
-
const transport = new StdioServerTransport();
|
|
13518
|
-
await server.connect(transport);
|
|
13519
|
-
console.log('');
|
|
13520
|
-
console.log('${name} is running (stdio mode)');
|
|
13521
|
-
console.log('');
|
|
13522
|
-
console.log('MCP servers communicate over stdin/stdout \u2014 not HTTP.');
|
|
13523
|
-
console.log('You need an MCP client to connect:');
|
|
13524
|
-
console.log('');
|
|
13525
|
-
console.log(' Claude Code Open this folder, .mcp.json is auto-detected');
|
|
13526
|
-
console.log(' Antigravity .agents/mcp_config.json (or ~/.gemini/config/mcp_config.json)');
|
|
13527
|
-
console.log(' OpenClaw Uses openclaw.plugin.json config');
|
|
13528
|
-
console.log('');
|
|
13529
|
-
console.log('Press Ctrl+C to stop.');
|
|
13530
|
-
`
|
|
13531
|
-
);
|
|
13532
|
-
writeFileSync11(
|
|
13533
|
-
join16(dir, ".mcp.json"),
|
|
13534
|
-
JSON.stringify(
|
|
13535
|
-
{
|
|
13536
|
-
mcpServers: {
|
|
13537
|
-
[name]: {
|
|
13538
|
-
command: "node",
|
|
13539
|
-
args: ["dist/index.js"],
|
|
13540
|
-
env: {
|
|
13541
|
-
SOLONGATE_API_KEY: "sg_live_YOUR_KEY_HERE"
|
|
13542
|
-
}
|
|
13543
|
-
}
|
|
13544
|
-
}
|
|
13545
|
-
},
|
|
13546
|
-
null,
|
|
13547
|
-
2
|
|
13548
|
-
) + "\n"
|
|
13549
|
-
);
|
|
13550
|
-
writeFileSync11(
|
|
13551
|
-
join16(dir, ".env"),
|
|
13552
|
-
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
13553
|
-
`
|
|
13554
|
-
);
|
|
13555
|
-
writeFileSync11(
|
|
13556
|
-
join16(dir, ".gitignore"),
|
|
13557
|
-
`node_modules/
|
|
13558
|
-
dist/
|
|
13559
|
-
*.solongate-backup
|
|
13560
|
-
.env
|
|
13561
|
-
.env.local
|
|
13562
|
-
.mcp.json
|
|
13563
|
-
`
|
|
13564
|
-
);
|
|
13565
|
-
}
|
|
13566
|
-
async function main2() {
|
|
13567
|
-
const opts = parseCreateArgs(process.argv);
|
|
13568
|
-
const dir = resolve8(opts.name);
|
|
13569
|
-
printBanner("Create MCP Server");
|
|
13570
|
-
if (existsSync9(dir)) {
|
|
13571
|
-
log3(` ${c.red}Error:${c.reset} Directory "${opts.name}" already exists.`);
|
|
13572
|
-
process.exit(1);
|
|
13573
|
-
}
|
|
13574
|
-
withSpinner(`Setting up ${opts.name}...`, () => {
|
|
13575
|
-
mkdirSync10(dir, { recursive: true });
|
|
13576
|
-
createProject(dir, opts.name, opts.policy);
|
|
13577
|
-
});
|
|
13578
|
-
if (!opts.noInstall) {
|
|
13579
|
-
withSpinner("Installing dependencies...", () => {
|
|
13580
|
-
execSync2("npm install", { cwd: dir, stdio: "pipe" });
|
|
13581
|
-
});
|
|
13582
|
-
}
|
|
13583
|
-
log3("");
|
|
13584
|
-
const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
13585
|
-
const W = 52;
|
|
13586
|
-
const hr = "\u2500".repeat(W + 2);
|
|
13587
|
-
const bLine = (text) => {
|
|
13588
|
-
const visible = stripAnsi(text);
|
|
13589
|
-
const padding = W - visible.length;
|
|
13590
|
-
log3(` ${c.dim}\u2502${c.reset} ${text}${" ".repeat(Math.max(0, padding))} ${c.dim}\u2502${c.reset}`);
|
|
13591
|
-
};
|
|
13592
|
-
const bEmpty = () => log3(` ${c.dim}\u2502${c.reset} ${" ".repeat(W)} ${c.dim}\u2502${c.reset}`);
|
|
13593
|
-
log3(` ${c.dim}\u256D${hr}\u256E${c.reset}`);
|
|
13594
|
-
log3(` ${c.dim}\u2502${c.reset} ${c.green}${c.bold}\u2714 MCP Server created successfully!${c.reset}${" ".repeat(W - 35)} ${c.dim}\u2502${c.reset}`);
|
|
13595
|
-
log3(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
|
|
13596
|
-
bEmpty();
|
|
13597
|
-
bLine(`${c.yellow}Next steps:${c.reset}`);
|
|
13598
|
-
bEmpty();
|
|
13599
|
-
bLine(` ${c.cyan}$${c.reset} cd ${c.bold}${opts.name}${c.reset}`);
|
|
13600
|
-
bLine(` ${c.cyan}$${c.reset} npm run build`);
|
|
13601
|
-
bLine(` ${c.cyan}$${c.reset} npm run dev ${c.dim}# dev mode${c.reset}`);
|
|
13602
|
-
bLine(` ${c.cyan}$${c.reset} npm start ${c.dim}# production${c.reset}`);
|
|
13603
|
-
bEmpty();
|
|
13604
|
-
log3(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
|
|
13605
|
-
bEmpty();
|
|
13606
|
-
bLine(`${c.yellow}Set your API key:${c.reset}`);
|
|
13607
|
-
bEmpty();
|
|
13608
|
-
bLine(` ${c.cyan}$${c.reset} export SOLONGATE_API_KEY=${c.blue3}sg_live_xxx${c.reset}`);
|
|
13609
|
-
bEmpty();
|
|
13610
|
-
bLine(`${c.dim}https://dashboard.solongate.com/api-keys/${c.reset}`);
|
|
13611
|
-
bEmpty();
|
|
13612
|
-
log3(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
|
|
13613
|
-
bEmpty();
|
|
13614
|
-
bLine(`${c.yellow}Use with any MCP server:${c.reset}`);
|
|
13615
|
-
bEmpty();
|
|
13616
|
-
bLine(` ${c.cyan}$${c.reset} solongate-proxy -- npx @modelcontextprotocol/server-filesystem .`);
|
|
13617
|
-
bLine(` ${c.cyan}$${c.reset} solongate-proxy -- npx @playwright/mcp@latest`);
|
|
13618
|
-
bLine(` ${c.dim}Wraps any MCP server or AI tool with SolonGate protection${c.reset}`);
|
|
13619
|
-
bEmpty();
|
|
13620
|
-
log3(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
|
|
13621
|
-
bEmpty();
|
|
13622
|
-
bLine(`${c.yellow}Use with Claude Code / MCP client:${c.reset}`);
|
|
13623
|
-
bEmpty();
|
|
13624
|
-
bLine(` ${c.dim}1.${c.reset} Replace ${c.blue3}sg_live_YOUR_KEY_HERE${c.reset} in .mcp.json`);
|
|
13625
|
-
bLine(` ${c.dim}2.${c.reset} Open this folder in your MCP client`);
|
|
13626
|
-
bLine(` ${c.dim}3.${c.reset} .mcp.json is auto-detected on startup`);
|
|
13627
|
-
bEmpty();
|
|
13628
|
-
bLine(`${c.yellow}Direct test (without MCP client):${c.reset}`);
|
|
13629
|
-
bEmpty();
|
|
13630
|
-
bLine(` ${c.dim}1.${c.reset} Replace ${c.blue3}sg_live_YOUR_KEY_HERE${c.reset} in .env`);
|
|
13631
|
-
bLine(` ${c.dim}2.${c.reset} ${c.cyan}$${c.reset} npm run build && npm start`);
|
|
13632
|
-
bEmpty();
|
|
13633
|
-
log3(` ${c.dim}\u2570${hr}\u256F${c.reset}`);
|
|
13634
|
-
log3("");
|
|
13635
|
-
}
|
|
13636
|
-
var init_create = __esm({
|
|
13637
|
-
"src/create.ts"() {
|
|
13638
|
-
"use strict";
|
|
13639
|
-
init_cli_utils();
|
|
13640
|
-
main2().catch((err2) => {
|
|
13641
|
-
log3(`Fatal: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
13642
|
-
process.exit(1);
|
|
13643
|
-
});
|
|
13644
|
-
}
|
|
13645
|
-
});
|
|
13646
|
-
|
|
13647
12596
|
// src/pull-push.ts
|
|
13648
12597
|
var pull_push_exports = {};
|
|
13649
|
-
import { readFileSync as
|
|
13650
|
-
import { resolve as
|
|
12598
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync10, existsSync as existsSync7 } from "fs";
|
|
12599
|
+
import { resolve as resolve6 } from "path";
|
|
13651
12600
|
function loadEnv() {
|
|
13652
12601
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
13653
|
-
const envPath =
|
|
13654
|
-
if (!
|
|
12602
|
+
const envPath = resolve6(".env");
|
|
12603
|
+
if (!existsSync7(envPath)) return;
|
|
13655
12604
|
try {
|
|
13656
|
-
const content =
|
|
12605
|
+
const content = readFileSync12(envPath, "utf-8");
|
|
13657
12606
|
for (const line of content.split("\n")) {
|
|
13658
12607
|
const trimmed = line.trim();
|
|
13659
12608
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -13695,20 +12644,20 @@ function parseCliArgs() {
|
|
|
13695
12644
|
}
|
|
13696
12645
|
}
|
|
13697
12646
|
if (!apiKey) {
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
12647
|
+
log3(red2("ERROR: API key not found."));
|
|
12648
|
+
log3("");
|
|
12649
|
+
log3("Set it in .env file:");
|
|
12650
|
+
log3(" SOLONGATE_API_KEY=sg_live_...");
|
|
12651
|
+
log3("");
|
|
12652
|
+
log3("Or pass via environment:");
|
|
12653
|
+
log3(` SOLONGATE_API_KEY=sg_live_... solongate-proxy ${command}`);
|
|
13705
12654
|
process.exit(1);
|
|
13706
12655
|
}
|
|
13707
12656
|
if (!apiKey.startsWith("sg_live_")) {
|
|
13708
|
-
|
|
12657
|
+
log3(red2("ERROR: Pull/push/list requires a live API key (sg_live_...)."));
|
|
13709
12658
|
process.exit(1);
|
|
13710
12659
|
}
|
|
13711
|
-
return { command, apiKey, file:
|
|
12660
|
+
return { command, apiKey, file: resolve6(file), policyId };
|
|
13712
12661
|
}
|
|
13713
12662
|
async function listPolicies(apiKey) {
|
|
13714
12663
|
const res = await fetch(`${API_URL}/api/v1/policies`, {
|
|
@@ -13721,18 +12670,18 @@ async function listPolicies(apiKey) {
|
|
|
13721
12670
|
async function list5(apiKey, policyId) {
|
|
13722
12671
|
const policies = await listPolicies(apiKey);
|
|
13723
12672
|
if (policies.length === 0) {
|
|
13724
|
-
|
|
13725
|
-
|
|
12673
|
+
log3(yellow2("No policies found. Create one in the dashboard first."));
|
|
12674
|
+
log3(dim2(" https://dashboard.solongate.com/policies"));
|
|
13726
12675
|
return;
|
|
13727
12676
|
}
|
|
13728
12677
|
if (policyId) {
|
|
13729
12678
|
const match = policies.find((p) => p.id === policyId);
|
|
13730
12679
|
if (!match) {
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
12680
|
+
log3(red2(`Policy not found: ${policyId}`));
|
|
12681
|
+
log3("");
|
|
12682
|
+
log3("Available policies:");
|
|
13734
12683
|
for (const p of policies) {
|
|
13735
|
-
|
|
12684
|
+
log3(` ${dim2("\u2022")} ${p.id}`);
|
|
13736
12685
|
}
|
|
13737
12686
|
process.exit(1);
|
|
13738
12687
|
}
|
|
@@ -13740,10 +12689,10 @@ async function list5(apiKey, policyId) {
|
|
|
13740
12689
|
printPolicyDetail(full);
|
|
13741
12690
|
return;
|
|
13742
12691
|
}
|
|
13743
|
-
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
12692
|
+
log3("");
|
|
12693
|
+
log3(bold2(` Policies (${policies.length})`));
|
|
12694
|
+
log3(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
12695
|
+
log3("");
|
|
13747
12696
|
const fullPolicies = await Promise.all(
|
|
13748
12697
|
policies.map(
|
|
13749
12698
|
(p) => fetchCloudPolicy(apiKey, API_URL, p.id).then((full) => ({ policy: p, rules: full.rules })).catch(() => ({ policy: p, rules: [] }))
|
|
@@ -13752,136 +12701,136 @@ async function list5(apiKey, policyId) {
|
|
|
13752
12701
|
for (const { policy, rules } of fullPolicies) {
|
|
13753
12702
|
printPolicySummary(policy, [...rules]);
|
|
13754
12703
|
}
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
|
|
12704
|
+
log3(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
12705
|
+
log3("");
|
|
12706
|
+
log3(` ${dim2("View details:")} solongate-proxy list --policy-id <ID>`);
|
|
12707
|
+
log3(` ${dim2("Pull policy:")} solongate-proxy pull --policy-id <ID>`);
|
|
12708
|
+
log3(` ${dim2("Push policy:")} solongate-proxy push --policy-id <ID>`);
|
|
12709
|
+
log3("");
|
|
13761
12710
|
}
|
|
13762
12711
|
function printPolicySummary(p, rules) {
|
|
13763
12712
|
const ruleCount = rules.length;
|
|
13764
12713
|
const allowCount = rules.filter((r) => r.effect === "ALLOW").length;
|
|
13765
12714
|
const denyCount = rules.filter((r) => r.effect === "DENY").length;
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
12715
|
+
log3(` ${cyan2(p.id)}`);
|
|
12716
|
+
log3(` ${bold2(p.name)} ${dim2(`v${p.version ?? "?"}`)}`);
|
|
12717
|
+
log3(` ${dim2("Rules:")} ${ruleCount} ${green2(`${allowCount} ALLOW`)} ${red2(`${denyCount} DENY`)}`);
|
|
13769
12718
|
if (p.created_at) {
|
|
13770
|
-
|
|
12719
|
+
log3(` ${dim2("Updated:")} ${new Date(p.created_at).toLocaleString()}`);
|
|
13771
12720
|
}
|
|
13772
|
-
|
|
12721
|
+
log3("");
|
|
13773
12722
|
}
|
|
13774
12723
|
function printPolicyDetail(policy) {
|
|
13775
|
-
|
|
13776
|
-
|
|
13777
|
-
|
|
13778
|
-
|
|
12724
|
+
log3("");
|
|
12725
|
+
log3(bold2(` ${policy.name}`));
|
|
12726
|
+
log3(` ${dim2("ID:")} ${cyan2(policy.id)} ${dim2("Version:")} ${policy.version} ${dim2("Rules:")} ${policy.rules.length}`);
|
|
12727
|
+
log3("");
|
|
13779
12728
|
if (policy.rules.length === 0) {
|
|
13780
|
-
|
|
13781
|
-
|
|
12729
|
+
log3(yellow2(" No rules defined."));
|
|
12730
|
+
log3("");
|
|
13782
12731
|
return;
|
|
13783
12732
|
}
|
|
13784
|
-
|
|
12733
|
+
log3(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
13785
12734
|
for (const rule of policy.rules) {
|
|
13786
12735
|
const effectColor = rule.effect === "ALLOW" ? green2 : red2;
|
|
13787
|
-
|
|
13788
|
-
|
|
12736
|
+
log3("");
|
|
12737
|
+
log3(` ${effectColor(rule.effect.padEnd(5))} ${bold2(rule.toolPattern)} ${dim2(`P:${rule.priority}`)}`);
|
|
13789
12738
|
if (rule.description) {
|
|
13790
|
-
|
|
12739
|
+
log3(` ${dim2(rule.description)}`);
|
|
13791
12740
|
}
|
|
13792
|
-
|
|
12741
|
+
log3(` ${dim2(`${rule.permission} trust:${rule.minimumTrustLevel || "UNTRUSTED"}`)}`);
|
|
13793
12742
|
if (rule.pathConstraints) {
|
|
13794
12743
|
const pc = rule.pathConstraints;
|
|
13795
|
-
if (pc.rootDirectory)
|
|
13796
|
-
if (pc.allowed?.length)
|
|
13797
|
-
if (pc.denied?.length)
|
|
12744
|
+
if (pc.rootDirectory) log3(` ${magenta("ROOT")} ${pc.rootDirectory}`);
|
|
12745
|
+
if (pc.allowed?.length) log3(` ${green2("PATHS")} ${pc.allowed.join(", ")}`);
|
|
12746
|
+
if (pc.denied?.length) log3(` ${red2("DENY")} ${pc.denied.join(", ")}`);
|
|
13798
12747
|
}
|
|
13799
12748
|
if (rule.commandConstraints) {
|
|
13800
12749
|
const cc = rule.commandConstraints;
|
|
13801
|
-
if (cc.allowed?.length)
|
|
13802
|
-
if (cc.denied?.length)
|
|
12750
|
+
if (cc.allowed?.length) log3(` ${green2("CMDS")} ${cc.allowed.join(", ")}`);
|
|
12751
|
+
if (cc.denied?.length) log3(` ${red2("DENY")} ${cc.denied.join(", ")}`);
|
|
13803
12752
|
}
|
|
13804
12753
|
if (rule.filenameConstraints) {
|
|
13805
12754
|
const fc = rule.filenameConstraints;
|
|
13806
|
-
if (fc.allowed?.length)
|
|
13807
|
-
if (fc.denied?.length)
|
|
12755
|
+
if (fc.allowed?.length) log3(` ${green2("FILES")} ${fc.allowed.join(", ")}`);
|
|
12756
|
+
if (fc.denied?.length) log3(` ${red2("DENY")} ${fc.denied.join(", ")}`);
|
|
13808
12757
|
}
|
|
13809
12758
|
if (rule.urlConstraints) {
|
|
13810
12759
|
const uc = rule.urlConstraints;
|
|
13811
|
-
if (uc.allowed?.length)
|
|
13812
|
-
if (uc.denied?.length)
|
|
12760
|
+
if (uc.allowed?.length) log3(` ${green2("URLS")} ${uc.allowed.join(", ")}`);
|
|
12761
|
+
if (uc.denied?.length) log3(` ${red2("DENY")} ${uc.denied.join(", ")}`);
|
|
13813
12762
|
}
|
|
13814
12763
|
}
|
|
13815
|
-
|
|
13816
|
-
|
|
13817
|
-
|
|
12764
|
+
log3("");
|
|
12765
|
+
log3(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
12766
|
+
log3("");
|
|
13818
12767
|
}
|
|
13819
12768
|
async function pull(apiKey, file, policyId) {
|
|
13820
12769
|
if (!policyId) {
|
|
13821
12770
|
const policies = await listPolicies(apiKey);
|
|
13822
12771
|
if (policies.length === 0) {
|
|
13823
|
-
|
|
12772
|
+
log3(red2("No policies found. Create one in the dashboard first."));
|
|
13824
12773
|
process.exit(1);
|
|
13825
12774
|
}
|
|
13826
12775
|
if (policies.length === 1) {
|
|
13827
12776
|
policyId = policies[0].id;
|
|
13828
|
-
|
|
12777
|
+
log3(dim2(`Auto-selecting only policy: ${policyId}`));
|
|
13829
12778
|
} else {
|
|
13830
|
-
|
|
13831
|
-
|
|
12779
|
+
log3(yellow2(`Found ${policies.length} policies:`));
|
|
12780
|
+
log3("");
|
|
13832
12781
|
for (const p of policies) {
|
|
13833
|
-
|
|
12782
|
+
log3(` ${cyan2(p.id)} ${p.name} ${dim2(`v${p.version ?? "?"}`)}`);
|
|
13834
12783
|
}
|
|
13835
|
-
|
|
13836
|
-
|
|
12784
|
+
log3("");
|
|
12785
|
+
log3("Use --policy-id <ID> to specify which one to pull.");
|
|
13837
12786
|
process.exit(1);
|
|
13838
12787
|
}
|
|
13839
12788
|
}
|
|
13840
|
-
|
|
12789
|
+
log3(`Pulling ${cyan2(policyId)} from dashboard...`);
|
|
13841
12790
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
13842
12791
|
const { id: _id, ...policyWithoutId } = policy;
|
|
13843
12792
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
12793
|
+
writeFileSync10(file, json, "utf-8");
|
|
12794
|
+
log3("");
|
|
12795
|
+
log3(green2(" Saved to: ") + file);
|
|
12796
|
+
log3(` ${dim2("Name:")} ${policy.name}`);
|
|
12797
|
+
log3(` ${dim2("Version:")} ${policy.version}`);
|
|
12798
|
+
log3(` ${dim2("Rules:")} ${policy.rules.length}`);
|
|
12799
|
+
log3("");
|
|
12800
|
+
log3(dim2("The policy file does not contain an ID."));
|
|
12801
|
+
log3(dim2("Use --policy-id to specify the target when pushing/pulling."));
|
|
12802
|
+
log3("");
|
|
13854
12803
|
}
|
|
13855
12804
|
async function push(apiKey, file, policyId) {
|
|
13856
|
-
if (!
|
|
13857
|
-
|
|
12805
|
+
if (!existsSync7(file)) {
|
|
12806
|
+
log3(red2(`ERROR: File not found: ${file}`));
|
|
13858
12807
|
process.exit(1);
|
|
13859
12808
|
}
|
|
13860
12809
|
if (!policyId) {
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
|
|
12810
|
+
log3(red2("ERROR: --policy-id is required for push."));
|
|
12811
|
+
log3("");
|
|
12812
|
+
log3("This determines which cloud policy to update.");
|
|
12813
|
+
log3("");
|
|
12814
|
+
log3("Usage:");
|
|
12815
|
+
log3(" solongate-proxy push --policy-id my-policy");
|
|
12816
|
+
log3(" solongate-proxy push --policy-id my-policy --file custom.json");
|
|
12817
|
+
log3("");
|
|
12818
|
+
log3("List your policies:");
|
|
12819
|
+
log3(" solongate-proxy list");
|
|
13871
12820
|
process.exit(1);
|
|
13872
12821
|
}
|
|
13873
|
-
const content =
|
|
12822
|
+
const content = readFileSync12(file, "utf-8");
|
|
13874
12823
|
let policy;
|
|
13875
12824
|
try {
|
|
13876
12825
|
policy = JSON.parse(content);
|
|
13877
12826
|
} catch {
|
|
13878
|
-
|
|
12827
|
+
log3(red2(`ERROR: Invalid JSON in ${file}`));
|
|
13879
12828
|
process.exit(1);
|
|
13880
12829
|
}
|
|
13881
|
-
|
|
13882
|
-
|
|
13883
|
-
|
|
13884
|
-
|
|
12830
|
+
log3(`Pushing to ${cyan2(policyId)}...`);
|
|
12831
|
+
log3(` ${dim2("File:")} ${file}`);
|
|
12832
|
+
log3(` ${dim2("Name:")} ${policy.name || "Unnamed"}`);
|
|
12833
|
+
log3(` ${dim2("Rules:")} ${(policy.rules || []).length}`);
|
|
13885
12834
|
const checkRes = await fetch(`${API_URL}/api/v1/policies/${policyId}`, {
|
|
13886
12835
|
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
13887
12836
|
});
|
|
@@ -13903,17 +12852,17 @@ async function push(apiKey, file, policyId) {
|
|
|
13903
12852
|
});
|
|
13904
12853
|
if (!res.ok) {
|
|
13905
12854
|
const body = await res.text().catch(() => "");
|
|
13906
|
-
|
|
12855
|
+
log3(red2(`ERROR: Push failed (${res.status}): ${body}`));
|
|
13907
12856
|
process.exit(1);
|
|
13908
12857
|
}
|
|
13909
12858
|
const data = await res.json();
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
12859
|
+
log3("");
|
|
12860
|
+
log3(green2(` Pushed to cloud: v${data._version ?? "created"}`));
|
|
12861
|
+
log3(` ${dim2("Policy ID:")} ${policyId}`);
|
|
12862
|
+
log3(` ${dim2("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
|
|
12863
|
+
log3("");
|
|
13915
12864
|
}
|
|
13916
|
-
async function
|
|
12865
|
+
async function main() {
|
|
13917
12866
|
const { command, apiKey, file, policyId } = parseCliArgs();
|
|
13918
12867
|
try {
|
|
13919
12868
|
if (command === "pull") {
|
|
@@ -13923,32 +12872,32 @@ async function main3() {
|
|
|
13923
12872
|
} else if (command === "list" || command === "ls") {
|
|
13924
12873
|
await list5(apiKey, policyId);
|
|
13925
12874
|
} else {
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
12875
|
+
log3(red2(`Unknown command: ${command}`));
|
|
12876
|
+
log3("");
|
|
12877
|
+
log3(bold2("Usage:"));
|
|
12878
|
+
log3(" solongate-proxy list List all policies");
|
|
12879
|
+
log3(" solongate-proxy list --policy-id <ID> Show policy details");
|
|
12880
|
+
log3(" solongate-proxy pull --policy-id <ID> Pull policy to local file");
|
|
12881
|
+
log3(" solongate-proxy push --policy-id <ID> Push local file to cloud");
|
|
12882
|
+
log3("");
|
|
12883
|
+
log3(bold2("Flags:"));
|
|
12884
|
+
log3(" --policy-id, --id <ID> Cloud policy ID (required for push)");
|
|
12885
|
+
log3(" --file, -f <path> Local file path (default: policy.json)");
|
|
12886
|
+
log3(" --api-key <key> API key (or set SOLONGATE_API_KEY)");
|
|
12887
|
+
log3("");
|
|
13939
12888
|
process.exit(1);
|
|
13940
12889
|
}
|
|
13941
12890
|
} catch (err2) {
|
|
13942
|
-
|
|
12891
|
+
log3(red2(`ERROR: ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
13943
12892
|
process.exit(1);
|
|
13944
12893
|
}
|
|
13945
12894
|
}
|
|
13946
|
-
var
|
|
12895
|
+
var log3, dim2, bold2, green2, red2, yellow2, cyan2, magenta, API_URL;
|
|
13947
12896
|
var init_pull_push = __esm({
|
|
13948
12897
|
"src/pull-push.ts"() {
|
|
13949
12898
|
"use strict";
|
|
13950
12899
|
init_config();
|
|
13951
|
-
|
|
12900
|
+
log3 = (...args) => process.stderr.write(`${args.map(String).join(" ")}
|
|
13952
12901
|
`);
|
|
13953
12902
|
dim2 = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
13954
12903
|
bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
@@ -13958,15 +12907,15 @@ var init_pull_push = __esm({
|
|
|
13958
12907
|
cyan2 = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
13959
12908
|
magenta = (s) => `\x1B[35m${s}\x1B[0m`;
|
|
13960
12909
|
API_URL = "https://api.solongate.com";
|
|
13961
|
-
|
|
12910
|
+
main();
|
|
13962
12911
|
}
|
|
13963
12912
|
});
|
|
13964
12913
|
|
|
13965
12914
|
// src/index.ts
|
|
13966
12915
|
init_config();
|
|
13967
|
-
import { readFileSync as
|
|
12916
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
13968
12917
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13969
|
-
import { dirname as dirname4, join as
|
|
12918
|
+
import { dirname as dirname4, join as join16 } from "path";
|
|
13970
12919
|
|
|
13971
12920
|
// src/proxy.ts
|
|
13972
12921
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -16390,7 +15339,7 @@ var Mutex = class {
|
|
|
16390
15339
|
this.locked = true;
|
|
16391
15340
|
return;
|
|
16392
15341
|
}
|
|
16393
|
-
return new Promise((
|
|
15342
|
+
return new Promise((resolve7, reject) => {
|
|
16394
15343
|
const timer = setTimeout(() => {
|
|
16395
15344
|
const idx = this.queue.indexOf(onReady);
|
|
16396
15345
|
if (idx !== -1) this.queue.splice(idx, 1);
|
|
@@ -16398,7 +15347,7 @@ var Mutex = class {
|
|
|
16398
15347
|
}, timeoutMs);
|
|
16399
15348
|
const onReady = () => {
|
|
16400
15349
|
clearTimeout(timer);
|
|
16401
|
-
|
|
15350
|
+
resolve7();
|
|
16402
15351
|
};
|
|
16403
15352
|
this.queue.push(onReady);
|
|
16404
15353
|
});
|
|
@@ -16989,7 +15938,7 @@ ${msg.content.text}`;
|
|
|
16989
15938
|
|
|
16990
15939
|
// src/index.ts
|
|
16991
15940
|
init_cli_utils();
|
|
16992
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["
|
|
15941
|
+
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["pull", "push", "list", "ls", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
|
|
16993
15942
|
var CLI_INFO_ARGS = /* @__PURE__ */ new Set(["login", "help", "--help", "-h", "--version", "-v", "version"]);
|
|
16994
15943
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "") || CLI_INFO_ARGS.has(process.argv[2] ?? "");
|
|
16995
15944
|
if (!IS_HUMAN_CLI) {
|
|
@@ -17008,8 +15957,8 @@ if (!IS_HUMAN_CLI) {
|
|
|
17008
15957
|
}
|
|
17009
15958
|
var PKG_VERSION = (() => {
|
|
17010
15959
|
try {
|
|
17011
|
-
const p =
|
|
17012
|
-
return JSON.parse(
|
|
15960
|
+
const p = join16(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
15961
|
+
return JSON.parse(readFileSync13(p, "utf-8")).version || "unknown";
|
|
17013
15962
|
} catch {
|
|
17014
15963
|
return "unknown";
|
|
17015
15964
|
}
|
|
@@ -17028,7 +15977,7 @@ function printWelcome() {
|
|
|
17028
15977
|
console.log(` ${c.dim}Manage it at ${c.reset}${c.cyan}https://dashboard.solongate.com${c.reset}`);
|
|
17029
15978
|
console.log("");
|
|
17030
15979
|
}
|
|
17031
|
-
function
|
|
15980
|
+
function printHelp() {
|
|
17032
15981
|
const W = 46;
|
|
17033
15982
|
const head = (t) => console.log(`
|
|
17034
15983
|
${c.bold}${t}${c.reset}`);
|
|
@@ -17051,7 +16000,6 @@ function printHelp3() {
|
|
|
17051
16000
|
head("Setup & status");
|
|
17052
16001
|
cmd("solongate", "open the dataroom UI (login, policies, audit, settings)");
|
|
17053
16002
|
cmd("doctor [--json]", "health check: login, policy, guard, local logs");
|
|
17054
|
-
cmd("create", "scaffold a guarded MCP server in this folder");
|
|
17055
16003
|
cmd("logs-server", "serve local audit logs to the dashboard");
|
|
17056
16004
|
head("Policies");
|
|
17057
16005
|
cmd("policy list", "list all policies");
|
|
@@ -17090,12 +16038,7 @@ function printHelp3() {
|
|
|
17090
16038
|
cmd("webhooks list");
|
|
17091
16039
|
cmd("webhooks add --url <https://\u2026> [--events denials|allowed|all]", "event webhook");
|
|
17092
16040
|
cmd("webhooks remove <id>");
|
|
17093
|
-
head("
|
|
17094
|
-
cmd("keys list", "list API keys (prefix only)");
|
|
17095
|
-
cmd("keys create --name <name>", "create a key (secret shown once)");
|
|
17096
|
-
cmd("keys revoke <id>", "revoke a key");
|
|
17097
|
-
cmd("mcp", "list protected MCP servers");
|
|
17098
|
-
cmd("shield -- <command>", "wrap a command with LLM-path secret redaction");
|
|
16041
|
+
head("Policy sync");
|
|
17099
16042
|
cmd("pull --policy-id <ID> [--file f]", "pull a cloud policy to a local file");
|
|
17100
16043
|
cmd("push --policy-id <ID> [--file f]", "push a local policy file to the cloud");
|
|
17101
16044
|
console.log("");
|
|
@@ -17103,10 +16046,10 @@ function printHelp3() {
|
|
|
17103
16046
|
console.log(` ${c.dim}Details for a command: ${c.reset}${c.cyan}solongate <command> help${c.reset}${c.dim} \xB7 Dashboard: ${c.reset}${c.cyan}https://dashboard.solongate.com${c.reset}`);
|
|
17104
16047
|
console.log("");
|
|
17105
16048
|
}
|
|
17106
|
-
async function
|
|
16049
|
+
async function main2() {
|
|
17107
16050
|
const subcommand = process.argv[2];
|
|
17108
16051
|
if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
17109
|
-
|
|
16052
|
+
printHelp();
|
|
17110
16053
|
return;
|
|
17111
16054
|
}
|
|
17112
16055
|
if (subcommand === "--version" || subcommand === "-v" || subcommand === "version") {
|
|
@@ -17138,7 +16081,7 @@ async function main4() {
|
|
|
17138
16081
|
await launchTui2();
|
|
17139
16082
|
return;
|
|
17140
16083
|
}
|
|
17141
|
-
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "
|
|
16084
|
+
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks"]);
|
|
17142
16085
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
17143
16086
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
17144
16087
|
const code = await runCommand2(subcommand, process.argv.slice(3));
|
|
@@ -17151,26 +16094,11 @@ async function main4() {
|
|
|
17151
16094
|
console.log("");
|
|
17152
16095
|
return;
|
|
17153
16096
|
}
|
|
17154
|
-
if (subcommand === "shield") {
|
|
17155
|
-
const { runShield: runShield2 } = await Promise.resolve().then(() => (init_shield(), shield_exports));
|
|
17156
|
-
await runShield2();
|
|
17157
|
-
return;
|
|
17158
|
-
}
|
|
17159
16097
|
if (subcommand === "logs-server" || subcommand === "local-logs") {
|
|
17160
16098
|
const { runLogsServer: runLogsServer2 } = await Promise.resolve().then(() => (init_logs_server(), logs_server_exports));
|
|
17161
16099
|
await runLogsServer2();
|
|
17162
16100
|
return;
|
|
17163
16101
|
}
|
|
17164
|
-
if (subcommand === "inject") {
|
|
17165
|
-
process.argv.splice(2, 1);
|
|
17166
|
-
await Promise.resolve().then(() => (init_inject(), inject_exports));
|
|
17167
|
-
return;
|
|
17168
|
-
}
|
|
17169
|
-
if (subcommand === "create") {
|
|
17170
|
-
process.argv.splice(2, 1);
|
|
17171
|
-
await Promise.resolve().then(() => (init_create(), create_exports));
|
|
17172
|
-
return;
|
|
17173
|
-
}
|
|
17174
16102
|
if (subcommand === "pull" || subcommand === "push" || subcommand === "list" || subcommand === "ls") {
|
|
17175
16103
|
await Promise.resolve().then(() => (init_pull_push(), pull_push_exports));
|
|
17176
16104
|
return;
|
|
@@ -17197,4 +16125,4 @@ async function main4() {
|
|
|
17197
16125
|
process.exit(1);
|
|
17198
16126
|
}
|
|
17199
16127
|
}
|
|
17200
|
-
|
|
16128
|
+
main2();
|