@sanity/cli 8.22.1 → 8.24.0

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 (98) hide show
  1. package/README.md +313 -0
  2. package/dist/actions/codemods/dashboard.js +136 -8
  3. package/dist/actions/codemods/dashboard.js.map +1 -1
  4. package/dist/actions/codemods/types.js.map +1 -1
  5. package/dist/actions/context/watchJob.js +9 -3
  6. package/dist/actions/context/watchJob.js.map +1 -1
  7. package/dist/actions/deploy/blueprintManaged.js +59 -0
  8. package/dist/actions/deploy/blueprintManaged.js.map +1 -0
  9. package/dist/actions/deploy/deployApp.js +117 -1
  10. package/dist/actions/deploy/deployApp.js.map +1 -1
  11. package/dist/actions/deploy/deployRunner.js.map +1 -1
  12. package/dist/actions/deploy/deployStudio.js +6 -31
  13. package/dist/actions/deploy/deployStudio.js.map +1 -1
  14. package/dist/actions/exec/runScript.worker.js +6 -2
  15. package/dist/actions/exec/runScript.worker.js.map +1 -1
  16. package/dist/actions/init/bootstrapLocalTemplate.js +35 -11
  17. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  18. package/dist/actions/init/createMediaLibraryCliConfig.js +12 -0
  19. package/dist/actions/init/createMediaLibraryCliConfig.js.map +1 -0
  20. package/dist/actions/init/determineMediaLibraryTemplate.js +14 -0
  21. package/dist/actions/init/determineMediaLibraryTemplate.js.map +1 -0
  22. package/dist/actions/init/initAction.js +35 -6
  23. package/dist/actions/init/initAction.js.map +1 -1
  24. package/dist/actions/init/initApp.js +81 -6
  25. package/dist/actions/init/initApp.js.map +1 -1
  26. package/dist/actions/init/offerAspectPull.js +81 -0
  27. package/dist/actions/init/offerAspectPull.js.map +1 -0
  28. package/dist/actions/init/project/getOrCreateDataset.js +8 -5
  29. package/dist/actions/init/project/getOrCreateDataset.js.map +1 -1
  30. package/dist/actions/init/project/getOrCreateProject.js +7 -5
  31. package/dist/actions/init/project/getOrCreateProject.js.map +1 -1
  32. package/dist/actions/init/project/getProjectDetails.js +25 -2
  33. package/dist/actions/init/project/getProjectDetails.js.map +1 -1
  34. package/dist/actions/init/project/promptUserForOrganization.js +6 -4
  35. package/dist/actions/init/project/promptUserForOrganization.js.map +1 -1
  36. package/dist/actions/init/templates/index.js +3 -0
  37. package/dist/actions/init/templates/index.js.map +1 -1
  38. package/dist/actions/init/templates/mediaLibraryConfig.js +51 -0
  39. package/dist/actions/init/templates/mediaLibraryConfig.js.map +1 -0
  40. package/dist/actions/media/aspectName.js +8 -0
  41. package/dist/actions/media/aspectName.js.map +1 -0
  42. package/dist/actions/media/aspectSync/contract.js +163 -0
  43. package/dist/actions/media/aspectSync/contract.js.map +1 -0
  44. package/dist/actions/media/aspectSync/syncAspects.js +115 -0
  45. package/dist/actions/media/aspectSync/syncAspects.js.map +1 -0
  46. package/dist/actions/media/cliConfigFields.js +192 -0
  47. package/dist/actions/media/cliConfigFields.js.map +1 -0
  48. package/dist/actions/media/pullAspects.js +225 -0
  49. package/dist/actions/media/pullAspects.js.map +1 -0
  50. package/dist/actions/media/resolveMediaLibraryId.js +83 -0
  51. package/dist/actions/media/resolveMediaLibraryId.js.map +1 -0
  52. package/dist/commands/codemod.js +1 -0
  53. package/dist/commands/codemod.js.map +1 -1
  54. package/dist/commands/context/build.js +2 -2
  55. package/dist/commands/context/build.js.map +1 -1
  56. package/dist/commands/context/entries/get.js +83 -0
  57. package/dist/commands/context/entries/get.js.map +1 -0
  58. package/dist/commands/context/entries/list.js +82 -0
  59. package/dist/commands/context/entries/list.js.map +1 -0
  60. package/dist/commands/context/entries/rebuild.js +95 -0
  61. package/dist/commands/context/entries/rebuild.js.map +1 -0
  62. package/dist/commands/context/issues/apply.js +86 -0
  63. package/dist/commands/context/issues/apply.js.map +1 -0
  64. package/dist/commands/context/issues/dismiss.js +52 -0
  65. package/dist/commands/context/issues/dismiss.js.map +1 -0
  66. package/dist/commands/context/issues/get.js +105 -0
  67. package/dist/commands/context/issues/get.js.map +1 -0
  68. package/dist/commands/context/issues/list.js +128 -0
  69. package/dist/commands/context/issues/list.js.map +1 -0
  70. package/dist/commands/context/issues/reopen.js +53 -0
  71. package/dist/commands/context/issues/reopen.js.map +1 -0
  72. package/dist/commands/context/issues/resolve.js +137 -0
  73. package/dist/commands/context/issues/resolve.js.map +1 -0
  74. package/dist/commands/context/jobs/get.js +2 -2
  75. package/dist/commands/context/jobs/get.js.map +1 -1
  76. package/dist/commands/context/query.js +92 -0
  77. package/dist/commands/context/query.js.map +1 -0
  78. package/dist/commands/deploy.js +13 -0
  79. package/dist/commands/deploy.js.map +1 -1
  80. package/dist/commands/media/prune-aspect-data.js +170 -0
  81. package/dist/commands/media/prune-aspect-data.js.map +1 -0
  82. package/dist/commands/media/pull-aspects.js +309 -0
  83. package/dist/commands/media/pull-aspects.js.map +1 -0
  84. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +17 -0
  85. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  86. package/dist/services/context.js +96 -3
  87. package/dist/services/context.js.map +1 -1
  88. package/dist/services/mediaLibraries.js +175 -8
  89. package/dist/services/mediaLibraries.js.map +1 -1
  90. package/dist/util/searchChoices.js +52 -0
  91. package/dist/util/searchChoices.js.map +1 -0
  92. package/oclif.manifest.json +2134 -1445
  93. package/package.json +9 -8
  94. package/templates/media-library-config/README.md +52 -0
  95. package/templates/media-library-config/eslint.config.txt +52 -0
  96. package/templates/media-library-config/src/fields/caption.tsx +29 -0
  97. package/templates/media-library-config/src/fields/notes.tsx +54 -0
  98. package/templates/shopify/.gitignore +0 -26
