beatcursor 0.0.15
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/README.md +12 -0
- package/dist/cli.cjs +3361 -0
- package/dist/models-catalog.json +1 -0
- package/package.json +41 -0
- package/vsix/beatcursor-0.0.15.vsix +0 -0
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,3361 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
|
|
25
|
+
// src/install.js
|
|
26
|
+
var import_fs13 = require("fs");
|
|
27
|
+
|
|
28
|
+
// src/detect.js
|
|
29
|
+
var import_fs = require("fs");
|
|
30
|
+
var import_os = require("os");
|
|
31
|
+
var import_path = require("path");
|
|
32
|
+
function getCandidateRoots() {
|
|
33
|
+
const home = (0, import_os.homedir)();
|
|
34
|
+
switch ((0, import_os.platform)()) {
|
|
35
|
+
case "darwin":
|
|
36
|
+
return [
|
|
37
|
+
"/Applications/Cursor.app/Contents/Resources/app",
|
|
38
|
+
(0, import_path.join)(home, "Applications/Cursor.app/Contents/Resources/app")
|
|
39
|
+
];
|
|
40
|
+
case "linux":
|
|
41
|
+
return [
|
|
42
|
+
"/opt/Cursor/resources/app",
|
|
43
|
+
"/opt/cursor/resources/app",
|
|
44
|
+
"/usr/share/cursor/resources/app",
|
|
45
|
+
"/usr/lib/cursor/resources/app",
|
|
46
|
+
(0, import_path.join)(home, ".local/share/cursor/resources/app")
|
|
47
|
+
];
|
|
48
|
+
case "win32": {
|
|
49
|
+
const localAppData = process.env.LOCALAPPDATA || (0, import_path.join)(home, "AppData", "Local");
|
|
50
|
+
const programFiles = process.env.ProgramFiles || "C:\\Program Files";
|
|
51
|
+
const programFilesX86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
|
|
52
|
+
return [
|
|
53
|
+
// Per-user install (default from Cursor installer)
|
|
54
|
+
(0, import_path.join)(localAppData, "Programs", "cursor", "resources", "app"),
|
|
55
|
+
(0, import_path.join)(localAppData, "Programs", "Cursor", "resources", "app"),
|
|
56
|
+
// System-wide install
|
|
57
|
+
(0, import_path.join)(programFiles, "Cursor", "resources", "app"),
|
|
58
|
+
(0, import_path.join)(programFilesX86, "Cursor", "resources", "app"),
|
|
59
|
+
// Scoop
|
|
60
|
+
(0, import_path.join)(home, "scoop", "apps", "cursor", "current", "resources", "app")
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
default:
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function getExtensionHostPath(appRoot) {
|
|
68
|
+
return (0, import_path.join)(appRoot, "out", "vs", "workbench", "api", "node", "extensionHostProcess.js");
|
|
69
|
+
}
|
|
70
|
+
function readCursorVersion(appRoot) {
|
|
71
|
+
try {
|
|
72
|
+
const pkg = JSON.parse((0, import_fs.readFileSync)((0, import_path.join)(appRoot, "package.json"), "utf-8"));
|
|
73
|
+
return pkg.version || "0.0.0";
|
|
74
|
+
} catch {
|
|
75
|
+
return "0.0.0";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function parseSemver(v) {
|
|
79
|
+
const [major = 0, minor = 0, patch = 0] = v.split(".").map(Number);
|
|
80
|
+
return { major, minor, patch };
|
|
81
|
+
}
|
|
82
|
+
function buildPaths(appRoot) {
|
|
83
|
+
const cursorVersion = readCursorVersion(appRoot);
|
|
84
|
+
const semver = parseSemver(cursorVersion);
|
|
85
|
+
const hasGlass = semver.major > 3 || semver.major === 3 && semver.minor >= 8;
|
|
86
|
+
return {
|
|
87
|
+
appRoot,
|
|
88
|
+
cursorVersion,
|
|
89
|
+
hasGlass,
|
|
90
|
+
workbenchJs: (0, import_path.join)(appRoot, "out", "vs", "workbench", "workbench.desktop.main.js"),
|
|
91
|
+
glassJs: (0, import_path.join)(appRoot, "out", "vs", "workbench", "workbench.glass.main.js"),
|
|
92
|
+
alwaysLocalMain: (0, import_path.join)(appRoot, "extensions", "cursor-always-local", "dist", "main.js"),
|
|
93
|
+
agentHostDist: (0, import_path.join)(appRoot, "extensions", "cursor-agent-host", "dist"),
|
|
94
|
+
agentHostMain: (0, import_path.join)(appRoot, "extensions", "cursor-agent-host", "dist", "main.js"),
|
|
95
|
+
agentHostPackageJson: (0, import_path.join)(appRoot, "extensions", "cursor-agent-host", "package.json"),
|
|
96
|
+
alwaysLocalSingletonJs: (0, import_path.join)(appRoot, "out", "vs", "code", "electron-utility", "alwaysLocalSingleton", "alwaysLocalSingletonMain.js"),
|
|
97
|
+
extensionHostJs: getExtensionHostPath(appRoot),
|
|
98
|
+
productJson: (0, import_path.join)(appRoot, "product.json"),
|
|
99
|
+
extensionsDir: (0, import_path.join)(appRoot, "extensions"),
|
|
100
|
+
beatcursorDir: (0, import_path.join)(appRoot, "extensions", "beatcursor")
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function findCursorPathsDetailed() {
|
|
104
|
+
const diagnostic = { platform: (0, import_os.platform)(), tried: [] };
|
|
105
|
+
const envRoot = process.env.BEATCURSOR_CURSOR_ROOT;
|
|
106
|
+
if (envRoot) {
|
|
107
|
+
diagnostic.tried.push({ path: envRoot, status: "env-override" });
|
|
108
|
+
if (!(0, import_fs.existsSync)((0, import_path.join)(envRoot, "product.json"))) {
|
|
109
|
+
diagnostic.hint = `BEATCURSOR_CURSOR_ROOT has no product.json: ${envRoot}`;
|
|
110
|
+
return { paths: null, diagnostic };
|
|
111
|
+
}
|
|
112
|
+
const paths = buildPaths(envRoot);
|
|
113
|
+
if (!(0, import_fs.existsSync)(paths.workbenchJs)) {
|
|
114
|
+
diagnostic.hint = `Found product.json but workbench.desktop.main.js is missing: ${paths.workbenchJs}`;
|
|
115
|
+
return { paths: null, diagnostic };
|
|
116
|
+
}
|
|
117
|
+
return { paths, diagnostic };
|
|
118
|
+
}
|
|
119
|
+
const candidates = getCandidateRoots();
|
|
120
|
+
let foundProductJsonWithoutWorkbench = null;
|
|
121
|
+
for (const appRoot of candidates) {
|
|
122
|
+
if (!(0, import_fs.existsSync)((0, import_path.join)(appRoot, "product.json"))) {
|
|
123
|
+
diagnostic.tried.push({ path: appRoot, status: "missing" });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const paths = buildPaths(appRoot);
|
|
127
|
+
if ((0, import_fs.existsSync)(paths.workbenchJs)) {
|
|
128
|
+
diagnostic.tried.push({ path: appRoot, status: "ok" });
|
|
129
|
+
return { paths, diagnostic };
|
|
130
|
+
}
|
|
131
|
+
foundProductJsonWithoutWorkbench = appRoot;
|
|
132
|
+
diagnostic.tried.push({ path: appRoot, status: "partial" });
|
|
133
|
+
}
|
|
134
|
+
if (foundProductJsonWithoutWorkbench) {
|
|
135
|
+
diagnostic.hint = `Found Cursor install dir but workbench.desktop.main.js is missing:
|
|
136
|
+
${foundProductJsonWithoutWorkbench}
|
|
137
|
+
Cursor version may be too old or the layout has changed.`;
|
|
138
|
+
} else {
|
|
139
|
+
diagnostic.hint = "Cursor not found in any default location.\nIf installed in a custom path, set BEATCURSOR_CURSOR_ROOT to point at the resources/app directory and retry.";
|
|
140
|
+
}
|
|
141
|
+
return { paths: null, diagnostic };
|
|
142
|
+
}
|
|
143
|
+
function formatDiagnostic(diagnostic) {
|
|
144
|
+
const lines = [];
|
|
145
|
+
lines.push(`Platform: ${diagnostic.platform}`);
|
|
146
|
+
lines.push("Tried paths:");
|
|
147
|
+
if (diagnostic.tried.length === 0) {
|
|
148
|
+
lines.push(" (none \u2014 unsupported platform)");
|
|
149
|
+
} else {
|
|
150
|
+
for (const t of diagnostic.tried) {
|
|
151
|
+
const tag = t.status === "ok" ? "\u2713" : t.status === "partial" ? "~" : t.status === "env-override" ? "\u2192" : "\u2717";
|
|
152
|
+
lines.push(` ${tag} ${t.path}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (diagnostic.hint) {
|
|
156
|
+
lines.push("");
|
|
157
|
+
lines.push(diagnostic.hint);
|
|
158
|
+
}
|
|
159
|
+
return lines.join("\n");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// node_modules/fflate/esm/index.mjs
|
|
163
|
+
var import_module = require("module");
|
|
164
|
+
var require2 = (0, import_module.createRequire)("/");
|
|
165
|
+
var _a;
|
|
166
|
+
var Worker;
|
|
167
|
+
var isMarkedAsUntransferable;
|
|
168
|
+
try {
|
|
169
|
+
_a = require2("worker_threads"), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable;
|
|
170
|
+
} catch (e) {
|
|
171
|
+
}
|
|
172
|
+
var u8 = Uint8Array;
|
|
173
|
+
var u16 = Uint16Array;
|
|
174
|
+
var i32 = Int32Array;
|
|
175
|
+
var fleb = new u8([
|
|
176
|
+
0,
|
|
177
|
+
0,
|
|
178
|
+
0,
|
|
179
|
+
0,
|
|
180
|
+
0,
|
|
181
|
+
0,
|
|
182
|
+
0,
|
|
183
|
+
0,
|
|
184
|
+
1,
|
|
185
|
+
1,
|
|
186
|
+
1,
|
|
187
|
+
1,
|
|
188
|
+
2,
|
|
189
|
+
2,
|
|
190
|
+
2,
|
|
191
|
+
2,
|
|
192
|
+
3,
|
|
193
|
+
3,
|
|
194
|
+
3,
|
|
195
|
+
3,
|
|
196
|
+
4,
|
|
197
|
+
4,
|
|
198
|
+
4,
|
|
199
|
+
4,
|
|
200
|
+
5,
|
|
201
|
+
5,
|
|
202
|
+
5,
|
|
203
|
+
5,
|
|
204
|
+
0,
|
|
205
|
+
/* unused */
|
|
206
|
+
0,
|
|
207
|
+
0,
|
|
208
|
+
/* impossible */
|
|
209
|
+
0
|
|
210
|
+
]);
|
|
211
|
+
var fdeb = new u8([
|
|
212
|
+
0,
|
|
213
|
+
0,
|
|
214
|
+
0,
|
|
215
|
+
0,
|
|
216
|
+
1,
|
|
217
|
+
1,
|
|
218
|
+
2,
|
|
219
|
+
2,
|
|
220
|
+
3,
|
|
221
|
+
3,
|
|
222
|
+
4,
|
|
223
|
+
4,
|
|
224
|
+
5,
|
|
225
|
+
5,
|
|
226
|
+
6,
|
|
227
|
+
6,
|
|
228
|
+
7,
|
|
229
|
+
7,
|
|
230
|
+
8,
|
|
231
|
+
8,
|
|
232
|
+
9,
|
|
233
|
+
9,
|
|
234
|
+
10,
|
|
235
|
+
10,
|
|
236
|
+
11,
|
|
237
|
+
11,
|
|
238
|
+
12,
|
|
239
|
+
12,
|
|
240
|
+
13,
|
|
241
|
+
13,
|
|
242
|
+
/* unused */
|
|
243
|
+
0,
|
|
244
|
+
0
|
|
245
|
+
]);
|
|
246
|
+
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
247
|
+
var freb = function(eb, start) {
|
|
248
|
+
var b = new u16(31);
|
|
249
|
+
for (var i = 0; i < 31; ++i) {
|
|
250
|
+
b[i] = start += 1 << eb[i - 1];
|
|
251
|
+
}
|
|
252
|
+
var r = new i32(b[30]);
|
|
253
|
+
for (var i = 1; i < 30; ++i) {
|
|
254
|
+
for (var j = b[i]; j < b[i + 1]; ++j) {
|
|
255
|
+
r[j] = j - b[i] << 5 | i;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return { b, r };
|
|
259
|
+
};
|
|
260
|
+
var _a = freb(fleb, 2);
|
|
261
|
+
var fl = _a.b;
|
|
262
|
+
var revfl = _a.r;
|
|
263
|
+
fl[28] = 258, revfl[258] = 28;
|
|
264
|
+
var _b = freb(fdeb, 0);
|
|
265
|
+
var fd = _b.b;
|
|
266
|
+
var revfd = _b.r;
|
|
267
|
+
var rev = new u16(32768);
|
|
268
|
+
for (i = 0; i < 32768; ++i) {
|
|
269
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
270
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
271
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
272
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
273
|
+
}
|
|
274
|
+
var x;
|
|
275
|
+
var i;
|
|
276
|
+
var hMap = (function(cd, mb, r) {
|
|
277
|
+
var s = cd.length;
|
|
278
|
+
var i = 0;
|
|
279
|
+
var l = new u16(mb);
|
|
280
|
+
for (; i < s; ++i) {
|
|
281
|
+
if (cd[i])
|
|
282
|
+
++l[cd[i] - 1];
|
|
283
|
+
}
|
|
284
|
+
var le = new u16(mb);
|
|
285
|
+
for (i = 1; i < mb; ++i) {
|
|
286
|
+
le[i] = le[i - 1] + l[i - 1] << 1;
|
|
287
|
+
}
|
|
288
|
+
var co;
|
|
289
|
+
if (r) {
|
|
290
|
+
co = new u16(1 << mb);
|
|
291
|
+
var rvb = 15 - mb;
|
|
292
|
+
for (i = 0; i < s; ++i) {
|
|
293
|
+
if (cd[i]) {
|
|
294
|
+
var sv = i << 4 | cd[i];
|
|
295
|
+
var r_1 = mb - cd[i];
|
|
296
|
+
var v = le[cd[i] - 1]++ << r_1;
|
|
297
|
+
for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
|
|
298
|
+
co[rev[v] >> rvb] = sv;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
co = new u16(s);
|
|
304
|
+
for (i = 0; i < s; ++i) {
|
|
305
|
+
if (cd[i]) {
|
|
306
|
+
co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return co;
|
|
311
|
+
});
|
|
312
|
+
var flt = new u8(288);
|
|
313
|
+
for (i = 0; i < 144; ++i)
|
|
314
|
+
flt[i] = 8;
|
|
315
|
+
var i;
|
|
316
|
+
for (i = 144; i < 256; ++i)
|
|
317
|
+
flt[i] = 9;
|
|
318
|
+
var i;
|
|
319
|
+
for (i = 256; i < 280; ++i)
|
|
320
|
+
flt[i] = 7;
|
|
321
|
+
var i;
|
|
322
|
+
for (i = 280; i < 288; ++i)
|
|
323
|
+
flt[i] = 8;
|
|
324
|
+
var i;
|
|
325
|
+
var fdt = new u8(32);
|
|
326
|
+
for (i = 0; i < 32; ++i)
|
|
327
|
+
fdt[i] = 5;
|
|
328
|
+
var i;
|
|
329
|
+
var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
|
|
330
|
+
var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
|
|
331
|
+
var max = function(a) {
|
|
332
|
+
var m = a[0];
|
|
333
|
+
for (var i = 1; i < a.length; ++i) {
|
|
334
|
+
if (a[i] > m)
|
|
335
|
+
m = a[i];
|
|
336
|
+
}
|
|
337
|
+
return m;
|
|
338
|
+
};
|
|
339
|
+
var bits = function(d, p, m) {
|
|
340
|
+
var o = p / 8 | 0;
|
|
341
|
+
return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
|
|
342
|
+
};
|
|
343
|
+
var bits16 = function(d, p) {
|
|
344
|
+
var o = p / 8 | 0;
|
|
345
|
+
return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
|
|
346
|
+
};
|
|
347
|
+
var shft = function(p) {
|
|
348
|
+
return (p + 7) / 8 | 0;
|
|
349
|
+
};
|
|
350
|
+
var slc = function(v, s, e) {
|
|
351
|
+
if (s == null || s < 0)
|
|
352
|
+
s = 0;
|
|
353
|
+
if (e == null || e > v.length)
|
|
354
|
+
e = v.length;
|
|
355
|
+
return new u8(v.subarray(s, e));
|
|
356
|
+
};
|
|
357
|
+
var ec = [
|
|
358
|
+
"unexpected EOF",
|
|
359
|
+
"invalid block type",
|
|
360
|
+
"invalid length/literal",
|
|
361
|
+
"invalid distance",
|
|
362
|
+
"stream finished",
|
|
363
|
+
"no stream handler",
|
|
364
|
+
,
|
|
365
|
+
// determined by compression function
|
|
366
|
+
"no callback",
|
|
367
|
+
"invalid UTF-8 data",
|
|
368
|
+
"extra field too long",
|
|
369
|
+
"date not in range 1980-2099",
|
|
370
|
+
"filename too long",
|
|
371
|
+
"stream finishing",
|
|
372
|
+
"invalid zip data"
|
|
373
|
+
// determined by unknown compression method
|
|
374
|
+
];
|
|
375
|
+
var err = function(ind, msg, nt) {
|
|
376
|
+
var e = new Error(msg || ec[ind]);
|
|
377
|
+
e.code = ind;
|
|
378
|
+
if (Error.captureStackTrace)
|
|
379
|
+
Error.captureStackTrace(e, err);
|
|
380
|
+
if (!nt)
|
|
381
|
+
throw e;
|
|
382
|
+
return e;
|
|
383
|
+
};
|
|
384
|
+
var inflt = function(dat, st, buf, dict) {
|
|
385
|
+
var sl = dat.length, dl = dict ? dict.length : 0;
|
|
386
|
+
if (!sl || st.f && !st.l)
|
|
387
|
+
return buf || new u8(0);
|
|
388
|
+
var noBuf = !buf;
|
|
389
|
+
var resize = noBuf || st.i != 2;
|
|
390
|
+
var noSt = st.i;
|
|
391
|
+
if (noBuf)
|
|
392
|
+
buf = new u8(sl * 3);
|
|
393
|
+
var cbuf = function(l2) {
|
|
394
|
+
var bl = buf.length;
|
|
395
|
+
if (l2 > bl) {
|
|
396
|
+
var nbuf = new u8(Math.max(bl * 2, l2));
|
|
397
|
+
nbuf.set(buf);
|
|
398
|
+
buf = nbuf;
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
|
|
402
|
+
var tbts = sl * 8;
|
|
403
|
+
do {
|
|
404
|
+
if (!lm) {
|
|
405
|
+
final = bits(dat, pos, 1);
|
|
406
|
+
var type = bits(dat, pos + 1, 3);
|
|
407
|
+
pos += 3;
|
|
408
|
+
if (!type) {
|
|
409
|
+
var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
|
|
410
|
+
if (t > sl) {
|
|
411
|
+
if (noSt)
|
|
412
|
+
err(0);
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
if (resize)
|
|
416
|
+
cbuf(bt + l);
|
|
417
|
+
buf.set(dat.subarray(s, t), bt);
|
|
418
|
+
st.b = bt += l, st.p = pos = t * 8, st.f = final;
|
|
419
|
+
continue;
|
|
420
|
+
} else if (type == 1)
|
|
421
|
+
lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
|
|
422
|
+
else if (type == 2) {
|
|
423
|
+
var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
|
|
424
|
+
var tl = hLit + bits(dat, pos + 5, 31) + 1;
|
|
425
|
+
pos += 14;
|
|
426
|
+
var ldt = new u8(tl);
|
|
427
|
+
var clt = new u8(19);
|
|
428
|
+
for (var i = 0; i < hcLen; ++i) {
|
|
429
|
+
clt[clim[i]] = bits(dat, pos + i * 3, 7);
|
|
430
|
+
}
|
|
431
|
+
pos += hcLen * 3;
|
|
432
|
+
var clb = max(clt), clbmsk = (1 << clb) - 1;
|
|
433
|
+
var clm = hMap(clt, clb, 1);
|
|
434
|
+
for (var i = 0; i < tl; ) {
|
|
435
|
+
var r = clm[bits(dat, pos, clbmsk)];
|
|
436
|
+
pos += r & 15;
|
|
437
|
+
var s = r >> 4;
|
|
438
|
+
if (s < 16) {
|
|
439
|
+
ldt[i++] = s;
|
|
440
|
+
} else {
|
|
441
|
+
var c = 0, n = 0;
|
|
442
|
+
if (s == 16)
|
|
443
|
+
n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
|
|
444
|
+
else if (s == 17)
|
|
445
|
+
n = 3 + bits(dat, pos, 7), pos += 3;
|
|
446
|
+
else if (s == 18)
|
|
447
|
+
n = 11 + bits(dat, pos, 127), pos += 7;
|
|
448
|
+
while (n--)
|
|
449
|
+
ldt[i++] = c;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
|
|
453
|
+
lbt = max(lt);
|
|
454
|
+
dbt = max(dt);
|
|
455
|
+
lm = hMap(lt, lbt, 1);
|
|
456
|
+
dm = hMap(dt, dbt, 1);
|
|
457
|
+
} else
|
|
458
|
+
err(1);
|
|
459
|
+
if (pos > tbts) {
|
|
460
|
+
if (noSt)
|
|
461
|
+
err(0);
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (resize)
|
|
466
|
+
cbuf(bt + 131072);
|
|
467
|
+
var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
|
|
468
|
+
var lpos = pos;
|
|
469
|
+
for (; ; lpos = pos) {
|
|
470
|
+
var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
|
|
471
|
+
pos += c & 15;
|
|
472
|
+
if (pos > tbts) {
|
|
473
|
+
if (noSt)
|
|
474
|
+
err(0);
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
if (!c)
|
|
478
|
+
err(2);
|
|
479
|
+
if (sym < 256)
|
|
480
|
+
buf[bt++] = sym;
|
|
481
|
+
else if (sym == 256) {
|
|
482
|
+
lpos = pos, lm = null;
|
|
483
|
+
break;
|
|
484
|
+
} else {
|
|
485
|
+
var add = sym - 254;
|
|
486
|
+
if (sym > 264) {
|
|
487
|
+
var i = sym - 257, b = fleb[i];
|
|
488
|
+
add = bits(dat, pos, (1 << b) - 1) + fl[i];
|
|
489
|
+
pos += b;
|
|
490
|
+
}
|
|
491
|
+
var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
|
|
492
|
+
if (!d)
|
|
493
|
+
err(3);
|
|
494
|
+
pos += d & 15;
|
|
495
|
+
var dt = fd[dsym];
|
|
496
|
+
if (dsym > 3) {
|
|
497
|
+
var b = fdeb[dsym];
|
|
498
|
+
dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
|
|
499
|
+
}
|
|
500
|
+
if (pos > tbts) {
|
|
501
|
+
if (noSt)
|
|
502
|
+
err(0);
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
if (resize)
|
|
506
|
+
cbuf(bt + 131072);
|
|
507
|
+
var end = bt + add;
|
|
508
|
+
if (bt < dt) {
|
|
509
|
+
var shift = dl - dt, dend = Math.min(dt, end);
|
|
510
|
+
if (shift + bt < 0)
|
|
511
|
+
err(3);
|
|
512
|
+
for (; bt < dend; ++bt)
|
|
513
|
+
buf[bt] = dict[shift + bt];
|
|
514
|
+
}
|
|
515
|
+
for (; bt < end; ++bt)
|
|
516
|
+
buf[bt] = buf[bt - dt];
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
st.l = lm, st.p = lpos, st.b = bt, st.f = final;
|
|
520
|
+
if (lm)
|
|
521
|
+
final = 1, st.m = lbt, st.d = dm, st.n = dbt;
|
|
522
|
+
} while (!final);
|
|
523
|
+
return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
|
|
524
|
+
};
|
|
525
|
+
var et = /* @__PURE__ */ new u8(0);
|
|
526
|
+
var b2 = function(d, b) {
|
|
527
|
+
return d[b] | d[b + 1] << 8;
|
|
528
|
+
};
|
|
529
|
+
var b4 = function(d, b) {
|
|
530
|
+
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
|
|
531
|
+
};
|
|
532
|
+
var b8 = function(d, b) {
|
|
533
|
+
return b4(d, b) + b4(d, b + 4) * 4294967296;
|
|
534
|
+
};
|
|
535
|
+
function inflateSync(data, opts) {
|
|
536
|
+
return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
|
|
537
|
+
}
|
|
538
|
+
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
|
|
539
|
+
var tds = 0;
|
|
540
|
+
try {
|
|
541
|
+
td.decode(et, { stream: true });
|
|
542
|
+
tds = 1;
|
|
543
|
+
} catch (e) {
|
|
544
|
+
}
|
|
545
|
+
var dutf8 = function(d) {
|
|
546
|
+
for (var r = "", i = 0; ; ) {
|
|
547
|
+
var c = d[i++];
|
|
548
|
+
var eb = (c > 127) + (c > 223) + (c > 239);
|
|
549
|
+
if (i + eb > d.length)
|
|
550
|
+
return { s: r, r: slc(d, i - 1) };
|
|
551
|
+
if (!eb)
|
|
552
|
+
r += String.fromCharCode(c);
|
|
553
|
+
else if (eb == 3) {
|
|
554
|
+
c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
|
|
555
|
+
} else if (eb & 1)
|
|
556
|
+
r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
|
|
557
|
+
else
|
|
558
|
+
r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
function strFromU8(dat, latin1) {
|
|
562
|
+
if (latin1) {
|
|
563
|
+
var r = "";
|
|
564
|
+
for (var i = 0; i < dat.length; i += 16384)
|
|
565
|
+
r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
|
|
566
|
+
return r;
|
|
567
|
+
} else if (td) {
|
|
568
|
+
return td.decode(dat);
|
|
569
|
+
} else {
|
|
570
|
+
var _a2 = dutf8(dat), s = _a2.s, r = _a2.r;
|
|
571
|
+
if (r.length)
|
|
572
|
+
err(8);
|
|
573
|
+
return s;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
var slzh = function(d, b) {
|
|
577
|
+
return b + 30 + b2(d, b + 26) + b2(d, b + 28);
|
|
578
|
+
};
|
|
579
|
+
var zh = function(d, b, z) {
|
|
580
|
+
var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn2 = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl;
|
|
581
|
+
var _a2 = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a2[0], su = _a2[1], off = _a2[2];
|
|
582
|
+
return [b2(d, b + 10), sc, su, fn2, es + efl + b2(d, b + 32), off];
|
|
583
|
+
};
|
|
584
|
+
var z64hs = function(d, b, l, z, sc, su, off) {
|
|
585
|
+
var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
|
|
586
|
+
var nf = nsc + nsu + noff;
|
|
587
|
+
if (z && nf) {
|
|
588
|
+
for (; b + 4 < e; b += 4 + b2(d, b + 2)) {
|
|
589
|
+
if (b2(d, b) == 1) {
|
|
590
|
+
return [
|
|
591
|
+
nsc ? b8(d, b + 4 + 8 * nsu) : sc,
|
|
592
|
+
nsu ? b8(d, b + 4) : su,
|
|
593
|
+
noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off,
|
|
594
|
+
1
|
|
595
|
+
];
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
if (z < 2)
|
|
599
|
+
err(13);
|
|
600
|
+
}
|
|
601
|
+
return [sc, su, off, 0];
|
|
602
|
+
};
|
|
603
|
+
function unzipSync(data, opts) {
|
|
604
|
+
var files = {};
|
|
605
|
+
var e = data.length - 22;
|
|
606
|
+
for (; b4(data, e) != 101010256; --e) {
|
|
607
|
+
if (!e || data.length - e > 65558)
|
|
608
|
+
err(13);
|
|
609
|
+
}
|
|
610
|
+
;
|
|
611
|
+
var c = b2(data, e + 8);
|
|
612
|
+
if (!c)
|
|
613
|
+
return {};
|
|
614
|
+
var o = b4(data, e + 16);
|
|
615
|
+
var z = b4(data, e - 20) == 117853008;
|
|
616
|
+
if (z) {
|
|
617
|
+
var ze = b4(data, e - 12);
|
|
618
|
+
z = b4(data, ze) == 101075792;
|
|
619
|
+
if (z) {
|
|
620
|
+
c = b4(data, ze + 32);
|
|
621
|
+
o = b4(data, ze + 48);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
var fltr = opts && opts.filter;
|
|
625
|
+
for (var i = 0; i < c; ++i) {
|
|
626
|
+
var _a2 = zh(data, o, z), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn2 = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off);
|
|
627
|
+
o = no;
|
|
628
|
+
if (!fltr || fltr({
|
|
629
|
+
name: fn2,
|
|
630
|
+
size: sc,
|
|
631
|
+
originalSize: su,
|
|
632
|
+
compression: c_2
|
|
633
|
+
})) {
|
|
634
|
+
if (!c_2)
|
|
635
|
+
files[fn2] = slc(data, b, b + sc);
|
|
636
|
+
else if (c_2 == 8)
|
|
637
|
+
files[fn2] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });
|
|
638
|
+
else
|
|
639
|
+
err(14, "unknown compression type " + c_2);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return files;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// src/extension-embed.js
|
|
646
|
+
var import_fs2 = require("fs");
|
|
647
|
+
var import_path2 = require("path");
|
|
648
|
+
var __pkgRoot = (0, import_path2.join)(__dirname, "..");
|
|
649
|
+
function installExtension(paths, log) {
|
|
650
|
+
log?.("[extension] Installing to Cursor.app/extensions/beatcursor/...");
|
|
651
|
+
const vsixDir = (0, import_path2.join)(__pkgRoot, "vsix");
|
|
652
|
+
const vsixFiles = (0, import_fs2.existsSync)(vsixDir) ? (0, import_fs2.readdirSync)(vsixDir).filter((f) => f.endsWith(".vsix")) : [];
|
|
653
|
+
if (vsixFiles.length === 0) {
|
|
654
|
+
throw new Error('No .vsix file found in vsix/ directory. Run "npm run build" first.');
|
|
655
|
+
}
|
|
656
|
+
const vsixPath = (0, import_path2.join)(vsixDir, vsixFiles[0]);
|
|
657
|
+
const targetDir = paths.beatcursorDir;
|
|
658
|
+
if ((0, import_fs2.existsSync)(targetDir)) {
|
|
659
|
+
(0, import_fs2.rmSync)(targetDir, { recursive: true, force: true });
|
|
660
|
+
}
|
|
661
|
+
(0, import_fs2.mkdirSync)(targetDir, { recursive: true });
|
|
662
|
+
const zipData = new Uint8Array((0, import_fs2.readFileSync)(vsixPath));
|
|
663
|
+
const files = unzipSync(zipData);
|
|
664
|
+
const prefix = "extension/";
|
|
665
|
+
let count = 0;
|
|
666
|
+
for (const [name, data] of Object.entries(files)) {
|
|
667
|
+
if (!name.startsWith(prefix) || name.endsWith("/"))
|
|
668
|
+
continue;
|
|
669
|
+
const relPath = name.slice(prefix.length);
|
|
670
|
+
const destPath = (0, import_path2.join)(targetDir, relPath);
|
|
671
|
+
(0, import_fs2.mkdirSync)((0, import_path2.dirname)(destPath), { recursive: true });
|
|
672
|
+
(0, import_fs2.writeFileSync)(destPath, data);
|
|
673
|
+
count++;
|
|
674
|
+
}
|
|
675
|
+
log?.(` Installed: ${targetDir} (${count} files)`);
|
|
676
|
+
log?.(` From: ${vsixFiles[0]}`);
|
|
677
|
+
}
|
|
678
|
+
function removeExtension(paths, log) {
|
|
679
|
+
if ((0, import_fs2.existsSync)(paths.beatcursorDir)) {
|
|
680
|
+
(0, import_fs2.rmSync)(paths.beatcursorDir, { recursive: true, force: true });
|
|
681
|
+
log?.("[extension] Removed beatcursor from extensions/");
|
|
682
|
+
} else {
|
|
683
|
+
log?.("[extension] Not installed");
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function isExtensionInstalled(paths) {
|
|
687
|
+
return (0, import_fs2.existsSync)((0, import_path2.join)(paths.beatcursorDir, "package.json"));
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// src/backup.js
|
|
691
|
+
var import_fs3 = require("fs");
|
|
692
|
+
var import_path3 = require("path");
|
|
693
|
+
var PREFIX = "backup-byok";
|
|
694
|
+
function backupNamePattern(base2, tag) {
|
|
695
|
+
return `${base2}.${PREFIX}-${tag}-`;
|
|
696
|
+
}
|
|
697
|
+
function listBackups(dir, base2, tag) {
|
|
698
|
+
if (!(0, import_fs3.existsSync)(dir)) return [];
|
|
699
|
+
const prefix = backupNamePattern(base2, tag);
|
|
700
|
+
return (0, import_fs3.readdirSync)(dir).filter((f) => f.startsWith(prefix)).sort();
|
|
701
|
+
}
|
|
702
|
+
function createBackup(filePath, tag, log) {
|
|
703
|
+
const dir = (0, import_path3.dirname)(filePath);
|
|
704
|
+
const base2 = (0, import_path3.basename)(filePath);
|
|
705
|
+
const existing = listBackups(dir, base2, tag);
|
|
706
|
+
if (existing.length > 0) {
|
|
707
|
+
log?.(` Backup exists: ${existing[0]}`);
|
|
708
|
+
return (0, import_path3.join)(dir, existing[0]);
|
|
709
|
+
}
|
|
710
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
711
|
+
const backupPath = `${filePath}.${PREFIX}-${tag}-${ts}`;
|
|
712
|
+
(0, import_fs3.copyFileSync)(filePath, backupPath);
|
|
713
|
+
log?.(` Backup [${tag}]: ${(0, import_path3.basename)(backupPath)}`);
|
|
714
|
+
return backupPath;
|
|
715
|
+
}
|
|
716
|
+
function restoreBackup(filePath, tag, log) {
|
|
717
|
+
const dir = (0, import_path3.dirname)(filePath);
|
|
718
|
+
const base2 = (0, import_path3.basename)(filePath);
|
|
719
|
+
const backups = listBackups(dir, base2, tag);
|
|
720
|
+
if (backups.length === 0) {
|
|
721
|
+
log?.(` No [${tag}] backup for ${base2}`);
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
const primary = backups[0];
|
|
725
|
+
(0, import_fs3.renameSync)((0, import_path3.join)(dir, primary), filePath);
|
|
726
|
+
for (let i = 1; i < backups.length; i++) {
|
|
727
|
+
try {
|
|
728
|
+
(0, import_fs3.unlinkSync)((0, import_path3.join)(dir, backups[i]));
|
|
729
|
+
} catch {
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
log?.(` Restored [${tag}]: ${base2}`);
|
|
733
|
+
return true;
|
|
734
|
+
}
|
|
735
|
+
function hasBackup(filePath, tag) {
|
|
736
|
+
const dir = (0, import_path3.dirname)(filePath);
|
|
737
|
+
const base2 = (0, import_path3.basename)(filePath);
|
|
738
|
+
if (!(0, import_fs3.existsSync)(dir)) return false;
|
|
739
|
+
if (tag) {
|
|
740
|
+
return listBackups(dir, base2, tag).length > 0;
|
|
741
|
+
}
|
|
742
|
+
return (0, import_fs3.readdirSync)(dir).some((f) => f.startsWith(`${base2}.${PREFIX}-`));
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// src/patch-inject.js
|
|
746
|
+
var import_fs6 = require("fs");
|
|
747
|
+
var acorn = __toESM(require("acorn"), 1);
|
|
748
|
+
|
|
749
|
+
// src/checksum.js
|
|
750
|
+
var import_crypto = require("crypto");
|
|
751
|
+
var import_fs4 = require("fs");
|
|
752
|
+
var import_path4 = require("path");
|
|
753
|
+
function computeHash(filePath) {
|
|
754
|
+
return (0, import_crypto.createHash)("sha256").update((0, import_fs4.readFileSync)(filePath)).digest("base64").replace(/=+$/, "");
|
|
755
|
+
}
|
|
756
|
+
function updateChecksums(paths, modifiedFiles, tag, log) {
|
|
757
|
+
const product = JSON.parse((0, import_fs4.readFileSync)(paths.productJson, "utf-8"));
|
|
758
|
+
if (!product.checksums) {
|
|
759
|
+
log?.(" No checksums in product.json");
|
|
760
|
+
return 0;
|
|
761
|
+
}
|
|
762
|
+
let updated = 0;
|
|
763
|
+
for (const file of modifiedFiles) {
|
|
764
|
+
const key = (0, import_path4.relative)((0, import_path4.join)(paths.appRoot, "out"), file).replace(/\\/g, "/");
|
|
765
|
+
if (product.checksums[key]) {
|
|
766
|
+
product.checksums[key] = computeHash(file);
|
|
767
|
+
updated++;
|
|
768
|
+
log?.(` Checksum: ${key}`);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
if (updated > 0) {
|
|
772
|
+
createBackup(paths.productJson, tag, log);
|
|
773
|
+
(0, import_fs4.writeFileSync)(paths.productJson, JSON.stringify(product, null, 2) + "\n");
|
|
774
|
+
}
|
|
775
|
+
return updated;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// src/routes.js
|
|
779
|
+
var import_fs5 = require("fs");
|
|
780
|
+
var import_path5 = require("path");
|
|
781
|
+
var import_os2 = require("os");
|
|
782
|
+
|
|
783
|
+
// src/defaults.js
|
|
784
|
+
var BEATCURSOR_DIR_NAME = ".beatcursor";
|
|
785
|
+
var ROUTES_FILE_NAME = "routes.json";
|
|
786
|
+
var PROVIDERS_FILE_NAME = "providers.json";
|
|
787
|
+
var DEFAULT_HOST = "127.0.0.1";
|
|
788
|
+
var DEFAULT_PORT = 39831;
|
|
789
|
+
var DEFAULT_COLLECTOR_PORT = 14800;
|
|
790
|
+
var BASE_REDIRECT = [
|
|
791
|
+
"REST:/auth/full_stripe_profile",
|
|
792
|
+
"REST:/auth/stripe_profile"
|
|
793
|
+
];
|
|
794
|
+
var BYOK_REDIRECT = [
|
|
795
|
+
// ── BYOK 核心 ──
|
|
796
|
+
"aiserver.v1.AiService/AvailableModels",
|
|
797
|
+
"agent.v1.AgentService/RunSSE",
|
|
798
|
+
"agent.v1.AgentService/UploadConversationBlobs",
|
|
799
|
+
"aiserver.v1.BidiService/BidiAppend",
|
|
800
|
+
// ── 本地摘要持久化(BYOK Agent 配套) ──
|
|
801
|
+
"aiserver.v1.ChatService/GetConversationSummary",
|
|
802
|
+
"aiserver.v1.ChatService/StreamSpeculativeSummaries",
|
|
803
|
+
// ── Rules / Knowledge Base (本地持久化) ──
|
|
804
|
+
"aiserver.v1.AiService/KnowledgeBaseList",
|
|
805
|
+
"aiserver.v1.AiService/KnowledgeBaseAdd",
|
|
806
|
+
"aiserver.v1.AiService/KnowledgeBaseUpdate",
|
|
807
|
+
"aiserver.v1.AiService/KnowledgeBaseRemove",
|
|
808
|
+
// AiService: 模型/配置端点 — BYOK 拦截返回本地配置,不打官方
|
|
809
|
+
"aiserver.v1.AiService/ServerTime",
|
|
810
|
+
"aiserver.v1.AiService/GetDefaultModel",
|
|
811
|
+
"aiserver.v1.AiService/GetDefaultModelNudgeData",
|
|
812
|
+
// ── BYOK 流程下需要 stub 的服务 ──
|
|
813
|
+
"aiserver.v1.AuthService",
|
|
814
|
+
// AnalyticsService: 遥测上报返空; BootstrapStatsig 不拦截(直通官方拿真实 feature gate 配置)
|
|
815
|
+
"aiserver.v1.AnalyticsService/Batch",
|
|
816
|
+
// DashboardService: 逐方法挂入 — 未列出的方法 (如 ListMarketplacePlugins) 直接透传官方 API
|
|
817
|
+
"aiserver.v1.DashboardService/GetPlanInfo",
|
|
818
|
+
"aiserver.v1.DashboardService/GetCurrentPeriodUsage",
|
|
819
|
+
"aiserver.v1.DashboardService/GetTeams",
|
|
820
|
+
"aiserver.v1.DashboardService/GetUserPrivacyMode",
|
|
821
|
+
"aiserver.v1.DashboardService/GetUsageLimitStatusAndActiveGrants",
|
|
822
|
+
"aiserver.v1.DashboardService/GetEffectiveUserPlugins",
|
|
823
|
+
"aiserver.v1.DashboardService/IsOnNewPricing",
|
|
824
|
+
"aiserver.v1.DashboardService/GetManagedSkills",
|
|
825
|
+
"aiserver.v1.DashboardService/GetTeamAdminSettingsOrEmptyIfNotInTeam",
|
|
826
|
+
"aiserver.v1.DashboardService/GetTeamReposOrEmptyIfNotInTeam",
|
|
827
|
+
// 3.6 新增: 不带 OrEmpty 后缀的 Team 端点 (非 team 用户打官方返回 unauthenticated 重试风暴)
|
|
828
|
+
"aiserver.v1.DashboardService/GetTeamAdminSettings",
|
|
829
|
+
"aiserver.v1.DashboardService/GetTeamBackgroundAgentSettings",
|
|
830
|
+
"aiserver.v1.DashboardService/GetTeamRepos",
|
|
831
|
+
// 'aiserver.v1.DashboardService/GetMe',
|
|
832
|
+
"aiserver.v1.DashboardService/GetGlobalCommands",
|
|
833
|
+
"aiserver.v1.DashboardService/GetTeamCommands",
|
|
834
|
+
"aiserver.v1.DashboardService/GetSlackInstallUrl",
|
|
835
|
+
"aiserver.v1.DashboardService/ShareCanvas",
|
|
836
|
+
"aiserver.v1.DashboardService/LookupSharedCanvasByKey",
|
|
837
|
+
"aiserver.v1.ServerConfigService",
|
|
838
|
+
"aiserver.v1.NetworkService",
|
|
839
|
+
"aiserver.v1.HealthService",
|
|
840
|
+
"aiserver.v1.InAppAdService",
|
|
841
|
+
// ── BackgroundComposerService (逐方法 stub — 启动轮询 + UI 初始化) ──
|
|
842
|
+
"aiserver.v1.BackgroundComposerService/ListBackgroundComposers",
|
|
843
|
+
"aiserver.v1.BackgroundComposerService/GetBackgroundComposerUserSettings",
|
|
844
|
+
"aiserver.v1.BackgroundComposerService/ListTeamEnvironments",
|
|
845
|
+
"aiserver.v1.BackgroundComposerService/ListPersonalEnvironments",
|
|
846
|
+
// ── REST endpoints (BYOK 流程下需要的假账号 stub) ──
|
|
847
|
+
"REST:/auth/has_valid_payment_method",
|
|
848
|
+
"REST:/auth/poll",
|
|
849
|
+
"REST:/auth/logout"
|
|
850
|
+
];
|
|
851
|
+
var DEFAULT_REDIRECT = [...BASE_REDIRECT, ...BYOK_REDIRECT];
|
|
852
|
+
var DEFAULT_ROUTES = {
|
|
853
|
+
$schemaVersion: 1,
|
|
854
|
+
byokMode: 1,
|
|
855
|
+
server: { host: DEFAULT_HOST, port: DEFAULT_PORT },
|
|
856
|
+
collector: { host: DEFAULT_HOST, port: DEFAULT_COLLECTOR_PORT },
|
|
857
|
+
redirect: [...BASE_REDIRECT, ...BYOK_REDIRECT]
|
|
858
|
+
};
|
|
859
|
+
var DEFAULT_PROVIDERS = {
|
|
860
|
+
$schemaVersion: 1,
|
|
861
|
+
providers: []
|
|
862
|
+
};
|
|
863
|
+
var MODELS_CATALOG_FILE_NAME = "models-catalog.json";
|
|
864
|
+
var WEB_TOOLS_FILE_NAME = "web-tools.json";
|
|
865
|
+
var DEFAULT_WEB_TOOLS = {
|
|
866
|
+
$schemaVersion: 1,
|
|
867
|
+
search: {
|
|
868
|
+
providers: [
|
|
869
|
+
{ id: "default-ddg", type: "duckduckgo", enabled: true },
|
|
870
|
+
{ id: "default-exa", type: "exa", enabled: false },
|
|
871
|
+
{ id: "default-tavily", type: "tavily", enabled: false },
|
|
872
|
+
{ id: "default-brave", type: "brave", enabled: false },
|
|
873
|
+
{ id: "default-jina", type: "jina", enabled: false },
|
|
874
|
+
{ id: "default-firecrawl", type: "firecrawl", enabled: false }
|
|
875
|
+
],
|
|
876
|
+
parallel: false,
|
|
877
|
+
maxResults: 10
|
|
878
|
+
},
|
|
879
|
+
fetch: {
|
|
880
|
+
provider: "builtin"
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// src/routes.js
|
|
885
|
+
var BEATCURSOR_DIR = (0, import_path5.join)((0, import_os2.homedir)(), BEATCURSOR_DIR_NAME);
|
|
886
|
+
var ROUTES_PATH = (0, import_path5.join)(BEATCURSOR_DIR, ROUTES_FILE_NAME);
|
|
887
|
+
function loadRoutes() {
|
|
888
|
+
if (!(0, import_fs5.existsSync)(ROUTES_PATH)) return cloneDefaults();
|
|
889
|
+
try {
|
|
890
|
+
const parsed = JSON.parse((0, import_fs5.readFileSync)(ROUTES_PATH, "utf-8"));
|
|
891
|
+
return mergeWithDefaults(parsed);
|
|
892
|
+
} catch {
|
|
893
|
+
return cloneDefaults();
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function cloneDefaults() {
|
|
897
|
+
return JSON.parse(JSON.stringify(DEFAULT_ROUTES));
|
|
898
|
+
}
|
|
899
|
+
function mergeWithDefaults(loaded) {
|
|
900
|
+
const fallback = cloneDefaults();
|
|
901
|
+
if (!loaded || typeof loaded !== "object") return fallback;
|
|
902
|
+
return {
|
|
903
|
+
$schemaVersion: loaded.$schemaVersion ?? fallback.$schemaVersion,
|
|
904
|
+
server: {
|
|
905
|
+
host: loaded.server?.host ?? fallback.server.host,
|
|
906
|
+
port: loaded.server?.port ?? fallback.server.port
|
|
907
|
+
},
|
|
908
|
+
collector: {
|
|
909
|
+
host: loaded.collector?.host ?? fallback.collector.host,
|
|
910
|
+
port: loaded.collector?.port ?? fallback.collector.port
|
|
911
|
+
},
|
|
912
|
+
redirect: Array.isArray(loaded.redirect) && loaded.redirect.length > 0 ? loaded.redirect.slice() : fallback.redirect
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// src/patch-inject.js
|
|
917
|
+
var HOOK_MARKER = "__byokWrapTransport";
|
|
918
|
+
var HOOK_SOURCE_MARKER = "CURSOR-BYOK-HOOK-START";
|
|
919
|
+
var HOOK_CALL_SITE = `typeof globalThis.${HOOK_MARKER}==="function"?globalThis.${HOOK_MARKER}(`;
|
|
920
|
+
function isInjectPatched(code) {
|
|
921
|
+
return code.slice(0, 12e4).includes(`/* ${HOOK_SOURCE_MARKER} */`) && code.includes(HOOK_CALL_SITE);
|
|
922
|
+
}
|
|
923
|
+
var ANCHORS = [
|
|
924
|
+
"callback-client.js",
|
|
925
|
+
"promise-client.js"
|
|
926
|
+
];
|
|
927
|
+
var SCAN_WINDOW = 2e3;
|
|
928
|
+
function skipString(source, i) {
|
|
929
|
+
const quote = source[i];
|
|
930
|
+
i++;
|
|
931
|
+
while (i < source.length) {
|
|
932
|
+
const ch = source[i];
|
|
933
|
+
if (ch === "\\") {
|
|
934
|
+
i += 2;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
if (ch === quote) return i + 1;
|
|
938
|
+
if (quote === "`" && ch === "$" && source[i + 1] === "{") {
|
|
939
|
+
i += 2;
|
|
940
|
+
let depth = 1;
|
|
941
|
+
while (i < source.length && depth > 0) {
|
|
942
|
+
const c = source[i];
|
|
943
|
+
if (c === "{") depth++;
|
|
944
|
+
else if (c === "}") depth--;
|
|
945
|
+
else if (c === '"' || c === "'" || c === "`") {
|
|
946
|
+
i = skipString(source, i);
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
i++;
|
|
950
|
+
}
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
i++;
|
|
954
|
+
}
|
|
955
|
+
return i;
|
|
956
|
+
}
|
|
957
|
+
function extractFunction(source, startOffset) {
|
|
958
|
+
let i = startOffset;
|
|
959
|
+
const len = source.length;
|
|
960
|
+
while (i < len && source[i] !== "(") i++;
|
|
961
|
+
if (i >= len) return null;
|
|
962
|
+
let parenDepth = 0;
|
|
963
|
+
while (i < len) {
|
|
964
|
+
const ch = source[i];
|
|
965
|
+
if (ch === "(") parenDepth++;
|
|
966
|
+
else if (ch === ")") {
|
|
967
|
+
parenDepth--;
|
|
968
|
+
if (parenDepth === 0) {
|
|
969
|
+
i++;
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
} else if (ch === '"' || ch === "'" || ch === "`") {
|
|
973
|
+
i = skipString(source, i);
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
i++;
|
|
977
|
+
}
|
|
978
|
+
while (i < len && source[i] !== "{") i++;
|
|
979
|
+
if (i >= len) return null;
|
|
980
|
+
let braceDepth = 0;
|
|
981
|
+
while (i < len) {
|
|
982
|
+
const ch = source[i];
|
|
983
|
+
if (ch === "{") braceDepth++;
|
|
984
|
+
else if (ch === "}") {
|
|
985
|
+
braceDepth--;
|
|
986
|
+
if (braceDepth === 0) return { start: startOffset, end: i + 1 };
|
|
987
|
+
} else if (ch === '"' || ch === "'" || ch === "`") {
|
|
988
|
+
i = skipString(source, i);
|
|
989
|
+
continue;
|
|
990
|
+
} else if (ch === "/" && i + 1 < len) {
|
|
991
|
+
if (source[i + 1] === "/") {
|
|
992
|
+
while (i < len && source[i] !== "\n") i++;
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
if (source[i + 1] === "*") {
|
|
996
|
+
i += 2;
|
|
997
|
+
while (i + 1 < len && !(source[i] === "*" && source[i + 1] === "/")) i++;
|
|
998
|
+
i += 2;
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
i++;
|
|
1003
|
+
}
|
|
1004
|
+
return null;
|
|
1005
|
+
}
|
|
1006
|
+
function findFunctionStarts(source, from, windowSize) {
|
|
1007
|
+
const results = [];
|
|
1008
|
+
const end = Math.min(from + windowSize, source.length);
|
|
1009
|
+
let i = from;
|
|
1010
|
+
while (i < end) {
|
|
1011
|
+
const idx = source.indexOf("function ", i);
|
|
1012
|
+
if (idx === -1 || idx >= end) break;
|
|
1013
|
+
if (idx > 0 && /[\w$]/.test(source[idx - 1])) {
|
|
1014
|
+
i = idx + 9;
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
results.push(idx);
|
|
1018
|
+
i = idx + 9;
|
|
1019
|
+
}
|
|
1020
|
+
return results;
|
|
1021
|
+
}
|
|
1022
|
+
function buildHookPayload(hasGlass) {
|
|
1023
|
+
const routes = loadRoutes();
|
|
1024
|
+
const BYOK_HOST = routes.server.host;
|
|
1025
|
+
const BYOK_PORT = routes.server.port;
|
|
1026
|
+
const COLLECTOR_HOST = routes.collector.host;
|
|
1027
|
+
const COLLECTOR_PORT = routes.collector.port;
|
|
1028
|
+
const restRedirects = BASE_REDIRECT.filter((r) => r.startsWith("REST:")).map((r) => r.slice(5));
|
|
1029
|
+
const restListJson = JSON.stringify(restRedirects);
|
|
1030
|
+
const main = `(function(){if(globalThis.__byokReady)return;globalThis.__byokReady=true;var _hasGlass=${hasGlass ? "true" : "false"};var _q=globalThis.__byokQueue=[];var _collectorUrl="http://${COLLECTOR_HOST}:${COLLECTOR_PORT}";var _byokUrl="http://${BYOK_HOST}:${BYOK_PORT}";var _sending=false;var _down=false;var _restPaths=${restListJson};var _restSet=new Set(_restPaths);function __byokLog(e){if(_down)return;e._t=Date.now();_q.push(e);if(!_sending)_flush()}function _flush(){if(_down||!_q.length){_sending=false;return}_sending=true;var batch=_q.splice(0,50);fetch(_collectorUrl+"/hook",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(batch)}).then(function(){}).catch(function(){_down=true;_q.length=0;console.warn("[BYOK] Collector not reachable at "+_collectorUrl+", logging disabled for this session")}).finally(function(){if(!_down)setTimeout(_flush,100);else _sending=false})}function __byokMsgToJson(e){if(!e)return null;try{if(typeof e.toJson==="function")return e.toJson()}catch(x){}try{if(typeof e.toJsonString==="function")return JSON.parse(e.toJsonString())}catch(x){}return e}function __byokHeadersToObj(e){if(!e)return{};try{if(e instanceof Headers)return Object.fromEntries(e)}catch(x){}return typeof e==="object"?e:{}}function __byokCloneBody(r){if(!r.body)return Promise.resolve(null);try{return r.clone().text()}catch(e){return Promise.resolve(null)}}function __byokInjectWid(hdrs){var wid=typeof window!=="undefined"&&window.vscodeWindowId;if(typeof wid!=="number")return hdrs;var widStr=String(wid);try{if(hdrs&&typeof hdrs.set==="function"){hdrs.set("x-client-wid",widStr);return hdrs}if(hdrs&&typeof hdrs==="object"&&!Array.isArray(hdrs)){hdrs["x-client-wid"]=widStr;return hdrs}if(Array.isArray(hdrs)){hdrs.push(["x-client-wid",widStr]);return hdrs}}catch(e){}var h=new Headers();h.set("x-client-wid",widStr);return h}globalThis.__byokWrapTransport=function(t,n){return{unary:async function(e,r,i,o,s,a,c){s=__byokInjectWid(s);var u=Math.random().toString(36).slice(2,10),l=Date.now();__byokLog({type:"unary_req",id:u,svc:e.typeName,mtd:r.name,hdr:__byokHeadersToObj(s),msg:__byokMsgToJson(a)});try{var d=await t.unary(e,r,i,o,s,a,c);__byokLog({type:"unary_res",id:u,dur:Date.now()-l,svc:e.typeName,mtd:r.name,msg:__byokMsgToJson(d.message)});return d}catch(d){__byokLog({type:"unary_err",id:u,dur:Date.now()-l,svc:e.typeName,mtd:r.name,err:d?.message||String(d),code:d?.code});throw d}},stream:async function(e,r,i,o,s,a,c){s=__byokInjectWid(s);var u=Math.random().toString(36).slice(2,10),l=Date.now();__byokLog({type:"stream_req",id:u,svc:e.typeName,mtd:r.name,hdr:__byokHeadersToObj(s)});var f=(async function*(){var t=0;for await(var n of a){__byokLog({type:"stream_in",id:u,svc:e.typeName,mtd:r.name,idx:t++,msg:__byokMsgToJson(n)});yield n}})();try{var d=await t.stream(e,r,i,o,s,f,c),h=d.message;d.message=(async function*(){var t=0;for await(var n of h){__byokLog({type:"stream_out",id:u,svc:e.typeName,mtd:r.name,idx:t++,msg:__byokMsgToJson(n)});yield n}__byokLog({type:"stream_end",id:u,dur:Date.now()-l,svc:e.typeName,mtd:r.name,chunks:t})})();return d}catch(d){__byokLog({type:"stream_err",id:u,dur:Date.now()-l,svc:e.typeName,mtd:r.name,err:d?.message||String(d),code:d?.code});throw d}}}};if(_restPaths.length>0){var _origFetch=globalThis.fetch;globalThis.fetch=function(){var args=Array.prototype.slice.call(arguments);var urlArg=args[0];var u=typeof urlArg==="string"?urlArg:(urlArg instanceof Request?urlArg.url:"");var init=args[1]||{};for(var i=0;i<_restPaths.length;i++){if(u.indexOf(_restPaths[i])!==-1){var id=Math.random().toString(36).slice(2,10);var ts=Date.now();var reqMethod=init.method||(urlArg instanceof Request?urlArg.method:"GET")||"GET";var reqHeaders=__byokHeadersToObj(urlArg instanceof Request?urlArg.headers:init.headers);var reqBody=urlArg instanceof Request&&urlArg.body?urlArg.body:(init.body||null);var path=_restPaths[i];var newUrl=_byokUrl+(u.match(/^https?:\\/\\/[^/]*/)?u.replace(/^https?:\\/\\/[^/]*/,""):"/");__byokLog({type:"rest_redirect",id:id,path:path,originalUrl:u,redirectUrl:newUrl,method:reqMethod,reqHeaders:reqHeaders,reqBody:reqBody});var newInit=Object.assign({},init);newInit.headers=__byokInjectWid(newInit.headers);var newArgs=[newUrl,newInit];for(var j=2;j<args.length;j++)newArgs.push(args[j]);return _origFetch.apply(globalThis,newArgs).then(function(resp){var r=resp.clone();__byokLog({type:"rest_response",id:id,path:path,status:r.status,resHeaders:__byokHeadersToObj(r.headers)});__byokCloneBody(r).then(function(text){if(text){__byokLog({type:"rest_body",id:id,path:path,body:text})}}).catch(function(){});return resp}).catch(function(err){__byokLog({type:"rest_error",id:id,path:path,error:err?.message||String(err)});throw err})}}if(u.indexOf(_byokUrl)===0){var nInit=Object.assign({},init);nInit.headers=__byokInjectWid(nInit.headers);var nArgs=[urlArg,nInit];for(var k=2;k<args.length;k++)nArgs.push(args[k]);return _origFetch.apply(globalThis,nArgs)}return _origFetch.apply(globalThis,arguments)}}`;
|
|
1031
|
+
const pickerRefresh = `(function(){if(!document.body)return;var _prObs=new MutationObserver(function(){var inp=document.querySelector('input[placeholder="Search models"]');if(!inp)return;var wrap=inp.closest(".ui-input-group");if(!wrap||wrap.querySelector("#byok-refresh-btn"))return;var btn=document.createElement("button");btn.type="button";btn.id="byok-refresh-btn";var _rDonor=_hasGlass?document.querySelector("button.ui-icon-button"):null;btn.className=_rDonor?_rDonor.className:"ui-icon-button";btn.dataset.variant="default";btn.dataset.size="sm";btn.setAttribute("aria-label","Refresh Models");btn.style.cssText="margin-right:4px;flex-shrink:0;cursor:pointer;";btn.textContent="\\u21BB";btn.addEventListener("click",function(ev){ev.stopPropagation();globalThis.__byokRefreshModels&&globalThis.__byokRefreshModels();console.log("[BYOK] manual refresh from picker")});wrap.appendChild(btn)});_prObs.observe(document.body,{childList:true,subtree:true})})();`;
|
|
1032
|
+
const glassStatus = `(function(){var _bEl=null,_bTip=null,_bSrv=false,_bMode=false;function _bCreate(){var e=document.createElement("button");e.type="button";e.className="ui-icon-button";e.dataset.variant="default";e.dataset.size="lg";e.id="byok-glass-status";if(_hasGlass){var donor=document.querySelector("button.ui-icon-button");if(donor){e.className=donor.className}else{e.className="ui-icon-button"}e.style.cssText="width:auto;min-width:auto;font-size:10px;gap:2px;white-space:nowrap;"}else{e.className="ui-icon-button";e.dataset.variant="default";e.dataset.size="lg";e.style.cssText="font-size:11px;gap:3px;width:auto;white-space:nowrap;"}e.addEventListener("click",function(){fetch(_byokUrl+"/byok/toggle",{method:"POST"}).then(function(r){return r.json()}).then(function(d){console.log("[BYOK] toggle \\u2192",d.byokMode?"ON":"OFF")}).catch(function(e){console.warn("[BYOK] toggle failed:",e&&e.message||e)})});e.addEventListener("mouseenter",function(){_bShowTip()});e.addEventListener("mouseleave",function(){_bHideTip()});return e}function _bShowTip(){if(_bTip||!_bEl)return;var t=document.createElement("div");t.className="ui-tooltip";t.setAttribute("role","tooltip");t.style.cssText="position:fixed;z-index:99999;pointer-events:none;box-sizing:border-box;width:max-content;max-width:320px;background:var(--cursor-bg-elevated);color:var(--cursor-text-primary);border:var(--ui-tooltip-border-width,1px) solid var(--cursor-stroke-primary);border-radius:var(--ui-tooltip-border-radius,var(--cursor-radius-lg));box-shadow:var(--ui-tooltip-box-shadow,var(--cursor-box-shadow-popup));padding:var(--ui-tooltip-padding-y,var(--cursor-spacing-1-5)) var(--ui-tooltip-padding-x,var(--cursor-spacing-2-5));font-size:var(--ui-tooltip-font-size,var(--cursor-font-size-base));line-height:var(--ui-tooltip-line-height,var(--cursor-line-height-base));letter-spacing:var(--ui-tooltip-letter-spacing,var(--cursor-letter-spacing-base));white-space:pre-line;";t.textContent=(_bSrv?"Server online":"Server offline")+" \\u00B7 "+(_bMode?"BYOK ON":"BYOK OFF");document.body.appendChild(t);var r=_bEl.getBoundingClientRect();var tw=t.offsetWidth,th=t.offsetHeight;t.style.left=Math.round(r.left+r.width/2-tw/2)+"px";t.style.top=Math.round(r.top-th-6)+"px";_bTip=t}function _bHideTip(){if(_bTip){_bTip.remove();_bTip=null}}function _bRender(){if(!_bEl)return;var icon=_bSrv?"\\u2713":"\\u2717";var glyph=_bMode?"\\u25C9":"\\u25CB";_bEl.textContent=icon+" BYOK "+glyph}function _bInject(){if(_bEl&&document.contains(_bEl))return;var footer=document.querySelector('[data-component="glass-sidebar-footer"]');if(footer){var gear=footer.querySelector("button.ui-icon-button");if(gear&&gear.parentElement){_bEl=_bCreate();_bRender();gear.parentElement.insertBefore(_bEl,gear);return}}var trigger=document.querySelector(".glass-sidebar-footer-account-trigger");var endIcon=trigger&&trigger.querySelector(".ui-sidebar-menu-button-end");if(trigger&&endIcon){_bEl=_bCreate();_bRender();trigger.insertBefore(_bEl,endIcon);return}var actOld=document.querySelector(".glass-sidebar-footer-actions-right");if(actOld){_bEl=_bCreate();_bRender();actOld.insertBefore(_bEl,actOld.firstChild)}}if(document.body){var _bObs=new MutationObserver(function(){_bInject()});_bObs.observe(document.body,{childList:true,subtree:true});_bInject()}globalThis.__byokGlassStatus=function(srv,mode){if(srv!==void 0)_bSrv=srv;if(mode!==void 0)_bMode=mode;_bRender()}})();`;
|
|
1033
|
+
const refreshLogic = `globalThis.__byokRefreshModels=function(){if(globalThis.__byokAiSvc&&typeof globalThis.__byokAiSvc.refreshDefaultModels==="function"){try{var p=globalThis.__byokAiSvc.refreshDefaultModels();console.log("[BYOK] refreshDefaultModels() invoked via captured aiService ref");if(p&&typeof p.then==="function")p.catch(function(e){console.warn("[BYOK] refreshDefaultModels failed:",e&&e.message||e)});return"service"}catch(e){console.warn("[BYOK] refreshDefaultModels threw:",e&&e.message||e)}}var btn=document.querySelector('[title="Refresh model list"]');if(btn&&typeof btn.click==="function"){btn.click();console.log("[BYOK] refresh triggered via DOM click fallback");return"click"}console.warn("[BYOK] no refresh mechanism available (aiService not captured, picker not visible)");return"none"};try{var _byokEs=new EventSource(_byokUrl+"/byok/events");_byokEs.addEventListener("open",function(){globalThis.__byokGlassStatus&&globalThis.__byokGlassStatus(true,_restPaths.length>2)});_byokEs.addEventListener("refresh",function(){console.log("[BYOK] refresh event received");globalThis.__byokRefreshModels&&globalThis.__byokRefreshModels()});_byokEs.addEventListener("routes",function(ev){try{var newPaths=JSON.parse(ev.data);_restPaths=newPaths;_restSet=new Set(newPaths);console.log("[BYOK] REST redirects hot-reloaded: "+newPaths.length+" paths");globalThis.__byokGlassStatus&&globalThis.__byokGlassStatus(void 0,newPaths.length>2)}catch(e){console.warn("[BYOK] routes event parse failed:",e&&e.message||e)}});_byokEs.addEventListener("error",function(){globalThis.__byokGlassStatus&&globalThis.__byokGlassStatus(false,void 0)})}catch(e){console.warn("[BYOK] EventSource init failed:",e&&e.message||e)}`;
|
|
1034
|
+
return main + refreshLogic + pickerRefresh + glassStatus + `console.log("[BYOK] Hook loaded, collector="+_collectorUrl+", byok="+_byokUrl+", REST redirects="+_restPaths.length)})()`;
|
|
1035
|
+
}
|
|
1036
|
+
function findTarget(code, log) {
|
|
1037
|
+
let anchorOffset = -1;
|
|
1038
|
+
for (const anchor of ANCHORS) {
|
|
1039
|
+
const idx = code.indexOf(anchor);
|
|
1040
|
+
if (idx !== -1) {
|
|
1041
|
+
anchorOffset = idx;
|
|
1042
|
+
log?.(` Anchor: "${anchor}" at ${idx}`);
|
|
1043
|
+
break;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
if (anchorOffset === -1) throw new Error("ConnectRPC client module anchor not found");
|
|
1047
|
+
const funcStarts = findFunctionStarts(code, anchorOffset, SCAN_WINDOW);
|
|
1048
|
+
let dispatcherName = null, dispatcherBounds = null;
|
|
1049
|
+
for (const fStart of funcStarts) {
|
|
1050
|
+
const bounds = extractFunction(code, fStart);
|
|
1051
|
+
if (!bounds) continue;
|
|
1052
|
+
const body = code.slice(bounds.start, bounds.end);
|
|
1053
|
+
if (body.includes(".Unary") && body.includes(".ServerStreaming") && body.includes(".BiDiStreaming")) {
|
|
1054
|
+
let ast;
|
|
1055
|
+
try {
|
|
1056
|
+
ast = acorn.parse(body, { ecmaVersion: 2022, sourceType: "script" });
|
|
1057
|
+
} catch {
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1060
|
+
const decl = ast.body[0];
|
|
1061
|
+
if (decl?.type === "FunctionDeclaration" && decl.id?.name) {
|
|
1062
|
+
dispatcherName = decl.id.name;
|
|
1063
|
+
dispatcherBounds = bounds;
|
|
1064
|
+
log?.(` Dispatcher: ${dispatcherName}`);
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
if (!dispatcherName) throw new Error("Dispatcher function not found");
|
|
1070
|
+
const postStarts = findFunctionStarts(code, dispatcherBounds.end, SCAN_WINDOW);
|
|
1071
|
+
for (const fStart of postStarts) {
|
|
1072
|
+
const bounds = extractFunction(code, fStart);
|
|
1073
|
+
if (!bounds) continue;
|
|
1074
|
+
const body = code.slice(bounds.start, bounds.end);
|
|
1075
|
+
if (!body.includes(dispatcherName)) continue;
|
|
1076
|
+
let ast;
|
|
1077
|
+
try {
|
|
1078
|
+
ast = acorn.parse(body, { ecmaVersion: 2022, sourceType: "script" });
|
|
1079
|
+
} catch {
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
const decl = ast.body[0];
|
|
1083
|
+
if (!decl || decl.type !== "FunctionDeclaration") continue;
|
|
1084
|
+
if (decl.params?.length !== 2) continue;
|
|
1085
|
+
if (decl.params.some((p) => p.type !== "Identifier")) continue;
|
|
1086
|
+
const p0 = decl.params[0].name, p1 = decl.params[1].name;
|
|
1087
|
+
const stmts = decl.body?.body;
|
|
1088
|
+
if (!stmts || stmts.length !== 1 || stmts[0].type !== "ReturnStatement") continue;
|
|
1089
|
+
const ret = stmts[0].argument;
|
|
1090
|
+
if (!ret || ret.type !== "CallExpression") continue;
|
|
1091
|
+
if (ret.callee?.type !== "Identifier" || ret.callee.name !== dispatcherName) continue;
|
|
1092
|
+
if (ret.arguments?.length !== 2) continue;
|
|
1093
|
+
if (ret.arguments[0].name !== p0 || ret.arguments[1].name !== p1) continue;
|
|
1094
|
+
return { name: decl.id.name, bounds, source: body, paramService: p0, paramTransport: p1, innerFn: dispatcherName };
|
|
1095
|
+
}
|
|
1096
|
+
throw new Error(`No delegate wrapper found for "${dispatcherName}"`);
|
|
1097
|
+
}
|
|
1098
|
+
function captureAiServiceRef(code, log) {
|
|
1099
|
+
const NEEDLE = ".aiService.refreshDefaultModels(";
|
|
1100
|
+
const replacements = [];
|
|
1101
|
+
let scanFrom = 0;
|
|
1102
|
+
let candidateCount = 0;
|
|
1103
|
+
while (true) {
|
|
1104
|
+
const dotIdx = code.indexOf(NEEDLE, scanFrom);
|
|
1105
|
+
if (dotIdx === -1) break;
|
|
1106
|
+
candidateCount++;
|
|
1107
|
+
scanFrom = dotIdx + NEEDLE.length;
|
|
1108
|
+
let i = dotIdx - 1;
|
|
1109
|
+
while (i >= 0 && /[a-zA-Z0-9_$]/.test(code[i])) i--;
|
|
1110
|
+
const xStart = i + 1;
|
|
1111
|
+
if (xStart === dotIdx) continue;
|
|
1112
|
+
let ast;
|
|
1113
|
+
try {
|
|
1114
|
+
ast = acorn.parseExpressionAt(code, xStart, { ecmaVersion: 2022, sourceType: "module" });
|
|
1115
|
+
} catch {
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
if (ast.type === "SequenceExpression") ast = ast.expressions[0];
|
|
1119
|
+
if (ast?.type !== "CallExpression") continue;
|
|
1120
|
+
const c = ast.callee;
|
|
1121
|
+
if (c?.type !== "MemberExpression") continue;
|
|
1122
|
+
if (c.property?.type !== "Identifier" || c.property.name !== "refreshDefaultModels") continue;
|
|
1123
|
+
if (c.object?.type !== "MemberExpression") continue;
|
|
1124
|
+
if (c.object.property?.type !== "Identifier" || c.object.property.name !== "aiService") continue;
|
|
1125
|
+
const inner = c.object.object;
|
|
1126
|
+
if (inner.type !== "Identifier" && inner.type !== "ThisExpression") continue;
|
|
1127
|
+
const xText = code.slice(inner.start, inner.end);
|
|
1128
|
+
replacements.push({
|
|
1129
|
+
start: inner.start,
|
|
1130
|
+
end: c.object.end,
|
|
1131
|
+
text: `(globalThis.__byokAiSvc=${xText}.aiService)`
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
replacements.sort((a, b) => b.start - a.start);
|
|
1135
|
+
let result = code;
|
|
1136
|
+
for (const r of replacements) {
|
|
1137
|
+
result = result.slice(0, r.start) + r.text + result.slice(r.end);
|
|
1138
|
+
}
|
|
1139
|
+
log?.(` aiService ref capture: ${replacements.length}/${candidateCount} call sites (AST validated)`);
|
|
1140
|
+
return result;
|
|
1141
|
+
}
|
|
1142
|
+
function patchMaxModeToggle(code, log) {
|
|
1143
|
+
const BODY_ANCHOR = '"MAX Mode"';
|
|
1144
|
+
const anchorIdx = code.indexOf(BODY_ANCHOR);
|
|
1145
|
+
if (anchorIdx === -1) {
|
|
1146
|
+
log?.(' [max-mode-toggle] anchor "MAX Mode" not found \u2014 skipping');
|
|
1147
|
+
return code;
|
|
1148
|
+
}
|
|
1149
|
+
const funcStarts = findFunctionStarts(code, Math.max(0, anchorIdx - 3e3), 3e3);
|
|
1150
|
+
let targetFn = null;
|
|
1151
|
+
for (const fStart of funcStarts) {
|
|
1152
|
+
const bounds = extractFunction(code, fStart);
|
|
1153
|
+
if (!bounds || bounds.end < anchorIdx) continue;
|
|
1154
|
+
if (bounds.start > anchorIdx) break;
|
|
1155
|
+
const body = code.slice(bounds.start, bounds.end);
|
|
1156
|
+
if (body.includes(BODY_ANCHOR) && body.includes("setMaxMode")) {
|
|
1157
|
+
targetFn = bounds;
|
|
1158
|
+
break;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
if (!targetFn) {
|
|
1162
|
+
log?.(" [max-mode-toggle] MaxModeToggle function not found \u2014 skipping");
|
|
1163
|
+
return code;
|
|
1164
|
+
}
|
|
1165
|
+
const fnSource = code.slice(targetFn.start, targetFn.end);
|
|
1166
|
+
let ast;
|
|
1167
|
+
try {
|
|
1168
|
+
ast = acorn.parse(fnSource, { ecmaVersion: 2022, sourceType: "script" });
|
|
1169
|
+
} catch (e) {
|
|
1170
|
+
log?.(` [max-mode-toggle] AST parse failed: ${e.message} \u2014 skipping`);
|
|
1171
|
+
return code;
|
|
1172
|
+
}
|
|
1173
|
+
const fnDecl = ast.body[0];
|
|
1174
|
+
if (!fnDecl || fnDecl.type !== "FunctionDeclaration" || !fnDecl.id?.name) {
|
|
1175
|
+
log?.(" [max-mode-toggle] unexpected AST shape \u2014 skipping");
|
|
1176
|
+
return code;
|
|
1177
|
+
}
|
|
1178
|
+
let contextHookName = null;
|
|
1179
|
+
function walkForContextHook(node) {
|
|
1180
|
+
if (!node || typeof node !== "object") return;
|
|
1181
|
+
if (node.type === "VariableDeclarator" && node.id?.type === "ObjectPattern" && node.init?.type === "CallExpression") {
|
|
1182
|
+
const hasSetMaxMode = node.id.properties?.some((p) => p.key?.name === "setMaxMode");
|
|
1183
|
+
if (hasSetMaxMode && node.init.callee?.type === "Identifier") {
|
|
1184
|
+
contextHookName = node.init.callee.name;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
for (const key of Object.keys(node)) {
|
|
1188
|
+
if (contextHookName) return;
|
|
1189
|
+
const child = node[key];
|
|
1190
|
+
if (Array.isArray(child)) child.forEach((c) => {
|
|
1191
|
+
if (c && c.type) walkForContextHook(c);
|
|
1192
|
+
});
|
|
1193
|
+
else if (child && child.type) walkForContextHook(child);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
walkForContextHook(fnDecl);
|
|
1197
|
+
if (!contextHookName) {
|
|
1198
|
+
log?.(" [max-mode-toggle] context hook (setMaxMode destructor) not found via AST \u2014 skipping");
|
|
1199
|
+
return code;
|
|
1200
|
+
}
|
|
1201
|
+
const bodyStart = targetFn.start + fnDecl.body.start + 1;
|
|
1202
|
+
const guard = `const{models:_ms}=${contextHookName}();if(!_ms.some(_m=>_m.name!=="default"&&_m.supportsMaxMode))return null;`;
|
|
1203
|
+
const result = code.slice(0, bodyStart) + guard + code.slice(bodyStart);
|
|
1204
|
+
log?.(` [max-mode-toggle] injected guard into ${fnDecl.id.name}() via ${contextHookName}(): return null when no model supports Max Mode`);
|
|
1205
|
+
return result;
|
|
1206
|
+
}
|
|
1207
|
+
var EXTENSION_ID = "beatcursor.beatcursor";
|
|
1208
|
+
function patchKatexMathSvgSanitizer(code, log) {
|
|
1209
|
+
const requiredTags = ["math", "semantics", "mrow", "mi", "mo", "mn", "mtext", "mfrac", "msqrt", "mroot", "annotation"];
|
|
1210
|
+
const svgTags = ["svg", "path", "line"];
|
|
1211
|
+
const svgAttrs = ["xmlns", "width", "height", "viewBox", "viewbox", "preserveAspectRatio", "preserveaspectratio"];
|
|
1212
|
+
const lineAttrs = ["x1", "y1", "x2", "y2", "stroke-width", "strokeWidth"];
|
|
1213
|
+
function literalString(node) {
|
|
1214
|
+
return node && node.type === "Literal" && typeof node.value === "string" ? node.value : void 0;
|
|
1215
|
+
}
|
|
1216
|
+
function propertyName(prop) {
|
|
1217
|
+
if (!prop || prop.type !== "Property" || prop.computed) return void 0;
|
|
1218
|
+
if (prop.key.type === "Identifier") return prop.key.name;
|
|
1219
|
+
return literalString(prop.key);
|
|
1220
|
+
}
|
|
1221
|
+
function arrayStrings(node) {
|
|
1222
|
+
if (!node || node.type !== "ArrayExpression") return void 0;
|
|
1223
|
+
const values = [];
|
|
1224
|
+
for (let i = 0; i < node.elements.length; i++) {
|
|
1225
|
+
const value = literalString(node.elements[i]);
|
|
1226
|
+
if (value === void 0) return void 0;
|
|
1227
|
+
values.push(value);
|
|
1228
|
+
}
|
|
1229
|
+
return values;
|
|
1230
|
+
}
|
|
1231
|
+
function firstExpr(expr) {
|
|
1232
|
+
return expr && expr.type === "SequenceExpression" ? expr.expressions[0] : expr;
|
|
1233
|
+
}
|
|
1234
|
+
function containsAll(values, required) {
|
|
1235
|
+
for (let i = 0; i < required.length; i++) {
|
|
1236
|
+
if (!values.includes(required[i])) return false;
|
|
1237
|
+
}
|
|
1238
|
+
return true;
|
|
1239
|
+
}
|
|
1240
|
+
function tagAssignmentValues(expr) {
|
|
1241
|
+
const candidate = firstExpr(expr);
|
|
1242
|
+
if (!candidate || candidate.type !== "AssignmentExpression" || candidate.operator !== "=") return void 0;
|
|
1243
|
+
if (!candidate.left || candidate.left.type !== "Identifier") return void 0;
|
|
1244
|
+
const values = arrayStrings(candidate.right);
|
|
1245
|
+
if (!values || !containsAll(values, requiredTags)) return void 0;
|
|
1246
|
+
return { assignment: candidate, values };
|
|
1247
|
+
}
|
|
1248
|
+
function attributeSchemaInfo(node) {
|
|
1249
|
+
if (!node || node.type !== "ObjectExpression") return void 0;
|
|
1250
|
+
const props = /* @__PURE__ */ Object.create(null);
|
|
1251
|
+
for (let i = 0; i < node.properties.length; i++) {
|
|
1252
|
+
const prop = node.properties[i];
|
|
1253
|
+
const key = propertyName(prop);
|
|
1254
|
+
if (key) props[key] = prop.value;
|
|
1255
|
+
}
|
|
1256
|
+
const requiredKeys = ["math", "semantics", "annotation", "mfrac", "msqrt", "mroot", "mtd"];
|
|
1257
|
+
for (let i = 0; i < requiredKeys.length; i++) {
|
|
1258
|
+
if (!props[requiredKeys[i]]) return void 0;
|
|
1259
|
+
}
|
|
1260
|
+
const mathAttrs = arrayStrings(props.math) || [];
|
|
1261
|
+
const mtdAttrs = arrayStrings(props.mtd) || [];
|
|
1262
|
+
const mfracAttrs = arrayStrings(props.mfrac) || [];
|
|
1263
|
+
if (!mathAttrs.includes("xmlns") || !mathAttrs.includes("display")) return void 0;
|
|
1264
|
+
if (!mtdAttrs.includes("columnalign")) return void 0;
|
|
1265
|
+
if (!mfracAttrs.includes("linethickness")) return void 0;
|
|
1266
|
+
return { node, props };
|
|
1267
|
+
}
|
|
1268
|
+
function svgPropertySource(key) {
|
|
1269
|
+
if (key === "svg") return `svg:${JSON.stringify(svgAttrs)}`;
|
|
1270
|
+
if (key === "path") return 'path:["d"]';
|
|
1271
|
+
if (key === "line") return `line:${JSON.stringify(lineAttrs)}`;
|
|
1272
|
+
throw new Error(`unknown KaTeX SVG sanitizer property: ${key}`);
|
|
1273
|
+
}
|
|
1274
|
+
function assignmentStartBeforeArray(arrayStart) {
|
|
1275
|
+
let i = arrayStart - 1;
|
|
1276
|
+
while (i >= 0 && /\s/.test(code[i])) i--;
|
|
1277
|
+
if (code[i] !== "=") return -1;
|
|
1278
|
+
i--;
|
|
1279
|
+
while (i >= 0 && /\s/.test(code[i])) i--;
|
|
1280
|
+
const end = i + 1;
|
|
1281
|
+
while (i >= 0 && /[a-zA-Z0-9_$]/.test(code[i])) i--;
|
|
1282
|
+
const start = i + 1;
|
|
1283
|
+
return start === end ? -1 : start;
|
|
1284
|
+
}
|
|
1285
|
+
const edits = [];
|
|
1286
|
+
const seenTagStarts = [];
|
|
1287
|
+
const seenAttrStarts = [];
|
|
1288
|
+
let candidateCount = 0;
|
|
1289
|
+
let scanFrom = 0;
|
|
1290
|
+
while (true) {
|
|
1291
|
+
const msqrtIdx = code.indexOf('"msqrt"', scanFrom);
|
|
1292
|
+
if (msqrtIdx === -1) break;
|
|
1293
|
+
scanFrom = msqrtIdx + 7;
|
|
1294
|
+
candidateCount++;
|
|
1295
|
+
const arrayStart = code.lastIndexOf("[", msqrtIdx);
|
|
1296
|
+
if (arrayStart === -1) continue;
|
|
1297
|
+
const exprStart = assignmentStartBeforeArray(arrayStart);
|
|
1298
|
+
if (exprStart === -1 || seenTagStarts.includes(exprStart)) continue;
|
|
1299
|
+
let parsed;
|
|
1300
|
+
try {
|
|
1301
|
+
parsed = acorn.parseExpressionAt(code, exprStart, { ecmaVersion: 2022, sourceType: "script" });
|
|
1302
|
+
} catch {
|
|
1303
|
+
continue;
|
|
1304
|
+
}
|
|
1305
|
+
const tagInfo = tagAssignmentValues(parsed);
|
|
1306
|
+
if (!tagInfo) continue;
|
|
1307
|
+
seenTagStarts.push(exprStart);
|
|
1308
|
+
const missingTags = [];
|
|
1309
|
+
for (let i = 0; i < svgTags.length; i++) {
|
|
1310
|
+
if (!tagInfo.values.includes(svgTags[i])) missingTags.push(svgTags[i]);
|
|
1311
|
+
}
|
|
1312
|
+
if (missingTags.length > 0) {
|
|
1313
|
+
const parts = [];
|
|
1314
|
+
for (let i = 0; i < missingTags.length; i++) parts.push(JSON.stringify(missingTags[i]));
|
|
1315
|
+
edits.push({
|
|
1316
|
+
start: tagInfo.assignment.right.end - 1,
|
|
1317
|
+
end: tagInfo.assignment.right.end - 1,
|
|
1318
|
+
text: `${tagInfo.values.length > 0 ? "," : ""}${parts.join(",")}`
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
const expressions = parsed.type === "SequenceExpression" ? parsed.expressions : [parsed];
|
|
1322
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
1323
|
+
const expr = expressions[i];
|
|
1324
|
+
if (!expr || expr.type !== "AssignmentExpression" || expr.operator !== "=") continue;
|
|
1325
|
+
if (!expr.left || expr.left.type !== "Identifier") continue;
|
|
1326
|
+
const attrInfo = attributeSchemaInfo(expr.right);
|
|
1327
|
+
if (!attrInfo || seenAttrStarts.includes(expr.right.start)) continue;
|
|
1328
|
+
seenAttrStarts.push(expr.right.start);
|
|
1329
|
+
const existingKeys = [];
|
|
1330
|
+
for (let j = 0; j < expr.right.properties.length; j++) {
|
|
1331
|
+
const key = propertyName(expr.right.properties[j]);
|
|
1332
|
+
if (key) existingKeys.push(key);
|
|
1333
|
+
}
|
|
1334
|
+
const missingProps = [];
|
|
1335
|
+
for (let j = 0; j < svgTags.length; j++) {
|
|
1336
|
+
if (!existingKeys.includes(svgTags[j])) missingProps.push(svgTags[j]);
|
|
1337
|
+
}
|
|
1338
|
+
if (missingProps.length > 0) {
|
|
1339
|
+
const propSources = [];
|
|
1340
|
+
for (let j = 0; j < missingProps.length; j++) propSources.push(svgPropertySource(missingProps[j]));
|
|
1341
|
+
edits.push({
|
|
1342
|
+
start: expr.right.end - 1,
|
|
1343
|
+
end: expr.right.end - 1,
|
|
1344
|
+
text: `${expr.right.properties.length > 0 ? "," : ""}${propSources.join(",")}`
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
break;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
if (seenTagStarts.length === 0) {
|
|
1351
|
+
log?.(` [katex-svg] WARNING: no AST-validated KaTeX math tag allowlist found (${candidateCount} candidate(s))`);
|
|
1352
|
+
return code;
|
|
1353
|
+
}
|
|
1354
|
+
if (seenAttrStarts.length === 0) {
|
|
1355
|
+
log?.(` [katex-svg] WARNING: no AST-validated KaTeX math attribute schema found (${seenTagStarts.length} tag allowlist(s))`);
|
|
1356
|
+
return code;
|
|
1357
|
+
}
|
|
1358
|
+
if (edits.length === 0) {
|
|
1359
|
+
log?.(` [katex-svg] already patched (${seenTagStarts.length} math sanitizer schema(s))`);
|
|
1360
|
+
return code;
|
|
1361
|
+
}
|
|
1362
|
+
edits.sort((a, b) => b.start - a.start);
|
|
1363
|
+
let result = code;
|
|
1364
|
+
for (let i = 0; i < edits.length; i++) {
|
|
1365
|
+
const edit = edits[i];
|
|
1366
|
+
result = result.slice(0, edit.start) + edit.text + result.slice(edit.end);
|
|
1367
|
+
}
|
|
1368
|
+
log?.(` [katex-svg] patched ${seenTagStarts.length} KaTeX math sanitizer schema(s), ${edits.length} insertion(s)`);
|
|
1369
|
+
return result;
|
|
1370
|
+
}
|
|
1371
|
+
function patchGlassExtensionAllowlist(code, log) {
|
|
1372
|
+
const entry = `,"${EXTENSION_ID}"`;
|
|
1373
|
+
let result = code;
|
|
1374
|
+
let patched = 0;
|
|
1375
|
+
const jesEnd = '"vscode.github-authentication"]';
|
|
1376
|
+
if (result.includes(jesEnd)) {
|
|
1377
|
+
result = result.replace(jesEnd, `"vscode.github-authentication"${entry}]`);
|
|
1378
|
+
patched++;
|
|
1379
|
+
}
|
|
1380
|
+
const gesEnd = '"anysphere.remote-wsl"]';
|
|
1381
|
+
if (result.includes(gesEnd)) {
|
|
1382
|
+
result = result.replace(gesEnd, `"anysphere.remote-wsl"${entry}]`);
|
|
1383
|
+
patched++;
|
|
1384
|
+
}
|
|
1385
|
+
if (patched === 0) {
|
|
1386
|
+
log?.(" [glass-allowlist] WARNING: allowlist arrays not found, skipping");
|
|
1387
|
+
} else {
|
|
1388
|
+
log?.(` [glass-allowlist] injected ${EXTENSION_ID} into ${patched} allowlist array(s)`);
|
|
1389
|
+
}
|
|
1390
|
+
return result;
|
|
1391
|
+
}
|
|
1392
|
+
function patchSingleWorkbench(filePath, label, paths, log) {
|
|
1393
|
+
const code = (0, import_fs6.readFileSync)(filePath, "utf-8");
|
|
1394
|
+
if (isInjectPatched(code)) {
|
|
1395
|
+
log?.(`[inject] ${label}: already patched`);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (code.includes(HOOK_MARKER) || code.includes(HOOK_SOURCE_MARKER)) {
|
|
1399
|
+
throw new Error(`${label}: partial renderer hook detected (payload/call-site mismatch)`);
|
|
1400
|
+
}
|
|
1401
|
+
const target = findTarget(code, log);
|
|
1402
|
+
log?.(` Target: function ${target.name}(${target.paramService}, ${target.paramTransport})`);
|
|
1403
|
+
const { name: fnName, paramService: ps, paramTransport: pt, innerFn } = target;
|
|
1404
|
+
const replacement = `function ${fnName}(${ps},${pt}){return ${innerFn}(${ps},(typeof globalThis.${HOOK_MARKER}==="function"?globalThis.${HOOK_MARKER}(${pt},${ps}.typeName):${pt}))}`;
|
|
1405
|
+
let patched = code.slice(0, target.bounds.start) + replacement + code.slice(target.bounds.end);
|
|
1406
|
+
patched = captureAiServiceRef(patched, log);
|
|
1407
|
+
const payload = buildHookPayload(paths.hasGlass);
|
|
1408
|
+
patched = `/* CURSOR-BYOK-HOOK-START */${payload}/* CURSOR-BYOK-HOOK-END */;${patched}`;
|
|
1409
|
+
patched = patchMaxModeToggle(patched, log);
|
|
1410
|
+
patched = patchKatexMathSvgSanitizer(patched, log);
|
|
1411
|
+
patched = patchGlassExtensionAllowlist(patched, log);
|
|
1412
|
+
if (!patched.includes(HOOK_MARKER)) throw new Error(`Verification failed for ${label}`);
|
|
1413
|
+
createBackup(filePath, "inject", log);
|
|
1414
|
+
(0, import_fs6.writeFileSync)(filePath, patched);
|
|
1415
|
+
updateChecksums(paths, [filePath], "inject", log);
|
|
1416
|
+
}
|
|
1417
|
+
function patchInject(paths, log) {
|
|
1418
|
+
const targets = [
|
|
1419
|
+
{ path: paths.workbenchJs, label: "desktop" },
|
|
1420
|
+
{ path: paths.glassJs, label: "glass" }
|
|
1421
|
+
];
|
|
1422
|
+
for (const { path, label } of targets) {
|
|
1423
|
+
if (!(0, import_fs6.existsSync)(path)) {
|
|
1424
|
+
log?.(`[inject] ${label}: not found, skipping (pre-3.8)`);
|
|
1425
|
+
continue;
|
|
1426
|
+
}
|
|
1427
|
+
log?.(`[inject] Patching ${label} workbench.js...`);
|
|
1428
|
+
patchSingleWorkbench(path, label, paths, log);
|
|
1429
|
+
}
|
|
1430
|
+
log?.("[inject] Done");
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
// src/patch-always-local.js
|
|
1434
|
+
var import_fs7 = require("fs");
|
|
1435
|
+
var acorn3 = __toESM(require("acorn"), 1);
|
|
1436
|
+
|
|
1437
|
+
// src/node-http11-router.js
|
|
1438
|
+
var HTTP11_ROUTER_VERSION_MARKER = "__byokHttp11RouterV2";
|
|
1439
|
+
var HTTP11_ROUTER_SOURCE_MARKER = "BYOK-HTTP11-ROUTER-V2";
|
|
1440
|
+
function buildNodeHttp11RouterPayload({ guardMarker, processLabel }) {
|
|
1441
|
+
const fallbackHost = JSON.stringify(DEFAULT_HOST);
|
|
1442
|
+
const fallbackPort = String(DEFAULT_PORT);
|
|
1443
|
+
const configDirName = JSON.stringify(BEATCURSOR_DIR_NAME);
|
|
1444
|
+
const routesFile = JSON.stringify(ROUTES_FILE_NAME);
|
|
1445
|
+
const guard = JSON.stringify(guardMarker);
|
|
1446
|
+
const label = JSON.stringify(processLabel);
|
|
1447
|
+
const versionMarker = JSON.stringify(HTTP11_ROUTER_VERSION_MARKER);
|
|
1448
|
+
return `/* ${HTTP11_ROUTER_SOURCE_MARKER} */
|
|
1449
|
+
(function(){
|
|
1450
|
+
var VERSION_MARKER=${versionMarker},GUARD_MARKER=${guard},PROCESS_LABEL=${label};
|
|
1451
|
+
if(globalThis[VERSION_MARKER]){globalThis[GUARD_MARKER]=true;return;}
|
|
1452
|
+
globalThis[VERSION_MARKER]=true;globalThis[GUARD_MARKER]=true;
|
|
1453
|
+
var _http=require("http"),_https=require("https"),_fs=require("fs"),_path=require("path"),_os=require("os"),_module=require("module");
|
|
1454
|
+
var _proxyHttpRequest=_http.request,_proxyHttpsRequest=_https.request;
|
|
1455
|
+
var _proxyHttpGet=_http.get,_proxyHttpsGet=_https.get;
|
|
1456
|
+
var _directHttpOwner=_http.__vscodeOriginal||_http;
|
|
1457
|
+
var _directHttpRequest=(_http.__vscodeOriginal&&_http.__vscodeOriginal.request)||_proxyHttpRequest;
|
|
1458
|
+
var ROUTES_PATH=_path.join(_os.homedir(),${configDirName},${routesFile});
|
|
1459
|
+
var FALLBACK_HOST=${fallbackHost},FALLBACK_PORT=${fallbackPort};
|
|
1460
|
+
var _title=String(process.env.VSCODE_PROCESS_TITLE||""),_widMatch=_title.match(/\\[(\\d+)-\\d+\\]/),WINDOW_ID=_widMatch?_widMatch[1]:null;
|
|
1461
|
+
var state={host:FALLBACK_HOST,port:FALLBACK_PORT,base:"http://"+FALLBACK_HOST+":"+FALLBACK_PORT,svcSet:new Set(),methodSet:new Set(),restSet:new Set(),ruleCount:0,restCount:0};
|
|
1462
|
+
function baseUrl(host,port){var h=String(host);if(h.indexOf(":")!==-1&&h.charAt(0)!=="[")h="["+h+"]";return"http://"+h+":"+port;}
|
|
1463
|
+
function emptyState(){return{host:FALLBACK_HOST,port:FALLBACK_PORT,base:baseUrl(FALLBACK_HOST,FALLBACK_PORT),svcSet:new Set(),methodSet:new Set(),restSet:new Set(),ruleCount:0,restCount:0};}
|
|
1464
|
+
function loadConfig(){try{
|
|
1465
|
+
var cfg=JSON.parse(_fs.readFileSync(ROUTES_PATH,"utf-8"));
|
|
1466
|
+
var host=cfg&&cfg.server&&typeof cfg.server.host==="string"&&cfg.server.host.trim()?cfg.server.host.trim():FALLBACK_HOST;
|
|
1467
|
+
var rawPort=cfg&&cfg.server&&cfg.server.port;
|
|
1468
|
+
var port=(typeof rawPort==="number"||typeof rawPort==="string")&&String(rawPort).trim()?rawPort:FALLBACK_PORT;
|
|
1469
|
+
var rules=cfg&&Array.isArray(cfg.redirect)?cfg.redirect:[];
|
|
1470
|
+
var svcSet=new Set(),methodSet=new Set(),restSet=new Set(),ruleCount=0,restCount=0;
|
|
1471
|
+
for(var i=0;i<rules.length;i++){var rule=rules[i];if(typeof rule!=="string")continue;
|
|
1472
|
+
if(rule.indexOf("REST:")===0){restSet.add(rule.slice(5));restCount++;}
|
|
1473
|
+
else if(rule.indexOf("/")!==-1){methodSet.add(rule);ruleCount++;}
|
|
1474
|
+
else{svcSet.add(rule);ruleCount++;}}
|
|
1475
|
+
return{host:host,port:port,base:baseUrl(host,port),svcSet:svcSet,methodSet:methodSet,restSet:restSet,ruleCount:ruleCount,restCount:restCount};
|
|
1476
|
+
}catch(e){return emptyState();}}
|
|
1477
|
+
function applyState(event){state=loadConfig();console.log("[BYOK] "+PROCESS_LABEL+" "+event+" -> "+state.base+" (ConnectRPC="+state.ruleCount+", REST="+state.restCount+")");}
|
|
1478
|
+
applyState("routes loaded");
|
|
1479
|
+
try{_fs.watchFile(ROUTES_PATH,{interval:2000,persistent:false},function(){applyState("routes reloaded");});}catch(e){console.warn("[BYOK] "+PROCESS_LABEL+" watchFile failed: "+e.message);}
|
|
1480
|
+
function normalizeHost(host){return String(host||"").trim().replace(/^\\[|\\]$/g,"").toLowerCase();}
|
|
1481
|
+
function isCursorApiHost(host){host=normalizeHost(host);return/(^|\\.)api[234]\\.cursor\\.sh$|(^|\\.)api5\\.cursor\\.sh$|(^|\\.)gcpp\\.cursor\\.sh$|^api\\.playground\\.cursor\\.sh$/.test(host);}
|
|
1482
|
+
function pathOnly(pathname){pathname=String(pathname||"");var hash=pathname.indexOf("#");if(hash!==-1)pathname=pathname.slice(0,hash);var query=pathname.indexOf("?");return query===-1?pathname:pathname.slice(0,query);}
|
|
1483
|
+
function shouldRedirect(pathname){pathname=pathOnly(pathname);if(!pathname||pathname.length<2)return false;if(state.restSet.has(pathname))return true;var path=pathname.charAt(0)==="/"?pathname.slice(1):pathname;var slash=path.indexOf("/");if(slash===-1)return false;if(state.methodSet.has(path))return true;return state.svcSet.has(path.slice(0,slash));}
|
|
1484
|
+
function parseRequest(input){try{
|
|
1485
|
+
if(typeof input==="string"){var s=new URL(input);return{hostname:s.hostname,port:s.port,protocol:s.protocol,path:s.pathname+s.search,raw:input,kind:"string"};}
|
|
1486
|
+
if(input instanceof URL)return{hostname:input.hostname,port:input.port,protocol:input.protocol,path:input.pathname+input.search,raw:input,kind:"url"};
|
|
1487
|
+
if(input&&typeof input==="object"){var hostText=String(input.hostname||input.host||""),port=input.port||"";
|
|
1488
|
+
if(!input.hostname&&hostText.charAt(0)!=="["){var colon=hostText.lastIndexOf(":");if(colon>0&&/^\\d+$/.test(hostText.slice(colon+1))){if(!port)port=hostText.slice(colon+1);hostText=hostText.slice(0,colon);}}
|
|
1489
|
+
return{hostname:hostText,port:String(port||""),protocol:input.protocol||"",path:input.path||((input.pathname||"/")+(input.search||"")),raw:input,kind:"object"};}
|
|
1490
|
+
}catch(e){}return null;}
|
|
1491
|
+
function isConfiguredLocal(parsed){if(!parsed||(parsed.protocol&&parsed.protocol!=="http:"))return false;if(normalizeHost(parsed.hostname)!==normalizeHost(state.host))return false;return!parsed.port||String(parsed.port)===String(state.port);}
|
|
1492
|
+
function cloneHeaders(headers){var result={};if(!headers)return result;try{if(typeof Headers!=="undefined"&&headers instanceof Headers){headers.forEach(function(value,key){result[key]=value;});return result;}}catch(e){}
|
|
1493
|
+
if(Array.isArray(headers)){if(headers.length&&Array.isArray(headers[0])){for(var i=0;i<headers.length;i++)if(headers[i]&&headers[i].length>=2)result[String(headers[i][0])]=headers[i][1];}else{for(var j=0;j+1<headers.length;j+=2)result[String(headers[j])]=headers[j+1];}return result;}
|
|
1494
|
+
if(typeof headers==="object")for(var key in headers)if(Object.prototype.hasOwnProperty.call(headers,key))result[key]=headers[key];return result;}
|
|
1495
|
+
function routeHeaders(headers){var result=cloneHeaders(headers),hasWid=false;for(var key in result){var lower=key.toLowerCase();if(lower==="host"||lower===":authority")delete result[key];else if(lower==="x-client-wid")hasWid=true;}if(WINDOW_ID&&!hasWid)result["x-client-wid"]=WINDOW_ID;result["x-byok-route-source"]=PROCESS_LABEL;return result;}
|
|
1496
|
+
function localOptions(options){var result=Object.assign({},options||{});result.headers=routeHeaders(result.headers);result.agent=false;delete result.host;delete result.servername;delete result.createConnection;delete result.ALPNProtocols;return result;}
|
|
1497
|
+
function rewriteOptions(options){var result=localOptions(options);result.protocol="http:";result.hostname=state.host;result.port=state.port;return result;}
|
|
1498
|
+
function rewriteUrl(parsed){var path=parsed.path||"/";return state.base+(path.charAt(0)==="/"?path:"/"+path);}
|
|
1499
|
+
function directRequest(parsed,second,callback){var cb=typeof second==="function"?second:callback;if(parsed.kind==="object")return _directHttpRequest.call(_directHttpOwner,rewriteOptions(parsed.raw),cb);var options=typeof second==="function"||second==null?{}:second;return _directHttpRequest.call(_directHttpOwner,rewriteUrl(parsed),localOptions(options),cb);}
|
|
1500
|
+
function interceptRequest(isHttps){return function(input,options,callback){var parsed=parseRequest(input);if(parsed&&((isCursorApiHost(parsed.hostname)&&shouldRedirect(parsed.path))||isConfiguredLocal(parsed)))return directRequest(parsed,options,callback);var original=isHttps?_proxyHttpsRequest:_proxyHttpRequest;return original.call(isHttps?_https:_http,input,options,callback);};}
|
|
1501
|
+
function interceptGet(isHttps){return function(input,options,callback){var parsed=parseRequest(input);if(parsed&&((isCursorApiHost(parsed.hostname)&&shouldRedirect(parsed.path))||isConfiguredLocal(parsed))){var request=(isHttps?_https:_http).request(input,options,callback);request.end();return request;}var original=isHttps?_proxyHttpsGet:_proxyHttpGet;return original.call(isHttps?_https:_http,input,options,callback);};}
|
|
1502
|
+
_http.request=interceptRequest(false);_https.request=interceptRequest(true);_http.get=interceptGet(false);_https.get=interceptGet(true);
|
|
1503
|
+
try{if(typeof _module.syncBuiltinESMExports==="function")_module.syncBuiltinESMExports();}catch(e){console.warn("[BYOK] "+PROCESS_LABEL+" syncBuiltinESMExports failed: "+e.message);}
|
|
1504
|
+
console.log("[BYOK] "+PROCESS_LABEL+" HTTP/1.1 whitelist router active (config: "+ROUTES_PATH+")");
|
|
1505
|
+
})();
|
|
1506
|
+
/* ${HTTP11_ROUTER_SOURCE_MARKER}-END */
|
|
1507
|
+
`;
|
|
1508
|
+
}
|
|
1509
|
+
function isNodeHttp11RouterPatched(source, guardMarker) {
|
|
1510
|
+
const head = source.slice(0, 24e3);
|
|
1511
|
+
return head.includes(`/* ${HTTP11_ROUTER_SOURCE_MARKER} */`) && head.includes(HTTP11_ROUTER_VERSION_MARKER) && head.includes(guardMarker) && head.includes("_http.request=interceptRequest(false)") && head.includes("_https.request=interceptRequest(true)") && head.includes("_module.syncBuiltinESMExports");
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
// src/agent-websocket-guard.js
|
|
1515
|
+
var acorn2 = __toESM(require("acorn"), 1);
|
|
1516
|
+
|
|
1517
|
+
// node_modules/acorn-walk/dist/walk.mjs
|
|
1518
|
+
function simple(node, visitors, baseVisitor, state, override) {
|
|
1519
|
+
if (!baseVisitor) {
|
|
1520
|
+
baseVisitor = base;
|
|
1521
|
+
}
|
|
1522
|
+
(function c(node2, st, override2) {
|
|
1523
|
+
var type = override2 || node2.type;
|
|
1524
|
+
visitNode(baseVisitor, type, node2, st, c);
|
|
1525
|
+
if (visitors[type]) {
|
|
1526
|
+
visitors[type](node2, st);
|
|
1527
|
+
}
|
|
1528
|
+
})(node, state, override);
|
|
1529
|
+
}
|
|
1530
|
+
function skipThrough(node, st, c) {
|
|
1531
|
+
c(node, st);
|
|
1532
|
+
}
|
|
1533
|
+
function ignore(_node, _st, _c) {
|
|
1534
|
+
}
|
|
1535
|
+
function visitNode(baseVisitor, type, node, st, c) {
|
|
1536
|
+
if (baseVisitor[type] == null) {
|
|
1537
|
+
throw new Error("No walker function defined for node type " + type);
|
|
1538
|
+
}
|
|
1539
|
+
baseVisitor[type](node, st, c);
|
|
1540
|
+
}
|
|
1541
|
+
var base = {};
|
|
1542
|
+
base.Program = base.BlockStatement = base.StaticBlock = function(node, st, c) {
|
|
1543
|
+
for (var i = 0, list = node.body; i < list.length; i += 1) {
|
|
1544
|
+
var stmt = list[i];
|
|
1545
|
+
c(stmt, st, "Statement");
|
|
1546
|
+
}
|
|
1547
|
+
};
|
|
1548
|
+
base.Statement = skipThrough;
|
|
1549
|
+
base.EmptyStatement = ignore;
|
|
1550
|
+
base.ExpressionStatement = base.ParenthesizedExpression = base.ChainExpression = function(node, st, c) {
|
|
1551
|
+
return c(node.expression, st, "Expression");
|
|
1552
|
+
};
|
|
1553
|
+
base.IfStatement = function(node, st, c) {
|
|
1554
|
+
c(node.test, st, "Expression");
|
|
1555
|
+
c(node.consequent, st, "Statement");
|
|
1556
|
+
if (node.alternate) {
|
|
1557
|
+
c(node.alternate, st, "Statement");
|
|
1558
|
+
}
|
|
1559
|
+
};
|
|
1560
|
+
base.LabeledStatement = function(node, st, c) {
|
|
1561
|
+
return c(node.body, st, "Statement");
|
|
1562
|
+
};
|
|
1563
|
+
base.BreakStatement = base.ContinueStatement = ignore;
|
|
1564
|
+
base.WithStatement = function(node, st, c) {
|
|
1565
|
+
c(node.object, st, "Expression");
|
|
1566
|
+
c(node.body, st, "Statement");
|
|
1567
|
+
};
|
|
1568
|
+
base.SwitchStatement = function(node, st, c) {
|
|
1569
|
+
c(node.discriminant, st, "Expression");
|
|
1570
|
+
for (var i = 0, list = node.cases; i < list.length; i += 1) {
|
|
1571
|
+
var cs = list[i];
|
|
1572
|
+
c(cs, st);
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
base.SwitchCase = function(node, st, c) {
|
|
1576
|
+
if (node.test) {
|
|
1577
|
+
c(node.test, st, "Expression");
|
|
1578
|
+
}
|
|
1579
|
+
for (var i = 0, list = node.consequent; i < list.length; i += 1) {
|
|
1580
|
+
var cons = list[i];
|
|
1581
|
+
c(cons, st, "Statement");
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
base.ReturnStatement = base.YieldExpression = base.AwaitExpression = function(node, st, c) {
|
|
1585
|
+
if (node.argument) {
|
|
1586
|
+
c(node.argument, st, "Expression");
|
|
1587
|
+
}
|
|
1588
|
+
};
|
|
1589
|
+
base.ThrowStatement = base.SpreadElement = function(node, st, c) {
|
|
1590
|
+
return c(node.argument, st, "Expression");
|
|
1591
|
+
};
|
|
1592
|
+
base.TryStatement = function(node, st, c) {
|
|
1593
|
+
c(node.block, st, "Statement");
|
|
1594
|
+
if (node.handler) {
|
|
1595
|
+
c(node.handler, st);
|
|
1596
|
+
}
|
|
1597
|
+
if (node.finalizer) {
|
|
1598
|
+
c(node.finalizer, st, "Statement");
|
|
1599
|
+
}
|
|
1600
|
+
};
|
|
1601
|
+
base.CatchClause = function(node, st, c) {
|
|
1602
|
+
if (node.param) {
|
|
1603
|
+
c(node.param, st, "Pattern");
|
|
1604
|
+
}
|
|
1605
|
+
c(node.body, st, "Statement");
|
|
1606
|
+
};
|
|
1607
|
+
base.WhileStatement = base.DoWhileStatement = function(node, st, c) {
|
|
1608
|
+
c(node.test, st, "Expression");
|
|
1609
|
+
c(node.body, st, "Statement");
|
|
1610
|
+
};
|
|
1611
|
+
base.ForStatement = function(node, st, c) {
|
|
1612
|
+
if (node.init) {
|
|
1613
|
+
c(node.init, st, "ForInit");
|
|
1614
|
+
}
|
|
1615
|
+
if (node.test) {
|
|
1616
|
+
c(node.test, st, "Expression");
|
|
1617
|
+
}
|
|
1618
|
+
if (node.update) {
|
|
1619
|
+
c(node.update, st, "Expression");
|
|
1620
|
+
}
|
|
1621
|
+
c(node.body, st, "Statement");
|
|
1622
|
+
};
|
|
1623
|
+
base.ForInStatement = base.ForOfStatement = function(node, st, c) {
|
|
1624
|
+
c(node.left, st, "ForInit");
|
|
1625
|
+
c(node.right, st, "Expression");
|
|
1626
|
+
c(node.body, st, "Statement");
|
|
1627
|
+
};
|
|
1628
|
+
base.ForInit = function(node, st, c) {
|
|
1629
|
+
if (node.type === "VariableDeclaration") {
|
|
1630
|
+
c(node, st);
|
|
1631
|
+
} else {
|
|
1632
|
+
c(node, st, "Expression");
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
base.DebuggerStatement = ignore;
|
|
1636
|
+
base.FunctionDeclaration = function(node, st, c) {
|
|
1637
|
+
return c(node, st, "Function");
|
|
1638
|
+
};
|
|
1639
|
+
base.VariableDeclaration = function(node, st, c) {
|
|
1640
|
+
for (var i = 0, list = node.declarations; i < list.length; i += 1) {
|
|
1641
|
+
var decl = list[i];
|
|
1642
|
+
c(decl, st);
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
base.VariableDeclarator = function(node, st, c) {
|
|
1646
|
+
c(node.id, st, "Pattern");
|
|
1647
|
+
if (node.init) {
|
|
1648
|
+
c(node.init, st, "Expression");
|
|
1649
|
+
}
|
|
1650
|
+
};
|
|
1651
|
+
base.Function = function(node, st, c) {
|
|
1652
|
+
if (node.id) {
|
|
1653
|
+
c(node.id, st, "Pattern");
|
|
1654
|
+
}
|
|
1655
|
+
for (var i = 0, list = node.params; i < list.length; i += 1) {
|
|
1656
|
+
var param = list[i];
|
|
1657
|
+
c(param, st, "Pattern");
|
|
1658
|
+
}
|
|
1659
|
+
c(node.body, st, node.expression ? "Expression" : "Statement");
|
|
1660
|
+
};
|
|
1661
|
+
base.Pattern = function(node, st, c) {
|
|
1662
|
+
if (node.type === "Identifier") {
|
|
1663
|
+
c(node, st, "VariablePattern");
|
|
1664
|
+
} else if (node.type === "MemberExpression") {
|
|
1665
|
+
c(node, st, "MemberPattern");
|
|
1666
|
+
} else {
|
|
1667
|
+
c(node, st);
|
|
1668
|
+
}
|
|
1669
|
+
};
|
|
1670
|
+
base.VariablePattern = ignore;
|
|
1671
|
+
base.MemberPattern = skipThrough;
|
|
1672
|
+
base.RestElement = function(node, st, c) {
|
|
1673
|
+
return c(node.argument, st, "Pattern");
|
|
1674
|
+
};
|
|
1675
|
+
base.ArrayPattern = function(node, st, c) {
|
|
1676
|
+
for (var i = 0, list = node.elements; i < list.length; i += 1) {
|
|
1677
|
+
var elt = list[i];
|
|
1678
|
+
if (elt) {
|
|
1679
|
+
c(elt, st, "Pattern");
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
base.ObjectPattern = function(node, st, c) {
|
|
1684
|
+
for (var i = 0, list = node.properties; i < list.length; i += 1) {
|
|
1685
|
+
var prop = list[i];
|
|
1686
|
+
if (prop.type === "Property") {
|
|
1687
|
+
if (prop.computed) {
|
|
1688
|
+
c(prop.key, st, "Expression");
|
|
1689
|
+
}
|
|
1690
|
+
c(prop.value, st, "Pattern");
|
|
1691
|
+
} else if (prop.type === "RestElement") {
|
|
1692
|
+
c(prop.argument, st, "Pattern");
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
};
|
|
1696
|
+
base.Expression = skipThrough;
|
|
1697
|
+
base.ThisExpression = base.Super = base.MetaProperty = ignore;
|
|
1698
|
+
base.ArrayExpression = function(node, st, c) {
|
|
1699
|
+
for (var i = 0, list = node.elements; i < list.length; i += 1) {
|
|
1700
|
+
var elt = list[i];
|
|
1701
|
+
if (elt) {
|
|
1702
|
+
c(elt, st, "Expression");
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
base.ObjectExpression = function(node, st, c) {
|
|
1707
|
+
for (var i = 0, list = node.properties; i < list.length; i += 1) {
|
|
1708
|
+
var prop = list[i];
|
|
1709
|
+
c(prop, st);
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration;
|
|
1713
|
+
base.SequenceExpression = function(node, st, c) {
|
|
1714
|
+
for (var i = 0, list = node.expressions; i < list.length; i += 1) {
|
|
1715
|
+
var expr = list[i];
|
|
1716
|
+
c(expr, st, "Expression");
|
|
1717
|
+
}
|
|
1718
|
+
};
|
|
1719
|
+
base.TemplateLiteral = function(node, st, c) {
|
|
1720
|
+
for (var i = 0, list = node.quasis; i < list.length; i += 1) {
|
|
1721
|
+
var quasi = list[i];
|
|
1722
|
+
c(quasi, st);
|
|
1723
|
+
}
|
|
1724
|
+
for (var i$1 = 0, list$1 = node.expressions; i$1 < list$1.length; i$1 += 1) {
|
|
1725
|
+
var expr = list$1[i$1];
|
|
1726
|
+
c(expr, st, "Expression");
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
base.TemplateElement = ignore;
|
|
1730
|
+
base.UnaryExpression = base.UpdateExpression = function(node, st, c) {
|
|
1731
|
+
c(node.argument, st, "Expression");
|
|
1732
|
+
};
|
|
1733
|
+
base.BinaryExpression = base.LogicalExpression = function(node, st, c) {
|
|
1734
|
+
c(node.left, st, "Expression");
|
|
1735
|
+
c(node.right, st, "Expression");
|
|
1736
|
+
};
|
|
1737
|
+
base.AssignmentExpression = base.AssignmentPattern = function(node, st, c) {
|
|
1738
|
+
c(node.left, st, "Pattern");
|
|
1739
|
+
c(node.right, st, "Expression");
|
|
1740
|
+
};
|
|
1741
|
+
base.ConditionalExpression = function(node, st, c) {
|
|
1742
|
+
c(node.test, st, "Expression");
|
|
1743
|
+
c(node.consequent, st, "Expression");
|
|
1744
|
+
c(node.alternate, st, "Expression");
|
|
1745
|
+
};
|
|
1746
|
+
base.NewExpression = base.CallExpression = function(node, st, c) {
|
|
1747
|
+
c(node.callee, st, "Expression");
|
|
1748
|
+
if (node.arguments) {
|
|
1749
|
+
for (var i = 0, list = node.arguments; i < list.length; i += 1) {
|
|
1750
|
+
var arg = list[i];
|
|
1751
|
+
c(arg, st, "Expression");
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
};
|
|
1755
|
+
base.MemberExpression = function(node, st, c) {
|
|
1756
|
+
c(node.object, st, "Expression");
|
|
1757
|
+
if (node.computed) {
|
|
1758
|
+
c(node.property, st, "Expression");
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
base.ExportNamedDeclaration = base.ExportDefaultDeclaration = function(node, st, c) {
|
|
1762
|
+
if (node.declaration) {
|
|
1763
|
+
c(node.declaration, st, node.type === "ExportNamedDeclaration" || node.declaration.id ? "Statement" : "Expression");
|
|
1764
|
+
}
|
|
1765
|
+
if (node.source) {
|
|
1766
|
+
c(node.source, st, "Expression");
|
|
1767
|
+
}
|
|
1768
|
+
if (node.attributes) {
|
|
1769
|
+
for (var i = 0, list = node.attributes; i < list.length; i += 1) {
|
|
1770
|
+
var attr = list[i];
|
|
1771
|
+
c(attr, st);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
};
|
|
1775
|
+
base.ExportAllDeclaration = function(node, st, c) {
|
|
1776
|
+
if (node.exported) {
|
|
1777
|
+
c(node.exported, st);
|
|
1778
|
+
}
|
|
1779
|
+
c(node.source, st, "Expression");
|
|
1780
|
+
if (node.attributes) {
|
|
1781
|
+
for (var i = 0, list = node.attributes; i < list.length; i += 1) {
|
|
1782
|
+
var attr = list[i];
|
|
1783
|
+
c(attr, st);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
base.ImportAttribute = function(node, st, c) {
|
|
1788
|
+
c(node.value, st, "Expression");
|
|
1789
|
+
};
|
|
1790
|
+
base.ImportDeclaration = function(node, st, c) {
|
|
1791
|
+
for (var i = 0, list = node.specifiers; i < list.length; i += 1) {
|
|
1792
|
+
var spec = list[i];
|
|
1793
|
+
c(spec, st);
|
|
1794
|
+
}
|
|
1795
|
+
c(node.source, st, "Expression");
|
|
1796
|
+
if (node.attributes) {
|
|
1797
|
+
for (var i$1 = 0, list$1 = node.attributes; i$1 < list$1.length; i$1 += 1) {
|
|
1798
|
+
var attr = list$1[i$1];
|
|
1799
|
+
c(attr, st);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
base.ImportExpression = function(node, st, c) {
|
|
1804
|
+
c(node.source, st, "Expression");
|
|
1805
|
+
if (node.options) {
|
|
1806
|
+
c(node.options, st, "Expression");
|
|
1807
|
+
}
|
|
1808
|
+
};
|
|
1809
|
+
base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.PrivateIdentifier = base.Literal = ignore;
|
|
1810
|
+
base.TaggedTemplateExpression = function(node, st, c) {
|
|
1811
|
+
c(node.tag, st, "Expression");
|
|
1812
|
+
c(node.quasi, st, "Expression");
|
|
1813
|
+
};
|
|
1814
|
+
base.ClassDeclaration = base.ClassExpression = function(node, st, c) {
|
|
1815
|
+
return c(node, st, "Class");
|
|
1816
|
+
};
|
|
1817
|
+
base.Class = function(node, st, c) {
|
|
1818
|
+
if (node.id) {
|
|
1819
|
+
c(node.id, st, "Pattern");
|
|
1820
|
+
}
|
|
1821
|
+
if (node.superClass) {
|
|
1822
|
+
c(node.superClass, st, "Expression");
|
|
1823
|
+
}
|
|
1824
|
+
c(node.body, st);
|
|
1825
|
+
};
|
|
1826
|
+
base.ClassBody = function(node, st, c) {
|
|
1827
|
+
for (var i = 0, list = node.body; i < list.length; i += 1) {
|
|
1828
|
+
var elt = list[i];
|
|
1829
|
+
c(elt, st);
|
|
1830
|
+
}
|
|
1831
|
+
};
|
|
1832
|
+
base.MethodDefinition = base.PropertyDefinition = base.Property = function(node, st, c) {
|
|
1833
|
+
if (node.computed) {
|
|
1834
|
+
c(node.key, st, "Expression");
|
|
1835
|
+
}
|
|
1836
|
+
if (node.value) {
|
|
1837
|
+
c(node.value, st, "Expression");
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1840
|
+
|
|
1841
|
+
// src/agent-websocket-guard.js
|
|
1842
|
+
var AGENT_WS_GATE_MARKER = "__byokAgentWebSocketGateDisabled";
|
|
1843
|
+
var AGENT_WS_ORIGINS_MARKER = "__byokAgentWebSocketOriginsDisabled";
|
|
1844
|
+
var OLD_GATE_MARKER = "__byokAgentHostWebSocketGateDisabled";
|
|
1845
|
+
var OLD_ORIGINS_MARKER = "__byokAgentHostWebSocketOriginsDisabled";
|
|
1846
|
+
var DISABLED_WS_GATE = "__byok_disabled_nal_websocket_client";
|
|
1847
|
+
function parseBundle(source, label) {
|
|
1848
|
+
try {
|
|
1849
|
+
return acorn2.parse(source, { ecmaVersion: "latest", sourceType: "script" });
|
|
1850
|
+
} catch (error) {
|
|
1851
|
+
throw new Error(`${label} JavaScript parse failed: ${error.message}`);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
function websocketAstInfo(source, label) {
|
|
1855
|
+
const ast = parseBundle(source, label);
|
|
1856
|
+
const gateLiterals = [];
|
|
1857
|
+
const acceptedOriginArrays = [];
|
|
1858
|
+
simple(ast, {
|
|
1859
|
+
Literal(node) {
|
|
1860
|
+
if (node.value === "nal_websocket_client") gateLiterals.push(node);
|
|
1861
|
+
},
|
|
1862
|
+
ArrayExpression(node) {
|
|
1863
|
+
const values = node.elements.filter(Boolean).map((element) => element.type === "Literal" ? element.value : void 0);
|
|
1864
|
+
if (values.includes("https://api.playground.cursor.sh") && values.includes("https://api2.cursor.sh")) {
|
|
1865
|
+
acceptedOriginArrays.push(node);
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
});
|
|
1869
|
+
return { gateLiterals, acceptedOriginArrays };
|
|
1870
|
+
}
|
|
1871
|
+
function hasGateMarker(source) {
|
|
1872
|
+
return source.includes(AGENT_WS_GATE_MARKER) || source.includes(OLD_GATE_MARKER);
|
|
1873
|
+
}
|
|
1874
|
+
function hasOriginsMarker(source) {
|
|
1875
|
+
return source.includes(AGENT_WS_ORIGINS_MARKER) || source.includes(OLD_ORIGINS_MARKER);
|
|
1876
|
+
}
|
|
1877
|
+
function hasAgentWebSocketStack(source) {
|
|
1878
|
+
return source.includes("/agent/v1/run") && source.includes("createAgentRunWebSocketSelection");
|
|
1879
|
+
}
|
|
1880
|
+
function isAgentWebSocketDisabled(source, label = "Agent network bundle") {
|
|
1881
|
+
if (!hasAgentWebSocketStack(source)) return true;
|
|
1882
|
+
if (!hasGateMarker(source) || !hasOriginsMarker(source)) return false;
|
|
1883
|
+
const info4 = websocketAstInfo(source, label);
|
|
1884
|
+
return info4.gateLiterals.length === 0 && info4.acceptedOriginArrays.length === 0;
|
|
1885
|
+
}
|
|
1886
|
+
function disableAgentWebSocket(source, label = "Agent network bundle") {
|
|
1887
|
+
if (!hasAgentWebSocketStack(source)) return { source, changed: false, required: false };
|
|
1888
|
+
if (isAgentWebSocketDisabled(source, label)) return { source, changed: false, required: true };
|
|
1889
|
+
const info4 = websocketAstInfo(source, label);
|
|
1890
|
+
const edits = [];
|
|
1891
|
+
if (!hasGateMarker(source)) {
|
|
1892
|
+
if (info4.gateLiterals.length !== 1) {
|
|
1893
|
+
throw new Error(`${label}: expected one nal_websocket_client gate literal, found ${info4.gateLiterals.length}`);
|
|
1894
|
+
}
|
|
1895
|
+
const gate = info4.gateLiterals[0];
|
|
1896
|
+
edits.push({
|
|
1897
|
+
start: gate.start,
|
|
1898
|
+
end: gate.end,
|
|
1899
|
+
text: `${JSON.stringify(DISABLED_WS_GATE)}/*${AGENT_WS_GATE_MARKER}*/`
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
if (!hasOriginsMarker(source)) {
|
|
1903
|
+
if (info4.acceptedOriginArrays.length !== 1) {
|
|
1904
|
+
throw new Error(`${label}: expected one Agent WebSocket accepted-origin set, found ${info4.acceptedOriginArrays.length}`);
|
|
1905
|
+
}
|
|
1906
|
+
const origins = info4.acceptedOriginArrays[0];
|
|
1907
|
+
edits.push({
|
|
1908
|
+
start: origins.start + 1,
|
|
1909
|
+
end: origins.end - 1,
|
|
1910
|
+
text: `/*${AGENT_WS_ORIGINS_MARKER}*/`
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
edits.sort((a, b) => b.start - a.start);
|
|
1914
|
+
let patched = source;
|
|
1915
|
+
for (const edit of edits) patched = patched.slice(0, edit.start) + edit.text + patched.slice(edit.end);
|
|
1916
|
+
parseBundle(patched, `${label} (patched)`);
|
|
1917
|
+
if (!isAgentWebSocketDisabled(patched, label)) throw new Error(`${label}: WebSocket disable verification failed`);
|
|
1918
|
+
return { source: patched, changed: edits.length > 0, required: true };
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
// src/patch-always-local.js
|
|
1922
|
+
var ALWAYS_LOCAL_ROUTER_MARKER = "__byokUrlRewrite";
|
|
1923
|
+
var WAIT_MARKER = "__byokWaitServer";
|
|
1924
|
+
var SIG_PATTERN = /if\(!\w\.valid\)/;
|
|
1925
|
+
function buildPayload() {
|
|
1926
|
+
return buildNodeHttp11RouterPayload({
|
|
1927
|
+
guardMarker: ALWAYS_LOCAL_ROUTER_MARKER,
|
|
1928
|
+
processLabel: "always-local"
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1931
|
+
function patchAlwaysLocal(paths, log) {
|
|
1932
|
+
log?.("[always-local] Patching...");
|
|
1933
|
+
if (!(0, import_fs7.existsSync)(paths.alwaysLocalMain)) throw new Error(`Not found: ${paths.alwaysLocalMain}`);
|
|
1934
|
+
if (!(0, import_fs7.existsSync)(paths.extensionHostJs)) throw new Error(`Not found: ${paths.extensionHostJs}`);
|
|
1935
|
+
const modified = [];
|
|
1936
|
+
const original = (0, import_fs7.readFileSync)(paths.alwaysLocalMain, "utf-8");
|
|
1937
|
+
let patched = original;
|
|
1938
|
+
if (!isNodeHttp11RouterPatched(patched, ALWAYS_LOCAL_ROUTER_MARKER)) {
|
|
1939
|
+
patched = buildPayload() + patched;
|
|
1940
|
+
log?.(" HTTP/1.1 whitelist router injected");
|
|
1941
|
+
} else {
|
|
1942
|
+
log?.(" HTTP/1.1 whitelist router already active");
|
|
1943
|
+
}
|
|
1944
|
+
const websocket = disableAgentWebSocket(patched, "cursor-always-local main.js");
|
|
1945
|
+
patched = websocket.source;
|
|
1946
|
+
if (websocket.required) {
|
|
1947
|
+
log?.(" Legacy Agent WebSocket bypass disabled");
|
|
1948
|
+
}
|
|
1949
|
+
const waited = injectActivateWait(patched, "always-local", log);
|
|
1950
|
+
if (!waited.ok) throw new Error("cursor-always-local activate function not found");
|
|
1951
|
+
patched = waited.source;
|
|
1952
|
+
if (patched !== original) {
|
|
1953
|
+
createBackup(paths.alwaysLocalMain, "always-local", log);
|
|
1954
|
+
(0, import_fs7.writeFileSync)(paths.alwaysLocalMain, patched);
|
|
1955
|
+
modified.push(paths.alwaysLocalMain);
|
|
1956
|
+
}
|
|
1957
|
+
const ehCode = (0, import_fs7.readFileSync)(paths.extensionHostJs, "utf-8");
|
|
1958
|
+
const ehPatched = ehCode.includes("if(!1)") && !SIG_PATTERN.test(ehCode);
|
|
1959
|
+
if (ehPatched) {
|
|
1960
|
+
log?.(" extensionHostProcess sig bypass already applied");
|
|
1961
|
+
} else {
|
|
1962
|
+
const match = ehCode.match(SIG_PATTERN);
|
|
1963
|
+
if (!match) throw new Error("Signature validation pattern not found");
|
|
1964
|
+
createBackup(paths.extensionHostJs, "always-local", log);
|
|
1965
|
+
(0, import_fs7.writeFileSync)(paths.extensionHostJs, ehCode.replace(SIG_PATTERN, "if(!1)"));
|
|
1966
|
+
modified.push(paths.extensionHostJs);
|
|
1967
|
+
log?.(` Sig bypass: ${match[0]} \u2192 if(!1)`);
|
|
1968
|
+
}
|
|
1969
|
+
if (modified.length > 0) updateChecksums(paths, modified, "always-local", log);
|
|
1970
|
+
log?.("[always-local] Done");
|
|
1971
|
+
}
|
|
1972
|
+
function inspectAlwaysLocalPatch(paths) {
|
|
1973
|
+
if (!(0, import_fs7.existsSync)(paths.alwaysLocalMain)) {
|
|
1974
|
+
return { present: false, router: false, wait: false, fullyPatched: false };
|
|
1975
|
+
}
|
|
1976
|
+
const source = (0, import_fs7.readFileSync)(paths.alwaysLocalMain, "utf-8");
|
|
1977
|
+
const router = isNodeHttp11RouterPatched(source, ALWAYS_LOCAL_ROUTER_MARKER);
|
|
1978
|
+
const wait = hasActivateWait(source);
|
|
1979
|
+
const websocketRequired = hasAgentWebSocketStack(source);
|
|
1980
|
+
const websocketDisabled = isAgentWebSocketDisabled(source, "cursor-always-local main.js");
|
|
1981
|
+
return {
|
|
1982
|
+
present: true,
|
|
1983
|
+
router,
|
|
1984
|
+
wait,
|
|
1985
|
+
websocketRequired,
|
|
1986
|
+
websocketDisabled,
|
|
1987
|
+
fullyPatched: router && wait && websocketDisabled
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
function checkAlwaysLocalPatch(paths, log) {
|
|
1991
|
+
log?.("[check] Verifying cursor-always-local HTTP/1.1 route target...");
|
|
1992
|
+
if (!(0, import_fs7.existsSync)(paths.alwaysLocalMain)) {
|
|
1993
|
+
log?.(" cursor-always-local main.js not found");
|
|
1994
|
+
return false;
|
|
1995
|
+
}
|
|
1996
|
+
try {
|
|
1997
|
+
let candidate = (0, import_fs7.readFileSync)(paths.alwaysLocalMain, "utf-8");
|
|
1998
|
+
if (!isNodeHttp11RouterPatched(candidate, ALWAYS_LOCAL_ROUTER_MARKER)) candidate = buildPayload() + candidate;
|
|
1999
|
+
candidate = disableAgentWebSocket(candidate, "cursor-always-local main.js").source;
|
|
2000
|
+
const waited = injectActivateWait(candidate, "always-local", log);
|
|
2001
|
+
if (!waited.ok) throw new Error("activate function not found");
|
|
2002
|
+
candidate = waited.source;
|
|
2003
|
+
if (!isNodeHttp11RouterPatched(candidate, ALWAYS_LOCAL_ROUTER_MARKER)) throw new Error("router call-site verification failed");
|
|
2004
|
+
if (!hasActivateWait(candidate)) throw new Error("activate wait verification failed");
|
|
2005
|
+
if (!isAgentWebSocketDisabled(candidate, "cursor-always-local main.js")) throw new Error("legacy WebSocket disable verification failed");
|
|
2006
|
+
log?.(" [OK] HTTP/1.1 router + activate wait + legacy WebSocket guard");
|
|
2007
|
+
return true;
|
|
2008
|
+
} catch (error) {
|
|
2009
|
+
log?.(` [FAIL] ${error.message}`);
|
|
2010
|
+
return false;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
function buildWaitSnippet(processLabel) {
|
|
2014
|
+
const fallbackHost = JSON.stringify(DEFAULT_HOST);
|
|
2015
|
+
const fallbackPort = String(DEFAULT_PORT);
|
|
2016
|
+
const configDirName = JSON.stringify(BEATCURSOR_DIR_NAME);
|
|
2017
|
+
const routesFile = JSON.stringify(ROUTES_FILE_NAME);
|
|
2018
|
+
const label = JSON.stringify(processLabel);
|
|
2019
|
+
return `await(async()=>{if(globalThis.${WAIT_MARKER})return;globalThis.${WAIT_MARKER}=true;const _label=${label};const _h=require("http");const _fs=require("fs");const _p=require("path");const _o=require("os");let _host=${fallbackHost},_port=${fallbackPort};try{const _c=JSON.parse(_fs.readFileSync(_p.join(_o.homedir(),${configDirName},${routesFile}),"utf-8"));if(_c&&_c.server){_host=_c.server.host||_host;_port=_c.server.port||_port;}}catch{}const _deadline=Date.now()+30000;while(Date.now()<_deadline){try{await new Promise((ok,no)=>{const r=_h.get("http://"+_host+":"+_port+"/health",res=>{res.resume();res.statusCode===200?ok():no()});r.on("error",no);r.setTimeout(500,()=>{r.destroy();no()})});console.log("[BYOK] Server ready, proceeding with "+_label+" activate");return}catch{}await new Promise(r=>setTimeout(r,500))}console.warn("[BYOK] Server not ready after 30s; "+_label+" will continue but routed requests remain local")})();`;
|
|
2020
|
+
}
|
|
2021
|
+
function hasActivateWait(source) {
|
|
2022
|
+
return source.includes(`await(async()=>{if(globalThis.${WAIT_MARKER})`);
|
|
2023
|
+
}
|
|
2024
|
+
function injectActivateWait(source, processLabel, log) {
|
|
2025
|
+
if (hasActivateWait(source)) {
|
|
2026
|
+
log?.(" activate wait-for-server already injected");
|
|
2027
|
+
return { source, changed: false, ok: true };
|
|
2028
|
+
}
|
|
2029
|
+
const position = findActivateInsertPosition(source, log);
|
|
2030
|
+
if (!position) return { source, changed: false, ok: false };
|
|
2031
|
+
const asyncPrefix = position.isAsync ? "" : "async ";
|
|
2032
|
+
let patched = source.slice(0, position.funcKeyword) + asyncPrefix + source.slice(position.funcKeyword);
|
|
2033
|
+
const bodyStart = position.bodyStart + asyncPrefix.length;
|
|
2034
|
+
patched = patched.slice(0, bodyStart) + buildWaitSnippet(processLabel) + patched.slice(bodyStart);
|
|
2035
|
+
if (!position.isAsync) log?.(" activate: function \u2192 async function");
|
|
2036
|
+
log?.(" activate: wait-for-server injected");
|
|
2037
|
+
return { source: patched, changed: true, ok: true };
|
|
2038
|
+
}
|
|
2039
|
+
function findActivateInsertPosition(source, log) {
|
|
2040
|
+
const resultA = findActivateAssignment(source, log);
|
|
2041
|
+
if (resultA) return resultA;
|
|
2042
|
+
const resultB = findActivateExportedFunction(source, log);
|
|
2043
|
+
if (resultB) return resultB;
|
|
2044
|
+
return null;
|
|
2045
|
+
}
|
|
2046
|
+
function findActivateAssignment(source, log) {
|
|
2047
|
+
const NEEDLE = "activate";
|
|
2048
|
+
const LOOKBACK = 10;
|
|
2049
|
+
let searchFrom = 0;
|
|
2050
|
+
while (true) {
|
|
2051
|
+
const idx = source.indexOf(NEEDLE, searchFrom);
|
|
2052
|
+
if (idx < 0) break;
|
|
2053
|
+
searchFrom = idx + NEEDLE.length;
|
|
2054
|
+
if (idx > 0 && /[a-zA-Z_$]/.test(source[idx - 1])) continue;
|
|
2055
|
+
if (idx + NEEDLE.length < source.length && /[a-zA-Z0-9_$]/.test(source[idx + NEEDLE.length])) continue;
|
|
2056
|
+
const before = source.substring(Math.max(0, idx - LOOKBACK), idx).trimEnd();
|
|
2057
|
+
if (!before.endsWith(".")) continue;
|
|
2058
|
+
const dotPos = idx - 1 - (before.length - before.trimEnd().length);
|
|
2059
|
+
let lhsStart = dotPos;
|
|
2060
|
+
while (lhsStart > 0 && /[a-zA-Z0-9_$]/.test(source[lhsStart - 1])) lhsStart--;
|
|
2061
|
+
let i = idx + NEEDLE.length;
|
|
2062
|
+
while (i < source.length && /[\s=]/.test(source[i])) i++;
|
|
2063
|
+
const funcKeyword = i;
|
|
2064
|
+
const ahead = source.substring(i, i + 20);
|
|
2065
|
+
if (!ahead.startsWith("function") && !ahead.startsWith("async")) continue;
|
|
2066
|
+
while (i < source.length && source[i] !== "(") i++;
|
|
2067
|
+
if (i >= source.length) continue;
|
|
2068
|
+
let parenDepth = 0;
|
|
2069
|
+
for (; i < source.length; i++) {
|
|
2070
|
+
if (source[i] === "(") parenDepth++;
|
|
2071
|
+
if (source[i] === ")") {
|
|
2072
|
+
parenDepth--;
|
|
2073
|
+
if (parenDepth === 0) {
|
|
2074
|
+
i++;
|
|
2075
|
+
break;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
while (i < source.length && source[i] !== "{") i++;
|
|
2080
|
+
if (i >= source.length) continue;
|
|
2081
|
+
const bodyStart = i + 1;
|
|
2082
|
+
const snippet = source.substring(lhsStart, bodyStart) + "}";
|
|
2083
|
+
let ast;
|
|
2084
|
+
try {
|
|
2085
|
+
ast = acorn3.parse(snippet, { ecmaVersion: 2022 });
|
|
2086
|
+
} catch {
|
|
2087
|
+
continue;
|
|
2088
|
+
}
|
|
2089
|
+
const stmt = ast.body[0];
|
|
2090
|
+
if (!stmt || stmt.type !== "ExpressionStatement") continue;
|
|
2091
|
+
const expr = stmt.expression;
|
|
2092
|
+
if (!expr || expr.type !== "AssignmentExpression") continue;
|
|
2093
|
+
if (!expr.left || expr.left.type !== "MemberExpression") continue;
|
|
2094
|
+
const prop = expr.left.property;
|
|
2095
|
+
if (!prop || prop.type === "Identifier" && prop.name !== "activate") continue;
|
|
2096
|
+
if (!expr.right || expr.right.type !== "FunctionExpression") continue;
|
|
2097
|
+
const VERIFY_RANGE = 5e3;
|
|
2098
|
+
const nearbyRange = source.substring(Math.max(0, lhsStart - VERIFY_RANGE), Math.min(source.length, bodyStart + VERIFY_RANGE));
|
|
2099
|
+
if (!nearbyRange.includes(".deactivate") && !nearbyRange.includes("deactivate")) continue;
|
|
2100
|
+
log?.(` AST match: .activate = FunctionExpression at ${lhsStart}, body at ${bodyStart}`);
|
|
2101
|
+
return { bodyStart, funcKeyword, isAsync: expr.right.async === true };
|
|
2102
|
+
}
|
|
2103
|
+
return null;
|
|
2104
|
+
}
|
|
2105
|
+
function findActivateExportedFunction(source, log) {
|
|
2106
|
+
const NEEDLE = "activate";
|
|
2107
|
+
let searchFrom = 0;
|
|
2108
|
+
let activateFuncName = null;
|
|
2109
|
+
let activateExportEnd = 0;
|
|
2110
|
+
while (true) {
|
|
2111
|
+
const idx = source.indexOf(NEEDLE, searchFrom);
|
|
2112
|
+
if (idx < 0) break;
|
|
2113
|
+
searchFrom = idx + NEEDLE.length;
|
|
2114
|
+
if (idx > 0 && /[a-zA-Z_$]/.test(source[idx - 1])) continue;
|
|
2115
|
+
if (idx + NEEDLE.length < source.length && /[a-zA-Z0-9_$]/.test(source[idx + NEEDLE.length])) continue;
|
|
2116
|
+
let objStart = idx;
|
|
2117
|
+
while (objStart > 0 && source[objStart] !== "{") objStart--;
|
|
2118
|
+
if (source[objStart] !== "{") continue;
|
|
2119
|
+
let objEnd = idx;
|
|
2120
|
+
let braceDepth = 0;
|
|
2121
|
+
for (let k = objStart; k < source.length && k < objStart + 500; k++) {
|
|
2122
|
+
if (source[k] === "{") braceDepth++;
|
|
2123
|
+
if (source[k] === "}") {
|
|
2124
|
+
braceDepth--;
|
|
2125
|
+
if (braceDepth === 0) {
|
|
2126
|
+
objEnd = k + 1;
|
|
2127
|
+
break;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
if (braceDepth !== 0) continue;
|
|
2132
|
+
const objSnippet = "(" + source.substring(objStart, objEnd) + ")";
|
|
2133
|
+
let ast;
|
|
2134
|
+
try {
|
|
2135
|
+
ast = acorn3.parse(objSnippet, { ecmaVersion: 2022 });
|
|
2136
|
+
} catch {
|
|
2137
|
+
continue;
|
|
2138
|
+
}
|
|
2139
|
+
const exprStmt = ast.body[0];
|
|
2140
|
+
if (!exprStmt || exprStmt.type !== "ExpressionStatement") continue;
|
|
2141
|
+
const obj = exprStmt.expression;
|
|
2142
|
+
if (!obj || obj.type !== "ObjectExpression") continue;
|
|
2143
|
+
let activateProp = null;
|
|
2144
|
+
let hasDeactivate = false;
|
|
2145
|
+
for (const prop of obj.properties) {
|
|
2146
|
+
if (prop.type !== "Property") continue;
|
|
2147
|
+
const key = prop.key;
|
|
2148
|
+
const name = key.type === "Identifier" ? key.name : key.type === "Literal" ? key.value : null;
|
|
2149
|
+
if (name === "activate") activateProp = prop;
|
|
2150
|
+
if (name === "deactivate") hasDeactivate = true;
|
|
2151
|
+
}
|
|
2152
|
+
if (!activateProp || !hasDeactivate) continue;
|
|
2153
|
+
const arrow = activateProp.value;
|
|
2154
|
+
if (!arrow || arrow.type !== "ArrowFunctionExpression") continue;
|
|
2155
|
+
if (!arrow.body || arrow.body.type !== "Identifier") continue;
|
|
2156
|
+
activateFuncName = arrow.body.name;
|
|
2157
|
+
activateExportEnd = objEnd;
|
|
2158
|
+
log?.(` Export object found: activate => ${activateFuncName}`);
|
|
2159
|
+
break;
|
|
2160
|
+
}
|
|
2161
|
+
if (!activateFuncName) return null;
|
|
2162
|
+
const funcNeedle = "function " + activateFuncName;
|
|
2163
|
+
let fIdx = source.indexOf(funcNeedle, activateExportEnd);
|
|
2164
|
+
if (fIdx < 0) fIdx = source.lastIndexOf(funcNeedle, activateExportEnd);
|
|
2165
|
+
while (fIdx >= 0) {
|
|
2166
|
+
let i = fIdx + funcNeedle.length;
|
|
2167
|
+
while (i < source.length && source[i] !== "(") i++;
|
|
2168
|
+
if (i >= source.length) {
|
|
2169
|
+
fIdx = source.indexOf(funcNeedle, fIdx + 1);
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2172
|
+
let parenDepth = 0;
|
|
2173
|
+
for (; i < source.length; i++) {
|
|
2174
|
+
if (source[i] === "(") parenDepth++;
|
|
2175
|
+
if (source[i] === ")") {
|
|
2176
|
+
parenDepth--;
|
|
2177
|
+
if (parenDepth === 0) {
|
|
2178
|
+
i++;
|
|
2179
|
+
break;
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
while (i < source.length && source[i] !== "{") i++;
|
|
2184
|
+
if (i >= source.length) {
|
|
2185
|
+
fIdx = source.indexOf(funcNeedle, fIdx + 1);
|
|
2186
|
+
continue;
|
|
2187
|
+
}
|
|
2188
|
+
const bodyStart = i + 1;
|
|
2189
|
+
const beforeFunction = source.slice(Math.max(0, fIdx - 16), fIdx);
|
|
2190
|
+
const asyncMatch = beforeFunction.match(/async\s+$/);
|
|
2191
|
+
const funcKeyword = asyncMatch ? fIdx - asyncMatch[0].length : fIdx;
|
|
2192
|
+
const snippet = source.substring(funcKeyword, bodyStart) + "}";
|
|
2193
|
+
let ast;
|
|
2194
|
+
try {
|
|
2195
|
+
ast = acorn3.parse(snippet, { ecmaVersion: 2022 });
|
|
2196
|
+
} catch {
|
|
2197
|
+
fIdx = source.indexOf(funcNeedle, fIdx + 1);
|
|
2198
|
+
continue;
|
|
2199
|
+
}
|
|
2200
|
+
const decl = ast.body[0];
|
|
2201
|
+
if (!decl || decl.type !== "FunctionDeclaration") {
|
|
2202
|
+
fIdx = source.indexOf(funcNeedle, fIdx + 1);
|
|
2203
|
+
continue;
|
|
2204
|
+
}
|
|
2205
|
+
if (decl.id?.name !== activateFuncName) {
|
|
2206
|
+
fIdx = source.indexOf(funcNeedle, fIdx + 1);
|
|
2207
|
+
continue;
|
|
2208
|
+
}
|
|
2209
|
+
log?.(` AST match (exported): ${decl.async ? "async " : ""}function ${activateFuncName} at ${funcKeyword}, body at ${bodyStart}`);
|
|
2210
|
+
return { bodyStart, funcKeyword, isAsync: decl.async === true };
|
|
2211
|
+
}
|
|
2212
|
+
log?.(` Export found activate => ${activateFuncName}, but function definition not found`);
|
|
2213
|
+
return null;
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
// src/patch-agent-host.js
|
|
2217
|
+
var import_fs8 = require("fs");
|
|
2218
|
+
var import_path6 = require("path");
|
|
2219
|
+
var acorn4 = __toESM(require("acorn"), 1);
|
|
2220
|
+
var TAG = "agent-host";
|
|
2221
|
+
var AGENT_HOST_ROUTER_MARKER = "__byokAgentHostUrlRewrite";
|
|
2222
|
+
var ENTRY_FINGERPRINTS = [
|
|
2223
|
+
"cursorAgentHostEnabled",
|
|
2224
|
+
"registerAgentHostProvider",
|
|
2225
|
+
"Activating agent host extension"
|
|
2226
|
+
];
|
|
2227
|
+
var NETWORK_FINGERPRINTS = [
|
|
2228
|
+
"agent.v1.AgentService",
|
|
2229
|
+
"RunSSE",
|
|
2230
|
+
"BidiAppend",
|
|
2231
|
+
"AiConnectTransportHandler",
|
|
2232
|
+
"HTTP/1.1 transport created with network settings"
|
|
2233
|
+
];
|
|
2234
|
+
function parseBundle2(source, label) {
|
|
2235
|
+
try {
|
|
2236
|
+
return acorn4.parse(source, { ecmaVersion: "latest", sourceType: "script" });
|
|
2237
|
+
} catch (error) {
|
|
2238
|
+
throw new Error(`${label} JavaScript parse failed: ${error.message}`);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
function agentHostDist(paths) {
|
|
2242
|
+
return paths.agentHostDist || (0, import_path6.dirname)(paths.agentHostMain);
|
|
2243
|
+
}
|
|
2244
|
+
function hasAgentHost(paths) {
|
|
2245
|
+
return Boolean(paths.agentHostMain && (0, import_fs8.existsSync)(paths.agentHostMain));
|
|
2246
|
+
}
|
|
2247
|
+
function hasValidPackage(paths) {
|
|
2248
|
+
const packagePath = paths.agentHostPackageJson || (0, import_path6.join)((0, import_path6.dirname)(agentHostDist(paths)), "package.json");
|
|
2249
|
+
if (!(0, import_fs8.existsSync)(packagePath)) return false;
|
|
2250
|
+
try {
|
|
2251
|
+
const pkg = JSON.parse((0, import_fs8.readFileSync)(packagePath, "utf-8"));
|
|
2252
|
+
return pkg.name === "cursor-agent-host" && pkg.publisher === "anysphere" && pkg.main === "./dist/main.js";
|
|
2253
|
+
} catch {
|
|
2254
|
+
return false;
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
function isAgentHostEntry(source) {
|
|
2258
|
+
return ENTRY_FINGERPRINTS.every((fingerprint) => source.includes(fingerprint));
|
|
2259
|
+
}
|
|
2260
|
+
function isAgentHostNetworkSource(source) {
|
|
2261
|
+
return NETWORK_FINGERPRINTS.every((fingerprint) => source.includes(fingerprint));
|
|
2262
|
+
}
|
|
2263
|
+
function listDistJavaScript(paths) {
|
|
2264
|
+
const dist = agentHostDist(paths);
|
|
2265
|
+
if (!(0, import_fs8.existsSync)(dist)) return [];
|
|
2266
|
+
return (0, import_fs8.readdirSync)(dist, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".js") && !entry.name.endsWith(".unminify.js")).map((entry) => (0, import_path6.join)(dist, entry.name));
|
|
2267
|
+
}
|
|
2268
|
+
function findAgentHostNetworkTargets(paths) {
|
|
2269
|
+
const targets = [];
|
|
2270
|
+
for (const file of listDistJavaScript(paths)) {
|
|
2271
|
+
const source = (0, import_fs8.readFileSync)(file, "utf-8");
|
|
2272
|
+
if (isAgentHostNetworkSource(source)) targets.push(file);
|
|
2273
|
+
}
|
|
2274
|
+
return targets;
|
|
2275
|
+
}
|
|
2276
|
+
function buildAgentHostRouter() {
|
|
2277
|
+
return buildNodeHttp11RouterPayload({
|
|
2278
|
+
guardMarker: AGENT_HOST_ROUTER_MARKER,
|
|
2279
|
+
processLabel: "agent-host"
|
|
2280
|
+
});
|
|
2281
|
+
}
|
|
2282
|
+
function prepareAgentHostPatch(paths, log) {
|
|
2283
|
+
if (!hasValidPackage(paths)) throw new Error("cursor-agent-host package fingerprint mismatch");
|
|
2284
|
+
const originalEntry = (0, import_fs8.readFileSync)(paths.agentHostMain, "utf-8");
|
|
2285
|
+
if (!isAgentHostEntry(originalEntry)) throw new Error("cursor-agent-host entry fingerprint mismatch");
|
|
2286
|
+
const networkTargets = findAgentHostNetworkTargets(paths);
|
|
2287
|
+
if (networkTargets.length === 0) throw new Error("Agent Host network transport chunk not found by content fingerprint");
|
|
2288
|
+
const originalByFile = /* @__PURE__ */ new Map();
|
|
2289
|
+
for (const file of /* @__PURE__ */ new Set([paths.agentHostMain, ...networkTargets])) {
|
|
2290
|
+
originalByFile.set(file, (0, import_fs8.readFileSync)(file, "utf-8"));
|
|
2291
|
+
}
|
|
2292
|
+
const patchedByFile = new Map(originalByFile);
|
|
2293
|
+
let entry = patchedByFile.get(paths.agentHostMain);
|
|
2294
|
+
if (!isNodeHttp11RouterPatched(entry, AGENT_HOST_ROUTER_MARKER)) {
|
|
2295
|
+
entry = buildAgentHostRouter() + entry;
|
|
2296
|
+
log?.(" Agent Host HTTP/1.1 whitelist router injected");
|
|
2297
|
+
}
|
|
2298
|
+
const waited = injectActivateWait(entry, "agent-host", log);
|
|
2299
|
+
if (!waited.ok) throw new Error("cursor-agent-host activate function not found");
|
|
2300
|
+
entry = waited.source;
|
|
2301
|
+
patchedByFile.set(paths.agentHostMain, entry);
|
|
2302
|
+
let websocketTargets = 0;
|
|
2303
|
+
for (const file of networkTargets) {
|
|
2304
|
+
const source = patchedByFile.get(file);
|
|
2305
|
+
if (!hasAgentWebSocketStack(source)) continue;
|
|
2306
|
+
websocketTargets++;
|
|
2307
|
+
const disabled = disableAgentWebSocket(source, (0, import_path6.basename)(file));
|
|
2308
|
+
patchedByFile.set(file, disabled.source);
|
|
2309
|
+
log?.(` Agent WebSocket disabled in content-matched chunk: ${(0, import_path6.basename)(file)}`);
|
|
2310
|
+
}
|
|
2311
|
+
for (const [file, source] of patchedByFile) {
|
|
2312
|
+
if (source !== originalByFile.get(file)) parseBundle2(source, (0, import_path6.basename)(file));
|
|
2313
|
+
}
|
|
2314
|
+
return { originalByFile, patchedByFile, networkTargets, websocketTargets };
|
|
2315
|
+
}
|
|
2316
|
+
function patchAgentHost(paths, log) {
|
|
2317
|
+
if (!hasAgentHost(paths)) {
|
|
2318
|
+
log?.("[agent-host] Not present (Cursor < 3.13), skipping");
|
|
2319
|
+
return false;
|
|
2320
|
+
}
|
|
2321
|
+
log?.("[agent-host] Patching independent Agent Host transport...");
|
|
2322
|
+
const prepared = prepareAgentHostPatch(paths, log);
|
|
2323
|
+
const modified = [];
|
|
2324
|
+
for (const [file, source] of prepared.patchedByFile) {
|
|
2325
|
+
if (source === prepared.originalByFile.get(file)) continue;
|
|
2326
|
+
createBackup(file, TAG, log);
|
|
2327
|
+
(0, import_fs8.writeFileSync)(file, source);
|
|
2328
|
+
modified.push(file);
|
|
2329
|
+
}
|
|
2330
|
+
if (modified.length === 0) {
|
|
2331
|
+
log?.("[agent-host] Already fully patched");
|
|
2332
|
+
return false;
|
|
2333
|
+
}
|
|
2334
|
+
updateChecksums(paths, modified, TAG, log);
|
|
2335
|
+
log?.(`[agent-host] Done (${modified.length} file(s), ${prepared.networkTargets.length} network chunk(s), ${prepared.websocketTargets} WebSocket chunk(s))`);
|
|
2336
|
+
return true;
|
|
2337
|
+
}
|
|
2338
|
+
function inspectAgentHostPatch(paths) {
|
|
2339
|
+
if (!hasAgentHost(paths)) {
|
|
2340
|
+
return {
|
|
2341
|
+
present: false,
|
|
2342
|
+
required: false,
|
|
2343
|
+
fullyPatched: true,
|
|
2344
|
+
entryValid: true,
|
|
2345
|
+
router: true,
|
|
2346
|
+
wait: true,
|
|
2347
|
+
networkTargets: [],
|
|
2348
|
+
websocketTargets: [],
|
|
2349
|
+
websocketDisabled: true,
|
|
2350
|
+
errors: []
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
const errors = [];
|
|
2354
|
+
const packageValid = hasValidPackage(paths);
|
|
2355
|
+
if (!packageValid) errors.push("package fingerprint mismatch");
|
|
2356
|
+
let entry = "";
|
|
2357
|
+
try {
|
|
2358
|
+
entry = (0, import_fs8.readFileSync)(paths.agentHostMain, "utf-8");
|
|
2359
|
+
} catch (error) {
|
|
2360
|
+
errors.push(error.message);
|
|
2361
|
+
}
|
|
2362
|
+
const entryValid = Boolean(entry) && isAgentHostEntry(entry);
|
|
2363
|
+
if (!entryValid) errors.push("entry fingerprint mismatch");
|
|
2364
|
+
const router = Boolean(entry) && isNodeHttp11RouterPatched(entry, AGENT_HOST_ROUTER_MARKER);
|
|
2365
|
+
const wait = Boolean(entry) && hasActivateWait(entry);
|
|
2366
|
+
let networkTargets = [];
|
|
2367
|
+
try {
|
|
2368
|
+
networkTargets = findAgentHostNetworkTargets(paths);
|
|
2369
|
+
} catch (error) {
|
|
2370
|
+
errors.push(error.message);
|
|
2371
|
+
}
|
|
2372
|
+
if (networkTargets.length === 0) errors.push("network transport chunk not found");
|
|
2373
|
+
const websocketTargets = [];
|
|
2374
|
+
let websocketDisabled = true;
|
|
2375
|
+
for (const file of networkTargets) {
|
|
2376
|
+
try {
|
|
2377
|
+
const source = (0, import_fs8.readFileSync)(file, "utf-8");
|
|
2378
|
+
if (!hasAgentWebSocketStack(source)) continue;
|
|
2379
|
+
websocketTargets.push(file);
|
|
2380
|
+
if (!isAgentWebSocketDisabled(source, (0, import_path6.basename)(file))) websocketDisabled = false;
|
|
2381
|
+
} catch (error) {
|
|
2382
|
+
websocketDisabled = false;
|
|
2383
|
+
errors.push(error.message);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
const fullyPatched = packageValid && entryValid && router && wait && networkTargets.length > 0 && websocketDisabled && errors.length === 0;
|
|
2387
|
+
return {
|
|
2388
|
+
present: true,
|
|
2389
|
+
required: true,
|
|
2390
|
+
fullyPatched,
|
|
2391
|
+
entryValid,
|
|
2392
|
+
router,
|
|
2393
|
+
wait,
|
|
2394
|
+
networkTargets,
|
|
2395
|
+
websocketTargets,
|
|
2396
|
+
websocketDisabled,
|
|
2397
|
+
errors
|
|
2398
|
+
};
|
|
2399
|
+
}
|
|
2400
|
+
function isAgentHostPatched(paths) {
|
|
2401
|
+
return inspectAgentHostPatch(paths).fullyPatched;
|
|
2402
|
+
}
|
|
2403
|
+
function checkAgentHostPatch(paths, log) {
|
|
2404
|
+
if (!hasAgentHost(paths)) {
|
|
2405
|
+
log?.(" cursor-agent-host not present (pre-3.13, not required)");
|
|
2406
|
+
return true;
|
|
2407
|
+
}
|
|
2408
|
+
const current = inspectAgentHostPatch(paths);
|
|
2409
|
+
if (current.fullyPatched) {
|
|
2410
|
+
log?.(` Already patched: entry + ${current.networkTargets.length} content-matched network chunk(s)`);
|
|
2411
|
+
return true;
|
|
2412
|
+
}
|
|
2413
|
+
try {
|
|
2414
|
+
const prepared = prepareAgentHostPatch(paths, log);
|
|
2415
|
+
log?.(` [OK] Agent Host entry/router/activate target found`);
|
|
2416
|
+
log?.(` [OK] ${prepared.networkTargets.length} network chunk(s) found by semantic fingerprints`);
|
|
2417
|
+
log?.(` [OK] ${prepared.websocketTargets} WebSocket chunk(s) can be disabled`);
|
|
2418
|
+
return true;
|
|
2419
|
+
} catch (error) {
|
|
2420
|
+
log?.(` [FAIL] ${error.message}`);
|
|
2421
|
+
return false;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
function getAgentHostBackupTargets(paths) {
|
|
2425
|
+
const targets = /* @__PURE__ */ new Set();
|
|
2426
|
+
if (paths.agentHostMain) targets.add(paths.agentHostMain);
|
|
2427
|
+
const dist = agentHostDist(paths);
|
|
2428
|
+
if (!(0, import_fs8.existsSync)(dist)) return [...targets];
|
|
2429
|
+
const marker = `.backup-byok-${TAG}-`;
|
|
2430
|
+
for (const entry of (0, import_fs8.readdirSync)(dist, { withFileTypes: true })) {
|
|
2431
|
+
if (!entry.isFile()) continue;
|
|
2432
|
+
const index = entry.name.indexOf(marker);
|
|
2433
|
+
if (index > 0) targets.add((0, import_path6.join)(dist, entry.name.slice(0, index)));
|
|
2434
|
+
}
|
|
2435
|
+
return [...targets].sort();
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
// src/patch-katex.js
|
|
2439
|
+
var import_fs9 = require("fs");
|
|
2440
|
+
var KATEX_LINK = '<link rel="stylesheet" href="../../../../../extensions/markdown-math/notebook-out/katex.min.css">';
|
|
2441
|
+
var MARKER = "katex.min.css";
|
|
2442
|
+
function parseSemver2(v) {
|
|
2443
|
+
const [major = 0, minor = 0, patch = 0] = String(v || "0.0.0").split(".").map((n) => Number(n) || 0);
|
|
2444
|
+
return { major, minor, patch };
|
|
2445
|
+
}
|
|
2446
|
+
function needsKatexPatch(paths) {
|
|
2447
|
+
const v = parseSemver2(paths?.cursorVersion);
|
|
2448
|
+
if (v.major !== 3) return false;
|
|
2449
|
+
return v.minor >= 6 && v.minor < 9;
|
|
2450
|
+
}
|
|
2451
|
+
function patchKatex(paths, log) {
|
|
2452
|
+
if (!needsKatexPatch(paths)) {
|
|
2453
|
+
const v = paths?.cursorVersion || "?";
|
|
2454
|
+
log?.(`[katex] Cursor ${v} outside 3.6\u20133.8 range, skipping (official KaTeX CSS present or not yet regressed)`);
|
|
2455
|
+
return false;
|
|
2456
|
+
}
|
|
2457
|
+
const htmlPath = `${paths.appRoot}/out/vs/code/electron-sandbox/workbench/workbench.html`;
|
|
2458
|
+
if (!(0, import_fs9.existsSync)(htmlPath)) {
|
|
2459
|
+
log?.("[katex] WARNING: workbench.html not found, skipping");
|
|
2460
|
+
return false;
|
|
2461
|
+
}
|
|
2462
|
+
const katexCssPath = `${paths.appRoot}/extensions/markdown-math/notebook-out/katex.min.css`;
|
|
2463
|
+
if (!(0, import_fs9.existsSync)(katexCssPath)) {
|
|
2464
|
+
log?.("[katex] WARNING: katex.min.css not found, skipping");
|
|
2465
|
+
return false;
|
|
2466
|
+
}
|
|
2467
|
+
let html = (0, import_fs9.readFileSync)(htmlPath, "utf-8");
|
|
2468
|
+
if (html.includes(MARKER)) {
|
|
2469
|
+
log?.("[katex] already linked");
|
|
2470
|
+
return false;
|
|
2471
|
+
}
|
|
2472
|
+
createBackup(htmlPath, "katex", log);
|
|
2473
|
+
const needle = 'workbench.desktop.main.css">';
|
|
2474
|
+
const idx = html.indexOf(needle);
|
|
2475
|
+
if (idx === -1) {
|
|
2476
|
+
log?.("[katex] WARNING: workbench CSS link not found in HTML, appending to <head>");
|
|
2477
|
+
html = html.replace("</head>", ` ${KATEX_LINK}
|
|
2478
|
+
</head>`);
|
|
2479
|
+
} else {
|
|
2480
|
+
html = html.slice(0, idx + needle.length) + "\n " + KATEX_LINK + html.slice(idx + needle.length);
|
|
2481
|
+
}
|
|
2482
|
+
(0, import_fs9.writeFileSync)(htmlPath, html, "utf-8");
|
|
2483
|
+
log?.("[katex] linked katex.min.css in workbench.html");
|
|
2484
|
+
updateChecksums(paths, [htmlPath], "katex", log);
|
|
2485
|
+
log?.("[katex] Done");
|
|
2486
|
+
return true;
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
// src/patch-proxy-39.js
|
|
2490
|
+
var import_fs10 = require("fs");
|
|
2491
|
+
var import_path7 = require("path");
|
|
2492
|
+
var TAG2 = "proxy-39";
|
|
2493
|
+
var SYNC_MARKER = "__byokSyncBuiltinESMExports";
|
|
2494
|
+
var SYNC_CALL_MARKER = "/*BYOK-PROXY39*/";
|
|
2495
|
+
var ROUTER_MARKER = "__byokSingletonUrlRewrite";
|
|
2496
|
+
var ROUTER_CALL_MARKER = "/*BYOK-SINGLETON-ROUTER*/";
|
|
2497
|
+
var TARGET_REL = "out/vs/code/electron-utility/alwaysLocalSingleton/alwaysLocalSingletonMain.js";
|
|
2498
|
+
function parseSemver3(v) {
|
|
2499
|
+
const [major = 0, minor = 0, patch = 0] = String(v || "0.0.0").split(".").map((n) => Number(n) || 0);
|
|
2500
|
+
return { major, minor, patch };
|
|
2501
|
+
}
|
|
2502
|
+
function is39OrNewer(version) {
|
|
2503
|
+
const v = parseSemver3(version);
|
|
2504
|
+
return v.major > 3 || v.major === 3 && v.minor >= 9;
|
|
2505
|
+
}
|
|
2506
|
+
function is1125OrNewer(version) {
|
|
2507
|
+
const v = parseSemver3(version);
|
|
2508
|
+
if (v.major > 3) return true;
|
|
2509
|
+
if (v.major < 3) return false;
|
|
2510
|
+
if (v.minor > 11) return true;
|
|
2511
|
+
if (v.minor < 11) return false;
|
|
2512
|
+
return v.patch >= 25;
|
|
2513
|
+
}
|
|
2514
|
+
function getProxy39Target(paths) {
|
|
2515
|
+
return paths.alwaysLocalSingletonJs || (0, import_path7.join)(paths.appRoot, TARGET_REL);
|
|
2516
|
+
}
|
|
2517
|
+
function needsProxy39Patch(paths) {
|
|
2518
|
+
return is39OrNewer(paths.cursorVersion) && (0, import_fs10.existsSync)(getProxy39Target(paths));
|
|
2519
|
+
}
|
|
2520
|
+
function hasSyncPatch(code) {
|
|
2521
|
+
return code.includes(SYNC_CALL_MARKER);
|
|
2522
|
+
}
|
|
2523
|
+
function hasRouterPatch(code) {
|
|
2524
|
+
return code.includes(ROUTER_MARKER);
|
|
2525
|
+
}
|
|
2526
|
+
function isProxy39Patched(paths) {
|
|
2527
|
+
const target = getProxy39Target(paths);
|
|
2528
|
+
if (!(0, import_fs10.existsSync)(target)) return false;
|
|
2529
|
+
const code = (0, import_fs10.readFileSync)(target, "utf-8");
|
|
2530
|
+
const syncOk = hasSyncPatch(code) || is1125OrNewer(paths.cursorVersion);
|
|
2531
|
+
return hasRouterPatch(code) && syncOk;
|
|
2532
|
+
}
|
|
2533
|
+
function findCreateRequireAlias(source) {
|
|
2534
|
+
const re = /import\s*\{([^}]*)\}\s*from\s*(["'])node:module\2;?/g;
|
|
2535
|
+
let match;
|
|
2536
|
+
while ((match = re.exec(source)) !== null) {
|
|
2537
|
+
const spec = match[1].trim();
|
|
2538
|
+
const alias = spec.match(/\bcreateRequire\s+as\s+([$A-Z_a-z][$\w]*)\b/)?.[1];
|
|
2539
|
+
if (alias) return alias;
|
|
2540
|
+
if (/\bcreateRequire\b/.test(spec)) return "createRequire";
|
|
2541
|
+
}
|
|
2542
|
+
return null;
|
|
2543
|
+
}
|
|
2544
|
+
function ensureSyncImport(source) {
|
|
2545
|
+
const re = /import\s*\{([^}]*)\}\s*from\s*(["'])node:module\2;?/g;
|
|
2546
|
+
let match;
|
|
2547
|
+
let targetMatch = null;
|
|
2548
|
+
let createRequireName = null;
|
|
2549
|
+
while ((match = re.exec(source)) !== null) {
|
|
2550
|
+
const spec2 = match[1].trim();
|
|
2551
|
+
const alias = spec2.match(/\bcreateRequire\s+as\s+([$A-Z_a-z][$\w]*)\b/)?.[1];
|
|
2552
|
+
if (alias) createRequireName = alias;
|
|
2553
|
+
else if (/\bcreateRequire\b/.test(spec2)) createRequireName = "createRequire";
|
|
2554
|
+
const syncAlias = spec2.match(/\bsyncBuiltinESMExports\s+as\s+([$A-Z_a-z][$\w]*)\b/)?.[1];
|
|
2555
|
+
if (syncAlias) return { source, fnName: syncAlias, createRequireName };
|
|
2556
|
+
if (/\bsyncBuiltinESMExports\b/.test(spec2)) return { source, fnName: "syncBuiltinESMExports", createRequireName };
|
|
2557
|
+
if (!targetMatch && createRequireName) targetMatch = match;
|
|
2558
|
+
}
|
|
2559
|
+
if (!createRequireName) {
|
|
2560
|
+
throw new Error("node:module createRequire import not found in alwaysLocalSingletonMain.js");
|
|
2561
|
+
}
|
|
2562
|
+
if (!targetMatch) {
|
|
2563
|
+
throw new Error("node:module import for createRequire not found");
|
|
2564
|
+
}
|
|
2565
|
+
const spec = targetMatch[1].trim();
|
|
2566
|
+
const replacement = `import{${spec},syncBuiltinESMExports as ${SYNC_MARKER}}from${targetMatch[2]}node:module${targetMatch[2]};`;
|
|
2567
|
+
return { source: source.replace(targetMatch[0], replacement), fnName: SYNC_MARKER, createRequireName };
|
|
2568
|
+
}
|
|
2569
|
+
function buildSingletonRouterCall(createRequireName) {
|
|
2570
|
+
const fallbackHost = JSON.stringify(DEFAULT_HOST);
|
|
2571
|
+
const fallbackPort = String(DEFAULT_PORT);
|
|
2572
|
+
const configDirName = JSON.stringify(BEATCURSOR_DIR_NAME);
|
|
2573
|
+
const routesFile = JSON.stringify(ROUTES_FILE_NAME);
|
|
2574
|
+
return `${ROUTER_CALL_MARKER}(function(__byokCreateRequire){if(globalThis.${ROUTER_MARKER})return;globalThis.${ROUTER_MARKER}=true;var _require=__byokCreateRequire(import.meta.url);var _http=_require("http");var _https=_require("https");var _fs=_require("fs");var _path=_require("path");var _os=_require("os");var _proxyHttp=_http.request;var _proxyHttps=_https.request;var _directHttp=(_http.__vscodeOriginal&&_http.__vscodeOriginal.request)||_proxyHttp;var ROUTES_PATH=_path.join(_os.homedir(),${configDirName},${routesFile});var FALLBACK_HOST=${fallbackHost};var FALLBACK_PORT=${fallbackPort};var state={host:FALLBACK_HOST,port:FALLBACK_PORT,base:"http://"+FALLBACK_HOST+":"+FALLBACK_PORT,svcSet:new Set(),methodSet:new Set(),restSet:new Set(),ruleCount:0,restCount:0};function loadConfig(){try{var raw=_fs.readFileSync(ROUTES_PATH,"utf-8");var cfg=JSON.parse(raw);var host=(cfg&&cfg.server&&cfg.server.host)||FALLBACK_HOST;var port=(cfg&&cfg.server&&cfg.server.port)||FALLBACK_PORT;var rules=(cfg&&Array.isArray(cfg.redirect))?cfg.redirect:[];var svcSet=new Set(),methodSet=new Set(),restSet=new Set(),ruleCount=0,restCount=0;for(var i=0;i<rules.length;i++){var r=rules[i];if(typeof r!=="string")continue;if(r.indexOf("REST:")===0){restSet.add(r.slice(5));restCount++}else if(r.indexOf("/")!==-1){methodSet.add(r);ruleCount++}else{svcSet.add(r);ruleCount++}}return{host:host,port:port,base:"http://"+host+":"+port,svcSet:svcSet,methodSet:methodSet,restSet:restSet,ruleCount:ruleCount,restCount:restCount}}catch(e){return{host:FALLBACK_HOST,port:FALLBACK_PORT,base:"http://"+FALLBACK_HOST+":"+FALLBACK_PORT,svcSet:new Set(),methodSet:new Set(),restSet:new Set(),ruleCount:0,restCount:0}}}function applyState(label){state=loadConfig();console.log("[BYOK] singleton "+label+" -> "+state.base+" (ConnectRPC="+state.ruleCount+", REST="+state.restCount+")")}applyState("routes loaded");try{_fs.watchFile(ROUTES_PATH,{interval:2000,persistent:false},function(){applyState("routes reloaded")})}catch(e){console.warn("[BYOK] singleton watchFile failed: "+e.message)}function isApiHost(h){h=String(h||"").toLowerCase();return /(^|\\.)api[234]\\.cursor\\.sh$|(^|\\.)api5\\.cursor\\.sh$|(^|\\.)gcpp\\.cursor\\.sh$/.test(h)}function normalizePath(p){p=String(p||"");var q=p.indexOf("?");return q===-1?p:p.slice(0,q)}function shouldRedirect(pathname){pathname=normalizePath(pathname);if(!pathname||pathname.length<2)return false;if(state.restSet.has(pathname))return true;var p=pathname.charAt(0)==="/"?pathname.slice(1):pathname;var slash=p.indexOf("/");if(slash===-1)return false;if(state.methodSet.has(p))return true;var svc=p.slice(0,slash);return state.svcSet.has(svc)}function parseUrl(u){try{if(typeof u==="string"){var s=new URL(u);return{hostname:s.hostname,path:s.pathname+s.search,raw:u,kind:"string"}}if(u instanceof URL)return{hostname:u.hostname,path:u.pathname+u.search,raw:u,kind:"url"};if(u&&typeof u==="object"){var host=u.hostname||(u.host?String(u.host).replace(/:\\d+$/,""):"");var path=u.path||((u.pathname||"/")+(u.search||""));return{hostname:host,path:path,raw:u,kind:"object"}}}catch(e){}return null}function rewriteToString(p){return state.base+(p.path&&p.path.charAt(0)==="/"?p.path:"/"+(p.path||""))}function rewriteOpts(u){var o=Object.assign({},u);o.protocol="http:";o.hostname=state.host;o.host=state.host+":"+state.port;o.port=state.port;return o}function intercept(isHttps){return function(u,o,cb){var parsed=parseUrl(u);if(parsed&&isApiHost(parsed.hostname)&&shouldRedirect(parsed.path)){if(parsed.kind==="object")return _directHttp.call(_http,rewriteOpts(parsed.raw),o,cb);return _directHttp.call(_http,rewriteToString(parsed),o,cb)}return(isHttps?_proxyHttps:_proxyHttp).call(isHttps?_https:_http,u,o,cb)}}_http.request=intercept(false);_https.request=intercept(true);console.log("[BYOK] singleton whitelist router active (config: "+ROUTES_PATH+")")})(${createRequireName})`;
|
|
2575
|
+
}
|
|
2576
|
+
function insertBeforeSyncCall(source, routerCall, fnName) {
|
|
2577
|
+
const exact = `${SYNC_CALL_MARKER}${fnName}()`;
|
|
2578
|
+
const idx = source.indexOf(exact);
|
|
2579
|
+
if (idx !== -1) {
|
|
2580
|
+
return source.slice(0, idx) + `${routerCall},` + source.slice(idx);
|
|
2581
|
+
}
|
|
2582
|
+
const call = `${fnName}()`;
|
|
2583
|
+
const phrase = "[AlwaysLocalSingleton] proxy-agent patches installed";
|
|
2584
|
+
const anchor = source.indexOf(phrase);
|
|
2585
|
+
if (anchor === -1) throw new Error("proxy-agent installed log anchor not found in alwaysLocalSingletonMain.js");
|
|
2586
|
+
const callIdx = source.lastIndexOf(call, anchor);
|
|
2587
|
+
if (callIdx === -1) throw new Error("syncBuiltinESMExports call not found before proxy-agent log anchor");
|
|
2588
|
+
return source.slice(0, callIdx) + `${routerCall},${SYNC_CALL_MARKER}` + source.slice(callIdx);
|
|
2589
|
+
}
|
|
2590
|
+
function insertRouterOnly(source, routerCall) {
|
|
2591
|
+
const phrase = "[AlwaysLocalSingleton] proxy-agent patches installed";
|
|
2592
|
+
const idx = source.indexOf(phrase);
|
|
2593
|
+
if (idx === -1) throw new Error("proxy-agent installed log anchor not found in alwaysLocalSingletonMain.js");
|
|
2594
|
+
const start = Math.max(0, idx - 600);
|
|
2595
|
+
const window = source.slice(start, idx);
|
|
2596
|
+
const commaIdx = window.lastIndexOf("),");
|
|
2597
|
+
if (commaIdx === -1) throw new Error("proxy-agent install call not found before log anchor");
|
|
2598
|
+
const insertAt = start + commaIdx + 1;
|
|
2599
|
+
return source.slice(0, insertAt) + `,${routerCall}` + source.slice(insertAt);
|
|
2600
|
+
}
|
|
2601
|
+
function insertPatches(source, fnName, createRequireName, nativeSync) {
|
|
2602
|
+
const hasRouter = hasRouterPatch(source);
|
|
2603
|
+
const hasSync = hasSyncPatch(source) || nativeSync;
|
|
2604
|
+
if (hasRouter && hasSync) return source;
|
|
2605
|
+
const routerCall = buildSingletonRouterCall(createRequireName);
|
|
2606
|
+
if (nativeSync) {
|
|
2607
|
+
if (hasRouter) return source;
|
|
2608
|
+
return insertRouterOnly(source, routerCall);
|
|
2609
|
+
}
|
|
2610
|
+
if (hasSync && !hasRouter) {
|
|
2611
|
+
return insertBeforeSyncCall(source, routerCall, fnName);
|
|
2612
|
+
}
|
|
2613
|
+
const directRe = /([$_A-Z_a-z][$\w]*)\(([^(){};]{1,160})\),\s*([$_A-Z_a-z][$\w]*)\.info\((["'])\[AlwaysLocalSingleton\] proxy-agent patches installed\4\)/;
|
|
2614
|
+
if (directRe.test(source)) {
|
|
2615
|
+
return source.replace(directRe, (_m, installFn, arg, logger, quote) => {
|
|
2616
|
+
const syncCall = hasSync ? "" : `,${SYNC_CALL_MARKER}${fnName}()`;
|
|
2617
|
+
const router = hasRouter ? "" : `,${routerCall}`;
|
|
2618
|
+
return `${installFn}(${arg})${router}${syncCall},${logger}.info(${quote}[AlwaysLocalSingleton] proxy-agent patches installed${quote})`;
|
|
2619
|
+
});
|
|
2620
|
+
}
|
|
2621
|
+
const phrase = "[AlwaysLocalSingleton] proxy-agent patches installed";
|
|
2622
|
+
const anchorIdx = source.indexOf(phrase);
|
|
2623
|
+
if (anchorIdx === -1) {
|
|
2624
|
+
throw new Error("proxy-agent installed log anchor not found in alwaysLocalSingletonMain.js");
|
|
2625
|
+
}
|
|
2626
|
+
const start = Math.max(0, anchorIdx - 400);
|
|
2627
|
+
const window = source.slice(start, anchorIdx);
|
|
2628
|
+
const commaIdx = window.lastIndexOf("),");
|
|
2629
|
+
if (commaIdx === -1) {
|
|
2630
|
+
throw new Error("proxy-agent install call not found before log anchor");
|
|
2631
|
+
}
|
|
2632
|
+
const insertAt = start + commaIdx + 1;
|
|
2633
|
+
const patchCalls = `${hasRouter ? "" : `,${routerCall}`}${hasSync ? "" : `,${SYNC_CALL_MARKER}${fnName}()`}`;
|
|
2634
|
+
return source.slice(0, insertAt) + patchCalls + source.slice(insertAt);
|
|
2635
|
+
}
|
|
2636
|
+
function patchProxy39(paths, log) {
|
|
2637
|
+
if (!is39OrNewer(paths.cursorVersion)) {
|
|
2638
|
+
log?.("[proxy-39] Cursor < 3.9, skipping");
|
|
2639
|
+
return false;
|
|
2640
|
+
}
|
|
2641
|
+
const target = getProxy39Target(paths);
|
|
2642
|
+
if (!(0, import_fs10.existsSync)(target)) {
|
|
2643
|
+
log?.("[proxy-39] alwaysLocalSingletonMain.js not found, skipping");
|
|
2644
|
+
return false;
|
|
2645
|
+
}
|
|
2646
|
+
let code = (0, import_fs10.readFileSync)(target, "utf-8");
|
|
2647
|
+
if (isProxy39Patched(paths)) {
|
|
2648
|
+
log?.("[proxy-39] Singleton BYOK router/proxy sync already applied");
|
|
2649
|
+
return false;
|
|
2650
|
+
}
|
|
2651
|
+
if (!/from\s*["']https["']/.test(code) || !/from\s*["']http["']/.test(code) || !code.includes("proxy-agent patches installed")) {
|
|
2652
|
+
log?.("[proxy-39] 3.9 inline HTTP/1.1 transport signature not found, skipping");
|
|
2653
|
+
return false;
|
|
2654
|
+
}
|
|
2655
|
+
const nativeSync = is1125OrNewer(paths.cursorVersion);
|
|
2656
|
+
if (nativeSync) {
|
|
2657
|
+
log?.("[proxy-39] 3.11.25+ detected: native syncBuiltinESMExports, injecting router only...");
|
|
2658
|
+
const createRequireName = findCreateRequireAlias(code);
|
|
2659
|
+
if (!createRequireName) {
|
|
2660
|
+
throw new Error("node:module createRequire import not found in alwaysLocalSingletonMain.js");
|
|
2661
|
+
}
|
|
2662
|
+
code = insertPatches(code, null, createRequireName, true);
|
|
2663
|
+
} else {
|
|
2664
|
+
log?.("[proxy-39] Patching singleton BYOK router + proxy sync...");
|
|
2665
|
+
const imported = ensureSyncImport(code);
|
|
2666
|
+
code = insertPatches(imported.source, imported.fnName, imported.createRequireName, false);
|
|
2667
|
+
}
|
|
2668
|
+
if (!hasRouterPatch(code)) {
|
|
2669
|
+
throw new Error("proxy-39 patch insertion failed verification (router)");
|
|
2670
|
+
}
|
|
2671
|
+
if (!nativeSync && !hasSyncPatch(code)) {
|
|
2672
|
+
throw new Error("proxy-39 patch insertion failed verification (sync)");
|
|
2673
|
+
}
|
|
2674
|
+
createBackup(target, TAG2, log);
|
|
2675
|
+
(0, import_fs10.writeFileSync)(target, code);
|
|
2676
|
+
updateChecksums(paths, [target], TAG2, log);
|
|
2677
|
+
log?.("[proxy-39] Done");
|
|
2678
|
+
return true;
|
|
2679
|
+
}
|
|
2680
|
+
function checkProxy39Patch(paths, log) {
|
|
2681
|
+
if (!is39OrNewer(paths.cursorVersion)) {
|
|
2682
|
+
log?.(" Cursor < 3.9, not required");
|
|
2683
|
+
return true;
|
|
2684
|
+
}
|
|
2685
|
+
const target = getProxy39Target(paths);
|
|
2686
|
+
if (!(0, import_fs10.existsSync)(target)) {
|
|
2687
|
+
log?.(" alwaysLocalSingletonMain.js not found");
|
|
2688
|
+
return false;
|
|
2689
|
+
}
|
|
2690
|
+
const code = (0, import_fs10.readFileSync)(target, "utf-8");
|
|
2691
|
+
const nativeSync = is1125OrNewer(paths.cursorVersion);
|
|
2692
|
+
if (hasRouterPatch(code) && (hasSyncPatch(code) || nativeSync)) {
|
|
2693
|
+
log?.(" Already patched");
|
|
2694
|
+
return true;
|
|
2695
|
+
}
|
|
2696
|
+
try {
|
|
2697
|
+
if (nativeSync) {
|
|
2698
|
+
const createRequireName = findCreateRequireAlias(code);
|
|
2699
|
+
if (!createRequireName) throw new Error("createRequire alias not found");
|
|
2700
|
+
const patched = insertPatches(code, null, createRequireName, true);
|
|
2701
|
+
if (!hasRouterPatch(patched)) throw new Error("dry-run did not produce router marker");
|
|
2702
|
+
log?.(" [OK] 3.11.25+ singleton BYOK router insertion point found (native sync)");
|
|
2703
|
+
} else {
|
|
2704
|
+
const imported = ensureSyncImport(code);
|
|
2705
|
+
const patched = insertPatches(imported.source, imported.fnName, imported.createRequireName, false);
|
|
2706
|
+
if (!hasRouterPatch(patched) || !hasSyncPatch(patched)) {
|
|
2707
|
+
throw new Error("dry-run insertion did not produce both router and sync markers");
|
|
2708
|
+
}
|
|
2709
|
+
log?.(" [OK] singleton BYOK router/proxy sync insertion point found");
|
|
2710
|
+
}
|
|
2711
|
+
return true;
|
|
2712
|
+
} catch (e) {
|
|
2713
|
+
log?.(` [FAIL] ${e.message}`);
|
|
2714
|
+
return false;
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
// src/patch-http-protocol.js
|
|
2719
|
+
var import_fs11 = require("fs");
|
|
2720
|
+
var import_os3 = require("os");
|
|
2721
|
+
var import_path8 = require("path");
|
|
2722
|
+
var TAG3 = "http-protocol";
|
|
2723
|
+
var HTTP2_SETTING = "cursor.general.disableHttp2";
|
|
2724
|
+
var HTTP1_SSE_SETTING = "cursor.general.disableHttp1SSE";
|
|
2725
|
+
function getUserSettingsPath() {
|
|
2726
|
+
const override = process.env.CURSOR_USER_SETTINGS;
|
|
2727
|
+
if (override) return override;
|
|
2728
|
+
const home = (0, import_os3.homedir)();
|
|
2729
|
+
switch ((0, import_os3.platform)()) {
|
|
2730
|
+
case "darwin":
|
|
2731
|
+
return (0, import_path8.join)(home, "Library", "Application Support", "Cursor", "User", "settings.json");
|
|
2732
|
+
case "win32":
|
|
2733
|
+
return (0, import_path8.join)(process.env.APPDATA || (0, import_path8.join)(home, "AppData", "Roaming"), "Cursor", "User", "settings.json");
|
|
2734
|
+
default:
|
|
2735
|
+
return (0, import_path8.join)(process.env.XDG_CONFIG_HOME || (0, import_path8.join)(home, ".config"), "Cursor", "User", "settings.json");
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
function settingPattern(key) {
|
|
2739
|
+
return new RegExp(`("${key.replace(/\./g, "\\.")}"\\s*:\\s*)(true|false)`);
|
|
2740
|
+
}
|
|
2741
|
+
function readSettings(file) {
|
|
2742
|
+
if (!(0, import_fs11.existsSync)(file)) return null;
|
|
2743
|
+
try {
|
|
2744
|
+
return (0, import_fs11.readFileSync)(file, "utf-8");
|
|
2745
|
+
} catch {
|
|
2746
|
+
return null;
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
function detectIndent(source) {
|
|
2750
|
+
const m = source.match(/\n([ \t]+)"/);
|
|
2751
|
+
return m ? m[1] : " ";
|
|
2752
|
+
}
|
|
2753
|
+
function readBool(source, key) {
|
|
2754
|
+
const m = source.match(settingPattern(key));
|
|
2755
|
+
if (!m) return void 0;
|
|
2756
|
+
return m[2] === "true";
|
|
2757
|
+
}
|
|
2758
|
+
function inspectHttpProtocolSettings() {
|
|
2759
|
+
const file = getUserSettingsPath();
|
|
2760
|
+
const source = readSettings(file);
|
|
2761
|
+
if (source === null) {
|
|
2762
|
+
return { file, exists: false, http2Disabled: void 0, http1SseDisabled: void 0, ok: false };
|
|
2763
|
+
}
|
|
2764
|
+
const http2Disabled = readBool(source, HTTP2_SETTING);
|
|
2765
|
+
const http1SseDisabled = readBool(source, HTTP1_SSE_SETTING);
|
|
2766
|
+
return {
|
|
2767
|
+
file,
|
|
2768
|
+
exists: true,
|
|
2769
|
+
http2Disabled,
|
|
2770
|
+
http1SseDisabled,
|
|
2771
|
+
// 两个键都取默认值 false 时 → useHttp2=true → bidi Run → Protocol error
|
|
2772
|
+
ok: http2Disabled === true && http1SseDisabled !== true
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
function insertSetting(source, key, value, indent) {
|
|
2776
|
+
const brace = source.indexOf("{");
|
|
2777
|
+
if (brace === -1) return null;
|
|
2778
|
+
const line = `
|
|
2779
|
+
${indent}"${key}": ${value},`;
|
|
2780
|
+
return source.slice(0, brace + 1) + line + source.slice(brace + 1);
|
|
2781
|
+
}
|
|
2782
|
+
function applySetting(source, key, value, indent) {
|
|
2783
|
+
const pattern = settingPattern(key);
|
|
2784
|
+
if (pattern.test(source)) {
|
|
2785
|
+
return source.replace(pattern, `$1${value}`);
|
|
2786
|
+
}
|
|
2787
|
+
return insertSetting(source, key, value, indent);
|
|
2788
|
+
}
|
|
2789
|
+
function patchHttpProtocolSettings(log) {
|
|
2790
|
+
const file = getUserSettingsPath();
|
|
2791
|
+
const state = inspectHttpProtocolSettings();
|
|
2792
|
+
if (state.ok) {
|
|
2793
|
+
log?.(" HTTP/1.1 SSE transport already configured");
|
|
2794
|
+
return { changed: false, skipped: true, reason: "already-configured" };
|
|
2795
|
+
}
|
|
2796
|
+
if (!state.exists) {
|
|
2797
|
+
const dir = file.slice(0, Math.max(file.lastIndexOf("/"), file.lastIndexOf("\\")));
|
|
2798
|
+
if (!(0, import_fs11.existsSync)(dir)) {
|
|
2799
|
+
log?.(` Cursor user directory not found: ${dir}`);
|
|
2800
|
+
return { changed: false, skipped: true, reason: "no-user-dir" };
|
|
2801
|
+
}
|
|
2802
|
+
(0, import_fs11.writeFileSync)(file, `{
|
|
2803
|
+
"${HTTP2_SETTING}": true
|
|
2804
|
+
}
|
|
2805
|
+
`, "utf-8");
|
|
2806
|
+
log?.(` Created settings.json with ${HTTP2_SETTING}=true`);
|
|
2807
|
+
return { changed: true, skipped: false, reason: "created" };
|
|
2808
|
+
}
|
|
2809
|
+
const source = readSettings(file);
|
|
2810
|
+
const indent = detectIndent(source);
|
|
2811
|
+
let next = source;
|
|
2812
|
+
if (state.http2Disabled !== true) {
|
|
2813
|
+
const applied = applySetting(next, HTTP2_SETTING, "true", indent);
|
|
2814
|
+
if (applied === null) {
|
|
2815
|
+
log?.(" settings.json has no top-level object; skipped");
|
|
2816
|
+
return { changed: false, skipped: true, reason: "unparsable" };
|
|
2817
|
+
}
|
|
2818
|
+
next = applied;
|
|
2819
|
+
}
|
|
2820
|
+
if (state.http1SseDisabled === true) {
|
|
2821
|
+
next = applySetting(next, HTTP1_SSE_SETTING, "false", indent);
|
|
2822
|
+
}
|
|
2823
|
+
if (next === source) {
|
|
2824
|
+
return { changed: false, skipped: true, reason: "no-op" };
|
|
2825
|
+
}
|
|
2826
|
+
createBackup(file, TAG3, log);
|
|
2827
|
+
(0, import_fs11.writeFileSync)(file, next, "utf-8");
|
|
2828
|
+
log?.(` ${HTTP2_SETTING}=true (agent stream \u2192 HTTP/1.1 SSE)`);
|
|
2829
|
+
return { changed: true, skipped: false, reason: "patched" };
|
|
2830
|
+
}
|
|
2831
|
+
function unpatchHttpProtocolSettings(log) {
|
|
2832
|
+
const file = getUserSettingsPath();
|
|
2833
|
+
const source = readSettings(file);
|
|
2834
|
+
if (source === null) return false;
|
|
2835
|
+
const lineOf = (key) => new RegExp(`^[ \\t]*"${key.replace(/\./g, "\\.")}"\\s*:\\s*(?:true|false)\\s*,?[ \\t]*\\r?\\n`, "m");
|
|
2836
|
+
let next = source;
|
|
2837
|
+
for (const key of [HTTP2_SETTING, HTTP1_SSE_SETTING]) {
|
|
2838
|
+
next = next.replace(lineOf(key), "");
|
|
2839
|
+
}
|
|
2840
|
+
if (next === source) return false;
|
|
2841
|
+
try {
|
|
2842
|
+
JSON.parse(next);
|
|
2843
|
+
} catch {
|
|
2844
|
+
log?.(" settings.json is not plain JSON; left HTTP protocol settings in place");
|
|
2845
|
+
return false;
|
|
2846
|
+
}
|
|
2847
|
+
(0, import_fs11.writeFileSync)(file, next, "utf-8");
|
|
2848
|
+
log?.(` Removed ${HTTP2_SETTING} / ${HTTP1_SSE_SETTING}`);
|
|
2849
|
+
return true;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
// src/release-defaults.js
|
|
2853
|
+
var import_fs12 = require("fs");
|
|
2854
|
+
var import_child_process = require("child_process");
|
|
2855
|
+
var import_path9 = require("path");
|
|
2856
|
+
var import_os4 = require("os");
|
|
2857
|
+
function getCursorStateDbPath() {
|
|
2858
|
+
const home = (0, import_os4.homedir)();
|
|
2859
|
+
switch (process.platform) {
|
|
2860
|
+
case "darwin":
|
|
2861
|
+
return (0, import_path9.join)(home, "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
2862
|
+
case "win32":
|
|
2863
|
+
return (0, import_path9.join)(process.env.APPDATA || (0, import_path9.join)(home, "AppData", "Roaming"), "Cursor", "User", "globalStorage", "state.vscdb");
|
|
2864
|
+
case "linux":
|
|
2865
|
+
return (0, import_path9.join)(process.env.XDG_CONFIG_HOME || (0, import_path9.join)(home, ".config"), "Cursor", "User", "globalStorage", "state.vscdb");
|
|
2866
|
+
default:
|
|
2867
|
+
return (0, import_path9.join)(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
function detectByokMode(log) {
|
|
2871
|
+
const vscdb = getCursorStateDbPath();
|
|
2872
|
+
if (!(0, import_fs12.existsSync)(vscdb)) {
|
|
2873
|
+
log?.(" [detect] state.vscdb not found \u2192 byokMode: 0 (fresh Cursor)");
|
|
2874
|
+
return 0;
|
|
2875
|
+
}
|
|
2876
|
+
try {
|
|
2877
|
+
const query = "SELECT value FROM ItemTable WHERE key='cursorAuth/accessToken' LIMIT 1";
|
|
2878
|
+
const token = (0, import_child_process.execFileSync)("sqlite3", [vscdb, query], { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
2879
|
+
if (!token || token.length < 10) {
|
|
2880
|
+
log?.(" [detect] no accessToken \u2192 byokMode: 0 (not logged in)");
|
|
2881
|
+
return 0;
|
|
2882
|
+
}
|
|
2883
|
+
const query2 = "SELECT value FROM ItemTable WHERE key='workbench.contrib.onboarding.browser.gettingStarted.contribution.ts.firsttime' LIMIT 1";
|
|
2884
|
+
const firsttime = (0, import_child_process.execFileSync)("sqlite3", [vscdb, query2], { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
2885
|
+
if (firsttime === "" || firsttime === "true") {
|
|
2886
|
+
log?.(" [detect] onboarding not completed \u2192 byokMode: 0");
|
|
2887
|
+
return 0;
|
|
2888
|
+
}
|
|
2889
|
+
log?.(" [detect] logged in + onboarding done \u2192 byokMode: 1");
|
|
2890
|
+
return 1;
|
|
2891
|
+
} catch (e) {
|
|
2892
|
+
log?.(` [detect] sqlite3 failed: ${e.message} \u2192 byokMode: 1 (fallback)`);
|
|
2893
|
+
return 1;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
function release(filename, content, log, { force = false } = {}) {
|
|
2897
|
+
const dest = (0, import_path9.join)(BEATCURSOR_DIR, filename);
|
|
2898
|
+
if (!force && (0, import_fs12.existsSync)(dest)) {
|
|
2899
|
+
log?.(` ${filename} already exists, keep`);
|
|
2900
|
+
return false;
|
|
2901
|
+
}
|
|
2902
|
+
const existed = (0, import_fs12.existsSync)(dest);
|
|
2903
|
+
(0, import_fs12.writeFileSync)(dest, JSON.stringify(content, null, 2) + "\n", "utf-8");
|
|
2904
|
+
log?.(` ${filename} ${existed ? "overwritten" : "released"}`);
|
|
2905
|
+
return true;
|
|
2906
|
+
}
|
|
2907
|
+
function resolveAssetPath(filename) {
|
|
2908
|
+
const candidates = [
|
|
2909
|
+
(0, import_path9.join)(__dirname, filename),
|
|
2910
|
+
// bundled: dist/<file>
|
|
2911
|
+
(0, import_path9.join)(__dirname, "..", "assets", filename)
|
|
2912
|
+
// dev: src/../assets/<file>
|
|
2913
|
+
];
|
|
2914
|
+
for (const p of candidates) {
|
|
2915
|
+
if ((0, import_fs12.existsSync)(p)) return p;
|
|
2916
|
+
}
|
|
2917
|
+
return null;
|
|
2918
|
+
}
|
|
2919
|
+
function copyAsset(filename, log, { force = false } = {}) {
|
|
2920
|
+
const dest = (0, import_path9.join)(BEATCURSOR_DIR, filename);
|
|
2921
|
+
if (!force && (0, import_fs12.existsSync)(dest)) {
|
|
2922
|
+
log?.(` ${filename} already exists, keep`);
|
|
2923
|
+
return false;
|
|
2924
|
+
}
|
|
2925
|
+
const src = resolveAssetPath(filename);
|
|
2926
|
+
if (!src) {
|
|
2927
|
+
log?.(` ${filename} asset not bundled, skip`);
|
|
2928
|
+
return false;
|
|
2929
|
+
}
|
|
2930
|
+
const existed = (0, import_fs12.existsSync)(dest);
|
|
2931
|
+
(0, import_fs12.copyFileSync)(src, dest);
|
|
2932
|
+
const size = ((0, import_fs12.readFileSync)(dest).length / 1024).toFixed(1);
|
|
2933
|
+
log?.(` ${filename} ${existed ? "updated" : "released"} (${size} KB)`);
|
|
2934
|
+
return true;
|
|
2935
|
+
}
|
|
2936
|
+
function releaseDefaults(log) {
|
|
2937
|
+
log?.("[defaults] Releasing to ~/.beatcursor/...");
|
|
2938
|
+
(0, import_fs12.mkdirSync)(BEATCURSOR_DIR, { recursive: true });
|
|
2939
|
+
const mode = detectByokMode(log);
|
|
2940
|
+
const routes = {
|
|
2941
|
+
...DEFAULT_ROUTES,
|
|
2942
|
+
byokMode: mode,
|
|
2943
|
+
redirect: mode ? [...DEFAULT_REDIRECT] : [...BASE_REDIRECT]
|
|
2944
|
+
};
|
|
2945
|
+
release(ROUTES_FILE_NAME, routes, log, { force: true });
|
|
2946
|
+
release(PROVIDERS_FILE_NAME, DEFAULT_PROVIDERS, log);
|
|
2947
|
+
release(WEB_TOOLS_FILE_NAME, DEFAULT_WEB_TOOLS, log);
|
|
2948
|
+
copyAsset(MODELS_CATALOG_FILE_NAME, log, { force: true });
|
|
2949
|
+
log?.("[defaults] Done");
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
// src/install.js
|
|
2953
|
+
var ok = (msg) => console.log(`\x1B[32m[OK]\x1B[0m ${msg}`);
|
|
2954
|
+
var info = (msg) => console.log(`\x1B[34m[>]\x1B[0m ${msg}`);
|
|
2955
|
+
var warn = (msg) => console.log(`\x1B[33m[!]\x1B[0m ${msg}`);
|
|
2956
|
+
var fail = (msg) => console.log(`\x1B[31m[X]\x1B[0m ${msg}`);
|
|
2957
|
+
async function install() {
|
|
2958
|
+
info("BeatCursor Installer");
|
|
2959
|
+
console.log("");
|
|
2960
|
+
const { paths, diagnostic } = findCursorPathsDetailed();
|
|
2961
|
+
if (!paths) {
|
|
2962
|
+
fail("Cursor installation not found");
|
|
2963
|
+
console.log("");
|
|
2964
|
+
console.log(formatDiagnostic(diagnostic));
|
|
2965
|
+
console.log("");
|
|
2966
|
+
throw new Error("Cursor installation not found");
|
|
2967
|
+
}
|
|
2968
|
+
info(`Cursor: ${paths.appRoot}`);
|
|
2969
|
+
info(`Version: ${paths.cursorVersion}${paths.hasGlass ? " (glass)" : ""}`);
|
|
2970
|
+
const extInstalled = isExtensionInstalled(paths);
|
|
2971
|
+
const desktopPatched = (0, import_fs13.existsSync)(paths.workbenchJs) && isInjectPatched((0, import_fs13.readFileSync)(paths.workbenchJs, "utf-8"));
|
|
2972
|
+
const glassPatched = !(0, import_fs13.existsSync)(paths.glassJs) || isInjectPatched((0, import_fs13.readFileSync)(paths.glassJs, "utf-8"));
|
|
2973
|
+
const hookInjected = desktopPatched && glassPatched;
|
|
2974
|
+
const alPatched = inspectAlwaysLocalPatch(paths).fullyPatched;
|
|
2975
|
+
const agentHostPatched = isAgentHostPatched(paths);
|
|
2976
|
+
const proxy39Ok = !needsProxy39Patch(paths) || isProxy39Patched(paths);
|
|
2977
|
+
const agentHostBackups = getAgentHostBackupTargets(paths).some((file) => hasBackup(file, "agent-host"));
|
|
2978
|
+
const hasBackups = hasBackup(paths.workbenchJs) || hasBackup(paths.glassJs) || hasBackup(paths.alwaysLocalMain) || hasBackup(paths.alwaysLocalSingletonJs) || hasBackup(paths.extensionHostJs) || agentHostBackups;
|
|
2979
|
+
if (extInstalled && hookInjected && alPatched && agentHostPatched && proxy39Ok) {
|
|
2980
|
+
if (!inspectHttpProtocolSettings().ok) {
|
|
2981
|
+
info("Repairing HTTP transport settings...");
|
|
2982
|
+
patchHttpProtocolSettings(info);
|
|
2983
|
+
console.log("");
|
|
2984
|
+
ok("Already installed; transport settings repaired");
|
|
2985
|
+
return;
|
|
2986
|
+
}
|
|
2987
|
+
ok("Already fully installed");
|
|
2988
|
+
info('To reinstall, run "beatcursor uninstall" first');
|
|
2989
|
+
return;
|
|
2990
|
+
}
|
|
2991
|
+
if (hasBackups && !extInstalled) {
|
|
2992
|
+
warn("Found backup files from a previous installation");
|
|
2993
|
+
warn('Run "beatcursor uninstall" to clean up before reinstalling');
|
|
2994
|
+
return;
|
|
2995
|
+
}
|
|
2996
|
+
console.log("");
|
|
2997
|
+
releaseDefaults(info);
|
|
2998
|
+
installExtension(paths, info);
|
|
2999
|
+
patchInject(paths, info);
|
|
3000
|
+
patchAlwaysLocal(paths, info);
|
|
3001
|
+
patchAgentHost(paths, info);
|
|
3002
|
+
patchProxy39(paths, info);
|
|
3003
|
+
patchKatex(paths, info);
|
|
3004
|
+
patchHttpProtocolSettings(info);
|
|
3005
|
+
console.log("");
|
|
3006
|
+
ok("Installation complete!");
|
|
3007
|
+
warn("Restart Cursor for changes to take effect.");
|
|
3008
|
+
info("Uninstall: npx beatcursor uninstall");
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
// src/uninstall.js
|
|
3012
|
+
var import_path10 = require("path");
|
|
3013
|
+
var ok2 = (msg) => console.log(`\x1B[32m[OK]\x1B[0m ${msg}`);
|
|
3014
|
+
var info2 = (msg) => console.log(`\x1B[34m[>]\x1B[0m ${msg}`);
|
|
3015
|
+
var warn2 = (msg) => console.log(`\x1B[33m[!]\x1B[0m ${msg}`);
|
|
3016
|
+
var fail2 = (msg) => console.log(`\x1B[31m[X]\x1B[0m ${msg}`);
|
|
3017
|
+
async function uninstall() {
|
|
3018
|
+
info2("BeatAPI BYOK Uninstaller");
|
|
3019
|
+
console.log("");
|
|
3020
|
+
const { paths, diagnostic } = findCursorPathsDetailed();
|
|
3021
|
+
if (!paths) {
|
|
3022
|
+
fail2("Cursor installation not found");
|
|
3023
|
+
console.log("");
|
|
3024
|
+
console.log(formatDiagnostic(diagnostic));
|
|
3025
|
+
console.log("");
|
|
3026
|
+
throw new Error("Cursor installation not found");
|
|
3027
|
+
}
|
|
3028
|
+
info2(`Cursor: ${paths.appRoot}`);
|
|
3029
|
+
let restored = 0;
|
|
3030
|
+
const workbenchHtml = (0, import_path10.join)(paths.appRoot, "out", "vs", "code", "electron-sandbox", "workbench", "workbench.html");
|
|
3031
|
+
const singletonJs = (0, import_path10.join)(paths.appRoot, "out", "vs", "code", "electron-utility", "alwaysLocalSingleton", "alwaysLocalSingletonMain.js");
|
|
3032
|
+
info2("Restoring katex patches...");
|
|
3033
|
+
for (const file of [paths.productJson, workbenchHtml]) {
|
|
3034
|
+
if (restoreBackup(file, "katex", info2)) restored++;
|
|
3035
|
+
}
|
|
3036
|
+
info2("Restoring proxy-39 patches...");
|
|
3037
|
+
for (const file of [paths.productJson, singletonJs]) {
|
|
3038
|
+
if (restoreBackup(file, "proxy-39", info2)) restored++;
|
|
3039
|
+
}
|
|
3040
|
+
info2("Restoring agent-host patches...");
|
|
3041
|
+
for (const file of [paths.productJson, ...getAgentHostBackupTargets(paths)]) {
|
|
3042
|
+
if (restoreBackup(file, "agent-host", info2)) restored++;
|
|
3043
|
+
}
|
|
3044
|
+
info2("Restoring always-local patches...");
|
|
3045
|
+
for (const file of [paths.productJson, paths.extensionHostJs, paths.alwaysLocalMain]) {
|
|
3046
|
+
if (restoreBackup(file, "always-local", info2)) restored++;
|
|
3047
|
+
}
|
|
3048
|
+
info2("Restoring inject patches...");
|
|
3049
|
+
for (const file of [paths.productJson, paths.glassJs, paths.workbenchJs]) {
|
|
3050
|
+
if (restoreBackup(file, "inject", info2)) restored++;
|
|
3051
|
+
}
|
|
3052
|
+
info2("Removing HTTP transport settings...");
|
|
3053
|
+
unpatchHttpProtocolSettings(info2);
|
|
3054
|
+
removeExtension(paths, info2);
|
|
3055
|
+
console.log("");
|
|
3056
|
+
if (restored > 0) {
|
|
3057
|
+
ok2(`Restored ${restored} file(s)`);
|
|
3058
|
+
} else {
|
|
3059
|
+
warn2("No backups found (already clean?)");
|
|
3060
|
+
}
|
|
3061
|
+
ok2("Uninstallation complete");
|
|
3062
|
+
warn2("Restart Cursor for changes to take effect.");
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
// src/status.js
|
|
3066
|
+
var import_fs14 = require("fs");
|
|
3067
|
+
var import_path11 = require("path");
|
|
3068
|
+
var ok3 = (s) => `\x1B[32m\u2713 ${s}\x1B[0m`;
|
|
3069
|
+
var fail3 = (s) => `\x1B[31m\u2717 ${s}\x1B[0m`;
|
|
3070
|
+
var na = (s) => `\x1B[2m- ${s}\x1B[0m`;
|
|
3071
|
+
async function status() {
|
|
3072
|
+
const { paths, diagnostic } = findCursorPathsDetailed();
|
|
3073
|
+
if (!paths) {
|
|
3074
|
+
console.log(fail3("Cursor installation not found"));
|
|
3075
|
+
console.log("");
|
|
3076
|
+
console.log(formatDiagnostic(diagnostic));
|
|
3077
|
+
return;
|
|
3078
|
+
}
|
|
3079
|
+
console.log(`Cursor: ${paths.appRoot}
|
|
3080
|
+
`);
|
|
3081
|
+
const extInstalled = isExtensionInstalled(paths);
|
|
3082
|
+
console.log(extInstalled ? ok3("Extension installed") : fail3("Extension not installed"));
|
|
3083
|
+
if ((0, import_fs14.existsSync)(paths.workbenchJs)) {
|
|
3084
|
+
const wb = (0, import_fs14.readFileSync)(paths.workbenchJs, "utf-8");
|
|
3085
|
+
const injected = isInjectPatched(wb);
|
|
3086
|
+
console.log(injected ? ok3("Renderer hook injected (desktop)") : fail3("Renderer hook not injected (desktop)"));
|
|
3087
|
+
} else {
|
|
3088
|
+
console.log(na("workbench.desktop.main.js not found"));
|
|
3089
|
+
}
|
|
3090
|
+
if ((0, import_fs14.existsSync)(paths.glassJs)) {
|
|
3091
|
+
const gl = (0, import_fs14.readFileSync)(paths.glassJs, "utf-8");
|
|
3092
|
+
const injected = isInjectPatched(gl);
|
|
3093
|
+
console.log(injected ? ok3("Renderer hook injected (glass)") : fail3("Renderer hook not injected (glass)"));
|
|
3094
|
+
} else {
|
|
3095
|
+
console.log(na("workbench.glass.main.js not found (pre-3.8)"));
|
|
3096
|
+
}
|
|
3097
|
+
const alwaysLocal = inspectAlwaysLocalPatch(paths);
|
|
3098
|
+
if (alwaysLocal.present) {
|
|
3099
|
+
console.log(alwaysLocal.router ? ok3("Legacy Agent HTTP/1.1 router active") : fail3("Legacy Agent HTTP/1.1 router missing"));
|
|
3100
|
+
console.log(alwaysLocal.wait ? ok3("Legacy Agent server wait active") : fail3("Legacy Agent server wait missing"));
|
|
3101
|
+
if (alwaysLocal.websocketRequired) {
|
|
3102
|
+
console.log(alwaysLocal.websocketDisabled ? ok3("Legacy Agent WebSocket bypass disabled") : fail3("Legacy Agent WebSocket bypass is active"));
|
|
3103
|
+
}
|
|
3104
|
+
} else {
|
|
3105
|
+
console.log(na("cursor-always-local not found"));
|
|
3106
|
+
}
|
|
3107
|
+
const agentHost = inspectAgentHostPatch(paths);
|
|
3108
|
+
if (!agentHost.present) {
|
|
3109
|
+
console.log(na("cursor-agent-host not found (pre-3.13)"));
|
|
3110
|
+
} else {
|
|
3111
|
+
console.log(agentHost.router ? ok3("Agent Host HTTP/1.1 router active") : fail3("Agent Host HTTP/1.1 router missing"));
|
|
3112
|
+
console.log(agentHost.wait ? ok3("Agent Host server wait active") : fail3("Agent Host server wait missing"));
|
|
3113
|
+
console.log(agentHost.networkTargets.length > 0 ? ok3(`Agent Host network target verified (${agentHost.networkTargets.map((file) => file.split(/[\\/]/).pop()).join(", ")})`) : fail3("Agent Host network target not found"));
|
|
3114
|
+
if (agentHost.websocketTargets.length > 0) {
|
|
3115
|
+
console.log(agentHost.websocketDisabled ? ok3("Agent Host WebSocket bypass disabled") : fail3("Agent Host WebSocket bypass is active"));
|
|
3116
|
+
} else {
|
|
3117
|
+
console.log(na("Agent Host WebSocket transport not present (3.13\u20133.15)"));
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
if ((0, import_fs14.existsSync)(paths.extensionHostJs)) {
|
|
3121
|
+
const eh = (0, import_fs14.readFileSync)(paths.extensionHostJs, "utf-8");
|
|
3122
|
+
const bypassed = eh.includes("if(!1)") && !/if\(!\w\.valid\)/.test(eh);
|
|
3123
|
+
console.log(bypassed ? ok3("Signature bypass active") : fail3("Signature bypass not active"));
|
|
3124
|
+
} else {
|
|
3125
|
+
console.log(na("extensionHostProcess.js not found"));
|
|
3126
|
+
}
|
|
3127
|
+
if (needsProxy39Patch(paths)) {
|
|
3128
|
+
console.log(isProxy39Patched(paths) ? ok3("Cursor 3.9 singleton BYOK router/proxy patch active") : fail3("Cursor 3.9 singleton BYOK router/proxy patch missing"));
|
|
3129
|
+
} else if ((0, import_fs14.existsSync)(getProxy39Target(paths))) {
|
|
3130
|
+
console.log(na("Cursor 3.9 singleton BYOK router/proxy patch not required"));
|
|
3131
|
+
}
|
|
3132
|
+
const httpProtocol = inspectHttpProtocolSettings();
|
|
3133
|
+
if (!httpProtocol.exists) {
|
|
3134
|
+
console.log(fail3(`settings.json not found at ${httpProtocol.file}`));
|
|
3135
|
+
} else if (httpProtocol.ok) {
|
|
3136
|
+
console.log(ok3("Agent stream transport: HTTP/1.1 SSE"));
|
|
3137
|
+
} else if (httpProtocol.http1SseDisabled === true) {
|
|
3138
|
+
console.log(fail3(`Agent stream would use RunPoll \u2014 set ${HTTP1_SSE_SETTING}=false`));
|
|
3139
|
+
} else {
|
|
3140
|
+
console.log(fail3(`Agent stream would use bidi Run over HTTP/2 \u2014 set ${HTTP2_SETTING}=true`));
|
|
3141
|
+
}
|
|
3142
|
+
console.log("");
|
|
3143
|
+
const routesPath = (0, import_path11.join)(BEATCURSOR_DIR, ROUTES_FILE_NAME);
|
|
3144
|
+
const providersPath = (0, import_path11.join)(BEATCURSOR_DIR, PROVIDERS_FILE_NAME);
|
|
3145
|
+
console.log((0, import_fs14.existsSync)(routesPath) ? ok3(`routes.json: ${routesPath}`) : fail3(`routes.json missing at ${routesPath}`));
|
|
3146
|
+
console.log((0, import_fs14.existsSync)(providersPath) ? ok3(`providers.json: ${providersPath}`) : fail3(`providers.json missing at ${providersPath}`));
|
|
3147
|
+
console.log("");
|
|
3148
|
+
const backupFiles = [.../* @__PURE__ */ new Set([
|
|
3149
|
+
paths.workbenchJs,
|
|
3150
|
+
paths.glassJs,
|
|
3151
|
+
paths.alwaysLocalMain,
|
|
3152
|
+
paths.alwaysLocalSingletonJs,
|
|
3153
|
+
paths.extensionHostJs,
|
|
3154
|
+
paths.productJson,
|
|
3155
|
+
...getAgentHostBackupTargets(paths)
|
|
3156
|
+
])];
|
|
3157
|
+
const backupCount = backupFiles.filter((f) => hasBackup(f)).length;
|
|
3158
|
+
console.log(`Backups: ${backupCount}/${backupFiles.length} files backed up`);
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
// src/check.js
|
|
3162
|
+
var import_fs15 = require("fs");
|
|
3163
|
+
var ok4 = (s) => `\x1B[32m\u2713 ${s}\x1B[0m`;
|
|
3164
|
+
var fail4 = (s) => `\x1B[31m\u2717 ${s}\x1B[0m`;
|
|
3165
|
+
var info3 = (s) => `\x1B[34m[>]\x1B[0m ${s}`;
|
|
3166
|
+
async function check() {
|
|
3167
|
+
const { paths, diagnostic } = findCursorPathsDetailed();
|
|
3168
|
+
if (!paths) {
|
|
3169
|
+
console.log(fail4("Cursor installation not found"));
|
|
3170
|
+
console.log();
|
|
3171
|
+
console.log(formatDiagnostic(diagnostic));
|
|
3172
|
+
return;
|
|
3173
|
+
}
|
|
3174
|
+
console.log(info3(`Cursor: ${paths.appRoot}`));
|
|
3175
|
+
console.log();
|
|
3176
|
+
let allOk = true;
|
|
3177
|
+
for (const [file, label] of [[paths.workbenchJs, "desktop"], [paths.glassJs, "glass"]]) {
|
|
3178
|
+
if (!(0, import_fs15.existsSync)(file)) {
|
|
3179
|
+
if (label === "glass") console.log(info3("Glass workbench not found (pre-3.8, OK)"));
|
|
3180
|
+
continue;
|
|
3181
|
+
}
|
|
3182
|
+
const wb = (0, import_fs15.readFileSync)(file, "utf-8");
|
|
3183
|
+
if (isInjectPatched(wb)) {
|
|
3184
|
+
console.log(ok4(`Renderer hook (${label}): payload + active transport call site`));
|
|
3185
|
+
continue;
|
|
3186
|
+
}
|
|
3187
|
+
if (wb.includes("__byokWrapTransport") || wb.includes("CURSOR-BYOK-HOOK-START")) {
|
|
3188
|
+
console.log(fail4(`Renderer hook (${label}) is partial (payload/call-site mismatch)`));
|
|
3189
|
+
allOk = false;
|
|
3190
|
+
continue;
|
|
3191
|
+
}
|
|
3192
|
+
const anchors = [
|
|
3193
|
+
"callback-client.js",
|
|
3194
|
+
"promise-client.js"
|
|
3195
|
+
];
|
|
3196
|
+
const found = anchors.find((a) => wb.includes(a));
|
|
3197
|
+
if (found) {
|
|
3198
|
+
console.log(ok4(`Inject anchor (${label}): "${found}"`));
|
|
3199
|
+
} else {
|
|
3200
|
+
console.log(fail4(`Inject anchor (${label}) not found`));
|
|
3201
|
+
allOk = false;
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
if ((0, import_fs15.existsSync)(paths.extensionHostJs)) {
|
|
3205
|
+
const eh = (0, import_fs15.readFileSync)(paths.extensionHostJs, "utf-8");
|
|
3206
|
+
const hasSigPattern = /if\(!\w\.valid\)/.test(eh);
|
|
3207
|
+
const alreadyBypassed = eh.includes("if(!1)") && !hasSigPattern;
|
|
3208
|
+
if (hasSigPattern || alreadyBypassed) {
|
|
3209
|
+
console.log(ok4(`Sig bypass: ${alreadyBypassed ? "already applied" : "pattern found"}`));
|
|
3210
|
+
} else {
|
|
3211
|
+
console.log(fail4("Sig bypass pattern not found"));
|
|
3212
|
+
allOk = false;
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
const alwaysLocalOk = checkAlwaysLocalPatch(paths, (s) => console.log(info3(s)));
|
|
3216
|
+
if (!alwaysLocalOk) allOk = false;
|
|
3217
|
+
console.log(info3("[check] Verifying cursor-agent-host transport coverage..."));
|
|
3218
|
+
const agentHostOk = checkAgentHostPatch(paths, (s) => console.log(info3(s)));
|
|
3219
|
+
if (!agentHostOk) allOk = false;
|
|
3220
|
+
if (needsProxy39Patch(paths)) {
|
|
3221
|
+
console.log(info3("[check] Verifying Cursor 3.9 singleton routing/proxy patch target..."));
|
|
3222
|
+
const proxyOk = checkProxy39Patch(paths, (s) => console.log(info3(s)));
|
|
3223
|
+
if (!proxyOk) allOk = false;
|
|
3224
|
+
} else {
|
|
3225
|
+
console.log(info3("Cursor 3.9 singleton routing/proxy patch not required"));
|
|
3226
|
+
}
|
|
3227
|
+
if ((0, import_fs15.existsSync)(paths.alwaysLocalMain)) {
|
|
3228
|
+
console.log(ok4("cursor-always-local main.js found"));
|
|
3229
|
+
} else {
|
|
3230
|
+
console.log(fail4("cursor-always-local main.js not found"));
|
|
3231
|
+
allOk = false;
|
|
3232
|
+
}
|
|
3233
|
+
console.log();
|
|
3234
|
+
if (allOk) {
|
|
3235
|
+
console.log(ok4("All patch targets matchable"));
|
|
3236
|
+
} else {
|
|
3237
|
+
console.log(fail4("Some targets not matchable \u2014 install may fail"));
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3241
|
+
// src/patch-local-mode.js
|
|
3242
|
+
var import_fs16 = require("fs");
|
|
3243
|
+
var import_path12 = require("path");
|
|
3244
|
+
var TAG4 = "local-mode";
|
|
3245
|
+
var PATTERN = "localMode:!1";
|
|
3246
|
+
var REPLACEMENT = "localMode:!0";
|
|
3247
|
+
var TARGET_FILES = [
|
|
3248
|
+
"out/main.js",
|
|
3249
|
+
"out/vs/workbench/workbench.desktop.main.js",
|
|
3250
|
+
"out/vs/workbench/workbench.glass.main.js",
|
|
3251
|
+
"out/vs/workbench/api/node/extensionHostProcess.js",
|
|
3252
|
+
"out/vs/code/electron-utility/alwaysLocalSingleton/alwaysLocalSingletonMain.js"
|
|
3253
|
+
];
|
|
3254
|
+
function patchLocalMode(paths, log) {
|
|
3255
|
+
log?.("[local-mode] Patching buildFlags.localMode...");
|
|
3256
|
+
let patched = 0;
|
|
3257
|
+
const modifiedFiles = [];
|
|
3258
|
+
for (const rel of TARGET_FILES) {
|
|
3259
|
+
const filePath = (0, import_path12.join)(paths.appRoot, rel);
|
|
3260
|
+
if (!(0, import_fs16.existsSync)(filePath)) {
|
|
3261
|
+
log?.(` [local-mode] ${rel}: not found, skipping`);
|
|
3262
|
+
continue;
|
|
3263
|
+
}
|
|
3264
|
+
const code = (0, import_fs16.readFileSync)(filePath, "utf-8");
|
|
3265
|
+
if (code.includes(REPLACEMENT)) {
|
|
3266
|
+
log?.(` [local-mode] ${rel}: already patched`);
|
|
3267
|
+
patched++;
|
|
3268
|
+
continue;
|
|
3269
|
+
}
|
|
3270
|
+
if (!code.includes(PATTERN)) {
|
|
3271
|
+
log?.(` [local-mode] ${rel}: pattern not found, skipping`);
|
|
3272
|
+
continue;
|
|
3273
|
+
}
|
|
3274
|
+
createBackup(filePath, TAG4, log);
|
|
3275
|
+
(0, import_fs16.writeFileSync)(filePath, code.replace(PATTERN, REPLACEMENT));
|
|
3276
|
+
modifiedFiles.push(filePath);
|
|
3277
|
+
patched++;
|
|
3278
|
+
log?.(` [local-mode] ${rel}: patched`);
|
|
3279
|
+
}
|
|
3280
|
+
if (modifiedFiles.length > 0) {
|
|
3281
|
+
updateChecksums(paths, modifiedFiles, TAG4, log);
|
|
3282
|
+
}
|
|
3283
|
+
log?.(`[local-mode] Done (${patched}/${TARGET_FILES.length} files)`);
|
|
3284
|
+
return patched;
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
// src/cli.js
|
|
3288
|
+
async function update() {
|
|
3289
|
+
await uninstall();
|
|
3290
|
+
console.log("");
|
|
3291
|
+
await install();
|
|
3292
|
+
}
|
|
3293
|
+
var command = process.argv[2];
|
|
3294
|
+
var commands = {
|
|
3295
|
+
install,
|
|
3296
|
+
uninstall,
|
|
3297
|
+
update,
|
|
3298
|
+
upgrade: update,
|
|
3299
|
+
status,
|
|
3300
|
+
check,
|
|
3301
|
+
"local-mode": async () => {
|
|
3302
|
+
const info4 = (msg) => console.log(`\x1B[34m[>]\x1B[0m ${msg}`);
|
|
3303
|
+
const { paths, diagnostic } = findCursorPathsDetailed();
|
|
3304
|
+
if (!paths) {
|
|
3305
|
+
console.log(formatDiagnostic(diagnostic));
|
|
3306
|
+
process.exit(1);
|
|
3307
|
+
}
|
|
3308
|
+
info4(`Cursor: ${paths.appRoot}`);
|
|
3309
|
+
patchLocalMode(paths, info4);
|
|
3310
|
+
},
|
|
3311
|
+
"local-mode-off": async () => {
|
|
3312
|
+
const info4 = (msg) => console.log(`\x1B[34m[>]\x1B[0m ${msg}`);
|
|
3313
|
+
const { paths, diagnostic } = findCursorPathsDetailed();
|
|
3314
|
+
if (!paths) {
|
|
3315
|
+
console.log(formatDiagnostic(diagnostic));
|
|
3316
|
+
process.exit(1);
|
|
3317
|
+
}
|
|
3318
|
+
info4(`Cursor: ${paths.appRoot}`);
|
|
3319
|
+
info4("Restoring local-mode patches...");
|
|
3320
|
+
let restored = 0;
|
|
3321
|
+
const { join: join13 } = await import("path");
|
|
3322
|
+
const targets = [
|
|
3323
|
+
"out/main.js",
|
|
3324
|
+
"out/vs/workbench/workbench.desktop.main.js",
|
|
3325
|
+
"out/vs/workbench/workbench.glass.main.js",
|
|
3326
|
+
"out/vs/workbench/api/node/extensionHostProcess.js",
|
|
3327
|
+
"out/vs/code/electron-utility/alwaysLocalSingleton/alwaysLocalSingletonMain.js"
|
|
3328
|
+
];
|
|
3329
|
+
for (const rel of targets) {
|
|
3330
|
+
if (restoreBackup(join13(paths.appRoot, rel), "local-mode", info4)) restored++;
|
|
3331
|
+
}
|
|
3332
|
+
if (restoreBackup(paths.productJson, "local-mode", info4)) restored++;
|
|
3333
|
+
console.log(restored > 0 ? `\x1B[32m[OK]\x1B[0m Restored ${restored} file(s)` : "\x1B[33m[!]\x1B[0m No backups found");
|
|
3334
|
+
},
|
|
3335
|
+
help: async () => {
|
|
3336
|
+
console.log(`
|
|
3337
|
+
beatcursor \u2014 BeatCursor Installer
|
|
3338
|
+
|
|
3339
|
+
Commands:
|
|
3340
|
+
install Install BeatAPI extension and apply patches
|
|
3341
|
+
uninstall Remove extension and restore all patches
|
|
3342
|
+
update Upgrade: uninstall then reinstall
|
|
3343
|
+
local-mode Standalone tool: enable Cursor's built-in Local Agent mode
|
|
3344
|
+
local-mode-off Standalone tool: disable Local Agent mode (restore originals)
|
|
3345
|
+
status Check current installation status
|
|
3346
|
+
check Dry-run: verify AST patch targets are matchable
|
|
3347
|
+
help Show this help message
|
|
3348
|
+
`);
|
|
3349
|
+
}
|
|
3350
|
+
};
|
|
3351
|
+
var fn = commands[command];
|
|
3352
|
+
if (!fn) {
|
|
3353
|
+
console.error(`Unknown command: ${command || "(none)"}`);
|
|
3354
|
+
commands.help();
|
|
3355
|
+
process.exit(1);
|
|
3356
|
+
}
|
|
3357
|
+
fn().catch((err2) => {
|
|
3358
|
+
console.error(`
|
|
3359
|
+
\x1B[31m[ERROR]\x1B[0m ${err2.message}`);
|
|
3360
|
+
process.exit(1);
|
|
3361
|
+
});
|