@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
|
@@ -37,8 +37,9 @@ Options:
|
|
|
37
37
|
--skip-mobile Skip the mobile bundle (\`expo export\`). Also honored via
|
|
38
38
|
CATS_SKIP_MOBILE=1 in the environment or .env.
|
|
39
39
|
--release Build an official release package: embed the release
|
|
40
|
-
descriptor, require platform signing credentials
|
|
41
|
-
|
|
40
|
+
descriptor, require platform signing credentials (plus
|
|
41
|
+
macOS notarization credentials), and allow signing
|
|
42
|
+
identity discovery. Requires a GitHub
|
|
42
43
|
Actions tag run whose tag matches the package version.
|
|
43
44
|
Also honored via CATS_DESKTOP_RELEASE_MODE=1.
|
|
44
45
|
--preview Build an unsupported unsigned GitHub prerelease preview.
|
|
@@ -46,6 +47,12 @@ Options:
|
|
|
46
47
|
omits the official descriptor, and disables signing
|
|
47
48
|
identity discovery. Also honored via
|
|
48
49
|
CATS_DESKTOP_PREVIEW_MODE=1.
|
|
50
|
+
--sign Let local packaging use a signing identity from the
|
|
51
|
+
OS keychain. Off by default so an unconfigured machine
|
|
52
|
+
cannot pick up an unrelated certificate. Ignored by
|
|
53
|
+
--release and --preview, which always sign when their
|
|
54
|
+
credentials are present. Also honored via
|
|
55
|
+
CATS_DESKTOP_SIGN_LOCAL=1.
|
|
49
56
|
--publish <never|always> Publish policy, default never. Publishing requires
|
|
50
57
|
--release or --preview plus a GitHub token. Also honored
|
|
51
58
|
via CATS_DESKTOP_PUBLISH.
|
|
@@ -99,6 +106,7 @@ export function parseArgs(argv, env = process.env) {
|
|
|
99
106
|
let skipMobile = parseBooleanFlag(env.CATS_SKIP_MOBILE);
|
|
100
107
|
let releaseMode = parseBooleanFlag(env.CATS_DESKTOP_RELEASE_MODE);
|
|
101
108
|
let previewMode = parseBooleanFlag(env.CATS_DESKTOP_PREVIEW_MODE);
|
|
109
|
+
let allowLocalSigning = parseBooleanFlag(env.CATS_DESKTOP_SIGN_LOCAL);
|
|
102
110
|
let publish = resolvePublishPolicy(env.CATS_DESKTOP_PUBLISH);
|
|
103
111
|
// GITHUB_REF_NAME is a runner-provided default. A workflow `env:` block
|
|
104
112
|
// cannot override anything in the GITHUB_ namespace, and a preview run is
|
|
@@ -118,6 +126,7 @@ export function parseArgs(argv, env = process.env) {
|
|
|
118
126
|
skipMobile,
|
|
119
127
|
releaseMode,
|
|
120
128
|
previewMode,
|
|
129
|
+
allowLocalSigning,
|
|
121
130
|
publish,
|
|
122
131
|
tag,
|
|
123
132
|
...(appsLock ? { appsLock } : {}),
|
|
@@ -144,6 +153,14 @@ export function parseArgs(argv, env = process.env) {
|
|
|
144
153
|
previewMode = false;
|
|
145
154
|
continue;
|
|
146
155
|
}
|
|
156
|
+
if (value === '--sign') {
|
|
157
|
+
allowLocalSigning = true;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (value === '--no-sign') {
|
|
161
|
+
allowLocalSigning = false;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
147
164
|
if (value === '--publish') {
|
|
148
165
|
publish = resolvePublishPolicy(argv[index + 1] ?? '');
|
|
149
166
|
index += 1;
|
|
@@ -194,6 +211,7 @@ export function parseArgs(argv, env = process.env) {
|
|
|
194
211
|
skipMobile,
|
|
195
212
|
releaseMode,
|
|
196
213
|
previewMode,
|
|
214
|
+
allowLocalSigning,
|
|
197
215
|
publish,
|
|
198
216
|
tag,
|
|
199
217
|
...(appsLock ? { appsLock } : {}),
|
|
@@ -241,28 +259,45 @@ async function resolveCommandInvocation(command, args) {
|
|
|
241
259
|
};
|
|
242
260
|
}
|
|
243
261
|
|
|
262
|
+
const MACOS_NOTARIZATION_CREDENTIAL_KEYS = [
|
|
263
|
+
'APPLE_API_KEY',
|
|
264
|
+
'APPLE_API_KEY_ID',
|
|
265
|
+
'APPLE_API_ISSUER',
|
|
266
|
+
];
|
|
267
|
+
|
|
244
268
|
const SIGNING_CREDENTIAL_KEYS = [
|
|
245
269
|
'WIN_CSC_LINK',
|
|
246
270
|
'CSC_LINK',
|
|
247
271
|
'WIN_CSC_KEY_PASSWORD',
|
|
248
272
|
'CSC_KEY_PASSWORD',
|
|
273
|
+
...MACOS_NOTARIZATION_CREDENTIAL_KEYS,
|
|
249
274
|
];
|
|
250
275
|
|
|
251
276
|
/**
|
|
252
277
|
* Local and test packaging must never reach for a signing identity, because an
|
|
253
278
|
* unconfigured machine would otherwise pick up an unrelated certificate from
|
|
254
|
-
* the OS keychain.
|
|
255
|
-
* configured certificate can actually be used.
|
|
279
|
+
* the OS keychain. Both guarded workflow paths leave identity discovery alone
|
|
280
|
+
* so a configured certificate can actually be used.
|
|
281
|
+
*
|
|
282
|
+
* ADR-117: a preview is signed on any platform whose credentials exist, so
|
|
283
|
+
* preview mode is a signing path too. Signing is artifact trust; it says
|
|
284
|
+
* nothing about whether the build claims official release identity.
|
|
285
|
+
*
|
|
286
|
+
* `--sign` is the local escape hatch. It is an explicit request rather than an
|
|
287
|
+
* inference from the environment, because a developer machine may hold
|
|
288
|
+
* unrelated certificates.
|
|
256
289
|
*
|
|
257
|
-
* Empty credential variables are dropped in
|
|
290
|
+
* Empty credential variables are dropped in every mode: electron-builder treats
|
|
258
291
|
* an empty CSC_LINK as a relative path and resolves it against the project
|
|
259
292
|
* root.
|
|
260
293
|
*/
|
|
261
294
|
export function buildInstallerEnvironment(baseEnv = process.env, options = {}) {
|
|
262
|
-
const
|
|
295
|
+
const signingAllowed = options.releaseMode === true
|
|
296
|
+
|| options.previewMode === true
|
|
297
|
+
|| options.allowLocalSigning === true;
|
|
263
298
|
const env = { ...baseEnv };
|
|
264
299
|
|
|
265
|
-
if (!
|
|
300
|
+
if (!signingAllowed) {
|
|
266
301
|
env.CSC_IDENTITY_AUTO_DISCOVERY = 'false';
|
|
267
302
|
}
|
|
268
303
|
|
|
@@ -286,6 +321,22 @@ export function hasMacosSigningCredentials(env = process.env) {
|
|
|
286
321
|
return typeof link === 'string' && link.trim() !== '';
|
|
287
322
|
}
|
|
288
323
|
|
|
324
|
+
/**
|
|
325
|
+
* electron-builder reads notarization credentials straight from the
|
|
326
|
+
* environment and only warns when they are absent, so a misconfigured release
|
|
327
|
+
* would otherwise produce a signed but un-notarized app. Gatekeeper rejects
|
|
328
|
+
* that on every machine except the one that built it.
|
|
329
|
+
*
|
|
330
|
+
* App Store Connect API keys are used rather than an Apple ID and
|
|
331
|
+
* app-specific password: they are revocable on their own and survive an Apple
|
|
332
|
+
* ID password change, which a CI secret has no way to notice.
|
|
333
|
+
*/
|
|
334
|
+
export function hasMacosNotarizationCredentials(env = process.env) {
|
|
335
|
+
return MACOS_NOTARIZATION_CREDENTIAL_KEYS.every(
|
|
336
|
+
(key) => typeof env[key] === 'string' && env[key].trim() !== '',
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
289
340
|
/**
|
|
290
341
|
* Signing is a release gate, not a nice-to-have.
|
|
291
342
|
*
|
|
@@ -302,16 +353,53 @@ export function resolveSigningProblems({ env = process.env, target } = {}) {
|
|
|
302
353
|
}];
|
|
303
354
|
}
|
|
304
355
|
|
|
305
|
-
if (target === 'macos'
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
356
|
+
if (target === 'macos') {
|
|
357
|
+
const problems = [];
|
|
358
|
+
if (!hasMacosSigningCredentials(env)) {
|
|
359
|
+
problems.push({
|
|
360
|
+
code: 'release_macos_signing_missing',
|
|
361
|
+
message: 'An official macOS release requires CSC_LINK.',
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
if (!hasMacosNotarizationCredentials(env)) {
|
|
365
|
+
problems.push({
|
|
366
|
+
code: 'release_macos_notarization_missing',
|
|
367
|
+
message: 'An official macOS release requires APPLE_API_KEY, APPLE_API_KEY_ID, and APPLE_API_ISSUER.',
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
return problems;
|
|
310
371
|
}
|
|
311
372
|
|
|
312
373
|
return [];
|
|
313
374
|
}
|
|
314
375
|
|
|
376
|
+
/**
|
|
377
|
+
* ADR-117: trust is resolved per platform from the credentials actually
|
|
378
|
+
* present. The build states which it got, because a silently unsigned artifact
|
|
379
|
+
* is indistinguishable from a signed one until a user tries to install it.
|
|
380
|
+
*/
|
|
381
|
+
export function describeArtifactTrust(target, env = process.env) {
|
|
382
|
+
if (target === 'linux') {
|
|
383
|
+
return 'unsigned (Linux packages are not signed)';
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (target === 'windows') {
|
|
387
|
+
return hasWindowsSigningCredentials(env)
|
|
388
|
+
? 'signed'
|
|
389
|
+
: 'unsigned (no Windows certificate configured)';
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const signed = hasMacosSigningCredentials(env);
|
|
393
|
+
const notarized = hasMacosNotarizationCredentials(env);
|
|
394
|
+
if (signed && notarized) {
|
|
395
|
+
return 'signed and notarized';
|
|
396
|
+
}
|
|
397
|
+
if (signed) {
|
|
398
|
+
return 'signed but NOT notarized (no App Store Connect API key) — Gatekeeper will reject the download';
|
|
399
|
+
}
|
|
400
|
+
return 'unsigned (no Developer ID certificate)';
|
|
401
|
+
}
|
|
402
|
+
|
|
315
403
|
/**
|
|
316
404
|
* Release and preview publication are only meaningful inside the guarded
|
|
317
405
|
* workflow. Anything else could publish from an unreviewed tree, so the
|
|
@@ -648,8 +736,14 @@ export function electronBuilderArgs(target, archOverride, formatOverride, option
|
|
|
648
736
|
}
|
|
649
737
|
|
|
650
738
|
const releaseMode = options.releaseMode === true;
|
|
739
|
+
const previewMode = options.previewMode === true;
|
|
740
|
+
// Signing overrides key off artifact trust, not release identity, so both
|
|
741
|
+
// guarded paths qualify. Local packaging never does, even with `--sign`:
|
|
742
|
+
// an ad-hoc local build has no reason to reach Apple's notary service.
|
|
743
|
+
const signedBuild = releaseMode || previewMode;
|
|
651
744
|
const publish = resolvePublishPolicy(options.publish ?? 'never');
|
|
652
745
|
const signWindowsExecutable = options.signWindowsExecutable === true;
|
|
746
|
+
const notarizeMacos = options.notarizeMacos === true;
|
|
653
747
|
const formats = normalizeFormats(target, formatOverride);
|
|
654
748
|
const platformFlag = target === 'windows' ? '--win' : target === 'macos' ? '--mac' : '--linux';
|
|
655
749
|
const args = ['electron-builder', platformFlag];
|
|
@@ -667,10 +761,17 @@ export function electronBuilderArgs(target, archOverride, formatOverride, option
|
|
|
667
761
|
// package.json pins signAndEditExecutable to false so unsigned local builds
|
|
668
762
|
// avoid the winCodeSign download. A release build with real credentials has
|
|
669
763
|
// to opt back in, and only then.
|
|
670
|
-
if (
|
|
764
|
+
if (signedBuild && target === 'windows' && signWindowsExecutable) {
|
|
671
765
|
args.push('-c.win.signAndEditExecutable=true');
|
|
672
766
|
}
|
|
673
767
|
|
|
768
|
+
// package.json pins mac.notarize to false so an unsigned preview never waits
|
|
769
|
+
// on Apple and a half-configured environment cannot quietly ship an
|
|
770
|
+
// un-notarized build. A release build with real credentials opts back in.
|
|
771
|
+
if (signedBuild && target === 'macos' && notarizeMacos) {
|
|
772
|
+
args.push('-c.mac.notarize=true');
|
|
773
|
+
}
|
|
774
|
+
|
|
674
775
|
args.push('--publish', publish);
|
|
675
776
|
return args;
|
|
676
777
|
}
|
|
@@ -687,7 +788,11 @@ async function main() {
|
|
|
687
788
|
// in an OS temporary directory so retries never redownload a moving asset.
|
|
688
789
|
const selectedApps = parsed.appsLock ? await resolveAppLock(resolve(parsed.appsLock)) : null;
|
|
689
790
|
const appLockForBuild = selectedApps ? await materializeAppSelection(selectedApps) : null;
|
|
690
|
-
const envOptions = {
|
|
791
|
+
const envOptions = {
|
|
792
|
+
releaseMode: parsed.releaseMode,
|
|
793
|
+
previewMode: parsed.previewMode,
|
|
794
|
+
allowLocalSigning: parsed.allowLocalSigning,
|
|
795
|
+
};
|
|
691
796
|
|
|
692
797
|
if (parsed.releaseMode && parsed.previewMode) {
|
|
693
798
|
throw new Error('--release and --preview are mutually exclusive build modes.');
|
|
@@ -717,10 +822,11 @@ async function main() {
|
|
|
717
822
|
.join('\n')}`,
|
|
718
823
|
);
|
|
719
824
|
}
|
|
720
|
-
const buildKind = parsed.releaseMode ? 'official' : '
|
|
825
|
+
const buildKind = parsed.releaseMode ? 'official' : 'preview';
|
|
721
826
|
process.stdout.write(
|
|
722
827
|
`[build-desktop-installer] ${buildKind} ${resolvedTarget} build for `
|
|
723
|
-
+ `${process.env.GITHUB_REF_NAME} (publish=${parsed.publish}
|
|
828
|
+
+ `${process.env.GITHUB_REF_NAME} (publish=${parsed.publish}, `
|
|
829
|
+
+ `trust=${describeArtifactTrust(resolvedTarget, process.env)}).\n`,
|
|
724
830
|
);
|
|
725
831
|
}
|
|
726
832
|
|
|
@@ -786,8 +892,10 @@ async function main() {
|
|
|
786
892
|
'npx',
|
|
787
893
|
electronBuilderArgs(resolvedTarget, parsed.arch, parsed.format, {
|
|
788
894
|
releaseMode: parsed.releaseMode,
|
|
895
|
+
previewMode: parsed.previewMode,
|
|
789
896
|
publish: parsed.publish,
|
|
790
897
|
signWindowsExecutable: hasWindowsSigningCredentials(process.env),
|
|
898
|
+
notarizeMacos: hasMacosNotarizationCredentials(process.env),
|
|
791
899
|
}),
|
|
792
900
|
PROJECT_ROOT,
|
|
793
901
|
{},
|
package/scripts/dev-server.mjs
CHANGED
|
@@ -26,7 +26,10 @@ let crashCount = 0;
|
|
|
26
26
|
|
|
27
27
|
function spawnServer() {
|
|
28
28
|
intentionalRestart = false;
|
|
29
|
-
child = spawn(process.execPath, [
|
|
29
|
+
child = spawn(process.execPath, [
|
|
30
|
+
'--import', 'tsx', entry,
|
|
31
|
+
'--startup-mode', 'app-managed', '--managed-by', 'dev-server', '--ready-output', 'plain',
|
|
32
|
+
], {
|
|
30
33
|
stdio: 'inherit',
|
|
31
34
|
env: process.env,
|
|
32
35
|
});
|
|
@@ -60,6 +60,11 @@ declare -a applied_changes=()
|
|
|
60
60
|
declare -a warnings=()
|
|
61
61
|
declare -a manual_steps=()
|
|
62
62
|
|
|
63
|
+
# A Desktop-launched helper may inherit PATH from before gh was installed.
|
|
64
|
+
# Include our fallback destination and the supported Homebrew locations in this
|
|
65
|
+
# process only; check mode must not edit the user's shell profile.
|
|
66
|
+
export PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"
|
|
67
|
+
|
|
63
68
|
resolve_gh_path() {
|
|
64
69
|
command -v gh 2>/dev/null || true
|
|
65
70
|
}
|
|
@@ -90,7 +90,7 @@ is_node_installed() {
|
|
|
90
90
|
if [ "$skip_node_probe" = 'true' ]; then
|
|
91
91
|
return 1
|
|
92
92
|
fi
|
|
93
|
-
command -v node >/dev/null 2>&1
|
|
93
|
+
command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
json_array_from_lines() {
|
|
@@ -149,6 +149,12 @@ JSON
|
|
|
149
149
|
exit "$exit_code"
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
# Desktop's environment may predate nvm installation. Load it before read-only
|
|
153
|
+
# detection too; a bundled or standalone node without npm is not this substrate.
|
|
154
|
+
if [ "$install_state" = 'auto' ] && [ "$skip_node_probe" = 'false' ]; then
|
|
155
|
+
load_nvm
|
|
156
|
+
fi
|
|
157
|
+
|
|
152
158
|
# Mode: check
|
|
153
159
|
if [ "$mode" = 'check' ]; then
|
|
154
160
|
if is_node_installed; then
|
|
@@ -214,10 +220,10 @@ case "$mode" in
|
|
|
214
220
|
;;
|
|
215
221
|
esac
|
|
216
222
|
|
|
217
|
-
if command -v node >/dev/null 2>&1; then
|
|
223
|
+
if command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1; then
|
|
218
224
|
emit_result 'ready' 'true' 0
|
|
219
225
|
else
|
|
220
|
-
warnings+=('Node
|
|
226
|
+
warnings+=('Node.js or npm is still missing after install.')
|
|
221
227
|
manual_steps+=('Open a new terminal so PATH picks up the nvm-managed node binary.')
|
|
222
228
|
emit_result 'failed' 'false' 1
|
|
223
229
|
fi
|
|
@@ -8,6 +8,7 @@ readonly CATS_PLATFORM_UNIX_NODE_COMMON_SH=1
|
|
|
8
8
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
9
|
# shellcheck source=provider-cli-common.sh
|
|
10
10
|
. "$SCRIPT_DIR/provider-cli-common.sh"
|
|
11
|
+
. "$SCRIPT_DIR/verified-npm-update.sh"
|
|
11
12
|
|
|
12
13
|
normalize_npm_registry() {
|
|
13
14
|
case "$1" in
|
|
@@ -52,25 +53,51 @@ ensure_node_and_npm() {
|
|
|
52
53
|
printf 'npm is required but was not found.\n' >&2
|
|
53
54
|
return 1
|
|
54
55
|
fi
|
|
56
|
+
# Desktop invokes each helper in a fresh non-login shell. Read the configured
|
|
57
|
+
# prefix, never source arbitrary shell startup files to recover its commands.
|
|
58
|
+
local configured_prefix
|
|
59
|
+
configured_prefix="$(npm config get prefix 2>/dev/null || true)"
|
|
60
|
+
[ -z "$configured_prefix" ] || prepend_path_if_missing "$configured_prefix/bin"
|
|
61
|
+
return 0
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
has_explicit_npm_prefix() {
|
|
65
|
+
[ -z "${NPM_CONFIG_PREFIX:-${npm_config_prefix:-}}" ] || return 0
|
|
66
|
+
local npmrc="${NPM_CONFIG_USERCONFIG:-${npm_config_userconfig:-$HOME/.npmrc}}"
|
|
67
|
+
[ -f "$npmrc" ] && grep -qE '^[[:space:]]*prefix[[:space:]]*=' "$npmrc"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
preferred_npm_prefix() {
|
|
71
|
+
local existing canonical_home
|
|
72
|
+
existing="$(npm config get prefix 2>/dev/null || true)"
|
|
73
|
+
if [ -n "$existing" ] && has_explicit_npm_prefix; then printf '%s\n' "$existing"; return 0; fi
|
|
74
|
+
if [ -d "$existing" ] && [ -w "$existing" ]; then
|
|
75
|
+
existing="$(cd -P -- "$existing" && pwd -P)"
|
|
76
|
+
canonical_home="$(cd -P -- "$HOME" && pwd -P)"
|
|
77
|
+
case "$existing" in "$canonical_home"/*) printf '%s\n' "$existing"; return 0 ;; esac
|
|
78
|
+
fi
|
|
79
|
+
printf '%s\n' "$HOME/.npm-global"
|
|
55
80
|
}
|
|
56
81
|
|
|
57
82
|
ensure_npm_global_path_export() {
|
|
58
|
-
local shell_rc="$1"
|
|
83
|
+
local shell_rc="$1" prefix="${2:-$HOME/.npm-global}" export_line
|
|
84
|
+
printf -v export_line 'export PATH=%q:$PATH' "$prefix/bin"
|
|
59
85
|
append_line_if_missing "$shell_rc" '# Added by cats-platform self-hosted npm helpers' '# Added by cats-platform self-hosted npm helpers'
|
|
60
|
-
append_line_if_missing "$shell_rc"
|
|
61
|
-
prepend_path_if_missing "$
|
|
86
|
+
append_line_if_missing "$shell_rc" "$export_line" "$export_line"
|
|
87
|
+
prepend_path_if_missing "$prefix/bin"
|
|
62
88
|
}
|
|
63
89
|
|
|
64
90
|
node_prefix_ready() {
|
|
65
|
-
local prefix
|
|
91
|
+
local prefix desired_prefix
|
|
66
92
|
local registry
|
|
67
93
|
local shell_rc
|
|
68
94
|
|
|
69
95
|
prefix="$(npm config get prefix 2>/dev/null || printf '')"
|
|
70
96
|
registry="$(normalize_npm_registry "$(npm config get registry 2>/dev/null || printf '')")"
|
|
71
97
|
shell_rc="$(detect_shell_rc)"
|
|
98
|
+
desired_prefix="$(preferred_npm_prefix)"
|
|
72
99
|
|
|
73
|
-
if nvm_is_active; then
|
|
100
|
+
if nvm_is_active && ! has_explicit_npm_prefix; then
|
|
74
101
|
if npmrc_has_prefix_conflict; then
|
|
75
102
|
return 1
|
|
76
103
|
fi
|
|
@@ -78,7 +105,7 @@ node_prefix_ready() {
|
|
|
78
105
|
return $?
|
|
79
106
|
fi
|
|
80
107
|
|
|
81
|
-
if [ "$prefix" != "$
|
|
108
|
+
if [ "$prefix" != "$desired_prefix" ]; then
|
|
82
109
|
return 1
|
|
83
110
|
fi
|
|
84
111
|
|
|
@@ -86,11 +113,11 @@ node_prefix_ready() {
|
|
|
86
113
|
return 1
|
|
87
114
|
fi
|
|
88
115
|
|
|
89
|
-
if [[ ":$PATH:" == *":$
|
|
116
|
+
if [[ ":$PATH:" == *":$desired_prefix/bin:"* ]]; then
|
|
90
117
|
return 0
|
|
91
118
|
fi
|
|
92
119
|
|
|
93
|
-
|
|
120
|
+
return 1
|
|
94
121
|
}
|
|
95
122
|
|
|
96
123
|
node_prefix_help() {
|
|
@@ -119,7 +146,7 @@ run_node_prefix_setup() {
|
|
|
119
146
|
local force='false'
|
|
120
147
|
local emit_json='false'
|
|
121
148
|
local shell_rc
|
|
122
|
-
local prefix
|
|
149
|
+
local prefix desired_prefix
|
|
123
150
|
local registry
|
|
124
151
|
local status='ready'
|
|
125
152
|
local execution_mode='apply'
|
|
@@ -170,6 +197,7 @@ run_node_prefix_setup() {
|
|
|
170
197
|
execution_mode='apply'
|
|
171
198
|
fi
|
|
172
199
|
|
|
200
|
+
desired_prefix="$HOME/.npm-global"
|
|
173
201
|
load_nvm_if_present
|
|
174
202
|
if ! ensure_node_and_npm; then
|
|
175
203
|
if [ "$emit_json" = 'true' ]; then
|
|
@@ -178,7 +206,7 @@ run_node_prefix_setup() {
|
|
|
178
206
|
printf '"mode":"%s",' "$execution_mode"
|
|
179
207
|
printf '"status":"failed",'
|
|
180
208
|
printf '"restartRequired":false,'
|
|
181
|
-
printf '"desiredPrefix":"%s",' "$(json_escape "$
|
|
209
|
+
printf '"desiredPrefix":"%s",' "$(json_escape "$desired_prefix")"
|
|
182
210
|
printf '"shellRc":"%s",' "$(json_escape "$(detect_shell_rc)")"
|
|
183
211
|
printf '"plannedActions":[],'
|
|
184
212
|
printf '"appliedChanges":[],'
|
|
@@ -191,10 +219,11 @@ run_node_prefix_setup() {
|
|
|
191
219
|
fi
|
|
192
220
|
|
|
193
221
|
shell_rc="$(detect_shell_rc)"
|
|
222
|
+
desired_prefix="$(preferred_npm_prefix)"
|
|
194
223
|
prefix="$(npm config get prefix 2>/dev/null || printf '')"
|
|
195
224
|
registry="$(normalize_npm_registry "$(npm config get registry 2>/dev/null || printf '')")"
|
|
196
225
|
|
|
197
|
-
if nvm_is_active; then
|
|
226
|
+
if nvm_is_active && ! has_explicit_npm_prefix; then
|
|
198
227
|
if npmrc_has_prefix_conflict; then
|
|
199
228
|
planned_actions+=('clear_npm_prefix_conflict')
|
|
200
229
|
fi
|
|
@@ -202,13 +231,13 @@ run_node_prefix_setup() {
|
|
|
202
231
|
planned_actions+=('set_npm_registry')
|
|
203
232
|
fi
|
|
204
233
|
else
|
|
205
|
-
if [ "$prefix" != "$
|
|
234
|
+
if [ "$prefix" != "$desired_prefix" ]; then
|
|
206
235
|
planned_actions+=('set_npm_prefix')
|
|
207
236
|
fi
|
|
208
237
|
if [ "$registry" != 'https://registry.npmjs.org/' ]; then
|
|
209
238
|
planned_actions+=('set_npm_registry')
|
|
210
239
|
fi
|
|
211
|
-
if [[ ":$PATH:" != *":$
|
|
240
|
+
if [[ ":$PATH:" != *":$desired_prefix/bin:"* ]]; then
|
|
212
241
|
planned_actions+=('repair_npm_global_path')
|
|
213
242
|
fi
|
|
214
243
|
fi
|
|
@@ -224,7 +253,7 @@ run_node_prefix_setup() {
|
|
|
224
253
|
printf '"mode":"check",'
|
|
225
254
|
printf '"status":"%s",' "$status"
|
|
226
255
|
printf '"restartRequired":false,'
|
|
227
|
-
printf '"desiredPrefix":"%s",' "$(json_escape "$
|
|
256
|
+
printf '"desiredPrefix":"%s",' "$(json_escape "$desired_prefix")"
|
|
228
257
|
printf '"shellRc":"%s",' "$(json_escape "$shell_rc")"
|
|
229
258
|
printf '"plannedActions":'
|
|
230
259
|
json_string_array "${planned_actions[@]}"
|
|
@@ -251,7 +280,7 @@ run_node_prefix_setup() {
|
|
|
251
280
|
printf '"mode":"%s",' "$execution_mode"
|
|
252
281
|
printf '"status":"ready",'
|
|
253
282
|
printf '"restartRequired":false,'
|
|
254
|
-
printf '"desiredPrefix":"%s",' "$(json_escape "$
|
|
283
|
+
printf '"desiredPrefix":"%s",' "$(json_escape "$desired_prefix")"
|
|
255
284
|
printf '"shellRc":"%s",' "$(json_escape "$shell_rc")"
|
|
256
285
|
printf '"plannedActions":[],'
|
|
257
286
|
printf '"appliedChanges":[],'
|
|
@@ -265,7 +294,7 @@ run_node_prefix_setup() {
|
|
|
265
294
|
return 0
|
|
266
295
|
fi
|
|
267
296
|
|
|
268
|
-
if nvm_is_active; then
|
|
297
|
+
if nvm_is_active && ! has_explicit_npm_prefix; then
|
|
269
298
|
nvm use --delete-prefix "$(node -v)" --silent >/dev/null 2>&1 || true
|
|
270
299
|
npm config delete prefix >/dev/null 2>&1 || true
|
|
271
300
|
npm config delete globalconfig >/dev/null 2>&1 || true
|
|
@@ -275,10 +304,10 @@ run_node_prefix_setup() {
|
|
|
275
304
|
applied_changes+=('clear_npm_prefix_conflict')
|
|
276
305
|
fi
|
|
277
306
|
else
|
|
278
|
-
mkdir -p "$
|
|
279
|
-
npm config set prefix "$
|
|
307
|
+
mkdir -p "$desired_prefix"
|
|
308
|
+
npm config set prefix "$desired_prefix"
|
|
280
309
|
npm config set registry 'https://registry.npmjs.org/'
|
|
281
|
-
ensure_npm_global_path_export "$shell_rc"
|
|
310
|
+
ensure_npm_global_path_export "$shell_rc" "$desired_prefix"
|
|
282
311
|
applied_changes+=('set_npm_prefix' 'set_npm_registry' 'repair_npm_global_path')
|
|
283
312
|
fi
|
|
284
313
|
|
|
@@ -294,7 +323,7 @@ run_node_prefix_setup() {
|
|
|
294
323
|
printf '"mode":"%s",' "$execution_mode"
|
|
295
324
|
printf '"status":"%s",' "$status"
|
|
296
325
|
printf '"restartRequired":false,'
|
|
297
|
-
printf '"desiredPrefix":"%s",' "$(json_escape "$
|
|
326
|
+
printf '"desiredPrefix":"%s",' "$(json_escape "$desired_prefix")"
|
|
298
327
|
printf '"shellRc":"%s",' "$(json_escape "$shell_rc")"
|
|
299
328
|
printf '"plannedActions":'
|
|
300
329
|
json_string_array "${planned_actions[@]}"
|
|
@@ -340,8 +369,8 @@ remove_superseded_npm_packages() {
|
|
|
340
369
|
while IFS= read -r legacy; do
|
|
341
370
|
[ -n "$legacy" ] || continue
|
|
342
371
|
npm list -g "$legacy" --depth=0 >/dev/null 2>&1 || continue
|
|
343
|
-
printf 'Removing superseded package %s (replaced by %s).\n' "$legacy" "$package_name"
|
|
344
|
-
npm uninstall -g "$legacy" >/dev/null 2>&1 ||
|
|
372
|
+
printf 'Removing superseded package %s (replaced by %s).\n' "$legacy" "$package_name" >&2
|
|
373
|
+
npm uninstall -g "$legacy" >/dev/null 2>&1 || return 1
|
|
345
374
|
done <<EOF
|
|
346
375
|
$(node_cli_superseded_packages "$package_name")
|
|
347
376
|
EOF
|
|
@@ -1081,9 +1110,6 @@ run_npm_cli_provider() {
|
|
|
1081
1110
|
shift
|
|
1082
1111
|
done
|
|
1083
1112
|
|
|
1084
|
-
if [ "$check_only" != 'true' ] && [ "$uninstall" != 'true' ]; then
|
|
1085
|
-
remove_superseded_npm_packages "$package_name"
|
|
1086
|
-
fi
|
|
1087
1113
|
|
|
1088
1114
|
if [ "$force" = 'true' ]; then
|
|
1089
1115
|
upgrade='false'
|
|
@@ -1134,7 +1160,17 @@ run_npm_cli_provider() {
|
|
|
1134
1160
|
if command -v "$command_name" >/dev/null 2>&1 || npm list -g "$package_name" --depth=0 >/dev/null 2>&1; then
|
|
1135
1161
|
installed='true'
|
|
1136
1162
|
command_path="$(command -v "$command_name" 2>/dev/null || true)"
|
|
1137
|
-
detected_version="$(npm list -g --depth=0 --json "$package_name" 2>/dev/null |
|
|
1163
|
+
detected_version="$( (npm list -g --depth=0 --json "$package_name" 2>/dev/null || true) | node -e 'let s="";process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>{try{console.log(JSON.parse(s).dependencies?.[process.argv[1]]?.version||"")}catch{}})' "$package_name")"
|
|
1164
|
+
fi
|
|
1165
|
+
|
|
1166
|
+
if [ "$installed" = true ] && [ -z "$detected_version" ]; then
|
|
1167
|
+
local legacy
|
|
1168
|
+
while IFS= read -r legacy; do
|
|
1169
|
+
[ -n "$legacy" ] || continue
|
|
1170
|
+
if npm list -g "$legacy" --depth=0 >/dev/null 2>&1; then installed=false; break; fi
|
|
1171
|
+
done <<LEGACY_EOF
|
|
1172
|
+
$(node_cli_superseded_packages "$package_name")
|
|
1173
|
+
LEGACY_EOF
|
|
1138
1174
|
fi
|
|
1139
1175
|
|
|
1140
1176
|
if [ "$execution_mode" = 'uninstall' ]; then
|
|
@@ -1208,13 +1244,15 @@ run_npm_cli_provider() {
|
|
|
1208
1244
|
return 0
|
|
1209
1245
|
fi
|
|
1210
1246
|
|
|
1211
|
-
local is_outdated=
|
|
1212
|
-
if [ "$upgrade" =
|
|
1213
|
-
if [ "$
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1247
|
+
local is_outdated=false expected_version=''
|
|
1248
|
+
if [ "$check_only" = false ] && [ "$uninstall" = false ] && [ "$dry_run" = false ] && { [ "$upgrade" = true ] || [ "$force" = true ] || [ "$installed" = false ]; }; then
|
|
1249
|
+
if [ "$upgrade" = true ]; then cats_upgrade_npm || return 1; fi
|
|
1250
|
+
expected_version="$(npm view "${package_name}@latest" version --fetch-retries=0 --fetch-timeout=10000 --loglevel=error)" || { printf 'Provider version query failed.\n' >&2; return 1; }
|
|
1251
|
+
[[ "$expected_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$ ]] || { printf 'Invalid provider version metadata.\n' >&2; return 1; }
|
|
1252
|
+
local comparison
|
|
1253
|
+
comparison="$(cats_version_compare "$detected_version" "$expected_version")"
|
|
1254
|
+
if [ -z "$detected_version" ] || [ "$comparison" = -1 ]; then is_outdated=true
|
|
1255
|
+
elif [ "$comparison" = 0 ] && [[ "$detected_version" == *-* ]] && [[ "$expected_version" != *-* ]]; then is_outdated=true; fi
|
|
1218
1256
|
fi
|
|
1219
1257
|
|
|
1220
1258
|
local planned_action='skip'
|
|
@@ -1293,25 +1331,26 @@ run_npm_cli_provider() {
|
|
|
1293
1331
|
fi
|
|
1294
1332
|
|
|
1295
1333
|
local applied=()
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
npm install -g --include=optional "$package_name" --force >/dev/null
|
|
1307
|
-
applied+=("${package_name}:reinstall")
|
|
1308
|
-
;;
|
|
1309
|
-
esac
|
|
1334
|
+
if [ "$dry_run" = true ]; then
|
|
1335
|
+
printf '{"helper":"%s","mode":"%s","status":"preview","plannedActions":["%s:%s"],"appliedChanges":[],"warnings":[],"manualSteps":[],"interruptions":[]}\n' "$helper_id" "$execution_mode" "$package_name" "$planned_action"
|
|
1336
|
+
return 0
|
|
1337
|
+
fi
|
|
1338
|
+
if [ "$check_only" != 'true' ] && [ "$dry_run" != 'true' ]; then
|
|
1339
|
+
remove_superseded_npm_packages "$package_name"
|
|
1340
|
+
fi
|
|
1341
|
+
npm install -g --include=optional --engine-strict --fetch-retries=0 --fetch-timeout=30000 "${package_name}@${expected_version}" >/dev/null || return 1
|
|
1342
|
+
applied+=("${package_name}:${planned_action}")
|
|
1343
|
+
hash -r
|
|
1310
1344
|
|
|
1311
1345
|
local final_command_path
|
|
1312
1346
|
final_command_path="$(command -v "$command_name" 2>/dev/null || true)"
|
|
1313
1347
|
local final_version
|
|
1314
|
-
final_version="$(npm list -g --depth=0 --json "$package_name" 2>/dev/null |
|
|
1348
|
+
final_version="$(npm list -g --depth=0 --json "$package_name" 2>/dev/null | node -e 'let s="";process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>{try{console.log(JSON.parse(s).dependencies?.[process.argv[1]]?.version||"")}catch{}})' "$package_name")"
|
|
1349
|
+
|
|
1350
|
+
if [ -z "$final_command_path" ] || [ "$final_version" != "$expected_version" ]; then
|
|
1351
|
+
printf 'Provider verification failed. Check npm prefix and PATH.\n' >&2
|
|
1352
|
+
return 1
|
|
1353
|
+
fi
|
|
1315
1354
|
|
|
1316
1355
|
if [ "$emit_json" = 'true' ]; then
|
|
1317
1356
|
printf '{'
|