transloadit 4.7.4 → 4.7.6

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 (142) hide show
  1. package/README.md +888 -5
  2. package/dist/Transloadit.d.ts +3 -3
  3. package/dist/Transloadit.d.ts.map +1 -1
  4. package/dist/Transloadit.js +2 -2
  5. package/dist/Transloadit.js.map +1 -1
  6. package/dist/alphalib/types/assembliesGet.d.ts +5 -0
  7. package/dist/alphalib/types/assembliesGet.d.ts.map +1 -1
  8. package/dist/alphalib/types/assemblyReplay.d.ts +5 -0
  9. package/dist/alphalib/types/assemblyReplay.d.ts.map +1 -1
  10. package/dist/alphalib/types/assemblyReplayNotification.d.ts +5 -0
  11. package/dist/alphalib/types/assemblyReplayNotification.d.ts.map +1 -1
  12. package/dist/alphalib/types/assemblyStatus.d.ts +25 -25
  13. package/dist/alphalib/types/assemblyStatus.d.ts.map +1 -1
  14. package/dist/alphalib/types/assemblyStatus.js +4 -1
  15. package/dist/alphalib/types/assemblyStatus.js.map +1 -1
  16. package/dist/alphalib/types/bill.d.ts +5 -0
  17. package/dist/alphalib/types/bill.d.ts.map +1 -1
  18. package/dist/alphalib/types/builtinTemplates.d.ts +83 -0
  19. package/dist/alphalib/types/builtinTemplates.d.ts.map +1 -0
  20. package/dist/alphalib/types/builtinTemplates.js +19 -0
  21. package/dist/alphalib/types/builtinTemplates.js.map +1 -0
  22. package/dist/alphalib/types/robots/ai-chat.d.ts.map +1 -1
  23. package/dist/alphalib/types/robots/ai-chat.js +1 -0
  24. package/dist/alphalib/types/robots/ai-chat.js.map +1 -1
  25. package/dist/alphalib/types/skillFrontmatter.d.ts +29 -0
  26. package/dist/alphalib/types/skillFrontmatter.d.ts.map +1 -0
  27. package/dist/alphalib/types/skillFrontmatter.js +19 -0
  28. package/dist/alphalib/types/skillFrontmatter.js.map +1 -0
  29. package/dist/alphalib/types/template.d.ts +36 -0
  30. package/dist/alphalib/types/template.d.ts.map +1 -1
  31. package/dist/alphalib/types/template.js +10 -0
  32. package/dist/alphalib/types/template.js.map +1 -1
  33. package/dist/alphalib/types/templateCredential.d.ts +10 -0
  34. package/dist/alphalib/types/templateCredential.d.ts.map +1 -1
  35. package/dist/cli/commands/assemblies.d.ts +8 -2
  36. package/dist/cli/commands/assemblies.d.ts.map +1 -1
  37. package/dist/cli/commands/assemblies.js +566 -411
  38. package/dist/cli/commands/assemblies.js.map +1 -1
  39. package/dist/cli/commands/index.d.ts.map +1 -1
  40. package/dist/cli/commands/index.js +5 -0
  41. package/dist/cli/commands/index.js.map +1 -1
  42. package/dist/cli/commands/templates.d.ts.map +1 -1
  43. package/dist/cli/commands/templates.js +4 -14
  44. package/dist/cli/commands/templates.js.map +1 -1
  45. package/dist/cli/fileProcessingOptions.d.ts +35 -0
  46. package/dist/cli/fileProcessingOptions.d.ts.map +1 -0
  47. package/dist/cli/fileProcessingOptions.js +182 -0
  48. package/dist/cli/fileProcessingOptions.js.map +1 -0
  49. package/dist/cli/generateIntentDocs.d.ts +2 -0
  50. package/dist/cli/generateIntentDocs.d.ts.map +1 -0
  51. package/dist/cli/generateIntentDocs.js +321 -0
  52. package/dist/cli/generateIntentDocs.js.map +1 -0
  53. package/dist/cli/intentCommandSpecs.d.ts +36 -0
  54. package/dist/cli/intentCommandSpecs.d.ts.map +1 -0
  55. package/dist/cli/intentCommandSpecs.js +181 -0
  56. package/dist/cli/intentCommandSpecs.js.map +1 -0
  57. package/dist/cli/intentCommands.d.ts +13 -0
  58. package/dist/cli/intentCommands.d.ts.map +1 -0
  59. package/dist/cli/intentCommands.js +368 -0
  60. package/dist/cli/intentCommands.js.map +1 -0
  61. package/dist/cli/intentFields.d.ts +25 -0
  62. package/dist/cli/intentFields.d.ts.map +1 -0
  63. package/dist/cli/intentFields.js +298 -0
  64. package/dist/cli/intentFields.js.map +1 -0
  65. package/dist/cli/intentInputPolicy.d.ts +10 -0
  66. package/dist/cli/intentInputPolicy.d.ts.map +1 -0
  67. package/dist/cli/intentInputPolicy.js +2 -0
  68. package/dist/cli/intentInputPolicy.js.map +1 -0
  69. package/dist/cli/intentRuntime.d.ts +114 -0
  70. package/dist/cli/intentRuntime.d.ts.map +1 -0
  71. package/dist/cli/intentRuntime.js +464 -0
  72. package/dist/cli/intentRuntime.js.map +1 -0
  73. package/dist/cli/resultFiles.d.ts +19 -0
  74. package/dist/cli/resultFiles.d.ts.map +1 -0
  75. package/dist/cli/resultFiles.js +66 -0
  76. package/dist/cli/resultFiles.js.map +1 -0
  77. package/dist/cli/resultUrls.d.ts +19 -0
  78. package/dist/cli/resultUrls.d.ts.map +1 -0
  79. package/dist/cli/resultUrls.js +36 -0
  80. package/dist/cli/resultUrls.js.map +1 -0
  81. package/dist/cli/semanticIntents/imageDescribe.d.ts +43 -0
  82. package/dist/cli/semanticIntents/imageDescribe.d.ts.map +1 -0
  83. package/dist/cli/semanticIntents/imageDescribe.js +188 -0
  84. package/dist/cli/semanticIntents/imageDescribe.js.map +1 -0
  85. package/dist/cli/semanticIntents/index.d.ts +18 -0
  86. package/dist/cli/semanticIntents/index.d.ts.map +1 -0
  87. package/dist/cli/semanticIntents/index.js +18 -0
  88. package/dist/cli/semanticIntents/index.js.map +1 -0
  89. package/dist/cli/semanticIntents/markdownPdf.d.ts +4 -0
  90. package/dist/cli/semanticIntents/markdownPdf.d.ts.map +1 -0
  91. package/dist/cli/semanticIntents/markdownPdf.js +93 -0
  92. package/dist/cli/semanticIntents/markdownPdf.js.map +1 -0
  93. package/dist/cli/semanticIntents/parsing.d.ts +11 -0
  94. package/dist/cli/semanticIntents/parsing.d.ts.map +1 -0
  95. package/dist/cli/semanticIntents/parsing.js +29 -0
  96. package/dist/cli/semanticIntents/parsing.js.map +1 -0
  97. package/dist/cli/stepsInput.d.ts +4 -0
  98. package/dist/cli/stepsInput.d.ts.map +1 -0
  99. package/dist/cli/stepsInput.js +23 -0
  100. package/dist/cli/stepsInput.js.map +1 -0
  101. package/dist/cli.d.ts +1 -1
  102. package/dist/cli.d.ts.map +1 -1
  103. package/dist/cli.js +5 -4
  104. package/dist/cli.js.map +1 -1
  105. package/dist/ensureUniqueCounter.d.ts +8 -0
  106. package/dist/ensureUniqueCounter.d.ts.map +1 -0
  107. package/dist/ensureUniqueCounter.js +48 -0
  108. package/dist/ensureUniqueCounter.js.map +1 -0
  109. package/dist/inputFiles.d.ts +9 -0
  110. package/dist/inputFiles.d.ts.map +1 -1
  111. package/dist/inputFiles.js +177 -26
  112. package/dist/inputFiles.js.map +1 -1
  113. package/dist/robots.js +1 -1
  114. package/dist/robots.js.map +1 -1
  115. package/package.json +9 -7
  116. package/src/Transloadit.ts +3 -3
  117. package/src/alphalib/types/assemblyStatus.ts +4 -1
  118. package/src/alphalib/types/builtinTemplates.ts +24 -0
  119. package/src/alphalib/types/robots/ai-chat.ts +1 -0
  120. package/src/alphalib/types/skillFrontmatter.ts +24 -0
  121. package/src/alphalib/types/template.ts +14 -0
  122. package/src/cli/commands/assemblies.ts +825 -505
  123. package/src/cli/commands/index.ts +6 -3
  124. package/src/cli/commands/templates.ts +6 -17
  125. package/src/cli/fileProcessingOptions.ts +294 -0
  126. package/src/cli/generateIntentDocs.ts +419 -0
  127. package/src/cli/intentCommandSpecs.ts +282 -0
  128. package/src/cli/intentCommands.ts +525 -0
  129. package/src/cli/intentFields.ts +403 -0
  130. package/src/cli/intentInputPolicy.ts +11 -0
  131. package/src/cli/intentRuntime.ts +734 -0
  132. package/src/cli/resultFiles.ts +105 -0
  133. package/src/cli/resultUrls.ts +72 -0
  134. package/src/cli/semanticIntents/imageDescribe.ts +254 -0
  135. package/src/cli/semanticIntents/index.ts +48 -0
  136. package/src/cli/semanticIntents/markdownPdf.ts +120 -0
  137. package/src/cli/semanticIntents/parsing.ts +56 -0
  138. package/src/cli/stepsInput.ts +32 -0
  139. package/src/cli.ts +5 -4
  140. package/src/ensureUniqueCounter.ts +75 -0
  141. package/src/inputFiles.ts +277 -26
  142. package/src/robots.ts +1 -1
