@@ -29,12 +29,6 @@ export type AgentUserCreateResponse = {
2929 permissionSetErrors : Array < { permissionSet : string ; error : string } > ;
3030} ;
3131
32- type UserLicenseInfo = {
33- totalLicenses : number ;
34- usedLicenses : number ;
35- availableLicenses : number ;
36- } ;
37-
3832export default class OrgCreateAgentUser extends SfCommand < AgentUserCreateResponse > {
3933 public static readonly summary = messages . getMessage ( 'summary' ) ;
4034 public static readonly description = messages . getMessage ( 'description' ) ;
@@ -78,12 +72,8 @@ export default class OrgCreateAgentUser extends SfCommand<AgentUserCreateRespons
7872 const profileId = await this . getProfileId ( connection ) ;
7973 this . log ( 'Using profile: Einstein Agent User' ) ;
8074
81- // Infer locale settings from current user
82- const localeSettings = await this . inferLocaleSettings ( connection ) ;
83- this . log ( `Using locale settings from org: ${ localeSettings . locale } ` ) ;
84-
8575 // Create the agent user
86- const userId = await this . createAgentUser ( connection , username , profileId , localeSettings , {
76+ const userId = await this . createAgentUser ( connection , username , profileId , {
8777 firstName : flags [ 'first-name' ] ,
8878 lastName : flags [ 'last-name' ] ,
8979 } ) ;
@@ -183,69 +173,69 @@ export default class OrgCreateAgentUser extends SfCommand<AgentUserCreateRespons
183173 }
184174
185175 private async checkAgentUserLicenses ( connection : Connection ) : Promise < void > {
186- try {
187- // Query for Agentforce Service Agent license type
188- const licenseQuery = `
189- SELECT TotalLicenses, UsedLicenses, Name, MasterLabel
190- FROM UserLicense
191- WHERE Name LIKE '%Agent%' OR MasterLabel LIKE '%Agent%'
192- ` ;
193- const licenseResult = await connection . query < {
194- TotalLicenses : number ;
195- UsedLicenses : number ;
176+ // Query the Einstein Agent User profile to get its associated license
177+ const profileResult = await connection . query < {
178+ UserLicense : {
179+ Id : string ;
196180 Name : string ;
197181 MasterLabel : string ;
198- } > ( licenseQuery ) ;
199-
200- if ( licenseResult . totalSize === 0 ) {
201- throw new SfError (
202- 'No Agent user licenses found in this org. Agent user licenses are required to create agent users.' ,
203- 'NoAgentLicensesError' ,
204- [
205- 'Contact your Salesforce account team to add Agent user licenses to your org' ,
206- 'Verify that Agentforce is enabled for your org' ,
207- ]
208- ) ;
209- }
182+ TotalLicenses : number ;
183+ UsedLicenses : number ;
184+ } ;
185+ } > ( `
186+ SELECT UserLicense.Id, UserLicense.Name, UserLicense.MasterLabel,
187+ UserLicense.TotalLicenses, UserLicense.UsedLicenses
188+ FROM Profile
189+ WHERE Name = 'Einstein Agent User'
190+ ` ) ;
191+
192+ if ( profileResult . totalSize === 0 ) {
193+ throw new SfError (
194+ 'Einstein Agent User profile not found in this org. This profile is required for agent users.' ,
195+ 'ProfileNotFoundError' ,
196+ [
197+ 'Verify that Agentforce is enabled for your org' ,
198+ 'Contact your Salesforce account team to enable Agentforce features' ,
199+ ]
200+ ) ;
201+ }
210202
211- // Check each license type for availability
212- const licenseInfo : UserLicenseInfo [ ] = licenseResult . records . map ( ( record ) => ( {
213- totalLicenses : record . TotalLicenses ,
214- usedLicenses : record . UsedLicenses ,
215- availableLicenses : record . TotalLicenses - record . UsedLicenses ,
216- } ) ) ;
203+ const license = profileResult . records [ 0 ] . UserLicense ;
204+ if ( ! license ) {
205+ throw new SfError (
206+ 'No license information found for Einstein Agent User profile. This may indicate an org configuration issue.' ,
207+ 'NoAgentLicensesError' ,
208+ [ 'Contact your Salesforce account team' , 'Verify that Agentforce is properly configured in your org' ]
209+ ) ;
210+ }
217211
218- const hasAvailableLicense = licenseInfo . some ( ( info ) => info . availableLicenses > 0 ) ;
212+ // Check if licenses are available
213+ const availableLicenses = license . TotalLicenses - license . UsedLicenses ;
219214
220- if ( ! hasAvailableLicense ) {
221- const licenseDetails = licenseResult . records
222- . map ( ( r ) => `${ r . MasterLabel } : ${ r . UsedLicenses } /${ r . TotalLicenses } used` )
223- . join ( ', ' ) ;
224- throw new SfError (
225- `No available Agent user licenses in this org. License usage: ${ licenseDetails } ` ,
226- 'NoAvailableAgentLicensesError' ,
227- [
228- 'Remove an existing agent user to free up a license' ,
229- 'Contact your Salesforce account team to add more Agent user licenses' ,
230- ]
231- ) ;
232- }
215+ if ( license . TotalLicenses === 0 ) {
216+ throw new SfError (
217+ `No ${ license . MasterLabel } licenses are provisioned in this org. These licenses are required to create agent users.` ,
218+ 'NoAgentLicensesError' ,
219+ [
220+ `Contact your Salesforce account team to add ${ license . MasterLabel } licenses to your org` ,
221+ 'Verify that Agentforce is enabled for your org' ,
222+ ]
223+ ) ;
224+ }
233225
234- // Log license availability
235- licenseResult . records . forEach ( ( record ) => {
236- const available = record . TotalLicenses - record . UsedLicenses ;
237- this . log ( `${ record . MasterLabel } : ${ available } of ${ record . TotalLicenses } licenses available` ) ;
238- } ) ;
239- } catch ( error ) {
240- if ( error instanceof SfError ) {
241- throw error ;
242- }
226+ if ( availableLicenses <= 0 ) {
243227 throw new SfError (
244- `Failed to check agent user license availability: ${ error instanceof Error ? error . message : String ( error ) } ` ,
245- 'LicenseCheckError' ,
246- [ 'Verify your connection to the org' , 'Check that you have permission to query UserLicense records' ]
228+ `No available ${ license . MasterLabel } licenses in this org. License usage: ${ license . UsedLicenses } /${ license . TotalLicenses } used` ,
229+ 'NoAvailableAgentLicensesError' ,
230+ [
231+ 'Remove an existing agent user to free up a license' ,
232+ `Contact your Salesforce account team to add more ${ license . MasterLabel } licenses` ,
233+ ]
247234 ) ;
248235 }
236+
237+ // Log license availability
238+ this . log ( `${ license . MasterLabel } : ${ availableLicenses } of ${ license . TotalLicenses } licenses available` ) ;
249239 }
250240
251241 // eslint-disable-next-line class-methods-use-this
@@ -272,101 +262,45 @@ export default class OrgCreateAgentUser extends SfCommand<AgentUserCreateRespons
272262 }
273263 }
274264
275- private async inferLocaleSettings ( connection : Connection ) : Promise < {
276- timeZone : string ;
277- locale : string ;
278- emailEncoding : string ;
279- language : string ;
280- } > {
281- try {
282- // Get locale settings from the current user (the one running the command)
283- const userId = connection . getAuthInfoFields ( ) . userId ;
284- if ( ! userId ) {
285- throw new Error ( 'Unable to determine current user ID' ) ;
286- }
287-
288- const soql = `SELECT TimeZoneSidKey, LocaleSidKey, EmailEncodingKey, LanguageLocaleKey FROM User WHERE Id = '${ userId } '` ;
289- const userResult = await connection . singleRecordQuery < {
290- TimeZoneSidKey : string ;
291- LocaleSidKey : string ;
292- EmailEncodingKey : string ;
293- LanguageLocaleKey : string ;
294- } > ( soql ) ;
295-
296- return {
297- timeZone : userResult . TimeZoneSidKey ,
298- locale : userResult . LocaleSidKey ,
299- emailEncoding : userResult . EmailEncodingKey ,
300- language : userResult . LanguageLocaleKey ,
301- } ;
302- } catch ( error ) {
303- // Fallback to sensible defaults if we can't query the current user
304- this . warn ( 'Unable to infer locale settings from current user, using defaults' ) ;
305- return {
306- timeZone : 'America/Los_Angeles' ,
307- locale : 'en_US' ,
308- emailEncoding : 'UTF-8' ,
309- language : 'en_US' ,
310- } ;
311- }
312- }
313-
314265 // eslint-disable-next-line class-methods-use-this
315266 private async createAgentUser (
316267 connection : Connection ,
317268 username : string ,
318269 profileId : string ,
319- localeSettings : {
320- timeZone : string ;
321- locale : string ;
322- emailEncoding : string ;
323- language : string ;
324- } ,
325270 nameFields : {
326271 firstName : string ;
327272 lastName : string ;
328273 }
329274 ) : Promise < string > {
330- try {
331- // Generate alias from username (max 8 chars)
332- // Take first part before @ or first 8 chars of username
333- const aliasPart = username . split ( '@' ) [ 0 ] . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '' ) ;
334- const alias = aliasPart . substring ( 0 , 8 ) ;
335-
336- const userRecord = await connection . sobject ( 'User' ) . create ( {
337- FirstName : nameFields . firstName ,
338- LastName : nameFields . lastName ,
339- Alias : alias ,
340- Email : username ,
341- Username : username ,
342- ProfileId : profileId ,
343- TimeZoneSidKey : localeSettings . timeZone ,
344- LocaleSidKey : localeSettings . locale ,
345- EmailEncodingKey : localeSettings . emailEncoding ,
346- LanguageLocaleKey : localeSettings . language ,
347- } ) ;
348-
349- if ( ! userRecord . success || ! userRecord . id ) {
350- const errorMessages = userRecord . errors ?. map ( ( e ) => e . message ) . join ( ', ' ) ?? 'Unknown error' ;
351- throw new SfError ( `Failed to create agent user: ${ errorMessages } ` , 'UserCreationError' , [
352- 'Verify that the username is globally unique' ,
353- 'Ensure the Einstein Agent User profile exists in your org' ,
354- 'Check that Agentforce is enabled for your org' ,
355- 'Verify you have permission to create User records' ,
356- ] ) ;
357- }
275+ // Generate alias from username (max 8 chars)
276+ // Take first part before @ or first 8 chars of username
277+ const aliasPart = username . split ( '@' ) [ 0 ] . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '' ) ;
278+ const alias = aliasPart . substring ( 0 , 8 ) ;
279+
280+ const userRecord = await connection . sobject ( 'User' ) . create ( {
281+ FirstName : nameFields . firstName ,
282+ LastName : nameFields . lastName ,
283+ Alias : alias ,
284+ Email : username ,
285+ Username : username ,
286+ ProfileId : profileId ,
287+ TimeZoneSidKey : 'America/Los_Angeles' ,
288+ LocaleSidKey : 'en_US' ,
289+ EmailEncodingKey : 'UTF-8' ,
290+ LanguageLocaleKey : 'en_US' ,
291+ } ) ;
358292
359- return userRecord . id ;
360- } catch ( error ) {
361- if ( error instanceof SfError ) {
362- throw error ;
363- }
364- throw new SfError (
365- `Failed to create agent user: ${ error instanceof Error ? error . message : String ( error ) } ` ,
366- 'UserCreationError' ,
367- [ 'Verify your connection to the org' , 'Check that you have permission to create User records' ]
368- ) ;
293+ if ( ! userRecord . success || ! userRecord . id ) {
294+ const errorMessages = userRecord . errors ?. map ( ( e ) => e . message ) . join ( ', ' ) ?? 'Unknown error' ;
295+ throw new SfError ( `Failed to create agent user: ${ errorMessages } ` , 'UserCreationError' , [
296+ 'Verify that the username is globally unique' ,
297+ 'Ensure the Einstein Agent User profile exists in your org' ,
298+ 'Check that Agentforce is enabled for your org' ,
299+ 'Verify you have permission to create User records' ,
300+ ] ) ;
369301 }
302+
303+ return userRecord . id ;
370304 }
371305
372306 private async assignPermissionSets (
0 commit comments