impel-cli 0.18.15-beta.7 → 0.18.15-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/docs/experimental-managed-cursor.md +1 -1
- package/package.json +1 -1
- package/src/apps.js +25 -12
- package/src/cursorLocal.js +10 -5
package/README.md
CHANGED
|
@@ -128,7 +128,7 @@ when a compatible version or commit changes. If Cursor changes any reviewed
|
|
|
128
128
|
local-agent, provider-priority, or model-transport source contract, Impel keeps
|
|
129
129
|
the previous managed generation intact and refuses the update until the patch is
|
|
130
130
|
reviewed. `experimental cursor open` performs this prepare step before every
|
|
131
|
-
launch. A real packaged GUI battle test proves that Cursor 3.
|
|
131
|
+
launch. A real packaged GUI battle test proves that Cursor 3.13.25 can run
|
|
132
132
|
Agent through the selected tenant's gateway with Cursor's own non-secret smoke
|
|
133
133
|
identity. The logical `default` model is resolved by the gateway to its
|
|
134
134
|
registered Cursor default; explicit gateway models continue to use Responses.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This hidden macOS experiment runs the stable Cursor desktop Agent against the
|
|
4
4
|
selected Impel tenant without a real Cursor account or Cursor-routed BYOK. It is
|
|
5
|
-
validated against Cursor 3.
|
|
5
|
+
validated against Cursor 3.13.25 and remains separate from the public
|
|
6
6
|
`impel setup` / `impel update` state machine:
|
|
7
7
|
|
|
8
8
|
```sh
|
package/package.json
CHANGED
package/src/apps.js
CHANGED
|
@@ -269,7 +269,7 @@ export const CURRENT_CONFIG_VERSION = 26;
|
|
|
269
269
|
// — which is what made every `impel update` re-trigger macOS permission
|
|
270
270
|
// prompts. Bump this ONLY when a code change alters the bytes of a built
|
|
271
271
|
// bundle; leave it alone for changes that don't touch bundle contents.
|
|
272
|
-
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-07-31.
|
|
272
|
+
export const BUNDLE_BUILD_FINGERPRINT = "bundle-2026-07-31.2";
|
|
273
273
|
|
|
274
274
|
/** Parse the tenant's install manifest, or null when absent/corrupt. */
|
|
275
275
|
export function readTenantManifest(homeDir = os.homedir(), tenantId = null) {
|
|
@@ -347,7 +347,7 @@ export function bundleIsCurrent(status, {
|
|
|
347
347
|
compatibility.vendorSignaturesPreserved === true
|
|
348
348
|
&& compatibility.resourceRoot === CHATGPT_RESOURCE_ROOT
|
|
349
349
|
&& compatibility.patches?.fastModeForGatewayAuth > 0
|
|
350
|
-
&& compatibility.patches?.tenantDisplayNamePreload ===
|
|
350
|
+
&& compatibility.patches?.tenantDisplayNamePreload === 2
|
|
351
351
|
)),
|
|
352
352
|
);
|
|
353
353
|
}
|
|
@@ -1772,7 +1772,7 @@ function writeVendoredChatGPTBundleLocked(paths, vendorPath, gatewayUrl, homeDir
|
|
|
1772
1772
|
patches: {
|
|
1773
1773
|
fastModeForGatewayAuth: fastModePatchCount,
|
|
1774
1774
|
desktopAPIForGatewayAuth: 0,
|
|
1775
|
-
tenantDisplayNamePreload:
|
|
1775
|
+
tenantDisplayNamePreload: 2,
|
|
1776
1776
|
},
|
|
1777
1777
|
vendorSignaturesPreserved: true,
|
|
1778
1778
|
resourceRoot: CHATGPT_RESOURCE_ROOT,
|
|
@@ -2299,6 +2299,7 @@ secure_codex_home
|
|
|
2299
2299
|
BROWSER_DATA=${shellQuote(paths.chatgpt.browserData)}
|
|
2300
2300
|
mkdir -p "$BROWSER_DATA"
|
|
2301
2301
|
export IMPEL_APP_DISPLAY_NAME=${shellQuote(paths.chatgpt.displayName)}
|
|
2302
|
+
export IMPEL_APP_BUNDLE_ID=${shellQuote(paths.chatgpt.bundleIdentifier)}
|
|
2302
2303
|
PRELOAD="$HERE/../Resources/impel-chatgpt-preload.cjs"
|
|
2303
2304
|
export NODE_OPTIONS="--require=\\\"$PRELOAD\\\""
|
|
2304
2305
|
# Electron resolves resources from the Impel wrapper when the nested app is
|
|
@@ -2313,13 +2314,14 @@ function vendoredChatGPTDisplayNamePreload() {
|
|
|
2313
2314
|
return `"use strict";
|
|
2314
2315
|
|
|
2315
2316
|
const displayName = process.env.IMPEL_APP_DISPLAY_NAME;
|
|
2316
|
-
|
|
2317
|
+
const bundleIdentifier = process.env.IMPEL_APP_BUNDLE_ID;
|
|
2318
|
+
if (process.type === "browser" && displayName && bundleIdentifier) {
|
|
2317
2319
|
const Module = require("node:module");
|
|
2318
2320
|
const path = require("node:path");
|
|
2319
2321
|
const load = Module._load;
|
|
2320
2322
|
let objc;
|
|
2321
2323
|
let appKit;
|
|
2322
|
-
let
|
|
2324
|
+
let launchServicesIdentified = false;
|
|
2323
2325
|
let activationPolicyRefreshed = false;
|
|
2324
2326
|
|
|
2325
2327
|
const loadNativeBridge = () => {
|
|
@@ -2331,20 +2333,31 @@ if (process.type === "browser" && displayName) {
|
|
|
2331
2333
|
return { objc, appKit };
|
|
2332
2334
|
};
|
|
2333
2335
|
|
|
2334
|
-
const
|
|
2335
|
-
if (
|
|
2336
|
+
const setLaunchServicesApplicationIdentity = () => {
|
|
2337
|
+
if (launchServicesIdentified) return;
|
|
2336
2338
|
try {
|
|
2337
2339
|
const native = loadNativeBridge();
|
|
2338
2340
|
new native.objc.NobjcLibrary(
|
|
2339
2341
|
"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices",
|
|
2340
2342
|
);
|
|
2341
2343
|
const title = native.appKit.NSString.stringWithUTF8String$(displayName);
|
|
2344
|
+
const identifier = native.appKit.NSString.stringWithUTF8String$(bundleIdentifier);
|
|
2342
2345
|
const info = native.appKit.NSMutableDictionary.dictionaryWithDictionary$(
|
|
2343
2346
|
native.appKit.NSBundle.mainBundle().infoDictionary(),
|
|
2344
2347
|
);
|
|
2345
2348
|
for (const key of ["CFBundleName", "CFBundleDisplayName"]) {
|
|
2346
2349
|
info.setObject$forKey$(title, native.appKit.NSString.stringWithUTF8String$(key));
|
|
2347
2350
|
}
|
|
2351
|
+
// The signed vendor executable runs from the nested ChatGPT.app, so
|
|
2352
|
+
// LaunchServices initially checks it in as com.openai.codex. When the
|
|
2353
|
+
// native app is also open, Dock groups both processes under ChatGPT even
|
|
2354
|
+
// though LSDisplayName was already tenant-branded. Check the process in
|
|
2355
|
+
// again with the unique outer-wrapper identity to keep each tenant's
|
|
2356
|
+
// Dock item distinct while preserving the vendor executable signature.
|
|
2357
|
+
info.setObject$forKey$(
|
|
2358
|
+
identifier,
|
|
2359
|
+
native.appKit.NSString.stringWithUTF8String$("CFBundleIdentifier"),
|
|
2360
|
+
);
|
|
2348
2361
|
native.objc.callFunction(
|
|
2349
2362
|
"_LSSetApplicationLaunchServicesServerConnectionStatus",
|
|
2350
2363
|
{ returns: "v", args: ["Q", "@"] },
|
|
@@ -2368,7 +2381,7 @@ if (process.type === "browser" && displayName) {
|
|
|
2368
2381
|
title,
|
|
2369
2382
|
null,
|
|
2370
2383
|
);
|
|
2371
|
-
|
|
2384
|
+
launchServicesIdentified = status === 0;
|
|
2372
2385
|
} catch {
|
|
2373
2386
|
// Keep the signed vendor app usable if LaunchServices changes this
|
|
2374
2387
|
// private-but-established process-title API in a future macOS release.
|
|
@@ -2403,7 +2416,7 @@ if (process.type === "browser" && displayName) {
|
|
|
2403
2416
|
const setName = loaded.app.setName.bind(loaded.app);
|
|
2404
2417
|
setName(displayName);
|
|
2405
2418
|
loaded.app.setName = () => setName(displayName);
|
|
2406
|
-
|
|
2419
|
+
setLaunchServicesApplicationIdentity();
|
|
2407
2420
|
setNativeApplicationMenuTitle();
|
|
2408
2421
|
const setApplicationMenu = loaded.Menu.setApplicationMenu.bind(loaded.Menu);
|
|
2409
2422
|
loaded.Menu.setApplicationMenu = (menu) => {
|
|
@@ -2414,11 +2427,11 @@ if (process.type === "browser" && displayName) {
|
|
|
2414
2427
|
loaded.app.setActivationPolicy("accessory");
|
|
2415
2428
|
setTimeout(() => {
|
|
2416
2429
|
loaded.app.setActivationPolicy("regular");
|
|
2417
|
-
|
|
2418
|
-
|
|
2430
|
+
launchServicesIdentified = false;
|
|
2431
|
+
setLaunchServicesApplicationIdentity();
|
|
2419
2432
|
setApplicationMenu(menu);
|
|
2420
2433
|
setNativeApplicationMenuTitle();
|
|
2421
|
-
},
|
|
2434
|
+
}, 100);
|
|
2422
2435
|
}
|
|
2423
2436
|
setTimeout(setNativeApplicationMenuTitle, 0);
|
|
2424
2437
|
return result;
|
package/src/cursorLocal.js
CHANGED
|
@@ -36,7 +36,7 @@ const CURSOR_VERIFIED_EXTENSIONS = Object.freeze([
|
|
|
36
36
|
|
|
37
37
|
const CURSOR_LOCAL_RUNTIME_FILE = "extensions/cursor-local-agent-runtime/dist/main.js";
|
|
38
38
|
const CURSOR_REASONING_TRANSPORT_DISABLED = 'void 0===a?(delete e.reasoning,delete e.reasoning_effort):"output_config.effort"===a.param?';
|
|
39
|
-
const CURSOR_REASONING_TRANSPORT_ENABLED = 'void 0===a?"responses"===o?(e.reasoning=Object.assign(Object.assign({},
|
|
39
|
+
const CURSOR_REASONING_TRANSPORT_ENABLED = 'void 0===a?"responses"===o?(e.reasoning=Object.assign(Object.assign({},qRt(e.reasoning)?e.reasoning:{}),{effort:i}),delete e.reasoning_effort):(delete e.reasoning,delete e.reasoning_effort):"output_config.effort"===a.param?';
|
|
40
40
|
const CURSOR_HELPER_BUNDLES = Object.freeze([
|
|
41
41
|
"Cursor Helper (GPU).app",
|
|
42
42
|
"Cursor Helper (Plugin).app",
|
|
@@ -47,8 +47,8 @@ const PRODUCT_FILE = "product.json";
|
|
|
47
47
|
const PACKAGE_FILE = "package.json";
|
|
48
48
|
const LOCAL_MODE_DISABLED = "localMode:!1";
|
|
49
49
|
const LOCAL_MODE_ENABLED = "localMode:!0";
|
|
50
|
-
const PERSONAL_DATA_IMPORT_GUARD = "if(!
|
|
51
|
-
const MANAGED_DATA_IMPORT_GUARD = "if(
|
|
50
|
+
const PERSONAL_DATA_IMPORT_GUARD = "if(!Ui.localMode)";
|
|
51
|
+
const MANAGED_DATA_IMPORT_GUARD = "if(Ui.localMode )";
|
|
52
52
|
const DISABLE_LIBRARY_VALIDATION_ENTITLEMENT = "com.apple.security.cs.disable-library-validation";
|
|
53
53
|
const DIRECT_PROVIDER_ENV_KEYS = Object.freeze([
|
|
54
54
|
"ANTHROPIC_API_KEY",
|
|
@@ -332,8 +332,13 @@ function assertLocalRuntimeContract(resourcesRoot) {
|
|
|
332
332
|
throw new Error(`Cursor local-agent runtime contract changed (missing ${missing.join(", ")}); review this update before use`);
|
|
333
333
|
}
|
|
334
334
|
const responseEndpointSelection = /\.includes\("responses"\)\|\|[^?]{0,120}\.includes\("openai_responses"\)\?"responses":/u;
|
|
335
|
-
const
|
|
336
|
-
|
|
335
|
+
const chatCompletionsEndpointSelection = /\.includes\("chat_completions"\)\|\|[^?]{0,120}\.includes\("openai_chat"\)\?"chat_completions":/u;
|
|
336
|
+
const anthropicApiTypeSelection = /\.includes\("anthropic_messages"\)&&![^?]{0,80}\?"anthropic_messages":"openai_compatible"/u;
|
|
337
|
+
if (
|
|
338
|
+
!responseEndpointSelection.test(runtime)
|
|
339
|
+
|| !chatCompletionsEndpointSelection.test(runtime)
|
|
340
|
+
|| !anthropicApiTypeSelection.test(runtime)
|
|
341
|
+
) {
|
|
337
342
|
throw new Error("Cursor local-agent Responses/model-picker contract changed; review this update before use");
|
|
338
343
|
}
|
|
339
344
|
if (countOccurrences(runtime, CURSOR_REASONING_TRANSPORT_DISABLED) !== 1) {
|