55 * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66 */
77import { resolve } from 'node:path' ;
8- import { readFileSync , writeFileSync } from 'node:fs' ;
8+ import { existsSync , readFileSync , writeFileSync } from 'node:fs' ;
99import YAML from 'yaml' ;
1010import { SfCommand , Flags } from '@salesforce/sf-plugins-core' ;
1111import { Lifecycle , Messages } from '@salesforce/core' ;
1212import { MultiStageOutput } from '@oclif/multi-stage-output' ;
13+ import { input as inquirerInput } from '@inquirer/prompts' ;
1314import { colorize } from '@oclif/core/ux' ;
1415import {
1516 Agent ,
@@ -20,7 +21,8 @@ import {
2021 generateAgentApiName ,
2122} from '@salesforce/agents' ;
2223import { FlaggablePrompt , makeFlags , promptForFlag , validateAgentType } from '../../flags.js' ;
23- import { AgentSpecFileContents } from './generate/spec.js' ;
24+ import { theme } from '../../inquirer-theme.js' ;
25+ import { AgentSpecFileContents } from './generate/agent-spec.js' ;
2426
2527Messages . importMessagesDirectoryFromMetaUrl ( import . meta. url ) ;
2628const messages = Messages . loadMessages ( '@salesforce/plugin-agent' , 'agent.create' ) ;
@@ -43,6 +45,33 @@ const FLAGGABLE_PROMPTS = {
4345 validate : ( d : string ) : boolean | string => d . length > 0 || 'Agent Name cannot be empty' ,
4446 required : true ,
4547 } ,
48+ 'agent-api-name' : {
49+ message : messages . getMessage ( 'flags.agent-api-name.summary' ) ,
50+ validate : ( d : string ) : boolean | string => {
51+ if ( d . length === 0 ) {
52+ return true ;
53+ }
54+ if ( d . length > 80 ) {
55+ return 'API name cannot be over 80 characters.' ;
56+ }
57+ const regex = / ^ [ A - Z a - z ] [ A - Z a - z 0 - 9 _ ] * [ A - Z a - z 0 - 9 ] + $ / ;
58+ if ( ! regex . test ( d ) ) {
59+ return 'Invalid API name.' ;
60+ }
61+ return true ;
62+ } ,
63+ } ,
64+ spec : {
65+ message : messages . getMessage ( 'flags.spec.summary' ) ,
66+ validate : ( d : string ) : boolean | string => {
67+ const specPath = resolve ( d ) ;
68+ if ( ! existsSync ( specPath ) ) {
69+ return 'Please enter an existing agent spec (yaml) file' ;
70+ }
71+ return true ;
72+ } ,
73+ required : true ,
74+ } ,
4675} satisfies Record < string , FlaggablePrompt > ;
4776
4877export default class AgentCreate extends SfCommand < AgentCreateResult > {
@@ -56,18 +85,9 @@ export default class AgentCreate extends SfCommand<AgentCreateResult> {
5685 'target-org' : Flags . requiredOrg ( ) ,
5786 'api-version' : Flags . orgApiVersion ( ) ,
5887 ...makeFlags ( FLAGGABLE_PROMPTS ) ,
59- spec : Flags . file ( {
60- // char: 'f',
61- summary : messages . getMessage ( 'flags.spec.summary' ) ,
62- exists : true ,
63- required : true ,
64- } ) ,
6588 preview : Flags . boolean ( {
6689 summary : messages . getMessage ( 'flags.preview.summary' ) ,
6790 } ) ,
68- 'agent-api-name' : Flags . string ( {
69- summary : messages . getMessage ( 'flags.agent-api-name.summary' ) ,
70- } ) ,
7191 // This would be used as more of an agent update than create.
7292 // Could possibly move to an `agent update` command.
7393 'planner-id' : Flags . string ( {
@@ -81,17 +101,36 @@ export default class AgentCreate extends SfCommand<AgentCreateResult> {
81101 const { flags } = await this . parse ( AgentCreate ) ;
82102
83103 // throw error if --json is used and not all required flags are provided
84- if ( this . jsonEnabled ( ) && ! flags [ 'agent-name' ] ) {
85- throw messages . createError ( 'error.missingRequiredFlags' , [ 'agent-name' ] ) ;
104+ if ( this . jsonEnabled ( ) ) {
105+ if ( ! flags [ 'agent-name' ] ) {
106+ throw messages . createError ( 'error.missingRequiredFlags' , [ 'agent-name' ] ) ;
107+ }
108+ if ( ! flags . spec ) {
109+ throw messages . createError ( 'error.missingRequiredFlags' , [ 'spec' ] ) ;
110+ }
86111 }
87112
113+ // If we don't have an agent spec yet, prompt.
114+ const specPath = flags . spec ?? ( await promptForFlag ( FLAGGABLE_PROMPTS [ 'spec' ] ) ) ;
115+
88116 // Read the agent spec and validate
89- const inputSpec = YAML . parse ( readFileSync ( resolve ( flags . spec ) , 'utf8' ) ) as AgentSpecFileContents ;
117+ const inputSpec = YAML . parse ( readFileSync ( resolve ( specPath ) , 'utf8' ) ) as AgentSpecFileContents ;
90118 validateSpec ( inputSpec ) ;
91119
92120 // If we don't have an agent name yet, prompt.
93121 const agentName = flags [ 'agent-name' ] ?? ( await promptForFlag ( FLAGGABLE_PROMPTS [ 'agent-name' ] ) ) ;
94- const agentApiName = flags [ 'agent-api-name' ] ?? generateAgentApiName ( agentName ) ;
122+ let agentApiName = flags [ 'agent-api-name' ] ;
123+ if ( ! agentApiName ) {
124+ agentApiName = generateAgentApiName ( agentName ) ;
125+ const promptedValue = await inquirerInput ( {
126+ message : messages . getMessage ( 'flags.agent-api-name.prompt' , [ agentApiName ] ) ,
127+ validate : FLAGGABLE_PROMPTS [ 'agent-api-name' ] . validate ,
128+ theme,
129+ } ) ;
130+ if ( promptedValue ?. length ) {
131+ agentApiName = promptedValue ;
132+ }
133+ }
95134
96135 let title : string ;
97136 const stages = [ MSO_STAGES . parse ] ;
0 commit comments