@stacksjs/buddy 0.70.258 → 0.70.260

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.
Files changed (112) hide show
  1. package/dist/cli.d.ts +11 -1
  2. package/dist/cli.js +5 -164
  3. package/dist/commands/about.js +1 -35
  4. package/dist/commands/add.js +1 -25
  5. package/dist/commands/ai-context.js +4 -27
  6. package/dist/commands/auth.js +1 -68
  7. package/dist/commands/build.js +1 -221
  8. package/dist/commands/cd.js +8 -39
  9. package/dist/commands/changelog.js +1 -32
  10. package/dist/commands/clean.js +1 -44
  11. package/dist/commands/cloud.js +2 -519
  12. package/dist/commands/commit.js +1 -16
  13. package/dist/commands/completion.js +6 -42
  14. package/dist/commands/config-migrate.js +6 -94
  15. package/dist/commands/configure.js +2 -45
  16. package/dist/commands/create.js +1 -162
  17. package/dist/commands/deploy.js +13 -1676
  18. package/dist/commands/desktop-apple.js +12 -399
  19. package/dist/commands/dev.js +6 -1083
  20. package/dist/commands/dns.js +3 -103
  21. package/dist/commands/docs/buddy-commands.js +10 -132
  22. package/dist/commands/docs/buddy-commands.test.js +1 -38
  23. package/dist/commands/docs/framework-repo.js +1 -14
  24. package/dist/commands/docs/framework-repo.test.js +1 -68
  25. package/dist/commands/docs/generated-artifacts.js +3 -70
  26. package/dist/commands/docs/generated-artifacts.test.js +1 -19
  27. package/dist/commands/docs/links.js +2 -85
  28. package/dist/commands/docs/links.test.js +4 -66
  29. package/dist/commands/docs.js +1 -24
  30. package/dist/commands/doctor.js +2 -478
  31. package/dist/commands/domains.js +2 -152
  32. package/dist/commands/email.js +31 -503
  33. package/dist/commands/env.js +1 -312
  34. package/dist/commands/extension.js +1 -239
  35. package/dist/commands/features.js +9 -345
  36. package/dist/commands/fresh.js +1 -46
  37. package/dist/commands/generate.js +2 -152
  38. package/dist/commands/http.js +1 -33
  39. package/dist/commands/index.js +1 -57
  40. package/dist/commands/install.js +1 -22
  41. package/dist/commands/key.js +1 -23
  42. package/dist/commands/link.js +2 -147
  43. package/dist/commands/lint.js +2 -84
  44. package/dist/commands/list.js +1 -140
  45. package/dist/commands/mail.js +15 -1477
  46. package/dist/commands/maintenance.js +1 -141
  47. package/dist/commands/make.js +1 -392
  48. package/dist/commands/migrate-project.js +1 -49
  49. package/dist/commands/migrate.js +27 -625
  50. package/dist/commands/outdated.js +1 -19
  51. package/dist/commands/package.js +1 -17
  52. package/dist/commands/phone.js +17 -181
  53. package/dist/commands/ports.js +2 -118
  54. package/dist/commands/prepublish.js +1 -17
  55. package/dist/commands/projects.js +1 -29
  56. package/dist/commands/protocol/craft-evidence.js +4 -98
  57. package/dist/commands/protocol/craft-evidence.test.js +1 -20
  58. package/dist/commands/protocol/desktop-lifecycle-report.js +3 -57
  59. package/dist/commands/protocol/desktop-lifecycle-report.test.js +1 -32
  60. package/dist/commands/protocol/desktop-support.js +2 -32
  61. package/dist/commands/protocol/desktop-workflow.test.js +3 -35
  62. package/dist/commands/protocol/driver-registry.js +2 -71
  63. package/dist/commands/protocol/pantry-evidence.js +4 -144
  64. package/dist/commands/protocol/pantry-evidence.test.js +1 -29
  65. package/dist/commands/protocol/release-manifest.js +3 -102
  66. package/dist/commands/protocol/release-manifest.test.js +2 -34
  67. package/dist/commands/protocol/run-conformance.js +4 -346
  68. package/dist/commands/protocol/run-conformance.test.js +1 -52
  69. package/dist/commands/protocol/run-driver-contracts.js +4 -83
  70. package/dist/commands/protocol/run-driver-contracts.test.js +1 -18
  71. package/dist/commands/protocol/source-manifest.js +3 -113
  72. package/dist/commands/protocol/sync-suite.js +3 -136
  73. package/dist/commands/protocol/sync-suite.test.js +1 -44
  74. package/dist/commands/protocol.js +1 -60
  75. package/dist/commands/publish.js +8 -500
  76. package/dist/commands/queue.js +1 -248
  77. package/dist/commands/release.js +1 -42
  78. package/dist/commands/route.js +1 -21
  79. package/dist/commands/run-tool.js +1 -9
  80. package/dist/commands/saas.js +1 -25
  81. package/dist/commands/schedule.js +1 -61
  82. package/dist/commands/search.js +1 -84
  83. package/dist/commands/seed.js +1 -47
  84. package/dist/commands/serve.js +1 -55
  85. package/dist/commands/setup-ai.js +2 -121
  86. package/dist/commands/setup.js +2 -305
  87. package/dist/commands/share.js +1 -214
  88. package/dist/commands/sms.js +32 -319
  89. package/dist/commands/stacks.js +1 -72
  90. package/dist/commands/telemetry.js +1 -74
  91. package/dist/commands/test.js +1 -130
  92. package/dist/commands/tinker.js +1 -37
  93. package/dist/commands/types.js +1 -18
  94. package/dist/commands/upgrade.js +1 -98
  95. package/dist/commands/user.js +3 -84
  96. package/dist/commands/version.js +1 -14
  97. package/dist/config.js +1 -231
  98. package/dist/custom-cli.js +1 -23
  99. package/dist/database-preflight.js +1 -88
  100. package/dist/global-options.js +1 -4
  101. package/dist/index.js +1 -1
  102. package/dist/lazy-commands.js +1 -241
  103. package/dist/migrators/index.js +2 -62
  104. package/dist/migrators/laravel/index.js +1 -148
  105. package/dist/migrators/laravel/migrations.js +4 -231
  106. package/dist/migrators/laravel/models.js +8 -111
  107. package/dist/migrators/rails/index.js +1 -11
  108. package/dist/production-server.js +1 -257
  109. package/dist/project-setup.js +1 -36
  110. package/dist/serve-entry.js +1 -5
  111. package/dist/version-info.js +1 -5
  112. package/package.json +53 -46
