@@ -321,15 +321,9 @@ function buildFeishuPayloadCard(params: {
321321 } ) ;
322322}
323323
324- /**
325- * Check whether any presentation block contains a visible command action
326- * that would be rendered as copyable text in the fallback output.
327- *
328- * Must match the same conditions used by the shared
329- * {@link renderMessagePresentationFallbackText} so that Feishu comment-thread
330- * guidance is only shown when a copyable command is actually rendered.
331- */
332- function hasRenderedCommandAction (
324+ // Keep this aligned with the shared fallback renderer: guidance is valid only
325+ // when the fallback text exposes a command the user can copy.
326+ function hasVisibleFallbackCommand (
333327 blocks : readonly MessagePresentationBlock [ ] | undefined ,
334328) : boolean {
335329 return (
@@ -364,11 +358,8 @@ function renderFeishuPresentationPayload({
364358 const existingFeishuData = isRecord ( payload . channelData ?. feishu )
365359 ? payload . channelData . feishu
366360 : undefined ;
367- // Preserve a rendered-command marker in channelData so the downstream
368- // comment-target branch in sendPayload can detect that a command was
369- // rendered even after core renderPresentationForDelivery strips the
370- // presentation field before calling sendPayload.
371- const hasCmd = hasRenderedCommandAction ( presentation ?. blocks ) ;
361+ // Core consumes presentation before sendPayload; carry the fallback fact.
362+ const fallbackHasCommand = hasVisibleFallbackCommand ( presentation ?. blocks ) ;
372363 return {
373364 ...payload ,
374365 text : renderMessagePresentationFallbackText ( { text : payload . text , presentation } ) ,
@@ -377,7 +368,7 @@ function renderFeishuPresentationPayload({
377368 feishu : {
378369 ...existingFeishuData ,
379370 card,
380- ...( hasCmd ? { hasRenderedCommandAction : true } : { } ) ,
371+ ...( fallbackHasCommand ? { fallbackHasCommand : true } : { } ) ,
381372 } ,
382373 } ,
383374 } ;
@@ -549,18 +540,12 @@ export const feishuOutbound: ChannelOutboundAdapter = {
549540 text : ctx . payload . text ,
550541 presentation : normalizedPresentation ,
551542 } ) ;
552- // Use isRecord to narrow channelData.feishu before reading the marker,
553- // matching the same pattern used in renderFeishuPresentationPayload.
554- const feishuMarker = isRecord ( ctx . payload . channelData ?. feishu )
555- ? ctx . payload . channelData . feishu . hasRenderedCommandAction
556- : undefined ;
557- const hasCmd =
558- hasRenderedCommandAction ( normalizedPresentation ?. blocks ) ||
559- // When core delivery strips presentation via renderPresentationForDelivery
560- // before calling sendPayload, the blocks check above returns false. Fall
561- // back to the marker set by renderFeishuPresentationPayload.
562- Boolean ( feishuMarker ) ;
563- const text = hasCmd
543+ // Direct delivery retains blocks; core-rendered delivery carries the fact.
544+ const fallbackHasCommand =
545+ hasVisibleFallbackCommand ( normalizedPresentation ?. blocks ) ||
546+ ( isRecord ( ctx . payload . channelData ?. feishu ) &&
547+ ctx . payload . channelData . feishu . fallbackHasCommand === true ) ;
548+ const text = fallbackHasCommand
564549 ? `${ presentationFallbackText } \n\n> Interactive buttons are unavailable in Feishu document comments. You can type the command shown above manually.`
565550 : presentationFallbackText ;
566551
0 commit comments