From c54cd1627167c5932ff5ac3d0c9329cbb8fd5c4b Mon Sep 17 00:00:00 2001 From: Marcelino Llano Date: Fri, 13 Feb 2026 18:38:28 +0100 Subject: [PATCH 1/3] fix: use API name instead of label for published agents in preview picker --- src/commands/agent/preview.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commands/agent/preview.ts b/src/commands/agent/preview.ts index 78bc550..bc81383 100644 --- a/src/commands/agent/preview.ts +++ b/src/commands/agent/preview.ts @@ -91,7 +91,10 @@ export default class AgentPreview extends SfCommand { } else { const previewableAgents = await Agent.listPreviewable(conn, this.project!); const choices = previewableAgents.map((agent) => ({ - name: agent.source === AgentSource.PUBLISHED ? `${agent.name} (Published)` : `${agent.name} (Agent Script)`, + name: + agent.source === AgentSource.PUBLISHED + ? `${agent.developerName ?? agent.name} (Published)` + : `${agent.name} (Agent Script)`, value: agent, })); const choice = await select({ From 9b969d3935766924828d14b6beb2795b82c87c9b Mon Sep 17 00:00:00 2001 From: Marcelino Llano Date: Fri, 13 Feb 2026 21:47:54 +0100 Subject: [PATCH 2/3] feat: sort preview picker by type (script first) and alphabetically --- src/commands/agent/preview.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/commands/agent/preview.ts b/src/commands/agent/preview.ts index bc81383..114be22 100644 --- a/src/commands/agent/preview.ts +++ b/src/commands/agent/preview.ts @@ -90,7 +90,13 @@ export default class AgentPreview extends SfCommand { selectedAgent = await Agent.init({ connection: conn, project: this.project!, apiNameOrId }); } else { const previewableAgents = await Agent.listPreviewable(conn, this.project!); - const choices = previewableAgents.map((agent) => ({ + const sorted = previewableAgents.sort((a, b) => { + if (a.source !== b.source) { + return a.source === AgentSource.SCRIPT ? -1 : 1; + } + return a.name.localeCompare(b.name); + }); + const choices = sorted.map((agent) => ({ name: agent.source === AgentSource.PUBLISHED ? `${agent.developerName ?? agent.name} (Published)` From e54fe9c45c3f47c028711a5db1ba6243c8360a6b Mon Sep 17 00:00:00 2001 From: Marcelino Llano Date: Fri, 13 Feb 2026 21:50:40 +0100 Subject: [PATCH 3/3] test: add tests for preview picker sorting and label formatting --- src/commands/agent/preview.ts | 35 +++++---- test/commands/agent/preview/index.test.ts | 95 +++++++++++++++++++++++ 2 files changed, 117 insertions(+), 13 deletions(-) diff --git a/src/commands/agent/preview.ts b/src/commands/agent/preview.ts index 114be22..3026841 100644 --- a/src/commands/agent/preview.ts +++ b/src/commands/agent/preview.ts @@ -90,19 +90,7 @@ export default class AgentPreview extends SfCommand { selectedAgent = await Agent.init({ connection: conn, project: this.project!, apiNameOrId }); } else { const previewableAgents = await Agent.listPreviewable(conn, this.project!); - const sorted = previewableAgents.sort((a, b) => { - if (a.source !== b.source) { - return a.source === AgentSource.SCRIPT ? -1 : 1; - } - return a.name.localeCompare(b.name); - }); - const choices = sorted.map((agent) => ({ - name: - agent.source === AgentSource.PUBLISHED - ? `${agent.developerName ?? agent.name} (Published)` - : `${agent.name} (Agent Script)`, - value: agent, - })); + const choices = getPreviewChoices(previewableAgents); const choice = await select({ message: 'Select an agent', choices, @@ -171,3 +159,24 @@ export const validateAgent = (agent: AgentData): boolean => { return true; }; + +export const sortPreviewableAgents = (agents: PreviewableAgent[]): PreviewableAgent[] => + [...agents].sort((a, b) => { + if (a.source !== b.source) { + return a.source === AgentSource.SCRIPT ? -1 : 1; + } + return a.name.localeCompare(b.name); + }); + +export const getPreviewChoiceLabel = (agent: PreviewableAgent): string => + agent.source === AgentSource.PUBLISHED + ? `${agent.developerName ?? agent.name} (Published)` + : `${agent.name} (Agent Script)`; + +export const getPreviewChoices = ( + agents: PreviewableAgent[] +): Array<{ name: string; value: PreviewableAgent }> => + sortPreviewableAgents(agents).map((agent) => ({ + name: getPreviewChoiceLabel(agent), + value: agent, + })); diff --git a/test/commands/agent/preview/index.test.ts b/test/commands/agent/preview/index.test.ts index ba7a102..543befa 100644 --- a/test/commands/agent/preview/index.test.ts +++ b/test/commands/agent/preview/index.test.ts @@ -17,12 +17,16 @@ import { expect } from 'chai'; // import { Messages } from '@salesforce/core/messages'; import sinon from 'sinon'; +import { AgentSource, type PreviewableAgent } from '@salesforce/agents'; import { type AgentData, UNSUPPORTED_AGENTS, agentIsUnsupported, agentIsInactive, validateAgent, + sortPreviewableAgents, + getPreviewChoiceLabel, + getPreviewChoices, } from '../../../../src/commands/agent/preview.js'; // TODO - pull in error messages @@ -158,4 +162,95 @@ describe('Agent Preview', () => { expect(publishedAgent.source).to.equal('published'); }); }); + + describe('sortPreviewableAgents', () => { + it('places script agents before published agents', () => { + const agents: PreviewableAgent[] = [ + { name: 'Published_Agent', source: AgentSource.PUBLISHED, developerName: 'Published_Agent' }, + { name: 'Script_Agent', source: AgentSource.SCRIPT }, + ]; + const sorted = sortPreviewableAgents(agents); + expect(sorted[0].source).to.equal(AgentSource.SCRIPT); + expect(sorted[1].source).to.equal(AgentSource.PUBLISHED); + }); + + it('sorts alphabetically within the same source type', () => { + const agents: PreviewableAgent[] = [ + { name: 'Zebra_Agent', source: AgentSource.SCRIPT }, + { name: 'Alpha_Agent', source: AgentSource.SCRIPT }, + { name: 'Middle_Agent', source: AgentSource.SCRIPT }, + ]; + const sorted = sortPreviewableAgents(agents); + expect(sorted.map((a) => a.name)).to.deep.equal(['Alpha_Agent', 'Middle_Agent', 'Zebra_Agent']); + }); + + it('sorts by type first, then alphabetically', () => { + const agents: PreviewableAgent[] = [ + { name: 'Zebra_Published', source: AgentSource.PUBLISHED, developerName: 'Zebra_Published' }, + { name: 'Beta_Script', source: AgentSource.SCRIPT }, + { name: 'Alpha_Published', source: AgentSource.PUBLISHED, developerName: 'Alpha_Published' }, + { name: 'Alpha_Script', source: AgentSource.SCRIPT }, + ]; + const sorted = sortPreviewableAgents(agents); + expect(sorted.map((a) => a.name)).to.deep.equal([ + 'Alpha_Script', + 'Beta_Script', + 'Alpha_Published', + 'Zebra_Published', + ]); + }); + + it('does not mutate the original array', () => { + const agents: PreviewableAgent[] = [ + { name: 'B_Agent', source: AgentSource.SCRIPT }, + { name: 'A_Agent', source: AgentSource.SCRIPT }, + ]; + sortPreviewableAgents(agents); + expect(agents[0].name).to.equal('B_Agent'); + }); + }); + + describe('getPreviewChoiceLabel', () => { + it('uses developerName for published agents', () => { + const agent: PreviewableAgent = { + name: 'My Friendly Label', + source: AgentSource.PUBLISHED, + developerName: 'My_Api_Name', + }; + expect(getPreviewChoiceLabel(agent)).to.equal('My_Api_Name (Published)'); + }); + + it('falls back to name when developerName is undefined for published agents', () => { + const agent: PreviewableAgent = { + name: 'Fallback_Name', + source: AgentSource.PUBLISHED, + }; + expect(getPreviewChoiceLabel(agent)).to.equal('Fallback_Name (Published)'); + }); + + it('uses name for script agents', () => { + const agent: PreviewableAgent = { + name: 'My_Script_Agent', + source: AgentSource.SCRIPT, + }; + expect(getPreviewChoiceLabel(agent)).to.equal('My_Script_Agent (Agent Script)'); + }); + }); + + describe('getPreviewChoices', () => { + it('returns sorted choices with correct labels', () => { + const agents: PreviewableAgent[] = [ + { name: 'Published Label', source: AgentSource.PUBLISHED, developerName: 'Published_Api' }, + { name: 'Script_Agent', source: AgentSource.SCRIPT }, + ]; + const choices = getPreviewChoices(agents); + expect(choices).to.have.length(2); + expect(choices[0].name).to.equal('Script_Agent (Agent Script)'); + expect(choices[1].name).to.equal('Published_Api (Published)'); + }); + + it('returns empty array for empty input', () => { + expect(getPreviewChoices([])).to.deep.equal([]); + }); + }); });