@cursorpool-dev/cli 0.5.8 → 0.5.10
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 +46 -116
- package/node_modules/@cursor-pool/extension/package.json +3 -3
- package/node_modules/@cursor-pool/extension/src/api.ts +2 -17
- package/node_modules/@cursor-pool/extension/src/panel.ts +3 -26
- package/node_modules/@cursor-pool/extension/test/panel.test.ts +1 -34
- package/node_modules/@cursor-pool/patcher/package.json +2 -2
- package/node_modules/@cursor-pool/patcher/src/marker.ts +72 -7
- package/node_modules/@cursor-pool/patcher/src/workbenchAuthGateMarker.ts +102 -19
- package/node_modules/@cursor-pool/patcher/test/patchCursorAgentExec.test.ts +88 -13
- package/node_modules/@cursor-pool/patcher/test/patchCursorWorkbench.test.ts +162 -149
- package/node_modules/@cursor-pool/service/package.json +2 -2
- package/node_modules/@cursor-pool/service/src/platformSession.ts +7 -30
- package/node_modules/@cursor-pool/service/src/server.ts +1 -1
- package/node_modules/@cursor-pool/service/test/platformSession.test.ts +4 -5
- package/node_modules/@cursor-pool/service/test/server.test.ts +1 -130
- package/node_modules/@cursor-pool/shared/package.json +1 -1
- package/node_modules/@cursor-pool/shared/src/manifest.ts +0 -35
- package/node_modules/@cursor-pool/shared/test/manifest.test.ts +9 -43
- package/package.json +5 -7
- package/src/compat.ts +201 -194
- package/src/cursor.ts +45 -4
- package/src/extensionBundle.ts +1 -1
- package/src/extensionLink.ts +8 -29
- package/src/install.ts +10 -62
- package/src/installRecord.ts +0 -2
- package/src/patchSet.ts +49 -13
- package/src/platform.ts +3 -3
- package/src/repair.ts +9 -13
- package/src/restore.ts +11 -12
- package/src/status.ts +5 -9
- package/src/target.ts +12 -0
- package/src/trial.ts +2 -3
- package/src/uninstall.ts +6 -2
- package/test/compat.test.ts +146 -192
- package/test/cursor.test.ts +54 -0
- package/test/e2e-install.test.ts +29 -46
- package/test/extensionLink.test.ts +26 -49
- package/test/install.test.ts +4 -64
- package/test/patchSet.test.ts +71 -0
- package/test/repair.test.ts +131 -1
- package/test/restore.test.ts +59 -3
- package/test/status.test.ts +0 -1
- package/test/target.test.ts +28 -0
- package/test/trial.test.ts +15 -1
- package/node_modules/@cursor-pool/takeover-plans/package.json +0 -12
- package/node_modules/@cursor-pool/takeover-plans/src/index.ts +0 -22
- package/node_modules/@cursor-pool/takeover-plans/src/plans.ts +0 -37
- package/node_modules/@cursor-pool/takeover-plans/src/types.ts +0 -9
- package/node_modules/@cursor-pool/takeover-plans/test/registry.test.ts +0 -23
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
|
|
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.
|
|
107
|
+
const PACKAGE_VERSION = '0.5.10';
|
|
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
|
|
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 (
|
|
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
|
|
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
|
-
|
|
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);
|
|
@@ -655,8 +603,8 @@ export async function install(options: InstallOptions = {}) {
|
|
|
655
603
|
try {
|
|
656
604
|
await restoreCursorSet(cursor.appPath, {
|
|
657
605
|
backupDir: options.backupDir,
|
|
606
|
+
agentExecTargetRelativePath: compat.targetRelativePath,
|
|
658
607
|
platform: environment.platform,
|
|
659
|
-
workbenchTargetRelativePath,
|
|
660
608
|
restoreCursorAgentExec: options.restoreCursorAgentExec,
|
|
661
609
|
restoreCursorAlwaysLocal: options.restoreCursorAlwaysLocal,
|
|
662
610
|
restoreCursorWorkbenchAuthGate: options.restoreCursorWorkbenchAuthGate,
|
package/src/installRecord.ts
CHANGED
|
@@ -13,7 +13,6 @@ export type InstallRecord = {
|
|
|
13
13
|
appPath: string;
|
|
14
14
|
cursorVersion: string;
|
|
15
15
|
cursorCommit: string;
|
|
16
|
-
takeoverPlanId: string;
|
|
17
16
|
targetRelativePath: string;
|
|
18
17
|
originalSha256: string;
|
|
19
18
|
compatSupportStatus: CompatibilityManifestEntry['supportStatus'];
|
|
@@ -92,7 +91,6 @@ export function isInstallRecordStale(record: InstallRecord | null, actual: Insta
|
|
|
92
91
|
'appPath',
|
|
93
92
|
'cursorVersion',
|
|
94
93
|
'cursorCommit',
|
|
95
|
-
'takeoverPlanId',
|
|
96
94
|
'targetRelativePath',
|
|
97
95
|
'originalSha256',
|
|
98
96
|
'compatSupportStatus',
|
package/src/patchSet.ts
CHANGED
|
@@ -54,13 +54,43 @@ const LINUX_WORKBENCH_RELATIVE_PATH =
|
|
|
54
54
|
'usr/share/cursor/resources/app/out/vs/workbench/workbench.desktop.main.js';
|
|
55
55
|
const LINUX_ALWAYS_LOCAL_RELATIVE_PATH =
|
|
56
56
|
'usr/share/cursor/resources/app/extensions/cursor-always-local/dist/main.js';
|
|
57
|
+
const LINUX_DEB_WORKBENCH_RELATIVE_PATH =
|
|
58
|
+
'resources/app/out/vs/workbench/workbench.desktop.main.js';
|
|
59
|
+
const LINUX_DEB_ALWAYS_LOCAL_RELATIVE_PATH =
|
|
60
|
+
'resources/app/extensions/cursor-always-local/dist/main.js';
|
|
57
61
|
|
|
58
|
-
function
|
|
59
|
-
return options.
|
|
62
|
+
function linuxUsesDebRoot(options: { agentExecTargetRelativePath?: string }) {
|
|
63
|
+
return options.agentExecTargetRelativePath?.startsWith('resources/app/') ?? false;
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
function
|
|
63
|
-
|
|
66
|
+
function workbenchRelativePath(options: {
|
|
67
|
+
platform?: NodeJS.Platform;
|
|
68
|
+
agentExecTargetRelativePath?: string;
|
|
69
|
+
workbenchTargetRelativePath?: string;
|
|
70
|
+
}) {
|
|
71
|
+
if (options.workbenchTargetRelativePath) {
|
|
72
|
+
return options.workbenchTargetRelativePath;
|
|
73
|
+
}
|
|
74
|
+
if (options.platform === 'linux') {
|
|
75
|
+
return linuxUsesDebRoot(options) ? LINUX_DEB_WORKBENCH_RELATIVE_PATH : LINUX_WORKBENCH_RELATIVE_PATH;
|
|
76
|
+
}
|
|
77
|
+
return CURSOR_WORKBENCH_RELATIVE_PATH;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function alwaysLocalRelativePath(options: {
|
|
81
|
+
platform?: NodeJS.Platform;
|
|
82
|
+
agentExecTargetRelativePath?: string;
|
|
83
|
+
alwaysLocalTargetRelativePath?: string;
|
|
84
|
+
}) {
|
|
85
|
+
if (options.alwaysLocalTargetRelativePath) {
|
|
86
|
+
return options.alwaysLocalTargetRelativePath;
|
|
87
|
+
}
|
|
88
|
+
if (options.platform === 'linux') {
|
|
89
|
+
return linuxUsesDebRoot(options)
|
|
90
|
+
? LINUX_DEB_ALWAYS_LOCAL_RELATIVE_PATH
|
|
91
|
+
: LINUX_ALWAYS_LOCAL_RELATIVE_PATH;
|
|
92
|
+
}
|
|
93
|
+
return CURSOR_ALWAYS_LOCAL_RELATIVE_PATH;
|
|
64
94
|
}
|
|
65
95
|
|
|
66
96
|
async function fileContainsMarker(
|
|
@@ -143,11 +173,12 @@ export async function patchCursorSet(appPath: string, options: PatchCursorSetOpt
|
|
|
143
173
|
}
|
|
144
174
|
|
|
145
175
|
export async function restoreCursorSet(appPath: string, options: RestoreCursorSetOptions = {}) {
|
|
146
|
-
const restoreErrors: unknown[] = [];
|
|
147
176
|
const before = await readCursorPatchSetState(appPath, {
|
|
177
|
+
agentExecTargetRelativePath: options.agentExecTargetRelativePath,
|
|
148
178
|
platform: options.platform,
|
|
149
179
|
workbenchTargetRelativePath: options.workbenchTargetRelativePath,
|
|
150
180
|
});
|
|
181
|
+
const restoreErrors: unknown[] = [];
|
|
151
182
|
const restore = async (operation: () => Promise<unknown>) => {
|
|
152
183
|
try {
|
|
153
184
|
await operation();
|
|
@@ -156,14 +187,12 @@ export async function restoreCursorSet(appPath: string, options: RestoreCursorSe
|
|
|
156
187
|
}
|
|
157
188
|
};
|
|
158
189
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
);
|
|
166
|
-
}
|
|
190
|
+
await restore(() =>
|
|
191
|
+
(options.restoreCursorWorkbenchAuthGate ?? restoreCursorWorkbenchAuthGate)(appPath, {
|
|
192
|
+
backupDir: options.backupDir,
|
|
193
|
+
targetRelativePath: workbenchRelativePath(options),
|
|
194
|
+
}),
|
|
195
|
+
);
|
|
167
196
|
const alwaysLocalPath = resolveCursorAlwaysLocalPath(appPath, alwaysLocalRelativePath(options));
|
|
168
197
|
const shouldRestoreAlwaysLocal =
|
|
169
198
|
Boolean(options.restoreCursorAlwaysLocal) ||
|
|
@@ -179,10 +208,17 @@ export async function restoreCursorSet(appPath: string, options: RestoreCursorSe
|
|
|
179
208
|
await restore(() =>
|
|
180
209
|
(options.restoreCursorAgentExec ?? restoreCursorAgentExec)(appPath, {
|
|
181
210
|
backupDir: options.backupDir,
|
|
211
|
+
targetRelativePath: options.agentExecTargetRelativePath,
|
|
182
212
|
}),
|
|
183
213
|
);
|
|
184
214
|
|
|
185
215
|
if (restoreErrors.length > 0) {
|
|
186
216
|
throw new AggregateError(restoreErrors, 'Failed to restore one or more Cursor patches.');
|
|
187
217
|
}
|
|
218
|
+
const after = await readCursorPatchSetState(appPath, {
|
|
219
|
+
agentExecTargetRelativePath: options.agentExecTargetRelativePath,
|
|
220
|
+
platform: options.platform,
|
|
221
|
+
workbenchTargetRelativePath: options.workbenchTargetRelativePath,
|
|
222
|
+
});
|
|
223
|
+
return { before, after };
|
|
188
224
|
}
|
package/src/platform.ts
CHANGED
|
@@ -82,9 +82,9 @@ function buildDeviceInfo() {
|
|
|
82
82
|
name: hostname(),
|
|
83
83
|
os: osPlatform(),
|
|
84
84
|
arch: arch(),
|
|
85
|
-
cliVersion: '0.5.
|
|
86
|
-
serviceVersion: '0.5.
|
|
87
|
-
extensionVersion: '0.5.
|
|
85
|
+
cliVersion: '0.5.10',
|
|
86
|
+
serviceVersion: '0.5.10',
|
|
87
|
+
extensionVersion: '0.5.10',
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
|
package/src/repair.ts
CHANGED
|
@@ -69,7 +69,7 @@ export type RepairOptions = FindCursorOptions &
|
|
|
69
69
|
adHocResignApp?: typeof adHocResignApp;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
const PACKAGE_VERSION = '0.5.
|
|
72
|
+
const PACKAGE_VERSION = '0.5.10';
|
|
73
73
|
|
|
74
74
|
function normalizeAppPath(path: string) {
|
|
75
75
|
return normalize(path).replace(/\/+$/, '');
|
|
@@ -96,10 +96,6 @@ function assertRealRepairInstallRecord(
|
|
|
96
96
|
return record;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
function workbenchTargetRelativePathFromCompat(compat: CompatibilityManifestEntry) {
|
|
100
|
-
return compat.patchTargets?.find((target) => target.name === 'workbench')?.targetRelativePath;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
99
|
function resolveRepairCompatEntry({
|
|
104
100
|
cursorVersion,
|
|
105
101
|
cursorCommit,
|
|
@@ -114,12 +110,14 @@ function resolveRepairCompatEntry({
|
|
|
114
110
|
entries?: CompatibilityManifestEntry[];
|
|
115
111
|
}) {
|
|
116
112
|
const compatEntries = entries ?? DEFAULT_COMPAT_ENTRIES;
|
|
113
|
+
const versionFamily = cursorVersion.match(/^(\d+\.\d+)(?:\.|$)/)?.[1];
|
|
117
114
|
const entry = compatEntries.find(
|
|
118
115
|
(candidate) =>
|
|
119
116
|
candidate.platform === platform &&
|
|
120
117
|
candidate.arch === arch &&
|
|
121
|
-
candidate.cursorVersion === cursorVersion
|
|
122
|
-
|
|
118
|
+
(candidate.cursorVersion === cursorVersion ||
|
|
119
|
+
candidate.cursorVersion === versionFamily) &&
|
|
120
|
+
(candidate.cursorCommit === '*' || candidate.cursorCommit === cursorCommit),
|
|
123
121
|
);
|
|
124
122
|
|
|
125
123
|
if (!entry) {
|
|
@@ -200,13 +198,13 @@ async function maybeAdHocResign({
|
|
|
200
198
|
}
|
|
201
199
|
|
|
202
200
|
export async function repair(options: RepairOptions = {}) {
|
|
203
|
-
const
|
|
201
|
+
const environment = detectEnvironment(options);
|
|
202
|
+
const target = resolveCursorTarget({ ...options, platform: environment.platform });
|
|
204
203
|
if (target.mode !== 'real') {
|
|
205
204
|
throw new Error('repair is only supported for real Cursor installs in MVP-1');
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
const cursor = await findCursor({ ...options, appPath: target.appPath });
|
|
209
|
-
const environment = detectEnvironment(options);
|
|
210
208
|
const compatEntries = await loadCompatEntries({
|
|
211
209
|
compatEntries: options.compatEntries,
|
|
212
210
|
apiBaseUrl: options.apiBaseUrl,
|
|
@@ -227,7 +225,6 @@ export async function repair(options: RepairOptions = {}) {
|
|
|
227
225
|
if (compat.supportStatus === 'blocked' || compat.supportStatus === 'unknown') {
|
|
228
226
|
throw new Error(`compat: ${compat.supportStatus}`);
|
|
229
227
|
}
|
|
230
|
-
const workbenchTargetRelativePath = workbenchTargetRelativePathFromCompat(compat);
|
|
231
228
|
const targetPath = join(cursor.appPath, compat.targetRelativePath);
|
|
232
229
|
const runtimeFile = options.runtimeFile ?? installRecord.runtimeFile ?? DEFAULT_RUNTIME_FILE;
|
|
233
230
|
const backupDir = options.backupDir ?? installRecord.backupDir;
|
|
@@ -261,6 +258,7 @@ export async function repair(options: RepairOptions = {}) {
|
|
|
261
258
|
installRecord.originalSha256 && patchState.currentHash === installRecord.originalSha256;
|
|
262
259
|
if (
|
|
263
260
|
!patchState.legacyMarkerPresent &&
|
|
261
|
+
compat.expectedSha256 !== '*' &&
|
|
264
262
|
patchState.currentHash !== compat.expectedSha256 &&
|
|
265
263
|
!matchesInstallOriginal
|
|
266
264
|
) {
|
|
@@ -327,9 +325,8 @@ export async function repair(options: RepairOptions = {}) {
|
|
|
327
325
|
}
|
|
328
326
|
|
|
329
327
|
const patchSetState = await readCursorPatchSetState(cursor.appPath, {
|
|
330
|
-
agentExecTargetRelativePath: compat.targetRelativePath,
|
|
331
328
|
platform: environment.platform,
|
|
332
|
-
|
|
329
|
+
agentExecTargetRelativePath: compat.targetRelativePath,
|
|
333
330
|
});
|
|
334
331
|
|
|
335
332
|
if (patchSetState.allApplied) {
|
|
@@ -340,7 +337,6 @@ export async function repair(options: RepairOptions = {}) {
|
|
|
340
337
|
backupDir,
|
|
341
338
|
platform: environment.platform,
|
|
342
339
|
agentExecTargetRelativePath: compat.targetRelativePath,
|
|
343
|
-
workbenchTargetRelativePath,
|
|
344
340
|
patchCursorAgentExec: options.patchCursorAgentExec,
|
|
345
341
|
patchCursorWorkbenchAuthGate: options.patchCursorWorkbenchAuthGate,
|
|
346
342
|
});
|
package/src/restore.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type ConfirmRealOperationOptions,
|
|
8
8
|
} from './confirm';
|
|
9
9
|
import { findCursor, type FindCursorOptions } from './cursor';
|
|
10
|
+
import { detectEnvironment, type DetectEnvironmentOptions } from './environment';
|
|
10
11
|
import {
|
|
11
12
|
installIdForAppPath,
|
|
12
13
|
readInstallRecord,
|
|
@@ -14,15 +15,12 @@ import {
|
|
|
14
15
|
type InstallRecordOptions,
|
|
15
16
|
} from './installRecord';
|
|
16
17
|
import { stopRuntimeService } from './serviceProcess';
|
|
17
|
-
import {
|
|
18
|
-
formatCursorPatchSetState,
|
|
19
|
-
readCursorPatchSetState,
|
|
20
|
-
restoreCursorSet,
|
|
21
|
-
} from './patchSet';
|
|
22
18
|
import { resolveCursorTarget, type CursorTargetOptions } from './target';
|
|
23
19
|
import { assertDisposableCursorAppPath, readTrialRecord, type TrialRecordOptions } from './trial';
|
|
20
|
+
import { formatCursorPatchSetState, restoreCursorSet } from './patchSet';
|
|
24
21
|
|
|
25
22
|
export type RestoreOptions = FindCursorOptions &
|
|
23
|
+
DetectEnvironmentOptions &
|
|
26
24
|
CursorTargetOptions &
|
|
27
25
|
TrialRecordOptions &
|
|
28
26
|
InstallRecordOptions & {
|
|
@@ -90,9 +88,12 @@ function formatRestoreConfirmation({
|
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
export async function restore(options: RestoreOptions = {}) {
|
|
93
|
-
const
|
|
91
|
+
const environment = detectEnvironment(options);
|
|
92
|
+
const target = resolveCursorTarget({ ...options, platform: environment.platform });
|
|
94
93
|
const appPath =
|
|
95
|
-
target.mode === 'disposable'
|
|
94
|
+
target.mode === 'disposable'
|
|
95
|
+
? assertDisposableCursorAppPath(target.appPath, { platform: environment.platform })
|
|
96
|
+
: target.appPath;
|
|
96
97
|
const cursor = await findCursor({ ...options, appPath });
|
|
97
98
|
const installRecord =
|
|
98
99
|
target.mode === 'real'
|
|
@@ -137,12 +138,10 @@ export async function restore(options: RestoreOptions = {}) {
|
|
|
137
138
|
});
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
await restoreCursorSet(cursor.appPath, {
|
|
141
|
+
const result = await restoreCursorSet(cursor.appPath, {
|
|
141
142
|
backupDir,
|
|
142
143
|
agentExecTargetRelativePath: targetRelativePath,
|
|
143
|
-
|
|
144
|
-
const patchSetState = await readCursorPatchSetState(cursor.appPath, {
|
|
145
|
-
agentExecTargetRelativePath: targetRelativePath,
|
|
144
|
+
platform: environment.platform,
|
|
146
145
|
});
|
|
147
146
|
if (target.mode === 'real') {
|
|
148
147
|
await stopRuntimeServiceIfRecorded(runtimeFile);
|
|
@@ -153,7 +152,7 @@ export async function restore(options: RestoreOptions = {}) {
|
|
|
153
152
|
`mode: ${target.mode}`,
|
|
154
153
|
`app: ${cursor.appPath}`,
|
|
155
154
|
'restore: ok',
|
|
156
|
-
`patch: ${formatCursorPatchSetState(
|
|
155
|
+
`patch: ${formatCursorPatchSetState(result.after)}`,
|
|
157
156
|
target.mode === 'real'
|
|
158
157
|
? `install-record: ${realInstallRecord ? 'recorded' : 'missing'}`
|
|
159
158
|
: `trial: ${trialRecord ? 'recorded' : 'missing'}`,
|
package/src/status.ts
CHANGED
|
@@ -49,10 +49,6 @@ type LatestTakeoverResponse = {
|
|
|
49
49
|
};
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
function workbenchTargetRelativePathFromCompat(compat: CompatibilityManifestEntry) {
|
|
53
|
-
return compat.patchTargets?.find((target) => target.name === 'workbench')?.targetRelativePath;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
52
|
const MAX_CANARY_FIELD_LENGTH = 256;
|
|
57
53
|
|
|
58
54
|
function isSafeCanaryString(value: unknown): value is string {
|
|
@@ -150,10 +146,12 @@ async function getTakeoverStatus(
|
|
|
150
146
|
}
|
|
151
147
|
|
|
152
148
|
export async function status(options: StatusOptions = {}) {
|
|
153
|
-
const target = resolveCursorTarget(options);
|
|
154
|
-
const appPath =
|
|
155
|
-
target.mode === 'disposable' ? assertDisposableCursorAppPath(target.appPath) : target.appPath;
|
|
156
149
|
const environment = detectEnvironment(options);
|
|
150
|
+
const target = resolveCursorTarget({ ...options, platform: environment.platform });
|
|
151
|
+
const appPath =
|
|
152
|
+
target.mode === 'disposable'
|
|
153
|
+
? assertDisposableCursorAppPath(target.appPath, { platform: environment.platform })
|
|
154
|
+
: target.appPath;
|
|
157
155
|
const cursor = await findCursor({ ...options, appPath });
|
|
158
156
|
const compatEntries = await loadCompatEntries({
|
|
159
157
|
compatEntries: options.compatEntries,
|
|
@@ -162,7 +160,6 @@ export async function status(options: StatusOptions = {}) {
|
|
|
162
160
|
fetchManifest: options.fetchCompatManifest,
|
|
163
161
|
});
|
|
164
162
|
const compat = resolveCompatEntry(cursor, environment, { entries: compatEntries });
|
|
165
|
-
const workbenchTargetRelativePath = workbenchTargetRelativePathFromCompat(compat);
|
|
166
163
|
const installRecord =
|
|
167
164
|
target.mode === 'real'
|
|
168
165
|
? await readInstallRecord({ installRecordFile: options.installRecordFile })
|
|
@@ -194,7 +191,6 @@ export async function status(options: StatusOptions = {}) {
|
|
|
194
191
|
const patchSetState = await readCursorPatchSetState(cursor.appPath, {
|
|
195
192
|
agentExecTargetRelativePath: compat.targetRelativePath,
|
|
196
193
|
platform: environment.platform,
|
|
197
|
-
workbenchTargetRelativePath,
|
|
198
194
|
});
|
|
199
195
|
const serviceRunning = await isRuntimeHealthy(runtime);
|
|
200
196
|
const takeoverStatus = await getTakeoverStatus(runtime, serviceRunning);
|
package/src/target.ts
CHANGED
|
@@ -20,8 +20,20 @@ export type CursorTarget =
|
|
|
20
20
|
requiresConfirmation: true;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
function isLinuxRealCursorPath(appPath: string, platform: NodeJS.Platform | undefined) {
|
|
24
|
+
return platform === 'linux' && appPath.replace(/\/+$/, '') === '/usr/share/cursor';
|
|
25
|
+
}
|
|
26
|
+
|
|
23
27
|
export function resolveCursorTarget(options: CursorTargetOptions = {}): CursorTarget {
|
|
24
28
|
if (options.appPath) {
|
|
29
|
+
if (isLinuxRealCursorPath(options.appPath, options.platform)) {
|
|
30
|
+
return {
|
|
31
|
+
mode: 'real',
|
|
32
|
+
appPath: options.appPath.replace(/\/+$/, ''),
|
|
33
|
+
requiresConfirmation: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
return {
|
|
26
38
|
mode: 'disposable',
|
|
27
39
|
appPath: assertDisposableCursorAppPath(options.appPath, { platform: options.platform }),
|
package/src/trial.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { realpathSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
-
import { dirname, join, normalize } from 'node:path';
|
|
5
|
+
import { dirname, join, normalize, resolve } from 'node:path';
|
|
6
6
|
import { DEFAULT_MACOS_CURSOR_APP_PATH } from './cursor';
|
|
7
7
|
|
|
8
8
|
export type ExtensionState = 'bundled' | 'linked' | 'manual-step-required' | 'missing';
|
|
@@ -12,7 +12,6 @@ export type TrialRecord = {
|
|
|
12
12
|
appPath: string;
|
|
13
13
|
cursorVersion: string;
|
|
14
14
|
cursorCommit: string;
|
|
15
|
-
takeoverPlanId: string;
|
|
16
15
|
targetRelativePath: string;
|
|
17
16
|
originalSha256: string;
|
|
18
17
|
compatSupportStatus: 'supported' | 'canary' | 'warning' | 'blocked' | 'unknown';
|
|
@@ -40,7 +39,7 @@ function resolveHomePath(path: string) {
|
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
function normalizeAppPath(path: string) {
|
|
43
|
-
return normalize(path).replace(/\/+$/, '');
|
|
42
|
+
return resolve(normalize(path).replace(/\/+$/, ''));
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
function isRealCursorAppPath(path: string) {
|
package/src/uninstall.ts
CHANGED
|
@@ -28,6 +28,7 @@ import { restore } from './restore';
|
|
|
28
28
|
import type { RestoreOptions } from './restore';
|
|
29
29
|
import { stopRuntimeService } from './serviceProcess';
|
|
30
30
|
import { removeUserAutostart } from './autostart';
|
|
31
|
+
import { detectEnvironment } from './environment';
|
|
31
32
|
import { resolveCursorTarget, type CursorTargetOptions } from './target';
|
|
32
33
|
import {
|
|
33
34
|
assertDisposableCursorAppPath,
|
|
@@ -107,9 +108,12 @@ async function removeRecordedLinkedExtensionBundle(
|
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
export async function uninstall(options: UninstallOptions = {}) {
|
|
110
|
-
const
|
|
111
|
+
const environment = detectEnvironment(options);
|
|
112
|
+
const target = resolveCursorTarget({ ...options, platform: environment.platform });
|
|
111
113
|
const appPath =
|
|
112
|
-
target.mode === 'disposable'
|
|
114
|
+
target.mode === 'disposable'
|
|
115
|
+
? assertDisposableCursorAppPath(target.appPath, { platform: environment.platform })
|
|
116
|
+
: target.appPath;
|
|
113
117
|
const cursor = await findCursor({ ...options, appPath });
|
|
114
118
|
const installRecord =
|
|
115
119
|
target.mode === 'real'
|