package/README.md CHANGED
@@ -36,14 +36,24 @@ Code for sanity cli
36
36
  - [`sanity context build KNOWLEDGEBASEID`](#sanity-context-build-knowledgebaseid)
37
37
  - [`sanity context create`](#sanity-context-create)
38
38
  - [`sanity context delete KNOWLEDGEBASEID`](#sanity-context-delete-knowledgebaseid)
39
+ - [`sanity context entries get KNOWLEDGEBASEID PATH`](#sanity-context-entries-get-knowledgebaseid-path)
40
+ - [`sanity context entries list KNOWLEDGEBASEID`](#sanity-context-entries-list-knowledgebaseid)
41
+ - [`sanity context entries rebuild KNOWLEDGEBASEID PATH`](#sanity-context-entries-rebuild-knowledgebaseid-path)
39
42
  - [`sanity context get KNOWLEDGEBASEID`](#sanity-context-get-knowledgebaseid)
40
43
  - [`sanity context imports create KNOWLEDGEBASEID`](#sanity-context-imports-create-knowledgebaseid)
41
44
  - [`sanity context imports delete KNOWLEDGEBASEID IMPORTID`](#sanity-context-imports-delete-knowledgebaseid-importid)
42
45
  - [`sanity context imports download KNOWLEDGEBASEID IMPORTID`](#sanity-context-imports-download-knowledgebaseid-importid)
43
46
  - [`sanity context imports get KNOWLEDGEBASEID IMPORTID`](#sanity-context-imports-get-knowledgebaseid-importid)
44
47
  - [`sanity context imports list KNOWLEDGEBASEID`](#sanity-context-imports-list-knowledgebaseid)
48
+ - [`sanity context issues apply KNOWLEDGEBASEID ISSUEID`](#sanity-context-issues-apply-knowledgebaseid-issueid)
49
+ - [`sanity context issues dismiss KNOWLEDGEBASEID ISSUEID`](#sanity-context-issues-dismiss-knowledgebaseid-issueid)
50
+ - [`sanity context issues get KNOWLEDGEBASEID ISSUEID`](#sanity-context-issues-get-knowledgebaseid-issueid)
51
+ - [`sanity context issues list KNOWLEDGEBASEID`](#sanity-context-issues-list-knowledgebaseid)
52
+ - [`sanity context issues reopen KNOWLEDGEBASEID ISSUEID`](#sanity-context-issues-reopen-knowledgebaseid-issueid)
53
+ - [`sanity context issues resolve KNOWLEDGEBASEID ISSUEID`](#sanity-context-issues-resolve-knowledgebaseid-issueid)
45
54
  - [`sanity context jobs get KNOWLEDGEBASEID JOBID`](#sanity-context-jobs-get-knowledgebaseid-jobid)
46
55
  - [`sanity context list`](#sanity-context-list)
56
+ - [`sanity context query QUERY`](#sanity-context-query-query)
47
57
  - [`sanity context refresh KNOWLEDGEBASEID`](#sanity-context-refresh-knowledgebaseid)
48
58
  - [`sanity context update KNOWLEDGEBASEID`](#sanity-context-update-knowledgebaseid)
49
59
  - [`sanity cors add ORIGIN`](#sanity-cors-add-origin)
@@ -1060,6 +1070,89 @@ EXAMPLES
1060
1070
  $ sanity context delete kb-abc123 --yes
1061
1071
  ```
1062
1072
 
1073
+ ## `sanity context entries get KNOWLEDGEBASEID PATH`
1074
+
1075
+ Get an entry and its content
1076
+
1077
+ ```
1078
+ USAGE
1079
+ $ sanity context entries get KNOWLEDGEBASEID PATH [--json]
1080
+
1081
+ ARGUMENTS
1082
+ KNOWLEDGEBASEID Knowledge base ID
1083
+ PATH Entry path, as listed by `sanity context entries list`
1084
+
1085
+ GLOBAL FLAGS
1086
+ --json Format output as json.
1087
+
1088
+ DESCRIPTION
1089
+ Get an entry and its content
1090
+
1091
+ EXAMPLES
1092
+ Print an entry and its content
1093
+
1094
+ $ sanity context entries get kb-abc123 billing/refunds
1095
+
1096
+ Output the entry, including citations, as JSON
1097
+
1098
+ $ sanity context entries get kb-abc123 billing/refunds --json
1099
+ ```
1100
+
1101
+ ## `sanity context entries list KNOWLEDGEBASEID`
1102
+
1103
+ List the entries a knowledge base build produced
1104
+
1105
+ ```
1106
+ USAGE
1107
+ $ sanity context entries list KNOWLEDGEBASEID [--json]
1108
+
1109
+ ARGUMENTS
1110
+ KNOWLEDGEBASEID Knowledge base ID
1111
+
1112
+ GLOBAL FLAGS
1113
+ --json Format output as json.
1114
+
1115
+ DESCRIPTION
1116
+ List the entries a knowledge base build produced
1117
+
1118
+ EXAMPLES
1119
+ List all entries for a knowledge base
1120
+
1121
+ $ sanity context entries list kb-abc123
1122
+
1123
+ Output entries as JSON
1124
+
1125
+ $ sanity context entries list kb-abc123 --json
1126
+ ```
1127
+
1128
+ ## `sanity context entries rebuild KNOWLEDGEBASEID PATH`
1129
+
1130
+ Rebuild one entry from its sources
1131
+
1132
+ ```
1133
+ USAGE
1134
+ $ sanity context entries rebuild KNOWLEDGEBASEID PATH [--watch]
1135
+
1136
+ ARGUMENTS
1137
+ KNOWLEDGEBASEID Knowledge base ID
1138
+ PATH Entry path, as listed by `sanity context entries list`
1139
+
1140
+ FLAGS
1141
+ --watch Wait for the rebuild to finish, exiting non-zero if it fails
1142
+
1143
+ DESCRIPTION
1144
+ Rebuild one entry from its sources
1145
+
1146
+ EXAMPLES
1147
+ Start a rebuild and return the job ID
1148
+
1149
+ $ sanity context entries rebuild kb-abc123 billing/refunds
1150
+
1151
+ Rebuild an entry and wait for it to finish (non-zero exit on failure)
1152
+
1153
+ $ sanity context entries rebuild kb-abc123 billing/refunds --watch
1154
+ ```
1155
+
1063
1156
  ## `sanity context get KNOWLEDGEBASEID`
1064
1157
 
1065
1158
  Get details of a knowledge base
@@ -1239,6 +1332,192 @@ EXAMPLES
1239
1332
  $ sanity context imports list kb-abc123 --json
1240
1333
  ```
1241
1334
 
1335
+ ## `sanity context issues apply KNOWLEDGEBASEID ISSUEID`
1336
+
1337
+ Accept and apply issues to a knowledge base
1338
+
1339
+ ```
1340
+ USAGE
1341
+ $ sanity context issues apply KNOWLEDGEBASEID ISSUEID... [--watch]
1342
+
1343
+ ARGUMENTS
1344
+ KNOWLEDGEBASEID Knowledge base ID
1345
+ ISSUEID... ID of an issue to accept and apply (pass several to apply them in one batch). Conflicts can't be
1346
+ applied; resolve them with `sanity context issues resolve`
1347
+
1348
+ FLAGS
1349
+ --watch Wait for the apply to finish, exiting non-zero if it fails
1350
+
1351
+ DESCRIPTION
1352
+ Accept and apply issues to a knowledge base
1353
+
1354
+ EXAMPLES
1355
+ Accept and apply two issues in one batch
1356
+
1357
+ $ sanity context issues apply kb-abc123 issue.def456 issue.ghi789
1358
+
1359
+ Apply an issue and wait for it to finish (non-zero exit on failure)
1360
+
1361
+ $ sanity context issues apply kb-abc123 issue.def456 --watch
1362
+ ```
1363
+
1364
+ ## `sanity context issues dismiss KNOWLEDGEBASEID ISSUEID`
1365
+
1366
+ Dismiss an issue
1367
+
1368
+ ```
1369
+ USAGE
1370
+ $ sanity context issues dismiss KNOWLEDGEBASEID ISSUEID
1371
+
1372
+ ARGUMENTS
1373
+ KNOWLEDGEBASEID Knowledge base ID
1374
+ ISSUEID Issue ID
1375
+
1376
+ DESCRIPTION
1377
+ Dismiss an issue
1378
+
1379
+ Dismissing is permanent: dismissed issues can't be reopened.
1380
+
1381
+ EXAMPLES
1382
+ Dismiss an issue
1383
+
1384
+ $ sanity context issues dismiss kb-abc123 issue.def456
1385
+ ```
1386
+
1387
+ ## `sanity context issues get KNOWLEDGEBASEID ISSUEID`
1388
+
1389
+ Get details of an issue
1390
+
1391
+ ```
1392
+ USAGE
1393
+ $ sanity context issues get KNOWLEDGEBASEID ISSUEID [--json]
1394
+
1395
+ ARGUMENTS
1396
+ KNOWLEDGEBASEID Knowledge base ID
1397
+ ISSUEID Issue ID
1398
+
1399
+ GLOBAL FLAGS
1400
+ --json Format output as json.
1401
+
1402
+ DESCRIPTION
1403
+ Get details of an issue
1404
+
1405
+ EXAMPLES
1406
+ Get details of a specific issue
1407
+
1408
+ $ sanity context issues get kb-abc123 issue.def456
1409
+
1410
+ Output the issue as JSON
1411
+
1412
+ $ sanity context issues get kb-abc123 issue.def456 --json
1413
+ ```
1414
+
1415
+ ## `sanity context issues list KNOWLEDGEBASEID`
1416
+
1417
+ List issues found by knowledge base builds
1418
+
1419
+ ```
1420
+ USAGE
1421
+ $ sanity context issues list KNOWLEDGEBASEID [--json] [--kind
1422
+ add_entry|conflict|gap|merge_entry|remove_entry|split_entry|update_required] [--scope <path>] [--severity
1423
+ critical|suggestion] [--status open|accepted|rejected]
1424
+
1425
+ ARGUMENTS
1426
+ KNOWLEDGEBASEID Knowledge base ID
1427
+
1428
+ FLAGS
1429
+ --kind=<option> Only list issues of this kind
1430
+ <options: add_entry|conflict|gap|merge_entry|remove_entry|split_entry|update_required>
1431
+ --scope=<path> Only list issues about this entry path or anything under it (`*` for knowledge-base-wide issues)
1432
+ --severity=<option> Only list issues of this severity
1433
+ <options: critical|suggestion>
1434
+ --status=<option> Only list issues with this status (rejected = dismissed, accepted = resolved or applied)
1435
+ <options: open|accepted|rejected>
1436
+
1437
+ GLOBAL FLAGS
1438
+ --json Format output as json.
1439
+
1440
+ DESCRIPTION
1441
+ List issues found by knowledge base builds
1442
+
1443
+ EXAMPLES
1444
+ List all issues for a knowledge base
1445
+
1446
+ $ sanity context issues list kb-abc123
1447
+
1448
+ List issues awaiting triage
1449
+
1450
+ $ sanity context issues list kb-abc123 --status open
1451
+
1452
+ List critical conflicts
1453
+
1454
+ $ sanity context issues list kb-abc123 --kind conflict --severity critical
1455
+
1456
+ List issues about entries under billing/
1457
+
1458
+ $ sanity context issues list kb-abc123 --scope billing
1459
+
1460
+ Output issues as JSON
1461
+
1462
+ $ sanity context issues list kb-abc123 --json
1463
+ ```
1464
+
1465
+ ## `sanity context issues reopen KNOWLEDGEBASEID ISSUEID`
1466
+
1467
+ Reopen a resolved conflict issue
1468
+
1469
+ ```
1470
+ USAGE
1471
+ $ sanity context issues reopen KNOWLEDGEBASEID ISSUEID
1472
+
1473
+ ARGUMENTS
1474
+ KNOWLEDGEBASEID Knowledge base ID
1475
+ ISSUEID Issue ID
1476
+
1477
+ DESCRIPTION
1478
+ Reopen a resolved conflict issue
1479
+
1480
+ EXAMPLES
1481
+ Return a resolved conflict issue to triage
1482
+
1483
+ $ sanity context issues reopen kb-abc123 issue.def456
1484
+ ```
1485
+
1486
+ ## `sanity context issues resolve KNOWLEDGEBASEID ISSUEID`
1487
+
1488
+ Resolve a conflict issue by choosing the correct side
1489
+
1490
+ ```
1491
+ USAGE
1492
+ $ sanity context issues resolve KNOWLEDGEBASEID ISSUEID [--side <value>] [--watch]
1493
+
1494
+ ARGUMENTS
1495
+ KNOWLEDGEBASEID Knowledge base ID
1496
+ ISSUEID Issue ID
1497
+
1498
+ FLAGS
1499
+ --side=<value> Index of the correct side, as listed by `sanity context issues get`
1500
+ --watch Wait for the entry rewrite to finish, exiting non-zero if it fails
1501
+
1502
+ DESCRIPTION
1503
+ Resolve a conflict issue by choosing the correct side
1504
+
1505
+ Resolving also creates a standing instruction that future builds follow. `sanity context issues reopen` removes it.
1506
+
1507
+ EXAMPLES
1508
+ Interactively choose the correct side of a conflict
1509
+
1510
+ $ sanity context issues resolve kb-abc123 issue.def456
1511
+
1512
+ Choose side 1 and wait for the entry to be rewritten
1513
+
1514
+ $ sanity context issues resolve kb-abc123 issue.def456 --side 1 --watch
1515
+
1516
+ Keep the entry as it is (for a conflict on a single entry)
1517
+
1518
+ $ sanity context issues resolve kb-abc123 issue.def456 --side 0
1519
+ ```
1520
+
1242
1521
  ## `sanity context jobs get KNOWLEDGEBASEID JOBID`
1243
1522
 
1244
1523
  Get the status of a knowledge base job
@@ -1301,6 +1580,40 @@ EXAMPLES
1301
1580
  $ sanity context list --organization org-abc123 --json
1302
1581
  ```
1303
1582
 
1583
+ ## `sanity context query QUERY`
1584
+
1585
+ Query an organization's Context documents with GROQ
1586
+
1587
+ ```
1588
+ USAGE
1589
+ $ sanity context query QUERY [--json] [--organization <id>] [--params <json>]
1590
+
1591
+ ARGUMENTS
1592
+ QUERY GROQ query to run against the organization's Context documents
1593
+
1594
+ FLAGS
1595
+ --params=<json> Query parameters as a JSON object
1596
+
1597
+ GLOBAL FLAGS
1598
+ --json Format output as json.
1599
+
1600
+ OVERRIDE FLAGS
1601
+ --organization=<id> Organization to query (overrides CLI configuration)
1602
+
1603
+ DESCRIPTION
1604
+ Query an organization's Context documents with GROQ
1605
+
1606
+ EXAMPLES
1607
+ List open issues across all knowledge bases
1608
+
1609
+ $ sanity context query '*[_type == "sanity.context.issue" && status == "open"]{_id, knowledgeBaseId}'
1610
+
1611
+ List the entry paths of one knowledge base as plain JSON
1612
+
1613
+ $ sanity context query '*[_type == "sanity.context.entry" && knowledgeBaseId == $kb].path' --params '{"kb": \
1614
+ "kb-abc123"}' --json
1615
+ ```
1616
+
1304
1617
  ## `sanity context refresh KNOWLEDGEBASEID`
1305
1618
 
1306
1619
  Refresh a knowledge base: re-check sources and apply what changed
@@ -1,17 +1,47 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
1
3
  import { findPathForFiles, getCliConfig, getLocalPackageVersion, getStudioConfig, isWorkbenchApp, tryFindStudioConfigPath } from '@sanity/cli-core';
2
- import { input, select } from '@sanity/cli-core/ux';
4
+ import { getYarnMajorVersion, readPackageJson } from '@sanity/cli-core/package-manager';
5
+ import { confirm, input, select } from '@sanity/cli-core/ux';
3
6
  import { toAppSlug } from '@sanity/workbench-cli/init';
7
+ import { execa } from 'execa';
4
8
  import { lt } from 'semver';
9
+ import yaml from 'yaml';
5
10
  import { getOrganizationGrants, listOrganizations } from '../../services/organizations.js';
6
11
  import { getProjectById } from '../../services/projects.js';
12
+ import { determineIsApp } from '../../util/determineIsApp.js';
13
+ import { detectWorkspace } from '../../util/packageManager/installationInfo/detectWorkspace.js';
14
+ import { getPackageManagerChoice, getPartialEnvWithNpmPath } from '../../util/packageManager/packageManagerChoice.js';
7
15
  import { getManageUrl } from '../projects/getManageUrl.js';
8
- // The first `sanity` release whose `sanity/cli` exports `defineApplication`
9
- const MIN_SANITY_VERSION = '6.12.0';
16
+ // `defineApplication` landed in 6.12.0; the Dashboard also needs the CLI fixes released since
17
+ const MIN_SANITY_VERSION = '6.20.0';
18
+ const MIN_SDK_VERSION = '3.9.1';
19
+ async function findOutdated(packages, workDir) {
20
+ const installed = await Promise.all(packages.map(({ name })=>getLocalPackageVersion(name, workDir)));
21
+ return packages.flatMap((pkg, index)=>{
22
+ const version = installed[index];
23
+ return version && lt(version, pkg.min) ? [
24
+ {
25
+ ...pkg,
26
+ version
27
+ }
28
+ ] : [];
29
+ });
30
+ }
31
+ // corepack's `packageManager: "yarn@4.9.1"` names the major even without a .yarnrc.yml
32
+ function declaredYarnMajor(field) {
33
+ const match = typeof field === 'string' ? /^yarn@(\d+)/.exec(field) : null;
34
+ return match ? Number.parseInt(match[1], 10) : undefined;
35
+ }
36
+ function listOutdated(packages) {
37
+ return packages.map(({ min, name, neededBy, version })=>` - ${name} ${version} (${neededBy} ${min} or later)`).join('\n');
38
+ }
10
39
  const purpose = 'Move an existing Studio or SDK app onto the Dashboard';
11
40
  const description = `
12
41
  Rewrites sanity.cli.ts (or .js) so the next \`sanity dev\` and \`sanity deploy\` run the project
13
42
  as a new Dashboard application. Asks for the application's title and slug, and looks up the
14
- organization from the project.
43
+ organization from the project. Offers to upgrade sanity (older than ${MIN_SANITY_VERSION}) and, in
44
+ SDK apps, @sanity/sdk and @sanity/sdk-react (older than ${MIN_SDK_VERSION}) to their latest versions.
15
45
 
16
46
  from: app: {organizationId: 'oAbc', entry: './src/App.tsx'}
17
47
  to: app: defineApplication({title: 'Acme', slug: 'acme', organizationId: 'oAbc', entry: './src/App.tsx'})
@@ -22,7 +52,7 @@ Dashboard build replaces the existing application.
22
52
  export const dashboard = {
23
53
  description,
24
54
  filename: 'dashboard.js',
25
- prepare: async ({ output, workDir })=>{
55
+ prepare: async ({ dry, output, workDir })=>{
26
56
  const config = await getCliConfig(workDir);
27
57
  if (isWorkbenchApp(config.app)) {
28
58
  throw new Error('This project is already a Dashboard application.');
@@ -88,9 +118,107 @@ export const dashboard = {
88
118
  if (appIdKey) {
89
119
  output.warn(`Remove \`${appIdKey}\` from your CLI config before you deploy. It points at your existing application, and deploying with it in place replaces that application with the Dashboard build.`);
90
120
  }
91
- const sanityVersion = await getLocalPackageVersion('sanity', workDir);
92
- if (sanityVersion && lt(sanityVersion, MIN_SANITY_VERSION)) {
93
- output.warn(`This project uses sanity ${sanityVersion}, and \`defineApplication\` needs ${MIN_SANITY_VERSION} or later. Upgrade sanity before you run \`sanity dev\` or \`sanity deploy\`.`);
121
+ const required = [
122
+ {
123
+ min: MIN_SANITY_VERSION,
124
+ name: 'sanity',
125
+ neededBy: 'the Dashboard needs'
126
+ },
127
+ ...determineIsApp(config) ? [
128
+ '@sanity/sdk',
129
+ '@sanity/sdk-react'
130
+ ].map((name)=>({
131
+ min: MIN_SDK_VERSION,
132
+ name,
133
+ neededBy: 'SDK apps need'
134
+ })) : []
135
+ ];
136
+ const outdated = await findOutdated(required, workDir);
137
+ if (outdated.length > 0) {
138
+ output.warn(`\`sanity dev\` and \`sanity deploy\` will fail until you upgrade:\n${listOutdated(outdated)}`);
139
+ const { chosen: packageManager } = await getPackageManagerChoice(workDir, {
140
+ interactive: false
141
+ });
142
+ const { root, yarnBerry } = await detectWorkspace(workDir);
143
+ const [{ dependencies, devDependencies }, rootManifest] = await Promise.all([
144
+ readPackageJson(path.join(workDir, 'package.json'), {
145
+ skipSchemaValidation: true
146
+ }),
147
+ readFile(path.join(root, 'package.json'), 'utf8').then(JSON.parse, ()=>null)
148
+ ]);
149
+ let pnpmOverrides = [];
150
+ if (packageManager === 'pnpm') {
151
+ const workspacePath = path.join(root, 'pnpm-workspace.yaml');
152
+ const workspaceConfig = await readFile(workspacePath, 'utf8').then(yaml.parse, ()=>null);
153
+ pnpmOverrides = Object.keys({
154
+ ...rootManifest?.pnpm?.overrides,
155
+ ...workspaceConfig?.overrides
156
+ });
157
+ }
158
+ // bun's upgrade leaves a catalog untouched, yarn's swaps `catalog:` for a plain range, and
159
+ // pnpm's does the same when `overrides` pins the package
160
+ const isUnupgradableCatalog = (name)=>(dependencies?.[name] ?? devDependencies?.[name] ?? '').startsWith('catalog:') && (packageManager === 'bun' || packageManager === 'yarn' || pnpmOverrides.some((key)=>key === name || key.startsWith(`${name}@`)));
161
+ const catalogued = outdated.filter(({ name })=>isUnupgradableCatalog(name));
162
+ const upgradable = outdated.filter(({ name })=>!isUnupgradableCatalog(name));
163
+ if (catalogued.length > 0) {
164
+ const targets = catalogued.map(({ min, name })=>`${name} to ^${min} or later`).join(', ');
165
+ const install = `then run \`${packageManager} install\``;
166
+ output.log(packageManager === 'pnpm' ? `pnpm can't upgrade catalog packages that \`overrides\` pin, so update them yourself: set ${targets} in the catalog and in \`overrides\`, ${install}.` : `${packageManager} can't upgrade catalog packages, so update them yourself: set ${targets} in the catalog in ${packageManager === 'bun' ? 'the root package.json' : '.yarnrc.yml'}, ${install}.`);
167
+ }
168
+ if (upgradable.length > 0) {
169
+ const names = upgradable.map(({ name })=>name);
170
+ const latest = names.map((name)=>`${name}@latest`);
171
+ // Berry dropped `yarn upgrade`, and the user agent only names yarn when the CLI itself was
172
+ // run through yarn, so take the project's own signals first
173
+ const isYarnBerry = yarnBerry || (declaredYarnMajor(rootManifest?.packageManager) ?? getYarnMajorVersion() ?? 1) >= 2;
174
+ // pnpm keeps `catalog:` and bumps the catalog entry only with `update --latest`
175
+ const command = {
176
+ bun: [
177
+ 'bun',
178
+ 'update',
179
+ ...latest
180
+ ],
181
+ manual: undefined,
182
+ npm: [
183
+ 'npm',
184
+ 'install',
185
+ '--legacy-peer-deps',
186
+ ...latest
187
+ ],
188
+ pnpm: [
189
+ 'pnpm',
190
+ 'update',
191
+ ...names,
192
+ '--latest'
193
+ ],
194
+ yarn: [
195
+ 'yarn',
196
+ isYarnBerry ? 'up' : 'upgrade',
197
+ ...latest
198
+ ]
199
+ }[packageManager];
200
+ if (!command) {
201
+ output.log(`Upgrade ${names.join(', ')} to the latest version with your package manager.`);
202
+ } else if (dry || !await confirm({
203
+ default: true,
204
+ message: `Upgrade ${names.join(', ')} to the latest version now?`
205
+ })) {
206
+ output.log(`Run \`${command.join(' ')}\` to upgrade.`);
207
+ } else {
208
+ output.log(`Running \`${command.join(' ')}\``);
209
+ // The version check below reports a failed upgrade, so the exit code isn't needed
210
+ await execa(command[0], command.slice(1), {
211
+ cwd: workDir,
212
+ env: getPartialEnvWithNpmPath(workDir),
213
+ reject: false,
214
+ stdio: 'inherit'
215
+ });
216
+ const stillOutdated = await findOutdated(upgradable, workDir);
217
+ if (stillOutdated.length > 0) {
218
+ output.warn(`These are still too old after the upgrade. Upgrade them before you run \`sanity dev\` or \`sanity deploy\`:\n${listOutdated(stillOutdated)}`);
219
+ }
220
+ }
221
+ }
94
222
  }
95
223
  // getCliConfig has already checked there is exactly one
96
224
  const cliConfigPaths = await findPathForFiles(workDir, [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/codemods/dashboard.ts"],"sourcesContent":["import {\n findPathForFiles,\n getCliConfig,\n getLocalPackageVersion,\n getStudioConfig,\n isWorkbenchApp,\n tryFindStudioConfigPath,\n} from '@sanity/cli-core'\nimport {input, select} from '@sanity/cli-core/ux'\nimport {toAppSlug} from '@sanity/workbench-cli/init'\nimport {lt} from 'semver'\n\nimport {getOrganizationGrants, listOrganizations} from '../../services/organizations.js'\nimport {getProjectById} from '../../services/projects.js'\nimport {getManageUrl} from '../projects/getManageUrl.js'\nimport {type CodeMod} from './types.js'\n\n// The first `sanity` release whose `sanity/cli` exports `defineApplication`\nconst MIN_SANITY_VERSION = '6.12.0'\n\nconst purpose = 'Move an existing Studio or SDK app onto the Dashboard'\nconst description = `\nRewrites sanity.cli.ts (or .js) so the next \\`sanity dev\\` and \\`sanity deploy\\` run the project\nas a new Dashboard application. Asks for the application's title and slug, and looks up the\norganization from the project.\n\nfrom: app: {organizationId: 'oAbc', entry: './src/App.tsx'}\n to: app: defineApplication({title: 'Acme', slug: 'acme', organizationId: 'oAbc', entry: './src/App.tsx'})\n\nThe existing deployment is left alone. Remove \\`deployment.appId\\` before deploying, or the\nDashboard build replaces the existing application.\n`.trim()\n\nexport const dashboard: CodeMod = {\n description,\n filename: 'dashboard.js',\n prepare: async ({output, workDir}) => {\n const config = await getCliConfig(workDir)\n if (isWorkbenchApp(config.app)) {\n throw new Error('This project is already a Dashboard application.')\n }\n\n const projectId = config.api?.projectId\n let organizationId = config.app?.organizationId\n // Deploy creates the application with both IDs, and the API rejects a project outside the\n // organization, so a project's organization is the only valid choice\n if (!organizationId && projectId) {\n organizationId = (await getProjectById(projectId)).organizationId ?? undefined\n if (!organizationId) {\n throw new Error(\n `Project ${projectId} isn't in an organization, and a Dashboard application needs one. Move the project into an organization at ${getManageUrl(projectId)}, then run this again.`,\n )\n }\n }\n if (!organizationId) {\n const choices = await Promise.all(\n (await listOrganizations()).map(async ({id, name}) => {\n // Grants can 401 for implicit memberships; treat any failure as no access\n const grants = await getOrganizationGrants(id).catch(() => null)\n const canDeploy = (grants?.['sanity.sdk.applications'] ?? []).some((resource) =>\n resource.grants.some((grant) => grant.name === 'deploy'),\n )\n return {\n disabled: canDeploy ? false : 'Insufficient permissions',\n name: `${name} [${id}]`,\n value: id,\n }\n }),\n )\n if (!choices.some((choice) => choice.disabled === false)) {\n throw new Error(\n \"You can't deploy applications in any of your organizations. Ask an organization administrator for access, then run this again.\",\n )\n }\n organizationId = await select({choices, message: 'Organization that owns the application:'})\n }\n\n let suggestedTitle = config.app?.title\n if (!suggestedTitle && (await tryFindStudioConfigPath(workDir))) {\n const studioConfig = await getStudioConfig(workDir, {resolvePlugins: false})\n suggestedTitle = Array.isArray(studioConfig) ? undefined : studioConfig.title\n }\n\n const title = await input({\n default: suggestedTitle,\n message: 'Application title:',\n validate: (value) => (value.trim() ? true : 'Enter a title for the application.'),\n })\n\n // A studio titled after its host would otherwise suggest the one slug that's rejected\n const suggestedSlug = toAppSlug(title) ?? undefined\n const slug = await input({\n default: suggestedSlug === config.studioHost ? undefined : suggestedSlug,\n message: 'Application slug (the hostname it deploys to):',\n validate: (value) => {\n if (toAppSlug(value) !== value) {\n return 'Use lowercase letters, numbers and hyphens, starting with a letter.'\n }\n if (value === config.studioHost) {\n return `\"${value}\" is your Studio's hostname (studioHost), so the deploy would fail. Choose a different slug.`\n }\n return true\n },\n })\n\n // `app.id` is the deprecated spelling and deploy still honours it\n const appIdKey = config.deployment?.appId ? 'deployment.appId' : config.app?.id && 'app.id'\n if (appIdKey) {\n output.warn(\n `Remove \\`${appIdKey}\\` from your CLI config before you deploy. It points at your existing application, and deploying with it in place replaces that application with the Dashboard build.`,\n )\n }\n\n const sanityVersion = await getLocalPackageVersion('sanity', workDir)\n if (sanityVersion && lt(sanityVersion, MIN_SANITY_VERSION)) {\n output.warn(\n `This project uses sanity ${sanityVersion}, and \\`defineApplication\\` needs ${MIN_SANITY_VERSION} or later. Upgrade sanity before you run \\`sanity dev\\` or \\`sanity deploy\\`.`,\n )\n }\n\n // getCliConfig has already checked there is exactly one\n const cliConfigPaths = await findPathForFiles(workDir, ['sanity.cli.ts', 'sanity.cli.js'])\n const paths = cliConfigPaths.filter((path) => path.exists).map((path) => path.path)\n\n return {options: {organizationId, slug, title: title.trim()}, paths}\n },\n purpose,\n}\n"],"names":["findPathForFiles","getCliConfig","getLocalPackageVersion","getStudioConfig","isWorkbenchApp","tryFindStudioConfigPath","input","select","toAppSlug","lt","getOrganizationGrants","listOrganizations","getProjectById","getManageUrl","MIN_SANITY_VERSION","purpose","description","trim","dashboard","filename","prepare","output","workDir","config","app","Error","projectId","api","organizationId","undefined","choices","Promise","all","map","id","name","grants","catch","canDeploy","some","resource","grant","disabled","value","choice","message","suggestedTitle","title","studioConfig","resolvePlugins","Array","isArray","default","validate","suggestedSlug","slug","studioHost","appIdKey","deployment","appId","warn","sanityVersion","cliConfigPaths","paths","filter","path","exists","options"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/codemods/dashboard.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {\n findPathForFiles,\n getCliConfig,\n getLocalPackageVersion,\n getStudioConfig,\n isWorkbenchApp,\n tryFindStudioConfigPath,\n} from '@sanity/cli-core'\nimport {getYarnMajorVersion, readPackageJson} from '@sanity/cli-core/package-manager'\nimport {confirm, input, select} from '@sanity/cli-core/ux'\nimport {toAppSlug} from '@sanity/workbench-cli/init'\nimport {execa} from 'execa'\nimport {lt} from 'semver'\nimport yaml from 'yaml'\n\nimport {getOrganizationGrants, listOrganizations} from '../../services/organizations.js'\nimport {getProjectById} from '../../services/projects.js'\nimport {determineIsApp} from '../../util/determineIsApp.js'\nimport {detectWorkspace} from '../../util/packageManager/installationInfo/detectWorkspace.js'\nimport {\n getPackageManagerChoice,\n getPartialEnvWithNpmPath,\n} from '../../util/packageManager/packageManagerChoice.js'\nimport {getManageUrl} from '../projects/getManageUrl.js'\nimport {type CodeMod} from './types.js'\n\n// `defineApplication` landed in 6.12.0; the Dashboard also needs the CLI fixes released since\nconst MIN_SANITY_VERSION = '6.20.0'\nconst MIN_SDK_VERSION = '3.9.1'\n\ninterface RequiredPackage {\n min: string\n name: string\n neededBy: string\n}\n\nasync function findOutdated(packages: RequiredPackage[], workDir: string) {\n const installed = await Promise.all(\n packages.map(({name}) => getLocalPackageVersion(name, workDir)),\n )\n return packages.flatMap((pkg, index) => {\n const version = installed[index]\n return version && lt(version, pkg.min) ? [{...pkg, version}] : []\n })\n}\n\n// corepack's `packageManager: \"yarn@4.9.1\"` names the major even without a .yarnrc.yml\nfunction declaredYarnMajor(field: unknown) {\n const match = typeof field === 'string' ? /^yarn@(\\d+)/.exec(field) : null\n return match ? Number.parseInt(match[1], 10) : undefined\n}\n\nfunction listOutdated(packages: Awaited<ReturnType<typeof findOutdated>>) {\n return packages\n .map(({min, name, neededBy, version}) => ` - ${name} ${version} (${neededBy} ${min} or later)`)\n .join('\\n')\n}\n\nconst purpose = 'Move an existing Studio or SDK app onto the Dashboard'\nconst description = `\nRewrites sanity.cli.ts (or .js) so the next \\`sanity dev\\` and \\`sanity deploy\\` run the project\nas a new Dashboard application. Asks for the application's title and slug, and looks up the\norganization from the project. Offers to upgrade sanity (older than ${MIN_SANITY_VERSION}) and, in\nSDK apps, @sanity/sdk and @sanity/sdk-react (older than ${MIN_SDK_VERSION}) to their latest versions.\n\nfrom: app: {organizationId: 'oAbc', entry: './src/App.tsx'}\n to: app: defineApplication({title: 'Acme', slug: 'acme', organizationId: 'oAbc', entry: './src/App.tsx'})\n\nThe existing deployment is left alone. Remove \\`deployment.appId\\` before deploying, or the\nDashboard build replaces the existing application.\n`.trim()\n\nexport const dashboard: CodeMod = {\n description,\n filename: 'dashboard.js',\n prepare: async ({dry, output, workDir}) => {\n const config = await getCliConfig(workDir)\n if (isWorkbenchApp(config.app)) {\n throw new Error('This project is already a Dashboard application.')\n }\n\n const projectId = config.api?.projectId\n let organizationId = config.app?.organizationId\n // Deploy creates the application with both IDs, and the API rejects a project outside the\n // organization, so a project's organization is the only valid choice\n if (!organizationId && projectId) {\n organizationId = (await getProjectById(projectId)).organizationId ?? undefined\n if (!organizationId) {\n throw new Error(\n `Project ${projectId} isn't in an organization, and a Dashboard application needs one. Move the project into an organization at ${getManageUrl(projectId)}, then run this again.`,\n )\n }\n }\n if (!organizationId) {\n const choices = await Promise.all(\n (await listOrganizations()).map(async ({id, name}) => {\n // Grants can 401 for implicit memberships; treat any failure as no access\n const grants = await getOrganizationGrants(id).catch(() => null)\n const canDeploy = (grants?.['sanity.sdk.applications'] ?? []).some((resource) =>\n resource.grants.some((grant) => grant.name === 'deploy'),\n )\n return {\n disabled: canDeploy ? false : 'Insufficient permissions',\n name: `${name} [${id}]`,\n value: id,\n }\n }),\n )\n if (!choices.some((choice) => choice.disabled === false)) {\n throw new Error(\n \"You can't deploy applications in any of your organizations. Ask an organization administrator for access, then run this again.\",\n )\n }\n organizationId = await select({choices, message: 'Organization that owns the application:'})\n }\n\n let suggestedTitle = config.app?.title\n if (!suggestedTitle && (await tryFindStudioConfigPath(workDir))) {\n const studioConfig = await getStudioConfig(workDir, {resolvePlugins: false})\n suggestedTitle = Array.isArray(studioConfig) ? undefined : studioConfig.title\n }\n\n const title = await input({\n default: suggestedTitle,\n message: 'Application title:',\n validate: (value) => (value.trim() ? true : 'Enter a title for the application.'),\n })\n\n // A studio titled after its host would otherwise suggest the one slug that's rejected\n const suggestedSlug = toAppSlug(title) ?? undefined\n const slug = await input({\n default: suggestedSlug === config.studioHost ? undefined : suggestedSlug,\n message: 'Application slug (the hostname it deploys to):',\n validate: (value) => {\n if (toAppSlug(value) !== value) {\n return 'Use lowercase letters, numbers and hyphens, starting with a letter.'\n }\n if (value === config.studioHost) {\n return `\"${value}\" is your Studio's hostname (studioHost), so the deploy would fail. Choose a different slug.`\n }\n return true\n },\n })\n\n // `app.id` is the deprecated spelling and deploy still honours it\n const appIdKey = config.deployment?.appId ? 'deployment.appId' : config.app?.id && 'app.id'\n if (appIdKey) {\n output.warn(\n `Remove \\`${appIdKey}\\` from your CLI config before you deploy. It points at your existing application, and deploying with it in place replaces that application with the Dashboard build.`,\n )\n }\n\n const required: RequiredPackage[] = [\n {min: MIN_SANITY_VERSION, name: 'sanity', neededBy: 'the Dashboard needs'},\n ...(determineIsApp(config)\n ? ['@sanity/sdk', '@sanity/sdk-react'].map((name) => ({\n min: MIN_SDK_VERSION,\n name,\n neededBy: 'SDK apps need',\n }))\n : []),\n ]\n const outdated = await findOutdated(required, workDir)\n if (outdated.length > 0) {\n output.warn(\n `\\`sanity dev\\` and \\`sanity deploy\\` will fail until you upgrade:\\n${listOutdated(outdated)}`,\n )\n\n const {chosen: packageManager} = await getPackageManagerChoice(workDir, {interactive: false})\n const {root, yarnBerry} = await detectWorkspace(workDir)\n const [{dependencies, devDependencies}, rootManifest] = await Promise.all([\n readPackageJson(path.join(workDir, 'package.json'), {skipSchemaValidation: true}),\n readFile(path.join(root, 'package.json'), 'utf8').then(JSON.parse, () => null),\n ])\n let pnpmOverrides: string[] = []\n if (packageManager === 'pnpm') {\n const workspacePath = path.join(root, 'pnpm-workspace.yaml')\n const workspaceConfig = await readFile(workspacePath, 'utf8').then(yaml.parse, () => null)\n pnpmOverrides = Object.keys({\n ...rootManifest?.pnpm?.overrides,\n ...workspaceConfig?.overrides,\n })\n }\n\n // bun's upgrade leaves a catalog untouched, yarn's swaps `catalog:` for a plain range, and\n // pnpm's does the same when `overrides` pins the package\n const isUnupgradableCatalog = (name: string) =>\n (dependencies?.[name] ?? devDependencies?.[name] ?? '').startsWith('catalog:') &&\n (packageManager === 'bun' ||\n packageManager === 'yarn' ||\n pnpmOverrides.some((key) => key === name || key.startsWith(`${name}@`)))\n const catalogued = outdated.filter(({name}) => isUnupgradableCatalog(name))\n const upgradable = outdated.filter(({name}) => !isUnupgradableCatalog(name))\n\n if (catalogued.length > 0) {\n const targets = catalogued.map(({min, name}) => `${name} to ^${min} or later`).join(', ')\n const install = `then run \\`${packageManager} install\\``\n output.log(\n packageManager === 'pnpm'\n ? `pnpm can't upgrade catalog packages that \\`overrides\\` pin, so update them yourself: set ${targets} in the catalog and in \\`overrides\\`, ${install}.`\n : `${packageManager} can't upgrade catalog packages, so update them yourself: set ${targets} in the catalog in ${packageManager === 'bun' ? 'the root package.json' : '.yarnrc.yml'}, ${install}.`,\n )\n }\n\n if (upgradable.length > 0) {\n const names = upgradable.map(({name}) => name)\n const latest = names.map((name) => `${name}@latest`)\n // Berry dropped `yarn upgrade`, and the user agent only names yarn when the CLI itself was\n // run through yarn, so take the project's own signals first\n const isYarnBerry =\n yarnBerry ||\n (declaredYarnMajor(rootManifest?.packageManager) ?? getYarnMajorVersion() ?? 1) >= 2\n // pnpm keeps `catalog:` and bumps the catalog entry only with `update --latest`\n const command = {\n bun: ['bun', 'update', ...latest],\n manual: undefined,\n npm: ['npm', 'install', '--legacy-peer-deps', ...latest],\n pnpm: ['pnpm', 'update', ...names, '--latest'],\n yarn: ['yarn', isYarnBerry ? 'up' : 'upgrade', ...latest],\n }[packageManager]\n\n if (!command) {\n output.log(`Upgrade ${names.join(', ')} to the latest version with your package manager.`)\n } else if (\n dry ||\n !(await confirm({\n default: true,\n message: `Upgrade ${names.join(', ')} to the latest version now?`,\n }))\n ) {\n output.log(`Run \\`${command.join(' ')}\\` to upgrade.`)\n } else {\n output.log(`Running \\`${command.join(' ')}\\``)\n // The version check below reports a failed upgrade, so the exit code isn't needed\n await execa(command[0], command.slice(1), {\n cwd: workDir,\n env: getPartialEnvWithNpmPath(workDir),\n reject: false,\n stdio: 'inherit',\n })\n const stillOutdated = await findOutdated(upgradable, workDir)\n if (stillOutdated.length > 0) {\n output.warn(\n `These are still too old after the upgrade. Upgrade them before you run \\`sanity dev\\` or \\`sanity deploy\\`:\\n${listOutdated(stillOutdated)}`,\n )\n }\n }\n }\n }\n\n // getCliConfig has already checked there is exactly one\n const cliConfigPaths = await findPathForFiles(workDir, ['sanity.cli.ts', 'sanity.cli.js'])\n const paths = cliConfigPaths.filter((path) => path.exists).map((path) => path.path)\n\n return {options: {organizationId, slug, title: title.trim()}, paths}\n },\n purpose,\n}\n"],"names":["readFile","path","findPathForFiles","getCliConfig","getLocalPackageVersion","getStudioConfig","isWorkbenchApp","tryFindStudioConfigPath","getYarnMajorVersion","readPackageJson","confirm","input","select","toAppSlug","execa","lt","yaml","getOrganizationGrants","listOrganizations","getProjectById","determineIsApp","detectWorkspace","getPackageManagerChoice","getPartialEnvWithNpmPath","getManageUrl","MIN_SANITY_VERSION","MIN_SDK_VERSION","findOutdated","packages","workDir","installed","Promise","all","map","name","flatMap","pkg","index","version","min","declaredYarnMajor","field","match","exec","Number","parseInt","undefined","listOutdated","neededBy","join","purpose","description","trim","dashboard","filename","prepare","dry","output","config","app","Error","projectId","api","organizationId","choices","id","grants","catch","canDeploy","some","resource","grant","disabled","value","choice","message","suggestedTitle","title","studioConfig","resolvePlugins","Array","isArray","default","validate","suggestedSlug","slug","studioHost","appIdKey","deployment","appId","warn","required","outdated","length","chosen","packageManager","interactive","root","yarnBerry","dependencies","devDependencies","rootManifest","skipSchemaValidation","then","JSON","parse","pnpmOverrides","workspacePath","workspaceConfig","Object","keys","pnpm","overrides","isUnupgradableCatalog","startsWith","key","catalogued","filter","upgradable","targets","install","log","names","latest","isYarnBerry","command","bun","manual","npm","yarn","slice","cwd","env","reject","stdio","stillOutdated","cliConfigPaths","paths","exists","options"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/codemods/types.ts"],"sourcesContent":["import {type Output} from '@sanity/cli-core'\n\nexport interface CodeMod {\n description: string\n // Must match filename in `cli/codemods/`\n filename: string\n purpose: string\n\n /**\n * Runs in the CLI process before the transform (prompts, API lookups). `options` reach the\n * transform's `options` argument; `paths` replace the default target of the whole directory.\n */\n prepare?: (context: {output: Output; workDir: string}) => Promise<{\n options: Record<string, string>\n paths: string[]\n }>\n verify?: (context: {workDir: string}) => Promise<void>\n}\n"],"names":[],"mappings":"AAEA,WAeC"}
1
+ {"version":3,"sources":["../../../src/actions/codemods/types.ts"],"sourcesContent":["import {type Output} from '@sanity/cli-core'\n\nexport interface CodeMod {\n description: string\n // Must match filename in `cli/codemods/`\n filename: string\n purpose: string\n\n /**\n * Runs in the CLI process before the transform (prompts, API lookups). `options` reach the\n * transform's `options` argument; `paths` replace the default target of the whole directory.\n */\n prepare?: (context: {dry: boolean; output: Output; workDir: string}) => Promise<{\n options: Record<string, string>\n paths: string[]\n }>\n verify?: (context: {workDir: string}) => Promise<void>\n}\n"],"names":[],"mappings":"AAEA,WAeC"}
@@ -1,5 +1,11 @@
1
1
  import { spinner } from '@sanity/cli-core/ux';
2
2
  import { waitForJob } from './waitForJob.js';
3
+ /**
4
+ * Error message for a job that ended in a non-succeeded terminal state,
5
+ * e.g. "Build failed: <reason>"
6
+ */ export function formatJobFailure(noun, job) {
7
+ return `${noun} ${job.status}${job.error ? `: ${job.error}` : ''}`;
8
+ }
3
9
  /**
4
10
  * Watch a knowledge base job with a spinner until it reaches a terminal
5
11
  * state, updating the spinner text with the job status on each poll.
@@ -18,13 +24,13 @@ import { waitForJob } from './waitForJob.js';
18
24
  }
19
25
  });
20
26
  } catch (error) {
21
- spin.fail();
27
+ spin.fail(label);
22
28
  throw error;
23
29
  }
24
30
  if (job.status === 'succeeded') {
25
- spin.succeed(successText);
31
+ spin.succeed(successText ?? label);
26
32
  } else {
27
- spin.fail();
33
+ spin.fail(label);
28
34
  }
29
35
  return job;
30
36
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/context/watchJob.ts"],"sourcesContent":["import {spinner} from '@sanity/cli-core/ux'\nimport {type Context} from '@sanity/client'\n\nimport {waitForJob} from './waitForJob.js'\n\n/**\n * Watch a knowledge base job with a spinner until it reaches a terminal\n * state, updating the spinner text with the job status on each poll.\n *\n * Fails the spinner and rethrows on polling errors, and fails it when the\n * terminal status is not `succeeded` — turning either outcome into a\n * command error (and exit code) is the caller's responsibility.\n */\nexport async function watchJob(\n knowledgeBaseId: string,\n jobId: string,\n options: {label: string; successText?: string},\n): Promise<Context.Job> {\n const {label, successText} = options\n const spin = spinner(label).start()\n\n let job: Context.Job\n try {\n job = await waitForJob(knowledgeBaseId, jobId, {\n onPoll: (pending) => {\n spin.text = `${label} (${pending.status})`\n },\n })\n } catch (error) {\n spin.fail()\n throw error\n }\n\n if (job.status === 'succeeded') {\n spin.succeed(successText)\n } else {\n spin.fail()\n }\n\n return job\n}\n"],"names":["spinner","waitForJob","watchJob","knowledgeBaseId","jobId","options","label","successText","spin","start","job","onPoll","pending","text","status","error","fail","succeed"],"mappings":"AAAA,SAAQA,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,UAAU,QAAO,kBAAiB;AAE1C;;;;;;;CAOC,GACD,OAAO,eAAeC,SACpBC,eAAuB,EACvBC,KAAa,EACbC,OAA8C;IAE9C,MAAM,EAACC,KAAK,EAAEC,WAAW,EAAC,GAAGF;IAC7B,MAAMG,OAAOR,QAAQM,OAAOG,KAAK;IAEjC,IAAIC;IACJ,IAAI;QACFA,MAAM,MAAMT,WAAWE,iBAAiBC,OAAO;YAC7CO,QAAQ,CAACC;gBACPJ,KAAKK,IAAI,GAAG,GAAGP,MAAM,EAAE,EAAEM,QAAQE,MAAM,CAAC,CAAC,CAAC;YAC5C;QACF;IACF,EAAE,OAAOC,OAAO;QACdP,KAAKQ,IAAI;QACT,MAAMD;IACR;IAEA,IAAIL,IAAII,MAAM,KAAK,aAAa;QAC9BN,KAAKS,OAAO,CAACV;IACf,OAAO;QACLC,KAAKQ,IAAI;IACX;IAEA,OAAON;AACT"}
1
+ {"version":3,"sources":["../../../src/actions/context/watchJob.ts"],"sourcesContent":["import {spinner} from '@sanity/cli-core/ux'\nimport {type Context} from '@sanity/client'\n\nimport {waitForJob} from './waitForJob.js'\n\n/**\n * Error message for a job that ended in a non-succeeded terminal state,\n * e.g. \"Build failed: <reason>\"\n */\nexport function formatJobFailure(noun: string, job: Context.Job): string {\n return `${noun} ${job.status}${job.error ? `: ${job.error}` : ''}`\n}\n\n/**\n * Watch a knowledge base job with a spinner until it reaches a terminal\n * state, updating the spinner text with the job status on each poll.\n *\n * Fails the spinner and rethrows on polling errors, and fails it when the\n * terminal status is not `succeeded` — turning either outcome into a\n * command error (and exit code) is the caller's responsibility.\n */\nexport async function watchJob(\n knowledgeBaseId: string,\n jobId: string,\n options: {label: string; successText?: string},\n): Promise<Context.Job> {\n const {label, successText} = options\n const spin = spinner(label).start()\n\n let job: Context.Job\n try {\n job = await waitForJob(knowledgeBaseId, jobId, {\n onPoll: (pending) => {\n spin.text = `${label} (${pending.status})`\n },\n })\n } catch (error) {\n spin.fail(label)\n throw error\n }\n\n if (job.status === 'succeeded') {\n spin.succeed(successText ?? label)\n } else {\n spin.fail(label)\n }\n\n return job\n}\n"],"names":["spinner","waitForJob","formatJobFailure","noun","job","status","error","watchJob","knowledgeBaseId","jobId","options","label","successText","spin","start","onPoll","pending","text","fail","succeed"],"mappings":"AAAA,SAAQA,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,UAAU,QAAO,kBAAiB;AAE1C;;;CAGC,GACD,OAAO,SAASC,iBAAiBC,IAAY,EAAEC,GAAgB;IAC7D,OAAO,GAAGD,KAAK,CAAC,EAAEC,IAAIC,MAAM,GAAGD,IAAIE,KAAK,GAAG,CAAC,EAAE,EAAEF,IAAIE,KAAK,EAAE,GAAG,IAAI;AACpE;AAEA;;;;;;;CAOC,GACD,OAAO,eAAeC,SACpBC,eAAuB,EACvBC,KAAa,EACbC,OAA8C;IAE9C,MAAM,EAACC,KAAK,EAAEC,WAAW,EAAC,GAAGF;IAC7B,MAAMG,OAAOb,QAAQW,OAAOG,KAAK;IAEjC,IAAIV;IACJ,IAAI;QACFA,MAAM,MAAMH,WAAWO,iBAAiBC,OAAO;YAC7CM,QAAQ,CAACC;gBACPH,KAAKI,IAAI,GAAG,GAAGN,MAAM,EAAE,EAAEK,QAAQX,MAAM,CAAC,CAAC,CAAC;YAC5C;QACF;IACF,EAAE,OAAOC,OAAO;QACdO,KAAKK,IAAI,CAACP;QACV,MAAML;IACR;IAEA,IAAIF,IAAIC,MAAM,KAAK,aAAa;QAC9BQ,KAAKM,OAAO,CAACP,eAAeD;IAC9B,OAAO;QACLE,KAAKK,IAAI,CAACP;IACZ;IAEA,OAAOP;AACT"}