@@ -176,6 +176,33 @@ const requestJson = async (params) => {
176176 return response . json ( ) ;
177177} ;
178178
179+ const findExistingSkillVersion = async ( params ) => {
180+ const { apiBaseUrl, apiKey, name, version } = params ;
181+ const response = await requestJson ( {
182+ method : 'GET' ,
183+ url : buildApiUrl ( apiBaseUrl , '/skills/list' , {
184+ name,
185+ version,
186+ limit : 20 ,
187+ } ) ,
188+ apiKey,
189+ } ) ;
190+
191+ const items = Array . isArray ( response ?. items ) ? response . items : [ ] ;
192+ for ( const item of items ) {
193+ if ( ! item || typeof item !== 'object' || Array . isArray ( item ) ) {
194+ continue ;
195+ }
196+ const itemName = typeof item . name === 'string' ? item . name . trim ( ) : '' ;
197+ const itemVersion = typeof item . version === 'string' ? item . version . trim ( ) : '' ;
198+ if ( itemName === name && itemVersion === version ) {
199+ return item ;
200+ }
201+ }
202+
203+ return null ;
204+ } ;
205+
179206const parseEventPayload = async ( ) => {
180207 const eventPath = getEnv ( 'GITHUB_EVENT_PATH' ) ;
181208 if ( ! eventPath ) {
@@ -237,15 +264,19 @@ const buildPublishMarkdown = (result) => {
237264 const lines = [ ] ;
238265 lines . push ( '### HCS-26 skill publish result' ) ;
239266 lines . push ( '' ) ;
267+ lines . push ( `- Status: \`${ result . published === false ? 'skipped' : 'published' } \`` ) ;
240268 lines . push ( `- Name: \`${ result . skillName } \`` ) ;
241269 lines . push ( `- Version: \`${ result . skillVersion } \`` ) ;
242- lines . push ( `- Quote ID: \`${ result . quoteId } \`` ) ;
243- lines . push ( `- Job ID: \`${ result . jobId } \`` ) ;
270+ lines . push ( `- Quote ID: \`${ result . quoteId || 'n/a' } \`` ) ;
271+ lines . push ( `- Job ID: \`${ result . jobId || 'n/a' } \`` ) ;
244272 lines . push ( `- Directory Topic: \`${ result . directoryTopicId ?? 'n/a' } \`` ) ;
245273 lines . push ( `- Package Topic: \`${ result . packageTopicId ?? 'n/a' } \`` ) ;
246274 lines . push ( `- skill.json HRL: \`${ result . skillJsonHrl ?? 'n/a' } \`` ) ;
247- lines . push ( `- Credits: \`${ result . credits } \`` ) ;
248- lines . push ( `- Estimated Cost: \`${ result . estimatedCostHbar } HBAR\`` ) ;
275+ lines . push ( `- Credits: \`${ result . credits ?? 0 } \`` ) ;
276+ lines . push ( `- Estimated Cost: \`${ result . estimatedCostHbar ?? '0' } HBAR\`` ) ;
277+ if ( result . published === false && result . skippedReason ) {
278+ lines . push ( `- Skip reason: \`${ result . skippedReason } \`` ) ;
279+ }
249280 lines . push ( '' ) ;
250281 lines . push ( `- Repo: \`${ result . repoUrl ?? 'n/a' } \`` ) ;
251282 lines . push ( `- Commit: \`${ result . commitSha ?? 'n/a' } \`` ) ;
@@ -417,6 +448,62 @@ const run = async () => {
417448 throw new ActionError ( 'skill.json must include description.' ) ;
418449 }
419450
451+ const existingVersion = await findExistingSkillVersion ( {
452+ apiBaseUrl,
453+ apiKey,
454+ name : skillName ,
455+ version : skillVersion ,
456+ } ) ;
457+
458+ if ( existingVersion ) {
459+ const result = {
460+ skillName,
461+ skillVersion,
462+ quoteId : '' ,
463+ jobId : '' ,
464+ directoryTopicId :
465+ typeof existingVersion . directoryTopicId === 'string'
466+ ? existingVersion . directoryTopicId
467+ : null ,
468+ packageTopicId :
469+ typeof existingVersion . packageTopicId === 'string'
470+ ? existingVersion . packageTopicId
471+ : typeof existingVersion . versionRegistryTopicId === 'string'
472+ ? existingVersion . versionRegistryTopicId
473+ : null ,
474+ skillJsonHrl :
475+ typeof existingVersion . skillJsonHrl === 'string'
476+ ? existingVersion . skillJsonHrl
477+ : typeof existingVersion . manifestHrl === 'string'
478+ ? existingVersion . manifestHrl
479+ : null ,
480+ credits : 0 ,
481+ estimatedCostHbar : '0' ,
482+ repoUrl : repoUrl || null ,
483+ commitSha : commitSha || null ,
484+ published : false ,
485+ skippedReason : 'version-exists' ,
486+ } ;
487+
488+ stdout ( `Skill version ${ skillName } @${ skillVersion } already exists. Skipping publish.` ) ;
489+
490+ const markdown = buildPublishMarkdown ( result ) ;
491+ await appendStepSummary ( markdown ) ;
492+
493+ await setActionOutput ( 'skill-name' , result . skillName ) ;
494+ await setActionOutput ( 'skill-version' , result . skillVersion ) ;
495+ await setActionOutput ( 'quote-id' , '' ) ;
496+ await setActionOutput ( 'job-id' , '' ) ;
497+ await setActionOutput ( 'directory-topic-id' , result . directoryTopicId ?? '' ) ;
498+ await setActionOutput ( 'package-topic-id' , result . packageTopicId ?? '' ) ;
499+ await setActionOutput ( 'skill-json-hrl' , result . skillJsonHrl ?? '' ) ;
500+ await setActionOutput ( 'annotation-target' , 'none' ) ;
501+ await setActionOutput ( 'result-json' , JSON . stringify ( result , null , 2 ) ) ;
502+
503+ stdout ( markdown ) ;
504+ return ;
505+ }
506+
420507 const config = await requestJson ( {
421508 method : 'GET' ,
422509 url : buildApiUrl ( apiBaseUrl , '/skills/config' ) ,
0 commit comments