@getpaseo/server 0.1.101 → 0.1.102-beta.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/dist/scripts/supervisor.js +26 -8
- package/dist/server/server/agent/activity-curator.d.ts +17 -0
- package/dist/server/server/agent/activity-curator.js +101 -24
- package/dist/server/server/agent/agent-manager.js +5 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +7 -2
- package/dist/server/server/agent/provider-snapshot-manager.d.ts +8 -1
- package/dist/server/server/agent/provider-snapshot-manager.js +78 -33
- package/dist/server/server/agent/providers/acp-agent.d.ts +7 -0
- package/dist/server/server/agent/providers/acp-agent.js +8 -1
- package/dist/server/server/agent/providers/claude/agent.js +51 -14
- package/dist/server/server/agent/providers/claude/query.d.ts +3 -0
- package/dist/server/server/agent/providers/claude/query.js +4 -2
- package/dist/server/server/agent/providers/mock-load-test-agent.js +8 -0
- package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/paths.js +7 -0
- package/dist/server/server/agent/providers/opencode/server-manager.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/server-manager.js +34 -5
- package/dist/server/server/agent/providers/opencode-agent.d.ts +4 -0
- package/dist/server/server/agent/providers/opencode-agent.js +14 -2
- package/dist/server/server/agent/providers/pi/agent.d.ts +3 -0
- package/dist/server/server/agent/providers/pi/agent.js +9 -3
- package/dist/server/server/agent/providers/provider-image-output.js +11 -6
- package/dist/server/server/agent/tools/paseo-tools.d.ts +1 -1
- package/dist/server/server/agent/tools/paseo-tools.js +0 -2
- package/dist/server/server/bootstrap.d.ts +7 -1
- package/dist/server/server/bootstrap.js +18 -0
- package/dist/server/server/config.d.ts +2 -0
- package/dist/server/server/config.js +57 -1
- package/dist/server/server/daemon-worker.js +19 -7
- package/dist/server/server/lifecycle-reasons.d.ts +4 -0
- package/dist/server/server/lifecycle-reasons.js +6 -0
- package/dist/server/server/persisted-config.d.ts +7 -0
- package/dist/server/server/persisted-config.js +8 -0
- package/dist/server/server/process-diagnostics.d.ts +17 -0
- package/dist/server/server/process-diagnostics.js +22 -0
- package/dist/server/server/relay-transport.js +1 -0
- package/dist/server/server/resolve-worktree-creation-intent.js +3 -1
- package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +32 -0
- package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +88 -0
- package/dist/server/server/session/daemon/daemon-self-updater.d.ts +32 -0
- package/dist/server/server/session/daemon/daemon-self-updater.js +56 -0
- package/dist/server/server/session/daemon/daemon-session.d.ts +12 -0
- package/dist/server/server/session/daemon/daemon-session.js +12 -0
- package/dist/server/server/session/daemon/diagnostics.js +10 -0
- package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
- package/dist/server/server/session/daemon/install-origin.js +64 -0
- package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
- package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
- package/dist/server/server/session/provider/provider-catalog-session.js +8 -4
- package/dist/server/server/session.d.ts +5 -3
- package/dist/server/server/session.js +74 -32
- package/dist/server/server/web-ui.d.ts +10 -0
- package/dist/server/server/web-ui.js +205 -0
- package/dist/server/server/websocket/runtime-metrics.d.ts +3 -0
- package/dist/server/server/websocket-server.d.ts +3 -0
- package/dist/server/server/websocket-server.js +190 -32
- package/dist/server/services/quota-fetcher/manifest.js +5 -0
- package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
- package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
- package/dist/server/terminal/agent-hooks/agent-hook-installer.js +2 -2
- package/dist/server/utils/checkout-git.js +156 -3
- package/dist/server/utils/directory-suggestions.js +1 -4
- package/dist/server/utils/path.d.ts +2 -0
- package/dist/server/utils/path.js +13 -0
- package/dist/server/utils/worktree.d.ts +1 -0
- package/dist/server/utils/worktree.js +92 -11
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js +16157 -0
- package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js +3 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js.gz +0 -0
- package/dist/server/web-ui/apple-touch-icon.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/antigravity.6e91a685c33435e0b466a56db86cf141.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/cursor.c31d6bce4fe9aadc3fe59962f4c4fcf3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/file-explorer.3e15e8f72c825c85ce336bcb0cdef776.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/finder.7f68fc2c475621a672e1be09309d5567.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/vscode.832bdb4c685d930f1c864c793703600b.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/webstorm.aa5dc2cd8c20cc0a155c4c5c5ab3c5f5.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/zed.f3a670b7f9aa226da4fe53fb86f1abbd.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
- package/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
- package/dist/server/web-ui/favicon.ico +0 -0
- package/dist/server/web-ui/index.html +90 -0
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/dist/server/web-ui/manifest.json +27 -0
- package/dist/server/web-ui/manifest.json.br +0 -0
- package/dist/server/web-ui/manifest.json.gz +0 -0
- package/dist/server/web-ui/metadata.json +1 -0
- package/dist/server/web-ui/metadata.json.br +1 -0
- package/dist/server/web-ui/metadata.json.gz +0 -0
- package/dist/server/web-ui/pwa-icon-192.png +0 -0
- package/dist/server/web-ui/pwa-icon-512.png +0 -0
- package/dist/server/web-ui/robots.txt +2 -0
- package/dist/src/server/persisted-config.js +8 -0
- package/package.json +7 -7
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { createReadStream, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const EXCLUDED_PATH_PREFIXES = ["/api/", "/mcp/", "/public/"];
|
|
4
|
+
const EXCLUDED_PATHS = new Set(["/api", "/mcp", "/public"]);
|
|
5
|
+
function isExcludedPath(requestPath) {
|
|
6
|
+
for (const prefix of EXCLUDED_PATH_PREFIXES) {
|
|
7
|
+
if (requestPath.startsWith(prefix)) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return EXCLUDED_PATHS.has(requestPath);
|
|
12
|
+
}
|
|
13
|
+
const CONTENT_TYPES = {
|
|
14
|
+
".html": "text/html; charset=utf-8",
|
|
15
|
+
".js": "application/javascript; charset=utf-8",
|
|
16
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
17
|
+
".css": "text/css; charset=utf-8",
|
|
18
|
+
".json": "application/json; charset=utf-8",
|
|
19
|
+
".png": "image/png",
|
|
20
|
+
".jpg": "image/jpeg",
|
|
21
|
+
".jpeg": "image/jpeg",
|
|
22
|
+
".gif": "image/gif",
|
|
23
|
+
".svg": "image/svg+xml",
|
|
24
|
+
".ico": "image/x-icon",
|
|
25
|
+
".woff": "font/woff",
|
|
26
|
+
".woff2": "font/woff2",
|
|
27
|
+
".ttf": "font/ttf",
|
|
28
|
+
".otf": "font/otf",
|
|
29
|
+
".eot": "application/vnd.ms-fontobject",
|
|
30
|
+
".map": "application/json",
|
|
31
|
+
};
|
|
32
|
+
function getContentType(filePath) {
|
|
33
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
34
|
+
return CONTENT_TYPES[ext] ?? "application/octet-stream";
|
|
35
|
+
}
|
|
36
|
+
function selectEncoding(acceptEncoding) {
|
|
37
|
+
if (!acceptEncoding) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const normalized = acceptEncoding.toLowerCase();
|
|
41
|
+
if (normalized.includes("br")) {
|
|
42
|
+
return "br";
|
|
43
|
+
}
|
|
44
|
+
if (normalized.includes("gzip")) {
|
|
45
|
+
return "gzip";
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function isHashedAsset(filePath) {
|
|
50
|
+
const base = path.basename(filePath);
|
|
51
|
+
// Match content hashes like index-abc123def456.js or main.abc123def456.css.
|
|
52
|
+
return /[-.][0-9a-f]{16,}[-.]/i.test(base);
|
|
53
|
+
}
|
|
54
|
+
function isInsideDir(targetPath, dirPath) {
|
|
55
|
+
const resolvedDir = path.resolve(dirPath);
|
|
56
|
+
const resolvedTarget = path.resolve(targetPath);
|
|
57
|
+
return resolvedTarget === resolvedDir || resolvedTarget.startsWith(resolvedDir + path.sep);
|
|
58
|
+
}
|
|
59
|
+
function resolveTargetFile(distDir, requestPath) {
|
|
60
|
+
const safePath = path.normalize(requestPath).replace(/^(\.\.[/\\])+/, "");
|
|
61
|
+
let filePath = path.join(distDir, safePath);
|
|
62
|
+
const stat = safeStat(filePath);
|
|
63
|
+
if (stat?.isDirectory()) {
|
|
64
|
+
filePath = path.join(filePath, "index.html");
|
|
65
|
+
}
|
|
66
|
+
const finalStat = safeStat(filePath);
|
|
67
|
+
if (!finalStat?.isFile()) {
|
|
68
|
+
filePath = path.join(distDir, "index.html");
|
|
69
|
+
const fallbackStat = safeStat(filePath);
|
|
70
|
+
if (!fallbackStat?.isFile()) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!isInsideDir(filePath, distDir)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const resolvedFile = path.resolve(filePath);
|
|
78
|
+
const isIndexHtml = path.basename(resolvedFile).toLowerCase() === "index.html";
|
|
79
|
+
return { resolvedFile, isIndexHtml };
|
|
80
|
+
}
|
|
81
|
+
function safeStat(filePath) {
|
|
82
|
+
try {
|
|
83
|
+
return statSync(filePath);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function resolveContentEncoding(resolvedFile, acceptEncoding) {
|
|
90
|
+
const encoding = selectEncoding(acceptEncoding);
|
|
91
|
+
if (!encoding) {
|
|
92
|
+
return { finalFile: resolvedFile, contentEncoding: null };
|
|
93
|
+
}
|
|
94
|
+
const compressedFile = `${resolvedFile}.${encoding === "br" ? "br" : "gz"}`;
|
|
95
|
+
const compressedStat = safeStat(compressedFile);
|
|
96
|
+
if (compressedStat?.isFile()) {
|
|
97
|
+
return { finalFile: compressedFile, contentEncoding: encoding };
|
|
98
|
+
}
|
|
99
|
+
return { finalFile: resolvedFile, contentEncoding: null };
|
|
100
|
+
}
|
|
101
|
+
function setResponseCacheHeaders(res, isIndexHtml, resolvedFile) {
|
|
102
|
+
if (isIndexHtml) {
|
|
103
|
+
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate");
|
|
104
|
+
res.setHeader("Pragma", "no-cache");
|
|
105
|
+
res.setHeader("Expires", "0");
|
|
106
|
+
}
|
|
107
|
+
else if (isHashedAsset(resolvedFile)) {
|
|
108
|
+
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export function createWebUiMiddleware(options) {
|
|
115
|
+
const { enabled, distDir, label, logger } = options;
|
|
116
|
+
const childLogger = logger.child({ module: "web-ui" });
|
|
117
|
+
if (!enabled || !distDir) {
|
|
118
|
+
childLogger.info({ enabled, hasDistDir: !!distDir }, "Daemon web UI disabled or missing dist directory");
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
childLogger.info({ distDir }, "Daemon web UI mounted");
|
|
122
|
+
}
|
|
123
|
+
return (req, res, next) => {
|
|
124
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
125
|
+
next();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (isExcludedPath(req.path)) {
|
|
129
|
+
next();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (!enabled || !distDir) {
|
|
133
|
+
res.status(404).end();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
serveWebUiFile({ distDir, requestPath: req.path, label, req, res });
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function serveWebUiFile(options) {
|
|
140
|
+
const { distDir, requestPath, label, req, res } = options;
|
|
141
|
+
const target = resolveTargetFile(distDir, requestPath);
|
|
142
|
+
if (!target) {
|
|
143
|
+
res.status(404).end();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const { resolvedFile, isIndexHtml } = target;
|
|
147
|
+
const acceptEncoding = isIndexHtml ? undefined : req.headers["accept-encoding"];
|
|
148
|
+
const { finalFile, contentEncoding } = resolveContentEncoding(resolvedFile, acceptEncoding);
|
|
149
|
+
res.setHeader("Content-Type", getContentType(resolvedFile));
|
|
150
|
+
if (contentEncoding) {
|
|
151
|
+
res.setHeader("Content-Encoding", contentEncoding);
|
|
152
|
+
res.setHeader("Vary", "Accept-Encoding");
|
|
153
|
+
}
|
|
154
|
+
setResponseCacheHeaders(res, isIndexHtml, resolvedFile);
|
|
155
|
+
if (req.method === "HEAD") {
|
|
156
|
+
res.status(200).end();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (isIndexHtml) {
|
|
160
|
+
sendIndexHtml(res, finalFile, req, label);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const stream = createReadStream(finalFile);
|
|
164
|
+
stream.on("error", () => {
|
|
165
|
+
if (!res.headersSent) {
|
|
166
|
+
res.status(500).end();
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
res.end();
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
stream.pipe(res);
|
|
173
|
+
}
|
|
174
|
+
function sendIndexHtml(res, filePath, req, label) {
|
|
175
|
+
try {
|
|
176
|
+
const html = readFileSync(filePath, "utf-8");
|
|
177
|
+
const injected = injectConnectionHint(html, req, label);
|
|
178
|
+
res.status(200).send(injected);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
res.status(500).end();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function serializeInlineScriptJson(value) {
|
|
185
|
+
return JSON.stringify(value)
|
|
186
|
+
.replace(/</g, "\\u003C")
|
|
187
|
+
.replace(/>/g, "\\u003E")
|
|
188
|
+
.replace(/&/g, "\\u0026");
|
|
189
|
+
}
|
|
190
|
+
function injectConnectionHint(html, req, label) {
|
|
191
|
+
const host = typeof req.headers.host === "string" ? req.headers.host : "";
|
|
192
|
+
const useTls = req.protocol === "https";
|
|
193
|
+
const hint = {
|
|
194
|
+
listen: host,
|
|
195
|
+
useTls,
|
|
196
|
+
label,
|
|
197
|
+
};
|
|
198
|
+
const script = `<script>window.__PASEO_INITIAL_DAEMON_CONNECTION__=${serializeInlineScriptJson(hint)}</script>`;
|
|
199
|
+
const headClose = /<\/head>/i;
|
|
200
|
+
if (headClose.test(html)) {
|
|
201
|
+
return html.replace(headClose, `${script}</head>`);
|
|
202
|
+
}
|
|
203
|
+
return script + html;
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=web-ui.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { WSOutboundMessage } from "../messages.js";
|
|
2
|
+
import type { ProcessMemoryDiagnostics } from "../process-diagnostics.js";
|
|
2
3
|
export interface WebSocketRuntimeCounters {
|
|
3
4
|
connectedAwaitingHello: number;
|
|
4
5
|
helloResumed: number;
|
|
@@ -56,6 +57,8 @@ export interface WebSocketRuntimeDiagnosticSnapshot<TRuntime = unknown, TAgents
|
|
|
56
57
|
p99Ms: number;
|
|
57
58
|
maxMs: number;
|
|
58
59
|
} | null;
|
|
60
|
+
uptimeSeconds: number;
|
|
61
|
+
memory: ProcessMemoryDiagnostics;
|
|
59
62
|
runtime: TRuntime;
|
|
60
63
|
agents: TAgents;
|
|
61
64
|
}
|
|
@@ -26,6 +26,7 @@ import { type DaemonAuthConfig } from "./auth.js";
|
|
|
26
26
|
export interface ExternalSocketMetadata {
|
|
27
27
|
transport: "relay";
|
|
28
28
|
externalSessionKey?: string;
|
|
29
|
+
relayConnectionId?: string;
|
|
29
30
|
}
|
|
30
31
|
interface WebSocketServerConfig {
|
|
31
32
|
allowedOrigins: Set<string>;
|
|
@@ -50,6 +51,7 @@ export declare class VoiceAssistantWebSocketServer {
|
|
|
50
51
|
private readonly wss;
|
|
51
52
|
private readonly pendingConnections;
|
|
52
53
|
private readonly sessions;
|
|
54
|
+
private readonly socketIdentities;
|
|
53
55
|
private readonly externalSessionsByKey;
|
|
54
56
|
private readonly serverId;
|
|
55
57
|
private readonly daemonVersion;
|
|
@@ -156,5 +158,6 @@ export declare class VoiceAssistantWebSocketServer {
|
|
|
156
158
|
private broadcastAgentAttention;
|
|
157
159
|
private broadcastTerminalAttention;
|
|
158
160
|
}
|
|
161
|
+
export declare function isWebSocketSameOrigin(origin: string | undefined, requestHost: string | null): boolean;
|
|
159
162
|
export {};
|
|
160
163
|
//# sourceMappingURL=websocket-server.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WebSocketServer } from "ws";
|
|
2
2
|
import { basename, join } from "path";
|
|
3
3
|
import { hostname as getHostname } from "node:os";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
4
5
|
import { monitorEventLoopDelay } from "node:perf_hooks";
|
|
5
6
|
import { WSInboundMessageSchema, wrapSessionMessage, } from "./messages.js";
|
|
6
7
|
import { asUint8Array, decodeBinaryFrame } from "@getpaseo/protocol/binary-frames/index";
|
|
@@ -15,6 +16,8 @@ import { createGitHubService } from "../services/github-service.js";
|
|
|
15
16
|
import { extractWsBearerProtocol, extractWsBearerToken, isBearerTokenValid, } from "./auth.js";
|
|
16
17
|
import { WebSocketRuntimeMetricsWindow, } from "./websocket/runtime-metrics.js";
|
|
17
18
|
import { ProviderUsageService } from "../services/quota-fetcher/service.js";
|
|
19
|
+
import { getProcessMemoryDiagnostics, getProcessUptimeSeconds } from "./process-diagnostics.js";
|
|
20
|
+
import { CLIENT_SHUTDOWN_RPC_REASON, normalizeClientRestartRpcReason, } from "./lifecycle-reasons.js";
|
|
18
21
|
const WS_CLOSE_DAEMON_AUTH_FAILED = 4401;
|
|
19
22
|
function resolveTerminalAttentionReason(input) {
|
|
20
23
|
if (input.attentionReason === "finished")
|
|
@@ -222,6 +225,7 @@ export class VoiceAssistantWebSocketServer {
|
|
|
222
225
|
constructor(server, logger, serverId, agentManager, agentStorage, downloadTokenStore, paseoHome, daemonConfigStore, mcpBaseUrl, wsConfig, auth, speech, terminalManager, dictation, daemonVersion, onLifecycleIntent, projectRegistry, workspaceRegistry, chatService, loopService, scheduleService, checkoutDiffManager, serviceProxy, scriptRuntimeStore, onBranchChanged, getDaemonTcpPort, getDaemonTcpHost, resolveScriptHealth, workspaceGitService, github, pushNotificationSender, providerSnapshotManager, daemonRuntimeConfig, serviceProxyPublicBaseUrl) {
|
|
223
226
|
this.pendingConnections = new Map();
|
|
224
227
|
this.sessions = new Map();
|
|
228
|
+
this.socketIdentities = new Map();
|
|
225
229
|
this.externalSessionsByKey = new Map();
|
|
226
230
|
this.voiceSpeakHandlers = new Map();
|
|
227
231
|
this.voiceCallerContexts = new Map();
|
|
@@ -391,9 +395,7 @@ export class VoiceAssistantWebSocketServer {
|
|
|
391
395
|
callback(false, 403, "Host not allowed");
|
|
392
396
|
return;
|
|
393
397
|
}
|
|
394
|
-
const sameOrigin =
|
|
395
|
-
!!requestHost &&
|
|
396
|
-
(origin === `http://${requestHost}` || origin === `https://${requestHost}`);
|
|
398
|
+
const sameOrigin = isWebSocketSameOrigin(origin, requestHost);
|
|
397
399
|
if (!origin || allowedOrigins.has("*") || allowedOrigins.has(origin) || sameOrigin) {
|
|
398
400
|
callback(true);
|
|
399
401
|
}
|
|
@@ -508,6 +510,7 @@ export class VoiceAssistantWebSocketServer {
|
|
|
508
510
|
this.workspaceGitService.dispose();
|
|
509
511
|
this.pendingConnections.clear();
|
|
510
512
|
this.sessions.clear();
|
|
513
|
+
this.socketIdentities.clear();
|
|
511
514
|
this.externalSessionsByKey.clear();
|
|
512
515
|
this.wss.close();
|
|
513
516
|
}
|
|
@@ -550,25 +553,13 @@ export class VoiceAssistantWebSocketServer {
|
|
|
550
553
|
}
|
|
551
554
|
async attachSocket(ws, request, metadata) {
|
|
552
555
|
const requestMetadata = extractSocketRequestMetadata(request);
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
if (requestMetadata.host) {
|
|
557
|
-
connectionLoggerFields.host = requestMetadata.host;
|
|
558
|
-
}
|
|
559
|
-
if (requestMetadata.origin) {
|
|
560
|
-
connectionLoggerFields.origin = requestMetadata.origin;
|
|
561
|
-
}
|
|
562
|
-
if (requestMetadata.userAgent) {
|
|
563
|
-
connectionLoggerFields.userAgent = requestMetadata.userAgent;
|
|
564
|
-
}
|
|
565
|
-
if (requestMetadata.remoteAddress) {
|
|
566
|
-
connectionLoggerFields.remoteAddress = requestMetadata.remoteAddress;
|
|
567
|
-
}
|
|
568
|
-
const connectionLogger = this.logger.child(connectionLoggerFields);
|
|
556
|
+
const identity = createWebSocketConnectionIdentity(requestMetadata, metadata);
|
|
557
|
+
this.socketIdentities.set(ws, identity);
|
|
558
|
+
const connectionLogger = this.logger.child(toConnectionLogFields(identity));
|
|
569
559
|
const pending = {
|
|
570
560
|
connectionLogger,
|
|
571
561
|
helloTimeout: null,
|
|
562
|
+
identity,
|
|
572
563
|
};
|
|
573
564
|
const timeout = setTimeout(() => {
|
|
574
565
|
if (this.pendingConnections.get(ws) !== pending) {
|
|
@@ -576,7 +567,7 @@ export class VoiceAssistantWebSocketServer {
|
|
|
576
567
|
}
|
|
577
568
|
pending.helloTimeout = null;
|
|
578
569
|
this.pendingConnections.delete(ws);
|
|
579
|
-
pending.connectionLogger.warn({ timeoutMs: HELLO_TIMEOUT_MS }, "Closing connection due to missing hello");
|
|
570
|
+
pending.connectionLogger.warn({ ...toConnectionLogFields(identity), timeoutMs: HELLO_TIMEOUT_MS }, "Closing connection due to missing hello");
|
|
580
571
|
try {
|
|
581
572
|
ws.close(WS_CLOSE_HELLO_TIMEOUT, "Hello timeout");
|
|
582
573
|
}
|
|
@@ -589,7 +580,8 @@ export class VoiceAssistantWebSocketServer {
|
|
|
589
580
|
this.pendingConnections.set(ws, pending);
|
|
590
581
|
this.incrementRuntimeCounter("connectedAwaitingHello");
|
|
591
582
|
this.bindSocketHandlers(ws);
|
|
592
|
-
pending.connectionLogger.
|
|
583
|
+
pending.connectionLogger.info({
|
|
584
|
+
...toConnectionLogFields(identity),
|
|
593
585
|
totalPendingConnections: this.pendingConnections.size,
|
|
594
586
|
}, "Client connected; awaiting hello");
|
|
595
587
|
}
|
|
@@ -744,6 +736,10 @@ export class VoiceAssistantWebSocketServer {
|
|
|
744
736
|
return;
|
|
745
737
|
}
|
|
746
738
|
this.clearPendingConnection(ws);
|
|
739
|
+
pending.identity.clientId = clientId;
|
|
740
|
+
if (message.appVersion) {
|
|
741
|
+
pending.identity.appVersion = message.appVersion;
|
|
742
|
+
}
|
|
747
743
|
const existing = this.externalSessionsByKey.get(clientId);
|
|
748
744
|
if (existing) {
|
|
749
745
|
this.incrementRuntimeCounter("helloResumed");
|
|
@@ -764,9 +760,10 @@ export class VoiceAssistantWebSocketServer {
|
|
|
764
760
|
}
|
|
765
761
|
existing.sockets.add(ws);
|
|
766
762
|
this.sessions.set(ws, existing);
|
|
763
|
+
pending.identity.sessionId = existing.session.getSessionId();
|
|
767
764
|
this.sendToClient(ws, this.createServerInfoMessage());
|
|
768
|
-
|
|
769
|
-
|
|
765
|
+
pending.connectionLogger.info({
|
|
766
|
+
...toConnectionLogFields(pending.identity),
|
|
770
767
|
resumed: true,
|
|
771
768
|
totalSessions: this.sessions.size,
|
|
772
769
|
}, "Client connected via hello");
|
|
@@ -783,9 +780,10 @@ export class VoiceAssistantWebSocketServer {
|
|
|
783
780
|
});
|
|
784
781
|
this.sessions.set(ws, connection);
|
|
785
782
|
this.externalSessionsByKey.set(clientId, connection);
|
|
783
|
+
pending.identity.sessionId = connection.session.getSessionId();
|
|
786
784
|
this.sendToClient(ws, this.createServerInfoMessage());
|
|
787
|
-
connection.connectionLogger.
|
|
788
|
-
|
|
785
|
+
connection.connectionLogger.info({
|
|
786
|
+
...toConnectionLogFields(pending.identity),
|
|
789
787
|
resumed: false,
|
|
790
788
|
totalSessions: this.sessions.size,
|
|
791
789
|
}, "Client connected via hello");
|
|
@@ -825,6 +823,10 @@ export class VoiceAssistantWebSocketServer {
|
|
|
825
823
|
agentDetach: true,
|
|
826
824
|
// COMPAT(daemonDiagnostics): added in v0.1.100, remove gate after 2026-12-25 once daemon floor >= v0.1.100.
|
|
827
825
|
daemonDiagnostics: true,
|
|
826
|
+
// COMPAT(daemonSelfUpdate): added in v0.1.93, remove gate after 2026-12-13.
|
|
827
|
+
daemonSelfUpdate: true,
|
|
828
|
+
// COMPAT(agentForkContext): added in v0.1.102, remove gate after 2026-12-28.
|
|
829
|
+
agentForkContext: true,
|
|
828
830
|
},
|
|
829
831
|
};
|
|
830
832
|
}
|
|
@@ -882,21 +884,34 @@ export class VoiceAssistantWebSocketServer {
|
|
|
882
884
|
return this.voiceCallerContexts.get(callerAgentId) ?? null;
|
|
883
885
|
}
|
|
884
886
|
async detachSocket(ws, details) {
|
|
887
|
+
const identity = this.socketIdentities.get(ws);
|
|
888
|
+
const identityFields = identity ? toConnectionLogFields(identity) : {};
|
|
885
889
|
const pending = this.clearPendingConnection(ws);
|
|
886
890
|
if (pending) {
|
|
887
891
|
this.incrementRuntimeCounter("pendingDisconnected");
|
|
888
|
-
pending.connectionLogger.
|
|
892
|
+
pending.connectionLogger.info({
|
|
893
|
+
...identityFields,
|
|
889
894
|
code: details.code,
|
|
890
895
|
reason: stringifyCloseReason(details.reason),
|
|
891
896
|
}, "Pending client disconnected");
|
|
897
|
+
this.socketIdentities.delete(ws);
|
|
892
898
|
return;
|
|
893
899
|
}
|
|
894
900
|
const connection = this.sessions.get(ws);
|
|
895
901
|
if (!connection) {
|
|
902
|
+
if (identity) {
|
|
903
|
+
this.logger.info({
|
|
904
|
+
...identityFields,
|
|
905
|
+
code: details.code,
|
|
906
|
+
reason: stringifyCloseReason(details.reason),
|
|
907
|
+
}, "Client socket closed without active session");
|
|
908
|
+
this.socketIdentities.delete(ws);
|
|
909
|
+
}
|
|
896
910
|
return;
|
|
897
911
|
}
|
|
898
912
|
this.sessions.delete(ws);
|
|
899
913
|
connection.sockets.delete(ws);
|
|
914
|
+
this.socketIdentities.delete(ws);
|
|
900
915
|
if (connection.sockets.size === 0) {
|
|
901
916
|
this.incrementRuntimeCounter("sessionDisconnectedWaitingReconnect");
|
|
902
917
|
if (connection.externalDisconnectCleanupTimeout) {
|
|
@@ -910,8 +925,8 @@ export class VoiceAssistantWebSocketServer {
|
|
|
910
925
|
void this.cleanupConnection(connection, "Client disconnected (grace timeout)");
|
|
911
926
|
}, EXTERNAL_SESSION_DISCONNECT_GRACE_MS);
|
|
912
927
|
connection.externalDisconnectCleanupTimeout = timeout;
|
|
913
|
-
connection.connectionLogger.
|
|
914
|
-
|
|
928
|
+
connection.connectionLogger.info({
|
|
929
|
+
...identityFields,
|
|
915
930
|
code: details.code,
|
|
916
931
|
reason: stringifyCloseReason(details.reason),
|
|
917
932
|
reconnectGraceMs: EXTERNAL_SESSION_DISCONNECT_GRACE_MS,
|
|
@@ -920,8 +935,8 @@ export class VoiceAssistantWebSocketServer {
|
|
|
920
935
|
}
|
|
921
936
|
if (connection.sockets.size > 0) {
|
|
922
937
|
this.incrementRuntimeCounter("sessionSocketDisconnectedAttached");
|
|
923
|
-
connection.connectionLogger.
|
|
924
|
-
|
|
938
|
+
connection.connectionLogger.info({
|
|
939
|
+
...identityFields,
|
|
925
940
|
remainingSockets: connection.sockets.size,
|
|
926
941
|
code: details.code,
|
|
927
942
|
reason: stringifyCloseReason(details.reason),
|
|
@@ -938,6 +953,7 @@ export class VoiceAssistantWebSocketServer {
|
|
|
938
953
|
}
|
|
939
954
|
for (const socket of connection.sockets) {
|
|
940
955
|
this.sessions.delete(socket);
|
|
956
|
+
this.socketIdentities.delete(socket);
|
|
941
957
|
}
|
|
942
958
|
connection.sockets.clear();
|
|
943
959
|
const existing = this.externalSessionsByKey.get(connection.clientId);
|
|
@@ -1112,7 +1128,7 @@ export class VoiceAssistantWebSocketServer {
|
|
|
1112
1128
|
return;
|
|
1113
1129
|
}
|
|
1114
1130
|
if (message.type === "session") {
|
|
1115
|
-
void this.dispatchSessionMessage(activeConnection, message).catch((error) => {
|
|
1131
|
+
void this.dispatchSessionMessage(ws, activeConnection, message).catch((error) => {
|
|
1116
1132
|
this.handleRawMessageError({ ws, data, error, log: activeConnection.connectionLogger });
|
|
1117
1133
|
});
|
|
1118
1134
|
}
|
|
@@ -1121,8 +1137,16 @@ export class VoiceAssistantWebSocketServer {
|
|
|
1121
1137
|
this.handleRawMessageError({ ws, data, error, log });
|
|
1122
1138
|
}
|
|
1123
1139
|
}
|
|
1124
|
-
async dispatchSessionMessage(activeConnection, message) {
|
|
1140
|
+
async dispatchSessionMessage(ws, activeConnection, message) {
|
|
1125
1141
|
this.recordInboundSessionRequestType(message.message.type);
|
|
1142
|
+
const controlRpc = getControlRpcLogInfo(message.message);
|
|
1143
|
+
if (controlRpc) {
|
|
1144
|
+
const identity = this.socketIdentities.get(ws);
|
|
1145
|
+
activeConnection.connectionLogger.warn({
|
|
1146
|
+
...(identity ? toConnectionLogFields(identity) : { clientId: activeConnection.clientId }),
|
|
1147
|
+
...controlRpc,
|
|
1148
|
+
}, "ws_control_rpc_received");
|
|
1149
|
+
}
|
|
1126
1150
|
const startMs = performance.now();
|
|
1127
1151
|
await activeConnection.session.handleMessage(message.message);
|
|
1128
1152
|
const durationMs = performance.now() - startMs;
|
|
@@ -1258,6 +1282,8 @@ export class VoiceAssistantWebSocketServer {
|
|
|
1258
1282
|
outboundBinaryFrameTypesTop: runtimeMetrics.outboundBinaryFrameTypesTop,
|
|
1259
1283
|
bufferedAmount: runtimeMetrics.bufferedAmount,
|
|
1260
1284
|
eventLoopDelay: this.snapshotEventLoopDelay(),
|
|
1285
|
+
uptimeSeconds: getProcessUptimeSeconds(),
|
|
1286
|
+
memory: getProcessMemoryDiagnostics(),
|
|
1261
1287
|
runtime: sessionMetrics,
|
|
1262
1288
|
latency: runtimeMetrics.latency,
|
|
1263
1289
|
agents: agentSnapshot,
|
|
@@ -1390,6 +1416,31 @@ export class VoiceAssistantWebSocketServer {
|
|
|
1390
1416
|
}
|
|
1391
1417
|
}
|
|
1392
1418
|
}
|
|
1419
|
+
function createWebSocketConnectionIdentity(requestMetadata, metadata) {
|
|
1420
|
+
return {
|
|
1421
|
+
connectionId: `conn_${randomUUID().replaceAll("-", "")}`,
|
|
1422
|
+
transport: metadata?.transport === "relay" ? "relay" : "direct",
|
|
1423
|
+
...(requestMetadata.host ? { host: requestMetadata.host } : {}),
|
|
1424
|
+
...(requestMetadata.origin ? { origin: requestMetadata.origin } : {}),
|
|
1425
|
+
...(requestMetadata.userAgent ? { userAgent: requestMetadata.userAgent } : {}),
|
|
1426
|
+
...(requestMetadata.remoteAddress ? { remoteAddress: requestMetadata.remoteAddress } : {}),
|
|
1427
|
+
...(metadata?.relayConnectionId ? { relayConnectionId: metadata.relayConnectionId } : {}),
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
function toConnectionLogFields(identity) {
|
|
1431
|
+
return {
|
|
1432
|
+
connectionId: identity.connectionId,
|
|
1433
|
+
transport: identity.transport,
|
|
1434
|
+
...(identity.host ? { host: identity.host } : {}),
|
|
1435
|
+
...(identity.origin ? { origin: identity.origin } : {}),
|
|
1436
|
+
...(identity.userAgent ? { userAgent: identity.userAgent } : {}),
|
|
1437
|
+
...(identity.remoteAddress ? { remoteAddress: identity.remoteAddress } : {}),
|
|
1438
|
+
...(identity.relayConnectionId ? { relayConnectionId: identity.relayConnectionId } : {}),
|
|
1439
|
+
...(identity.clientId ? { clientId: identity.clientId } : {}),
|
|
1440
|
+
...(identity.sessionId ? { sessionId: identity.sessionId } : {}),
|
|
1441
|
+
...(identity.appVersion ? { appVersion: identity.appVersion } : {}),
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1393
1444
|
function extractSocketRequestMetadata(request) {
|
|
1394
1445
|
if (!request || typeof request !== "object") {
|
|
1395
1446
|
return {};
|
|
@@ -1406,6 +1457,88 @@ function extractSocketRequestMetadata(request) {
|
|
|
1406
1457
|
...(remoteAddress ? { remoteAddress } : {}),
|
|
1407
1458
|
};
|
|
1408
1459
|
}
|
|
1460
|
+
function stripIpv6Brackets(hostname) {
|
|
1461
|
+
return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
|
|
1462
|
+
}
|
|
1463
|
+
function parseHostAuthority(host) {
|
|
1464
|
+
const trimmed = host.trim();
|
|
1465
|
+
if (!trimmed) {
|
|
1466
|
+
return null;
|
|
1467
|
+
}
|
|
1468
|
+
if (trimmed.startsWith("[")) {
|
|
1469
|
+
const end = trimmed.indexOf("]");
|
|
1470
|
+
if (end === -1) {
|
|
1471
|
+
return null;
|
|
1472
|
+
}
|
|
1473
|
+
const hostname = stripIpv6Brackets(trimmed.slice(0, end + 1)).toLowerCase();
|
|
1474
|
+
const rest = trimmed.slice(end + 1);
|
|
1475
|
+
if (!rest) {
|
|
1476
|
+
return { hostname, port: null };
|
|
1477
|
+
}
|
|
1478
|
+
if (!rest.startsWith(":")) {
|
|
1479
|
+
return null;
|
|
1480
|
+
}
|
|
1481
|
+
const port = rest.slice(1);
|
|
1482
|
+
return port ? { hostname, port } : null;
|
|
1483
|
+
}
|
|
1484
|
+
const firstColon = trimmed.indexOf(":");
|
|
1485
|
+
if (firstColon === -1) {
|
|
1486
|
+
return { hostname: trimmed.toLowerCase(), port: null };
|
|
1487
|
+
}
|
|
1488
|
+
if (trimmed.indexOf(":", firstColon + 1) !== -1) {
|
|
1489
|
+
return { hostname: trimmed.toLowerCase(), port: null };
|
|
1490
|
+
}
|
|
1491
|
+
const hostname = trimmed.slice(0, firstColon).toLowerCase();
|
|
1492
|
+
const port = trimmed.slice(firstColon + 1);
|
|
1493
|
+
return hostname && port ? { hostname, port } : null;
|
|
1494
|
+
}
|
|
1495
|
+
function defaultPortForOriginProtocol(protocol) {
|
|
1496
|
+
if (protocol === "http:") {
|
|
1497
|
+
return "80";
|
|
1498
|
+
}
|
|
1499
|
+
if (protocol === "https:") {
|
|
1500
|
+
return "443";
|
|
1501
|
+
}
|
|
1502
|
+
return null;
|
|
1503
|
+
}
|
|
1504
|
+
function isLoopbackAlias(hostname) {
|
|
1505
|
+
const normalized = stripIpv6Brackets(hostname).toLowerCase();
|
|
1506
|
+
if (normalized === "localhost" || normalized.endsWith(".localhost")) {
|
|
1507
|
+
return true;
|
|
1508
|
+
}
|
|
1509
|
+
if (normalized === "::1" || normalized === "0:0:0:0:0:0:0:1") {
|
|
1510
|
+
return true;
|
|
1511
|
+
}
|
|
1512
|
+
return /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
1513
|
+
}
|
|
1514
|
+
export function isWebSocketSameOrigin(origin, requestHost) {
|
|
1515
|
+
if (!origin || !requestHost) {
|
|
1516
|
+
return false;
|
|
1517
|
+
}
|
|
1518
|
+
if (origin === `http://${requestHost}` || origin === `https://${requestHost}`) {
|
|
1519
|
+
return true;
|
|
1520
|
+
}
|
|
1521
|
+
let originUrl;
|
|
1522
|
+
try {
|
|
1523
|
+
originUrl = new URL(origin);
|
|
1524
|
+
}
|
|
1525
|
+
catch {
|
|
1526
|
+
return false;
|
|
1527
|
+
}
|
|
1528
|
+
const originPort = originUrl.port || defaultPortForOriginProtocol(originUrl.protocol);
|
|
1529
|
+
if (!originPort) {
|
|
1530
|
+
return false;
|
|
1531
|
+
}
|
|
1532
|
+
const requestAuthority = parseHostAuthority(requestHost);
|
|
1533
|
+
if (!requestAuthority) {
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
const requestPort = requestAuthority.port || defaultPortForOriginProtocol(originUrl.protocol);
|
|
1537
|
+
if (originPort !== requestPort) {
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
return isLoopbackAlias(originUrl.hostname) && isLoopbackAlias(requestAuthority.hostname);
|
|
1541
|
+
}
|
|
1409
1542
|
function selectWebSocketProtocol(protocols, password) {
|
|
1410
1543
|
if (!password) {
|
|
1411
1544
|
return protocols.values().next().value ?? false;
|
|
@@ -1432,6 +1565,31 @@ function stringifyCloseReason(reason) {
|
|
|
1432
1565
|
const text = String(reason);
|
|
1433
1566
|
return text.length > 0 ? text : null;
|
|
1434
1567
|
}
|
|
1568
|
+
function getControlRpcLogInfo(message) {
|
|
1569
|
+
if (message.type === "shutdown_server_request") {
|
|
1570
|
+
return {
|
|
1571
|
+
requestType: message.type,
|
|
1572
|
+
requestId: message.requestId,
|
|
1573
|
+
reason: CLIENT_SHUTDOWN_RPC_REASON,
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
if (message.type === "restart_server_request") {
|
|
1577
|
+
const reason = normalizeClientRestartRpcReason(message.reason);
|
|
1578
|
+
return {
|
|
1579
|
+
requestType: message.type,
|
|
1580
|
+
requestId: message.requestId,
|
|
1581
|
+
reason,
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
if (message.type === "daemon.update.request") {
|
|
1585
|
+
return {
|
|
1586
|
+
requestType: message.type,
|
|
1587
|
+
requestId: message.requestId,
|
|
1588
|
+
reason: "daemon_update",
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
return null;
|
|
1592
|
+
}
|
|
1435
1593
|
function extractRequestInfoFromUnknownWsInbound(payload) {
|
|
1436
1594
|
if (!payload || typeof payload !== "object") {
|
|
1437
1595
|
return null;
|
|
@@ -4,6 +4,7 @@ import { CopilotQuotaProvider } from "./providers/copilot.js";
|
|
|
4
4
|
import { CursorQuotaProvider } from "./providers/cursor.js";
|
|
5
5
|
import { GrokQuotaProvider } from "./providers/grok.js";
|
|
6
6
|
import { KimiQuotaProvider } from "./providers/kimi.js";
|
|
7
|
+
import { MiniMaxQuotaProvider } from "./providers/minimax.js";
|
|
7
8
|
import { ZaiQuotaProvider } from "./providers/zai.js";
|
|
8
9
|
export const PROVIDER_USAGE_FETCHERS = [
|
|
9
10
|
{
|
|
@@ -40,6 +41,10 @@ export const PROVIDER_USAGE_FETCHERS = [
|
|
|
40
41
|
providerId: "kimi",
|
|
41
42
|
create: (options) => new KimiQuotaProvider({ logger: options.logger, fetch: options.fetch }),
|
|
42
43
|
},
|
|
44
|
+
{
|
|
45
|
+
providerId: "minimax",
|
|
46
|
+
create: (options) => new MiniMaxQuotaProvider({ logger: options.logger, fetch: options.fetch }),
|
|
47
|
+
},
|
|
43
48
|
];
|
|
44
49
|
export function createProviderUsageFetchers(options) {
|
|
45
50
|
return PROVIDER_USAGE_FETCHERS.map((entry) => entry.create(options));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Logger } from "pino";
|
|
2
|
+
import type { ProviderUsage } from "../../../server/messages.js";
|
|
3
|
+
import type { ProviderApiFetch, ProviderUsageFetcher } from "../provider.js";
|
|
4
|
+
interface MiniMaxQuotaProviderOptions {
|
|
5
|
+
logger: Logger;
|
|
6
|
+
fetch?: ProviderApiFetch;
|
|
7
|
+
configPath?: string;
|
|
8
|
+
credentialsPath?: string;
|
|
9
|
+
env?: NodeJS.ProcessEnv;
|
|
10
|
+
now?: () => number;
|
|
11
|
+
}
|
|
12
|
+
export declare class MiniMaxQuotaProvider implements ProviderUsageFetcher {
|
|
13
|
+
readonly providerId = "minimax";
|
|
14
|
+
readonly displayName = "MiniMax";
|
|
15
|
+
private readonly logger;
|
|
16
|
+
private readonly fetchApi;
|
|
17
|
+
private readonly configPath;
|
|
18
|
+
private readonly credentialsPath;
|
|
19
|
+
private readonly env;
|
|
20
|
+
private readonly now;
|
|
21
|
+
constructor(options: MiniMaxQuotaProviderOptions);
|
|
22
|
+
fetchUsage(): Promise<ProviderUsage>;
|
|
23
|
+
private resolveAuth;
|
|
24
|
+
private isExpired;
|
|
25
|
+
private readCredentials;
|
|
26
|
+
private readConfig;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=minimax.d.ts.map
|