@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.
Files changed (108) hide show
  1. package/node_modules/@cursor-pool/extension/dist/extension.js +116 -46
  2. package/node_modules/@cursor-pool/extension/package.json +3 -3
  3. package/node_modules/@cursor-pool/extension/src/api.ts +17 -2
  4. package/node_modules/@cursor-pool/extension/src/panel.ts +26 -3
  5. package/node_modules/@cursor-pool/extension/test/panel.test.ts +34 -1
  6. package/node_modules/@cursor-pool/patcher/package.json +2 -2
  7. package/node_modules/@cursor-pool/patcher/src/marker.ts +5 -1
  8. package/node_modules/@cursor-pool/patcher/src/workbenchAuthGateMarker.ts +58 -7
  9. package/node_modules/@cursor-pool/patcher/test/patchCursorAgentExec.test.ts +20 -0
  10. package/node_modules/@cursor-pool/patcher/test/patchCursorWorkbench.test.ts +193 -2
  11. package/node_modules/@cursor-pool/service/package.json +2 -2
  12. package/node_modules/@cursor-pool/service/src/platformSession.ts +30 -7
  13. package/node_modules/@cursor-pool/service/src/server.ts +1 -0
  14. package/node_modules/@cursor-pool/service/test/platformSession.test.ts +5 -4
  15. package/node_modules/@cursor-pool/service/test/server.test.ts +130 -0
  16. package/node_modules/@cursor-pool/shared/package.json +1 -1
  17. package/node_modules/@cursor-pool/shared/src/manifest.ts +35 -0
  18. package/node_modules/@cursor-pool/shared/test/manifest.test.ts +43 -9
  19. package/node_modules/@cursor-pool/takeover-plans/package.json +12 -0
  20. package/node_modules/@cursor-pool/takeover-plans/src/index.ts +22 -0
  21. package/node_modules/@cursor-pool/takeover-plans/src/plans.ts +37 -0
  22. package/node_modules/@cursor-pool/takeover-plans/src/types.ts +9 -0
  23. package/node_modules/@cursor-pool/takeover-plans/test/registry.test.ts +23 -0
  24. package/node_modules/@esbuild/linux-x64/README.md +3 -0
  25. package/node_modules/@esbuild/linux-x64/bin/esbuild +0 -0
  26. package/node_modules/@esbuild/linux-x64/package.json +20 -0
  27. package/node_modules/esbuild/LICENSE.md +21 -0
  28. package/node_modules/esbuild/README.md +3 -0
  29. package/node_modules/esbuild/bin/esbuild +223 -0
  30. package/node_modules/esbuild/install.js +300 -0
  31. package/node_modules/esbuild/lib/main.d.ts +716 -0
  32. package/node_modules/esbuild/lib/main.js +2532 -0
  33. package/node_modules/esbuild/package.json +74 -0
  34. package/node_modules/tsx/LICENSE +21 -0
  35. package/node_modules/tsx/README.md +32 -0
  36. package/node_modules/tsx/dist/cjs/api/index.cjs +1 -0
  37. package/node_modules/tsx/dist/cjs/api/index.d.cts +35 -0
  38. package/node_modules/tsx/dist/cjs/api/index.d.mts +35 -0
  39. package/node_modules/tsx/dist/cjs/api/index.mjs +1 -0
  40. package/node_modules/tsx/dist/cjs/index.cjs +1 -0
  41. package/node_modules/tsx/dist/cjs/index.mjs +1 -0
  42. package/node_modules/tsx/dist/cli.cjs +54 -0
  43. package/node_modules/tsx/dist/cli.mjs +55 -0
  44. package/node_modules/tsx/dist/client-D3mGB526.cjs +1 -0
  45. package/node_modules/tsx/dist/client-D_mPDF5S.mjs +1 -0
  46. package/node_modules/tsx/dist/esm/api/index.cjs +1 -0
  47. package/node_modules/tsx/dist/esm/api/index.d.cts +35 -0
  48. package/node_modules/tsx/dist/esm/api/index.d.mts +35 -0
  49. package/node_modules/tsx/dist/esm/api/index.mjs +1 -0
  50. package/node_modules/tsx/dist/esm/index.cjs +1 -0
  51. package/node_modules/tsx/dist/esm/index.mjs +1 -0
  52. package/node_modules/tsx/dist/get-pipe-path-D4YM6rQt.cjs +1 -0
  53. package/node_modules/tsx/dist/get-pipe-path-_tAJyU_v.mjs +1 -0
  54. package/node_modules/tsx/dist/index-BWFBUo6r.cjs +1 -0
  55. package/node_modules/tsx/dist/index-D9F1FXzN.cjs +14 -0
  56. package/node_modules/tsx/dist/index-XurvG3JN.mjs +14 -0
  57. package/node_modules/tsx/dist/index-gbaejti9.mjs +1 -0
  58. package/node_modules/tsx/dist/lexer-DQCqS3nf.mjs +3 -0
  59. package/node_modules/tsx/dist/lexer-DgIbo0BU.cjs +3 -0
  60. package/node_modules/tsx/dist/loader.cjs +1 -0
  61. package/node_modules/tsx/dist/loader.mjs +1 -0
  62. package/node_modules/tsx/dist/node-features-B9BBLzwu.mjs +1 -0
  63. package/node_modules/tsx/dist/node-features-CQLdkVE6.cjs +1 -0
  64. package/node_modules/tsx/dist/package-CGdS2_oX.cjs +1 -0
  65. package/node_modules/tsx/dist/package-DyJMwVU5.mjs +1 -0
  66. package/node_modules/tsx/dist/patch-repl.cjs +1 -0
  67. package/node_modules/tsx/dist/patch-repl.mjs +1 -0
  68. package/node_modules/tsx/dist/preflight.cjs +1 -0
  69. package/node_modules/tsx/dist/preflight.mjs +1 -0
  70. package/node_modules/tsx/dist/register-BOkp8V6j.cjs +10 -0
  71. package/node_modules/tsx/dist/register-BnTWPeIB.mjs +10 -0
  72. package/node_modules/tsx/dist/register-CHVGxKtC.cjs +2 -0
  73. package/node_modules/tsx/dist/register-D_B8UL5H.mjs +2 -0
  74. package/node_modules/tsx/dist/repl.cjs +3 -0
  75. package/node_modules/tsx/dist/repl.mjs +3 -0
  76. package/node_modules/tsx/dist/require-CjvaJWEr.cjs +1 -0
  77. package/node_modules/tsx/dist/require-DzmC1hVr.mjs +1 -0
  78. package/node_modules/tsx/dist/suppress-warnings.cjs +1 -0
  79. package/node_modules/tsx/dist/suppress-warnings.mjs +1 -0
  80. package/node_modules/tsx/dist/temporary-directory-B83uKxJF.cjs +1 -0
  81. package/node_modules/tsx/dist/temporary-directory-BDDVQOvU.mjs +1 -0
  82. package/node_modules/tsx/dist/types-Cxp8y2TL.d.ts +5 -0
  83. package/node_modules/tsx/package.json +67 -0
  84. package/package.json +11 -6
  85. package/src/autostart.ts +5 -1
  86. package/src/compat.ts +193 -47
  87. package/src/cursor.ts +59 -3
  88. package/src/extensionBundle.ts +1 -1
  89. package/src/extensionLink.ts +28 -7
  90. package/src/install.ts +176 -24
  91. package/src/installRecord.ts +2 -0
  92. package/src/patchSet.ts +12 -6
  93. package/src/platform.ts +3 -3
  94. package/src/repair.ts +10 -1
  95. package/src/restore.ts +12 -4
  96. package/src/serviceProcess.ts +2 -1
  97. package/src/status.ts +6 -0
  98. package/src/trial.ts +1 -0
  99. package/test/autostart.test.ts +23 -2
  100. package/test/compat.test.ts +238 -3
  101. package/test/cursor-pool-bin.test.ts +1 -0
  102. package/test/cursor.test.ts +60 -1
  103. package/test/e2e-install.test.ts +53 -0
  104. package/test/extensionLink.test.ts +48 -2
  105. package/test/install.test.ts +191 -6
  106. package/test/repair.test.ts +1 -0
  107. package/test/serviceProcess.test.ts +10 -1
  108. package/test/status.test.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  import assert from 'node:assert/strict';
