@cats-inc/cats-platform 0.2.8 → 0.3.5
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 +25 -1
- package/build/desktop/bootstrapPage.d.ts.map +1 -1
- package/build/desktop/bootstrapPage.js +26 -129
- package/build/desktop/bootstrapPage.js.map +1 -1
- package/build/desktop/cliInventoryProbe.d.ts +6 -0
- package/build/desktop/cliInventoryProbe.d.ts.map +1 -1
- package/build/desktop/cliInventoryProbe.js +6 -3
- package/build/desktop/cliInventoryProbe.js.map +1 -1
- package/build/desktop/contracts.d.ts +2 -0
- package/build/desktop/contracts.d.ts.map +1 -1
- package/build/desktop/contracts.js.map +1 -1
- package/build/desktop/main.js +95 -41
- package/build/desktop/main.js.map +1 -1
- package/build/desktop/preload.cjs +8 -6
- package/build/desktop/preload.cjs.map +1 -1
- package/build/desktop/providerManager.d.ts +46 -0
- package/build/desktop/providerManager.d.ts.map +1 -0
- package/build/desktop/providerManager.js +220 -0
- package/build/desktop/providerManager.js.map +1 -0
- package/build/desktop/providerSelection.d.ts +1 -0
- package/build/desktop/providerSelection.d.ts.map +1 -1
- package/build/desktop/providerSelection.js +7 -1
- package/build/desktop/providerSelection.js.map +1 -1
- package/build/desktop/setupAssets.d.ts.map +1 -1
- package/build/desktop/setupAssets.js +12 -0
- package/build/desktop/setupAssets.js.map +1 -1
- package/build/desktop/setupAudit.d.ts +3 -1
- package/build/desktop/setupAudit.d.ts.map +1 -1
- package/build/desktop/setupAudit.js +12 -8
- package/build/desktop/setupAudit.js.map +1 -1
- package/build/desktop/setupBridge.js +1 -1
- package/build/desktop/setupBridge.js.map +1 -1
- package/build/desktop/setupPrerequisites.d.ts +11 -0
- package/build/desktop/setupPrerequisites.d.ts.map +1 -0
- package/build/desktop/setupPrerequisites.js +47 -0
- package/build/desktop/setupPrerequisites.js.map +1 -0
- package/build/renderer/assets/ActiveSessionPermissionChip-BugyYoVY.js +1 -0
- package/build/renderer/assets/{App-BZA23O2J.js → App-1MFRMMld.js} +1 -1
- package/build/renderer/assets/{App-YqprEL2n.js → App-BWgnfutX.js} +1 -1
- package/build/renderer/assets/{App-rGw9J8PZ.js → App-Cm_tok6f.js} +1 -1
- package/build/renderer/assets/{WorkspaceAppRoutes-BCHCikmJ.js → WorkspaceAppRoutes-B8U5FWao.js} +1 -1
- package/build/renderer/assets/app-CqnsY5ed.css +1 -0
- package/build/renderer/assets/app-DTDTNtih.js +85 -0
- package/build/renderer/assets/{client-BdGHAUoK.js → client-DREGSZqQ.js} +1 -1
- package/build/renderer/assets/conversationSidebarRecentEntries-y_bEg3Cp.js +6 -0
- package/build/renderer/assets/{screenshotOverlay-DfBcolX-.js → screenshotOverlay-EF07cXvw.js} +1 -1
- package/build/renderer/assets/{useDraftSessionChips-D9BX6X92.js → useDraftSessionChips-BD6ZGG_y.js} +1 -1
- package/build/renderer/desktop/overlay/index.html +2 -2
- package/build/renderer/index.html +3 -3
- package/build/server/app/renderer/auth/api.d.ts.map +1 -1
- package/build/server/app/renderer/auth/api.js +4 -1
- package/build/server/app/renderer/auth/api.js.map +1 -1
- package/build/server/app/renderer/providerCatalogClient.d.ts.map +1 -1
- package/build/server/app/renderer/providerCatalogClient.js +19 -6
- package/build/server/app/renderer/providerCatalogClient.js.map +1 -1
- package/build/server/app/renderer/providerClientInvalidation.d.ts +6 -0
- package/build/server/app/renderer/providerClientInvalidation.d.ts.map +1 -0
- package/build/server/app/renderer/providerClientInvalidation.js +12 -0
- package/build/server/app/renderer/providerClientInvalidation.js.map +1 -0
- package/build/server/app/renderer/providerReadLoop.d.ts +5 -0
- package/build/server/app/renderer/providerReadLoop.d.ts.map +1 -0
- package/build/server/app/renderer/providerReadLoop.js +52 -0
- package/build/server/app/renderer/providerReadLoop.js.map +1 -0
- package/build/server/app/renderer/providerRegistryClient.d.ts +2 -1
- package/build/server/app/renderer/providerRegistryClient.d.ts.map +1 -1
- package/build/server/app/renderer/providerRegistryClient.js +33 -17
- package/build/server/app/renderer/providerRegistryClient.js.map +1 -1
- package/build/server/app/server/authGatePolicy.js +7 -0
- package/build/server/app/server/authGatePolicy.js.map +1 -1
- package/build/server/app/server/shutdown.d.ts.map +1 -1
- package/build/server/app/server/shutdown.js +3 -1
- package/build/server/app/server/shutdown.js.map +1 -1
- package/build/server/app/server/startup.d.ts +4 -3
- package/build/server/app/server/startup.d.ts.map +1 -1
- package/build/server/app/server/startup.js +8 -0
- package/build/server/app/server/startup.js.map +1 -1
- package/build/server/app/server/subscribeRoutes.d.ts.map +1 -1
- package/build/server/app/server/subscribeRoutes.js +5 -3
- package/build/server/app/server/subscribeRoutes.js.map +1 -1
- package/build/server/design/components/providerModelFieldsSupport.d.ts +2 -21
- package/build/server/design/components/providerModelFieldsSupport.d.ts.map +1 -1
- package/build/server/design/components/providerModelFieldsSupport.js +32 -36
- package/build/server/design/components/providerModelFieldsSupport.js.map +1 -1
- package/build/server/design/components/useProviderCatalogState.d.ts +1 -2
- package/build/server/design/components/useProviderCatalogState.d.ts.map +1 -1
- package/build/server/design/components/useProviderCatalogState.js +71 -152
- package/build/server/design/components/useProviderCatalogState.js.map +1 -1
- package/build/server/design/components/useProviderModelFieldActions.js +2 -2
- package/build/server/design/components/useProviderModelFieldActions.js.map +1 -1
- package/build/server/design/components/useProviderRegistryState.d.ts +1 -7
- package/build/server/design/components/useProviderRegistryState.d.ts.map +1 -1
- package/build/server/design/components/useProviderRegistryState.js +41 -91
- package/build/server/design/components/useProviderRegistryState.js.map +1 -1
- package/build/server/design/components/useProviderTargetReconciliation.d.ts +1 -0
- package/build/server/design/components/useProviderTargetReconciliation.d.ts.map +1 -1
- package/build/server/design/components/useProviderTargetReconciliation.js +1 -1
- package/build/server/design/components/useProviderTargetReconciliation.js.map +1 -1
- package/build/server/index.js +30 -0
- package/build/server/index.js.map +1 -1
- package/build/server/platform/orchestration/entitySubscriptions/channel.d.ts +2 -1
- package/build/server/platform/orchestration/entitySubscriptions/channel.d.ts.map +1 -1
- package/build/server/platform/orchestration/entitySubscriptions/channel.js +3 -18
- package/build/server/platform/orchestration/entitySubscriptions/channel.js.map +1 -1
- package/build/server/platform/orchestration/entitySubscriptions/index.d.ts +1 -0
- package/build/server/platform/orchestration/entitySubscriptions/index.d.ts.map +1 -1
- package/build/server/platform/orchestration/entitySubscriptions/index.js.map +1 -1
- package/build/server/products/chat/api/routeSupport.d.ts +9 -1
- package/build/server/products/chat/api/routeSupport.d.ts.map +1 -1
- package/build/server/products/chat/api/routeSupport.js +22 -0
- package/build/server/products/chat/api/routeSupport.js.map +1 -1
- package/build/server/products/chat/state/model/readModels.d.ts +1 -0
- package/build/server/products/chat/state/model/readModels.d.ts.map +1 -1
- package/build/server/products/chat/state/model/readModels.js +2 -1
- package/build/server/products/chat/state/model/readModels.js.map +1 -1
- package/build/server/products/shared/renderer/api/appShell.d.ts +1 -0
- package/build/server/products/shared/renderer/api/appShell.d.ts.map +1 -1
- package/build/server/products/shared/renderer/api/appShell.js +9 -0
- package/build/server/products/shared/renderer/api/appShell.js.map +1 -1
- package/build/server/runtime/client.d.ts.map +1 -1
- package/build/server/runtime/client.js +5 -1
- package/build/server/runtime/client.js.map +1 -1
- package/build/server/runtime/setup.d.ts +4 -0
- package/build/server/runtime/setup.d.ts.map +1 -1
- package/build/server/runtime/setup.js +3 -1
- package/build/server/runtime/setup.js.map +1 -1
- package/build/server/server/routes/providers.d.ts.map +1 -1
- package/build/server/server/routes/providers.js +21 -50
- package/build/server/server/routes/providers.js.map +1 -1
- package/build/server/shared/cliInteraction.d.ts +17 -0
- package/build/server/shared/cliInteraction.d.ts.map +1 -0
- package/build/server/shared/cliInteraction.js +102 -0
- package/build/server/shared/cliInteraction.js.map +1 -0
- package/build/server/shared/desktopRecoveryBridge.d.ts +2 -1
- package/build/server/shared/desktopRecoveryBridge.d.ts.map +1 -1
- package/build/server/shared/desktopRecoveryBridge.js.map +1 -1
- package/build/server/shared/providerCatalogData.d.ts +168 -96
- package/build/server/shared/providerCatalogData.d.ts.map +1 -1
- package/build/server/shared/providerCatalogData.js +68 -42
- package/build/server/shared/providerCatalogData.js.map +1 -1
- package/build/server/shared/providerRegistryWarnings.d.ts +4 -0
- package/build/server/shared/providerRegistryWarnings.d.ts.map +1 -1
- package/build/server/shared/providerRegistryWarnings.js +7 -0
- package/build/server/shared/providerRegistryWarnings.js.map +1 -1
- package/package.json +13 -6
- package/packages/provider-setup/manager.d.ts +79 -0
- package/packages/provider-setup/manager.js +441 -0
- package/scripts/README.md +23 -0
- package/scripts/build-desktop-installer.mjs +124 -16
- package/scripts/dev-server.mjs +4 -1
- package/scripts/linux/install-github-cli.sh +5 -0
- package/scripts/linux/install-node.sh +9 -3
- package/scripts/linux/node-cli-common.sh +87 -48
- package/scripts/linux/provider-cli-common.sh +80 -105
- package/scripts/linux/provider-version-common.sh +247 -0
- package/scripts/linux/test-linux-package-smoke.sh +2 -0
- package/scripts/linux/verified-npm-update.sh +20 -0
- package/scripts/macos/install-github-cli.sh +5 -0
- package/scripts/macos/install-node.sh +9 -3
- package/scripts/macos/node-cli-common.sh +87 -48
- package/scripts/macos/provider-cli-common.sh +80 -105
- package/scripts/macos/provider-version-common.sh +247 -0
- package/scripts/macos/test-macos-package-smoke.sh +2 -0
- package/scripts/macos/verified-npm-update.sh +20 -0
- package/scripts/testing/conversation-navigation-smoke-electron.cjs +134 -0
- package/scripts/testing/conversation-navigation-smoke-renderer.tsx +102 -0
- package/scripts/testing/conversation-navigation-smoke.mjs +67 -0
- package/scripts/validate-release-assets.mjs +4 -1
- package/scripts/windows/Install-Antigravity.ps1 +26 -3
- package/scripts/windows/Install-ClaudeCode.ps1 +25 -7
- package/scripts/windows/Install-CursorAgent.ps1 +45 -30
- package/scripts/windows/Install-Devin.ps1 +16 -47
- package/scripts/windows/Install-GitHubCli.ps1 +4 -0
- package/scripts/windows/Install-Goose.ps1 +18 -1
- package/scripts/windows/Install-Grok.ps1 +14 -1
- package/scripts/windows/Install-Junie.ps1 +32 -11
- package/scripts/windows/Install-KiroCli.ps1 +37 -13
- package/scripts/windows/Install-MetaCli.ps1 +8 -1
- package/scripts/windows/Install-Node.ps1 +6 -1
- package/scripts/windows/Setup-NodeGlobalPrefix.ps1 +10 -0
- package/scripts/windows/Test-WindowsInstallerSmoke.ps1 +2 -0
- package/scripts/windows/_HiddenProcess.ps1 +14 -3
- package/scripts/windows/_NativeInstallerSupport.ps1 +308 -0
- package/scripts/windows/_NpmCliInstaller.ps1 +35 -14
- package/scripts/windows/_PackagedUninstall.ps1 +9 -1
- package/scripts/windows/_VerifiedNpmUpdate.ps1 +25 -0
- package/build/renderer/assets/ActiveSessionPermissionChip-CAgN-tXv.js +0 -1
- package/build/renderer/assets/app-BV3UAQkR.css +0 -1
- package/build/renderer/assets/app-CVPqqfZo.js +0 -45
- package/build/renderer/assets/conversationSidebarRecentEntries-iqaLqA1n.js +0 -6
- package/build/server/app/renderer/settings/runtimeLifecycleHelpers.d.ts +0 -48
- package/build/server/app/renderer/settings/runtimeLifecycleHelpers.d.ts.map +0 -1
- package/build/server/app/renderer/settings/runtimeLifecycleHelpers.js +0 -535
- package/build/server/app/renderer/settings/runtimeLifecycleHelpers.js.map +0 -1
- package/build/server/design/components/useProviderRegistryAutoRecheck.d.ts +0 -13
- package/build/server/design/components/useProviderRegistryAutoRecheck.d.ts.map +0 -1
- package/build/server/design/components/useProviderRegistryAutoRecheck.js +0 -70
- package/build/server/design/components/useProviderRegistryAutoRecheck.js.map +0 -1
- package/build/server/products/shared/renderer/api/providerCatalogRefreshStore.d.ts +0 -19
- package/build/server/products/shared/renderer/api/providerCatalogRefreshStore.d.ts.map +0 -1
- package/build/server/products/shared/renderer/api/providerCatalogRefreshStore.js +0 -53
- package/build/server/products/shared/renderer/api/providerCatalogRefreshStore.js.map +0 -1
- package/build/server/products/shared/renderer/api/providers.d.ts +0 -17
- package/build/server/products/shared/renderer/api/providers.d.ts.map +0 -1
- package/build/server/products/shared/renderer/api/providers.js +0 -50
- package/build/server/products/shared/renderer/api/providers.js.map +0 -1
|
@@ -43,6 +43,7 @@ param(
|
|
|
43
43
|
[switch]$Apply,
|
|
44
44
|
[switch]$Upgrade,
|
|
45
45
|
[switch]$Force,
|
|
46
|
+
[switch]$DryRun,
|
|
46
47
|
[switch]$Json,
|
|
47
48
|
[switch]$AllowAdmin,
|
|
48
49
|
[ValidateSet('auto', 'installed', 'missing')]
|
|
@@ -55,6 +56,7 @@ Set-StrictMode -Version Latest
|
|
|
55
56
|
$ErrorActionPreference = 'Stop'
|
|
56
57
|
|
|
57
58
|
. (Join-Path $PSScriptRoot '_HiddenProcess.ps1')
|
|
59
|
+
. (Join-Path $PSScriptRoot '_NativeInstallerSupport.ps1')
|
|
58
60
|
|
|
59
61
|
function Write-StructuredResult {
|
|
60
62
|
param(
|
|
@@ -62,6 +64,10 @@ function Write-StructuredResult {
|
|
|
62
64
|
[int]$ExitCode
|
|
63
65
|
)
|
|
64
66
|
|
|
67
|
+
if (Get-Variable -Name catsInitialObservation -Scope Script -ErrorAction SilentlyContinue) {
|
|
68
|
+
Add-CatsNativeObservation -Result $Result -Before $script:catsInitialObservation -Attempted ([bool]$script:shouldInstall) -Skipped ([bool]$SkipInstaller)
|
|
69
|
+
}
|
|
70
|
+
|
|
65
71
|
if ($Json) {
|
|
66
72
|
$Result | ConvertTo-Json -Depth 10
|
|
67
73
|
} else {
|
|
@@ -86,7 +92,11 @@ function Write-StructuredResult {
|
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
function Resolve-KiroExecutablePath {
|
|
89
|
-
|
|
95
|
+
$perUser = Join-Path $env:LOCALAPPDATA 'Kiro-Cli\kiro-cli.exe'
|
|
96
|
+
$machine = Join-Path $env:ProgramFiles 'Kiro-Cli\kiro-cli.exe'
|
|
97
|
+
if (Test-Path -LiteralPath $perUser -PathType Leaf) { return $perUser }
|
|
98
|
+
if (Test-Path -LiteralPath $machine -PathType Leaf) { return $machine }
|
|
99
|
+
return $perUser
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
function Refresh-UserPath {
|
|
@@ -145,12 +155,8 @@ function Invoke-KiroInstaller {
|
|
|
145
155
|
}
|
|
146
156
|
}
|
|
147
157
|
|
|
148
|
-
$installScript = Invoke-RestMethod 'https://cli.kiro.dev/install.ps1'
|
|
149
|
-
Invoke-
|
|
150
|
-
|
|
151
|
-
return [pscustomobject]@{
|
|
152
|
-
skipped = $false
|
|
153
|
-
}
|
|
158
|
+
$installScript = Invoke-RestMethod -TimeoutSec 30 -UseBasicParsing 'https://cli.kiro.dev/install.ps1'
|
|
159
|
+
return Invoke-CatsRemoteInstaller -ScriptText $installScript
|
|
154
160
|
}
|
|
155
161
|
|
|
156
162
|
if (-not $CheckOnly -and -not $Apply -and -not $Upgrade -and -not $Force) {
|
|
@@ -205,9 +211,26 @@ if ($CheckOnly) {
|
|
|
205
211
|
Write-StructuredResult -Result $result -ExitCode 0
|
|
206
212
|
}
|
|
207
213
|
|
|
214
|
+
if ($DryRun) {
|
|
215
|
+
Write-CatsNativePreview -Helper 'windows-kiro-native-installer' -Mode $executionMode -Detected $detected -Actions $plannedActions.ToArray() -EmitJson ([bool]$Json)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
$installFailed = $false
|
|
219
|
+
$catsInitialObservation = $detected.PSObject.Copy()
|
|
208
220
|
$shouldInstall = $Force -or $Upgrade -or -not $detected.installed
|
|
221
|
+
if ($Upgrade -and -not $Force -and $detected.installed -and -not $SkipInstaller -and -not $installFailed) {
|
|
222
|
+
$versionGate = Test-CatsNativeUpgrade -Provider 'kiro' -InstalledVersion $detected.detectedVersion
|
|
223
|
+
$shouldInstall = $versionGate.shouldInstall
|
|
224
|
+
if (-not $versionGate.known) { $warnings.Add('Could not compare the published version; the official installer will verify the update.') }
|
|
225
|
+
if (-not $shouldInstall) { $plannedActions.Clear() }
|
|
226
|
+
}
|
|
227
|
+
$installFailed = $false
|
|
209
228
|
if ($shouldInstall) {
|
|
210
|
-
$installResult = Invoke-KiroInstaller
|
|
229
|
+
$installResult = try { Invoke-KiroInstaller } catch { [pscustomobject]@{ skipped = $false; success = $false; stderr = [string]$_.Exception.Message; usedPowerShell51Fallback = $false; usedWingetFallback = $false } }
|
|
230
|
+
if ($installResult.PSObject.Properties['success'] -and -not $installResult.success) {
|
|
231
|
+
$installFailed = $true
|
|
232
|
+
$warnings.Add($installResult.stderr)
|
|
233
|
+
}
|
|
211
234
|
if ($installResult.skipped) {
|
|
212
235
|
$warnings.Add('Installer invocation was skipped by request.')
|
|
213
236
|
}
|
|
@@ -215,8 +238,9 @@ if ($shouldInstall) {
|
|
|
215
238
|
Start-Sleep -Seconds 3
|
|
216
239
|
Refresh-UserPath
|
|
217
240
|
$detected = Detect-KiroInstall
|
|
218
|
-
if (-not $detected.installed -and -not $SkipInstaller) {
|
|
219
|
-
|
|
241
|
+
if (-not $detected.installed -and -not $SkipInstaller -and -not $installFailed) {
|
|
242
|
+
$warnings.Add('Kiro CLI installation completed but kiro-cli was still not detected.')
|
|
243
|
+
$installFailed = $true
|
|
220
244
|
}
|
|
221
245
|
|
|
222
246
|
if ($Force) {
|
|
@@ -232,7 +256,7 @@ $interruptions = [System.Collections.Generic.List[object]]::new()
|
|
|
232
256
|
if ($shouldInstall) {
|
|
233
257
|
$interruptions.Add([pscustomobject]@{
|
|
234
258
|
kind = 'relaunch_required'
|
|
235
|
-
summary = '
|
|
259
|
+
summary = 'Run Detect Again after the Kiro CLI install step if the command is not visible yet.'
|
|
236
260
|
resumable = $true
|
|
237
261
|
requiresRestart = $false
|
|
238
262
|
requiresElevation = $false
|
|
@@ -242,7 +266,7 @@ if ($shouldInstall) {
|
|
|
242
266
|
$result = [pscustomobject]@{
|
|
243
267
|
helper = 'windows-kiro-native-installer'
|
|
244
268
|
mode = $executionMode
|
|
245
|
-
status = if ($interruptions.Count -gt 0) { [string]$interruptions[0].kind } else { 'ready' }
|
|
269
|
+
status = if ($installFailed) { 'failed' } elseif ($interruptions.Count -gt 0) { [string]$interruptions[0].kind } else { 'ready' }
|
|
246
270
|
installed = [bool]$detected.installed
|
|
247
271
|
detectedVersion = if ($detected.detectedVersion) { $detected.detectedVersion } else { $null }
|
|
248
272
|
commandPath = $detected.commandPath
|
|
@@ -253,4 +277,4 @@ $result = [pscustomobject]@{
|
|
|
253
277
|
manualSteps = $manualSteps.ToArray()
|
|
254
278
|
interruptions = $interruptions.ToArray()
|
|
255
279
|
}
|
|
256
|
-
Write-StructuredResult -Result $result -ExitCode 0
|
|
280
|
+
Write-StructuredResult -Result $result -ExitCode $(if ($installFailed) { 1 } else { 0 })
|
|
@@ -42,6 +42,7 @@ Set-StrictMode -Version Latest
|
|
|
42
42
|
$ErrorActionPreference = 'Stop'
|
|
43
43
|
|
|
44
44
|
. (Join-Path $PSScriptRoot '_HiddenProcess.ps1')
|
|
45
|
+
. (Join-Path $PSScriptRoot '_NativeInstallerSupport.ps1')
|
|
45
46
|
. (Join-Path $PSScriptRoot '_PackagedUninstall.ps1')
|
|
46
47
|
|
|
47
48
|
function Write-StructuredResult {
|
|
@@ -50,6 +51,10 @@ function Write-StructuredResult {
|
|
|
50
51
|
[int]$ExitCode
|
|
51
52
|
)
|
|
52
53
|
|
|
54
|
+
if (Get-Variable -Name catsInitialObservation -Scope Script -ErrorAction SilentlyContinue) {
|
|
55
|
+
Add-CatsNativeObservation -Result $Result -Before $script:catsInitialObservation -Attempted ([bool]$script:shouldInstall) -Skipped ([bool]$SkipInstaller)
|
|
56
|
+
}
|
|
57
|
+
|
|
53
58
|
if ($Json) {
|
|
54
59
|
$Result | ConvertTo-Json -Depth 10
|
|
55
60
|
} else {
|
|
@@ -364,6 +369,8 @@ if ($CheckOnly) {
|
|
|
364
369
|
}) -ExitCode 0
|
|
365
370
|
}
|
|
366
371
|
|
|
372
|
+
$installFailed = $false
|
|
373
|
+
$catsInitialObservation = $detected.PSObject.Copy()
|
|
367
374
|
$shouldInstall = $Force -or $Upgrade -or -not $detected.installed
|
|
368
375
|
$installFailed = $false
|
|
369
376
|
$installSkipped = $false
|
|
@@ -423,7 +430,7 @@ $interruptions = [System.Collections.Generic.List[object]]::new()
|
|
|
423
430
|
if ($shouldInstall -and -not $installFailed -and -not $DryRun) {
|
|
424
431
|
$interruptions.Add([pscustomobject]@{
|
|
425
432
|
kind = 'relaunch_required'
|
|
426
|
-
summary = '
|
|
433
|
+
summary = 'Run Detect Again after the Meta Muse install step if the command is not visible yet.'
|
|
427
434
|
resumable = $true
|
|
428
435
|
requiresRestart = $false
|
|
429
436
|
requiresElevation = $false
|
|
@@ -155,7 +155,8 @@ function Test-NodeInstalled {
|
|
|
155
155
|
return $false
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
return [bool](Get-Command node -ErrorAction SilentlyContinue)
|
|
158
|
+
return [bool](Get-Command node -ErrorAction SilentlyContinue) -and
|
|
159
|
+
[bool](Get-Command npm -ErrorAction SilentlyContinue)
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
if (-not $CheckOnly -and -not $Apply -and -not $Upgrade -and -not $Force) {
|
|
@@ -180,6 +181,10 @@ $mode = if ($CheckOnly) {
|
|
|
180
181
|
'apply'
|
|
181
182
|
}
|
|
182
183
|
|
|
184
|
+
# Each invocation inherits the long-lived Desktop host's environment. Include
|
|
185
|
+
# newly installed system/user commands before check-only detection as well.
|
|
186
|
+
$env:Path = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' +
|
|
187
|
+
[System.Environment]::GetEnvironmentVariable('Path', 'User') + ';' + $env:Path
|
|
183
188
|
$installed = Test-NodeInstalled -Mode $mode
|
|
184
189
|
$detected = Get-NodeDetectedVersion -Override $DetectedVersion
|
|
185
190
|
$commandPath = if ($SkipNodeProbe) { '' } else { Resolve-NodeCommandPath }
|
|
@@ -215,6 +215,16 @@ if (-not $SkipNodeCheck) {
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
if (-not $PSBoundParameters.ContainsKey('DesiredPrefix') -and $prefixProbe) {
|
|
219
|
+
$existingPrefix = [IO.Path]::GetFullPath($prefixProbe)
|
|
220
|
+
$userRoot = [IO.Path]::GetFullPath($UserHome).TrimEnd('\') + '\'
|
|
221
|
+
$npmrc = if ($env:NPM_CONFIG_USERCONFIG) { $env:NPM_CONFIG_USERCONFIG } else { Join-Path $UserHome '.npmrc' }
|
|
222
|
+
$explicitPrefix = $env:NPM_CONFIG_PREFIX -or ((Test-Path -LiteralPath $npmrc -PathType Leaf) -and
|
|
223
|
+
(Select-String -LiteralPath $npmrc -Pattern '^\s*prefix\s*=' -Quiet))
|
|
224
|
+
if ($explicitPrefix -or $existingPrefix.StartsWith($userRoot, [StringComparison]::OrdinalIgnoreCase)) {
|
|
225
|
+
$desiredPrefixPath = $existingPrefix
|
|
226
|
+
}
|
|
227
|
+
}
|
|
218
228
|
$pathEntries = Get-PathEntries -PathValue $pathProbe
|
|
219
229
|
$needsDirectory = -not (Test-Path -LiteralPath $desiredPrefixPath -PathType Container)
|
|
220
230
|
$needsPrefixUpdate = (Normalize-PathValue -Path $prefixProbe).ToLowerInvariant() -ne
|
|
@@ -190,6 +190,8 @@ $requiredFiles = @(
|
|
|
190
190
|
@{ Path = (Join-Path $resourcesRoot 'cats-runtime\config\providers.yaml.example'); Label = 'bundled cats-runtime provider config example' },
|
|
191
191
|
@{ Path = (Join-Path $resourcesRoot 'cats-runtime\config\curated-model-catalogs.yaml.example'); Label = 'bundled cats-runtime curated model catalog example' },
|
|
192
192
|
@{ Path = (Join-Path $resourcesRoot 'cats-runtime\node_modules\playwright-core\package.json'); Label = 'bundled cats-runtime external dependency marker' },
|
|
193
|
+
@{ Path = (Join-Path $resourcesRoot 'desktop\setup-assets\windows\_NativeInstallerSupport.ps1'); Label = 'bundled native version/installer support' },
|
|
194
|
+
@{ Path = (Join-Path $resourcesRoot 'desktop\setup-assets\windows\_VerifiedNpmUpdate.ps1'); Label = 'bundled verified npm update support' },
|
|
193
195
|
@{ Path = (Join-Path $resourcesRoot 'desktop\setup-assets\windows\Install-Node.ps1'); Label = 'bundled Windows Node.js LTS host installer' },
|
|
194
196
|
@{ Path = (Join-Path $resourcesRoot 'desktop\setup-assets\windows\Install-GitHubCli.ps1'); Label = 'bundled Windows GitHub CLI host installer' },
|
|
195
197
|
@{ Path = (Join-Path $resourcesRoot 'desktop\setup-assets\windows\Setup-NodeGlobalPrefix.ps1'); Label = 'bundled Windows npm prefix helper' },
|
|
@@ -15,7 +15,8 @@ function Invoke-HiddenCommand {
|
|
|
15
15
|
[Parameter(Mandatory)]
|
|
16
16
|
[string]$FileName,
|
|
17
17
|
|
|
18
|
-
[string[]]$ArgumentList = @()
|
|
18
|
+
[string[]]$ArgumentList = @(),
|
|
19
|
+
[int]$TimeoutMs = 0
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
|
@@ -36,9 +37,19 @@ function Invoke-HiddenCommand {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
$proc = [System.Diagnostics.Process]::Start($psi)
|
|
39
|
-
$
|
|
40
|
-
$
|
|
40
|
+
$outputTask = $proc.StandardOutput.ReadToEndAsync()
|
|
41
|
+
$errorTask = $proc.StandardError.ReadToEndAsync()
|
|
42
|
+
if ($TimeoutMs -gt 0 -and -not $proc.WaitForExit($TimeoutMs)) {
|
|
43
|
+
# taskkill /T works in Windows PowerShell 5.1 as well as PowerShell 7;
|
|
44
|
+
# Process.Kill(true) is unavailable in the former. Only this owned tree is killed.
|
|
45
|
+
$null = Invoke-HiddenCommand -FileName (Join-Path $env:SystemRoot 'System32\taskkill.exe') -ArgumentList @('/PID', [string]$proc.Id, '/T', '/F')
|
|
46
|
+
if (-not $proc.HasExited) { $proc.Kill() }
|
|
47
|
+
$proc.WaitForExit()
|
|
48
|
+
return [pscustomobject]@{ ExitCode = -1; Output = ''; ErrorOutput = 'Command timed out.' }
|
|
49
|
+
}
|
|
41
50
|
$proc.WaitForExit()
|
|
51
|
+
$output = $outputTask.GetAwaiter().GetResult()
|
|
52
|
+
$errorOutput = $errorTask.GetAwaiter().GetResult()
|
|
42
53
|
|
|
43
54
|
return [pscustomobject]@{
|
|
44
55
|
ExitCode = $proc.ExitCode
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Shared native installer version gates, isolated child execution and observed results.
|
|
4
|
+
.DESCRIPTION
|
|
5
|
+
Dot-source from the packaged native helpers. Metadata parsing is adapted from
|
|
6
|
+
environment-bootstrap at 752dc13; no query occurs during check-only actions.
|
|
7
|
+
Vendor scripts execute in a hidden child so an upstream exit cannot end our JSON response.
|
|
8
|
+
.EXAMPLE
|
|
9
|
+
. "$PSScriptRoot\_NativeInstallerSupport.ps1"
|
|
10
|
+
Test-CatsNativeUpgrade -Provider grok -InstalledVersion '1.0.0'
|
|
11
|
+
#>
|
|
12
|
+
. (Join-Path $PSScriptRoot '_HiddenProcess.ps1')
|
|
13
|
+
|
|
14
|
+
function Get-CatsNativeLatestVersion {
|
|
15
|
+
param([string]$Provider)
|
|
16
|
+
try {
|
|
17
|
+
switch ($Provider) {
|
|
18
|
+
antigravity { return Get-AntigravityLatestVersion }
|
|
19
|
+
cursor { return Get-CursorAgentLatestVersion -InstallerText (Invoke-RestMethod 'https://cursor.com/install?win32=true' -TimeoutSec 20 -UseBasicParsing) }
|
|
20
|
+
junie { return Get-JunieLatestBuild }
|
|
21
|
+
devin { return Get-DevinLatestVersion }
|
|
22
|
+
grok { return Get-GrokLatestVersion }
|
|
23
|
+
kiro { return [string](Invoke-RestMethod 'https://prod.download.cli.kiro.dev/stable/latest/manifest.json' -TimeoutSec 20 -UseBasicParsing).version }
|
|
24
|
+
goose { return [string](Invoke-RestMethod 'https://api.github.com/repos/aaif-goose/goose/releases/latest' -TimeoutSec 20 -UseBasicParsing -Headers @{ 'User-Agent' = 'Cats-Desktop'; Accept = 'application/vnd.github+json' }).tag_name }
|
|
25
|
+
default { return $null }
|
|
26
|
+
}
|
|
27
|
+
} catch { return $null }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function Get-CatsNativeVersionToken {
|
|
31
|
+
param([string]$Provider, [string]$Version)
|
|
32
|
+
if ($Provider -eq 'junie') {
|
|
33
|
+
$match = [regex]::Match($Version, '\((\d+(?:\.\d+)+)\)')
|
|
34
|
+
if ($match.Success) { return $match.Groups[1].Value }
|
|
35
|
+
return ''
|
|
36
|
+
}
|
|
37
|
+
return [regex]::Match($Version, '\d+(?:\.\d+)+(?:-[a-zA-Z0-9.]+)?').Value
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function Test-CatsNativeUpgrade {
|
|
41
|
+
param([string]$Provider, [string]$InstalledVersion, [AllowNull()][string]$LatestVersion = $null)
|
|
42
|
+
if (-not $PSBoundParameters.ContainsKey('LatestVersion')) { $LatestVersion = Get-CatsNativeLatestVersion $Provider }
|
|
43
|
+
$current = Get-CatsNativeVersionToken $Provider $InstalledVersion
|
|
44
|
+
$comparison = Compare-ToolVersion -Installed $current -Latest $LatestVersion
|
|
45
|
+
$known = $null -ne $comparison
|
|
46
|
+
$currentRelease = $known -and ($comparison -ge 0)
|
|
47
|
+
if ($Provider -eq 'cursor' -and $comparison -eq 0 -and $current -ne $LatestVersion) { $currentRelease = $false }
|
|
48
|
+
return [pscustomobject]@{ shouldInstall = -not $currentRelease; latestVersion = $LatestVersion; known = $known }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function Invoke-CatsRemoteInstaller {
|
|
52
|
+
param([Parameter(Mandatory)][string]$ScriptText, [switch]$RetrySharingViolation)
|
|
53
|
+
$temporary = Join-Path ([System.IO.Path]::GetTempPath()) ('cats-native-' + [guid]::NewGuid().ToString('N') + '.ps1')
|
|
54
|
+
try {
|
|
55
|
+
if ([string]::IsNullOrWhiteSpace($ScriptText)) { throw 'Vendor returned an empty installer.' }
|
|
56
|
+
$ast = [System.Management.Automation.Language.Parser]::ParseInput($ScriptText, [ref]$null, [ref]$null)
|
|
57
|
+
$offsets = @(0)
|
|
58
|
+
if ($ast.ParamBlock) { $offsets += $ast.ParamBlock.Extent.EndOffset }
|
|
59
|
+
foreach ($usingStatement in $ast.UsingStatements) { $offsets += $usingStatement.Extent.EndOffset }
|
|
60
|
+
$offset = ($offsets | Measure-Object -Maximum).Maximum
|
|
61
|
+
$prologue = '$env:PSModulePath = (@([System.Environment]::GetEnvironmentVariable(''PSModulePath'',''User''), [System.Environment]::GetEnvironmentVariable(''PSModulePath'',''Machine''), (Join-Path $PSHOME ''Modules'')) | Where-Object { $_ }) -join '';'''
|
|
62
|
+
$body = $ScriptText.Insert($offset, "`n$prologue`n")
|
|
63
|
+
if ($RetrySharingViolation) {
|
|
64
|
+
$encoded = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($body))
|
|
65
|
+
$body = @'
|
|
66
|
+
$ErrorActionPreference = 'Stop'
|
|
67
|
+
$installer = [scriptblock]::Create([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('__SOURCE__')))
|
|
68
|
+
for ($attempt = 1; $attempt -le 3; $attempt++) {
|
|
69
|
+
try { & $installer; exit 0 }
|
|
70
|
+
catch {
|
|
71
|
+
$exception = $_.Exception
|
|
72
|
+
while ($exception.InnerException) { $exception = $exception.InnerException }
|
|
73
|
+
if ($attempt -eq 3 -or -not ($exception -is [IO.IOException]) -or ($exception.HResult -band 0xffff) -ne 32) { throw }
|
|
74
|
+
Start-Sleep -Seconds 5
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
'@
|
|
78
|
+
$body = $body.Replace('__SOURCE__', $encoded)
|
|
79
|
+
}
|
|
80
|
+
[IO.File]::WriteAllText($temporary, $body, [Text.UTF8Encoding]::new($true))
|
|
81
|
+
$hostExe = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe'
|
|
82
|
+
$result = Invoke-HiddenCommand -FileName $hostExe -ArgumentList @('-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', $temporary)
|
|
83
|
+
return [pscustomobject]@{ skipped = $false; success = $result.ExitCode -eq 0; exitCode = $result.ExitCode; stderr = $result.ErrorOutput; stdout = $result.Output }
|
|
84
|
+
} catch {
|
|
85
|
+
return [pscustomobject]@{ skipped = $false; success = $false; exitCode = -1; stderr = [string]$_.Exception.Message }
|
|
86
|
+
} finally {
|
|
87
|
+
# This is one uniquely-created file; never recursively remove a computed directory.
|
|
88
|
+
Remove-Item -LiteralPath $temporary -Force -ErrorAction SilentlyContinue
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function Add-CatsNativeObservation {
|
|
93
|
+
param([pscustomobject]$Result, [AllowNull()]$Before, [bool]$Attempted, [bool]$Skipped)
|
|
94
|
+
if ($Result.mode -in @('check', 'uninstall') -or $null -eq $Before) { return }
|
|
95
|
+
$change = if ($Result.status -eq 'failed') { 'failed' }
|
|
96
|
+
elseif ($Skipped -or $Result.status -eq 'preview' -or -not $Attempted) { 'unchanged' }
|
|
97
|
+
elseif (-not $Result.installed) { 'failed' }
|
|
98
|
+
elseif (-not $Before.installed) { 'installed' }
|
|
99
|
+
elseif ($Before.detectedVersion -and $Result.detectedVersion -and $Before.detectedVersion -ne $Result.detectedVersion) {
|
|
100
|
+
$comparison = Compare-ToolVersion -Installed $Result.detectedVersion -Latest $Before.detectedVersion
|
|
101
|
+
if ($comparison -gt 0) { 'upgraded' } elseif ($comparison -lt 0) { 'downgraded' } else { 'version_changed' }
|
|
102
|
+
}
|
|
103
|
+
else { 'unchanged' }
|
|
104
|
+
if ($Result.mode -in @('upgrade', 'force') -and -not $Skipped -and $Result.status -ne 'preview' -and $change -ne 'failed' -and $Result.installed -and $Result.detectedVersion) {
|
|
105
|
+
$provider = $Result.helper -replace '^windows-', '' -replace '-native-installer$', ''
|
|
106
|
+
if ($provider -in @('cursor', 'devin', 'junie')) {
|
|
107
|
+
try { Remove-CatsStaleNativeVersions -Provider $provider -Version $Result.detectedVersion } catch { Write-Warning 'Old-version cleanup was skipped.' }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
$Result | Add-Member -NotePropertyName observedChange -NotePropertyValue $change -Force
|
|
111
|
+
$Result | Add-Member -NotePropertyName previousVersion -NotePropertyValue $Before.detectedVersion -Force
|
|
112
|
+
$description = "$change"
|
|
113
|
+
if ($change -in @('upgraded', 'downgraded', 'version_changed')) { $description += ": $($Before.detectedVersion) -> $($Result.detectedVersion)" }
|
|
114
|
+
elseif ($Result.detectedVersion) { $description += ": $($Result.detectedVersion)" }
|
|
115
|
+
$Result | Add-Member -NotePropertyName summary -NotePropertyValue $description -Force
|
|
116
|
+
if ($change -in @('failed', 'unchanged')) { $Result.appliedChanges = @() }
|
|
117
|
+
else { $Result.appliedChanges = @("${change}_native_installation") }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function Write-CatsNativePreview {
|
|
121
|
+
param([string]$Helper, [string]$Mode, $Detected, [string[]]$Actions, [bool]$EmitJson)
|
|
122
|
+
$result = [pscustomobject]@{
|
|
123
|
+
helper = $Helper; mode = $Mode; status = 'preview'; installed = [bool]$Detected.installed
|
|
124
|
+
detectedVersion = $Detected.detectedVersion; commandPath = $Detected.commandPath
|
|
125
|
+
restartRequired = $false; plannedActions = @($Actions); appliedChanges = @()
|
|
126
|
+
warnings = @(); manualSteps = @(); interruptions = @(); observedChange = 'unchanged'
|
|
127
|
+
}
|
|
128
|
+
if ($EmitJson) { $result | ConvertTo-Json -Depth 10 } else { Write-Host "Preview: $($Actions -join ', ')" }
|
|
129
|
+
exit 0
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function Get-CatsShimVersionText {
|
|
133
|
+
param([string]$Path)
|
|
134
|
+
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { return '' }
|
|
135
|
+
$literal = "'" + $Path.Replace("'", "''") + "'"
|
|
136
|
+
$script = "& $literal --version; exit " + '$LASTEXITCODE'
|
|
137
|
+
$encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($script))
|
|
138
|
+
$hostExe = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe'
|
|
139
|
+
$result = Invoke-HiddenCommand -FileName $hostExe -ArgumentList @('-NoProfile', '-NonInteractive', '-EncodedCommand', $encoded) -TimeoutMs 15000
|
|
140
|
+
if ($result.ExitCode -ne 0) { return '' }
|
|
141
|
+
return $result.Output.Trim()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function Remove-CatsStaleNativeVersions {
|
|
145
|
+
param([string]$Provider, [string]$Version)
|
|
146
|
+
$keep = Get-CatsNativeVersionToken $Provider $Version
|
|
147
|
+
if (-not $keep) { return }
|
|
148
|
+
$data = switch ($Provider) {
|
|
149
|
+
cursor { Join-Path $env:LOCALAPPDATA 'cursor-agent' }
|
|
150
|
+
devin { Join-Path $env:LOCALAPPDATA 'devin\cli' }
|
|
151
|
+
junie {
|
|
152
|
+
if ($env:JUNIE_DATA_DIR) { $env:JUNIE_DATA_DIR } else { Join-Path $env:USERPROFILE '.local\share\junie' }
|
|
153
|
+
}
|
|
154
|
+
default { return }
|
|
155
|
+
}
|
|
156
|
+
$versions = [IO.Path]::GetFullPath((Join-Path $data $(if ($Provider -eq 'devin') { '_versions' } else { 'versions' })))
|
|
157
|
+
if ($Provider -eq 'junie') {
|
|
158
|
+
if (Test-Path -LiteralPath (Join-Path $data 'updates\pending-update.json')) { return }
|
|
159
|
+
$currentFile = Join-Path $data 'current'
|
|
160
|
+
if (-not (Test-Path -LiteralPath $currentFile -PathType Leaf)) { return }
|
|
161
|
+
if ((Get-Content -LiteralPath $currentFile -Raw).Trim() -ne $keep) { return }
|
|
162
|
+
}
|
|
163
|
+
# Only known user roots; do not follow a junction in any ancestor or delete
|
|
164
|
+
# current/newer/pending builds. A custom directory outside those roots is kept.
|
|
165
|
+
if (-not (Test-PackagedProviderPathRemovable $versions)) { return }
|
|
166
|
+
$ancestor = Get-Item -LiteralPath $versions
|
|
167
|
+
while ($ancestor) {
|
|
168
|
+
if ($ancestor.Attributes -band [IO.FileAttributes]::ReparsePoint) { return }
|
|
169
|
+
$ancestor = $ancestor.Parent
|
|
170
|
+
}
|
|
171
|
+
foreach ($directory in (Get-ChildItem -LiteralPath $versions -Directory)) {
|
|
172
|
+
if ($directory.Attributes -band [IO.FileAttributes]::ReparsePoint) { continue }
|
|
173
|
+
if ($directory.Name -notmatch '^\d+(\.\d+)+(-[a-zA-Z0-9]+)?$') { continue }
|
|
174
|
+
if ((Compare-ToolVersion -Installed $directory.Name -Latest $keep) -ne -1) { continue }
|
|
175
|
+
$resolved = [IO.Path]::GetFullPath($directory.FullName)
|
|
176
|
+
if (-not $resolved.StartsWith($versions.TrimEnd('\') + '\', [StringComparison]::OrdinalIgnoreCase)) { continue }
|
|
177
|
+
if (Get-ChildItem -LiteralPath $resolved -Recurse -Force | Where-Object { $_.Attributes -band [IO.FileAttributes]::ReparsePoint } | Select-Object -First 1) { continue }
|
|
178
|
+
try { Remove-Item -LiteralPath $resolved -Recurse -Force -ErrorAction Stop } catch { Write-Warning "Could not remove old $Provider version $($directory.Name)." }
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function ConvertTo-ComparableVersion {
|
|
182
|
+
param([string]$Version)
|
|
183
|
+
|
|
184
|
+
if ([string]::IsNullOrWhiteSpace($Version)) { return $null }
|
|
185
|
+
|
|
186
|
+
# 第一個版本樣式的 token;額外吃下 Git for Windows 的 .windows.N 尾段
|
|
187
|
+
$match = [regex]::Match($Version, '\d+(?:\.\d+)+(?:\.windows\.\d+)?')
|
|
188
|
+
if (-not $match.Success) { return $null }
|
|
189
|
+
|
|
190
|
+
$parts = ($match.Value -replace '\.windows\.', '.') -split '\.' |
|
|
191
|
+
Select-Object -First 4
|
|
192
|
+
|
|
193
|
+
while ($parts.Count -lt 4) { $parts += '0' }
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
return [version]($parts -join '.')
|
|
197
|
+
} catch {
|
|
198
|
+
return $null
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function Compare-ToolVersion {
|
|
203
|
+
param(
|
|
204
|
+
[string]$Installed,
|
|
205
|
+
[string]$Latest
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
$installedVersion = ConvertTo-ComparableVersion $Installed
|
|
209
|
+
$latestVersion = ConvertTo-ComparableVersion $Latest
|
|
210
|
+
|
|
211
|
+
if (-not $installedVersion -or -not $latestVersion) { return $null }
|
|
212
|
+
|
|
213
|
+
return $installedVersion.CompareTo($latestVersion)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function Get-AntigravityLatestVersion {
|
|
217
|
+
param([string]$InstallerText)
|
|
218
|
+
|
|
219
|
+
$baseUrl = 'https://antigravity-cli-auto-updater-974169037036.us-central1.run.app'
|
|
220
|
+
if ($InstallerText) {
|
|
221
|
+
$m = [regex]::Match($InstallerText, '\$DOWNLOAD_BASE_URL\s*=\s*"(https://[^"]+)"')
|
|
222
|
+
if ($m.Success) { $baseUrl = $m.Groups[1].Value }
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
$arch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE }
|
|
226
|
+
$platform = if ($arch -eq 'ARM64') { 'windows_arm64' } else { 'windows_amd64' }
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
$manifest = Invoke-RestMethod -Uri "$baseUrl/manifests/$platform.json" -TimeoutSec 20 -UseBasicParsing -ErrorAction Stop
|
|
230
|
+
if (-not $manifest.version) { return $null }
|
|
231
|
+
return "$($manifest.version)"
|
|
232
|
+
} catch {
|
|
233
|
+
return $null
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function Get-CursorAgentLatestVersion {
|
|
238
|
+
param(
|
|
239
|
+
[Parameter(Mandatory=$true)]
|
|
240
|
+
[string]$InstallerText
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
$m = [regex]::Match($InstallerText, "(?m)^\s*\`$version\s*=\s*'([^']+)'")
|
|
244
|
+
if (-not $m.Success) { return $null }
|
|
245
|
+
return $m.Groups[1].Value
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function Get-JunieLatestBuild {
|
|
249
|
+
$archName = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64' -or $env:PROCESSOR_ARCHITEW6432 -eq 'ARM64') { 'aarch64' } else { 'amd64' }
|
|
250
|
+
$platform = "windows-$archName"
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
$jsonl = Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/jetbrains-junie/junie/main/update-info.jsonl' `
|
|
254
|
+
-TimeoutSec 20 -UseBasicParsing -ErrorAction Stop
|
|
255
|
+
} catch {
|
|
256
|
+
return $null
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
$best = $null
|
|
260
|
+
foreach ($line in ("$jsonl" -split "`n")) {
|
|
261
|
+
if ($line -notmatch "`"platform`":`"$platform`"") { continue }
|
|
262
|
+
try { $entry = $line | ConvertFrom-Json } catch { continue }
|
|
263
|
+
if (-not $entry.version) { continue }
|
|
264
|
+
$candidate = ConvertTo-ComparableVersion "$($entry.version)"
|
|
265
|
+
if (-not $candidate) { continue }
|
|
266
|
+
if ($null -eq $best -or $candidate -gt $best.Comparable) {
|
|
267
|
+
$best = @{ Build = "$($entry.version)"; Comparable = $candidate }
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if ($null -eq $best) { return $null }
|
|
272
|
+
return $best.Build
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function Get-DevinLatestVersion {
|
|
276
|
+
try {
|
|
277
|
+
$manifest = Invoke-RestMethod -Uri 'https://static.devin.ai/cli/current/manifest.json' -TimeoutSec 20 -UseBasicParsing -ErrorAction Stop
|
|
278
|
+
if (-not $manifest.version) { return $null }
|
|
279
|
+
return "$($manifest.version)"
|
|
280
|
+
} catch {
|
|
281
|
+
return $null
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function Get-GrokLatestVersion {
|
|
286
|
+
param([string]$Channel)
|
|
287
|
+
|
|
288
|
+
if (-not $Channel) {
|
|
289
|
+
$Channel = if ($env:GROK_CHANNEL) { $env:GROK_CHANNEL } else { 'stable' }
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
$urls = @(
|
|
293
|
+
"https://x.ai/cli/$Channel",
|
|
294
|
+
"https://storage.googleapis.com/grok-build-public-artifacts/cli/$Channel"
|
|
295
|
+
)
|
|
296
|
+
foreach ($url in $urls) {
|
|
297
|
+
try {
|
|
298
|
+
$text = Invoke-RestMethod -Uri $url -TimeoutSec 20 -UseBasicParsing -ErrorAction Stop
|
|
299
|
+
} catch {
|
|
300
|
+
continue
|
|
301
|
+
}
|
|
302
|
+
$line = @("$text" -split "`r?`n")[0]
|
|
303
|
+
if ($null -eq $line) { continue }
|
|
304
|
+
$line = $line.Trim()
|
|
305
|
+
if ($line -match '^\d+\.\d+\.\d+(-[A-Za-z0-9._]+)?$') { return $line }
|
|
306
|
+
}
|
|
307
|
+
return $null
|
|
308
|
+
}
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
can run it explicitly when needed.
|
|
24
24
|
#>
|
|
25
25
|
|
|
26
|
+
. (Join-Path $PSScriptRoot '_VerifiedNpmUpdate.ps1')
|
|
27
|
+
|
|
26
28
|
function Test-NpmCliInstallerAdminGuard {
|
|
27
29
|
param(
|
|
28
30
|
[Parameter(Mandatory = $true)]
|
|
@@ -163,11 +165,16 @@ function Test-NpmCliPackageOutdated {
|
|
|
163
165
|
[string]$PackageName
|
|
164
166
|
)
|
|
165
167
|
|
|
166
|
-
$
|
|
167
|
-
if ([
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
168
|
+
$latest = ((& npm view "$PackageName@latest" version --fetch-retries=0 --fetch-timeout=10000 --loglevel=error) | Out-String).Trim()
|
|
169
|
+
if ($LASTEXITCODE -ne 0 -or $latest -notmatch '^\d+\.\d+\.\d+(-[a-zA-Z0-9._-]+)?$') { throw 'Provider version query failed; update status is unknown.' }
|
|
170
|
+
$installed = Get-NpmCliPackageVersion -PackageName $PackageName
|
|
171
|
+
if (-not $installed) { return $true }
|
|
172
|
+
$currentBase = [version]($installed -split '-')[0]
|
|
173
|
+
$latestBase = [version]($latest -split '-')[0]
|
|
174
|
+
# Preserve a newer local/pre-release build. Equal numeric prerelease advances
|
|
175
|
+
# to the stable release; Repair remains the explicit reinstall action.
|
|
176
|
+
return $currentBase -lt $latestBase -or ($currentBase -eq $latestBase -and $installed.Contains('-') -and -not $latest.Contains('-'))
|
|
177
|
+
|
|
171
178
|
}
|
|
172
179
|
|
|
173
180
|
function Resolve-NpmCliCommandPath {
|
|
@@ -216,6 +223,7 @@ function Remove-SupersededNpmPackages {
|
|
|
216
223
|
|
|
217
224
|
Write-Host "Removing superseded package $legacy (replaced by $PackageName)."
|
|
218
225
|
& npm uninstall -g $legacy 2>$null | Out-Null
|
|
226
|
+
if ($LASTEXITCODE -ne 0) { throw "Could not remove superseded package $legacy." }
|
|
219
227
|
if ($AppliedChanges) {
|
|
220
228
|
$AppliedChanges.Add("${legacy}:removed-superseded") | Out-Null
|
|
221
229
|
}
|
|
@@ -315,6 +323,12 @@ function Invoke-PackagedNpmCliInstall {
|
|
|
315
323
|
$null
|
|
316
324
|
}
|
|
317
325
|
$commandPath = if ($installed) { Resolve-NpmCliCommandPath -CommandName $CommandName } else { $null }
|
|
326
|
+
if ($installed -and -not $detectedVersion -and -not $SkipNpmInvocation) {
|
|
327
|
+
foreach ($legacy in (Get-SupersededNpmPackages -PackageName $PackageName)) {
|
|
328
|
+
& npm list -g --depth=0 $legacy 2>$null | Out-Null
|
|
329
|
+
if ($LASTEXITCODE -eq 0) { $installed = $false; break }
|
|
330
|
+
}
|
|
331
|
+
}
|
|
318
332
|
|
|
319
333
|
$plannedActions = [System.Collections.Generic.List[string]]::new()
|
|
320
334
|
$appliedChanges = [System.Collections.Generic.List[string]]::new()
|
|
@@ -444,6 +458,17 @@ function Invoke-PackagedNpmCliInstall {
|
|
|
444
458
|
exit 0
|
|
445
459
|
}
|
|
446
460
|
|
|
461
|
+
if ($DryRun -and -not $CheckOnly) {
|
|
462
|
+
$preview = [pscustomobject]@{
|
|
463
|
+
helper = $HelperId; mode = $mode; status = 'preview'; installed = [bool]$installed
|
|
464
|
+
detectedVersion = $detectedVersion; commandPath = $commandPath; restartRequired = $false
|
|
465
|
+
plannedActions = @("${PackageName}:${mode}"); appliedChanges = @(); warnings = @(); manualSteps = @(); interruptions = @()
|
|
466
|
+
}
|
|
467
|
+
if ($Json) { $preview | ConvertTo-Json -Depth 10 } else { Write-Host "Preview: ${PackageName}:${mode}" }
|
|
468
|
+
exit 0
|
|
469
|
+
}
|
|
470
|
+
if ($Upgrade -and -not $CheckOnly -and -not $SkipNpmInvocation) { Update-CatsNpm }
|
|
471
|
+
|
|
447
472
|
$isOutdated = if (-not $Upgrade -and -not $Force) {
|
|
448
473
|
$false
|
|
449
474
|
} else {
|
|
@@ -565,15 +590,9 @@ function Invoke-PackagedNpmCliInstall {
|
|
|
565
590
|
# Without it, packages like @openai/codex skip their platform-specific
|
|
566
591
|
# binaries (codex-win32-x64, codex-darwin-arm64, ...), leaving a shim that
|
|
567
592
|
# silently exits when invoked. Pure-JS CLIs such as copilot don't notice.
|
|
568
|
-
$
|
|
569
|
-
if ($
|
|
570
|
-
|
|
571
|
-
} else {
|
|
572
|
-
$arguments += $PackageName
|
|
573
|
-
}
|
|
574
|
-
if ($plannedAction -eq 'reinstall') {
|
|
575
|
-
$arguments += '--force'
|
|
576
|
-
}
|
|
593
|
+
$expectedVersion = ((& npm view "$PackageName@latest" version --fetch-retries=0 --fetch-timeout=10000 --loglevel=error) | Out-String).Trim()
|
|
594
|
+
if ($LASTEXITCODE -ne 0 -or $expectedVersion -notmatch '^\d+\.\d+\.\d+(-[a-zA-Z0-9._-]+)?$') { throw 'Could not resolve the provider version before installing.' }
|
|
595
|
+
$arguments = @('install', '-g', '--include=optional', '--engine-strict', '--fetch-retries=0', '--fetch-timeout=30000', "$PackageName@$expectedVersion")
|
|
577
596
|
|
|
578
597
|
& npm @arguments | Out-Null
|
|
579
598
|
if ($LASTEXITCODE -ne 0) {
|
|
@@ -585,6 +604,8 @@ function Invoke-PackagedNpmCliInstall {
|
|
|
585
604
|
$finalCommandPath = if ($finalInstalled) { Resolve-NpmCliCommandPath -CommandName $CommandName } else { $null }
|
|
586
605
|
$finalVersion = if ($finalInstalled) { Get-NpmCliPackageVersion -PackageName $PackageName } else { $null }
|
|
587
606
|
|
|
607
|
+
if (-not $finalInstalled -or -not $finalCommandPath -or $finalVersion -ne $expectedVersion) { throw 'Provider installation verification failed. Check npm prefix and command PATH.' }
|
|
608
|
+
|
|
588
609
|
$result = [pscustomobject]@{
|
|
589
610
|
helper = $HelperId
|
|
590
611
|
mode = $mode
|
|
@@ -24,7 +24,15 @@ if (-not (Get-Module -ListAvailable -Name Microsoft.PowerShell.Utility)) {
|
|
|
24
24
|
function Test-PackagedProviderPathRemovable {
|
|
25
25
|
param([string]$Path)
|
|
26
26
|
if ([string]::IsNullOrWhiteSpace($Path)) { return $false }
|
|
27
|
-
|
|
27
|
+
$fullPath = [IO.Path]::GetFullPath($Path).TrimEnd('\', '/')
|
|
28
|
+
$withinUserRoot = $false
|
|
29
|
+
foreach ($base in @($env:USERPROFILE, $env:LOCALAPPDATA)) {
|
|
30
|
+
if (-not $base) { continue }
|
|
31
|
+
$root = [IO.Path]::GetFullPath($base).TrimEnd('\', '/') + '\'
|
|
32
|
+
if ($fullPath.StartsWith($root, [StringComparison]::OrdinalIgnoreCase)) { $withinUserRoot = $true }
|
|
33
|
+
}
|
|
34
|
+
if (-not $withinUserRoot) { return $false }
|
|
35
|
+
return (Test-Path -LiteralPath $fullPath)
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
function Test-DetectedPathInPlannedRemovals {
|