@sanity/cli 8.22.1 → 8.23.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 (83) hide show
  1. package/dist/actions/context/watchJob.js +9 -3
  2. package/dist/actions/context/watchJob.js.map +1 -1
  3. package/dist/actions/deploy/blueprintManaged.js +59 -0
  4. package/dist/actions/deploy/blueprintManaged.js.map +1 -0
  5. package/dist/actions/deploy/deployApp.js +117 -1
  6. package/dist/actions/deploy/deployApp.js.map +1 -1
  7. package/dist/actions/deploy/deployRunner.js.map +1 -1
  8. package/dist/actions/deploy/deployStudio.js +6 -31
  9. package/dist/actions/deploy/deployStudio.js.map +1 -1
  10. package/dist/actions/exec/runScript.worker.js +6 -2
  11. package/dist/actions/exec/runScript.worker.js.map +1 -1
  12. package/dist/actions/init/bootstrapLocalTemplate.js +35 -11
  13. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  14. package/dist/actions/init/createMediaLibraryCliConfig.js +12 -0
  15. package/dist/actions/init/createMediaLibraryCliConfig.js.map +1 -0
  16. package/dist/actions/init/determineMediaLibraryTemplate.js +14 -0
  17. package/dist/actions/init/determineMediaLibraryTemplate.js.map +1 -0
  18. package/dist/actions/init/initAction.js +35 -6
  19. package/dist/actions/init/initAction.js.map +1 -1
  20. package/dist/actions/init/initApp.js +81 -6
  21. package/dist/actions/init/initApp.js.map +1 -1
  22. package/dist/actions/init/offerAspectPull.js +81 -0
  23. package/dist/actions/init/offerAspectPull.js.map +1 -0
  24. package/dist/actions/init/project/getProjectDetails.js +25 -2
  25. package/dist/actions/init/project/getProjectDetails.js.map +1 -1
  26. package/dist/actions/init/templates/index.js +3 -0
  27. package/dist/actions/init/templates/index.js.map +1 -1
  28. package/dist/actions/init/templates/mediaLibraryConfig.js +51 -0
  29. package/dist/actions/init/templates/mediaLibraryConfig.js.map +1 -0
  30. package/dist/actions/media/aspectName.js +8 -0
  31. package/dist/actions/media/aspectName.js.map +1 -0
  32. package/dist/actions/media/aspectSync/contract.js +163 -0
  33. package/dist/actions/media/aspectSync/contract.js.map +1 -0
  34. package/dist/actions/media/aspectSync/syncAspects.js +115 -0
  35. package/dist/actions/media/aspectSync/syncAspects.js.map +1 -0
  36. package/dist/actions/media/cliConfigFields.js +192 -0
  37. package/dist/actions/media/cliConfigFields.js.map +1 -0
  38. package/dist/actions/media/pullAspects.js +225 -0
  39. package/dist/actions/media/pullAspects.js.map +1 -0
  40. package/dist/actions/media/resolveMediaLibraryId.js +83 -0
  41. package/dist/actions/media/resolveMediaLibraryId.js.map +1 -0
  42. package/dist/commands/context/build.js +2 -2
  43. package/dist/commands/context/build.js.map +1 -1
  44. package/dist/commands/context/entries/get.js +83 -0
  45. package/dist/commands/context/entries/get.js.map +1 -0
  46. package/dist/commands/context/entries/list.js +82 -0
  47. package/dist/commands/context/entries/list.js.map +1 -0
  48. package/dist/commands/context/entries/rebuild.js +95 -0
  49. package/dist/commands/context/entries/rebuild.js.map +1 -0
  50. package/dist/commands/context/issues/apply.js +86 -0
  51. package/dist/commands/context/issues/apply.js.map +1 -0
  52. package/dist/commands/context/issues/dismiss.js +52 -0
  53. package/dist/commands/context/issues/dismiss.js.map +1 -0
  54. package/dist/commands/context/issues/get.js +105 -0
  55. package/dist/commands/context/issues/get.js.map +1 -0
  56. package/dist/commands/context/issues/list.js +128 -0
  57. package/dist/commands/context/issues/list.js.map +1 -0
  58. package/dist/commands/context/issues/reopen.js +53 -0
  59. package/dist/commands/context/issues/reopen.js.map +1 -0
  60. package/dist/commands/context/issues/resolve.js +137 -0
  61. package/dist/commands/context/issues/resolve.js.map +1 -0
  62. package/dist/commands/context/jobs/get.js +2 -2
  63. package/dist/commands/context/jobs/get.js.map +1 -1
  64. package/dist/commands/context/query.js +92 -0
  65. package/dist/commands/context/query.js.map +1 -0
  66. package/dist/commands/deploy.js +13 -0
  67. package/dist/commands/deploy.js.map +1 -1
  68. package/dist/commands/media/prune-aspect-data.js +170 -0
  69. package/dist/commands/media/prune-aspect-data.js.map +1 -0
  70. package/dist/commands/media/pull-aspects.js +309 -0
  71. package/dist/commands/media/pull-aspects.js.map +1 -0
  72. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +17 -0
  73. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  74. package/dist/services/context.js +96 -3
  75. package/dist/services/context.js.map +1 -1
  76. package/dist/services/mediaLibraries.js +175 -8
  77. package/dist/services/mediaLibraries.js.map +1 -1
  78. package/oclif.manifest.json +2930 -2241
  79. package/package.json +6 -5
  80. package/templates/media-library-config/README.md +52 -0
  81. package/templates/media-library-config/eslint.config.txt +52 -0
  82. package/templates/media-library-config/src/fields/caption.tsx +29 -0
  83. package/templates/media-library-config/src/fields/notes.tsx +54 -0