@@ -0,0 +1,525 @@
1
+ import type { CommandClass } from 'clipanion'
2
+ import { Command } from 'clipanion'
3
+ import type { ZodObject, ZodRawShape, ZodTypeAny } from 'zod'
4
+
5
+ import type { RobotMetaInput } from '../alphalib/types/robots/_instructions-primitives.ts'
6
+ import type {
7
+ IntentDefinition,
8
+ IntentInputMode,
9
+ IntentOutputMode,
10
+ RobotIntentDefinition,
11
+ SemanticIntentDefinition,
12
+ } from './intentCommandSpecs.ts'
13
+ import { getIntentPaths, getIntentResultStepName, intentCatalog } from './intentCommandSpecs.ts'
14
+ import type { IntentFieldKind, IntentFieldSpec } from './intentFields.ts'
15
+ import {
16
+ createIntentOption,
17
+ inferIntentExampleValue,
18
+ inferIntentFieldKind,
19
+ unwrapIntentSchema,
20
+ } from './intentFields.ts'
21
+ import type { IntentInputPolicy } from './intentInputPolicy.ts'
22
+ import type {
23
+ IntentCommandDefinition,
24
+ IntentFileCommandDefinition,
25
+ IntentNoInputCommandDefinition,
26
+ IntentSingleStepExecutionDefinition,
27
+ } from './intentRuntime.ts'
28
+ import {
29
+ GeneratedBundledFileIntentCommand,
30
+ GeneratedNoInputIntentCommand,
31
+ GeneratedStandardFileIntentCommand,
32
+ GeneratedWatchableFileIntentCommand,
33
+ getIntentOptionDefinitions,
34
+ } from './intentRuntime.ts'
35
+ import { getSemanticIntentDescriptor } from './semanticIntents/index.ts'
36
+
37
+ interface GeneratedSchemaField extends IntentFieldSpec {
38
+ description?: string
39
+ exampleValue: string
40
+ optionFlags: string
41
+ propertyName: string
42
+ required: boolean
43
+ }
44
+
45
+ interface ResolvedIntentLocalFilesInput {
46
+ defaultSingleAssembly?: boolean
47
+ inputPolicy: IntentInputPolicy
48
+ kind: 'local-files'
49
+ }
50
+
51
+ interface ResolvedIntentNoneInput {
52
+ kind: 'none'
53
+ }
54
+
55
+ type ResolvedIntentInput = ResolvedIntentLocalFilesInput | ResolvedIntentNoneInput
56
+
57
+ type IntentBaseClass =
58
+ | typeof GeneratedBundledFileIntentCommand
59
+ | typeof GeneratedNoInputIntentCommand
60
+ | typeof GeneratedStandardFileIntentCommand
61
+ | typeof GeneratedWatchableFileIntentCommand
62
+
63
+ type BuiltIntentCommandDefinition = IntentCommandDefinition & {
64
+ intentDefinition: IntentFileCommandDefinition | IntentNoInputCommandDefinition
65
+ }
66
+
67
+ export type ResolvedIntentCommandDefinition = BuiltIntentCommandDefinition & {
68
+ catalogDefinition: IntentDefinition
69
+ }
70
+
71
+ const hiddenFieldNames = new Set([
72
+ 'ffmpeg_stack',
73
+ 'force_accept',
74
+ 'ignore_errors',
75
+ 'imagemagick_stack',
76
+ 'output_meta',
77
+ 'queue',
78
+ 'result',
79
+ 'robot',
80
+ 'stack',
81
+ 'use',
82
+ ])
83
+
84
+ function toCamelCase(value: string): string {
85
+ return value.replace(/_([a-z])/g, (_match, letter: string) => letter.toUpperCase())
86
+ }
87
+
88
+ function toKebabCase(value: string): string {
89
+ return value.replaceAll('_', '-')
90
+ }
91
+
92
+ function toPascalCase(parts: string[]): string {
93
+ return parts
94
+ .flatMap((part) => part.split('-'))
95
+ .map((part) => `${part[0]?.toUpperCase() ?? ''}${part.slice(1)}`)
96
+ .join('')
97
+ }
98
+
99
+ function stripTrailingPunctuation(value: string): string {
100
+ return value.replace(/[.:]+$/, '').trim()
101
+ }
102
+
103
+ function getTypicalInputFile(meta: RobotMetaInput): string {
104
+ switch (meta.typical_file_type) {
105
+ case 'audio file':
106
+ return 'input.mp3'
107
+ case 'document':
108
+ return 'input.pdf'
109
+ case 'image':
110
+ return 'input.png'
111
+ case 'video':
112
+ return 'input.mp4'
113
+ default:
114
+ return 'input.file'
115
+ }
116
+ }
117
+
118
+ function getDefaultOutputPath(paths: string[], outputMode: IntentOutputMode): string {
119
+ if (outputMode === 'directory') {
120
+ return 'output/'
121
+ }
122
+
123
+ const [group] = paths
124
+ if (group === 'audio') return 'output.png'
125
+ if (group === 'document') return 'output.pdf'
126
+ if (group === 'image') return 'output.png'
127
+ if (group === 'text') return 'output.mp3'
128
+ return 'output.file'
129
+ }
130
+
131
+ function inferOutputPath(
132
+ paths: string[],
133
+ outputMode: IntentOutputMode,
134
+ fieldSpecs: readonly GeneratedSchemaField[],
135
+ ): string {
136
+ if (outputMode === 'directory') {
137
+ return 'output/'
138
+ }
139
+
140
+ const formatExample = fieldSpecs
141
+ .map((fieldSpec) =>
142
+ fieldSpec.required && fieldSpec.name === 'format' ? fieldSpec.exampleValue : null,
143
+ )
144
+ .find((value) => value != null)
145
+
146
+ if (fieldSpecs.some((fieldSpec) => fieldSpec.name === 'format') && formatExample != null) {
147
+ if (fieldSpecs.some((fieldSpec) => fieldSpec.name === 'relative_pathname')) {
148
+ return `archive.${formatExample}`
149
+ }
150
+ }
151
+
152
+ if (formatExample != null && /^[-\w]+$/.test(formatExample)) {
153
+ return `output.${formatExample}`
154
+ }
155
+
156
+ return getDefaultOutputPath(paths, outputMode)
157
+ }
158
+
159
+ function inferInputModeFromShape(shape: Record<string, ZodTypeAny>): IntentInputMode {
160
+ if ('prompt' in shape) {
161
+ return unwrapIntentSchema(shape.prompt).required ? 'none' : 'local-files'
162
+ }
163
+
164
+ return 'local-files'
165
+ }
166
+
167
+ function inferIntentInput(
168
+ definition: RobotIntentDefinition,
169
+ shape: Record<string, ZodTypeAny>,
170
+ ): ResolvedIntentInput {
171
+ const inputMode = definition.inputMode ?? inferInputModeFromShape(shape)
172
+ if (inputMode === 'none') {
173
+ return { kind: 'none' }
174
+ }
175
+
176
+ const promptIsOptional = 'prompt' in shape && !unwrapIntentSchema(shape.prompt).required
177
+ const inputPolicy = promptIsOptional
178
+ ? ({
179
+ kind: 'optional',
180
+ field: 'prompt',
181
+ attachUseWhenInputsProvided: true,
182
+ } satisfies IntentInputPolicy)
183
+ : ({ kind: 'required' } satisfies IntentInputPolicy)
184
+
185
+ if (definition.defaultSingleAssembly) {
186
+ return {
187
+ kind: 'local-files',
188
+ defaultSingleAssembly: true,
189
+ inputPolicy,
190
+ }
191
+ }
192
+
193
+ return {
194
+ kind: 'local-files',
195
+ inputPolicy,
196
+ }
197
+ }
198
+
199
+ function inferFixedValues(
200
+ definition: RobotIntentDefinition,
201
+ input: ResolvedIntentInput,
202
+ inputMode: IntentInputMode,
203
+ ): Record<string, unknown> {
204
+ if (definition.defaultSingleAssembly) {
205
+ return {
206
+ robot: definition.robot,
207
+ result: true,
208
+ use: {
209
+ steps: [':original'],
210
+ bundle_steps: true,
211
+ },
212
+ }
213
+ }
214
+
215
+ if (inputMode === 'none') {
216
+ return {
217
+ robot: definition.robot,
218
+ result: true,
219
+ }
220
+ }
221
+
222
+ if (input.kind === 'local-files' && input.inputPolicy.kind === 'required') {
223
+ return {
224
+ robot: definition.robot,
225
+ result: true,
226
+ use: ':original',
227
+ }
228
+ }
229
+
230
+ return {
231
+ robot: definition.robot,
232
+ result: true,
233
+ }
234
+ }
235
+
236
+ function collectSchemaFields(
237
+ schemaShape: Record<string, ZodTypeAny>,
238
+ fixedValues: Record<string, unknown>,
239
+ input: ResolvedIntentInput,
240
+ ): GeneratedSchemaField[] {
241
+ return Object.entries(schemaShape)
242
+ .filter(([key]) => !hiddenFieldNames.has(key) && !Object.hasOwn(fixedValues, key))
243
+ .flatMap(([key, fieldSchema]) => {
244
+ const { required: schemaRequired, schema: unwrappedSchema } = unwrapIntentSchema(fieldSchema)
245
+
246
+ let kind: IntentFieldKind
247
+ try {
248
+ kind = inferIntentFieldKind(unwrappedSchema)
249
+ } catch {
250
+ return []
251
+ }
252
+
253
+ return [
254
+ {
255
+ name: key,
256
+ propertyName: toCamelCase(key),
257
+ optionFlags: `--${toKebabCase(key)}`,
258
+ required: (input.kind === 'none' && key === 'prompt') || schemaRequired,
259
+ description: fieldSchema.description,
260
+ exampleValue: inferIntentExampleValue({
261
+ kind,
262
+ name: key,
263
+ schema: unwrappedSchema as ZodTypeAny,
264
+ }),
265
+ kind,
266
+ },
267
+ ]
268
+ })
269
+ }
270
+
271
+ function inferExamples(
272
+ spec: BuiltIntentCommandDefinition,
273
+ definition?: RobotIntentDefinition,
274
+ ): Array<[string, string]> {
275
+ if (definition == null) {
276
+ if (spec.intentDefinition.execution.kind === 'dynamic-step') {
277
+ return spec.examples
278
+ }
279
+
280
+ return [
281
+ ['Run the command', `transloadit ${spec.paths.join(' ')} --input input.mp4 --out output/`],
282
+ ]
283
+ }
284
+
285
+ const parts = ['transloadit', ...spec.paths]
286
+ const schemaShape = (definition.schema as ZodObject<ZodRawShape>).shape as Record<
287
+ string,
288
+ ZodTypeAny
289
+ >
290
+ const inputMode = definition.inputMode ?? inferInputModeFromShape(schemaShape)
291
+ const fieldSpecs =
292
+ spec.intentDefinition.execution.kind === 'single-step'
293
+ ? (spec.intentDefinition.execution.fields as readonly GeneratedSchemaField[])
294
+ : []
295
+
296
+ if (inputMode === 'local-files') {
297
+ parts.push('--input', getTypicalInputFile(definition.meta))
298
+ }
299
+
300
+ if (inputMode === 'none') {
301
+ const promptField = fieldSpecs.find((fieldSpec) => fieldSpec.name === 'prompt')
302
+ parts.push('--prompt', promptField?.exampleValue ?? JSON.stringify('A red bicycle in a studio'))
303
+ }
304
+
305
+ for (const fieldSpec of fieldSpecs) {
306
+ if (!fieldSpec.required) continue
307
+ if (fieldSpec.name === 'prompt' && inputMode === 'none') continue
308
+
309
+ parts.push(fieldSpec.optionFlags, fieldSpec.exampleValue)
310
+ }
311
+
312
+ const outputMode = spec.intentDefinition.outputMode ?? 'file'
313
+ parts.push('--out', inferOutputPath(spec.paths, outputMode, fieldSpecs))
314
+
315
+ return [['Run the command', parts.join(' ')]]
316
+ }
317
+
318
+ function resolveRobotIntent(definition: RobotIntentDefinition): BuiltIntentCommandDefinition {
319
+ const paths = getIntentPaths(definition)
320
+ const className = `${toPascalCase(paths)}Command`
321
+ const commandLabel = paths.join(' ')
322
+ const schema = definition.schema as ZodObject<ZodRawShape>
323
+ const schemaShape = schema.shape as Record<string, ZodTypeAny>
324
+ const inputMode = definition.inputMode ?? inferInputModeFromShape(schemaShape)
325
+ const input = inferIntentInput(definition, schemaShape)
326
+ const fixedValues = inferFixedValues(definition, input, inputMode)
327
+ const fieldSpecs = collectSchemaFields(schemaShape, fixedValues, input)
328
+ const outputMode = definition.outputMode ?? 'file'
329
+ const execution: IntentSingleStepExecutionDefinition = {
330
+ kind: 'single-step',
331
+ schema,
332
+ fields: fieldSpecs,
333
+ fixedValues,
334
+ resultStepName:
335
+ getIntentResultStepName(definition) ??
336
+ (() => {
337
+ throw new Error(`Could not infer result step name for "${definition.robot}"`)
338
+ })(),
339
+ }
340
+
341
+ const spec: BuiltIntentCommandDefinition = {
342
+ className,
343
+ description: stripTrailingPunctuation(definition.meta.title),
344
+ details: getIntentDetails({
345
+ defaultSingleAssembly: definition.defaultSingleAssembly === true,
346
+ inputMode,
347
+ outputMode,
348
+ robot: definition.robot,
349
+ }),
350
+ examples: [],
351
+ paths,
352
+ runnerKind:
353
+ input.kind === 'none' ? 'no-input' : input.defaultSingleAssembly ? 'bundled' : 'standard',
354
+ intentDefinition:
355
+ input.kind === 'none'
356
+ ? {
357
+ execution,
358
+ outputDescription: 'Write the result to this path',
359
+ outputMode,
360
+ }
361
+ : {
362
+ commandLabel,
363
+ execution,
364
+ inputPolicy: input.inputPolicy,
365
+ outputDescription:
366
+ outputMode === 'directory'
367
+ ? 'Write the results to this directory'
368
+ : 'Write the result to this path or directory',
369
+ outputMode,
370
+ },
371
+ }
372
+
373
+ return {
374
+ ...spec,
375
+ examples: inferExamples(spec, definition),
376
+ }
377
+ }
378
+
379
+ function getIntentDetails({
380
+ defaultSingleAssembly,
381
+ inputMode,
382
+ outputMode,
383
+ robot,
384
+ }: {
385
+ defaultSingleAssembly: boolean
386
+ inputMode: IntentInputMode
387
+ outputMode: 'directory' | 'file'
388
+ robot: string
389
+ }): string {
390
+ if (inputMode === 'none') {
391
+ return `Runs \`${robot}\` and writes the result to \`--out\`.`
392
+ }
393
+
394
+ if (defaultSingleAssembly) {
395
+ return `Runs \`${robot}\` for the provided inputs and writes the result to \`--out\`.`
396
+ }
397
+
398
+ if (outputMode === 'directory') {
399
+ return `Runs \`${robot}\` on each input file and writes the results to \`--out\`.`
400
+ }
401
+
402
+ return `Runs \`${robot}\` on each input file and writes the result to \`--out\`.`
403
+ }
404
+
405
+ function resolveSemanticIntent(definition: SemanticIntentDefinition): BuiltIntentCommandDefinition {
406
+ const paths = getIntentPaths(definition)
407
+ const descriptor = getSemanticIntentDescriptor(definition.semantic)
408
+
409
+ return {
410
+ className: `${toPascalCase(paths)}Command`,
411
+ description: descriptor.presentation.description,
412
+ details: descriptor.presentation.details,
413
+ examples: [...descriptor.presentation.examples],
414
+ paths,
415
+ runnerKind: descriptor.runnerKind,
416
+ intentDefinition: {
417
+ commandLabel: paths.join(' '),
418
+ execution: descriptor.execution,
419
+ inputPolicy: descriptor.inputPolicy,
420
+ outputDescription: descriptor.outputDescription,
421
+ },
422
+ }
423
+ }
424
+
425
+ function resolveTemplateIntent(
426
+ definition: IntentDefinition & { kind: 'template' },
427
+ ): BuiltIntentCommandDefinition {
428
+ const outputMode = definition.outputMode ?? 'file'
429
+ const paths = getIntentPaths(definition)
430
+ const spec: BuiltIntentCommandDefinition = {
431
+ className: `${toPascalCase(paths)}Command`,
432
+ description: `Run ${stripTrailingPunctuation(definition.templateId)}`,
433
+ details: `Runs the \`${definition.templateId}\` template and writes the outputs to \`--out\`.`,
434
+ examples: [],
435
+ paths,
436
+ runnerKind: 'standard',
437
+ intentDefinition: {
438
+ commandLabel: paths.join(' '),
439
+ execution: {
440
+ kind: 'template',
441
+ templateId: definition.templateId,
442
+ },
443
+ inputPolicy: { kind: 'required' },
444
+ outputDescription:
445
+ outputMode === 'directory'
446
+ ? 'Write the results to this directory'
447
+ : 'Write the result to this path or directory',
448
+ outputMode,
449
+ },
450
+ }
451
+
452
+ return {
453
+ ...spec,
454
+ examples: inferExamples(spec),
455
+ }
456
+ }
457
+
458
+ function resolveIntent(definition: IntentDefinition): BuiltIntentCommandDefinition {
459
+ if (definition.kind === 'robot') {
460
+ return resolveRobotIntent(definition)
461
+ }
462
+
463
+ if (definition.kind === 'semantic') {
464
+ return resolveSemanticIntent(definition)
465
+ }
466
+
467
+ return resolveTemplateIntent(definition)
468
+ }
469
+
470
+ export function resolveIntentCommandDefinitions(): ResolvedIntentCommandDefinition[] {
471
+ return intentCatalog.map((definition) => ({
472
+ ...resolveIntent(definition),
473
+ catalogDefinition: definition,
474
+ }))
475
+ }
476
+
477
+ function getBaseClass(spec: BuiltIntentCommandDefinition): IntentBaseClass {
478
+ if (spec.runnerKind === 'no-input') {
479
+ return GeneratedNoInputIntentCommand
480
+ }
481
+
482
+ if (spec.runnerKind === 'bundled') {
483
+ return GeneratedBundledFileIntentCommand
484
+ }
485
+
486
+ if (spec.runnerKind === 'watchable') {
487
+ return GeneratedWatchableFileIntentCommand
488
+ }
489
+
490
+ return GeneratedStandardFileIntentCommand
491
+ }
492
+
493
+ function createIntentCommandClass(spec: BuiltIntentCommandDefinition): CommandClass {
494
+ const BaseClass = getBaseClass(spec)
495
+
496
+ class RuntimeIntentCommand extends BaseClass {}
497
+
498
+ Object.defineProperty(RuntimeIntentCommand, 'name', {
499
+ value: spec.className,
500
+ })
501
+
502
+ Object.assign(RuntimeIntentCommand, {
503
+ paths: [spec.paths],
504
+ intentDefinition: spec.intentDefinition,
505
+ usage: Command.Usage({
506
+ category: 'Intent Commands',
507
+ description: spec.description,
508
+ details: spec.details,
509
+ examples: spec.examples,
510
+ }),
511
+ })
512
+
513
+ for (const field of getIntentOptionDefinitions(spec.intentDefinition)) {
514
+ Object.defineProperty(RuntimeIntentCommand.prototype, field.propertyName, {
515
+ configurable: true,
516
+ enumerable: true,
517
+ writable: true,
518
+ value: createIntentOption(field),
519
+ })
520
+ }
521
+
522
+ return RuntimeIntentCommand as unknown as CommandClass
523
+ }
524
+
525
+ export const intentCommands = resolveIntentCommandDefinitions().map(createIntentCommandClass)