@cursorpool-dev/cli 0.5.8 → 0.5.9

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.
Files changed (42) hide show
  1. package/node_modules/@cursor-pool/extension/dist/extension.js +46 -116
  2. package/node_modules/@cursor-pool/extension/package.json +3 -3
  3. package/node_modules/@cursor-pool/extension/src/api.ts +2 -17
  4. package/node_modules/@cursor-pool/extension/src/panel.ts +3 -26
  5. package/node_modules/@cursor-pool/extension/test/panel.test.ts +1 -34
  6. package/node_modules/@cursor-pool/patcher/package.json +2 -2
  7. package/node_modules/@cursor-pool/patcher/src/marker.ts +72 -7
  8. package/node_modules/@cursor-pool/patcher/src/workbenchAuthGateMarker.ts +80 -17
  9. package/node_modules/@cursor-pool/patcher/test/patchCursorAgentExec.test.ts +88 -13
  10. package/node_modules/@cursor-pool/patcher/test/patchCursorWorkbench.test.ts +151 -149
  11. package/node_modules/@cursor-pool/service/package.json +2 -2
  12. package/node_modules/@cursor-pool/service/src/platformSession.ts +7 -30
  13. package/node_modules/@cursor-pool/service/src/server.ts +1 -1
  14. package/node_modules/@cursor-pool/service/test/platformSession.test.ts +4 -5
  15. package/node_modules/@cursor-pool/service/test/server.test.ts +1 -130
  16. package/node_modules/@cursor-pool/shared/package.json +1 -1
  17. package/node_modules/@cursor-pool/shared/src/manifest.ts +0 -35
  18. package/node_modules/@cursor-pool/shared/test/manifest.test.ts +9 -43
  19. package/package.json +5 -7
  20. package/src/compat.ts +124 -196
  21. package/src/extensionBundle.ts +1 -1
  22. package/src/extensionLink.ts +8 -29
  23. package/src/install.ts +9 -62
  24. package/src/installRecord.ts +0 -2
  25. package/src/patchSet.ts +6 -12
  26. package/src/platform.ts +3 -3
  27. package/src/repair.ts +2 -10
  28. package/src/restore.ts +4 -12
  29. package/src/status.ts +0 -6
  30. package/src/trial.ts +2 -3
  31. package/test/compat.test.ts +59 -195
  32. package/test/e2e-install.test.ts +0 -53
  33. package/test/extensionLink.test.ts +26 -49
  34. package/test/install.test.ts +4 -64
  35. package/test/repair.test.ts +0 -1
  36. package/test/status.test.ts +0 -1
  37. package/test/trial.test.ts +15 -1
  38. package/node_modules/@cursor-pool/takeover-plans/package.json +0 -12
  39. package/node_modules/@cursor-pool/takeover-plans/src/index.ts +0 -22
  40. package/node_modules/@cursor-pool/takeover-plans/src/plans.ts +0 -37
  41. package/node_modules/@cursor-pool/takeover-plans/src/types.ts +0 -9
  42. package/node_modules/@cursor-pool/takeover-plans/test/registry.test.ts +0 -23
package/src/compat.ts CHANGED
@@ -5,171 +5,129 @@ import type {
5
5
  CompatibilityManifestEntry,
6
6
  CompatibilityManifestEnvelope,
7
7
  } from '@cursor-pool/shared/manifest';
8
- import {
9
- CURSOR_AGENT_EXEC_RELATIVE_PATH,
10
- CURSOR_WORKBENCH_RELATIVE_PATH,
11
- } from '@cursor-pool/patcher';
8
+ import { CURSOR_AGENT_EXEC_RELATIVE_PATH } from '@cursor-pool/patcher';
12
9
  import type { CliEnvironment } from './environment';
13
10
  import type { CursorInfo } from './cursor';
14
11
 