@@ -0,0 +1,225 @@
1
+ import { validateMediaLibraryAssetAspect } from '@sanity/schema/_internal';
2
+ import startCase from 'lodash-es/startCase.js';
3
+ import { VALID_ASPECT_NAME } from './aspectName.js';
4
+ /** Keys whose object members are schema definitions, printed wrapped in a definer call. */ const DEFINER_BY_PARENT_KEY = {
5
+ fields: 'defineField',
6
+ of: 'defineArrayMember'
7
+ };
8
+ const IDENTIFIER_KEY = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
9
+ /** Scalar arrays shorter than this print inline (e.g. `options.list`). */ const INLINE_ARRAY_MAX_WIDTH = 60;
10
+ /**
11
+ * Convert a page of stored aspect documents into field modules, one per field
12
+ * name. Two stored documents can resolve to the same name (a legacy document
13
+ * whose `_id` predates its `definition.name`), which would otherwise produce
14
+ * the same module twice — the document whose `_id` matches the name wins, the
15
+ * rest are reported as skipped. Shared by `sanity media pull-aspects` and the
16
+ * init-time pull offer.
17
+ *
18
+ * @internal
19
+ */ export function convertAspectDocuments(documents) {
20
+ const skipped = [];
21
+ // First pass: convert every stored document.
22
+ const candidates = [];
23
+ for (const doc of documents){
24
+ const outcome = aspectDocumentToFieldModule(doc);
25
+ if (outcome.status === 'skipped') {
26
+ skipped.push(outcome);
27
+ } else {
28
+ candidates.push({
29
+ module: outcome,
30
+ sourceId: String(doc._id)
31
+ });
32
+ }
33
+ }
34
+ // Second pass: pick one winner per name.
35
+ const byName = new Map();
36
+ for (const candidate of candidates){
37
+ const group = byName.get(candidate.module.name) ?? [];
38
+ group.push(candidate);
39
+ byName.set(candidate.module.name, group);
40
+ }
41
+ const modules = [];
42
+ for (const [name, group] of byName){
43
+ const winner = group.find((candidate)=>candidate.sourceId === name) ?? group[0];
44
+ modules.push(winner.module);
45
+ for (const loser of group){
46
+ if (loser === winner) continue;
47
+ skipped.push({
48
+ id: loser.sourceId,
49
+ reasons: [
50
+ `Also defines "${name}" — generated from "${winner.sourceId}" instead`
51
+ ],
52
+ status: 'skipped',
53
+ validationErrors: []
54
+ });
55
+ }
56
+ }
57
+ return {
58
+ modules,
59
+ skipped
60
+ };
61
+ }
62
+ /**
63
+ * Codegen one stored aspect document into a `src/fields/<name>.tsx` field
64
+ * module for a Media Library config app.
65
+ *
66
+ * Stored aspects are migration-ready by construction: `definition` is the
67
+ * JSON-serialized `defineField(...)` value with functions and component
68
+ * references already stripped, so generation is mechanical pretty-printing
69
+ * into a `defineField({...})` call (nested `fields`/`of` members wrapped in
70
+ * `defineField`/`defineArrayMember`, matching hand-authored style).
71
+ *
72
+ * Edge cases handled here, not silently:
73
+ *
74
+ * - `_id` vs `definition.name` mismatch: the module is generated under
75
+ * `definition.name` — the `aspects.<name>` key existing asset data lives
76
+ * under. Normalizing onto `_id` instead would silently orphan that data.
77
+ * The old document (keyed `_id`) is reported for manual deletion.
78
+ * - `assetType` has no equivalent in the config model; a document carrying it
79
+ * generates with a warning that the scoping is lost.
80
+ * - Definitions failing current schema validation are skipped with the
81
+ * validation errors, mirroring `sanity media deploy-aspect`.
82
+ *
83
+ * Pure (no I/O): the command decides where modules are written.
84
+ *
85
+ * @internal
86
+ */ export function aspectDocumentToFieldModule(doc) {
87
+ const { _id } = doc;
88
+ if (!isRecord(doc.definition)) {
89
+ return {
90
+ id: _id,
91
+ reasons: [
92
+ 'The stored document has no field definition object'
93
+ ],
94
+ status: 'skipped',
95
+ validationErrors: []
96
+ };
97
+ }
98
+ const definitionName = typeof doc.definition.name === 'string' ? doc.definition.name : undefined;
99
+ const name = definitionName ?? _id;
100
+ if (!VALID_ASPECT_NAME.test(name)) {
101
+ return {
102
+ id: _id,
103
+ reasons: [
104
+ `"${name}" is not a valid field name (${VALID_ASPECT_NAME}) — it becomes the module name and the aspects.<name> key on assets`
105
+ ],
106
+ status: 'skipped',
107
+ validationErrors: []
108
+ };
109
+ }
110
+ const warnings = [];
111
+ if (definitionName === undefined) {
112
+ warnings.push(`The stored definition has no name — using the document _id "${_id}"`);
113
+ } else if (definitionName !== _id) {
114
+ warnings.push(`Stored _id "${_id}" and definition name "${definitionName}" differ. Generated as ` + `"${definitionName}" — the aspects.<name> key existing asset data lives under; using ` + `"${_id}" would orphan that data. Deploying the config creates "${definitionName}" ` + `and deletes the old "${_id}" document.`);
115
+ }
116
+ if (doc.assetType !== undefined && doc.assetType !== null) {
117
+ warnings.push(`The stored document scopes the aspect by assetType (${JSON.stringify(doc.assetType)}), ` + `which has no equivalent in the config model — the generated field applies to all ` + `asset types, and syncing the config drops the scoping.`);
118
+ }
119
+ // Normalize the name in before validating, so a document that only carries
120
+ // its name as `_id` isn't rejected for the missing property.
121
+ const definition = definitionName ? doc.definition : {
122
+ name,
123
+ ...doc.definition
124
+ };
125
+ const [valid, validationErrors] = validateMediaLibraryAssetAspect(definition);
126
+ if (!valid) {
127
+ return {
128
+ id: _id,
129
+ reasons: [
130
+ 'The stored definition fails schema validation'
131
+ ],
132
+ status: 'skipped',
133
+ validationErrors
134
+ };
135
+ }
136
+ return {
137
+ // .tsx although the generated content has no JSX: field modules are
138
+ // expected to grow custom input components (the one thing the stored
139
+ // aspect could not carry), and a later rename would also mean fixing the
140
+ // `src:` entry in sanity.cli.ts. Matches the template's example modules.
141
+ filename: `${name}.tsx`,
142
+ name,
143
+ ...typeof doc.public === 'boolean' ? {
144
+ public: doc.public
145
+ } : {},
146
+ source: printFieldModule(definition),
147
+ status: 'generated',
148
+ title: typeof definition.title === 'string' ? definition.title : startCase(name),
149
+ warnings
150
+ };
151
+ }
152
+ /**
153
+ * The paste-ready `fields: [...]` entries for `sanity.cli.ts`, one line per
154
+ * generated module. When `writtenPaths` (module name to root-relative path)
155
+ * has an entry for a module, that path wins — the module may have replaced an
156
+ * existing file (e.g. a `.tsx` variant) rather than landing at the default
157
+ * `<srcDir>/<filename>` location.
158
+ *
159
+ * @internal
160
+ */ export function formatFieldEntries(modules, srcDir, writtenPaths) {
161
+ const dir = srcDir.replaceAll('\\', '/').replace(/\/+$/, '');
162
+ return modules.map((module)=>{
163
+ const src = writtenPaths?.get(module.name)?.replaceAll('\\', '/') ?? `${dir}/${module.filename}`;
164
+ const publicPart = module.public === undefined ? '' : `, public: ${module.public}`;
165
+ return `{name: '${module.name}', src: './${src}', title: ${quote(module.title)}${publicPart}},`;
166
+ }).join('\n');
167
+ }
168
+ function isRecord(value) {
169
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
170
+ }
171
+ function printFieldModule(definition) {
172
+ const state = {
173
+ usesDefineArrayMember: false
174
+ };
175
+ const literal = printObject(definition, '', state);
176
+ const imports = state.usesDefineArrayMember ? 'defineArrayMember, defineField' : 'defineField';
177
+ return `import {${imports}} from 'sanity'\n\nexport default defineField(${literal})\n`;
178
+ }
179
+ function quote(value) {
180
+ const escaped = value.replaceAll('\\', '\\\\').replaceAll("'", String.raw`\'`).replaceAll('\n', String.raw`\n`).replaceAll('\r', String.raw`\r`).replaceAll('\t', String.raw`\t`);
181
+ return `'${escaped}'`;
182
+ }
183
+ function printKey(key) {
184
+ return IDENTIFIER_KEY.test(key) ? key : quote(key);
185
+ }
186
+ function printValue(value, indent, parentKey, state) {
187
+ if (value === null) return 'null';
188
+ if (typeof value === 'string') return quote(value);
189
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value);
190
+ if (Array.isArray(value)) return printArray(value, indent, parentKey, state);
191
+ if (isRecord(value)) return printObject(value, indent, state);
192
+ // Stored definitions are JSON documents; anything else cannot occur.
193
+ throw new TypeError(`Cannot print value of type ${typeof value}`);
194
+ }
195
+ function printArray(items, indent, parentKey, state) {
196
+ if (items.length === 0) return '[]';
197
+ const allScalar = items.every((item)=>item === null || [
198
+ 'boolean',
199
+ 'number',
200
+ 'string'
201
+ ].includes(typeof item));
202
+ if (allScalar) {
203
+ const inline = `[${items.map((item)=>printValue(item, indent, null, state)).join(', ')}]`;
204
+ if (inline.length <= INLINE_ARRAY_MAX_WIDTH) return inline;
205
+ }
206
+ const definer = parentKey === null ? undefined : DEFINER_BY_PARENT_KEY[parentKey];
207
+ const innerIndent = `${indent} `;
208
+ const lines = items.map((item)=>{
209
+ if (definer !== undefined && isRecord(item)) {
210
+ if (definer === 'defineArrayMember') state.usesDefineArrayMember = true;
211
+ return `${innerIndent}${definer}(${printObject(item, innerIndent, state)}),`;
212
+ }
213
+ return `${innerIndent}${printValue(item, innerIndent, null, state)},`;
214
+ });
215
+ return `[\n${lines.join('\n')}\n${indent}]`;
216
+ }
217
+ function printObject(obj, indent, state) {
218
+ const entries = Object.entries(obj).filter(([, value])=>value !== undefined);
219
+ if (entries.length === 0) return '{}';
220
+ const innerIndent = `${indent} `;
221
+ const lines = entries.map(([key, value])=>`${innerIndent}${printKey(key)}: ${printValue(value, innerIndent, key, state)},`);
222
+ return `{\n${lines.join('\n')}\n${indent}}`;
223
+ }
224
+
225
+ //# sourceMappingURL=pullAspects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/media/pullAspects.ts"],"sourcesContent":["import {validateMediaLibraryAssetAspect} from '@sanity/schema/_internal'\nimport {type SchemaValidationProblem} from '@sanity/types'\nimport startCase from 'lodash-es/startCase.js'\n\nimport {type StoredAspectDocument} from '../../services/mediaLibraries.js'\nimport {VALID_ASPECT_NAME} from './aspectName.js'\n\n/** Keys whose object members are schema definitions, printed wrapped in a definer call. */\nconst DEFINER_BY_PARENT_KEY: Record<string, string> = {\n fields: 'defineField',\n of: 'defineArrayMember',\n}\n\nconst IDENTIFIER_KEY = /^[A-Za-z_$][A-Za-z0-9_$]*$/\n\n/** Scalar arrays shorter than this print inline (e.g. `options.list`). */\nconst INLINE_ARRAY_MAX_WIDTH = 60\n\n/**\n * The stored `sanity.asset.aspect` document shape this migration reads.\n * Deliberately loose: documents may predate the config model (authored via\n * `sanity media deploy-aspect` or by hand) and carry fields the model has no\n * equivalent for.\n */\nexport type PullableAspectDocument = StoredAspectDocument\n\nexport interface GeneratedFieldModule {\n filename: string\n /** The `aspects.<name>` data key — module filename and config entry name. */\n name: string\n source: string\n status: 'generated'\n title: string\n warnings: string[]\n\n public?: boolean\n}\n\nexport interface SkippedAspect {\n id: string\n reasons: string[]\n status: 'skipped'\n validationErrors: SchemaValidationProblem[][]\n}\n\nexport type PullAspectOutcome = GeneratedFieldModule | SkippedAspect\n\n/**\n * Convert a page of stored aspect documents into field modules, one per field\n * name. Two stored documents can resolve to the same name (a legacy document\n * whose `_id` predates its `definition.name`), which would otherwise produce\n * the same module twice — the document whose `_id` matches the name wins, the\n * rest are reported as skipped. Shared by `sanity media pull-aspects` and the\n * init-time pull offer.\n *\n * @internal\n */\nexport function convertAspectDocuments(documents: PullableAspectDocument[]): {\n modules: GeneratedFieldModule[]\n skipped: SkippedAspect[]\n} {\n const skipped: SkippedAspect[] = []\n\n // First pass: convert every stored document.\n const candidates: Array<{module: GeneratedFieldModule; sourceId: string}> = []\n for (const doc of documents) {\n const outcome = aspectDocumentToFieldModule(doc)\n if (outcome.status === 'skipped') {\n skipped.push(outcome)\n } else {\n candidates.push({module: outcome, sourceId: String(doc._id)})\n }\n }\n\n // Second pass: pick one winner per name.\n const byName = new Map<string, Array<{module: GeneratedFieldModule; sourceId: string}>>()\n for (const candidate of candidates) {\n const group = byName.get(candidate.module.name) ?? []\n group.push(candidate)\n byName.set(candidate.module.name, group)\n }\n const modules: GeneratedFieldModule[] = []\n for (const [name, group] of byName) {\n const winner = group.find((candidate) => candidate.sourceId === name) ?? group[0]\n modules.push(winner.module)\n for (const loser of group) {\n if (loser === winner) continue\n skipped.push({\n id: loser.sourceId,\n reasons: [`Also defines \"${name}\" — generated from \"${winner.sourceId}\" instead`],\n status: 'skipped',\n validationErrors: [],\n })\n }\n }\n\n return {modules, skipped}\n}\n\n/**\n * Codegen one stored aspect document into a `src/fields/<name>.tsx` field\n * module for a Media Library config app.\n *\n * Stored aspects are migration-ready by construction: `definition` is the\n * JSON-serialized `defineField(...)` value with functions and component\n * references already stripped, so generation is mechanical pretty-printing\n * into a `defineField({...})` call (nested `fields`/`of` members wrapped in\n * `defineField`/`defineArrayMember`, matching hand-authored style).\n *\n * Edge cases handled here, not silently:\n *\n * - `_id` vs `definition.name` mismatch: the module is generated under\n * `definition.name` — the `aspects.<name>` key existing asset data lives\n * under. Normalizing onto `_id` instead would silently orphan that data.\n * The old document (keyed `_id`) is reported for manual deletion.\n * - `assetType` has no equivalent in the config model; a document carrying it\n * generates with a warning that the scoping is lost.\n * - Definitions failing current schema validation are skipped with the\n * validation errors, mirroring `sanity media deploy-aspect`.\n *\n * Pure (no I/O): the command decides where modules are written.\n *\n * @internal\n */\nexport function aspectDocumentToFieldModule(doc: PullableAspectDocument): PullAspectOutcome {\n const {_id} = doc\n\n if (!isRecord(doc.definition)) {\n return {\n id: _id,\n reasons: ['The stored document has no field definition object'],\n status: 'skipped',\n validationErrors: [],\n }\n }\n\n const definitionName = typeof doc.definition.name === 'string' ? doc.definition.name : undefined\n const name = definitionName ?? _id\n\n if (!VALID_ASPECT_NAME.test(name)) {\n return {\n id: _id,\n reasons: [\n `\"${name}\" is not a valid field name (${VALID_ASPECT_NAME}) — it becomes the module name and the aspects.<name> key on assets`,\n ],\n status: 'skipped',\n validationErrors: [],\n }\n }\n\n const warnings: string[] = []\n\n if (definitionName === undefined) {\n warnings.push(`The stored definition has no name — using the document _id \"${_id}\"`)\n } else if (definitionName !== _id) {\n warnings.push(\n `Stored _id \"${_id}\" and definition name \"${definitionName}\" differ. Generated as ` +\n `\"${definitionName}\" — the aspects.<name> key existing asset data lives under; using ` +\n `\"${_id}\" would orphan that data. Deploying the config creates \"${definitionName}\" ` +\n `and deletes the old \"${_id}\" document.`,\n )\n }\n\n if (doc.assetType !== undefined && doc.assetType !== null) {\n warnings.push(\n `The stored document scopes the aspect by assetType (${JSON.stringify(doc.assetType)}), ` +\n `which has no equivalent in the config model — the generated field applies to all ` +\n `asset types, and syncing the config drops the scoping.`,\n )\n }\n\n // Normalize the name in before validating, so a document that only carries\n // its name as `_id` isn't rejected for the missing property.\n const definition: Record<string, unknown> = definitionName\n ? doc.definition\n : {name, ...doc.definition}\n\n const [valid, validationErrors] = validateMediaLibraryAssetAspect(definition)\n if (!valid) {\n return {\n id: _id,\n reasons: ['The stored definition fails schema validation'],\n status: 'skipped',\n validationErrors,\n }\n }\n\n return {\n // .tsx although the generated content has no JSX: field modules are\n // expected to grow custom input components (the one thing the stored\n // aspect could not carry), and a later rename would also mean fixing the\n // `src:` entry in sanity.cli.ts. Matches the template's example modules.\n filename: `${name}.tsx`,\n name,\n ...(typeof doc.public === 'boolean' ? {public: doc.public} : {}),\n source: printFieldModule(definition),\n status: 'generated',\n title: typeof definition.title === 'string' ? definition.title : startCase(name),\n warnings,\n }\n}\n\n/**\n * The paste-ready `fields: [...]` entries for `sanity.cli.ts`, one line per\n * generated module. When `writtenPaths` (module name to root-relative path)\n * has an entry for a module, that path wins — the module may have replaced an\n * existing file (e.g. a `.tsx` variant) rather than landing at the default\n * `<srcDir>/<filename>` location.\n *\n * @internal\n */\nexport function formatFieldEntries(\n modules: GeneratedFieldModule[],\n srcDir: string,\n writtenPaths?: Map<string, string>,\n): string {\n const dir = srcDir.replaceAll('\\\\', '/').replace(/\\/+$/, '')\n return modules\n .map((module) => {\n const src =\n writtenPaths?.get(module.name)?.replaceAll('\\\\', '/') ?? `${dir}/${module.filename}`\n const publicPart = module.public === undefined ? '' : `, public: ${module.public}`\n return `{name: '${module.name}', src: './${src}', title: ${quote(module.title)}${publicPart}},`\n })\n .join('\\n')\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\ninterface PrinterState {\n usesDefineArrayMember: boolean\n}\n\nfunction printFieldModule(definition: Record<string, unknown>): string {\n const state: PrinterState = {usesDefineArrayMember: false}\n const literal = printObject(definition, '', state)\n const imports = state.usesDefineArrayMember ? 'defineArrayMember, defineField' : 'defineField'\n\n return `import {${imports}} from 'sanity'\\n\\nexport default defineField(${literal})\\n`\n}\n\nfunction quote(value: string): string {\n const escaped = value\n .replaceAll('\\\\', '\\\\\\\\')\n .replaceAll(\"'\", String.raw`\\'`)\n .replaceAll('\\n', String.raw`\\n`)\n .replaceAll('\\r', String.raw`\\r`)\n .replaceAll('\\t', String.raw`\\t`)\n return `'${escaped}'`\n}\n\nfunction printKey(key: string): string {\n return IDENTIFIER_KEY.test(key) ? key : quote(key)\n}\n\nfunction printValue(\n value: unknown,\n indent: string,\n parentKey: string | null,\n state: PrinterState,\n): string {\n if (value === null) return 'null'\n if (typeof value === 'string') return quote(value)\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n if (Array.isArray(value)) return printArray(value, indent, parentKey, state)\n if (isRecord(value)) return printObject(value, indent, state)\n // Stored definitions are JSON documents; anything else cannot occur.\n throw new TypeError(`Cannot print value of type ${typeof value}`)\n}\n\nfunction printArray(\n items: unknown[],\n indent: string,\n parentKey: string | null,\n state: PrinterState,\n): string {\n if (items.length === 0) return '[]'\n\n const allScalar = items.every(\n (item) => item === null || ['boolean', 'number', 'string'].includes(typeof item),\n )\n if (allScalar) {\n const inline = `[${items.map((item) => printValue(item, indent, null, state)).join(', ')}]`\n if (inline.length <= INLINE_ARRAY_MAX_WIDTH) return inline\n }\n\n const definer = parentKey === null ? undefined : DEFINER_BY_PARENT_KEY[parentKey]\n const innerIndent = `${indent} `\n const lines = items.map((item) => {\n if (definer !== undefined && isRecord(item)) {\n if (definer === 'defineArrayMember') state.usesDefineArrayMember = true\n return `${innerIndent}${definer}(${printObject(item, innerIndent, state)}),`\n }\n return `${innerIndent}${printValue(item, innerIndent, null, state)},`\n })\n return `[\\n${lines.join('\\n')}\\n${indent}]`\n}\n\nfunction printObject(obj: Record<string, unknown>, indent: string, state: PrinterState): string {\n const entries = Object.entries(obj).filter(([, value]) => value !== undefined)\n if (entries.length === 0) return '{}'\n\n const innerIndent = `${indent} `\n const lines = entries.map(\n ([key, value]) =>\n `${innerIndent}${printKey(key)}: ${printValue(value, innerIndent, key, state)},`,\n )\n return `{\\n${lines.join('\\n')}\\n${indent}}`\n}\n"],"names":["validateMediaLibraryAssetAspect","startCase","VALID_ASPECT_NAME","DEFINER_BY_PARENT_KEY","fields","of","IDENTIFIER_KEY","INLINE_ARRAY_MAX_WIDTH","convertAspectDocuments","documents","skipped","candidates","doc","outcome","aspectDocumentToFieldModule","status","push","module","sourceId","String","_id","byName","Map","candidate","group","get","name","set","modules","winner","find","loser","id","reasons","validationErrors","isRecord","definition","definitionName","undefined","test","warnings","assetType","JSON","stringify","valid","filename","public","source","printFieldModule","title","formatFieldEntries","srcDir","writtenPaths","dir","replaceAll","replace","map","src","publicPart","quote","join","value","Array","isArray","state","usesDefineArrayMember","literal","printObject","imports","escaped","raw","printKey","key","printValue","indent","parentKey","printArray","TypeError","items","length","allScalar","every","item","includes","inline","definer","innerIndent","lines","obj","entries","Object","filter"],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { CLIError } from '@oclif/core/errors';
2
+ import { exitCodes } from '@sanity/cli-core';
3
+ import { promptForMediaLibrary } from '../../prompts/promptForMediaLibrary.js';
4
+ import { getMediaLibrariesForOrganization } from '../../services/mediaLibraries.js';
5
+ /** @see MediaLibraryResolution */ export async function resolveMediaLibrary(options) {
6
+ const { mediaLibraryIdFlag, organizationId } = options;
7
+ const libraries = await getMediaLibrariesForOrganization(organizationId);
8
+ const libraryIds = libraries.map((library)=>library.id);
9
+ if (mediaLibraryIdFlag) {
10
+ if (!libraryIds.includes(mediaLibraryIdFlag)) {
11
+ return {
12
+ message: `Media library ${mediaLibraryIdFlag} is not an active library of organization ` + `${organizationId} (found: ${libraryIds.join(', ') || 'none'})`,
13
+ solution: 'Pass --media-library-id with one of the active library ids',
14
+ type: 'invalid-flag'
15
+ };
16
+ }
17
+ return {
18
+ mediaLibraryId: mediaLibraryIdFlag,
19
+ type: 'resolved'
20
+ };
21
+ }
22
+ if (libraries.length === 0) {
23
+ return {
24
+ message: `Organization ${organizationId} has no active media library`,
25
+ solution: 'Install the Media Library for the organization first',
26
+ type: 'none-active'
27
+ };
28
+ }
29
+ if (libraries.length > 1) {
30
+ return {
31
+ libraries,
32
+ message: `Organization ${organizationId} has ${libraries.length} active media libraries ` + `(${libraryIds.join(', ')})`,
33
+ solution: 'Pass --media-library-id with the library this config belongs to',
34
+ type: 'ambiguous'
35
+ };
36
+ }
37
+ return {
38
+ mediaLibraryId: libraries[0].id,
39
+ type: 'resolved'
40
+ };
41
+ }
42
+ /**
43
+ * Command-facing resolution: ambiguity prompts when interactive (Ctrl+C there
44
+ * raises `ExitPromptError`, which callers must let propagate to
45
+ * `SanityCommand.catch`); misuse — a bad flag value, a missing required flag
46
+ * in unattended mode — exits with the usage code. No active library is an
47
+ * environment problem, not misuse, so it keeps the runtime code.
48
+ */ export async function resolveMediaLibraryId(options) {
49
+ const { mediaLibraryIdFlag, organizationId, unattended } = options;
50
+ const resolution = await resolveMediaLibrary({
51
+ mediaLibraryIdFlag,
52
+ organizationId
53
+ });
54
+ switch(resolution.type){
55
+ case 'ambiguous':
56
+ {
57
+ if (!unattended) return promptForMediaLibrary({
58
+ mediaLibraries: resolution.libraries
59
+ });
60
+ throw new CLIError(`${resolution.message}. ${resolution.solution}.`, {
61
+ exit: exitCodes.USAGE_ERROR
62
+ });
63
+ }
64
+ case 'invalid-flag':
65
+ {
66
+ throw new CLIError(`${resolution.message}. ${resolution.solution}.`, {
67
+ exit: exitCodes.USAGE_ERROR
68
+ });
69
+ }
70
+ case 'none-active':
71
+ {
72
+ throw new CLIError(`${resolution.message}. ${resolution.solution}.`, {
73
+ exit: exitCodes.RUNTIME_ERROR
74
+ });
75
+ }
76
+ default:
77
+ {
78
+ return resolution.mediaLibraryId;
79
+ }
80
+ }
81
+ }
82
+
83
+ //# sourceMappingURL=resolveMediaLibraryId.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/media/resolveMediaLibraryId.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\n\nimport {promptForMediaLibrary} from '../../prompts/promptForMediaLibrary.js'\nimport {getMediaLibrariesForOrganization, type MediaLibrary} from '../../services/mediaLibraries.js'\n\n/**\n * The target-library resolution config-app media operations share: the flag\n * wins (validated against the organization's active libraries), a single\n * active library is unambiguous, anything else is a verdict the caller turns\n * into its own failure shape — a prompt, a usage error, or a deploy check.\n */\nexport type MediaLibraryResolution =\n | {\n /** The active libraries a prompt would offer. */\n libraries: MediaLibrary[]\n message: string\n solution: string\n type: 'ambiguous'\n }\n | {mediaLibraryId: string; type: 'resolved'}\n | {message: string; solution: string; type: 'invalid-flag'}\n | {message: string; solution: string; type: 'none-active'}\n\n/** @see MediaLibraryResolution */\nexport async function resolveMediaLibrary(options: {\n mediaLibraryIdFlag: string | undefined\n organizationId: string\n}): Promise<MediaLibraryResolution> {\n const {mediaLibraryIdFlag, organizationId} = options\n const libraries = await getMediaLibrariesForOrganization(organizationId)\n const libraryIds = libraries.map((library) => library.id)\n\n if (mediaLibraryIdFlag) {\n if (!libraryIds.includes(mediaLibraryIdFlag)) {\n return {\n message:\n `Media library ${mediaLibraryIdFlag} is not an active library of organization ` +\n `${organizationId} (found: ${libraryIds.join(', ') || 'none'})`,\n solution: 'Pass --media-library-id with one of the active library ids',\n type: 'invalid-flag',\n }\n }\n return {mediaLibraryId: mediaLibraryIdFlag, type: 'resolved'}\n }\n\n if (libraries.length === 0) {\n return {\n message: `Organization ${organizationId} has no active media library`,\n solution: 'Install the Media Library for the organization first',\n type: 'none-active',\n }\n }\n if (libraries.length > 1) {\n return {\n libraries,\n message:\n `Organization ${organizationId} has ${libraries.length} active media libraries ` +\n `(${libraryIds.join(', ')})`,\n solution: 'Pass --media-library-id with the library this config belongs to',\n type: 'ambiguous',\n }\n }\n return {mediaLibraryId: libraries[0].id, type: 'resolved'}\n}\n\n/**\n * Command-facing resolution: ambiguity prompts when interactive (Ctrl+C there\n * raises `ExitPromptError`, which callers must let propagate to\n * `SanityCommand.catch`); misuse — a bad flag value, a missing required flag\n * in unattended mode — exits with the usage code. No active library is an\n * environment problem, not misuse, so it keeps the runtime code.\n */\nexport async function resolveMediaLibraryId(options: {\n mediaLibraryIdFlag: string | undefined\n organizationId: string\n unattended: boolean\n}): Promise<string> {\n const {mediaLibraryIdFlag, organizationId, unattended} = options\n const resolution = await resolveMediaLibrary({mediaLibraryIdFlag, organizationId})\n\n switch (resolution.type) {\n case 'ambiguous': {\n if (!unattended) return promptForMediaLibrary({mediaLibraries: resolution.libraries})\n throw new CLIError(`${resolution.message}. ${resolution.solution}.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n case 'invalid-flag': {\n throw new CLIError(`${resolution.message}. ${resolution.solution}.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n case 'none-active': {\n throw new CLIError(`${resolution.message}. ${resolution.solution}.`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n default: {\n return resolution.mediaLibraryId\n }\n }\n}\n"],"names":["CLIError","exitCodes","promptForMediaLibrary","getMediaLibrariesForOrganization","resolveMediaLibrary","options","mediaLibraryIdFlag","organizationId","libraries","libraryIds","map","library","id","includes","message","join","solution","type","mediaLibraryId","length","resolveMediaLibraryId","unattended","resolution","mediaLibraries","exit","USAGE_ERROR","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,qBAAoB;AAC3C,SAAQC,SAAS,QAAO,mBAAkB;AAE1C,SAAQC,qBAAqB,QAAO,yCAAwC;AAC5E,SAAQC,gCAAgC,QAA0B,mCAAkC;AAoBpG,gCAAgC,GAChC,OAAO,eAAeC,oBAAoBC,OAGzC;IACC,MAAM,EAACC,kBAAkB,EAAEC,cAAc,EAAC,GAAGF;IAC7C,MAAMG,YAAY,MAAML,iCAAiCI;IACzD,MAAME,aAAaD,UAAUE,GAAG,CAAC,CAACC,UAAYA,QAAQC,EAAE;IAExD,IAAIN,oBAAoB;QACtB,IAAI,CAACG,WAAWI,QAAQ,CAACP,qBAAqB;YAC5C,OAAO;gBACLQ,SACE,CAAC,cAAc,EAAER,mBAAmB,0CAA0C,CAAC,GAC/E,GAAGC,eAAe,SAAS,EAAEE,WAAWM,IAAI,CAAC,SAAS,OAAO,CAAC,CAAC;gBACjEC,UAAU;gBACVC,MAAM;YACR;QACF;QACA,OAAO;YAACC,gBAAgBZ;YAAoBW,MAAM;QAAU;IAC9D;IAEA,IAAIT,UAAUW,MAAM,KAAK,GAAG;QAC1B,OAAO;YACLL,SAAS,CAAC,aAAa,EAAEP,eAAe,4BAA4B,CAAC;YACrES,UAAU;YACVC,MAAM;QACR;IACF;IACA,IAAIT,UAAUW,MAAM,GAAG,GAAG;QACxB,OAAO;YACLX;YACAM,SACE,CAAC,aAAa,EAAEP,eAAe,KAAK,EAAEC,UAAUW,MAAM,CAAC,wBAAwB,CAAC,GAChF,CAAC,CAAC,EAAEV,WAAWM,IAAI,CAAC,MAAM,CAAC,CAAC;YAC9BC,UAAU;YACVC,MAAM;QACR;IACF;IACA,OAAO;QAACC,gBAAgBV,SAAS,CAAC,EAAE,CAACI,EAAE;QAAEK,MAAM;IAAU;AAC3D;AAEA;;;;;;CAMC,GACD,OAAO,eAAeG,sBAAsBf,OAI3C;IACC,MAAM,EAACC,kBAAkB,EAAEC,cAAc,EAAEc,UAAU,EAAC,GAAGhB;IACzD,MAAMiB,aAAa,MAAMlB,oBAAoB;QAACE;QAAoBC;IAAc;IAEhF,OAAQe,WAAWL,IAAI;QACrB,KAAK;YAAa;gBAChB,IAAI,CAACI,YAAY,OAAOnB,sBAAsB;oBAACqB,gBAAgBD,WAAWd,SAAS;gBAAA;gBACnF,MAAM,IAAIR,SAAS,GAAGsB,WAAWR,OAAO,CAAC,EAAE,EAAEQ,WAAWN,QAAQ,CAAC,CAAC,CAAC,EAAE;oBACnEQ,MAAMvB,UAAUwB,WAAW;gBAC7B;YACF;QACA,KAAK;YAAgB;gBACnB,MAAM,IAAIzB,SAAS,GAAGsB,WAAWR,OAAO,CAAC,EAAE,EAAEQ,WAAWN,QAAQ,CAAC,CAAC,CAAC,EAAE;oBACnEQ,MAAMvB,UAAUwB,WAAW;gBAC7B;YACF;QACA,KAAK;YAAe;gBAClB,MAAM,IAAIzB,SAAS,GAAGsB,WAAWR,OAAO,CAAC,EAAE,EAAEQ,WAAWN,QAAQ,CAAC,CAAC,CAAC,EAAE;oBACnEQ,MAAMvB,UAAUyB,aAAa;gBAC/B;YACF;QACA;YAAS;gBACP,OAAOJ,WAAWJ,cAAc;YAClC;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 { spinner } from '@sanity/cli-core/ux';
5
5
  import { isHttpError } from '@sanity/client';
