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/src/windowsApps.js
CHANGED
|
@@ -11,9 +11,10 @@ import { environmentValue, nativeCommandInvocation } from "./nativeProcess.js";
|
|
|
11
11
|
import { normalizeTenantId } from "./tenants.js";
|
|
12
12
|
import { brandedEnvironmentName, RUNTIME_BRAND } from "./runtimeBrand.js";
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
export const
|
|
16
|
-
export const
|
|
14
|
+
const WINDOWS_CHATGPT_PIN = PINNED_VENDOR_APPS.chatgpt.windows;
|
|
15
|
+
export const WINDOWS_CHATGPT_PACKAGE = WINDOWS_CHATGPT_PIN.storeProductId;
|
|
16
|
+
export const WINDOWS_CHATGPT_PACKAGE_NAME = WINDOWS_CHATGPT_PIN.packageName;
|
|
17
|
+
export const WINDOWS_CHATGPT_PUBLISHER_ID = WINDOWS_CHATGPT_PIN.publisherId;
|
|
17
18
|
const WINDOWS_CLAUDE_DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1000;
|
|
18
19
|
const WINDOWS_WINGET_UPDATE_NOT_APPLICABLE = 0x8A15002B;
|
|
19
20
|
|
|
@@ -60,20 +61,26 @@ function versionedSquirrelCandidates(root, readDirectory = fs.readdirSync) {
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
function installedMsixChatGPT(environment, run = spawnSync) {
|
|
64
|
+
function installedMsixChatGPT(environment, run = spawnSync, pin = null) {
|
|
64
65
|
const script = [
|
|
65
66
|
`$package = Get-AppxPackage -Name '${WINDOWS_CHATGPT_PACKAGE_NAME}' -ErrorAction SilentlyContinue`,
|
|
66
|
-
`$package = $package | Where-Object PublisherId -
|
|
67
|
+
`$package = $package | Where-Object { $_.PublisherId -ceq '${WINDOWS_CHATGPT_PUBLISHER_ID}' -and (-not $env:IMPEL_CHATGPT_PACKAGE_VERSION -or $_.Version.ToString() -ceq $env:IMPEL_CHATGPT_PACKAGE_VERSION) } | Sort-Object Version -Descending | Select-Object -First 1`,
|
|
67
68
|
"if ($package) {",
|
|
68
69
|
" $manifest = Get-AppxPackageManifest -Package $package",
|
|
69
70
|
" $relative = $manifest.Package.Applications.Application | Where-Object Id -eq 'App' | Select-Object -First 1 -ExpandProperty Executable",
|
|
70
|
-
"
|
|
71
|
+
" $normalized = ([string]$relative).Replace('/', '\\')",
|
|
72
|
+
" $expected = ([string]$env:IMPEL_CHATGPT_PACKAGE_EXECUTABLE).Replace('/', '\\')",
|
|
73
|
+
" if ($relative -and (-not $expected -or $normalized -ieq $expected)) { Join-Path $package.InstallLocation $relative }",
|
|
71
74
|
"}",
|
|
72
75
|
].join("; ");
|
|
73
76
|
try {
|
|
74
77
|
const result = run("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
75
78
|
encoding: "utf8",
|
|
76
|
-
env:
|
|
79
|
+
env: {
|
|
80
|
+
...windowsPowerShellEnvironment(environment),
|
|
81
|
+
IMPEL_CHATGPT_PACKAGE_VERSION: pin?.packageVersion || "",
|
|
82
|
+
IMPEL_CHATGPT_PACKAGE_EXECUTABLE: pin?.executable || "",
|
|
83
|
+
},
|
|
77
84
|
stdio: ["ignore", "pipe", "ignore"],
|
|
78
85
|
windowsHide: true,
|
|
79
86
|
});
|
|
@@ -141,9 +148,23 @@ export function findWindowsChatGPTApp(environment = process.env, dependencies =
|
|
|
141
148
|
return msix && exists(msix) ? path.win32.normalize(msix) : null;
|
|
142
149
|
}
|
|
143
150
|
|
|
144
|
-
function
|
|
151
|
+
function pinnedWindowsChatGPTApp(environment = process.env, dependencies = {}) {
|
|
152
|
+
const exists = dependencies.isFile || isFile;
|
|
153
|
+
const pin = dependencies.pin || WINDOWS_CHATGPT_PIN;
|
|
154
|
+
const msix = (dependencies.queryMsix || installedMsixChatGPT)(environment, dependencies.run, pin);
|
|
155
|
+
return msix && exists(msix) ? path.win32.normalize(msix) : null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function wingetInvocation(action, environment, {
|
|
159
|
+
packageId,
|
|
160
|
+
source = "winget",
|
|
161
|
+
scope = "user",
|
|
162
|
+
}) {
|
|
145
163
|
const verb = action === "update" ? "upgrade" : "install";
|
|
146
164
|
const scopeArgs = scope ? ["--scope", scope] : [];
|
|
165
|
+
// Microsoft Store packages commonly report Version "Unknown" to winget.
|
|
166
|
+
// Without this switch winget refuses to consider their available update.
|
|
167
|
+
const updateArgs = action === "update" ? ["--include-unknown"] : [];
|
|
147
168
|
return nativeCommandInvocation(
|
|
148
169
|
"winget",
|
|
149
170
|
[
|
|
@@ -154,6 +175,7 @@ function wingetInvocation(action, environment, { packageId, source = "winget", s
|
|
|
154
175
|
"--source",
|
|
155
176
|
source,
|
|
156
177
|
...scopeArgs,
|
|
178
|
+
...updateArgs,
|
|
157
179
|
"--silent",
|
|
158
180
|
"--disable-interactivity",
|
|
159
181
|
"--accept-package-agreements",
|
|
@@ -372,21 +394,32 @@ export async function ensureWindowsClaudeApp(_options = {}, dependencies = {}) {
|
|
|
372
394
|
|
|
373
395
|
/** Install/update OpenAI's official ChatGPT/Codex Store package. */
|
|
374
396
|
export function ensureWindowsChatGPTApp({ update = false } = {}, dependencies = {}) {
|
|
397
|
+
const find = dependencies.find || findWindowsChatGPTApp;
|
|
398
|
+
const findPinned = dependencies.findPinned || dependencies.find || pinnedWindowsChatGPTApp;
|
|
375
399
|
const io = {
|
|
376
400
|
environment: process.env,
|
|
377
|
-
find
|
|
401
|
+
find,
|
|
402
|
+
findPinned,
|
|
378
403
|
logger: console,
|
|
404
|
+
pin: WINDOWS_CHATGPT_PIN,
|
|
379
405
|
run: spawnSync,
|
|
380
406
|
...dependencies,
|
|
381
407
|
};
|
|
382
408
|
const before = io.find(io.environment);
|
|
383
|
-
|
|
409
|
+
const pinnedBefore = io.findPinned(io.environment, { pin: io.pin, run: io.run });
|
|
410
|
+
if (pinnedBefore && !update) {
|
|
411
|
+
return { binary: pinnedBefore, action: "existing", result: null };
|
|
412
|
+
}
|
|
384
413
|
|
|
385
|
-
// `impel update`
|
|
386
|
-
// be installed, not sent to
|
|
414
|
+
// `impel update` converges an older official Store package to the current
|
|
415
|
+
// reviewed pin. A missing Store package must be installed, not sent to
|
|
416
|
+
// `winget upgrade` (which returns 0x8A150014).
|
|
387
417
|
const shouldUpdate = Boolean(update && before);
|
|
418
|
+
// The msstore source rejects its AppX package version as a winget --version
|
|
419
|
+
// selector. Install the current Store package, then fail closed below unless
|
|
420
|
+
// Windows registered the exact reviewed package version and executable.
|
|
388
421
|
const invocation = wingetInvocation(shouldUpdate ? "update" : "install", io.environment, {
|
|
389
|
-
packageId:
|
|
422
|
+
packageId: io.pin.storeProductId,
|
|
390
423
|
source: "msstore",
|
|
391
424
|
scope: null,
|
|
392
425
|
});
|
|
@@ -400,26 +433,36 @@ export function ensureWindowsChatGPTApp({ update = false } = {}, dependencies =
|
|
|
400
433
|
} catch (error) {
|
|
401
434
|
result = { status: null, error };
|
|
402
435
|
}
|
|
403
|
-
|
|
436
|
+
let resultBinary = io.findPinned(io.environment, { pin: io.pin, run: io.run });
|
|
404
437
|
// winget uses an error HRESULT when `upgrade` finds an installed package
|
|
405
438
|
// with no newer Store release. That is a healthy idempotent update result,
|
|
406
439
|
// not an installation failure (APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE).
|
|
407
440
|
const alreadyUpToDate = Boolean(
|
|
408
441
|
shouldUpdate
|
|
409
|
-
&&
|
|
442
|
+
&& resultBinary
|
|
410
443
|
&& !result?.error
|
|
411
444
|
&& Number.isInteger(result?.status)
|
|
412
445
|
&& (result.status >>> 0) === WINDOWS_WINGET_UPDATE_NOT_APPLICABLE,
|
|
413
446
|
);
|
|
414
447
|
if (alreadyUpToDate) {
|
|
415
|
-
io.logger.log(
|
|
448
|
+
io.logger.log(`ChatGPT/Codex: Microsoft Store package ${io.pin.packageVersion} already up to date.`);
|
|
449
|
+
}
|
|
450
|
+
const commandSucceeded = (result?.status === 0 && !result?.error) || alreadyUpToDate;
|
|
451
|
+
if (commandSucceeded && !resultBinary) {
|
|
452
|
+
result = {
|
|
453
|
+
...result,
|
|
454
|
+
error: new Error(
|
|
455
|
+
`ChatGPT/Codex Store package ${io.pin.packageVersion} did not appear after winget completed`,
|
|
456
|
+
),
|
|
457
|
+
};
|
|
416
458
|
}
|
|
417
|
-
const succeeded =
|
|
459
|
+
const succeeded = commandSucceeded && Boolean(resultBinary);
|
|
460
|
+
if (!succeeded) resultBinary = null;
|
|
418
461
|
return {
|
|
419
|
-
binary,
|
|
462
|
+
binary: resultBinary,
|
|
420
463
|
action: alreadyUpToDate
|
|
421
464
|
? "existing"
|
|
422
|
-
: succeeded ? (shouldUpdate ? "updated" : "installed") :
|
|
465
|
+
: succeeded ? (shouldUpdate ? "updated" : "installed") : "install-failed",
|
|
423
466
|
result,
|
|
424
467
|
};
|
|
425
468
|
}
|
|
@@ -617,6 +660,7 @@ export function launchWindowsChatGPTApp(binary, {
|
|
|
617
660
|
"CODEX_AUTHAPI_BASE_URL",
|
|
618
661
|
"CODEX_ELECTRON_USER_DATA_PATH",
|
|
619
662
|
"CODEX_HOME",
|
|
663
|
+
"CODEX_SPARKLE_ENABLED",
|
|
620
664
|
"OPENAI_API_KEY",
|
|
621
665
|
"OPENAI_BASE_URL",
|
|
622
666
|
]);
|
|
@@ -625,6 +669,7 @@ export function launchWindowsChatGPTApp(binary, {
|
|
|
625
669
|
}
|
|
626
670
|
environment.CODEX_HOME = codexHome;
|
|
627
671
|
environment.CODEX_AUTHAPI_BASE_URL = `${gatewayUrl}/chatgpt_passthrough/backend-api`;
|
|
672
|
+
environment.CODEX_SPARKLE_ENABLED = "false";
|
|
628
673
|
// Codex Desktop resolves this before acquiring Electron's single-instance
|
|
629
674
|
// lock. Keep --user-data-dir below as a compatibility fallback for builds
|
|
630
675
|
// that predate the dedicated desktop override.
|
package/src/windowsSetup.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
nativeSpawnInvocation,
|
|
9
9
|
} from "./nativeProcess.js";
|
|
10
10
|
import { syncSkillsSafe } from "./skills.js";
|
|
11
|
+
import { PINNED_VENDOR_CLI_VERSIONS } from "./vendorCliVersions.js";
|
|
11
12
|
import { provisionWindowsGit } from "./windowsGit.js";
|
|
12
13
|
|
|
13
14
|
const POWERSHELL_ARGS = [
|
|
@@ -27,12 +28,14 @@ const POWERSHELL_ARGS = [
|
|
|
27
28
|
*/
|
|
28
29
|
export const WINDOWS_CLI_INSTALLERS = Object.freeze({
|
|
29
30
|
claude: Object.freeze({
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
version: PINNED_VENDOR_CLI_VERSIONS.claude,
|
|
32
|
+
command: `powershell -ExecutionPolicy Bypass -NoProfile -Command "& ([scriptblock]::Create((irm https://claude.ai/install.ps1))) '${PINNED_VENDOR_CLI_VERSIONS.claude}'"`,
|
|
33
|
+
script: `& ([scriptblock]::Create((Invoke-RestMethod -Uri 'https://claude.ai/install.ps1'))) '${PINNED_VENDOR_CLI_VERSIONS.claude}'`,
|
|
32
34
|
}),
|
|
33
35
|
codex: Object.freeze({
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
version: PINNED_VENDOR_CLI_VERSIONS.codex,
|
|
37
|
+
command: `powershell -ExecutionPolicy Bypass -NoProfile -Command "[Environment]::SetEnvironmentVariable('CODEX_NON_INTERACTIVE','1','Process'); & ([scriptblock]::Create((irm https://chatgpt.com/codex/install.ps1))) -Release '${PINNED_VENDOR_CLI_VERSIONS.codex}'"`,
|
|
38
|
+
script: `[Environment]::SetEnvironmentVariable('CODEX_NON_INTERACTIVE', '1', 'Process'); & ([scriptblock]::Create((Invoke-RestMethod -Uri 'https://chatgpt.com/codex/install.ps1'))) -Release '${PINNED_VENDOR_CLI_VERSIONS.codex}'`,
|
|
36
39
|
}),
|
|
37
40
|
});
|
|
38
41
|
|