15
- function macPatchTargets(agentSha256: string, workbenchSha256: string) {
16
- return [
17
- {
18
- name: 'agent-exec',
19
- targetRelativePath: CURSOR_AGENT_EXEC_RELATIVE_PATH,
20
- expectedSha256: agentSha256,
21
- patchStrategy: 'cursor-agent-exec-snippet',
22
- verifyMarker: 'cursor-pool',
23
- },
24
- {
25
- name: 'workbench',
26
- targetRelativePath: CURSOR_WORKBENCH_RELATIVE_PATH,
27
- expectedSha256: workbenchSha256,
28
- patchStrategy: 'cursor-workbench-auth-gate',
29
- verifyMarker: 'cursor-pool-workbench',
30
- },
31
- ];
32
- }
33
-
34
- function macCompatEntry(input: {
35
- arch: 'arm64' | 'x64';
36
- officialMajorVersion: string;
37
- verifiedCursorVersion: string;
38
- cursorVersion: string;
39
- cursorCommit: string;
40
- adapterVersion: string;
41
- structureFamily: string;
42
- takeoverPlanId: string;
43
- agentSha256: string;
44
- workbenchSha256: string;
45
- userMessage: string;
46
- }): CompatibilityManifestEntry {
47
- return {
12
+ export const DEFAULT_COMPAT_ENTRIES: CompatibilityManifestEntry[] = [
13
+ {
48
14
  platform: 'darwin',
49
- arch: input.arch,
50
- officialSourceUrl: 'https://cursor.com/download',
51
- officialDownloadUrl: `https://api2.cursor.sh/updates/download/golden/darwin-${input.arch}/cursor/${input.officialMajorVersion}`,
52
- officialDownloadPlatform: `darwin-${input.arch}`,
53
- verifiedCursorVersion: input.verifiedCursorVersion,
54
- cursorVersion: input.officialMajorVersion,
55
- cursorCommit: input.cursorCommit,
15
+ arch: 'arm64',
16
+ cursorVersion: '3.4',
17
+ cursorCommit: '*',
56
18
  supportStatus: 'supported',
57
- adapterVersion: input.adapterVersion,
58
- takeoverPlanId: input.takeoverPlanId,
59
- structureFamily: input.structureFamily,
60
- patchTargets: macPatchTargets(input.agentSha256, input.workbenchSha256),
61
19
  targetRelativePath: CURSOR_AGENT_EXEC_RELATIVE_PATH,
62
- expectedSha256: input.agentSha256,
63
- structureSignature: input.structureFamily,
20
+ expectedSha256: '*',
21
+ structureSignature: 'ep1-cursor-3-4-family',
64
22
  patchStrategy: 'cursor-agent-exec-snippet',
65
23
  verifyMarker: 'cursor-pool',
66
24
  restoreStrategy: 'external-backup',
67
- minCliVersion: '0.5.8',
68
- minExtensionVersion: '0.5.8',
69
- minServiceVersion: '0.5.8',
25
+ minCliVersion: '0.5.9',
26
+ minExtensionVersion: '0.5.9',
27
+ minServiceVersion: '0.5.9',
70
28
  requiresWritableAppBundle: true,
71
29
  requiresAdHocResign: true,
72
- userMessage: input.userMessage,
73
- };
74
- }
75
-
76
- export const DEFAULT_COMPAT_ENTRIES: CompatibilityManifestEntry[] = [
77
- macCompatEntry({
78
- arch: 'arm64',
79
- officialMajorVersion: '3.4',
80
- verifiedCursorVersion: '3.4.20',
81
- cursorVersion: '3.4.20',
82
- cursorCommit: '0cf8b06883f54e26bb4f0fb8647c9500ccb43310',
83
- adapterVersion: '0.4.8',
84
- structureFamily: 'mac-agent-D-workbench-U0',
85
- takeoverPlanId: 'cursor-3.4-mac-agent-d-workbench-u0',
86
- agentSha256: 'c63ae78a3b72df82db224839d552b1f8ca38011e45a37a55ae4ccd75fcdc125f',
87
- workbenchSha256: '01a7005df6a76159b4edafee3c4a233003626e082212f9d042a81239a2bde388',
88
- userMessage: 'Cursor 3.4.20 macOS arm64 is supported by the v0.4 adapter.',
89
- }),
90
- macCompatEntry({
91
- arch: 'x64',
92
- officialMajorVersion: '3.4',
93
- verifiedCursorVersion: '3.4.20',
94
- cursorVersion: '3.4.20',
95
- cursorCommit: '0cf8b06883f54e26bb4f0fb8647c9500ccb43310',
96
- adapterVersion: '0.4.8',
97
- structureFamily: 'mac-agent-D-workbench-U0',
98
- takeoverPlanId: 'cursor-3.4-mac-agent-d-workbench-u0',
99
- agentSha256: 'c63ae78a3b72df82db224839d552b1f8ca38011e45a37a55ae4ccd75fcdc125f',
100
- workbenchSha256: '01a7005df6a76159b4edafee3c4a233003626e082212f9d042a81239a2bde388',
101
- userMessage: 'Cursor 3.4.20 macOS x64 is supported by the v0.4 adapter.',
102
- }),
103
- macCompatEntry({
30
+ userMessage: 'Cursor 3.4.x is supported for MVP-0.',
31
+ },
32
+ {
33
+ platform: 'darwin',
104
34
  arch: 'arm64',
105
- officialMajorVersion: '3.5',
106
- verifiedCursorVersion: '3.5.38',
107
- cursorVersion: '3.5.38',
108
- cursorCommit: '009bb5a3600dd98fe1c1f25798f767f686e14750',
109
- adapterVersion: '0.5.8',
110
- structureFamily: 'mac-agent-F-workbench-p-L0',
111
- takeoverPlanId: 'cursor-3.5-mac-agent-f-workbench-p-l0',
112
- agentSha256: 'cb18f0237278884a39e2ce2b8664255e12689ad0803c20096c38e86c36acc51f',
113
- workbenchSha256: '19762fb81b7d5f1a42ffa8c0c487648432874d0892cfcdb32824b107f6dcf99d',
114
- userMessage: 'Cursor 3.5.38 macOS arm64 is supported by the v0.5 adapter.',
115
- }),
116
- macCompatEntry({
35
+ cursorVersion: '3.5',
36
+ cursorCommit: '*',
37
+ supportStatus: 'supported',
38
+ targetRelativePath: CURSOR_AGENT_EXEC_RELATIVE_PATH,
39
+ expectedSha256: '*',
40
+ structureSignature: 'ep1-cursor-3-5-family',
41
+ patchStrategy: 'cursor-agent-exec-snippet',
42
+ verifyMarker: 'cursor-pool',
43
+ restoreStrategy: 'external-backup',
44
+ minCliVersion: '0.5.9',
45
+ minExtensionVersion: '0.5.9',
46
+ minServiceVersion: '0.5.9',
47
+ requiresWritableAppBundle: true,
48
+ requiresAdHocResign: true,
49
+ userMessage: 'Cursor 3.5.x is supported for MVP-0.',
50
+ },
51
+ {
52
+ platform: 'darwin',
117
53
  arch: 'x64',
118
- officialMajorVersion: '3.5',
119
- verifiedCursorVersion: '3.5.38',
120
- cursorVersion: '3.5.38',
121
- cursorCommit: '009bb5a3600dd98fe1c1f25798f767f686e14750',
122
- adapterVersion: '0.5.8',
123
- structureFamily: 'mac-agent-F-workbench-p-L0',
124
- takeoverPlanId: 'cursor-3.5-mac-agent-f-workbench-p-l0',
125
- agentSha256: 'cb18f0237278884a39e2ce2b8664255e12689ad0803c20096c38e86c36acc51f',
126
- workbenchSha256: '19762fb81b7d5f1a42ffa8c0c487648432874d0892cfcdb32824b107f6dcf99d',
127
- userMessage: 'Cursor 3.5.38 macOS x64 is supported by the v0.5 adapter.',
128
- }),
129
- macCompatEntry({
54
+ cursorVersion: '3.5',
55
+ cursorCommit: '*',
56
+ supportStatus: 'supported',
57
+ targetRelativePath: CURSOR_AGENT_EXEC_RELATIVE_PATH,
58
+ expectedSha256: '*',
59
+ structureSignature: 'ep1-cursor-3-5-family',
60
+ patchStrategy: 'cursor-agent-exec-snippet',
61
+ verifyMarker: 'cursor-pool',
62
+ restoreStrategy: 'external-backup',
63
+ minCliVersion: '0.5.9',
64
+ minExtensionVersion: '0.5.9',
65
+ minServiceVersion: '0.5.9',
66
+ requiresWritableAppBundle: true,
67
+ requiresAdHocResign: true,
68
+ userMessage: 'Cursor 3.5.x is supported for MVP-0 under Rosetta-launched installers.',
69
+ },
70
+ {
71
+ platform: 'darwin',
130
72
  arch: 'arm64',
131
- officialMajorVersion: '3.6',
132
- verifiedCursorVersion: '3.6.21',
133
- cursorVersion: '3.6.21',
134
- cursorCommit: 'e7a7e93f4d75f8272503ecf33cedbaae10114a10',
135
- adapterVersion: '0.5.8',
136
- structureFamily: 'mac-agent-c-workbench-h-uv',
137
- takeoverPlanId: 'cursor-3.6-mac-agent-c-workbench-h-uv',
138
- agentSha256: '222512631b78fddcdca3fa76c0dd458a7a86751dde19c998ceb31b3fe1905ebf',
139
- workbenchSha256: '97562e30eebf41b9e162eb100966a2caf09c1c2fcf55bc87d5a84f9de67511f5',
140
- userMessage: 'Cursor 3.6.21 macOS arm64 is supported by the v0.5 adapter.',
141
- }),
142
- macCompatEntry({
73
+ cursorVersion: '3.6',
74
+ cursorCommit: '*',
75
+ supportStatus: 'supported',
76
+ targetRelativePath: CURSOR_AGENT_EXEC_RELATIVE_PATH,
77
+ expectedSha256: '*',
78
+ structureSignature: 'ep1-cursor-3-6-family',
79
+ patchStrategy: 'cursor-agent-exec-snippet',
80
+ verifyMarker: 'cursor-pool',
81
+ restoreStrategy: 'external-backup',
82
+ minCliVersion: '0.5.9',
83
+ minExtensionVersion: '0.5.9',
84
+ minServiceVersion: '0.5.9',
85
+ requiresWritableAppBundle: true,
86
+ requiresAdHocResign: true,
87
+ userMessage: 'Cursor 3.6.x is supported for MVP-0.',
88
+ },
89
+ {
90
+ platform: 'darwin',
143
91
  arch: 'arm64',
144
- officialMajorVersion: '3.6',
145
- verifiedCursorVersion: '3.6.31',
92
+ cursorVersion: '3.7',
93
+ cursorCommit: '*',
94
+ supportStatus: 'supported',
95
+ targetRelativePath: CURSOR_AGENT_EXEC_RELATIVE_PATH,
96
+ expectedSha256: '*',
97
+ structureSignature: 'ep1-cursor-3-7-family',
98
+ patchStrategy: 'cursor-agent-exec-snippet',
99
+ verifyMarker: 'cursor-pool',
100
+ restoreStrategy: 'external-backup',
101
+ minCliVersion: '0.5.9',
102
+ minExtensionVersion: '0.5.9',
103
+ minServiceVersion: '0.5.9',
104
+ requiresWritableAppBundle: true,
105
+ requiresAdHocResign: true,
106
+ userMessage: 'Cursor 3.7.x is supported for MVP-0.',
107
+ },
108
+ {
109
+ platform: 'linux',
110
+ arch: 'x64',
146
111
  cursorVersion: '3.6.31',
147
112
  cursorCommit: '81fcf2931d7687b4ff3f3017858d0c6dee7e2a60',
148
- adapterVersion: '0.5.8',
149
- structureFamily: 'mac-agent-c-workbench-h-uv',
150
- takeoverPlanId: 'cursor-3.6-mac-agent-c-workbench-h-uv',
151
- agentSha256: '05bfa29eacb8271c378765ead4bf881f806b97549dd13367183aa7a9331c1131',
152
- workbenchSha256: '97562e30eebf41b9e162eb100966a2caf09c1c2fcf55bc87d5a84f9de67511f5',
153
- userMessage: 'Cursor 3.6.31 macOS arm64 is supported by the v0.5 adapter.',
154
- }),
155
- macCompatEntry({
156
- arch: 'arm64',
157
- officialMajorVersion: '3.7',
158
- verifiedCursorVersion: '3.7.12',
159
- cursorVersion: '3.7.12',
160
- cursorCommit: 'b887a26c4f70bd8136bfffeda812b24194ec9ce0',
161
- adapterVersion: '0.6.0',
162
- structureFamily: 'mac-3.7-agent-Et-workbench-wv',
163
- takeoverPlanId: 'cursor-3.7-mac-agent-et-workbench-wv',
164
- agentSha256: '9ce7a2f40a98a27eb1b609a79e0e1707bad5fbb02493693f6f18945a7640dde4',
165
- workbenchSha256: 'e91aa502a84d5b1653a2c1f3a71a2d4160ab5f1de5809dd230756ecc0cc27db9',
166
- userMessage: 'Cursor 3.7.12 macOS arm64 is supported by the v0.6 adapter.',
167
- }),
113
+ supportStatus: 'supported',
114
+ targetRelativePath: 'usr/share/cursor/resources/app/extensions/cursor-agent-exec/dist/main.js',
115
+ expectedSha256: '05bfa29eacb8271c378765ead4bf881f806b97549dd13367183aa7a9331c1131',
116
+ structureSignature: 'linux-appimage-3-6-31-cursor-agent-exec',
117
+ patchStrategy: 'cursor-agent-exec-snippet',
118
+ verifyMarker: 'cursor-pool',
119
+ restoreStrategy: 'external-backup',
120
+ minCliVersion: '0.5.7',
121
+ minExtensionVersion: '0.5.7',
122
+ minServiceVersion: '0.5.7',
123
+ requiresWritableAppBundle: true,
124
+ requiresAdHocResign: false,
125
+ userMessage: 'Cursor 3.6.31 Linux x64 AppImage is supported.',
126
+ },
168
127
  ];
169
128
 
170
129
  export type ResolveCompatOptions = {
171
130
  entries?: CompatibilityManifestEntry[];
172
- adapterVersion?: string;
173
131
  };
174
132
 
175
133
  export type CompatManifestFetchResponse = {
@@ -220,34 +178,6 @@ function asBoolean(value: unknown, field: string) {
220
178
  return value;
221
179
  }
222
180
 
223
- function asOptionalString(value: unknown, field: string) {
224
- if (value === undefined) {
225
- return undefined;
226
- }
227
- return asString(value, field);
228
- }
229
-
230
- function normalizePatchTargets(value: unknown) {
231
- if (value === undefined) {
232
- return undefined;
233
- }
234
- if (!Array.isArray(value)) {
235
- throw new Error('compat manifest patchTargets invalid');
236
- }
237
- return value.map((target) => {
238
- if (!isRecord(target)) {
239
- throw new Error('compat manifest patchTarget invalid');
240
- }
241
- return {
242
- name: asString(target.name, 'patchTargets.name'),
243
- targetRelativePath: asString(target.targetRelativePath, 'patchTargets.targetRelativePath'),
244
- expectedSha256: asString(target.expectedSha256, 'patchTargets.expectedSha256'),
245
- patchStrategy: asString(target.patchStrategy, 'patchTargets.patchStrategy'),
246
- verifyMarker: asString(target.verifyMarker, 'patchTargets.verifyMarker'),
247
- };
248
- });
249
- }
250
-
251
181
  function normalizeRule(value: unknown): RemoteCompatibilityManifestRule {
252
182
  if (!isRecord(value)) {
253
183
  throw new Error('compat manifest rule invalid');
@@ -263,23 +193,12 @@ function normalizeRule(value: unknown): RemoteCompatibilityManifestRule {
263
193
  ) {
264
194
  throw new Error('compat manifest revision invalid');
265
195
  }
266
- const adapterVersion = asOptionalString(value.adapterVersion, 'adapterVersion');
267
- const structureFamily = asOptionalString(value.structureFamily, 'structureFamily');
268
- const patchTargets = normalizePatchTargets(value.patchTargets);
269
196
  return {
270
197
  platform: asString(value.platform, 'platform'),
271
198
  arch: asString(value.arch, 'arch'),
272
- ...(value.officialSourceUrl === undefined ? {} : { officialSourceUrl: asString(value.officialSourceUrl, 'officialSourceUrl') }),
273
- ...(value.officialDownloadUrl === undefined ? {} : { officialDownloadUrl: asString(value.officialDownloadUrl, 'officialDownloadUrl') }),
274
- ...(value.officialDownloadPlatform === undefined ? {} : { officialDownloadPlatform: asString(value.officialDownloadPlatform, 'officialDownloadPlatform') }),
275
- ...(value.verifiedCursorVersion === undefined ? {} : { verifiedCursorVersion: asString(value.verifiedCursorVersion, 'verifiedCursorVersion') }),
276
199
  cursorVersion: asString(value.cursorVersion, 'cursorVersion'),
277
200
  cursorCommit: asString(value.cursorCommit, 'cursorCommit'),
278
201
  supportStatus,
279
- ...(adapterVersion === undefined ? {} : { adapterVersion }),
280
- takeoverPlanId: asString(value.takeoverPlanId, 'takeoverPlanId'),
281
- ...(structureFamily === undefined ? {} : { structureFamily }),
282
- ...(patchTargets === undefined ? {} : { patchTargets }),
283
202
  targetRelativePath: asString(value.targetRelativePath, 'targetRelativePath'),
284
203
  expectedSha256: asString(value.expectedSha256, 'expectedSha256'),
285
204
  structureSignature: asString(value.structureSignature, 'structureSignature'),
@@ -301,10 +220,8 @@ function canonicalRuleSegment(rule: RemoteCompatibilityManifestRule) {
301
220
  rule.platform,
302
221
  rule.arch,
303
222
  rule.cursorVersion,
304
- rule.verifiedCursorVersion ?? '',
305
223
  rule.cursorCommit,
306
224
  rule.supportStatus,
307
- rule.takeoverPlanId,
308
225
  String(rule.revision ?? 1),
309
226
  ].join(':');
310
227
  }
@@ -318,6 +235,27 @@ function safeEqualHex(left: string, right: string) {
318
235
  return timingSafeEqual(leftBuffer, rightBuffer);
319
236
  }
320
237
 
238
+ function cursorVersionFamily(version: string) {
239
+ const match = version.match(/^(\d+\.\d+)(?:\.|$)/);
240
+ return match?.[1];
241
+ }
242
+
243
+ function compatEntryMatches(
244
+ candidate: CompatibilityManifestEntry,
245
+ cursor: CursorInfo,
246
+ environment: CliEnvironment,
247
+ ) {
248
+ if (candidate.platform !== environment.platform || candidate.arch !== environment.arch) {
249
+ return false;
250
+ }
251
+ const versionMatches =
252
+ candidate.cursorVersion === cursor.version ||
253
+ candidate.cursorVersion === cursorVersionFamily(cursor.version);
254
+ const commitMatches =
255
+ candidate.cursorCommit === '*' || candidate.cursorCommit === cursor.commit;
256
+ return versionMatches && commitMatches;
257
+ }
258
+
321
259
  export function buildCompatManifestSignature(
322
260
  version: number,
323
261
  rules: RemoteCompatibilityManifestRule[],
@@ -356,11 +294,6 @@ export function verifyCompatManifestEnvelope(
356
294
  return rules.map(({ revision, ...rule }) => rule);
357
295
  }
358
296
 
359
- function officialCursorMajorVersion(cursorVersion: string) {
360
- const match = cursorVersion.match(/^(\d+\.\d+)(?:\.|$)/);
361
- return match?.[1] ?? cursorVersion;
362
- }
363
-
364
297
  export function compatManifestUrlFromApiBaseUrl(apiBaseUrl: string) {
365
298
  return `${apiBaseUrl.replace(/\/+$/, '')}/api/client/compatibility/manifest`;
366
299
  }
@@ -407,12 +340,7 @@ export function resolveCompatEntry(
407
340
  ) {
408
341
  const entries = options.entries ?? DEFAULT_COMPAT_ENTRIES;
409
342
  const entry = entries.find(
410
- (candidate) =>
411
- candidate.platform === environment.platform &&
412
- candidate.arch === environment.arch &&
413
- candidate.cursorVersion === officialCursorMajorVersion(cursor.version) &&
414
- candidate.cursorCommit === cursor.commit &&
415
- (!options.adapterVersion || candidate.adapterVersion === options.adapterVersion),
343
+ (candidate) => compatEntryMatches(candidate, cursor, environment),
416
344
  );
417
345
 
418
346
  if (!entry) {
@@ -55,7 +55,7 @@ async function exists(path: string) {
55
55
  function buildRuntimeManifest(sourceManifest: Record<string, unknown>) {
56
56
  return {
57
57
  name: 'cursorpool',
58
- version: typeof sourceManifest.version === 'string' ? sourceManifest.version : '0.5.8',
58
+ version: typeof sourceManifest.version === 'string' ? sourceManifest.version : '0.5.9',
59
59
  displayName: 'Cursor Pool 平台模式',
60
60
  publisher: 'cursor-pool',
61
61
  type: sourceManifest.type,
@@ -4,8 +4,7 @@ import { basename, dirname, join, resolve } from 'node:path';
4
4
  import { resolveExtensionInstallPath } from './extensionBundle';
5
5
  import type { ExtensionState } from './trial';
6
6
 
7
- export const LINKED_EXTENSION_DIRNAME = 'cursor-pool.extension-0.5.8';
8
- const LINKED_EXTENSION_DIRNAME_PREFIX = 'cursor-pool.extension-';
7
+ export const LINKED_EXTENSION_DIRNAME = 'cursor-pool.extension-0.5.9';
9
8
  const RUNTIME_EXTENSION_ID = 'cursor-pool.cursorpool';
10
9
  const STALE_EXTENSION_IDS = new Set([
11
10
  RUNTIME_EXTENSION_ID,
@@ -49,17 +48,10 @@ async function readRuntimeManifest(linkedPath: string) {
49
48
  };
50
49
  const publisher = typeof manifest.publisher === 'string' ? manifest.publisher : 'cursor-pool';
51
50
  const name = typeof manifest.name === 'string' ? manifest.name : 'cursorpool';
52
- const version = typeof manifest.version === 'string' ? manifest.version : '0.5.8';
51
+ const version = typeof manifest.version === 'string' ? manifest.version : '0.5.9';
53
52
  return { id: `${publisher}.${name}`, version };
54
53
  }
55
54
 
56
- function linkedExtensionDirnameForVersion(version: string) {
57
- if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(version)) {
58
- throw new Error(`Unsafe extension version: ${version}`);
59
- }
60
- return `${LINKED_EXTENSION_DIRNAME_PREFIX}${version}`;
61
- }
62
-
63
55
  export async function refreshCursorExtensionsIndex(cursorExtensionsDir: string, linkedPath: string) {
64
56
  const indexPath = join(resolveExtensionInstallPath(cursorExtensionsDir), 'extensions.json');
65
57
  if (!(await exists(indexPath))) {
@@ -71,13 +63,11 @@ export async function refreshCursorExtensionsIndex(cursorExtensionsDir: string,
71
63
  relativeLocation?: string;
72
64
  }>;
73
65
  const manifest = await readRuntimeManifest(linkedPath);
74
- const relativeLocation = basename(linkedPath);
75
66
  const nextEntries = entries.filter((entry) => {
76
67
  const id = entry.identifier?.id;
77
- const relativeLocation = entry.relativeLocation ?? '';
78
68
  return (
79
69
  !STALE_EXTENSION_IDS.has(id ?? '') &&
80
- !relativeLocation.startsWith(LINKED_EXTENSION_DIRNAME_PREFIX) &&
70
+ entry.relativeLocation !== LINKED_EXTENSION_DIRNAME &&
81
71
  entry.relativeLocation !== 'keg1255.cursorpool-1.0.52'
82
72
  );
83
73
  });
@@ -89,7 +79,7 @@ export async function refreshCursorExtensionsIndex(cursorExtensionsDir: string,
89
79
  path: linkedPath,
90
80
  scheme: 'file',
91
81
  },
92
- relativeLocation,
82
+ relativeLocation: LINKED_EXTENSION_DIRNAME,
93
83
  version: manifest.version,
94
84
  });
95
85
  await writeFile(indexPath, `${JSON.stringify(nextEntries, null, 2)}\n`, 'utf8');
@@ -102,23 +92,15 @@ function assertSafeLinkedExtensionPath(linkedPath: string) {
102
92
  (segment) => segment === 'extensions' || segment === 'Extensions',
103
93
  );
104
94
 
105
- if (!basename(resolvedLinkedPath).startsWith(LINKED_EXTENSION_DIRNAME_PREFIX) || !hasExtensionsParent) {
95
+ if (basename(resolvedLinkedPath) !== LINKED_EXTENSION_DIRNAME || !hasExtensionsParent) {
106
96
  throw new Error(
107
- `Unsafe linked extension path for recursive removal: ${linkedPath}. Expected an extensions/${LINKED_EXTENSION_DIRNAME_PREFIX}<version> bundle path.`,
97
+ `Unsafe linked extension path for recursive removal: ${linkedPath}. Expected an extensions/${LINKED_EXTENSION_DIRNAME} bundle path.`,
108
98
  );
109
99
  }
110
100
  }
111
101
 
112
102
  export function linkedExtensionPathForDir(cursorExtensionsDir: string) {
113
- return join(resolveExtensionInstallPath(cursorExtensionsDir), LINKED_EXTENSION_DIRNAME);
114
- }
115
-
116
- export async function linkedExtensionPathForSource(cursorExtensionsDir: string, sourceBundlePath: string) {
117
- const manifest = await readRuntimeManifest(sourceBundlePath);
118
- return join(
119
- resolveExtensionInstallPath(cursorExtensionsDir),
120
- linkedExtensionDirnameForVersion(manifest.version),
121
- );
103
+ return join(resolve(resolveExtensionInstallPath(cursorExtensionsDir)), LINKED_EXTENSION_DIRNAME);
122
104
  }
123
105
 
124
106
  export async function getLinkedExtensionState(linkedPath: string | undefined): Promise<LinkedExtensionState> {
@@ -137,10 +119,7 @@ export async function linkExtensionBundle({
137
119
  cursorExtensionsDir,
138
120
  }: LinkExtensionBundleOptions): Promise<LinkExtensionBundleResult> {
139
121
  const resolvedSourceBundlePath = resolveExtensionInstallPath(sourceBundlePath);
140
- const linkedPath =
141
- (await getLinkedExtensionState(resolvedSourceBundlePath)) === 'missing'
142
- ? linkedExtensionPathForDir(cursorExtensionsDir)
143
- : await linkedExtensionPathForSource(cursorExtensionsDir, resolvedSourceBundlePath);
122
+ const linkedPath = linkedExtensionPathForDir(cursorExtensionsDir);
144
123
 
145
124
  if ((await getLinkedExtensionState(resolvedSourceBundlePath)) === 'missing') {
146
125
  return { state: 'missing', linkedPath };
package/src/install.ts CHANGED
@@ -7,18 +7,16 @@ import {
7
7
  restoreCursorAgentExec,
8
8
  restoreCursorAlwaysLocal,
9
9
  restoreCursorWorkbenchAuthGate,
10
- containsCursorWorkbenchAuthGateMarker,
11
10
  } from '@cursor-pool/patcher';
12
11
  import { sha256File } from '@cursor-pool/patcher/hash';
13
12
  import { startServer } from '@cursor-pool/service';
14
- import { assertBundledTakeoverPlan } from '@cursor-pool/takeover-plans';
15
13
  import {
16
14
  readRuntimeInfo,
17
15
  resolveRuntimeFile,
18
16
  writeRuntimeInfo,
19
17
  type RuntimeInfo,
20
18
  } from '@cursor-pool/service';
21
- import type { CompatibilityManifestEntry, CompatibilityPatchTarget } from '@cursor-pool/shared/manifest';
19
+ import type { CompatibilityManifestEntry } from '@cursor-pool/shared/manifest';
22
20
  import { DEFAULT_RUNTIME_FILE } from '@cursor-pool/shared/runtime';
23
21
  import { writeClientConfig } from '@cursor-pool/shared/clientConfig';
24
22
  import { containsCursorPoolMarker } from '@cursor-pool/patcher/marker';
@@ -34,7 +32,6 @@ import {
34
32
  import {
35
33
  getLinkedExtensionState,
36
34
  linkExtensionBundle,
37
- linkedExtensionPathForSource,
38
35
  linkedExtensionPathForDir,
39
36
  refreshCursorExtensionsIndex,
40
37
  removeLinkedExtensionBundle,
@@ -107,7 +104,7 @@ export type InstallOptions = FindCursorOptions &
107
104
  };
108
105
 
109
106
  const REAL_CURSOR_EXTENSIONS_DIR = '~/.cursor/extensions';
110
- const PACKAGE_VERSION = '0.5.8';
107
+ const PACKAGE_VERSION = '0.5.9';
111
108
  const AUTOSTART_SERVICE_STARTUP_TIMEOUT_MS = 30_000;
112
109
 
113
110
  function delay(ms: number) {
@@ -133,57 +130,17 @@ async function maybeAdHocResign({
133
130
  return 'ad-hoc' as const;
134
131
  }
135
132
 
136
- function markerPredicateForPatchTarget(target: CompatibilityPatchTarget) {
137
- if (target.name === 'workbench' || target.verifyMarker === 'cursor-pool-workbench') {
138
- return containsCursorWorkbenchAuthGateMarker;
139
- }
140
- return containsCursorPoolMarker;
141
- }
142
-
143
- async function assertExpectedHash(
144
- targetPath: string,
145
- expectedSha256: string,
146
- containsExpectedMarker = containsCursorPoolMarker,
147
- ) {
133
+ async function assertExpectedHash(targetPath: string, expectedSha256: string) {
148
134
  const currentHash = await sha256File(targetPath);
149
135
  if (currentHash !== expectedSha256) {
150
136
  const content = await readFile(targetPath, 'utf8');
151
- if (containsExpectedMarker(content)) {
137
+ if (containsCursorPoolMarker(content)) {
152
138
  return;
153
139
  }
154
140
  throw new Error(`Patch target hash mismatch: expected ${expectedSha256}, got ${currentHash}`);
155
141
  }
156
142
  }
157
143
 
158
- function compatPatchTargets(compat: CompatibilityManifestEntry): CompatibilityPatchTarget[] {
159
- if (compat.patchTargets?.length) {
160
- return compat.patchTargets;
161
- }
162
- return [
163
- {
164
- name: 'agent-exec',
165
- targetRelativePath: compat.targetRelativePath,
166
- expectedSha256: compat.expectedSha256,
167
- patchStrategy: compat.patchStrategy,
168
- verifyMarker: compat.verifyMarker,
169
- },
170
- ];
171
- }
172
-
173
- function workbenchTargetRelativePathFromCompat(compat: CompatibilityManifestEntry) {
174
- return compat.patchTargets?.find((target) => target.name === 'workbench')?.targetRelativePath;
175
- }
176
-
177
- async function assertExpectedPatchTargetHashes(appPath: string, compat: CompatibilityManifestEntry) {
178
- for (const target of compatPatchTargets(compat)) {
179
- await assertExpectedHash(
180
- join(appPath, target.targetRelativePath),
181
- target.expectedSha256,
182
- markerPredicateForPatchTarget(target),
183
- );
184
- }
185
- }
186
-
187
144
  async function startServiceFromAutostart(options: InstallOptions, targetMode: 'real' | 'disposable') {
188
145
  const autostart = await installAutostart(options, targetMode);
189
146
  const runtimeFile = options.runtimeFile ?? DEFAULT_RUNTIME_FILE;
@@ -418,12 +375,11 @@ async function linkInstallExtensionBundle({
418
375
  sourceBundlePath: string;
419
376
  cursorExtensionsDir: string;
420
377
  }): ReturnType<typeof linkExtensionBundle> {
378
+ const linkedPath = linkedExtensionPathForDir(cursorExtensionsDir);
421
379
  if ((await getLinkedExtensionState(sourceBundlePath)) === 'missing') {
422
- const linkedPath = linkedExtensionPathForDir(cursorExtensionsDir);
423
380
  return { state: 'missing', linkedPath };
424
381
  }
425
382
 
426
- const linkedPath = await linkedExtensionPathForSource(cursorExtensionsDir, sourceBundlePath);
427
383
  await removeInstallLinkedExtensionBundle(linkedPath, cursorExtensionsDir);
428
384
  await mkdir(dirname(linkedPath), { recursive: true });
429
385
  await cp(sourceBundlePath, linkedPath, { recursive: true });
@@ -447,19 +403,15 @@ export async function install(options: InstallOptions = {}) {
447
403
  compatManifestUrl: options.compatManifestUrl,
448
404
  fetchManifest: options.fetchCompatManifest,
449
405
  });
450
- const adapterVersion = PACKAGE_VERSION === '0.5.8'
451
- ? undefined
452
- : PACKAGE_VERSION.split('-', 1)[0].split('+', 1)[0];
453
- const compat = resolveCompatEntry(cursor, environment, { entries: compatEntries, adapterVersion });
454
- assertBundledTakeoverPlan(compat.takeoverPlanId);
455
- const workbenchTargetRelativePath = workbenchTargetRelativePathFromCompat(compat);
406
+ const compat = resolveCompatEntry(cursor, environment, { entries: compatEntries });
456
407
  const targetPath = join(cursor.appPath, compat.targetRelativePath);
457
408
  const originalSha256 = await sha256File(targetPath);
458
- await assertExpectedPatchTargetHashes(cursor.appPath, compat);
409
+ if (compat.expectedSha256 !== '*') {
410
+ await assertExpectedHash(targetPath, compat.expectedSha256);
411
+ }
459
412
  const patchSetBeforeInstall = await readCursorPatchSetState(cursor.appPath, {
460
413
  agentExecTargetRelativePath: compat.targetRelativePath,
461
414
  platform: environment.platform,
462
- workbenchTargetRelativePath,
463
415
  });
464
416
  const wasPatchedBeforeInstall = patchSetBeforeInstall.allApplied;
465
417
  const existingTrialRecord = await readTrialRecord(cursor.appPath, {
@@ -551,7 +503,6 @@ export async function install(options: InstallOptions = {}) {
551
503
  backupDir: options.backupDir,
552
504
  platform: environment.platform,
553
505
  agentExecTargetRelativePath: compat.targetRelativePath,
554
- workbenchTargetRelativePath,
555
506
  patchCursorAgentExec: options.patchCursorAgentExec,
556
507
  patchCursorWorkbenchAuthGate: options.patchCursorWorkbenchAuthGate,
557
508
  });
@@ -581,7 +532,6 @@ export async function install(options: InstallOptions = {}) {
581
532
  appPath: cursor.appPath,
582
533
  cursorVersion: cursor.version,
583
534
  cursorCommit: cursor.commit,
584
- takeoverPlanId: compat.takeoverPlanId,
585
535
  targetRelativePath: compat.targetRelativePath,
586
536
  originalSha256,
587
537
  compatSupportStatus: compat.supportStatus,
@@ -626,7 +576,6 @@ export async function install(options: InstallOptions = {}) {
626
576
  `mode: ${target.mode}`,
627
577
  `app: ${cursor.appPath}`,
628
578
  `compat: ${compat.supportStatus}`,
629
- `takeover-plan: ${compat.takeoverPlanId}`,
630
579
  `extension: ${extension.state}`,
631
580
  `service: running ${service.host}:${service.port}`,
632
581
  `autostart: ${autostartState}`,
@@ -646,7 +595,6 @@ export async function install(options: InstallOptions = {}) {
646
595
  (await readCursorPatchSetState(cursor.appPath, {
647
596
  agentExecTargetRelativePath: compat.targetRelativePath,
648
597
  platform: environment.platform,
649
- workbenchTargetRelativePath,
650
598
  })).appliedCount > 0);
651
599
  } catch (rollbackError) {
652
600
  rollbackErrors.push(rollbackError);
@@ -656,7 +604,6 @@ export async function install(options: InstallOptions = {}) {
656
604
  await restoreCursorSet(cursor.appPath, {
657
605
  backupDir: options.backupDir,
658
606
  platform: environment.platform,
659
- workbenchTargetRelativePath,
660
607
  restoreCursorAgentExec: options.restoreCursorAgentExec,
661
608
  restoreCursorAlwaysLocal: options.restoreCursorAlwaysLocal,
662
609
  restoreCursorWorkbenchAuthGate: options.restoreCursorWorkbenchAuthGate,