@suveren/gateway 0.7.0 → 0.7.2
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/bin/suveren-gateway.js +24 -5
- package/dist/control-plane/index.mjs +161 -61
- package/dist/mcp-server/http.mjs +28 -0
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/child_process.d.ts +0 -1
- package/node_modules/@types/node/crypto.d.ts +6 -6
- package/node_modules/@types/node/dns/promises.d.ts +5 -5
- package/node_modules/@types/node/dns.d.ts +5 -5
- package/node_modules/@types/node/fs.d.ts +7 -0
- package/node_modules/@types/node/http.d.ts +30 -0
- package/node_modules/@types/node/http2.d.ts +4 -4
- package/node_modules/@types/node/os.d.ts +30 -30
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/@types/node/perf_hooks.d.ts +2 -1
- package/node_modules/@types/node/process.d.ts +42 -43
- package/node_modules/@types/node/quic.d.ts +1049 -84
- package/node_modules/@types/node/sqlite.d.ts +14 -1
- package/node_modules/@types/node/stream/iter.d.ts +3 -2
- package/node_modules/@types/node/test.d.ts +61 -0
- package/node_modules/@types/node/v8.d.ts +20 -23
- package/package.json +1 -1
package/bin/suveren-gateway.js
CHANGED
|
@@ -323,8 +323,14 @@ function serviceRunning() {
|
|
|
323
323
|
return p.status === 0 && /state = running/.test(p.stdout || '');
|
|
324
324
|
}
|
|
325
325
|
if (os === 'win32') {
|
|
326
|
-
|
|
327
|
-
|
|
326
|
+
// NOT schtasks /Query: its LIST output is localized — a German Windows
|
|
327
|
+
// prints "Wird ausgeführt", so matching the English word "Running" reports
|
|
328
|
+
// every non-English machine as stopped, and restart silently falls back to
|
|
329
|
+
// the manual path. Get-ScheduledTask's State is a .NET enum; its name is
|
|
330
|
+
// English on every locale.
|
|
331
|
+
const p = runQuiet('powershell', ['-NoProfile', '-NonInteractive', '-Command',
|
|
332
|
+
`(Get-ScheduledTask -TaskName '${WIN_TASK_NAME}' -ErrorAction Stop).State`]);
|
|
333
|
+
return p.status === 0 && /^Running/m.test((p.stdout || '').trim());
|
|
328
334
|
}
|
|
329
335
|
const p = runQuiet('systemctl', ['--user', 'is-active', SYSTEMD_UNIT]);
|
|
330
336
|
return (p.stdout || '').trim() === 'active';
|
|
@@ -344,7 +350,16 @@ function serviceRestart() {
|
|
|
344
350
|
if (os === 'darwin') {
|
|
345
351
|
runQuiet('launchctl', ['kickstart', '-k', `gui/${process.getuid()}/${LAUNCH_AGENT_LABEL}`]);
|
|
346
352
|
} else if (os === 'win32') {
|
|
347
|
-
|
|
353
|
+
// NOT schtasks /End: it TerminateProcess()es only the task's ROOT process
|
|
354
|
+
// (node server.js). No signal is delivered, so the shutdown handlers never
|
|
355
|
+
// run and the control-plane / MCP children survive — still holding ports
|
|
356
|
+
// 3400/3430, which makes the relaunched instance die on EADDRINUSE and
|
|
357
|
+
// "restart" quietly become "stop". taskkill /T takes the whole tree.
|
|
358
|
+
const like = SERVER_ENTRY.replace(/'/g, "''").replace(/([\[\]*?])/g, '`$1');
|
|
359
|
+
runQuiet('powershell', ['-NoProfile', '-NonInteractive', '-Command',
|
|
360
|
+
`Get-CimInstance Win32_Process -Filter "Name='node.exe'" | ` +
|
|
361
|
+
`Where-Object { $_.CommandLine -like '*${like}*' } | ` +
|
|
362
|
+
`ForEach-Object { taskkill.exe /PID $_.ProcessId /T /F } | Out-Null`]);
|
|
348
363
|
runQuiet('schtasks', ['/Run', '/TN', WIN_TASK_NAME]);
|
|
349
364
|
} else {
|
|
350
365
|
runQuiet('systemctl', ['--user', 'restart', SYSTEMD_UNIT]);
|
|
@@ -573,8 +588,12 @@ async function serviceStatusWindows() {
|
|
|
573
588
|
console.log(`Login service: ${installed ? 'installed' : 'not installed'}`);
|
|
574
589
|
if (installed) {
|
|
575
590
|
console.log(` Task: ${WIN_TASK_NAME}`);
|
|
576
|
-
|
|
577
|
-
|
|
591
|
+
// Locale-independent state (see serviceRunning): the schtasks LIST value
|
|
592
|
+
// is localized; the PowerShell enum name is not.
|
|
593
|
+
const st = runQuiet('powershell', ['-NoProfile', '-NonInteractive', '-Command',
|
|
594
|
+
`(Get-ScheduledTask -TaskName '${WIN_TASK_NAME}' -ErrorAction Stop).State`]);
|
|
595
|
+
const state = (st.stdout || '').trim();
|
|
596
|
+
if (st.status === 0 && state) console.log(` State: ${state}`);
|
|
578
597
|
}
|
|
579
598
|
}
|
|
580
599
|
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
7
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
8
|
-
import { existsSync as
|
|
9
|
-
import { dirname as
|
|
10
|
-
import { homedir as
|
|
8
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, renameSync } from "fs";
|
|
9
|
+
import { dirname as dirname5, join as join6 } from "path";
|
|
10
|
+
import { homedir as homedir5 } from "os";
|
|
11
11
|
import express from "express";
|
|
12
12
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
|
13
13
|
|
|
@@ -1540,15 +1540,15 @@ import { promisify } from "util";
|
|
|
1540
1540
|
var run = promisify(execFile);
|
|
1541
1541
|
var SUPPORTED = /* @__PURE__ */ new Set(["darwin", "win32", "linux"]);
|
|
1542
1542
|
var MODULE_DIR = pathDirname(fileURLToPath(import.meta.url));
|
|
1543
|
-
function findCli(
|
|
1543
|
+
function findCli(dirname6 = MODULE_DIR) {
|
|
1544
1544
|
const candidates = [
|
|
1545
1545
|
// Bundled (the shipped layout): dist/control-plane → dist → root → bin
|
|
1546
|
-
resolve(
|
|
1546
|
+
resolve(dirname6, "..", "..", "bin", "suveren-gateway.js"),
|
|
1547
1547
|
// Bundled, were the routes/ directory ever preserved.
|
|
1548
|
-
resolve(
|
|
1548
|
+
resolve(dirname6, "..", "..", "..", "bin", "suveren-gateway.js"),
|
|
1549
1549
|
// Dev, running from source: the repo's own bundle directory.
|
|
1550
|
-
resolve(
|
|
1551
|
-
resolve(
|
|
1550
|
+
resolve(dirname6, "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js"),
|
|
1551
|
+
resolve(dirname6, "..", "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js")
|
|
1552
1552
|
// Deliberately NO process.cwd() fallback: it makes the result depend on
|
|
1553
1553
|
// where the process happened to be launched from, so the same install
|
|
1554
1554
|
// resolves differently between a shell and a login service — and it would
|
|
@@ -1633,38 +1633,86 @@ function createAutostartRouter() {
|
|
|
1633
1633
|
|
|
1634
1634
|
// src/lib/desktop-notify.ts
|
|
1635
1635
|
import { spawn, spawnSync } from "child_process";
|
|
1636
|
+
|
|
1637
|
+
// src/lib/notifier-icon.ts
|
|
1638
|
+
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync3 } from "fs";
|
|
1639
|
+
import { homedir as homedir2 } from "os";
|
|
1640
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
1641
|
+
var ICON_BASE64 = "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";
|
|
1642
|
+
function ensureNotifierIcon(dataDir) {
|
|
1643
|
+
try {
|
|
1644
|
+
const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join2(homedir2(), ".suveren");
|
|
1645
|
+
const path = join2(dir, "notifier-icon.png");
|
|
1646
|
+
if (!existsSync3(path)) {
|
|
1647
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
1648
|
+
writeFileSync2(path, Buffer.from(ICON_BASE64, "base64"));
|
|
1649
|
+
}
|
|
1650
|
+
return path;
|
|
1651
|
+
} catch {
|
|
1652
|
+
return null;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// src/lib/desktop-notify.ts
|
|
1636
1657
|
function osaQuote(value) {
|
|
1637
1658
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1638
1659
|
}
|
|
1639
1660
|
function psQuote(value) {
|
|
1640
1661
|
return `'${value.replace(/'/g, "''")}'`;
|
|
1641
1662
|
}
|
|
1663
|
+
function xmlEscape(value) {
|
|
1664
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1665
|
+
}
|
|
1666
|
+
var WINDOWS_AUMID = "Suveren.Gateway";
|
|
1667
|
+
function windowsToastScript(title, message, url, iconPath) {
|
|
1668
|
+
const toastXml = `<toast${url ? ` activationType="protocol" launch="${xmlEscape(url)}"` : ""}><visual><binding template="ToastGeneric"><text>${xmlEscape(title)}</text><text>${xmlEscape(message)}</text>` + (iconPath ? `<image placement="appLogoOverride" src="${xmlEscape(iconPath)}"/>` : "") + `</binding></visual><audio src="ms-winsoundevent:Notification.Default"/></toast>`;
|
|
1669
|
+
return `$ErrorActionPreference='SilentlyContinue'; $aumid=${psQuote(WINDOWS_AUMID)}; $reg="HKCU:\\Software\\Classes\\AppUserModelId\\$aumid"; if (-not (Test-Path $reg)) { New-Item -Path $reg -Force | Out-Null }; New-ItemProperty -Path $reg -Name DisplayName -Value 'Suveren' -PropertyType String -Force | Out-Null; ` + (iconPath ? `New-ItemProperty -Path $reg -Name IconUri -Value ${psQuote(iconPath)} -PropertyType String -Force | Out-Null; ` : "") + `[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] | Out-Null; [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom, ContentType=WindowsRuntime] | Out-Null; $doc = New-Object Windows.Data.Xml.Dom.XmlDocument; $doc.LoadXml(${psQuote(toastXml)}); $toast = New-Object Windows.UI.Notifications.ToastNotification $doc; [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($aumid).Show($toast)`;
|
|
1670
|
+
}
|
|
1671
|
+
var MAC_SOUND = "Glass";
|
|
1642
1672
|
function buildNotifyCommand(platform, title, message, options = {}) {
|
|
1643
|
-
const { url, hasTerminalNotifier: hasTerminalNotifier2 = false } = options;
|
|
1673
|
+
const { url, hasTerminalNotifier: hasTerminalNotifier2 = false, iconPath } = options;
|
|
1644
1674
|
switch (platform) {
|
|
1645
1675
|
case "darwin":
|
|
1646
1676
|
if (url && hasTerminalNotifier2) {
|
|
1647
1677
|
return {
|
|
1648
1678
|
cmd: "terminal-notifier",
|
|
1649
|
-
args: [
|
|
1679
|
+
args: [
|
|
1680
|
+
"-title",
|
|
1681
|
+
title,
|
|
1682
|
+
"-message",
|
|
1683
|
+
message,
|
|
1684
|
+
"-open",
|
|
1685
|
+
url,
|
|
1686
|
+
"-sound",
|
|
1687
|
+
MAC_SOUND,
|
|
1688
|
+
...iconPath ? ["-appIcon", iconPath] : [],
|
|
1689
|
+
"-group",
|
|
1690
|
+
"ai.suveren.gateway"
|
|
1691
|
+
]
|
|
1650
1692
|
};
|
|
1651
1693
|
}
|
|
1652
1694
|
return {
|
|
1653
1695
|
cmd: "osascript",
|
|
1654
|
-
args: [
|
|
1696
|
+
args: [
|
|
1697
|
+
"-e",
|
|
1698
|
+
`display notification ${osaQuote(message)} with title ${osaQuote(title)} sound name ${osaQuote(MAC_SOUND)}`
|
|
1699
|
+
]
|
|
1655
1700
|
};
|
|
1656
1701
|
case "win32":
|
|
1657
1702
|
return {
|
|
1658
1703
|
cmd: "powershell",
|
|
1704
|
+
args: ["-NoProfile", "-NonInteractive", "-Command", windowsToastScript(title, message, url, iconPath)]
|
|
1705
|
+
};
|
|
1706
|
+
case "linux":
|
|
1707
|
+
return {
|
|
1708
|
+
cmd: "notify-send",
|
|
1659
1709
|
args: [
|
|
1660
|
-
"-
|
|
1661
|
-
"-
|
|
1662
|
-
|
|
1663
|
-
|
|
1710
|
+
"--app-name=Suveren",
|
|
1711
|
+
...iconPath ? ["-i", iconPath] : [],
|
|
1712
|
+
title,
|
|
1713
|
+
message
|
|
1664
1714
|
]
|
|
1665
1715
|
};
|
|
1666
|
-
case "linux":
|
|
1667
|
-
return { cmd: "notify-send", args: ["--app-name=Suveren", title, message] };
|
|
1668
1716
|
default:
|
|
1669
1717
|
return null;
|
|
1670
1718
|
}
|
|
@@ -1688,15 +1736,32 @@ function hasTerminalNotifier() {
|
|
|
1688
1736
|
}
|
|
1689
1737
|
return terminalNotifierCache;
|
|
1690
1738
|
}
|
|
1739
|
+
function notifySpawnOptions(platform) {
|
|
1740
|
+
return {
|
|
1741
|
+
detached: platform !== "win32",
|
|
1742
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
1743
|
+
};
|
|
1744
|
+
}
|
|
1691
1745
|
function notify(title, message, platform = process.platform, url) {
|
|
1692
1746
|
const command = buildNotifyCommand(platform, title, message, {
|
|
1693
1747
|
url,
|
|
1694
|
-
|
|
1695
|
-
|
|
1748
|
+
hasTerminalNotifier: platform === "darwin" ? hasTerminalNotifier() : false,
|
|
1749
|
+
// Windows and Linux show it on the toast itself; macOS only via
|
|
1750
|
+
// terminal-notifier. Failure to write it must never block the sound.
|
|
1751
|
+
iconPath: ensureNotifierIcon()
|
|
1696
1752
|
});
|
|
1697
1753
|
if (!command) return;
|
|
1698
1754
|
try {
|
|
1699
|
-
const child = spawn(command.cmd, command.args,
|
|
1755
|
+
const child = spawn(command.cmd, command.args, notifySpawnOptions(platform));
|
|
1756
|
+
let stderr = "";
|
|
1757
|
+
child.stderr?.on("data", (d) => {
|
|
1758
|
+
stderr += d.toString().slice(0, 500);
|
|
1759
|
+
});
|
|
1760
|
+
child.on("close", (code) => {
|
|
1761
|
+
if (code !== 0) {
|
|
1762
|
+
console.error(`[notify] ${command.cmd} exited ${code}${stderr ? `: ${stderr.trim()}` : ""}`);
|
|
1763
|
+
}
|
|
1764
|
+
});
|
|
1700
1765
|
child.on("error", () => {
|
|
1701
1766
|
});
|
|
1702
1767
|
child.unref();
|
|
@@ -1812,13 +1877,13 @@ function createDecryptIntentRouter(vault2) {
|
|
|
1812
1877
|
|
|
1813
1878
|
// src/routes/approved-intents.ts
|
|
1814
1879
|
import { Router as Router9 } from "express";
|
|
1815
|
-
import { readFileSync as readFileSync2, writeFileSync as
|
|
1816
|
-
import { homedir as
|
|
1817
|
-
import { join as
|
|
1818
|
-
var SUVEREN_DATA_DIR = process.env.SUVEREN_DATA_DIR ??
|
|
1819
|
-
var FILE_PATH =
|
|
1880
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
1881
|
+
import { homedir as homedir3 } from "os";
|
|
1882
|
+
import { join as join3 } from "path";
|
|
1883
|
+
var SUVEREN_DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join3(homedir3(), ".suveren");
|
|
1884
|
+
var FILE_PATH = join3(SUVEREN_DATA_DIR, "approved-intents.enc.json");
|
|
1820
1885
|
function readFile() {
|
|
1821
|
-
if (!
|
|
1886
|
+
if (!existsSync4(FILE_PATH)) {
|
|
1822
1887
|
return { version: 1, entries: {} };
|
|
1823
1888
|
}
|
|
1824
1889
|
try {
|
|
@@ -1828,8 +1893,8 @@ function readFile() {
|
|
|
1828
1893
|
}
|
|
1829
1894
|
}
|
|
1830
1895
|
function writeFile(data) {
|
|
1831
|
-
|
|
1832
|
-
|
|
1896
|
+
mkdirSync3(SUVEREN_DATA_DIR, { recursive: true });
|
|
1897
|
+
writeFileSync3(FILE_PATH, JSON.stringify(data, null, 2), "utf-8");
|
|
1833
1898
|
}
|
|
1834
1899
|
function createApprovedIntentsRouter(vault2) {
|
|
1835
1900
|
const router = Router9();
|
|
@@ -1875,7 +1940,7 @@ function createApprovedIntentsRouter(vault2) {
|
|
|
1875
1940
|
|
|
1876
1941
|
// src/lib/update-checker.ts
|
|
1877
1942
|
import { execSync } from "child_process";
|
|
1878
|
-
import { dirname as
|
|
1943
|
+
import { dirname as dirname3 } from "path";
|
|
1879
1944
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1880
1945
|
var GHCR_IMAGE = "suverenai/suveren-gateway";
|
|
1881
1946
|
var NPM_PACKAGE = "@suveren/gateway";
|
|
@@ -1941,7 +2006,7 @@ function compareSemver(a, b) {
|
|
|
1941
2006
|
return 0;
|
|
1942
2007
|
}
|
|
1943
2008
|
function checkDev() {
|
|
1944
|
-
const cwd =
|
|
2009
|
+
const cwd = dirname3(fileURLToPath2(import.meta.url));
|
|
1945
2010
|
try {
|
|
1946
2011
|
execSync("git fetch origin --quiet", { cwd, stdio: "ignore", timeout: 15e3 });
|
|
1947
2012
|
const out = execSync("git rev-list HEAD..origin/main --count", {
|
|
@@ -2012,15 +2077,15 @@ data: null
|
|
|
2012
2077
|
import { Router as Router10 } from "express";
|
|
2013
2078
|
|
|
2014
2079
|
// src/lib/gateway-settings.ts
|
|
2015
|
-
import { readFileSync as readFileSync3, writeFileSync as
|
|
2016
|
-
import { homedir as
|
|
2017
|
-
import { join as
|
|
2080
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
2081
|
+
import { homedir as homedir4 } from "os";
|
|
2082
|
+
import { join as join4, dirname as dirname4 } from "path";
|
|
2018
2083
|
var DEFAULT_SETTINGS = {
|
|
2019
2084
|
desktopNotifications: true
|
|
2020
2085
|
};
|
|
2021
2086
|
function settingsPath(dataDir) {
|
|
2022
|
-
const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ??
|
|
2023
|
-
return
|
|
2087
|
+
const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join4(homedir4(), ".suveren");
|
|
2088
|
+
return join4(dir, "settings.json");
|
|
2024
2089
|
}
|
|
2025
2090
|
function readSettings(dataDir) {
|
|
2026
2091
|
try {
|
|
@@ -2038,8 +2103,8 @@ function writeSettings(patch, dataDir) {
|
|
|
2038
2103
|
...typeof patch.desktopNotifications === "boolean" ? { desktopNotifications: patch.desktopNotifications } : {}
|
|
2039
2104
|
};
|
|
2040
2105
|
const path = settingsPath(dataDir);
|
|
2041
|
-
|
|
2042
|
-
|
|
2106
|
+
mkdirSync4(dirname4(path), { recursive: true });
|
|
2107
|
+
writeFileSync4(path, JSON.stringify(next, null, 2) + "\n", "utf8");
|
|
2043
2108
|
return next;
|
|
2044
2109
|
}
|
|
2045
2110
|
|
|
@@ -2067,6 +2132,37 @@ function createGatewaySettingsRouter() {
|
|
|
2067
2132
|
return router;
|
|
2068
2133
|
}
|
|
2069
2134
|
|
|
2135
|
+
// src/routes/internal-events.ts
|
|
2136
|
+
import { Router as Router11 } from "express";
|
|
2137
|
+
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
2138
|
+
var ALLOWED = ["proposal-added", "action-approval-needed"];
|
|
2139
|
+
function secretMatches(provided, expected) {
|
|
2140
|
+
if (!expected) return false;
|
|
2141
|
+
if (!provided) return false;
|
|
2142
|
+
const a = Buffer.from(provided);
|
|
2143
|
+
const b = Buffer.from(expected);
|
|
2144
|
+
if (a.length !== b.length) return false;
|
|
2145
|
+
return timingSafeEqual2(a, b);
|
|
2146
|
+
}
|
|
2147
|
+
function createInternalEventsRouter(getSecret) {
|
|
2148
|
+
const router = Router11();
|
|
2149
|
+
router.post("/event", (req, res) => {
|
|
2150
|
+
if (!secretMatches(req.headers["x-internal-secret"], getSecret())) {
|
|
2151
|
+
res.status(401).json({ error: "Unauthorized" });
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
const type = (req.body ?? {}).type;
|
|
2155
|
+
if (typeof type !== "string" || !ALLOWED.includes(type)) {
|
|
2156
|
+
res.status(400).json({ error: "Unsupported event type" });
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
console.error(`[Control Plane] Internal event received: ${type}`);
|
|
2160
|
+
eventBus.emit(type);
|
|
2161
|
+
res.json({ ok: true });
|
|
2162
|
+
});
|
|
2163
|
+
return router;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2070
2166
|
// src/lib/notification-dispatcher.ts
|
|
2071
2167
|
var TRIGGER_EVENTS = ["proposal-added", "action-approval-needed"];
|
|
2072
2168
|
var TITLE = "Suveren";
|
|
@@ -2132,6 +2228,9 @@ var NotificationDispatcher = class {
|
|
|
2132
2228
|
} catch {
|
|
2133
2229
|
enabled = true;
|
|
2134
2230
|
}
|
|
2231
|
+
console.error(
|
|
2232
|
+
`[Control Plane] Review pending \u2014 desktop notification ${enabled ? "sent" : "suppressed (turned off)"}`
|
|
2233
|
+
);
|
|
2135
2234
|
if (enabled) {
|
|
2136
2235
|
const message = count >= FLOOD_THRESHOLD ? floodMessage(count) : WAITING_MESSAGE;
|
|
2137
2236
|
this.notifyFn(TITLE, message, process.platform, this.url);
|
|
@@ -2150,16 +2249,16 @@ function startNotificationDispatcher(opts = {}) {
|
|
|
2150
2249
|
}
|
|
2151
2250
|
|
|
2152
2251
|
// src/lib/denials-reader.ts
|
|
2153
|
-
import { existsSync as
|
|
2154
|
-
import { join as
|
|
2252
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
2253
|
+
import { join as join5 } from "path";
|
|
2155
2254
|
function loadDenials(dataDir, decrypt) {
|
|
2156
|
-
const encPath =
|
|
2157
|
-
const plainPath =
|
|
2158
|
-
if (
|
|
2255
|
+
const encPath = join5(dataDir, "denials.enc.json");
|
|
2256
|
+
const plainPath = join5(dataDir, "denials.json");
|
|
2257
|
+
if (existsSync5(encPath)) {
|
|
2159
2258
|
const { blob } = JSON.parse(readFileSync4(encPath, "utf-8"));
|
|
2160
2259
|
return JSON.parse(decrypt(blob)).records ?? [];
|
|
2161
2260
|
}
|
|
2162
|
-
if (
|
|
2261
|
+
if (existsSync5(plainPath)) {
|
|
2163
2262
|
return JSON.parse(readFileSync4(plainPath, "utf-8")).records ?? [];
|
|
2164
2263
|
}
|
|
2165
2264
|
return [];
|
|
@@ -2175,9 +2274,9 @@ function selectDenials(records, opts = {}) {
|
|
|
2175
2274
|
// src/index.ts
|
|
2176
2275
|
(function migrateDataDir() {
|
|
2177
2276
|
if (process.env.SUVEREN_DATA_DIR) return;
|
|
2178
|
-
const oldDir =
|
|
2179
|
-
const newDir =
|
|
2180
|
-
if (!
|
|
2277
|
+
const oldDir = join6(homedir5(), ".hap");
|
|
2278
|
+
const newDir = join6(homedir5(), ".suveren");
|
|
2279
|
+
if (!existsSync6(newDir) && existsSync6(oldDir)) {
|
|
2181
2280
|
try {
|
|
2182
2281
|
renameSync(oldDir, newDir);
|
|
2183
2282
|
console.error(`[Control Plane] Migrated data directory: ${oldDir} \u2192 ${newDir}`);
|
|
@@ -2190,7 +2289,7 @@ function selectDenials(records, opts = {}) {
|
|
|
2190
2289
|
var SP_URL2 = process.env.SUVEREN_AS_URL ?? "https://www.suveren.ai";
|
|
2191
2290
|
var port = parseInt(process.env.SUVEREN_CP_PORT ?? "3402", 10);
|
|
2192
2291
|
var HAP_MODE = process.env.HAP_MODE ?? "personal";
|
|
2193
|
-
var UI_DIST = process.env.HAP_UI_DIST ??
|
|
2292
|
+
var UI_DIST = process.env.HAP_UI_DIST ?? join6(import.meta.dirname ?? __dirname, "../../ui/dist");
|
|
2194
2293
|
var vault = new Vault();
|
|
2195
2294
|
var internalSecret2 = process.env.SUVEREN_INTERNAL_SECRET ?? randomBytes2(32).toString("hex");
|
|
2196
2295
|
setInternalSecret(internalSecret2);
|
|
@@ -2420,6 +2519,7 @@ app.get("/auth/oauth/:integrationId/health", authGuard, async (req, res) => {
|
|
|
2420
2519
|
}
|
|
2421
2520
|
});
|
|
2422
2521
|
app.get("/events", requireAllowedHost, requireAuthQueryOrHeader(vault), createEventsHandler());
|
|
2522
|
+
app.use("/internal", jsonParser, createInternalEventsRouter(() => internalSecret2));
|
|
2423
2523
|
app.use("/vault", jsonParser, authGuard, createVaultRouter(vault));
|
|
2424
2524
|
app.use("/ai", jsonParser, authGuard, createAIRouter(vault));
|
|
2425
2525
|
app.use("/ai-prompts", jsonParser, authGuard, createAIPromptsRouter());
|
|
@@ -2557,7 +2657,7 @@ app.get("/active-authorizations", authGuard, async (_req, res) => {
|
|
|
2557
2657
|
});
|
|
2558
2658
|
app.get("/denials", authGuard, (req, res) => {
|
|
2559
2659
|
try {
|
|
2560
|
-
const dataDir = process.env.SUVEREN_DATA_DIR ??
|
|
2660
|
+
const dataDir = process.env.SUVEREN_DATA_DIR ?? join6(homedir5(), ".suveren");
|
|
2561
2661
|
const all = loadDenials(dataDir, (blob) => vault.decrypt(blob));
|
|
2562
2662
|
const since = Number(req.query.since);
|
|
2563
2663
|
const limit = Number(req.query.limit);
|
|
@@ -2590,11 +2690,11 @@ app.post("/resync-gates", authGuard, async (_req, res) => {
|
|
|
2590
2690
|
}
|
|
2591
2691
|
});
|
|
2592
2692
|
var AGENT_CONTEXT_MAX_BYTES = 16 * 1024;
|
|
2593
|
-
var SUVEREN_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ??
|
|
2693
|
+
var SUVEREN_DATA_DIR2 = process.env.SUVEREN_DATA_DIR ?? join6(homedir5(), ".suveren");
|
|
2594
2694
|
app.get("/agent-brief/context", authGuard, async (_req, res) => {
|
|
2595
2695
|
try {
|
|
2596
2696
|
const { readFileSync: readFileSync6, existsSync: fileExists } = await import("fs");
|
|
2597
|
-
const filePath =
|
|
2697
|
+
const filePath = join6(SUVEREN_DATA_DIR2, "context.md");
|
|
2598
2698
|
if (!fileExists(filePath)) {
|
|
2599
2699
|
res.json({ content: "" });
|
|
2600
2700
|
return;
|
|
@@ -2617,11 +2717,11 @@ app.put("/agent-brief/context", jsonParser, authGuard, async (req, res) => {
|
|
|
2617
2717
|
res.status(413).json({ error: `Context exceeds ${AGENT_CONTEXT_MAX_BYTES}-byte cap` });
|
|
2618
2718
|
return;
|
|
2619
2719
|
}
|
|
2620
|
-
const { mkdirSync:
|
|
2621
|
-
|
|
2622
|
-
const filePath =
|
|
2720
|
+
const { mkdirSync: mkdirSync5, writeFileSync: writeFileSync5, renameSync: renameSync2 } = await import("fs");
|
|
2721
|
+
mkdirSync5(SUVEREN_DATA_DIR2, { recursive: true });
|
|
2722
|
+
const filePath = join6(SUVEREN_DATA_DIR2, "context.md");
|
|
2623
2723
|
const tmpPath = `${filePath}.tmp`;
|
|
2624
|
-
|
|
2724
|
+
writeFileSync5(tmpPath, content, "utf-8");
|
|
2625
2725
|
renameSync2(tmpPath, filePath);
|
|
2626
2726
|
res.json({ ok: true });
|
|
2627
2727
|
} catch (err) {
|
|
@@ -2671,13 +2771,13 @@ app.use(
|
|
|
2671
2771
|
})
|
|
2672
2772
|
);
|
|
2673
2773
|
function detectInstallMethod() {
|
|
2674
|
-
if (
|
|
2774
|
+
if (existsSync6("/.dockerenv")) return "docker";
|
|
2675
2775
|
const dir = import.meta.dirname ?? __dirname;
|
|
2676
2776
|
if (dir.includes("/node_modules/@suveren/gateway/")) return "npm";
|
|
2677
2777
|
let cursor = dir;
|
|
2678
2778
|
for (let i = 0; i < 8; i++) {
|
|
2679
|
-
if (
|
|
2680
|
-
const parent =
|
|
2779
|
+
if (existsSync6(join6(cursor, ".git"))) return "dev";
|
|
2780
|
+
const parent = dirname5(cursor);
|
|
2681
2781
|
if (parent === cursor) break;
|
|
2682
2782
|
cursor = parent;
|
|
2683
2783
|
}
|
|
@@ -2689,8 +2789,8 @@ function detectRunningVersion() {
|
|
|
2689
2789
|
return process.env.HAP_BUILD_SHA ?? "dev";
|
|
2690
2790
|
}
|
|
2691
2791
|
const dir = import.meta.dirname ?? __dirname;
|
|
2692
|
-
const bundlePkg =
|
|
2693
|
-
if (
|
|
2792
|
+
const bundlePkg = join6(dir, "..", "..", "package.json");
|
|
2793
|
+
if (existsSync6(bundlePkg)) {
|
|
2694
2794
|
try {
|
|
2695
2795
|
const pkg = JSON.parse(readFileSync5(bundlePkg, "utf8"));
|
|
2696
2796
|
if (pkg.name === "@suveren/gateway" && typeof pkg.version === "string") {
|
|
@@ -2720,7 +2820,7 @@ app.get("/health", async (req, res) => {
|
|
|
2720
2820
|
}
|
|
2721
2821
|
});
|
|
2722
2822
|
});
|
|
2723
|
-
if (
|
|
2823
|
+
if (existsSync6(UI_DIST)) {
|
|
2724
2824
|
app.use(express.static(UI_DIST, {
|
|
2725
2825
|
setHeaders: (res, filePath) => {
|
|
2726
2826
|
if (filePath.endsWith("index.html")) {
|
|
@@ -2730,7 +2830,7 @@ if (existsSync5(UI_DIST)) {
|
|
|
2730
2830
|
}));
|
|
2731
2831
|
app.get("*", (_req, res) => {
|
|
2732
2832
|
res.setHeader("Cache-Control", "no-store, must-revalidate");
|
|
2733
|
-
res.sendFile(
|
|
2833
|
+
res.sendFile(join6(UI_DIST, "index.html"));
|
|
2734
2834
|
});
|
|
2735
2835
|
} else {
|
|
2736
2836
|
app.get("/", (_req, res) => {
|
package/dist/mcp-server/http.mjs
CHANGED
|
@@ -6,6 +6,33 @@ import express from "express";
|
|
|
6
6
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
7
7
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
8
8
|
|
|
9
|
+
// src/lib/cp-notify.ts
|
|
10
|
+
var CP_PORT = process.env.SUVEREN_CP_PORT ?? "3402";
|
|
11
|
+
var CP_BASE = process.env.SUVEREN_CP_INTERNAL_URL ?? `http://127.0.0.1:${CP_PORT}`;
|
|
12
|
+
var TIMEOUT_MS = 2e3;
|
|
13
|
+
async function notifyControlPlane(type) {
|
|
14
|
+
const secret = process.env.SUVEREN_INTERNAL_SECRET ?? "";
|
|
15
|
+
if (!secret) return;
|
|
16
|
+
try {
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
19
|
+
try {
|
|
20
|
+
await fetch(`${CP_BASE}/internal/event`, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: {
|
|
23
|
+
"Content-Type": "application/json",
|
|
24
|
+
"X-Internal-Secret": secret
|
|
25
|
+
},
|
|
26
|
+
body: JSON.stringify({ type }),
|
|
27
|
+
signal: controller.signal
|
|
28
|
+
});
|
|
29
|
+
} finally {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
}
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
9
36
|
// src/lib/sp-client.ts
|
|
10
37
|
var SPReceiptError = class extends Error {
|
|
11
38
|
constructor(message, statusCode, body) {
|
|
@@ -167,6 +194,7 @@ var SPClient = class {
|
|
|
167
194
|
const body = await res.json().catch(() => ({}));
|
|
168
195
|
throw new Error(body.error ?? `SP proposal submission failed: ${res.status}`);
|
|
169
196
|
}
|
|
197
|
+
void notifyControlPlane("proposal-added");
|
|
170
198
|
return res.json();
|
|
171
199
|
}
|
|
172
200
|
/**
|
|
@@ -8,7 +8,7 @@ This package contains type definitions for node (https://nodejs.org/).
|
|
|
8
8
|
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node.
|
|
9
9
|
|
|
10
10
|
### Additional Details
|
|
11
|
-
* Last updated:
|
|
11
|
+
* Last updated: Fri, 07 Aug 2026 17:46:44 GMT
|
|
12
12
|
* Dependencies: [undici-types](https://npmjs.com/package/undici-types)
|
|
13
13
|
|
|
14
14
|
# Credits
|
|
@@ -2698,12 +2698,12 @@ declare module "node:crypto" {
|
|
|
2698
2698
|
*/
|
|
2699
2699
|
function sign(
|
|
2700
2700
|
algorithm: string | null | undefined,
|
|
2701
|
-
data:
|
|
2701
|
+
data: BinaryLike,
|
|
2702
2702
|
key: KeyLike | SignKeyObjectInput | SignPrivateKeyInput | SignJsonWebKeyInput,
|
|
2703
2703
|
): NonSharedBuffer;
|
|
2704
2704
|
function sign(
|
|
2705
2705
|
algorithm: string | null | undefined,
|
|
2706
|
-
data:
|
|
2706
|
+
data: BinaryLike,
|
|
2707
2707
|
key: KeyLike | SignKeyObjectInput | SignPrivateKeyInput | SignJsonWebKeyInput,
|
|
2708
2708
|
callback: (error: Error | null, data: NonSharedBuffer) => void,
|
|
2709
2709
|
): void;
|
|
@@ -2729,15 +2729,15 @@ declare module "node:crypto" {
|
|
|
2729
2729
|
*/
|
|
2730
2730
|
function verify(
|
|
2731
2731
|
algorithm: string | null | undefined,
|
|
2732
|
-
data:
|
|
2732
|
+
data: BinaryLike,
|
|
2733
2733
|
key: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput | VerifyJsonWebKeyInput,
|
|
2734
|
-
signature:
|
|
2734
|
+
signature: BinaryLike,
|
|
2735
2735
|
): boolean;
|
|
2736
2736
|
function verify(
|
|
2737
2737
|
algorithm: string | null | undefined,
|
|
2738
|
-
data:
|
|
2738
|
+
data: BinaryLike,
|
|
2739
2739
|
key: KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput | VerifyJsonWebKeyInput,
|
|
2740
|
-
signature:
|
|
2740
|
+
signature: BinaryLike,
|
|
2741
2741
|
callback: (error: Error | null, result: boolean) => void,
|
|
2742
2742
|
): void;
|
|
2743
2743
|
/**
|
|
@@ -183,7 +183,7 @@ declare module "node:dns/promises" {
|
|
|
183
183
|
* refresh: 900,
|
|
184
184
|
* retry: 900,
|
|
185
185
|
* expire: 1800,
|
|
186
|
-
* minttl: 60 } ]
|
|
186
|
+
* minttl: 60 } ];
|
|
187
187
|
* ```
|
|
188
188
|
* @since v10.6.0
|
|
189
189
|
*/
|
|
@@ -226,7 +226,7 @@ declare module "node:dns/promises" {
|
|
|
226
226
|
* regexp: '',
|
|
227
227
|
* replacement: '_sip._udp.example.com',
|
|
228
228
|
* order: 30,
|
|
229
|
-
* preference: 100
|
|
229
|
+
* preference: 100,
|
|
230
230
|
* }
|
|
231
231
|
* ```
|
|
232
232
|
* @since v10.6.0
|
|
@@ -265,7 +265,7 @@ declare module "node:dns/promises" {
|
|
|
265
265
|
* refresh: 10000,
|
|
266
266
|
* retry: 2400,
|
|
267
267
|
* expire: 604800,
|
|
268
|
-
* minttl: 3600
|
|
268
|
+
* minttl: 3600,
|
|
269
269
|
* }
|
|
270
270
|
* ```
|
|
271
271
|
* @since v10.6.0
|
|
@@ -285,7 +285,7 @@ declare module "node:dns/promises" {
|
|
|
285
285
|
* priority: 10,
|
|
286
286
|
* weight: 5,
|
|
287
287
|
* port: 21223,
|
|
288
|
-
* name: 'service.example.com'
|
|
288
|
+
* name: 'service.example.com',
|
|
289
289
|
* }
|
|
290
290
|
* ```
|
|
291
291
|
* @since v10.6.0
|
|
@@ -306,7 +306,7 @@ declare module "node:dns/promises" {
|
|
|
306
306
|
* certUsage: 3,
|
|
307
307
|
* selector: 1,
|
|
308
308
|
* match: 1,
|
|
309
|
-
* data: [ArrayBuffer]
|
|
309
|
+
* data: [ArrayBuffer],
|
|
310
310
|
* }
|
|
311
311
|
* ```
|
|
312
312
|
* @since v23.9.0, v22.15.0
|