@cursorpool-dev/cli 0.5.6

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 (105) hide show
  1. package/bin/cursor-pool.mjs +9 -0
  2. package/bin/cursor-pool.ts +169 -0
  3. package/node_modules/@cursor-pool/extension/dist/extension.js +2910 -0
  4. package/node_modules/@cursor-pool/extension/package.json +64 -0
  5. package/node_modules/@cursor-pool/extension/resources/cursor-pool.svg +6 -0
  6. package/node_modules/@cursor-pool/extension/src/api.ts +545 -0
  7. package/node_modules/@cursor-pool/extension/src/extension.ts +104 -0
  8. package/node_modules/@cursor-pool/extension/src/index.ts +1 -0
  9. package/node_modules/@cursor-pool/extension/src/panel.ts +569 -0
  10. package/node_modules/@cursor-pool/extension/src/runtime.ts +22 -0
  11. package/node_modules/@cursor-pool/extension/test/panel.test.ts +1785 -0
  12. package/node_modules/@cursor-pool/patcher/package.json +17 -0
  13. package/node_modules/@cursor-pool/patcher/src/alwaysLocalMarker.ts +86 -0
  14. package/node_modules/@cursor-pool/patcher/src/hash.ts +7 -0
  15. package/node_modules/@cursor-pool/patcher/src/index.ts +55 -0
  16. package/node_modules/@cursor-pool/patcher/src/marker.ts +159 -0
  17. package/node_modules/@cursor-pool/patcher/src/patchCursorAgentExec.ts +154 -0
  18. package/node_modules/@cursor-pool/patcher/src/patchCursorAlwaysLocal.ts +142 -0
  19. package/node_modules/@cursor-pool/patcher/src/patchCursorWorkbenchAuthGate.ts +140 -0
  20. package/node_modules/@cursor-pool/patcher/src/restoreCursorAgentExec.ts +52 -0
  21. package/node_modules/@cursor-pool/patcher/src/restoreCursorAlwaysLocal.ts +52 -0
  22. package/node_modules/@cursor-pool/patcher/src/restoreCursorWorkbenchAuthGate.ts +70 -0
  23. package/node_modules/@cursor-pool/patcher/src/workbenchAuthGateMarker.ts +243 -0
  24. package/node_modules/@cursor-pool/patcher/test/patchCursorAgentExec.test.ts +630 -0
  25. package/node_modules/@cursor-pool/patcher/test/patchCursorAlwaysLocal.test.ts +144 -0
  26. package/node_modules/@cursor-pool/patcher/test/patchCursorWorkbench.test.ts +770 -0
  27. package/node_modules/@cursor-pool/patcher/test/restoreCursorAgentExec.test.ts +139 -0
  28. package/node_modules/@cursor-pool/service/package.json +17 -0
  29. package/node_modules/@cursor-pool/service/src/canary.ts +61 -0
  30. package/node_modules/@cursor-pool/service/src/diagnostics.ts +385 -0
  31. package/node_modules/@cursor-pool/service/src/entry.ts +161 -0
  32. package/node_modules/@cursor-pool/service/src/health.ts +10 -0
  33. package/node_modules/@cursor-pool/service/src/index.ts +29 -0
  34. package/node_modules/@cursor-pool/service/src/metadata.ts +22 -0
  35. package/node_modules/@cursor-pool/service/src/platformSession.ts +1178 -0
  36. package/node_modules/@cursor-pool/service/src/requestCheck.ts +81 -0
  37. package/node_modules/@cursor-pool/service/src/requestGate.ts +100 -0
  38. package/node_modules/@cursor-pool/service/src/requestGateway.ts +441 -0
  39. package/node_modules/@cursor-pool/service/src/runtime.ts +48 -0
  40. package/node_modules/@cursor-pool/service/src/server.ts +939 -0
  41. package/node_modules/@cursor-pool/service/src/takeover.ts +111 -0
  42. package/node_modules/@cursor-pool/service/test/canary.test.ts +140 -0
  43. package/node_modules/@cursor-pool/service/test/diagnostics.test.ts +506 -0
  44. package/node_modules/@cursor-pool/service/test/metadata.test.ts +63 -0
  45. package/node_modules/@cursor-pool/service/test/platformSession.test.ts +2428 -0
  46. package/node_modules/@cursor-pool/service/test/requestCheck.test.ts +152 -0
  47. package/node_modules/@cursor-pool/service/test/requestGate.test.ts +207 -0
  48. package/node_modules/@cursor-pool/service/test/requestGateway.test.ts +466 -0
  49. package/node_modules/@cursor-pool/service/test/runtime.test.ts +47 -0
  50. package/node_modules/@cursor-pool/service/test/server.test.ts +2570 -0
  51. package/node_modules/@cursor-pool/shared/package.json +17 -0
  52. package/node_modules/@cursor-pool/shared/src/clientConfig.ts +49 -0
  53. package/node_modules/@cursor-pool/shared/src/index.ts +14 -0
  54. package/node_modules/@cursor-pool/shared/src/manifest.ts +36 -0
  55. package/node_modules/@cursor-pool/shared/src/metadata.ts +19 -0
  56. package/node_modules/@cursor-pool/shared/src/paths.ts +5 -0
  57. package/node_modules/@cursor-pool/shared/src/runtime.ts +3 -0
  58. package/node_modules/@cursor-pool/shared/test/index.test.ts +56 -0
  59. package/node_modules/@cursor-pool/shared/test/manifest.test.ts +65 -0
  60. package/node_modules/@cursor-pool/shared/test/metadata.test.ts +25 -0
  61. package/node_modules/@cursor-pool/shared/test/runtime.test.ts +8 -0
  62. package/package.json +28 -0
  63. package/src/adHocResign.ts +65 -0
  64. package/src/autostart.ts +240 -0
  65. package/src/compat.ts +282 -0
  66. package/src/confirm.ts +76 -0
  67. package/src/cursor.ts +94 -0
  68. package/src/diagnostics.ts +558 -0
  69. package/src/environment.ts +18 -0
  70. package/src/extensionBundle.ts +111 -0
  71. package/src/extensionLink.ts +168 -0
  72. package/src/index.ts +23 -0
  73. package/src/install.ts +614 -0
  74. package/src/installRecord.ts +105 -0
  75. package/src/launch.ts +182 -0
  76. package/src/patchSet.ts +182 -0
  77. package/src/platform.ts +132 -0
  78. package/src/repair.ts +383 -0
  79. package/src/restore.ts +153 -0
  80. package/src/serviceCommands.ts +79 -0
  81. package/src/serviceProcess.ts +188 -0
  82. package/src/status.ts +241 -0
  83. package/src/target.ts +37 -0
  84. package/src/trial.ts +133 -0
  85. package/src/uninstall.ts +213 -0
  86. package/test/autostart.test.ts +151 -0
  87. package/test/compat.test.ts +192 -0
  88. package/test/confirm.test.ts +114 -0
  89. package/test/cursor-pool-bin.test.ts +658 -0
  90. package/test/cursor.test.ts +20 -0
  91. package/test/diagnostics.test.ts +709 -0
  92. package/test/e2e-install.test.ts +773 -0
  93. package/test/extensionBundle.test.ts +161 -0
  94. package/test/extensionLink.test.ts +209 -0
  95. package/test/install.test.ts +862 -0
  96. package/test/installRecord.test.ts +107 -0
  97. package/test/launch.test.ts +138 -0
  98. package/test/platform.test.ts +226 -0
  99. package/test/repair.test.ts +575 -0
  100. package/test/restore.test.ts +211 -0
  101. package/test/serviceCommands.test.ts +135 -0
  102. package/test/serviceProcess.test.ts +280 -0
  103. package/test/status.test.ts +615 -0
  104. package/test/target.test.ts +49 -0
  105. package/test/trial.test.ts +146 -0