2
2
  import { createHash } from 'node:crypto';
3
- import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
6
  import test from 'node:test';
@@ -8,7 +8,7 @@ import {
8
8
  CURSOR_POOL_AGENT_EXEC_PROVIDER_REGISTER_ANCHOR,
9
9
  CURSOR_POOL_PATCH_MARKER,
10
10
  } from '../../patcher/src/marker';
11
- import { writeRuntimeInfo } from '../../service/src/runtime';
11
+ import { readRuntimeInfo, writeRuntimeInfo } from '../../service/src/runtime';
12
12
  import type { CompatibilityManifestEntry } from '../../shared/src/manifest';
13
13
  import { buildCompatManifestSignature } from '../src/compat';
14
14
  import { getExtensionState } from '../src/extensionBundle';
@@ -69,15 +69,36 @@ async function createFixtureApp() {
69
69
  );
70
70
  await writeFile(targetPath, targetContent, 'utf8');
71
71
  await writeFile(join(appPath, alwaysLocalRelativePath), 'function alwaysLocal(){}\n', 'utf8');
72
- await writeFile(join(appPath, workbenchRelativePath), workbenchFixture(), 'utf8');
72
+ const workbenchContent = workbenchFixture();
73
+ await writeFile(join(appPath, workbenchRelativePath), workbenchContent, 'utf8');
73
74
 