6
- import { watchJob } from '../../actions/context/watchJob.js';
6
+ import { formatJobFailure, watchJob } from '../../actions/context/watchJob.js';
7
7
  import { formatKeyValue } from '../../actions/debug/output.js';
8
8
  import { buildKnowledgeBase, cancelKnowledgeBaseBuild } from '../../services/context.js';
9
9
  const buildContextDebug = subdebug('context:build');
@@ -85,7 +85,7 @@ export class BuildKnowledgeBaseCommand extends SanityCommand {
85
85
  });
86
86
  }
87
87
  if (job.status !== 'succeeded') {
88
- this.error(`Build ${job.status}${job.error ? `: ${job.error}` : ''}`, {
88
+ this.error(formatJobFailure('Build', job), {
89
89
  exit: exitCodes.RUNTIME_ERROR
90
90
  });
91
91
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/context/build.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 {isHttpError} from '@sanity/client'\n\nimport {watchJob} from '../../actions/context/watchJob.js'\nimport {formatKeyValue} from '../../actions/debug/output.js'\nimport {buildKnowledgeBase, cancelKnowledgeBaseBuild} from '../../services/context.js'\n\nconst buildContextDebug = subdebug('context:build')\n\nexport class BuildKnowledgeBaseCommand extends SanityCommand<typeof BuildKnowledgeBaseCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'Build a knowledge base from its imported content'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'Start a build and return the job ID',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --watch',\n description: 'Start a build and wait for it to finish (non-zero exit on failure)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --cancel',\n description: 'Cancel the running build, if any',\n },\n ]\n\n static override flags = {\n cancel: Flags.boolean({\n default: false,\n description: 'Cancel the running build instead of starting one',\n exclusive: ['watch'],\n }),\n watch: Flags.boolean({\n default: false,\n description: 'Wait for the build to finish, exiting non-zero if it fails',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {cancel, watch} = this.flags\n\n if (cancel) {\n await this.cancelBuild(knowledgeBaseId)\n return\n }\n\n let jobId: string\n const spin = spinner('Starting build').start()\n try {\n const accepted = await buildKnowledgeBase(knowledgeBaseId)\n jobId = accepted.jobId\n spin.succeed('Build started')\n } catch (error) {\n spin.fail()\n buildContextDebug('Error starting build', 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 start build: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n this.log(formatKeyValue('Job ID', jobId))\n this.log(`Track it with: sanity context jobs get ${knowledgeBaseId} ${jobId}`)\n\n if (!watch) {\n return\n }\n\n let job\n try {\n job = await watchJob(knowledgeBaseId, jobId, {\n label: 'Building knowledge base',\n successText: 'Build succeeded',\n })\n } catch (error) {\n buildContextDebug('Error watching build job', error)\n this.error(`Failed to watch build job: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (job.status !== 'succeeded') {\n this.error(`Build ${job.status}${job.error ? `: ${job.error}` : ''}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async cancelBuild(knowledgeBaseId: string): Promise<void> {\n try {\n const {cancelled} = await cancelKnowledgeBaseBuild(knowledgeBaseId)\n this.log(cancelled ? 'Build cancelled' : 'No running build to cancel')\n } catch (error) {\n buildContextDebug('Error cancelling build', 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 cancel build: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","spinner","isHttpError","watchJob","formatKeyValue","buildKnowledgeBase","cancelKnowledgeBaseBuild","buildContextDebug","BuildKnowledgeBaseCommand","args","knowledgeBaseId","string","description","required","examples","command","flags","cancel","boolean","default","exclusive","watch","run","cancelBuild","jobId","spin","start","accepted","succeed","error","fail","statusCode","exit","RUNTIME_ERROR","log","job","label","successText","status","cancelled"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/commands/context/build.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 {isHttpError} from '@sanity/client'\n\nimport {formatJobFailure, watchJob} from '../../actions/context/watchJob.js'\nimport {formatKeyValue} from '../../actions/debug/output.js'\nimport {buildKnowledgeBase, cancelKnowledgeBaseBuild} from '../../services/context.js'\n\nconst buildContextDebug = subdebug('context:build')\n\nexport class BuildKnowledgeBaseCommand extends SanityCommand<typeof BuildKnowledgeBaseCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'Build a knowledge base from its imported content'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'Start a build and return the job ID',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --watch',\n description: 'Start a build and wait for it to finish (non-zero exit on failure)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --cancel',\n description: 'Cancel the running build, if any',\n },\n ]\n\n static override flags = {\n cancel: Flags.boolean({\n default: false,\n description: 'Cancel the running build instead of starting one',\n exclusive: ['watch'],\n }),\n watch: Flags.boolean({\n default: false,\n description: 'Wait for the build to finish, exiting non-zero if it fails',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {cancel, watch} = this.flags\n\n if (cancel) {\n await this.cancelBuild(knowledgeBaseId)\n return\n }\n\n let jobId: string\n const spin = spinner('Starting build').start()\n try {\n const accepted = await buildKnowledgeBase(knowledgeBaseId)\n jobId = accepted.jobId\n spin.succeed('Build started')\n } catch (error) {\n spin.fail()\n buildContextDebug('Error starting build', 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 start build: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n this.log(formatKeyValue('Job ID', jobId))\n this.log(`Track it with: sanity context jobs get ${knowledgeBaseId} ${jobId}`)\n\n if (!watch) {\n return\n }\n\n let job\n try {\n job = await watchJob(knowledgeBaseId, jobId, {\n label: 'Building knowledge base',\n successText: 'Build succeeded',\n })\n } catch (error) {\n buildContextDebug('Error watching build job', error)\n this.error(`Failed to watch build job: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (job.status !== 'succeeded') {\n this.error(formatJobFailure('Build', job), {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async cancelBuild(knowledgeBaseId: string): Promise<void> {\n try {\n const {cancelled} = await cancelKnowledgeBaseBuild(knowledgeBaseId)\n this.log(cancelled ? 'Build cancelled' : 'No running build to cancel')\n } catch (error) {\n buildContextDebug('Error cancelling build', 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 cancel build: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","spinner","isHttpError","formatJobFailure","watchJob","formatKeyValue","buildKnowledgeBase","cancelKnowledgeBaseBuild","buildContextDebug","BuildKnowledgeBaseCommand","args","knowledgeBaseId","string","description","required","examples","command","flags","cancel","boolean","default","exclusive","watch","run","cancelBuild","jobId","spin","start","accepted","succeed","error","fail","statusCode","exit","RUNTIME_ERROR","log","job","label","successText","status","cancelled"],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { Args } from '@oclif/core';
2
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
+ import { getErrorMessage } from '@sanity/cli-core/errors';
4
+ import { isHttpError } from '@sanity/client';
5
+ import { formatKeyValue } from '../../../actions/debug/output.js';
6
+ import { getEntry } from '../../../services/context.js';
7
+ const getEntryDebug = subdebug('context:entries:get');
8
+ export class GetEntryCommand extends SanityCommand {
9
+ static args = {
10
+ knowledgeBaseId: Args.string({
11
+ description: 'Knowledge base ID',
12
+ required: true
13
+ }),
14
+ path: Args.string({
15
+ description: 'Entry path, as listed by `sanity context entries list`',
16
+ required: true
17
+ })
18
+ };
19
+ static description = 'Get an entry and its content';
20
+ static enableJsonFlag = true;
21
+ static examples = [
22
+ {
23
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 billing/refunds',
24
+ description: 'Print an entry and its content'
25
+ },
26
+ {
27
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 billing/refunds --json',
28
+ description: 'Output the entry, including citations, as JSON'
29
+ }
30
+ ];
31
+ async run() {
32
+ const { knowledgeBaseId, path } = this.args;
33
+ const { json } = this.flags;
34
+ let entry;
35
+ try {
36
+ entry = await getEntry(knowledgeBaseId, path);
37
+ } catch (error) {
38
+ getEntryDebug('Error getting entry', error);
39
+ if (isHttpError(error) && error.statusCode === 404) {
40
+ this.error(`Knowledge base "${knowledgeBaseId}" not found`, {
41
+ exit: exitCodes.RUNTIME_ERROR
42
+ });
43
+ }
44
+ this.error(`Failed to get entry: ${getErrorMessage(error)}`, {
45
+ exit: exitCodes.RUNTIME_ERROR
46
+ });
47
+ }
48
+ if (!entry) {
49
+ this.error(`Entry "${path}" not found on knowledge base "${knowledgeBaseId}"`, {
50
+ exit: exitCodes.RUNTIME_ERROR
51
+ });
52
+ }
53
+ if (json) {
54
+ this.logJson(entry);
55
+ return;
56
+ }
57
+ const padTo = 9 // "Citations" and "Generated" are the longest keys
58
+ ;
59
+ this.log(formatKeyValue('Path', entry.path, {
60
+ padTo
61
+ }));
62
+ this.log(formatKeyValue('Title', entry.title, {
63
+ padTo
64
+ }));
65
+ this.log(formatKeyValue('Status', entry.status, {
66
+ padTo
67
+ }));
68
+ this.log(formatKeyValue('Scope', entry.tldr?.scope ?? '-', {
69
+ padTo
70
+ }));
71
+ this.log(formatKeyValue('Citations', String(entry.citations?.length ?? 0), {
72
+ padTo
73
+ }));
74
+ this.log(formatKeyValue('Generated', entry.generatedAt, {
75
+ padTo
76
+ }));
77
+ if (entry.body) {
78
+ this.log(`\n${entry.body}`);
79
+ }
80
+ }
81
+ }
82
+
83
+ //# sourceMappingURL=get.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/commands/context/entries/get.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {formatKeyValue} from '../../../actions/debug/output.js'\nimport {getEntry} from '../../../services/context.js'\n\nconst getEntryDebug = subdebug('context:entries:get')\n\nexport class GetEntryCommand extends SanityCommand<typeof GetEntryCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n path: Args.string({\n description: 'Entry path, as listed by `sanity context entries list`',\n required: true,\n }),\n }\n\n static override description = 'Get an entry and its content'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 billing/refunds',\n description: 'Print an entry and its content',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 billing/refunds --json',\n description: 'Output the entry, including citations, as JSON',\n },\n ]\n\n public async run(): Promise<void> {\n const {knowledgeBaseId, path} = this.args\n const {json} = this.flags\n\n let entry\n try {\n entry = await getEntry(knowledgeBaseId, path)\n } catch (error) {\n getEntryDebug('Error getting entry', 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 get entry: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (!entry) {\n this.error(`Entry \"${path}\" not found on knowledge base \"${knowledgeBaseId}\"`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (json) {\n this.logJson(entry)\n return\n }\n\n const padTo = 9 // \"Citations\" and \"Generated\" are the longest keys\n this.log(formatKeyValue('Path', entry.path, {padTo}))\n this.log(formatKeyValue('Title', entry.title, {padTo}))\n this.log(formatKeyValue('Status', entry.status, {padTo}))\n this.log(formatKeyValue('Scope', entry.tldr?.scope ?? '-', {padTo}))\n this.log(formatKeyValue('Citations', String(entry.citations?.length ?? 0), {padTo}))\n this.log(formatKeyValue('Generated', entry.generatedAt, {padTo}))\n\n if (entry.body) {\n this.log(`\\n${entry.body}`)\n }\n }\n}\n"],"names":["Args","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","formatKeyValue","getEntry","getEntryDebug","GetEntryCommand","args","knowledgeBaseId","string","description","required","path","enableJsonFlag","examples","command","run","json","flags","entry","error","statusCode","exit","RUNTIME_ERROR","logJson","padTo","log","title","status","tldr","scope","String","citations","length","generatedAt","body"],"mappings":"AAAA,SAAQA,IAAI,QAAO,cAAa;AAChC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,cAAc,QAAO,mCAAkC;AAC/D,SAAQC,QAAQ,QAAO,+BAA8B;AAErD,MAAMC,gBAAgBL,SAAS;AAE/B,OAAO,MAAMM,wBAAwBP;IACnC,OAAgBQ,OAAO;QACrBC,iBAAiBX,KAAKY,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;QACAC,MAAMf,KAAKY,MAAM,CAAC;YAChBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,+BAA8B;IAE5D,OAAgBG,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTL,aAAa;QACf;QACA;YACEK,SAAS;YACTL,aAAa;QACf;KACD,CAAA;IAED,MAAaM,MAAqB;QAChC,MAAM,EAACR,eAAe,EAAEI,IAAI,EAAC,GAAG,IAAI,CAACL,IAAI;QACzC,MAAM,EAACU,IAAI,EAAC,GAAG,IAAI,CAACC,KAAK;QAEzB,IAAIC;QACJ,IAAI;YACFA,QAAQ,MAAMf,SAASI,iBAAiBI;QAC1C,EAAE,OAAOQ,OAAO;YACdf,cAAc,uBAAuBe;YACrC,IAAIlB,YAAYkB,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CAAC,CAAC,gBAAgB,EAAEZ,gBAAgB,WAAW,CAAC,EAAE;oBAC1Dc,MAAMxB,UAAUyB,aAAa;gBAC/B;YACF;YACA,IAAI,CAACH,KAAK,CAAC,CAAC,qBAAqB,EAAEnB,gBAAgBmB,QAAQ,EAAE;gBAC3DE,MAAMxB,UAAUyB,aAAa;YAC/B;QACF;QAEA,IAAI,CAACJ,OAAO;YACV,IAAI,CAACC,KAAK,CAAC,CAAC,OAAO,EAAER,KAAK,+BAA+B,EAAEJ,gBAAgB,CAAC,CAAC,EAAE;gBAC7Ec,MAAMxB,UAAUyB,aAAa;YAC/B;QACF;QAEA,IAAIN,MAAM;YACR,IAAI,CAACO,OAAO,CAACL;YACb;QACF;QAEA,MAAMM,QAAQ,EAAE,mDAAmD;;QACnE,IAAI,CAACC,GAAG,CAACvB,eAAe,QAAQgB,MAAMP,IAAI,EAAE;YAACa;QAAK;QAClD,IAAI,CAACC,GAAG,CAACvB,eAAe,SAASgB,MAAMQ,KAAK,EAAE;YAACF;QAAK;QACpD,IAAI,CAACC,GAAG,CAACvB,eAAe,UAAUgB,MAAMS,MAAM,EAAE;YAACH;QAAK;QACtD,IAAI,CAACC,GAAG,CAACvB,eAAe,SAASgB,MAAMU,IAAI,EAAEC,SAAS,KAAK;YAACL;QAAK;QACjE,IAAI,CAACC,GAAG,CAACvB,eAAe,aAAa4B,OAAOZ,MAAMa,SAAS,EAAEC,UAAU,IAAI;YAACR;QAAK;QACjF,IAAI,CAACC,GAAG,CAACvB,eAAe,aAAagB,MAAMe,WAAW,EAAE;YAACT;QAAK;QAE9D,IAAIN,MAAMgB,IAAI,EAAE;YACd,IAAI,CAACT,GAAG,CAAC,CAAC,EAAE,EAAEP,MAAMgB,IAAI,EAAE;QAC5B;IACF;AACF"}
@@ -0,0 +1,82 @@
1
+ import { Args } from '@oclif/core';
2
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
+ import { getErrorMessage } from '@sanity/cli-core/errors';
4
+ import { isHttpError } from '@sanity/client';
5
+ import { listEntries } from '../../../services/context.js';
6
+ import { Table } from '../../../util/responsiveTable.js';
7
+ const listEntriesDebug = subdebug('context:entries:list');
8
+ export class ListEntriesCommand extends SanityCommand {
9
+ static args = {
10
+ knowledgeBaseId: Args.string({
11
+ description: 'Knowledge base ID',
12
+ required: true
13
+ })
14
+ };
15
+ static description = 'List the entries a knowledge base build produced';
16
+ static enableJsonFlag = true;
17
+ static examples = [
18
+ {
19
+ command: '<%= config.bin %> <%= command.id %> kb-abc123',
20
+ description: 'List all entries for a knowledge base'
21
+ },
22
+ {
23
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 --json',
24
+ description: 'Output entries as JSON'
25
+ }
26
+ ];
27
+ async run() {
28
+ const { knowledgeBaseId } = this.args;
29
+ const { json } = this.flags;
30
+ let entries;
31
+ try {
32
+ entries = await listEntries(knowledgeBaseId);
33
+ } catch (error) {
34
+ listEntriesDebug('Error listing entries', error);
35
+ if (isHttpError(error) && error.statusCode === 404) {
36
+ this.error(`Knowledge base "${knowledgeBaseId}" not found`, {
37
+ exit: exitCodes.RUNTIME_ERROR
38
+ });
39
+ }
40
+ this.error(`Failed to list entries: ${getErrorMessage(error)}`, {
41
+ exit: exitCodes.RUNTIME_ERROR
42
+ });
43
+ }
44
+ if (json) {
45
+ this.logJson(entries);
46
+ return;
47
+ }
48
+ if (entries.length === 0) {
49
+ this.log('No entries found');
50
+ return;
51
+ }
52
+ const table = new Table({
53
+ columns: [
54
+ {
55
+ alignment: 'left',
56
+ name: 'path',
57
+ title: 'Path'
58
+ },
59
+ {
60
+ alignment: 'left',
61
+ name: 'title',
62
+ title: 'Title'
63
+ },
64
+ {
65
+ alignment: 'left',
66
+ name: 'status',
67
+ title: 'Status'
68
+ }
69
+ ]
70
+ });
71
+ for (const { path, status, title } of entries){
72
+ table.addRow({
73
+ path,
74
+ status,
75
+ title
76
+ });
77
+ }
78
+ this.log(table.render());
79
+ }
80
+ }
81
+
82
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/commands/context/entries/list.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {listEntries} from '../../../services/context.js'\nimport {Table} from '../../../util/responsiveTable.js'\n\nconst listEntriesDebug = subdebug('context:entries:list')\n\nexport class ListEntriesCommand extends SanityCommand<typeof ListEntriesCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'List the entries a knowledge base build produced'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'List all entries for a knowledge base',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --json',\n description: 'Output entries as JSON',\n },\n ]\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {json} = this.flags\n\n let entries\n try {\n entries = await listEntries(knowledgeBaseId)\n } catch (error) {\n listEntriesDebug('Error listing entries', 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 entries: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (json) {\n this.logJson(entries)\n return\n }\n\n if (entries.length === 0) {\n this.log('No entries found')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'path', title: 'Path'},\n {alignment: 'left', name: 'title', title: 'Title'},\n {alignment: 'left', name: 'status', title: 'Status'},\n ],\n })\n\n for (const {path, status, title} of entries) {\n table.addRow({path, status, title})\n }\n\n this.log(table.render())\n }\n}\n"],"names":["Args","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","listEntries","Table","listEntriesDebug","ListEntriesCommand","args","knowledgeBaseId","string","description","required","enableJsonFlag","examples","command","run","json","flags","entries","error","statusCode","exit","RUNTIME_ERROR","logJson","length","log","table","columns","alignment","name","title","path","status","addRow","render"],"mappings":"AAAA,SAAQA,IAAI,QAAO,cAAa;AAChC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,WAAW,QAAO,+BAA8B;AACxD,SAAQC,KAAK,QAAO,mCAAkC;AAEtD,MAAMC,mBAAmBL,SAAS;AAElC,OAAO,MAAMM,2BAA2BP;IACtC,OAAgBQ,OAAO;QACrBC,iBAAiBX,KAAKY,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,mDAAkD;IAEhF,OAAgBE,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,MAAaK,MAAqB;QAChC,MAAM,EAACP,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QACnC,MAAM,EAACS,IAAI,EAAC,GAAG,IAAI,CAACC,KAAK;QAEzB,IAAIC;QACJ,IAAI;YACFA,UAAU,MAAMf,YAAYK;QAC9B,EAAE,OAAOW,OAAO;YACdd,iBAAiB,yBAAyBc;YAC1C,IAAIjB,YAAYiB,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CAAC,CAAC,gBAAgB,EAAEX,gBAAgB,WAAW,CAAC,EAAE;oBAC1Da,MAAMvB,UAAUwB,aAAa;gBAC/B;YACF;YACA,IAAI,CAACH,KAAK,CAAC,CAAC,wBAAwB,EAAElB,gBAAgBkB,QAAQ,EAAE;gBAC9DE,MAAMvB,UAAUwB,aAAa;YAC/B;QACF;QAEA,IAAIN,MAAM;YACR,IAAI,CAACO,OAAO,CAACL;YACb;QACF;QAEA,IAAIA,QAAQM,MAAM,KAAK,GAAG;YACxB,IAAI,CAACC,GAAG,CAAC;YACT;QACF;QAEA,MAAMC,QAAQ,IAAItB,MAAM;YACtBuB,SAAS;gBACP;oBAACC,WAAW;oBAAQC,MAAM;oBAAQC,OAAO;gBAAM;gBAC/C;oBAACF,WAAW;oBAAQC,MAAM;oBAASC,OAAO;gBAAO;gBACjD;oBAACF,WAAW;oBAAQC,MAAM;oBAAUC,OAAO;gBAAQ;aACpD;QACH;QAEA,KAAK,MAAM,EAACC,IAAI,EAAEC,MAAM,EAAEF,KAAK,EAAC,IAAIZ,QAAS;YAC3CQ,MAAMO,MAAM,CAAC;gBAACF;gBAAMC;gBAAQF;YAAK;QACnC;QAEA,IAAI,CAACL,GAAG,CAACC,MAAMQ,MAAM;IACvB;AACF"}