@cursorpool-dev/cli 0.5.6 → 0.5.8
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/node_modules/@cursor-pool/extension/dist/extension.js +116 -46
- package/node_modules/@cursor-pool/extension/package.json +3 -3
- package/node_modules/@cursor-pool/extension/src/api.ts +17 -2
- package/node_modules/@cursor-pool/extension/src/panel.ts +26 -3
- package/node_modules/@cursor-pool/extension/test/panel.test.ts +34 -1
- package/node_modules/@cursor-pool/patcher/package.json +2 -2
- package/node_modules/@cursor-pool/patcher/src/marker.ts +5 -1
- package/node_modules/@cursor-pool/patcher/src/workbenchAuthGateMarker.ts +58 -7
- package/node_modules/@cursor-pool/patcher/test/patchCursorAgentExec.test.ts +20 -0
- package/node_modules/@cursor-pool/patcher/test/patchCursorWorkbench.test.ts +193 -2
- package/node_modules/@cursor-pool/service/package.json +2 -2
- package/node_modules/@cursor-pool/service/src/platformSession.ts +30 -7
- package/node_modules/@cursor-pool/service/src/server.ts +1 -0
- package/node_modules/@cursor-pool/service/test/platformSession.test.ts +5 -4
- package/node_modules/@cursor-pool/service/test/server.test.ts +130 -0
- package/node_modules/@cursor-pool/shared/package.json +1 -1
- package/node_modules/@cursor-pool/shared/src/manifest.ts +35 -0
- package/node_modules/@cursor-pool/shared/test/manifest.test.ts +43 -9
- package/node_modules/@cursor-pool/takeover-plans/package.json +12 -0
- package/node_modules/@cursor-pool/takeover-plans/src/index.ts +22 -0
- package/node_modules/@cursor-pool/takeover-plans/src/plans.ts +37 -0
- package/node_modules/@cursor-pool/takeover-plans/src/types.ts +9 -0
- package/node_modules/@cursor-pool/takeover-plans/test/registry.test.ts +23 -0
- package/node_modules/@esbuild/linux-x64/README.md +3 -0
- package/node_modules/@esbuild/linux-x64/bin/esbuild +0 -0
- package/node_modules/@esbuild/linux-x64/package.json +20 -0
- package/node_modules/esbuild/LICENSE.md +21 -0
- package/node_modules/esbuild/README.md +3 -0
- package/node_modules/esbuild/bin/esbuild +223 -0
- package/node_modules/esbuild/install.js +300 -0
- package/node_modules/esbuild/lib/main.d.ts +716 -0
- package/node_modules/esbuild/lib/main.js +2532 -0
- package/node_modules/esbuild/package.json +74 -0
- package/node_modules/tsx/LICENSE +21 -0
- package/node_modules/tsx/README.md +32 -0
- package/node_modules/tsx/dist/cjs/api/index.cjs +1 -0
- package/node_modules/tsx/dist/cjs/api/index.d.cts +35 -0
- package/node_modules/tsx/dist/cjs/api/index.d.mts +35 -0
- package/node_modules/tsx/dist/cjs/api/index.mjs +1 -0
- package/node_modules/tsx/dist/cjs/index.cjs +1 -0
- package/node_modules/tsx/dist/cjs/index.mjs +1 -0
- package/node_modules/tsx/dist/cli.cjs +54 -0
- package/node_modules/tsx/dist/cli.mjs +55 -0
- package/node_modules/tsx/dist/client-D3mGB526.cjs +1 -0
- package/node_modules/tsx/dist/client-D_mPDF5S.mjs +1 -0
- package/node_modules/tsx/dist/esm/api/index.cjs +1 -0
- package/node_modules/tsx/dist/esm/api/index.d.cts +35 -0
- package/node_modules/tsx/dist/esm/api/index.d.mts +35 -0
- package/node_modules/tsx/dist/esm/api/index.mjs +1 -0
- package/node_modules/tsx/dist/esm/index.cjs +1 -0
- package/node_modules/tsx/dist/esm/index.mjs +1 -0
- package/node_modules/tsx/dist/get-pipe-path-D4YM6rQt.cjs +1 -0
- package/node_modules/tsx/dist/get-pipe-path-_tAJyU_v.mjs +1 -0
- package/node_modules/tsx/dist/index-BWFBUo6r.cjs +1 -0
- package/node_modules/tsx/dist/index-D9F1FXzN.cjs +14 -0
- package/node_modules/tsx/dist/index-XurvG3JN.mjs +14 -0
- package/node_modules/tsx/dist/index-gbaejti9.mjs +1 -0
- package/node_modules/tsx/dist/lexer-DQCqS3nf.mjs +3 -0
- package/node_modules/tsx/dist/lexer-DgIbo0BU.cjs +3 -0
- package/node_modules/tsx/dist/loader.cjs +1 -0
- package/node_modules/tsx/dist/loader.mjs +1 -0
- package/node_modules/tsx/dist/node-features-B9BBLzwu.mjs +1 -0
- package/node_modules/tsx/dist/node-features-CQLdkVE6.cjs +1 -0
- package/node_modules/tsx/dist/package-CGdS2_oX.cjs +1 -0
- package/node_modules/tsx/dist/package-DyJMwVU5.mjs +1 -0
- package/node_modules/tsx/dist/patch-repl.cjs +1 -0
- package/node_modules/tsx/dist/patch-repl.mjs +1 -0
- package/node_modules/tsx/dist/preflight.cjs +1 -0
- package/node_modules/tsx/dist/preflight.mjs +1 -0
- package/node_modules/tsx/dist/register-BOkp8V6j.cjs +10 -0
- package/node_modules/tsx/dist/register-BnTWPeIB.mjs +10 -0
- package/node_modules/tsx/dist/register-CHVGxKtC.cjs +2 -0
- package/node_modules/tsx/dist/register-D_B8UL5H.mjs +2 -0
- package/node_modules/tsx/dist/repl.cjs +3 -0
- package/node_modules/tsx/dist/repl.mjs +3 -0
- package/node_modules/tsx/dist/require-CjvaJWEr.cjs +1 -0
- package/node_modules/tsx/dist/require-DzmC1hVr.mjs +1 -0
- package/node_modules/tsx/dist/suppress-warnings.cjs +1 -0
- package/node_modules/tsx/dist/suppress-warnings.mjs +1 -0
- package/node_modules/tsx/dist/temporary-directory-B83uKxJF.cjs +1 -0
- package/node_modules/tsx/dist/temporary-directory-BDDVQOvU.mjs +1 -0
- package/node_modules/tsx/dist/types-Cxp8y2TL.d.ts +5 -0
- package/node_modules/tsx/package.json +67 -0
- package/package.json +11 -6
- package/src/autostart.ts +5 -1
- package/src/compat.ts +193 -47
- package/src/cursor.ts +59 -3
- package/src/extensionBundle.ts +1 -1
- package/src/extensionLink.ts +28 -7
- package/src/install.ts +176 -24
- package/src/installRecord.ts +2 -0
- package/src/patchSet.ts +12 -6
- package/src/platform.ts +3 -3
- package/src/repair.ts +10 -1
- package/src/restore.ts +12 -4
- package/src/serviceProcess.ts +2 -1
- package/src/status.ts +6 -0
- package/src/trial.ts +1 -0
- package/test/autostart.test.ts +23 -2
- package/test/compat.test.ts +238 -3
- package/test/cursor-pool-bin.test.ts +1 -0
- package/test/cursor.test.ts +60 -1
- package/test/e2e-install.test.ts +53 -0
- package/test/extensionLink.test.ts +48 -2
- package/test/install.test.ts +191 -6
- package/test/repair.test.ts +1 -0
- package/test/serviceProcess.test.ts +10 -1
- package/test/status.test.ts +1 -0
package/test/compat.test.ts
CHANGED
|
@@ -15,12 +15,34 @@ import {
|
|
|
15
15
|
} from '../src/compat';
|
|
16
16
|
|
|
17
17
|
function remoteRuleFor(cursorVersion: string, cursorCommit: string): CompatibilityManifestEntry {
|
|
18
|
+
const cursorMajor = cursorVersion.replace(/^(\d+\.\d+).*/, '$1');
|
|
19
|
+
const planByMajor: Record<string, string> = {
|
|
20
|
+
'3.5': 'cursor-3.5-mac-agent-f-workbench-p-l0',
|
|
21
|
+
'3.6': 'cursor-3.6-mac-agent-c-workbench-h-uv',
|
|
22
|
+
'3.7': 'cursor-3.7-mac-agent-et-workbench-wv',
|
|
23
|
+
};
|
|
18
24
|
return {
|
|
19
25
|
platform: 'darwin',
|
|
20
26
|
arch: 'arm64',
|
|
21
|
-
|
|
27
|
+
officialSourceUrl: 'https://cursor.com/download',
|
|
28
|
+
officialDownloadUrl: `https://api2.cursor.sh/updates/download/golden/darwin-arm64/cursor/${cursorVersion.replace(/^(\d+\.\d+).*/, '$1')}`,
|
|
29
|
+
officialDownloadPlatform: 'darwin-arm64',
|
|
30
|
+
verifiedCursorVersion: cursorVersion,
|
|
31
|
+
cursorVersion: cursorMajor,
|
|
22
32
|
cursorCommit,
|
|
23
33
|
supportStatus: 'supported',
|
|
34
|
+
adapterVersion: '0.5.8',
|
|
35
|
+
takeoverPlanId: planByMajor[cursorMajor] ?? `cursor-${cursorMajor}-remote-plan`,
|
|
36
|
+
structureFamily: 'mac-agent-c-workbench-h-uv',
|
|
37
|
+
patchTargets: [
|
|
38
|
+
{
|
|
39
|
+
name: 'agent-exec',
|
|
40
|
+
targetRelativePath: CURSOR_AGENT_EXEC_RELATIVE_PATH,
|
|
41
|
+
expectedSha256: 'remote-sha256',
|
|
42
|
+
patchStrategy: 'cursor-agent-exec-snippet',
|
|
43
|
+
verifyMarker: 'cursor-pool',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
24
46
|
targetRelativePath: CURSOR_AGENT_EXEC_RELATIVE_PATH,
|
|
25
47
|
expectedSha256: 'remote-sha256',
|
|
26
48
|
structureSignature: 'remote-structure',
|
|
@@ -70,13 +92,161 @@ test('default compatibility manifest supports Cursor 3.6.21 on macOS arm64', ()
|
|
|
70
92
|
assert.equal(
|
|
71
93
|
DEFAULT_COMPAT_ENTRIES.some(
|
|
72
94
|
(candidate) =>
|
|
73
|
-
candidate.cursorVersion === '3.6
|
|
95
|
+
candidate.cursorVersion === '3.6' &&
|
|
74
96
|
candidate.cursorCommit === 'e7a7e93f4d75f8272503ecf33cedbaae10114a10',
|
|
75
97
|
),
|
|
76
98
|
true,
|
|
77
99
|
);
|
|
78
100
|
});
|
|
79
101
|
|
|
102
|
+
test('default compatibility entries are keyed by official Cursor major download versions only', () => {
|
|
103
|
+
assert.deepEqual(
|
|
104
|
+
Array.from(new Set(DEFAULT_COMPAT_ENTRIES.map((entry) => entry.cursorVersion))).sort(),
|
|
105
|
+
['3.4', '3.5', '3.6', '3.7'],
|
|
106
|
+
);
|
|
107
|
+
assert.equal(
|
|
108
|
+
DEFAULT_COMPAT_ENTRIES.every((entry) =>
|
|
109
|
+
entry.officialDownloadUrl?.startsWith(
|
|
110
|
+
`https://api2.cursor.sh/updates/download/golden/${entry.officialDownloadPlatform}/cursor/${entry.cursorVersion}`,
|
|
111
|
+
),
|
|
112
|
+
),
|
|
113
|
+
true,
|
|
114
|
+
);
|
|
115
|
+
assert.equal(
|
|
116
|
+
DEFAULT_COMPAT_ENTRIES.some((entry) => entry.officialSourceUrl !== 'https://cursor.com/download'),
|
|
117
|
+
false,
|
|
118
|
+
);
|
|
119
|
+
assert.equal(
|
|
120
|
+
DEFAULT_COMPAT_ENTRIES.some((entry) => entry.platform === 'linux' || entry.platform === 'win32'),
|
|
121
|
+
false,
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('default compatibility manifest supports Cursor 3.4.20 on macOS arm64 with the v0.4 adapter', () => {
|
|
126
|
+
const entry = resolveCompatEntry(
|
|
127
|
+
{
|
|
128
|
+
appPath: '/Applications/Cursor.app',
|
|
129
|
+
version: '3.4.20',
|
|
130
|
+
commit: '0cf8b06883f54e26bb4f0fb8647c9500ccb43310',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
platform: 'darwin',
|
|
134
|
+
arch: 'arm64',
|
|
135
|
+
nodeVersion: process.version,
|
|
136
|
+
},
|
|
137
|
+
{ adapterVersion: '0.4.8' },
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
assert.equal(entry.supportStatus, 'supported');
|
|
141
|
+
assert.equal(entry.adapterVersion, '0.4.8');
|
|
142
|
+
assert.equal(entry.cursorVersion, '3.4');
|
|
143
|
+
assert.equal(entry.structureFamily, 'mac-agent-D-workbench-U0');
|
|
144
|
+
assert.equal(entry.patchTargets?.map((target) => target.name).join(','), 'agent-exec,workbench');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('default compatibility manifest does not match Cursor 3.4.20 from the v0.5 adapter', () => {
|
|
148
|
+
assert.throws(
|
|
149
|
+
() =>
|
|
150
|
+
resolveCompatEntry(
|
|
151
|
+
{
|
|
152
|
+
appPath: '/Applications/Cursor.app',
|
|
153
|
+
version: '3.4.20',
|
|
154
|
+
commit: '0cf8b06883f54e26bb4f0fb8647c9500ccb43310',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
platform: 'darwin',
|
|
158
|
+
arch: 'arm64',
|
|
159
|
+
nodeVersion: process.version,
|
|
160
|
+
},
|
|
161
|
+
{ adapterVersion: '0.5.8' },
|
|
162
|
+
),
|
|
163
|
+
/No compatibility entry for Cursor 3\.4\.20/,
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('default compatibility manifest supports Cursor 3.6.31 on macOS arm64 with the v0.5 adapter', () => {
|
|
168
|
+
const entry = resolveCompatEntry(
|
|
169
|
+
{
|
|
170
|
+
appPath: '/Applications/Cursor.app',
|
|
171
|
+
version: '3.6.31',
|
|
172
|
+
commit: '81fcf2931d7687b4ff3f3017858d0c6dee7e2a60',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
platform: 'darwin',
|
|
176
|
+
arch: 'arm64',
|
|
177
|
+
nodeVersion: process.version,
|
|
178
|
+
},
|
|
179
|
+
{ adapterVersion: '0.5.8' },
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
assert.equal(entry.supportStatus, 'supported');
|
|
183
|
+
assert.equal(entry.adapterVersion, '0.5.8');
|
|
184
|
+
assert.equal(entry.cursorVersion, '3.6');
|
|
185
|
+
assert.equal(entry.structureFamily, 'mac-agent-c-workbench-h-uv');
|
|
186
|
+
assert.equal(entry.patchTargets?.map((target) => target.name).join(','), 'agent-exec,workbench');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('default compatibility manifest supports Cursor 3.7.12 on macOS arm64 with the v0.6 adapter', () => {
|
|
190
|
+
const entry = resolveCompatEntry(
|
|
191
|
+
{
|
|
192
|
+
appPath: '/Applications/Cursor.app',
|
|
193
|
+
version: '3.7.12',
|
|
194
|
+
commit: 'b887a26c4f70bd8136bfffeda812b24194ec9ce0',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
platform: 'darwin',
|
|
198
|
+
arch: 'arm64',
|
|
199
|
+
nodeVersion: process.version,
|
|
200
|
+
},
|
|
201
|
+
{ adapterVersion: '0.6.0' },
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
assert.equal(entry.supportStatus, 'supported');
|
|
205
|
+
assert.equal(entry.adapterVersion, '0.6.0');
|
|
206
|
+
assert.equal(entry.cursorVersion, '3.7');
|
|
207
|
+
assert.equal(entry.structureFamily, 'mac-3.7-agent-Et-workbench-wv');
|
|
208
|
+
assert.equal(entry.patchTargets?.map((target) => target.name).join(','), 'agent-exec,workbench');
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('default compatibility manifest does not match Cursor 3.7.12 from the v0.5 adapter', () => {
|
|
212
|
+
assert.throws(
|
|
213
|
+
() =>
|
|
214
|
+
resolveCompatEntry(
|
|
215
|
+
{
|
|
216
|
+
appPath: '/Applications/Cursor.app',
|
|
217
|
+
version: '3.7.12',
|
|
218
|
+
commit: 'b887a26c4f70bd8136bfffeda812b24194ec9ce0',
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
platform: 'darwin',
|
|
222
|
+
arch: 'arm64',
|
|
223
|
+
nodeVersion: process.version,
|
|
224
|
+
},
|
|
225
|
+
{ adapterVersion: '0.5.8' },
|
|
226
|
+
),
|
|
227
|
+
/No compatibility entry for Cursor 3\.7\.12/,
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('default compatibility manifest does not claim unverified Linux Cursor packages as supported', () => {
|
|
232
|
+
assert.throws(
|
|
233
|
+
() =>
|
|
234
|
+
resolveCompatEntry(
|
|
235
|
+
{
|
|
236
|
+
appPath: '/home/xubuntu/.cursor-pool/appimages/Cursor-89aa899ccc46fb58/squashfs-root',
|
|
237
|
+
version: '3.6.31',
|
|
238
|
+
commit: '81fcf2931d7687b4ff3f3017858d0c6dee7e2a60',
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
platform: 'linux',
|
|
242
|
+
arch: 'x64',
|
|
243
|
+
nodeVersion: process.version,
|
|
244
|
+
},
|
|
245
|
+
),
|
|
246
|
+
/No compatibility entry for Cursor 3\.6\.31/,
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
|
|
80
250
|
test('default compatibility manifest supports Cursor 3.5.38 on macOS x64 for Rosetta-launched installers', () => {
|
|
81
251
|
const entry = resolveCompatEntry(
|
|
82
252
|
{
|
|
@@ -93,6 +263,7 @@ test('default compatibility manifest supports Cursor 3.5.38 on macOS x64 for Ros
|
|
|
93
263
|
|
|
94
264
|
assert.equal(entry.supportStatus, 'supported');
|
|
95
265
|
assert.equal(entry.requiresAdHocResign, true);
|
|
266
|
+
assert.equal(entry.cursorVersion, '3.5');
|
|
96
267
|
assert.equal(entry.targetRelativePath, CURSOR_AGENT_EXEC_RELATIVE_PATH);
|
|
97
268
|
assert.equal(
|
|
98
269
|
entry.expectedSha256,
|
|
@@ -146,7 +317,8 @@ test('loads remote compatibility entries from api base url when signature is val
|
|
|
146
317
|
},
|
|
147
318
|
});
|
|
148
319
|
|
|
149
|
-
assert.equal(entries[0]?.cursorVersion, '3.7
|
|
320
|
+
assert.equal(entries[0]?.cursorVersion, '3.7');
|
|
321
|
+
assert.equal(entries[0]?.verifiedCursorVersion, '3.7.0');
|
|
150
322
|
});
|
|
151
323
|
|
|
152
324
|
test('loads compatibility entries from a local file URL for disposable client validation', async () => {
|
|
@@ -190,3 +362,66 @@ test('falls back to injected compatibility entries before fetching remote manife
|
|
|
190
362
|
|
|
191
363
|
assert.equal(entries, injected);
|
|
192
364
|
});
|
|
365
|
+
|
|
366
|
+
test('resolveCompatEntry only matches the current adapter version when provided', () => {
|
|
367
|
+
const cursor = {
|
|
368
|
+
appPath: '/Applications/Cursor.app',
|
|
369
|
+
version: '3.7.12',
|
|
370
|
+
commit: 'b887a26c4f70bd8136bfffeda812b24194ec9ce0',
|
|
371
|
+
};
|
|
372
|
+
const environment = {
|
|
373
|
+
platform: 'darwin' as const,
|
|
374
|
+
arch: 'arm64',
|
|
375
|
+
nodeVersion: process.version,
|
|
376
|
+
};
|
|
377
|
+
const matchingRule = remoteRuleFor(cursor.version, cursor.commit);
|
|
378
|
+
const otherAdapterRule = {
|
|
379
|
+
...matchingRule,
|
|
380
|
+
adapterVersion: '0.6.0',
|
|
381
|
+
userMessage: 'Cursor 3.7.12 needs the 0.6 adapter.',
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
assert.throws(
|
|
385
|
+
() =>
|
|
386
|
+
resolveCompatEntry(cursor, environment, {
|
|
387
|
+
entries: [otherAdapterRule],
|
|
388
|
+
adapterVersion: '0.5.8',
|
|
389
|
+
}),
|
|
390
|
+
/No compatibility entry for Cursor 3\.7\.12/,
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
const resolved = resolveCompatEntry(cursor, environment, {
|
|
394
|
+
entries: [otherAdapterRule],
|
|
395
|
+
adapterVersion: '0.6.0',
|
|
396
|
+
});
|
|
397
|
+
assert.equal(resolved.adapterVersion, '0.6.0');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
test('resolveCompatEntry rejects legacy rules without adapterVersion when current adapter is known', () => {
|
|
401
|
+
const cursor = {
|
|
402
|
+
appPath: '/Applications/Cursor.app',
|
|
403
|
+
version: '3.6.21',
|
|
404
|
+
commit: 'e7a7e93f4d75f8272503ecf33cedbaae10114a10',
|
|
405
|
+
};
|
|
406
|
+
const environment = {
|
|
407
|
+
platform: 'darwin' as const,
|
|
408
|
+
arch: 'arm64',
|
|
409
|
+
nodeVersion: process.version,
|
|
410
|
+
};
|
|
411
|
+
const { adapterVersion: _adapterVersion, ...legacyRule } = remoteRuleFor(cursor.version, cursor.commit);
|
|
412
|
+
|
|
413
|
+
assert.throws(
|
|
414
|
+
() =>
|
|
415
|
+
resolveCompatEntry(cursor, environment, {
|
|
416
|
+
entries: [legacyRule],
|
|
417
|
+
adapterVersion: '0.5.8',
|
|
418
|
+
}),
|
|
419
|
+
/No compatibility entry for Cursor 3\.6\.21/,
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
const resolved = resolveCompatEntry(cursor, environment, {
|
|
423
|
+
entries: [legacyRule],
|
|
424
|
+
});
|
|
425
|
+
assert.equal(resolved.cursorVersion, '3.6');
|
|
426
|
+
assert.equal(resolved.verifiedCursorVersion, '3.6.21');
|
|
427
|
+
});
|
|
@@ -59,6 +59,7 @@ test('CLI common options include target, record, trial, extension, and service l
|
|
|
59
59
|
cursorExtensionsDir: '/tmp/Cursor-Pool-Trial-Extensions',
|
|
60
60
|
userDataDir: '/tmp/Cursor-Pool-Trial-UserData',
|
|
61
61
|
serviceLogFile: '/tmp/service.log',
|
|
62
|
+
configFile: undefined,
|
|
62
63
|
diagnosticsFile: '/tmp/diagnostics.jsonl',
|
|
63
64
|
sessionFile: '/tmp/session.json',
|
|
64
65
|
code: 'CODE-123',
|
package/test/cursor.test.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
2
5
|
import test from 'node:test';
|
|
3
|
-
import { defaultCursorAppPath } from '../src/cursor';
|
|
6
|
+
import { defaultCursorAppPath, findCursor } from '../src/cursor';
|
|
4
7
|
|
|
5
8
|
test('defaultCursorAppPath resolves the user-level Windows Cursor install directory', () => {
|
|
6
9
|
assert.equal(
|
|
@@ -18,3 +21,59 @@ test('defaultCursorAppPath gives a helpful Windows error when LOCALAPPDATA is un
|
|
|
18
21
|
/LOCALAPPDATA is required to auto-detect Cursor on Windows/,
|
|
19
22
|
);
|
|
20
23
|
});
|
|
24
|
+
|
|
25
|
+
test('findCursor extracts Linux AppImage files before reading product metadata', async () => {
|
|
26
|
+
const tempDir = await mkdtemp(join(tmpdir(), 'cursor-pool-linux-appimage-'));
|
|
27
|
+
const appImagePath = join(tempDir, 'Cursor.AppImage');
|
|
28
|
+
const extractedRoots: string[] = [];
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
await writeFile(appImagePath, '#!/bin/sh\n', { mode: 0o755 });
|
|
32
|
+
|
|
33
|
+
const cursor = await findCursor({
|
|
34
|
+
appPath: appImagePath,
|
|
35
|
+
platform: 'linux',
|
|
36
|
+
appImageExtract: async (path, outputRoot) => {
|
|
37
|
+
assert.equal(path, appImagePath);
|
|
38
|
+
extractedRoots.push(outputRoot);
|
|
39
|
+
const extractedPath = join(outputRoot, 'squashfs-root');
|
|
40
|
+
await mkdir(join(extractedPath, 'usr/share/cursor/resources/app'), { recursive: true });
|
|
41
|
+
await writeFile(
|
|
42
|
+
join(extractedPath, 'usr/share/cursor/resources/app/product.json'),
|
|
43
|
+
JSON.stringify({ version: '3.6.31', commit: 'linux-commit' }),
|
|
44
|
+
'utf8',
|
|
45
|
+
);
|
|
46
|
+
return extractedPath;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
assert.equal(cursor.version, '3.6.31');
|
|
51
|
+
assert.equal(cursor.commit, 'linux-commit');
|
|
52
|
+
assert.match(cursor.appPath, /squashfs-root$/);
|
|
53
|
+
assert.equal(extractedRoots.length, 1);
|
|
54
|
+
} finally {
|
|
55
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('findCursor keeps macOS app bundle product path unchanged', async () => {
|
|
60
|
+
const tempDir = await mkdtemp(join(tmpdir(), 'cursor-pool-macos-app-'));
|
|
61
|
+
const appPath = join(tempDir, 'Cursor.app');
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
await mkdir(join(appPath, 'Contents/Resources/app'), { recursive: true });
|
|
65
|
+
await writeFile(
|
|
66
|
+
join(appPath, 'Contents/Resources/app/product.json'),
|
|
67
|
+
JSON.stringify({ version: '3.5.38', commit: 'mac-commit' }),
|
|
68
|
+
'utf8',
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const cursor = await findCursor({ appPath, platform: 'darwin' });
|
|
72
|
+
|
|
73
|
+
assert.equal(cursor.appPath, appPath);
|
|
74
|
+
assert.equal(cursor.version, '3.5.38');
|
|
75
|
+
assert.equal(cursor.commit, 'mac-commit');
|
|
76
|
+
} finally {
|
|
77
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
78
|
+
}
|
|
79
|
+
});
|
package/test/e2e-install.test.ts
CHANGED
|
@@ -13,6 +13,16 @@ import {
|
|
|
13
13
|
CURSOR_POOL_PATCH_MARKER,
|
|
14
14
|
} from '../../patcher/src/marker';
|
|
15
15
|
import { backupPathForCursorAgentExec } from '../../patcher/src/patchCursorAgentExec';
|
|
16
|
+
import { CURSOR_WORKBENCH_RELATIVE_PATH } from '../../patcher/src/patchCursorWorkbenchAuthGate';
|
|
17
|
+
import {
|
|
18
|
+
CURSOR_WORKBENCH_AGENT_CLIENT_RUN_LOCAL_MODE_ANCHOR,
|
|
19
|
+
CURSOR_WORKBENCH_AGENT_EDITOR_SEND_BUTTON_AUTH_GATE_ANCHOR,
|
|
20
|
+
CURSOR_WORKBENCH_AGENT_EDITOR_SEND_BUTTON_LOGIN_ANCHOR,
|
|
21
|
+
CURSOR_WORKBENCH_AGENT_LOOP_RUN_ANCHOR,
|
|
22
|
+
CURSOR_WORKBENCH_BUILD_FLAGS_LOCAL_MODE_ANCHOR,
|
|
23
|
+
CURSOR_WORKBENCH_COMPOSER_AUTH_GATE_ANCHOR,
|
|
24
|
+
CURSOR_WORKBENCH_COMPOSER_SUBMIT_AUTH_GATE_ANCHOR,
|
|
25
|
+
} from '../../patcher/src/workbenchAuthGateMarker';
|
|
16
26
|
import type { CompatibilityManifestEntry } from '../../shared/src/manifest';
|
|
17
27
|
import { getExtensionState } from '../src/extensionBundle';
|
|
18
28
|
import { getLinkedExtensionState, linkedExtensionPathForDir } from '../src/extensionLink';
|
|
@@ -35,30 +45,70 @@ const targetRelativePath =
|
|
|
35
45
|
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
|
|
36
46
|
const serviceServerPath = resolve(repoRoot, 'packages/service/src/server.ts');
|
|
37
47
|
|
|
48
|
+
function workbenchFixtureContent() {
|
|
49
|
+
const localProviderConfigAnchor =
|
|
50
|
+
'async getLocalAgentProviderConfig(e){const t="[AgentClientService][getLocalAgentProviderConfig]",i=L0.localMode?await this.shellEnvironmentService.getShellEnv():{},r=e?.credentials,s=r?.case==="apiKeyCredentials"?r.value:void 0,o=this.reactiveStorageService.applicationUserPersistentStorage,a=o.useOpenAIKey===!0?this.cursorAuthenticationService.openAIKey()??void 0:void 0,u=xgS({apiKeyCandidates:[{value:s?.apiKey,source:"modelDetails.apiKeyCredentials.apiKey"},{value:a,source:"storage.openAIKey"}],baseUrlCandidates:[{value:s?.baseUrl,source:"modelDetails.apiKeyCredentials.baseUrl"},{value:o.openAIBaseUrl,source:"storage.openAIBaseUrl"}]});return{baseUrl:u.baseUrl,apiKey:u.apiKey}}createDefaultLocalModel(e){return "default"}';
|
|
51
|
+
return [
|
|
52
|
+
`function composer(){return he(Mt,{${CURSOR_WORKBENCH_COMPOSER_AUTH_GATE_ANCHOR},get children(){return "controls"}})}`,
|
|
53
|
+
`async function submit(){${CURSOR_WORKBENCH_COMPOSER_SUBMIT_AUTH_GATE_ANCHOR};return "submitted";}`,
|
|
54
|
+
`function agentEditorControls(){const T=()=>{${CURSOR_WORKBENCH_AGENT_EDITOR_SEND_BUTTON_LOGIN_ANCHOR};return n.handleSubmit()};return he(Mt,{${CURSOR_WORKBENCH_AGENT_EDITOR_SEND_BUTTON_AUTH_GATE_ANCHOR}"controls"}})}`,
|
|
55
|
+
`const flags={${CURSOR_WORKBENCH_BUILD_FLAGS_LOCAL_MODE_ANCHOR}}`,
|
|
56
|
+
localProviderConfigAnchor,
|
|
57
|
+
`async function runAgentLoop(){${CURSOR_WORKBENCH_AGENT_LOOP_RUN_ANCHOR}}`,
|
|
58
|
+
`async function agentClientRun(){const g={...p,isRunningInTest:p.isRunningInTest??this.environmentService.enableSmokeTestDriver===!0,clientSupportsInlineImages:!0};${CURSOR_WORKBENCH_AGENT_CLIENT_RUN_LOCAL_MODE_ANCHOR}}`,
|
|
59
|
+
].join(';');
|
|
60
|
+
}
|
|
61
|
+
|
|
38
62
|
async function createFixtureApp(prefix: string) {
|
|
39
63
|
const tempDir = await mkdtemp(join(tmpdir(), prefix));
|
|
40
64
|
const appPath = join(tempDir, 'Cursor.app');
|
|
41
65
|
const targetPath = join(appPath, targetRelativePath);
|
|
42
66
|
const targetContent = `function main() { return "agent"; }\n${CURSOR_POOL_AGENT_EXEC_PROVIDER_REGISTER_ANCHOR}\nmain();\n`;
|
|
67
|
+
const workbenchPath = join(appPath, CURSOR_WORKBENCH_RELATIVE_PATH);
|
|
68
|
+
const workbenchContent = workbenchFixtureContent();
|
|
43
69
|
await mkdir(join(appPath, 'Contents/Resources/app/extensions/cursor-agent-exec/dist'), {
|
|
44
70
|
recursive: true,
|
|
45
71
|
});
|
|
72
|
+
await mkdir(join(appPath, 'Contents/Resources/app/out/vs/workbench'), {
|
|
73
|
+
recursive: true,
|
|
74
|
+
});
|
|
46
75
|
await writeFile(
|
|
47
76
|
join(appPath, 'Contents/Resources/app/product.json'),
|
|
48
77
|
JSON.stringify({ version: cursorVersion, commit: cursorCommit }),
|
|
49
78
|
'utf8',
|
|
50
79
|
);
|
|
51
80
|
await writeFile(targetPath, targetContent, 'utf8');
|
|
81
|
+
await writeFile(workbenchPath, workbenchContent, 'utf8');
|
|
52
82
|
|
|
53
83
|
const originalHash = createHash('sha256').update(targetContent).digest('hex');
|
|
84
|
+
const workbenchOriginalHash = createHash('sha256').update(workbenchContent).digest('hex');
|
|
54
85
|
const compatEntry: CompatibilityManifestEntry = {
|
|
55
86
|
platform: process.platform,
|
|
56
87
|
arch: process.arch,
|
|
57
88
|
cursorVersion,
|
|
58
89
|
cursorCommit,
|
|
59
90
|
supportStatus: 'supported',
|
|
91
|
+
takeoverPlanId: 'cursor-3.6-mac-agent-c-workbench-h-uv',
|
|
60
92
|
targetRelativePath,
|
|
61
93
|
expectedSha256: originalHash,
|
|
94
|
+
adapterVersion: '0.5.8',
|
|
95
|
+
structureFamily: 'fixture-agent-exec-workbench',
|
|
96
|
+
patchTargets: [
|
|
97
|
+
{
|
|
98
|
+
name: 'agent-exec',
|
|
99
|
+
targetRelativePath,
|
|
100
|
+
expectedSha256: originalHash,
|
|
101
|
+
patchStrategy: 'cursor-agent-exec-snippet',
|
|
102
|
+
verifyMarker: 'cursor-pool',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'workbench',
|
|
106
|
+
targetRelativePath: CURSOR_WORKBENCH_RELATIVE_PATH,
|
|
107
|
+
expectedSha256: workbenchOriginalHash,
|
|
108
|
+
patchStrategy: 'cursor-workbench-auth-gate',
|
|
109
|
+
verifyMarker: 'cursor-pool-workbench',
|
|
110
|
+
},
|
|
111
|
+
],
|
|
62
112
|
structureSignature: 'fixture',
|
|
63
113
|
patchStrategy: 'cursor-agent-exec-snippet',
|
|
64
114
|
verifyMarker: 'cursor-pool',
|
|
@@ -77,6 +127,9 @@ async function createFixtureApp(prefix: string) {
|
|
|
77
127
|
targetPath,
|
|
78
128
|
targetContent,
|
|
79
129
|
originalHash,
|
|
130
|
+
workbenchPath,
|
|
131
|
+
workbenchContent,
|
|
132
|
+
workbenchOriginalHash,
|
|
80
133
|
runtimeFile: join(tempDir, 'runtime.json'),
|
|
81
134
|
backupDir: join(tempDir, 'backups'),
|
|
82
135
|
compatEntry,
|
|
@@ -12,12 +12,12 @@ import {
|
|
|
12
12
|
snapshotLinkedExtensionBundle,
|
|
13
13
|
} from '../src/extensionLink';
|
|
14
14
|
|
|
15
|
-
async function createSourceBundle(tempDir: string) {
|
|
15
|
+
async function createSourceBundle(tempDir: string, version = '0.0.0') {
|
|
16
16
|
const sourceBundlePath = join(tempDir, 'source/extensions/cursor-pool-status');
|
|
17
17
|
await mkdir(join(sourceBundlePath, 'dist'), { recursive: true });
|
|
18
18
|
await writeFile(
|
|
19
19
|
join(sourceBundlePath, 'package.json'),
|
|
20
|
-
JSON.stringify({ name: 'cursorpool', publisher: 'cursor-pool', version
|
|
20
|
+
JSON.stringify({ name: 'cursorpool', publisher: 'cursor-pool', version }),
|
|
21
21
|
'utf8',
|
|
22
22
|
);
|
|
23
23
|
await writeFile(join(sourceBundlePath, 'dist/extension.js'), 'export function activate() {}\n', 'utf8');
|
|
@@ -54,6 +54,52 @@ test('linkExtensionBundle copies source bundle into Cursor extensions directory'
|
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
test('linkExtensionBundle uses the source manifest version for the linked directory and index', async () => {
|
|
58
|
+
const tempDir = await mkdtemp(join(tmpdir(), 'cursor-pool-extension-link-version-'));
|
|
59
|
+
const sourceBundlePath = await createSourceBundle(tempDir, '0.5.6');
|
|
60
|
+
const cursorExtensionsDir = join(tempDir, 'Extensions');
|
|
61
|
+
await mkdir(cursorExtensionsDir, { recursive: true });
|
|
62
|
+
await writeFile(join(cursorExtensionsDir, 'extensions.json'), '[]', 'utf8');
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const result = await linkExtensionBundle({ sourceBundlePath, cursorExtensionsDir });
|
|
66
|
+
const index = JSON.parse(await readFile(join(cursorExtensionsDir, 'extensions.json'), 'utf8'));
|
|
67
|
+
|
|
68
|
+
assert.deepEqual(result, {
|
|
69
|
+
state: 'linked',
|
|
70
|
+
linkedPath: join(cursorExtensionsDir, 'cursor-pool.extension-0.5.6'),
|
|
71
|
+
});
|
|
72
|
+
assert.equal(await getLinkedExtensionState(result.linkedPath), 'linked');
|
|
73
|
+
assert.deepEqual(index.at(-1), {
|
|
74
|
+
identifier: { id: 'cursor-pool.cursorpool' },
|
|
75
|
+
location: {
|
|
76
|
+
$mid: 1,
|
|
77
|
+
path: result.linkedPath,
|
|
78
|
+
scheme: 'file',
|
|
79
|
+
},
|
|
80
|
+
relativeLocation: 'cursor-pool.extension-0.5.6',
|
|
81
|
+
version: '0.5.6',
|
|
82
|
+
});
|
|
83
|
+
} finally {
|
|
84
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('linkExtensionBundle rejects unsafe source manifest versions before linking', async () => {
|
|
89
|
+
const tempDir = await mkdtemp(join(tmpdir(), 'cursor-pool-extension-link-version-unsafe-'));
|
|
90
|
+
const sourceBundlePath = await createSourceBundle(tempDir, '../../bad');
|
|
91
|
+
const cursorExtensionsDir = join(tempDir, 'Extensions');
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
await assert.rejects(
|
|
95
|
+
linkExtensionBundle({ sourceBundlePath, cursorExtensionsDir }),
|
|
96
|
+
/Unsafe extension version/,
|
|
97
|
+
);
|
|
98
|
+
} finally {
|
|
99
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
57
103
|
test('linkExtensionBundle refreshes Cursor extensions index with runtime extension id', async () => {
|
|
58
104
|
const tempDir = await mkdtemp(join(tmpdir(), 'cursor-pool-extension-link-index-'));
|
|
59
105
|
const sourceBundlePath = await createSourceBundle(tempDir);
|