@@ -1,90 +1,6 @@
1
- import { createHash } from "node:crypto";
2
- import {
3
- chmodSync,
4
- copyFileSync,
5
- existsSync,
6
- mkdirSync,
7
- readFileSync,
8
- rmSync,
9
- writeFileSync
10
- } from "node:fs";
11
- import { basename, join, resolve } from "node:path";
12
- import process from "node:process";
13
- import { log } from "@stacksjs/cli";
14
- import { projectPath, storagePath } from "@stacksjs/path";
15
- const REQUIRED_TOOLS = ["codesign", "security", "productbuild", "pkgutil", "xcrun"];
16
- function env(name) {
17
- return process.env[name]?.trim() || "";
18
- }
19
- function xml(value) {
20
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
21
- }
22
- function packageMetadata() {
23
- const packageJson = JSON.parse(readFileSync(projectPath("package.json"), "utf8"));
24
- return {
25
- name: packageJson.name || "Stacks",
26
- version: packageJson.version || "0.1.0"
27
- };
28
- }
29
- export function resolveAppleDesktopConfig(options = {}) {
30
- const metadata = packageMetadata(), provisioningProfile = options.provisioningProfile || env("APPLE_PROVISIONING_PROFILE"), apiKeyPath = options.apiKeyPath || env("APP_STORE_CONNECT_API_KEY_PATH");
31
- return {
32
- appName: options.appName || env("APPLE_APP_NAME") || env("APP_NAME") || metadata.name,
33
- bundleId: options.bundleId || env("APPLE_BUNDLE_ID"),
34
- teamId: options.teamId || env("APPLE_TEAM_ID"),
35
- version: options.appVersion || env("APPLE_APP_VERSION") || metadata.version,
36
- buildNumber: options.buildNumber || env("APPLE_BUILD_NUMBER") || env("GITHUB_RUN_NUMBER") || String(Math.floor(Date.now() / 1000)),
37
- minimumMacos: options.minimumMacos || env("APPLE_MINIMUM_MACOS") || "13.0",
38
- category: options.category || env("APPLE_APP_CATEGORY") || "public.app-category.productivity",
39
- appSigningIdentity: options.appSigningIdentity || env("APPLE_APP_SIGNING_IDENTITY"),
40
- installerSigningIdentity: options.installerSigningIdentity || env("APPLE_INSTALLER_SIGNING_IDENTITY"),
41
- provisioningProfile: provisioningProfile ? resolve(provisioningProfile) : "",
42
- apiKeyId: options.apiKeyId || env("APP_STORE_CONNECT_API_KEY_ID"),
43
- apiIssuerId: options.apiIssuerId || env("APP_STORE_CONNECT_API_ISSUER_ID"),
44
- apiKeyPath: apiKeyPath ? resolve(apiKeyPath) : "",
45
- icon: options.icon || env("APPLE_APP_ICON") || void 0
46
- };
47
- }
48
- export function validateAppleDesktopConfig(config, includeApi = !0) {
49
- const errors = [];
50
- if (process.platform !== "darwin")
51
- errors.push("Mac App Store packaging must run on macOS");
52
- if (!config.appName)
53
- errors.push("APPLE_APP_NAME or --app-name is required");
54
- if (!/^[A-Za-z0-9][A-Za-z0-9.-]+$/.test(config.bundleId))
55
- errors.push("APPLE_BUNDLE_ID must be a reverse-DNS bundle identifier");
56
- if (!/^[A-Z0-9]{10}$/.test(config.teamId))
57
- errors.push("APPLE_TEAM_ID must be the 10-character Apple Developer team ID");
58
- if (!/^\d+(?:\.\d+){0,2}$/.test(config.version))
59
- errors.push("The marketing version must contain one to three numeric components");
60
- if (!/^[A-Za-z0-9.-]+$/.test(config.buildNumber))
61
- errors.push("The build number must contain only letters, numbers, periods, and hyphens");
62
- if (!config.appSigningIdentity)
63
- errors.push("APPLE_APP_SIGNING_IDENTITY is required");
64
- if (!config.installerSigningIdentity)
65
- errors.push("APPLE_INSTALLER_SIGNING_IDENTITY is required");
66
- if (!config.provisioningProfile || !existsSync(config.provisioningProfile))
67
- errors.push("APPLE_PROVISIONING_PROFILE must point to an existing .provisionprofile file");
68
- if (config.icon && !existsSync(resolve(config.icon)))
69
- errors.push(`Apple app icon does not exist: ${config.icon}`);
70
- if (includeApi) {
71
- if (!config.apiKeyId)
72
- errors.push("APP_STORE_CONNECT_API_KEY_ID is required");
73
- if (!config.apiIssuerId)
74
- errors.push("APP_STORE_CONNECT_API_ISSUER_ID is required");
75
- if (!config.apiKeyPath || !existsSync(config.apiKeyPath))
76
- errors.push("APP_STORE_CONNECT_API_KEY_PATH must point to an existing .p8 file");
77
- }
78
- for (const tool of REQUIRED_TOOLS)
79
- if (!Bun.which(tool))
80
- errors.push(`Required Apple command is unavailable: ${tool}`);
81
- return errors;
82
- }
83
- export function renderInfoPlist(config, executable = "stacks-desktop") {
84
- const iconEntry = config.icon ? `
1
+ import{createHash}from"node:crypto";import{chmodSync,copyFileSync,existsSync,mkdirSync,readFileSync,rmSync,writeFileSync}from"node:fs";import{basename,join,resolve}from"node:path";import process from"node:process";import{log}from"@stacksjs/cli";import{projectPath,storagePath}from"@stacksjs/path";const REQUIRED_TOOLS=["codesign","security","productbuild","pkgutil","xcrun"];function env(name){return process.env[name]?.trim()||""}function xml(value){return value.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&apos;")}function packageMetadata(){const packageJson=JSON.parse(readFileSync(projectPath("package.json"),"utf8"));return{name:packageJson.name||"Stacks",version:packageJson.version||"0.1.0"}}export function resolveAppleDesktopConfig(options={}){const metadata=packageMetadata(),provisioningProfile=options.provisioningProfile||env("APPLE_PROVISIONING_PROFILE"),apiKeyPath=options.apiKeyPath||env("APP_STORE_CONNECT_API_KEY_PATH");return{appName:options.appName||env("APPLE_APP_NAME")||env("APP_NAME")||metadata.name,bundleId:options.bundleId||env("APPLE_BUNDLE_ID"),teamId:options.teamId||env("APPLE_TEAM_ID"),version:options.appVersion||env("APPLE_APP_VERSION")||metadata.version,buildNumber:options.buildNumber||env("APPLE_BUILD_NUMBER")||env("GITHUB_RUN_NUMBER")||String(Math.floor(Date.now()/1000)),minimumMacos:options.minimumMacos||env("APPLE_MINIMUM_MACOS")||"13.0",category:options.category||env("APPLE_APP_CATEGORY")||"public.app-category.productivity",appSigningIdentity:options.appSigningIdentity||env("APPLE_APP_SIGNING_IDENTITY"),installerSigningIdentity:options.installerSigningIdentity||env("APPLE_INSTALLER_SIGNING_IDENTITY"),provisioningProfile:provisioningProfile?resolve(provisioningProfile):"",apiKeyId:options.apiKeyId||env("APP_STORE_CONNECT_API_KEY_ID"),apiIssuerId:options.apiIssuerId||env("APP_STORE_CONNECT_API_ISSUER_ID"),apiKeyPath:apiKeyPath?resolve(apiKeyPath):"",icon:options.icon||env("APPLE_APP_ICON")||void 0}}export function validateAppleDesktopConfig(config,includeApi=!0){const errors=[];if(process.platform!=="darwin")errors.push("Mac App Store packaging must run on macOS");if(!config.appName)errors.push("APPLE_APP_NAME or --app-name is required");if(!/^[A-Za-z0-9][A-Za-z0-9.-]+$/.test(config.bundleId))errors.push("APPLE_BUNDLE_ID must be a reverse-DNS bundle identifier");if(!/^[A-Z0-9]{10}$/.test(config.teamId))errors.push("APPLE_TEAM_ID must be the 10-character Apple Developer team ID");if(!/^\d+(?:\.\d+){0,2}$/.test(config.version))errors.push("The marketing version must contain one to three numeric components");if(!/^[A-Za-z0-9.-]+$/.test(config.buildNumber))errors.push("The build number must contain only letters, numbers, periods, and hyphens");if(!config.appSigningIdentity)errors.push("APPLE_APP_SIGNING_IDENTITY is required");if(!config.installerSigningIdentity)errors.push("APPLE_INSTALLER_SIGNING_IDENTITY is required");if(!config.provisioningProfile||!existsSync(config.provisioningProfile))errors.push("APPLE_PROVISIONING_PROFILE must point to an existing .provisionprofile file");if(config.icon&&!existsSync(resolve(config.icon)))errors.push(`Apple app icon does not exist: ${config.icon}`);if(includeApi){if(!config.apiKeyId)errors.push("APP_STORE_CONNECT_API_KEY_ID is required");if(!config.apiIssuerId)errors.push("APP_STORE_CONNECT_API_ISSUER_ID is required");if(!config.apiKeyPath||!existsSync(config.apiKeyPath))errors.push("APP_STORE_CONNECT_API_KEY_PATH must point to an existing .p8 file")}for(const tool of REQUIRED_TOOLS)if(!Bun.which(tool))errors.push(`Required Apple command is unavailable: ${tool}`);return errors}export function renderInfoPlist(config,executable="stacks-desktop"){const iconEntry=config.icon?`
85
2
  <key>CFBundleIconFile</key>
86
- <string>AppIcon</string>` : "";
87
- return `<?xml version="1.0" encoding="UTF-8"?>
3
+ <string>AppIcon</string>`:"";return`<?xml version="1.0" encoding="UTF-8"?>
88
4
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
89
5
  <plist version="1.0">
90
6
  <dict>
@@ -112,10 +28,7 @@ export function renderInfoPlist(config, executable = "stacks-desktop") {
112
28
  <true/>
113
29
  </dict>
114
30
  </plist>
115
- `;
116
- }
117
- export function renderAppEntitlements(config) {
118
- return `<?xml version="1.0" encoding="UTF-8"?>
31
+ `}export function renderAppEntitlements(config){return`<?xml version="1.0" encoding="UTF-8"?>
119
32
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
120
33
  <plist version="1.0">
121
34
  <dict>
@@ -129,10 +42,7 @@ export function renderAppEntitlements(config) {
129
42
  <true/>
130
43
  </dict>
131
44
  </plist>
132
- `;
133
- }
134
- export function renderHelperEntitlements() {
135
- return `<?xml version="1.0" encoding="UTF-8"?>
45
+ `}export function renderHelperEntitlements(){return`<?xml version="1.0" encoding="UTF-8"?>
136
46
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
137
47
  <plist version="1.0">
138
48
  <dict>
@@ -142,10 +52,7 @@ export function renderHelperEntitlements() {
142
52
  <true/>
143
53
  </dict>
144
54
  </plist>
145
- `;
146
- }
147
- export function renderAppleWorkflowCaller() {
148
- return `name: Publish Mac App Store
55
+ `}export function renderAppleWorkflowCaller(){return`name: Publish Mac App Store
149
56
 
150
57
  on:
151
58
  workflow_dispatch:
@@ -186,304 +93,10 @@ jobs:
186
93
  s3-prefix: \${{ vars.RELEASE_S3_PREFIX }}
187
94
  s3-public-url: \${{ vars.RELEASE_S3_PUBLIC_URL }}
188
95
  secrets: inherit
189
- `;
190
- }
191
- function command(args, cwd = projectPath()) {
192
- const result = Bun.spawnSync(args, {
193
- cwd,
194
- stdin: "inherit",
195
- stdout: "inherit",
196
- stderr: "inherit"
197
- });
198
- if (result.exitCode !== 0)
199
- throw Error(`${args[0]} ${args.slice(1).join(" ")} exited with code ${result.exitCode}`);
200
- }
201
- function signingIdentityExists(identity) {
202
- if (!identity)
203
- return !1;
204
- const result = Bun.spawnSync(["security", "find-identity", "-v"], {
205
- stdout: "pipe",
206
- stderr: "pipe"
207
- });
208
- return result.exitCode === 0 && result.stdout.toString().includes(identity);
209
- }
210
- function provisioningProfileMatches(config) {
211
- if (!config.provisioningProfile || !existsSync(config.provisioningProfile))
212
- return !1;
213
- const result = Bun.spawnSync(["security", "cms", "-D", "-i", config.provisioningProfile], {
214
- stdout: "pipe",
215
- stderr: "pipe"
216
- });
217
- if (result.exitCode !== 0)
218
- return !1;
219
- const profile = result.stdout.toString();
220
- return profile.includes(config.bundleId) && profile.includes(config.teamId);
221
- }
222
- async function buildDesktop() {
223
- const { runAction } = await import("@stacksjs/actions"), { Action } = await import("@stacksjs/enums"), result = await runAction(Action.BuildDesktop);
224
- if (result.isErr)
225
- throw result.error;
226
- }
227
- function sha256(path) {
228
- return createHash("sha256").update(readFileSync(path)).digest("hex");
229
- }
230
- async function packageAppleDesktop(config, skipBuild = !1) {
231
- const errors = validateAppleDesktopConfig(config, !1);
232
- if (!signingIdentityExists(config.appSigningIdentity))
233
- errors.push(`App signing identity is not installed: ${config.appSigningIdentity}`);
234
- if (!signingIdentityExists(config.installerSigningIdentity))
235
- errors.push(`Installer signing identity is not installed: ${config.installerSigningIdentity}`);
236
- if (!provisioningProfileMatches(config))
237
- errors.push(`Provisioning profile does not match ${config.teamId}.${config.bundleId}`);
238
- if (errors.length)
239
- throw Error(errors.join(`
240
- `));
241
- if (!skipBuild)
242
- await buildDesktop();
243
- const desktopDist = storagePath("framework/desktop-dist"), launcher = join(desktopDist, "stacks-desktop"), runtime = join(desktopDist, "craft-runtime"), manifest = join(desktopDist, "desktop.json");
244
- for (const path of [launcher, runtime, manifest])
245
- if (!existsSync(path))
246
- throw Error(`Desktop build artifact is missing: ${path}`);
247
- const appleDir = join(desktopDist, "apple"), appPath = join(appleDir, `${config.appName}.app`), contents = join(appPath, "Contents"), macosDir = join(contents, "MacOS"), resourcesDir = join(contents, "Resources");
248
- if (existsSync(appleDir))
249
- rmSync(appleDir, { recursive: !0 });
250
- mkdirSync(macosDir, { recursive: !0 });
251
- mkdirSync(resourcesDir, { recursive: !0 });
252
- copyFileSync(launcher, join(macosDir, "stacks-desktop"));
253
- copyFileSync(runtime, join(macosDir, "craft-runtime"));
254
- copyFileSync(manifest, join(macosDir, "desktop.json"));
255
- copyFileSync(config.provisioningProfile, join(contents, "embedded.provisionprofile"));
256
- chmodSync(join(macosDir, "stacks-desktop"), 493);
257
- chmodSync(join(macosDir, "craft-runtime"), 493);
258
- if (config.icon)
259
- copyFileSync(resolve(config.icon), join(resourcesDir, "AppIcon.icns"));
260
- const infoPlist = join(contents, "Info.plist"), appEntitlements = join(appleDir, "app.entitlements"), helperEntitlements = join(appleDir, "helper.entitlements");
261
- writeFileSync(infoPlist, renderInfoPlist(config));
262
- writeFileSync(appEntitlements, renderAppEntitlements(config));
263
- writeFileSync(helperEntitlements, renderHelperEntitlements());
264
- command(["plutil", "-lint", infoPlist, appEntitlements, helperEntitlements]);
265
- command([
266
- "codesign",
267
- "--force",
268
- "--timestamp",
269
- "--options",
270
- "runtime",
271
- "--entitlements",
272
- helperEntitlements,
273
- "--sign",
274
- config.appSigningIdentity,
275
- join(macosDir, "craft-runtime")
276
- ]);
277
- command([
278
- "codesign",
279
- "--force",
280
- "--timestamp",
281
- "--options",
282
- "runtime",
283
- "--entitlements",
284
- appEntitlements,
285
- "--sign",
286
- config.appSigningIdentity,
287
- appPath
288
- ]);
289
- command(["codesign", "--verify", "--deep", "--strict", "--verbose=2", appPath]);
290
- command(["codesign", "-d", "--entitlements", ":-", appPath]);
291
- const packagePath = join(appleDir, `${config.appName}-${config.version}-${config.buildNumber}.pkg`);
292
- command([
293
- "productbuild",
294
- "--component",
295
- appPath,
296
- "/Applications",
297
- "--sign",
298
- config.installerSigningIdentity,
299
- packagePath
300
- ]);
301
- command(["pkgutil", "--check-signature", packagePath]);
302
- const packageHash = sha256(packagePath);
303
- writeFileSync(join(appleDir, "checksums.sha256"), `${packageHash} ${basename(packagePath)}
304
- `);
305
- writeFileSync(join(appleDir, "apple-provenance.json"), `${JSON.stringify({
306
- schemaVersion: "1.0.0",
307
- appName: config.appName,
308
- bundleId: config.bundleId,
309
- teamId: config.teamId,
310
- version: config.version,
311
- buildNumber: config.buildNumber,
312
- minimumMacos: config.minimumMacos,
313
- package: { name: basename(packagePath), sha256: packageHash },
314
- sourceRevision: Bun.spawnSync(["git", "rev-parse", "HEAD"], { cwd: projectPath() }).stdout.toString().trim(),
315
- craft: { sha256: sha256(join(macosDir, "craft-runtime")) }
316
- }, null, 2)}
317
- `);
318
- return packagePath;
319
- }
320
- function validateOrUpload(packagePath, config, validateOnly) {
321
- const errors = validateAppleDesktopConfig(config, !0);
322
- if (errors.length)
323
- throw Error(errors.join(`
324
- `));
325
- const common = [
326
- "--type",
327
- "macos",
328
- "--file",
329
- packagePath,
330
- "--apiKey",
331
- config.apiKeyId,
332
- "--apiIssuer",
333
- config.apiIssuerId
334
- ];
335
- process.env.API_PRIVATE_KEYS_DIR = resolve(config.apiKeyPath, "..");
336
- command(["xcrun", "altool", "--validate-app", ...common]);
337
- if (!validateOnly)
338
- command(["xcrun", "altool", "--upload-app", ...common]);
339
- }
340
- function fail(error) {
341
- log.error(error instanceof Error ? error.message : String(error));
342
- process.exit(1);
343
- }
344
- export function desktopApple(buddy) {
345
- buddy.command("desktop:apple:csr", "Generate local private keys and CSRs for Mac App Store distribution certificates").option("--common-name <name>", "Certificate request common name").option("--output <path>", "Directory for private keys and certificate requests").action(async (options) => {
346
- try {
347
- const metadata = packageMetadata(), outputDirectory = resolve(options.output || storagePath("framework/desktop-dist/apple/provisioning")), { generateMacCertificateRequests } = await import("ts-pantry");
348
- generateMacCertificateRequests({
349
- outputDirectory,
350
- commonName: options.commonName || metadata.name
351
- });
352
- log.success(`Generated Apple certificate requests and private keys in ${outputDirectory}`);
353
- } catch (error) {
354
- fail(error);
355
- }
356
- });
357
- buddy.command("desktop:apple:provision", "Plan or reconcile Apple Bundle ID, capabilities, certificates, and profile").option("--app-name <name>", "Mac App Store display name").option("--bundle-id <id>", "Reverse-DNS bundle identifier").option("--api-key-id <id>", "App Store Connect API key ID").option("--api-issuer-id <id>", "App Store Connect API issuer ID").option("--api-key-path <path>", "App Store Connect AuthKey .p8 file").option("--capabilities <types>", "Comma-separated Apple capability types").option("--app-certificate-csr <path>", "CSR for a missing Mac App Distribution certificate").option("--installer-certificate-csr <path>", "CSR for a missing Mac Installer Distribution certificate").option("--profile-name <name>", "Provisioning profile name").option("--output <path>", "Directory for the plan and downloaded Apple assets").option("--plan", "Report the idempotent Apple resource diff without mutating it").option("--apply", "Apply the Apple resource diff without revoking existing certificates").action(async (options) => {
358
- try {
359
- if (options.plan && options.apply)
360
- throw Error("Choose either --plan or --apply");
361
- const config = resolveAppleDesktopConfig(options);
362
- if (!config.bundleId)
363
- throw Error("APPLE_BUNDLE_ID or --bundle-id is required");
364
- if (!config.apiKeyId || !config.apiIssuerId || !config.apiKeyPath || !existsSync(config.apiKeyPath))
365
- throw Error("App Store Connect API key ID, issuer ID, and existing .p8 key path are required");
366
- const readCsr = (file) => {
367
- if (!file)
368
- return;
369
- const resolved = resolve(file);
370
- if (!existsSync(resolved))
371
- throw Error(`Apple certificate CSR does not exist: ${resolved}`);
372
- return readFileSync(resolved, "utf8");
373
- }, { exportAppleCertificateP12, provisionMacApp } = await import("ts-pantry"), result = await provisionMacApp({
374
- identifier: config.bundleId,
375
- name: config.appName,
376
- capabilities: options.capabilities?.split(",").map((value) => value.trim()).filter(Boolean),
377
- appCertificateCsr: readCsr(options.appCertificateCsr),
378
- installerCertificateCsr: readCsr(options.installerCertificateCsr),
379
- profileName: options.profileName,
380
- keyId: config.apiKeyId,
381
- issuerId: config.apiIssuerId,
382
- keyPath: config.apiKeyPath,
383
- checkOnly: !options.apply
384
- }), outputDirectory = resolve(options.output || storagePath("framework/desktop-dist/apple/provisioning"));
385
- mkdirSync(outputDirectory, { recursive: !0 });
386
- for (const certificate of result.certificates) {
387
- if (!certificate.certificateContent)
388
- continue;
389
- const fileName = certificate.type === "MAC_APP_DISTRIBUTION" ? "mac-app-distribution.cer" : "mac-installer-distribution.cer";
390
- writeFileSync(join(outputDirectory, fileName), Buffer.from(certificate.certificateContent, "base64"), { mode: 384 });
391
- }
392
- if (result.profile.profileContent)
393
- writeFileSync(join(outputDirectory, "mac-app-store.provisionprofile"), Buffer.from(result.profile.profileContent, "base64"), { mode: 384 });
394
- const certificatePassword = env("APPLE_CERTIFICATE_PASSWORD"), certificateExports = [
395
- {
396
- type: "MAC_APP_DISTRIBUTION",
397
- csr: options.appCertificateCsr,
398
- certificate: "mac-app-distribution.cer",
399
- output: "mac-app-distribution.p12",
400
- name: `${config.appName} Mac App Distribution`
401
- },
402
- {
403
- type: "MAC_INSTALLER_DISTRIBUTION",
404
- csr: options.installerCertificateCsr,
405
- certificate: "mac-installer-distribution.cer",
406
- output: "mac-installer-distribution.p12",
407
- name: `${config.appName} Mac Installer Distribution`
408
- }
409
- ];
410
- for (const certificateExport of certificateExports) {
411
- if (!result.certificates.find((item) => item.type === certificateExport.type)?.certificateContent || !certificateExport.csr || !certificatePassword)
412
- continue;
413
- exportAppleCertificateP12({
414
- certificatePath: join(outputDirectory, certificateExport.certificate),
415
- privateKeyPath: resolve(certificateExport.csr.replace(/\.csr$/i, ".key")),
416
- outputPath: join(outputDirectory, certificateExport.output),
417
- password: certificatePassword,
418
- name: certificateExport.name
419
- });
420
- }
421
- const certificates = result.certificates.map((item) => {
422
- const certificate = { ...item };
423
- delete certificate.certificateContent;
424
- return certificate;
425
- }), profile = { ...result.profile };
426
- delete profile.profileContent;
427
- const report = {
428
- ...result,
429
- certificates,
430
- profile
431
- }, reportPath = join(outputDirectory, "provisioning-plan.json");
432
- writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}
433
- `, { mode: 384 });
434
- log.success(`${options.apply ? "Applied" : "Planned"} Apple provisioning: ${reportPath}`);
435
- if (!result.appRecord.exists && result.appRecord.manualAction)
436
- log.warn(result.appRecord.manualAction);
437
- } catch (error) {
438
- fail(error);
439
- }
440
- });
441
- buddy.command("desktop:apple:doctor", "Validate Mac App Store tooling, credentials, certificates, and project metadata").option("--app-name <name>", "Mac App Store display name").option("--bundle-id <id>", "Reverse-DNS bundle identifier").option("--team-id <id>", "Apple Developer team ID").option("--app-signing-identity <identity>", "Mac App Distribution signing identity").option("--installer-signing-identity <identity>", "Mac Installer Distribution signing identity").option("--provisioning-profile <path>", "Mac App Store provisioning profile").option("--api-key-id <id>", "App Store Connect API key ID").option("--api-issuer-id <id>", "App Store Connect API issuer ID").option("--api-key-path <path>", "App Store Connect AuthKey .p8 file").action((options) => {
442
- try {
443
- const config = resolveAppleDesktopConfig(options), errors = validateAppleDesktopConfig(config, !0);
444
- if (!signingIdentityExists(config.appSigningIdentity))
445
- errors.push(`App signing identity is not installed: ${config.appSigningIdentity}`);
446
- if (!signingIdentityExists(config.installerSigningIdentity))
447
- errors.push(`Installer signing identity is not installed: ${config.installerSigningIdentity}`);
448
- if (!provisioningProfileMatches(config))
449
- errors.push(`Provisioning profile does not match ${config.teamId}.${config.bundleId}`);
450
- if (errors.length)
451
- throw Error(errors.join(`
452
- `));
453
- log.success(`Mac App Store prerequisites are ready for ${config.bundleId}`);
454
- } catch (error) {
455
- fail(error);
456
- }
457
- });
458
- buddy.command("desktop:apple:init", "Create a GitHub Actions caller for the reusable Stacks Mac App Store workflow").option("--force", "Replace an existing workflow").action((options) => {
459
- try {
460
- const workflowPath = projectPath(".github/workflows/apple-app-store.yml");
461
- if (existsSync(workflowPath) && !options.force)
462
- throw Error(`${workflowPath} already exists. Use --force to replace it.`);
463
- mkdirSync(resolve(workflowPath, ".."), { recursive: !0 });
464
- writeFileSync(workflowPath, renderAppleWorkflowCaller());
465
- log.success(`Created ${workflowPath}`);
466
- } catch (error) {
467
- fail(error);
468
- }
469
- });
470
- const addSharedOptions = (commandBuilder) => commandBuilder.option("--app-name <name>", "Mac App Store display name").option("--bundle-id <id>", "Reverse-DNS bundle identifier").option("--team-id <id>", "Apple Developer team ID").option("--app-version <version>", "Marketing version").option("--build-number <number>", "Unique App Store build number").option("--minimum-macos <version>", "Minimum supported macOS version").option("--category <category>", "LSApplicationCategoryType value").option("--app-signing-identity <identity>", "Mac App Distribution signing identity").option("--installer-signing-identity <identity>", "Mac Installer Distribution signing identity").option("--provisioning-profile <path>", "Mac App Store provisioning profile").option("--icon <path>", "Optional .icns app icon").option("--skip-build", "Package existing storage/framework/desktop-dist artifacts");
471
- addSharedOptions(buddy.command("desktop:apple:package", "Build, sandbox, sign, and package a Mac App Store desktop app")).action(async (options) => {
472
- try {
473
- const packagePath = await packageAppleDesktop(resolveAppleDesktopConfig(options), Boolean(options.skipBuild));
474
- log.success(`Created signed Mac App Store package ${packagePath}`);
475
- } catch (error) {
476
- fail(error);
477
- }
478
- });
479
- addSharedOptions(buddy.command("desktop:apple:publish", "Build and validate or upload a signed Mac App Store package")).option("--api-key-id <id>", "App Store Connect API key ID").option("--api-issuer-id <id>", "App Store Connect API issuer ID").option("--api-key-path <path>", "App Store Connect AuthKey .p8 file").option("--validate-only", "Validate with App Store Connect without uploading").option("--package-only", "Create the signed package without contacting App Store Connect").action(async (options) => {
480
- try {
481
- const config = resolveAppleDesktopConfig(options), packagePath = await packageAppleDesktop(config, Boolean(options.skipBuild));
482
- if (!options.packageOnly)
483
- validateOrUpload(packagePath, config, Boolean(options.validateOnly));
484
- log.success(options.packageOnly ? `Created signed Mac App Store package ${packagePath}` : options.validateOnly ? `Validated ${packagePath} with App Store Connect` : `Uploaded ${packagePath} to App Store Connect`);
485
- } catch (error) {
486
- fail(error);
487
- }
488
- });
489
- }
96
+ `}function command(args,cwd=projectPath()){const result=Bun.spawnSync(args,{cwd,stdin:"inherit",stdout:"inherit",stderr:"inherit"});if(result.exitCode!==0)throw Error(`${args[0]} ${args.slice(1).join(" ")} exited with code ${result.exitCode}`)}function signingIdentityExists(identity){if(!identity)return!1;const result=Bun.spawnSync(["security","find-identity","-v"],{stdout:"pipe",stderr:"pipe"});return result.exitCode===0&&result.stdout.toString().includes(identity)}function provisioningProfileMatches(config){if(!config.provisioningProfile||!existsSync(config.provisioningProfile))return!1;const result=Bun.spawnSync(["security","cms","-D","-i",config.provisioningProfile],{stdout:"pipe",stderr:"pipe"});if(result.exitCode!==0)return!1;const profile=result.stdout.toString();return profile.includes(config.bundleId)&&profile.includes(config.teamId)}async function buildDesktop(){const{runAction}=await import("@stacksjs/actions"),{Action}=await import("@stacksjs/enums"),result=await runAction(Action.BuildDesktop);if(result.isErr)throw result.error}function sha256(path){return createHash("sha256").update(readFileSync(path)).digest("hex")}async function packageAppleDesktop(config,skipBuild=!1){const errors=validateAppleDesktopConfig(config,!1);if(!signingIdentityExists(config.appSigningIdentity))errors.push(`App signing identity is not installed: ${config.appSigningIdentity}`);if(!signingIdentityExists(config.installerSigningIdentity))errors.push(`Installer signing identity is not installed: ${config.installerSigningIdentity}`);if(!provisioningProfileMatches(config))errors.push(`Provisioning profile does not match ${config.teamId}.${config.bundleId}`);if(errors.length)throw Error(errors.join(`
97
+ `));if(!skipBuild)await buildDesktop();const desktopDist=storagePath("framework/desktop-dist"),launcher=join(desktopDist,"stacks-desktop"),runtime=join(desktopDist,"craft-runtime"),manifest=join(desktopDist,"desktop.json");for(const path of[launcher,runtime,manifest])if(!existsSync(path))throw Error(`Desktop build artifact is missing: ${path}`);const appleDir=join(desktopDist,"apple"),appPath=join(appleDir,`${config.appName}.app`),contents=join(appPath,"Contents"),macosDir=join(contents,"MacOS"),resourcesDir=join(contents,"Resources");if(existsSync(appleDir))rmSync(appleDir,{recursive:!0});mkdirSync(macosDir,{recursive:!0});mkdirSync(resourcesDir,{recursive:!0});copyFileSync(launcher,join(macosDir,"stacks-desktop"));copyFileSync(runtime,join(macosDir,"craft-runtime"));copyFileSync(manifest,join(macosDir,"desktop.json"));copyFileSync(config.provisioningProfile,join(contents,"embedded.provisionprofile"));chmodSync(join(macosDir,"stacks-desktop"),493);chmodSync(join(macosDir,"craft-runtime"),493);if(config.icon)copyFileSync(resolve(config.icon),join(resourcesDir,"AppIcon.icns"));const infoPlist=join(contents,"Info.plist"),appEntitlements=join(appleDir,"app.entitlements"),helperEntitlements=join(appleDir,"helper.entitlements");writeFileSync(infoPlist,renderInfoPlist(config));writeFileSync(appEntitlements,renderAppEntitlements(config));writeFileSync(helperEntitlements,renderHelperEntitlements());command(["plutil","-lint",infoPlist,appEntitlements,helperEntitlements]);command(["codesign","--force","--timestamp","--options","runtime","--entitlements",helperEntitlements,"--sign",config.appSigningIdentity,join(macosDir,"craft-runtime")]);command(["codesign","--force","--timestamp","--options","runtime","--entitlements",appEntitlements,"--sign",config.appSigningIdentity,appPath]);command(["codesign","--verify","--deep","--strict","--verbose=2",appPath]);command(["codesign","-d","--entitlements",":-",appPath]);const packagePath=join(appleDir,`${config.appName}-${config.version}-${config.buildNumber}.pkg`);command(["productbuild","--component",appPath,"/Applications","--sign",config.installerSigningIdentity,packagePath]);command(["pkgutil","--check-signature",packagePath]);const packageHash=sha256(packagePath);writeFileSync(join(appleDir,"checksums.sha256"),`${packageHash} ${basename(packagePath)}
98
+ `);writeFileSync(join(appleDir,"apple-provenance.json"),`${JSON.stringify({schemaVersion:"1.0.0",appName:config.appName,bundleId:config.bundleId,teamId:config.teamId,version:config.version,buildNumber:config.buildNumber,minimumMacos:config.minimumMacos,package:{name:basename(packagePath),sha256:packageHash},sourceRevision:Bun.spawnSync(["git","rev-parse","HEAD"],{cwd:projectPath()}).stdout.toString().trim(),craft:{sha256:sha256(join(macosDir,"craft-runtime"))}},null,2)}
99
+ `);return packagePath}function validateOrUpload(packagePath,config,validateOnly){const errors=validateAppleDesktopConfig(config,!0);if(errors.length)throw Error(errors.join(`
100
+ `));const common=["--type","macos","--file",packagePath,"--apiKey",config.apiKeyId,"--apiIssuer",config.apiIssuerId];process.env.API_PRIVATE_KEYS_DIR=resolve(config.apiKeyPath,"..");command(["xcrun","altool","--validate-app",...common]);if(!validateOnly)command(["xcrun","altool","--upload-app",...common])}function fail(error){log.error(error instanceof Error?error.message:String(error));process.exit(1)}export function desktopApple(buddy){buddy.command("desktop:apple:csr","Generate local private keys and CSRs for Mac App Store distribution certificates").option("--common-name <name>","Certificate request common name").option("--output <path>","Directory for private keys and certificate requests").action(async(options)=>{try{const metadata=packageMetadata(),outputDirectory=resolve(options.output||storagePath("framework/desktop-dist/apple/provisioning")),{generateMacCertificateRequests}=await import("ts-pantry");generateMacCertificateRequests({outputDirectory,commonName:options.commonName||metadata.name});log.success(`Generated Apple certificate requests and private keys in ${outputDirectory}`)}catch(error){fail(error)}});buddy.command("desktop:apple:provision","Plan or reconcile Apple Bundle ID, capabilities, certificates, and profile").option("--app-name <name>","Mac App Store display name").option("--bundle-id <id>","Reverse-DNS bundle identifier").option("--api-key-id <id>","App Store Connect API key ID").option("--api-issuer-id <id>","App Store Connect API issuer ID").option("--api-key-path <path>","App Store Connect AuthKey .p8 file").option("--capabilities <types>","Comma-separated Apple capability types").option("--app-certificate-csr <path>","CSR for a missing Mac App Distribution certificate").option("--installer-certificate-csr <path>","CSR for a missing Mac Installer Distribution certificate").option("--profile-name <name>","Provisioning profile name").option("--output <path>","Directory for the plan and downloaded Apple assets").option("--plan","Report the idempotent Apple resource diff without mutating it").option("--apply","Apply the Apple resource diff without revoking existing certificates").action(async(options)=>{try{if(options.plan&&options.apply)throw Error("Choose either --plan or --apply");const config=resolveAppleDesktopConfig(options);if(!config.bundleId)throw Error("APPLE_BUNDLE_ID or --bundle-id is required");if(!config.apiKeyId||!config.apiIssuerId||!config.apiKeyPath||!existsSync(config.apiKeyPath))throw Error("App Store Connect API key ID, issuer ID, and existing .p8 key path are required");const readCsr=(file)=>{if(!file)return;const resolved=resolve(file);if(!existsSync(resolved))throw Error(`Apple certificate CSR does not exist: ${resolved}`);return readFileSync(resolved,"utf8")},{exportAppleCertificateP12,provisionMacApp}=await import("ts-pantry"),result=await provisionMacApp({identifier:config.bundleId,name:config.appName,capabilities:options.capabilities?.split(",").map((value)=>value.trim()).filter(Boolean),appCertificateCsr:readCsr(options.appCertificateCsr),installerCertificateCsr:readCsr(options.installerCertificateCsr),profileName:options.profileName,keyId:config.apiKeyId,issuerId:config.apiIssuerId,keyPath:config.apiKeyPath,checkOnly:!options.apply}),outputDirectory=resolve(options.output||storagePath("framework/desktop-dist/apple/provisioning"));mkdirSync(outputDirectory,{recursive:!0});for(const certificate of result.certificates){if(!certificate.certificateContent)continue;const fileName=certificate.type==="MAC_APP_DISTRIBUTION"?"mac-app-distribution.cer":"mac-installer-distribution.cer";writeFileSync(join(outputDirectory,fileName),Buffer.from(certificate.certificateContent,"base64"),{mode:384})}if(result.profile.profileContent)writeFileSync(join(outputDirectory,"mac-app-store.provisionprofile"),Buffer.from(result.profile.profileContent,"base64"),{mode:384});const certificatePassword=env("APPLE_CERTIFICATE_PASSWORD"),certificateExports=[{type:"MAC_APP_DISTRIBUTION",csr:options.appCertificateCsr,certificate:"mac-app-distribution.cer",output:"mac-app-distribution.p12",name:`${config.appName} Mac App Distribution`},{type:"MAC_INSTALLER_DISTRIBUTION",csr:options.installerCertificateCsr,certificate:"mac-installer-distribution.cer",output:"mac-installer-distribution.p12",name:`${config.appName} Mac Installer Distribution`}];for(const certificateExport of certificateExports){if(!result.certificates.find((item)=>item.type===certificateExport.type)?.certificateContent||!certificateExport.csr||!certificatePassword)continue;exportAppleCertificateP12({certificatePath:join(outputDirectory,certificateExport.certificate),privateKeyPath:resolve(certificateExport.csr.replace(/\.csr$/i,".key")),outputPath:join(outputDirectory,certificateExport.output),password:certificatePassword,name:certificateExport.name})}const certificates=result.certificates.map((item)=>{const certificate={...item};delete certificate.certificateContent;return certificate}),profile={...result.profile};delete profile.profileContent;const report={...result,certificates,profile},reportPath=join(outputDirectory,"provisioning-plan.json");writeFileSync(reportPath,`${JSON.stringify(report,null,2)}
101
+ `,{mode:384});log.success(`${options.apply?"Applied":"Planned"} Apple provisioning: ${reportPath}`);if(!result.appRecord.exists&&result.appRecord.manualAction)log.warn(result.appRecord.manualAction)}catch(error){fail(error)}});buddy.command("desktop:apple:doctor","Validate Mac App Store tooling, credentials, certificates, and project metadata").option("--app-name <name>","Mac App Store display name").option("--bundle-id <id>","Reverse-DNS bundle identifier").option("--team-id <id>","Apple Developer team ID").option("--app-signing-identity <identity>","Mac App Distribution signing identity").option("--installer-signing-identity <identity>","Mac Installer Distribution signing identity").option("--provisioning-profile <path>","Mac App Store provisioning profile").option("--api-key-id <id>","App Store Connect API key ID").option("--api-issuer-id <id>","App Store Connect API issuer ID").option("--api-key-path <path>","App Store Connect AuthKey .p8 file").action((options)=>{try{const config=resolveAppleDesktopConfig(options),errors=validateAppleDesktopConfig(config,!0);if(!signingIdentityExists(config.appSigningIdentity))errors.push(`App signing identity is not installed: ${config.appSigningIdentity}`);if(!signingIdentityExists(config.installerSigningIdentity))errors.push(`Installer signing identity is not installed: ${config.installerSigningIdentity}`);if(!provisioningProfileMatches(config))errors.push(`Provisioning profile does not match ${config.teamId}.${config.bundleId}`);if(errors.length)throw Error(errors.join(`
102
+ `));log.success(`Mac App Store prerequisites are ready for ${config.bundleId}`)}catch(error){fail(error)}});buddy.command("desktop:apple:init","Create a GitHub Actions caller for the reusable Stacks Mac App Store workflow").option("--force","Replace an existing workflow").action((options)=>{try{const workflowPath=projectPath(".github/workflows/apple-app-store.yml");if(existsSync(workflowPath)&&!options.force)throw Error(`${workflowPath} already exists. Use --force to replace it.`);mkdirSync(resolve(workflowPath,".."),{recursive:!0});writeFileSync(workflowPath,renderAppleWorkflowCaller());log.success(`Created ${workflowPath}`)}catch(error){fail(error)}});const addSharedOptions=(commandBuilder)=>commandBuilder.option("--app-name <name>","Mac App Store display name").option("--bundle-id <id>","Reverse-DNS bundle identifier").option("--team-id <id>","Apple Developer team ID").option("--app-version <version>","Marketing version").option("--build-number <number>","Unique App Store build number").option("--minimum-macos <version>","Minimum supported macOS version").option("--category <category>","LSApplicationCategoryType value").option("--app-signing-identity <identity>","Mac App Distribution signing identity").option("--installer-signing-identity <identity>","Mac Installer Distribution signing identity").option("--provisioning-profile <path>","Mac App Store provisioning profile").option("--icon <path>","Optional .icns app icon").option("--skip-build","Package existing storage/framework/desktop-dist artifacts");addSharedOptions(buddy.command("desktop:apple:package","Build, sandbox, sign, and package a Mac App Store desktop app")).action(async(options)=>{try{const packagePath=await packageAppleDesktop(resolveAppleDesktopConfig(options),Boolean(options.skipBuild));log.success(`Created signed Mac App Store package ${packagePath}`)}catch(error){fail(error)}});addSharedOptions(buddy.command("desktop:apple:publish","Build and validate or upload a signed Mac App Store package")).option("--api-key-id <id>","App Store Connect API key ID").option("--api-issuer-id <id>","App Store Connect API issuer ID").option("--api-key-path <path>","App Store Connect AuthKey .p8 file").option("--validate-only","Validate with App Store Connect without uploading").option("--package-only","Create the signed package without contacting App Store Connect").action(async(options)=>{try{const config=resolveAppleDesktopConfig(options),packagePath=await packageAppleDesktop(config,Boolean(options.skipBuild));if(!options.packageOnly)validateOrUpload(packagePath,config,Boolean(options.validateOnly));log.success(options.packageOnly?`Created signed Mac App Store package ${packagePath}`:options.validateOnly?`Validated ${packagePath} with App Store Connect`:`Uploaded ${packagePath} to App Store Connect`)}catch(error){fail(error)}})}