74
75
  const expectedSha256 = createHash('sha256').update(targetContent).digest('hex');
76
+ const workbenchSha256 = createHash('sha256').update(workbenchContent).digest('hex');
75
77
  const compatEntry: CompatibilityManifestEntry = {
76
78
  platform: process.platform,
77
79
  arch: process.arch,
78
- cursorVersion: '3.5.38',
80
+ cursorVersion: '3.5',
79
81
  cursorCommit: '009bb5a3600dd98fe1c1f25798f767f686e14750',
80
82
  supportStatus: 'supported',
83
+ adapterVersion: '0.5.8',
84
+ takeoverPlanId: 'cursor-3.5-mac-agent-f-workbench-p-l0',
85
+ structureFamily: 'mac-agent-F-workbench-p-L0',
86
+ patchTargets: [
87
+ {
88
+ name: 'agent-exec',
89
+ targetRelativePath,
90
+ expectedSha256,
91
+ patchStrategy: 'cursor-agent-exec-snippet',
92
+ verifyMarker: 'cursor-pool',
93
+ },
94
+ {
95
+ name: 'workbench',
96
+ targetRelativePath: workbenchRelativePath,
97
+ expectedSha256: workbenchSha256,
98
+ patchStrategy: 'cursor-workbench-auth-gate',
99
+ verifyMarker: 'cursor-pool-workbench',
100
+ },
101
+ ],
81
102
  targetRelativePath,
82
103
  expectedSha256,
83
104
  structureSignature: 'fixture',
@@ -141,9 +162,10 @@ async function createLinuxFixtureApp() {
141
162
  const compatEntry: CompatibilityManifestEntry = {
142
163
  platform: 'linux',
143
164
  arch: process.arch,
144
- cursorVersion: '3.6.31',
165
+ cursorVersion: '3.6',
145
166
  cursorCommit: 'linux-commit',
146
167
  supportStatus: 'supported',
168
+ takeoverPlanId: 'cursor-3.6-mac-agent-c-workbench-h-uv',
147
169
  targetRelativePath,
148
170
  expectedSha256,
149
171
  structureSignature: 'linux-fixture',
@@ -188,7 +210,7 @@ async function createRemoteOnlyFixtureApp() {
188
210
  );
189
211
  const compatEntry = {
190
212
  ...fixture.compatEntry,
191
- cursorVersion: '3.7.0',
213
+ cursorVersion: '3.7',
192
214
  cursorCommit: 'remote-commit',
193
215
  userMessage: 'remote fixture supported',
194
216
  };
@@ -212,6 +234,7 @@ test('install reports Cursor version, simulated extension, service, patch, and h
212
234
  assert.match(output, /Cursor 3\.5\.38/);
213
235
  assert.match(output, /mode: disposable/);
214
236
  assert.match(output, /app: .*Cursor\.app/);
237
+ assert.match(output, /takeover-plan: cursor-3\.5-mac-agent-f-workbench-p-l0/);
215
238
  assert.match(output, /extension: bundled/);
216
239
  assert.match(output, /trial: recorded/);
217
240
  assert.match(output, /service: running/);
@@ -225,6 +248,7 @@ test('install reports Cursor version, simulated extension, service, patch, and h
225
248
 
226
249
  test('install detects Linux Cursor AppImage layout under usr/share/cursor', async () => {
227
250
  const fixture = await createLinuxFixtureApp();
251
+ const launcherFile = join(fixture.tempDir, 'bin/cursor-pool-cursor');
228
252
 
229
253
  try {
230
254
  const output = await install({
@@ -235,14 +259,20 @@ test('install detects Linux Cursor AppImage layout under usr/share/cursor', asyn
235
259
  backupDir: fixture.backupDir,
236
260
  trialRecordDir: join(fixture.tempDir, 'trials'),
237
261
  extensionInstallPath: join(fixture.tempDir, 'extensions/cursor-pool-status'),
262
+ linuxLauncherFile: launcherFile,
238
263
  compatEntries: [fixture.compatEntry],
239
264
  stopServiceAfterInstall: true,
240
265
  });
241
266
 
242
267
  assert.match(output, /Cursor 3\.6\.31/);
243
268
  assert.match(output, /patch: applied/);
269
+ assert.match(output, /launcher: .*cursor-pool-cursor/);
244
270
  assert.match(output, /health: ok/);
245
271
  assert.match(await readFile(fixture.targetPath, 'utf8'), new RegExp(CURSOR_POOL_PATCH_MARKER));
272
+ const launcher = await readFile(launcherFile, 'utf8');
273
+ assert.match(launcher, /AppRun/);
274
+ assert.match(launcher, /--no-sandbox/);
275
+ assert.equal((await stat(launcherFile)).mode & 0o111, 0o111);
246
276
  } finally {
247
277
  await rm(fixture.tempDir, { recursive: true, force: true });
248
278
  }
@@ -280,6 +310,36 @@ test('install can use a signed remote compatibility manifest from api base url',
280
310
  }
281
311
  });
282
312
 
313
+ test('install rejects when a secondary patch target hash does not match', async () => {
314
+ const fixture = await createFixtureApp();
315
+ const compatEntry: CompatibilityManifestEntry = {
316
+ ...fixture.compatEntry,
317
+ patchTargets: fixture.compatEntry.patchTargets?.map((target) =>
318
+ target.name === 'workbench'
319
+ ? { ...target, expectedSha256: 'f'.repeat(64) }
320
+ : target,
321
+ ),
322
+ };
323
+
324
+ try {
325
+ await assert.rejects(
326
+ () =>
327
+ install({
328
+ appPath: fixture.appPath,
329
+ runtimeFile: fixture.runtimeFile,
330
+ backupDir: fixture.backupDir,
331
+ trialRecordDir: join(fixture.tempDir, 'trials'),
332
+ extensionInstallPath: join(fixture.tempDir, 'extensions/cursor-pool-status'),
333
+ compatEntries: [compatEntry],
334
+ stopServiceAfterInstall: true,
335
+ }),
336
+ /Patch target hash mismatch/,
337
+ );
338
+ } finally {
339
+ await rm(fixture.tempDir, { recursive: true, force: true });
340
+ }
341
+ });
342
+
283
343
  test('install passes API base URL to detached service startup', async () => {
284
344
  const fixture = await createFixtureApp();
285
345
  const serviceCalls: Record<string, unknown>[] = [];
@@ -350,6 +410,124 @@ test('install persists API base URL and installs user autostart for real client
350
410
  }
351
411
  });
352
412
 
413
+ test('Linux real install falls back to user systemd when detached service startup is unhealthy', async () => {
414
+ const fixture = await createLinuxFixtureApp();
415
+ const configFile = join(fixture.tempDir, 'client-config.json');
416
+ const cursorExtensionsDir = join(fixture.tempDir, 'real-extensions');
417
+ const installRecordFile = join(fixture.tempDir, 'install.json');
418
+ const launcherFile = join(fixture.tempDir, 'bin/cursor-pool-cursor');
419
+ const calls: string[] = [];
420
+
421
+ try {
422
+ const output = await install({
423
+ realAppPath: fixture.appPath,
424
+ yes: true,
425
+ platform: 'linux',
426
+ arch: process.arch,
427
+ runtimeFile: fixture.runtimeFile,
428
+ backupDir: fixture.backupDir,
429
+ installRecordFile,
430
+ cursorExtensionsDir,
431
+ clientConfigFile: configFile,
432
+ linuxLauncherFile: launcherFile,
433
+ compatEntries: [fixture.compatEntry],
434
+ startDetachedService: async () => {
435
+ calls.push('detached');
436
+ throw new Error('Detached service failed to become healthy');
437
+ },
438
+ installUserAutostart: async (options) => {
439
+ calls.push('autostart');
440
+ await writeRuntimeInfo(
441
+ { host: '127.0.0.1', port: 56393, runtimeId: 'systemd-runtime' },
442
+ { runtimeFile: options.runtimeFile },
443
+ );
444
+ return { state: 'installed' as const };
445
+ },
446
+ fetchHealth: async (url) => {
447
+ calls.push(`health:${url}`);
448
+ return { ok: true, healthy: true };
449
+ },
450
+ });
451
+
452
+ assert.deepEqual(calls, [
453
+ 'detached',
454
+ 'autostart',
455
+ 'health:http://127.0.0.1:56393/health',
456
+ 'health:http://127.0.0.1:56393/health',
457
+ ]);
458
+ assert.match(output, /mode: real/);
459
+ assert.match(output, /service: running 127\.0\.0\.1:56393/);
460
+ assert.match(output, /autostart: installed/);
461
+ assert.match(output, /health: ok/);
462
+ assert.deepEqual(await readRuntimeInfo({ runtimeFile: fixture.runtimeFile }), {
463
+ host: '127.0.0.1',
464
+ port: 56393,
465
+ runtimeId: 'systemd-runtime',
466
+ });
467
+ } finally {
468
+ await rm(fixture.tempDir, { recursive: true, force: true });
469
+ }
470
+ });
471
+
472
+ test('Linux real install waits for delayed user systemd runtime during fallback', async () => {
473
+ const fixture = await createLinuxFixtureApp();
474
+ const configFile = join(fixture.tempDir, 'client-config.json');
475
+ const cursorExtensionsDir = join(fixture.tempDir, 'real-extensions');
476
+ const installRecordFile = join(fixture.tempDir, 'install.json');
477
+ const launcherFile = join(fixture.tempDir, 'bin/cursor-pool-cursor');
478
+ const calls: string[] = [];
479
+
480
+ try {
481
+ const output = await install({
482
+ realAppPath: fixture.appPath,
483
+ yes: true,
484
+ platform: 'linux',
485
+ arch: process.arch,
486
+ runtimeFile: fixture.runtimeFile,
487
+ backupDir: fixture.backupDir,
488
+ installRecordFile,
489
+ cursorExtensionsDir,
490
+ clientConfigFile: configFile,
491
+ linuxLauncherFile: launcherFile,
492
+ compatEntries: [fixture.compatEntry],
493
+ startDetachedService: async () => {
494
+ calls.push('detached');
495
+ throw new Error('Detached service failed to become healthy');
496
+ },
497
+ installUserAutostart: async (options) => {
498
+ calls.push('autostart');
499
+ setTimeout(() => {
500
+ void writeRuntimeInfo(
501
+ { host: '127.0.0.1', port: 56394, runtimeId: 'delayed-systemd-runtime' },
502
+ { runtimeFile: options.runtimeFile },
503
+ );
504
+ }, 100);
505
+ return { state: 'installed' as const };
506
+ },
507
+ fetchHealth: async (url) => {
508
+ calls.push(`health:${url}`);
509
+ return { ok: true, healthy: true };
510
+ },
511
+ });
512
+
513
+ assert.match(output, /service: running 127\.0\.0\.1:56394/);
514
+ assert.match(output, /autostart: installed/);
515
+ assert.match(output, /health: ok/);
516
+ assert.deepEqual(await readRuntimeInfo({ runtimeFile: fixture.runtimeFile }), {
517
+ host: '127.0.0.1',
518
+ port: 56394,
519
+ runtimeId: 'delayed-systemd-runtime',
520
+ });
521
+ assert.deepEqual(calls.slice(0, 3), [
522
+ 'detached',
523
+ 'autostart',
524
+ 'health:http://127.0.0.1:56394/health',
525
+ ]);
526
+ } finally {
527
+ await rm(fixture.tempDir, { recursive: true, force: true });
528
+ }
529
+ });
530
+
353
531
  test('real-mode install writes install record and reports real mode', async () => {
354
532
  const fixture = await createFixtureApp();
355
533
  const installRecordFile = join(fixture.tempDir, 'install.json');
@@ -370,6 +548,7 @@ test('real-mode install writes install record and reports real mode', async () =
370
548
  });
371
549
 
372
550
  assert.match(output, /mode: real/);
551
+ assert.match(output, /takeover-plan: cursor-3\.5-mac-agent-f-workbench-p-l0/);
373
552
  assert.match(output, /patch: applied/);
374
553
  assert.match(output, /install-record: recorded/);
375
554
  assert.doesNotMatch(output, /trial: recorded/);
@@ -380,6 +559,7 @@ test('real-mode install writes install record and reports real mode', async () =
380
559
  assert.equal(record.mode, 'real');
381
560
  assert.equal(record.appPath, fixture.appPath);
382
561
  assert.equal(record.cursorVersion, '3.5.38');
562
+ assert.equal(record.takeoverPlanId, 'cursor-3.5-mac-agent-f-workbench-p-l0');
383
563
  assert.equal(record.extensionInstallPath, extensionInstallPath);
384
564
  assert.equal(record.extensionLinkedPath, linkedExtensionPathForDir(cursorExtensionsDir));
385
565
  assert.equal(record.lastOperation, 'install');
@@ -393,6 +573,7 @@ test('real-mode install rolls back install record after health failure', async (
393
573
  const fixture = await createFixtureApp();
394
574
  const installRecordFile = join(fixture.tempDir, 'install.json');
395
575
  const extensionInstallPath = join(fixture.tempDir, 'extensions/cursor-pool-status');
576
+ const cursorExtensionsDir = join(fixture.tempDir, 'real-extensions');
396
577
 
397
578
  try {
398
579
  await assert.rejects(
@@ -403,6 +584,7 @@ test('real-mode install rolls back install record after health failure', async (
403
584
  backupDir: fixture.backupDir,
404
585
  installRecordFile,
405
586
  extensionInstallPath,
587
+ cursorExtensionsDir,
406
588
  compatEntries: [fixture.compatEntry],
407
589
  stopServiceAfterInstall: true,
408
590
  fetchHealth: async () => ({ ok: false, healthy: false }),
@@ -421,6 +603,7 @@ test('real-mode install requires confirmation when yes is missing', async () =>
421
603
  const originalTargetContent = await readFile(fixture.targetPath, 'utf8');
422
604
  const installRecordFile = join(fixture.tempDir, 'install.json');
423
605
  const extensionInstallPath = join(fixture.tempDir, 'extensions/cursor-pool-status');
606
+ const cursorExtensionsDir = join(fixture.tempDir, 'real-extensions');
424
607
 
425
608
  try {
426
609
  await assert.rejects(
@@ -431,6 +614,7 @@ test('real-mode install requires confirmation when yes is missing', async () =>
431
614
  backupDir: fixture.backupDir,
432
615
  installRecordFile,
433
616
  extensionInstallPath,
617
+ cursorExtensionsDir,
434
618
  compatEntries: [fixture.compatEntry],
435
619
  stopServiceAfterInstall: true,
436
620
  }),
@@ -469,6 +653,7 @@ test('install links extension into an explicit Cursor extensions directory', asy
469
653
  assert.equal(await getLinkedExtensionState(linkedPath), 'linked');
470
654
 
471
655
  const trialRecord = await readTrialRecord(fixture.appPath, { trialRecordDir });
656
+ assert.equal(trialRecord?.takeoverPlanId, 'cursor-3.5-mac-agent-f-workbench-p-l0');
472
657
  assert.equal(trialRecord?.extensionState, 'linked');
473
658
  assert.equal(trialRecord?.extensionInstallPath, extensionInstallPath);
474
659
  assert.equal(trialRecord?.extensionLinkedPath, linkedPath);
@@ -89,6 +89,7 @@ async function createFixtureApp() {
89
89
  cursorVersion: '3.5.38',
90
90
  cursorCommit: '009bb5a3600dd98fe1c1f25798f767f686e14750',
91
91
  supportStatus: 'supported',
92
+ takeoverPlanId: 'cursor-3.6-mac-agent-c-workbench-h-uv',
92
93
  targetRelativePath,
93
94
  expectedSha256: createHash('sha256').update(targetContent).digest('hex'),
94
95
  structureSignature: 'fixture',
@@ -6,10 +6,19 @@ import { fileURLToPath } from 'node:url';
6
6
  import test from 'node:test';
7
7
  import { readRuntimeInfo } from '../../service/src/runtime';
8
8
  import { startServer } from '../../service/src/server';
9
- import { startDetachedService, stopRuntimeService, waitForRuntimeHealth } from '../src/serviceProcess';
9
+ import {
10
+ DEFAULT_DETACHED_SERVICE_STARTUP_TIMEOUT_MS,
11
+ startDetachedService,
12
+ stopRuntimeService,
13
+ waitForRuntimeHealth,
14
+ } from '../src/serviceProcess';
10
15
 
11
16
  const cliRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
12
17
 
18
+ test('default detached service startup timeout allows slow Linux VMs', () => {
19
+ assert.equal(DEFAULT_DETACHED_SERVICE_STARTUP_TIMEOUT_MS, 30_000);
20
+ });
21
+
13
22
  test('startDetachedService starts a service discoverable by runtime file', async () => {
14
23
  const tempDir = await mkdtemp(join(tmpdir(), 'cursor-pool-detached-service-'));
15
24
  const runtimeFile = join(tempDir, 'runtime.json');
@@ -136,6 +136,7 @@ async function createFixtureApp() {
136
136
  cursorVersion: '3.5.38',
137
137
  cursorCommit: '009bb5a3600dd98fe1c1f25798f767f686e14750',
138
138
  supportStatus: 'supported',
139
+ takeoverPlanId: 'cursor-3.6-mac-agent-c-workbench-h-uv',
139
140
  targetRelativePath,
140
141
  expectedSha256: createHash('sha256').update(targetContent).digest('hex'),
141
142
  structureSignature: 'fixture',