@sanity/cli 8.25.0 → 8.27.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 (127) hide show
  1. package/README.md +3 -2
  2. package/dist/actions/build/shouldAutoUpdate.js +1 -26
  3. package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
  4. package/dist/actions/context/mcpEndpoint.js +165 -0
  5. package/dist/actions/context/mcpEndpoint.js.map +1 -0
  6. package/dist/actions/context/resolveOrganizationId.js +8 -1
  7. package/dist/actions/context/resolveOrganizationId.js.map +1 -1
  8. package/dist/actions/deploy/deployApp.js +10 -3
  9. package/dist/actions/deploy/deployApp.js.map +1 -1
  10. package/dist/actions/deploy/deployStudio.js +11 -4
  11. package/dist/actions/deploy/deployStudio.js.map +1 -1
  12. package/dist/actions/init/initAction.js +3 -3
  13. package/dist/actions/init/initAction.js.map +1 -1
  14. package/dist/actions/init/plan/verifyCoupon.js +0 -1
  15. package/dist/actions/init/plan/verifyCoupon.js.map +1 -1
  16. package/dist/actions/init/scaffoldTemplate.js +1 -1
  17. package/dist/actions/init/scaffoldTemplate.js.map +1 -1
  18. package/dist/commands/api.js +10 -0
  19. package/dist/commands/api.js.map +1 -1
  20. package/dist/commands/backups/download.js +6 -0
  21. package/dist/commands/backups/download.js.map +1 -1
  22. package/dist/commands/context/create.js +8 -22
  23. package/dist/commands/context/create.js.map +1 -1
  24. package/dist/commands/context/delete.js +8 -1
  25. package/dist/commands/context/delete.js.map +1 -1
  26. package/dist/commands/context/issues/list.js +0 -5
  27. package/dist/commands/context/issues/list.js.map +1 -1
  28. package/dist/commands/context/list.js +6 -14
  29. package/dist/commands/context/list.js.map +1 -1
  30. package/dist/commands/context/mcp/create.js +152 -0
  31. package/dist/commands/context/mcp/create.js.map +1 -0
  32. package/dist/commands/context/mcp/delete.js +82 -0
  33. package/dist/commands/context/mcp/delete.js.map +1 -0
  34. package/dist/commands/context/mcp/get.js +42 -0
  35. package/dist/commands/context/mcp/get.js.map +1 -0
  36. package/dist/commands/context/mcp/list.js +87 -0
  37. package/dist/commands/context/mcp/list.js.map +1 -0
  38. package/dist/commands/context/mcp/status.js +98 -0
  39. package/dist/commands/context/mcp/status.js.map +1 -0
  40. package/dist/commands/context/mcp/update.js +225 -0
  41. package/dist/commands/context/mcp/update.js.map +1 -0
  42. package/dist/commands/context/query.js +6 -14
  43. package/dist/commands/context/query.js.map +1 -1
  44. package/dist/commands/context/update.js +12 -1
  45. package/dist/commands/context/update.js.map +1 -1
  46. package/dist/commands/datasets/create.js +6 -0
  47. package/dist/commands/datasets/create.js.map +1 -1
  48. package/dist/commands/datasets/embeddings/enable.js +6 -0
  49. package/dist/commands/datasets/embeddings/enable.js.map +1 -1
  50. package/dist/commands/datasets/import.js +6 -0
  51. package/dist/commands/datasets/import.js.map +1 -1
  52. package/dist/commands/deploy.js +7 -0
  53. package/dist/commands/deploy.js.map +1 -1
  54. package/dist/commands/documents/validate.js +6 -0
  55. package/dist/commands/documents/validate.js.map +1 -1
  56. package/dist/commands/exec.js +4 -2
  57. package/dist/commands/exec.js.map +1 -1
  58. package/dist/commands/init.js +13 -0
  59. package/dist/commands/init.js.map +1 -1
  60. package/dist/commands/manifest/extract.js +6 -0
  61. package/dist/commands/manifest/extract.js.map +1 -1
  62. package/dist/commands/media/create-aspect.js +7 -0
  63. package/dist/commands/media/create-aspect.js.map +1 -1
  64. package/dist/commands/migrations/run.js +6 -0
  65. package/dist/commands/migrations/run.js.map +1 -1
  66. package/dist/commands/organizations/create.js +6 -0
  67. package/dist/commands/organizations/create.js.map +1 -1
  68. package/dist/commands/organizations/update.js +6 -0
  69. package/dist/commands/organizations/update.js.map +1 -1
  70. package/dist/commands/schemas/delete.js +6 -0
  71. package/dist/commands/schemas/delete.js.map +1 -1
  72. package/dist/commands/schemas/deploy.js +6 -0
  73. package/dist/commands/schemas/deploy.js.map +1 -1
  74. package/dist/commands/schemas/extract.js +28 -3
  75. package/dist/commands/schemas/extract.js.map +1 -1
  76. package/dist/commands/schemas/list.js +6 -0
  77. package/dist/commands/schemas/list.js.map +1 -1
  78. package/dist/commands/schemas/validate.js +6 -0
  79. package/dist/commands/schemas/validate.js.map +1 -1
  80. package/dist/commands/tokens/rotate.js +6 -0
  81. package/dist/commands/tokens/rotate.js.map +1 -1
  82. package/dist/commands/typegen/generate.js +25 -1
  83. package/dist/commands/typegen/generate.js.map +1 -1
  84. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +6 -0
  85. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  86. package/dist/generated/apiRoutes.js +22 -0
  87. package/dist/generated/apiRoutes.js.map +1 -1
  88. package/dist/hooks/prerun/setupTelemetry.js +2 -3
  89. package/dist/hooks/prerun/setupTelemetry.js.map +1 -1
  90. package/dist/prompts/promptForText.js +12 -0
  91. package/dist/prompts/promptForText.js.map +1 -0
  92. package/dist/services/context.js +174 -1
  93. package/dist/services/context.js.map +1 -1
  94. package/dist/services/telemetry.js +4 -2
  95. package/dist/services/telemetry.js.map +1 -1
  96. package/dist/telemetry/cli.telemetry.js +1 -1
  97. package/dist/telemetry/cli.telemetry.js.map +1 -1
  98. package/dist/telemetry/init.telemetry.js +1 -1
  99. package/dist/telemetry/init.telemetry.js.map +1 -1
  100. package/dist/telemetry/typegen.telemetry.js +12 -0
  101. package/dist/telemetry/typegen.telemetry.js.map +1 -0
  102. package/dist/util/parseArguments.js +12 -40
  103. package/dist/util/parseArguments.js.map +1 -1
  104. package/dist/util/sharedFlags.js.map +1 -1
  105. package/dist/util/telemetry/cliCommandIdentity.js +222 -0
  106. package/dist/util/telemetry/cliCommandIdentity.js.map +1 -0
  107. package/dist/util/telemetry/cliTelemetryFlags.js +186 -0
  108. package/dist/util/telemetry/cliTelemetryFlags.js.map +1 -0
  109. package/dist/util/telemetry/commandTelemetry.js +56 -11
  110. package/dist/util/telemetry/commandTelemetry.js.map +1 -1
  111. package/dist/util/telemetry/createTelemetryStore.js +13 -5
  112. package/dist/util/telemetry/createTelemetryStore.js.map +1 -1
  113. package/dist/util/telemetry/createTraceId.js +3 -3
  114. package/dist/util/telemetry/createTraceId.js.map +1 -1
  115. package/dist/util/telemetry/flushTelemetryFiles.js +14 -4
  116. package/dist/util/telemetry/flushTelemetryFiles.js.map +1 -1
  117. package/dist/util/telemetry/logger.js +1 -1
  118. package/dist/util/telemetry/logger.js.map +1 -1
  119. package/dist/util/telemetry/readNDJSON.js +1 -1
  120. package/dist/util/telemetry/readNDJSON.js.map +1 -1
  121. package/dist/util/telemetry/sanitizeTelemetryEvent.js +304 -0
  122. package/dist/util/telemetry/sanitizeTelemetryEvent.js.map +1 -0
  123. package/dist/util/telemetry/trace.js +4 -7
  124. package/dist/util/telemetry/trace.js.map +1 -1
  125. package/oclif.config.js +1 -1
  126. package/oclif.manifest.json +2380 -1526
  127. package/package.json +8 -11
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/backups/download.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport {access, mkdir, mkdtemp} from 'node:fs/promises'\nimport {tmpdir} from 'node:os'\nimport path from 'node:path'\nimport {finished} from 'node:stream/promises'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {requiredWhenUnattended} from '@sanity/cli-core/flags'\nimport {boxen, confirm, input, select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport pMap from 'p-map'\nimport prettyMs from 'pretty-ms'\n\nimport {archiveDir} from '../../actions/backup/archiveDir.js'\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {backupDownloadDebug} from '../../actions/backup/backupDownloadDebug.js'\nimport {cleanupTmpDir} from '../../actions/backup/cleanupTmpDir.js'\nimport {downloadAsset} from '../../actions/backup/downloadAsset.js'\nimport {downloadDocument} from '../../actions/backup/downloadDocument.js'\nimport {type File, PaginatedGetBackupStream} from '../../actions/backup/fetchNextBackupPage.js'\nimport {newProgress} from '../../actions/backup/progressSpinner.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type BackupItem, listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {humanFileSize} from '../../util/humanFileSize.js'\nimport {isPathDirName} from '../../util/isPathDirName.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst DEFAULT_DOWNLOAD_CONCURRENCY = 10\nconst MAX_DOWNLOAD_CONCURRENCY = 24\n\ninterface DownloadBackupOptions {\n backupId: string\n concurrency: number\n datasetName: string\n outDir: string\n outFileName: string\n overwrite: boolean\n projectId: string\n}\n\nexport class DownloadBackupCommand extends SanityCommand<typeof DownloadBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to download backup from',\n required: false,\n }),\n }\n\n static override description = 'Download a dataset backup to a local file'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively download a backup',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-1',\n description: 'Download a specific backup for the production dataset',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-2 --out /path/to/file',\n description: 'Download backup to a specific file',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-3 --out /path/to/file --overwrite',\n description: 'Download backup and overwrite existing file',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to download backup from',\n semantics: 'override',\n }),\n 'backup-id': requiredWhenUnattended(\n Flags.string({\n description: 'The backup ID to download',\n }),\n ),\n concurrency: Flags.integer({\n default: DEFAULT_DOWNLOAD_CONCURRENCY,\n description: `Concurrent number of backup item downloads (max: ${MAX_DOWNLOAD_CONCURRENCY})`,\n }),\n out: Flags.string({\n description: 'The file or directory path the backup should download to',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Allows overwriting of existing backup file',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:download']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DownloadBackupCommand)\n let {dataset} = args\n\n if (this.isUnattended() && !dataset) {\n this.error('Dataset is required in unattended mode. Pass it as the `<dataset>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset, this.output)\n } else {\n dataset = await promptForDataset({allowCreation: false, datasets})\n }\n\n const opts = await this.prepareBackupOptions(projectId, dataset)\n const outFilePath = path.join(opts.outDir, opts.outFileName)\n\n this.log(\n boxen(\n `Downloading backup for:\n\n${styleText('bold', 'projectId')}: ${styleText('cyan', opts.projectId)}\n${styleText('bold', 'dataset')}: ${styleText('cyan', opts.datasetName)}\n${styleText('bold', 'backupId')}: ${styleText('cyan', opts.backupId)}`,\n {\n borderColor: 'cyan',\n borderStyle: 'round',\n padding: 1,\n },\n ),\n )\n this.log('')\n this.log(`Downloading backup to \"${styleText('cyan', outFilePath)}\"`)\n\n const start = Date.now()\n const progressSpinner = newProgress('Setting up backup environment...')\n\n // Create a unique temporary directory to store files before bundling them into the archive at outputPath.\n // Temporary directories are normally deleted at the end of backup process, any unexpected exit may leave them\n // behind, hence it is important to create a unique directory for each attempt.\n const tmpOutDir = await mkdtemp(path.join(tmpdir(), `sanity-backup-`))\n\n // Create required directories if they don't exist.\n for (const dir of [\n opts.outDir,\n path.join(tmpOutDir, 'images'),\n path.join(tmpOutDir, 'files'),\n ]) {\n await mkdir(dir, {recursive: true})\n }\n\n backupDownloadDebug('Writing to temporary directory %s', tmpOutDir)\n const tmpOutDocumentsFile = path.join(tmpOutDir, 'data.ndjson')\n\n const docOutStream = createWriteStream(tmpOutDocumentsFile)\n\n try {\n const backupFileStream = new PaginatedGetBackupStream(\n opts.projectId,\n opts.datasetName,\n opts.backupId,\n )\n\n const files: File[] = []\n let i = 0\n for await (const file of backupFileStream) {\n files.push(file)\n i++\n progressSpinner.set({\n current: i,\n step: `Reading backup files...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n }\n\n let totalItemsDownloaded = 0\n await pMap(\n files,\n async (file: File) => {\n if (file.type === 'file' || file.type === 'image') {\n await downloadAsset(file.url, file.name, file.type, tmpOutDir)\n } else {\n const doc = await downloadDocument(file.url)\n docOutStream.write(`${doc}\\n`)\n }\n\n totalItemsDownloaded += 1\n progressSpinner.set({\n current: totalItemsDownloaded,\n step: `Downloading documents and assets...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n },\n {concurrency: opts.concurrency},\n )\n } catch (error) {\n progressSpinner.fail()\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Downloading dataset backup failed: ${message}`, error)\n this.error(`Downloading dataset backup failed: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n docOutStream.end()\n await finished(docOutStream)\n\n progressSpinner.set({step: `Archiving files into a tarball...`, update: true})\n try {\n await archiveDir(tmpOutDir, outFilePath, (processedBytes: number) => {\n progressSpinner.update({\n step: `Archiving files into a tarball, ${humanFileSize(processedBytes)} bytes written...`,\n })\n })\n } catch (err) {\n progressSpinner.fail()\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Archiving backup failed: ${message}`, err)\n this.error(`Archiving backup failed: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n progressSpinner.set({\n step: `Cleaning up temporary files at ${styleText('cyan', `${tmpOutDir}`)}`,\n })\n await cleanupTmpDir(tmpOutDir)\n\n progressSpinner.set({\n step: `Backup download complete [${prettyMs(Date.now() - start)}]`,\n })\n progressSpinner.succeed()\n }\n\n private async getOutputPath(defaultOutFileName: string): Promise<string> {\n if (this.flags.out !== undefined) {\n // Rewrite the output path to an absolute path, if it is not already.\n return path.resolve(this.flags.out)\n }\n\n const workDir = process.cwd()\n const defaultPath = path.join(workDir, defaultOutFileName)\n if (this.isUnattended()) {\n return defaultPath\n }\n\n const inputResult = await input({\n default: defaultPath,\n message: 'Output path:',\n })\n return path.resolve(inputResult)\n }\n\n private async prepareBackupOptions(\n projectId: string,\n datasetName: string,\n ): Promise<DownloadBackupOptions> {\n const err = validateDatasetName(datasetName)\n if (err) {\n this.error(err, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n const backupId = String(\n this.flags['backup-id'] || (await this.promptForBackupId(projectId, datasetName)),\n )\n\n if (\n 'concurrency' in this.flags &&\n (this.flags.concurrency < 1 || this.flags.concurrency > MAX_DOWNLOAD_CONCURRENCY)\n ) {\n this.error(`\\`--concurrency\\` must be between 1 and ${MAX_DOWNLOAD_CONCURRENCY}.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const defaultOutFileName = `${datasetName}-backup-${backupId}.tar.gz`\n let out = await this.getOutputPath(defaultOutFileName)\n\n // If path is a directory name, then add a default file name to the path.\n if (isPathDirName(out)) {\n out = path.join(out, defaultOutFileName)\n }\n\n const exists = await access(out).then(\n () => true,\n () => false,\n )\n // If the file already exists, ask for confirmation if it should be overwritten.\n if (!this.flags.overwrite && exists) {\n if (this.isUnattended()) {\n this.error(`File \"${out}\" already exists. Pass \\`--overwrite\\` to replace it.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n const shouldOverwrite = await confirm({\n default: false,\n message: `File \"${out}\" already exists, would you like to overwrite it?`,\n })\n\n // If the user does not want to overwrite the file, cancel the operation.\n if (!shouldOverwrite) {\n this.error('Operation cancelled.', {exit: exitCodes.USER_ABORT})\n }\n }\n\n return {\n backupId,\n concurrency: this.flags.concurrency || DEFAULT_DOWNLOAD_CONCURRENCY,\n datasetName,\n outDir: path.dirname(out),\n outFileName: path.basename(out),\n overwrite: this.flags.overwrite,\n projectId,\n }\n }\n\n private async promptForBackupId(projectId: string, datasetName: string): Promise<string> {\n const maxBackupIdsShown = 100\n\n try {\n const response = await listBackups({\n datasetName,\n limit: maxBackupIdsShown,\n projectId,\n })\n\n if (!response?.backups?.length) {\n this.error('No backups found', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n const backupIdChoices = response.backups.map((backup: BackupItem) => ({\n name: backup.id,\n value: backup.id,\n }))\n\n const hint =\n backupIdChoices.length === maxBackupIdsShown\n ? ` (only last ${maxBackupIdsShown} shown)`\n : ''\n\n return select({\n choices: backupIdChoices,\n message: `Select backup ID to use${hint}`,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Failed to fetch backups for dataset ${datasetName}: ${message}`, err)\n this.error(`Failed to fetch backups for dataset ${datasetName}: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["createWriteStream","access","mkdir","mkdtemp","tmpdir","path","finished","styleText","Args","Flags","exitCodes","SanityCommand","requiredWhenUnattended","boxen","confirm","input","select","pMap","prettyMs","archiveDir","assertDatasetExists","backupDownloadDebug","cleanupTmpDir","downloadAsset","downloadDocument","PaginatedGetBackupStream","newProgress","validateDatasetName","promptForDataset","promptForProject","listBackups","listDatasets","humanFileSize","isPathDirName","getProjectIdFlag","DEFAULT_DOWNLOAD_CONCURRENCY","MAX_DOWNLOAD_CONCURRENCY","DownloadBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","concurrency","integer","default","out","overwrite","boolean","hiddenAliases","run","parse","isUnattended","error","exit","USAGE_ERROR","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","message","Error","String","RUNTIME_ERROR","length","output","allowCreation","opts","prepareBackupOptions","outFilePath","join","outDir","outFileName","log","datasetName","backupId","borderColor","borderStyle","padding","start","Date","now","progressSpinner","tmpOutDir","dir","recursive","tmpOutDocumentsFile","docOutStream","backupFileStream","files","i","file","push","set","current","step","total","totalFiles","update","totalItemsDownloaded","type","url","name","doc","write","fail","end","processedBytes","err","succeed","getOutputPath","defaultOutFileName","undefined","resolve","workDir","process","cwd","defaultPath","inputResult","promptForBackupId","exists","then","shouldOverwrite","USER_ABORT","dirname","basename","maxBackupIdsShown","response","limit","backups","backupIdChoices","map","backup","id","value","hint","choices"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/backups/download.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport {access, mkdir, mkdtemp} from 'node:fs/promises'\nimport {tmpdir} from 'node:os'\nimport path from 'node:path'\nimport {finished} from 'node:stream/promises'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {requiredWhenUnattended} from '@sanity/cli-core/flags'\nimport {boxen, confirm, input, select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport pMap from 'p-map'\nimport prettyMs from 'pretty-ms'\n\nimport {archiveDir} from '../../actions/backup/archiveDir.js'\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {backupDownloadDebug} from '../../actions/backup/backupDownloadDebug.js'\nimport {cleanupTmpDir} from '../../actions/backup/cleanupTmpDir.js'\nimport {downloadAsset} from '../../actions/backup/downloadAsset.js'\nimport {downloadDocument} from '../../actions/backup/downloadDocument.js'\nimport {type File, PaginatedGetBackupStream} from '../../actions/backup/fetchNextBackupPage.js'\nimport {newProgress} from '../../actions/backup/progressSpinner.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type BackupItem, listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {humanFileSize} from '../../util/humanFileSize.js'\nimport {isPathDirName} from '../../util/isPathDirName.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\nimport {defineCommandTelemetry} from '../../util/telemetry/commandTelemetry.js'\n\nconst DEFAULT_DOWNLOAD_CONCURRENCY = 10\nconst MAX_DOWNLOAD_CONCURRENCY = 24\n\ninterface DownloadBackupOptions {\n backupId: string\n concurrency: number\n datasetName: string\n outDir: string\n outFileName: string\n overwrite: boolean\n projectId: string\n}\n\nexport class DownloadBackupCommand extends SanityCommand<typeof DownloadBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to download backup from',\n required: false,\n }),\n }\n\n static override description = 'Download a dataset backup to a local file'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively download a backup',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-1',\n description: 'Download a specific backup for the production dataset',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-2 --out /path/to/file',\n description: 'Download backup to a specific file',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-3 --out /path/to/file --overwrite',\n description: 'Download backup and overwrite existing file',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to download backup from',\n semantics: 'override',\n }),\n 'backup-id': requiredWhenUnattended(\n Flags.string({\n description: 'The backup ID to download',\n }),\n ),\n concurrency: Flags.integer({\n default: DEFAULT_DOWNLOAD_CONCURRENCY,\n description: `Concurrent number of backup item downloads (max: ${MAX_DOWNLOAD_CONCURRENCY})`,\n }),\n out: Flags.string({\n description: 'The file or directory path the backup should download to',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Allows overwriting of existing backup file',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:download']\n\n static telemetry = defineCommandTelemetry(this.flags, {redact: ['out']})\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DownloadBackupCommand)\n let {dataset} = args\n\n if (this.isUnattended() && !dataset) {\n this.error('Dataset is required in unattended mode. Pass it as the `<dataset>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset, this.output)\n } else {\n dataset = await promptForDataset({allowCreation: false, datasets})\n }\n\n const opts = await this.prepareBackupOptions(projectId, dataset)\n const outFilePath = path.join(opts.outDir, opts.outFileName)\n\n this.log(\n boxen(\n `Downloading backup for:\n\n${styleText('bold', 'projectId')}: ${styleText('cyan', opts.projectId)}\n${styleText('bold', 'dataset')}: ${styleText('cyan', opts.datasetName)}\n${styleText('bold', 'backupId')}: ${styleText('cyan', opts.backupId)}`,\n {\n borderColor: 'cyan',\n borderStyle: 'round',\n padding: 1,\n },\n ),\n )\n this.log('')\n this.log(`Downloading backup to \"${styleText('cyan', outFilePath)}\"`)\n\n const start = Date.now()\n const progressSpinner = newProgress('Setting up backup environment...')\n\n // Create a unique temporary directory to store files before bundling them into the archive at outputPath.\n // Temporary directories are normally deleted at the end of backup process, any unexpected exit may leave them\n // behind, hence it is important to create a unique directory for each attempt.\n const tmpOutDir = await mkdtemp(path.join(tmpdir(), `sanity-backup-`))\n\n // Create required directories if they don't exist.\n for (const dir of [\n opts.outDir,\n path.join(tmpOutDir, 'images'),\n path.join(tmpOutDir, 'files'),\n ]) {\n await mkdir(dir, {recursive: true})\n }\n\n backupDownloadDebug('Writing to temporary directory %s', tmpOutDir)\n const tmpOutDocumentsFile = path.join(tmpOutDir, 'data.ndjson')\n\n const docOutStream = createWriteStream(tmpOutDocumentsFile)\n\n try {\n const backupFileStream = new PaginatedGetBackupStream(\n opts.projectId,\n opts.datasetName,\n opts.backupId,\n )\n\n const files: File[] = []\n let i = 0\n for await (const file of backupFileStream) {\n files.push(file)\n i++\n progressSpinner.set({\n current: i,\n step: `Reading backup files...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n }\n\n let totalItemsDownloaded = 0\n await pMap(\n files,\n async (file: File) => {\n if (file.type === 'file' || file.type === 'image') {\n await downloadAsset(file.url, file.name, file.type, tmpOutDir)\n } else {\n const doc = await downloadDocument(file.url)\n docOutStream.write(`${doc}\\n`)\n }\n\n totalItemsDownloaded += 1\n progressSpinner.set({\n current: totalItemsDownloaded,\n step: `Downloading documents and assets...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n },\n {concurrency: opts.concurrency},\n )\n } catch (error) {\n progressSpinner.fail()\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Downloading dataset backup failed: ${message}`, error)\n this.error(`Downloading dataset backup failed: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n docOutStream.end()\n await finished(docOutStream)\n\n progressSpinner.set({step: `Archiving files into a tarball...`, update: true})\n try {\n await archiveDir(tmpOutDir, outFilePath, (processedBytes: number) => {\n progressSpinner.update({\n step: `Archiving files into a tarball, ${humanFileSize(processedBytes)} bytes written...`,\n })\n })\n } catch (err) {\n progressSpinner.fail()\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Archiving backup failed: ${message}`, err)\n this.error(`Archiving backup failed: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n progressSpinner.set({\n step: `Cleaning up temporary files at ${styleText('cyan', `${tmpOutDir}`)}`,\n })\n await cleanupTmpDir(tmpOutDir)\n\n progressSpinner.set({\n step: `Backup download complete [${prettyMs(Date.now() - start)}]`,\n })\n progressSpinner.succeed()\n }\n\n private async getOutputPath(defaultOutFileName: string): Promise<string> {\n if (this.flags.out !== undefined) {\n // Rewrite the output path to an absolute path, if it is not already.\n return path.resolve(this.flags.out)\n }\n\n const workDir = process.cwd()\n const defaultPath = path.join(workDir, defaultOutFileName)\n if (this.isUnattended()) {\n return defaultPath\n }\n\n const inputResult = await input({\n default: defaultPath,\n message: 'Output path:',\n })\n return path.resolve(inputResult)\n }\n\n private async prepareBackupOptions(\n projectId: string,\n datasetName: string,\n ): Promise<DownloadBackupOptions> {\n const err = validateDatasetName(datasetName)\n if (err) {\n this.error(err, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n const backupId = String(\n this.flags['backup-id'] || (await this.promptForBackupId(projectId, datasetName)),\n )\n\n if (\n 'concurrency' in this.flags &&\n (this.flags.concurrency < 1 || this.flags.concurrency > MAX_DOWNLOAD_CONCURRENCY)\n ) {\n this.error(`\\`--concurrency\\` must be between 1 and ${MAX_DOWNLOAD_CONCURRENCY}.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const defaultOutFileName = `${datasetName}-backup-${backupId}.tar.gz`\n let out = await this.getOutputPath(defaultOutFileName)\n\n // If path is a directory name, then add a default file name to the path.\n if (isPathDirName(out)) {\n out = path.join(out, defaultOutFileName)\n }\n\n const exists = await access(out).then(\n () => true,\n () => false,\n )\n // If the file already exists, ask for confirmation if it should be overwritten.\n if (!this.flags.overwrite && exists) {\n if (this.isUnattended()) {\n this.error(`File \"${out}\" already exists. Pass \\`--overwrite\\` to replace it.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n const shouldOverwrite = await confirm({\n default: false,\n message: `File \"${out}\" already exists, would you like to overwrite it?`,\n })\n\n // If the user does not want to overwrite the file, cancel the operation.\n if (!shouldOverwrite) {\n this.error('Operation cancelled.', {exit: exitCodes.USER_ABORT})\n }\n }\n\n return {\n backupId,\n concurrency: this.flags.concurrency || DEFAULT_DOWNLOAD_CONCURRENCY,\n datasetName,\n outDir: path.dirname(out),\n outFileName: path.basename(out),\n overwrite: this.flags.overwrite,\n projectId,\n }\n }\n\n private async promptForBackupId(projectId: string, datasetName: string): Promise<string> {\n const maxBackupIdsShown = 100\n\n try {\n const response = await listBackups({\n datasetName,\n limit: maxBackupIdsShown,\n projectId,\n })\n\n if (!response?.backups?.length) {\n this.error('No backups found', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n const backupIdChoices = response.backups.map((backup: BackupItem) => ({\n name: backup.id,\n value: backup.id,\n }))\n\n const hint =\n backupIdChoices.length === maxBackupIdsShown\n ? ` (only last ${maxBackupIdsShown} shown)`\n : ''\n\n return select({\n choices: backupIdChoices,\n message: `Select backup ID to use${hint}`,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Failed to fetch backups for dataset ${datasetName}: ${message}`, err)\n this.error(`Failed to fetch backups for dataset ${datasetName}: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["createWriteStream","access","mkdir","mkdtemp","tmpdir","path","finished","styleText","Args","Flags","exitCodes","SanityCommand","requiredWhenUnattended","boxen","confirm","input","select","pMap","prettyMs","archiveDir","assertDatasetExists","backupDownloadDebug","cleanupTmpDir","downloadAsset","downloadDocument","PaginatedGetBackupStream","newProgress","validateDatasetName","promptForDataset","promptForProject","listBackups","listDatasets","humanFileSize","isPathDirName","getProjectIdFlag","defineCommandTelemetry","DEFAULT_DOWNLOAD_CONCURRENCY","MAX_DOWNLOAD_CONCURRENCY","DownloadBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","concurrency","integer","default","out","overwrite","boolean","hiddenAliases","telemetry","redact","run","parse","isUnattended","error","exit","USAGE_ERROR","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","message","Error","String","RUNTIME_ERROR","length","output","allowCreation","opts","prepareBackupOptions","outFilePath","join","outDir","outFileName","log","datasetName","backupId","borderColor","borderStyle","padding","start","Date","now","progressSpinner","tmpOutDir","dir","recursive","tmpOutDocumentsFile","docOutStream","backupFileStream","files","i","file","push","set","current","step","total","totalFiles","update","totalItemsDownloaded","type","url","name","doc","write","fail","end","processedBytes","err","succeed","getOutputPath","defaultOutFileName","undefined","resolve","workDir","process","cwd","defaultPath","inputResult","promptForBackupId","exists","then","shouldOverwrite","USER_ABORT","dirname","basename","maxBackupIdsShown","response","limit","backups","backupIdChoices","map","backup","id","value","hint","choices"],"mappings":"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"}
@@ -2,9 +2,10 @@ import { Flags } from '@oclif/core';
2
2
  import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
3
  import { getErrorMessage } from '@sanity/cli-core/errors';
4
4
  import { requiredWhenUnattended } from '@sanity/cli-core/flags';
5
- import { input, spinner } from '@sanity/cli-core/ux';
6
- import { MissingOrganizationError, resolveOrganizationId } from '../../actions/context/resolveOrganizationId.js';
5
+ import { spinner } from '@sanity/cli-core/ux';
6
+ import { resolveOrganizationId } from '../../actions/context/resolveOrganizationId.js';
7
7
  import { formatKeyValue } from '../../actions/debug/output.js';
8
+ import { promptForText } from '../../prompts/promptForText.js';
8
9
  import { createKnowledgeBase } from '../../services/context.js';
9
10
  import { getOrganizationFlag } from '../../util/sharedFlags.js';
10
11
  import { defineCommandTelemetry } from '../../util/telemetry/commandTelemetry.js';
@@ -52,19 +53,11 @@ export class CreateKnowledgeBaseCommand extends SanityCommand {
52
53
  exit: exitCodes.USAGE_ERROR
53
54
  });
54
55
  }
55
- let organizationId;
56
- try {
57
- organizationId = await resolveOrganizationId({
58
- configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,
59
- flagOrganizationId: organization,
60
- unattended: this.isUnattended()
61
- });
62
- } catch (error) {
63
- createContextDebug('Error resolving organization', error);
64
- this.error(getErrorMessage(error), {
65
- exit: error instanceof MissingOrganizationError ? exitCodes.USAGE_ERROR : exitCodes.RUNTIME_ERROR
66
- });
67
- }
56
+ const organizationId = await resolveOrganizationId({
57
+ configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,
58
+ flagOrganizationId: organization,
59
+ unattended: this.isUnattended()
60
+ });
68
61
  const title = titleFlag?.trim() || await promptForText('Knowledge base title:');
69
62
  const description = descriptionFlag?.trim() || await promptForText('Knowledge base description:');
70
63
  const spin = spinner('Creating knowledge base').start();
@@ -95,12 +88,5 @@ export class CreateKnowledgeBaseCommand extends SanityCommand {
95
88
  }
96
89
  }
97
90
  }
98
- async function promptForText(message) {
99
- const value = await input({
100
- message,
101
- validate: (input_)=>input_.trim().length > 0 || 'Value cannot be empty'
102
- });
103
- return value.trim();
104
- }
105
91
 
106
92
  //# sourceMappingURL=create.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/context/create.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {requiredWhenUnattended} from '@sanity/cli-core/flags'\nimport {input, spinner} from '@sanity/cli-core/ux'\n\nimport {\n MissingOrganizationError,\n resolveOrganizationId,\n} from '../../actions/context/resolveOrganizationId.js'\nimport {formatKeyValue} from '../../actions/debug/output.js'\nimport {createKnowledgeBase} from '../../services/context.js'\nimport {getOrganizationFlag} from '../../util/sharedFlags.js'\nimport {defineCommandTelemetry} from '../../util/telemetry/commandTelemetry.js'\n\nconst createContextDebug = subdebug('context:create')\n\nconst flags = {\n ...getOrganizationFlag({\n description: 'Organization to create the knowledge base in',\n semantics: 'override',\n }),\n description: requiredWhenUnattended(\n Flags.string({\n description: 'Knowledge base description',\n }),\n ),\n title: requiredWhenUnattended(\n Flags.string({\n description: 'Knowledge base title',\n }),\n ),\n} satisfies FlagInput\n\nexport class CreateKnowledgeBaseCommand extends SanityCommand<typeof CreateKnowledgeBaseCommand> {\n static override description = 'Create a knowledge base'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively create a knowledge base',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> --organization org-abc123 --title \"Support docs\" --description \"Product docs and troubleshooting guides\"',\n description: 'Create a knowledge base in a specific organization',\n },\n ]\n\n static override flags = flags\n\n static telemetry = defineCommandTelemetry(flags, {redact: ['title', 'description']})\n\n public async run(): Promise<void> {\n const {description: descriptionFlag, organization, title: titleFlag} = this.flags\n\n if (titleFlag !== undefined && titleFlag.trim() === '') {\n this.error('Title cannot be empty', {exit: exitCodes.USAGE_ERROR})\n }\n if (descriptionFlag !== undefined && descriptionFlag.trim() === '') {\n this.error('Description cannot be empty', {exit: exitCodes.USAGE_ERROR})\n }\n\n let organizationId: string\n try {\n organizationId = await resolveOrganizationId({\n configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,\n flagOrganizationId: organization,\n unattended: this.isUnattended(),\n })\n } catch (error) {\n createContextDebug('Error resolving organization', error)\n this.error(getErrorMessage(error), {\n exit:\n error instanceof MissingOrganizationError\n ? exitCodes.USAGE_ERROR\n : exitCodes.RUNTIME_ERROR,\n })\n }\n\n const title = titleFlag?.trim() || (await promptForText('Knowledge base title:'))\n const description =\n descriptionFlag?.trim() || (await promptForText('Knowledge base description:'))\n\n const spin = spinner('Creating knowledge base').start()\n try {\n const knowledgeBase = await createKnowledgeBase({description, organizationId, title})\n spin.succeed('Knowledge base created')\n const padTo = 12 // \"Organization\" is the longest key\n this.log(formatKeyValue('ID', knowledgeBase.publicId, {padTo}))\n this.log(formatKeyValue('Title', knowledgeBase.title, {padTo}))\n this.log(formatKeyValue('Organization', knowledgeBase.organizationId, {padTo}))\n } catch (error) {\n spin.fail()\n createContextDebug('Error creating knowledge base', error)\n this.error(`Failed to create knowledge base: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n\nasync function promptForText(message: string): Promise<string> {\n const value = await input({\n message,\n validate: (input_) => input_.trim().length > 0 || 'Value cannot be empty',\n })\n return value.trim()\n}\n"],"names":["Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","requiredWhenUnattended","input","spinner","MissingOrganizationError","resolveOrganizationId","formatKeyValue","createKnowledgeBase","getOrganizationFlag","defineCommandTelemetry","createContextDebug","flags","description","semantics","string","title","CreateKnowledgeBaseCommand","examples","command","telemetry","redact","run","descriptionFlag","organization","titleFlag","undefined","trim","error","exit","USAGE_ERROR","organizationId","configuredOrganizationId","tryGetCliConfig","app","flagOrganizationId","unattended","isUnattended","RUNTIME_ERROR","promptForText","spin","start","knowledgeBase","succeed","padTo","log","publicId","fail","message","value","validate","input_","length"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/context/create.ts"],"sourcesContent":["import {Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {requiredWhenUnattended} from '@sanity/cli-core/flags'\nimport {spinner} from '@sanity/cli-core/ux'\n\nimport {resolveOrganizationId} from '../../actions/context/resolveOrganizationId.js'\nimport {formatKeyValue} from '../../actions/debug/output.js'\nimport {promptForText} from '../../prompts/promptForText.js'\nimport {createKnowledgeBase} from '../../services/context.js'\nimport {getOrganizationFlag} from '../../util/sharedFlags.js'\nimport {defineCommandTelemetry} from '../../util/telemetry/commandTelemetry.js'\n\nconst createContextDebug = subdebug('context:create')\n\nconst flags = {\n ...getOrganizationFlag({\n description: 'Organization to create the knowledge base in',\n semantics: 'override',\n }),\n description: requiredWhenUnattended(\n Flags.string({\n description: 'Knowledge base description',\n }),\n ),\n title: requiredWhenUnattended(\n Flags.string({\n description: 'Knowledge base title',\n }),\n ),\n} satisfies FlagInput\n\nexport class CreateKnowledgeBaseCommand extends SanityCommand<typeof CreateKnowledgeBaseCommand> {\n static override description = 'Create a knowledge base'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively create a knowledge base',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> --organization org-abc123 --title \"Support docs\" --description \"Product docs and troubleshooting guides\"',\n description: 'Create a knowledge base in a specific organization',\n },\n ]\n\n static override flags = flags\n\n static telemetry = defineCommandTelemetry(flags, {redact: ['title', 'description']})\n\n public async run(): Promise<void> {\n const {description: descriptionFlag, organization, title: titleFlag} = this.flags\n\n if (titleFlag !== undefined && titleFlag.trim() === '') {\n this.error('Title cannot be empty', {exit: exitCodes.USAGE_ERROR})\n }\n if (descriptionFlag !== undefined && descriptionFlag.trim() === '') {\n this.error('Description cannot be empty', {exit: exitCodes.USAGE_ERROR})\n }\n\n const organizationId = await resolveOrganizationId({\n configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,\n flagOrganizationId: organization,\n unattended: this.isUnattended(),\n })\n\n const title = titleFlag?.trim() || (await promptForText('Knowledge base title:'))\n const description =\n descriptionFlag?.trim() || (await promptForText('Knowledge base description:'))\n\n const spin = spinner('Creating knowledge base').start()\n try {\n const knowledgeBase = await createKnowledgeBase({description, organizationId, title})\n spin.succeed('Knowledge base created')\n const padTo = 12 // \"Organization\" is the longest key\n this.log(formatKeyValue('ID', knowledgeBase.publicId, {padTo}))\n this.log(formatKeyValue('Title', knowledgeBase.title, {padTo}))\n this.log(formatKeyValue('Organization', knowledgeBase.organizationId, {padTo}))\n } catch (error) {\n spin.fail()\n createContextDebug('Error creating knowledge base', error)\n this.error(`Failed to create knowledge base: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","requiredWhenUnattended","spinner","resolveOrganizationId","formatKeyValue","promptForText","createKnowledgeBase","getOrganizationFlag","defineCommandTelemetry","createContextDebug","flags","description","semantics","string","title","CreateKnowledgeBaseCommand","examples","command","telemetry","redact","run","descriptionFlag","organization","titleFlag","undefined","trim","error","exit","USAGE_ERROR","organizationId","configuredOrganizationId","tryGetCliConfig","app","flagOrganizationId","unattended","isUnattended","spin","start","knowledgeBase","succeed","padTo","log","publicId","fail","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,KAAK,QAAO,cAAa;AAEjC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,sBAAsB,QAAO,yBAAwB;AAC7D,SAAQC,OAAO,QAAO,sBAAqB;AAE3C,SAAQC,qBAAqB,QAAO,iDAAgD;AACpF,SAAQC,cAAc,QAAO,gCAA+B;AAC5D,SAAQC,aAAa,QAAO,iCAAgC;AAC5D,SAAQC,mBAAmB,QAAO,4BAA2B;AAC7D,SAAQC,mBAAmB,QAAO,4BAA2B;AAC7D,SAAQC,sBAAsB,QAAO,2CAA0C;AAE/E,MAAMC,qBAAqBV,SAAS;AAEpC,MAAMW,QAAQ;IACZ,GAAGH,oBAAoB;QACrBI,aAAa;QACbC,WAAW;IACb,EAAE;IACFD,aAAaV,uBACXL,MAAMiB,MAAM,CAAC;QACXF,aAAa;IACf;IAEFG,OAAOb,uBACLL,MAAMiB,MAAM,CAAC;QACXF,aAAa;IACf;AAEJ;AAEA,OAAO,MAAMI,mCAAmCjB;IAC9C,OAAgBa,cAAc,0BAAyB;IAEvD,OAAgBK,WAAW;QACzB;YACEC,SAAS;YACTN,aAAa;QACf;QACA;YACEM,SACE;YACFN,aAAa;QACf;KACD,CAAA;IAED,OAAgBD,QAAQA,MAAK;IAE7B,OAAOQ,YAAYV,uBAAuBE,OAAO;QAACS,QAAQ;YAAC;YAAS;SAAc;IAAA,GAAE;IAEpF,MAAaC,MAAqB;QAChC,MAAM,EAACT,aAAaU,eAAe,EAAEC,YAAY,EAAER,OAAOS,SAAS,EAAC,GAAG,IAAI,CAACb,KAAK;QAEjF,IAAIa,cAAcC,aAAaD,UAAUE,IAAI,OAAO,IAAI;YACtD,IAAI,CAACC,KAAK,CAAC,yBAAyB;gBAACC,MAAM9B,UAAU+B,WAAW;YAAA;QAClE;QACA,IAAIP,oBAAoBG,aAAaH,gBAAgBI,IAAI,OAAO,IAAI;YAClE,IAAI,CAACC,KAAK,CAAC,+BAA+B;gBAACC,MAAM9B,UAAU+B,WAAW;YAAA;QACxE;QAEA,MAAMC,iBAAiB,MAAM1B,sBAAsB;YACjD2B,0BAA0B,AAAC,CAAA,MAAM,IAAI,CAACC,eAAe,EAAC,EAAGC,GAAG,EAAEH;YAC9DI,oBAAoBX;YACpBY,YAAY,IAAI,CAACC,YAAY;QAC/B;QAEA,MAAMrB,QAAQS,WAAWE,UAAW,MAAMpB,cAAc;QACxD,MAAMM,cACJU,iBAAiBI,UAAW,MAAMpB,cAAc;QAElD,MAAM+B,OAAOlC,QAAQ,2BAA2BmC,KAAK;QACrD,IAAI;YACF,MAAMC,gBAAgB,MAAMhC,oBAAoB;gBAACK;gBAAakB;gBAAgBf;YAAK;YACnFsB,KAAKG,OAAO,CAAC;YACb,MAAMC,QAAQ,GAAG,oCAAoC;;YACrD,IAAI,CAACC,GAAG,CAACrC,eAAe,MAAMkC,cAAcI,QAAQ,EAAE;gBAACF;YAAK;YAC5D,IAAI,CAACC,GAAG,CAACrC,eAAe,SAASkC,cAAcxB,KAAK,EAAE;gBAAC0B;YAAK;YAC5D,IAAI,CAACC,GAAG,CAACrC,eAAe,gBAAgBkC,cAAcT,cAAc,EAAE;gBAACW;YAAK;QAC9E,EAAE,OAAOd,OAAO;YACdU,KAAKO,IAAI;YACTlC,mBAAmB,iCAAiCiB;YACpD,IAAI,CAACA,KAAK,CAAC,CAAC,iCAAiC,EAAE1B,gBAAgB0B,QAAQ,EAAE;gBACvEC,MAAM9B,UAAU+C,aAAa;YAC/B;QACF;IACF;AACF"}
@@ -3,7 +3,7 @@ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
3
  import { getErrorMessage } from '@sanity/cli-core/errors';
4
4
  import { confirm } from '@sanity/cli-core/ux';
5
5
  import { isHttpError } from '@sanity/client';
6
- import { deleteKnowledgeBase } from '../../services/context.js';
6
+ import { deleteKnowledgeBase, describeBlueprintManager, getKnowledgeBaseBlueprintOwnership } from '../../services/context.js';
7
7
  const deleteContextDebug = subdebug('context:delete');
8
8
  export class DeleteKnowledgeBaseCommand extends SanityCommand {
9
9
  static args = {
@@ -33,6 +33,13 @@ export class DeleteKnowledgeBaseCommand extends SanityCommand {
33
33
  async run() {
34
34
  const { knowledgeBaseId } = this.args;
35
35
  const { yes: skipConfirmation } = this.flags;
36
+ const ownership = await getKnowledgeBaseBlueprintOwnership(knowledgeBaseId);
37
+ if (ownership.managed) {
38
+ const manager = describeBlueprintManager(ownership.stackName);
39
+ this.error(`${manager} manages knowledge base "${knowledgeBaseId}". To delete it, deploy it with \`lifecycle: {deletionPolicy: 'allow'}\` in the blueprint, then remove it from the blueprint and deploy again.`, {
40
+ exit: exitCodes.USAGE_ERROR
41
+ });
42
+ }
36
43
  if (this.isUnattended() && !skipConfirmation) {
37
44
  this.error('Deletion requires confirmation. Pass `--yes` to delete the knowledge base.', {
38
45
  exit: exitCodes.USAGE_ERROR
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/context/delete.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {confirm} from '@sanity/cli-core/ux'\nimport {isHttpError} from '@sanity/client'\n\nimport {deleteKnowledgeBase} from '../../services/context.js'\n\nconst deleteContextDebug = subdebug('context:delete')\n\nexport class DeleteKnowledgeBaseCommand extends SanityCommand<typeof DeleteKnowledgeBaseCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'Delete a knowledge base and its generated content'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'Delete a knowledge base after confirmation',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --yes',\n description: 'Delete a knowledge base without confirmation prompt',\n },\n ]\n\n static override flags = {\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: 'Skip confirmation prompt (unattended mode)',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {yes: skipConfirmation} = this.flags\n\n if (this.isUnattended() && !skipConfirmation) {\n this.error('Deletion requires confirmation. Pass `--yes` to delete the knowledge base.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n if (!skipConfirmation) {\n const confirmed = await confirm({\n default: false,\n message: `Delete knowledge base \"${knowledgeBaseId}\"? This permanently deletes its generated content.`,\n })\n\n if (!confirmed) {\n this.log('Knowledge base not deleted')\n this.exit(exitCodes.USER_ABORT)\n }\n }\n\n try {\n await deleteKnowledgeBase(knowledgeBaseId)\n this.log('Knowledge base deleted')\n } catch (error) {\n deleteContextDebug('Error deleting knowledge base', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to delete knowledge base: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","confirm","isHttpError","deleteKnowledgeBase","deleteContextDebug","DeleteKnowledgeBaseCommand","args","knowledgeBaseId","string","description","required","examples","command","flags","yes","boolean","char","default","run","skipConfirmation","isUnattended","error","exit","USAGE_ERROR","confirmed","message","log","USER_ABORT","statusCode","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,mBAAmB,QAAO,4BAA2B;AAE7D,MAAMC,qBAAqBL,SAAS;AAEpC,OAAO,MAAMM,mCAAmCP;IAC9C,OAAgBQ,OAAO;QACrBC,iBAAiBZ,KAAKa,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,oDAAmD;IAEjF,OAAgBE,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtBC,KAAKlB,MAAMmB,OAAO,CAAC;YACjBC,MAAM;YACNC,SAAS;YACTR,aAAa;QACf;IACF,EAAqB;IAErB,MAAaS,MAAqB;QAChC,MAAM,EAACX,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QACnC,MAAM,EAACQ,KAAKK,gBAAgB,EAAC,GAAG,IAAI,CAACN,KAAK;QAE1C,IAAI,IAAI,CAACO,YAAY,MAAM,CAACD,kBAAkB;YAC5C,IAAI,CAACE,KAAK,CAAC,8EAA8E;gBACvFC,MAAMzB,UAAU0B,WAAW;YAC7B;QACF;QAEA,IAAI,CAACJ,kBAAkB;YACrB,MAAMK,YAAY,MAAMvB,QAAQ;gBAC9BgB,SAAS;gBACTQ,SAAS,CAAC,uBAAuB,EAAElB,gBAAgB,kDAAkD,CAAC;YACxG;YAEA,IAAI,CAACiB,WAAW;gBACd,IAAI,CAACE,GAAG,CAAC;gBACT,IAAI,CAACJ,IAAI,CAACzB,UAAU8B,UAAU;YAChC;QACF;QAEA,IAAI;YACF,MAAMxB,oBAAoBI;YAC1B,IAAI,CAACmB,GAAG,CAAC;QACX,EAAE,OAAOL,OAAO;YACdjB,mBAAmB,iCAAiCiB;YACpD,IAAInB,YAAYmB,UAAUA,MAAMO,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACP,KAAK,CAAC,CAAC,gBAAgB,EAAEd,gBAAgB,WAAW,CAAC,EAAE;oBAC1De,MAAMzB,UAAUgC,aAAa;gBAC/B;YACF;YACA,IAAI,CAACR,KAAK,CAAC,CAAC,iCAAiC,EAAErB,gBAAgBqB,QAAQ,EAAE;gBACvEC,MAAMzB,UAAUgC,aAAa;YAC/B;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/context/delete.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {confirm} from '@sanity/cli-core/ux'\nimport {isHttpError} from '@sanity/client'\n\nimport {\n deleteKnowledgeBase,\n describeBlueprintManager,\n getKnowledgeBaseBlueprintOwnership,\n} from '../../services/context.js'\n\nconst deleteContextDebug = subdebug('context:delete')\n\nexport class DeleteKnowledgeBaseCommand extends SanityCommand<typeof DeleteKnowledgeBaseCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'Delete a knowledge base and its generated content'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'Delete a knowledge base after confirmation',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --yes',\n description: 'Delete a knowledge base without confirmation prompt',\n },\n ]\n\n static override flags = {\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: 'Skip confirmation prompt (unattended mode)',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {yes: skipConfirmation} = this.flags\n\n const ownership = await getKnowledgeBaseBlueprintOwnership(knowledgeBaseId)\n if (ownership.managed) {\n const manager = describeBlueprintManager(ownership.stackName)\n this.error(\n `${manager} manages knowledge base \"${knowledgeBaseId}\". To delete it, deploy it with \\`lifecycle: {deletionPolicy: 'allow'}\\` in the blueprint, then remove it from the blueprint and deploy again.`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n if (this.isUnattended() && !skipConfirmation) {\n this.error('Deletion requires confirmation. Pass `--yes` to delete the knowledge base.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n if (!skipConfirmation) {\n const confirmed = await confirm({\n default: false,\n message: `Delete knowledge base \"${knowledgeBaseId}\"? This permanently deletes its generated content.`,\n })\n\n if (!confirmed) {\n this.log('Knowledge base not deleted')\n this.exit(exitCodes.USER_ABORT)\n }\n }\n\n try {\n await deleteKnowledgeBase(knowledgeBaseId)\n this.log('Knowledge base deleted')\n } catch (error) {\n deleteContextDebug('Error deleting knowledge base', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to delete knowledge base: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","confirm","isHttpError","deleteKnowledgeBase","describeBlueprintManager","getKnowledgeBaseBlueprintOwnership","deleteContextDebug","DeleteKnowledgeBaseCommand","args","knowledgeBaseId","string","description","required","examples","command","flags","yes","boolean","char","default","run","skipConfirmation","ownership","managed","manager","stackName","error","exit","USAGE_ERROR","isUnattended","confirmed","message","log","USER_ABORT","statusCode","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SACEC,mBAAmB,EACnBC,wBAAwB,EACxBC,kCAAkC,QAC7B,4BAA2B;AAElC,MAAMC,qBAAqBP,SAAS;AAEpC,OAAO,MAAMQ,mCAAmCT;IAC9C,OAAgBU,OAAO;QACrBC,iBAAiBd,KAAKe,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,oDAAmD;IAEjF,OAAgBE,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtBC,KAAKpB,MAAMqB,OAAO,CAAC;YACjBC,MAAM;YACNC,SAAS;YACTR,aAAa;QACf;IACF,EAAqB;IAErB,MAAaS,MAAqB;QAChC,MAAM,EAACX,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QACnC,MAAM,EAACQ,KAAKK,gBAAgB,EAAC,GAAG,IAAI,CAACN,KAAK;QAE1C,MAAMO,YAAY,MAAMjB,mCAAmCI;QAC3D,IAAIa,UAAUC,OAAO,EAAE;YACrB,MAAMC,UAAUpB,yBAAyBkB,UAAUG,SAAS;YAC5D,IAAI,CAACC,KAAK,CACR,GAAGF,QAAQ,yBAAyB,EAAEf,gBAAgB,8IAA8I,CAAC,EACrM;gBAACkB,MAAM9B,UAAU+B,WAAW;YAAA;QAEhC;QAEA,IAAI,IAAI,CAACC,YAAY,MAAM,CAACR,kBAAkB;YAC5C,IAAI,CAACK,KAAK,CAAC,8EAA8E;gBACvFC,MAAM9B,UAAU+B,WAAW;YAC7B;QACF;QAEA,IAAI,CAACP,kBAAkB;YACrB,MAAMS,YAAY,MAAM7B,QAAQ;gBAC9BkB,SAAS;gBACTY,SAAS,CAAC,uBAAuB,EAAEtB,gBAAgB,kDAAkD,CAAC;YACxG;YAEA,IAAI,CAACqB,WAAW;gBACd,IAAI,CAACE,GAAG,CAAC;gBACT,IAAI,CAACL,IAAI,CAAC9B,UAAUoC,UAAU;YAChC;QACF;QAEA,IAAI;YACF,MAAM9B,oBAAoBM;YAC1B,IAAI,CAACuB,GAAG,CAAC;QACX,EAAE,OAAON,OAAO;YACdpB,mBAAmB,iCAAiCoB;YACpD,IAAIxB,YAAYwB,UAAUA,MAAMQ,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACR,KAAK,CAAC,CAAC,gBAAgB,EAAEjB,gBAAgB,WAAW,CAAC,EAAE;oBAC1DkB,MAAM9B,UAAUsC,aAAa;gBAC/B;YACF;YACA,IAAI,CAACT,KAAK,CAAC,CAAC,iCAAiC,EAAE1B,gBAAgB0B,QAAQ,EAAE;gBACvEC,MAAM9B,UAAUsC,aAAa;YAC/B;QACF;IACF;AACF"}
@@ -40,12 +40,7 @@ export class ListIssuesCommand extends SanityCommand {
40
40
  description: 'Only list issues of this kind',
41
41
  // A Record forces every kind the client knows to be listed, so the options can't drift
42
42
  options: Object.keys({
43
- add_entry: true,
44
43
  conflict: true,
45
- gap: true,
46
- merge_entry: true,
47
- remove_entry: true,
48
- split_entry: true,
49
44
  update_required: true
50
45
  })
51
46
  })(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/commands/context/issues/list.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {type Context, isHttpError} from '@sanity/client'\n\nimport {listIssues} from '../../../services/context.js'\n\nconst listIssuesDebug = subdebug('context:issues:list')\n\nexport class ListIssuesCommand extends SanityCommand<typeof ListIssuesCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'List issues found by knowledge base builds'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'List all issues for a knowledge base',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --status open',\n description: 'List issues awaiting triage',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --kind conflict --severity critical',\n description: 'List critical conflicts',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --scope billing',\n description: 'List issues about entries under billing/',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --json',\n description: 'Output issues as JSON',\n },\n ]\n\n static override flags = {\n kind: Flags.custom<IssueKind>({\n description: 'Only list issues of this kind',\n // A Record forces every kind the client knows to be listed, so the options can't drift\n options: Object.keys({\n add_entry: true,\n conflict: true,\n gap: true,\n merge_entry: true,\n remove_entry: true,\n split_entry: true,\n update_required: true,\n } satisfies Record<IssueKind, true>),\n })(),\n scope: Flags.string({\n description:\n 'Only list issues about this entry path or anything under it (`*` for knowledge-base-wide issues)',\n helpValue: '<path>',\n parse: async (input: string) => {\n const trimmed = input.trim().replace(/\\/+$/, '')\n if (trimmed === '') {\n throw new Error('`--scope` cannot be empty if provided')\n }\n return trimmed\n },\n }),\n severity: Flags.custom<Context.IssueDoc['content']['severity']>({\n description: 'Only list issues of this severity',\n options: ['critical', 'suggestion'],\n })(),\n status: Flags.custom<Context.IssueDoc['status']>({\n description:\n 'Only list issues with this status (rejected = dismissed, accepted = resolved or applied)',\n options: ['open', 'accepted', 'rejected'],\n })(),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {json, kind, scope, severity, status} = this.flags\n\n let issues\n try {\n issues = await listIssues(knowledgeBaseId, status)\n } catch (error) {\n listIssuesDebug('Error listing issues', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to list issues: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // The client only filters on status; the rest are applied here\n const matches = issues.filter(\n ({content}) =>\n (kind === undefined || content.kind === kind) &&\n (severity === undefined || content.severity === severity) &&\n (scope === undefined ||\n content.scopePath === scope ||\n content.scopePath.startsWith(`${scope}/`)),\n )\n\n if (json) {\n this.logJson(matches)\n return\n }\n\n if (matches.length === 0) {\n this.log('No issues found')\n return\n }\n\n // Two lines per issue so long IDs never wrap: ID and metadata, then the summary cut to fit\n const width = Math.max(process.stdout.columns ?? 100, 40)\n const blocks = matches.map(({_id, content, status: issueStatus}) => {\n const meta = [content.kind, content.severity, issueStatus, content.scopePath].join(' · ')\n return `${_id} ${meta}\\n ${truncate(content.issue, width - 2)}`\n })\n this.log(blocks.join('\\n\\n'))\n }\n}\n\ntype IssueKind = Context.IssueDoc['content']['kind']\n\nfunction truncate(text: string, maxLength: number): string {\n // Count characters, not UTF-16 units, so an emoji at the cut point isn't split\n const chars = [...text.replaceAll(/\\s+/g, ' ').trim()]\n return chars.length <= maxLength ? chars.join('') : `${chars.slice(0, maxLength - 1).join('')}…`\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","listIssues","listIssuesDebug","ListIssuesCommand","args","knowledgeBaseId","string","description","required","enableJsonFlag","examples","command","flags","kind","custom","options","Object","keys","add_entry","conflict","gap","merge_entry","remove_entry","split_entry","update_required","scope","helpValue","parse","input","trimmed","trim","replace","Error","severity","status","run","json","issues","error","statusCode","exit","RUNTIME_ERROR","matches","filter","content","undefined","scopePath","startsWith","logJson","length","log","width","Math","max","process","stdout","columns","blocks","map","_id","issueStatus","meta","join","truncate","issue","text","maxLength","chars","replaceAll","slice"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/commands/context/issues/list.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {type Context, isHttpError} from '@sanity/client'\n\nimport {listIssues} from '../../../services/context.js'\n\nconst listIssuesDebug = subdebug('context:issues:list')\n\nexport class ListIssuesCommand extends SanityCommand<typeof ListIssuesCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'List issues found by knowledge base builds'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'List all issues for a knowledge base',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --status open',\n description: 'List issues awaiting triage',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --kind conflict --severity critical',\n description: 'List critical conflicts',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --scope billing',\n description: 'List issues about entries under billing/',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --json',\n description: 'Output issues as JSON',\n },\n ]\n\n static override flags = {\n kind: Flags.custom<IssueKind>({\n description: 'Only list issues of this kind',\n // A Record forces every kind the client knows to be listed, so the options can't drift\n options: Object.keys({\n conflict: true,\n update_required: true,\n } satisfies Record<IssueKind, true>),\n })(),\n scope: Flags.string({\n description:\n 'Only list issues about this entry path or anything under it (`*` for knowledge-base-wide issues)',\n helpValue: '<path>',\n parse: async (input: string) => {\n const trimmed = input.trim().replace(/\\/+$/, '')\n if (trimmed === '') {\n throw new Error('`--scope` cannot be empty if provided')\n }\n return trimmed\n },\n }),\n severity: Flags.custom<Context.IssueDoc['content']['severity']>({\n description: 'Only list issues of this severity',\n options: ['critical', 'suggestion'],\n })(),\n status: Flags.custom<Context.IssueDoc['status']>({\n description:\n 'Only list issues with this status (rejected = dismissed, accepted = resolved or applied)',\n options: ['open', 'accepted', 'rejected'],\n })(),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {json, kind, scope, severity, status} = this.flags\n\n let issues\n try {\n issues = await listIssues(knowledgeBaseId, status)\n } catch (error) {\n listIssuesDebug('Error listing issues', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to list issues: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // The client only filters on status; the rest are applied here\n const matches = issues.filter(\n ({content}) =>\n (kind === undefined || content.kind === kind) &&\n (severity === undefined || content.severity === severity) &&\n (scope === undefined ||\n content.scopePath === scope ||\n content.scopePath.startsWith(`${scope}/`)),\n )\n\n if (json) {\n this.logJson(matches)\n return\n }\n\n if (matches.length === 0) {\n this.log('No issues found')\n return\n }\n\n // Two lines per issue so long IDs never wrap: ID and metadata, then the summary cut to fit\n const width = Math.max(process.stdout.columns ?? 100, 40)\n const blocks = matches.map(({_id, content, status: issueStatus}) => {\n const meta = [content.kind, content.severity, issueStatus, content.scopePath].join(' · ')\n return `${_id} ${meta}\\n ${truncate(content.issue, width - 2)}`\n })\n this.log(blocks.join('\\n\\n'))\n }\n}\n\ntype IssueKind = Context.IssueDoc['content']['kind']\n\nfunction truncate(text: string, maxLength: number): string {\n // Count characters, not UTF-16 units, so an emoji at the cut point isn't split\n const chars = [...text.replaceAll(/\\s+/g, ' ').trim()]\n return chars.length <= maxLength ? chars.join('') : `${chars.slice(0, maxLength - 1).join('')}…`\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","listIssues","listIssuesDebug","ListIssuesCommand","args","knowledgeBaseId","string","description","required","enableJsonFlag","examples","command","flags","kind","custom","options","Object","keys","conflict","update_required","scope","helpValue","parse","input","trimmed","trim","replace","Error","severity","status","run","json","issues","error","statusCode","exit","RUNTIME_ERROR","matches","filter","content","undefined","scopePath","startsWith","logJson","length","log","width","Math","max","process","stdout","columns","blocks","map","_id","issueStatus","meta","join","truncate","issue","text","maxLength","chars","replaceAll","slice"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
2
2
  import { getErrorMessage } from '@sanity/cli-core/errors';
3
- import { MissingOrganizationError, resolveOrganizationId } from '../../actions/context/resolveOrganizationId.js';
3
+ import { resolveOrganizationId } from '../../actions/context/resolveOrganizationId.js';
4
4
  import { listKnowledgeBases } from '../../services/context.js';
5
5
  import { Table } from '../../util/responsiveTable.js';
6
6
  import { getOrganizationFlag } from '../../util/sharedFlags.js';
@@ -30,19 +30,11 @@ export class ListKnowledgeBasesCommand extends SanityCommand {
30
30
  };
31
31
  async run() {
32
32
  const { json, organization } = this.flags;
33
- let organizationId;
34
- try {
35
- organizationId = await resolveOrganizationId({
36
- configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,
37
- flagOrganizationId: organization,
38
- unattended: this.isUnattended()
39
- });
40
- } catch (error) {
41
- listContextDebug('Error resolving organization', error);
42
- this.error(getErrorMessage(error), {
43
- exit: error instanceof MissingOrganizationError ? exitCodes.USAGE_ERROR : exitCodes.RUNTIME_ERROR
44
- });
45
- }
33
+ const organizationId = await resolveOrganizationId({
34
+ configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,
35
+ flagOrganizationId: organization,
36
+ unattended: this.isUnattended()
37
+ });
46
38
  let knowledgeBases;
47
39
  try {
48
40
  knowledgeBases = await listKnowledgeBases(organizationId);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/context/list.ts"],"sourcesContent":["import {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\n\nimport {\n MissingOrganizationError,\n resolveOrganizationId,\n} from '../../actions/context/resolveOrganizationId.js'\nimport {listKnowledgeBases} from '../../services/context.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getOrganizationFlag} from '../../util/sharedFlags.js'\n\nconst listContextDebug = subdebug('context:list')\n\nexport class ListKnowledgeBasesCommand extends SanityCommand<typeof ListKnowledgeBasesCommand> {\n static override description = 'List knowledge bases in an organization'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List knowledge bases, selecting the organization interactively',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --organization org-abc123',\n description: 'List knowledge bases in a specific organization',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --organization org-abc123 --json',\n description: 'Output knowledge bases as JSON',\n },\n ]\n\n static override flags = {\n ...getOrganizationFlag({\n description: 'Organization to list knowledge bases for',\n semantics: 'override',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {json, organization} = this.flags\n\n let organizationId: string\n try {\n organizationId = await resolveOrganizationId({\n configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,\n flagOrganizationId: organization,\n unattended: this.isUnattended(),\n })\n } catch (error) {\n listContextDebug('Error resolving organization', error)\n this.error(getErrorMessage(error), {\n exit:\n error instanceof MissingOrganizationError\n ? exitCodes.USAGE_ERROR\n : exitCodes.RUNTIME_ERROR,\n })\n }\n\n let knowledgeBases\n try {\n knowledgeBases = await listKnowledgeBases(organizationId)\n } catch (error) {\n listContextDebug('Error listing knowledge bases', error)\n this.error(`Failed to list knowledge bases: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (json) {\n this.logJson(knowledgeBases)\n return\n }\n\n if (knowledgeBases.length === 0) {\n this.log('No knowledge bases found')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'title', title: 'Title'},\n {alignment: 'left', name: 'state', title: 'State'},\n {alignment: 'right', name: 'openIssues', title: 'Open issues'},\n {alignment: 'left', name: 'updatedAt', title: 'Updated'},\n ],\n })\n\n for (const {openIssueCount, publicId, state, title, updatedAt} of knowledgeBases) {\n table.addRow({id: publicId, openIssues: openIssueCount, state, title, updatedAt})\n }\n\n this.log(table.render())\n }\n}\n"],"names":["exitCodes","SanityCommand","subdebug","getErrorMessage","MissingOrganizationError","resolveOrganizationId","listKnowledgeBases","Table","getOrganizationFlag","listContextDebug","ListKnowledgeBasesCommand","description","enableJsonFlag","examples","command","flags","semantics","run","json","organization","organizationId","configuredOrganizationId","tryGetCliConfig","app","flagOrganizationId","unattended","isUnattended","error","exit","USAGE_ERROR","RUNTIME_ERROR","knowledgeBases","logJson","length","log","table","columns","alignment","name","title","openIssueCount","publicId","state","updatedAt","addRow","id","openIssues","render"],"mappings":"AACA,SAAQA,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AAEvD,SACEC,wBAAwB,EACxBC,qBAAqB,QAChB,iDAAgD;AACvD,SAAQC,kBAAkB,QAAO,4BAA2B;AAC5D,SAAQC,KAAK,QAAO,gCAA+B;AACnD,SAAQC,mBAAmB,QAAO,4BAA2B;AAE7D,MAAMC,mBAAmBP,SAAS;AAElC,OAAO,MAAMQ,kCAAkCT;IAC7C,OAAgBU,cAAc,0CAAyC;IAEvE,OAAgBC,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtB,GAAGP,oBAAoB;YACrBG,aAAa;YACbK,WAAW;QACb,EAAE;IACJ,EAAqB;IAErB,MAAaC,MAAqB;QAChC,MAAM,EAACC,IAAI,EAAEC,YAAY,EAAC,GAAG,IAAI,CAACJ,KAAK;QAEvC,IAAIK;QACJ,IAAI;YACFA,iBAAiB,MAAMf,sBAAsB;gBAC3CgB,0BAA0B,AAAC,CAAA,MAAM,IAAI,CAACC,eAAe,EAAC,EAAGC,GAAG,EAAEH;gBAC9DI,oBAAoBL;gBACpBM,YAAY,IAAI,CAACC,YAAY;YAC/B;QACF,EAAE,OAAOC,OAAO;YACdlB,iBAAiB,gCAAgCkB;YACjD,IAAI,CAACA,KAAK,CAACxB,gBAAgBwB,QAAQ;gBACjCC,MACED,iBAAiBvB,2BACbJ,UAAU6B,WAAW,GACrB7B,UAAU8B,aAAa;YAC/B;QACF;QAEA,IAAIC;QACJ,IAAI;YACFA,iBAAiB,MAAMzB,mBAAmBc;QAC5C,EAAE,OAAOO,OAAO;YACdlB,iBAAiB,iCAAiCkB;YAClD,IAAI,CAACA,KAAK,CAAC,CAAC,gCAAgC,EAAExB,gBAAgBwB,QAAQ,EAAE;gBACtEC,MAAM5B,UAAU8B,aAAa;YAC/B;QACF;QAEA,IAAIZ,MAAM;YACR,IAAI,CAACc,OAAO,CAACD;YACb;QACF;QAEA,IAAIA,eAAeE,MAAM,KAAK,GAAG;YAC/B,IAAI,CAACC,GAAG,CAAC;YACT;QACF;QAEA,MAAMC,QAAQ,IAAI5B,MAAM;YACtB6B,SAAS;gBACP;oBAACC,WAAW;oBAAQC,MAAM;oBAAMC,OAAO;gBAAI;gBAC3C;oBAACF,WAAW;oBAAQC,MAAM;oBAASC,OAAO;gBAAO;gBACjD;oBAACF,WAAW;oBAAQC,MAAM;oBAASC,OAAO;gBAAO;gBACjD;oBAACF,WAAW;oBAASC,MAAM;oBAAcC,OAAO;gBAAa;gBAC7D;oBAACF,WAAW;oBAAQC,MAAM;oBAAaC,OAAO;gBAAS;aACxD;QACH;QAEA,KAAK,MAAM,EAACC,cAAc,EAAEC,QAAQ,EAAEC,KAAK,EAAEH,KAAK,EAAEI,SAAS,EAAC,IAAIZ,eAAgB;YAChFI,MAAMS,MAAM,CAAC;gBAACC,IAAIJ;gBAAUK,YAAYN;gBAAgBE;gBAAOH;gBAAOI;YAAS;QACjF;QAEA,IAAI,CAACT,GAAG,CAACC,MAAMY,MAAM;IACvB;AACF"}
1
+ {"version":3,"sources":["../../../src/commands/context/list.ts"],"sourcesContent":["import {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\n\nimport {resolveOrganizationId} from '../../actions/context/resolveOrganizationId.js'\nimport {listKnowledgeBases} from '../../services/context.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getOrganizationFlag} from '../../util/sharedFlags.js'\n\nconst listContextDebug = subdebug('context:list')\n\nexport class ListKnowledgeBasesCommand extends SanityCommand<typeof ListKnowledgeBasesCommand> {\n static override description = 'List knowledge bases in an organization'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List knowledge bases, selecting the organization interactively',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --organization org-abc123',\n description: 'List knowledge bases in a specific organization',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --organization org-abc123 --json',\n description: 'Output knowledge bases as JSON',\n },\n ]\n\n static override flags = {\n ...getOrganizationFlag({\n description: 'Organization to list knowledge bases for',\n semantics: 'override',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {json, organization} = this.flags\n\n const organizationId = await resolveOrganizationId({\n configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,\n flagOrganizationId: organization,\n unattended: this.isUnattended(),\n })\n\n let knowledgeBases\n try {\n knowledgeBases = await listKnowledgeBases(organizationId)\n } catch (error) {\n listContextDebug('Error listing knowledge bases', error)\n this.error(`Failed to list knowledge bases: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (json) {\n this.logJson(knowledgeBases)\n return\n }\n\n if (knowledgeBases.length === 0) {\n this.log('No knowledge bases found')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'title', title: 'Title'},\n {alignment: 'left', name: 'state', title: 'State'},\n {alignment: 'right', name: 'openIssues', title: 'Open issues'},\n {alignment: 'left', name: 'updatedAt', title: 'Updated'},\n ],\n })\n\n for (const {openIssueCount, publicId, state, title, updatedAt} of knowledgeBases) {\n table.addRow({id: publicId, openIssues: openIssueCount, state, title, updatedAt})\n }\n\n this.log(table.render())\n }\n}\n"],"names":["exitCodes","SanityCommand","subdebug","getErrorMessage","resolveOrganizationId","listKnowledgeBases","Table","getOrganizationFlag","listContextDebug","ListKnowledgeBasesCommand","description","enableJsonFlag","examples","command","flags","semantics","run","json","organization","organizationId","configuredOrganizationId","tryGetCliConfig","app","flagOrganizationId","unattended","isUnattended","knowledgeBases","error","exit","RUNTIME_ERROR","logJson","length","log","table","columns","alignment","name","title","openIssueCount","publicId","state","updatedAt","addRow","id","openIssues","render"],"mappings":"AACA,SAAQA,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AAEvD,SAAQC,qBAAqB,QAAO,iDAAgD;AACpF,SAAQC,kBAAkB,QAAO,4BAA2B;AAC5D,SAAQC,KAAK,QAAO,gCAA+B;AACnD,SAAQC,mBAAmB,QAAO,4BAA2B;AAE7D,MAAMC,mBAAmBN,SAAS;AAElC,OAAO,MAAMO,kCAAkCR;IAC7C,OAAgBS,cAAc,0CAAyC;IAEvE,OAAgBC,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtB,GAAGP,oBAAoB;YACrBG,aAAa;YACbK,WAAW;QACb,EAAE;IACJ,EAAqB;IAErB,MAAaC,MAAqB;QAChC,MAAM,EAACC,IAAI,EAAEC,YAAY,EAAC,GAAG,IAAI,CAACJ,KAAK;QAEvC,MAAMK,iBAAiB,MAAMf,sBAAsB;YACjDgB,0BAA0B,AAAC,CAAA,MAAM,IAAI,CAACC,eAAe,EAAC,EAAGC,GAAG,EAAEH;YAC9DI,oBAAoBL;YACpBM,YAAY,IAAI,CAACC,YAAY;QAC/B;QAEA,IAAIC;QACJ,IAAI;YACFA,iBAAiB,MAAMrB,mBAAmBc;QAC5C,EAAE,OAAOQ,OAAO;YACdnB,iBAAiB,iCAAiCmB;YAClD,IAAI,CAACA,KAAK,CAAC,CAAC,gCAAgC,EAAExB,gBAAgBwB,QAAQ,EAAE;gBACtEC,MAAM5B,UAAU6B,aAAa;YAC/B;QACF;QAEA,IAAIZ,MAAM;YACR,IAAI,CAACa,OAAO,CAACJ;YACb;QACF;QAEA,IAAIA,eAAeK,MAAM,KAAK,GAAG;YAC/B,IAAI,CAACC,GAAG,CAAC;YACT;QACF;QAEA,MAAMC,QAAQ,IAAI3B,MAAM;YACtB4B,SAAS;gBACP;oBAACC,WAAW;oBAAQC,MAAM;oBAAMC,OAAO;gBAAI;gBAC3C;oBAACF,WAAW;oBAAQC,MAAM;oBAASC,OAAO;gBAAO;gBACjD;oBAACF,WAAW;oBAAQC,MAAM;oBAASC,OAAO;gBAAO;gBACjD;oBAACF,WAAW;oBAASC,MAAM;oBAAcC,OAAO;gBAAa;gBAC7D;oBAACF,WAAW;oBAAQC,MAAM;oBAAaC,OAAO;gBAAS;aACxD;QACH;QAEA,KAAK,MAAM,EAACC,cAAc,EAAEC,QAAQ,EAAEC,KAAK,EAAEH,KAAK,EAAEI,SAAS,EAAC,IAAIf,eAAgB;YAChFO,MAAMS,MAAM,CAAC;gBAACC,IAAIJ;gBAAUK,YAAYN;gBAAgBE;gBAAOH;gBAAOI;YAAS;QACjF;QAEA,IAAI,CAACT,GAAG,CAACC,MAAMY,MAAM;IACvB;AACF"}
@@ -0,0 +1,152 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
+ import { getErrorMessage } from '@sanity/cli-core/errors';
4
+ import { requiredWhenUnattended } from '@sanity/cli-core/flags';
5
+ import { spinner } from '@sanity/cli-core/ux';
6
+ import { datasetSourceId, editSources, formatMcpEndpoint, parseEndpointName, parseNonEmpty } from '../../../actions/context/mcpEndpoint.js';
7
+ import { resolveOrganizationId } from '../../../actions/context/resolveOrganizationId.js';
8
+ import { promptForText } from '../../../prompts/promptForText.js';
9
+ import { createMcpEndpoint } from '../../../services/context.js';
10
+ import { getDatasetFlag, getOrganizationFlag, getProjectIdFlag } from '../../../util/sharedFlags.js';
11
+ import { defineCommandTelemetry } from '../../../util/telemetry/commandTelemetry.js';
12
+ const createMcpDebug = subdebug('context:mcp:create');
13
+ const SOURCE_FLAGS = [
14
+ 'knowledge-base',
15
+ 'dataset'
16
+ ];
17
+ const flags = {
18
+ ...getOrganizationFlag({
19
+ description: 'Organization to create the MCP endpoint in',
20
+ semantics: 'override'
21
+ }),
22
+ ...getDatasetFlag({
23
+ atLeastOne: SOURCE_FLAGS,
24
+ description: 'Dataset the endpoint serves',
25
+ semantics: 'specify'
26
+ }),
27
+ ...getProjectIdFlag({
28
+ dependsOn: [
29
+ 'dataset'
30
+ ],
31
+ description: 'Project the dataset belongs to',
32
+ semantics: 'override'
33
+ }),
34
+ 'groq-filter': Flags.string({
35
+ dependsOn: [
36
+ 'dataset'
37
+ ],
38
+ description: 'GROQ filter that limits which dataset documents the endpoint serves',
39
+ parse: parseNonEmpty('groq-filter')
40
+ }),
41
+ instructions: Flags.string({
42
+ description: 'Instructions the endpoint serves to connecting agents',
43
+ parse: parseNonEmpty('instructions')
44
+ }),
45
+ 'knowledge-base': Flags.string({
46
+ atLeastOne: SOURCE_FLAGS,
47
+ description: 'Knowledge base the endpoint serves; repeat the flag to serve several',
48
+ helpValue: '<id>',
49
+ multiple: true,
50
+ parse: parseNonEmpty('knowledge-base')
51
+ }),
52
+ perspective: Flags.custom({
53
+ dependsOn: [
54
+ 'dataset'
55
+ ],
56
+ description: 'Perspective agents query the dataset with',
57
+ options: [
58
+ 'published',
59
+ 'drafts',
60
+ 'raw'
61
+ ]
62
+ })(),
63
+ 'semantic-search': Flags.boolean({
64
+ allowNo: true,
65
+ dependsOn: [
66
+ 'dataset'
67
+ ],
68
+ description: 'Let agents use semantic search on the dataset (--no-semantic-search to turn it off)'
69
+ }),
70
+ title: requiredWhenUnattended(Flags.string({
71
+ description: 'MCP endpoint title',
72
+ parse: parseNonEmpty('title')
73
+ })),
74
+ workspace: Flags.string({
75
+ dependsOn: [
76
+ 'dataset'
77
+ ],
78
+ description: 'Studio workspace whose schema agents use, instead of the first workspace',
79
+ parse: parseNonEmpty('workspace')
80
+ })
81
+ };
82
+ export class CreateMcpEndpointCommand extends SanityCommand {
83
+ static args = {
84
+ name: Args.string({
85
+ description: 'Permanent MCP endpoint name used in its URL, made of lowercase letters, digits and hyphens',
86
+ parse: parseEndpointName,
87
+ required: true
88
+ })
89
+ };
90
+ static description = 'Create a Context MCP endpoint that serves knowledge bases and a dataset to agents';
91
+ static examples = [
92
+ {
93
+ command: '<%= config.bin %> <%= command.id %> support --title "Support" --knowledge-base kb-abc123 --knowledge-base kb-def456',
94
+ description: 'Create an MCP endpoint that serves two knowledge bases'
95
+ },
96
+ {
97
+ command: '<%= config.bin %> <%= command.id %> catalog --title "Catalog" --project abc123 --dataset production --perspective drafts --groq-filter \'_type in ["product"]\'',
98
+ description: 'Create an MCP endpoint that serves the products in a dataset'
99
+ }
100
+ ];
101
+ static flags = flags;
102
+ static telemetry = defineCommandTelemetry(flags, {
103
+ redact: [
104
+ 'title',
105
+ 'instructions',
106
+ 'groq-filter'
107
+ ]
108
+ });
109
+ async run() {
110
+ const { name } = this.args;
111
+ const { dataset, 'groq-filter': groqFilter, instructions, 'knowledge-base': knowledgeBaseIds = [], organization, perspective, project, 'semantic-search': semanticSearch, title: titleFlag, workspace } = this.flags;
112
+ const cliConfig = await this.tryGetCliConfig();
113
+ const datasetId = datasetSourceId(dataset, project ?? cliConfig.api?.projectId);
114
+ const organizationId = await resolveOrganizationId({
115
+ configuredOrganizationId: cliConfig.app?.organizationId,
116
+ flagOrganizationId: organization,
117
+ unattended: this.isUnattended()
118
+ });
119
+ const title = titleFlag || await promptForText('MCP endpoint title:');
120
+ const spin = spinner('Creating MCP endpoint').start();
121
+ try {
122
+ const endpoint = await createMcpEndpoint(organizationId, {
123
+ groqFilter,
124
+ instructions,
125
+ name,
126
+ sources: editSources([], {
127
+ addKnowledgeBases: knowledgeBaseIds,
128
+ dataset: datasetId,
129
+ removeKnowledgeBases: [],
130
+ settings: {
131
+ perspective,
132
+ semanticSearch,
133
+ workspace
134
+ }
135
+ }).sources,
136
+ title
137
+ });
138
+ spin.succeed('MCP endpoint created');
139
+ for (const line of formatMcpEndpoint(endpoint)){
140
+ this.log(line);
141
+ }
142
+ } catch (error) {
143
+ spin.fail();
144
+ createMcpDebug('Error creating MCP endpoint', error);
145
+ this.error(`Failed to create MCP endpoint: ${getErrorMessage(error)}`, {
146
+ exit: exitCodes.RUNTIME_ERROR
147
+ });
148
+ }
149
+ }
150
+ }
151
+
152
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/commands/context/mcp/create.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {requiredWhenUnattended} from '@sanity/cli-core/flags'\nimport {spinner} from '@sanity/cli-core/ux'\n\nimport {\n datasetSourceId,\n editSources,\n formatMcpEndpoint,\n parseEndpointName,\n parseNonEmpty,\n} from '../../../actions/context/mcpEndpoint.js'\nimport {resolveOrganizationId} from '../../../actions/context/resolveOrganizationId.js'\nimport {promptForText} from '../../../prompts/promptForText.js'\nimport {createMcpEndpoint} from '../../../services/context.js'\nimport {getDatasetFlag, getOrganizationFlag, getProjectIdFlag} from '../../../util/sharedFlags.js'\nimport {defineCommandTelemetry} from '../../../util/telemetry/commandTelemetry.js'\n\nconst createMcpDebug = subdebug('context:mcp:create')\n\nconst SOURCE_FLAGS = ['knowledge-base', 'dataset']\n\nconst flags = {\n ...getOrganizationFlag({\n description: 'Organization to create the MCP endpoint in',\n semantics: 'override',\n }),\n ...getDatasetFlag({\n atLeastOne: SOURCE_FLAGS,\n description: 'Dataset the endpoint serves',\n semantics: 'specify',\n }),\n ...getProjectIdFlag({\n dependsOn: ['dataset'],\n description: 'Project the dataset belongs to',\n semantics: 'override',\n }),\n 'groq-filter': Flags.string({\n dependsOn: ['dataset'],\n description: 'GROQ filter that limits which dataset documents the endpoint serves',\n parse: parseNonEmpty('groq-filter'),\n }),\n instructions: Flags.string({\n description: 'Instructions the endpoint serves to connecting agents',\n parse: parseNonEmpty('instructions'),\n }),\n 'knowledge-base': Flags.string({\n atLeastOne: SOURCE_FLAGS,\n description: 'Knowledge base the endpoint serves; repeat the flag to serve several',\n helpValue: '<id>',\n multiple: true,\n parse: parseNonEmpty('knowledge-base'),\n }),\n perspective: Flags.custom<'drafts' | 'published' | 'raw'>({\n dependsOn: ['dataset'],\n description: 'Perspective agents query the dataset with',\n options: ['published', 'drafts', 'raw'],\n })(),\n 'semantic-search': Flags.boolean({\n allowNo: true,\n dependsOn: ['dataset'],\n description:\n 'Let agents use semantic search on the dataset (--no-semantic-search to turn it off)',\n }),\n title: requiredWhenUnattended(\n Flags.string({\n description: 'MCP endpoint title',\n parse: parseNonEmpty('title'),\n }),\n ),\n workspace: Flags.string({\n dependsOn: ['dataset'],\n description: 'Studio workspace whose schema agents use, instead of the first workspace',\n parse: parseNonEmpty('workspace'),\n }),\n} satisfies FlagInput\n\nexport class CreateMcpEndpointCommand extends SanityCommand<typeof CreateMcpEndpointCommand> {\n static override args = {\n name: Args.string({\n description:\n 'Permanent MCP endpoint name used in its URL, made of lowercase letters, digits and hyphens',\n parse: parseEndpointName,\n required: true,\n }),\n }\n\n static override description =\n 'Create a Context MCP endpoint that serves knowledge bases and a dataset to agents'\n\n static override examples = [\n {\n command:\n '<%= config.bin %> <%= command.id %> support --title \"Support\" --knowledge-base kb-abc123 --knowledge-base kb-def456',\n description: 'Create an MCP endpoint that serves two knowledge bases',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> catalog --title \"Catalog\" --project abc123 --dataset production --perspective drafts --groq-filter \\'_type in [\"product\"]\\'',\n description: 'Create an MCP endpoint that serves the products in a dataset',\n },\n ]\n\n static override flags = flags\n\n static telemetry = defineCommandTelemetry(flags, {\n redact: ['title', 'instructions', 'groq-filter'],\n })\n\n public async run(): Promise<void> {\n const {name} = this.args\n const {\n dataset,\n 'groq-filter': groqFilter,\n instructions,\n 'knowledge-base': knowledgeBaseIds = [],\n organization,\n perspective,\n project,\n 'semantic-search': semanticSearch,\n title: titleFlag,\n workspace,\n } = this.flags\n\n const cliConfig = await this.tryGetCliConfig()\n const datasetId = datasetSourceId(dataset, project ?? cliConfig.api?.projectId)\n\n const organizationId = await resolveOrganizationId({\n configuredOrganizationId: cliConfig.app?.organizationId,\n flagOrganizationId: organization,\n unattended: this.isUnattended(),\n })\n\n const title = titleFlag || (await promptForText('MCP endpoint title:'))\n\n const spin = spinner('Creating MCP endpoint').start()\n try {\n const endpoint = await createMcpEndpoint(organizationId, {\n groqFilter,\n instructions,\n name,\n sources: editSources([], {\n addKnowledgeBases: knowledgeBaseIds,\n dataset: datasetId,\n removeKnowledgeBases: [],\n settings: {perspective, semanticSearch, workspace},\n }).sources,\n title,\n })\n spin.succeed('MCP endpoint created')\n for (const line of formatMcpEndpoint(endpoint)) {\n this.log(line)\n }\n } catch (error) {\n spin.fail()\n createMcpDebug('Error creating MCP endpoint', error)\n this.error(`Failed to create MCP endpoint: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","requiredWhenUnattended","spinner","datasetSourceId","editSources","formatMcpEndpoint","parseEndpointName","parseNonEmpty","resolveOrganizationId","promptForText","createMcpEndpoint","getDatasetFlag","getOrganizationFlag","getProjectIdFlag","defineCommandTelemetry","createMcpDebug","SOURCE_FLAGS","flags","description","semantics","atLeastOne","dependsOn","string","parse","instructions","helpValue","multiple","perspective","custom","options","boolean","allowNo","title","workspace","CreateMcpEndpointCommand","args","name","required","examples","command","telemetry","redact","run","dataset","groqFilter","knowledgeBaseIds","organization","project","semanticSearch","titleFlag","cliConfig","tryGetCliConfig","datasetId","api","projectId","organizationId","configuredOrganizationId","app","flagOrganizationId","unattended","isUnattended","spin","start","endpoint","sources","addKnowledgeBases","removeKnowledgeBases","settings","succeed","line","log","error","fail","exit","RUNTIME_ERROR"],"mappings":"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"}