@sanity/cli 8.26.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.
- package/dist/actions/context/mcpEndpoint.js +165 -0
- package/dist/actions/context/mcpEndpoint.js.map +1 -0
- package/dist/actions/context/resolveOrganizationId.js +8 -1
- package/dist/actions/context/resolveOrganizationId.js.map +1 -1
- package/dist/commands/context/create.js +8 -22
- package/dist/commands/context/create.js.map +1 -1
- package/dist/commands/context/delete.js +2 -2
- package/dist/commands/context/delete.js.map +1 -1
- package/dist/commands/context/issues/list.js +0 -5
- package/dist/commands/context/issues/list.js.map +1 -1
- package/dist/commands/context/list.js +6 -14
- package/dist/commands/context/list.js.map +1 -1
- package/dist/commands/context/mcp/create.js +152 -0
- package/dist/commands/context/mcp/create.js.map +1 -0
- package/dist/commands/context/mcp/delete.js +82 -0
- package/dist/commands/context/mcp/delete.js.map +1 -0
- package/dist/commands/context/mcp/get.js +42 -0
- package/dist/commands/context/mcp/get.js.map +1 -0
- package/dist/commands/context/mcp/list.js +87 -0
- package/dist/commands/context/mcp/list.js.map +1 -0
- package/dist/commands/context/mcp/status.js +98 -0
- package/dist/commands/context/mcp/status.js.map +1 -0
- package/dist/commands/context/mcp/update.js +225 -0
- package/dist/commands/context/mcp/update.js.map +1 -0
- package/dist/commands/context/query.js +6 -14
- package/dist/commands/context/query.js.map +1 -1
- package/dist/commands/context/update.js +2 -2
- package/dist/commands/context/update.js.map +1 -1
- package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +6 -0
- package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
- package/dist/prompts/promptForText.js +12 -0
- package/dist/prompts/promptForText.js.map +1 -0
- package/dist/services/context.js +107 -6
- package/dist/services/context.js.map +1 -1
- package/dist/util/sharedFlags.js.map +1 -1
- package/dist/util/telemetry/cliCommandIdentity.js +6 -0
- package/dist/util/telemetry/cliCommandIdentity.js.map +1 -1
- package/oclif.config.js +1 -1
- package/oclif.manifest.json +2527 -1977
- package/package.json +2 -2
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
4
|
+
import { spinner } from '@sanity/cli-core/ux';
|
|
5
|
+
import { isHttpError } from '@sanity/client';
|
|
6
|
+
import { datasetSourceId, editSources, findMcpEndpoint, formatMcpEndpoint, mcpEndpointNameArg, mcpEndpointOrganizationFlag, parseNonEmpty } from '../../../actions/context/mcpEndpoint.js';
|
|
7
|
+
import { resolveOrganizationId } from '../../../actions/context/resolveOrganizationId.js';
|
|
8
|
+
import { describeBlueprintManager, getMcpEndpointBlueprintOwnership, updateMcpEndpoint } from '../../../services/context.js';
|
|
9
|
+
import { getDatasetFlag, getProjectIdFlag } from '../../../util/sharedFlags.js';
|
|
10
|
+
import { defineCommandTelemetry } from '../../../util/telemetry/commandTelemetry.js';
|
|
11
|
+
const updateMcpDebug = subdebug('context:mcp:update');
|
|
12
|
+
const UPDATE_FLAGS = [
|
|
13
|
+
'title',
|
|
14
|
+
'add-knowledge-base',
|
|
15
|
+
'remove-knowledge-base',
|
|
16
|
+
'knowledge-base',
|
|
17
|
+
'dataset',
|
|
18
|
+
'no-dataset',
|
|
19
|
+
'workspace',
|
|
20
|
+
'perspective',
|
|
21
|
+
'semantic-search',
|
|
22
|
+
'instructions',
|
|
23
|
+
'groq-filter'
|
|
24
|
+
];
|
|
25
|
+
const flags = {
|
|
26
|
+
...mcpEndpointOrganizationFlag,
|
|
27
|
+
'add-knowledge-base': Flags.string({
|
|
28
|
+
atLeastOne: UPDATE_FLAGS,
|
|
29
|
+
description: 'Knowledge base to add to the endpoint; repeat the flag to add several',
|
|
30
|
+
helpValue: '<id>',
|
|
31
|
+
multiple: true,
|
|
32
|
+
parse: parseNonEmpty('add-knowledge-base')
|
|
33
|
+
}),
|
|
34
|
+
...getDatasetFlag({
|
|
35
|
+
atLeastOne: UPDATE_FLAGS,
|
|
36
|
+
description: 'Dataset the endpoint serves, replacing its current dataset',
|
|
37
|
+
semantics: 'specify'
|
|
38
|
+
}),
|
|
39
|
+
...getProjectIdFlag({
|
|
40
|
+
dependsOn: [
|
|
41
|
+
'dataset'
|
|
42
|
+
],
|
|
43
|
+
description: 'Project the dataset belongs to',
|
|
44
|
+
semantics: 'override'
|
|
45
|
+
}),
|
|
46
|
+
'groq-filter': Flags.string({
|
|
47
|
+
atLeastOne: UPDATE_FLAGS,
|
|
48
|
+
description: 'GROQ filter that limits which dataset documents the endpoint serves ("" removes it)'
|
|
49
|
+
}),
|
|
50
|
+
instructions: Flags.string({
|
|
51
|
+
atLeastOne: UPDATE_FLAGS,
|
|
52
|
+
description: 'Instructions the endpoint serves to connecting agents ("" removes them)'
|
|
53
|
+
}),
|
|
54
|
+
'knowledge-base': Flags.string({
|
|
55
|
+
atLeastOne: UPDATE_FLAGS,
|
|
56
|
+
hidden: true,
|
|
57
|
+
multiple: true
|
|
58
|
+
}),
|
|
59
|
+
'no-dataset': Flags.boolean({
|
|
60
|
+
atLeastOne: UPDATE_FLAGS,
|
|
61
|
+
description: 'Stop serving the dataset, which also removes the GROQ filter',
|
|
62
|
+
exclusive: [
|
|
63
|
+
'dataset'
|
|
64
|
+
]
|
|
65
|
+
}),
|
|
66
|
+
perspective: Flags.custom({
|
|
67
|
+
atLeastOne: UPDATE_FLAGS,
|
|
68
|
+
description: 'Perspective agents query the dataset with',
|
|
69
|
+
options: [
|
|
70
|
+
'published',
|
|
71
|
+
'drafts',
|
|
72
|
+
'raw'
|
|
73
|
+
]
|
|
74
|
+
})(),
|
|
75
|
+
'remove-knowledge-base': Flags.string({
|
|
76
|
+
atLeastOne: UPDATE_FLAGS,
|
|
77
|
+
description: 'Knowledge base to remove from the endpoint; repeat the flag to remove several',
|
|
78
|
+
helpValue: '<id>',
|
|
79
|
+
multiple: true,
|
|
80
|
+
parse: parseNonEmpty('remove-knowledge-base')
|
|
81
|
+
}),
|
|
82
|
+
'semantic-search': Flags.boolean({
|
|
83
|
+
allowNo: true,
|
|
84
|
+
atLeastOne: UPDATE_FLAGS,
|
|
85
|
+
description: 'Let agents use semantic search on the dataset (--no-semantic-search to turn it off)'
|
|
86
|
+
}),
|
|
87
|
+
title: Flags.string({
|
|
88
|
+
atLeastOne: UPDATE_FLAGS,
|
|
89
|
+
description: 'New MCP endpoint title',
|
|
90
|
+
parse: parseNonEmpty('title')
|
|
91
|
+
}),
|
|
92
|
+
workspace: Flags.string({
|
|
93
|
+
atLeastOne: UPDATE_FLAGS,
|
|
94
|
+
description: 'Studio workspace whose schema agents use ("" goes back to the first workspace)'
|
|
95
|
+
})
|
|
96
|
+
};
|
|
97
|
+
export class UpdateMcpEndpointCommand extends SanityCommand {
|
|
98
|
+
static args = {
|
|
99
|
+
name: mcpEndpointNameArg
|
|
100
|
+
};
|
|
101
|
+
static description = `Update a Context MCP endpoint
|
|
102
|
+
|
|
103
|
+
Only the settings you pass change. Dataset settings (--workspace, --perspective, --semantic-search) apply to the endpoint's dataset and start from the defaults when --dataset switches to another dataset.`;
|
|
104
|
+
static examples = [
|
|
105
|
+
{
|
|
106
|
+
command: '<%= config.bin %> <%= command.id %> support --title "Customer support"',
|
|
107
|
+
description: 'Rename an MCP endpoint'
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
command: '<%= config.bin %> <%= command.id %> support --add-knowledge-base kb-def456 --remove-knowledge-base kb-abc123',
|
|
111
|
+
description: 'Serve a different knowledge base'
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
command: '<%= config.bin %> <%= command.id %> catalog --project abc123 --dataset staging --perspective drafts',
|
|
115
|
+
description: 'Switch to another dataset and query its drafts'
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
command: '<%= config.bin %> <%= command.id %> support --no-dataset',
|
|
119
|
+
description: 'Stop serving the dataset'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
command: '<%= config.bin %> <%= command.id %> support --instructions ""',
|
|
123
|
+
description: 'Remove the instructions'
|
|
124
|
+
}
|
|
125
|
+
];
|
|
126
|
+
static flags = flags;
|
|
127
|
+
static telemetry = defineCommandTelemetry(flags, {
|
|
128
|
+
redact: [
|
|
129
|
+
'title',
|
|
130
|
+
'instructions',
|
|
131
|
+
'groq-filter'
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
async run() {
|
|
135
|
+
const { name } = this.args;
|
|
136
|
+
const { 'add-knowledge-base': addKnowledgeBases = [], dataset, 'groq-filter': groqFilter, instructions, 'knowledge-base': knowledgeBase, 'no-dataset': noDataset, organization, perspective, project, 'remove-knowledge-base': removeKnowledgeBases = [], 'semantic-search': semanticSearch, title, workspace } = this.flags;
|
|
137
|
+
if (knowledgeBase !== undefined) {
|
|
138
|
+
this.error('`--knowledge-base` only works with `sanity context mcp create`. Use `--add-knowledge-base` or `--remove-knowledge-base` to change the knowledge bases of an endpoint.', {
|
|
139
|
+
exit: exitCodes.USAGE_ERROR
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (noDataset && [
|
|
143
|
+
groqFilter,
|
|
144
|
+
perspective,
|
|
145
|
+
semanticSearch,
|
|
146
|
+
workspace
|
|
147
|
+
].some((v)=>v !== undefined)) {
|
|
148
|
+
this.error('`--no-dataset` cannot be combined with `--groq-filter`, `--perspective`, `--semantic-search` or `--workspace`, which only apply to a dataset.', {
|
|
149
|
+
exit: exitCodes.USAGE_ERROR
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const addedAndRemoved = addKnowledgeBases.find((id)=>removeKnowledgeBases.includes(id));
|
|
153
|
+
if (addedAndRemoved) {
|
|
154
|
+
this.error(`"${addedAndRemoved}" is passed to both \`--add-knowledge-base\` and \`--remove-knowledge-base\`.`, {
|
|
155
|
+
exit: exitCodes.USAGE_ERROR
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const cliConfig = await this.tryGetCliConfig();
|
|
159
|
+
const datasetId = datasetSourceId(dataset, project ?? cliConfig.api?.projectId);
|
|
160
|
+
const params = {};
|
|
161
|
+
if (title !== undefined) params.title = title;
|
|
162
|
+
if (instructions !== undefined) params.instructions = instructions.trim() || null;
|
|
163
|
+
if (groqFilter !== undefined) params.groqFilter = groqFilter.trim() || null;
|
|
164
|
+
const settings = {};
|
|
165
|
+
if (workspace !== undefined) settings.workspace = workspace.trim() || null;
|
|
166
|
+
if (perspective !== undefined) settings.perspective = perspective;
|
|
167
|
+
if (semanticSearch !== undefined) settings.semanticSearch = semanticSearch;
|
|
168
|
+
const changesSources = addKnowledgeBases.length > 0 || removeKnowledgeBases.length > 0 || dataset !== undefined || noDataset || Object.keys(settings).length > 0;
|
|
169
|
+
const needsDataset = Object.keys(settings).length > 0 || Boolean(params.groqFilter);
|
|
170
|
+
const organizationId = await resolveOrganizationId({
|
|
171
|
+
configuredOrganizationId: cliConfig.app?.organizationId,
|
|
172
|
+
flagOrganizationId: organization,
|
|
173
|
+
unattended: this.isUnattended()
|
|
174
|
+
});
|
|
175
|
+
const current = await findMcpEndpoint(organizationId, name);
|
|
176
|
+
const ownership = await getMcpEndpointBlueprintOwnership(organizationId, current);
|
|
177
|
+
if (ownership.managed) {
|
|
178
|
+
const manager = describeBlueprintManager(ownership.stackName);
|
|
179
|
+
this.error(`${manager} manages MCP endpoint "${name}", so the next deploy would undo this change. Change it in the blueprint and run \`sanity blueprints deploy\` instead.`, {
|
|
180
|
+
exit: exitCodes.USAGE_ERROR
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
if (changesSources || needsDataset) {
|
|
184
|
+
const { notes, sources } = editSources(current.sources, {
|
|
185
|
+
addKnowledgeBases,
|
|
186
|
+
dataset: noDataset ? null : datasetId,
|
|
187
|
+
removeKnowledgeBases,
|
|
188
|
+
settings
|
|
189
|
+
});
|
|
190
|
+
if (needsDataset && !sources.some((source)=>source.type === 'dataset')) {
|
|
191
|
+
this.error(`MCP endpoint "${name}" has no dataset source. Pass \`--dataset\` to add one.`, {
|
|
192
|
+
exit: exitCodes.USAGE_ERROR
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (sources.length === 0) {
|
|
196
|
+
this.error('An MCP endpoint needs at least one knowledge base or dataset', {
|
|
197
|
+
exit: exitCodes.USAGE_ERROR
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
for (const note of notes)this.warn(note);
|
|
201
|
+
if (changesSources) params.sources = sources;
|
|
202
|
+
}
|
|
203
|
+
const spin = spinner('Updating MCP endpoint').start();
|
|
204
|
+
try {
|
|
205
|
+
const endpoint = await updateMcpEndpoint(organizationId, current.name, params);
|
|
206
|
+
spin.succeed('MCP endpoint updated');
|
|
207
|
+
for (const line of formatMcpEndpoint(endpoint)){
|
|
208
|
+
this.log(line);
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
spin.fail();
|
|
212
|
+
updateMcpDebug('Error updating MCP endpoint', error);
|
|
213
|
+
if (isHttpError(error) && error.statusCode === 404) {
|
|
214
|
+
this.error(`MCP endpoint "${name}" not found`, {
|
|
215
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
this.error(`Failed to update MCP endpoint: ${getErrorMessage(error)}`, {
|
|
219
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/context/mcp/update.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 {spinner} from '@sanity/cli-core/ux'\nimport {type Context, isHttpError} from '@sanity/client'\n\nimport {\n type DatasetSettings,\n datasetSourceId,\n editSources,\n findMcpEndpoint,\n formatMcpEndpoint,\n mcpEndpointNameArg,\n mcpEndpointOrganizationFlag,\n parseNonEmpty,\n} from '../../../actions/context/mcpEndpoint.js'\nimport {resolveOrganizationId} from '../../../actions/context/resolveOrganizationId.js'\nimport {\n describeBlueprintManager,\n getMcpEndpointBlueprintOwnership,\n updateMcpEndpoint,\n} from '../../../services/context.js'\nimport {getDatasetFlag, getProjectIdFlag} from '../../../util/sharedFlags.js'\nimport {defineCommandTelemetry} from '../../../util/telemetry/commandTelemetry.js'\n\nconst updateMcpDebug = subdebug('context:mcp:update')\n\nconst UPDATE_FLAGS = [\n 'title',\n 'add-knowledge-base',\n 'remove-knowledge-base',\n 'knowledge-base',\n 'dataset',\n 'no-dataset',\n 'workspace',\n 'perspective',\n 'semantic-search',\n 'instructions',\n 'groq-filter',\n]\n\nconst flags = {\n ...mcpEndpointOrganizationFlag,\n 'add-knowledge-base': Flags.string({\n atLeastOne: UPDATE_FLAGS,\n description: 'Knowledge base to add to the endpoint; repeat the flag to add several',\n helpValue: '<id>',\n multiple: true,\n parse: parseNonEmpty('add-knowledge-base'),\n }),\n ...getDatasetFlag({\n atLeastOne: UPDATE_FLAGS,\n description: 'Dataset the endpoint serves, replacing its current dataset',\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 atLeastOne: UPDATE_FLAGS,\n description:\n 'GROQ filter that limits which dataset documents the endpoint serves (\"\" removes it)',\n }),\n instructions: Flags.string({\n atLeastOne: UPDATE_FLAGS,\n description: 'Instructions the endpoint serves to connecting agents (\"\" removes them)',\n }),\n 'knowledge-base': Flags.string({\n atLeastOne: UPDATE_FLAGS,\n hidden: true,\n multiple: true,\n }),\n 'no-dataset': Flags.boolean({\n atLeastOne: UPDATE_FLAGS,\n description: 'Stop serving the dataset, which also removes the GROQ filter',\n exclusive: ['dataset'],\n }),\n perspective: Flags.custom<'drafts' | 'published' | 'raw'>({\n atLeastOne: UPDATE_FLAGS,\n description: 'Perspective agents query the dataset with',\n options: ['published', 'drafts', 'raw'],\n })(),\n 'remove-knowledge-base': Flags.string({\n atLeastOne: UPDATE_FLAGS,\n description: 'Knowledge base to remove from the endpoint; repeat the flag to remove several',\n helpValue: '<id>',\n multiple: true,\n parse: parseNonEmpty('remove-knowledge-base'),\n }),\n 'semantic-search': Flags.boolean({\n allowNo: true,\n atLeastOne: UPDATE_FLAGS,\n description:\n 'Let agents use semantic search on the dataset (--no-semantic-search to turn it off)',\n }),\n title: Flags.string({\n atLeastOne: UPDATE_FLAGS,\n description: 'New MCP endpoint title',\n parse: parseNonEmpty('title'),\n }),\n workspace: Flags.string({\n atLeastOne: UPDATE_FLAGS,\n description: 'Studio workspace whose schema agents use (\"\" goes back to the first workspace)',\n }),\n} satisfies FlagInput\n\nexport class UpdateMcpEndpointCommand extends SanityCommand<typeof UpdateMcpEndpointCommand> {\n static override args = {\n name: mcpEndpointNameArg,\n }\n\n static override description = `Update a Context MCP endpoint\n\nOnly the settings you pass change. Dataset settings (--workspace, --perspective, --semantic-search) apply to the endpoint's dataset and start from the defaults when --dataset switches to another dataset.`\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> support --title \"Customer support\"',\n description: 'Rename an MCP endpoint',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> support --add-knowledge-base kb-def456 --remove-knowledge-base kb-abc123',\n description: 'Serve a different knowledge base',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> catalog --project abc123 --dataset staging --perspective drafts',\n description: 'Switch to another dataset and query its drafts',\n },\n {\n command: '<%= config.bin %> <%= command.id %> support --no-dataset',\n description: 'Stop serving the dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> support --instructions \"\"',\n description: 'Remove the instructions',\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 'add-knowledge-base': addKnowledgeBases = [],\n dataset,\n 'groq-filter': groqFilter,\n instructions,\n 'knowledge-base': knowledgeBase,\n 'no-dataset': noDataset,\n organization,\n perspective,\n project,\n 'remove-knowledge-base': removeKnowledgeBases = [],\n 'semantic-search': semanticSearch,\n title,\n workspace,\n } = this.flags\n\n if (knowledgeBase !== undefined) {\n this.error(\n '`--knowledge-base` only works with `sanity context mcp create`. Use `--add-knowledge-base` or `--remove-knowledge-base` to change the knowledge bases of an endpoint.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n if (\n noDataset &&\n [groqFilter, perspective, semanticSearch, workspace].some((v) => v !== undefined)\n ) {\n this.error(\n '`--no-dataset` cannot be combined with `--groq-filter`, `--perspective`, `--semantic-search` or `--workspace`, which only apply to a dataset.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n const addedAndRemoved = addKnowledgeBases.find((id) => removeKnowledgeBases.includes(id))\n if (addedAndRemoved) {\n this.error(\n `\"${addedAndRemoved}\" is passed to both \\`--add-knowledge-base\\` and \\`--remove-knowledge-base\\`.`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n const cliConfig = await this.tryGetCliConfig()\n const datasetId = datasetSourceId(dataset, project ?? cliConfig.api?.projectId)\n\n const params: Context.EditMcpEndpointParams = {}\n if (title !== undefined) params.title = title\n if (instructions !== undefined) params.instructions = instructions.trim() || null\n if (groqFilter !== undefined) params.groqFilter = groqFilter.trim() || null\n\n const settings: DatasetSettings = {}\n if (workspace !== undefined) settings.workspace = workspace.trim() || null\n if (perspective !== undefined) settings.perspective = perspective\n if (semanticSearch !== undefined) settings.semanticSearch = semanticSearch\n const changesSources =\n addKnowledgeBases.length > 0 ||\n removeKnowledgeBases.length > 0 ||\n dataset !== undefined ||\n noDataset ||\n Object.keys(settings).length > 0\n const needsDataset = Object.keys(settings).length > 0 || Boolean(params.groqFilter)\n\n const organizationId = await resolveOrganizationId({\n configuredOrganizationId: cliConfig.app?.organizationId,\n flagOrganizationId: organization,\n unattended: this.isUnattended(),\n })\n\n const current = await findMcpEndpoint(organizationId, name)\n\n const ownership = await getMcpEndpointBlueprintOwnership(organizationId, current)\n if (ownership.managed) {\n const manager = describeBlueprintManager(ownership.stackName)\n this.error(\n `${manager} manages MCP endpoint \"${name}\", so the next deploy would undo this change. Change it in the blueprint and run \\`sanity blueprints deploy\\` instead.`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n if (changesSources || needsDataset) {\n const {notes, sources} = editSources(current.sources, {\n addKnowledgeBases,\n dataset: noDataset ? null : datasetId,\n removeKnowledgeBases,\n settings,\n })\n if (needsDataset && !sources.some((source) => source.type === 'dataset')) {\n this.error(`MCP endpoint \"${name}\" has no dataset source. Pass \\`--dataset\\` to add one.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n if (sources.length === 0) {\n this.error('An MCP endpoint needs at least one knowledge base or dataset', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n for (const note of notes) this.warn(note)\n if (changesSources) params.sources = sources\n }\n\n const spin = spinner('Updating MCP endpoint').start()\n try {\n const endpoint = await updateMcpEndpoint(organizationId, current.name, params)\n spin.succeed('MCP endpoint updated')\n for (const line of formatMcpEndpoint(endpoint)) {\n this.log(line)\n }\n } catch (error) {\n spin.fail()\n updateMcpDebug('Error updating MCP endpoint', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`MCP endpoint \"${name}\" not found`, {exit: exitCodes.RUNTIME_ERROR})\n }\n this.error(`Failed to update MCP endpoint: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","spinner","isHttpError","datasetSourceId","editSources","findMcpEndpoint","formatMcpEndpoint","mcpEndpointNameArg","mcpEndpointOrganizationFlag","parseNonEmpty","resolveOrganizationId","describeBlueprintManager","getMcpEndpointBlueprintOwnership","updateMcpEndpoint","getDatasetFlag","getProjectIdFlag","defineCommandTelemetry","updateMcpDebug","UPDATE_FLAGS","flags","string","atLeastOne","description","helpValue","multiple","parse","semantics","dependsOn","instructions","hidden","boolean","exclusive","perspective","custom","options","allowNo","title","workspace","UpdateMcpEndpointCommand","args","name","examples","command","telemetry","redact","run","addKnowledgeBases","dataset","groqFilter","knowledgeBase","noDataset","organization","project","removeKnowledgeBases","semanticSearch","undefined","error","exit","USAGE_ERROR","some","v","addedAndRemoved","find","id","includes","cliConfig","tryGetCliConfig","datasetId","api","projectId","params","trim","settings","changesSources","length","Object","keys","needsDataset","Boolean","organizationId","configuredOrganizationId","app","flagOrganizationId","unattended","isUnattended","current","ownership","managed","manager","stackName","notes","sources","source","type","note","warn","spin","start","endpoint","succeed","line","log","fail","statusCode","RUNTIME_ERROR"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { Args, Flags } from '@oclif/core';
|
|
|
2
2
|
import { colorizeJson, exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
3
|
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
4
4
|
import { isRecord } from '@sanity/cli-core/util';
|
|
5
|
-
import {
|
|
5
|
+
import { resolveOrganizationId } from '../../actions/context/resolveOrganizationId.js';
|
|
6
6
|
import { queryContext } from '../../services/context.js';
|
|
7
7
|
import { getOrganizationFlag } from '../../util/sharedFlags.js';
|
|
8
8
|
import { defineCommandTelemetry } from '../../util/telemetry/commandTelemetry.js';
|
|
@@ -57,19 +57,11 @@ export class QueryContextCommand extends SanityCommand {
|
|
|
57
57
|
async run() {
|
|
58
58
|
const { query } = this.args;
|
|
59
59
|
const { json, organization, params } = this.flags;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
unattended: this.isUnattended()
|
|
66
|
-
});
|
|
67
|
-
} catch (error) {
|
|
68
|
-
queryContextDebug('Error resolving organization', error);
|
|
69
|
-
this.error(getErrorMessage(error), {
|
|
70
|
-
exit: error instanceof MissingOrganizationError ? exitCodes.USAGE_ERROR : exitCodes.RUNTIME_ERROR
|
|
71
|
-
});
|
|
72
|
-
}
|
|
60
|
+
const organizationId = await resolveOrganizationId({
|
|
61
|
+
configuredOrganizationId: (await this.tryGetCliConfig()).app?.organizationId,
|
|
62
|
+
flagOrganizationId: organization,
|
|
63
|
+
unattended: this.isUnattended()
|
|
64
|
+
});
|
|
73
65
|
let result;
|
|
74
66
|
try {
|
|
75
67
|
result = await queryContext(organizationId, query, params);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/context/query.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {colorizeJson, exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isRecord} from '@sanity/cli-core/util'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/context/query.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {colorizeJson, exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isRecord} from '@sanity/cli-core/util'\n\nimport {resolveOrganizationId} from '../../actions/context/resolveOrganizationId.js'\nimport {queryContext} from '../../services/context.js'\nimport {getOrganizationFlag} from '../../util/sharedFlags.js'\nimport {defineCommandTelemetry} from '../../util/telemetry/commandTelemetry.js'\n\nconst queryContextDebug = subdebug('context:query')\n\nconst flags = {\n ...getOrganizationFlag({\n description: 'Organization to query',\n semantics: 'override',\n }),\n params: Flags.custom<Record<string, unknown>>({\n description: 'Query parameters as a JSON object',\n helpValue: '<json>',\n parse: async (input: string) => {\n let parsed: unknown\n try {\n parsed = JSON.parse(input)\n } catch {\n throw new Error('`--params` must be valid JSON')\n }\n if (!isRecord(parsed)) {\n throw new Error('`--params` must be a JSON object, like \\'{\"type\": \"issue\"}\\'')\n }\n return parsed\n },\n })(),\n} satisfies FlagInput\n\nexport class QueryContextCommand extends SanityCommand<typeof QueryContextCommand> {\n static override args = {\n query: Args.string({\n description: \"GROQ query to run against the organization's Context documents\",\n required: true,\n }),\n }\n\n static override description = \"Query an organization's Context documents with GROQ\"\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command:\n '<%= config.bin %> <%= command.id %> \\'*[_type == \"sanity.context.issue\" && status == \"open\"]{_id, knowledgeBaseId}\\'',\n description: 'List open issues across all knowledge bases',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> \\'*[_type == \"sanity.context.entry\" && knowledgeBaseId == $kb].path\\' --params \\'{\"kb\": \"kb-abc123\"}\\' --json',\n description: 'List the entry paths of one knowledge base as plain JSON',\n },\n ]\n\n static override flags = flags\n\n static telemetry = defineCommandTelemetry(flags, {redact: ['params']})\n\n public async run(): Promise<void> {\n const {query} = this.args\n const {json, organization, params} = 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 result\n try {\n result = await queryContext(organizationId, query, params)\n } catch (error) {\n queryContextDebug('Error running query', error)\n this.error(`Failed to run query: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // GROQ returns null for no match; guard undefined, which colorizeJson cannot tokenize\n const output = result ?? null\n if (json) {\n this.logJson(output)\n return\n }\n\n this.log(colorizeJson(output))\n }\n}\n"],"names":["Args","Flags","colorizeJson","exitCodes","SanityCommand","subdebug","getErrorMessage","isRecord","resolveOrganizationId","queryContext","getOrganizationFlag","defineCommandTelemetry","queryContextDebug","flags","description","semantics","params","custom","helpValue","parse","input","parsed","JSON","Error","QueryContextCommand","args","query","string","required","enableJsonFlag","examples","command","telemetry","redact","run","json","organization","organizationId","configuredOrganizationId","tryGetCliConfig","app","flagOrganizationId","unattended","isUnattended","result","error","exit","RUNTIME_ERROR","output","logJson","log"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,YAAY,EAAEC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACjF,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,QAAQ,QAAO,wBAAuB;AAE9C,SAAQC,qBAAqB,QAAO,iDAAgD;AACpF,SAAQC,YAAY,QAAO,4BAA2B;AACtD,SAAQC,mBAAmB,QAAO,4BAA2B;AAC7D,SAAQC,sBAAsB,QAAO,2CAA0C;AAE/E,MAAMC,oBAAoBP,SAAS;AAEnC,MAAMQ,QAAQ;IACZ,GAAGH,oBAAoB;QACrBI,aAAa;QACbC,WAAW;IACb,EAAE;IACFC,QAAQf,MAAMgB,MAAM,CAA0B;QAC5CH,aAAa;QACbI,WAAW;QACXC,OAAO,OAAOC;YACZ,IAAIC;YACJ,IAAI;gBACFA,SAASC,KAAKH,KAAK,CAACC;YACtB,EAAE,OAAM;gBACN,MAAM,IAAIG,MAAM;YAClB;YACA,IAAI,CAAChB,SAASc,SAAS;gBACrB,MAAM,IAAIE,MAAM;YAClB;YACA,OAAOF;QACT;IACF;AACF;AAEA,OAAO,MAAMG,4BAA4BpB;IACvC,OAAgBqB,OAAO;QACrBC,OAAO1B,KAAK2B,MAAM,CAAC;YACjBb,aAAa;YACbc,UAAU;QACZ;IACF,EAAC;IAED,OAAgBd,cAAc,sDAAqD;IAEnF,OAAgBe,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SACE;YACFjB,aAAa;QACf;QACA;YACEiB,SACE;YACFjB,aAAa;QACf;KACD,CAAA;IAED,OAAgBD,QAAQA,MAAK;IAE7B,OAAOmB,YAAYrB,uBAAuBE,OAAO;QAACoB,QAAQ;YAAC;SAAS;IAAA,GAAE;IAEtE,MAAaC,MAAqB;QAChC,MAAM,EAACR,KAAK,EAAC,GAAG,IAAI,CAACD,IAAI;QACzB,MAAM,EAACU,IAAI,EAAEC,YAAY,EAAEpB,MAAM,EAAC,GAAG,IAAI,CAACH,KAAK;QAE/C,MAAMwB,iBAAiB,MAAM7B,sBAAsB;YACjD8B,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,SAAS,MAAMnC,aAAa4B,gBAAgBX,OAAOV;QACrD,EAAE,OAAO6B,OAAO;YACdjC,kBAAkB,uBAAuBiC;YACzC,IAAI,CAACA,KAAK,CAAC,CAAC,qBAAqB,EAAEvC,gBAAgBuC,QAAQ,EAAE;gBAC3DC,MAAM3C,UAAU4C,aAAa;YAC/B;QACF;QAEA,sFAAsF;QACtF,MAAMC,SAASJ,UAAU;QACzB,IAAIT,MAAM;YACR,IAAI,CAACc,OAAO,CAACD;YACb;QACF;QAEA,IAAI,CAACE,GAAG,CAAChD,aAAa8C;IACxB;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 { spinner } from '@sanity/cli-core/ux';
|
|
5
5
|
import { isHttpError } from '@sanity/client';
|
|
6
|
-
import { getKnowledgeBaseBlueprintOwnership, updateKnowledgeBase } from '../../services/context.js';
|
|
6
|
+
import { describeBlueprintManager, getKnowledgeBaseBlueprintOwnership, updateKnowledgeBase } from '../../services/context.js';
|
|
7
7
|
import { defineCommandTelemetry } from '../../util/telemetry/commandTelemetry.js';
|
|
8
8
|
const updateContextDebug = subdebug('context:update');
|
|
9
9
|
const UPDATE_FLAGS = [
|
|
@@ -109,7 +109,7 @@ export class UpdateKnowledgeBaseCommand extends SanityCommand {
|
|
|
109
109
|
managed: false
|
|
110
110
|
};
|
|
111
111
|
if (ownership.managed) {
|
|
112
|
-
const manager = ownership.stackName
|
|
112
|
+
const manager = describeBlueprintManager(ownership.stackName);
|
|
113
113
|
const refreshHint = params.refreshEnabled === undefined && params.refreshFrequency === undefined ? '' : ' Refresh settings are not managed by the blueprint, so you can change them without `--title` and `--description`.';
|
|
114
114
|
this.error(`${manager} manages the title and description of knowledge base "${knowledgeBaseId}", so the next deploy would undo this change. Change them in the blueprint and run \`sanity blueprints deploy\` instead.${refreshHint}`, {
|
|
115
115
|
exit: exitCodes.USAGE_ERROR
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/context/update.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 {spinner} from '@sanity/cli-core/ux'\nimport {type Context, isHttpError} from '@sanity/client'\n\nimport {\n type BlueprintOwnership,\n getKnowledgeBaseBlueprintOwnership,\n updateKnowledgeBase,\n} from '../../services/context.js'\nimport {defineCommandTelemetry} from '../../util/telemetry/commandTelemetry.js'\n\nconst updateContextDebug = subdebug('context:update')\n\nconst UPDATE_FLAGS = ['title', 'description', 'refresh-enabled', 'refresh-frequency'] as const\n\nconst flags = {\n description: Flags.string({\n atLeastOne: [...UPDATE_FLAGS],\n description: 'New knowledge base description',\n required: false,\n }),\n 'refresh-enabled': Flags.boolean({\n allowNo: true,\n atLeastOne: [...UPDATE_FLAGS],\n description: 'Enable scheduled refresh (--no-refresh-enabled to disable)',\n required: false,\n }),\n 'refresh-frequency': Flags.custom<'monthly' | 'weekly'>({\n atLeastOne: [...UPDATE_FLAGS],\n description: 'How often scheduled refresh runs',\n options: ['weekly', 'monthly'],\n required: false,\n })(),\n title: Flags.string({\n atLeastOne: [...UPDATE_FLAGS],\n description: 'New knowledge base title',\n required: false,\n }),\n} satisfies FlagInput\n\nexport class UpdateKnowledgeBaseCommand extends SanityCommand<typeof UpdateKnowledgeBaseCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'Update a knowledge base'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --title \"New title\"',\n description: 'Rename a knowledge base',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> kb-abc123 --refresh-enabled --refresh-frequency weekly',\n description: 'Enable weekly scheduled refresh',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --no-refresh-enabled',\n description: 'Disable scheduled refresh',\n },\n ]\n\n static override flags = flags\n\n static telemetry = defineCommandTelemetry(flags, {\n redact: ['title', 'description'],\n })\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {\n description,\n 'refresh-enabled': refreshEnabled,\n 'refresh-frequency': refreshFrequency,\n title,\n } = this.flags\n\n const params: Context.EditKnowledgeBaseParams = {}\n if (title !== undefined) {\n const trimmedTitle = title.trim()\n if (trimmedTitle === '') {\n this.error('Title cannot be empty', {exit: exitCodes.USAGE_ERROR})\n }\n params.title = trimmedTitle\n }\n if (description !== undefined) {\n const trimmedDescription = description.trim()\n if (trimmedDescription === '') {\n this.error('Description cannot be empty', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n params.description = trimmedDescription\n }\n if (refreshEnabled !== undefined) {\n params.refreshEnabled = refreshEnabled\n }\n if (refreshFrequency !== undefined) {\n params.refreshFrequency = refreshFrequency\n }\n\n const changesBlueprintFields = params.title !== undefined || params.description !== undefined\n const ownership: BlueprintOwnership = changesBlueprintFields\n ? await getKnowledgeBaseBlueprintOwnership(knowledgeBaseId)\n : {managed: false}\n if (ownership.managed) {\n const manager = ownership.stackName\n
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/context/update.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 {spinner} from '@sanity/cli-core/ux'\nimport {type Context, isHttpError} from '@sanity/client'\n\nimport {\n type BlueprintOwnership,\n describeBlueprintManager,\n getKnowledgeBaseBlueprintOwnership,\n updateKnowledgeBase,\n} from '../../services/context.js'\nimport {defineCommandTelemetry} from '../../util/telemetry/commandTelemetry.js'\n\nconst updateContextDebug = subdebug('context:update')\n\nconst UPDATE_FLAGS = ['title', 'description', 'refresh-enabled', 'refresh-frequency'] as const\n\nconst flags = {\n description: Flags.string({\n atLeastOne: [...UPDATE_FLAGS],\n description: 'New knowledge base description',\n required: false,\n }),\n 'refresh-enabled': Flags.boolean({\n allowNo: true,\n atLeastOne: [...UPDATE_FLAGS],\n description: 'Enable scheduled refresh (--no-refresh-enabled to disable)',\n required: false,\n }),\n 'refresh-frequency': Flags.custom<'monthly' | 'weekly'>({\n atLeastOne: [...UPDATE_FLAGS],\n description: 'How often scheduled refresh runs',\n options: ['weekly', 'monthly'],\n required: false,\n })(),\n title: Flags.string({\n atLeastOne: [...UPDATE_FLAGS],\n description: 'New knowledge base title',\n required: false,\n }),\n} satisfies FlagInput\n\nexport class UpdateKnowledgeBaseCommand extends SanityCommand<typeof UpdateKnowledgeBaseCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'Update a knowledge base'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --title \"New title\"',\n description: 'Rename a knowledge base',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> kb-abc123 --refresh-enabled --refresh-frequency weekly',\n description: 'Enable weekly scheduled refresh',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --no-refresh-enabled',\n description: 'Disable scheduled refresh',\n },\n ]\n\n static override flags = flags\n\n static telemetry = defineCommandTelemetry(flags, {\n redact: ['title', 'description'],\n })\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {\n description,\n 'refresh-enabled': refreshEnabled,\n 'refresh-frequency': refreshFrequency,\n title,\n } = this.flags\n\n const params: Context.EditKnowledgeBaseParams = {}\n if (title !== undefined) {\n const trimmedTitle = title.trim()\n if (trimmedTitle === '') {\n this.error('Title cannot be empty', {exit: exitCodes.USAGE_ERROR})\n }\n params.title = trimmedTitle\n }\n if (description !== undefined) {\n const trimmedDescription = description.trim()\n if (trimmedDescription === '') {\n this.error('Description cannot be empty', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n params.description = trimmedDescription\n }\n if (refreshEnabled !== undefined) {\n params.refreshEnabled = refreshEnabled\n }\n if (refreshFrequency !== undefined) {\n params.refreshFrequency = refreshFrequency\n }\n\n const changesBlueprintFields = params.title !== undefined || params.description !== undefined\n const ownership: BlueprintOwnership = changesBlueprintFields\n ? await getKnowledgeBaseBlueprintOwnership(knowledgeBaseId)\n : {managed: false}\n if (ownership.managed) {\n const manager = describeBlueprintManager(ownership.stackName)\n const refreshHint =\n params.refreshEnabled === undefined && params.refreshFrequency === undefined\n ? ''\n : ' Refresh settings are not managed by the blueprint, so you can change them without `--title` and `--description`.'\n this.error(\n `${manager} manages the title and description of knowledge base \"${knowledgeBaseId}\", so the next deploy would undo this change. Change them in the blueprint and run \\`sanity blueprints deploy\\` instead.${refreshHint}`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n const spin = spinner('Updating knowledge base').start()\n try {\n await updateKnowledgeBase(knowledgeBaseId, params)\n spin.succeed()\n this.log('Knowledge base updated')\n } catch (error) {\n spin.fail()\n updateContextDebug('Error updating 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 update knowledge base: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","spinner","isHttpError","describeBlueprintManager","getKnowledgeBaseBlueprintOwnership","updateKnowledgeBase","defineCommandTelemetry","updateContextDebug","UPDATE_FLAGS","flags","description","string","atLeastOne","required","boolean","allowNo","custom","options","title","UpdateKnowledgeBaseCommand","args","knowledgeBaseId","examples","command","telemetry","redact","run","refreshEnabled","refreshFrequency","params","undefined","trimmedTitle","trim","error","exit","USAGE_ERROR","trimmedDescription","changesBlueprintFields","ownership","managed","manager","stackName","refreshHint","spin","start","succeed","log","fail","statusCode","RUNTIME_ERROR"],"mappings":"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"}
|
|
@@ -94,6 +94,12 @@ function apiValidator({ args, flags }) {
|
|
|
94
94
|
// See context:build — --watch has no deadline and would hang the MCP tool call.
|
|
95
95
|
'context:jobs:get': conditionalDenyFlags('watch'),
|
|
96
96
|
'context:list': allow,
|
|
97
|
+
'context:mcp:create': allow,
|
|
98
|
+
'context:mcp:delete': allow,
|
|
99
|
+
'context:mcp:get': allow,
|
|
100
|
+
'context:mcp:list': allow,
|
|
101
|
+
'context:mcp:status': allow,
|
|
102
|
+
'context:mcp:update': allow,
|
|
97
103
|
'context:query': allow,
|
|
98
104
|
'context:refresh': allow,
|
|
99
105
|
'context:update': allow,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/exports/invokeSanityCli/commandPolicies/mcpPolicy.ts"],"sourcesContent":["import {\n allow,\n type CommandPolicySet,\n conditionalDenyFlags,\n conditionalPolicy,\n deny,\n} from '@sanity/cli-core/commandPolicy'\n\nimport {isRemoteAssetSource} from '../../../util/isRemoteAssetSource.js'\n\nfunction apiValidator({\n args,\n flags,\n}: {\n args: Readonly<Record<string, unknown>>\n flags: Readonly<Record<string, unknown>>\n}): boolean {\n const fields: unknown[] = Array.isArray(flags.field) ? flags.field : []\n\n const fieldReadsFromHost = fields.some((field) => {\n if (typeof field !== 'string') return false\n const separatorIndex = field.indexOf('=')\n return separatorIndex > 0 && field[separatorIndex + 1] === '@'\n })\n if (fieldReadsFromHost) return false\n\n const headers: unknown[] = Array.isArray(flags.header) ? flags.header : []\n\n const headerOverridesAuthentication = headers.some((header) => {\n if (typeof header !== 'string') return false\n const separatorIndex = header.indexOf(':')\n if (separatorIndex <= 0) return false\n\n const name = header.slice(0, separatorIndex).trim().toLowerCase()\n return name === 'authorization' || name === 'cookie'\n })\n\n if (headerOverridesAuthentication) return false\n\n const endpoint = typeof args.endpoint === 'string' ? URL.parse(args.endpoint) : null\n const urlEmbedsCredentials =\n endpoint !== null && (endpoint.username !== '' || endpoint.password !== '')\n\n return !urlEmbedsCredentials\n}\n\n/**\n * MCP programmatic mode disables local project/config discovery (see the CLI\n * execution context). Missing project or dataset values may therefore produce\n * a usage error, but cannot cause local filesystem access. Destructive remote\n * operations are allowed and do not by themselves make a command unsafe.\n *\n * Every command this package contributes must have exactly one policy here:\n * - allow: every valid invocation is safe\n * - conditional: safety depends on parsed arguments or flags\n * - deny: no invocation is safe\n *\n * Commands contributed by plugins are not listed here. Each plugin declares\n * policies for its own commands (see `PluginInvocationPolicies` in\n * `@sanity/cli-core/commandPolicy`).\n */\nexport const mcpPolicy: CommandPolicySet = {\n // Special exception, this can be very dangerous but is also super useful\n // to expose. Refuse authentication overrides and host input channels:\n // `--token`, Authorization, and Cookie headers replace the MCP user's authentication,\n // URL-embedded credentials replace it with Basic authentication,\n // `--input` reads the request body from the host's filesystem or stdin, and\n // `-F key=@<file>` / `-F key=@-` field values do the same.\n api: conditionalPolicy({\n deniedFlags: ['input', 'token'],\n validate: apiValidator,\n }),\n\n // --file reads from the machine running the command and must only run locally.\n 'assets:upload': conditionalPolicy({\n deniedFlags: ['content-type', 'file'],\n validate: ({flags}) => typeof flags['from-url'] === 'string' && flags['from-url'].length > 0,\n }),\n\n 'backups:disable': allow,\n // Writes a downloaded backup to the local filesystem.\n 'backups:download': deny,\n 'backups:enable': allow,\n 'backups:list': allow,\n\n // Requires a local Studio project and writes build output to disk.\n build: deny,\n\n // Reads and rewrites local source code.\n codemod: deny,\n\n // --watch polls a job with no deadline; a stuck job would hang the MCP tool\n // call indefinitely. Non-watch invocations are single remote requests.\n 'context:build': conditionalDenyFlags('watch'),\n 'context:create': allow,\n 'context:delete': allow,\n 'context:entries:get': allow,\n 'context:entries:list': allow,\n // See context:build — --watch has no deadline and would hang the MCP tool call.\n 'context:entries:rebuild': conditionalDenyFlags('watch'),\n 'context:get': allow,\n // --file reads the import payload from the local filesystem; text, URL and\n // dataset imports are remote-only.\n 'context:imports:create': conditionalDenyFlags('file'),\n 'context:imports:delete': allow,\n 'context:imports:download': allow,\n 'context:imports:get': allow,\n 'context:imports:list': allow,\n // See context:build — --watch has no deadline and would hang the MCP tool call.\n 'context:issues:apply': conditionalDenyFlags('watch'),\n 'context:issues:dismiss': allow,\n 'context:issues:get': allow,\n 'context:issues:list': allow,\n 'context:issues:reopen': allow,\n // See context:build — --watch has no deadline and would hang the MCP tool call.\n 'context:issues:resolve': conditionalDenyFlags('watch'),\n // See context:build — --watch has no deadline and would hang the MCP tool call.\n 'context:jobs:get': conditionalDenyFlags('watch'),\n 'context:list': allow,\n 'context:query': allow,\n 'context:refresh': allow,\n 'context:update': allow,\n\n 'cors:add': allow,\n 'cors:delete': allow,\n 'cors:list': allow,\n\n 'datasets:alias:create': allow,\n 'datasets:alias:delete': allow,\n 'datasets:alias:link': allow,\n 'datasets:alias:unlink': allow,\n 'datasets:copy': allow,\n 'datasets:create': allow,\n 'datasets:delete': allow,\n 'datasets:embeddings:disable': allow,\n 'datasets:embeddings:enable': allow,\n 'datasets:embeddings:status': allow,\n // Writes dataset contents and assets to the local filesystem.\n 'datasets:export': deny,\n // Reads import data from the local filesystem and may replace documents.\n 'datasets:import': deny,\n 'datasets:list': allow,\n 'datasets:visibility:get': allow,\n 'datasets:visibility:set': allow,\n\n // Inspects local project files and can print authentication secrets.\n debug: deny,\n\n // Reads, builds, and deploys a local Studio project.\n deploy: deny,\n\n // Loads a local Studio project and starts a development server.\n dev: deny,\n\n // Opens a browser on the machine running the MCP server.\n 'docs:browse': deny,\n // --web opens a browser on the machine running the MCP server.\n 'docs:read': conditionalDenyFlags('web'),\n 'docs:search': allow,\n\n // Reads and executes local project configuration for diagnostics.\n doctor: deny,\n\n // Reads document input from disk or launches a local editor.\n 'documents:create': deny,\n 'documents:delete': allow,\n 'documents:get': allow,\n 'documents:query': allow,\n // Loads a local Studio schema to validate documents.\n 'documents:validate': deny,\n\n // Executes arbitrary code in the local Studio context.\n exec: deny,\n\n // Loads a local schema and deploys a GraphQL API.\n 'graphql:deploy': deny,\n 'graphql:list': allow,\n // --api loads GraphQL definitions from the local project; explicit project/dataset flags are safe.\n 'graphql:undeploy': conditionalDenyFlags('api'),\n\n 'hooks:attempt': allow,\n 'hooks:create': allow,\n 'hooks:delete': allow,\n 'hooks:list': allow,\n 'hooks:logs': allow,\n\n // Creates or modifies a local project and may install dependencies.\n init: deny,\n\n // Installs packages into the local project.\n install: deny,\n\n // Opens a browser on the machine running the MCP server.\n learn: deny,\n\n // Performs an authentication flow.\n login: deny,\n\n // Performs an authentication operation and clears local credentials.\n logout: deny,\n\n // Reads local project configuration and opens a browser.\n manage: deny,\n\n // Loads local Studio configuration and writes manifest files.\n 'manifest:extract': deny,\n\n // Reads and writes local MCP client configuration.\n 'mcp:configure': deny,\n\n // Writes an aspect definition to the local filesystem.\n 'media:create-aspect': deny,\n 'media:delete-aspect': allow,\n // Reads a local aspect definition before deploying it.\n 'media:deploy-aspect': deny,\n // Writes media assets to the local filesystem.\n 'media:export': deny,\n // A directory or archive source reads media assets from the local\n // filesystem. A URL source does not: Sanity fetches the asset itself, so the\n // only local input is the URL. `--replace-aspects` is meaningless for a URL\n // source (the command rejects the combination), so it is hidden here rather\n // than advertised as usable surface.\n 'media:import': conditionalPolicy({\n deniedFlags: ['replace-aspects'],\n validate: ({args}) => typeof args.source === 'string' && isRemoteAssetSource(args.source),\n }),\n // media:pull-aspects and media:prune-aspect-data are hidden while the\n // config app is in beta, so they take the deny-by-default path like any\n // unlisted command. The exhaustiveness test forces explicit entries when\n // they are unhidden.\n\n // Creates migration source files in the local project.\n 'migrations:create': deny,\n // Reads and loads migration definitions from the local project.\n 'migrations:list': deny,\n // Executes local migration code that may perform arbitrary document mutations.\n 'migrations:run': deny,\n\n // Writes project setup values and scaffolds local applications.\n new: deny,\n\n // --web opens a browser on the machine running the MCP server.\n 'openapi:get': conditionalDenyFlags('web'),\n 'openapi:list': conditionalDenyFlags('web'),\n\n 'organizations:create': allow,\n 'organizations:delete': allow,\n 'organizations:get': allow,\n 'organizations:list': allow,\n 'organizations:update': allow,\n\n // Serves a local production build.\n preview: deny,\n\n 'projects:create': allow,\n 'projects:list': allow,\n // Reads locally stored claim URLs and robot tokens.\n 'projects:unclaimed': deny,\n\n // Loads the local Studio configuration to resolve the datasets containing each schema.\n 'schemas:delete': deny,\n // Loads local schema files before deploying them.\n 'schemas:deploy': deny,\n // Loads local Studio configuration and writes an extracted schema to disk.\n 'schemas:extract': deny,\n // Requires a local project and loads its schema configuration.\n 'schemas:list': deny,\n // Loads and executes a local Studio schema.\n 'schemas:validate': deny,\n\n // Installs skills into local editor configuration directories.\n 'skills:install': deny,\n\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:disable': deny,\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:enable': deny,\n 'telemetry:status': allow,\n\n // Creates authentication credentials.\n 'tokens:create': deny,\n // Deletes authentication credentials.\n 'tokens:delete': deny,\n // Exposes authentication credential metadata.\n 'tokens:list': deny,\n // Replaces authentication credentials and exposes the new secret.\n 'tokens:rotate': deny,\n\n // Reads the local schema and source files and writes generated types to the project.\n 'typegen:generate': deny,\n\n // Loads local CLI and workbench configuration to identify the deployed Studio or application.\n undeploy: deny,\n\n // Grants a user access to a project.\n 'users:invite': deny,\n 'users:list': allow,\n\n // Reads the local project and installed package tree.\n versions: deny,\n\n // Reads the authenticated user from the API using the execution context token.\n whoami: allow,\n}\n"],"names":["allow","conditionalDenyFlags","conditionalPolicy","deny","isRemoteAssetSource","apiValidator","args","flags","fields","Array","isArray","field","fieldReadsFromHost","some","separatorIndex","indexOf","headers","header","headerOverridesAuthentication","name","slice","trim","toLowerCase","endpoint","URL","parse","urlEmbedsCredentials","username","password","mcpPolicy","api","deniedFlags","validate","length","build","codemod","debug","deploy","dev","doctor","exec","init","install","learn","login","logout","manage","source","new","preview","undeploy","versions","whoami"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/exports/invokeSanityCli/commandPolicies/mcpPolicy.ts"],"sourcesContent":["import {\n allow,\n type CommandPolicySet,\n conditionalDenyFlags,\n conditionalPolicy,\n deny,\n} from '@sanity/cli-core/commandPolicy'\n\nimport {isRemoteAssetSource} from '../../../util/isRemoteAssetSource.js'\n\nfunction apiValidator({\n args,\n flags,\n}: {\n args: Readonly<Record<string, unknown>>\n flags: Readonly<Record<string, unknown>>\n}): boolean {\n const fields: unknown[] = Array.isArray(flags.field) ? flags.field : []\n\n const fieldReadsFromHost = fields.some((field) => {\n if (typeof field !== 'string') return false\n const separatorIndex = field.indexOf('=')\n return separatorIndex > 0 && field[separatorIndex + 1] === '@'\n })\n if (fieldReadsFromHost) return false\n\n const headers: unknown[] = Array.isArray(flags.header) ? flags.header : []\n\n const headerOverridesAuthentication = headers.some((header) => {\n if (typeof header !== 'string') return false\n const separatorIndex = header.indexOf(':')\n if (separatorIndex <= 0) return false\n\n const name = header.slice(0, separatorIndex).trim().toLowerCase()\n return name === 'authorization' || name === 'cookie'\n })\n\n if (headerOverridesAuthentication) return false\n\n const endpoint = typeof args.endpoint === 'string' ? URL.parse(args.endpoint) : null\n const urlEmbedsCredentials =\n endpoint !== null && (endpoint.username !== '' || endpoint.password !== '')\n\n return !urlEmbedsCredentials\n}\n\n/**\n * MCP programmatic mode disables local project/config discovery (see the CLI\n * execution context). Missing project or dataset values may therefore produce\n * a usage error, but cannot cause local filesystem access. Destructive remote\n * operations are allowed and do not by themselves make a command unsafe.\n *\n * Every command this package contributes must have exactly one policy here:\n * - allow: every valid invocation is safe\n * - conditional: safety depends on parsed arguments or flags\n * - deny: no invocation is safe\n *\n * Commands contributed by plugins are not listed here. Each plugin declares\n * policies for its own commands (see `PluginInvocationPolicies` in\n * `@sanity/cli-core/commandPolicy`).\n */\nexport const mcpPolicy: CommandPolicySet = {\n // Special exception, this can be very dangerous but is also super useful\n // to expose. Refuse authentication overrides and host input channels:\n // `--token`, Authorization, and Cookie headers replace the MCP user's authentication,\n // URL-embedded credentials replace it with Basic authentication,\n // `--input` reads the request body from the host's filesystem or stdin, and\n // `-F key=@<file>` / `-F key=@-` field values do the same.\n api: conditionalPolicy({\n deniedFlags: ['input', 'token'],\n validate: apiValidator,\n }),\n\n // --file reads from the machine running the command and must only run locally.\n 'assets:upload': conditionalPolicy({\n deniedFlags: ['content-type', 'file'],\n validate: ({flags}) => typeof flags['from-url'] === 'string' && flags['from-url'].length > 0,\n }),\n\n 'backups:disable': allow,\n // Writes a downloaded backup to the local filesystem.\n 'backups:download': deny,\n 'backups:enable': allow,\n 'backups:list': allow,\n\n // Requires a local Studio project and writes build output to disk.\n build: deny,\n\n // Reads and rewrites local source code.\n codemod: deny,\n\n // --watch polls a job with no deadline; a stuck job would hang the MCP tool\n // call indefinitely. Non-watch invocations are single remote requests.\n 'context:build': conditionalDenyFlags('watch'),\n 'context:create': allow,\n 'context:delete': allow,\n 'context:entries:get': allow,\n 'context:entries:list': allow,\n // See context:build — --watch has no deadline and would hang the MCP tool call.\n 'context:entries:rebuild': conditionalDenyFlags('watch'),\n 'context:get': allow,\n // --file reads the import payload from the local filesystem; text, URL and\n // dataset imports are remote-only.\n 'context:imports:create': conditionalDenyFlags('file'),\n 'context:imports:delete': allow,\n 'context:imports:download': allow,\n 'context:imports:get': allow,\n 'context:imports:list': allow,\n // See context:build — --watch has no deadline and would hang the MCP tool call.\n 'context:issues:apply': conditionalDenyFlags('watch'),\n 'context:issues:dismiss': allow,\n 'context:issues:get': allow,\n 'context:issues:list': allow,\n 'context:issues:reopen': allow,\n // See context:build — --watch has no deadline and would hang the MCP tool call.\n 'context:issues:resolve': conditionalDenyFlags('watch'),\n // See context:build — --watch has no deadline and would hang the MCP tool call.\n 'context:jobs:get': conditionalDenyFlags('watch'),\n 'context:list': allow,\n 'context:mcp:create': allow,\n 'context:mcp:delete': allow,\n 'context:mcp:get': allow,\n 'context:mcp:list': allow,\n 'context:mcp:status': allow,\n 'context:mcp:update': allow,\n 'context:query': allow,\n 'context:refresh': allow,\n 'context:update': allow,\n\n 'cors:add': allow,\n 'cors:delete': allow,\n 'cors:list': allow,\n\n 'datasets:alias:create': allow,\n 'datasets:alias:delete': allow,\n 'datasets:alias:link': allow,\n 'datasets:alias:unlink': allow,\n 'datasets:copy': allow,\n 'datasets:create': allow,\n 'datasets:delete': allow,\n 'datasets:embeddings:disable': allow,\n 'datasets:embeddings:enable': allow,\n 'datasets:embeddings:status': allow,\n // Writes dataset contents and assets to the local filesystem.\n 'datasets:export': deny,\n // Reads import data from the local filesystem and may replace documents.\n 'datasets:import': deny,\n 'datasets:list': allow,\n 'datasets:visibility:get': allow,\n 'datasets:visibility:set': allow,\n\n // Inspects local project files and can print authentication secrets.\n debug: deny,\n\n // Reads, builds, and deploys a local Studio project.\n deploy: deny,\n\n // Loads a local Studio project and starts a development server.\n dev: deny,\n\n // Opens a browser on the machine running the MCP server.\n 'docs:browse': deny,\n // --web opens a browser on the machine running the MCP server.\n 'docs:read': conditionalDenyFlags('web'),\n 'docs:search': allow,\n\n // Reads and executes local project configuration for diagnostics.\n doctor: deny,\n\n // Reads document input from disk or launches a local editor.\n 'documents:create': deny,\n 'documents:delete': allow,\n 'documents:get': allow,\n 'documents:query': allow,\n // Loads a local Studio schema to validate documents.\n 'documents:validate': deny,\n\n // Executes arbitrary code in the local Studio context.\n exec: deny,\n\n // Loads a local schema and deploys a GraphQL API.\n 'graphql:deploy': deny,\n 'graphql:list': allow,\n // --api loads GraphQL definitions from the local project; explicit project/dataset flags are safe.\n 'graphql:undeploy': conditionalDenyFlags('api'),\n\n 'hooks:attempt': allow,\n 'hooks:create': allow,\n 'hooks:delete': allow,\n 'hooks:list': allow,\n 'hooks:logs': allow,\n\n // Creates or modifies a local project and may install dependencies.\n init: deny,\n\n // Installs packages into the local project.\n install: deny,\n\n // Opens a browser on the machine running the MCP server.\n learn: deny,\n\n // Performs an authentication flow.\n login: deny,\n\n // Performs an authentication operation and clears local credentials.\n logout: deny,\n\n // Reads local project configuration and opens a browser.\n manage: deny,\n\n // Loads local Studio configuration and writes manifest files.\n 'manifest:extract': deny,\n\n // Reads and writes local MCP client configuration.\n 'mcp:configure': deny,\n\n // Writes an aspect definition to the local filesystem.\n 'media:create-aspect': deny,\n 'media:delete-aspect': allow,\n // Reads a local aspect definition before deploying it.\n 'media:deploy-aspect': deny,\n // Writes media assets to the local filesystem.\n 'media:export': deny,\n // A directory or archive source reads media assets from the local\n // filesystem. A URL source does not: Sanity fetches the asset itself, so the\n // only local input is the URL. `--replace-aspects` is meaningless for a URL\n // source (the command rejects the combination), so it is hidden here rather\n // than advertised as usable surface.\n 'media:import': conditionalPolicy({\n deniedFlags: ['replace-aspects'],\n validate: ({args}) => typeof args.source === 'string' && isRemoteAssetSource(args.source),\n }),\n // media:pull-aspects and media:prune-aspect-data are hidden while the\n // config app is in beta, so they take the deny-by-default path like any\n // unlisted command. The exhaustiveness test forces explicit entries when\n // they are unhidden.\n\n // Creates migration source files in the local project.\n 'migrations:create': deny,\n // Reads and loads migration definitions from the local project.\n 'migrations:list': deny,\n // Executes local migration code that may perform arbitrary document mutations.\n 'migrations:run': deny,\n\n // Writes project setup values and scaffolds local applications.\n new: deny,\n\n // --web opens a browser on the machine running the MCP server.\n 'openapi:get': conditionalDenyFlags('web'),\n 'openapi:list': conditionalDenyFlags('web'),\n\n 'organizations:create': allow,\n 'organizations:delete': allow,\n 'organizations:get': allow,\n 'organizations:list': allow,\n 'organizations:update': allow,\n\n // Serves a local production build.\n preview: deny,\n\n 'projects:create': allow,\n 'projects:list': allow,\n // Reads locally stored claim URLs and robot tokens.\n 'projects:unclaimed': deny,\n\n // Loads the local Studio configuration to resolve the datasets containing each schema.\n 'schemas:delete': deny,\n // Loads local schema files before deploying them.\n 'schemas:deploy': deny,\n // Loads local Studio configuration and writes an extracted schema to disk.\n 'schemas:extract': deny,\n // Requires a local project and loads its schema configuration.\n 'schemas:list': deny,\n // Loads and executes a local Studio schema.\n 'schemas:validate': deny,\n\n // Installs skills into local editor configuration directories.\n 'skills:install': deny,\n\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:disable': deny,\n // Changes account telemetry preferences and mutates local cached configuration.\n 'telemetry:enable': deny,\n 'telemetry:status': allow,\n\n // Creates authentication credentials.\n 'tokens:create': deny,\n // Deletes authentication credentials.\n 'tokens:delete': deny,\n // Exposes authentication credential metadata.\n 'tokens:list': deny,\n // Replaces authentication credentials and exposes the new secret.\n 'tokens:rotate': deny,\n\n // Reads the local schema and source files and writes generated types to the project.\n 'typegen:generate': deny,\n\n // Loads local CLI and workbench configuration to identify the deployed Studio or application.\n undeploy: deny,\n\n // Grants a user access to a project.\n 'users:invite': deny,\n 'users:list': allow,\n\n // Reads the local project and installed package tree.\n versions: deny,\n\n // Reads the authenticated user from the API using the execution context token.\n whoami: allow,\n}\n"],"names":["allow","conditionalDenyFlags","conditionalPolicy","deny","isRemoteAssetSource","apiValidator","args","flags","fields","Array","isArray","field","fieldReadsFromHost","some","separatorIndex","indexOf","headers","header","headerOverridesAuthentication","name","slice","trim","toLowerCase","endpoint","URL","parse","urlEmbedsCredentials","username","password","mcpPolicy","api","deniedFlags","validate","length","build","codemod","debug","deploy","dev","doctor","exec","init","install","learn","login","logout","manage","source","new","preview","undeploy","versions","whoami"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { input } from '@sanity/cli-core/ux';
|
|
2
|
+
/**
|
|
3
|
+
* Prompt for a required line of text, trimmed
|
|
4
|
+
*/ export async function promptForText(message) {
|
|
5
|
+
const value = await input({
|
|
6
|
+
message,
|
|
7
|
+
validate: (input_)=>input_.trim().length > 0 || 'Value cannot be empty'
|
|
8
|
+
});
|
|
9
|
+
return value.trim();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=promptForText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/prompts/promptForText.ts"],"sourcesContent":["import {input} from '@sanity/cli-core/ux'\n\n/**\n * Prompt for a required line of text, trimmed\n */\nexport async 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":["input","promptForText","message","value","validate","input_","trim","length"],"mappings":"AAAA,SAAQA,KAAK,QAAO,sBAAqB;AAEzC;;CAEC,GACD,OAAO,eAAeC,cAAcC,OAAe;IACjD,MAAMC,QAAQ,MAAMH,MAAM;QACxBE;QACAE,UAAU,CAACC,SAAWA,OAAOC,IAAI,GAAGC,MAAM,GAAG,KAAK;IACpD;IACA,OAAOJ,MAAMG,IAAI;AACnB"}
|