@@ -0,0 +1,770 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { dirname, join } from 'node:path';
5
+ import { Script } from 'node:vm';
6
+ import test from 'node:test';
7
+ import { sha256File } from '../src/hash';
8
+ import {
9
+ CURSOR_POOL_WORKBENCH_AUTH_GATE_MARKER,
10
+ CURSOR_POOL_WORKBENCH_AUTH_GATE_SIGNATURE,
11
+ CURSOR_POOL_WORKBENCH_AGENT_LOOP_SIGNATURE,
12
+ CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE,
13
+ CURSOR_POOL_WORKBENCH_SUBMIT_GATE_SIGNATURE,
14
+ containsCursorWorkbenchAuthGateMarker,
15
+ injectCursorWorkbenchAuthGatePatch,
16
+ } from '../src/workbenchAuthGateMarker';
17
+ import {
18
+ patchCursorWorkbenchAuthGate,
19
+ backupPathForCursorWorkbenchAuthGate,
20
+ resolveCursorWorkbenchPath,
21
+ } from '../src/patchCursorWorkbenchAuthGate';
22
+ import { restoreCursorWorkbenchAuthGate } from '../src/restoreCursorWorkbenchAuthGate';
23
+
24
+ const workbenchRelativePath = 'Contents/Resources/app/out/vs/workbench/workbench.desktop.main.js';
25
+ const composerAuthGateAnchor =
26
+ 'get when(){return p()&&!fzC},get fallback(){return he(DGC,{})}';
27
+ const composerSubmitAuthGateAnchor =
28
+ 'if(!p()){e.cursorAuthenticationService.login(),e.commandService.executeCommand(wV,"general");return}';
29
+ const agentEditorSendButtonAuthGateAnchor =
30
+ 'get when(){return t()},get fallback(){return(()=>{var D=avx();return Pe(D,he(sl,{keybinding:" \\u23CE",onClick:T,hintText:"Log in to use Cloud Agents",variant:"secondary",children:"Log in"})),D})()},get children(){return';
31
+ const agentEditorSendButtonLoginAnchor =
32
+ 'if(!t()){e.cursorAuthenticationService.login();return}';
33
+ const agentLoopRunAnchor = 'await this.agentClientService.run(te,H,$e,Ne,Ce,T,ze,me,we,[],ct)';
34
+ const buildFlagsLocalModeAnchor = 'localMode:!1';
35
+ const localProviderConfigAnchor =
36
+ '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"}';
37
+ const agentClientRunLocalModeAnchor =
38
+ 'if(L0.localMode){try{g.onNetworkPhaseStart?.()}catch(b){this.logService.warn("[AgentClientService] onNetworkPhaseStart callback failed in local mode",b)}return this.runLocalAgentInExtensionHost(e,t,i,r,s,a,d,h,g)}return this.client.run(e,t,i,r,s,o,a,u,d,h,g)';
39
+
40
+ function workbenchFixture(extra = '') {
41
+ return [
42
+ `function composer(){return he(Mt,{${composerAuthGateAnchor},get children(){return "controls"}})}`,
43
+ `async function submit(){${composerSubmitAuthGateAnchor};return "submitted";}`,
44
+ `function agentEditorControls(){const T=()=>{${agentEditorSendButtonLoginAnchor};return n.handleSubmit()};return he(Mt,{${agentEditorSendButtonAuthGateAnchor}"controls"}})}`,
45
+ `const flags={${buildFlagsLocalModeAnchor}}`,
46
+ localProviderConfigAnchor,
47
+ `async function runAgentLoop(){${agentLoopRunAnchor}}`,
48
+ `async function agentClientRun(){const g={...p,isRunningInTest:p.isRunningInTest??this.environmentService.enableSmokeTestDriver===!0,clientSupportsInlineImages:!0};${agentClientRunLocalModeAnchor}}`,
49
+ extra,
50
+ ].join(';');
51
+ }
52
+
53
+ async function createFixture(
54
+ content = workbenchFixture(),
55
+ ) {
56
+ const base = await mkdtemp(join(tmpdir(), 'cursor-pool-workbench-patcher-'));
57
+ const appPath = join(base, `Fixture-${Date.now()}-${Math.random()}.app`);
58
+ await mkdir(join(appPath, 'Contents/Resources/app/out/vs/workbench'), {
59
+ recursive: true,
60
+ });
61
+ await writeFile(join(appPath, workbenchRelativePath), content, 'utf8');
62
+
63
+ return {
64
+ appPath,
65
+ targetPath: join(appPath, workbenchRelativePath),
66
+ };
67
+ }
68
+
69
+ test('workbench auth gate patch renders composer controls only with official login or active platform mode', () => {
70
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
71
+ const markerStart = patched.indexOf(CURSOR_POOL_WORKBENCH_AUTH_GATE_SIGNATURE);
72
+ const objectStart = patched.lastIndexOf('get when()', markerStart);
73
+ const objectEnd = patched.indexOf('get fallback()', markerStart) + 'get fallback(){return he(DGC,{})}'.length;
74
+ const objectLiteral = patched.slice(objectStart, objectEnd);
75
+
76
+ assert.equal(containsCursorWorkbenchAuthGateMarker(patched), true);
77
+ assert.equal(patched.includes(CURSOR_POOL_WORKBENCH_AUTH_GATE_MARKER), true);
78
+ assert.equal(patched.includes(CURSOR_POOL_WORKBENCH_AUTH_GATE_SIGNATURE), true);
79
+ assert.equal(patched.includes(CURSOR_POOL_WORKBENCH_SUBMIT_GATE_SIGNATURE), true);
80
+ assert.equal(patched.includes(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE), true);
81
+ assert.equal(
82
+ patched.includes('get when(){return (p()||((globalThis.__cursorPoolEnsurePlatformModeGuard||(globalThis.__cursorPoolEnsurePlatformModeGuard=()=>{'),
83
+ true,
84
+ );
85
+ assert.equal(patched.includes(composerAuthGateAnchor), false);
86
+ assert.equal(patched.includes(composerSubmitAuthGateAnchor), false);
87
+ assert.equal(
88
+ patched.includes(
89
+ 'if(!p()&&!globalThis.__cursorPoolIsPlatformModeActive?.()){e.cursorAuthenticationService.login(),e.commandService.executeCommand(wV,"general");return}',
90
+ ),
91
+ true,
92
+ );
93
+ assert.doesNotThrow(() => new Function('he', 'DGC', `return ({${objectLiteral}});`));
94
+ });
95
+
96
+ test('workbench auth gate patch lets the Agent Editor send controls render in platform mode', () => {
97
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
98
+
99
+ assert.equal(patched.includes(agentEditorSendButtonAuthGateAnchor), false);
100
+ assert.equal(patched.includes(agentEditorSendButtonLoginAnchor), false);
101
+ assert.equal(
102
+ patched.includes('get when(){return t()||((globalThis.__cursorPoolEnsurePlatformModeGuard||(globalThis.__cursorPoolEnsurePlatformModeGuard=()=>{'),
103
+ true,
104
+ );
105
+ assert.equal(
106
+ patched.includes(
107
+ 'if(!t()&&!((globalThis.__cursorPoolEnsurePlatformModeGuard||(globalThis.__cursorPoolEnsurePlatformModeGuard=()=>{',
108
+ ),
109
+ true,
110
+ );
111
+ });
112
+
113
+ test('workbench auth gate patch treats old V6 markers as legacy and reapplies Agent Editor gates', () => {
114
+ const oldV6Patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture()).replaceAll(
115
+ 'CURSOR_POOL_MVP1_WORKBENCH_AUTH_GATE_PATCH_V9_ALWAYS_NATIVE_LOCAL',
116
+ 'CURSOR_POOL_MVP1_WORKBENCH_AUTH_GATE_PATCH_V6_ACTIVE_ONLY_NATIVE_LOCAL_AGENT',
117
+ ).replace('["__cursorPoolWorkbenchAgentEditorSendButton"]:true,\n', '')
118
+ .replace('["__cursorPoolWorkbenchAgentEditorSubmit"]:true,\n', '')
119
+ .replace(
120
+ 'get when(){return t()||globalThis.__cursorPoolIsPlatformModeActive?.()}',
121
+ 'get when(){return t()}',
122
+ )
123
+ .replace(
124
+ 'if(!t()&&!globalThis.__cursorPoolIsPlatformModeActive?.()){e.cursorAuthenticationService.login();return}',
125
+ 'if(!t()){e.cursorAuthenticationService.login();return}',
126
+ );
127
+
128
+ assert.equal(containsCursorWorkbenchAuthGateMarker(oldV6Patched), false);
129
+ const repatched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
130
+
131
+ assert.equal(containsCursorWorkbenchAuthGateMarker(repatched), true);
132
+ assert.equal(
133
+ repatched.includes('get when(){return t()||((globalThis.__cursorPoolEnsurePlatformModeGuard||(globalThis.__cursorPoolEnsurePlatformModeGuard=()=>{'),
134
+ true,
135
+ );
136
+ });
137
+
138
+ test('patchCursorWorkbenchAuthGate upgrades old V9 always-active guard from clean backup', async () => {
139
+ const backupDir = join(tmpdir(), `cursor-pool-workbench-v9-upgrade-${Date.now()}-${Math.random()}`);
140
+ const fixture = await createFixture();
141
+
142
+ try {
143
+ const originalContent = await readFile(fixture.targetPath, 'utf8');
144
+ const backupPath = await backupPathForCursorWorkbenchAuthGate(
145
+ fixture.appPath,
146
+ fixture.targetPath,
147
+ backupDir,
148
+ );
149
+ await mkdir(dirname(backupPath), { recursive: true });
150
+ await writeFile(backupPath, originalContent, 'utf8');
151
+ const oldV9Patched = injectCursorWorkbenchAuthGatePatch(originalContent)
152
+ .replaceAll(
153
+ CURSOR_POOL_WORKBENCH_AUTH_GATE_MARKER,
154
+ 'CURSOR_POOL_MVP1_WORKBENCH_AUTH_GATE_PATCH_V9_ALWAYS_NATIVE_LOCAL',
155
+ )
156
+ .replace(
157
+ /globalThis\.__cursorPoolIsPlatformModeActive=\(\)=>\{try\{.*?\}\},void 0\)/,
158
+ 'globalThis.__cursorPoolIsPlatformModeActive=()=>!0,void 0)',
159
+ );
160
+ await writeFile(fixture.targetPath, oldV9Patched, 'utf8');
161
+
162
+ const result = await patchCursorWorkbenchAuthGate(fixture.appPath, { backupDir });
163
+ const upgraded = await readFile(fixture.targetPath, 'utf8');
164
+
165
+ assert.notEqual(result.afterHash, result.beforeHash);
166
+ assert.equal(containsCursorWorkbenchAuthGateMarker(upgraded), true);
167
+ assert.equal(upgraded.includes('CURSOR_POOL_MVP1_WORKBENCH_AUTH_GATE_PATCH_V9_ALWAYS_NATIVE_LOCAL'), false);
168
+ assert.equal(upgraded.includes('cursorPoolPlatformModeActive'), true);
169
+ assert.equal(upgraded.includes('globalThis.__cursorPoolIsPlatformModeActive=()=>!0'), false);
170
+ } finally {
171
+ await rm(fixture.appPath, { recursive: true, force: true });
172
+ await rm(backupDir, { recursive: true, force: true });
173
+ }
174
+ });
175
+
176
+ test('workbench auth gate patch keeps the native agent loop instead of appending fake AI bubbles', () => {
177
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
178
+
179
+ assert.equal(patched.includes(CURSOR_POOL_WORKBENCH_AGENT_LOOP_SIGNATURE), true);
180
+ assert.equal(patched.includes(agentLoopRunAnchor), true);
181
+ assert.equal(patched.includes('/agent/takeover'), false);
182
+ assert.equal(patched.includes('fetch("http://127.0.0.1:56393/agent/takeover"'), false);
183
+ assert.equal(patched.includes('appendComposerBubbles'), false);
184
+ assert.equal(patched.includes('Tt=bt.content'), false);
185
+ assert.equal(patched.includes('De("status","completed")'), false);
186
+ assert.equal(patched.includes('return}}await this.agentClientService.run'), false);
187
+ });
188
+
189
+ test('workbench auth gate patch delegates agent turns to the local service only in platform mode', () => {
190
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
191
+
192
+ assert.equal(patched.includes(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE), true);
193
+ assert.equal(patched.includes('localMode:!1'), true);
194
+ assert.equal(patched.includes('localMode:!0'), false);
195
+ assert.equal(patched.includes('__cursorPoolIsPlatformModeActive'), true);
196
+ assert.equal(patched.includes('cursorPoolPlatformModeActive'), true);
197
+ assert.equal(patched.includes('/platform/status'), true);
198
+ assert.equal(patched.includes('mode?.state==="active"'), true);
199
+ assert.equal(patched.includes('platformMode==="active"'), true);
200
+ assert.equal(patched.includes('__cursorPoolRuntimeBaseUrl'), true);
201
+ assert.equal(patched.includes('baseUrl:r'), true);
202
+ assert.equal(patched.includes('baseUrl:"http://127.0.0.1:56393"'), false);
203
+ assert.equal(patched.includes('apiKey:"cursor-pool-local"'), true);
204
+ assert.equal(patched.includes('if(((globalThis.__cursorPoolEnsurePlatformModeGuard||(globalThis.__cursorPoolEnsurePlatformModeGuard=()=>{'), true);
205
+ assert.equal(patched.includes('if(!0||L0.localMode)'), false);
206
+ assert.equal(patched.includes('return this.runLocalAgentInExtensionHost(e,t,i,r,s,a,d,h,g)'), true);
207
+ assert.equal(patched.includes('return this.client.run(e,t,i,r,s,o,a,u,d,h,g)'), true);
208
+ });
209
+
210
+ test('workbench auth gate patch reads the local service port from runtime json', () => {
211
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
212
+ const markerStart = patched.indexOf(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE);
213
+ const objectStart = patched.lastIndexOf('get when()', markerStart);
214
+ const objectEnd = patched.indexOf('get fallback()', markerStart) + 'get fallback(){return he(DGC,{})}'.length;
215
+ const objectLiteral = patched.slice(objectStart, objectEnd);
216
+ const runtime = { host: '127.0.0.1', port: 61372, runtimeId: 'runtime-dynamic' };
217
+ const sandboxGlobal = {
218
+ localStorage: {
219
+ getItem() {
220
+ return null;
221
+ },
222
+ setItem() {},
223
+ },
224
+ setInterval() {
225
+ return 1;
226
+ },
227
+ } as { __cursorPoolRuntimeBaseUrl?: () => string | null };
228
+ const fakeRequire = (moduleName: string) => {
229
+ if (moduleName === 'node:fs') {
230
+ return {
231
+ existsSync: () => true,
232
+ readFileSync: (path: string) =>
233
+ path.endsWith('runtime.json')
234
+ ? JSON.stringify(runtime)
235
+ : JSON.stringify({ device: { status: 'inactive' } }),
236
+ };
237
+ }
238
+ if (moduleName === 'node:os') {
239
+ return { homedir: () => '/Users/tester' };
240
+ }
241
+ if (moduleName === 'node:path') {
242
+ return { join: (...parts: string[]) => parts.join('/') };
243
+ }
244
+ throw new Error(`unexpected module ${moduleName}`);
245
+ };
246
+
247
+ new Function(
248
+ 'he',
249
+ 'DGC',
250
+ 'globalThis',
251
+ 'require',
252
+ 'process',
253
+ `return ({${objectLiteral}});`,
254
+ )(
255
+ () => undefined,
256
+ {},
257
+ sandboxGlobal,
258
+ fakeRequire,
259
+ { env: {} },
260
+ );
261
+
262
+ assert.equal(sandboxGlobal.__cursorPoolRuntimeBaseUrl?.(), 'http://127.0.0.1:61372');
263
+ });
264
+
265
+ test('workbench platform-mode guard self-bootstraps from the real session file shape', async () => {
266
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
267
+ const gatePrefix = 'get when(){return t()||';
268
+ const gateStart = patched.indexOf(gatePrefix);
269
+ const gateEnd = patched.indexOf('},get fallback(){return', gateStart);
270
+ const gateExpression = patched.slice(gateStart + gatePrefix.length, gateEnd);
271
+ const sandboxGlobal = {
272
+ localStorage: {
273
+ getItem() {
274
+ return null;
275
+ },
276
+ setItem() {},
277
+ },
278
+ } as {
279
+ __cursorPoolIsPlatformModeActive?: () => boolean;
280
+ __cursorPoolEnsurePlatformModeGuard?: () => void;
281
+ };
282
+ const session = {
283
+ device: { status: 'active' },
284
+ platformMode: 'active',
285
+ activeProductId: 'prod_basic',
286
+ platformModeStartedAt: '2026-06-04T03:10:06.880Z',
287
+ };
288
+ const fakeRequire = (moduleName: string) => {
289
+ if (moduleName === 'node:fs') {
290
+ return {
291
+ existsSync: () => true,
292
+ readFileSync: () => JSON.stringify(session),
293
+ };
294
+ }
295
+ if (moduleName === 'node:os') {
296
+ return { homedir: () => '/Users/tester' };
297
+ }
298
+ if (moduleName === 'node:path') {
299
+ return { join: (...parts: string[]) => parts.join('/') };
300
+ }
301
+ throw new Error(`unexpected module ${moduleName}`);
302
+ };
303
+
304
+ const gate = new Function(
305
+ 't',
306
+ 'globalThis',
307
+ 'require',
308
+ 'process',
309
+ `return ${gateExpression};`,
310
+ )(
311
+ () => false,
312
+ sandboxGlobal,
313
+ fakeRequire,
314
+ { env: {} },
315
+ );
316
+
317
+ assert.equal(gate, true);
318
+ assert.equal(sandboxGlobal.__cursorPoolIsPlatformModeActive?.(), true);
319
+ });
320
+
321
+ test('workbench platform-mode runtime guard does not trust stale renderer storage without verified timestamp', async () => {
322
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
323
+ const markerStart = patched.indexOf(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE);
324
+ const objectStart = patched.lastIndexOf('get when()', markerStart);
325
+ const objectEnd = patched.indexOf('get fallback()', markerStart) + 'get fallback(){return he(DGC,{})}'.length;
326
+ const objectLiteral = patched.slice(objectStart, objectEnd);
327
+ const values = new Map([['cursorPoolPlatformModeActive', '1']]);
328
+ const sandboxGlobal = {
329
+ localStorage: {
330
+ getItem(key: string) {
331
+ return values.get(key) ?? null;
332
+ },
333
+ setItem(key: string, value: string) {
334
+ values.set(key, value);
335
+ },
336
+ },
337
+ setInterval() {
338
+ return 1;
339
+ },
340
+ } as { __cursorPoolIsPlatformModeActive?: () => boolean };
341
+
342
+ new Function(
343
+ 'he',
344
+ 'DGC',
345
+ 'globalThis',
346
+ 'require',
347
+ `return ({${objectLiteral}});`,
348
+ )(
349
+ () => undefined,
350
+ {},
351
+ sandboxGlobal,
352
+ () => {
353
+ throw new Error('node require unavailable');
354
+ },
355
+ );
356
+
357
+ assert.equal(sandboxGlobal.__cursorPoolIsPlatformModeActive?.(), false);
358
+ });
359
+
360
+ test('workbench platform-mode runtime guard trusts recently verified renderer cache synchronously', async () => {
361
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
362
+ const markerStart = patched.indexOf(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE);
363
+ const objectStart = patched.lastIndexOf('get when()', markerStart);
364
+ const objectEnd = patched.indexOf('get fallback()', markerStart) + 'get fallback(){return he(DGC,{})}'.length;
365
+ const objectLiteral = patched.slice(objectStart, objectEnd);
366
+ const values = new Map([
367
+ ['cursorPoolPlatformModeActive', '1'],
368
+ ['cursorPoolPlatformModeCheckedAt', String(Date.now())],
369
+ ]);
370
+ const sandboxGlobal = {
371
+ localStorage: {
372
+ getItem(key: string) {
373
+ return values.get(key) ?? null;
374
+ },
375
+ setItem(key: string, value: string) {
376
+ values.set(key, value);
377
+ },
378
+ },
379
+ setInterval() {
380
+ return 1;
381
+ },
382
+ } as { __cursorPoolIsPlatformModeActive?: () => boolean };
383
+
384
+ new Function(
385
+ 'he',
386
+ 'DGC',
387
+ 'globalThis',
388
+ 'require',
389
+ `return ({${objectLiteral}});`,
390
+ )(
391
+ () => undefined,
392
+ {},
393
+ sandboxGlobal,
394
+ () => {
395
+ throw new Error('node require unavailable');
396
+ },
397
+ );
398
+
399
+ assert.equal(sandboxGlobal.__cursorPoolIsPlatformModeActive?.(), true);
400
+ });
401
+
402
+ test('workbench platform-mode runtime guard lets inactive session override stale renderer storage', async () => {
403
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
404
+ const markerStart = patched.indexOf(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE);
405
+ const objectStart = patched.lastIndexOf('get when()', markerStart);
406
+ const objectEnd = patched.indexOf('get fallback()', markerStart) + 'get fallback(){return he(DGC,{})}'.length;
407
+ const objectLiteral = patched.slice(objectStart, objectEnd);
408
+ const values = new Map([['cursorPoolPlatformModeActive', '1']]);
409
+ const sandboxGlobal = {
410
+ localStorage: {
411
+ getItem(key: string) {
412
+ return values.get(key) ?? null;
413
+ },
414
+ setItem(key: string, value: string) {
415
+ values.set(key, value);
416
+ },
417
+ },
418
+ fetch: async () => ({ ok: true, json: async () => ({ mode: { state: 'inactive' } }) }),
419
+ setInterval() {
420
+ return 1;
421
+ },
422
+ setTimeout(callback: () => unknown) {
423
+ callback();
424
+ return 1;
425
+ },
426
+ location: {
427
+ reload() {},
428
+ },
429
+ } as { __cursorPoolIsPlatformModeActive?: () => boolean };
430
+ const fakeRequire = (moduleName: string) => {
431
+ if (moduleName === 'node:fs') {
432
+ return {
433
+ existsSync: () => true,
434
+ readFileSync: (path: string) =>
435
+ path.endsWith('runtime.json')
436
+ ? JSON.stringify({ host: '127.0.0.1', port: 61372, runtimeId: 'runtime-inactive-test' })
437
+ : JSON.stringify({
438
+ device: { status: 'active' },
439
+ selectedProductId: 'prod_basic',
440
+ }),
441
+ };
442
+ }
443
+ if (moduleName === 'node:os') {
444
+ return { homedir: () => '/Users/tester' };
445
+ }
446
+ if (moduleName === 'node:path') {
447
+ return { join: (...parts: string[]) => parts.join('/') };
448
+ }
449
+ throw new Error(`unexpected module ${moduleName}`);
450
+ };
451
+
452
+ new Function('he', 'DGC', 'globalThis', 'require', 'process', `return ({${objectLiteral}});`)(
453
+ () => undefined,
454
+ {},
455
+ sandboxGlobal,
456
+ fakeRequire,
457
+ { env: {} },
458
+ );
459
+ await new Promise((resolve) => setTimeout(resolve, 0));
460
+
461
+ assert.equal(sandboxGlobal.__cursorPoolIsPlatformModeActive?.(), false);
462
+ assert.equal(values.get('cursorPoolPlatformModeActive'), '0');
463
+ });
464
+
465
+ test('workbench platform-mode runtime guard stores fetched active state and reloads', async () => {
466
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
467
+ const markerStart = patched.indexOf(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE);
468
+ const objectStart = patched.lastIndexOf('get when()', markerStart);
469
+ const objectEnd = patched.indexOf('get fallback()', markerStart) + 'get fallback(){return he(DGC,{})}'.length;
470
+ const objectLiteral = patched.slice(objectStart, objectEnd);
471
+ const values = new Map([['cursorPoolPlatformModeActive', '0']]);
472
+ let reloads = 0;
473
+ let fetchedUrl = '';
474
+ const timers: Array<() => unknown> = [];
475
+ const sandboxGlobal = {
476
+ localStorage: {
477
+ getItem(key: string) {
478
+ return values.get(key) ?? null;
479
+ },
480
+ setItem(key: string, value: string) {
481
+ values.set(key, value);
482
+ },
483
+ },
484
+ fetch: async (url: string) => {
485
+ fetchedUrl = url;
486
+ return { ok: true, json: async () => ({ mode: { state: 'active' } }) };
487
+ },
488
+ setInterval(callback: () => unknown) {
489
+ timers.push(callback);
490
+ return 1;
491
+ },
492
+ setTimeout(callback: () => unknown) {
493
+ callback();
494
+ return 1;
495
+ },
496
+ location: {
497
+ reload() {
498
+ reloads += 1;
499
+ },
500
+ },
501
+ } as { __cursorPoolIsPlatformModeActive?: () => boolean };
502
+ const fakeRequire = (moduleName: string) => {
503
+ if (moduleName === 'node:fs') {
504
+ return {
505
+ existsSync: () => true,
506
+ readFileSync: (path: string) =>
507
+ path.endsWith('runtime.json')
508
+ ? JSON.stringify({ host: '127.0.0.1', port: 61372, runtimeId: 'runtime-fetch-test' })
509
+ : JSON.stringify({ device: { status: 'inactive' } }),
510
+ };
511
+ }
512
+ if (moduleName === 'node:os') {
513
+ return { homedir: () => '/Users/tester' };
514
+ }
515
+ if (moduleName === 'node:path') {
516
+ return { join: (...parts: string[]) => parts.join('/') };
517
+ }
518
+ throw new Error(`unexpected module ${moduleName}`);
519
+ };
520
+
521
+ new Function('he', 'DGC', 'globalThis', 'require', 'process', `return ({${objectLiteral}});`)(
522
+ () => undefined,
523
+ {},
524
+ sandboxGlobal,
525
+ fakeRequire,
526
+ { env: {} },
527
+ );
528
+ await new Promise((resolve) => setTimeout(resolve, 0));
529
+
530
+ assert.equal(fetchedUrl, 'http://127.0.0.1:61372/platform/status');
531
+ assert.equal(values.get('cursorPoolPlatformModeActive'), '1');
532
+ assert.equal(sandboxGlobal.__cursorPoolIsPlatformModeActive?.(), true);
533
+ assert.equal(reloads, 1);
534
+ });
535
+
536
+ test('workbench platform-mode runtime guard falls back to the default local port without node require', async () => {
537
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
538
+ const markerStart = patched.indexOf(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE);
539
+ const objectStart = patched.lastIndexOf('get when()', markerStart);
540
+ const objectEnd = patched.indexOf('get fallback()', markerStart) + 'get fallback(){return he(DGC,{})}'.length;
541
+ const objectLiteral = patched.slice(objectStart, objectEnd);
542
+ const values = new Map([['cursorPoolPlatformModeActive', '0']]);
543
+ let fetchedUrl = '';
544
+ let reloads = 0;
545
+ const sandboxGlobal = {
546
+ localStorage: {
547
+ getItem(key: string) {
548
+ return values.get(key) ?? null;
549
+ },
550
+ setItem(key: string, value: string) {
551
+ values.set(key, value);
552
+ },
553
+ },
554
+ fetch: async (url: string) => {
555
+ fetchedUrl = url;
556
+ return { ok: true, json: async () => ({ mode: { state: 'active' } }) };
557
+ },
558
+ setInterval() {
559
+ return 1;
560
+ },
561
+ setTimeout(callback: () => unknown) {
562
+ callback();
563
+ return 1;
564
+ },
565
+ location: {
566
+ reload() {
567
+ reloads += 1;
568
+ },
569
+ },
570
+ } as { __cursorPoolIsPlatformModeActive?: () => boolean };
571
+
572
+ new Script(`(({he,DGC,globalThis})=>({${objectLiteral}}))`).runInNewContext({
573
+ he: () => undefined,
574
+ DGC: {},
575
+ globalThis: sandboxGlobal,
576
+ })({ he: () => undefined, DGC: {}, globalThis: sandboxGlobal });
577
+ await new Promise((resolve) => setTimeout(resolve, 0));
578
+
579
+ assert.equal(fetchedUrl, 'http://127.0.0.1:56393/platform/status');
580
+ assert.equal(values.get('cursorPoolPlatformModeActive'), '1');
581
+ assert.equal(sandboxGlobal.__cursorPoolIsPlatformModeActive?.(), true);
582
+ assert.equal(reloads, 1);
583
+ });
584
+
585
+ test('workbench platform-mode runtime guard is renderer-safe without node require', () => {
586
+ const patched = injectCursorWorkbenchAuthGatePatch(workbenchFixture());
587
+ const markerStart = patched.indexOf(CURSOR_POOL_WORKBENCH_NATIVE_LOCAL_AGENT_SIGNATURE);
588
+ const objectStart = patched.lastIndexOf('get when()', markerStart);
589
+ const objectEnd = patched.indexOf('get fallback()', markerStart) + 'get fallback(){return he(DGC,{})}'.length;
590
+ const objectLiteral = patched.slice(objectStart, objectEnd);
591
+ const sandboxGlobal = {} as { __cursorPoolIsPlatformModeActive?: () => boolean };
592
+
593
+ new Script(`(({he,DGC,globalThis})=>({${objectLiteral}}))`).runInNewContext({
594
+ he: () => undefined,
595
+ DGC: {},
596
+ globalThis: sandboxGlobal,
597
+ })({ he: () => undefined, DGC: {}, globalThis: sandboxGlobal });
598
+
599
+ assert.equal(sandboxGlobal.__cursorPoolIsPlatformModeActive?.(), false);
600
+ });
601
+
602
+ test('workbench auth gate patch fails when the composer login anchor is missing', () => {
603
+ assert.throws(
604
+ () => injectCursorWorkbenchAuthGatePatch(workbenchFixture().replace(composerAuthGateAnchor, '')),
605
+ /composer auth gate anchor/,
606
+ );
607
+ });
608
+
609
+ test('workbench auth gate patch fails when the composer submit login anchor is missing', () => {
610
+ assert.throws(
611
+ () => injectCursorWorkbenchAuthGatePatch(workbenchFixture().replace(composerSubmitAuthGateAnchor, '')),
612
+ /composer submit auth gate anchor/,
613
+ );
614
+ });
615
+
616
+ test('workbench auth gate patch fails when the agent loop run anchor is missing', () => {
617
+ assert.throws(
618
+ () => injectCursorWorkbenchAuthGatePatch(workbenchFixture().replace(agentLoopRunAnchor, '')),
619
+ /agent loop run anchor/,
620
+ );
621
+ });
622
+
623
+ test('workbench auth gate patch fails when native local agent anchors are missing', () => {
624
+ assert.throws(
625
+ () => injectCursorWorkbenchAuthGatePatch(workbenchFixture().replace(buildFlagsLocalModeAnchor, '')),
626
+ /localMode build flag anchor/,
627
+ );
628
+ assert.throws(
629
+ () => injectCursorWorkbenchAuthGatePatch(workbenchFixture().replace(localProviderConfigAnchor, '')),
630
+ /local provider config anchor/,
631
+ );
632
+ assert.throws(
633
+ () => injectCursorWorkbenchAuthGatePatch(workbenchFixture().replace(agentClientRunLocalModeAnchor, '')),
634
+ /agent client run localMode anchor/,
635
+ );
636
+ });
637
+
638
+ test('patchCursorWorkbenchAuthGate writes a backup and marker', async () => {
639
+ const backupDir = join(tmpdir(), `cursor-pool-workbench-backups-${Date.now()}-${Math.random()}`);
640
+ const fixture = await createFixture();
641
+
642
+ try {
643
+ const beforeHash = await sha256File(fixture.targetPath);
644
+ const result = await patchCursorWorkbenchAuthGate(fixture.appPath, { backupDir });
645
+ const patchedContent = await readFile(fixture.targetPath, 'utf8');
646
+
647
+ assert.equal(result.targetPath, resolveCursorWorkbenchPath(fixture.appPath));
648
+ assert.equal(result.beforeHash, beforeHash);
649
+ assert.equal(result.afterHash, await sha256File(fixture.targetPath));
650
+ assert.equal(result.markerPresent, true);
651
+ assert.equal(containsCursorWorkbenchAuthGateMarker(patchedContent), true);
652
+ assert.equal(await readFile(result.backupPath, 'utf8'), await readFile(result.backupPath, 'utf8'));
653
+ } finally {
654
+ await rm(fixture.appPath, { recursive: true, force: true });
655
+ await rm(backupDir, { recursive: true, force: true });
656
+ }
657
+ });
658
+
659
+ test('patchCursorWorkbenchAuthGate supports Linux Cursor relative paths', async () => {
660
+ const base = await mkdtemp(join(tmpdir(), 'cursor-pool-workbench-linux-'));
661
+ const appPath = join(base, 'squashfs-root');
662
+ const linuxWorkbenchRelativePath =
663
+ 'usr/share/cursor/resources/app/out/vs/workbench/workbench.desktop.main.js';
664
+ const targetPath = join(appPath, linuxWorkbenchRelativePath);
665
+ const backupDir = join(tmpdir(), `cursor-pool-workbench-linux-backups-${Date.now()}-${Math.random()}`);
666
+
667
+ try {
668
+ await mkdir(join(appPath, 'usr/share/cursor/resources/app/out/vs/workbench'), {
669
+ recursive: true,
670
+ });
671
+ await writeFile(targetPath, workbenchFixture(), 'utf8');
672
+
673
+ assert.equal(resolveCursorWorkbenchPath(appPath, linuxWorkbenchRelativePath), targetPath);
674
+ const beforeHash = await sha256File(targetPath);
675
+ const result = await patchCursorWorkbenchAuthGate(appPath, {
676
+ backupDir,
677
+ targetRelativePath: linuxWorkbenchRelativePath,
678
+ });
679
+ const patchedContent = await readFile(targetPath, 'utf8');
680
+
681
+ assert.equal(result.targetPath, targetPath);
682
+ assert.equal(result.beforeHash, beforeHash);
683
+ assert.notEqual(result.afterHash, beforeHash);
684
+ assert.equal(containsCursorWorkbenchAuthGateMarker(patchedContent), true);
685
+ } finally {
686
+ await rm(base, { recursive: true, force: true });
687
+ await rm(backupDir, { recursive: true, force: true });
688
+ }
689
+ });
690
+
691
+ test('restoreCursorWorkbenchAuthGate returns patched target to original hash and removes marker', async () => {
692
+ const backupDir = join(tmpdir(), `cursor-pool-workbench-restore-${Date.now()}-${Math.random()}`);
693
+ const fixture = await createFixture();
694
+
695
+ try {
696
+ const beforeHash = await sha256File(fixture.targetPath);
697
+ const patch = await patchCursorWorkbenchAuthGate(fixture.appPath, { backupDir });
698
+ assert.equal(containsCursorWorkbenchAuthGateMarker(await readFile(fixture.targetPath, 'utf8')), true);
699
+
700
+ const restore = await restoreCursorWorkbenchAuthGate(fixture.appPath, { backupDir });
701
+
702
+ assert.equal(patch.beforeHash, beforeHash);
703
+ assert.equal(restore.beforeHash, patch.afterHash);
704
+ assert.equal(restore.afterHash, beforeHash);
705
+ assert.equal(containsCursorWorkbenchAuthGateMarker(await readFile(fixture.targetPath, 'utf8')), false);
706
+ } finally {
707
+ await rm(fixture.appPath, { recursive: true, force: true });
708
+ await rm(backupDir, { recursive: true, force: true });
709
+ }
710
+ });
711
+
712
+ test('restoreCursorWorkbenchAuthGate supports Linux Cursor relative paths', async () => {
713
+ const base = await mkdtemp(join(tmpdir(), 'cursor-pool-workbench-linux-restore-'));
714
+ const appPath = join(base, 'squashfs-root');
715
+ const linuxWorkbenchRelativePath =
716
+ 'usr/share/cursor/resources/app/out/vs/workbench/workbench.desktop.main.js';
717
+ const targetPath = join(appPath, linuxWorkbenchRelativePath);
718
+ const backupDir = join(tmpdir(), `cursor-pool-workbench-linux-restore-backups-${Date.now()}-${Math.random()}`);
719
+
720
+ try {
721
+ await mkdir(join(appPath, 'usr/share/cursor/resources/app/out/vs/workbench'), {
722
+ recursive: true,
723
+ });
724
+ await writeFile(targetPath, workbenchFixture(), 'utf8');
725
+ const beforeHash = await sha256File(targetPath);
726
+ await patchCursorWorkbenchAuthGate(appPath, {
727
+ backupDir,
728
+ targetRelativePath: linuxWorkbenchRelativePath,
729
+ });
730
+
731
+ const restore = await restoreCursorWorkbenchAuthGate(appPath, {
732
+ backupDir,
733
+ targetRelativePath: linuxWorkbenchRelativePath,
734
+ });
735
+
736
+ assert.equal(restore.targetPath, targetPath);
737
+ assert.equal(restore.afterHash, beforeHash);
738
+ assert.equal(containsCursorWorkbenchAuthGateMarker(await readFile(targetPath, 'utf8')), false);
739
+ } finally {
740
+ await rm(base, { recursive: true, force: true });
741
+ await rm(backupDir, { recursive: true, force: true });
742
+ }
743
+ });
744
+
745
+ test('restoreCursorWorkbenchAuthGate refuses a backup that contains auth gate marker text', async () => {
746
+ const backupDir = join(tmpdir(), `cursor-pool-workbench-bad-backup-${Date.now()}-${Math.random()}`);
747
+ const fixture = await createFixture();
748
+
749
+ try {
750
+ await patchCursorWorkbenchAuthGate(fixture.appPath, { backupDir });
751
+ const patchedHash = await sha256File(fixture.targetPath);
752
+ const backupPath = await backupPathForCursorWorkbenchAuthGate(
753
+ fixture.appPath,
754
+ fixture.targetPath,
755
+ backupDir,
756
+ );
757
+ await writeFile(backupPath, await readFile(fixture.targetPath, 'utf8'), 'utf8');
758
+
759
+ await assert.rejects(
760
+ restoreCursorWorkbenchAuthGate(fixture.appPath, { backupDir }),
761
+ /backup.*patch marker/i,
762
+ );
763
+
764
+ assert.equal(await sha256File(fixture.targetPath), patchedHash);
765
+ assert.equal(containsCursorWorkbenchAuthGateMarker(await readFile(fixture.targetPath, 'utf8')), true);
766
+ } finally {
767
+ await rm(fixture.appPath, { recursive: true, force: true });
768
+ await rm(backupDir, { recursive: true, force: true });
769
+ }
770
+ });