@sanity/cli 7.7.1 → 7.9.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.
- package/README.md +17 -2
- package/dist/actions/auth/ensureAuthenticated.js +1 -1
- package/dist/actions/auth/ensureAuthenticated.js.map +1 -1
- package/dist/actions/auth/login/validateToken.js +1 -1
- package/dist/actions/auth/login/validateToken.js.map +1 -1
- package/dist/actions/build/buildApp.js +2 -3
- package/dist/actions/build/buildApp.js.map +1 -1
- package/dist/actions/build/buildStudio.js +1 -2
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/actions/deploy/createUserApplication.js +8 -8
- package/dist/actions/deploy/createUserApplication.js.map +1 -1
- package/dist/actions/deploy/deployApp.js +128 -26
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployChecks.js +97 -72
- package/dist/actions/deploy/deployChecks.js.map +1 -1
- package/dist/actions/deploy/deployRunner.js +8 -8
- package/dist/actions/deploy/deployRunner.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +129 -23
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/deploy/deploymentPlan.js +29 -30
- package/dist/actions/deploy/deploymentPlan.js.map +1 -1
- package/dist/actions/deploy/findUserApplication.js +39 -14
- package/dist/actions/deploy/findUserApplication.js.map +1 -1
- package/dist/actions/deploy/resolveDeployTarget.js +44 -0
- package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
- package/dist/actions/deploy/urlUtils.js +0 -4
- package/dist/actions/deploy/urlUtils.js.map +1 -1
- package/dist/actions/dev/servers/getDevServerConfig.js +1 -1
- package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
- package/dist/actions/dev/servers/startStudioDevServer.js +1 -2
- package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
- package/dist/actions/documents/types.js.map +1 -1
- package/dist/actions/documents/validate.js +2 -1
- package/dist/actions/documents/validate.js.map +1 -1
- package/dist/actions/graphql/SchemaError.js.map +1 -1
- package/dist/actions/graphql/extractGraphQLAPIs.js +3 -1
- package/dist/actions/graphql/extractGraphQLAPIs.js.map +1 -1
- package/dist/actions/manifest/extractCoreAppManifest.js +1 -1
- package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
- package/dist/actions/organizations/getOrganization.js +1 -1
- package/dist/actions/organizations/getOrganization.js.map +1 -1
- package/dist/actions/schema/validateAction.js +1 -1
- package/dist/actions/schema/validateAction.js.map +1 -1
- package/dist/actions/skills/setupSkills.js +1 -1
- package/dist/actions/skills/setupSkills.js.map +1 -1
- package/dist/actions/undeploy/adapters.js +101 -0
- package/dist/actions/undeploy/adapters.js.map +1 -0
- package/dist/actions/undeploy/runUndeploy.js +179 -0
- package/dist/actions/undeploy/runUndeploy.js.map +1 -0
- package/dist/actions/undeploy/undeployPlan.js +123 -0
- package/dist/actions/undeploy/undeployPlan.js.map +1 -0
- package/dist/commands/datasets/copy.js +2 -1
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/commands/documents/validate.js +18 -17
- package/dist/commands/documents/validate.js.map +1 -1
- package/dist/commands/mcp/configure.js +1 -1
- package/dist/commands/mcp/configure.js.map +1 -1
- package/dist/commands/projects/create.js +18 -13
- package/dist/commands/projects/create.js.map +1 -1
- package/dist/commands/projects/list.js +2 -1
- package/dist/commands/projects/list.js.map +1 -1
- package/dist/commands/schemas/validate.js +3 -2
- package/dist/commands/schemas/validate.js.map +1 -1
- package/dist/commands/skills/install.js +1 -1
- package/dist/commands/skills/install.js.map +1 -1
- package/dist/commands/tokens/list.js +1 -1
- package/dist/commands/tokens/list.js.map +1 -1
- package/dist/commands/undeploy.js +47 -73
- package/dist/commands/undeploy.js.map +1 -1
- package/dist/server/devServer.js.map +1 -1
- package/dist/util/checks.js +83 -0
- package/dist/util/checks.js.map +1 -0
- package/dist/util/toStderrOutput.js +13 -0
- package/dist/util/toStderrOutput.js.map +1 -0
- package/oclif.manifest.json +28 -1
- package/package.json +7 -8
- package/dist/actions/undeploy/getStudioOrAppUserApplication.js +0 -36
- package/dist/actions/undeploy/getStudioOrAppUserApplication.js.map +0 -1
- package/dist/util/compareDependencyVersions.js +0 -110
- package/dist/util/compareDependencyVersions.js.map +0 -1
- package/dist/util/getErrorMessage.js +0 -28
- package/dist/util/getErrorMessage.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/datasets/copy.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exit} from '@oclif/core/errors'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {Table} from 'console-table-printer'\nimport {formatDistance} from 'date-fns/formatDistance'\nimport {formatDistanceToNow} from 'date-fns/formatDistanceToNow'\nimport {parseISO} from 'date-fns/parseISO'\n\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {\n copyDataset,\n type CopyJobProgressEvent,\n type DatasetCopyJob,\n followCopyJobProgress,\n listDatasetCopyJobs,\n listDatasets,\n} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst copyDatasetDebug = subdebug('dataset:copy')\n\nexport class CopyDatasetCommand extends SanityCommand<typeof CopyDatasetCommand> {\n static override args = {\n source: Args.string({\n description: 'Name of the dataset to copy from',\n required: false,\n }),\n target: Args.string({\n description: 'Name of the dataset to copy to',\n required: false,\n }),\n }\n\n static override description = 'Copy a dataset or manage copy jobs'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively copy a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> source-dataset',\n description: 'Copy from source-dataset (prompts for target)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> source-dataset target-dataset',\n description: 'Copy from source-dataset to target-dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --skip-history source target',\n description: 'Copy without preserving document history (faster for large datasets)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --skip-content-releases source target',\n description: 'Copy without content release documents',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --detach source target',\n description: 'Start copy job without waiting for completion',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --attach <job-id>',\n description: 'Attach to a running copy job to follow progress',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --list',\n description: 'List all dataset copy jobs',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --list --offset 2 --limit 10',\n description: 'List copy jobs with pagination',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to copy dataset in',\n semantics: 'override',\n }),\n attach: Flags.string({\n description: 'Attach to the running copy process to show progress',\n exclusive: ['list', 'detach', 'skip-history'],\n required: false,\n }),\n detach: Flags.boolean({\n description: 'Start the copy without waiting for it to finish',\n exclusive: ['list', 'attach'],\n required: false,\n }),\n limit: Flags.integer({\n dependsOn: ['list'],\n description: 'Maximum number of jobs returned (default 10, max 1000)',\n max: 1000,\n required: false,\n }),\n list: Flags.boolean({\n description: 'Lists all dataset copy jobs',\n exclusive: ['attach', 'detach', 'skip-history'],\n required: false,\n }),\n offset: Flags.integer({\n dependsOn: ['list'],\n description: 'Start position in the list of jobs (default 0)',\n required: false,\n }),\n 'skip-content-releases': Flags.boolean({\n description: \"Don't copy content release documents to the target dataset\",\n exclusive: ['list', 'attach'],\n required: false,\n }),\n 'skip-history': Flags.boolean({\n description: \"Don't preserve document history on copy\",\n exclusive: ['list', 'attach'],\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:copy']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CopyDatasetCommand)\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'create', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n // Route to appropriate mode\n if (flags.list) {\n return this.handleListMode(projectId, flags)\n }\n\n if (flags.attach) {\n return this.handleAttachMode(projectId, flags.attach)\n }\n\n return this.handleCopyMode(projectId, args, flags)\n }\n\n private displayCopyJobsTable(jobs: DatasetCopyJob[]): void {\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'Job ID'},\n {alignment: 'left', name: 'sourceDataset', title: 'Source Dataset'},\n {alignment: 'left', name: 'targetDataset', title: 'Target Dataset'},\n {alignment: 'left', name: 'state', title: 'State'},\n {alignment: 'left', name: 'withHistory', title: 'With history'},\n {alignment: 'left', name: 'timeStarted', title: 'Time started'},\n {alignment: 'left', name: 'timeTaken', title: 'Time taken'},\n ],\n title: 'Dataset copy jobs for this project in descending order',\n })\n\n for (const job of jobs) {\n const {createdAt, id, sourceDataset, state, targetDataset, updatedAt, withHistory} = job\n\n let timeStarted = ''\n if (createdAt !== '') {\n timeStarted = formatDistanceToNow(parseISO(createdAt))\n }\n\n let timeTaken = ''\n if (updatedAt !== '') {\n timeTaken = formatDistance(parseISO(updatedAt), parseISO(createdAt))\n }\n\n let color: '' | 'green' | 'red' | 'yellow'\n switch (state) {\n case 'completed': {\n color = 'green'\n break\n }\n case 'failed': {\n color = 'red'\n break\n }\n case 'pending': {\n color = 'yellow'\n break\n }\n default: {\n color = ''\n }\n }\n\n table.addRow(\n {\n id,\n sourceDataset,\n state,\n targetDataset,\n timeStarted: `${timeStarted} ago`,\n timeTaken,\n withHistory,\n },\n {color},\n )\n }\n\n this.output.log(table.render())\n }\n\n private async handleAttachMode(projectId: string, jobId: string): Promise<void> {\n copyDatasetDebug('Attaching to copy job %s', jobId)\n\n if (jobId.trim() === '') {\n return this.output.error('Please supply a valid jobId', {exit: 1})\n }\n\n try {\n await this.subscribeToProgress(projectId, jobId)\n this.output.log(`Job ${styleText('green', jobId)} completed`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to attach to copy job: %s', message, error)\n return this.output.error(`Failed to attach to copy job: ${message}`, {exit: 1})\n }\n }\n\n private async handleCopyMode(\n projectId: string,\n args: {source?: string; target?: string},\n flags: {detach?: boolean; 'skip-content-releases'?: boolean; 'skip-history'?: boolean},\n ): Promise<void> {\n copyDatasetDebug('Starting copy mode')\n\n const skipHistory = Boolean(flags['skip-history'])\n const skipContentReleases = Boolean(flags['skip-content-releases'])\n\n // Get and validate source dataset\n let sourceDataset = args.source\n if (sourceDataset) {\n const nameError = validateDatasetName(sourceDataset)\n if (nameError) {\n return this.output.error(nameError, {exit: 1})\n }\n }\n\n let datasetsResponse\n try {\n datasetsResponse = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to fetch datasets: %s', message, error)\n return this.output.error(`Failed to fetch datasets: ${message}`, {exit: 1})\n }\n\n const datasetNames = new Set(datasetsResponse.map((ds) => ds.name))\n\n // Prompt for source if not provided\n if (!sourceDataset) {\n sourceDataset = await promptForDataset({\n datasets: datasetsResponse,\n })\n }\n\n if (!datasetNames.has(sourceDataset)) {\n return this.output.error(`Source dataset \"${sourceDataset}\" doesn't exist`, {exit: 1})\n }\n\n // Get and validate target dataset\n let targetDataset = args.target\n if (targetDataset) {\n const nameError = validateDatasetName(targetDataset)\n if (nameError) {\n return this.output.error(nameError, {exit: 1})\n }\n } else {\n targetDataset = await promptForDatasetName({\n message: 'Target dataset name:',\n })\n }\n\n if (datasetNames.has(targetDataset)) {\n return this.output.error(`Target dataset \"${targetDataset}\" already exists`, {exit: 1})\n }\n\n // Start the copy job\n try {\n this.output.log(\n `Copying dataset ${styleText('green', sourceDataset)} to ${styleText('green', targetDataset)}...`,\n )\n\n if (!skipHistory) {\n this.output.log(\n `Note: You can run this command with flag '--skip-history'. The flag will reduce copy time in larger datasets.`,\n )\n }\n\n const response = await copyDataset({\n projectId,\n skipContentReleases,\n skipHistory,\n sourceDataset,\n targetDataset,\n })\n\n this.output.log(`Job ${styleText('green', response.jobId)} started`)\n\n if (flags.detach) {\n return\n }\n\n await this.subscribeToProgress(projectId, response.jobId)\n this.output.log(`Job ${styleText('green', response.jobId)} completed`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Dataset copying failed: %s', message, error)\n return this.output.error(`Dataset copying failed: ${message}`, {exit: 1})\n }\n }\n\n private async handleListMode(\n projectId: string,\n flags: {limit?: number; offset?: number},\n ): Promise<void> {\n copyDatasetDebug('Listing dataset copy jobs')\n\n try {\n const jobs = await listDatasetCopyJobs({\n limit: flags.limit,\n offset: flags.offset,\n projectId,\n })\n\n if (jobs.length === 0) {\n this.output.log(\"This project doesn't have any dataset copy jobs\")\n return\n }\n\n this.displayCopyJobsTable(jobs)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to list dataset copy jobs: %s', message, error)\n return this.output.error(`Failed to list dataset copy jobs: ${message}`, {exit: 1})\n }\n }\n\n private async subscribeToProgress(projectId: string, jobId: string): Promise<void> {\n const spin = spinner('').start()\n\n return new Promise<void>((resolve, reject) => {\n const sigintHandler = () => {\n subscription.unsubscribe()\n spin.fail('Copy interrupted.')\n exit(130)\n }\n\n const subscription = followCopyJobProgress({jobId, projectId}).subscribe({\n complete: () => {\n process.off('SIGINT', sigintHandler)\n spin.succeed('Copy finished.')\n resolve()\n },\n error: (err) => {\n process.off('SIGINT', sigintHandler)\n spin.fail('Copy failed.')\n reject(err)\n },\n next: (event: CopyJobProgressEvent) => {\n if (typeof event.progress === 'number') {\n spin.text = `Copy in progress: ${event.progress}%`\n }\n },\n })\n\n process.once('SIGINT', sigintHandler)\n })\n }\n}\n"],"names":["styleText","Args","Flags","exit","SanityCommand","subdebug","spinner","Table","formatDistance","formatDistanceToNow","parseISO","validateDatasetName","promptForDataset","promptForDatasetName","promptForProject","copyDataset","followCopyJobProgress","listDatasetCopyJobs","listDatasets","getProjectIdFlag","copyDatasetDebug","CopyDatasetCommand","args","source","string","description","required","target","examples","command","flags","semantics","attach","exclusive","detach","boolean","limit","integer","dependsOn","max","list","offset","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","handleListMode","handleAttachMode","handleCopyMode","displayCopyJobsTable","jobs","table","columns","alignment","name","title","job","createdAt","id","sourceDataset","state","targetDataset","updatedAt","withHistory","timeStarted","timeTaken","color","addRow","output","log","render","jobId","trim","error","subscribeToProgress","message","Error","String","skipHistory","Boolean","skipContentReleases","nameError","datasetsResponse","datasetNames","Set","map","ds","datasets","has","response","length","spin","start","Promise","resolve","reject","sigintHandler","subscription","unsubscribe","fail","subscribe","complete","process","off","succeed","err","next","event","progress","text","once"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/datasets/copy.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exit} from '@oclif/core/errors'\nimport {subdebug} from '@sanity/cli-core/debug'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {Table} from 'console-table-printer'\nimport {formatDistance} from 'date-fns/formatDistance'\nimport {formatDistanceToNow} from 'date-fns/formatDistanceToNow'\nimport {parseISO} from 'date-fns/parseISO'\n\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {\n copyDataset,\n type CopyJobProgressEvent,\n type DatasetCopyJob,\n followCopyJobProgress,\n listDatasetCopyJobs,\n listDatasets,\n} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst copyDatasetDebug = subdebug('dataset:copy')\n\nexport class CopyDatasetCommand extends SanityCommand<typeof CopyDatasetCommand> {\n static override args = {\n source: Args.string({\n description: 'Name of the dataset to copy from',\n required: false,\n }),\n target: Args.string({\n description: 'Name of the dataset to copy to',\n required: false,\n }),\n }\n\n static override description = 'Copy a dataset or manage copy jobs'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively copy a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> source-dataset',\n description: 'Copy from source-dataset (prompts for target)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> source-dataset target-dataset',\n description: 'Copy from source-dataset to target-dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --skip-history source target',\n description: 'Copy without preserving document history (faster for large datasets)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --skip-content-releases source target',\n description: 'Copy without content release documents',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --detach source target',\n description: 'Start copy job without waiting for completion',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --attach <job-id>',\n description: 'Attach to a running copy job to follow progress',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --list',\n description: 'List all dataset copy jobs',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --list --offset 2 --limit 10',\n description: 'List copy jobs with pagination',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to copy dataset in',\n semantics: 'override',\n }),\n attach: Flags.string({\n description: 'Attach to the running copy process to show progress',\n exclusive: ['list', 'detach', 'skip-history'],\n required: false,\n }),\n detach: Flags.boolean({\n description: 'Start the copy without waiting for it to finish',\n exclusive: ['list', 'attach'],\n required: false,\n }),\n limit: Flags.integer({\n dependsOn: ['list'],\n description: 'Maximum number of jobs returned (default 10, max 1000)',\n max: 1000,\n required: false,\n }),\n list: Flags.boolean({\n description: 'Lists all dataset copy jobs',\n exclusive: ['attach', 'detach', 'skip-history'],\n required: false,\n }),\n offset: Flags.integer({\n dependsOn: ['list'],\n description: 'Start position in the list of jobs (default 0)',\n required: false,\n }),\n 'skip-content-releases': Flags.boolean({\n description: \"Don't copy content release documents to the target dataset\",\n exclusive: ['list', 'attach'],\n required: false,\n }),\n 'skip-history': Flags.boolean({\n description: \"Don't preserve document history on copy\",\n exclusive: ['list', 'attach'],\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:copy']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CopyDatasetCommand)\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'create', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n // Route to appropriate mode\n if (flags.list) {\n return this.handleListMode(projectId, flags)\n }\n\n if (flags.attach) {\n return this.handleAttachMode(projectId, flags.attach)\n }\n\n return this.handleCopyMode(projectId, args, flags)\n }\n\n private displayCopyJobsTable(jobs: DatasetCopyJob[]): void {\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'Job ID'},\n {alignment: 'left', name: 'sourceDataset', title: 'Source Dataset'},\n {alignment: 'left', name: 'targetDataset', title: 'Target Dataset'},\n {alignment: 'left', name: 'state', title: 'State'},\n {alignment: 'left', name: 'withHistory', title: 'With history'},\n {alignment: 'left', name: 'timeStarted', title: 'Time started'},\n {alignment: 'left', name: 'timeTaken', title: 'Time taken'},\n ],\n title: 'Dataset copy jobs for this project in descending order',\n })\n\n for (const job of jobs) {\n const {createdAt, id, sourceDataset, state, targetDataset, updatedAt, withHistory} = job\n\n let timeStarted = ''\n if (createdAt !== '') {\n timeStarted = formatDistanceToNow(parseISO(createdAt))\n }\n\n let timeTaken = ''\n if (updatedAt !== '') {\n timeTaken = formatDistance(parseISO(updatedAt), parseISO(createdAt))\n }\n\n let color: '' | 'green' | 'red' | 'yellow'\n switch (state) {\n case 'completed': {\n color = 'green'\n break\n }\n case 'failed': {\n color = 'red'\n break\n }\n case 'pending': {\n color = 'yellow'\n break\n }\n default: {\n color = ''\n }\n }\n\n table.addRow(\n {\n id,\n sourceDataset,\n state,\n targetDataset,\n timeStarted: `${timeStarted} ago`,\n timeTaken,\n withHistory,\n },\n {color},\n )\n }\n\n this.output.log(table.render())\n }\n\n private async handleAttachMode(projectId: string, jobId: string): Promise<void> {\n copyDatasetDebug('Attaching to copy job %s', jobId)\n\n if (jobId.trim() === '') {\n return this.output.error('Please supply a valid jobId', {exit: 1})\n }\n\n try {\n await this.subscribeToProgress(projectId, jobId)\n this.output.log(`Job ${styleText('green', jobId)} completed`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to attach to copy job: %s', message, error)\n return this.output.error(`Failed to attach to copy job: ${message}`, {exit: 1})\n }\n }\n\n private async handleCopyMode(\n projectId: string,\n args: {source?: string; target?: string},\n flags: {detach?: boolean; 'skip-content-releases'?: boolean; 'skip-history'?: boolean},\n ): Promise<void> {\n copyDatasetDebug('Starting copy mode')\n\n const skipHistory = Boolean(flags['skip-history'])\n const skipContentReleases = Boolean(flags['skip-content-releases'])\n\n // Get and validate source dataset\n let sourceDataset = args.source\n if (sourceDataset) {\n const nameError = validateDatasetName(sourceDataset)\n if (nameError) {\n return this.output.error(nameError, {exit: 1})\n }\n }\n\n let datasetsResponse\n try {\n datasetsResponse = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to fetch datasets: %s', message, error)\n return this.output.error(`Failed to fetch datasets: ${message}`, {exit: 1})\n }\n\n const datasetNames = new Set(datasetsResponse.map((ds) => ds.name))\n\n // Prompt for source if not provided\n if (!sourceDataset) {\n sourceDataset = await promptForDataset({\n datasets: datasetsResponse,\n })\n }\n\n if (!datasetNames.has(sourceDataset)) {\n return this.output.error(`Source dataset \"${sourceDataset}\" doesn't exist`, {exit: 1})\n }\n\n // Get and validate target dataset\n let targetDataset = args.target\n if (targetDataset) {\n const nameError = validateDatasetName(targetDataset)\n if (nameError) {\n return this.output.error(nameError, {exit: 1})\n }\n } else {\n targetDataset = await promptForDatasetName({\n message: 'Target dataset name:',\n })\n }\n\n if (datasetNames.has(targetDataset)) {\n return this.output.error(`Target dataset \"${targetDataset}\" already exists`, {exit: 1})\n }\n\n // Start the copy job\n try {\n this.output.log(\n `Copying dataset ${styleText('green', sourceDataset)} to ${styleText('green', targetDataset)}...`,\n )\n\n if (!skipHistory) {\n this.output.log(\n `Note: You can run this command with flag '--skip-history'. The flag will reduce copy time in larger datasets.`,\n )\n }\n\n const response = await copyDataset({\n projectId,\n skipContentReleases,\n skipHistory,\n sourceDataset,\n targetDataset,\n })\n\n this.output.log(`Job ${styleText('green', response.jobId)} started`)\n\n if (flags.detach) {\n return\n }\n\n await this.subscribeToProgress(projectId, response.jobId)\n this.output.log(`Job ${styleText('green', response.jobId)} completed`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Dataset copying failed: %s', message, error)\n return this.output.error(`Dataset copying failed: ${message}`, {exit: 1})\n }\n }\n\n private async handleListMode(\n projectId: string,\n flags: {limit?: number; offset?: number},\n ): Promise<void> {\n copyDatasetDebug('Listing dataset copy jobs')\n\n try {\n const jobs = await listDatasetCopyJobs({\n limit: flags.limit,\n offset: flags.offset,\n projectId,\n })\n\n if (jobs.length === 0) {\n this.output.log(\"This project doesn't have any dataset copy jobs\")\n return\n }\n\n this.displayCopyJobsTable(jobs)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to list dataset copy jobs: %s', message, error)\n return this.output.error(`Failed to list dataset copy jobs: ${message}`, {exit: 1})\n }\n }\n\n private async subscribeToProgress(projectId: string, jobId: string): Promise<void> {\n const spin = spinner('').start()\n\n return new Promise<void>((resolve, reject) => {\n const sigintHandler = () => {\n subscription.unsubscribe()\n spin.fail('Copy interrupted.')\n exit(130)\n }\n\n const subscription = followCopyJobProgress({jobId, projectId}).subscribe({\n complete: () => {\n process.off('SIGINT', sigintHandler)\n spin.succeed('Copy finished.')\n resolve()\n },\n error: (err) => {\n process.off('SIGINT', sigintHandler)\n spin.fail('Copy failed.')\n reject(err)\n },\n next: (event: CopyJobProgressEvent) => {\n if (typeof event.progress === 'number') {\n spin.text = `Copy in progress: ${event.progress}%`\n }\n },\n })\n\n process.once('SIGINT', sigintHandler)\n })\n }\n}\n"],"names":["styleText","Args","Flags","exit","subdebug","SanityCommand","spinner","Table","formatDistance","formatDistanceToNow","parseISO","validateDatasetName","promptForDataset","promptForDatasetName","promptForProject","copyDataset","followCopyJobProgress","listDatasetCopyJobs","listDatasets","getProjectIdFlag","copyDatasetDebug","CopyDatasetCommand","args","source","string","description","required","target","examples","command","flags","semantics","attach","exclusive","detach","boolean","limit","integer","dependsOn","max","list","offset","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","handleListMode","handleAttachMode","handleCopyMode","displayCopyJobsTable","jobs","table","columns","alignment","name","title","job","createdAt","id","sourceDataset","state","targetDataset","updatedAt","withHistory","timeStarted","timeTaken","color","addRow","output","log","render","jobId","trim","error","subscribeToProgress","message","Error","String","skipHistory","Boolean","skipContentReleases","nameError","datasetsResponse","datasetNames","Set","map","ds","datasets","has","response","length","spin","start","Promise","resolve","reject","sigintHandler","subscription","unsubscribe","fail","subscribe","complete","process","off","succeed","err","next","event","progress","text","once"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { styleText } from 'node:util';
|
|
4
4
|
import { Flags } from '@oclif/core';
|
|
5
|
-
import { ProjectRootNotFoundError
|
|
5
|
+
import { ProjectRootNotFoundError } from '@sanity/cli-core/errors';
|
|
6
|
+
import { SanityCommand } from '@sanity/cli-core/SanityCommand';
|
|
6
7
|
import { confirm, logSymbols } from '@sanity/cli-core/ux';
|
|
7
8
|
import { validateDocuments } from '../../actions/documents/validate.js';
|
|
8
9
|
import { reporters } from '../../actions/documents/validation/reporters/index.js';
|
|
@@ -87,28 +88,28 @@ export class ValidateDocumentsCommand extends SanityCommand {
|
|
|
87
88
|
cliConfig = await this.getCliConfig();
|
|
88
89
|
} catch (err) {
|
|
89
90
|
if (err instanceof ProjectRootNotFoundError) {
|
|
90
|
-
this.error('This command must be run from within a Sanity project directory (requires studio schema for validation)', {
|
|
91
|
+
return this.output.error('This command must be run from within a Sanity project directory (requires studio schema for validation)', {
|
|
91
92
|
exit: 1
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
throw err;
|
|
95
96
|
}
|
|
96
97
|
if (!unattendedMode) {
|
|
97
|
-
this.log(`${styleText('yellow', `${logSymbols.warning} Warning:`)} This command ${file ? 'reads all documents from your input file' : 'downloads all documents from your dataset'} and processes them through your local schema within a ` + `simulated browser environment.\n`);
|
|
98
|
-
this.log(`Potential pitfalls:\n`);
|
|
99
|
-
this.log(`- Processes all documents locally (excluding assets). Large datasets may require more resources.`);
|
|
100
|
-
this.log(`- Executes all custom validation functions. Some functions may need to be refactored for compatibility.`);
|
|
101
|
-
this.log(`- Not all standard browser features are available and may cause issues while loading your Studio.`);
|
|
102
|
-
this.log(`- Adheres to document permissions. Ensure this account can see all desired documents.`);
|
|
98
|
+
this.output.log(`${styleText('yellow', `${logSymbols.warning} Warning:`)} This command ${file ? 'reads all documents from your input file' : 'downloads all documents from your dataset'} and processes them through your local schema within a ` + `simulated browser environment.\n`);
|
|
99
|
+
this.output.log(`Potential pitfalls:\n`);
|
|
100
|
+
this.output.log(`- Processes all documents locally (excluding assets). Large datasets may require more resources.`);
|
|
101
|
+
this.output.log(`- Executes all custom validation functions. Some functions may need to be refactored for compatibility.`);
|
|
102
|
+
this.output.log(`- Not all standard browser features are available and may cause issues while loading your Studio.`);
|
|
103
|
+
this.output.log(`- Adheres to document permissions. Ensure this account can see all desired documents.`);
|
|
103
104
|
if (file) {
|
|
104
|
-
this.log(`- Checks for missing document references against the live dataset if not found in your file.`);
|
|
105
|
+
this.output.log(`- Checks for missing document references against the live dataset if not found in your file.`);
|
|
105
106
|
}
|
|
106
107
|
const confirmed = await confirm({
|
|
107
108
|
default: true,
|
|
108
109
|
message: `Are you sure you want to continue?`
|
|
109
110
|
});
|
|
110
111
|
if (!confirmed) {
|
|
111
|
-
this.error('User aborted', {
|
|
112
|
+
return this.output.error('User aborted', {
|
|
112
113
|
exit: 1
|
|
113
114
|
});
|
|
114
115
|
}
|
|
@@ -118,16 +119,16 @@ export class ValidateDocumentsCommand extends SanityCommand {
|
|
|
118
119
|
style: 'long',
|
|
119
120
|
type: 'conjunction'
|
|
120
121
|
});
|
|
121
|
-
this.error(`Did not recognize format '${format}'. Available formats are ${formatter.format(Object.keys(reporters).map((key)=>`'${key}'`))}`, {
|
|
122
|
+
return this.output.error(`Did not recognize format '${format}'. Available formats are ${formatter.format(Object.keys(reporters).map((key)=>`'${key}'`))}`, {
|
|
122
123
|
exit: 1
|
|
123
124
|
});
|
|
124
125
|
}
|
|
125
126
|
let ndjsonFilePath;
|
|
126
127
|
if (file) {
|
|
127
128
|
const filePath = path.resolve(workDir, file);
|
|
128
|
-
const
|
|
129
|
-
if (!
|
|
130
|
-
this.error(`'--file' must point to a valid ndjson file or tarball`, {
|
|
129
|
+
const st = await stat(filePath);
|
|
130
|
+
if (!st.isFile()) {
|
|
131
|
+
return this.output.error(`'--file' must point to a valid ndjson file or tarball`, {
|
|
131
132
|
exit: 1
|
|
132
133
|
});
|
|
133
134
|
}
|
|
@@ -154,10 +155,10 @@ export class ValidateDocumentsCommand extends SanityCommand {
|
|
|
154
155
|
workspace
|
|
155
156
|
});
|
|
156
157
|
if (overallLevel === 'error') {
|
|
157
|
-
this.exit(1);
|
|
158
|
+
return this.exit(1);
|
|
158
159
|
}
|
|
159
160
|
} catch (err) {
|
|
160
|
-
this.error(err instanceof Error ? err.message : String(err), {
|
|
161
|
+
return this.output.error(err instanceof Error ? err.message : String(err), {
|
|
161
162
|
exit: 1
|
|
162
163
|
});
|
|
163
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/documents/validate.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {type CliConfig, ProjectRootNotFoundError, SanityCommand} from '@sanity/cli-core'\nimport {confirm, logSymbols} from '@sanity/cli-core/ux'\n\nimport {type Level} from '../../actions/documents/types.js'\nimport {validateDocuments} from '../../actions/documents/validate.js'\nimport {reporters} from '../../actions/documents/validation/reporters/index.js'\nimport {getDatasetFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\nexport class ValidateDocumentsCommand extends SanityCommand<typeof ValidateDocumentsCommand> {\n static description = 'Validate documents in a dataset against the studio schema'\n\n static examples = [\n {\n command: '<%= config.bin %> <%= command.id %> --workspace default',\n description: 'Validates all documents in a Sanity project with more than one workspace',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --workspace default --dataset staging',\n description: 'Override the dataset specified in the workspace',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --yes > report.txt',\n description: 'Save the results of the report into a file',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --level info',\n description: 'Report out info level validation markers too',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123 --dataset production',\n description: 'Validate documents in a specific project and dataset',\n },\n ]\n\n static flags = {\n ...getProjectIdFlag({\n description:\n 'Override the project ID used. By default, this is derived from the given workspace',\n semantics: 'specify',\n }),\n ...getDatasetFlag({\n description:\n 'Override the dataset used. By default, this is derived from the given workspace',\n semantics: 'specify',\n }),\n file: Flags.string({\n description:\n 'Provide a path to either an .ndjson file or a tarball containing an .ndjson file',\n }),\n format: Flags.string({\n description:\n 'The output format used to print the found validation markers and report progress',\n }),\n level: Flags.custom<Level>({\n default: 'warning',\n description: 'The minimum level reported. Defaults to warning',\n options: ['error', 'warning', 'info'],\n })(),\n 'max-custom-validation-concurrency': Flags.integer({\n default: 5,\n description: 'Specify how many custom validators can run concurrently',\n }),\n 'max-fetch-concurrency': Flags.integer({\n default: 25,\n description: 'Specify how many `client.fetch` requests are allowed to run concurrently',\n }),\n workspace: Flags.string({\n description: 'The name of the workspace to use when downloading and validating all documents',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: 'Skips the first confirmation prompt',\n }),\n }\n\n static override hiddenAliases: string[] = ['document:validate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(ValidateDocumentsCommand)\n const {\n dataset,\n file,\n format,\n level,\n 'max-custom-validation-concurrency': maxCustomValidationConcurrency,\n 'max-fetch-concurrency': maxFetchConcurrency,\n 'project-id': projectId,\n workspace,\n } = flags\n const unattendedMode = Boolean(flags.yes)\n\n let workDir: string\n let cliConfig: CliConfig\n try {\n const root = await this.getProjectRoot()\n workDir = root.directory\n cliConfig = await this.getCliConfig()\n } catch (err) {\n if (err instanceof ProjectRootNotFoundError) {\n this.error(\n 'This command must be run from within a Sanity project directory (requires studio schema for validation)',\n {exit: 1},\n )\n }\n throw err\n }\n\n if (!unattendedMode) {\n this.log(\n `${styleText('yellow', `${logSymbols.warning} Warning:`)} This command ${\n file\n ? 'reads all documents from your input file'\n : 'downloads all documents from your dataset'\n } and processes them through your local schema within a ` +\n `simulated browser environment.\\n`,\n )\n this.log(`Potential pitfalls:\\n`)\n this.log(\n `- Processes all documents locally (excluding assets). Large datasets may require more resources.`,\n )\n this.log(\n `- Executes all custom validation functions. Some functions may need to be refactored for compatibility.`,\n )\n this.log(\n `- Not all standard browser features are available and may cause issues while loading your Studio.`,\n )\n this.log(\n `- Adheres to document permissions. Ensure this account can see all desired documents.`,\n )\n if (file) {\n this.log(\n `- Checks for missing document references against the live dataset if not found in your file.`,\n )\n }\n\n const confirmed = await confirm({\n default: true,\n message: `Are you sure you want to continue?`,\n })\n\n if (!confirmed) {\n this.error('User aborted', {exit: 1})\n }\n }\n\n if (format && !(format in reporters)) {\n const formatter = new Intl.ListFormat('en-US', {\n style: 'long',\n type: 'conjunction',\n })\n this.error(\n `Did not recognize format '${format}'. Available formats are ${formatter.format(\n Object.keys(reporters).map((key) => `'${key}'`),\n )}`,\n {exit: 1},\n )\n }\n\n let ndjsonFilePath\n if (file) {\n const filePath = path.resolve(workDir, file)\n\n const stat = await fs.promises.stat(filePath)\n if (!stat.isFile()) {\n this.error(`'--file' must point to a valid ndjson file or tarball`, {exit: 1})\n }\n\n ndjsonFilePath = filePath\n }\n\n try {\n const overallLevel = await validateDocuments({\n dataset,\n level,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n ndjsonFilePath,\n projectId,\n reporter: (worker) => {\n const reporter =\n format && format in reporters\n ? reporters[format as keyof typeof reporters]\n : reporters.pretty\n\n return reporter({flags, output: this.output, worker})\n },\n studioHost: cliConfig.studioHost,\n workDir,\n workspace,\n })\n\n if (overallLevel === 'error') {\n this.exit(1)\n }\n } catch (err) {\n this.error(err instanceof Error ? err.message : String(err), {exit: 1})\n }\n }\n}\n"],"names":["fs","path","styleText","Flags","ProjectRootNotFoundError","SanityCommand","confirm","logSymbols","validateDocuments","reporters","getDatasetFlag","getProjectIdFlag","ValidateDocumentsCommand","description","examples","command","flags","semantics","file","string","format","level","custom","default","options","integer","workspace","yes","boolean","char","hiddenAliases","run","parse","dataset","maxCustomValidationConcurrency","maxFetchConcurrency","projectId","unattendedMode","Boolean","workDir","cliConfig","root","getProjectRoot","directory","getCliConfig","err","error","exit","log","warning","confirmed","message","formatter","Intl","ListFormat","style","type","Object","keys","map","key","ndjsonFilePath","filePath","resolve","stat","promises","isFile","overallLevel","reporter","worker","pretty","output","studioHost","Error","String"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/documents/validate.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {ProjectRootNotFoundError} from '@sanity/cli-core/errors'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {type CliConfig} from '@sanity/cli-core/types'\nimport {confirm, logSymbols} from '@sanity/cli-core/ux'\n\nimport {type Level} from '../../actions/documents/types.js'\nimport {validateDocuments} from '../../actions/documents/validate.js'\nimport {reporters} from '../../actions/documents/validation/reporters/index.js'\nimport {getDatasetFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\nexport class ValidateDocumentsCommand extends SanityCommand<typeof ValidateDocumentsCommand> {\n static description = 'Validate documents in a dataset against the studio schema'\n\n static examples = [\n {\n command: '<%= config.bin %> <%= command.id %> --workspace default',\n description: 'Validates all documents in a Sanity project with more than one workspace',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --workspace default --dataset staging',\n description: 'Override the dataset specified in the workspace',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --yes > report.txt',\n description: 'Save the results of the report into a file',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --level info',\n description: 'Report out info level validation markers too',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --project-id abc123 --dataset production',\n description: 'Validate documents in a specific project and dataset',\n },\n ]\n\n static flags = {\n ...getProjectIdFlag({\n description:\n 'Override the project ID used. By default, this is derived from the given workspace',\n semantics: 'specify',\n }),\n ...getDatasetFlag({\n description:\n 'Override the dataset used. By default, this is derived from the given workspace',\n semantics: 'specify',\n }),\n file: Flags.string({\n description:\n 'Provide a path to either an .ndjson file or a tarball containing an .ndjson file',\n }),\n format: Flags.string({\n description:\n 'The output format used to print the found validation markers and report progress',\n }),\n level: Flags.custom<Level>({\n default: 'warning',\n description: 'The minimum level reported. Defaults to warning',\n options: ['error', 'warning', 'info'],\n })(),\n 'max-custom-validation-concurrency': Flags.integer({\n default: 5,\n description: 'Specify how many custom validators can run concurrently',\n }),\n 'max-fetch-concurrency': Flags.integer({\n default: 25,\n description: 'Specify how many `client.fetch` requests are allowed to run concurrently',\n }),\n workspace: Flags.string({\n description: 'The name of the workspace to use when downloading and validating all documents',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: 'Skips the first confirmation prompt',\n }),\n }\n\n static override hiddenAliases: string[] = ['document:validate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(ValidateDocumentsCommand)\n const {\n dataset,\n file,\n format,\n level,\n 'max-custom-validation-concurrency': maxCustomValidationConcurrency,\n 'max-fetch-concurrency': maxFetchConcurrency,\n 'project-id': projectId,\n workspace,\n } = flags\n const unattendedMode = Boolean(flags.yes)\n\n let workDir: string\n let cliConfig: CliConfig\n try {\n const root = await this.getProjectRoot()\n workDir = root.directory\n cliConfig = await this.getCliConfig()\n } catch (err) {\n if (err instanceof ProjectRootNotFoundError) {\n return this.output.error(\n 'This command must be run from within a Sanity project directory (requires studio schema for validation)',\n {exit: 1},\n )\n }\n throw err\n }\n\n if (!unattendedMode) {\n this.output.log(\n `${styleText('yellow', `${logSymbols.warning} Warning:`)} This command ${\n file\n ? 'reads all documents from your input file'\n : 'downloads all documents from your dataset'\n } and processes them through your local schema within a ` +\n `simulated browser environment.\\n`,\n )\n this.output.log(`Potential pitfalls:\\n`)\n this.output.log(\n `- Processes all documents locally (excluding assets). Large datasets may require more resources.`,\n )\n this.output.log(\n `- Executes all custom validation functions. Some functions may need to be refactored for compatibility.`,\n )\n this.output.log(\n `- Not all standard browser features are available and may cause issues while loading your Studio.`,\n )\n this.output.log(\n `- Adheres to document permissions. Ensure this account can see all desired documents.`,\n )\n if (file) {\n this.output.log(\n `- Checks for missing document references against the live dataset if not found in your file.`,\n )\n }\n\n const confirmed = await confirm({\n default: true,\n message: `Are you sure you want to continue?`,\n })\n\n if (!confirmed) {\n return this.output.error('User aborted', {exit: 1})\n }\n }\n\n if (format && !(format in reporters)) {\n const formatter = new Intl.ListFormat('en-US', {\n style: 'long',\n type: 'conjunction',\n })\n return this.output.error(\n `Did not recognize format '${format}'. Available formats are ${formatter.format(\n Object.keys(reporters).map((key) => `'${key}'`),\n )}`,\n {exit: 1},\n )\n }\n\n let ndjsonFilePath\n if (file) {\n const filePath = path.resolve(workDir, file)\n\n const st = await stat(filePath)\n if (!st.isFile()) {\n return this.output.error(`'--file' must point to a valid ndjson file or tarball`, {exit: 1})\n }\n\n ndjsonFilePath = filePath\n }\n\n try {\n const overallLevel = await validateDocuments({\n dataset,\n level,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n ndjsonFilePath,\n projectId,\n reporter: (worker) => {\n const reporter =\n format && format in reporters\n ? reporters[format as keyof typeof reporters]\n : reporters.pretty\n\n return reporter({flags, output: this.output, worker})\n },\n studioHost: cliConfig.studioHost,\n workDir,\n workspace,\n })\n\n if (overallLevel === 'error') {\n return this.exit(1)\n }\n } catch (err) {\n return this.output.error(err instanceof Error ? err.message : String(err), {exit: 1})\n }\n }\n}\n"],"names":["stat","path","styleText","Flags","ProjectRootNotFoundError","SanityCommand","confirm","logSymbols","validateDocuments","reporters","getDatasetFlag","getProjectIdFlag","ValidateDocumentsCommand","description","examples","command","flags","semantics","file","string","format","level","custom","default","options","integer","workspace","yes","boolean","char","hiddenAliases","run","parse","dataset","maxCustomValidationConcurrency","maxFetchConcurrency","projectId","unattendedMode","Boolean","workDir","cliConfig","root","getProjectRoot","directory","getCliConfig","err","output","error","exit","log","warning","confirmed","message","formatter","Intl","ListFormat","style","type","Object","keys","map","key","ndjsonFilePath","filePath","resolve","st","isFile","overallLevel","reporter","worker","pretty","studioHost","Error","String"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isInteractive, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
2
|
+
import { getErrorMessage, toError } from '@sanity/cli-core/errors';
|
|
2
3
|
import { ensureAuthenticated } from '../../actions/auth/ensureAuthenticated.js';
|
|
3
4
|
import { setupMCP } from '../../actions/mcp/setupMCP.js';
|
|
4
5
|
import { LoginError } from '../../errors/LoginError.js';
|
|
5
6
|
import { MCPConfigureTrace } from '../../telemetry/mcp.telemetry.js';
|
|
6
|
-
import { getErrorMessage, toError } from '../../util/getErrorMessage.js';
|
|
7
7
|
const debug = subdebug('mcp:configure');
|
|
8
8
|
export class ConfigureMcpCommand extends SanityCommand {
|
|
9
9
|
static description = 'Configure Sanity MCP server for AI editors (Antigravity, Claude Code, Cline, Cline CLI, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, MCPorter, OpenCode, VS Code, VS Code Insiders, Zed)';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/mcp/configure.ts"],"sourcesContent":["import {isInteractive, SanityCommand, subdebug} from '@sanity/cli-core'\n\nimport {ensureAuthenticated} from '../../actions/auth/ensureAuthenticated.js'\nimport {setupMCP} from '../../actions/mcp/setupMCP.js'\nimport {LoginError} from '../../errors/LoginError.js'\nimport {MCPConfigureTrace} from '../../telemetry/mcp.telemetry.js'\
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/mcp/configure.ts"],"sourcesContent":["import {isInteractive, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage, toError} from '@sanity/cli-core/errors'\n\nimport {ensureAuthenticated} from '../../actions/auth/ensureAuthenticated.js'\nimport {setupMCP} from '../../actions/mcp/setupMCP.js'\nimport {LoginError} from '../../errors/LoginError.js'\nimport {MCPConfigureTrace} from '../../telemetry/mcp.telemetry.js'\n\nconst debug = subdebug('mcp:configure')\n\nexport class ConfigureMcpCommand extends SanityCommand<typeof ConfigureMcpCommand> {\n static override description =\n 'Configure Sanity MCP server for AI editors (Antigravity, Claude Code, Cline, Cline CLI, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, MCPorter, OpenCode, VS Code, VS Code Insiders, Zed)'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Configure Sanity MCP server for detected AI editors',\n },\n ]\n\n public async run(): Promise<void> {\n const trace = this.telemetry.trace(MCPConfigureTrace)\n trace.start()\n\n try {\n await ensureAuthenticated({output: this.output, telemetry: this.telemetry})\n } catch (error) {\n debug('Authentication check failed: %O', error)\n trace.error(toError(error))\n\n if (error instanceof LoginError) {\n this.error(\n `Failed to verify authentication credentials: ${error.message}. Try running \\`sanity login\\`.`,\n {exit: 1},\n )\n }\n\n this.error(`Failed to check authentication: ${getErrorMessage(error)}`, {exit: 1})\n }\n\n try {\n const mcpResult = await setupMCP({\n explicit: true,\n mode: isInteractive() ? 'prompt' : 'auto',\n output: this.output,\n skillsMode: 'skip',\n })\n\n trace.log({\n configuredEditors: mcpResult.configuredEditors,\n detectedEditors: mcpResult.detectedEditors,\n })\n\n if (mcpResult.error) {\n trace.error(mcpResult.error)\n } else {\n trace.complete()\n }\n } catch (error) {\n trace.error(toError(error))\n this.error(getErrorMessage(error), {exit: 1})\n }\n }\n}\n"],"names":["isInteractive","SanityCommand","subdebug","getErrorMessage","toError","ensureAuthenticated","setupMCP","LoginError","MCPConfigureTrace","debug","ConfigureMcpCommand","description","examples","command","run","trace","telemetry","start","output","error","message","exit","mcpResult","explicit","mode","skillsMode","log","configuredEditors","detectedEditors","complete"],"mappings":"AAAA,SAAQA,aAAa,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACvE,SAAQC,eAAe,EAAEC,OAAO,QAAO,0BAAyB;AAEhE,SAAQC,mBAAmB,QAAO,4CAA2C;AAC7E,SAAQC,QAAQ,QAAO,gCAA+B;AACtD,SAAQC,UAAU,QAAO,6BAA4B;AACrD,SAAQC,iBAAiB,QAAO,mCAAkC;AAElE,MAAMC,QAAQP,SAAS;AAEvB,OAAO,MAAMQ,4BAA4BT;IACvC,OAAgBU,cACd,iMAAgM;IAElM,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,MAAaG,MAAqB;QAChC,MAAMC,QAAQ,IAAI,CAACC,SAAS,CAACD,KAAK,CAACP;QACnCO,MAAME,KAAK;QAEX,IAAI;YACF,MAAMZ,oBAAoB;gBAACa,QAAQ,IAAI,CAACA,MAAM;gBAAEF,WAAW,IAAI,CAACA,SAAS;YAAA;QAC3E,EAAE,OAAOG,OAAO;YACdV,MAAM,mCAAmCU;YACzCJ,MAAMI,KAAK,CAACf,QAAQe;YAEpB,IAAIA,iBAAiBZ,YAAY;gBAC/B,IAAI,CAACY,KAAK,CACR,CAAC,6CAA6C,EAAEA,MAAMC,OAAO,CAAC,+BAA+B,CAAC,EAC9F;oBAACC,MAAM;gBAAC;YAEZ;YAEA,IAAI,CAACF,KAAK,CAAC,CAAC,gCAAgC,EAAEhB,gBAAgBgB,QAAQ,EAAE;gBAACE,MAAM;YAAC;QAClF;QAEA,IAAI;YACF,MAAMC,YAAY,MAAMhB,SAAS;gBAC/BiB,UAAU;gBACVC,MAAMxB,kBAAkB,WAAW;gBACnCkB,QAAQ,IAAI,CAACA,MAAM;gBACnBO,YAAY;YACd;YAEAV,MAAMW,GAAG,CAAC;gBACRC,mBAAmBL,UAAUK,iBAAiB;gBAC9CC,iBAAiBN,UAAUM,eAAe;YAC5C;YAEA,IAAIN,UAAUH,KAAK,EAAE;gBACnBJ,MAAMI,KAAK,CAACG,UAAUH,KAAK;YAC7B,OAAO;gBACLJ,MAAMc,QAAQ;YAChB;QACF,EAAE,OAAOV,OAAO;YACdJ,MAAMI,KAAK,CAACf,QAAQe;YACpB,IAAI,CAACA,KAAK,CAAChB,gBAAgBgB,QAAQ;gBAACE,MAAM;YAAC;QAC7C;IACF;AACF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import { CLIError } from '@oclif/core/errors';
|
|
3
|
-
import {
|
|
3
|
+
import { subdebug } from '@sanity/cli-core/debug';
|
|
4
|
+
import { SanityCommand } from '@sanity/cli-core/SanityCommand';
|
|
4
5
|
import { confirm, spinner } from '@sanity/cli-core/ux';
|
|
5
6
|
import { createDataset } from '../../actions/dataset/create.js';
|
|
6
7
|
import { validateDatasetName } from '../../actions/dataset/validateDatasetName.js';
|
|
@@ -104,7 +105,7 @@ export class CreateProjectCommand extends SanityCommand {
|
|
|
104
105
|
});
|
|
105
106
|
} catch (error) {
|
|
106
107
|
const errorText = organization ? `Failed to retrieve organization ${organization}` : 'Failed to retrieve an organization';
|
|
107
|
-
this.error(`${errorText}: ${error}`, {
|
|
108
|
+
return this.output.error(`${errorText}: ${error}`, {
|
|
108
109
|
exit: 1
|
|
109
110
|
});
|
|
110
111
|
}
|
|
@@ -122,11 +123,15 @@ export class CreateProjectCommand extends SanityCommand {
|
|
|
122
123
|
} catch (error) {
|
|
123
124
|
spin.fail();
|
|
124
125
|
debug(`Failed to create project: ${error}`);
|
|
125
|
-
this.error(`Failed to create project: ${error}`, {
|
|
126
|
+
return this.output.error(`Failed to create project: ${error}`, {
|
|
126
127
|
exit: 1
|
|
127
128
|
});
|
|
128
129
|
}
|
|
129
|
-
|
|
130
|
+
let newDataset;
|
|
131
|
+
// If dataset name specified, or in attended mode (to prompt for dataset name), create a dataset.
|
|
132
|
+
if (dataset || !this.isUnattended()) {
|
|
133
|
+
newDataset = await this.handleDatasetCreation(newProject.projectId, dataset, datasetVisibility);
|
|
134
|
+
}
|
|
130
135
|
this.printProjectCreationSuccess(chosenOrganization, newProject, newDataset);
|
|
131
136
|
}
|
|
132
137
|
async handleDatasetCreation(projectId, datasetFromFlag, datasetVisibility) {
|
|
@@ -160,24 +165,24 @@ export class CreateProjectCommand extends SanityCommand {
|
|
|
160
165
|
return;
|
|
161
166
|
} catch (error) {
|
|
162
167
|
debug(`Error creating dataset: ${error}`);
|
|
163
|
-
this.warn(`Project created but dataset creation failed: ${error}`);
|
|
168
|
+
this.output.warn(`Project created but dataset creation failed: ${error}`);
|
|
164
169
|
return;
|
|
165
170
|
}
|
|
166
171
|
}
|
|
167
172
|
async printProjectCreationSuccess(organization, project, dataset) {
|
|
168
173
|
if (this.flags.json) {
|
|
169
|
-
this.log(JSON.stringify(project, null, 2));
|
|
174
|
+
this.output.log(JSON.stringify(project, null, 2));
|
|
170
175
|
return;
|
|
171
176
|
}
|
|
172
|
-
this.log(`Project created successfully!`);
|
|
173
|
-
this.log(`ID: ${project.projectId}`);
|
|
174
|
-
this.log(`Name: ${project.displayName}`);
|
|
175
|
-
this.log(`Organization: ${organization?.name || 'Personal'}`);
|
|
177
|
+
this.output.log(`Project created successfully!`);
|
|
178
|
+
this.output.log(`ID: ${project.projectId}`);
|
|
179
|
+
this.output.log(`Name: ${project.displayName}`);
|
|
180
|
+
this.output.log(`Organization: ${organization?.name || 'Personal'}`);
|
|
176
181
|
if (dataset) {
|
|
177
|
-
this.log(`Dataset: ${dataset.datasetName} (${dataset.aclMode})`);
|
|
182
|
+
this.output.log(`Dataset: ${dataset.datasetName} (${dataset.aclMode})`);
|
|
178
183
|
}
|
|
179
|
-
this.log(``);
|
|
180
|
-
this.log(`Manage your project: ${getManageUrl(project.projectId)}`);
|
|
184
|
+
this.output.log(``);
|
|
185
|
+
this.output.log(`Manage your project: ${getManageUrl(project.projectId)}`);
|
|
181
186
|
}
|
|
182
187
|
}
|
|
183
188
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/projects/create.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {DatasetResponse} from '@sanity/client'\n\nimport {createDataset} from '../../actions/dataset/create.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {getOrganization} from '../../actions/organizations/getOrganization.js'\nimport {getManageUrl} from '../../actions/projects/getManageUrl.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForDefaultConfig} from '../../prompts/promptForDefaultConfig.js'\nimport {promptForProjectName} from '../../prompts/promptForProjectName.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectFeatures} from '../../services/getProjectFeatures.js'\nimport {OrganizationCreateResponse, ProjectOrganization} from '../../services/organizations.js'\nimport {createProject, CreateProjectResult} from '../../services/projects.js'\nimport {getCliUser} from '../../services/user.js'\n\nconst debug = subdebug('projects:create')\n\nexport class CreateProjectCommand extends SanityCommand<typeof CreateProjectCommand> {\n static override args = {\n projectName: Args.string({\n description: 'Name of the project to create',\n required: false,\n }),\n }\n\n static override description = 'Create a new Sanity project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively create a project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My New Project\"',\n description: 'Create a project named \"My New Project\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My Project\" --organization=my-org',\n description: 'Create a project in a specific organization',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> \"My Project\" --dataset=staging --dataset-visibility=private',\n description: 'Create a project with a private dataset named \"staging\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"CI Project\" --yes --json',\n description: 'Create a project non-interactively with JSON output',\n },\n ]\n\n static override flags = {\n dataset: Flags.string({\n description: 'Create a dataset. Prompts for visibility unless specified or --yes used',\n parse: async (input) => {\n const datasetNameError = validateDatasetName(input)\n if (datasetNameError) {\n throw new CLIError(datasetNameError, {exit: 1})\n }\n\n return input\n },\n }),\n 'dataset-visibility': Flags.string({\n description: 'Dataset visibility: public or private',\n options: ['private', 'public'],\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output in JSON format',\n }),\n organization: Flags.string({\n description: 'Organization to create the project in',\n helpValue: '<slug|id>',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Skip prompts and use defaults (project: \"My Sanity Project\", dataset: production, visibility: public)',\n }),\n }\n\n static override hiddenAliases: string[] = ['project:create']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CreateProjectCommand)\n const {projectName} = args\n const {dataset, 'dataset-visibility': datasetVisibility, organization, yes} = flags\n const user = await getCliUser()\n\n const finalProjectName =\n projectName ||\n (yes || this.isUnattended() ? 'My Sanity Project' : await promptForProjectName())\n\n debug('Creating project with options: %O', {\n dataset,\n datasetVisibility,\n organizationId: organization,\n projectName,\n unattended: yes,\n })\n\n let chosenOrganization: OrganizationCreateResponse | ProjectOrganization | undefined\n try {\n chosenOrganization = await getOrganization({\n isUnattended: this.isUnattended(),\n output: this.output,\n requestedId: organization,\n user,\n })\n } catch (error) {\n const errorText = organization\n ? `Failed to retrieve organization ${organization}`\n : 'Failed to retrieve an organization'\n this.error(`${errorText}: ${error}`, {exit: 1})\n }\n\n const spin = spinner('Creating project').start()\n let newProject\n try {\n newProject = await createProject({\n displayName: finalProjectName,\n metadata: {\n integration: 'cli',\n },\n organizationId: chosenOrganization?.id,\n })\n spin.succeed('Project created successfully')\n } catch (error) {\n spin.fail()\n debug(`Failed to create project: ${error}`)\n this.error(`Failed to create project: ${error}`, {exit: 1})\n }\n\n const newDataset = await this.handleDatasetCreation(\n newProject.projectId,\n dataset,\n datasetVisibility,\n )\n\n this.printProjectCreationSuccess(chosenOrganization, newProject, newDataset)\n }\n\n private async handleDatasetCreation(\n projectId: string,\n datasetFromFlag?: string,\n datasetVisibility?: string,\n ): Promise<DatasetResponse | undefined> {\n try {\n let datasetName: string | undefined = datasetFromFlag\n const existingDatasets = await listDatasets(projectId)\n const existingDatasetNames = existingDatasets.map((ds) => ds.name)\n\n // Prompt for dataset in interactive mode if not provided\n if (!datasetName && !this.isUnattended()) {\n const wantsDataset = await confirm({\n default: true,\n message: 'Would you like to create a dataset?',\n })\n\n if (wantsDataset) {\n const defaultConfig = await promptForDefaultConfig()\n\n datasetName = defaultConfig\n ? 'production'\n : await promptForDatasetName({}, existingDatasetNames)\n }\n }\n\n // Create dataset if we have a name\n if (datasetName) {\n const projectFeatures = await getProjectFeatures(projectId)\n return await createDataset({\n datasetName,\n isUnattended: this.isUnattended(),\n output: this.output,\n projectFeatures,\n projectId,\n visibility: datasetVisibility,\n })\n }\n\n return\n } catch (error) {\n debug(`Error creating dataset: ${error}`)\n this.warn(`Project created but dataset creation failed: ${error}`)\n return\n }\n }\n\n private async printProjectCreationSuccess(\n organization: OrganizationCreateResponse | ProjectOrganization | undefined,\n project: CreateProjectResult,\n dataset: DatasetResponse | undefined,\n ) {\n if (this.flags.json) {\n this.log(JSON.stringify(project, null, 2))\n return\n }\n\n this.log(`Project created successfully!`)\n this.log(`ID: ${project.projectId}`)\n this.log(`Name: ${project.displayName}`)\n this.log(`Organization: ${organization?.name || 'Personal'}`)\n\n if (dataset) {\n this.log(`Dataset: ${dataset.datasetName} (${dataset.aclMode})`)\n }\n\n this.log(``)\n this.log(`Manage your project: ${getManageUrl(project.projectId)}`)\n }\n}\n"],"names":["Args","Flags","CLIError","SanityCommand","subdebug","confirm","spinner","createDataset","validateDatasetName","getOrganization","getManageUrl","promptForDatasetName","promptForDefaultConfig","promptForProjectName","listDatasets","getProjectFeatures","createProject","getCliUser","debug","CreateProjectCommand","args","projectName","string","description","required","examples","command","flags","dataset","parse","input","datasetNameError","exit","options","json","boolean","default","organization","helpValue","yes","char","hiddenAliases","run","datasetVisibility","user","finalProjectName","isUnattended","organizationId","unattended","chosenOrganization","output","requestedId","error","errorText","spin","start","newProject","displayName","metadata","integration","id","succeed","fail","newDataset","handleDatasetCreation","projectId","printProjectCreationSuccess","datasetFromFlag","datasetName","existingDatasets","existingDatasetNames","map","ds","name","wantsDataset","message","defaultConfig","projectFeatures","visibility","warn","project","log","JSON","stringify","aclMode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/projects/create.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {subdebug} from '@sanity/cli-core/debug'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {confirm, spinner} from '@sanity/cli-core/ux'\nimport {type DatasetResponse} from '@sanity/client'\n\nimport {createDataset} from '../../actions/dataset/create.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {getOrganization} from '../../actions/organizations/getOrganization.js'\nimport {getManageUrl} from '../../actions/projects/getManageUrl.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForDefaultConfig} from '../../prompts/promptForDefaultConfig.js'\nimport {promptForProjectName} from '../../prompts/promptForProjectName.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectFeatures} from '../../services/getProjectFeatures.js'\nimport {\n type OrganizationCreateResponse,\n type ProjectOrganization,\n} from '../../services/organizations.js'\nimport {createProject, type CreateProjectResult} from '../../services/projects.js'\nimport {getCliUser} from '../../services/user.js'\n\nconst debug = subdebug('projects:create')\n\nexport class CreateProjectCommand extends SanityCommand<typeof CreateProjectCommand> {\n static override args = {\n projectName: Args.string({\n description: 'Name of the project to create',\n required: false,\n }),\n }\n\n static override description = 'Create a new Sanity project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively create a project',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My New Project\"',\n description: 'Create a project named \"My New Project\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"My Project\" --organization=my-org',\n description: 'Create a project in a specific organization',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> \"My Project\" --dataset=staging --dataset-visibility=private',\n description: 'Create a project with a private dataset named \"staging\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"CI Project\" --yes --json',\n description: 'Create a project non-interactively with JSON output',\n },\n ]\n\n static override flags = {\n dataset: Flags.string({\n description: 'Create a dataset. Prompts for visibility unless specified or --yes used',\n parse: async (input) => {\n const datasetNameError = validateDatasetName(input)\n if (datasetNameError) {\n throw new CLIError(datasetNameError, {exit: 1})\n }\n\n return input\n },\n }),\n 'dataset-visibility': Flags.string({\n description: 'Dataset visibility: public or private',\n options: ['private', 'public'],\n }),\n json: Flags.boolean({\n default: false,\n description: 'Output in JSON format',\n }),\n organization: Flags.string({\n description: 'Organization to create the project in',\n helpValue: '<slug|id>',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Skip prompts and use defaults (project: \"My Sanity Project\", dataset: production, visibility: public)',\n }),\n }\n\n static override hiddenAliases: string[] = ['project:create']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CreateProjectCommand)\n const {projectName} = args\n const {dataset, 'dataset-visibility': datasetVisibility, organization, yes} = flags\n const user = await getCliUser()\n\n const finalProjectName =\n projectName ||\n (yes || this.isUnattended() ? 'My Sanity Project' : await promptForProjectName())\n\n debug('Creating project with options: %O', {\n dataset,\n datasetVisibility,\n organizationId: organization,\n projectName,\n unattended: yes,\n })\n\n let chosenOrganization: OrganizationCreateResponse | ProjectOrganization | undefined\n try {\n chosenOrganization = await getOrganization({\n isUnattended: this.isUnattended(),\n output: this.output,\n requestedId: organization,\n user,\n })\n } catch (error) {\n const errorText = organization\n ? `Failed to retrieve organization ${organization}`\n : 'Failed to retrieve an organization'\n return this.output.error(`${errorText}: ${error}`, {exit: 1})\n }\n\n const spin = spinner('Creating project').start()\n let newProject\n try {\n newProject = await createProject({\n displayName: finalProjectName,\n metadata: {\n integration: 'cli',\n },\n organizationId: chosenOrganization?.id,\n })\n spin.succeed('Project created successfully')\n } catch (error) {\n spin.fail()\n debug(`Failed to create project: ${error}`)\n return this.output.error(`Failed to create project: ${error}`, {exit: 1})\n }\n\n let newDataset: DatasetResponse | undefined\n // If dataset name specified, or in attended mode (to prompt for dataset name), create a dataset.\n if (dataset || !this.isUnattended()) {\n newDataset = await this.handleDatasetCreation(\n newProject.projectId,\n dataset,\n datasetVisibility,\n )\n }\n\n this.printProjectCreationSuccess(chosenOrganization, newProject, newDataset)\n }\n\n private async handleDatasetCreation(\n projectId: string,\n datasetFromFlag?: string,\n datasetVisibility?: string,\n ): Promise<DatasetResponse | undefined> {\n try {\n let datasetName: string | undefined = datasetFromFlag\n const existingDatasets = await listDatasets(projectId)\n const existingDatasetNames = existingDatasets.map((ds) => ds.name)\n\n // Prompt for dataset in interactive mode if not provided\n if (!datasetName && !this.isUnattended()) {\n const wantsDataset = await confirm({\n default: true,\n message: 'Would you like to create a dataset?',\n })\n\n if (wantsDataset) {\n const defaultConfig = await promptForDefaultConfig()\n\n datasetName = defaultConfig\n ? 'production'\n : await promptForDatasetName({}, existingDatasetNames)\n }\n }\n\n // Create dataset if we have a name\n if (datasetName) {\n const projectFeatures = await getProjectFeatures(projectId)\n return await createDataset({\n datasetName,\n isUnattended: this.isUnattended(),\n output: this.output,\n projectFeatures,\n projectId,\n visibility: datasetVisibility,\n })\n }\n\n return\n } catch (error) {\n debug(`Error creating dataset: ${error}`)\n this.output.warn(`Project created but dataset creation failed: ${error}`)\n return\n }\n }\n\n private async printProjectCreationSuccess(\n organization: OrganizationCreateResponse | ProjectOrganization | undefined,\n project: CreateProjectResult,\n dataset: DatasetResponse | undefined,\n ) {\n if (this.flags.json) {\n this.output.log(JSON.stringify(project, null, 2))\n return\n }\n\n this.output.log(`Project created successfully!`)\n this.output.log(`ID: ${project.projectId}`)\n this.output.log(`Name: ${project.displayName}`)\n this.output.log(`Organization: ${organization?.name || 'Personal'}`)\n\n if (dataset) {\n this.output.log(`Dataset: ${dataset.datasetName} (${dataset.aclMode})`)\n }\n\n this.output.log(``)\n this.output.log(`Manage your project: ${getManageUrl(project.projectId)}`)\n }\n}\n"],"names":["Args","Flags","CLIError","subdebug","SanityCommand","confirm","spinner","createDataset","validateDatasetName","getOrganization","getManageUrl","promptForDatasetName","promptForDefaultConfig","promptForProjectName","listDatasets","getProjectFeatures","createProject","getCliUser","debug","CreateProjectCommand","args","projectName","string","description","required","examples","command","flags","dataset","parse","input","datasetNameError","exit","options","json","boolean","default","organization","helpValue","yes","char","hiddenAliases","run","datasetVisibility","user","finalProjectName","isUnattended","organizationId","unattended","chosenOrganization","output","requestedId","error","errorText","spin","start","newProject","displayName","metadata","integration","id","succeed","fail","newDataset","handleDatasetCreation","projectId","printProjectCreationSuccess","datasetFromFlag","datasetName","existingDatasets","existingDatasetNames","map","ds","name","wantsDataset","message","defaultConfig","projectFeatures","visibility","warn","project","log","JSON","stringify","aclMode"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { Flags } from '@oclif/core';
|
|
|
3
3
|
import { SanityCommand, subdebug } from '@sanity/cli-core';
|
|
4
4
|
import size from 'lodash-es/size.js';
|
|
5
5
|
import sortBy from 'lodash-es/sortBy.js';
|
|
6
|
+
import { getManageUrl } from '../../actions/projects/getManageUrl.js';
|
|
6
7
|
import { listProjects } from '../../services/projects.js';
|
|
7
8
|
const sortFields = [
|
|
8
9
|
'id',
|
|
@@ -47,7 +48,7 @@ export class List extends SanityCommand {
|
|
|
47
48
|
try {
|
|
48
49
|
const projects = await listProjects();
|
|
49
50
|
const ordered = sortBy(projects.map(({ createdAt, displayName, id, members = [] })=>{
|
|
50
|
-
const manage =
|
|
51
|
+
const manage = getManageUrl(id);
|
|
51
52
|
return [
|
|
52
53
|
id,
|
|
53
54
|
members.length,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/projects/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport size from 'lodash-es/size.js'\nimport sortBy from 'lodash-es/sortBy.js'\n\nimport {listProjects} from '../../services/projects.js'\n\nconst sortFields = ['id', 'members', 'name', 'url', 'created']\n\nconst projectsDebug = subdebug('projects')\n\nexport class List extends SanityCommand<typeof List> {\n static override description = 'List your projects'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List projects',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sort=members --order=asc',\n description: 'List projects sorted by member count, ascending',\n },\n ]\n\n static override flags = {\n order: Flags.string({\n default: 'desc',\n description: 'Sort direction',\n options: ['asc', 'desc'],\n }),\n sort: Flags.string({\n default: 'created',\n description: 'Sort field',\n options: sortFields,\n }),\n }\n\n static override hiddenAliases: string[] = ['project:list']\n\n public async run() {\n const {order, sort} = this.flags\n\n try {\n const projects = await listProjects()\n const ordered = sortBy(\n projects.map(({createdAt, displayName, id, members = []}) => {\n const manage =
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/projects/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport size from 'lodash-es/size.js'\nimport sortBy from 'lodash-es/sortBy.js'\n\nimport {getManageUrl} from '../../actions/projects/getManageUrl.js'\nimport {listProjects} from '../../services/projects.js'\n\nconst sortFields = ['id', 'members', 'name', 'url', 'created']\n\nconst projectsDebug = subdebug('projects')\n\nexport class List extends SanityCommand<typeof List> {\n static override description = 'List your projects'\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List projects',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --sort=members --order=asc',\n description: 'List projects sorted by member count, ascending',\n },\n ]\n\n static override flags = {\n order: Flags.string({\n default: 'desc',\n description: 'Sort direction',\n options: ['asc', 'desc'],\n }),\n sort: Flags.string({\n default: 'created',\n description: 'Sort field',\n options: sortFields,\n }),\n }\n\n static override hiddenAliases: string[] = ['project:list']\n\n public async run() {\n const {order, sort} = this.flags\n\n try {\n const projects = await listProjects()\n const ordered = sortBy(\n projects.map(({createdAt, displayName, id, members = []}) => {\n const manage = getManageUrl(id)\n return [id, members.length, displayName, manage, createdAt].map(String)\n }),\n [sortFields.indexOf(sort)],\n )\n\n const rows = order === 'asc' ? ordered : ordered.toReversed()\n\n // Initialize maxWidths with the width of each header\n const maxWidths = sortFields.map((str) => size(str))\n\n // Calculate maximum width for each column\n for (const row of rows) {\n for (const [i, element] of row.entries()) {\n maxWidths[i] = Math.max(size(element), maxWidths[i])\n }\n }\n\n const printRow = (row: string[]) =>\n row.map((col, i) => `${col}`.padEnd(maxWidths[i])).join(' ')\n\n this.log(styleText('cyan', printRow(sortFields)))\n for (const row of rows) this.log(printRow(row))\n } catch (error) {\n projectsDebug('Error listing projects', error)\n this.error('Failed to list projects', {exit: 1})\n }\n }\n}\n"],"names":["styleText","Flags","SanityCommand","subdebug","size","sortBy","getManageUrl","listProjects","sortFields","projectsDebug","List","description","examples","command","flags","order","string","default","options","sort","hiddenAliases","run","projects","ordered","map","createdAt","displayName","id","members","manage","length","String","indexOf","rows","toReversed","maxWidths","str","row","i","element","entries","Math","max","printRow","col","padEnd","join","log","error","exit"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,KAAK,QAAO,cAAa;AACjC,SAAQC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,OAAOC,UAAU,oBAAmB;AACpC,OAAOC,YAAY,sBAAqB;AAExC,SAAQC,YAAY,QAAO,yCAAwC;AACnE,SAAQC,YAAY,QAAO,6BAA4B;AAEvD,MAAMC,aAAa;IAAC;IAAM;IAAW;IAAQ;IAAO;CAAU;AAE9D,MAAMC,gBAAgBN,SAAS;AAE/B,OAAO,MAAMO,aAAaR;IACxB,OAAgBS,cAAc,qBAAoB;IAClD,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,OAAgBG,QAAQ;QACtBC,OAAOd,MAAMe,MAAM,CAAC;YAClBC,SAAS;YACTN,aAAa;YACbO,SAAS;gBAAC;gBAAO;aAAO;QAC1B;QACAC,MAAMlB,MAAMe,MAAM,CAAC;YACjBC,SAAS;YACTN,aAAa;YACbO,SAASV;QACX;IACF,EAAC;IAED,OAAgBY,gBAA0B;QAAC;KAAe,CAAA;IAE1D,MAAaC,MAAM;QACjB,MAAM,EAACN,KAAK,EAAEI,IAAI,EAAC,GAAG,IAAI,CAACL,KAAK;QAEhC,IAAI;YACF,MAAMQ,WAAW,MAAMf;YACvB,MAAMgB,UAAUlB,OACdiB,SAASE,GAAG,CAAC,CAAC,EAACC,SAAS,EAAEC,WAAW,EAAEC,EAAE,EAAEC,UAAU,EAAE,EAAC;gBACtD,MAAMC,SAASvB,aAAaqB;gBAC5B,OAAO;oBAACA;oBAAIC,QAAQE,MAAM;oBAAEJ;oBAAaG;oBAAQJ;iBAAU,CAACD,GAAG,CAACO;YAClE,IACA;gBAACvB,WAAWwB,OAAO,CAACb;aAAM;YAG5B,MAAMc,OAAOlB,UAAU,QAAQQ,UAAUA,QAAQW,UAAU;YAE3D,qDAAqD;YACrD,MAAMC,YAAY3B,WAAWgB,GAAG,CAAC,CAACY,MAAQhC,KAAKgC;YAE/C,0CAA0C;YAC1C,KAAK,MAAMC,OAAOJ,KAAM;gBACtB,KAAK,MAAM,CAACK,GAAGC,QAAQ,IAAIF,IAAIG,OAAO,GAAI;oBACxCL,SAAS,CAACG,EAAE,GAAGG,KAAKC,GAAG,CAACtC,KAAKmC,UAAUJ,SAAS,CAACG,EAAE;gBACrD;YACF;YAEA,MAAMK,WAAW,CAACN,MAChBA,IAAIb,GAAG,CAAC,CAACoB,KAAKN,IAAM,GAAGM,KAAK,CAACC,MAAM,CAACV,SAAS,CAACG,EAAE,GAAGQ,IAAI,CAAC;YAE1D,IAAI,CAACC,GAAG,CAAC/C,UAAU,QAAQ2C,SAASnC;YACpC,KAAK,MAAM6B,OAAOJ,KAAM,IAAI,CAACc,GAAG,CAACJ,SAASN;QAC5C,EAAE,OAAOW,OAAO;YACdvC,cAAc,0BAA0BuC;YACxC,IAAI,CAACA,KAAK,CAAC,2BAA2B;gBAACC,MAAM;YAAC;QAChD;IACF;AACF"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
-
import {
|
|
2
|
+
import { subdebug } from '@sanity/cli-core/debug';
|
|
3
|
+
import { SanityCommand } from '@sanity/cli-core/SanityCommand';
|
|
3
4
|
import { validateAction } from '../../actions/schema/validateAction.js';
|
|
4
5
|
const debug = subdebug('schema:validate');
|
|
5
6
|
export class SchemaValidate extends SanityCommand {
|
|
@@ -66,7 +67,7 @@ export class SchemaValidate extends SanityCommand {
|
|
|
66
67
|
await validateAction(options);
|
|
67
68
|
} catch (error) {
|
|
68
69
|
debug('Error validating schema', error);
|
|
69
|
-
this.error(`Error validating schema: ${error instanceof Error ? error.message : String(error)}`, {
|
|
70
|
+
return this.output.error(`Error validating schema: ${error instanceof Error ? error.message : String(error)}`, {
|
|
70
71
|
exit: 1
|
|
71
72
|
});
|
|
72
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/schemas/validate.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/schemas/validate.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {subdebug} from '@sanity/cli-core/debug'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\n\nimport {validateAction} from '../../actions/schema/validateAction.js'\n\nconst debug = subdebug('schema:validate')\nexport class SchemaValidate extends SanityCommand<typeof SchemaValidate> {\n static override description = 'Validates all schema types specified in a workspace'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> --workspace default',\n description: 'Validates all schema types in a Sanity project with more than one workspace',\n },\n {\n command: '<%= config.bin %> <%= command.id %> > report.txt',\n description: 'Save the results of the report into a file',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --level error',\n description: 'Report out only errors',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --debug-metafile-path metafile.json',\n description:\n 'Generate a report which can be analyzed with https://esbuild.github.io/analyze/',\n },\n ]\n\n static override flags = {\n 'debug-metafile-path': Flags.string({\n description:\n 'Optional path where a metafile will be written for build analysis. Only written on successful validation. Can be analyzed at https://esbuild.github.io/analyze/',\n helpGroup: 'DEBUG',\n }),\n format: Flags.string({\n default: 'pretty',\n description: 'The output format used to print schema errors and warnings',\n options: ['pretty', 'ndjson', 'json'],\n }),\n level: Flags.string({\n default: 'warning',\n description: 'The minimum level reported out',\n options: ['error', 'warning'],\n }),\n workspace: Flags.string({\n description: 'The name of the workspace to use when validating all schema types',\n }),\n }\n\n static override hiddenAliases: string[] = ['schema:validate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(SchemaValidate)\n\n const workDir = (await this.getProjectRoot()).directory\n\n const options = {\n debugMetafilePath: flags['debug-metafile-path'],\n format: flags.format,\n level: flags.level as 'error' | 'warning',\n output: this.output,\n workDir,\n workspace: flags.workspace,\n }\n\n try {\n await validateAction(options)\n } catch (error) {\n debug('Error validating schema', error)\n return this.output.error(\n `Error validating schema: ${error instanceof Error ? error.message : String(error)}`,\n {exit: 1},\n )\n }\n }\n}\n"],"names":["Flags","subdebug","SanityCommand","validateAction","debug","SchemaValidate","description","examples","command","flags","string","helpGroup","format","default","options","level","workspace","hiddenAliases","run","parse","workDir","getProjectRoot","directory","debugMetafilePath","output","error","Error","message","String","exit"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AACjC,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,aAAa,QAAO,iCAAgC;AAE5D,SAAQC,cAAc,QAAO,yCAAwC;AAErE,MAAMC,QAAQH,SAAS;AACvB,OAAO,MAAMI,uBAAuBH;IAClC,OAAgBI,cAAc,sDAAqD;IAEnF,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aAAa;QACf;QACA;YACEE,SAAS;YACTF,aACE;QACJ;KACD,CAAA;IAED,OAAgBG,QAAQ;QACtB,uBAAuBT,MAAMU,MAAM,CAAC;YAClCJ,aACE;YACFK,WAAW;QACb;QACAC,QAAQZ,MAAMU,MAAM,CAAC;YACnBG,SAAS;YACTP,aAAa;YACbQ,SAAS;gBAAC;gBAAU;gBAAU;aAAO;QACvC;QACAC,OAAOf,MAAMU,MAAM,CAAC;YAClBG,SAAS;YACTP,aAAa;YACbQ,SAAS;gBAAC;gBAAS;aAAU;QAC/B;QACAE,WAAWhB,MAAMU,MAAM,CAAC;YACtBJ,aAAa;QACf;IACF,EAAC;IAED,OAAgBW,gBAA0B;QAAC;KAAkB,CAAA;IAE7D,MAAaC,MAAqB;QAChC,MAAM,EAACT,KAAK,EAAC,GAAG,MAAM,IAAI,CAACU,KAAK,CAACd;QAEjC,MAAMe,UAAU,AAAC,CAAA,MAAM,IAAI,CAACC,cAAc,EAAC,EAAGC,SAAS;QAEvD,MAAMR,UAAU;YACdS,mBAAmBd,KAAK,CAAC,sBAAsB;YAC/CG,QAAQH,MAAMG,MAAM;YACpBG,OAAON,MAAMM,KAAK;YAClBS,QAAQ,IAAI,CAACA,MAAM;YACnBJ;YACAJ,WAAWP,MAAMO,SAAS;QAC5B;QAEA,IAAI;YACF,MAAMb,eAAeW;QACvB,EAAE,OAAOW,OAAO;YACdrB,MAAM,2BAA2BqB;YACjC,OAAO,IAAI,CAACD,MAAM,CAACC,KAAK,CACtB,CAAC,yBAAyB,EAAEA,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH,QAAQ,EACpF;gBAACI,MAAM;YAAC;QAEZ;IACF;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SanityCommand, subdebug } from '@sanity/cli-core';
|
|
2
|
+
import { getErrorMessage, toError } from '@sanity/cli-core/errors';
|
|
2
3
|
import { configureSkills } from '../../actions/skills/configureSkills.js';
|
|
3
4
|
import { SkillsInstallTrace } from '../../telemetry/skills.telemetry.js';
|
|
4
|
-
import { getErrorMessage, toError } from '../../util/getErrorMessage.js';
|
|
5
5
|
const debug = subdebug('skills:install');
|
|
6
6
|
export class InstallSkillsCommand extends SanityCommand {
|
|
7
7
|
static description = 'Install Sanity agent skills for detected AI editors (Antigravity, Claude Code, Cline, Cline CLI, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, OpenCode, VS Code, VS Code Insiders)';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/skills/install.ts"],"sourcesContent":["import {SanityCommand, subdebug} from '@sanity/cli-core'\
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/skills/install.ts"],"sourcesContent":["import {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage, toError} from '@sanity/cli-core/errors'\n\nimport {configureSkills} from '../../actions/skills/configureSkills.js'\nimport {SkillsInstallTrace} from '../../telemetry/skills.telemetry.js'\n\nconst debug = subdebug('skills:install')\n\nexport class InstallSkillsCommand extends SanityCommand<typeof InstallSkillsCommand> {\n static override description =\n 'Install Sanity agent skills for detected AI editors (Antigravity, Claude Code, Cline, Cline CLI, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, OpenCode, VS Code, VS Code Insiders)'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Install Sanity agent skills for detected AI editors',\n },\n ]\n\n public async run(): Promise<void> {\n const trace = this.telemetry.trace(SkillsInstallTrace)\n trace.start()\n\n try {\n const result = await configureSkills({output: this.output})\n\n trace.log({\n detectedEditors: result.detectedEditors,\n installedAgents: result.installedAgents,\n })\n\n if (result.error) {\n trace.error(result.error)\n } else {\n trace.complete()\n }\n } catch (error) {\n debug('Skills installation failed: %O', error)\n trace.error(toError(error))\n this.error(getErrorMessage(error), {exit: 1})\n }\n }\n}\n"],"names":["SanityCommand","subdebug","getErrorMessage","toError","configureSkills","SkillsInstallTrace","debug","InstallSkillsCommand","description","examples","command","run","trace","telemetry","start","result","output","log","detectedEditors","installedAgents","error","complete","exit"],"mappings":"AAAA,SAAQA,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,eAAe,EAAEC,OAAO,QAAO,0BAAyB;AAEhE,SAAQC,eAAe,QAAO,0CAAyC;AACvE,SAAQC,kBAAkB,QAAO,sCAAqC;AAEtE,MAAMC,QAAQL,SAAS;AAEvB,OAAO,MAAMM,6BAA6BP;IACxC,OAAgBQ,cACd,2LAA0L;IAE5L,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,MAAaG,MAAqB;QAChC,MAAMC,QAAQ,IAAI,CAACC,SAAS,CAACD,KAAK,CAACP;QACnCO,MAAME,KAAK;QAEX,IAAI;YACF,MAAMC,SAAS,MAAMX,gBAAgB;gBAACY,QAAQ,IAAI,CAACA,MAAM;YAAA;YAEzDJ,MAAMK,GAAG,CAAC;gBACRC,iBAAiBH,OAAOG,eAAe;gBACvCC,iBAAiBJ,OAAOI,eAAe;YACzC;YAEA,IAAIJ,OAAOK,KAAK,EAAE;gBAChBR,MAAMQ,KAAK,CAACL,OAAOK,KAAK;YAC1B,OAAO;gBACLR,MAAMS,QAAQ;YAChB;QACF,EAAE,OAAOD,OAAO;YACdd,MAAM,kCAAkCc;YACxCR,MAAMQ,KAAK,CAACjB,QAAQiB;YACpB,IAAI,CAACA,KAAK,CAAClB,gBAAgBkB,QAAQ;gBAACE,MAAM;YAAC;QAC7C;IACF;AACF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import { SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
3
4
|
import { Table } from 'console-table-printer';
|
|
4
5
|
import { promptForProject } from '../../prompts/promptForProject.js';
|
|
5
6
|
import { getTokens } from '../../services/tokens.js';
|
|
6
|
-
import { getErrorMessage } from '../../util/getErrorMessage.js';
|
|
7
7
|
import { getProjectIdFlag } from '../../util/sharedFlags.js';
|
|
8
8
|
const listTokenDebug = subdebug('tokens:list');
|
|
9
9
|
export class TokensListCommand extends SanityCommand {
|