impel-cli 0.18.15 → 0.18.16
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 +55 -0
- package/docs/experimental-managed-cursor.md +205 -0
- package/package.json +2 -1
- package/src/apps.js +213 -43
- package/src/commands/apps.js +43 -8
- package/src/commands/converge.js +18 -3
- package/src/commands/cursorExperimental.js +192 -0
- package/src/commands/experimental.js +8 -2
- package/src/commands/launch.js +11 -2
- package/src/commands/status.js +3 -2
- package/src/commands/update.js +23 -11
- package/src/cursorLocal.js +1554 -0
- package/src/macSetup.js +20 -38
- package/src/provisioning.js +10 -4
- package/src/skills.js +24 -8
- package/src/updates.js +57 -10
- package/src/vendorCliBinaries.js +121 -0
- package/src/vendorCliVersions.js +7 -0
- package/src/windowsApps.js +64 -19
- package/src/windowsSetup.js +7 -4
package/README.md
CHANGED
|
@@ -98,8 +98,58 @@ Names include the tenant, such as `Impel Claude (Acme)` and
|
|
|
98
98
|
`Impel ChatGPT (Acme)`. The selected CLI tenant does not affect which tenant an
|
|
99
99
|
app opens. Tenant variants can remain installed side by side.
|
|
100
100
|
|
|
101
|
+
Impel-managed apps do not run the vendors' in-app auto-updaters. The generated
|
|
102
|
+
Claude policy disables its updater, and the ChatGPT launcher disables Sparkle
|
|
103
|
+
before starting the pinned app. Run `impel update` to move managed apps to the
|
|
104
|
+
next exact vendor builds reviewed and shipped with the CLI. This does not
|
|
105
|
+
change the update settings of native personal Claude or ChatGPT installations.
|
|
106
|
+
|
|
101
107
|
Linux does not have managed desktop apps. Use the isolated CLI commands there.
|
|
102
108
|
|
|
109
|
+
## Experimental managed Cursor
|
|
110
|
+
|
|
111
|
+
On macOS, a hidden experiment can prepare an isolated Cursor runtime for the
|
|
112
|
+
selected Impel tenant:
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
impel experimental cursor prepare
|
|
116
|
+
impel experimental cursor open [workspace]
|
|
117
|
+
impel experimental cursor status
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The experiment never modifies `/Applications/Cursor.app` or the native Cursor
|
|
121
|
+
profile. It verifies the installed stable app's Developer ID signature, mirrors
|
|
122
|
+
it into the selected tenant's Impel-managed directory, enables Cursor's bundled
|
|
123
|
+
local-agent runtime with fail-closed fixed-width patches, verifies extension
|
|
124
|
+
integrity and signing, and prepares a tenant-only home, user-data directory,
|
|
125
|
+
and extension directory. Cursor's local-mode profile-import service is disabled
|
|
126
|
+
so it cannot inspect or copy the native Cursor profile. The managed bundle
|
|
127
|
+
recomputes Cursor's signed-source checksum table after its reviewed patches, and
|
|
128
|
+
the launcher uses Cursor's process-lifetime secret store because no persistent
|
|
129
|
+
Cursor account or provider secret belongs in this tenant runtime.
|
|
130
|
+
|
|
131
|
+
The native Cursor installation continues to update through Cursor. Every
|
|
132
|
+
`prepare` inspects it again and atomically rebuilds the managed copy
|
|
133
|
+
when a compatible version or commit changes. If Cursor changes any reviewed
|
|
134
|
+
local-agent, provider-priority, or model-transport source contract, Impel keeps
|
|
135
|
+
the previous managed generation intact and refuses the update until the patch is
|
|
136
|
+
reviewed. `experimental cursor open` performs this prepare step before every
|
|
137
|
+
launch. A real packaged GUI battle test proves that Cursor 3.13.25 can run
|
|
138
|
+
Agent through the selected tenant's gateway with Cursor's own non-secret smoke
|
|
139
|
+
identity. The logical `default` model is resolved by the gateway to its
|
|
140
|
+
registered Cursor default; explicit gateway models continue to use Responses.
|
|
141
|
+
|
|
142
|
+
This is not complete hosted-Cursor parity or an offline Cursor.
|
|
143
|
+
The managed local transport supports Agent chat, edits, terminal tools, MCP,
|
|
144
|
+
vision, reasoning, and gateway model discovery, and projects the live tenant
|
|
145
|
+
catalog into Cursor's model picker, but the current vendor build explicitly
|
|
146
|
+
disables hosted-only features such as Tab completion, cloud Background Agents,
|
|
147
|
+
shared chats/canvases, Bugbot, and server-side repository indexing in local
|
|
148
|
+
mode. Enabling those paths would either send work to Cursor-hosted models or
|
|
149
|
+
require additional unpublished Cursor protocols, so the experiment does not
|
|
150
|
+
claim or silently emulate them. See
|
|
151
|
+
[`docs/experimental-managed-cursor.md`](docs/experimental-managed-cursor.md).
|
|
152
|
+
|
|
103
153
|
## Use the CLI
|
|
104
154
|
|
|
105
155
|
Select the tenant used by CLI launches:
|
|
@@ -179,6 +229,11 @@ impel update --no-recovery # disable recovery for this run
|
|
|
179
229
|
schema verified by that CLI. It does not mean cloning an untested moving vendor
|
|
180
230
|
release.
|
|
181
231
|
|
|
232
|
+
Stable installations follow npm's `latest` tag. Prerelease installations made
|
|
233
|
+
from `impel-cli@next` remain on the `next` channel during `impel update`. If npm
|
|
234
|
+
metadata is temporarily unavailable, update preserves the installed CLI build
|
|
235
|
+
and continues tenant reconciliation without attempting a downgrade.
|
|
236
|
+
|
|
182
237
|
## Status and diagnosis
|
|
183
238
|
|
|
184
239
|
```sh
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Experimental managed Cursor
|
|
2
|
+
|
|
3
|
+
This hidden macOS experiment runs the stable Cursor desktop Agent against the
|
|
4
|
+
selected Impel tenant without a real Cursor account or Cursor-routed BYOK. It is
|
|
5
|
+
validated against Cursor 3.13.25 and remains separate from the public
|
|
6
|
+
`impel setup` / `impel update` state machine:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
impel experimental cursor prepare
|
|
10
|
+
impel experimental cursor status
|
|
11
|
+
impel experimental cursor open [workspace-or-Cursor-args...]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Why standard BYOK is insufficient
|
|
15
|
+
|
|
16
|
+
Cursor's supported BYOK mode still sends provider keys and requests through
|
|
17
|
+
Cursor's backend, applies only to chat models, and keeps Tab on Cursor-hosted
|
|
18
|
+
models. It cannot provide direct, tenant-scoped Impel inference.
|
|
19
|
+
|
|
20
|
+
The stable desktop bundle also contains a dormant local-agent runtime with
|
|
21
|
+
OpenAI Responses, Chat Completions, Anthropic Messages, `/models` discovery,
|
|
22
|
+
tools, streaming, reasoning, vision, and MCP support. Impel enables only the
|
|
23
|
+
exact reviewed local-mode signatures and locks provider resolution to its
|
|
24
|
+
process environment.
|
|
25
|
+
|
|
26
|
+
## Managed authentication
|
|
27
|
+
|
|
28
|
+
Cursor's packaged Agent UI considers a user logged in only when both an access
|
|
29
|
+
token and refresh token exist. The same stable bundle contains an unconditional
|
|
30
|
+
test command that creates:
|
|
31
|
+
|
|
32
|
+
- an unsigned JWT with issuer `cursor-smoke-test`, audience `cursor`, and
|
|
33
|
+
scope `smoke-test`;
|
|
34
|
+
- the literal refresh token `fake-refresh-token-for-testing`.
|
|
35
|
+
|
|
36
|
+
Impel reproduces that vendor-owned, non-secret identity in the tenant-only
|
|
37
|
+
`state.vscdb` and also passes the JWT through Cursor's
|
|
38
|
+
`--override-cursor-auth-token` process flag. It never asks for, reads, or
|
|
39
|
+
stores a real Cursor credential. The source markers, storage keys, JWT contract,
|
|
40
|
+
and command-line flags are part of the fail-closed vendor compatibility check.
|
|
41
|
+
|
|
42
|
+
The fake identity unlocks the local Agent UI. Cursor-hosted account, model,
|
|
43
|
+
analytics, and hosted-feature requests remain unauthenticated and cannot use
|
|
44
|
+
the fake token for service access. The Impel PAT-derived tenant credential is
|
|
45
|
+
given only to the bundled local provider:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
CURSOR_LOCAL_AGENT_BASE_URL=<gateway>/experimental/openai/v1
|
|
49
|
+
CURSOR_LOCAL_AGENT_API_KEY=<tenant-scoped Impel credential>
|
|
50
|
+
IMPEL_TENANT_ID=<tenant>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Update and isolation contract
|
|
54
|
+
|
|
55
|
+
For every prepare or open, Impel:
|
|
56
|
+
|
|
57
|
+
1. Finds the installed stable `Cursor.app`.
|
|
58
|
+
2. Verifies its complete Apple signature, Cursor bundle identifier, and vendor
|
|
59
|
+
Developer ID team.
|
|
60
|
+
3. Reads the exact version and commit from `product.json`.
|
|
61
|
+
4. Verifies every reviewed local-mode, authentication, provider-priority,
|
|
62
|
+
model-transport, and profile-import source contract.
|
|
63
|
+
5. Verifies Cursor's extension-integrity table, then updates exactly the hashes
|
|
64
|
+
affected by the reviewed fixed-width patches.
|
|
65
|
+
6. Recomputes Cursor's `product.json` checksum table after every reviewed
|
|
66
|
+
managed patch, so Cursor's own installation-integrity service verifies the
|
|
67
|
+
resulting managed bundle.
|
|
68
|
+
7. Assigns a tenant-specific packaged application name and uses tenant-only
|
|
69
|
+
`HOME`, XDG, user-data, and extension roots. This isolates Cursor's
|
|
70
|
+
hardcoded `~/.cursor` agents, rules, plugins, worktrees, and logs in addition
|
|
71
|
+
to the normal VS Code profile state.
|
|
72
|
+
8. Disables local-mode personal-data import so the managed app cannot inspect,
|
|
73
|
+
copy, or relaunch from the native Cursor profile.
|
|
74
|
+
9. Clears inherited OpenAI, Anthropic, Google, AWS/Bedrock, Azure OpenAI,
|
|
75
|
+
Cursor, Node, Electron, and portable-profile overrides.
|
|
76
|
+
10. Uses Cursor's built-in process-lifetime secret store. The managed runtime
|
|
77
|
+
has no real Cursor login or persistent provider key, while its gateway
|
|
78
|
+
bearer remains process-scoped in the launch environment.
|
|
79
|
+
11. Re-signs every Electron process bundle with the reviewed entitlements and
|
|
80
|
+
verifies the complete managed copy.
|
|
81
|
+
12. Atomically replaces the tenant generation only after every check passes.
|
|
82
|
+
|
|
83
|
+
Tenant state lives below:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
~/.config/impel/apps/tenants/<tenant>/cursor/
|
|
87
|
+
runtime/current/Cursor.app
|
|
88
|
+
runtime/current/manifest.json
|
|
89
|
+
home/
|
|
90
|
+
user-data/
|
|
91
|
+
extensions/
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The launcher rejects user-supplied `--user-data-dir`, `--extensions-dir`,
|
|
95
|
+
and `--override-cursor-auth-token`. The native Cursor profile and the
|
|
96
|
+
operator's `~/.cursor`, `~/.claude`, and `~/.codex` roots are never read or
|
|
97
|
+
modified. The isolated `HOME` means shell, Git, and extension state that
|
|
98
|
+
normally lives in a home directory must be configured separately for this
|
|
99
|
+
tenant runtime.
|
|
100
|
+
|
|
101
|
+
The managed copy disables self-updates. The signed native installation remains
|
|
102
|
+
Cursor's update authority, and every `open` re-runs `prepare`, adopting a
|
|
103
|
+
compatible stable vendor update immediately. If an update changes any reviewed
|
|
104
|
+
contract, Impel preserves the previous generation and refuses the new build
|
|
105
|
+
until its compatibility signatures and tests are reviewed.
|
|
106
|
+
|
|
107
|
+
## Gateway contract
|
|
108
|
+
|
|
109
|
+
The gateway must enable `IMPEL_EXPERIMENTAL_CROSS_APP_MODELS` and serve:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
GET /experimental/openai/v1/models
|
|
113
|
+
POST /experimental/openai/v1/chat/completions
|
|
114
|
+
POST /experimental/openai/v1/responses
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Cursor 3.12 initially submits Agent turns with its logical model `default`
|
|
118
|
+
over Chat Completions, independently of the discovered catalog. The gateway
|
|
119
|
+
maps that alias only on the experimental Cursor route to the exact registered
|
|
120
|
+
Cursor default (`gpt-5.6-sol` today). Bifrost then performs its typed
|
|
121
|
+
Chat-to-Responses conversion, including streaming response conversion, tools,
|
|
122
|
+
reasoning, and multimodal messages. The converted request follows the normal
|
|
123
|
+
pooled Codex path with `store:false`, tenant attribution, usage metering, and
|
|
124
|
+
server-owned provider authentication.
|
|
125
|
+
|
|
126
|
+
Explicit local-provider model requests can use Responses directly. The
|
|
127
|
+
authenticated catalog is filtered by PAT scopes and live tenant pool readiness
|
|
128
|
+
and advertises tools, streaming, reasoning, vision, context, modalities, and
|
|
129
|
+
both protocol markers required by Cursor's bundled parser.
|
|
130
|
+
|
|
131
|
+
Reasoning effort is a per-model, per-selection parameter rather than a global
|
|
132
|
+
Cursor setting. The gateway catalog owns each model's allowed levels and
|
|
133
|
+
default. Impel projects those values into Cursor's `Reasoning` selector, and the
|
|
134
|
+
local Responses transport sends the selected value as `reasoning.effort`.
|
|
135
|
+
Bifrost then converts that typed field for the selected Codex or Claude
|
|
136
|
+
subscription provider. Models that advertise no reasoning levels receive no
|
|
137
|
+
effort selector.
|
|
138
|
+
|
|
139
|
+
## Battle-test result and parity boundary
|
|
140
|
+
|
|
141
|
+
The gated packaged-GUI contract now proves all of the following against the
|
|
142
|
+
real signed stable app and patched managed copy:
|
|
143
|
+
|
|
144
|
+
- the native Cursor profile is unreadable and its sentinel remains unchanged;
|
|
145
|
+
- the onboarding and hosted-login wall are absent;
|
|
146
|
+
- the real `agent-exec` and local-agent runtime extensions activate;
|
|
147
|
+
- authenticated `GET /models` reaches the loopback gateway;
|
|
148
|
+
- the tenant catalog is reconciled into Cursor's named-model picker without
|
|
149
|
+
overwriting non-Impel model preferences;
|
|
150
|
+
- a real Agent submission sends `model: "default"` to Chat Completions with
|
|
151
|
+
the tenant bearer;
|
|
152
|
+
- the unique streamed gateway result is rendered in the Agent UI;
|
|
153
|
+
- no personal provider credential or native profile is used.
|
|
154
|
+
|
|
155
|
+
The direct runtime contract separately proves model discovery and a Responses
|
|
156
|
+
stream with the intended model and bearer.
|
|
157
|
+
|
|
158
|
+
The gateway conversion contract separately pins tool-call IDs across the next
|
|
159
|
+
turn's tool result, fragmented parallel argument streams, reasoning deltas,
|
|
160
|
+
`tool_calls` termination, vision input, and `store:false` after conversion.
|
|
161
|
+
|
|
162
|
+
| Cursor surface | Managed local mode |
|
|
163
|
+
| --- | --- |
|
|
164
|
+
| Editor, terminal, source control, extensions | Retained with tenant-isolated state |
|
|
165
|
+
| Agent chat, edits, terminal tools, MCP | Works through the Impel gateway |
|
|
166
|
+
| Streaming, reasoning, vision, tool calls | Preserved by Cursor and Bifrost's typed conversion |
|
|
167
|
+
| Model selection | Gateway owns `default`; concrete tenant models are projected into Cursor's named-model picker |
|
|
168
|
+
| Tab completion | Unavailable; Cursor disables CPP/Tab in local mode |
|
|
169
|
+
| Cloud Background Agents | Unavailable; hosted Cursor service |
|
|
170
|
+
| Shared chats/canvases, Bugbot, code tour | Unavailable; hosted Cursor services |
|
|
171
|
+
| Server-side repository indexing/search | Unavailable; hosted Cursor service |
|
|
172
|
+
|
|
173
|
+
This provides direct Impel inference for the local Agent with normal Cursor
|
|
174
|
+
editor updates. It cannot provide complete hosted-Cursor parity because Tab,
|
|
175
|
+
cloud agents, collaboration, Bugbot, and hosted indexing use unpublished
|
|
176
|
+
Cursor services rather than the bundled local-provider protocol. The app may
|
|
177
|
+
still contact Cursor domains for updates, extensions, and unavailable hosted
|
|
178
|
+
features; model inference is the gateway-owned boundary.
|
|
179
|
+
|
|
180
|
+
The tenant gateway bearer is process-scoped because Cursor's current local
|
|
181
|
+
provider contract resolves it from the launch environment. Treat extensions
|
|
182
|
+
installed into this isolated Cursor profile as trusted: a same-user extension
|
|
183
|
+
or process can inspect or reuse that gateway-only bearer. A short-lived,
|
|
184
|
+
route-bound desktop capability would be a future hardening, but it is not part
|
|
185
|
+
of the current PAT contract.
|
|
186
|
+
|
|
187
|
+
## Validation
|
|
188
|
+
|
|
189
|
+
The ordinary suite uses fake bundles and credentials. Validate the installed
|
|
190
|
+
stable bundle and the direct local-provider transport with:
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
IMPEL_VALIDATE_INSTALLED_CURSOR_LOCAL=1 node --test --test-name-pattern='installed stable Cursor' test/cursor-local.test.js
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The packaged GUI battle test uses only a disposable HOME, user-data directory,
|
|
197
|
+
extension directory, workspace, process-lifetime secret store, loopback HTTP
|
|
198
|
+
server, and loopback debugger:
|
|
199
|
+
|
|
200
|
+
```sh
|
|
201
|
+
IMPEL_VALIDATE_INSTALLED_CURSOR_GUI=1 node --test --test-name-pattern='managed Cursor GUI' test/cursor-local.test.js
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Neither test reads or writes the operator's native Cursor profile or uses live
|
|
205
|
+
provider credentials.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "impel-cli",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.16",
|
|
4
4
|
"description": "Prepare isolated Claude and Codex workspaces for every accessible Impel tenant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"bin",
|
|
15
|
+
"docs/experimental-managed-cursor.md",
|
|
15
16
|
"src",
|
|
16
17
|
"README.md"
|
|
17
18
|
],
|