@codex-app-sdk/vue 0.0.0-stage → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +39 -2
  3. package/dist/audio/apple-speech-transcription.d.ts +12 -0
  4. package/dist/audio/apple-speech-transcription.d.ts.map +1 -0
  5. package/dist/audio/browser-audio-recorder.d.ts +21 -0
  6. package/dist/audio/browser-audio-recorder.d.ts.map +1 -0
  7. package/dist/chat/ChatAnimatedDiffStat.vue.d.ts +9 -0
  8. package/dist/chat/ChatAnimatedDiffStat.vue.d.ts.map +1 -0
  9. package/dist/chat/ChatApprovalCard.vue.d.ts +33 -0
  10. package/dist/chat/ChatApprovalCard.vue.d.ts.map +1 -0
  11. package/dist/chat/ChatAttachmentBlock.vue.d.ts +10 -0
  12. package/dist/chat/ChatAttachmentBlock.vue.d.ts.map +1 -0
  13. package/dist/chat/ChatCompactionMessage.vue.d.ts +9 -0
  14. package/dist/chat/ChatCompactionMessage.vue.d.ts.map +1 -0
  15. package/dist/chat/ChatComposerActionMenu.vue.d.ts +43 -0
  16. package/dist/chat/ChatComposerActionMenu.vue.d.ts.map +1 -0
  17. package/dist/chat/ChatComposerActiveModes.vue.d.ts +15 -0
  18. package/dist/chat/ChatComposerActiveModes.vue.d.ts.map +1 -0
  19. package/dist/chat/ChatComposerAtMentionMenu.vue.d.ts +38 -0
  20. package/dist/chat/ChatComposerAtMentionMenu.vue.d.ts.map +1 -0
  21. package/dist/chat/ChatComposerFileMentionMenu.vue.d.ts +14 -0
  22. package/dist/chat/ChatComposerFileMentionMenu.vue.d.ts.map +1 -0
  23. package/dist/chat/ChatComposerPluginMenu.vue.d.ts +13 -0
  24. package/dist/chat/ChatComposerPluginMenu.vue.d.ts.map +1 -0
  25. package/dist/chat/ChatComposerShelf.vue.d.ts +38 -0
  26. package/dist/chat/ChatComposerShelf.vue.d.ts.map +1 -0
  27. package/dist/chat/ChatComposerSkillMenu.vue.d.ts +15 -0
  28. package/dist/chat/ChatComposerSkillMenu.vue.d.ts.map +1 -0
  29. package/dist/chat/ChatComposerSlashMenu.vue.d.ts +16 -0
  30. package/dist/chat/ChatComposerSlashMenu.vue.d.ts.map +1 -0
  31. package/dist/chat/ChatComposerVoiceButton.vue.d.ts +14 -0
  32. package/dist/chat/ChatComposerVoiceButton.vue.d.ts.map +1 -0
  33. package/dist/chat/ChatComposerVoiceField.vue.d.ts +11 -0
  34. package/dist/chat/ChatComposerVoiceField.vue.d.ts.map +1 -0
  35. package/dist/chat/ChatComposerWaveform.vue.d.ts +20 -0
  36. package/dist/chat/ChatComposerWaveform.vue.d.ts.map +1 -0
  37. package/dist/chat/ChatConfirmationRequest.vue.d.ts +14 -0
  38. package/dist/chat/ChatConfirmationRequest.vue.d.ts.map +1 -0
  39. package/dist/chat/ChatContextUsageIndicator.vue.d.ts +8 -0
  40. package/dist/chat/ChatContextUsageIndicator.vue.d.ts.map +1 -0
  41. package/dist/chat/ChatCopyButton.vue.d.ts +10 -0
  42. package/dist/chat/ChatCopyButton.vue.d.ts.map +1 -0
  43. package/dist/chat/ChatFoldTransition.vue.d.ts +17 -0
  44. package/dist/chat/ChatFoldTransition.vue.d.ts.map +1 -0
  45. package/dist/chat/ChatFollowUps.vue.d.ts +12 -0
  46. package/dist/chat/ChatFollowUps.vue.d.ts.map +1 -0
  47. package/dist/chat/ChatGoal.vue.d.ts +14 -0
  48. package/dist/chat/ChatGoal.vue.d.ts.map +1 -0
  49. package/dist/chat/ChatIconButton.vue.d.ts +25 -0
  50. package/dist/chat/ChatIconButton.vue.d.ts.map +1 -0
  51. package/dist/chat/ChatImageLightbox.vue.d.ts +19 -0
  52. package/dist/chat/ChatImageLightbox.vue.d.ts.map +1 -0
  53. package/dist/chat/ChatMediaBlock.vue.d.ts +10 -0
  54. package/dist/chat/ChatMediaBlock.vue.d.ts.map +1 -0
  55. package/dist/chat/ChatMentionChip.vue.d.ts +11 -0
  56. package/dist/chat/ChatMentionChip.vue.d.ts.map +1 -0
  57. package/dist/chat/ChatMermaidBlock.vue.d.ts +7 -0
  58. package/dist/chat/ChatMermaidBlock.vue.d.ts.map +1 -0
  59. package/dist/chat/ChatMessageActions.vue.d.ts +36 -0
  60. package/dist/chat/ChatMessageActions.vue.d.ts.map +1 -0
  61. package/dist/chat/ChatMessageBlock.vue.d.ts +96 -0
  62. package/dist/chat/ChatMessageBlock.vue.d.ts.map +1 -0
  63. package/dist/chat/ChatMessageEditor.vue.d.ts +16 -0
  64. package/dist/chat/ChatMessageEditor.vue.d.ts.map +1 -0
  65. package/dist/chat/ChatModelReasoningSelector.vue.d.ts +36 -0
  66. package/dist/chat/ChatModelReasoningSelector.vue.d.ts.map +1 -0
  67. package/dist/chat/ChatQuestionRequest.vue.d.ts +17 -0
  68. package/dist/chat/ChatQuestionRequest.vue.d.ts.map +1 -0
  69. package/dist/chat/ChatQueuedPrompt.vue.d.ts +18 -0
  70. package/dist/chat/ChatQueuedPrompt.vue.d.ts.map +1 -0
  71. package/dist/chat/ChatQueuedPrompts.vue.d.ts +18 -0
  72. package/dist/chat/ChatQueuedPrompts.vue.d.ts.map +1 -0
  73. package/dist/chat/ChatRichTextEditor.vue.d.ts +63 -0
  74. package/dist/chat/ChatRichTextEditor.vue.d.ts.map +1 -0
  75. package/dist/chat/ChatToolCall.vue.d.ts +24 -0
  76. package/dist/chat/ChatToolCall.vue.d.ts.map +1 -0
  77. package/dist/chat/ChatToolCallTitle.vue.d.ts +24 -0
  78. package/dist/chat/ChatToolCallTitle.vue.d.ts.map +1 -0
  79. package/dist/chat/ChatToolConfirmation.vue.d.ts +24 -0
  80. package/dist/chat/ChatToolConfirmation.vue.d.ts.map +1 -0
  81. package/dist/chat/ChatToolGroup.vue.d.ts +23 -0
  82. package/dist/chat/ChatToolGroup.vue.d.ts.map +1 -0
  83. package/dist/chat/ChatToolIcon.vue.d.ts +10 -0
  84. package/dist/chat/ChatToolIcon.vue.d.ts.map +1 -0
  85. package/dist/chat/ChatToolUserInputRequest.vue.d.ts +27 -0
  86. package/dist/chat/ChatToolUserInputRequest.vue.d.ts.map +1 -0
  87. package/dist/chat/ChatTurnGitInfo.vue.d.ts +8 -0
  88. package/dist/chat/ChatTurnGitInfo.vue.d.ts.map +1 -0
  89. package/dist/chat/ChatUserText.vue.d.ts +37 -0
  90. package/dist/chat/ChatUserText.vue.d.ts.map +1 -0
  91. package/dist/chat/ChatVisualizationBlock.vue.d.ts +13 -0
  92. package/dist/chat/ChatVisualizationBlock.vue.d.ts.map +1 -0
  93. package/dist/chat/ChatWorkGroup.vue.d.ts +21 -0
  94. package/dist/chat/ChatWorkGroup.vue.d.ts.map +1 -0
  95. package/dist/chat/approval-presets.d.ts +10 -0
  96. package/dist/chat/approval-presets.d.ts.map +1 -0
  97. package/dist/chat/chat-i18n.d.ts +6 -0
  98. package/dist/chat/chat-i18n.d.ts.map +1 -0
  99. package/dist/chat/codex-capabilities.d.ts +3 -0
  100. package/dist/chat/codex-capabilities.d.ts.map +1 -0
  101. package/dist/chat/codex-commands.d.ts +3 -0
  102. package/dist/chat/codex-commands.d.ts.map +1 -0
  103. package/dist/chat/composer-commands.d.ts +11 -0
  104. package/dist/chat/composer-commands.d.ts.map +1 -0
  105. package/dist/chat/composer-mentions-custom.d.ts +25 -0
  106. package/dist/chat/composer-mentions-custom.d.ts.map +1 -0
  107. package/dist/chat/composer-mentions.d.ts +9 -0
  108. package/dist/chat/composer-mentions.d.ts.map +1 -0
  109. package/dist/chat/composer-plugins.d.ts +7 -0
  110. package/dist/chat/composer-plugins.d.ts.map +1 -0
  111. package/dist/chat/composer-prompt-history.d.ts +12 -0
  112. package/dist/chat/composer-prompt-history.d.ts.map +1 -0
  113. package/dist/chat/composer-search.d.ts +5 -0
  114. package/dist/chat/composer-search.d.ts.map +1 -0
  115. package/dist/chat/composer-skills.d.ts +22 -0
  116. package/dist/chat/composer-skills.d.ts.map +1 -0
  117. package/dist/chat/contracts.d.ts +194 -0
  118. package/dist/chat/contracts.d.ts.map +1 -0
  119. package/dist/chat/conversation-links.d.ts +9 -0
  120. package/dist/chat/conversation-links.d.ts.map +1 -0
  121. package/dist/chat/file-search.d.ts +5 -0
  122. package/dist/chat/file-search.d.ts.map +1 -0
  123. package/dist/chat/html-escape.d.ts +3 -0
  124. package/dist/chat/html-escape.d.ts.map +1 -0
  125. package/dist/chat/message-actions.d.ts +7 -0
  126. package/dist/chat/message-actions.d.ts.map +1 -0
  127. package/dist/chat/message-blocks.d.ts +55 -0
  128. package/dist/chat/message-blocks.d.ts.map +1 -0
  129. package/dist/chat/message-image.d.ts +18 -0
  130. package/dist/chat/message-image.d.ts.map +1 -0
  131. package/dist/chat/message-markdown.d.ts +13 -0
  132. package/dist/chat/message-markdown.d.ts.map +1 -0
  133. package/dist/chat/message-text-selection.d.ts +16 -0
  134. package/dist/chat/message-text-selection.d.ts.map +1 -0
  135. package/dist/chat/message-time.d.ts +3 -0
  136. package/dist/chat/message-time.d.ts.map +1 -0
  137. package/dist/chat/message-work-state.d.ts +20 -0
  138. package/dist/chat/message-work-state.d.ts.map +1 -0
  139. package/dist/chat/portal-theme.d.ts +6 -0
  140. package/dist/chat/portal-theme.d.ts.map +1 -0
  141. package/dist/chat/queued-prompts.d.ts +6 -0
  142. package/dist/chat/queued-prompts.d.ts.map +1 -0
  143. package/dist/chat/renderer-message-adapter.d.ts +7 -0
  144. package/dist/chat/renderer-message-adapter.d.ts.map +1 -0
  145. package/dist/chat/syntax-highlighting.d.ts +3 -0
  146. package/dist/chat/syntax-highlighting.d.ts.map +1 -0
  147. package/dist/chat/tool-call-details.d.ts +6 -0
  148. package/dist/chat/tool-call-details.d.ts.map +1 -0
  149. package/dist/chat/tool-presentation.d.ts +20 -0
  150. package/dist/chat/tool-presentation.d.ts.map +1 -0
  151. package/dist/chat/tool-status.d.ts +35 -0
  152. package/dist/chat/tool-status.d.ts.map +1 -0
  153. package/dist/chat/tool-visibility.d.ts +6 -0
  154. package/dist/chat/tool-visibility.d.ts.map +1 -0
  155. package/dist/chat/types.d.ts +95 -0
  156. package/dist/chat/types.d.ts.map +1 -0
  157. package/dist/chat/use-chat-composer-suggestions.d.ts +63 -0
  158. package/dist/chat/use-chat-composer-suggestions.d.ts.map +1 -0
  159. package/dist/chat/use-chat-composer-voice.d.ts +50 -0
  160. package/dist/chat/use-chat-composer-voice.d.ts.map +1 -0
  161. package/dist/chat/use-conversation-escape-interrupt.d.ts +13 -0
  162. package/dist/chat/use-conversation-escape-interrupt.d.ts.map +1 -0
  163. package/dist/chat/user-text.d.ts +32 -0
  164. package/dist/chat/user-text.d.ts.map +1 -0
  165. package/dist/chat/visualization.d.ts +6 -0
  166. package/dist/chat/visualization.d.ts.map +1 -0
  167. package/dist/codex-theme.d.ts +12 -0
  168. package/dist/codex-theme.d.ts.map +1 -0
  169. package/dist/components/CodexApprovalPrompt.vue.d.ts +15 -0
  170. package/dist/components/CodexApprovalPrompt.vue.d.ts.map +1 -0
  171. package/dist/components/CodexComposer.vue.d.ts +110 -0
  172. package/dist/components/CodexComposer.vue.d.ts.map +1 -0
  173. package/dist/components/CodexComposerMenu.vue.d.ts +43 -0
  174. package/dist/components/CodexComposerMenu.vue.d.ts.map +1 -0
  175. package/dist/components/CodexComposerMenuList.vue.d.ts +29 -0
  176. package/dist/components/CodexComposerMenuList.vue.d.ts.map +1 -0
  177. package/dist/components/CodexComposerSendButton.vue.d.ts +25 -0
  178. package/dist/components/CodexComposerSendButton.vue.d.ts.map +1 -0
  179. package/dist/components/CodexConversationHistoryLoader.vue.d.ts +4 -0
  180. package/dist/components/CodexConversationHistoryLoader.vue.d.ts.map +1 -0
  181. package/dist/components/CodexConversationPane.vue.d.ts +254 -0
  182. package/dist/components/CodexConversationPane.vue.d.ts.map +1 -0
  183. package/dist/components/CodexConversationSidebar.vue.d.ts +25 -0
  184. package/dist/components/CodexConversationSidebar.vue.d.ts.map +1 -0
  185. package/dist/components/CodexMessage.vue.d.ts +141 -0
  186. package/dist/components/CodexMessage.vue.d.ts.map +1 -0
  187. package/dist/components/CodexMessageList.vue.d.ts +178 -0
  188. package/dist/components/CodexMessageList.vue.d.ts.map +1 -0
  189. package/dist/components/CodexMessageTurn.vue.d.ts +28 -0
  190. package/dist/components/CodexMessageTurn.vue.d.ts.map +1 -0
  191. package/dist/components/CodexScrollToBottom.vue.d.ts +13 -0
  192. package/dist/components/CodexScrollToBottom.vue.d.ts.map +1 -0
  193. package/dist/components/CodexWorkbenchLayout.vue.d.ts +25 -0
  194. package/dist/components/CodexWorkbenchLayout.vue.d.ts.map +1 -0
  195. package/dist/components/composer-menu-items.d.ts +29 -0
  196. package/dist/components/composer-menu-items.d.ts.map +1 -0
  197. package/dist/composer-menu.d.ts +49 -0
  198. package/dist/composer-menu.d.ts.map +1 -0
  199. package/dist/composer-state.d.ts +8 -0
  200. package/dist/composer-state.d.ts.map +1 -0
  201. package/dist/conversation-pane-controller.d.ts +149 -0
  202. package/dist/conversation-pane-controller.d.ts.map +1 -0
  203. package/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  204. package/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  205. package/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  206. package/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  207. package/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  208. package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  209. package/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  210. package/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  211. package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  212. package/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  213. package/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  214. package/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  215. package/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  216. package/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  217. package/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  218. package/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  219. package/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  220. package/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  221. package/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  222. package/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  223. package/dist/icons/app-icons.d.ts +2 -0
  224. package/dist/icons/app-icons.d.ts.map +1 -0
  225. package/dist/index.d.ts +99 -0
  226. package/dist/index.d.ts.map +1 -0
  227. package/dist/index.js +8668 -0
  228. package/dist/index.js.map +1 -0
  229. package/dist/native-capabilities.d.ts +11 -0
  230. package/dist/native-capabilities.d.ts.map +1 -0
  231. package/dist/styles.css +4 -0
  232. package/dist/types.d.ts +2 -0
  233. package/dist/types.d.ts.map +1 -0
  234. package/dist/use-codex-live-chat.d.ts +34 -0
  235. package/dist/use-codex-live-chat.d.ts.map +1 -0
  236. package/dist/use-codex-surface.d.ts +3639 -0
  237. package/dist/use-codex-surface.d.ts.map +1 -0
  238. package/package.json +52 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["$slots","$slots","$slots","$emit","$emit","$emit","$slots","$emit","$slots","$emit","$emit","$emit","$emit","$slots","$slots","$slots","$slots","$slots","$emit","$emit"],"sources":["../src/chat/contracts.ts","../src/chat/codex-capabilities.ts","../src/chat/codex-commands.ts","../src/chat/composer-prompt-history.ts","../src/components/CodexComposerSendButton.vue","../src/components/CodexComposerSendButton.vue","../src/chat/ChatComposerActiveModes.vue","../src/chat/ChatComposerActiveModes.vue","../src/chat/approval-presets.ts","../src/components/composer-menu-items.ts","../src/components/CodexComposerMenuList.vue","../src/components/CodexComposerMenuList.vue","../src/components/CodexComposerMenu.vue","../src/components/CodexComposerMenu.vue","../src/chat/ChatComposerActionMenu.vue","../src/chat/ChatComposerActionMenu.vue","../src/chat/ChatComposerVoiceButton.vue","../src/chat/ChatComposerVoiceButton.vue","../src/chat/ChatComposerWaveform.vue","../src/chat/ChatComposerWaveform.vue","../src/chat/ChatComposerVoiceField.vue","../src/chat/ChatComposerVoiceField.vue","../src/chat/conversation-links.ts","../src/chat/types.ts","../src/chat/tool-status.ts","../src/chat/chat-i18n.ts","../src/chat/ChatContextUsageIndicator.vue","../src/chat/ChatContextUsageIndicator.vue","../src/chat/ChatModelReasoningSelector.vue","../src/chat/ChatModelReasoningSelector.vue","../src/chat/composer-search.ts","../src/chat/composer-plugins.ts","../src/chat/ChatComposerAtMentionMenu.vue","../src/chat/ChatComposerAtMentionMenu.vue","../src/chat/composer-skills.ts","../src/chat/ChatComposerSkillMenu.vue","../src/chat/ChatComposerSkillMenu.vue","../src/chat/composer-commands.ts","../src/chat/ChatComposerSlashMenu.vue","../src/chat/ChatComposerSlashMenu.vue","../src/chat/ChatMentionChip.vue","../src/chat/ChatMentionChip.vue","../src/chat/composer-mentions-custom.ts","../src/chat/ChatRichTextEditor.vue","../src/chat/ChatRichTextEditor.vue","../src/chat/composer-mentions.ts","../src/chat/file-search.ts","../src/chat/use-chat-composer-suggestions.ts","../src/audio/browser-audio-recorder.ts","../src/audio/apple-speech-transcription.ts","../src/native-capabilities.ts","../src/chat/use-chat-composer-voice.ts","../src/composer-state.ts","../src/components/CodexComposer.vue","../src/components/CodexComposer.vue","../src/chat/ChatApprovalCard.vue","../src/chat/ChatApprovalCard.vue","../src/components/CodexApprovalPrompt.vue","../src/components/CodexApprovalPrompt.vue","../src/conversation-pane-controller.ts","../src/chat/message-blocks.ts","../src/chat/renderer-message-adapter.ts","../src/chat/use-conversation-escape-interrupt.ts","../src/chat/message-work-state.ts","../src/chat/ChatAnimatedDiffStat.vue","../src/chat/ChatAnimatedDiffStat.vue","../src/chat/ChatToolIcon.vue","../src/chat/ChatToolIcon.vue","../src/chat/ChatToolCallTitle.vue","../src/chat/ChatToolCallTitle.vue","../src/chat/ChatToolUserInputRequest.vue","../src/chat/ChatToolUserInputRequest.vue","../src/chat/ChatQuestionRequest.vue","../src/chat/ChatQuestionRequest.vue","../src/chat/ChatToolConfirmation.vue","../src/chat/ChatToolConfirmation.vue","../src/chat/ChatConfirmationRequest.vue","../src/chat/ChatConfirmationRequest.vue","../src/chat/ChatGoal.vue","../src/chat/ChatGoal.vue","../src/chat/ChatQueuedPrompt.vue","../src/chat/ChatQueuedPrompt.vue","../src/chat/ChatQueuedPrompts.vue","../src/chat/ChatQueuedPrompts.vue","../src/chat/ChatTurnGitInfo.vue","../src/chat/ChatTurnGitInfo.vue","../src/chat/ChatComposerShelf.vue","../src/chat/ChatComposerShelf.vue","../src/components/CodexConversationHistoryLoader.vue","../src/chat/tool-visibility.ts","../src/chat/ChatIconButton.vue","../src/chat/ChatIconButton.vue","../src/chat/portal-theme.ts","../src/chat/ChatImageLightbox.vue","../src/chat/ChatImageLightbox.vue","../src/chat/ChatAttachmentBlock.vue","../src/chat/ChatAttachmentBlock.vue","../src/chat/ChatFollowUps.vue","../src/chat/ChatFollowUps.vue","../src/chat/ChatCopyButton.vue","../src/chat/ChatCopyButton.vue","../src/chat/ChatFoldTransition.vue","../src/chat/ChatFoldTransition.vue","../src/chat/ChatMediaBlock.vue","../src/chat/ChatMediaBlock.vue","../src/chat/ChatMermaidBlock.vue","../src/chat/ChatMermaidBlock.vue","../src/chat/tool-presentation.ts","../src/chat/tool-call-details.ts","../src/chat/ChatToolCall.vue","../src/chat/ChatToolCall.vue","../src/chat/ChatToolGroup.vue","../src/chat/ChatToolGroup.vue","../src/chat/user-text.ts","../src/chat/ChatUserText.vue","../src/chat/ChatUserText.vue","../src/chat/ChatVisualizationBlock.vue","../src/chat/ChatVisualizationBlock.vue","../src/chat/ChatWorkGroup.vue","../src/chat/ChatWorkGroup.vue","../src/chat/html-escape.ts","../src/chat/syntax-highlighting.ts","../src/chat/message-markdown.ts","../src/chat/message-actions.ts","../src/chat/ChatMessageBlock.vue","../src/chat/ChatMessageBlock.vue","../src/chat/message-time.ts","../src/chat/ChatMessageActions.vue","../src/chat/ChatMessageActions.vue","../src/chat/ChatCompactionMessage.vue","../src/chat/ChatCompactionMessage.vue","../src/chat/ChatMessageEditor.vue","../src/chat/ChatMessageEditor.vue","../src/components/CodexMessage.vue","../src/components/CodexMessage.vue","../src/components/CodexMessageTurn.vue","../src/components/CodexMessageTurn.vue","../src/components/CodexScrollToBottom.vue","../src/components/CodexScrollToBottom.vue","../src/components/CodexMessageList.vue","../src/components/CodexMessageList.vue","../src/components/CodexWorkbenchLayout.vue","../src/components/CodexWorkbenchLayout.vue","../src/components/CodexConversationPane.vue","../src/components/CodexConversationPane.vue","../src/components/CodexConversationSidebar.vue","../src/components/CodexConversationSidebar.vue","../src/chat/ChatComposerFileMentionMenu.vue","../src/chat/ChatComposerFileMentionMenu.vue","../src/chat/ChatComposerPluginMenu.vue","../src/chat/ChatComposerPluginMenu.vue","../src/chat/queued-prompts.ts","../src/use-codex-surface.ts","../src/use-codex-live-chat.ts","../src/codex-theme.ts"],"sourcesContent":["import type { CodexSpeechTranscriptionResult as NativeSpeechTranscriptionResult } from '@codex-app-sdk/core/native';\nimport type { CodexSurfaceServiceTier } from '@codex-app-sdk/core/surface';\n\nexport type ApprovalPreset = 'ask-for-approval' | 'approve-for-me' | 'full-access';\n\nexport type ReasoningEffort = string;\n\nexport type CodexCapabilities = {\n models: boolean;\n skills: boolean;\n reasoningEffort: boolean;\n serviceTier?: boolean;\n planMode: boolean;\n goals: boolean;\n steerPrompt: boolean;\n interrupt: boolean;\n history: boolean;\n deleteTurn: boolean;\n editTurn: boolean;\n retryTurn: boolean;\n approvals: boolean;\n approvalPresets?: readonly ApprovalPreset[];\n};\n\nexport type CodexReasoningEffortOption = {\n reasoningEffort: ReasoningEffort;\n description: string;\n};\n\nexport type CodexModelOption = {\n id: string;\n model: string;\n displayName: string;\n description?: string;\n hidden?: boolean;\n supportedReasoningEfforts?: readonly CodexReasoningEffortOption[];\n defaultReasoningEffort?: ReasoningEffort | null;\n serviceTiers?: readonly CodexSurfaceServiceTier[];\n defaultServiceTier?: string | null;\n isDefault?: boolean;\n providerMetadata?: Record<string, unknown>;\n};\n\nexport type CodexSkillSummary = {\n id?: string;\n name: string;\n description?: string;\n shortDescription?: string;\n displayName?: string;\n iconSmall?: string;\n iconLarge?: string;\n brandColor?: string;\n defaultPrompt?: string;\n path: string;\n scope?: string;\n enabled: boolean;\n providerMetadata?: Record<string, unknown>;\n};\n\nexport type CodexCommandSummary = {\n id: string;\n name: string;\n displayName?: string;\n description?: string;\n slashName?: string;\n submitOnSelect?: boolean;\n composerMode?: {\n label?: string;\n placeholder?: string;\n };\n providerMetadata?: Record<string, unknown>;\n};\n\nexport type CodexFileSearchItem = {\n name: string;\n path: string;\n};\n\nexport type CodexConversationFileAction = 'read' | 'edit' | 'create';\n\nexport type CodexConversationLink =\n | { href: string; kind: 'external' }\n | {\n href: string;\n kind: 'file';\n path: string;\n /** Canonical alias for hosts handling a clicked tool target. */\n filepath?: string;\n /** Present for file-operation tool targets; absent for ordinary markdown links. */\n action?: CodexConversationFileAction;\n /** Conversation turn that produced the tool target, when available. */\n turnId?: string;\n /** Assistant message that contains the tool target, when available. */\n messageId?: string;\n /** App-server item that produced the tool target, when available. */\n itemId?: string;\n line?: number;\n column?: number;\n };\n\nexport type PromptSkillInput = {\n name: string;\n path: string;\n};\n\nexport type CodexContextUsage = {\n totalTokens: number;\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n reasoningOutputTokens: number;\n lastTotalTokens: number;\n modelContextWindow: number | null;\n usedPercent: number | null;\n};\n\nexport type CodexComposerPresentation = {\n actionMenu?: boolean;\n contextUsage?: boolean;\n voice?: boolean;\n};\n\nexport type CodexComposerShelfPresentation = {\n goal?: boolean;\n queuedPrompts?: boolean;\n turnGitDiff?: boolean;\n};\n\nexport type CodexMessageActionsPresentation = {\n copy?: boolean;\n delete?: boolean;\n edit?: boolean;\n fork?: boolean;\n quote?: boolean;\n retry?: boolean;\n};\n\nexport type CodexMessagesPresentation = {\n actions?: CodexMessageActionsPresentation;\n toolBlocks?: boolean;\n};\n\n/**\n * Controls the optional presentation supplied by the default conversation UI.\n * Omitted values preserve the full SDK experience. This never changes surface\n * capabilities or the operations available through the surface controller.\n */\nexport type CodexConversationPresentation = {\n composer?: CodexComposerPresentation;\n messages?: CodexMessagesPresentation;\n shelf?: CodexComposerShelfPresentation;\n};\n\nexport type ResolvedCodexConversationPresentation = {\n readonly composer: Readonly<Required<CodexComposerPresentation>>;\n readonly messages: {\n readonly actions: Readonly<Required<CodexMessageActionsPresentation>>;\n readonly toolBlocks: boolean;\n };\n readonly shelf: Readonly<Required<CodexComposerShelfPresentation>>;\n};\n\nexport const defaultCodexConversationPresentation: ResolvedCodexConversationPresentation = Object.freeze({\n composer: Object.freeze({\n actionMenu: true,\n contextUsage: true,\n voice: true,\n }),\n messages: Object.freeze({\n actions: Object.freeze({\n copy: true,\n delete: true,\n edit: true,\n fork: true,\n quote: true,\n retry: true,\n }),\n toolBlocks: true,\n }),\n shelf: Object.freeze({\n goal: true,\n queuedPrompts: true,\n turnGitDiff: true,\n }),\n});\n\nexport function resolveCodexConversationPresentation(\n presentation?: CodexConversationPresentation,\n): ResolvedCodexConversationPresentation {\n return {\n composer: {\n actionMenu: presentation?.composer?.actionMenu ?? defaultCodexConversationPresentation.composer.actionMenu,\n contextUsage: presentation?.composer?.contextUsage ?? defaultCodexConversationPresentation.composer.contextUsage,\n voice: presentation?.composer?.voice ?? defaultCodexConversationPresentation.composer.voice,\n },\n messages: {\n actions: {\n copy: presentation?.messages?.actions?.copy ?? defaultCodexConversationPresentation.messages.actions.copy,\n delete: presentation?.messages?.actions?.delete ?? defaultCodexConversationPresentation.messages.actions.delete,\n edit: presentation?.messages?.actions?.edit ?? defaultCodexConversationPresentation.messages.actions.edit,\n fork: presentation?.messages?.actions?.fork ?? defaultCodexConversationPresentation.messages.actions.fork,\n quote: presentation?.messages?.actions?.quote ?? defaultCodexConversationPresentation.messages.actions.quote,\n retry: presentation?.messages?.actions?.retry ?? defaultCodexConversationPresentation.messages.actions.retry,\n },\n toolBlocks: presentation?.messages?.toolBlocks ?? defaultCodexConversationPresentation.messages.toolBlocks,\n },\n shelf: {\n goal: presentation?.shelf?.goal ?? defaultCodexConversationPresentation.shelf.goal,\n queuedPrompts: presentation?.shelf?.queuedPrompts ?? defaultCodexConversationPresentation.shelf.queuedPrompts,\n turnGitDiff: presentation?.shelf?.turnGitDiff ?? defaultCodexConversationPresentation.shelf.turnGitDiff,\n },\n };\n}\n\nexport type ToolConfirmationDecision =\n | 'allow'\n | 'allow_conversation'\n | 'always_allow'\n | 'deny';\n\nexport type AskUserQuestionOption = {\n label: string;\n description: string;\n};\n\nexport type AskUserQuestion = {\n id: string;\n header: string;\n question: string;\n isOther: boolean;\n isSecret: boolean;\n multiSelect?: boolean;\n options: AskUserQuestionOption[] | null;\n};\n\nexport type AskUserAnswers = Record<string, { answers: string[] }>;\n\nexport type ClientRequestResponse = {\n id: string;\n payload?: {\n answers?: AskUserAnswers;\n cancelled?: boolean;\n decision?: ToolConfirmationDecision | null;\n };\n};\n\nexport type ThreadGoalStatus =\n | 'active'\n | 'paused'\n | 'blocked'\n | 'usageLimited'\n | 'budgetLimited'\n | 'complete';\n\nexport type ThreadGoal = {\n threadId: string;\n objective: string;\n status: ThreadGoalStatus;\n tokenBudget: number | null;\n tokensUsed: number;\n timeUsedSeconds: number;\n createdAt: number;\n updatedAt: number;\n};\n\nexport type TurnGitDiff = {\n turnId: string;\n addedLines: number;\n removedLines: number;\n diff?: string;\n updatedAt: string;\n};\n\nexport type CodexSpeechTranscriptionResult = NativeSpeechTranscriptionResult;\n\nexport type CodexChatTranscription = (\n audioData: ArrayBuffer,\n options?: { locale?: string },\n) => Promise<CodexSpeechTranscriptionResult>;\n","import type { CodexCapabilities } from './contracts';\n\nexport const codexCapabilities: CodexCapabilities = {\n models: true,\n skills: true,\n reasoningEffort: true,\n serviceTier: true,\n planMode: true,\n goals: true,\n steerPrompt: true,\n interrupt: true,\n history: true,\n deleteTurn: true,\n editTurn: true,\n retryTurn: true,\n approvals: true,\n approvalPresets: ['ask-for-approval', 'approve-for-me', 'full-access'],\n} as const;\n","import type { CodexCommandSummary } from './contracts';\n\nexport const codexCommands: readonly CodexCommandSummary[] = [\n {\n id: 'codex.compact',\n name: 'compact',\n displayName: 'Compact',\n description: 'Compact the current Codex context.',\n slashName: 'compact',\n submitOnSelect: true,\n },\n {\n id: 'codex.review',\n name: 'review',\n displayName: 'Review',\n description: 'Review current Codex changes and find issues.',\n slashName: 'review',\n submitOnSelect: true,\n },\n {\n id: 'codex.plan',\n name: 'plan',\n displayName: 'Plan',\n description: 'Switch to Codex Plan mode.',\n slashName: 'plan',\n submitOnSelect: true,\n },\n {\n id: 'codex.goal',\n name: 'goal',\n displayName: 'Goal',\n description: 'Set or view the Codex thread goal.',\n slashName: 'goal',\n composerMode: {\n label: 'Goal',\n placeholder: 'Describe the goal',\n },\n },\n] as const;\n","export type ComposerPromptHistoryDirection = 'ArrowDown' | 'ArrowUp';\n\nexport function createComposerPromptHistory(options: {\n apply(value: string): void;\n currentPrompt(): string;\n limit?: number;\n}) {\n const entries: string[] = [];\n const limit = Math.max(1, options.limit ?? 100);\n let index: number | null = null;\n\n function remember(value: string): void {\n entries.push(value);\n if (entries.length > limit) entries.splice(0, entries.length - limit);\n index = null;\n }\n\n function exit(): void {\n index = null;\n }\n\n function seed(values: readonly string[]): void {\n const next = values.slice(-limit);\n if (next.length === entries.length && next.every((value, entryIndex) => value === entries[entryIndex])) return;\n entries.splice(0, entries.length, ...next);\n index = null;\n }\n\n function recall(direction: ComposerPromptHistoryDirection): boolean {\n if (entries.length === 0) return false;\n if (index === null && options.currentPrompt() !== '') return false;\n\n if (direction === 'ArrowUp') {\n index = index === null ? entries.length - 1 : Math.max(0, index - 1);\n } else {\n if (index === null) return false;\n if (index >= entries.length - 1) {\n index = null;\n options.apply('');\n return true;\n }\n index += 1;\n }\n\n options.apply(entries[index] ?? '');\n return true;\n }\n\n return { exit, recall, remember, seed };\n}\n","<template>\n <button\n class=\"codex-chat-theme codex-composer-send-button\"\n :class=\"{\n 'codex-composer-send-button--busy': busy || interruptArmed,\n 'codex-composer-send-button--interrupt-armed': interruptArmed,\n 'codex-composer-send-button--disabled': disabled && !hoverActive,\n }\"\n type=\"button\"\n :disabled=\"disabled && !hoverToEnable\"\n :aria-disabled=\"disabled && hoverToEnable && !hoverActive ? 'true' : undefined\"\n :aria-label=\"interruptArmed ? interruptArmedLabel : busy ? interruptLabel : submitLabel\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n @click=\"handleClick\"\n >\n <PlayerPlayFilledIcon v-if=\"!busy && !interruptArmed\" aria-hidden=\"true\" :size=\"16\" />\n <svg\n v-if=\"busy\"\n class=\"codex-composer-send-button__spinner\"\n aria-hidden=\"true\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"6\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-dasharray=\"28\" stroke-dashoffset=\"10\" />\n </svg>\n <svg\n v-if=\"busy || interruptArmed\"\n class=\"codex-composer-send-button__stop\"\n aria-hidden=\"true\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n >\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" fill=\"currentColor\" />\n </svg>\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\nimport { PlayerPlayFilledIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n busy?: boolean;\n disabled?: boolean;\n hoverToEnable?: boolean;\n interruptArmed?: boolean;\n interruptArmedLabel?: string;\n interruptLabel?: string;\n submitLabel?: string;\n}>(), {\n busy: false,\n disabled: false,\n hoverToEnable: false,\n interruptArmed: false,\n interruptArmedLabel: 'Press Escape again or click to stop generation',\n interruptLabel: 'Interrupt',\n submitLabel: 'Send',\n});\n\nconst emit = defineEmits<{\n click: [];\n}>();\n// Stryker restore all\n\nconst hovered = ref(false);\nconst hoverActive = computed(() => props.hoverToEnable && hovered.value);\n\nfunction handleClick(): void {\n if (props.disabled && !hoverActive.value) return;\n emit('click');\n}\n</script>\n\n<style scoped>\n.codex-composer-send-button {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: var(--chat-composer-send-size, var(--chat-composer-control-size, var(--codex-composer-button-size, 32px)));\n height: var(--chat-composer-send-size, var(--chat-composer-control-size, var(--codex-composer-button-size, 32px)));\n padding: 0;\n border: 0;\n border-radius: 999px;\n color: var(--codex-composer-button-foreground, var(--color-surface-lowest, #fff));\n background: var(--codex-composer-button-background, var(--color-text, #202124));\n cursor: pointer;\n transition: opacity 120ms ease, transform 120ms ease, background 120ms ease;\n}\n\n.codex-composer-send-button:hover:not(:disabled) {\n background: var(--codex-composer-button-hover-background, color-mix(in srgb, var(--color-text, #202124) 86%, var(--color-background, #fff)));\n}\n\n.codex-composer-send-button:active:not(:disabled) {\n transform: scale(0.94);\n}\n\n.codex-composer-send-button:disabled,\n.codex-composer-send-button--disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.codex-composer-send-button__spinner,\n.codex-composer-send-button__stop {\n position: absolute;\n}\n\n.codex-composer-send-button__spinner {\n animation: codex-composer-spin 800ms linear infinite;\n}\n\n.codex-composer-send-button__stop {\n opacity: 0;\n}\n\n.codex-composer-send-button--busy:hover .codex-composer-send-button__spinner {\n opacity: 0;\n}\n\n.codex-composer-send-button--busy:hover .codex-composer-send-button__stop {\n opacity: 1;\n}\n\n.codex-composer-send-button--interrupt-armed .codex-composer-send-button__spinner {\n opacity: 0;\n}\n\n.codex-composer-send-button--interrupt-armed .codex-composer-send-button__stop {\n opacity: 1;\n}\n\n@keyframes codex-composer-spin {\n to { transform: rotate(360deg); }\n}\n</style>\n","<template>\n <button\n class=\"codex-chat-theme codex-composer-send-button\"\n :class=\"{\n 'codex-composer-send-button--busy': busy || interruptArmed,\n 'codex-composer-send-button--interrupt-armed': interruptArmed,\n 'codex-composer-send-button--disabled': disabled && !hoverActive,\n }\"\n type=\"button\"\n :disabled=\"disabled && !hoverToEnable\"\n :aria-disabled=\"disabled && hoverToEnable && !hoverActive ? 'true' : undefined\"\n :aria-label=\"interruptArmed ? interruptArmedLabel : busy ? interruptLabel : submitLabel\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n @click=\"handleClick\"\n >\n <PlayerPlayFilledIcon v-if=\"!busy && !interruptArmed\" aria-hidden=\"true\" :size=\"16\" />\n <svg\n v-if=\"busy\"\n class=\"codex-composer-send-button__spinner\"\n aria-hidden=\"true\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"6\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-dasharray=\"28\" stroke-dashoffset=\"10\" />\n </svg>\n <svg\n v-if=\"busy || interruptArmed\"\n class=\"codex-composer-send-button__stop\"\n aria-hidden=\"true\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n >\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" fill=\"currentColor\" />\n </svg>\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\nimport { PlayerPlayFilledIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n busy?: boolean;\n disabled?: boolean;\n hoverToEnable?: boolean;\n interruptArmed?: boolean;\n interruptArmedLabel?: string;\n interruptLabel?: string;\n submitLabel?: string;\n}>(), {\n busy: false,\n disabled: false,\n hoverToEnable: false,\n interruptArmed: false,\n interruptArmedLabel: 'Press Escape again or click to stop generation',\n interruptLabel: 'Interrupt',\n submitLabel: 'Send',\n});\n\nconst emit = defineEmits<{\n click: [];\n}>();\n// Stryker restore all\n\nconst hovered = ref(false);\nconst hoverActive = computed(() => props.hoverToEnable && hovered.value);\n\nfunction handleClick(): void {\n if (props.disabled && !hoverActive.value) return;\n emit('click');\n}\n</script>\n\n<style scoped>\n.codex-composer-send-button {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: var(--chat-composer-send-size, var(--chat-composer-control-size, var(--codex-composer-button-size, 32px)));\n height: var(--chat-composer-send-size, var(--chat-composer-control-size, var(--codex-composer-button-size, 32px)));\n padding: 0;\n border: 0;\n border-radius: 999px;\n color: var(--codex-composer-button-foreground, var(--color-surface-lowest, #fff));\n background: var(--codex-composer-button-background, var(--color-text, #202124));\n cursor: pointer;\n transition: opacity 120ms ease, transform 120ms ease, background 120ms ease;\n}\n\n.codex-composer-send-button:hover:not(:disabled) {\n background: var(--codex-composer-button-hover-background, color-mix(in srgb, var(--color-text, #202124) 86%, var(--color-background, #fff)));\n}\n\n.codex-composer-send-button:active:not(:disabled) {\n transform: scale(0.94);\n}\n\n.codex-composer-send-button:disabled,\n.codex-composer-send-button--disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.codex-composer-send-button__spinner,\n.codex-composer-send-button__stop {\n position: absolute;\n}\n\n.codex-composer-send-button__spinner {\n animation: codex-composer-spin 800ms linear infinite;\n}\n\n.codex-composer-send-button__stop {\n opacity: 0;\n}\n\n.codex-composer-send-button--busy:hover .codex-composer-send-button__spinner {\n opacity: 0;\n}\n\n.codex-composer-send-button--busy:hover .codex-composer-send-button__stop {\n opacity: 1;\n}\n\n.codex-composer-send-button--interrupt-armed .codex-composer-send-button__spinner {\n opacity: 0;\n}\n\n.codex-composer-send-button--interrupt-armed .codex-composer-send-button__stop {\n opacity: 1;\n}\n\n@keyframes codex-composer-spin {\n to { transform: rotate(360deg); }\n}\n</style>\n","<template>\n <div\n v-if=\"planMode || command\"\n class=\"codex-chat-theme chat-composer__modes\"\n aria-label=\"Active composer modes\"\n >\n <span v-if=\"planMode\" class=\"chat-composer__mode chat-composer__mode__info\">\n <ListDetailsIcon class=\"chat-composer__mode__icon\" />\n <CircleXIcon\n class=\"chat-composer__mode__remove\"\n aria-label=\"Disable plan mode\"\n role=\"button\"\n @click=\"emit('disablePlanMode')\"\n />\n Plan\n </span>\n <span v-if=\"command\" class=\"chat-composer__mode chat-composer__mode__info\">\n <TargetArrowIcon class=\"chat-composer__mode__icon\" />\n <CircleXIcon\n class=\"chat-composer__mode__remove\"\n :aria-label=\"`Remove ${command.composerMode?.label ?? command.displayName ?? command.name} command`\"\n role=\"button\"\n @click=\"emit('removeCommand')\"\n />\n {{ command.composerMode?.label ?? command.displayName ?? command.name }}\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { CodexCommandSummary } from './contracts'\nimport { CircleXIcon, ListDetailsIcon, TargetArrowIcon } from '../icons/app-icons'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n planMode: boolean\n command?: CodexCommandSummary | null\n}>()\n\nconst emit = defineEmits<{\n disablePlanMode: []\n removeCommand: []\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-composer__modes {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-composer__mode {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n min-height: 24px;\n padding: 0 var(--space-4);\n border-radius: var(--radius-full);\n background: var(--color-surface-base);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-18);\n}\n\n.chat-composer__mode svg {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n.chat-composer__mode .chat-composer__mode__remove {\n display: none;\n}\n\n.chat-composer__mode:hover .chat-composer__mode__icon {\n display: none;\n}\n\n.chat-composer__mode:hover .chat-composer__mode__remove {\n cursor: pointer;\n display: inline;\n}\n\n.chat-composer__mode.chat-composer__mode__info {\n background-color: var(--color-secondary-container);\n color: var(--color-on-secondary-container);\n}\n</style>\n","<template>\n <div\n v-if=\"planMode || command\"\n class=\"codex-chat-theme chat-composer__modes\"\n aria-label=\"Active composer modes\"\n >\n <span v-if=\"planMode\" class=\"chat-composer__mode chat-composer__mode__info\">\n <ListDetailsIcon class=\"chat-composer__mode__icon\" />\n <CircleXIcon\n class=\"chat-composer__mode__remove\"\n aria-label=\"Disable plan mode\"\n role=\"button\"\n @click=\"emit('disablePlanMode')\"\n />\n Plan\n </span>\n <span v-if=\"command\" class=\"chat-composer__mode chat-composer__mode__info\">\n <TargetArrowIcon class=\"chat-composer__mode__icon\" />\n <CircleXIcon\n class=\"chat-composer__mode__remove\"\n :aria-label=\"`Remove ${command.composerMode?.label ?? command.displayName ?? command.name} command`\"\n role=\"button\"\n @click=\"emit('removeCommand')\"\n />\n {{ command.composerMode?.label ?? command.displayName ?? command.name }}\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { CodexCommandSummary } from './contracts'\nimport { CircleXIcon, ListDetailsIcon, TargetArrowIcon } from '../icons/app-icons'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n planMode: boolean\n command?: CodexCommandSummary | null\n}>()\n\nconst emit = defineEmits<{\n disablePlanMode: []\n removeCommand: []\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-composer__modes {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-composer__mode {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n min-height: 24px;\n padding: 0 var(--space-4);\n border-radius: var(--radius-full);\n background: var(--color-surface-base);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-18);\n}\n\n.chat-composer__mode svg {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n.chat-composer__mode .chat-composer__mode__remove {\n display: none;\n}\n\n.chat-composer__mode:hover .chat-composer__mode__icon {\n display: none;\n}\n\n.chat-composer__mode:hover .chat-composer__mode__remove {\n cursor: pointer;\n display: inline;\n}\n\n.chat-composer__mode.chat-composer__mode__info {\n background-color: var(--color-secondary-container);\n color: var(--color-on-secondary-container);\n}\n</style>\n","import type { ApprovalPreset } from './contracts';\n\nexport const defaultApprovalPreset: ApprovalPreset = 'ask-for-approval';\n\nexport type ApprovalPresetOption = {\n id: ApprovalPreset;\n label: string;\n description: string;\n};\n\nexport const approvalPresetOptions: readonly ApprovalPresetOption[] = [\n {\n id: 'ask-for-approval',\n label: 'Ask for approval',\n description: 'Pause before tool calls that need user approval.',\n },\n {\n id: 'approve-for-me',\n label: 'Approve for me',\n description: 'Let Codex approve safe tool calls for the active session.',\n },\n {\n id: 'full-access',\n label: 'Full access',\n description: 'Run trusted workspace tools without extra prompts.',\n },\n] as const;\n\nexport function isApprovalPreset(value: unknown): value is ApprovalPreset {\n return value === 'ask-for-approval' || value === 'approve-for-me' || value === 'full-access';\n}\n","import { defineComponent, h, nextTick, reactive, type Component, type PropType, type Slots, type VNode } from 'vue';\nimport type {\n CodexComposerMenuItem,\n CodexComposerMenuSelectableItem,\n CodexComposerMenuSubmenuItem,\n} from '../composer-menu';\nimport { CheckIcon, ChevronRightIcon } from '../icons/app-icons';\n\nconst CodexComposerMenuItems = defineComponent({\n name: 'CodexComposerMenuItems',\n props: {\n ariaLabel: {\n type: String,\n default: 'Composer actions',\n },\n items: {\n type: Array as unknown as PropType<readonly CodexComposerMenuItem<unknown>[]>,\n required: true,\n },\n },\n emits: {\n select: (_item: CodexComposerMenuSelectableItem<unknown>) => true,\n },\n setup(props, { emit, slots }) {\n const openSubmenus = reactive(new Set<string>());\n const select = (item: CodexComposerMenuSelectableItem<unknown>): void => {\n emit('select', item);\n };\n\n return (): VNode => renderMenu(props.items, props.ariaLabel, slots, select, openSubmenus);\n },\n});\n\nfunction renderMenu(\n items: readonly CodexComposerMenuItem<unknown>[],\n ariaLabel: string,\n slots: Slots,\n select: (item: CodexComposerMenuSelectableItem<unknown>) => void,\n openSubmenus: Set<string>,\n className: string | Array<string | null> = 'codex-chat-theme codex-composer-menu-list',\n): VNode {\n const firstFocusableId = items.find((item) => item.type !== 'separator'\n && item.type !== 'heading'\n && !item.disabled\n && (item.type !== 'submenu' || item.items.length > 0))?.id;\n return h('div', {\n class: className,\n role: 'menu',\n 'aria-label': ariaLabel,\n onKeydown: (event: KeyboardEvent) => handleMenuKeydown(event, openSubmenus),\n }, items.map((item) => renderItem(item, slots, select, openSubmenus, item.id === firstFocusableId)));\n}\n\nfunction renderItem(\n item: CodexComposerMenuItem<unknown>,\n slots: Slots,\n select: (item: CodexComposerMenuSelectableItem<unknown>) => void,\n openSubmenus: Set<string>,\n firstFocusable: boolean,\n): VNode {\n if (item.type === 'separator') {\n return h('div', {\n key: item.id,\n class: 'codex-composer-menu-list__separator',\n role: 'separator',\n });\n }\n\n if (item.type === 'heading') {\n return h('div', {\n key: item.id,\n class: 'codex-composer-menu-list__heading',\n role: 'presentation',\n }, [\n h('span', { class: 'codex-composer-menu-list__heading-label' }, item.label),\n item.actions?.length\n ? h('span', { class: 'codex-composer-menu-list__heading-actions' }, item.actions.map((action) => (\n h('button', {\n key: action.id,\n class: 'codex-composer-menu-list__heading-action',\n type: 'button',\n role: 'menuitem',\n title: action.label,\n 'aria-label': action.label,\n disabled: action.disabled,\n tabindex: -1,\n onClick: () => select(action),\n }, action.icon\n ? [h(action.icon as Component, { 'aria-hidden': 'true' })]\n : action.label)\n )))\n : null,\n ]);\n }\n\n if (item.type === 'submenu') {\n const enabled = !item.disabled && item.items.length > 0;\n const expanded = enabled && openSubmenus.has(item.id);\n return h('div', {\n key: item.id,\n class: [\n 'codex-composer-menu-list__submenu',\n expanded ? 'codex-composer-menu-list__submenu--open' : null,\n ],\n 'data-submenu-id': item.id,\n onMouseenter: () => {\n if (enabled) openSubmenus.add(item.id);\n },\n onMouseleave: (event: MouseEvent) => {\n const submenu = (event.currentTarget as HTMLElement).querySelector(\n ':scope > .codex-composer-menu-list__submenu-list',\n );\n if (!(submenu instanceof HTMLElement) || !submenu.contains(document.activeElement)) {\n openSubmenus.delete(item.id);\n }\n },\n onFocusout: (event: FocusEvent) => {\n const container = event.currentTarget as HTMLElement;\n window.setTimeout(() => {\n if (!container.contains(document.activeElement)) openSubmenus.delete(item.id);\n }, 0);\n },\n }, [\n h('button', {\n class: 'codex-composer-menu-list__item codex-composer-menu-list__item--submenu',\n type: 'button',\n role: 'menuitem',\n 'aria-haspopup': 'menu',\n 'aria-expanded': expanded,\n disabled: !enabled,\n tabindex: firstFocusable ? 0 : -1,\n onClick: () => expanded ? openSubmenus.delete(item.id) : openSubmenus.add(item.id),\n onKeydown: (event: KeyboardEvent) => {\n if (event.key !== 'ArrowRight' || !enabled) return;\n const trigger = event.currentTarget as HTMLElement;\n event.preventDefault();\n event.stopPropagation();\n openSubmenus.add(item.id);\n void nextTick(() => {\n const submenu = trigger.nextElementSibling as HTMLElement | null;\n focusItem(submenu, menuItems(submenu)[0]);\n });\n },\n }, [\n ...renderContent(item, slots).nodes,\n h(ChevronRightIcon, {\n class: 'codex-composer-menu-list__chevron',\n 'aria-hidden': 'true',\n }),\n ]),\n enabled\n ? renderMenu(\n item.items,\n item.label,\n slots,\n (selected) => {\n if (selected.type === 'radio') openSubmenus.delete(item.id);\n select(selected);\n },\n openSubmenus,\n [\n 'codex-composer-menu-list codex-composer-menu-list__submenu-list',\n item.submenuAlignment === 'bottom'\n ? 'codex-composer-menu-list__submenu-list--bottom-aligned'\n : null,\n item.submenuWidth === 'wide' ? 'codex-composer-menu-list__submenu-list--wide' : null,\n ],\n )\n : null,\n ]);\n }\n\n const content = renderContent(item, slots);\n return h('button', {\n key: item.id,\n class: [\n 'codex-composer-menu-list__item',\n item.type === 'checkbox' && item.accessory === 'switch'\n ? 'codex-composer-menu-list__item--switch'\n : null,\n (item.type === 'action' || item.type === 'custom') && item.danger\n ? 'codex-composer-menu-list__item--danger'\n : null,\n ],\n type: 'button',\n role: itemRole(item),\n 'aria-checked': itemChecked(item),\n disabled: item.disabled,\n tabindex: firstFocusable ? 0 : -1,\n onClick: () => select(item),\n }, [\n ...content.nodes,\n item.type === 'checkbox' && item.accessory === 'switch'\n ? h('span', {\n class: [\n 'codex-composer-menu-list__switch',\n item.checked ? 'codex-composer-menu-list__switch--checked' : null,\n ],\n 'aria-hidden': 'true',\n }, [h('span', { class: 'codex-composer-menu-list__switch-thumb' })])\n : item.type === 'checkbox' || (item.type === 'radio' && item.checked && !content.leadingRadioCheck)\n ? h('span', { class: 'codex-composer-menu-list__selection', 'aria-hidden': 'true' }, item.checked ? '✓' : '')\n : null,\n ]);\n}\n\nfunction handleMenuKeydown(event: KeyboardEvent, openSubmenus: Set<string>): void {\n const menu = event.currentTarget as HTMLElement;\n const items = menuItems(menu);\n const current = event.target as HTMLButtonElement;\n const currentIndex = items.indexOf(current);\n let target: HTMLButtonElement | undefined;\n let submenuToClose: string | undefined;\n switch (event.key) {\n case 'ArrowDown': target = items[(currentIndex + 1 + items.length) % items.length]; break;\n case 'ArrowUp': target = items[(currentIndex - 1 + items.length) % items.length]; break;\n case 'Home': target = items[0]; break;\n case 'End': target = items.at(-1); break;\n case 'ArrowLeft': {\n if (!menu.classList.contains('codex-composer-menu-list__submenu-list')) return;\n const container = menu.parentElement;\n const trigger = container?.querySelector(':scope > button[role=\"menuitem\"]') as HTMLButtonElement | null;\n submenuToClose = container?.dataset.submenuId;\n target = trigger ?? undefined;\n break;\n }\n default: return;\n }\n event.preventDefault();\n event.stopPropagation();\n focusItem(menu, target);\n if (submenuToClose) openSubmenus.delete(submenuToClose);\n}\n\nfunction menuItems(menu: HTMLElement | null): HTMLButtonElement[] {\n if (!menu) return [];\n const items: HTMLButtonElement[] = [];\n for (const child of menu.children) {\n const candidates = child.matches('button[role^=\"menuitem\"]')\n ? [child]\n : child.querySelectorAll(\n ':scope > button[role^=\"menuitem\"], :scope > .codex-composer-menu-list__heading-actions > button[role^=\"menuitem\"]',\n );\n for (const candidate of candidates) {\n if (candidate instanceof HTMLButtonElement && !candidate.disabled) items.push(candidate);\n }\n }\n return items;\n}\n\nfunction focusItem(menu: HTMLElement | null, target: HTMLButtonElement | undefined): void {\n if (!target) return;\n for (const item of menuItems(menu)) item.tabIndex = item === target ? 0 : -1;\n target.focus();\n}\n\nfunction renderContent(\n item: CodexComposerMenuSelectableItem<unknown> | CodexComposerMenuSubmenuItem<unknown>,\n slots: Slots,\n): { nodes: Array<VNode | null>; leadingRadioCheck: boolean } {\n const customContent = slots.item?.({ item });\n if (customContent?.length) {\n return { nodes: customContent, leadingRadioCheck: false };\n }\n\n const customIcon = slots.icon?.({ item });\n const leadingRadioCheck = item.type === 'radio' && item.checked && !customIcon?.length;\n let icon: VNode[];\n if (customIcon?.length) {\n icon = customIcon;\n } else if (leadingRadioCheck) {\n icon = [h(CheckIcon, {\n class: 'codex-composer-menu-list__icon codex-composer-menu-list__radio-check',\n 'aria-hidden': 'true',\n })];\n } else if ('leadingColor' in item && item.leadingColor) {\n icon = [h('span', {\n class: 'codex-composer-menu-list__color-dot',\n style: { backgroundColor: item.leadingColor },\n 'aria-hidden': 'true',\n })];\n } else if (item.icon) {\n icon = [h(item.icon as Component, { class: 'codex-composer-menu-list__icon', 'aria-hidden': 'true' })];\n } else {\n icon = [h('span', {\n class: 'codex-composer-menu-list__icon codex-composer-menu-list__icon--empty',\n 'aria-hidden': 'true',\n })];\n }\n\n return {\n nodes: [\n ...icon,\n h('span', { class: 'codex-composer-menu-list__copy' }, [\n h('span', { class: 'codex-composer-menu-list__label' }, item.label),\n item.description\n ? h('span', { class: 'codex-composer-menu-list__description' }, ` • ${item.description}`)\n : null,\n ]),\n item.value || item.valueIcon\n ? h('span', { class: 'codex-composer-menu-list__value' }, [\n item.value\n ? h('span', {\n class: item.valueAppearance === 'badge'\n ? 'codex-composer-menu-list__value-badge'\n : undefined,\n }, item.value)\n : null,\n item.valueIcon\n ? h(item.valueIcon as Component, {\n class: 'codex-composer-menu-list__value-icon',\n title: item.valueIconLabel,\n 'aria-label': item.valueIconLabel,\n 'aria-hidden': item.valueIconLabel ? undefined : 'true',\n })\n : null,\n ])\n : null,\n ],\n leadingRadioCheck,\n };\n}\n\nfunction itemRole(item: CodexComposerMenuSelectableItem<unknown>): 'menuitem' | 'menuitemcheckbox' | 'menuitemradio' {\n if (item.type === 'checkbox') {\n return 'menuitemcheckbox';\n }\n if (item.type === 'radio') {\n return 'menuitemradio';\n }\n return 'menuitem';\n}\n\nfunction itemChecked(item: CodexComposerMenuSelectableItem<unknown>): boolean | undefined {\n return item.type === 'checkbox' || item.type === 'radio' ? item.checked : undefined;\n}\n\nexport default CodexComposerMenuItems;\n","<template>\n <CodexComposerMenuItems\n :aria-label=\"ariaLabel\"\n :items=\"items\"\n @select=\"forwardSelection\"\n >\n <template v-if=\"$slots.icon\" #icon=\"scope\"><slot name=\"icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.item\" #item=\"scope\"><slot name=\"item\" v-bind=\"scope\" /></template>\n </CodexComposerMenuItems>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport CodexComposerMenuItems from './composer-menu-items';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n ariaLabel?: string;\n items: readonly CodexComposerMenuItem<Payload>[];\n}>(), {\n ariaLabel: 'Composer actions',\n});\n\nconst emit = defineEmits<{\n select: [item: CodexComposerMenuSelectableItem<Payload>];\n}>();\n// Stryker restore all\n\nfunction forwardSelection(item: CodexComposerMenuSelectableItem<unknown>): void {\n emit('select', item as CodexComposerMenuSelectableItem<Payload>);\n}\n</script>\n\n<style>\n.codex-composer-menu-list {\n display: flex;\n flex-direction: column;\n width: var(--codex-composer-menu-width, 220px);\n padding: var(--codex-composer-menu-padding, var(--space-2));\n border: 1px solid var(--codex-border-color, var(--color-border, #dedede));\n border-radius: var(--codex-composer-menu-radius, 12px);\n color: var(--codex-text-color, var(--color-text, #0d0d0d));\n background: var(--codex-surface-color, var(--color-surface-lowest, #fff));\n box-shadow: var(--codex-composer-menu-shadow, var(--shadow-menu, 0 4px 6px rgb(0 0 0 / 8%), 0 2px 4px rgb(0 0 0 / 5%)));\n box-sizing: border-box;\n font-family: var(--codex-font-family, var(--font-family-base, ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif));\n font-size: var(--codex-composer-menu-font-size, 13px);\n line-height: 18px;\n}\n\n.codex-composer-menu-list__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-height: var(--chat-menu-control-min-height, 28px);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--codex-composer-menu-item-radius, 12px);\n color: inherit;\n background: transparent;\n font-family: inherit;\n font-size: var(--codex-composer-menu-item-font-size, var(--chat-menu-font-size, 14px));\n line-height: var(--chat-menu-line-height, 20px);\n text-align: left;\n cursor: pointer;\n}\n\n.codex-composer-menu-list__item:hover:not(:disabled),\n.codex-composer-menu-list__item:focus-visible {\n background: var(--codex-hover-color, var(--color-surface-low, #f4f4f4));\n outline: none;\n}\n\n.codex-composer-menu-list__item:disabled {\n color: var(--codex-muted-text-color, var(--color-text-muted, #666));\n cursor: not-allowed;\n opacity: 0.58;\n}\n\n.codex-composer-menu-list__item--danger {\n color: var(--codex-danger-color, var(--color-error, #d5351f));\n}\n\n.codex-composer-menu-list__item--switch {\n padding-block: var(--space-1);\n}\n\n.codex-composer-menu-list__item--submenu {\n padding-right: var(--space-2);\n}\n\n.codex-composer-menu-list__icon,\n.codex-composer-menu-list__chevron,\n.codex-composer-menu-list__selection {\n width: var(--codex-composer-menu-icon-size, 16px);\n height: var(--codex-composer-menu-icon-size, 16px);\n flex: 0 0 auto;\n}\n\n.codex-composer-menu-list__chevron,\n.codex-composer-menu-list__selection {\n color: var(--codex-muted-text-color, var(--color-text-muted, #666));\n}\n\n.codex-composer-menu-list__chevron {\n stroke-width: 2.5px;\n}\n\n.codex-composer-menu-list__icon--empty {\n visibility: hidden;\n}\n\n.codex-composer-menu-list__icon:is(svg),\n.codex-composer-menu-list__icon svg {\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.codex-composer-menu-list__item[aria-checked=\"true\"] .codex-composer-menu-list__icon:is(svg),\n.codex-composer-menu-list__item[aria-checked=\"true\"] .codex-composer-menu-list__icon svg {\n opacity: 1;\n stroke-width: 2.5px;\n}\n\n.codex-composer-menu-list__item[role=\"menuitemradio\"] .codex-composer-menu-list__icon:is(svg):not(.codex-composer-menu-list__radio-check),\n.codex-composer-menu-list__item[role=\"menuitemradio\"] .codex-composer-menu-list__icon svg {\n opacity: 0.4;\n stroke-width: 2px;\n}\n\n.codex-composer-menu-list__item[role=\"menuitemradio\"][aria-checked=\"true\"] .codex-composer-menu-list__selection {\n color: inherit;\n opacity: 1;\n}\n\n.codex-composer-menu-list__copy {\n min-width: 0;\n flex: 1 1 auto;\n overflow: hidden;\n white-space: nowrap;\n}\n\n.codex-composer-menu-list__label {\n font-weight: var(--font-weight-medium);\n}\n\n.codex-composer-menu-list__description,\n.codex-composer-menu-list__value {\n color: var(--codex-muted-text-color, var(--color-text-muted, #666));\n font-size: var(--codex-composer-menu-description-font-size, var(--chat-menu-description-font-size, 12px));\n}\n\n.codex-composer-menu-list__value {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n max-width: 96px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.codex-composer-menu-list__value-icon {\n width: 14px;\n height: 14px;\n flex: 0 0 auto;\n}\n\n.codex-composer-menu-list__value-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 20px;\n padding: 0 6px;\n border-radius: 6px;\n background: var(--codex-hover-color, var(--color-surface-low, #f4f4f4));\n font-size: 11px;\n font-weight: 600;\n line-height: 20px;\n}\n\n.codex-composer-menu-list__separator {\n height: 1px;\n margin: var(--space-2) var(--space-1);\n background: var(--codex-border-color, var(--color-border, #dedede));\n}\n\n.codex-composer-menu-list__heading {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-2) var(--space-4) var(--space-2) calc(var(--space-4) + var(--codex-composer-menu-icon-size, 16px) + var(--space-3));\n color: var(--codex-muted-text-color, var(--color-text-muted, #666));\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.codex-composer-menu-list__heading-label {\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.codex-composer-menu-list__heading-actions {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n}\n\n.codex-composer-menu-list__heading-action {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n color: inherit;\n background: transparent;\n cursor: pointer;\n}\n\n.codex-composer-menu-list__heading-action:hover:not(:disabled),\n.codex-composer-menu-list__heading-action:focus-visible {\n color: var(--codex-text-color, var(--color-text, #0d0d0d));\n background: var(--codex-hover-color, var(--color-surface-low, #f4f4f4));\n outline: none;\n}\n\n.codex-composer-menu-list__heading-action:disabled {\n cursor: not-allowed;\n opacity: 0.45;\n}\n\n.codex-composer-menu-list__heading-action > svg {\n width: 16px;\n height: 16px;\n}\n\n.codex-composer-menu-list__submenu {\n position: relative;\n}\n\n.codex-composer-menu-list__submenu-list {\n position: absolute;\n z-index: 2;\n top: 0;\n left: 100%;\n}\n\n.codex-composer-menu-list__submenu-list--bottom-aligned {\n top: auto;\n bottom: 0;\n}\n\n.codex-composer-menu-list__submenu-list--wide {\n width: 360px;\n max-width: min(360px, calc(100vw - 24px));\n}\n\n.codex-composer-menu-list__switch {\n position: relative;\n width: 28px;\n height: 16px;\n flex: 0 0 auto;\n border-radius: 999px;\n background: var(--codex-border-color, var(--color-border-strong, #b0b0b0));\n transition: background-color 120ms ease;\n}\n\n.codex-composer-menu-list__switch-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n background: var(--codex-surface-color, var(--color-surface-lowest, #fff));\n box-shadow: 0 1px 2px rgb(0 0 0 / 24%);\n transition: transform 120ms ease;\n}\n\n.codex-composer-menu-list__switch--checked {\n background: var(--codex-primary-color, var(--color-primary, #1b4fb2));\n}\n\n.codex-composer-menu-list__switch--checked .codex-composer-menu-list__switch-thumb {\n transform: translateX(12px);\n}\n\n.codex-composer-menu-list__color-dot {\n width: 10px;\n height: 10px;\n flex: 0 0 auto;\n border-radius: 50%;\n}\n\n.codex-composer-menu-list__submenu:not(.codex-composer-menu-list__submenu--open) > .codex-composer-menu-list__submenu-list {\n display: none;\n}\n</style>\n","<template>\n <CodexComposerMenuItems\n :aria-label=\"ariaLabel\"\n :items=\"items\"\n @select=\"forwardSelection\"\n >\n <template v-if=\"$slots.icon\" #icon=\"scope\"><slot name=\"icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.item\" #item=\"scope\"><slot name=\"item\" v-bind=\"scope\" /></template>\n </CodexComposerMenuItems>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport CodexComposerMenuItems from './composer-menu-items';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n ariaLabel?: string;\n items: readonly CodexComposerMenuItem<Payload>[];\n}>(), {\n ariaLabel: 'Composer actions',\n});\n\nconst emit = defineEmits<{\n select: [item: CodexComposerMenuSelectableItem<Payload>];\n}>();\n// Stryker restore all\n\nfunction forwardSelection(item: CodexComposerMenuSelectableItem<unknown>): void {\n emit('select', item as CodexComposerMenuSelectableItem<Payload>);\n}\n</script>\n\n<style>\n.codex-composer-menu-list {\n display: flex;\n flex-direction: column;\n width: var(--codex-composer-menu-width, 220px);\n padding: var(--codex-composer-menu-padding, var(--space-2));\n border: 1px solid var(--codex-border-color, var(--color-border, #dedede));\n border-radius: var(--codex-composer-menu-radius, 12px);\n color: var(--codex-text-color, var(--color-text, #0d0d0d));\n background: var(--codex-surface-color, var(--color-surface-lowest, #fff));\n box-shadow: var(--codex-composer-menu-shadow, var(--shadow-menu, 0 4px 6px rgb(0 0 0 / 8%), 0 2px 4px rgb(0 0 0 / 5%)));\n box-sizing: border-box;\n font-family: var(--codex-font-family, var(--font-family-base, ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif));\n font-size: var(--codex-composer-menu-font-size, 13px);\n line-height: 18px;\n}\n\n.codex-composer-menu-list__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-height: var(--chat-menu-control-min-height, 28px);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--codex-composer-menu-item-radius, 12px);\n color: inherit;\n background: transparent;\n font-family: inherit;\n font-size: var(--codex-composer-menu-item-font-size, var(--chat-menu-font-size, 14px));\n line-height: var(--chat-menu-line-height, 20px);\n text-align: left;\n cursor: pointer;\n}\n\n.codex-composer-menu-list__item:hover:not(:disabled),\n.codex-composer-menu-list__item:focus-visible {\n background: var(--codex-hover-color, var(--color-surface-low, #f4f4f4));\n outline: none;\n}\n\n.codex-composer-menu-list__item:disabled {\n color: var(--codex-muted-text-color, var(--color-text-muted, #666));\n cursor: not-allowed;\n opacity: 0.58;\n}\n\n.codex-composer-menu-list__item--danger {\n color: var(--codex-danger-color, var(--color-error, #d5351f));\n}\n\n.codex-composer-menu-list__item--switch {\n padding-block: var(--space-1);\n}\n\n.codex-composer-menu-list__item--submenu {\n padding-right: var(--space-2);\n}\n\n.codex-composer-menu-list__icon,\n.codex-composer-menu-list__chevron,\n.codex-composer-menu-list__selection {\n width: var(--codex-composer-menu-icon-size, 16px);\n height: var(--codex-composer-menu-icon-size, 16px);\n flex: 0 0 auto;\n}\n\n.codex-composer-menu-list__chevron,\n.codex-composer-menu-list__selection {\n color: var(--codex-muted-text-color, var(--color-text-muted, #666));\n}\n\n.codex-composer-menu-list__chevron {\n stroke-width: 2.5px;\n}\n\n.codex-composer-menu-list__icon--empty {\n visibility: hidden;\n}\n\n.codex-composer-menu-list__icon:is(svg),\n.codex-composer-menu-list__icon svg {\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.codex-composer-menu-list__item[aria-checked=\"true\"] .codex-composer-menu-list__icon:is(svg),\n.codex-composer-menu-list__item[aria-checked=\"true\"] .codex-composer-menu-list__icon svg {\n opacity: 1;\n stroke-width: 2.5px;\n}\n\n.codex-composer-menu-list__item[role=\"menuitemradio\"] .codex-composer-menu-list__icon:is(svg):not(.codex-composer-menu-list__radio-check),\n.codex-composer-menu-list__item[role=\"menuitemradio\"] .codex-composer-menu-list__icon svg {\n opacity: 0.4;\n stroke-width: 2px;\n}\n\n.codex-composer-menu-list__item[role=\"menuitemradio\"][aria-checked=\"true\"] .codex-composer-menu-list__selection {\n color: inherit;\n opacity: 1;\n}\n\n.codex-composer-menu-list__copy {\n min-width: 0;\n flex: 1 1 auto;\n overflow: hidden;\n white-space: nowrap;\n}\n\n.codex-composer-menu-list__label {\n font-weight: var(--font-weight-medium);\n}\n\n.codex-composer-menu-list__description,\n.codex-composer-menu-list__value {\n color: var(--codex-muted-text-color, var(--color-text-muted, #666));\n font-size: var(--codex-composer-menu-description-font-size, var(--chat-menu-description-font-size, 12px));\n}\n\n.codex-composer-menu-list__value {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n max-width: 96px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.codex-composer-menu-list__value-icon {\n width: 14px;\n height: 14px;\n flex: 0 0 auto;\n}\n\n.codex-composer-menu-list__value-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 20px;\n padding: 0 6px;\n border-radius: 6px;\n background: var(--codex-hover-color, var(--color-surface-low, #f4f4f4));\n font-size: 11px;\n font-weight: 600;\n line-height: 20px;\n}\n\n.codex-composer-menu-list__separator {\n height: 1px;\n margin: var(--space-2) var(--space-1);\n background: var(--codex-border-color, var(--color-border, #dedede));\n}\n\n.codex-composer-menu-list__heading {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-2) var(--space-4) var(--space-2) calc(var(--space-4) + var(--codex-composer-menu-icon-size, 16px) + var(--space-3));\n color: var(--codex-muted-text-color, var(--color-text-muted, #666));\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.codex-composer-menu-list__heading-label {\n min-width: 0;\n flex: 1 1 auto;\n}\n\n.codex-composer-menu-list__heading-actions {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n}\n\n.codex-composer-menu-list__heading-action {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n color: inherit;\n background: transparent;\n cursor: pointer;\n}\n\n.codex-composer-menu-list__heading-action:hover:not(:disabled),\n.codex-composer-menu-list__heading-action:focus-visible {\n color: var(--codex-text-color, var(--color-text, #0d0d0d));\n background: var(--codex-hover-color, var(--color-surface-low, #f4f4f4));\n outline: none;\n}\n\n.codex-composer-menu-list__heading-action:disabled {\n cursor: not-allowed;\n opacity: 0.45;\n}\n\n.codex-composer-menu-list__heading-action > svg {\n width: 16px;\n height: 16px;\n}\n\n.codex-composer-menu-list__submenu {\n position: relative;\n}\n\n.codex-composer-menu-list__submenu-list {\n position: absolute;\n z-index: 2;\n top: 0;\n left: 100%;\n}\n\n.codex-composer-menu-list__submenu-list--bottom-aligned {\n top: auto;\n bottom: 0;\n}\n\n.codex-composer-menu-list__submenu-list--wide {\n width: 360px;\n max-width: min(360px, calc(100vw - 24px));\n}\n\n.codex-composer-menu-list__switch {\n position: relative;\n width: 28px;\n height: 16px;\n flex: 0 0 auto;\n border-radius: 999px;\n background: var(--codex-border-color, var(--color-border-strong, #b0b0b0));\n transition: background-color 120ms ease;\n}\n\n.codex-composer-menu-list__switch-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n background: var(--codex-surface-color, var(--color-surface-lowest, #fff));\n box-shadow: 0 1px 2px rgb(0 0 0 / 24%);\n transition: transform 120ms ease;\n}\n\n.codex-composer-menu-list__switch--checked {\n background: var(--codex-primary-color, var(--color-primary, #1b4fb2));\n}\n\n.codex-composer-menu-list__switch--checked .codex-composer-menu-list__switch-thumb {\n transform: translateX(12px);\n}\n\n.codex-composer-menu-list__color-dot {\n width: 10px;\n height: 10px;\n flex: 0 0 auto;\n border-radius: 50%;\n}\n\n.codex-composer-menu-list__submenu:not(.codex-composer-menu-list__submenu--open) > .codex-composer-menu-list__submenu-list {\n display: none;\n}\n</style>\n","<template>\n <div ref=\"root\" class=\"codex-chat-theme codex-composer-menu\" @keydown.escape.prevent.stop=\"close(true)\">\n <slot name=\"trigger\" :open=\"menuOpen\" :toggle=\"toggle\">\n <button\n class=\"codex-composer-menu__trigger\"\n type=\"button\"\n :aria-label=\"buttonLabel\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"menuOpen\"\n :disabled=\"disabled\"\n @click=\"toggle\"\n >\n <svg aria-hidden=\"true\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\">\n <path d=\"M9 3.5v11M3.5 9h11\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-width=\"1.8\" />\n </svg>\n </button>\n </slot>\n <CodexComposerMenuList\n v-if=\"menuOpen\"\n class=\"codex-composer-menu__list\"\n :class=\"menuClass\"\n :aria-label=\"ariaLabel\"\n :items=\"items\"\n @select=\"selectItem\"\n >\n <template v-if=\"$slots.icon\" #icon=\"scope\"><slot name=\"icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.item\" #item=\"scope\"><slot name=\"item\" v-bind=\"scope\" /></template>\n </CodexComposerMenuList>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport CodexComposerMenuList from './CodexComposerMenuList.vue';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n ariaLabel?: string;\n buttonLabel?: string;\n disabled?: boolean;\n items: readonly CodexComposerMenuItem<Payload>[];\n menuClass?: string;\n open?: boolean;\n}>(), {\n ariaLabel: 'Composer actions',\n buttonLabel: 'Open composer actions',\n disabled: false,\n menuClass: undefined,\n open: undefined,\n});\n\nconst emit = defineEmits<{\n select: [item: CodexComposerMenuSelectableItem<Payload>];\n 'update:open': [open: boolean];\n}>();\n// Stryker restore all\n\nconst root = ref<HTMLElement | null>(null);\nconst triggerElement = ref<HTMLElement | null>(null);\nconst internalOpen = ref(false);\nconst menuOpen = computed(() => props.open ?? internalOpen.value);\n\nonMounted(() => document.addEventListener('click', closeOnOutsideClick));\nonBeforeUnmount(() => document.removeEventListener('click', closeOnOutsideClick));\n\nwatch(menuOpen, async (open) => {\n if (!open) return;\n await nextTick();\n const firstItem = root.value?.querySelector(\n '.codex-composer-menu__list > button[role^=\"menuitem\"], .codex-composer-menu__list > div > button[role^=\"menuitem\"]',\n );\n if (firstItem instanceof HTMLElement) firstItem.focus();\n}, { immediate: true });\n\nfunction setOpen(open: boolean): void {\n if (props.open === undefined) {\n internalOpen.value = open;\n }\n emit('update:open', open);\n}\n\nfunction toggle(event?: Event): void {\n event?.stopPropagation();\n if (event?.currentTarget instanceof HTMLElement) triggerElement.value = event.currentTarget;\n if (!props.disabled) {\n setOpen(!menuOpen.value);\n }\n}\n\nfunction close(restoreFocus = false): void {\n if (menuOpen.value) {\n setOpen(false);\n if (restoreFocus) void nextTick(() => triggerElement.value?.focus());\n }\n}\n\nfunction closeOnOutsideClick(event: MouseEvent): void {\n if (root.value && event.target && !root.value.contains(event.target as Node)) {\n close(false);\n }\n}\n\nfunction selectItem(item: CodexComposerMenuSelectableItem<Payload>): void {\n emit('select', item);\n const shouldClose = item.closeOnSelect ?? (item.type !== 'checkbox');\n if (shouldClose) {\n close(true);\n }\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineExpose({ close, open: () => setOpen(true), toggle });\n// Stryker restore all\n</script>\n\n<style scoped>\n.codex-composer-menu {\n position: relative;\n flex: 0 0 auto;\n}\n\n.codex-composer-menu__trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--chat-composer-control-size, var(--codex-composer-button-size, 36px));\n height: var(--chat-composer-control-size, var(--codex-composer-button-size, 36px));\n padding: 0;\n border: 0;\n border-radius: 999px;\n color: var(--codex-muted-text-color, var(--color-text-muted, #777b82));\n background: transparent;\n cursor: pointer;\n}\n\n.codex-composer-menu__trigger:hover:not(:disabled),\n.codex-composer-menu__trigger:focus-visible {\n color: var(--codex-text-color, var(--color-text, #202124));\n background: var(--codex-hover-color, var(--color-surface-low, rgb(0 0 0 / 6%)));\n outline: none;\n}\n\n.codex-composer-menu__trigger:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.codex-composer-menu__list {\n position: absolute;\n z-index: 10;\n bottom: calc(100% + var(--codex-space-2, 8px));\n left: 0;\n}\n</style>\n","<template>\n <div ref=\"root\" class=\"codex-chat-theme codex-composer-menu\" @keydown.escape.prevent.stop=\"close(true)\">\n <slot name=\"trigger\" :open=\"menuOpen\" :toggle=\"toggle\">\n <button\n class=\"codex-composer-menu__trigger\"\n type=\"button\"\n :aria-label=\"buttonLabel\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"menuOpen\"\n :disabled=\"disabled\"\n @click=\"toggle\"\n >\n <svg aria-hidden=\"true\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\">\n <path d=\"M9 3.5v11M3.5 9h11\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-width=\"1.8\" />\n </svg>\n </button>\n </slot>\n <CodexComposerMenuList\n v-if=\"menuOpen\"\n class=\"codex-composer-menu__list\"\n :class=\"menuClass\"\n :aria-label=\"ariaLabel\"\n :items=\"items\"\n @select=\"selectItem\"\n >\n <template v-if=\"$slots.icon\" #icon=\"scope\"><slot name=\"icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.item\" #item=\"scope\"><slot name=\"item\" v-bind=\"scope\" /></template>\n </CodexComposerMenuList>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport CodexComposerMenuList from './CodexComposerMenuList.vue';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n ariaLabel?: string;\n buttonLabel?: string;\n disabled?: boolean;\n items: readonly CodexComposerMenuItem<Payload>[];\n menuClass?: string;\n open?: boolean;\n}>(), {\n ariaLabel: 'Composer actions',\n buttonLabel: 'Open composer actions',\n disabled: false,\n menuClass: undefined,\n open: undefined,\n});\n\nconst emit = defineEmits<{\n select: [item: CodexComposerMenuSelectableItem<Payload>];\n 'update:open': [open: boolean];\n}>();\n// Stryker restore all\n\nconst root = ref<HTMLElement | null>(null);\nconst triggerElement = ref<HTMLElement | null>(null);\nconst internalOpen = ref(false);\nconst menuOpen = computed(() => props.open ?? internalOpen.value);\n\nonMounted(() => document.addEventListener('click', closeOnOutsideClick));\nonBeforeUnmount(() => document.removeEventListener('click', closeOnOutsideClick));\n\nwatch(menuOpen, async (open) => {\n if (!open) return;\n await nextTick();\n const firstItem = root.value?.querySelector(\n '.codex-composer-menu__list > button[role^=\"menuitem\"], .codex-composer-menu__list > div > button[role^=\"menuitem\"]',\n );\n if (firstItem instanceof HTMLElement) firstItem.focus();\n}, { immediate: true });\n\nfunction setOpen(open: boolean): void {\n if (props.open === undefined) {\n internalOpen.value = open;\n }\n emit('update:open', open);\n}\n\nfunction toggle(event?: Event): void {\n event?.stopPropagation();\n if (event?.currentTarget instanceof HTMLElement) triggerElement.value = event.currentTarget;\n if (!props.disabled) {\n setOpen(!menuOpen.value);\n }\n}\n\nfunction close(restoreFocus = false): void {\n if (menuOpen.value) {\n setOpen(false);\n if (restoreFocus) void nextTick(() => triggerElement.value?.focus());\n }\n}\n\nfunction closeOnOutsideClick(event: MouseEvent): void {\n if (root.value && event.target && !root.value.contains(event.target as Node)) {\n close(false);\n }\n}\n\nfunction selectItem(item: CodexComposerMenuSelectableItem<Payload>): void {\n emit('select', item);\n const shouldClose = item.closeOnSelect ?? (item.type !== 'checkbox');\n if (shouldClose) {\n close(true);\n }\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineExpose({ close, open: () => setOpen(true), toggle });\n// Stryker restore all\n</script>\n\n<style scoped>\n.codex-composer-menu {\n position: relative;\n flex: 0 0 auto;\n}\n\n.codex-composer-menu__trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--chat-composer-control-size, var(--codex-composer-button-size, 36px));\n height: var(--chat-composer-control-size, var(--codex-composer-button-size, 36px));\n padding: 0;\n border: 0;\n border-radius: 999px;\n color: var(--codex-muted-text-color, var(--color-text-muted, #777b82));\n background: transparent;\n cursor: pointer;\n}\n\n.codex-composer-menu__trigger:hover:not(:disabled),\n.codex-composer-menu__trigger:focus-visible {\n color: var(--codex-text-color, var(--color-text, #202124));\n background: var(--codex-hover-color, var(--color-surface-low, rgb(0 0 0 / 6%)));\n outline: none;\n}\n\n.codex-composer-menu__trigger:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.codex-composer-menu__list {\n position: absolute;\n z-index: 10;\n bottom: calc(100% + var(--codex-space-2, 8px));\n left: 0;\n}\n</style>\n","<template>\n <CodexComposerMenu\n v-if=\"menuItems.length > 0\"\n class=\"chat-composer-action-menu__root\"\n menu-class=\"chat-composer-action-menu\"\n aria-label=\"Composer actions\"\n button-label=\"Composer actions\"\n :disabled=\"disabled\"\n :items=\"menuItems\"\n @select=\"selectMenuItem\"\n >\n <template #trigger=\"{ open, toggle }\">\n <button\n class=\"chat-composer-action-menu__button\"\n type=\"button\"\n aria-label=\"Composer actions\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"open\"\n :disabled=\"disabled\"\n @click=\"toggle\"\n >\n <PlusIcon />\n </button>\n </template>\n <template v-if=\"$slots.icon\" #icon=\"scope\"><slot name=\"icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.item\" #item=\"scope\"><slot name=\"item\" v-bind=\"scope\" /></template>\n </CodexComposerMenu>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed, type Component } from 'vue';\nimport type { ApprovalPreset } from './contracts';\nimport { approvalPresetOptions } from './approval-presets';\nimport CodexComposerMenu from '../components/CodexComposerMenu.vue';\nimport type {\n CodexComposerMenuItem,\n CodexComposerMenuSelectableItem,\n} from '../composer-menu';\nimport { HandStopIcon, ListDetailsIcon, PaperclipIcon, PlusIcon, ShieldCheckIcon, Sparkles, TargetArrowIcon } from '../icons/app-icons';\n\ntype ComposerMenuAction = { kind: 'approval'; preset: ApprovalPreset };\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n attachEnabled?: boolean;\n disabled?: boolean;\n leadingMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n items?: readonly CodexComposerMenuItem<Payload>[];\n approvalPreset?: ApprovalPreset | null;\n approvalPresets?: readonly ApprovalPreset[];\n goalMode?: boolean;\n planMode: boolean;\n showApprovalMenu?: boolean;\n showGoalMode?: boolean;\n showPlanMode?: boolean;\n}>(), {\n attachEnabled: false,\n disabled: false,\n leadingMenuItems: () => [],\n items: () => [],\n approvalPreset: null,\n approvalPresets: () => [],\n goalMode: false,\n planMode: false,\n showApprovalMenu: false,\n showGoalMode: false,\n showPlanMode: true,\n});\n\nconst emit = defineEmits<{\n attach: [];\n select: [item: CodexComposerMenuSelectableItem<Payload>];\n selectApprovalPreset: [preset: ApprovalPreset];\n 'update:goalMode': [enabled: boolean];\n 'update:planMode': [enabled: boolean];\n}>();\n// Stryker restore all\n\nconst allowedApprovalPresets = computed(() => new Set(props.approvalPresets));\nconst menuItems = computed<CodexComposerMenuItem<ComposerMenuAction | Payload>[]>(() => {\n const items: CodexComposerMenuItem<ComposerMenuAction | Payload>[] = [];\n\n if (props.showApprovalMenu) {\n items.push({\n id: 'approval',\n type: 'submenu',\n label: 'Approval',\n icon: ShieldCheckIcon,\n items: approvalPresetOptions.map((option) => ({\n id: `approval:${option.id}`,\n type: 'radio',\n label: option.label,\n description: option.description,\n icon: approvalIcon(option.id),\n checked: option.id === props.approvalPreset,\n disabled: !allowedApprovalPresets.value.has(option.id),\n payload: { kind: 'approval', preset: option.id },\n })),\n });\n }\n\n items.push(...props.leadingMenuItems);\n\n if (props.showGoalMode) {\n items.push({\n id: 'goal-mode',\n type: 'checkbox',\n label: 'Goal mode',\n accessory: 'switch',\n checked: props.goalMode,\n icon: TargetArrowIcon,\n });\n }\n\n if (props.showPlanMode) {\n items.push({\n id: 'plan-mode',\n type: 'checkbox',\n label: 'Plan mode',\n accessory: 'switch',\n checked: props.planMode,\n icon: ListDetailsIcon,\n });\n }\n\n items.push(...props.items);\n\n if (props.attachEnabled) {\n if (items.length > 0 && items.at(-1)?.type !== 'separator') {\n items.push({ id: 'group-attach', type: 'separator' });\n }\n items.push({\n id: 'attach',\n type: 'action',\n label: 'Add Files & Photos',\n icon: PaperclipIcon,\n });\n }\n\n return items;\n});\n\nfunction approvalIcon(preset: ApprovalPreset): Component {\n if (preset === 'ask-for-approval') {\n return HandStopIcon;\n }\n if (preset === 'approve-for-me') {\n return Sparkles;\n }\n return ShieldCheckIcon;\n}\n\nfunction selectMenuItem(item: CodexComposerMenuSelectableItem<ComposerMenuAction | Payload>): void {\n const action = item.payload;\n if (item.id === 'plan-mode') {\n emit('update:planMode', !props.planMode);\n return;\n }\n if (item.id === 'goal-mode') {\n emit('update:goalMode', !props.goalMode);\n return;\n }\n if (item.id.startsWith('approval:') && isComposerMenuAction(action) && action.kind === 'approval') {\n emit('selectApprovalPreset', action.preset);\n return;\n }\n if (item.id === 'attach') {\n emit('attach');\n return;\n }\n\n emit('select', item as CodexComposerMenuSelectableItem<Payload>);\n}\n\nfunction isComposerMenuAction(value: unknown): value is ComposerMenuAction {\n return typeof value === 'object' && value !== null && 'kind' in value;\n}\n</script>\n\n<style scoped>\n.chat-composer-action-menu__root {\n --codex-composer-menu-radius: var(--radius-xl);\n --codex-composer-menu-shadow: var(--shadow-menu);\n}\n\n.chat-composer-action-menu__button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--chat-composer-action-size, 32px);\n height: var(--chat-composer-action-size, 32px);\n border: 0;\n border-radius: var(--radius-full);\n color: var(--color-text-muted);\n background: transparent;\n cursor: pointer;\n}\n\n.chat-composer-action-menu__button:hover:not(:disabled) {\n color: var(--color-text);\n background: var(--color-surface-base);\n}\n\n.chat-composer-action-menu__button:disabled {\n cursor: default;\n}\n\n.chat-composer-action-menu__button svg {\n width: var(--icon-lg);\n height: var(--icon-lg);\n stroke-width: 1.5;\n}\n\n:deep(.chat-composer-action-menu .codex-composer-menu-list__submenu-list) {\n width: 360px;\n max-width: min(360px, calc(100vw - var(--space-12)));\n}\n</style>\n","<template>\n <CodexComposerMenu\n v-if=\"menuItems.length > 0\"\n class=\"chat-composer-action-menu__root\"\n menu-class=\"chat-composer-action-menu\"\n aria-label=\"Composer actions\"\n button-label=\"Composer actions\"\n :disabled=\"disabled\"\n :items=\"menuItems\"\n @select=\"selectMenuItem\"\n >\n <template #trigger=\"{ open, toggle }\">\n <button\n class=\"chat-composer-action-menu__button\"\n type=\"button\"\n aria-label=\"Composer actions\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"open\"\n :disabled=\"disabled\"\n @click=\"toggle\"\n >\n <PlusIcon />\n </button>\n </template>\n <template v-if=\"$slots.icon\" #icon=\"scope\"><slot name=\"icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.item\" #item=\"scope\"><slot name=\"item\" v-bind=\"scope\" /></template>\n </CodexComposerMenu>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed, type Component } from 'vue';\nimport type { ApprovalPreset } from './contracts';\nimport { approvalPresetOptions } from './approval-presets';\nimport CodexComposerMenu from '../components/CodexComposerMenu.vue';\nimport type {\n CodexComposerMenuItem,\n CodexComposerMenuSelectableItem,\n} from '../composer-menu';\nimport { HandStopIcon, ListDetailsIcon, PaperclipIcon, PlusIcon, ShieldCheckIcon, Sparkles, TargetArrowIcon } from '../icons/app-icons';\n\ntype ComposerMenuAction = { kind: 'approval'; preset: ApprovalPreset };\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n attachEnabled?: boolean;\n disabled?: boolean;\n leadingMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n items?: readonly CodexComposerMenuItem<Payload>[];\n approvalPreset?: ApprovalPreset | null;\n approvalPresets?: readonly ApprovalPreset[];\n goalMode?: boolean;\n planMode: boolean;\n showApprovalMenu?: boolean;\n showGoalMode?: boolean;\n showPlanMode?: boolean;\n}>(), {\n attachEnabled: false,\n disabled: false,\n leadingMenuItems: () => [],\n items: () => [],\n approvalPreset: null,\n approvalPresets: () => [],\n goalMode: false,\n planMode: false,\n showApprovalMenu: false,\n showGoalMode: false,\n showPlanMode: true,\n});\n\nconst emit = defineEmits<{\n attach: [];\n select: [item: CodexComposerMenuSelectableItem<Payload>];\n selectApprovalPreset: [preset: ApprovalPreset];\n 'update:goalMode': [enabled: boolean];\n 'update:planMode': [enabled: boolean];\n}>();\n// Stryker restore all\n\nconst allowedApprovalPresets = computed(() => new Set(props.approvalPresets));\nconst menuItems = computed<CodexComposerMenuItem<ComposerMenuAction | Payload>[]>(() => {\n const items: CodexComposerMenuItem<ComposerMenuAction | Payload>[] = [];\n\n if (props.showApprovalMenu) {\n items.push({\n id: 'approval',\n type: 'submenu',\n label: 'Approval',\n icon: ShieldCheckIcon,\n items: approvalPresetOptions.map((option) => ({\n id: `approval:${option.id}`,\n type: 'radio',\n label: option.label,\n description: option.description,\n icon: approvalIcon(option.id),\n checked: option.id === props.approvalPreset,\n disabled: !allowedApprovalPresets.value.has(option.id),\n payload: { kind: 'approval', preset: option.id },\n })),\n });\n }\n\n items.push(...props.leadingMenuItems);\n\n if (props.showGoalMode) {\n items.push({\n id: 'goal-mode',\n type: 'checkbox',\n label: 'Goal mode',\n accessory: 'switch',\n checked: props.goalMode,\n icon: TargetArrowIcon,\n });\n }\n\n if (props.showPlanMode) {\n items.push({\n id: 'plan-mode',\n type: 'checkbox',\n label: 'Plan mode',\n accessory: 'switch',\n checked: props.planMode,\n icon: ListDetailsIcon,\n });\n }\n\n items.push(...props.items);\n\n if (props.attachEnabled) {\n if (items.length > 0 && items.at(-1)?.type !== 'separator') {\n items.push({ id: 'group-attach', type: 'separator' });\n }\n items.push({\n id: 'attach',\n type: 'action',\n label: 'Add Files & Photos',\n icon: PaperclipIcon,\n });\n }\n\n return items;\n});\n\nfunction approvalIcon(preset: ApprovalPreset): Component {\n if (preset === 'ask-for-approval') {\n return HandStopIcon;\n }\n if (preset === 'approve-for-me') {\n return Sparkles;\n }\n return ShieldCheckIcon;\n}\n\nfunction selectMenuItem(item: CodexComposerMenuSelectableItem<ComposerMenuAction | Payload>): void {\n const action = item.payload;\n if (item.id === 'plan-mode') {\n emit('update:planMode', !props.planMode);\n return;\n }\n if (item.id === 'goal-mode') {\n emit('update:goalMode', !props.goalMode);\n return;\n }\n if (item.id.startsWith('approval:') && isComposerMenuAction(action) && action.kind === 'approval') {\n emit('selectApprovalPreset', action.preset);\n return;\n }\n if (item.id === 'attach') {\n emit('attach');\n return;\n }\n\n emit('select', item as CodexComposerMenuSelectableItem<Payload>);\n}\n\nfunction isComposerMenuAction(value: unknown): value is ComposerMenuAction {\n return typeof value === 'object' && value !== null && 'kind' in value;\n}\n</script>\n\n<style scoped>\n.chat-composer-action-menu__root {\n --codex-composer-menu-radius: var(--radius-xl);\n --codex-composer-menu-shadow: var(--shadow-menu);\n}\n\n.chat-composer-action-menu__button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--chat-composer-action-size, 32px);\n height: var(--chat-composer-action-size, 32px);\n border: 0;\n border-radius: var(--radius-full);\n color: var(--color-text-muted);\n background: transparent;\n cursor: pointer;\n}\n\n.chat-composer-action-menu__button:hover:not(:disabled) {\n color: var(--color-text);\n background: var(--color-surface-base);\n}\n\n.chat-composer-action-menu__button:disabled {\n cursor: default;\n}\n\n.chat-composer-action-menu__button svg {\n width: var(--icon-lg);\n height: var(--icon-lg);\n stroke-width: 1.5;\n}\n\n:deep(.chat-composer-action-menu .codex-composer-menu-list__submenu-list) {\n width: 360px;\n max-width: min(360px, calc(100vw - var(--space-12)));\n}\n</style>\n","<template>\n <button\n class=\"codex-chat-theme chat-composer__voice\"\n :class=\"{ 'chat-composer__voice--recording': recording }\"\n type=\"button\"\n :disabled=\"disabled\"\n :aria-pressed=\"recording\"\n :aria-label=\"label\"\n :title=\"title\"\n @click=\"emit('toggle')\"\n >\n <MicrophoneIcon aria-hidden=\"true\" />\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { MicrophoneIcon } from '../icons/app-icons'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n disabled: boolean\n label: string\n recording: boolean\n title: string\n}>()\n\nconst emit = defineEmits<{\n toggle: []\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-composer__voice {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--chat-composer-compact-control-size, var(--chat-composer-button-size-small, 28px));\n height: var(--chat-composer-compact-control-size, var(--chat-composer-button-size-small, 28px));\n border: 0;\n border-radius: var(--radius-full);\n color: var(--color-text-muted);\n background: transparent;\n cursor: pointer;\n}\n\n.chat-composer__voice:hover:not(:disabled),\n.chat-composer__voice--recording {\n color: var(--color-text);\n background: var(--color-surface-base);\n}\n\n.chat-composer__voice:disabled {\n cursor: default;\n opacity: 0.42;\n}\n\n.chat-composer__voice svg {\n width: 20px;\n height: 20px;\n stroke-width: 1.8;\n}\n</style>\n","<template>\n <button\n class=\"codex-chat-theme chat-composer__voice\"\n :class=\"{ 'chat-composer__voice--recording': recording }\"\n type=\"button\"\n :disabled=\"disabled\"\n :aria-pressed=\"recording\"\n :aria-label=\"label\"\n :title=\"title\"\n @click=\"emit('toggle')\"\n >\n <MicrophoneIcon aria-hidden=\"true\" />\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { MicrophoneIcon } from '../icons/app-icons'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n disabled: boolean\n label: string\n recording: boolean\n title: string\n}>()\n\nconst emit = defineEmits<{\n toggle: []\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-composer__voice {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--chat-composer-compact-control-size, var(--chat-composer-button-size-small, 28px));\n height: var(--chat-composer-compact-control-size, var(--chat-composer-button-size-small, 28px));\n border: 0;\n border-radius: var(--radius-full);\n color: var(--color-text-muted);\n background: transparent;\n cursor: pointer;\n}\n\n.chat-composer__voice:hover:not(:disabled),\n.chat-composer__voice--recording {\n color: var(--color-text);\n background: var(--color-surface-base);\n}\n\n.chat-composer__voice:disabled {\n cursor: default;\n opacity: 0.42;\n}\n\n.chat-composer__voice svg {\n width: 20px;\n height: 20px;\n stroke-width: 1.8;\n}\n</style>\n","<template>\n <div\n class=\"codex-chat-theme chat-composer-waveform\"\n :aria-label=\"label\"\n role=\"img\"\n >\n <canvas\n ref=\"waveform\"\n :width=\"width\"\n :height=\"height\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue';\n\ntype WaveformAudioRecorder = {\n getAnalyser(): AnalyserNode | null;\n getBufferLength(): number;\n};\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n active?: boolean;\n audioRecorder: WaveformAudioRecorder | null;\n height?: number;\n label?: string;\n width?: number;\n}>(), {\n active: false,\n height: 28,\n label: 'Audio waveform',\n width: 640,\n});\n// Stryker restore all\n\nconst waveform = ref<HTMLCanvasElement | null>(null);\nlet animationFrameId: number | null = null;\nlet dataArray: Uint8Array<ArrayBuffer> | null = null;\nlet amplitudeHistory: number[] = [];\nlet lastSampleTime = 0;\n\nconst barGap = 2;\nconst barWidth = 2;\nconst minBarHeight = 2;\nconst sampleIntervalMs = 60;\nconst voiceScale = 3.2;\n\nwatch(() => props.active, (active) => {\n if (active) {\n startAnimation();\n return;\n }\n\n stopAnimation();\n});\n\nonMounted(() => {\n if (props.active) {\n startAnimation();\n }\n});\n\nonBeforeUnmount(stopAnimation);\n\nfunction startAnimation(): void {\n draw();\n}\n\nfunction stopAnimation(): void {\n if (animationFrameId !== null) {\n cancelAnimationFrame(animationFrameId);\n animationFrameId = null;\n }\n dataArray = null;\n lastSampleTime = 0;\n}\n\nfunction draw(): void {\n try {\n const canvas = waveform.value;\n const analyser = props.audioRecorder?.getAnalyser();\n const bufferLength = props.audioRecorder?.getBufferLength() ?? 0;\n const canvasContext = canvas?.getContext('2d');\n if (!canvas || !canvasContext || !analyser || bufferLength <= 0) {\n animationFrameId = props.active ? requestAnimationFrame(draw) : null;\n return;\n }\n\n const now = Date.now();\n if (now - lastSampleTime >= sampleIntervalMs) {\n if (!dataArray || dataArray.length !== bufferLength) {\n dataArray = new Uint8Array(new ArrayBuffer(bufferLength));\n amplitudeHistory = [];\n }\n analyser.getByteTimeDomainData(dataArray);\n amplitudeHistory.push(calculateVoiceActivity(dataArray));\n amplitudeHistory = amplitudeHistory.slice(-getMaxBars(canvas.width));\n lastSampleTime = now;\n }\n\n canvasContext.clearRect(0, 0, canvas.width, canvas.height);\n canvasContext.fillStyle = getComputedStyle(canvas).color;\n\n const step = barWidth + barGap;\n const centerY = canvas.height / 2;\n for (const positionFromRight of amplitudeHistory.keys()) {\n const x = canvas.width - barWidth - positionFromRight * step;\n if (x < 0) {\n break;\n }\n\n const amplitude = amplitudeHistory.at(-positionFromRight - 1) ?? 0;\n const barHeight = Math.max(minBarHeight, amplitude * canvas.height);\n canvasContext.fillRect(x, centerY - barHeight / 2, barWidth, barHeight);\n }\n } catch (error) {\n console.error('Error drawing waveform', error);\n }\n\n animationFrameId = props.active ? requestAnimationFrame(draw) : null;\n}\n\nfunction calculateVoiceActivity(samples: Uint8Array<ArrayBuffer>): number {\n let sumSquares = 0;\n for (const sample of samples) {\n const centeredSample = (sample - 128) / 128;\n sumSquares += centeredSample * centeredSample;\n }\n\n return Math.min(1, Math.sqrt(sumSquares / samples.length) * voiceScale);\n}\n\nfunction getMaxBars(width: number): number {\n return Math.max(1, Math.ceil(width / (barWidth + barGap)));\n}\n</script>\n\n<style scoped>\n.chat-composer-waveform {\n flex: 1 1 auto;\n min-width: 0;\n height: var(--space-10);\n display: flex;\n align-items: center;\n color: var(--color-text-muted);\n}\n\n.chat-composer-waveform canvas {\n width: 100%;\n height: 100%;\n display: block;\n}\n</style>\n","<template>\n <div\n class=\"codex-chat-theme chat-composer-waveform\"\n :aria-label=\"label\"\n role=\"img\"\n >\n <canvas\n ref=\"waveform\"\n :width=\"width\"\n :height=\"height\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue';\n\ntype WaveformAudioRecorder = {\n getAnalyser(): AnalyserNode | null;\n getBufferLength(): number;\n};\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n active?: boolean;\n audioRecorder: WaveformAudioRecorder | null;\n height?: number;\n label?: string;\n width?: number;\n}>(), {\n active: false,\n height: 28,\n label: 'Audio waveform',\n width: 640,\n});\n// Stryker restore all\n\nconst waveform = ref<HTMLCanvasElement | null>(null);\nlet animationFrameId: number | null = null;\nlet dataArray: Uint8Array<ArrayBuffer> | null = null;\nlet amplitudeHistory: number[] = [];\nlet lastSampleTime = 0;\n\nconst barGap = 2;\nconst barWidth = 2;\nconst minBarHeight = 2;\nconst sampleIntervalMs = 60;\nconst voiceScale = 3.2;\n\nwatch(() => props.active, (active) => {\n if (active) {\n startAnimation();\n return;\n }\n\n stopAnimation();\n});\n\nonMounted(() => {\n if (props.active) {\n startAnimation();\n }\n});\n\nonBeforeUnmount(stopAnimation);\n\nfunction startAnimation(): void {\n draw();\n}\n\nfunction stopAnimation(): void {\n if (animationFrameId !== null) {\n cancelAnimationFrame(animationFrameId);\n animationFrameId = null;\n }\n dataArray = null;\n lastSampleTime = 0;\n}\n\nfunction draw(): void {\n try {\n const canvas = waveform.value;\n const analyser = props.audioRecorder?.getAnalyser();\n const bufferLength = props.audioRecorder?.getBufferLength() ?? 0;\n const canvasContext = canvas?.getContext('2d');\n if (!canvas || !canvasContext || !analyser || bufferLength <= 0) {\n animationFrameId = props.active ? requestAnimationFrame(draw) : null;\n return;\n }\n\n const now = Date.now();\n if (now - lastSampleTime >= sampleIntervalMs) {\n if (!dataArray || dataArray.length !== bufferLength) {\n dataArray = new Uint8Array(new ArrayBuffer(bufferLength));\n amplitudeHistory = [];\n }\n analyser.getByteTimeDomainData(dataArray);\n amplitudeHistory.push(calculateVoiceActivity(dataArray));\n amplitudeHistory = amplitudeHistory.slice(-getMaxBars(canvas.width));\n lastSampleTime = now;\n }\n\n canvasContext.clearRect(0, 0, canvas.width, canvas.height);\n canvasContext.fillStyle = getComputedStyle(canvas).color;\n\n const step = barWidth + barGap;\n const centerY = canvas.height / 2;\n for (const positionFromRight of amplitudeHistory.keys()) {\n const x = canvas.width - barWidth - positionFromRight * step;\n if (x < 0) {\n break;\n }\n\n const amplitude = amplitudeHistory.at(-positionFromRight - 1) ?? 0;\n const barHeight = Math.max(minBarHeight, amplitude * canvas.height);\n canvasContext.fillRect(x, centerY - barHeight / 2, barWidth, barHeight);\n }\n } catch (error) {\n console.error('Error drawing waveform', error);\n }\n\n animationFrameId = props.active ? requestAnimationFrame(draw) : null;\n}\n\nfunction calculateVoiceActivity(samples: Uint8Array<ArrayBuffer>): number {\n let sumSquares = 0;\n for (const sample of samples) {\n const centeredSample = (sample - 128) / 128;\n sumSquares += centeredSample * centeredSample;\n }\n\n return Math.min(1, Math.sqrt(sumSquares / samples.length) * voiceScale);\n}\n\nfunction getMaxBars(width: number): number {\n return Math.max(1, Math.ceil(width / (barWidth + barGap)));\n}\n</script>\n\n<style scoped>\n.chat-composer-waveform {\n flex: 1 1 auto;\n min-width: 0;\n height: var(--space-10);\n display: flex;\n align-items: center;\n color: var(--color-text-muted);\n}\n\n.chat-composer-waveform canvas {\n width: 100%;\n height: 100%;\n display: block;\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-composer__audio-field\">\n <ChatComposerWaveform\n v-if=\"recording\"\n :active=\"recording\"\n :audio-recorder=\"recorder\"\n label=\"Audio waveform\"\n />\n <span v-else class=\"chat-composer__audio-status\">\n Transcribing...\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport ChatComposerWaveform from './ChatComposerWaveform.vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n recorder: {\n getAnalyser(): AnalyserNode | null\n getBufferLength(): number\n } | null\n recording: boolean\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-composer__audio-field {\n display: flex;\n align-items: center;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 28px;\n padding: 0 var(--space-2);\n}\n\n.chat-composer__audio-status {\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-20);\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-composer__audio-field\">\n <ChatComposerWaveform\n v-if=\"recording\"\n :active=\"recording\"\n :audio-recorder=\"recorder\"\n label=\"Audio waveform\"\n />\n <span v-else class=\"chat-composer__audio-status\">\n Transcribing...\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport ChatComposerWaveform from './ChatComposerWaveform.vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n recorder: {\n getAnalyser(): AnalyserNode | null\n getBufferLength(): number\n } | null\n recording: boolean\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-composer__audio-field {\n display: flex;\n align-items: center;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 28px;\n padding: 0 var(--space-2);\n}\n\n.chat-composer__audio-status {\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-20);\n}\n</style>\n","import type { CodexConversationLink } from './contracts';\n\nexport type CodexEditorFileReference = {\n path: string;\n line: number;\n column?: number;\n};\n\nexport function parseCodexEditorFileReference(value: string): CodexEditorFileReference | null {\n const match = /^(.*\\.[^./\\\\:\\s]+):(\\d+)(?::(\\d+))?$/.exec(value.trim());\n if (!match) return null;\n const filePath = match[1]!;\n if (filePath.includes(':')) return null;\n const line = Number(match[2]!);\n const column = match[3] === undefined ? undefined : Number(match[3]);\n if (!Number.isSafeInteger(line) || line <= 0) return null;\n if (column !== undefined && (!Number.isSafeInteger(column) || column <= 0)) return null;\n return { path: filePath, line, ...(column === undefined ? {} : { column }) };\n}\n\nexport function codexConversationLinkFromHref(href: string): CodexConversationLink | null {\n const normalizedHref = href.trim();\n if (!normalizedHref || /^(?:\\\\\\\\|\\/\\/)/.test(normalizedHref)) return null;\n if (/^[a-z]:[\\\\/]/i.test(normalizedHref)) {\n return { href: normalizedHref, kind: 'file', path: safelyDecodePath(stripLinkDecoration(normalizedHref)) };\n }\n\n const undecoratedHref = safelyDecodePath(stripLinkDecoration(normalizedHref));\n const relativeEditorReference = parseCodexEditorFileReference(undecoratedHref);\n if (relativeEditorReference) {\n return fileReferenceLink(normalizedHref, relativeEditorReference);\n }\n\n try {\n const url = new URL(normalizedHref);\n if (url.protocol === 'http:' || url.protocol === 'https:' || url.protocol === 'mailto:' || url.protocol === 'tel:') {\n return { href: normalizedHref, kind: 'external' };\n }\n if (url.protocol === 'file:') {\n const filePath = safelyDecodePath(url.pathname);\n const editorReference = parseCodexEditorFileReference(filePath);\n return editorReference\n ? fileReferenceLink(normalizedHref, editorReference)\n : { href: normalizedHref, kind: 'file', path: filePath };\n }\n return null;\n } catch {\n return undecoratedHref ? { href: normalizedHref, kind: 'file', path: undecoratedHref } : null;\n }\n}\n\nfunction fileReferenceLink(\n href: string,\n reference: CodexEditorFileReference,\n): Extract<CodexConversationLink, { kind: 'file' }> {\n return {\n href,\n kind: 'file',\n path: reference.path,\n line: reference.line,\n ...(reference.column === undefined ? {} : { column: reference.column }),\n };\n}\n\nfunction stripLinkDecoration(href: string): string {\n return href.split('#', 1)[0]!.split('?', 1)[0]!.trim();\n}\n\nfunction safelyDecodePath(path: string): string {\n try {\n return decodeURIComponent(path);\n } catch {\n return path;\n }\n}\n","export type ToolExecutionState = 'running' | 'completed' | 'error' | 'canceled';\n\nexport type ToolStatusDescriptor = {\n action: string;\n phase: string;\n params?: Record<string, unknown>;\n source: string;\n};\n\nexport type MessageToolCall = {\n args: unknown;\n done?: boolean;\n function: string;\n id: string;\n /** Assistant message that contains this tool call, when adapted from a surface message. */\n messageId?: string;\n kind?: string;\n metadata?: Readonly<Record<string, unknown>>;\n /** App-server item id for this tool call, when available. */\n itemId?: string;\n state: ToolExecutionState;\n status?: string;\n /** Turn that produced this tool call, when adapted from a surface message. */\n turnId?: string;\n result: unknown;\n};\n\nexport function getMessageToolCallName(toolCall: MessageToolCall) {\n return toolCall.function;\n}\n\nexport function isImageGenerationToolCall(toolCall: MessageToolCall): boolean {\n return toolCall.kind === 'imageGeneration' || toolCall.function === 'image_generation';\n}\n\nexport function getMessageToolCallArgs(toolCall: MessageToolCall) {\n return toolCall.args;\n}\n\nexport type MessageMedia = {\n alt?: string;\n mimeType?: string;\n prompt?: string;\n title?: string;\n url: string;\n};\n\nexport type MessageAttachment = {\n kind: 'file' | 'image';\n name: string;\n path?: string;\n url?: string;\n mimeType?: string;\n};\n\nexport type MessagePhase = 'commentary' | 'final_answer';\n\nexport type MessagePart =\n | { type: 'attachment'; attachment: MessageAttachment }\n | { type: 'media'; media: MessageMedia }\n | { type: 'question'; historical?: boolean; request: Extract<CodexSurfaceClientRequest, { kind: 'ask_user' }> }\n | { type: 'reasoning'; summary: string; itemId?: string; summaryIndex?: number }\n | { type: 'text'; content: string; itemId?: string; phase?: MessagePhase }\n | { type: 'tool'; toolCall: MessageToolCall };\n\nexport type MessageSuggestedPrompt = {\n kind: 'chat' | 'idea';\n text: string;\n};\n\nexport type Message = {\n compactionStatus?: 'completed' | 'running';\n role: 'user' | 'assistant';\n content: string;\n createdAt?: string;\n engine?: string;\n id?: string;\n model?: string;\n parts?: MessagePart[];\n streaming?: boolean;\n suggestedPrompts?: MessageSuggestedPrompt[];\n toolCalls?: MessageToolCall[];\n /** Turn that produced this message, when available. */\n turnId?: string;\n type?: 'compaction' | 'display' | 'steer' | 'text';\n};\n\nexport type ChatModelOption = {\n engine: string;\n internalId: string;\n label: string;\n};\nimport type { CodexSurfaceClientRequest } from '@codex-app-sdk/core/surface';\n","import type { CodexConversationFileAction, CodexConversationLink } from './contracts';\nimport { codexConversationLinkFromHref } from './conversation-links';\nimport { getMessageToolCallName, isImageGenerationToolCall, type MessageToolCall, type ToolStatusDescriptor } from './types';\n\ntype Translate = (key: string, params?: Record<string, unknown>) => string;\n\nexport type ToolLineDiff = {\n addedLines: number;\n removedLines: number;\n};\n\nexport type CodexToolTitlePresenterContext = {\n descriptor: ToolStatusDescriptor | undefined;\n toolCall: MessageToolCall;\n translate: Translate;\n};\n\nexport type CodexToolTitlePresenter = (\n context: CodexToolTitlePresenterContext,\n) => string | undefined;\n\nexport type CodexToolDisplayTargetPart = {\n label: string;\n link?: CodexConversationLink;\n separator?: string;\n suffix?: string;\n};\n\nconst toolTitlePresenters = new Set<CodexToolTitlePresenter>();\n\nexport function registerCodexToolTitlePresenter(presenter: CodexToolTitlePresenter): () => void {\n toolTitlePresenters.add(presenter);\n return () => toolTitlePresenters.delete(presenter);\n}\n\nexport function parseToolStatusDescriptor(value: unknown): ToolStatusDescriptor | undefined {\n if (typeof value !== 'string') return undefined;\n\n try {\n const parsed = JSON.parse(value) as Partial<ToolStatusDescriptor>;\n if (\n typeof parsed.source !== 'string' ||\n typeof parsed.action !== 'string' ||\n typeof parsed.phase !== 'string'\n ) {\n return undefined;\n }\n return {\n action: parsed.action,\n phase: parsed.phase,\n params: parsed.params && typeof parsed.params === 'object' && !Array.isArray(parsed.params) ? parsed.params : undefined,\n source: parsed.source,\n };\n } catch {}\n}\n\nexport function getToolLineDiff(descriptor: ToolStatusDescriptor | undefined): ToolLineDiff | undefined {\n const params = descriptor?.params;\n const addedLines = typeof params?.addedLines === 'number' ? params.addedLines : 0;\n const removedLines = typeof params?.removedLines === 'number' ? params.removedLines : 0;\n return addedLines || removedLines ? { addedLines, removedLines } : undefined;\n}\n\nexport function getToolGroupLineDiff(toolCalls: readonly MessageToolCall[]): ToolLineDiff | undefined {\n let addedLines = 0;\n let removedLines = 0;\n for (const toolCall of toolCalls) {\n const lineDiff = getToolLineDiff(parseToolStatusDescriptor(toolCall.status));\n addedLines += lineDiff?.addedLines ?? 0;\n removedLines += lineDiff?.removedLines ?? 0;\n }\n return addedLines || removedLines ? { addedLines, removedLines } : undefined;\n}\n\nexport function getToolDisplayTitle(\n toolCall: MessageToolCall,\n descriptor: ToolStatusDescriptor | undefined,\n t: Translate = defaultToolTranslate,\n) {\n for (const presenter of toolTitlePresenters) {\n const title = presenter({ descriptor, toolCall, translate: t });\n if (title) return title;\n }\n\n if (isImageGenerationToolCall(toolCall)) {\n return t(`chat.tool.imageGeneration.${imageGenerationPhase(toolCall)}`);\n }\n\n if (descriptor && isSemanticToolAction(descriptor.action)) {\n const phase = commandPhase(descriptor.phase);\n if (descriptor.action === 'plan') {\n const operation = descriptor.params?.operation === 'update' ? 'update' : 'write';\n return t(`chat.tool.command.plan.${operation}.${phase}`);\n }\n\n const target = displayFileTarget(toolCall, descriptor, commandTarget(descriptor, getMessageToolCallName(toolCall)));\n return t(`chat.tool.command.${descriptor.action}.${phase}`, target ? { target } : undefined);\n }\n\n if (descriptor) {\n return `${descriptor.phase} ${getMessageToolCallName(toolCall)}`;\n }\n\n return getToolFallbackTitle(toolCall, t);\n}\n\nexport function getToolDisplayTitleParts(\n toolCall: MessageToolCall,\n descriptor: ToolStatusDescriptor | undefined,\n t: Translate = defaultToolTranslate,\n): { prefix?: string; target?: string; title: string } {\n const title = getToolDisplayTitle(toolCall, descriptor, t);\n if (\n !descriptor\n || !['create', 'delete', 'edit', 'read'].includes(descriptor.action)\n ) {\n return { title };\n }\n\n const target = displayFileTarget(toolCall, descriptor, commandTarget(descriptor, getMessageToolCallName(toolCall)));\n const prefix = title.endsWith(target) ? title.slice(0, -target.length).trimEnd() : undefined;\n return prefix ? { prefix, target, title } : { title };\n}\n\nexport function getToolDisplayTargetLink(\n toolCall: MessageToolCall,\n descriptor: ToolStatusDescriptor | undefined,\n target?: string,\n): CodexConversationLink | undefined {\n return getToolDisplayTargetParts(toolCall, descriptor, target)?.find((part) => part.link)?.link;\n}\n\nexport function getToolDisplayTargetParts(\n toolCall: MessageToolCall,\n descriptor: ToolStatusDescriptor | undefined,\n _target?: string,\n): CodexToolDisplayTargetPart[] | undefined {\n if (\n !descriptor\n || !['create', 'edit', 'read'].includes(descriptor.action)\n ) {\n return undefined;\n }\n\n const targetValues = fileTargetValues(toolCall, descriptor.action);\n const targetTokens = targetValues.slice(0, 3);\n const filePaths = toolFilePaths(toolCall);\n if (!targetTokens.length || !filePaths.length) return undefined;\n\n const action = descriptor.action as CodexConversationFileAction;\n const parts = targetTokens.map((token, index) => {\n const filePath = filePaths.find((candidate) => displayFileName(candidate, descriptor.action) === token);\n const link = filePath ? codexConversationLinkFromHref(filePath) : undefined;\n const isSkillRead = descriptor.action === 'read' && filePath?.split(/[\\\\/]/u).at(-1) === 'SKILL.md' && token.endsWith(' Skill');\n return {\n label: isSkillRead ? token.slice(0, -' Skill'.length) : token,\n ...(link?.kind === 'file' ? {\n link: {\n ...link,\n filepath: link.path,\n action,\n ...(toolCall.itemId ? { itemId: toolCall.itemId } : {}),\n ...(toolCall.messageId ? { messageId: toolCall.messageId } : {}),\n ...(toolCall.turnId ? { turnId: toolCall.turnId } : {}),\n },\n } : {}),\n separator: index === 0 ? '' : ', ',\n ...(isSkillRead ? { suffix: ' Skill' } : {}),\n } satisfies CodexToolDisplayTargetPart;\n });\n\n const truncatedCount = targetValues.length - targetTokens.length;\n if (truncatedCount > 0) {\n parts.push({ label: `and ${truncatedCount} more`, separator: ' ' });\n }\n return parts;\n}\n\nexport function getToolFallbackTitle(toolCall: MessageToolCall, t: Translate = defaultToolTranslate) {\n const isRunning = !toolCall.done && toolCall.state !== 'completed';\n return t(`chat.tool.fallback.${isRunning ? 'running' : 'completed'}`, {\n name: getMessageToolCallName(toolCall),\n });\n}\n\nfunction commandTarget(descriptor: ToolStatusDescriptor, fallback: string) {\n const target = descriptor.params?.target;\n if (typeof target === 'string' && target.trim()) return target;\n\n for (const key of ['names', 'targets', 'actions']) {\n const values = descriptor.params?.[key];\n if (Array.isArray(values)) {\n const summary = values.filter((value): value is string => typeof value === 'string' && value.trim().length > 0).join(', ');\n if (summary) return summary;\n }\n }\n\n return fallback;\n}\n\nfunction displayFileTarget(\n toolCall: MessageToolCall,\n descriptor: ToolStatusDescriptor,\n target: string,\n): string {\n if (!['create', 'edit', 'read'].includes(descriptor.action)) return target;\n const values = fileTargetValues(toolCall, descriptor.action);\n if (values.length === 0) return target;\n if (values.length <= 3) return values.join(', ');\n return `${values.slice(0, 3).join(', ')} and ${values.length - 3} more`;\n}\n\nfunction fileTargetValues(toolCall: MessageToolCall, action: string): string[] {\n const args = isRecord(toolCall.args) ? toolCall.args : {};\n const values = [\n ...rawFileTargetValues(args.commandActions),\n ...rawFileTargetValues(args.changes),\n ...rawFileTargetValues(toolCall.metadata?.changes),\n ...(typeof args.path === 'string' ? [args.path] : []),\n ...(typeof args.name === 'string' ? [args.name] : []),\n ];\n return [...new Set(values.map((value) => displayFileName(value.trim(), action)).filter(Boolean))];\n}\n\nfunction displayFileName(value: string, action: string): string {\n const segments = value.split(/[\\\\/]/u).filter(Boolean);\n const name = segments.at(-1) ?? value;\n const skillDirectory = action === 'read' && name === 'SKILL.md' ? segments.at(-2) : undefined;\n if (!skillDirectory) return name;\n const title = skillDirectory.split(/[-_\\s]+/u).filter(Boolean).map((word, index) => (\n index > 0 && /^(?:a|an|and|at|by|for|in|of|on|or|the|to)$/iu.test(word)\n ? word.toLowerCase()\n : `${word.charAt(0).toUpperCase()}${word.slice(1)}`\n )).join(' ');\n return `${title} Skill`;\n}\n\nfunction rawFileTargetValues(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter(isRecord).flatMap((entry) => (\n typeof entry.path === 'string' ? [entry.path] : typeof entry.name === 'string' ? [entry.name] : []\n ));\n}\n\nfunction toolFilePaths(toolCall: MessageToolCall): string[] {\n const args = isRecord(toolCall.args) ? toolCall.args : {};\n const cwd = absolutePath(typeof args.cwd === 'string' ? args.cwd : toolCall.metadata?.cwd);\n const candidates = [\n ...filePathsFromArray(args.commandActions),\n ...filePathsFromArray(args.changes),\n ...filePathsFromArray(toolCall.metadata?.changes),\n ...(typeof args.path === 'string' ? [args.path] : []),\n ...(typeof args.name === 'string' ? [args.name] : []),\n ];\n return [...new Set(candidates.map((candidate) => (\n absolutePath(candidate) ?? (cwd ? joinPath(cwd, candidate) : undefined)\n )).filter((candidate): candidate is string => Boolean(candidate)))];\n}\n\nfunction filePathsFromArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter(isRecord).flatMap((entry) => (\n typeof entry.path === 'string' ? [entry.path] : typeof entry.name === 'string' ? [entry.name] : []\n ));\n}\n\nfunction absolutePath(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const path = value.trim();\n return /^(?:[a-z]:[\\\\/]|\\/)/iu.test(path) ? path : undefined;\n}\n\nfunction joinPath(cwd: string, path: string): string {\n return `${cwd.replace(/[\\\\/]$/u, '')}/${path.replace(/^[\\\\/]+/u, '')}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction commandPhase(phase: string) {\n if (phase === 'completed' || phase === 'failed') {\n return phase;\n }\n\n return 'running';\n}\n\nfunction imageGenerationPhase(toolCall: MessageToolCall): 'running' | 'completed' | 'failed' | 'canceled' {\n if (toolCall.state === 'error') return 'failed';\n if (toolCall.state === 'canceled') return 'canceled';\n return !toolCall.done && toolCall.state !== 'completed' ? 'running' : 'completed';\n}\n\nfunction isSemanticToolAction(action: string): action is 'create' | 'delete' | 'edit' | 'explore' | 'list' | 'plan' | 'read' | 'run' | 'search' {\n return action === 'create' || action === 'delete' || action === 'edit' || action === 'explore' || action === 'list' || action === 'plan' || action === 'read' || action === 'run' || action === 'search';\n}\n\nexport function defaultToolTranslate(key: string, params?: Record<string, unknown>) {\n const values = params ?? {};\n const templates: Record<string, string> = {\n 'chat.tool.command.edit.completed': 'Edited {target}',\n 'chat.tool.command.edit.failed': 'Failed editing {target}',\n 'chat.tool.command.edit.running': 'Editing {target}',\n 'chat.tool.command.create.completed': 'Created {target}',\n 'chat.tool.command.create.failed': 'Failed creating {target}',\n 'chat.tool.command.create.running': 'Creating {target}',\n 'chat.tool.command.delete.completed': 'Deleted {target}',\n 'chat.tool.command.delete.failed': 'Failed deleting {target}',\n 'chat.tool.command.delete.running': 'Deleting {target}',\n 'chat.tool.command.explore.completed': 'Explored {target}',\n 'chat.tool.command.explore.failed': 'Failed exploring {target}',\n 'chat.tool.command.explore.running': 'Exploring {target}',\n 'chat.tool.command.list.completed': 'Listed {target}',\n 'chat.tool.command.list.failed': 'Failed listing {target}',\n 'chat.tool.command.list.running': 'Listing {target}',\n 'chat.tool.command.plan.update.completed': 'Updated plan',\n 'chat.tool.command.plan.update.failed': 'Failed updating plan',\n 'chat.tool.command.plan.update.running': 'Updating plan',\n 'chat.tool.command.plan.write.completed': 'Wrote plan',\n 'chat.tool.command.plan.write.failed': 'Failed writing plan',\n 'chat.tool.command.plan.write.running': 'Writing plan',\n 'chat.tool.command.read.completed': 'Read {target}',\n 'chat.tool.command.read.failed': 'Failed reading {target}',\n 'chat.tool.command.read.running': 'Reading {target}',\n 'chat.tool.command.run.completed': 'Ran {target}',\n 'chat.tool.command.run.failed': 'Failed running {target}',\n 'chat.tool.command.run.running': 'Running {target}',\n 'chat.tool.command.search.completed': 'Searched {target}',\n 'chat.tool.command.search.failed': 'Failed searching {target}',\n 'chat.tool.command.search.running': 'Searching {target}',\n 'chat.tool.fallback.completed': 'Ran {name}',\n 'chat.tool.fallback.running': 'Running {name}',\n 'chat.tool.imageGeneration.canceled': 'Stopped generating image',\n 'chat.tool.imageGeneration.completed': 'Generated image',\n 'chat.tool.imageGeneration.failed': 'Failed generating image',\n 'chat.tool.imageGeneration.running': 'Generating image',\n };\n\n return (templates[key] ?? key).replace(/\\{(\\w+)\\}/g, (_, name: string) => String(values[name] ?? ''));\n}\n","import { inject, provide, type InjectionKey } from 'vue';\nimport { defaultToolTranslate } from './tool-status';\n\nexport type CodexChatTranslate = (key: string, params?: Record<string, unknown>) => string;\n\nconst translateKey: InjectionKey<CodexChatTranslate> = Symbol('codex-app-sdk-chat-translate');\n\nconst templates: Record<string, string> = {\n 'chat.actions.cancel': 'Cancel',\n 'chat.actions.copied': 'Copied',\n 'chat.actions.copy': 'Copy',\n 'chat.actions.delete': 'Delete',\n 'chat.actions.deleting': 'Deleting',\n 'chat.actions.edit': 'Edit',\n 'chat.actions.editPrompt': 'Edit prompt',\n 'chat.actions.fork': 'Fork',\n 'chat.actions.label': 'Message actions',\n 'chat.actions.quote': 'Quote',\n 'chat.actions.resubmit': 'Resubmit',\n 'chat.actions.retry': 'Retry',\n 'chat.compaction.completed': 'Context compacted',\n 'chat.compaction.running': 'Compacting context',\n 'chat.contextUsage.ariaLabel': 'Context usage',\n 'chat.contextUsage.title': 'Context window:',\n 'chat.contextUsage.usedAndLeft': '{used}% used ({left}% left)',\n 'chat.contextUsage.tokensUsed': '{used} / {window} tokens used',\n 'chat.commands.title': 'Commands',\n 'chat.code.copied': 'Code copied',\n 'chat.code.copy': 'Copy code',\n 'chat.files.empty': 'No matching files',\n 'chat.files.hint': 'Start typing to search files in this project.',\n 'chat.files.title': 'Files',\n 'chat.message.emptyResponse': 'Empty response',\n 'chat.work.doneHideDetails': 'Done · Hide details',\n 'chat.work.doneViewDetails': 'Done · View details',\n 'chat.work.failedHideDetails': 'Failed · Hide details',\n 'chat.work.failedViewDetails': 'Failed · View details',\n 'chat.work.stoppedHideDetails': 'Stopped · Hide details',\n 'chat.work.stoppedViewDetails': 'Stopped · View details',\n 'chat.work.working': 'Working',\n 'chat.skills.empty': 'No matching skills',\n 'chat.skills.title': 'Skills',\n};\n\nexport function provideCodexChatTranslate(translate: CodexChatTranslate): void {\n provide(translateKey, translate);\n}\n\n/** Reads the nearest chat translation function for the current Vue tree. */\nexport function useCodexChatTranslate(): CodexChatTranslate {\n return inject(translateKey, defaultCodexChatTranslate);\n}\n\nexport function defaultCodexChatTranslate(\n key: string,\n params: Record<string, unknown> = {},\n): string {\n const template = templates[key];\n if (!template) {\n return defaultToolTranslate(key, params);\n }\n\n return template.replace(/\\{(\\w+)\\}/g, (_, name: string) => String(params[name] ?? ''));\n}\n","<template>\n <span\n v-if=\"usagePercent !== null && usageDetails\"\n class=\"codex-chat-theme chat-context-usage\"\n :style=\"{ '--chat-context-usage-percent': `${usagePercent}%` }\"\n :aria-label=\"t('chat.contextUsage.ariaLabel')\"\n tabindex=\"0\"\n >\n <span class=\"chat-context-usage__dot\" />\n <span\n class=\"chat-context-usage__popover\"\n role=\"tooltip\"\n >\n <span class=\"chat-context-usage__title\">{{ t('chat.contextUsage.title') }}</span>\n <strong>{{ t('chat.contextUsage.usedAndLeft', { used: usagePercent, left: usageDetails.leftPercent }) }}</strong>\n <span>{{ t('chat.contextUsage.tokensUsed', { used: usageDetails.usedTokens, window: usageDetails.windowTokens }) }}</span>\n </span>\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { useCodexChatTranslate } from './chat-i18n';\nimport type { CodexContextUsage } from './contracts';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n contextUsage?: CodexContextUsage | null;\n}>();\n// Stryker restore all\nconst t = useCodexChatTranslate();\n\nconst usagePercent = computed(() => {\n const percent = props.contextUsage?.usedPercent;\n if (typeof percent !== 'number') {\n return null;\n }\n\n return Math.round(Math.min(100, Math.max(0, percent)));\n});\n\nconst usageDetails = computed(() => {\n const usage = props.contextUsage!;\n const percent = usagePercent.value!;\n if (typeof usage.modelContextWindow !== 'number') {\n return null;\n }\n\n const contextTokens = Math.min(Math.max(0, usage.lastTotalTokens), usage.modelContextWindow);\n return {\n leftPercent: Math.max(0, 100 - percent),\n usedTokens: compactTokenCount(contextTokens),\n windowTokens: compactTokenCount(usage.modelContextWindow),\n };\n});\n\nfunction compactTokenCount(tokens: number): string {\n if (tokens >= 1_000_000) {\n return `${Math.round(tokens / 100_000) / 10}m`;\n }\n\n if (tokens >= 1_000) {\n return `${Math.round(tokens / 1_000)}k`;\n }\n\n return tokens.toLocaleString();\n}\n</script>\n\n<style scoped>\n.chat-context-usage {\n --chat-context-usage-percent: 0%;\n position: relative;\n display: grid;\n place-items: center;\n width: 18px;\n height: 18px;\n outline: none;\n}\n\n.chat-context-usage__dot {\n position: relative;\n width: 12px;\n height: 12px;\n border-radius: var(--radius-full);\n border: 3px solid var(--color-surface-high);\n}\n\n.chat-context-usage__dot::after {\n position: absolute;\n inset: -3px;\n content: '';\n border-radius: var(--radius-full);\n background: conic-gradient(\n var(--color-primary) 0 var(--chat-context-usage-percent),\n transparent var(--chat-context-usage-percent) 100%\n );\n mask: radial-gradient(circle at center, transparent 0 45%, black 47%);\n}\n\n.chat-context-usage__popover {\n position: absolute;\n z-index: 30;\n right: 50%;\n bottom: calc(100% + var(--space-2));\n display: grid;\n min-width: 184px;\n justify-items: center;\n gap: var(--space-2);\n padding: var(--space-6) var(--space-8);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n color: var(--color-text);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-menu);\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n opacity: 0;\n pointer-events: none;\n text-align: center;\n transform: translateX(50%) translateY(2px);\n transition: opacity 120ms ease, transform 120ms ease;\n white-space: nowrap;\n}\n\n.chat-context-usage__title {\n color: var(--color-text-muted);\n}\n\n.chat-context-usage__popover strong {\n font-weight: var(--font-weight-medium);\n}\n\n.chat-context-usage:hover .chat-context-usage__popover,\n.chat-context-usage:focus-visible .chat-context-usage__popover {\n opacity: 1;\n transform: translateX(50%) translateY(0);\n}\n</style>\n","<template>\n <span\n v-if=\"usagePercent !== null && usageDetails\"\n class=\"codex-chat-theme chat-context-usage\"\n :style=\"{ '--chat-context-usage-percent': `${usagePercent}%` }\"\n :aria-label=\"t('chat.contextUsage.ariaLabel')\"\n tabindex=\"0\"\n >\n <span class=\"chat-context-usage__dot\" />\n <span\n class=\"chat-context-usage__popover\"\n role=\"tooltip\"\n >\n <span class=\"chat-context-usage__title\">{{ t('chat.contextUsage.title') }}</span>\n <strong>{{ t('chat.contextUsage.usedAndLeft', { used: usagePercent, left: usageDetails.leftPercent }) }}</strong>\n <span>{{ t('chat.contextUsage.tokensUsed', { used: usageDetails.usedTokens, window: usageDetails.windowTokens }) }}</span>\n </span>\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { useCodexChatTranslate } from './chat-i18n';\nimport type { CodexContextUsage } from './contracts';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n contextUsage?: CodexContextUsage | null;\n}>();\n// Stryker restore all\nconst t = useCodexChatTranslate();\n\nconst usagePercent = computed(() => {\n const percent = props.contextUsage?.usedPercent;\n if (typeof percent !== 'number') {\n return null;\n }\n\n return Math.round(Math.min(100, Math.max(0, percent)));\n});\n\nconst usageDetails = computed(() => {\n const usage = props.contextUsage!;\n const percent = usagePercent.value!;\n if (typeof usage.modelContextWindow !== 'number') {\n return null;\n }\n\n const contextTokens = Math.min(Math.max(0, usage.lastTotalTokens), usage.modelContextWindow);\n return {\n leftPercent: Math.max(0, 100 - percent),\n usedTokens: compactTokenCount(contextTokens),\n windowTokens: compactTokenCount(usage.modelContextWindow),\n };\n});\n\nfunction compactTokenCount(tokens: number): string {\n if (tokens >= 1_000_000) {\n return `${Math.round(tokens / 100_000) / 10}m`;\n }\n\n if (tokens >= 1_000) {\n return `${Math.round(tokens / 1_000)}k`;\n }\n\n return tokens.toLocaleString();\n}\n</script>\n\n<style scoped>\n.chat-context-usage {\n --chat-context-usage-percent: 0%;\n position: relative;\n display: grid;\n place-items: center;\n width: 18px;\n height: 18px;\n outline: none;\n}\n\n.chat-context-usage__dot {\n position: relative;\n width: 12px;\n height: 12px;\n border-radius: var(--radius-full);\n border: 3px solid var(--color-surface-high);\n}\n\n.chat-context-usage__dot::after {\n position: absolute;\n inset: -3px;\n content: '';\n border-radius: var(--radius-full);\n background: conic-gradient(\n var(--color-primary) 0 var(--chat-context-usage-percent),\n transparent var(--chat-context-usage-percent) 100%\n );\n mask: radial-gradient(circle at center, transparent 0 45%, black 47%);\n}\n\n.chat-context-usage__popover {\n position: absolute;\n z-index: 30;\n right: 50%;\n bottom: calc(100% + var(--space-2));\n display: grid;\n min-width: 184px;\n justify-items: center;\n gap: var(--space-2);\n padding: var(--space-6) var(--space-8);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n color: var(--color-text);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-menu);\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n opacity: 0;\n pointer-events: none;\n text-align: center;\n transform: translateX(50%) translateY(2px);\n transition: opacity 120ms ease, transform 120ms ease;\n white-space: nowrap;\n}\n\n.chat-context-usage__title {\n color: var(--color-text-muted);\n}\n\n.chat-context-usage__popover strong {\n font-weight: var(--font-weight-medium);\n}\n\n.chat-context-usage:hover .chat-context-usage__popover,\n.chat-context-usage:focus-visible .chat-context-usage__popover {\n opacity: 1;\n transform: translateX(50%) translateY(0);\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-model-selector\">\n <button\n v-if=\"models.length === 0\"\n class=\"chat-model-selector__button\"\n type=\"button\"\n aria-label=\"Model and reasoning\"\n disabled\n >\n <span class=\"chat-model-selector__label\">{{ selectorLabel }}</span>\n <ChevronDown class=\"chat-model-selector__chevron\" aria-hidden=\"true\" />\n </button>\n <CodexComposerMenu\n v-else\n aria-label=\"Model and reasoning\"\n button-label=\"Model and reasoning\"\n :disabled=\"controlDisabled\"\n :items=\"selectorItems\"\n menu-class=\"chat-model-selector__menu\"\n @select=\"onSelect\"\n >\n <template #trigger=\"{ open, toggle }\">\n <button\n class=\"chat-model-selector__button\"\n type=\"button\"\n aria-label=\"Model and reasoning\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"open\"\n :disabled=\"controlDisabled\"\n @click=\"toggle\"\n >\n <BoltIcon\n v-if=\"selectedModel && fastServiceTier && props.serviceTier === fastServiceTier.id\"\n class=\"chat-model-selector__leading-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"chat-model-selector__label\">{{ selectorLabel }}</span>\n <ChevronDown class=\"chat-model-selector__chevron\" aria-hidden=\"true\" />\n </button>\n </template>\n </CodexComposerMenu>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed } from 'vue';\nimport type { CodexModelOption, ReasoningEffort } from './contracts';\nimport { BoltIcon, ChevronDown } from '../icons/app-icons';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport CodexComposerMenu from '../components/CodexComposerMenu.vue';\n\ntype SelectorCommand<Payload> =\n | { source: 'selector'; kind: 'model' | 'reasoning' | 'serviceTier'; value: string }\n | { source: 'host'; item: CodexComposerMenuSelectableItem<Payload> };\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n disabled?: boolean;\n modelCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n modelId?: string | null;\n menuItems?: readonly CodexComposerMenuItem<Payload>[];\n models?: readonly CodexModelOption[];\n reasoningEffort?: ReasoningEffort | null;\n serviceTier?: string | null;\n showServiceTier?: boolean;\n showReasoning?: boolean;\n}>(), {\n disabled: false,\n modelCatalogStatus: 'notLoaded',\n modelId: null,\n models: () => [],\n menuItems: () => [],\n reasoningEffort: null,\n serviceTier: null,\n showServiceTier: true,\n showReasoning: true,\n});\n\nconst emit = defineEmits<{\n 'update:modelId': [modelId: string];\n menuSelect: [item: CodexComposerMenuSelectableItem<Payload>];\n 'update:reasoningEffort': [reasoningEffort: ReasoningEffort];\n 'update:serviceTier': [serviceTier: string | null];\n}>();\n// Stryker restore all\n\nconst selectedModel = computed(() => (\n props.models.find((model) => model.id === props.modelId) ??\n props.models.find((model) => model.isDefault) ??\n props.models[0] ??\n null\n));\n\nconst reasoningEfforts = computed(() => selectedModel.value?.supportedReasoningEfforts ?? []);\n\nconst showReasoning = computed(() => props.showReasoning && reasoningEfforts.value.length > 0);\n\nconst effectiveReasoningEffort = computed(() => (\n props.reasoningEffort ??\n selectedModel.value?.defaultReasoningEffort ??\n reasoningEfforts.value[0]?.reasoningEffort ??\n null\n));\n\nconst serviceTiers = computed(() => selectedModel.value?.serviceTiers ?? []);\nconst showServiceTier = computed(() => props.showServiceTier && serviceTiers.value.length > 0);\nconst fastServiceTier = computed(() => serviceTiers.value.find((tier) => (\n /^(fast|priority)$/i.test(tier.id) || /fast|priority/i.test(tier.name)\n)) ?? null);\n\nconst controlDisabled = computed(() => props.disabled);\n\nconst selectorItems = computed<CodexComposerMenuItem<SelectorCommand<Payload>>[]>(() => {\n const items: CodexComposerMenuItem<SelectorCommand<Payload>>[] = [];\n if (props.menuItems.length > 0) {\n items.push(...wrapHostMenuItems(props.menuItems));\n items.push({ id: 'host-model-menu-separator', type: 'separator' });\n }\n items.push({\n id: 'model',\n label: 'Model',\n type: 'submenu',\n value: selectedModel.value ? compactModelLabel(selectedModel.value.displayName) : undefined,\n submenuAlignment: 'bottom',\n submenuWidth: 'wide',\n items: props.models.map((model) => ({\n checked: model.id === selectedModel.value?.id,\n closeOnSelect: false,\n id: `model:${model.id}`,\n label: model.displayName,\n payload: { source: 'selector' as const, kind: 'model' as const, value: model.id },\n type: 'radio' as const,\n })),\n });\n\n if (showReasoning.value) {\n items.push({\n id: 'reasoning',\n label: 'Reasoning',\n type: 'submenu',\n value: effectiveReasoningEffort.value ? effortLabel(effectiveReasoningEffort.value) : undefined,\n submenuAlignment: 'bottom',\n submenuWidth: 'wide',\n items: reasoningEfforts.value.map((effort) => ({\n checked: effort.reasoningEffort === effectiveReasoningEffort.value,\n closeOnSelect: true,\n id: `reasoning:${effort.reasoningEffort}`,\n label: effortLabel(effort.reasoningEffort),\n payload: { source: 'selector' as const, kind: 'reasoning' as const, value: effort.reasoningEffort },\n type: 'radio' as const,\n })),\n });\n }\n\n if (showServiceTier.value && fastServiceTier.value) {\n items.push({ id: 'model-service-tier-separator', type: 'separator' });\n items.push({ id: 'service-tier-heading', type: 'heading', label: 'Speed' });\n items.push({\n accessory: 'switch',\n checked: props.serviceTier === fastServiceTier.value.id,\n closeOnSelect: false,\n description: fastServiceTier.value.description,\n id: `service-tier:${fastServiceTier.value.id}`,\n label: 'Fast mode',\n payload: { source: 'selector' as const, kind: 'serviceTier' as const, value: fastServiceTier.value.id },\n type: 'checkbox' as const,\n });\n }\n\n return items;\n});\n\nconst selectorLabel = computed(() => {\n if (!selectedModel.value) {\n return modelFallbackLabel.value;\n }\n\n if (!showReasoning.value) {\n return compactModelLabel(selectedModel.value.displayName);\n }\n\n const effort = effectiveReasoningEffort.value ? effortLabel(effectiveReasoningEffort.value) : effortFallbackLabel.value;\n return `${compactModelLabel(selectedModel.value.displayName)} ${effort}`;\n});\n\nconst modelFallbackLabel = computed(() => {\n if (props.modelCatalogStatus === 'loading') {\n return 'Loading models';\n }\n\n if (props.modelCatalogStatus === 'error') {\n return 'Models unavailable';\n }\n\n return 'Model';\n});\n\nconst effortFallbackLabel = computed(() => {\n if (props.modelCatalogStatus === 'loading') {\n return 'Loading';\n }\n\n return 'Reasoning';\n});\n\nfunction effortLabel(effort: ReasoningEffort): string {\n const labels: Record<string, string> = {\n xhigh: 'Extra High',\n };\n const normalized = effort.trim().toLowerCase();\n if (labels[normalized]) {\n return labels[normalized];\n }\n\n return effort\n .split(/[-_\\s]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\nfunction compactModelLabel(modelLabel: string): string {\n return modelLabel.replace(/^gpt[-\\s]*/i, '').trim() || modelLabel;\n}\n\nfunction onSelect(item: CodexComposerMenuSelectableItem<SelectorCommand<Payload>>): void {\n const command = item.payload;\n if (!command) {\n return;\n }\n\n if (command.source === 'host') {\n emit('menuSelect', command.item);\n } else if (command.kind === 'model') {\n emit('update:modelId', command.value);\n } else if (command.kind === 'reasoning' && showReasoning.value) {\n emit('update:reasoningEffort', command.value);\n } else if (command.kind === 'serviceTier' && fastServiceTier.value) {\n emit('update:serviceTier', props.serviceTier === fastServiceTier.value.id ? null : command.value);\n }\n}\n\nfunction wrapHostMenuItems(\n items: readonly CodexComposerMenuItem<Payload>[],\n parentPath: readonly number[] = [],\n): CodexComposerMenuItem<SelectorCommand<Payload>>[] {\n return items.map((item, index) => {\n const path = [...parentPath, index];\n const id = `host:${path.join('.')}:${item.id}`;\n if (item.type === 'separator') return { ...item, id };\n if (item.type === 'heading') {\n return {\n ...item,\n id,\n actions: item.actions?.map((action, actionIndex) => ({\n ...action,\n id: `${id}:action:${actionIndex}:${action.id}`,\n payload: { source: 'host', item: action },\n })),\n };\n }\n if (item.type === 'submenu') {\n const { items: childItems, payload: _payload, ...submenu } = item;\n return { ...submenu, id, items: wrapHostMenuItems(childItems, path) };\n }\n return {\n ...item,\n id,\n payload: { source: 'host', item },\n };\n });\n}\n</script>\n\n<style scoped>\n.chat-model-selector {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n min-width: 0;\n}\n\n.chat-model-selector__button {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n max-width: 184px;\n min-height: var(--chat-composer-button-size, 36px);\n padding: 0 var(--space-4);\n border: 0;\n border-radius: var(--radius-full);\n color: var(--color-text-muted);\n background: transparent;\n font-family: var(--font-family-base);\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n cursor: pointer;\n}\n\n.chat-model-selector__button:hover:not(:disabled),\n.chat-model-selector__button[aria-expanded=\"true\"] {\n color: var(--color-text);\n background: var(--color-surface-base);\n}\n\n.chat-model-selector__button:disabled {\n cursor: default;\n}\n\n.chat-model-selector__label,\n.chat-model-selector__option-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-model-selector__leading-icon,\n.chat-model-selector__chevron {\n flex: 0 0 auto;\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n:deep(.chat-model-selector__menu) {\n right: 0;\n left: auto;\n min-width: 220px;\n max-width: 260px;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-menu);\n color: var(--color-text);\n}\n\n:deep(.chat-model-selector__menu .codex-composer-menu-list__icon--empty) {\n display: none;\n}\n\n:deep(.chat-model-selector__menu [role=\"menuitemradio\"][aria-checked=\"true\"]) {\n background: var(--color-surface-low);\n}\n\n:deep(.chat-model-selector__menu [role=\"menuitemradio\"] .codex-composer-menu-list__radio-check),\n:deep(.chat-model-selector__menu [role=\"menuitemradio\"] .codex-composer-menu-list__selection) {\n display: none;\n}\n\n:deep(.chat-model-selector__menu .codex-composer-menu-list__submenu-list .codex-composer-menu-list__item) {\n font-size: var(--codex-composer-model-submenu-font-size, var(--font-size-13));\n}\n\n:deep(.chat-model-selector__menu .codex-composer-menu-list__heading) {\n padding-left: var(--space-4);\n}\n\n@media (max-width: 720px) {\n .chat-model-selector {\n display: none;\n }\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-model-selector\">\n <button\n v-if=\"models.length === 0\"\n class=\"chat-model-selector__button\"\n type=\"button\"\n aria-label=\"Model and reasoning\"\n disabled\n >\n <span class=\"chat-model-selector__label\">{{ selectorLabel }}</span>\n <ChevronDown class=\"chat-model-selector__chevron\" aria-hidden=\"true\" />\n </button>\n <CodexComposerMenu\n v-else\n aria-label=\"Model and reasoning\"\n button-label=\"Model and reasoning\"\n :disabled=\"controlDisabled\"\n :items=\"selectorItems\"\n menu-class=\"chat-model-selector__menu\"\n @select=\"onSelect\"\n >\n <template #trigger=\"{ open, toggle }\">\n <button\n class=\"chat-model-selector__button\"\n type=\"button\"\n aria-label=\"Model and reasoning\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"open\"\n :disabled=\"controlDisabled\"\n @click=\"toggle\"\n >\n <BoltIcon\n v-if=\"selectedModel && fastServiceTier && props.serviceTier === fastServiceTier.id\"\n class=\"chat-model-selector__leading-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"chat-model-selector__label\">{{ selectorLabel }}</span>\n <ChevronDown class=\"chat-model-selector__chevron\" aria-hidden=\"true\" />\n </button>\n </template>\n </CodexComposerMenu>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed } from 'vue';\nimport type { CodexModelOption, ReasoningEffort } from './contracts';\nimport { BoltIcon, ChevronDown } from '../icons/app-icons';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport CodexComposerMenu from '../components/CodexComposerMenu.vue';\n\ntype SelectorCommand<Payload> =\n | { source: 'selector'; kind: 'model' | 'reasoning' | 'serviceTier'; value: string }\n | { source: 'host'; item: CodexComposerMenuSelectableItem<Payload> };\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n disabled?: boolean;\n modelCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n modelId?: string | null;\n menuItems?: readonly CodexComposerMenuItem<Payload>[];\n models?: readonly CodexModelOption[];\n reasoningEffort?: ReasoningEffort | null;\n serviceTier?: string | null;\n showServiceTier?: boolean;\n showReasoning?: boolean;\n}>(), {\n disabled: false,\n modelCatalogStatus: 'notLoaded',\n modelId: null,\n models: () => [],\n menuItems: () => [],\n reasoningEffort: null,\n serviceTier: null,\n showServiceTier: true,\n showReasoning: true,\n});\n\nconst emit = defineEmits<{\n 'update:modelId': [modelId: string];\n menuSelect: [item: CodexComposerMenuSelectableItem<Payload>];\n 'update:reasoningEffort': [reasoningEffort: ReasoningEffort];\n 'update:serviceTier': [serviceTier: string | null];\n}>();\n// Stryker restore all\n\nconst selectedModel = computed(() => (\n props.models.find((model) => model.id === props.modelId) ??\n props.models.find((model) => model.isDefault) ??\n props.models[0] ??\n null\n));\n\nconst reasoningEfforts = computed(() => selectedModel.value?.supportedReasoningEfforts ?? []);\n\nconst showReasoning = computed(() => props.showReasoning && reasoningEfforts.value.length > 0);\n\nconst effectiveReasoningEffort = computed(() => (\n props.reasoningEffort ??\n selectedModel.value?.defaultReasoningEffort ??\n reasoningEfforts.value[0]?.reasoningEffort ??\n null\n));\n\nconst serviceTiers = computed(() => selectedModel.value?.serviceTiers ?? []);\nconst showServiceTier = computed(() => props.showServiceTier && serviceTiers.value.length > 0);\nconst fastServiceTier = computed(() => serviceTiers.value.find((tier) => (\n /^(fast|priority)$/i.test(tier.id) || /fast|priority/i.test(tier.name)\n)) ?? null);\n\nconst controlDisabled = computed(() => props.disabled);\n\nconst selectorItems = computed<CodexComposerMenuItem<SelectorCommand<Payload>>[]>(() => {\n const items: CodexComposerMenuItem<SelectorCommand<Payload>>[] = [];\n if (props.menuItems.length > 0) {\n items.push(...wrapHostMenuItems(props.menuItems));\n items.push({ id: 'host-model-menu-separator', type: 'separator' });\n }\n items.push({\n id: 'model',\n label: 'Model',\n type: 'submenu',\n value: selectedModel.value ? compactModelLabel(selectedModel.value.displayName) : undefined,\n submenuAlignment: 'bottom',\n submenuWidth: 'wide',\n items: props.models.map((model) => ({\n checked: model.id === selectedModel.value?.id,\n closeOnSelect: false,\n id: `model:${model.id}`,\n label: model.displayName,\n payload: { source: 'selector' as const, kind: 'model' as const, value: model.id },\n type: 'radio' as const,\n })),\n });\n\n if (showReasoning.value) {\n items.push({\n id: 'reasoning',\n label: 'Reasoning',\n type: 'submenu',\n value: effectiveReasoningEffort.value ? effortLabel(effectiveReasoningEffort.value) : undefined,\n submenuAlignment: 'bottom',\n submenuWidth: 'wide',\n items: reasoningEfforts.value.map((effort) => ({\n checked: effort.reasoningEffort === effectiveReasoningEffort.value,\n closeOnSelect: true,\n id: `reasoning:${effort.reasoningEffort}`,\n label: effortLabel(effort.reasoningEffort),\n payload: { source: 'selector' as const, kind: 'reasoning' as const, value: effort.reasoningEffort },\n type: 'radio' as const,\n })),\n });\n }\n\n if (showServiceTier.value && fastServiceTier.value) {\n items.push({ id: 'model-service-tier-separator', type: 'separator' });\n items.push({ id: 'service-tier-heading', type: 'heading', label: 'Speed' });\n items.push({\n accessory: 'switch',\n checked: props.serviceTier === fastServiceTier.value.id,\n closeOnSelect: false,\n description: fastServiceTier.value.description,\n id: `service-tier:${fastServiceTier.value.id}`,\n label: 'Fast mode',\n payload: { source: 'selector' as const, kind: 'serviceTier' as const, value: fastServiceTier.value.id },\n type: 'checkbox' as const,\n });\n }\n\n return items;\n});\n\nconst selectorLabel = computed(() => {\n if (!selectedModel.value) {\n return modelFallbackLabel.value;\n }\n\n if (!showReasoning.value) {\n return compactModelLabel(selectedModel.value.displayName);\n }\n\n const effort = effectiveReasoningEffort.value ? effortLabel(effectiveReasoningEffort.value) : effortFallbackLabel.value;\n return `${compactModelLabel(selectedModel.value.displayName)} ${effort}`;\n});\n\nconst modelFallbackLabel = computed(() => {\n if (props.modelCatalogStatus === 'loading') {\n return 'Loading models';\n }\n\n if (props.modelCatalogStatus === 'error') {\n return 'Models unavailable';\n }\n\n return 'Model';\n});\n\nconst effortFallbackLabel = computed(() => {\n if (props.modelCatalogStatus === 'loading') {\n return 'Loading';\n }\n\n return 'Reasoning';\n});\n\nfunction effortLabel(effort: ReasoningEffort): string {\n const labels: Record<string, string> = {\n xhigh: 'Extra High',\n };\n const normalized = effort.trim().toLowerCase();\n if (labels[normalized]) {\n return labels[normalized];\n }\n\n return effort\n .split(/[-_\\s]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\nfunction compactModelLabel(modelLabel: string): string {\n return modelLabel.replace(/^gpt[-\\s]*/i, '').trim() || modelLabel;\n}\n\nfunction onSelect(item: CodexComposerMenuSelectableItem<SelectorCommand<Payload>>): void {\n const command = item.payload;\n if (!command) {\n return;\n }\n\n if (command.source === 'host') {\n emit('menuSelect', command.item);\n } else if (command.kind === 'model') {\n emit('update:modelId', command.value);\n } else if (command.kind === 'reasoning' && showReasoning.value) {\n emit('update:reasoningEffort', command.value);\n } else if (command.kind === 'serviceTier' && fastServiceTier.value) {\n emit('update:serviceTier', props.serviceTier === fastServiceTier.value.id ? null : command.value);\n }\n}\n\nfunction wrapHostMenuItems(\n items: readonly CodexComposerMenuItem<Payload>[],\n parentPath: readonly number[] = [],\n): CodexComposerMenuItem<SelectorCommand<Payload>>[] {\n return items.map((item, index) => {\n const path = [...parentPath, index];\n const id = `host:${path.join('.')}:${item.id}`;\n if (item.type === 'separator') return { ...item, id };\n if (item.type === 'heading') {\n return {\n ...item,\n id,\n actions: item.actions?.map((action, actionIndex) => ({\n ...action,\n id: `${id}:action:${actionIndex}:${action.id}`,\n payload: { source: 'host', item: action },\n })),\n };\n }\n if (item.type === 'submenu') {\n const { items: childItems, payload: _payload, ...submenu } = item;\n return { ...submenu, id, items: wrapHostMenuItems(childItems, path) };\n }\n return {\n ...item,\n id,\n payload: { source: 'host', item },\n };\n });\n}\n</script>\n\n<style scoped>\n.chat-model-selector {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n min-width: 0;\n}\n\n.chat-model-selector__button {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n max-width: 184px;\n min-height: var(--chat-composer-button-size, 36px);\n padding: 0 var(--space-4);\n border: 0;\n border-radius: var(--radius-full);\n color: var(--color-text-muted);\n background: transparent;\n font-family: var(--font-family-base);\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n cursor: pointer;\n}\n\n.chat-model-selector__button:hover:not(:disabled),\n.chat-model-selector__button[aria-expanded=\"true\"] {\n color: var(--color-text);\n background: var(--color-surface-base);\n}\n\n.chat-model-selector__button:disabled {\n cursor: default;\n}\n\n.chat-model-selector__label,\n.chat-model-selector__option-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-model-selector__leading-icon,\n.chat-model-selector__chevron {\n flex: 0 0 auto;\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n:deep(.chat-model-selector__menu) {\n right: 0;\n left: auto;\n min-width: 220px;\n max-width: 260px;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-menu);\n color: var(--color-text);\n}\n\n:deep(.chat-model-selector__menu .codex-composer-menu-list__icon--empty) {\n display: none;\n}\n\n:deep(.chat-model-selector__menu [role=\"menuitemradio\"][aria-checked=\"true\"]) {\n background: var(--color-surface-low);\n}\n\n:deep(.chat-model-selector__menu [role=\"menuitemradio\"] .codex-composer-menu-list__radio-check),\n:deep(.chat-model-selector__menu [role=\"menuitemradio\"] .codex-composer-menu-list__selection) {\n display: none;\n}\n\n:deep(.chat-model-selector__menu .codex-composer-menu-list__submenu-list .codex-composer-menu-list__item) {\n font-size: var(--codex-composer-model-submenu-font-size, var(--font-size-13));\n}\n\n:deep(.chat-model-selector__menu .codex-composer-menu-list__heading) {\n padding-left: var(--space-4);\n}\n\n@media (max-width: 720px) {\n .chat-model-selector {\n display: none;\n }\n}\n</style>\n","export type ComposerSearchField<T> = {\n values: (item: T) => Array<string | null | undefined>;\n};\n\ntype RankedComposerSearchItem<T> = {\n fieldIndex: number;\n item: T;\n score: number;\n};\n\nexport function filterComposerSearchItems<T>(\n items: T[],\n query: string,\n fields: ComposerSearchField<T>[],\n maxResults = -1,\n): T[] {\n const value = query.trim().toLowerCase();\n if (!value) {\n return limitItems(items, maxResults);\n }\n\n const matches = items\n .map((item): RankedComposerSearchItem<T> | null => {\n const match = bestFieldMatch(item, value, fields);\n return match ? { item, ...match } : null;\n })\n .filter((entry): entry is RankedComposerSearchItem<T> => Boolean(entry))\n .sort((left, right) => (\n left.fieldIndex - right.fieldIndex ||\n right.score - left.score\n ));\n\n return limitItems(matches.map((entry) => entry.item), maxResults);\n}\n\nfunction bestFieldMatch<T>(\n item: T,\n value: string,\n fields: ComposerSearchField<T>[],\n): Pick<RankedComposerSearchItem<T>, 'fieldIndex' | 'score'> | null {\n let bestMatch: Pick<RankedComposerSearchItem<T>, 'fieldIndex' | 'score'> | null = null;\n\n fields.forEach((field, fieldIndex) => {\n const score = Math.max(0, ...field.values(item).map((fieldValue) => searchScore(value, fieldValue ?? '')));\n if (score > 0 && bestMatch === null) {\n bestMatch = { fieldIndex, score };\n }\n });\n\n return bestMatch;\n}\n\nfunction searchScore(pattern: string, target: string): number {\n const normalizedTarget = target.toLowerCase();\n if (!normalizedTarget.includes(pattern)) {\n return 0;\n }\n\n if (normalizedTarget === pattern) {\n return 30_000;\n }\n\n const words = normalizedTarget.split(/[^\\p{L}\\p{N}_]+/u);\n const score = words.includes(pattern) ? 20_000\n : words.some((word) => word.startsWith(pattern)) ? 15_000 : 10_000;\n return score - normalizedTarget.indexOf(pattern);\n}\n\nfunction limitItems<T>(items: T[], maxResults: number): T[] {\n return maxResults >= 0 ? items.slice(0, maxResults) : items;\n}\n","import type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport { filterComposerSearchItems } from './composer-search';\n\nexport function filterComposerPlugins(\n plugins: CodexSurfacePlugin[],\n query: string,\n maxResults = -1,\n): CodexSurfacePlugin[] {\n return filterComposerSearchItems(plugins, query, [\n { values: (plugin) => [plugin.id] },\n { values: (plugin) => [plugin.name, plugin.displayName] },\n { values: (plugin) => [plugin.shortDescription, plugin.longDescription] },\n ], maxResults);\n}\n\nexport function pluginDisplayName(plugin: CodexSurfacePlugin): string {\n return plugin.displayName || plugin.name;\n}\n\nexport function pluginDescription(plugin: CodexSurfacePlugin): string {\n return plugin.shortDescription || plugin.longDescription || '';\n}\n\nexport function pluginInsertText(plugin: CodexSurfacePlugin): string {\n return plugin.name || plugin.id;\n}\n\nexport function pluginMatchesMention(plugin: CodexSurfacePlugin, mention: string): boolean {\n const normalized = mention.trim().toLowerCase();\n return [plugin.id, plugin.name, plugin.displayName]\n .some((candidate) => candidate.trim().toLowerCase() === normalized);\n}\n","<template>\n <div class=\"codex-chat-theme chat-composer-at-menu\" role=\"listbox\" aria-label=\"Mentions\">\n <template v-for=\"group in leadingMentionGroups\" :key=\"`custom:${group.id}`\">\n <div class=\"chat-composer-at-menu__section\">{{ group.label }}</div>\n <button\n v-for=\"item in group.items\"\n :key=\"`custom:${group.id}:${item.id}`\"\n class=\"chat-composer-at-menu__item\"\n :class=\"{ 'chat-composer-at-menu__item--active': mentionIndex(group.id, item.id) === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select-mention', item, group)\"\n >\n <slot name=\"mention\" :group=\"group\" :item=\"item\" :active=\"mentionIndex(group.id, item.id) === activeIndex\">\n <SparklesIcon class=\"chat-composer-at-menu__icon\" aria-hidden=\"true\" />\n <span><strong>{{ item.label }}</strong><small v-if=\"item.description\">{{ item.description }}</small></span>\n </slot>\n </button>\n </template>\n <template v-if=\"visiblePlugins.length\">\n <div class=\"chat-composer-at-menu__section\">Plugins</div>\n <button\n v-for=\"(plugin, index) in visiblePlugins\"\n :key=\"`plugin:${plugin.id}`\"\n class=\"chat-composer-at-menu__item\"\n :class=\"{ 'chat-composer-at-menu__item--active': leadingMentionCount + index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select-plugin', plugin)\"\n >\n <PlugIcon class=\"chat-composer-at-menu__icon\" aria-hidden=\"true\" />\n <span><strong>{{ pluginDisplayName(plugin) }}</strong><small>{{ pluginDescription(plugin) }}</small></span>\n </button>\n </template>\n <template v-if=\"visibleFiles.length\">\n <div class=\"chat-composer-at-menu__section\">Files</div>\n <button\n v-for=\"(file, index) in visibleFiles\"\n :key=\"`file:${file.path}`\"\n class=\"chat-composer-at-menu__item\"\n :class=\"{ 'chat-composer-at-menu__item--active': leadingMentionCount + visiblePlugins.length + index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select-file', file)\"\n >\n <FileTextIcon class=\"chat-composer-at-menu__icon\" aria-hidden=\"true\" />\n <span><strong>{{ file.name }}</strong><small>{{ file.path }}</small></span>\n </button>\n </template>\n <template v-for=\"group in trailingMentionGroups\" :key=\"`custom:${group.id}`\">\n <div class=\"chat-composer-at-menu__section\">{{ group.label }}</div>\n <button\n v-for=\"item in group.items\"\n :key=\"`custom:${group.id}:${item.id}`\"\n class=\"chat-composer-at-menu__item\"\n :class=\"{ 'chat-composer-at-menu__item--active': mentionIndex(group.id, item.id) === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select-mention', item, group)\"\n >\n <slot name=\"mention\" :group=\"group\" :item=\"item\" :active=\"mentionIndex(group.id, item.id) === activeIndex\">\n <SparklesIcon class=\"chat-composer-at-menu__icon\" aria-hidden=\"true\" />\n <span><strong>{{ item.label }}</strong><small v-if=\"item.description\">{{ item.description }}</small></span>\n </slot>\n </button>\n </template>\n <div v-if=\"showFileHint && !visibleFiles.length\" class=\"chat-composer-at-menu__hint\">Type to search files</div>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed } from 'vue';\nimport type { CodexFileSearchItem } from './contracts';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport { FileTextIcon, PlugIcon, SparklesIcon } from '../icons/app-icons';\nimport { pluginDescription, pluginDisplayName } from './composer-plugins';\nimport type {\n CodexComposerMentionGroup,\n CodexComposerMentionItem,\n CodexComposerVisibleMentionGroup,\n} from './composer-mentions-custom';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n mentionGroups?: readonly CodexComposerVisibleMentionGroup<Payload>[];\n showFileHint: boolean;\n visibleFiles: CodexFileSearchItem[];\n visiblePlugins: CodexSurfacePlugin[];\n}>();\n\ndefineEmits<{\n 'select-file': [file: CodexFileSearchItem];\n 'select-plugin': [plugin: CodexSurfacePlugin];\n 'select-mention': [item: CodexComposerMentionItem<Payload>, group: CodexComposerMentionGroup<Payload>];\n}>();\n\ndefineSlots<{\n mention(props: {\n active: boolean;\n group: CodexComposerVisibleMentionGroup<Payload>;\n item: CodexComposerMentionItem<Payload>;\n }): unknown;\n}>();\n// Stryker restore all\n\nconst leadingMentionGroups = computed(() => props.mentionGroups?.filter((group) => group.placement !== 'after') ?? []);\nconst trailingMentionGroups = computed(() => props.mentionGroups?.filter((group) => group.placement === 'after') ?? []);\nconst leadingMentionCount = computed(() => leadingMentionGroups.value.reduce((total, group) => total + group.items.length, 0));\n\nfunction mentionIndex(groupId: string, itemId: string): number {\n let index = 0;\n for (const group of leadingMentionGroups.value) {\n for (const item of group.items) {\n if (group.id === groupId && item.id === itemId) return index;\n index += 1;\n }\n }\n index += props.visiblePlugins.length + props.visibleFiles.length;\n for (const group of trailingMentionGroups.value) {\n for (const item of group.items) {\n if (group.id === groupId && item.id === itemId) return index;\n index += 1;\n }\n }\n return -1;\n}\n</script>\n\n<style scoped>\n.chat-composer-at-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n.chat-composer-at-menu__section,\n.chat-composer-at-menu__hint { padding: var(--space-2) var(--space-4); color: var(--color-text-muted); font-size: var(--font-size-12); }\n.chat-composer-at-menu__section { font-size: var(--codex-composer-menu-heading-font-size, 13px); font-weight: var(--font-weight-medium); line-height: 18px; }\n.chat-composer-at-menu__item { display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--chat-menu-control-min-height); margin-block: 0.125px; padding: var(--space-2) var(--space-4); border: 0; border-radius: var(--radius-lg); background: transparent; color: var(--color-text); text-align: left; }\n.chat-composer-at-menu__item--active { background: var(--color-surface-low); }\n.chat-composer-at-menu__icon { width: var(--icon-md); height: var(--icon-md); flex: 0 0 var(--icon-md); opacity: 0.5; stroke-width: 2px; }\n.chat-composer-at-menu__item span { display: flex; min-width: 0; flex-direction: column; }\n.chat-composer-at-menu__item strong { font-weight: var(--font-weight-medium); }\n.chat-composer-at-menu__item small { overflow: hidden; color: var(--color-text-muted); text-overflow: ellipsis; white-space: nowrap; }\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-composer-at-menu\" role=\"listbox\" aria-label=\"Mentions\">\n <template v-for=\"group in leadingMentionGroups\" :key=\"`custom:${group.id}`\">\n <div class=\"chat-composer-at-menu__section\">{{ group.label }}</div>\n <button\n v-for=\"item in group.items\"\n :key=\"`custom:${group.id}:${item.id}`\"\n class=\"chat-composer-at-menu__item\"\n :class=\"{ 'chat-composer-at-menu__item--active': mentionIndex(group.id, item.id) === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select-mention', item, group)\"\n >\n <slot name=\"mention\" :group=\"group\" :item=\"item\" :active=\"mentionIndex(group.id, item.id) === activeIndex\">\n <SparklesIcon class=\"chat-composer-at-menu__icon\" aria-hidden=\"true\" />\n <span><strong>{{ item.label }}</strong><small v-if=\"item.description\">{{ item.description }}</small></span>\n </slot>\n </button>\n </template>\n <template v-if=\"visiblePlugins.length\">\n <div class=\"chat-composer-at-menu__section\">Plugins</div>\n <button\n v-for=\"(plugin, index) in visiblePlugins\"\n :key=\"`plugin:${plugin.id}`\"\n class=\"chat-composer-at-menu__item\"\n :class=\"{ 'chat-composer-at-menu__item--active': leadingMentionCount + index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select-plugin', plugin)\"\n >\n <PlugIcon class=\"chat-composer-at-menu__icon\" aria-hidden=\"true\" />\n <span><strong>{{ pluginDisplayName(plugin) }}</strong><small>{{ pluginDescription(plugin) }}</small></span>\n </button>\n </template>\n <template v-if=\"visibleFiles.length\">\n <div class=\"chat-composer-at-menu__section\">Files</div>\n <button\n v-for=\"(file, index) in visibleFiles\"\n :key=\"`file:${file.path}`\"\n class=\"chat-composer-at-menu__item\"\n :class=\"{ 'chat-composer-at-menu__item--active': leadingMentionCount + visiblePlugins.length + index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select-file', file)\"\n >\n <FileTextIcon class=\"chat-composer-at-menu__icon\" aria-hidden=\"true\" />\n <span><strong>{{ file.name }}</strong><small>{{ file.path }}</small></span>\n </button>\n </template>\n <template v-for=\"group in trailingMentionGroups\" :key=\"`custom:${group.id}`\">\n <div class=\"chat-composer-at-menu__section\">{{ group.label }}</div>\n <button\n v-for=\"item in group.items\"\n :key=\"`custom:${group.id}:${item.id}`\"\n class=\"chat-composer-at-menu__item\"\n :class=\"{ 'chat-composer-at-menu__item--active': mentionIndex(group.id, item.id) === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select-mention', item, group)\"\n >\n <slot name=\"mention\" :group=\"group\" :item=\"item\" :active=\"mentionIndex(group.id, item.id) === activeIndex\">\n <SparklesIcon class=\"chat-composer-at-menu__icon\" aria-hidden=\"true\" />\n <span><strong>{{ item.label }}</strong><small v-if=\"item.description\">{{ item.description }}</small></span>\n </slot>\n </button>\n </template>\n <div v-if=\"showFileHint && !visibleFiles.length\" class=\"chat-composer-at-menu__hint\">Type to search files</div>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed } from 'vue';\nimport type { CodexFileSearchItem } from './contracts';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport { FileTextIcon, PlugIcon, SparklesIcon } from '../icons/app-icons';\nimport { pluginDescription, pluginDisplayName } from './composer-plugins';\nimport type {\n CodexComposerMentionGroup,\n CodexComposerMentionItem,\n CodexComposerVisibleMentionGroup,\n} from './composer-mentions-custom';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n mentionGroups?: readonly CodexComposerVisibleMentionGroup<Payload>[];\n showFileHint: boolean;\n visibleFiles: CodexFileSearchItem[];\n visiblePlugins: CodexSurfacePlugin[];\n}>();\n\ndefineEmits<{\n 'select-file': [file: CodexFileSearchItem];\n 'select-plugin': [plugin: CodexSurfacePlugin];\n 'select-mention': [item: CodexComposerMentionItem<Payload>, group: CodexComposerMentionGroup<Payload>];\n}>();\n\ndefineSlots<{\n mention(props: {\n active: boolean;\n group: CodexComposerVisibleMentionGroup<Payload>;\n item: CodexComposerMentionItem<Payload>;\n }): unknown;\n}>();\n// Stryker restore all\n\nconst leadingMentionGroups = computed(() => props.mentionGroups?.filter((group) => group.placement !== 'after') ?? []);\nconst trailingMentionGroups = computed(() => props.mentionGroups?.filter((group) => group.placement === 'after') ?? []);\nconst leadingMentionCount = computed(() => leadingMentionGroups.value.reduce((total, group) => total + group.items.length, 0));\n\nfunction mentionIndex(groupId: string, itemId: string): number {\n let index = 0;\n for (const group of leadingMentionGroups.value) {\n for (const item of group.items) {\n if (group.id === groupId && item.id === itemId) return index;\n index += 1;\n }\n }\n index += props.visiblePlugins.length + props.visibleFiles.length;\n for (const group of trailingMentionGroups.value) {\n for (const item of group.items) {\n if (group.id === groupId && item.id === itemId) return index;\n index += 1;\n }\n }\n return -1;\n}\n</script>\n\n<style scoped>\n.chat-composer-at-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n.chat-composer-at-menu__section,\n.chat-composer-at-menu__hint { padding: var(--space-2) var(--space-4); color: var(--color-text-muted); font-size: var(--font-size-12); }\n.chat-composer-at-menu__section { font-size: var(--codex-composer-menu-heading-font-size, 13px); font-weight: var(--font-weight-medium); line-height: 18px; }\n.chat-composer-at-menu__item { display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--chat-menu-control-min-height); margin-block: 0.125px; padding: var(--space-2) var(--space-4); border: 0; border-radius: var(--radius-lg); background: transparent; color: var(--color-text); text-align: left; }\n.chat-composer-at-menu__item--active { background: var(--color-surface-low); }\n.chat-composer-at-menu__icon { width: var(--icon-md); height: var(--icon-md); flex: 0 0 var(--icon-md); opacity: 0.5; stroke-width: 2px; }\n.chat-composer-at-menu__item span { display: flex; min-width: 0; flex-direction: column; }\n.chat-composer-at-menu__item strong { font-weight: var(--font-weight-medium); }\n.chat-composer-at-menu__item small { overflow: hidden; color: var(--color-text-muted); text-overflow: ellipsis; white-space: nowrap; }\n</style>\n","import type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport type { CodexSkillSummary, PromptSkillInput } from './contracts';\nimport { filterComposerSearchItems } from './composer-search';\n\nexport type ActiveSkillSlash = {\n end: number;\n query: string;\n start: number;\n trigger: '$' | '/';\n};\n\nexport function findActiveSkillTrigger(value: string, caretPosition: number, trigger: '$' | '/' = '$'): ActiveSkillSlash | null {\n const safeCaret = Math.max(0, Math.min(caretPosition, value.length));\n const beforeCaret = value.slice(0, safeCaret);\n const start = beforeCaret.lastIndexOf(trigger);\n if (start < 0) {\n return null;\n }\n\n const previous = start > 0 ? beforeCaret[start - 1] : '';\n if (previous && /[\\w.%+-]/.test(previous)) {\n return null;\n }\n\n const query = beforeCaret.slice(start + 1);\n if (/[\\s/$]/.test(query)) {\n return null;\n }\n\n return {\n end: safeCaret,\n query,\n start,\n trigger,\n };\n}\n\nexport function findActiveSkillSlash(value: string, caretPosition: number): ActiveSkillSlash | null {\n return findActiveSkillTrigger(value, caretPosition, '/');\n}\n\nexport function filterComposerSkills(\n skills: CodexSkillSummary[],\n query: string,\n maxResults = -1,\n plugins: readonly CodexSurfacePlugin[] = [],\n): CodexSkillSummary[] {\n return filterComposerSearchItems(skills, query, [\n { values: (skill) => [skill.id, skillInsertText(skill), skill.name, skill.displayName, skillDisplayName(skill, plugins)] },\n { values: (skill) => [skill.shortDescription, skill.description] },\n ], maxResults);\n}\n\nexport function skillDisplayName(\n skill: CodexSkillSummary,\n plugins: readonly CodexSurfacePlugin[] = [],\n): string {\n if (skill.displayName) return skill.displayName;\n const separator = skill.name.indexOf(':');\n if (separator <= 0 || separator === skill.name.length - 1) return skill.name;\n const pluginId = skill.name.slice(0, separator);\n const plugin = plugins.find((candidate) => (\n candidate.id === pluginId\n || candidate.name === pluginId\n || candidate.id.startsWith(`${pluginId}@`)\n ));\n if (!plugin) return skill.name;\n const namespace = plugin.displayName\n .toLowerCase()\n .replace(/[^a-z\\d]+/g, '-')\n .replace(/^-|-$/g, '') || plugin.name;\n return `${namespace}:${skill.name.slice(separator + 1)}`;\n}\n\nexport function skillDescription(skill: CodexSkillSummary): string {\n return skill.shortDescription || skill.description || '';\n}\n\nexport function skillInsertText(skill: Pick<CodexSkillSummary, 'name' | 'path'>): string {\n const alias = /\\(([A-Za-z0-9_.-]+)\\)\\s*$/.exec(skill.name)?.[1];\n if (alias) return alias;\n if (/^[A-Za-z0-9_.-]+$/.test(skill.name)) return skill.name;\n const directoryName = skill.path.replace(/[\\\\/]+SKILL\\.md$/i, '').split(/[\\\\/]/).at(-1);\n return directoryName || skill.name.trim().replace(/\\s+/g, '-').toLowerCase();\n}\n\nexport function skillMatchesMention(\n skill: { id?: string; name: string; displayName?: string; path: string },\n mention: string,\n): boolean {\n const normalized = mention.trim().toLowerCase();\n const directoryName = skill.path.replace(/[\\\\/]+SKILL\\.md$/i, '').split(/[\\\\/]/).at(-1);\n return [skill.id, skill.name, skill.displayName, directoryName, skillInsertText(skill)]\n .some((candidate) => candidate?.trim().toLowerCase() === normalized);\n}\n\nexport function promptSkillInputsFromText(text: string, skills: CodexSkillSummary[]): PromptSkillInput[] {\n const names = new Set<string>();\n const pattern = /(?:^|[^\\w.%+-])[$/]([A-Za-z0-9_.-]+)/g;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(text)) !== null) {\n names.add(match[1]!);\n }\n\n return skills\n .filter((skill) => [...names].some((name) => skillMatchesMention(skill, name)) && Boolean(skill.path))\n .map((skill) => ({\n name: skill.name,\n path: skill.path,\n }));\n}\n","<template>\n <div\n ref=\"menuEl\"\n class=\"codex-chat-theme chat-composer-skill-menu\"\n role=\"listbox\"\n aria-label=\"Skills\"\n >\n <div class=\"chat-composer-skill-menu__section\">\n {{ t('chat.skills.title') }}\n </div>\n <button\n v-for=\"(skill, index) in visibleSkills\"\n :key=\"skill.path\"\n class=\"chat-composer-skill-menu__item\"\n :class=\"{ 'chat-composer-skill-menu__item--active': index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select', skill)\"\n >\n <span\n class=\"chat-composer-skill-menu__icon\"\n aria-hidden=\"true\"\n >\n <SparklesIcon />\n </span>\n <span class=\"chat-composer-skill-menu__main\">\n <span class=\"chat-composer-skill-menu__name\">{{ skillDisplayName(skill, plugins ?? []) }}</span>\n <span class=\"chat-composer-skill-menu__description\">{{ skillDescription(skill) }}</span>\n </span>\n </button>\n <div\n v-if=\"visibleSkills.length === 0\"\n class=\"chat-composer-skill-menu__empty\"\n >\n {{ t('chat.skills.empty') }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport { useCodexChatTranslate } from './chat-i18n';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport type { CodexSkillSummary } from './contracts';\nimport { skillDescription, skillDisplayName } from './composer-skills';\nimport { SparklesIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n plugins?: readonly CodexSurfacePlugin[];\n visibleSkills: CodexSkillSummary[];\n}>();\n\ndefineEmits<{\n select: [skill: CodexSkillSummary];\n}>();\n// Stryker restore all\n\nconst t = useCodexChatTranslate();\nconst menuEl = ref<HTMLElement | null>(null);\n\nwatch(\n () => [props.activeIndex, props.visibleSkills],\n async () => {\n await nextTick();\n const activeItem = menuEl.value?.querySelectorAll<HTMLButtonElement>('.chat-composer-skill-menu__item')\n .item(props.activeIndex);\n if (typeof activeItem?.scrollIntoView === 'function') {\n activeItem.scrollIntoView({ block: 'nearest' });\n }\n },\n);\n</script>\n\n<style scoped>\n.chat-composer-skill-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-composer-skill-menu__section {\n padding: var(--space-2) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.chat-composer-skill-menu__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n min-height: var(--chat-menu-control-min-height);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n line-height: 1.35;\n text-align: left;\n}\n\n.chat-composer-skill-menu__item:hover,\n.chat-composer-skill-menu__item--active {\n background: var(--color-surface);\n}\n\n.chat-composer-skill-menu__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--icon-md);\n height: var(--icon-md);\n flex: 0 0 var(--icon-md);\n}\n\n.chat-composer-skill-menu__icon svg {\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.chat-composer-skill-menu__main {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: var(--space-4);\n}\n\n.chat-composer-skill-menu__name {\n overflow: hidden;\n font-weight: var(--font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.chat-composer-skill-menu__description {\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 1;\n}\n\n.chat-composer-skill-menu__empty {\n padding: var(--space-3) var(--space-4) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: normal;\n}\n</style>\n","<template>\n <div\n ref=\"menuEl\"\n class=\"codex-chat-theme chat-composer-skill-menu\"\n role=\"listbox\"\n aria-label=\"Skills\"\n >\n <div class=\"chat-composer-skill-menu__section\">\n {{ t('chat.skills.title') }}\n </div>\n <button\n v-for=\"(skill, index) in visibleSkills\"\n :key=\"skill.path\"\n class=\"chat-composer-skill-menu__item\"\n :class=\"{ 'chat-composer-skill-menu__item--active': index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select', skill)\"\n >\n <span\n class=\"chat-composer-skill-menu__icon\"\n aria-hidden=\"true\"\n >\n <SparklesIcon />\n </span>\n <span class=\"chat-composer-skill-menu__main\">\n <span class=\"chat-composer-skill-menu__name\">{{ skillDisplayName(skill, plugins ?? []) }}</span>\n <span class=\"chat-composer-skill-menu__description\">{{ skillDescription(skill) }}</span>\n </span>\n </button>\n <div\n v-if=\"visibleSkills.length === 0\"\n class=\"chat-composer-skill-menu__empty\"\n >\n {{ t('chat.skills.empty') }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport { useCodexChatTranslate } from './chat-i18n';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport type { CodexSkillSummary } from './contracts';\nimport { skillDescription, skillDisplayName } from './composer-skills';\nimport { SparklesIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n plugins?: readonly CodexSurfacePlugin[];\n visibleSkills: CodexSkillSummary[];\n}>();\n\ndefineEmits<{\n select: [skill: CodexSkillSummary];\n}>();\n// Stryker restore all\n\nconst t = useCodexChatTranslate();\nconst menuEl = ref<HTMLElement | null>(null);\n\nwatch(\n () => [props.activeIndex, props.visibleSkills],\n async () => {\n await nextTick();\n const activeItem = menuEl.value?.querySelectorAll<HTMLButtonElement>('.chat-composer-skill-menu__item')\n .item(props.activeIndex);\n if (typeof activeItem?.scrollIntoView === 'function') {\n activeItem.scrollIntoView({ block: 'nearest' });\n }\n },\n);\n</script>\n\n<style scoped>\n.chat-composer-skill-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-composer-skill-menu__section {\n padding: var(--space-2) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.chat-composer-skill-menu__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n min-height: var(--chat-menu-control-min-height);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n line-height: 1.35;\n text-align: left;\n}\n\n.chat-composer-skill-menu__item:hover,\n.chat-composer-skill-menu__item--active {\n background: var(--color-surface);\n}\n\n.chat-composer-skill-menu__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--icon-md);\n height: var(--icon-md);\n flex: 0 0 var(--icon-md);\n}\n\n.chat-composer-skill-menu__icon svg {\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.chat-composer-skill-menu__main {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: var(--space-4);\n}\n\n.chat-composer-skill-menu__name {\n overflow: hidden;\n font-weight: var(--font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.chat-composer-skill-menu__description {\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 1;\n}\n\n.chat-composer-skill-menu__empty {\n padding: var(--space-3) var(--space-4) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: normal;\n}\n</style>\n","import type { CodexCommandSummary } from './contracts';\nimport { filterComposerSearchItems } from './composer-search';\n\nexport type ActiveCommandSlash = {\n end: number;\n query: string;\n start: number;\n};\n\nexport function findActiveCommandSlash(value: string, caretPosition: number): ActiveCommandSlash | null {\n const safeCaret = Math.max(0, Math.min(caretPosition, value.length));\n if (safeCaret === 0 || value[0] !== '/') {\n return null;\n }\n const beforeCaret = value.slice(0, safeCaret);\n const query = beforeCaret.slice(1);\n if (/[\\s/$]/.test(query)) {\n return null;\n }\n\n return {\n end: safeCaret,\n query,\n start: 0,\n };\n}\n\nexport function filterComposerCommands(commands: CodexCommandSummary[], query: string, maxResults = -1): CodexCommandSummary[] {\n return filterComposerSearchItems(commands, query, [\n { values: (command) => [command.id] },\n { values: (command) => [command.name, command.displayName, command.slashName] },\n { values: (command) => [command.description] },\n ], maxResults);\n}\n\nexport function commandDisplayName(command: CodexCommandSummary): string {\n return command.displayName || command.name;\n}\n\nexport function commandDescription(command: CodexCommandSummary): string {\n return command.description || '';\n}\n","<template>\n <div\n ref=\"menuEl\"\n class=\"codex-chat-theme chat-composer-slash-menu\"\n role=\"listbox\"\n aria-label=\"Commands and skills\"\n >\n <template v-if=\"visibleCommands.length > 0\">\n <div class=\"chat-composer-slash-menu__section\">\n {{ t('chat.commands.title') }}\n </div>\n <button\n v-for=\"(command, index) in visibleCommands\"\n :key=\"command.id\"\n class=\"chat-composer-slash-menu__item\"\n :class=\"{ 'chat-composer-slash-menu__item--active': index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('selectCommand', command)\"\n >\n <span\n class=\"chat-composer-slash-menu__icon\"\n aria-hidden=\"true\"\n >\n <TerminalIcon />\n </span>\n <span class=\"chat-composer-slash-menu__main\">\n <span class=\"chat-composer-slash-menu__name\">{{ command.name }}</span>\n <span class=\"chat-composer-slash-menu__description\">{{ commandDescription(command) }}</span>\n </span>\n </button>\n </template>\n\n <template v-if=\"visibleSkills.length > 0\">\n <div class=\"chat-composer-slash-menu__section\">\n {{ t('chat.skills.title') }}\n </div>\n <button\n v-for=\"(skill, index) in visibleSkills\"\n :key=\"skill.path\"\n class=\"chat-composer-slash-menu__item\"\n :class=\"{ 'chat-composer-slash-menu__item--active': visibleCommands.length + index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('selectSkill', skill)\"\n >\n <span\n class=\"chat-composer-slash-menu__icon\"\n aria-hidden=\"true\"\n >\n <SparklesIcon />\n </span>\n <span class=\"chat-composer-slash-menu__main\">\n <span class=\"chat-composer-slash-menu__name\">{{ skill.name }}</span>\n <span class=\"chat-composer-slash-menu__description\">{{ skillDescription(skill) }}</span>\n </span>\n </button>\n </template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport { useCodexChatTranslate } from './chat-i18n';\nimport type { CodexCommandSummary, CodexSkillSummary } from './contracts';\nimport { commandDescription } from './composer-commands';\nimport { skillDescription } from './composer-skills';\nimport { SparklesIcon, TerminalIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n visibleCommands: CodexCommandSummary[];\n visibleSkills: CodexSkillSummary[];\n}>();\n\ndefineEmits<{\n selectCommand: [command: CodexCommandSummary];\n selectSkill: [skill: CodexSkillSummary];\n}>();\n// Stryker restore all\n\nconst t = useCodexChatTranslate();\nconst menuEl = ref<HTMLElement | null>(null);\n\nwatch(\n () => [props.activeIndex, props.visibleCommands, props.visibleSkills],\n async () => {\n await nextTick();\n const activeItem = menuEl.value?.querySelectorAll<HTMLButtonElement>('.chat-composer-slash-menu__item')\n .item(props.activeIndex);\n if (typeof activeItem?.scrollIntoView === 'function') {\n activeItem.scrollIntoView({ block: 'nearest' });\n }\n },\n);\n</script>\n\n<style scoped>\n.chat-composer-slash-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-composer-slash-menu__section {\n padding: var(--space-2) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.chat-composer-slash-menu__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n min-height: var(--chat-menu-control-min-height);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n line-height: 1.35;\n text-align: left;\n}\n\n.chat-composer-slash-menu__item:hover,\n.chat-composer-slash-menu__item--active {\n background: var(--color-surface);\n}\n\n.chat-composer-slash-menu__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--icon-md);\n height: var(--icon-md);\n flex: 0 0 var(--icon-md);\n}\n\n.chat-composer-slash-menu__icon svg {\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.chat-composer-slash-menu__main {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: var(--space-4);\n}\n\n.chat-composer-slash-menu__name {\n overflow: hidden;\n font-weight: var(--font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.chat-composer-slash-menu__description {\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 1;\n}\n</style>\n","<template>\n <div\n ref=\"menuEl\"\n class=\"codex-chat-theme chat-composer-slash-menu\"\n role=\"listbox\"\n aria-label=\"Commands and skills\"\n >\n <template v-if=\"visibleCommands.length > 0\">\n <div class=\"chat-composer-slash-menu__section\">\n {{ t('chat.commands.title') }}\n </div>\n <button\n v-for=\"(command, index) in visibleCommands\"\n :key=\"command.id\"\n class=\"chat-composer-slash-menu__item\"\n :class=\"{ 'chat-composer-slash-menu__item--active': index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('selectCommand', command)\"\n >\n <span\n class=\"chat-composer-slash-menu__icon\"\n aria-hidden=\"true\"\n >\n <TerminalIcon />\n </span>\n <span class=\"chat-composer-slash-menu__main\">\n <span class=\"chat-composer-slash-menu__name\">{{ command.name }}</span>\n <span class=\"chat-composer-slash-menu__description\">{{ commandDescription(command) }}</span>\n </span>\n </button>\n </template>\n\n <template v-if=\"visibleSkills.length > 0\">\n <div class=\"chat-composer-slash-menu__section\">\n {{ t('chat.skills.title') }}\n </div>\n <button\n v-for=\"(skill, index) in visibleSkills\"\n :key=\"skill.path\"\n class=\"chat-composer-slash-menu__item\"\n :class=\"{ 'chat-composer-slash-menu__item--active': visibleCommands.length + index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('selectSkill', skill)\"\n >\n <span\n class=\"chat-composer-slash-menu__icon\"\n aria-hidden=\"true\"\n >\n <SparklesIcon />\n </span>\n <span class=\"chat-composer-slash-menu__main\">\n <span class=\"chat-composer-slash-menu__name\">{{ skill.name }}</span>\n <span class=\"chat-composer-slash-menu__description\">{{ skillDescription(skill) }}</span>\n </span>\n </button>\n </template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport { useCodexChatTranslate } from './chat-i18n';\nimport type { CodexCommandSummary, CodexSkillSummary } from './contracts';\nimport { commandDescription } from './composer-commands';\nimport { skillDescription } from './composer-skills';\nimport { SparklesIcon, TerminalIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n visibleCommands: CodexCommandSummary[];\n visibleSkills: CodexSkillSummary[];\n}>();\n\ndefineEmits<{\n selectCommand: [command: CodexCommandSummary];\n selectSkill: [skill: CodexSkillSummary];\n}>();\n// Stryker restore all\n\nconst t = useCodexChatTranslate();\nconst menuEl = ref<HTMLElement | null>(null);\n\nwatch(\n () => [props.activeIndex, props.visibleCommands, props.visibleSkills],\n async () => {\n await nextTick();\n const activeItem = menuEl.value?.querySelectorAll<HTMLButtonElement>('.chat-composer-slash-menu__item')\n .item(props.activeIndex);\n if (typeof activeItem?.scrollIntoView === 'function') {\n activeItem.scrollIntoView({ block: 'nearest' });\n }\n },\n);\n</script>\n\n<style scoped>\n.chat-composer-slash-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-composer-slash-menu__section {\n padding: var(--space-2) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.chat-composer-slash-menu__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n min-height: var(--chat-menu-control-min-height);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n line-height: 1.35;\n text-align: left;\n}\n\n.chat-composer-slash-menu__item:hover,\n.chat-composer-slash-menu__item--active {\n background: var(--color-surface);\n}\n\n.chat-composer-slash-menu__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--icon-md);\n height: var(--icon-md);\n flex: 0 0 var(--icon-md);\n}\n\n.chat-composer-slash-menu__icon svg {\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.chat-composer-slash-menu__main {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: var(--space-4);\n}\n\n.chat-composer-slash-menu__name {\n overflow: hidden;\n font-weight: var(--font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.chat-composer-slash-menu__description {\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 1;\n}\n</style>\n","<template>\n <span class=\"chat-mention-chip\">\n <img v-if=\"iconUrl\" class=\"chat-mention-chip__icon\" :src=\"iconUrl\" alt=\"\">\n <FileTextIcon v-else-if=\"kind === 'file'\" class=\"chat-mention-chip__icon\" aria-hidden=\"true\" />\n <SparklesIcon v-else-if=\"kind === 'skill'\" class=\"chat-mention-chip__icon\" aria-hidden=\"true\" />\n <PlugIcon v-else class=\"chat-mention-chip__icon\" aria-hidden=\"true\" />\n <span class=\"chat-mention-chip__label\">{{ name }}</span>\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { FileTextIcon, PlugIcon, SparklesIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n iconUrl?: string | null;\n kind: 'file' | 'plugin' | 'skill';\n name: string;\n}>(), {\n iconUrl: null,\n});\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-mention-chip {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n max-width: 220px;\n padding: var(--space-2) var(--space-4);\n border-radius: var(--radius-md);\n background: var(--color-primary-container);\n color: var(--color-on-primary-container);\n font-size: var(--font-size-13);\n line-height: 1.2;\n vertical-align: baseline;\n user-select: all;\n}\n\n.chat-mention-chip__icon {\n width: var(--icon-sm);\n height: var(--icon-sm);\n flex: 0 0 var(--icon-sm);\n object-fit: contain;\n}\n\n.chat-mention-chip__label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n</style>\n","<template>\n <span class=\"chat-mention-chip\">\n <img v-if=\"iconUrl\" class=\"chat-mention-chip__icon\" :src=\"iconUrl\" alt=\"\">\n <FileTextIcon v-else-if=\"kind === 'file'\" class=\"chat-mention-chip__icon\" aria-hidden=\"true\" />\n <SparklesIcon v-else-if=\"kind === 'skill'\" class=\"chat-mention-chip__icon\" aria-hidden=\"true\" />\n <PlugIcon v-else class=\"chat-mention-chip__icon\" aria-hidden=\"true\" />\n <span class=\"chat-mention-chip__label\">{{ name }}</span>\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { FileTextIcon, PlugIcon, SparklesIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n iconUrl?: string | null;\n kind: 'file' | 'plugin' | 'skill';\n name: string;\n}>(), {\n iconUrl: null,\n});\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-mention-chip {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n max-width: 220px;\n padding: var(--space-2) var(--space-4);\n border-radius: var(--radius-md);\n background: var(--color-primary-container);\n color: var(--color-on-primary-container);\n font-size: var(--font-size-13);\n line-height: 1.2;\n vertical-align: baseline;\n user-select: all;\n}\n\n.chat-mention-chip__icon {\n width: var(--icon-sm);\n height: var(--icon-sm);\n flex: 0 0 var(--icon-sm);\n object-fit: contain;\n}\n\n.chat-mention-chip__label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n</style>\n","import { filterComposerSearchItems } from './composer-search';\n\nexport type CodexComposerMentionItem<Payload = unknown> = {\n id: string;\n /** Stable text stored after the `@` prefix. */\n value: string;\n /** Friendly text rendered by the default mention UI. */\n label: string;\n description?: string;\n payload?: Payload;\n};\n\nexport type CodexComposerMentionGroup<Payload = unknown> = {\n id: string;\n label: string;\n /** Custom groups render before built-in plugins/files unless explicitly placed after them. */\n placement?: 'before' | 'after';\n items: readonly CodexComposerMentionItem<Payload>[];\n};\n\nexport type CodexComposerVisibleMentionGroup<Payload = unknown> = Omit<\n CodexComposerMentionGroup<Payload>,\n 'items'\n> & {\n items: readonly CodexComposerMentionItem<Payload>[];\n};\n\nexport function filterComposerMentionGroups<Payload>(\n groups: readonly CodexComposerMentionGroup<Payload>[],\n query: string,\n): CodexComposerVisibleMentionGroup<Payload>[] {\n return groups.flatMap((group) => {\n const items = filterComposerSearchItems([...group.items], query, [\n { values: (item) => [item.id, item.value, item.label] },\n { values: (item) => [item.description] },\n ]);\n return items.length > 0 ? [{ ...group, items }] : [];\n });\n}\n\nexport function findComposerMention<Payload>(\n groups: readonly CodexComposerMentionGroup<Payload>[],\n value: string,\n): { group: CodexComposerMentionGroup<Payload>; item: CodexComposerMentionItem<Payload> } | undefined {\n const normalized = value.trim().toLowerCase();\n for (const group of groups) {\n const item = group.items.find((candidate) => candidate.value.trim().toLowerCase() === normalized);\n if (item) return { group, item };\n }\n return undefined;\n}\n","<template>\n <div\n ref=\"editor\"\n class=\"chat-rich-text-editor\"\n :aria-disabled=\"disabled\"\n :aria-label=\"ariaLabel\"\n :contenteditable=\"disabled ? 'false' : 'true'\"\n :data-placeholder=\"placeholder\"\n role=\"textbox\"\n @input=\"onInput\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { Fragment, h, nextTick, onBeforeUnmount, onMounted, ref, render, useSlots, watch } from 'vue';\nimport type { CodexFileSearchItem, CodexSkillSummary } from './contracts';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport ChatMentionChip from './ChatMentionChip.vue';\nimport { skillMatchesMention } from './composer-skills';\nimport { pluginMatchesMention } from './composer-plugins';\nimport {\n findComposerMention,\n type CodexComposerMentionGroup,\n type CodexComposerMentionItem,\n} from './composer-mentions-custom';\n\nexport type CodexRichTextEditorExpose = {\n autoResize: () => void;\n focusEnd: () => void;\n getSelectionRange: () => { end: number; start: number; valid: boolean };\n insertTextAtSelection: (value: string) => void;\n readText: () => string;\n setCaret: (position: number, options?: { focus?: boolean }) => void;\n setSelection: (start: number, end: number, options?: { focus?: boolean }) => void;\n setText: (value: string, caret?: number, options?: { focus?: boolean }) => void;\n};\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n ariaLabel?: string;\n disabled?: boolean;\n files?: readonly CodexFileSearchItem[];\n maxHeight?: number;\n mentionGroups?: readonly CodexComposerMentionGroup[];\n modelValue: string;\n placeholder?: string;\n plugins?: readonly CodexSurfacePlugin[];\n skills?: readonly CodexSkillSummary[];\n}>(), {\n ariaLabel: 'Prompt',\n disabled: false,\n files: () => [],\n maxHeight: 304,\n mentionGroups: () => [],\n placeholder: '',\n plugins: () => [],\n skills: () => [],\n});\n// Stryker restore all\n\nconst slots = useSlots();\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n input: [];\n 'caret-change': [range: { end: number; start: number; valid: boolean }];\n 'update:modelValue': [value: string];\n}>();\n// Stryker restore all\n\nconst editor = ref<HTMLElement | null>(null);\nconst caretPosition = ref(0);\nconst catalogRevision = ref(0);\nconst inlineTokenPattern = /(`[^`]+`)|(^|[^\\w.%+-])([@$/])([^\\s@$]+)/g;\n\nwatch(() => [props.files, props.mentionGroups, props.plugins, props.skills], () => {\n catalogRevision.value += 1;\n}, { deep: true, flush: 'sync' });\n\nwatch(() => [props.modelValue, catalogRevision.value] as const, ([value, revision], previous) => {\n if (!editor.value || (revision === previous[1] && readText() === value)) return;\n renderText(value, Math.min(caretPosition.value, value.length));\n});\n\nonMounted(() => {\n renderText(props.modelValue, props.modelValue.length, { focus: false });\n document.addEventListener('selectionchange', handleDocumentSelectionChange);\n});\nonBeforeUnmount(() => {\n document.removeEventListener('selectionchange', handleDocumentSelectionChange);\n unmountChipHosts();\n});\n\nfunction handleDocumentSelectionChange(): void {\n const selection = getSelectionRange();\n if (!selection.valid) return;\n caretPosition.value = selection.end;\n emit('caret-change', selection);\n}\n\nfunction onInput(): void {\n normalizeTrailingBrowserLineBreak();\n const selection = getSelectionRange();\n const value = readText();\n caretPosition.value = selection.valid ? selection.end : value.length;\n emit('update:modelValue', value);\n emit('caret-change', selection.valid\n ? selection\n : { end: caretPosition.value, start: caretPosition.value, valid: false });\n emit('input');\n if (!value.endsWith('\\n')) {\n const placeholders = editor.value?.querySelectorAll('br[data-trailing-line-break]');\n if (placeholders?.length) {\n placeholders.forEach((placeholder) => placeholder.remove());\n setCaret(caretPosition.value, { focus: true });\n }\n }\n autoResize();\n}\n\nfunction normalizeTrailingBrowserLineBreak(): void {\n const lastChild = editor.value!.lastChild;\n if (!(lastChild instanceof HTMLBRElement) || lastChild.dataset.trailingLineBreak !== undefined) return;\n\n // Chromium keeps a terminal BR as a visual caret placeholder after native\n // deletion. Intentional trailing newlines already have an SDK sentinel, so\n // this unmarked terminal BR is browser-owned and must not enter the model.\n lastChild.dataset.trailingLineBreak = '';\n}\n\nfunction autoResize(): void {\n const element = editor.value;\n if (!element) return;\n element.style.height = 'auto';\n element.style.height = `${Math.min(element.scrollHeight, props.maxHeight)}px`;\n}\n\nfunction scrollCaretIntoView(element: HTMLElement): void {\n // A collapsed range after a trailing BR does not consistently expose a box\n // in Chromium. At the end of the draft, scrolling to the content bottom is\n // both exact and avoids waiting for the next native input event.\n if (caretPosition.value >= readText().length) {\n element.scrollTop = element.scrollHeight;\n return;\n }\n\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n if (!element.contains(range.startContainer) || typeof range.getBoundingClientRect !== 'function') return;\n const caretRect = range.getBoundingClientRect();\n const editorRect = element.getBoundingClientRect();\n if (caretRect.bottom > editorRect.bottom) {\n element.scrollTop += caretRect.bottom - editorRect.bottom;\n } else if (caretRect.top < editorRect.top) {\n element.scrollTop -= editorRect.top - caretRect.top;\n }\n}\n\nfunction readText(): string {\n return editor.value\n ? Array.from(editor.value.childNodes).map(canonicalNodeText).join('')\n : props.modelValue;\n}\n\nfunction canonicalNodeText(node: Node): string {\n if (node.nodeType === Node.TEXT_NODE) return node.textContent!;\n if (!(node instanceof HTMLElement)) return '';\n if (node.tagName === 'CODE') return `\\`${node.textContent!}\\``;\n if (node.dataset.pluginName) return `@${node.dataset.pluginName}`;\n if (node.dataset.fileMention) return `@${node.dataset.fileMention}`;\n if (node.dataset.mentionValue) return `@${node.dataset.mentionValue}`;\n if (node.dataset.skillName) return `${node.dataset.skillTrigger || '$'}${node.dataset.skillName}`;\n if (node.tagName === 'BR') return node.dataset.trailingLineBreak === undefined ? '\\n' : '';\n return Array.from(node.childNodes).map(canonicalNodeText).join('');\n}\n\nfunction canonicalNodeLength(node: Node): number {\n return canonicalNodeText(node).length;\n}\n\nfunction getSelectionRange(): { end: number; start: number; valid: boolean } {\n const element = editor.value;\n const selection = window.getSelection();\n if (!element || !selection || selection.rangeCount === 0) {\n return { end: caretPosition.value, start: caretPosition.value, valid: false };\n }\n const range = selection.getRangeAt(0);\n if (!element.contains(range.startContainer) || !element.contains(range.endContainer)) {\n return { end: caretPosition.value, start: caretPosition.value, valid: false };\n }\n const start = canonicalOffsetForDomPosition(element, range.startContainer, range.startOffset);\n const end = canonicalOffsetForDomPosition(element, range.endContainer, range.endOffset);\n return { end: Math.max(start, end), start: Math.min(start, end), valid: true };\n}\n\nfunction canonicalOffsetForDomPosition(root: HTMLElement, target: Node, offset: number): number {\n if (target === root) {\n return Array.from(root.childNodes).slice(0, offset)\n .reduce((total, node) => total + canonicalNodeLength(node), 0);\n }\n let position = 0;\n let found = false;\n const walk = (node: Node): void => {\n if (found) return;\n if (node === target) {\n position += node.nodeType === Node.TEXT_NODE\n ? offset\n : Array.from(node.childNodes).slice(0, offset)\n .reduce((total, child) => total + canonicalNodeLength(child), 0);\n found = true;\n return;\n }\n if (node.nodeType === Node.TEXT_NODE || node instanceof HTMLBRElement || isChipHost(node)) {\n position += canonicalNodeLength(node);\n return;\n }\n for (const child of Array.from(node.childNodes)) {\n walk(child);\n }\n };\n for (const child of Array.from(root.childNodes)) {\n walk(child);\n }\n return position;\n}\n\nfunction domPositionForCanonicalOffset(root: HTMLElement, position: number): { node: Node; offset: number } {\n let remaining = Math.max(0, position);\n const children = Array.from(root.childNodes);\n for (let index = 0; index < children.length; index += 1) {\n const child = children[index]!;\n const length = canonicalNodeLength(child);\n if (child.nodeType === Node.TEXT_NODE) {\n if (remaining <= length) return { node: child, offset: remaining };\n remaining -= length;\n continue;\n }\n if (isChipHost(child)) {\n if (remaining <= length) return { node: root, offset: remaining <= length / 2 ? index : index + 1 };\n remaining -= length;\n continue;\n }\n if (child instanceof HTMLBRElement) {\n // A real BR consumes one canonical character, so its two DOM sides map\n // to distinct offsets. This matters for a leading empty line: offset 0\n // is before the BR, while offset 1 is after it. The zero-length trailing\n // sentinel exists only to give Chromium a caret box, so its valid side\n // remains after the element.\n if (length === 0) return { node: root, offset: index + 1 };\n if (remaining === 0) return { node: root, offset: index };\n if (remaining <= length) return { node: root, offset: index + 1 };\n remaining -= length;\n continue;\n }\n if (remaining <= length && child instanceof HTMLElement) {\n return domPositionForCanonicalOffset(child, remaining);\n }\n remaining -= length;\n }\n return { node: root, offset: root.childNodes.length };\n}\n\nfunction isChipHost(node: Node): node is HTMLElement {\n return node instanceof HTMLElement && Boolean(\n node.dataset.pluginName || node.dataset.fileMention || node.dataset.mentionValue || node.dataset.skillName,\n );\n}\n\nfunction setCaret(position: number, options: { focus?: boolean } = {}): void {\n setSelection(position, position, options);\n}\n\nfunction setSelection(start: number, end: number, options: { focus?: boolean } = {}): void {\n const element = editor.value;\n if (!element) return;\n const shouldUpdateDocumentSelection = options.focus !== false || document.activeElement === element;\n if (options.focus !== false) element.focus();\n const length = readText().length;\n const nextStart = Math.max(0, Math.min(start, length));\n const nextEnd = Math.max(nextStart, Math.min(end, length));\n if (shouldUpdateDocumentSelection) {\n const startTarget = domPositionForCanonicalOffset(element, nextStart);\n const endTarget = domPositionForCanonicalOffset(element, nextEnd);\n const range = document.createRange();\n range.setStart(startTarget.node, startTarget.offset);\n range.setEnd(endTarget.node, endTarget.offset);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n }\n caretPosition.value = nextEnd;\n emit('caret-change', { end: nextEnd, start: nextStart, valid: true });\n}\n\nfunction setText(value: string, caret = value.length, options: { focus?: boolean } = {}): void {\n emit('update:modelValue', value);\n renderText(value, caret, options);\n}\n\nfunction insertTextAtSelection(value: string): void {\n const selection = getSelectionRange();\n // Native editing records an undo transaction; replacing the DOM does not.\n if (typeof document.execCommand === 'function') {\n setSelection(selection.start, selection.end);\n const text = document.createElement('span');\n appendTextNode(text, value);\n if (value.endsWith('\\n') && selection.end === readText().length) {\n const placeholder = document.createElement('br');\n placeholder.dataset.trailingLineBreak = '';\n text.append(placeholder);\n }\n if (document.execCommand('insertHTML', false, text.innerHTML)) {\n setCaret(selection.start + value.length);\n scrollCaretIntoView(editor.value!);\n return;\n }\n }\n const current = readText();\n const next = `${current.slice(0, selection.start)}${value}${current.slice(selection.end)}`;\n const nextCaret = selection.start + value.length;\n emit('update:modelValue', next);\n renderText(next, nextCaret, { focus: true });\n}\n\nfunction focusEnd(): void {\n void nextTick(() => setCaret(readText().length));\n}\n\nfunction renderText(value: string, caret = caretPosition.value, options: { focus?: boolean } = {}): void {\n const element = editor.value;\n if (!element) return;\n const shouldFocus = options.focus ?? document.activeElement === element;\n const fragment = document.createDocumentFragment();\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n inlineTokenPattern.lastIndex = 0;\n while ((match = inlineTokenPattern.exec(value)) !== null) {\n if (match[1]) continue;\n const prefix = match[2]!;\n const trigger = match[3];\n const tokenText = match[4]!;\n const tokenStart = match.index + prefix.length;\n const tokenEnd = tokenStart + tokenText.length + 1;\n const mention = trigger === '$'\n ? findSkill(tokenText)\n : trigger === '@'\n ? findAtMention(tokenText)\n : undefined;\n if (!mention) continue;\n appendTextNode(fragment, value.slice(lastIndex, tokenStart));\n if (trigger === '$') {\n fragment.append(createSkillChip(tokenText, mention as CodexSkillSummary));\n } else {\n const atMention = mention as Exclude<ReturnType<typeof findAtMention>, undefined>;\n fragment.append(atMention.kind === 'plugin'\n ? createPluginChip(tokenText, atMention.value)\n : atMention.kind === 'file'\n ? createFileChip(tokenText, atMention.value)\n : createCustomMentionChip(tokenText, atMention.group, atMention.item));\n }\n lastIndex = tokenEnd;\n }\n appendTextNode(fragment, value.slice(lastIndex));\n if (value.endsWith('\\n')) {\n const trailingLineBreak = document.createElement('br');\n trailingLineBreak.dataset.trailingLineBreak = '';\n fragment.append(trailingLineBreak);\n }\n unmountChipHosts();\n element.replaceChildren(fragment);\n setCaret(Math.min(caret, value.length), { focus: shouldFocus });\n autoResize();\n scrollCaretIntoView(element);\n}\n\nfunction appendTextNode(parent: Node, value: string): void {\n const lines = value.split('\\n');\n lines.forEach((line, index) => {\n if (line) parent.appendChild(document.createTextNode(line));\n if (index < lines.length - 1) parent.appendChild(document.createElement('br'));\n });\n}\n\nfunction findPlugin(name: string): CodexSurfacePlugin | undefined {\n return props.plugins.find((plugin) => pluginMatchesMention(plugin, name));\n}\n\nfunction findAtMention(name: string):\n | { kind: 'plugin'; value: CodexSurfacePlugin }\n | { kind: 'file'; value: CodexFileSearchItem }\n | { kind: 'custom'; group: CodexComposerMentionGroup; item: CodexComposerMentionItem }\n | undefined {\n const leadingMention = findComposerMention(\n props.mentionGroups.filter((group) => group.placement !== 'after'),\n name,\n );\n if (leadingMention) return { kind: 'custom', ...leadingMention };\n const plugin = findPlugin(name);\n if (plugin) return { kind: 'plugin', value: plugin };\n const file = findFile(name);\n if (file) return { kind: 'file', value: file };\n // Non-after groups were already exhausted by the leading lookup above.\n const trailingMention = findComposerMention(\n props.mentionGroups,\n name,\n );\n return trailingMention ? { kind: 'custom', ...trailingMention } : undefined;\n}\n\nfunction findFile(path: string): CodexFileSearchItem | undefined {\n return props.files.find((file) => file.path === path || file.name === path);\n}\n\nfunction findSkill(name: string): CodexSkillSummary | undefined {\n return props.skills.find((skill) => skillMatchesMention(skill, name));\n}\n\nfunction createChip(dataset: Record<string, string>, properties: {\n iconUrl?: string;\n kind: 'file' | 'plugin' | 'skill';\n name: string;\n}): HTMLElement {\n const host = document.createElement('span');\n host.className = 'chat-rich-text-editor__chip-token-host';\n host.contentEditable = 'false';\n Object.assign(host.dataset, dataset);\n host.setAttribute('aria-label', properties.name);\n render(h(ChatMentionChip, properties), host);\n return host;\n}\n\nfunction createPluginChip(name: string, plugin: CodexSurfacePlugin): HTMLElement {\n return createChip({ pluginName: name }, {\n iconUrl: plugin.iconUrl,\n kind: 'plugin',\n name: plugin.displayName || plugin.name,\n });\n}\n\nfunction createFileChip(path: string, file: CodexFileSearchItem): HTMLElement {\n return createChip({ fileMention: path }, { kind: 'file', name: file.name });\n}\n\nfunction createSkillChip(name: string, skill: CodexSkillSummary): HTMLElement {\n return createChip({ skillName: name, skillTrigger: '$' }, {\n iconUrl: skill.iconSmall,\n kind: 'skill',\n name: skill.displayName || skill.name,\n });\n}\n\nfunction createCustomMentionChip(\n value: string,\n group: CodexComposerMentionGroup,\n item: CodexComposerMentionItem,\n): HTMLElement {\n const host = document.createElement('span');\n host.className = 'chat-rich-text-editor__chip-token-host';\n host.contentEditable = 'false';\n host.dataset.mentionGroup = group.id;\n host.dataset.mentionValue = value;\n host.setAttribute('aria-label', item.label);\n render(slots.mention\n ? h(Fragment, null, slots.mention({ group, item, surface: 'composer' }))\n : h(ChatMentionChip, { kind: 'plugin', name: item.label }), host);\n return host;\n}\n\nfunction unmountChipHosts(): void {\n // A parent update can remove this editor before its post-render ref is assigned.\n if (!editor.value) return;\n for (const chip of editor.value.querySelectorAll('.chat-rich-text-editor__chip-token-host')) {\n render(null, chip as HTMLElement);\n }\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineExpose<CodexRichTextEditorExpose>({\n autoResize,\n focusEnd,\n getSelectionRange,\n insertTextAtSelection,\n readText,\n setCaret,\n setSelection,\n setText,\n});\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-rich-text-editor {\n display: block;\n flex: 1 1 auto;\n min-width: 0;\n min-height: var(--chat-composer-line-height, var(--line-height-24));\n max-height: var(--chat-composer-input-max-height, 304px);\n padding: var(--space-4) 0;\n overflow-y: auto;\n scrollbar-width: none;\n border: 0;\n outline: 0;\n background: transparent;\n color: var(--color-text);\n font: inherit;\n font-size: var(--chat-composer-font-size, var(--font-size-15));\n line-height: var(--chat-composer-line-height, var(--line-height-24));\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n.chat-rich-text-editor::-webkit-scrollbar {\n display: none;\n}\n\n.chat-rich-text-editor:empty::before {\n color: var(--color-text-muted);\n content: attr(data-placeholder);\n pointer-events: none;\n}\n\n.chat-rich-text-editor[aria-disabled=\"true\"] {\n cursor: not-allowed;\n}\n\n.chat-rich-text-editor :deep(.chat-rich-text-editor__chip-token-host) {\n display: inline-block;\n max-width: 220px;\n margin: 0 var(--space-1);\n vertical-align: -2px;\n}\n</style>\n","<template>\n <div\n ref=\"editor\"\n class=\"chat-rich-text-editor\"\n :aria-disabled=\"disabled\"\n :aria-label=\"ariaLabel\"\n :contenteditable=\"disabled ? 'false' : 'true'\"\n :data-placeholder=\"placeholder\"\n role=\"textbox\"\n @input=\"onInput\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { Fragment, h, nextTick, onBeforeUnmount, onMounted, ref, render, useSlots, watch } from 'vue';\nimport type { CodexFileSearchItem, CodexSkillSummary } from './contracts';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport ChatMentionChip from './ChatMentionChip.vue';\nimport { skillMatchesMention } from './composer-skills';\nimport { pluginMatchesMention } from './composer-plugins';\nimport {\n findComposerMention,\n type CodexComposerMentionGroup,\n type CodexComposerMentionItem,\n} from './composer-mentions-custom';\n\nexport type CodexRichTextEditorExpose = {\n autoResize: () => void;\n focusEnd: () => void;\n getSelectionRange: () => { end: number; start: number; valid: boolean };\n insertTextAtSelection: (value: string) => void;\n readText: () => string;\n setCaret: (position: number, options?: { focus?: boolean }) => void;\n setSelection: (start: number, end: number, options?: { focus?: boolean }) => void;\n setText: (value: string, caret?: number, options?: { focus?: boolean }) => void;\n};\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n ariaLabel?: string;\n disabled?: boolean;\n files?: readonly CodexFileSearchItem[];\n maxHeight?: number;\n mentionGroups?: readonly CodexComposerMentionGroup[];\n modelValue: string;\n placeholder?: string;\n plugins?: readonly CodexSurfacePlugin[];\n skills?: readonly CodexSkillSummary[];\n}>(), {\n ariaLabel: 'Prompt',\n disabled: false,\n files: () => [],\n maxHeight: 304,\n mentionGroups: () => [],\n placeholder: '',\n plugins: () => [],\n skills: () => [],\n});\n// Stryker restore all\n\nconst slots = useSlots();\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n input: [];\n 'caret-change': [range: { end: number; start: number; valid: boolean }];\n 'update:modelValue': [value: string];\n}>();\n// Stryker restore all\n\nconst editor = ref<HTMLElement | null>(null);\nconst caretPosition = ref(0);\nconst catalogRevision = ref(0);\nconst inlineTokenPattern = /(`[^`]+`)|(^|[^\\w.%+-])([@$/])([^\\s@$]+)/g;\n\nwatch(() => [props.files, props.mentionGroups, props.plugins, props.skills], () => {\n catalogRevision.value += 1;\n}, { deep: true, flush: 'sync' });\n\nwatch(() => [props.modelValue, catalogRevision.value] as const, ([value, revision], previous) => {\n if (!editor.value || (revision === previous[1] && readText() === value)) return;\n renderText(value, Math.min(caretPosition.value, value.length));\n});\n\nonMounted(() => {\n renderText(props.modelValue, props.modelValue.length, { focus: false });\n document.addEventListener('selectionchange', handleDocumentSelectionChange);\n});\nonBeforeUnmount(() => {\n document.removeEventListener('selectionchange', handleDocumentSelectionChange);\n unmountChipHosts();\n});\n\nfunction handleDocumentSelectionChange(): void {\n const selection = getSelectionRange();\n if (!selection.valid) return;\n caretPosition.value = selection.end;\n emit('caret-change', selection);\n}\n\nfunction onInput(): void {\n normalizeTrailingBrowserLineBreak();\n const selection = getSelectionRange();\n const value = readText();\n caretPosition.value = selection.valid ? selection.end : value.length;\n emit('update:modelValue', value);\n emit('caret-change', selection.valid\n ? selection\n : { end: caretPosition.value, start: caretPosition.value, valid: false });\n emit('input');\n if (!value.endsWith('\\n')) {\n const placeholders = editor.value?.querySelectorAll('br[data-trailing-line-break]');\n if (placeholders?.length) {\n placeholders.forEach((placeholder) => placeholder.remove());\n setCaret(caretPosition.value, { focus: true });\n }\n }\n autoResize();\n}\n\nfunction normalizeTrailingBrowserLineBreak(): void {\n const lastChild = editor.value!.lastChild;\n if (!(lastChild instanceof HTMLBRElement) || lastChild.dataset.trailingLineBreak !== undefined) return;\n\n // Chromium keeps a terminal BR as a visual caret placeholder after native\n // deletion. Intentional trailing newlines already have an SDK sentinel, so\n // this unmarked terminal BR is browser-owned and must not enter the model.\n lastChild.dataset.trailingLineBreak = '';\n}\n\nfunction autoResize(): void {\n const element = editor.value;\n if (!element) return;\n element.style.height = 'auto';\n element.style.height = `${Math.min(element.scrollHeight, props.maxHeight)}px`;\n}\n\nfunction scrollCaretIntoView(element: HTMLElement): void {\n // A collapsed range after a trailing BR does not consistently expose a box\n // in Chromium. At the end of the draft, scrolling to the content bottom is\n // both exact and avoids waiting for the next native input event.\n if (caretPosition.value >= readText().length) {\n element.scrollTop = element.scrollHeight;\n return;\n }\n\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n if (!element.contains(range.startContainer) || typeof range.getBoundingClientRect !== 'function') return;\n const caretRect = range.getBoundingClientRect();\n const editorRect = element.getBoundingClientRect();\n if (caretRect.bottom > editorRect.bottom) {\n element.scrollTop += caretRect.bottom - editorRect.bottom;\n } else if (caretRect.top < editorRect.top) {\n element.scrollTop -= editorRect.top - caretRect.top;\n }\n}\n\nfunction readText(): string {\n return editor.value\n ? Array.from(editor.value.childNodes).map(canonicalNodeText).join('')\n : props.modelValue;\n}\n\nfunction canonicalNodeText(node: Node): string {\n if (node.nodeType === Node.TEXT_NODE) return node.textContent!;\n if (!(node instanceof HTMLElement)) return '';\n if (node.tagName === 'CODE') return `\\`${node.textContent!}\\``;\n if (node.dataset.pluginName) return `@${node.dataset.pluginName}`;\n if (node.dataset.fileMention) return `@${node.dataset.fileMention}`;\n if (node.dataset.mentionValue) return `@${node.dataset.mentionValue}`;\n if (node.dataset.skillName) return `${node.dataset.skillTrigger || '$'}${node.dataset.skillName}`;\n if (node.tagName === 'BR') return node.dataset.trailingLineBreak === undefined ? '\\n' : '';\n return Array.from(node.childNodes).map(canonicalNodeText).join('');\n}\n\nfunction canonicalNodeLength(node: Node): number {\n return canonicalNodeText(node).length;\n}\n\nfunction getSelectionRange(): { end: number; start: number; valid: boolean } {\n const element = editor.value;\n const selection = window.getSelection();\n if (!element || !selection || selection.rangeCount === 0) {\n return { end: caretPosition.value, start: caretPosition.value, valid: false };\n }\n const range = selection.getRangeAt(0);\n if (!element.contains(range.startContainer) || !element.contains(range.endContainer)) {\n return { end: caretPosition.value, start: caretPosition.value, valid: false };\n }\n const start = canonicalOffsetForDomPosition(element, range.startContainer, range.startOffset);\n const end = canonicalOffsetForDomPosition(element, range.endContainer, range.endOffset);\n return { end: Math.max(start, end), start: Math.min(start, end), valid: true };\n}\n\nfunction canonicalOffsetForDomPosition(root: HTMLElement, target: Node, offset: number): number {\n if (target === root) {\n return Array.from(root.childNodes).slice(0, offset)\n .reduce((total, node) => total + canonicalNodeLength(node), 0);\n }\n let position = 0;\n let found = false;\n const walk = (node: Node): void => {\n if (found) return;\n if (node === target) {\n position += node.nodeType === Node.TEXT_NODE\n ? offset\n : Array.from(node.childNodes).slice(0, offset)\n .reduce((total, child) => total + canonicalNodeLength(child), 0);\n found = true;\n return;\n }\n if (node.nodeType === Node.TEXT_NODE || node instanceof HTMLBRElement || isChipHost(node)) {\n position += canonicalNodeLength(node);\n return;\n }\n for (const child of Array.from(node.childNodes)) {\n walk(child);\n }\n };\n for (const child of Array.from(root.childNodes)) {\n walk(child);\n }\n return position;\n}\n\nfunction domPositionForCanonicalOffset(root: HTMLElement, position: number): { node: Node; offset: number } {\n let remaining = Math.max(0, position);\n const children = Array.from(root.childNodes);\n for (let index = 0; index < children.length; index += 1) {\n const child = children[index]!;\n const length = canonicalNodeLength(child);\n if (child.nodeType === Node.TEXT_NODE) {\n if (remaining <= length) return { node: child, offset: remaining };\n remaining -= length;\n continue;\n }\n if (isChipHost(child)) {\n if (remaining <= length) return { node: root, offset: remaining <= length / 2 ? index : index + 1 };\n remaining -= length;\n continue;\n }\n if (child instanceof HTMLBRElement) {\n // A real BR consumes one canonical character, so its two DOM sides map\n // to distinct offsets. This matters for a leading empty line: offset 0\n // is before the BR, while offset 1 is after it. The zero-length trailing\n // sentinel exists only to give Chromium a caret box, so its valid side\n // remains after the element.\n if (length === 0) return { node: root, offset: index + 1 };\n if (remaining === 0) return { node: root, offset: index };\n if (remaining <= length) return { node: root, offset: index + 1 };\n remaining -= length;\n continue;\n }\n if (remaining <= length && child instanceof HTMLElement) {\n return domPositionForCanonicalOffset(child, remaining);\n }\n remaining -= length;\n }\n return { node: root, offset: root.childNodes.length };\n}\n\nfunction isChipHost(node: Node): node is HTMLElement {\n return node instanceof HTMLElement && Boolean(\n node.dataset.pluginName || node.dataset.fileMention || node.dataset.mentionValue || node.dataset.skillName,\n );\n}\n\nfunction setCaret(position: number, options: { focus?: boolean } = {}): void {\n setSelection(position, position, options);\n}\n\nfunction setSelection(start: number, end: number, options: { focus?: boolean } = {}): void {\n const element = editor.value;\n if (!element) return;\n const shouldUpdateDocumentSelection = options.focus !== false || document.activeElement === element;\n if (options.focus !== false) element.focus();\n const length = readText().length;\n const nextStart = Math.max(0, Math.min(start, length));\n const nextEnd = Math.max(nextStart, Math.min(end, length));\n if (shouldUpdateDocumentSelection) {\n const startTarget = domPositionForCanonicalOffset(element, nextStart);\n const endTarget = domPositionForCanonicalOffset(element, nextEnd);\n const range = document.createRange();\n range.setStart(startTarget.node, startTarget.offset);\n range.setEnd(endTarget.node, endTarget.offset);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n }\n caretPosition.value = nextEnd;\n emit('caret-change', { end: nextEnd, start: nextStart, valid: true });\n}\n\nfunction setText(value: string, caret = value.length, options: { focus?: boolean } = {}): void {\n emit('update:modelValue', value);\n renderText(value, caret, options);\n}\n\nfunction insertTextAtSelection(value: string): void {\n const selection = getSelectionRange();\n // Native editing records an undo transaction; replacing the DOM does not.\n if (typeof document.execCommand === 'function') {\n setSelection(selection.start, selection.end);\n const text = document.createElement('span');\n appendTextNode(text, value);\n if (value.endsWith('\\n') && selection.end === readText().length) {\n const placeholder = document.createElement('br');\n placeholder.dataset.trailingLineBreak = '';\n text.append(placeholder);\n }\n if (document.execCommand('insertHTML', false, text.innerHTML)) {\n setCaret(selection.start + value.length);\n scrollCaretIntoView(editor.value!);\n return;\n }\n }\n const current = readText();\n const next = `${current.slice(0, selection.start)}${value}${current.slice(selection.end)}`;\n const nextCaret = selection.start + value.length;\n emit('update:modelValue', next);\n renderText(next, nextCaret, { focus: true });\n}\n\nfunction focusEnd(): void {\n void nextTick(() => setCaret(readText().length));\n}\n\nfunction renderText(value: string, caret = caretPosition.value, options: { focus?: boolean } = {}): void {\n const element = editor.value;\n if (!element) return;\n const shouldFocus = options.focus ?? document.activeElement === element;\n const fragment = document.createDocumentFragment();\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n inlineTokenPattern.lastIndex = 0;\n while ((match = inlineTokenPattern.exec(value)) !== null) {\n if (match[1]) continue;\n const prefix = match[2]!;\n const trigger = match[3];\n const tokenText = match[4]!;\n const tokenStart = match.index + prefix.length;\n const tokenEnd = tokenStart + tokenText.length + 1;\n const mention = trigger === '$'\n ? findSkill(tokenText)\n : trigger === '@'\n ? findAtMention(tokenText)\n : undefined;\n if (!mention) continue;\n appendTextNode(fragment, value.slice(lastIndex, tokenStart));\n if (trigger === '$') {\n fragment.append(createSkillChip(tokenText, mention as CodexSkillSummary));\n } else {\n const atMention = mention as Exclude<ReturnType<typeof findAtMention>, undefined>;\n fragment.append(atMention.kind === 'plugin'\n ? createPluginChip(tokenText, atMention.value)\n : atMention.kind === 'file'\n ? createFileChip(tokenText, atMention.value)\n : createCustomMentionChip(tokenText, atMention.group, atMention.item));\n }\n lastIndex = tokenEnd;\n }\n appendTextNode(fragment, value.slice(lastIndex));\n if (value.endsWith('\\n')) {\n const trailingLineBreak = document.createElement('br');\n trailingLineBreak.dataset.trailingLineBreak = '';\n fragment.append(trailingLineBreak);\n }\n unmountChipHosts();\n element.replaceChildren(fragment);\n setCaret(Math.min(caret, value.length), { focus: shouldFocus });\n autoResize();\n scrollCaretIntoView(element);\n}\n\nfunction appendTextNode(parent: Node, value: string): void {\n const lines = value.split('\\n');\n lines.forEach((line, index) => {\n if (line) parent.appendChild(document.createTextNode(line));\n if (index < lines.length - 1) parent.appendChild(document.createElement('br'));\n });\n}\n\nfunction findPlugin(name: string): CodexSurfacePlugin | undefined {\n return props.plugins.find((plugin) => pluginMatchesMention(plugin, name));\n}\n\nfunction findAtMention(name: string):\n | { kind: 'plugin'; value: CodexSurfacePlugin }\n | { kind: 'file'; value: CodexFileSearchItem }\n | { kind: 'custom'; group: CodexComposerMentionGroup; item: CodexComposerMentionItem }\n | undefined {\n const leadingMention = findComposerMention(\n props.mentionGroups.filter((group) => group.placement !== 'after'),\n name,\n );\n if (leadingMention) return { kind: 'custom', ...leadingMention };\n const plugin = findPlugin(name);\n if (plugin) return { kind: 'plugin', value: plugin };\n const file = findFile(name);\n if (file) return { kind: 'file', value: file };\n // Non-after groups were already exhausted by the leading lookup above.\n const trailingMention = findComposerMention(\n props.mentionGroups,\n name,\n );\n return trailingMention ? { kind: 'custom', ...trailingMention } : undefined;\n}\n\nfunction findFile(path: string): CodexFileSearchItem | undefined {\n return props.files.find((file) => file.path === path || file.name === path);\n}\n\nfunction findSkill(name: string): CodexSkillSummary | undefined {\n return props.skills.find((skill) => skillMatchesMention(skill, name));\n}\n\nfunction createChip(dataset: Record<string, string>, properties: {\n iconUrl?: string;\n kind: 'file' | 'plugin' | 'skill';\n name: string;\n}): HTMLElement {\n const host = document.createElement('span');\n host.className = 'chat-rich-text-editor__chip-token-host';\n host.contentEditable = 'false';\n Object.assign(host.dataset, dataset);\n host.setAttribute('aria-label', properties.name);\n render(h(ChatMentionChip, properties), host);\n return host;\n}\n\nfunction createPluginChip(name: string, plugin: CodexSurfacePlugin): HTMLElement {\n return createChip({ pluginName: name }, {\n iconUrl: plugin.iconUrl,\n kind: 'plugin',\n name: plugin.displayName || plugin.name,\n });\n}\n\nfunction createFileChip(path: string, file: CodexFileSearchItem): HTMLElement {\n return createChip({ fileMention: path }, { kind: 'file', name: file.name });\n}\n\nfunction createSkillChip(name: string, skill: CodexSkillSummary): HTMLElement {\n return createChip({ skillName: name, skillTrigger: '$' }, {\n iconUrl: skill.iconSmall,\n kind: 'skill',\n name: skill.displayName || skill.name,\n });\n}\n\nfunction createCustomMentionChip(\n value: string,\n group: CodexComposerMentionGroup,\n item: CodexComposerMentionItem,\n): HTMLElement {\n const host = document.createElement('span');\n host.className = 'chat-rich-text-editor__chip-token-host';\n host.contentEditable = 'false';\n host.dataset.mentionGroup = group.id;\n host.dataset.mentionValue = value;\n host.setAttribute('aria-label', item.label);\n render(slots.mention\n ? h(Fragment, null, slots.mention({ group, item, surface: 'composer' }))\n : h(ChatMentionChip, { kind: 'plugin', name: item.label }), host);\n return host;\n}\n\nfunction unmountChipHosts(): void {\n // A parent update can remove this editor before its post-render ref is assigned.\n if (!editor.value) return;\n for (const chip of editor.value.querySelectorAll('.chat-rich-text-editor__chip-token-host')) {\n render(null, chip as HTMLElement);\n }\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineExpose<CodexRichTextEditorExpose>({\n autoResize,\n focusEnd,\n getSelectionRange,\n insertTextAtSelection,\n readText,\n setCaret,\n setSelection,\n setText,\n});\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-rich-text-editor {\n display: block;\n flex: 1 1 auto;\n min-width: 0;\n min-height: var(--chat-composer-line-height, var(--line-height-24));\n max-height: var(--chat-composer-input-max-height, 304px);\n padding: var(--space-4) 0;\n overflow-y: auto;\n scrollbar-width: none;\n border: 0;\n outline: 0;\n background: transparent;\n color: var(--color-text);\n font: inherit;\n font-size: var(--chat-composer-font-size, var(--font-size-15));\n line-height: var(--chat-composer-line-height, var(--line-height-24));\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n.chat-rich-text-editor::-webkit-scrollbar {\n display: none;\n}\n\n.chat-rich-text-editor:empty::before {\n color: var(--color-text-muted);\n content: attr(data-placeholder);\n pointer-events: none;\n}\n\n.chat-rich-text-editor[aria-disabled=\"true\"] {\n cursor: not-allowed;\n}\n\n.chat-rich-text-editor :deep(.chat-rich-text-editor__chip-token-host) {\n display: inline-block;\n max-width: 220px;\n margin: 0 var(--space-1);\n vertical-align: -2px;\n}\n</style>\n","export type ActiveComposerMention = {\n end: number;\n query: string;\n start: number;\n trigger: '@' | '$';\n};\n\nexport function findActivePluginMention(value: string, caretPosition: number): ActiveComposerMention | null {\n const safeCaret = Math.max(0, Math.min(caretPosition, value.length));\n const beforeCaret = value.slice(0, safeCaret);\n const atIndex = beforeCaret.lastIndexOf('@');\n const dollarIndex = beforeCaret.lastIndexOf('$');\n const start = Math.max(atIndex, dollarIndex);\n if (start < 0) return null;\n\n const previous = start > 0 ? beforeCaret[start - 1] : '';\n if (previous && /[\\w.%+-]/.test(previous)) return null;\n\n const query = beforeCaret.slice(start + 1);\n if (/[\\s@$/]/.test(query)) return null;\n\n return {\n end: safeCaret,\n query,\n start,\n trigger: beforeCaret[start] as '@' | '$',\n };\n}\n\nexport function findActiveFileMention(value: string, caretPosition: number): ActiveComposerMention | null {\n const safeCaret = Math.max(0, Math.min(caretPosition, value.length));\n const beforeCaret = value.slice(0, safeCaret);\n const start = beforeCaret.lastIndexOf('@');\n if (start < 0) {\n return null;\n }\n\n const previous = start > 0 ? beforeCaret[start - 1] : '';\n if (previous && /[\\w.%+-]/.test(previous)) {\n return null;\n }\n\n const query = beforeCaret.slice(start + 1);\n if (/[\\s@$/]/.test(query)) {\n return null;\n }\n\n return {\n end: safeCaret,\n query,\n start,\n trigger: '@',\n };\n}\n","import type { CodexFileSearchItem } from './contracts';\n\nexport const MAX_FILE_SEARCH_RESULTS = 50;\n\nexport function filterFileSearchItems<T extends CodexFileSearchItem>(\n files: T[],\n query: string,\n maxResults = MAX_FILE_SEARCH_RESULTS,\n): T[] {\n const value = query.trim().toLowerCase();\n if (!value) {\n return files.slice(0, maxResults);\n }\n\n return files\n .map((file) => ({\n file,\n score: Math.max(\n fuzzyScore(value, file.name.toLowerCase()),\n fuzzyScore(value, file.path.toLowerCase()),\n ),\n }))\n .filter((entry) => entry.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults)\n .map((entry) => entry.file);\n}\n\nexport function fuzzyScore(pattern: string, target: string): number {\n let score = 0;\n let patternIndex = 0;\n let lastMatch = -1;\n\n for (let index = 0; index < target.length && patternIndex < pattern.length; index += 1) {\n if (target[index] !== pattern[patternIndex]) {\n continue;\n }\n\n score += lastMatch === index - 1 ? 6 : 1;\n if (index === 0 || '/-_.'.includes(target[index - 1]!)) {\n score += 4;\n }\n lastMatch = index;\n patternIndex += 1;\n }\n\n return patternIndex === pattern.length ? score : 0;\n}\n","import { computed, ref, watch, type Ref } from 'vue'\nimport type {\n CodexFileSearchItem,\n CodexCommandSummary,\n CodexSkillSummary,\n} from './contracts'\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface'\nimport { findActiveFileMention, findActivePluginMention } from './composer-mentions'\nimport { filterFileSearchItems } from './file-search'\nimport { filterComposerCommands, findActiveCommandSlash } from './composer-commands'\nimport { filterComposerSkills, findActiveSkillTrigger, skillInsertText } from './composer-skills'\nimport { filterComposerPlugins } from './composer-plugins'\nimport {\n filterComposerMentionGroups,\n type CodexComposerMentionGroup,\n type CodexComposerMentionItem,\n} from './composer-mentions-custom'\n\ntype ChatComposerSuggestionOptions<Payload = unknown> = {\n caretPosition: Ref<number>\n commands: () => readonly CodexCommandSummary[]\n disabled: () => boolean\n files: () => readonly CodexFileSearchItem[]\n plugins?: () => readonly CodexSurfacePlugin[]\n mentionGroups?: () => readonly CodexComposerMentionGroup<Payload>[]\n onMentionSelected?: (\n item: CodexComposerMentionItem<Payload>,\n group: CodexComposerMentionGroup<Payload>,\n ) => void\n isSending: () => boolean\n onCommandActivated?: (command: CodexCommandSummary) => void\n onCommandSubmitted: (prompt: string) => void\n onTextInserted: (caretPosition: number) => void\n prompt: Ref<string>\n skills: () => readonly CodexSkillSummary[]\n skillsEnabled: () => boolean\n editor: Ref<{\n getSelectionRange: () => { end: number; start: number; valid: boolean }\n } | null>\n}\n\nexport function useChatComposerSuggestions<Payload = unknown>(options: ChatComposerSuggestionOptions<Payload>) {\n const openMenu = ref<'at' | 'skill' | 'slash' | null>(null)\n const activeFileIndex = ref(0)\n const activeSkillIndex = ref(0)\n const activePluginIndex = ref(0)\n const activeAtIndex = ref(0)\n const activeSlashIndex = ref(0)\n let dismissedSuggestionContext: string | null = null\n let suggestionsSuspended = false\n\n const activeFileMention = computed(() => findActiveFileMention(options.prompt.value, options.caretPosition.value))\n const visibleFiles = computed(() => {\n const mention = activeFileMention.value\n if (!mention?.query) {\n return []\n }\n return filterFileSearchItems([...options.files()], mention.query, 5)\n })\n const fileMenuShowsHint = computed(() => (\n activeFileMention.value !== null &&\n !activeFileMention.value.query &&\n options.files().length > 0\n ))\n const fileMenuVisible = computed(() => (\n openMenu.value === 'at' &&\n activeFileMention.value !== null &&\n options.files().length > 0 &&\n !inputDisabled()\n ))\n const activeSkillSlash = computed(() => findActiveSkillTrigger(options.prompt.value, options.caretPosition.value, '$'))\n const activePluginMention = computed(() => findActivePluginMention(options.prompt.value, options.caretPosition.value))\n const visibleSkills = computed(() => filterComposerSkills(\n [...options.skills()],\n activeSkillSlash.value?.query ?? '',\n -1,\n options.plugins?.() ?? [],\n ))\n const skillMenuVisible = computed(() => (\n openMenu.value === 'skill' &&\n options.skillsEnabled() &&\n activeSkillSlash.value !== null &&\n options.skills().length > 0 &&\n !inputDisabled()\n ))\n const visiblePlugins = computed(() => filterComposerPlugins([...(options.plugins?.() ?? [])], activePluginMention.value?.query ?? ''))\n const visibleMentionGroups = computed(() => filterComposerMentionGroups(\n options.mentionGroups?.() ?? [],\n activeFileMention.value?.query ?? '',\n ))\n const visibleLeadingMentionItems = computed(() => visibleMentionGroups.value\n .filter((group) => group.placement !== 'after')\n .flatMap((group) => group.items.map((item) => ({ group, item }))))\n const visibleTrailingMentionItems = computed(() => visibleMentionGroups.value\n .filter((group) => group.placement === 'after')\n .flatMap((group) => group.items.map((item) => ({ group, item }))))\n const pluginMenuVisible = computed(() => false)\n const atItemCount = computed(() => (\n visibleLeadingMentionItems.value.length\n + visiblePlugins.value.length\n + visibleFiles.value.length\n + visibleTrailingMentionItems.value.length\n ))\n const atMenuVisible = computed(() => (\n openMenu.value === 'at' &&\n activeFileMention.value !== null &&\n (atItemCount.value > 0 || fileMenuShowsHint.value) &&\n !inputDisabled()\n ))\n const activeCommandSlash = computed(() => findActiveCommandSlash(options.prompt.value, options.caretPosition.value))\n const visibleSlashCommands = computed(() => filterComposerCommands([...options.commands()], activeCommandSlash.value?.query ?? ''))\n const visibleSlashSkills = computed(() => options.skillsEnabled()\n ? []\n : [])\n const slashItemCount = computed(() => visibleSlashCommands.value.length + visibleSlashSkills.value.length)\n const slashMenuVisible = computed(() => (\n openMenu.value === 'slash' &&\n activeCommandSlash.value !== null &&\n slashItemCount.value > 0 &&\n !inputDisabled()\n ))\n\n watch([visibleSkills, activeSkillSlash], () => {\n activeSkillIndex.value = 0\n })\n watch([visiblePlugins, activePluginMention], () => {\n activePluginIndex.value = 0\n activeAtIndex.value = 0\n })\n watch(visibleMentionGroups, () => {\n activeAtIndex.value = 0\n })\n watch([visibleSlashCommands, visibleSlashSkills, activeCommandSlash], () => {\n activeSlashIndex.value = 0\n })\n watch([visibleFiles, activeFileMention], () => {\n activeFileIndex.value = 0\n })\n\n function handleKeydown(event: KeyboardEvent): boolean {\n if (handleMenuKeydown(event, atMenuVisible.value, atItemCount.value, activeAtIndex, () => {\n const leading = visibleLeadingMentionItems.value[activeAtIndex.value]\n if (leading) {\n selectMention(leading.item, leading.group)\n return\n }\n const builtInIndex = activeAtIndex.value - visibleLeadingMentionItems.value.length\n const plugin = visiblePlugins.value[builtInIndex]\n if (plugin) selectPlugin(plugin)\n else {\n const file = visibleFiles.value[builtInIndex - visiblePlugins.value.length]\n if (file) {\n selectFile(file)\n return\n }\n const trailing = visibleTrailingMentionItems.value[\n builtInIndex - visiblePlugins.value.length - visibleFiles.value.length\n ]\n if (trailing) selectMention(trailing.item, trailing.group)\n }\n })) {\n return true\n }\n\n if (handleMenuKeydown(event, skillMenuVisible.value, visibleSkills.value.length, activeSkillIndex, () => {\n const skill = visibleSkills.value[activeSkillIndex.value]\n if (skill) selectSkill(skill)\n })) {\n return true\n }\n\n if (slashMenuVisible.value && slashItemCount.value > 0 && event.key === 'Tab'\n && !event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey) {\n event.preventDefault()\n selectActiveSlashItem('complete')\n return true\n }\n\n if (handleMenuKeydown(event, slashMenuVisible.value, slashItemCount.value, activeSlashIndex,\n () => selectActiveSlashItem('execute'))) {\n return true\n }\n\n return false\n }\n\n function handleMenuKeydown(\n event: KeyboardEvent,\n visible: boolean,\n itemCount: number,\n activeIndex: Ref<number>,\n selectActive: () => void,\n ): boolean {\n if (!visible) {\n return false\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n if (itemCount > 0) {\n activeIndex.value = (activeIndex.value + (event.key === 'ArrowDown' ? 1 : -1) + itemCount) % itemCount\n }\n return true\n }\n if (event.key === 'Escape') {\n event.preventDefault()\n dismissedSuggestionContext = suggestionContext()\n close()\n return true\n }\n if (event.key === 'Enter' && !event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey && itemCount > 0) {\n event.preventDefault()\n selectActive()\n return true\n }\n return false\n }\n\n function selectFile(file: CodexFileSearchItem): void {\n const mention = activeFileMention.value\n if (!mention || !options.editor.value) {\n return\n }\n insert(`@${file.path} `, mention.start, mention.end)\n }\n\n function selectSkill(skill: CodexSkillSummary): void {\n const mention = activeSkillSlash.value\n if (mention) {\n insert(`$${skillInsertText(skill)} `, mention.start, mention.end)\n }\n }\n\n function selectPlugin(plugin: CodexSurfacePlugin): void {\n const mention = activePluginMention.value\n if (mention) {\n insert(`@${plugin.name || plugin.id} `, mention.start, mention.end)\n }\n }\n\n function selectMention(\n item: CodexComposerMentionItem<Payload>,\n group: CodexComposerMentionGroup<Payload>,\n ): void {\n const mention = activeFileMention.value\n if (!mention) return\n insert(`@${item.value} `, mention.start, mention.end)\n const catalogGroup = options.mentionGroups?.().find((candidate) => candidate.id === group.id) ?? group\n options.onMentionSelected?.(item, catalogGroup)\n }\n\n function selectSlashSkill(skill: CodexSkillSummary): void {\n const mention = activeCommandSlash.value\n if (mention) {\n insert(`/${skillInsertText(skill)} `, mention.start, mention.end)\n }\n }\n\n function selectCommand(command: CodexCommandSummary): void {\n handleCommand(command, 'default')\n }\n\n function handleCommand(command: CodexCommandSummary, action: 'default' | 'execute' | 'complete'): void {\n const mention = activeCommandSlash.value\n if (!mention || !options.editor.value) {\n return\n }\n\n const slashCommand = `/${command.slashName ?? command.name}`\n if (command.composerMode) {\n options.prompt.value = `${options.prompt.value.slice(0, mention.start)}${options.prompt.value.slice(mention.end)}`\n options.caretPosition.value = mention.start\n close()\n options.onCommandActivated?.(command)\n options.onTextInserted(mention.start)\n return\n }\n if (action === 'execute' || (action === 'default' && command.submitOnSelect)) {\n options.prompt.value = ''\n options.caretPosition.value = 0\n close()\n options.onCommandSubmitted(slashCommand)\n return\n }\n insert(`${slashCommand} `, mention.start, mention.end)\n }\n\n function selectActiveSlashItem(action: 'execute' | 'complete'): void {\n const command = visibleSlashCommands.value[activeSlashIndex.value]\n if (command) {\n handleCommand(command, action)\n return\n }\n const skill = visibleSlashSkills.value[activeSlashIndex.value - visibleSlashCommands.value.length]\n if (skill) {\n selectSlashSkill(skill)\n }\n }\n\n function insert(value: string, start: number, end: number): void {\n options.prompt.value = `${options.prompt.value.slice(0, start)}${value}${options.prompt.value.slice(end)}`\n const nextCaret = start + value.length\n options.caretPosition.value = nextCaret\n close()\n options.onTextInserted(nextCaret)\n }\n\n function updateCaretPosition(range?: { end: number }): void {\n options.caretPosition.value = range?.end\n ?? options.editor.value?.getSelectionRange().end\n ?? options.prompt.value.length\n sync()\n }\n\n function closeSoon(): void {\n window.setTimeout(close, 120)\n }\n\n function close(): void {\n openMenu.value = null\n }\n\n function suspend(): void {\n suggestionsSuspended = true\n close()\n }\n\n function resume(): void {\n suggestionsSuspended = false\n }\n\n function sync(): void {\n if (suggestionsSuspended) {\n close()\n return\n }\n const context = suggestionContext()\n if (dismissedSuggestionContext !== null) {\n if (context === dismissedSuggestionContext) {\n close()\n return\n }\n dismissedSuggestionContext = null\n }\n if (activeFileMention.value !== null) {\n openMenu.value = 'at'\n return\n }\n if (activeSkillSlash.value !== null) {\n openMenu.value = 'skill'\n return\n }\n if (activeCommandSlash.value !== null) {\n openMenu.value = 'slash'\n return\n }\n close()\n }\n\n function suggestionContext(): string {\n return `${options.prompt.value}\\u0000${options.caretPosition.value}`\n }\n\n function inputDisabled(): boolean {\n return options.disabled() && !options.isSending()\n }\n\n return {\n activeAtIndex,\n activeFileIndex,\n activeSkillIndex,\n activePluginIndex,\n activeSlashIndex,\n atMenuVisible,\n close,\n closeSoon,\n resume,\n fileMenuShowsHint,\n fileMenuVisible,\n handleKeydown,\n selectCommand,\n selectFile,\n selectSkill,\n selectPlugin,\n selectMention,\n selectSlashSkill,\n skillMenuVisible,\n pluginMenuVisible,\n slashMenuVisible,\n suspend,\n sync,\n updateCaretPosition,\n visibleFiles,\n visibleSkills,\n visiblePlugins,\n visibleMentionGroups,\n visibleSlashCommands,\n visibleSlashSkills,\n }\n}\n","export type RecordedAudio = {\n blob: Blob;\n durationMs: number;\n};\n\ntype AudioContextConstructor = typeof AudioContext;\n\nexport function isBrowserAudioRecordingSupported(): boolean {\n return Boolean(\n typeof navigator.mediaDevices?.getUserMedia === 'function' &&\n typeof MediaRecorder !== 'undefined' &&\n resolveAudioContextConstructor() &&\n (MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ||\n MediaRecorder.isTypeSupported('audio/webm') ||\n MediaRecorder.isTypeSupported('audio/mp4')),\n );\n}\n\nexport class BrowserAudioRecorder {\n private chunks: Blob[] = [];\n private mediaRecorder: MediaRecorder | null = null;\n private startTime = 0;\n private stream: MediaStream | null = null;\n private analyser: AnalyserNode | null = null;\n private audioContext: AudioContext | null = null;\n private bufferLength = 0;\n private microphone: MediaStreamAudioSourceNode | null = null;\n\n async start(): Promise<void> {\n this.release();\n this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n this.chunks = [];\n this.startTime = Date.now();\n const AudioContextCtor = resolveAudioContextConstructor();\n if (!AudioContextCtor) {\n throw new Error('Audio recording is not supported in this browser.');\n }\n\n this.audioContext = new AudioContextCtor();\n await this.audioContext.resume();\n this.microphone = this.audioContext.createMediaStreamSource(this.stream);\n this.analyser = this.audioContext.createAnalyser();\n this.analyser.fftSize = 256;\n this.bufferLength = this.analyser.frequencyBinCount;\n this.microphone.connect(this.analyser);\n this.mediaRecorder = new MediaRecorder(this.stream, preferredMediaRecorderOptions());\n this.mediaRecorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n this.chunks.push(event.data);\n }\n };\n this.mediaRecorder.start();\n }\n\n getAnalyser(): AnalyserNode | null {\n return this.analyser;\n }\n\n getBufferLength(): number {\n return this.bufferLength;\n }\n\n stop(): Promise<RecordedAudio> {\n const recorder = this.mediaRecorder;\n if (!recorder || recorder.state === 'inactive') {\n return Promise.reject(new Error('No active audio recording.'));\n }\n\n return new Promise((resolve, reject) => {\n recorder.onerror = () => {\n this.release();\n reject(new Error('Audio recording failed.'));\n };\n recorder.onstop = () => {\n const durationMs = Date.now() - this.startTime;\n const blob = new Blob(this.chunks, { type: recorder.mimeType || 'audio/webm' });\n this.release();\n resolve({ blob, durationMs });\n };\n recorder.stop();\n });\n }\n\n release(): void {\n if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {\n this.mediaRecorder.stop();\n }\n this.stream?.getTracks().forEach((track) => {\n track.stop();\n });\n this.microphone?.disconnect();\n this.analyser?.disconnect();\n void this.audioContext?.close();\n this.stream = null;\n this.mediaRecorder = null;\n this.microphone = null;\n this.analyser = null;\n this.audioContext = null;\n this.bufferLength = 0;\n this.chunks = [];\n this.startTime = 0;\n }\n}\n\nfunction preferredMediaRecorderOptions(): MediaRecorderOptions {\n if (MediaRecorder.isTypeSupported('audio/webm;codecs=opus')) {\n return { mimeType: 'audio/webm;codecs=opus' };\n }\n\n if (MediaRecorder.isTypeSupported('audio/webm')) {\n return { mimeType: 'audio/webm' };\n }\n\n if (MediaRecorder.isTypeSupported('audio/mp4')) {\n return { mimeType: 'audio/mp4' };\n }\n\n return {};\n}\n\nfunction resolveAudioContextConstructor(): AudioContextConstructor | null {\n return window.AudioContext ?? ((window as unknown as {\n webkitAudioContext?: AudioContextConstructor;\n }).webkitAudioContext ?? null);\n}\n","import fixWebmDuration from 'fix-webm-duration';\nimport type { CodexSpeechTranscriptionResult } from '../chat/contracts';\nimport type { RecordedAudio } from './browser-audio-recorder';\n\nexport type AppleSpeechTranscriptionApi = {\n transcribeAppleSpeech(audioData: ArrayBuffer, options?: { locale?: string }): Promise<CodexSpeechTranscriptionResult>;\n};\n\ntype WebmDurationFixer = (blob: Blob, durationMs: number) => Promise<Blob>;\n\nexport async function transcribeRecordedAudio(\n recording: RecordedAudio,\n api: AppleSpeechTranscriptionApi | undefined,\n): Promise<CodexSpeechTranscriptionResult> {\n if (!api?.transcribeAppleSpeech) {\n throw new Error('Apple speech transcription is not available.');\n }\n\n const audioData = await prepareAppleSpeechAudio(recording);\n return api.transcribeAppleSpeech(audioData, {\n locale: navigator.language,\n });\n}\n\nexport async function prepareAppleSpeechAudio(\n recording: RecordedAudio,\n fixDuration: WebmDurationFixer = fixWebmDuration,\n): Promise<ArrayBuffer> {\n const source = await normalizeWebmDuration(recording, fixDuration);\n const wavBlob = source.type.includes('webm')\n ? await convertWebmToWav(source)\n : source;\n\n return wavBlob.arrayBuffer();\n}\n\nasync function convertWebmToWav(source: Blob): Promise<Blob> {\n const AudioContextConstructor = resolveAudioContextConstructor();\n if (!AudioContextConstructor) {\n throw new Error('WebM audio conversion is not supported in this browser.');\n }\n\n const audioContext = new AudioContextConstructor();\n try {\n const audioBuffer = await audioContext.decodeAudioData(await source.arrayBuffer());\n return encodePcm16Wav(audioBuffer);\n } finally {\n await audioContext.close();\n }\n}\n\nfunction encodePcm16Wav(audioBuffer: AudioBuffer): Blob {\n const bytesPerSample = 2;\n const channelCount = audioBuffer.numberOfChannels;\n const dataSize = audioBuffer.length * channelCount * bytesPerSample;\n const output = new ArrayBuffer(44 + dataSize);\n const view = new DataView(output);\n\n writeAscii(view, 0, 'RIFF');\n view.setUint32(4, 36 + dataSize, true);\n writeAscii(view, 8, 'WAVE');\n writeAscii(view, 12, 'fmt ');\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, channelCount, true);\n view.setUint32(24, audioBuffer.sampleRate, true);\n view.setUint32(28, audioBuffer.sampleRate * channelCount * bytesPerSample, true);\n view.setUint16(32, channelCount * bytesPerSample, true);\n view.setUint16(34, bytesPerSample * 8, true);\n writeAscii(view, 36, 'data');\n view.setUint32(40, dataSize, true);\n\n const channels = Array.from(\n { length: channelCount },\n (_, channel) => audioBuffer.getChannelData(channel),\n );\n let offset = 44;\n for (let frame = 0; frame < audioBuffer.length; frame += 1) {\n for (const channel of channels) {\n const sample = Math.max(-1, Math.min(1, channel[frame] ?? 0));\n view.setInt16(offset, sample < 0 ? sample * 0x8000 : sample * 0x7fff, true);\n offset += bytesPerSample;\n }\n }\n\n return new Blob([output], { type: 'audio/wav' });\n}\n\nfunction writeAscii(view: DataView, offset: number, value: string): void {\n for (let index = 0; index < value.length; index += 1) {\n view.setUint8(offset + index, value.charCodeAt(index));\n }\n}\n\nfunction resolveAudioContextConstructor(): typeof AudioContext | undefined {\n if (typeof AudioContext !== 'undefined') return AudioContext;\n if (typeof window === 'undefined') return undefined;\n return (window as Window & { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n}\n\nasync function normalizeWebmDuration(recording: RecordedAudio, fixDuration: WebmDurationFixer): Promise<Blob> {\n if (!recording.blob.type.includes('webm')) {\n return recording.blob;\n }\n\n const fixedBlob = await fixDuration(recording.blob, recording.durationMs);\n if (fixedBlob.type === recording.blob.type) {\n return fixedBlob;\n }\n\n return new Blob([fixedBlob], { type: recording.blob.type });\n}\n","import type {\n CodexHostCapabilities,\n CodexHostAttachment,\n CodexHostAttachmentInput,\n CodexNativeRendererApi,\n} from '@codex-app-sdk/core/native';\nimport {\n hasInjectionContext,\n inject,\n provide,\n type InjectionKey,\n} from 'vue';\n\ntype CodexNativeWindow = Window & {\n codexAppSdkNative?: CodexNativeRendererApi;\n};\n\nconst hostCapabilitiesKey: InjectionKey<CodexHostCapabilities | undefined> = Symbol(\n 'codex-app-sdk-host-capabilities',\n);\n\nexport type CodexAttachmentPicker = () => Promise<CodexHostAttachment[]>;\nexport type CodexAttachmentIngester = (\n files: readonly CodexHostAttachmentInput[],\n) => Promise<CodexHostAttachment[]>;\n\nexport function provideCodexHostCapabilities(\n capabilities: CodexHostCapabilities | undefined,\n): CodexHostCapabilities | undefined {\n provide(hostCapabilitiesKey, capabilities);\n return capabilities;\n}\n\nexport function useCodexHostCapabilities(): CodexHostCapabilities | undefined {\n const fallback = getCodexGlobalHostCapabilities();\n return hasInjectionContext() ? inject(hostCapabilitiesKey, fallback) : fallback;\n}\n\nexport function getCodexGlobalHostCapabilities(): CodexHostCapabilities | undefined {\n if (typeof window === 'undefined') return undefined;\n return (window as CodexNativeWindow).codexAppSdkNative;\n}\n\n/** @deprecated Use `getCodexGlobalHostCapabilities` or the scoped provider. */\nexport function getCodexNativeRendererApi(): CodexNativeRendererApi | undefined {\n return getCodexGlobalHostCapabilities();\n}\n\nexport async function pickCodexAttachments(\n override?: CodexAttachmentPicker,\n capabilities: CodexHostCapabilities | undefined = getCodexGlobalHostCapabilities(),\n): Promise<CodexHostAttachment[]> {\n const pick = override ?? capabilities?.pickAttachments;\n return pick ? pick() : [];\n}\n\nexport async function ingestCodexAttachments(\n files: readonly File[],\n override?: CodexAttachmentIngester,\n capabilities: CodexHostCapabilities | undefined = getCodexGlobalHostCapabilities(),\n): Promise<CodexHostAttachment[]> {\n if (files.length === 0) return [];\n const ingest = override ?? capabilities?.ingestAttachments;\n if (!ingest) return [];\n\n const inputs = await Promise.all(files.map(async (file) => ({\n name: file.name,\n ...(file.type ? { mimeType: file.type } : {}),\n data: await file.arrayBuffer(),\n })));\n return ingest(inputs);\n}\n","import { computed, getCurrentScope, onScopeDispose, ref, type ComputedRef, type Ref } from 'vue'\nimport type { CodexSpeechTranscriptionResult, CodexChatTranscription } from './contracts'\nimport {\n BrowserAudioRecorder,\n isBrowserAudioRecordingSupported,\n type RecordedAudio,\n} from '../audio/browser-audio-recorder'\nimport { transcribeRecordedAudio } from '../audio/apple-speech-transcription'\nimport { useCodexHostCapabilities } from '../native-capabilities'\n\nexport type CodexComposerVoiceOptions = {\n isDisabled: () => boolean\n isSending: () => boolean\n onTranscript: (text: string) => void | Promise<void>\n transcribeAudio?: CodexChatTranscription\n}\n\nexport type CodexComposerVoiceRecorder = {\n getAnalyser(): AnalyserNode | null\n getBufferLength(): number\n}\n\nexport type CodexComposerVoiceController = {\n buttonDisabled: ComputedRef<boolean>\n buttonLabel: ComputedRef<string>\n buttonTitle: ComputedRef<string>\n error: Ref<string | null>\n isRecording: Ref<boolean>\n isTranscribing: Ref<boolean>\n recorder: ComputedRef<CodexComposerVoiceRecorder | null>\n stop: () => Promise<boolean>\n toggle: () => Promise<void>\n dispose: () => void\n}\n\ntype ChatComposerVoiceDependencies = {\n canTranscribe: () => boolean\n createRecorder: () => BrowserAudioRecorder\n isRecordingSupported: () => boolean\n transcribe: (recording: RecordedAudio) => Promise<CodexSpeechTranscriptionResult>\n}\n\nexport function useChatComposerVoice(\n options: CodexComposerVoiceOptions,\n dependencyOverrides: Partial<ChatComposerVoiceDependencies> = {},\n) {\n const hostCapabilities = useCodexHostCapabilities()\n const defaultDependencies: ChatComposerVoiceDependencies = {\n canTranscribe: () => hostCapabilities?.capabilities.transcription === true,\n createRecorder: () => new BrowserAudioRecorder(),\n isRecordingSupported: isBrowserAudioRecordingSupported,\n transcribe: (recording) => transcribeRecordedAudio(recording, {\n transcribeAppleSpeech: async (audioData, transcriptionOptions) => {\n if (!hostCapabilities) return { error: 'Speech transcription is not available.', text: '' }\n return hostCapabilities.transcribeAudio(audioData, transcriptionOptions)\n },\n }),\n }\n const providedTranscription = options.transcribeAudio\n ? {\n canTranscribe: () => true,\n transcribe: (recording: RecordedAudio) => transcribeRecordedAudio(recording, {\n transcribeAppleSpeech: options.transcribeAudio as CodexChatTranscription,\n }),\n }\n : {}\n const dependencies = { ...defaultDependencies, ...providedTranscription, ...dependencyOverrides }\n const recorder = ref<BrowserAudioRecorder | null>(null)\n const isRecording = ref(false)\n const isTranscribing = ref(false)\n const error = ref<string | null>(null)\n const exposedRecorder = computed<CodexComposerVoiceRecorder | null>(() => recorder.value)\n const recordingSupported = computed(() => dependencies.isRecordingSupported())\n const transcriptionAvailable = computed(() => dependencies.canTranscribe())\n const buttonDisabled = computed(() => (\n isTranscribing.value ||\n (options.isDisabled() && !options.isSending()) ||\n !recordingSupported.value ||\n !transcriptionAvailable.value\n ))\n const buttonLabel = computed(() => isRecording.value ? 'Stop recording' : 'Record voice prompt')\n const buttonTitle = computed(() => {\n if (error.value) {\n return error.value\n }\n if (!recordingSupported.value) {\n return 'Audio recording is not available.'\n }\n if (!transcriptionAvailable.value) {\n return 'Speech transcription is not available.'\n }\n if (isTranscribing.value) {\n return 'Transcribing...'\n }\n return buttonLabel.value\n })\n\n async function toggle(): Promise<void> {\n error.value = null\n if (isRecording.value) {\n await stop()\n return\n }\n await start()\n }\n\n async function start(): Promise<void> {\n if (buttonDisabled.value) {\n return\n }\n\n const nextRecorder = dependencies.createRecorder()\n try {\n await nextRecorder.start()\n recorder.value = nextRecorder\n isRecording.value = true\n } catch (startError) {\n nextRecorder.release()\n error.value = errorMessage(startError)\n }\n }\n\n async function stop(): Promise<boolean> {\n const activeRecorder = recorder.value\n if (!activeRecorder) {\n return false\n }\n\n isRecording.value = false\n isTranscribing.value = true\n recorder.value = null\n\n try {\n const recording = await activeRecorder.stop()\n const result = await dependencies.transcribe(recording)\n if (result.error) {\n error.value = result.error\n return false\n }\n await options.onTranscript(result.text)\n return true\n } catch (stopError) {\n error.value = errorMessage(stopError)\n return false\n } finally {\n isTranscribing.value = false\n }\n }\n\n function dispose(): void {\n recorder.value?.release()\n recorder.value = null\n isRecording.value = false\n }\n\n if (getCurrentScope()) {\n onScopeDispose(dispose)\n }\n\n return {\n buttonDisabled,\n buttonLabel,\n buttonTitle,\n error,\n isRecording,\n isTranscribing,\n recorder: exposedRecorder,\n stop,\n toggle,\n dispose,\n }\n}\n\n/**\n * Public voice controller for composing the SDK's voice button and waveform\n * without depending on the full CodexComposer component.\n */\nexport function useCodexComposerVoice(\n options: CodexComposerVoiceOptions,\n): CodexComposerVoiceController {\n return useChatComposerVoice(options)\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","export type CodexComposerState = {\n text: string;\n selectionStart: number;\n selectionEnd: number;\n activeCommandId?: string | null;\n};\n\nexport function normalizeCodexComposerState(state: CodexComposerState): CodexComposerState {\n const length = state.text.length;\n const selectionStart = Math.max(0, Math.min(state.selectionStart, length));\n const selectionEnd = Math.max(selectionStart, Math.min(state.selectionEnd, length));\n return {\n text: state.text,\n selectionStart,\n selectionEnd,\n ...(state.activeCommandId ? { activeCommandId: state.activeCommandId } : {}),\n };\n}\n","<template>\n <form\n class=\"codex-chat-theme chat-composer\"\n :class=\"{ 'chat-composer--disabled': disabled && !isSending }\"\n aria-label=\"Prompt composer\"\n @submit.prevent=\"submitPrompt\"\n >\n <slot name=\"before\" />\n <ChatComposerAtMentionMenu\n v-if=\"atMenuVisible\"\n :active-index=\"activeAtIndex\"\n :show-file-hint=\"fileMenuShowsHint\"\n :mention-groups=\"visibleMentionGroups\"\n :visible-files=\"visibleFiles\"\n :visible-plugins=\"visiblePlugins\"\n @select-file=\"selectFile\"\n @select-plugin=\"selectPlugin\"\n @select-mention=\"selectMention\"\n >\n <template v-if=\"$slots['suggestion-item']\" #mention=\"scope\">\n <slot name=\"suggestion-item\" v-bind=\"scope\" surface=\"menu\" />\n </template>\n </ChatComposerAtMentionMenu>\n\n <ChatComposerSkillMenu\n v-if=\"skillMenuVisible\"\n :active-index=\"activeSkillIndex\"\n :plugins=\"plugins\"\n :visible-skills=\"visibleSkills\"\n @select=\"selectSkill\"\n />\n\n <ChatComposerSlashMenu\n v-if=\"slashMenuVisible\"\n :active-index=\"activeSlashIndex\"\n :visible-commands=\"visibleSlashCommands\"\n :visible-skills=\"visibleSlashSkills\"\n @select-command=\"selectCommand\"\n @select-skill=\"selectSlashSkill\"\n />\n\n <div class=\"chat-composer__input-row\">\n <ChatComposerVoiceField\n v-if=\"voiceVisible && (isRecording || isTranscribing)\"\n :recorder=\"recorder\"\n :recording=\"isRecording\"\n />\n <ChatRichTextEditor\n v-else\n ref=\"editorEl\"\n v-model=\"prompt\"\n class=\"chat-composer__input\"\n :placeholder=\"effectivePlaceholder\"\n :disabled=\"disabled && !isSending\"\n :files=\"files\"\n :mention-groups=\"mentionGroups\"\n :plugins=\"plugins\"\n :skills=\"skills\"\n @blur=\"closeComposerMenusSoon\"\n @click=\"updateCaretPosition\"\n @caret-change=\"handleCaretChange\"\n @input=\"handleEditorInput\"\n @keydown=\"handleEditorKeydown\"\n @keyup=\"updateCaretPosition\"\n @paste=\"handleEditorPaste\"\n >\n <template v-if=\"$slots.mention\" #mention=\"scope\">\n <slot name=\"mention\" v-bind=\"scope\" surface=\"composer\" />\n </template>\n </ChatRichTextEditor>\n <slot name=\"after-input\" />\n </div>\n\n <div class=\"chat-composer__meta\">\n <div class=\"chat-composer__meta-leading\">\n <ChatComposerActionMenu\n v-if=\"effectivePresentation.composer.actionMenu\"\n :attach-enabled=\"attachEnabled\"\n :disabled=\"disabled\"\n :leading-menu-items=\"leadingMenuItems\"\n :items=\"menuItems\"\n :approval-preset=\"approvalPreset\"\n :approval-presets=\"effectiveCodexCapabilities.approvalPresets ?? []\"\n :goal-mode=\"goalMode\"\n :plan-mode=\"effectivePlanMode\"\n :show-approval-menu=\"effectiveCodexCapabilities.approvals && Boolean(approvalPreset) && (effectiveCodexCapabilities.approvalPresets?.length ?? 0) > 0\"\n :show-goal-mode=\"effectiveCodexCapabilities.goals && Boolean(goalCommand)\"\n :show-plan-mode=\"effectiveCodexCapabilities.planMode\"\n @attach=\"$emit('attach')\"\n @select=\"$emit('menuSelect', $event)\"\n @select-approval-preset=\"$emit('selectApprovalPreset', $event)\"\n @update:goal-mode=\"updateGoalMode\"\n @update:plan-mode=\"updatePlanMode\"\n >\n <template v-if=\"$slots['menu-icon']\" #icon=\"scope\"><slot name=\"menu-icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['menu-item']\" #item=\"scope\"><slot name=\"menu-item\" v-bind=\"scope\" /></template>\n </ChatComposerActionMenu>\n <slot name=\"before-meta\" />\n <ChatComposerActiveModes\n :plan-mode=\"effectivePlanMode\"\n :command=\"activeCommand\"\n @disable-plan-mode=\"updatePlanMode(false)\"\n @remove-command=\"removeActiveCommand\"\n />\n </div>\n <div class=\"chat-composer__meta-trailing\">\n <ChatContextUsageIndicator\n v-if=\"effectivePresentation.composer.contextUsage\"\n :context-usage=\"contextUsage\"\n />\n <ChatModelReasoningSelector\n v-if=\"effectiveCodexCapabilities.models\"\n :disabled=\"disabled\"\n :models=\"models\"\n :model-catalog-status=\"modelCatalogStatus\"\n :model-id=\"selectedModelId\"\n :menu-items=\"modelMenuItems\"\n :reasoning-effort=\"selectedReasoningEffort\"\n :service-tier=\"selectedServiceTier\"\n :show-service-tier=\"effectiveCodexCapabilities.serviceTier\"\n :show-reasoning=\"effectiveCodexCapabilities.reasoningEffort\"\n @update:model-id=\"$emit('update:modelId', $event)\"\n @menu-select=\"$emit('menuSelect', $event)\"\n @update:reasoning-effort=\"$emit('update:reasoningEffort', $event)\"\n @update:service-tier=\"$emit('update:serviceTier', $event)\"\n />\n <ChatComposerVoiceButton\n v-if=\"voiceVisible\"\n :disabled=\"voiceButtonDisabled\"\n :label=\"voiceButtonLabel\"\n :recording=\"isRecording\"\n :title=\"voiceButtonTitle\"\n @toggle=\"toggleRecording\"\n />\n <CodexComposerSendButton\n class=\"chat-composer__send\"\n :disabled=\"sendButtonDisabled\"\n :hover-to-enable=\"canSubmitEmptyPrompt\"\n :busy=\"sendButtonLoading\"\n :interrupt-armed=\"interruptArmed\"\n :submit-label=\"sendButtonLabel\"\n interrupt-label=\"Codex is working\"\n @click=\"handleSendButtonClick\"\n />\n <slot name=\"after\" />\n </div>\n </div>\n </form>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed, nextTick, onMounted, ref, watch } from 'vue';\nimport type { CodexContextUsage, CodexFileSearchItem, ApprovalPreset, CodexCapabilities, CodexCommandSummary, CodexModelOption, CodexSkillSummary, CodexChatTranscription, CodexConversationPresentation, ReasoningEffort } from '../chat/contracts';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport { resolveCodexConversationPresentation } from '../chat/contracts';\nimport { codexCapabilities } from '../chat/codex-capabilities';\nimport { codexCommands } from '../chat/codex-commands';\nimport { createComposerPromptHistory } from '../chat/composer-prompt-history';\nimport CodexComposerSendButton from './CodexComposerSendButton.vue';\nimport ChatComposerActiveModes from '../chat/ChatComposerActiveModes.vue';\nimport ChatComposerActionMenu from '../chat/ChatComposerActionMenu.vue';\nimport ChatComposerVoiceButton from '../chat/ChatComposerVoiceButton.vue';\nimport ChatComposerVoiceField from '../chat/ChatComposerVoiceField.vue';\nimport ChatContextUsageIndicator from '../chat/ChatContextUsageIndicator.vue';\nimport ChatModelReasoningSelector from '../chat/ChatModelReasoningSelector.vue';\nimport ChatComposerAtMentionMenu from '../chat/ChatComposerAtMentionMenu.vue';\nimport ChatComposerSkillMenu from '../chat/ChatComposerSkillMenu.vue';\nimport ChatComposerSlashMenu from '../chat/ChatComposerSlashMenu.vue';\nimport ChatRichTextEditor, { type CodexRichTextEditorExpose } from '../chat/ChatRichTextEditor.vue';\nimport { useChatComposerSuggestions } from '../chat/use-chat-composer-suggestions';\nimport { useChatComposerVoice } from '../chat/use-chat-composer-voice';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport { useCodexHostCapabilities } from '../native-capabilities';\nimport type { CodexComposerState } from '../composer-state';\nimport { normalizeCodexComposerState } from '../composer-state';\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from '../chat/composer-mentions-custom';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n autofocus?: boolean;\n attachEnabled?: boolean;\n canContinueInterruptedTurn?: boolean;\n contextUsage?: CodexContextUsage | null;\n disabled: boolean;\n draft?: string;\n draftRevision?: number;\n emptySendPrompt?: string;\n files?: readonly CodexFileSearchItem[];\n hasAttachments?: boolean;\n hasExternalContent?: boolean;\n plugins?: readonly CodexSurfacePlugin[];\n promptHistory?: readonly string[];\n promptHistoryLoading?: boolean;\n capabilities?: CodexCapabilities;\n commands?: readonly CodexCommandSummary[];\n composerState?: CodexComposerState;\n isSending: boolean;\n interruptArmed?: boolean;\n leadingMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n menuItems?: readonly CodexComposerMenuItem<Payload>[];\n mentionGroups?: readonly CodexComposerMentionGroup<Payload>[];\n modelCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n models?: readonly CodexModelOption[];\n modelMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n placeholder: string;\n queuedPromptId?: string | null;\n approvalPreset?: ApprovalPreset | null;\n planMode?: boolean;\n presentation?: CodexConversationPresentation;\n selectedModelId?: string | null;\n selectedReasoningEffort?: ReasoningEffort | null;\n selectedServiceTier?: string | null;\n skillCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n skills?: readonly CodexSkillSummary[];\n transcribeAudio?: CodexChatTranscription;\n}>();\n\nconst emit = defineEmits<{\n continueInterruptedTurn: [];\n error: [message: string | null];\n send: [prompt: string, options?: { inputMethod: 'dictated' }];\n steer: [prompt: string, options?: { inputMethod: 'dictated' }];\n steerQueuedPrompt: [promptId: string];\n attach: [];\n menuSelect: [item: CodexComposerMenuSelectableItem<Payload>];\n mentionSelect: [item: CodexComposerMentionItem<Payload>, group: CodexComposerMentionGroup<Payload>];\n interrupt: [];\n 'update:modelId': [modelId: string];\n 'update:composerState': [state: CodexComposerState];\n selectApprovalPreset: [preset: ApprovalPreset];\n 'update:planMode': [enabled: boolean];\n 'update:reasoningEffort': [reasoningEffort: ReasoningEffort];\n 'update:serviceTier': [serviceTier: string | null];\n}>();\n// Stryker restore all\n\nconst hostCapabilities = useCodexHostCapabilities();\n\nconst prompt = ref('');\nconst activeCommandId = ref<string | null>(null);\nconst dictatedInput = ref(false);\nconst editorEl = ref<CodexRichTextEditorExpose | null>(null);\nconst caretPosition = ref(0);\nconst selectionStart = ref(0);\nconst selectionEnd = ref(0);\nconst {\n exit: exitPromptHistory,\n recall: recallPrompt,\n remember: rememberSubmittedPrompt,\n seed: seedPromptHistory,\n} = createComposerPromptHistory({\n apply: applyRecalledPrompt,\n currentPrompt: () => prompt.value,\n});\nlet restoringComposerState = false;\nlet lastEmittedComposerState: CodexComposerState | null = null;\nlet composerRestoreRevision = 0;\nconst effectiveCodexCapabilities = computed(() => props.capabilities ?? codexCapabilities);\nconst effectivePresentation = computed(() => resolveCodexConversationPresentation(props.presentation));\nconst activeCommand = computed(() => (\n (props.commands ?? codexCommands).find((command) => command.id === activeCommandId.value) ?? null\n));\nconst goalCommand = computed(() => (\n (props.commands ?? codexCommands).find((command) => command.id === 'codex.goal' && command.composerMode) ?? null\n));\nconst goalMode = computed(() => Boolean(goalCommand.value && activeCommandId.value === goalCommand.value.id));\nconst effectivePlanMode = computed(() => Boolean(effectiveCodexCapabilities.value.planMode && props.planMode && !goalMode.value));\nconst effectivePlaceholder = computed(() => activeCommand.value?.composerMode?.placeholder ?? props.placeholder);\nconst voiceVisible = computed(() => (\n effectivePresentation.value.composer.voice\n && Boolean(props.transcribeAudio || hostCapabilities?.capabilities.transcription)\n));\n\nconst hasPrompt = computed(() => Boolean(prompt.value.trim()));\nconst emptySendPrompt = computed(() => props.emptySendPrompt?.trim() ?? '');\nconst canSend = computed(() => Boolean((activeCommand.value\n ? hasPrompt.value\n : hasPrompt.value || props.hasAttachments || props.hasExternalContent\n) && !props.disabled));\nconst canContinueInterruptedTurn = computed(() => Boolean(\n props.canContinueInterruptedTurn\n && !props.isSending\n && !hasPrompt.value\n && !props.hasAttachments\n && !props.hasExternalContent\n && !props.disabled,\n));\nconst canSubmitEmptyPrompt = computed(() => Boolean(\n emptySendPrompt.value\n && !props.isSending\n && !props.disabled\n && !hasPrompt.value\n && !props.hasAttachments\n && !props.hasExternalContent\n && !activeCommand.value\n && !canContinueInterruptedTurn.value,\n));\nlet pendingTranscriptCaret: number | null = null;\nconst canInterrupt = computed(() => Boolean(\n props.isSending\n && !hasPrompt.value\n && !props.hasAttachments\n && !props.hasExternalContent\n && !props.disabled\n && !isRecording.value\n && !isTranscribing.value,\n));\nconst sendButtonLoading = computed(() => canInterrupt.value);\nconst sendButtonDisabled = computed(() => {\n if (props.interruptArmed) return false;\n if (isTranscribing.value) return true;\n if (isRecording.value && !props.disabled) return false;\n return !canSend.value && !canInterrupt.value && !canContinueInterruptedTurn.value;\n});\nconst sendButtonLabel = computed(() => (\n canContinueInterruptedTurn.value\n ? 'Continue'\n : canSubmitEmptyPrompt.value\n ? 'Send default prompt'\n : props.isSending ? 'Queue prompt' : 'Send prompt'\n));\nconst {\n buttonDisabled: voiceButtonDisabled,\n buttonLabel: voiceButtonLabel,\n buttonTitle: voiceButtonTitle,\n error: voiceError,\n isRecording,\n isTranscribing,\n recorder,\n stop: stopRecording,\n toggle: toggleRecording,\n} = useChatComposerVoice({\n isDisabled: () => props.disabled,\n isSending: () => props.isSending,\n onTranscript: insertTranscript,\n transcribeAudio: props.transcribeAudio,\n});\n\nwatch(voiceError, (message) => emit('error', message));\nwatch(isTranscribing, (transcribing) => {\n if (transcribing || pendingTranscriptCaret === null) return;\n const caret = pendingTranscriptCaret;\n pendingTranscriptCaret = null;\n void nextTick(() => {\n editorEl.value?.setCaret(caret);\n });\n});\nlet pendingPromptHistorySteps = 0;\nwatch(() => [props.promptHistory, props.promptHistoryLoading] as const, ([history, loading]) => {\n seedPromptHistory(history ?? []);\n if (loading || pendingPromptHistorySteps === 0) return;\n const steps = pendingPromptHistorySteps;\n pendingPromptHistorySteps = 0;\n for (let step = 0; step < steps; step += 1) recallPrompt('ArrowUp');\n}, { immediate: true });\nconst {\n activeAtIndex,\n activeSkillIndex,\n activeSlashIndex,\n close: closeComposerMenus,\n closeSoon: closeComposerMenusSoon,\n resume: resumeComposerSuggestions,\n fileMenuShowsHint,\n atMenuVisible,\n handleKeydown: handleSuggestionKeydown,\n selectCommand,\n selectFile,\n selectPlugin,\n selectMention,\n selectSkill,\n selectSlashSkill,\n skillMenuVisible,\n slashMenuVisible,\n suspend: suspendComposerSuggestions,\n updateCaretPosition,\n visibleFiles,\n visiblePlugins,\n visibleMentionGroups,\n visibleSkills,\n visibleSlashCommands,\n visibleSlashSkills,\n} = useChatComposerSuggestions({\n caretPosition,\n commands: () => props.commands ?? codexCommands,\n disabled: () => props.disabled,\n files: () => props.files ?? [],\n plugins: () => props.plugins ?? [],\n mentionGroups: () => props.mentionGroups ?? [],\n isSending: () => props.isSending,\n onCommandActivated: (command) => {\n activateComposerCommand(command);\n },\n onCommandSubmitted: (command) => {\n if (command === '/plan' && goalMode.value) clearActiveCommand();\n rememberSubmittedPrompt(command);\n emit('send', command);\n },\n onTextInserted: focusAt,\n onMentionSelected: (item, group) => emit('mentionSelect', item, group),\n prompt,\n skills: () => props.skills ?? [],\n skillsEnabled: () => effectiveCodexCapabilities.value.skills,\n editor: editorEl,\n});\n\nwatch(() => props.composerState, (state) => {\n if (state) restoreComposerState(state);\n}, { deep: true, immediate: true });\n\nwatch(() => props.draftRevision, () => {\n if (!props.composerState) setComposerText(props.draft ?? '');\n}, { immediate: props.draftRevision !== undefined });\n\nwatch(prompt, () => emitComposerState());\n\nonMounted(() => {\n if (props.autofocus) {\n editorEl.value?.focusEnd();\n }\n});\n\nfunction submitPrompt(): void {\n if (canContinueInterruptedTurn.value) {\n emit('continueInterruptedTurn');\n return;\n }\n if (canSubmitEmptyPrompt.value) {\n emit('send', emptySendPrompt.value);\n return;\n }\n submitWithIntent('send');\n}\n\nasync function handleSendButtonClick(): Promise<void> {\n if (props.interruptArmed) {\n emit('interrupt');\n return;\n }\n if (isRecording.value) {\n if (await stopRecording()) {\n submitPrompt();\n }\n return;\n }\n if (canInterrupt.value) {\n emit('interrupt');\n return;\n }\n\n submitPrompt();\n}\n\nfunction submitSteer(): void {\n if (!effectiveCodexCapabilities.value.steerPrompt) {\n submitWithIntent('send');\n return;\n }\n if (!prompt.value.trim() && props.queuedPromptId && !props.hasAttachments && !props.hasExternalContent && !props.disabled) {\n emit('steerQueuedPrompt', props.queuedPromptId);\n return;\n }\n submitWithIntent('steer');\n}\n\nfunction submitWithIntent(intent: 'send' | 'steer'): void {\n const trimmed = prompt.value.trim();\n if (!canSend.value || (intent === 'steer' && !trimmed && !props.hasAttachments)) {\n return;\n }\n const slashCommand = activeCommand.value\n ? `/${activeCommand.value.slashName ?? activeCommand.value.name}`\n : null;\n const submittedPrompt = slashCommand && trimmed\n ? `${slashCommand} ${trimmed}`\n : trimmed || (props.hasAttachments ? '(no user instructions)' : '');\n const submissionOptions = dictatedInput.value ? { inputMethod: 'dictated' as const } : undefined;\n if (trimmed) rememberSubmittedPrompt(submittedPrompt);\n\n prompt.value = '';\n activeCommandId.value = null;\n dictatedInput.value = false;\n selectionStart.value = 0;\n selectionEnd.value = 0;\n caretPosition.value = 0;\n closeComposerMenus();\n if (intent === 'send') {\n if (submissionOptions) emit('send', submittedPrompt, submissionOptions);\n else emit('send', submittedPrompt);\n } else {\n if (submissionOptions) emit('steer', submittedPrompt, submissionOptions);\n else emit('steer', submittedPrompt);\n }\n}\n\nasync function insertTranscript(text: string): Promise<void> {\n const transcript = text.trim();\n if (!transcript) {\n return;\n }\n\n const selection = editorEl.value?.getSelectionRange();\n const start = selection?.start ?? selectionStart.value;\n const end = selection?.end ?? selectionEnd.value;\n const before = prompt.value.slice(0, start);\n const after = prompt.value.slice(end);\n const prefix = before && !/\\s$/.test(before) ? ' ' : '';\n const suffix = after && !/^\\s/.test(after) ? ' ' : '';\n const insertion = `${prefix}${transcript}${suffix}`;\n const nextCaret = before.length + insertion.length;\n prompt.value = `${before}${insertion}${after}`;\n dictatedInput.value = true;\n caretPosition.value = nextCaret;\n selectionStart.value = nextCaret;\n selectionEnd.value = nextCaret;\n pendingTranscriptCaret = nextCaret;\n closeComposerMenus();\n}\n\nfunction setComposerText(value: string): void {\n exitPromptHistory();\n restoreComposerState({ text: value, selectionStart: value.length, selectionEnd: value.length });\n}\n\nfunction removeActiveCommand(): void {\n clearActiveCommand();\n editorEl.value?.focusEnd();\n}\n\nfunction clearActiveCommand(): void {\n activeCommandId.value = null;\n emitComposerState();\n}\n\nfunction activateComposerCommand(command: CodexCommandSummary): void {\n if (command.id === goalCommand.value?.id && props.planMode) emit('update:planMode', false);\n activeCommandId.value = command.id;\n emitComposerState();\n}\n\nfunction updateGoalMode(enabled: boolean): void {\n if (enabled) {\n if (!goalCommand.value) return;\n activateComposerCommand(goalCommand.value);\n } else if (goalMode.value) {\n clearActiveCommand();\n }\n}\n\nfunction updatePlanMode(enabled: boolean): void {\n if (enabled && goalMode.value) clearActiveCommand();\n emit('update:planMode', enabled);\n}\n\nfunction restoreComposerState(state: CodexComposerState): void {\n const normalized = normalizeCodexComposerState(state);\n activeCommandId.value = normalized.activeCommandId ?? null;\n if (!sameComposerState(normalized, lastEmittedComposerState)) exitPromptHistory();\n const revision = ++composerRestoreRevision;\n const currentSelection = editorEl.value?.getSelectionRange();\n if (editorEl.value\n && prompt.value === normalized.text\n && editorEl.value.readText() === normalized.text\n && currentSelection?.valid\n && currentSelection.start === normalized.selectionStart\n && currentSelection.end === normalized.selectionEnd) {\n selectionStart.value = normalized.selectionStart;\n selectionEnd.value = normalized.selectionEnd;\n caretPosition.value = normalized.selectionEnd;\n lastEmittedComposerState = normalized;\n restoringComposerState = false;\n return;\n }\n\n restoringComposerState = true;\n prompt.value = normalized.text;\n selectionStart.value = normalized.selectionStart;\n selectionEnd.value = normalized.selectionEnd;\n caretPosition.value = normalized.selectionEnd;\n lastEmittedComposerState = normalized;\n closeComposerMenus();\n void nextTick(() => {\n if (revision !== composerRestoreRevision) return;\n if (prompt.value !== normalized.text) {\n restoringComposerState = false;\n return;\n }\n const restoredSelection = editorEl.value?.getSelectionRange();\n if (!restoredSelection?.valid\n || restoredSelection.start !== normalized.selectionStart\n || restoredSelection.end !== normalized.selectionEnd) {\n editorEl.value?.setSelection(normalized.selectionStart, normalized.selectionEnd, { focus: false });\n }\n restoringComposerState = false;\n });\n}\n\nfunction sameComposerState(left: CodexComposerState, right: CodexComposerState | null): boolean {\n return Boolean(right\n && left.text === right.text\n && left.selectionStart === right.selectionStart\n && left.selectionEnd === right.selectionEnd\n && (left.activeCommandId ?? null) === (right.activeCommandId ?? null));\n}\n\nfunction handleEditorKeydown(event: KeyboardEvent): void {\n if (handleSuggestionKeydown(event)) {\n return;\n }\n\n if (!event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey\n && (event.key === 'ArrowUp' || event.key === 'ArrowDown')\n && caretIsAtPromptEnd()) {\n if (recallPrompt(event.key)) {\n event.preventDefault();\n return;\n }\n if (event.key === 'ArrowUp' && props.promptHistoryLoading && prompt.value === '') {\n pendingPromptHistorySteps += 1;\n event.preventDefault();\n return;\n }\n }\n\n if (event.key === 'Tab' && event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey) {\n event.preventDefault();\n if (effectiveCodexCapabilities.value.planMode) {\n updatePlanMode(!effectivePlanMode.value);\n }\n return;\n }\n\n if (event.key !== 'Enter') {\n return;\n }\n\n if (event.shiftKey) {\n event.preventDefault();\n editorEl.value?.insertTextAtSelection('\\n');\n return;\n }\n\n event.preventDefault();\n if (event.metaKey && !event.ctrlKey && !event.altKey) {\n if (canContinueInterruptedTurn.value || (canSubmitEmptyPrompt.value && !props.queuedPromptId)) submitPrompt();\n else submitSteer();\n return;\n }\n\n if (!event.metaKey && !event.ctrlKey && !event.altKey) {\n submitPrompt();\n }\n}\n\nfunction caretIsAtPromptEnd(): boolean {\n const selection = editorEl.value?.getSelectionRange();\n if (selection?.valid) {\n return selection.start === selection.end && selection.end === prompt.value.length;\n }\n return selectionStart.value === selectionEnd.value && selectionEnd.value === prompt.value.length;\n}\n\nfunction handleEditorInput(): void {\n pendingPromptHistorySteps = 0;\n exitPromptHistory();\n resumeComposerSuggestions();\n updateCaretPosition();\n resizeEditor();\n}\n\nfunction applyRecalledPrompt(value: string): void {\n const caret = value.length;\n prompt.value = value;\n selectionStart.value = caret;\n selectionEnd.value = caret;\n caretPosition.value = caret;\n suspendComposerSuggestions();\n void nextTick(() => {\n editorEl.value?.setText(value, caret);\n });\n}\n\nfunction handleCaretChange(range: { end: number; start: number }): void {\n selectionStart.value = range.start;\n selectionEnd.value = range.end;\n updateCaretPosition(range);\n emitComposerState();\n}\n\nfunction emitComposerState(): void {\n if (restoringComposerState) return;\n const state = normalizeCodexComposerState({\n text: prompt.value,\n selectionStart: selectionStart.value,\n selectionEnd: selectionEnd.value,\n activeCommandId: activeCommandId.value,\n });\n if (sameComposerState(state, lastEmittedComposerState)) return;\n lastEmittedComposerState = state;\n emit('update:composerState', state);\n}\n\nfunction handleEditorPaste(event: ClipboardEvent): void {\n const clipboard = event.clipboardData;\n if (!clipboard) return;\n const text = clipboard.getData('text/plain');\n const containsRichOrFileContent = clipboard.files.length > 0 || [...(clipboard.types ?? [])].includes('text/html');\n if (!text && !containsRichOrFileContent) return;\n event.preventDefault();\n if (text) editorEl.value?.insertTextAtSelection(text);\n}\n\nfunction focusAt(caret: number): void {\n selectionStart.value = caret;\n selectionEnd.value = caret;\n caretPosition.value = caret;\n void nextTick(() => {\n editorEl.value?.setCaret(caret);\n });\n}\n\nfunction resizeEditor(): void {\n editorEl.value?.autoResize();\n}\n\nfunction focus(options?: { preserveSelection?: boolean }): void {\n if (options?.preserveSelection) {\n editorEl.value?.setSelection(selectionStart.value, selectionEnd.value);\n } else {\n editorEl.value?.focusEnd();\n }\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineExpose({ focus });\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-composer {\n --codex-composer-button-background: var(--color-on-surface-variant);\n --codex-composer-button-foreground: var(--color-surface);\n --codex-composer-button-hover-background: var(--color-on-surface);\n --chat-composer-button-size: var(--chat-composer-control-size, 36px);\n --chat-composer-button-size-small: var(--chat-composer-compact-control-size, 28px);\n --chat-composer-send-size: 28px;\n --chat-composer-input-max-height: calc(\n var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--space-4)\n + var(--space-4)\n );\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--space-2);\n width: 100%;\n padding: var(--space-4) var(--space-6) var(--space-3);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-2xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n transition: border-color 120ms ease, box-shadow 120ms ease;\n}\n\n.chat-composer:focus-within {\n box-shadow: 0 0 var(--space-6) var(--space-2) var(--color-surface-low), var(--shadow-md);\n}\n\n.chat-composer--disabled {\n opacity: 0.62;\n}\n\n.chat-composer__input {\n flex: 1 1 auto;\n min-width: 0;\n max-height: var(--chat-composer-input-max-height);\n width: 100%;\n padding: var(--space-2) var(--space-1) var(--space-4);\n border: 0;\n outline: 0;\n resize: none;\n overflow-y: auto;\n color: var(--color-text);\n background: transparent;\n font: inherit;\n font-size: var(--chat-composer-font-size, var(--font-size-15));\n line-height: var(--chat-composer-line-height, var(--line-height-24));\n}\n\n.chat-composer__input::placeholder {\n color: var(--color-text-muted);\n}\n\n.chat-composer__meta {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-6);\n width: 100%;\n min-height: var(--chat-composer-button-size, 36px);\n}\n\n.chat-composer__input-row,\n.chat-composer__meta-leading,\n.chat-composer__meta-trailing {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.chat-composer__input-row {\n width: 100%;\n align-items: flex-start;\n}\n\n.chat-composer__meta-leading {\n flex: 1 1 auto;\n gap: var(--space-3);\n}\n\n.chat-composer__meta-trailing {\n flex: 0 0 auto;\n gap: var(--space-3);\n}\n\n@media (max-width: 720px) {\n .chat-composer {\n border-radius: var(--radius-2xl);\n }\n}\n</style>\n","<template>\n <form\n class=\"codex-chat-theme chat-composer\"\n :class=\"{ 'chat-composer--disabled': disabled && !isSending }\"\n aria-label=\"Prompt composer\"\n @submit.prevent=\"submitPrompt\"\n >\n <slot name=\"before\" />\n <ChatComposerAtMentionMenu\n v-if=\"atMenuVisible\"\n :active-index=\"activeAtIndex\"\n :show-file-hint=\"fileMenuShowsHint\"\n :mention-groups=\"visibleMentionGroups\"\n :visible-files=\"visibleFiles\"\n :visible-plugins=\"visiblePlugins\"\n @select-file=\"selectFile\"\n @select-plugin=\"selectPlugin\"\n @select-mention=\"selectMention\"\n >\n <template v-if=\"$slots['suggestion-item']\" #mention=\"scope\">\n <slot name=\"suggestion-item\" v-bind=\"scope\" surface=\"menu\" />\n </template>\n </ChatComposerAtMentionMenu>\n\n <ChatComposerSkillMenu\n v-if=\"skillMenuVisible\"\n :active-index=\"activeSkillIndex\"\n :plugins=\"plugins\"\n :visible-skills=\"visibleSkills\"\n @select=\"selectSkill\"\n />\n\n <ChatComposerSlashMenu\n v-if=\"slashMenuVisible\"\n :active-index=\"activeSlashIndex\"\n :visible-commands=\"visibleSlashCommands\"\n :visible-skills=\"visibleSlashSkills\"\n @select-command=\"selectCommand\"\n @select-skill=\"selectSlashSkill\"\n />\n\n <div class=\"chat-composer__input-row\">\n <ChatComposerVoiceField\n v-if=\"voiceVisible && (isRecording || isTranscribing)\"\n :recorder=\"recorder\"\n :recording=\"isRecording\"\n />\n <ChatRichTextEditor\n v-else\n ref=\"editorEl\"\n v-model=\"prompt\"\n class=\"chat-composer__input\"\n :placeholder=\"effectivePlaceholder\"\n :disabled=\"disabled && !isSending\"\n :files=\"files\"\n :mention-groups=\"mentionGroups\"\n :plugins=\"plugins\"\n :skills=\"skills\"\n @blur=\"closeComposerMenusSoon\"\n @click=\"updateCaretPosition\"\n @caret-change=\"handleCaretChange\"\n @input=\"handleEditorInput\"\n @keydown=\"handleEditorKeydown\"\n @keyup=\"updateCaretPosition\"\n @paste=\"handleEditorPaste\"\n >\n <template v-if=\"$slots.mention\" #mention=\"scope\">\n <slot name=\"mention\" v-bind=\"scope\" surface=\"composer\" />\n </template>\n </ChatRichTextEditor>\n <slot name=\"after-input\" />\n </div>\n\n <div class=\"chat-composer__meta\">\n <div class=\"chat-composer__meta-leading\">\n <ChatComposerActionMenu\n v-if=\"effectivePresentation.composer.actionMenu\"\n :attach-enabled=\"attachEnabled\"\n :disabled=\"disabled\"\n :leading-menu-items=\"leadingMenuItems\"\n :items=\"menuItems\"\n :approval-preset=\"approvalPreset\"\n :approval-presets=\"effectiveCodexCapabilities.approvalPresets ?? []\"\n :goal-mode=\"goalMode\"\n :plan-mode=\"effectivePlanMode\"\n :show-approval-menu=\"effectiveCodexCapabilities.approvals && Boolean(approvalPreset) && (effectiveCodexCapabilities.approvalPresets?.length ?? 0) > 0\"\n :show-goal-mode=\"effectiveCodexCapabilities.goals && Boolean(goalCommand)\"\n :show-plan-mode=\"effectiveCodexCapabilities.planMode\"\n @attach=\"$emit('attach')\"\n @select=\"$emit('menuSelect', $event)\"\n @select-approval-preset=\"$emit('selectApprovalPreset', $event)\"\n @update:goal-mode=\"updateGoalMode\"\n @update:plan-mode=\"updatePlanMode\"\n >\n <template v-if=\"$slots['menu-icon']\" #icon=\"scope\"><slot name=\"menu-icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['menu-item']\" #item=\"scope\"><slot name=\"menu-item\" v-bind=\"scope\" /></template>\n </ChatComposerActionMenu>\n <slot name=\"before-meta\" />\n <ChatComposerActiveModes\n :plan-mode=\"effectivePlanMode\"\n :command=\"activeCommand\"\n @disable-plan-mode=\"updatePlanMode(false)\"\n @remove-command=\"removeActiveCommand\"\n />\n </div>\n <div class=\"chat-composer__meta-trailing\">\n <ChatContextUsageIndicator\n v-if=\"effectivePresentation.composer.contextUsage\"\n :context-usage=\"contextUsage\"\n />\n <ChatModelReasoningSelector\n v-if=\"effectiveCodexCapabilities.models\"\n :disabled=\"disabled\"\n :models=\"models\"\n :model-catalog-status=\"modelCatalogStatus\"\n :model-id=\"selectedModelId\"\n :menu-items=\"modelMenuItems\"\n :reasoning-effort=\"selectedReasoningEffort\"\n :service-tier=\"selectedServiceTier\"\n :show-service-tier=\"effectiveCodexCapabilities.serviceTier\"\n :show-reasoning=\"effectiveCodexCapabilities.reasoningEffort\"\n @update:model-id=\"$emit('update:modelId', $event)\"\n @menu-select=\"$emit('menuSelect', $event)\"\n @update:reasoning-effort=\"$emit('update:reasoningEffort', $event)\"\n @update:service-tier=\"$emit('update:serviceTier', $event)\"\n />\n <ChatComposerVoiceButton\n v-if=\"voiceVisible\"\n :disabled=\"voiceButtonDisabled\"\n :label=\"voiceButtonLabel\"\n :recording=\"isRecording\"\n :title=\"voiceButtonTitle\"\n @toggle=\"toggleRecording\"\n />\n <CodexComposerSendButton\n class=\"chat-composer__send\"\n :disabled=\"sendButtonDisabled\"\n :hover-to-enable=\"canSubmitEmptyPrompt\"\n :busy=\"sendButtonLoading\"\n :interrupt-armed=\"interruptArmed\"\n :submit-label=\"sendButtonLabel\"\n interrupt-label=\"Codex is working\"\n @click=\"handleSendButtonClick\"\n />\n <slot name=\"after\" />\n </div>\n </div>\n </form>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed, nextTick, onMounted, ref, watch } from 'vue';\nimport type { CodexContextUsage, CodexFileSearchItem, ApprovalPreset, CodexCapabilities, CodexCommandSummary, CodexModelOption, CodexSkillSummary, CodexChatTranscription, CodexConversationPresentation, ReasoningEffort } from '../chat/contracts';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport { resolveCodexConversationPresentation } from '../chat/contracts';\nimport { codexCapabilities } from '../chat/codex-capabilities';\nimport { codexCommands } from '../chat/codex-commands';\nimport { createComposerPromptHistory } from '../chat/composer-prompt-history';\nimport CodexComposerSendButton from './CodexComposerSendButton.vue';\nimport ChatComposerActiveModes from '../chat/ChatComposerActiveModes.vue';\nimport ChatComposerActionMenu from '../chat/ChatComposerActionMenu.vue';\nimport ChatComposerVoiceButton from '../chat/ChatComposerVoiceButton.vue';\nimport ChatComposerVoiceField from '../chat/ChatComposerVoiceField.vue';\nimport ChatContextUsageIndicator from '../chat/ChatContextUsageIndicator.vue';\nimport ChatModelReasoningSelector from '../chat/ChatModelReasoningSelector.vue';\nimport ChatComposerAtMentionMenu from '../chat/ChatComposerAtMentionMenu.vue';\nimport ChatComposerSkillMenu from '../chat/ChatComposerSkillMenu.vue';\nimport ChatComposerSlashMenu from '../chat/ChatComposerSlashMenu.vue';\nimport ChatRichTextEditor, { type CodexRichTextEditorExpose } from '../chat/ChatRichTextEditor.vue';\nimport { useChatComposerSuggestions } from '../chat/use-chat-composer-suggestions';\nimport { useChatComposerVoice } from '../chat/use-chat-composer-voice';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport { useCodexHostCapabilities } from '../native-capabilities';\nimport type { CodexComposerState } from '../composer-state';\nimport { normalizeCodexComposerState } from '../composer-state';\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from '../chat/composer-mentions-custom';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n autofocus?: boolean;\n attachEnabled?: boolean;\n canContinueInterruptedTurn?: boolean;\n contextUsage?: CodexContextUsage | null;\n disabled: boolean;\n draft?: string;\n draftRevision?: number;\n emptySendPrompt?: string;\n files?: readonly CodexFileSearchItem[];\n hasAttachments?: boolean;\n hasExternalContent?: boolean;\n plugins?: readonly CodexSurfacePlugin[];\n promptHistory?: readonly string[];\n promptHistoryLoading?: boolean;\n capabilities?: CodexCapabilities;\n commands?: readonly CodexCommandSummary[];\n composerState?: CodexComposerState;\n isSending: boolean;\n interruptArmed?: boolean;\n leadingMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n menuItems?: readonly CodexComposerMenuItem<Payload>[];\n mentionGroups?: readonly CodexComposerMentionGroup<Payload>[];\n modelCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n models?: readonly CodexModelOption[];\n modelMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n placeholder: string;\n queuedPromptId?: string | null;\n approvalPreset?: ApprovalPreset | null;\n planMode?: boolean;\n presentation?: CodexConversationPresentation;\n selectedModelId?: string | null;\n selectedReasoningEffort?: ReasoningEffort | null;\n selectedServiceTier?: string | null;\n skillCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n skills?: readonly CodexSkillSummary[];\n transcribeAudio?: CodexChatTranscription;\n}>();\n\nconst emit = defineEmits<{\n continueInterruptedTurn: [];\n error: [message: string | null];\n send: [prompt: string, options?: { inputMethod: 'dictated' }];\n steer: [prompt: string, options?: { inputMethod: 'dictated' }];\n steerQueuedPrompt: [promptId: string];\n attach: [];\n menuSelect: [item: CodexComposerMenuSelectableItem<Payload>];\n mentionSelect: [item: CodexComposerMentionItem<Payload>, group: CodexComposerMentionGroup<Payload>];\n interrupt: [];\n 'update:modelId': [modelId: string];\n 'update:composerState': [state: CodexComposerState];\n selectApprovalPreset: [preset: ApprovalPreset];\n 'update:planMode': [enabled: boolean];\n 'update:reasoningEffort': [reasoningEffort: ReasoningEffort];\n 'update:serviceTier': [serviceTier: string | null];\n}>();\n// Stryker restore all\n\nconst hostCapabilities = useCodexHostCapabilities();\n\nconst prompt = ref('');\nconst activeCommandId = ref<string | null>(null);\nconst dictatedInput = ref(false);\nconst editorEl = ref<CodexRichTextEditorExpose | null>(null);\nconst caretPosition = ref(0);\nconst selectionStart = ref(0);\nconst selectionEnd = ref(0);\nconst {\n exit: exitPromptHistory,\n recall: recallPrompt,\n remember: rememberSubmittedPrompt,\n seed: seedPromptHistory,\n} = createComposerPromptHistory({\n apply: applyRecalledPrompt,\n currentPrompt: () => prompt.value,\n});\nlet restoringComposerState = false;\nlet lastEmittedComposerState: CodexComposerState | null = null;\nlet composerRestoreRevision = 0;\nconst effectiveCodexCapabilities = computed(() => props.capabilities ?? codexCapabilities);\nconst effectivePresentation = computed(() => resolveCodexConversationPresentation(props.presentation));\nconst activeCommand = computed(() => (\n (props.commands ?? codexCommands).find((command) => command.id === activeCommandId.value) ?? null\n));\nconst goalCommand = computed(() => (\n (props.commands ?? codexCommands).find((command) => command.id === 'codex.goal' && command.composerMode) ?? null\n));\nconst goalMode = computed(() => Boolean(goalCommand.value && activeCommandId.value === goalCommand.value.id));\nconst effectivePlanMode = computed(() => Boolean(effectiveCodexCapabilities.value.planMode && props.planMode && !goalMode.value));\nconst effectivePlaceholder = computed(() => activeCommand.value?.composerMode?.placeholder ?? props.placeholder);\nconst voiceVisible = computed(() => (\n effectivePresentation.value.composer.voice\n && Boolean(props.transcribeAudio || hostCapabilities?.capabilities.transcription)\n));\n\nconst hasPrompt = computed(() => Boolean(prompt.value.trim()));\nconst emptySendPrompt = computed(() => props.emptySendPrompt?.trim() ?? '');\nconst canSend = computed(() => Boolean((activeCommand.value\n ? hasPrompt.value\n : hasPrompt.value || props.hasAttachments || props.hasExternalContent\n) && !props.disabled));\nconst canContinueInterruptedTurn = computed(() => Boolean(\n props.canContinueInterruptedTurn\n && !props.isSending\n && !hasPrompt.value\n && !props.hasAttachments\n && !props.hasExternalContent\n && !props.disabled,\n));\nconst canSubmitEmptyPrompt = computed(() => Boolean(\n emptySendPrompt.value\n && !props.isSending\n && !props.disabled\n && !hasPrompt.value\n && !props.hasAttachments\n && !props.hasExternalContent\n && !activeCommand.value\n && !canContinueInterruptedTurn.value,\n));\nlet pendingTranscriptCaret: number | null = null;\nconst canInterrupt = computed(() => Boolean(\n props.isSending\n && !hasPrompt.value\n && !props.hasAttachments\n && !props.hasExternalContent\n && !props.disabled\n && !isRecording.value\n && !isTranscribing.value,\n));\nconst sendButtonLoading = computed(() => canInterrupt.value);\nconst sendButtonDisabled = computed(() => {\n if (props.interruptArmed) return false;\n if (isTranscribing.value) return true;\n if (isRecording.value && !props.disabled) return false;\n return !canSend.value && !canInterrupt.value && !canContinueInterruptedTurn.value;\n});\nconst sendButtonLabel = computed(() => (\n canContinueInterruptedTurn.value\n ? 'Continue'\n : canSubmitEmptyPrompt.value\n ? 'Send default prompt'\n : props.isSending ? 'Queue prompt' : 'Send prompt'\n));\nconst {\n buttonDisabled: voiceButtonDisabled,\n buttonLabel: voiceButtonLabel,\n buttonTitle: voiceButtonTitle,\n error: voiceError,\n isRecording,\n isTranscribing,\n recorder,\n stop: stopRecording,\n toggle: toggleRecording,\n} = useChatComposerVoice({\n isDisabled: () => props.disabled,\n isSending: () => props.isSending,\n onTranscript: insertTranscript,\n transcribeAudio: props.transcribeAudio,\n});\n\nwatch(voiceError, (message) => emit('error', message));\nwatch(isTranscribing, (transcribing) => {\n if (transcribing || pendingTranscriptCaret === null) return;\n const caret = pendingTranscriptCaret;\n pendingTranscriptCaret = null;\n void nextTick(() => {\n editorEl.value?.setCaret(caret);\n });\n});\nlet pendingPromptHistorySteps = 0;\nwatch(() => [props.promptHistory, props.promptHistoryLoading] as const, ([history, loading]) => {\n seedPromptHistory(history ?? []);\n if (loading || pendingPromptHistorySteps === 0) return;\n const steps = pendingPromptHistorySteps;\n pendingPromptHistorySteps = 0;\n for (let step = 0; step < steps; step += 1) recallPrompt('ArrowUp');\n}, { immediate: true });\nconst {\n activeAtIndex,\n activeSkillIndex,\n activeSlashIndex,\n close: closeComposerMenus,\n closeSoon: closeComposerMenusSoon,\n resume: resumeComposerSuggestions,\n fileMenuShowsHint,\n atMenuVisible,\n handleKeydown: handleSuggestionKeydown,\n selectCommand,\n selectFile,\n selectPlugin,\n selectMention,\n selectSkill,\n selectSlashSkill,\n skillMenuVisible,\n slashMenuVisible,\n suspend: suspendComposerSuggestions,\n updateCaretPosition,\n visibleFiles,\n visiblePlugins,\n visibleMentionGroups,\n visibleSkills,\n visibleSlashCommands,\n visibleSlashSkills,\n} = useChatComposerSuggestions({\n caretPosition,\n commands: () => props.commands ?? codexCommands,\n disabled: () => props.disabled,\n files: () => props.files ?? [],\n plugins: () => props.plugins ?? [],\n mentionGroups: () => props.mentionGroups ?? [],\n isSending: () => props.isSending,\n onCommandActivated: (command) => {\n activateComposerCommand(command);\n },\n onCommandSubmitted: (command) => {\n if (command === '/plan' && goalMode.value) clearActiveCommand();\n rememberSubmittedPrompt(command);\n emit('send', command);\n },\n onTextInserted: focusAt,\n onMentionSelected: (item, group) => emit('mentionSelect', item, group),\n prompt,\n skills: () => props.skills ?? [],\n skillsEnabled: () => effectiveCodexCapabilities.value.skills,\n editor: editorEl,\n});\n\nwatch(() => props.composerState, (state) => {\n if (state) restoreComposerState(state);\n}, { deep: true, immediate: true });\n\nwatch(() => props.draftRevision, () => {\n if (!props.composerState) setComposerText(props.draft ?? '');\n}, { immediate: props.draftRevision !== undefined });\n\nwatch(prompt, () => emitComposerState());\n\nonMounted(() => {\n if (props.autofocus) {\n editorEl.value?.focusEnd();\n }\n});\n\nfunction submitPrompt(): void {\n if (canContinueInterruptedTurn.value) {\n emit('continueInterruptedTurn');\n return;\n }\n if (canSubmitEmptyPrompt.value) {\n emit('send', emptySendPrompt.value);\n return;\n }\n submitWithIntent('send');\n}\n\nasync function handleSendButtonClick(): Promise<void> {\n if (props.interruptArmed) {\n emit('interrupt');\n return;\n }\n if (isRecording.value) {\n if (await stopRecording()) {\n submitPrompt();\n }\n return;\n }\n if (canInterrupt.value) {\n emit('interrupt');\n return;\n }\n\n submitPrompt();\n}\n\nfunction submitSteer(): void {\n if (!effectiveCodexCapabilities.value.steerPrompt) {\n submitWithIntent('send');\n return;\n }\n if (!prompt.value.trim() && props.queuedPromptId && !props.hasAttachments && !props.hasExternalContent && !props.disabled) {\n emit('steerQueuedPrompt', props.queuedPromptId);\n return;\n }\n submitWithIntent('steer');\n}\n\nfunction submitWithIntent(intent: 'send' | 'steer'): void {\n const trimmed = prompt.value.trim();\n if (!canSend.value || (intent === 'steer' && !trimmed && !props.hasAttachments)) {\n return;\n }\n const slashCommand = activeCommand.value\n ? `/${activeCommand.value.slashName ?? activeCommand.value.name}`\n : null;\n const submittedPrompt = slashCommand && trimmed\n ? `${slashCommand} ${trimmed}`\n : trimmed || (props.hasAttachments ? '(no user instructions)' : '');\n const submissionOptions = dictatedInput.value ? { inputMethod: 'dictated' as const } : undefined;\n if (trimmed) rememberSubmittedPrompt(submittedPrompt);\n\n prompt.value = '';\n activeCommandId.value = null;\n dictatedInput.value = false;\n selectionStart.value = 0;\n selectionEnd.value = 0;\n caretPosition.value = 0;\n closeComposerMenus();\n if (intent === 'send') {\n if (submissionOptions) emit('send', submittedPrompt, submissionOptions);\n else emit('send', submittedPrompt);\n } else {\n if (submissionOptions) emit('steer', submittedPrompt, submissionOptions);\n else emit('steer', submittedPrompt);\n }\n}\n\nasync function insertTranscript(text: string): Promise<void> {\n const transcript = text.trim();\n if (!transcript) {\n return;\n }\n\n const selection = editorEl.value?.getSelectionRange();\n const start = selection?.start ?? selectionStart.value;\n const end = selection?.end ?? selectionEnd.value;\n const before = prompt.value.slice(0, start);\n const after = prompt.value.slice(end);\n const prefix = before && !/\\s$/.test(before) ? ' ' : '';\n const suffix = after && !/^\\s/.test(after) ? ' ' : '';\n const insertion = `${prefix}${transcript}${suffix}`;\n const nextCaret = before.length + insertion.length;\n prompt.value = `${before}${insertion}${after}`;\n dictatedInput.value = true;\n caretPosition.value = nextCaret;\n selectionStart.value = nextCaret;\n selectionEnd.value = nextCaret;\n pendingTranscriptCaret = nextCaret;\n closeComposerMenus();\n}\n\nfunction setComposerText(value: string): void {\n exitPromptHistory();\n restoreComposerState({ text: value, selectionStart: value.length, selectionEnd: value.length });\n}\n\nfunction removeActiveCommand(): void {\n clearActiveCommand();\n editorEl.value?.focusEnd();\n}\n\nfunction clearActiveCommand(): void {\n activeCommandId.value = null;\n emitComposerState();\n}\n\nfunction activateComposerCommand(command: CodexCommandSummary): void {\n if (command.id === goalCommand.value?.id && props.planMode) emit('update:planMode', false);\n activeCommandId.value = command.id;\n emitComposerState();\n}\n\nfunction updateGoalMode(enabled: boolean): void {\n if (enabled) {\n if (!goalCommand.value) return;\n activateComposerCommand(goalCommand.value);\n } else if (goalMode.value) {\n clearActiveCommand();\n }\n}\n\nfunction updatePlanMode(enabled: boolean): void {\n if (enabled && goalMode.value) clearActiveCommand();\n emit('update:planMode', enabled);\n}\n\nfunction restoreComposerState(state: CodexComposerState): void {\n const normalized = normalizeCodexComposerState(state);\n activeCommandId.value = normalized.activeCommandId ?? null;\n if (!sameComposerState(normalized, lastEmittedComposerState)) exitPromptHistory();\n const revision = ++composerRestoreRevision;\n const currentSelection = editorEl.value?.getSelectionRange();\n if (editorEl.value\n && prompt.value === normalized.text\n && editorEl.value.readText() === normalized.text\n && currentSelection?.valid\n && currentSelection.start === normalized.selectionStart\n && currentSelection.end === normalized.selectionEnd) {\n selectionStart.value = normalized.selectionStart;\n selectionEnd.value = normalized.selectionEnd;\n caretPosition.value = normalized.selectionEnd;\n lastEmittedComposerState = normalized;\n restoringComposerState = false;\n return;\n }\n\n restoringComposerState = true;\n prompt.value = normalized.text;\n selectionStart.value = normalized.selectionStart;\n selectionEnd.value = normalized.selectionEnd;\n caretPosition.value = normalized.selectionEnd;\n lastEmittedComposerState = normalized;\n closeComposerMenus();\n void nextTick(() => {\n if (revision !== composerRestoreRevision) return;\n if (prompt.value !== normalized.text) {\n restoringComposerState = false;\n return;\n }\n const restoredSelection = editorEl.value?.getSelectionRange();\n if (!restoredSelection?.valid\n || restoredSelection.start !== normalized.selectionStart\n || restoredSelection.end !== normalized.selectionEnd) {\n editorEl.value?.setSelection(normalized.selectionStart, normalized.selectionEnd, { focus: false });\n }\n restoringComposerState = false;\n });\n}\n\nfunction sameComposerState(left: CodexComposerState, right: CodexComposerState | null): boolean {\n return Boolean(right\n && left.text === right.text\n && left.selectionStart === right.selectionStart\n && left.selectionEnd === right.selectionEnd\n && (left.activeCommandId ?? null) === (right.activeCommandId ?? null));\n}\n\nfunction handleEditorKeydown(event: KeyboardEvent): void {\n if (handleSuggestionKeydown(event)) {\n return;\n }\n\n if (!event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey\n && (event.key === 'ArrowUp' || event.key === 'ArrowDown')\n && caretIsAtPromptEnd()) {\n if (recallPrompt(event.key)) {\n event.preventDefault();\n return;\n }\n if (event.key === 'ArrowUp' && props.promptHistoryLoading && prompt.value === '') {\n pendingPromptHistorySteps += 1;\n event.preventDefault();\n return;\n }\n }\n\n if (event.key === 'Tab' && event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey) {\n event.preventDefault();\n if (effectiveCodexCapabilities.value.planMode) {\n updatePlanMode(!effectivePlanMode.value);\n }\n return;\n }\n\n if (event.key !== 'Enter') {\n return;\n }\n\n if (event.shiftKey) {\n event.preventDefault();\n editorEl.value?.insertTextAtSelection('\\n');\n return;\n }\n\n event.preventDefault();\n if (event.metaKey && !event.ctrlKey && !event.altKey) {\n if (canContinueInterruptedTurn.value || (canSubmitEmptyPrompt.value && !props.queuedPromptId)) submitPrompt();\n else submitSteer();\n return;\n }\n\n if (!event.metaKey && !event.ctrlKey && !event.altKey) {\n submitPrompt();\n }\n}\n\nfunction caretIsAtPromptEnd(): boolean {\n const selection = editorEl.value?.getSelectionRange();\n if (selection?.valid) {\n return selection.start === selection.end && selection.end === prompt.value.length;\n }\n return selectionStart.value === selectionEnd.value && selectionEnd.value === prompt.value.length;\n}\n\nfunction handleEditorInput(): void {\n pendingPromptHistorySteps = 0;\n exitPromptHistory();\n resumeComposerSuggestions();\n updateCaretPosition();\n resizeEditor();\n}\n\nfunction applyRecalledPrompt(value: string): void {\n const caret = value.length;\n prompt.value = value;\n selectionStart.value = caret;\n selectionEnd.value = caret;\n caretPosition.value = caret;\n suspendComposerSuggestions();\n void nextTick(() => {\n editorEl.value?.setText(value, caret);\n });\n}\n\nfunction handleCaretChange(range: { end: number; start: number }): void {\n selectionStart.value = range.start;\n selectionEnd.value = range.end;\n updateCaretPosition(range);\n emitComposerState();\n}\n\nfunction emitComposerState(): void {\n if (restoringComposerState) return;\n const state = normalizeCodexComposerState({\n text: prompt.value,\n selectionStart: selectionStart.value,\n selectionEnd: selectionEnd.value,\n activeCommandId: activeCommandId.value,\n });\n if (sameComposerState(state, lastEmittedComposerState)) return;\n lastEmittedComposerState = state;\n emit('update:composerState', state);\n}\n\nfunction handleEditorPaste(event: ClipboardEvent): void {\n const clipboard = event.clipboardData;\n if (!clipboard) return;\n const text = clipboard.getData('text/plain');\n const containsRichOrFileContent = clipboard.files.length > 0 || [...(clipboard.types ?? [])].includes('text/html');\n if (!text && !containsRichOrFileContent) return;\n event.preventDefault();\n if (text) editorEl.value?.insertTextAtSelection(text);\n}\n\nfunction focusAt(caret: number): void {\n selectionStart.value = caret;\n selectionEnd.value = caret;\n caretPosition.value = caret;\n void nextTick(() => {\n editorEl.value?.setCaret(caret);\n });\n}\n\nfunction resizeEditor(): void {\n editorEl.value?.autoResize();\n}\n\nfunction focus(options?: { preserveSelection?: boolean }): void {\n if (options?.preserveSelection) {\n editorEl.value?.setSelection(selectionStart.value, selectionEnd.value);\n } else {\n editorEl.value?.focusEnd();\n }\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineExpose({ focus });\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-composer {\n --codex-composer-button-background: var(--color-on-surface-variant);\n --codex-composer-button-foreground: var(--color-surface);\n --codex-composer-button-hover-background: var(--color-on-surface);\n --chat-composer-button-size: var(--chat-composer-control-size, 36px);\n --chat-composer-button-size-small: var(--chat-composer-compact-control-size, 28px);\n --chat-composer-send-size: 28px;\n --chat-composer-input-max-height: calc(\n var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--chat-composer-line-height, var(--line-height-24))\n + var(--space-4)\n + var(--space-4)\n );\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--space-2);\n width: 100%;\n padding: var(--space-4) var(--space-6) var(--space-3);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-2xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n transition: border-color 120ms ease, box-shadow 120ms ease;\n}\n\n.chat-composer:focus-within {\n box-shadow: 0 0 var(--space-6) var(--space-2) var(--color-surface-low), var(--shadow-md);\n}\n\n.chat-composer--disabled {\n opacity: 0.62;\n}\n\n.chat-composer__input {\n flex: 1 1 auto;\n min-width: 0;\n max-height: var(--chat-composer-input-max-height);\n width: 100%;\n padding: var(--space-2) var(--space-1) var(--space-4);\n border: 0;\n outline: 0;\n resize: none;\n overflow-y: auto;\n color: var(--color-text);\n background: transparent;\n font: inherit;\n font-size: var(--chat-composer-font-size, var(--font-size-15));\n line-height: var(--chat-composer-line-height, var(--line-height-24));\n}\n\n.chat-composer__input::placeholder {\n color: var(--color-text-muted);\n}\n\n.chat-composer__meta {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-6);\n width: 100%;\n min-height: var(--chat-composer-button-size, 36px);\n}\n\n.chat-composer__input-row,\n.chat-composer__meta-leading,\n.chat-composer__meta-trailing {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.chat-composer__input-row {\n width: 100%;\n align-items: flex-start;\n}\n\n.chat-composer__meta-leading {\n flex: 1 1 auto;\n gap: var(--space-3);\n}\n\n.chat-composer__meta-trailing {\n flex: 0 0 auto;\n gap: var(--space-3);\n}\n\n@media (max-width: 720px) {\n .chat-composer {\n border-radius: var(--radius-2xl);\n }\n}\n</style>\n","<template>\n <section class=\"codex-chat-theme chat-tool-confirmation\">\n <header class=\"chat-tool-confirmation__header\">\n <span class=\"chat-tool-confirmation__tag\">Approve tool call</span>\n <span class=\"chat-tool-confirmation__question\">{{ summary }}</span>\n <p v-if=\"description\" class=\"chat-tool-confirmation__description\">{{ description }}</p>\n </header>\n <details v-if=\"details || $slots.details\" class=\"chat-tool-confirmation__details\">\n <summary class=\"chat-tool-confirmation__details-summary\">Details</summary>\n <div class=\"chat-tool-confirmation__details-body\">\n <slot name=\"details\"><pre>{{ details }}</pre></slot>\n </div>\n </details>\n <footer class=\"chat-tool-confirmation__actions\">\n <button\n v-for=\"action in actions\"\n :key=\"action.id\"\n class=\"codex-request-button chat-tool-confirmation__button\"\n :class=\"{ 'codex-request-button--primary': action.primary, 'chat-tool-confirmation__button--primary': action.primary }\"\n type=\"button\"\n :disabled=\"disabled\"\n @click=\"$emit('decide', action.id)\"\n >{{ action.label }}</button>\n </footer>\n </section>\n</template>\n\n<script setup lang=\"ts\" generic=\"Decision extends string\">\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n summary: string\n description?: string\n details?: string\n disabled?: boolean\n actions: readonly { id: Decision; label: string; primary?: boolean }[]\n}>()\ndefineEmits<{ decide: [decision: Decision] }>()\n// Stryker restore all\n</script>\n\n<style scoped src=\"./request-controls.css\"></style>\n\n<style scoped>\n.chat-tool-confirmation {\n display: flex;\n flex-direction: column;\n gap: var(--space-6);\n width: 100%;\n box-sizing: border-box;\n max-height: min(70vh, 38rem);\n overflow-y: auto;\n padding: var(--space-6);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n}\n\n.chat-tool-confirmation__header {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n}\n\n.chat-tool-confirmation__tag {\n width: fit-content;\n border: 1px solid color-mix(in srgb, var(--color-primary) 24%, transparent);\n border-radius: var(--radius-full);\n padding: var(--space-1) var(--space-3);\n background: var(--color-primary-container);\n color: var(--color-primary);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-16);\n}\n\n.chat-tool-confirmation__question {\n font-size: var(--font-size-16);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-24);\n}\n\n.chat-tool-confirmation__description {\n margin: 0;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-confirmation__details-body pre {\n margin: 0;\n font: inherit;\n white-space: inherit;\n}\n\n.chat-tool-confirmation__details {\n margin: 0;\n border-radius: var(--radius-md);\n color: var(--color-text-muted);\n font-size: var(--font-size-12);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-confirmation__details-summary {\n width: fit-content;\n cursor: pointer;\n}\n\n.chat-tool-confirmation__details-body {\n max-height: 12rem;\n overflow: auto;\n margin: var(--space-3) 0 0;\n padding: var(--space-4);\n border-radius: var(--radius-md);\n background: var(--color-surface-low);\n color: var(--color-text-muted);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-12);\n line-height: var(--line-height-20);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.chat-tool-confirmation__actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-3);\n}\n\n.chat-tool-confirmation__button:not(:disabled):hover {\n background: var(--color-surface-low);\n}\n\n.chat-tool-confirmation__button--primary:not(:disabled):hover {\n background: var(--color-secondary);\n}\n\n</style>\n","<template>\n <section class=\"codex-chat-theme chat-tool-confirmation\">\n <header class=\"chat-tool-confirmation__header\">\n <span class=\"chat-tool-confirmation__tag\">Approve tool call</span>\n <span class=\"chat-tool-confirmation__question\">{{ summary }}</span>\n <p v-if=\"description\" class=\"chat-tool-confirmation__description\">{{ description }}</p>\n </header>\n <details v-if=\"details || $slots.details\" class=\"chat-tool-confirmation__details\">\n <summary class=\"chat-tool-confirmation__details-summary\">Details</summary>\n <div class=\"chat-tool-confirmation__details-body\">\n <slot name=\"details\"><pre>{{ details }}</pre></slot>\n </div>\n </details>\n <footer class=\"chat-tool-confirmation__actions\">\n <button\n v-for=\"action in actions\"\n :key=\"action.id\"\n class=\"codex-request-button chat-tool-confirmation__button\"\n :class=\"{ 'codex-request-button--primary': action.primary, 'chat-tool-confirmation__button--primary': action.primary }\"\n type=\"button\"\n :disabled=\"disabled\"\n @click=\"$emit('decide', action.id)\"\n >{{ action.label }}</button>\n </footer>\n </section>\n</template>\n\n<script setup lang=\"ts\" generic=\"Decision extends string\">\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n summary: string\n description?: string\n details?: string\n disabled?: boolean\n actions: readonly { id: Decision; label: string; primary?: boolean }[]\n}>()\ndefineEmits<{ decide: [decision: Decision] }>()\n// Stryker restore all\n</script>\n\n<style scoped src=\"./request-controls.css\"></style>\n\n<style scoped>\n.chat-tool-confirmation {\n display: flex;\n flex-direction: column;\n gap: var(--space-6);\n width: 100%;\n box-sizing: border-box;\n max-height: min(70vh, 38rem);\n overflow-y: auto;\n padding: var(--space-6);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n}\n\n.chat-tool-confirmation__header {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n}\n\n.chat-tool-confirmation__tag {\n width: fit-content;\n border: 1px solid color-mix(in srgb, var(--color-primary) 24%, transparent);\n border-radius: var(--radius-full);\n padding: var(--space-1) var(--space-3);\n background: var(--color-primary-container);\n color: var(--color-primary);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-16);\n}\n\n.chat-tool-confirmation__question {\n font-size: var(--font-size-16);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-24);\n}\n\n.chat-tool-confirmation__description {\n margin: 0;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-confirmation__details-body pre {\n margin: 0;\n font: inherit;\n white-space: inherit;\n}\n\n.chat-tool-confirmation__details {\n margin: 0;\n border-radius: var(--radius-md);\n color: var(--color-text-muted);\n font-size: var(--font-size-12);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-confirmation__details-summary {\n width: fit-content;\n cursor: pointer;\n}\n\n.chat-tool-confirmation__details-body {\n max-height: 12rem;\n overflow: auto;\n margin: var(--space-3) 0 0;\n padding: var(--space-4);\n border-radius: var(--radius-md);\n background: var(--color-surface-low);\n color: var(--color-text-muted);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-12);\n line-height: var(--line-height-20);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n.chat-tool-confirmation__actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-3);\n}\n\n.chat-tool-confirmation__button:not(:disabled):hover {\n background: var(--color-surface-low);\n}\n\n.chat-tool-confirmation__button--primary:not(:disabled):hover {\n background: var(--color-secondary);\n}\n\n</style>\n","<template>\n <ChatApprovalCard\n class=\"codex-approval-prompt\"\n role=\"status\"\n :summary=\"approval.title\"\n :description=\"approval.description\"\n :actions=\"actions\"\n :disabled=\"disabled\"\n @decide=\"decide\"\n >\n <template v-if=\"approval.command || approval.cwd || approval.requestedPermissions?.length\" #details>\n <div class=\"codex-approval-prompt__details\">\n <code v-if=\"approval.command\">{{ approval.command }}</code>\n <small v-if=\"approval.cwd\">{{ approval.cwd }}</small>\n <ul v-if=\"approval.requestedPermissions?.length\" aria-label=\"Requested permissions\">\n <li v-for=\"(permission, index) in approval.requestedPermissions\" :key=\"index\">\n {{ permissionLabel(permission) }}\n </li>\n </ul>\n </div>\n </template>\n </ChatApprovalCard>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport ChatApprovalCard from '../chat/ChatApprovalCard.vue';\nimport type {\n CodexSurfaceApproval,\n CodexSurfaceApprovalDecision,\n CodexSurfaceApprovalScope,\n CodexSurfaceRequestedPermission,\n} from '@codex-app-sdk/core/surface';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n approval: CodexSurfaceApproval;\n disabled?: boolean;\n}>(), {\n disabled: false,\n});\n// Stryker restore all\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n resolve: [decision: CodexSurfaceApprovalDecision, scope: CodexSurfaceApprovalScope];\n}>();\n// Stryker restore all\n\nconst allowedScopes = computed(() => props.approval.allowedScopes ?? ['once', 'session']);\nconst canDeny = computed(() => props.approval.canDeny ?? true);\nconst actions = computed(() => [\n ...(allowedScopes.value.includes('once') ? [{ id: 'once' as const, label: 'Allow', primary: true }] : []),\n ...(allowedScopes.value.includes('session') ? [{ id: 'session' as const, label: 'Allow for session' }] : []),\n ...(canDeny.value ? [{ id: 'deny' as const, label: 'Deny' }] : []),\n]);\n\nfunction decide(decision: 'once' | 'session' | 'deny'): void {\n emit('resolve', decision === 'deny' ? 'deny' : 'approve', decision === 'session' ? 'session' : 'once');\n}\n\nfunction permissionLabel(permission: CodexSurfaceRequestedPermission): string {\n if (permission.kind === 'network') {\n const destination = permission.host\n ? ` to ${permission.protocol ? `${permission.protocol}://` : ''}${permission.host}`\n : '';\n return `Network access${destination}: ${permission.enabled ? 'enabled' : 'disabled'}`;\n }\n return `${permission.access[0]?.toUpperCase()}${permission.access.slice(1)} access: ${permission.path}`;\n}\n</script>\n\n<style scoped>\n.codex-approval-prompt__details {\n display: grid;\n gap: var(--space-3);\n}\n.codex-approval-prompt__details code,\n.codex-approval-prompt__details small {\n font: inherit;\n}\n.codex-approval-prompt__details ul {\n margin: 0;\n padding-left: var(--space-8);\n}\n</style>\n","<template>\n <ChatApprovalCard\n class=\"codex-approval-prompt\"\n role=\"status\"\n :summary=\"approval.title\"\n :description=\"approval.description\"\n :actions=\"actions\"\n :disabled=\"disabled\"\n @decide=\"decide\"\n >\n <template v-if=\"approval.command || approval.cwd || approval.requestedPermissions?.length\" #details>\n <div class=\"codex-approval-prompt__details\">\n <code v-if=\"approval.command\">{{ approval.command }}</code>\n <small v-if=\"approval.cwd\">{{ approval.cwd }}</small>\n <ul v-if=\"approval.requestedPermissions?.length\" aria-label=\"Requested permissions\">\n <li v-for=\"(permission, index) in approval.requestedPermissions\" :key=\"index\">\n {{ permissionLabel(permission) }}\n </li>\n </ul>\n </div>\n </template>\n </ChatApprovalCard>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport ChatApprovalCard from '../chat/ChatApprovalCard.vue';\nimport type {\n CodexSurfaceApproval,\n CodexSurfaceApprovalDecision,\n CodexSurfaceApprovalScope,\n CodexSurfaceRequestedPermission,\n} from '@codex-app-sdk/core/surface';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n approval: CodexSurfaceApproval;\n disabled?: boolean;\n}>(), {\n disabled: false,\n});\n// Stryker restore all\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n resolve: [decision: CodexSurfaceApprovalDecision, scope: CodexSurfaceApprovalScope];\n}>();\n// Stryker restore all\n\nconst allowedScopes = computed(() => props.approval.allowedScopes ?? ['once', 'session']);\nconst canDeny = computed(() => props.approval.canDeny ?? true);\nconst actions = computed(() => [\n ...(allowedScopes.value.includes('once') ? [{ id: 'once' as const, label: 'Allow', primary: true }] : []),\n ...(allowedScopes.value.includes('session') ? [{ id: 'session' as const, label: 'Allow for session' }] : []),\n ...(canDeny.value ? [{ id: 'deny' as const, label: 'Deny' }] : []),\n]);\n\nfunction decide(decision: 'once' | 'session' | 'deny'): void {\n emit('resolve', decision === 'deny' ? 'deny' : 'approve', decision === 'session' ? 'session' : 'once');\n}\n\nfunction permissionLabel(permission: CodexSurfaceRequestedPermission): string {\n if (permission.kind === 'network') {\n const destination = permission.host\n ? ` to ${permission.protocol ? `${permission.protocol}://` : ''}${permission.host}`\n : '';\n return `Network access${destination}: ${permission.enabled ? 'enabled' : 'disabled'}`;\n }\n return `${permission.access[0]?.toUpperCase()}${permission.access.slice(1)} access: ${permission.path}`;\n}\n</script>\n\n<style scoped>\n.codex-approval-prompt__details {\n display: grid;\n gap: var(--space-3);\n}\n.codex-approval-prompt__details code,\n.codex-approval-prompt__details small {\n font: inherit;\n}\n.codex-approval-prompt__details ul {\n margin: 0;\n padding-left: var(--space-8);\n}\n</style>\n","import type {\n CodexConversationLink,\n CodexContextUsage,\n CodexFileSearchItem,\n CodexModelOption,\n CodexSkillSummary,\n ApprovalPreset,\n CodexCapabilities,\n CodexCommandSummary,\n ClientRequestResponse,\n ReasoningEffort,\n ThreadGoal,\n TurnGitDiff,\n} from './chat/contracts';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from './composer-menu';\nimport type { Message } from './chat/types';\nimport type { CodexMessageImageOpenHandler } from './chat/message-image';\nimport type { CodexConversationVisualization } from './chat/visualization';\nimport type { CodexComposerState } from './composer-state';\nimport type { QueuedChatPrompt } from './chat/queued-prompts';\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from './chat/composer-mentions-custom';\nimport type { CodexHostAttachment } from '@codex-app-sdk/core/native';\nimport type {\n CodexSurfaceApproval,\n CodexSurfaceApprovalDecision,\n CodexSurfaceApprovalScope,\n CodexSurfaceClientRequest,\n CodexSurfacePlugin,\n CodexSurfaceTurn,\n CodexRendererSendMessageOptions,\n SurfaceMessage,\n UpdateCodexConversationSettings,\n} from '@codex-app-sdk/core/surface';\n\nexport type CodexConversationPaneIdentityState = {\n conversationKey?: string | number | null;\n activeTurnId?: string | null;\n turns?: readonly CodexSurfaceTurn[];\n messages: readonly (Message | SurfaceMessage)[];\n busy?: boolean;\n disabled?: boolean;\n error?: string | null;\n};\n\nexport type CodexConversationPaneHistoryState = {\n hasOlder?: boolean;\n loading?: boolean;\n loadingOlder?: boolean;\n};\n\nexport type CodexConversationPaneThreadState = {\n approvals?: readonly CodexSurfaceApproval[];\n answeredClientRequestIds?: ReadonlySet<string>;\n clientRequests?: readonly CodexSurfaceClientRequest[];\n goal?: ThreadGoal | null;\n queuedPrompts?: readonly QueuedChatPrompt[];\n turnGitDiff?: TurnGitDiff | null;\n contextUsage?: CodexContextUsage | null;\n};\n\nexport type CodexConversationPaneComposerState = {\n state?: CodexComposerState;\n attachments?: readonly CodexHostAttachment[];\n /** Chronological user prompts available to Up/Down recall. */\n promptHistory?: readonly string[];\n placeholder?: string;\n /** Host actions rendered after Approval and before Plan mode. */\n leadingMenuItems?: readonly CodexComposerMenuItem[];\n menuItems?: readonly CodexComposerMenuItem[];\n /** Host-owned actions rendered before the SDK's model, reasoning, and speed controls. */\n modelMenuItems?: readonly CodexComposerMenuItem[];\n approvalPreset?: ApprovalPreset | null;\n planMode?: boolean;\n selectedModelId?: string | null;\n selectedReasoningEffort?: ReasoningEffort | null;\n selectedServiceTier?: string | null;\n};\n\nexport type CodexConversationPaneCatalogState = {\n files?: readonly CodexFileSearchItem[];\n models?: readonly CodexModelOption[];\n commands?: readonly CodexCommandSummary[];\n skills?: readonly CodexSkillSummary[];\n plugins?: readonly CodexSurfacePlugin[];\n mentionGroups?: readonly CodexComposerMentionGroup[];\n modelCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n skillCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n};\n\nexport type CodexConversationPanePolicy = {\n actionsDisabled?: boolean;\n attachEnabled?: boolean;\n canDeleteTurn?: boolean;\n canEditTurn?: boolean;\n canForkTurn?: boolean;\n canRetryTurn?: boolean;\n followUpsDisabled?: boolean;\n};\n\nexport type CodexConversationPaneState = {\n identity: CodexConversationPaneIdentityState;\n history?: CodexConversationPaneHistoryState;\n thread?: CodexConversationPaneThreadState;\n composer?: CodexConversationPaneComposerState;\n catalogs?: CodexConversationPaneCatalogState;\n capabilities?: CodexCapabilities;\n policy?: CodexConversationPanePolicy;\n};\n\n/**\n * A Vue-version-independent reactive value source. Ref-like values are\n * intentionally structural so applications with a separately-resolved Vue\n * package can pass `computed`/`ref` values without nominal type conflicts.\n */\nexport type CodexConversationPaneValueSource<T> =\n | T\n | { readonly value: T }\n | (() => T);\n\nexport function resolveCodexConversationPaneValue<T>(\n source: CodexConversationPaneValueSource<T>,\n): T {\n if (typeof source === 'function') return (source as () => T)();\n if (source !== null && typeof source === 'object' && 'value' in source) {\n return (source as { readonly value: T }).value;\n }\n return source as T;\n}\n\ntype PaneAction<Args extends unknown[] = []> = (...args: Args) => void | Promise<void>;\n\nexport type CodexConversationPaneActions<Payload = unknown> = {\n attach?: PaneAction;\n cancel?: PaneAction;\n clientResponse?: PaneAction<[response: ClientRequestResponse]>;\n clearGoal?: PaneAction;\n continueInterruptedTurn?: PaneAction;\n /** Called after the SDK has copied a message to the clipboard. */\n onMessageCopied?: PaneAction<[index: number]>;\n deleteTurn?: PaneAction<[turnId: string]>;\n deleteQueuedPrompt?: PaneAction<[promptId: string]>;\n updateQueuedPrompt?: PaneAction<[promptId: string, prompt: string]>;\n editGoal?: PaneAction;\n editTurn?: PaneAction<[payload: { content: string; turnId: string }]>;\n forkTurn?: PaneAction<[turnId: string]>;\n interrupt?: PaneAction;\n loadOlderHistory?: PaneAction;\n menuSelect?: PaneAction<[item: CodexComposerMenuSelectableItem<Payload>]>;\n mentionSelect?: PaneAction<[item: CodexComposerMentionItem<Payload>, group: CodexComposerMentionGroup<Payload>]>;\n openImage?: CodexMessageImageOpenHandler;\n openLink?: PaneAction<[link: CodexConversationLink]>;\n openVisualization?: PaneAction<[visualization: CodexConversationVisualization]>;\n quoteMessage?: PaneAction<[index: number]>;\n /** Loads bounded user-only prompt history for the active conversation. */\n readPromptHistory?: () => readonly string[] | Promise<readonly string[]>;\n resolveApproval?: PaneAction<[\n approvalId: string,\n decision: CodexSurfaceApprovalDecision,\n scope: CodexSurfaceApprovalScope,\n ]>;\n retryTurn?: PaneAction<[turnId: string]>;\n selectApprovalPreset?: PaneAction<[preset: ApprovalPreset]>;\n sendFollowUp?: PaneAction<[prompt: string]>;\n steer?: PaneAction<[prompt: string, options?: CodexRendererSendMessageOptions]>;\n steerQueuedPrompt?: PaneAction<[promptId: string, prompt?: string]>;\n submit?: PaneAction<[prompt: string, options?: CodexRendererSendMessageOptions]>;\n updateAttachments?: PaneAction<[attachments: readonly CodexHostAttachment[]]>;\n updateComposerState?: PaneAction<[state: CodexComposerState]>;\n updateSettings?: PaneAction<[settings: UpdateCodexConversationSettings]>;\n};\n\nexport type CodexConversationPaneController<Payload = unknown> = {\n state: CodexConversationPaneValueSource<CodexConversationPaneState>;\n actions: CodexConversationPaneValueSource<CodexConversationPaneActions<Payload>>;\n};\n\nexport type CodexConversationPaneControllerSource<Payload = unknown> = CodexConversationPaneValueSource<\n CodexConversationPaneController<Payload>\n>;\n\nexport type CodexConversationPaneControllerOptions<Payload = unknown> = {\n state: CodexConversationPaneValueSource<CodexConversationPaneState>;\n actions: CodexConversationPaneValueSource<CodexConversationPaneActions<Payload>>;\n};\n\n/**\n * Creates a stable controlled-view adapter for CodexConversationPane.\n *\n * The adapter only normalizes reactive state and actions. It does not load a\n * conversation, clone messages, or own a backend. Keep the returned object\n * stable and update the supplied state leaves in place when possible.\n */\nexport function createCodexConversationPaneController<Payload = unknown>(\n options: CodexConversationPaneControllerOptions<Payload>,\n): CodexConversationPaneController<Payload> {\n return {\n // Preserve the host source instead of wrapping it in this Vue runtime's\n // computed(). A ref/computed from another Vue package must retain its own\n // dependency graph; the pane resolves the source at render time.\n state: options.state,\n actions: options.actions,\n };\n}\n","import { getMessageToolCallArgs, getMessageToolCallName, type Message, type MessageAttachment, type MessageMedia, type MessagePhase, type MessageToolCall, type MessagePart } from './types'\n\ntype PhasedMessageBlock = {\n phase?: MessagePhase\n}\n\nexport type MessageBlock =\n | { type: 'attachment'; attachment: MessageAttachment }\n | Extract<MessagePart, { type: 'question' }>\n | ({ type: 'text'; content: string } & PhasedMessageBlock)\n | { type: 'user-text'; content: string }\n | ({ type: 'reasoning'; content: string } & PhasedMessageBlock)\n | ({ type: 'mermaid'; code: string } & PhasedMessageBlock)\n | ({ type: 'visualization'; path?: string; title: string } & PhasedMessageBlock)\n | ({ type: 'media'; media: MessageMedia; toolCall?: MessageToolCall } & PhasedMessageBlock)\n | { type: 'tool'; toolCall: MessageToolCall }\n | { type: 'tool-group'; toolCalls: MessageToolCall[]; activityTitle?: string }\n | ({ type: 'follow-ups'; prompts: string[] } & PhasedMessageBlock)\n\nexport type RenderedMessageBlock = MessageBlock | {\n type: 'work-group'\n active: boolean\n blocks: MessageBlock[]\n continuation?: boolean\n finalStarted: boolean\n}\n\ntype CodeBlockRange = {\n start: number\n end: number\n}\n\nconst toolTagRegex = /<tool\\s+(id|index)=\"([^\"]*)\"><\\/tool>/g\nconst markdownImageRegex = /(?<!\\[)!\\[([^\\]]*)\\]\\(([^)\\s]+)(?:\\s+[\"']([^\"']*)[\"'])?\\)/g\nconst contextTagRegex = /<context>[\\s\\S]*?<\\/context>\\s*/g\nconst inAppBrowserContextTagRegex = /<in-app-browser-context(?:\\s+[^>]*)?>[\\s\\S]*?<\\/in-app-browser-context>\\s*/g\nconst ambientRequestHeadingRegex = /^[ \\t]*## My request for Codex:[ \\t]*(?:\\r?\\n|$)/m\nconst followUpTagRegex = /<follow-up>([\\s\\S]*?)<\\/follow-up>/g\nconst visualizationAnnotationRegex = /\\uE200visualize\\uE202([\\s\\S]*?)\\uE201/g\nconst ungroupedToolNames = new Set([\n 'ask_user_question',\n])\n\nexport function computeMessageBlocks(message: Message): MessageBlock[] {\n if (message.role !== 'assistant') {\n if ((message.parts?.length ?? 0) > 0) {\n return message.parts!.flatMap((part): MessageBlock[] => {\n if (part.type === 'attachment') {\n return [{ type: 'attachment', attachment: part.attachment }]\n }\n if (part.type === 'media') {\n return [{ type: 'media', media: part.media }]\n }\n if (part.type === 'text') {\n const content = stripMessageContext(part.content)\n return content ? [{ type: 'user-text', content }] : []\n }\n return []\n })\n }\n\n const content = stripMessageContext(message.content)\n return content ? [{ type: 'user-text', content }] : []\n }\n\n const toolCalls = message.toolCalls ?? []\n const parts = message.parts ?? []\n if (parts.length > 0) {\n return computeMessageBlocksFromParts(parts, toolCalls)\n }\n\n const anchoredToolCallIds = new Set<string>()\n const { blocks, prompts } = parseTextBlocks(message.content, toolCalls, anchoredToolCallIds)\n\n appendUnanchoredTools(blocks, toolCalls, anchoredToolCallIds)\n return finalizeAssistantBlocks(blocks, prompts)\n}\n\nexport function groupAssistantWorkBlocks(\n message: Message,\n blocks: MessageBlock[],\n workActive = message.streaming === true,\n groupWork = hasExplicitAssistantWorkPhases(message),\n answeredClientRequestIds?: ReadonlySet<string>,\n): RenderedMessageBlock[] {\n if (message.role !== 'assistant' || !groupWork) return blocks\n\n const finalStarted = message.parts?.some((part) => (\n part.type === 'text' && part.phase === 'final_answer' && part.content.trim().length > 0\n )) ?? false\n const rendered: RenderedMessageBlock[] = []\n let workBlocks: MessageBlock[] = []\n let workGroupCount = 0\n const flushWork = () => {\n if (workBlocks.length === 0) return\n rendered.push({\n type: 'work-group',\n active: workActive && !finalStarted,\n blocks: workBlocks,\n ...(workGroupCount > 0 ? { continuation: true } : {}),\n finalStarted,\n })\n workBlocks = []\n workGroupCount += 1\n }\n\n for (const block of blocks) {\n if (isAssistantWorkBlock(block, answeredClientRequestIds)) {\n workBlocks.push(block)\n continue\n }\n flushWork()\n rendered.push(block)\n }\n flushWork()\n return workGroupCount > 0 ? rendered : blocks\n}\n\nfunction computeMessageBlocksFromParts(parts: MessagePart[], toolCalls: MessageToolCall[]): MessageBlock[] {\n const blocks: MessageBlock[] = []\n const prompts: string[] = []\n const anchoredToolCallIds = new Set<string>()\n\n for (const [index, part] of parts.entries()) {\n if (part.type === 'tool') {\n anchoredToolCallIds.add(part.toolCall.id)\n blocks.push({ type: 'tool', toolCall: part.toolCall })\n continue\n }\n\n if (part.type === 'attachment') {\n blocks.push({ type: 'attachment', attachment: part.attachment })\n continue\n }\n\n if (part.type === 'media') {\n blocks.push({ type: 'media', media: part.media })\n continue\n }\n\n if (part.type === 'reasoning') {\n if (part.summary.trim()) {\n blocks.push({ type: 'reasoning', content: part.summary, phase: 'commentary' })\n }\n continue\n }\n\n if (part.type === 'question') {\n blocks.push({ ...part })\n continue\n }\n\n const nextPart = parts[index + 1]\n if (nextPart?.type === 'question'\n && nextPart.request.payload.request.questions.some((question) => question.question.trim() === part.content.trim())) {\n continue\n }\n\n const parsed = parseTextBlocks(part.content, toolCalls, anchoredToolCallIds, part.phase)\n blocks.push(...parsed.blocks)\n prompts.push(...parsed.prompts)\n }\n\n appendUnanchoredTools(blocks, toolCalls, anchoredToolCallIds)\n return finalizeAssistantBlocks(blocks, prompts)\n}\n\nfunction parseTextBlocks(\n rawContent: string,\n toolCalls: MessageToolCall[],\n anchoredToolCallIds: Set<string>,\n phase?: MessagePhase,\n) {\n const { content, prompts } = extractFollowUps(completeStreamingCustomTags(rawContent))\n const codeBlocks = findCodeBlocks(content)\n const blocks: MessageBlock[] = []\n let lastIndex = 0\n\n for (const item of findSpecialBlocks(content, codeBlocks)) {\n if (item.start > lastIndex) {\n pushTextBlock(blocks, content.slice(lastIndex, item.start), phase)\n }\n\n if (item.type === 'mermaid') {\n blocks.push({ type: 'mermaid', code: item.code, ...(phase ? { phase } : {}) })\n } else if (item.type === 'visualization') {\n blocks.push({\n type: 'visualization',\n title: item.title,\n ...(item.path ? { path: item.path } : {}),\n ...(phase ? { phase } : {}),\n })\n } else if (item.type === 'tool') {\n const toolCall = findToolCall(item.kind, item.value, toolCalls)\n if (toolCall) {\n anchoredToolCallIds.add(toolCall.id)\n blocks.push({ type: 'tool', toolCall })\n }\n } else {\n const toolCall = findMediaToolCall(item.media, toolCalls)\n if (toolCall) {\n anchoredToolCallIds.add(toolCall.id)\n }\n blocks.push({\n type: 'media',\n media: {\n ...item.media,\n prompt: item.media.prompt ?? getToolCallPrompt(toolCall),\n },\n toolCall,\n ...(phase ? { phase } : {}),\n })\n }\n\n lastIndex = item.end\n }\n\n if (lastIndex < content.length) {\n pushTextBlock(blocks, content.slice(lastIndex), phase)\n }\n\n return { blocks, prompts }\n}\n\nfunction appendUnanchoredTools(blocks: MessageBlock[], toolCalls: MessageToolCall[], anchoredToolCallIds: Set<string>) {\n for (const toolCall of toolCalls) {\n if (!anchoredToolCallIds.has(toolCall.id)) {\n blocks.push({ type: 'tool', toolCall })\n }\n }\n}\n\nfunction finalizeAssistantBlocks(blocks: MessageBlock[], prompts: string[]): MessageBlock[] {\n const grouped = groupToolBlocks(blocks)\n if (prompts.length > 0) {\n grouped.push({ type: 'follow-ups', prompts })\n }\n\n return grouped\n}\n\nexport function stripMessageContext(content: string) {\n const withoutContext = content.replace(contextTagRegex, '')\n const withoutBrowserContext = withoutContext.replace(inAppBrowserContextTagRegex, '')\n return (withoutBrowserContext === withoutContext\n ? withoutBrowserContext\n : withoutBrowserContext.replace(ambientRequestHeadingRegex, ''))\n .trim()\n}\n\nexport function groupToolBlocks(blocks: MessageBlock[]): MessageBlock[] {\n const result: MessageBlock[] = []\n let toolGroup: MessageToolCall[] = []\n let activityTitle: string | undefined\n\n const flushGroup = (showActivityTitle = false) => {\n if (toolGroup.length === 0) {\n if (showActivityTitle && activityTitle) {\n result.push({ type: 'tool-group', toolCalls: [], activityTitle })\n }\n activityTitle = undefined\n return\n }\n\n result.push({\n type: 'tool-group',\n toolCalls: [...toolGroup],\n ...(showActivityTitle && activityTitle ? { activityTitle } : {}),\n })\n toolGroup = []\n activityTitle = undefined\n }\n\n for (const block of blocks) {\n if (block.type === 'reasoning') {\n activityTitle = reasoningActivityTitle(block.content)\n continue\n }\n\n if (block.type === 'tool') {\n if (isUngroupedTool(block.toolCall)) {\n flushGroup()\n result.push(block)\n continue\n }\n\n toolGroup.push(block.toolCall)\n continue\n }\n\n flushGroup()\n result.push(block)\n }\n\n flushGroup(true)\n return result\n}\n\nfunction reasoningActivityTitle(summary: string) {\n const trimmed = summary.trim()\n const emphasized = /^\\*\\*([\\s\\S]*)\\*\\*$/u.exec(trimmed)?.[1]\n ?? /^__([\\s\\S]*)__$/u.exec(trimmed)?.[1]\n ?? trimmed\n return emphasized.trim().replace(/\\s+/gu, ' ')\n}\n\nfunction isUngroupedTool(toolCall: MessageToolCall) {\n if (ungroupedToolNames.has(getMessageToolCallName(toolCall))) {\n return true\n }\n\n const status = parseToolStatus(toolCall.status)\n if (status?.source === 'codex' && status.action === 'plan') {\n return true\n }\n\n return (status?.source === 'mcp' || status?.source === 'home') &&\n typeof status.params?.requestId === 'string' &&\n toolCall.state === 'running'\n}\n\nfunction parseToolStatus(status: unknown) {\n if (typeof status !== 'string' || !status.startsWith('{')) {\n return undefined\n }\n\n try {\n return JSON.parse(status) as {\n action?: unknown\n params?: Record<string, unknown>\n source?: unknown\n }\n } catch {\n return undefined\n }\n}\n\nfunction pushTextBlock(blocks: MessageBlock[], content: string, phase?: MessagePhase) {\n if (content.trim()) {\n blocks.push({ type: 'text', content, ...(phase ? { phase } : {}) })\n }\n}\n\nexport function hasExplicitAssistantWorkPhases(message: Message) {\n return message.parts?.some((part) => (\n part.type === 'reasoning' || (part.type === 'text' && part.phase !== undefined)\n )) ?? false\n}\n\nexport function isAssistantWorkBlock(block: MessageBlock, answeredClientRequestIds?: ReadonlySet<string>) {\n if (block.type === 'question') return block.historical === true || answeredClientRequestIds?.has(block.request.id) === true\n if (block.type === 'reasoning' || block.type === 'tool' || block.type === 'tool-group') return true\n if (block.type === 'media') return false\n return 'phase' in block && block.phase === 'commentary'\n}\n\nfunction extractFollowUps(content: string) {\n const prompts: string[] = []\n const stripped = content.replace(followUpTagRegex, (_match, prompt: string) => {\n const trimmed = prompt.trim()\n if (trimmed) {\n prompts.push(trimmed)\n }\n return ''\n })\n\n return { content: stripped, prompts }\n}\n\nfunction completeStreamingCustomTags(content: string) {\n return completeStreamingToolTag(completeStreamingPairedTag(content, 'follow-up'))\n}\n\nfunction completeStreamingPairedTag(content: string, tagName: string) {\n const openTag = `<${tagName}>`\n const closeTag = `</${tagName}>`\n const openIndex = content.lastIndexOf(openTag)\n const closeIndex = content.lastIndexOf(closeTag)\n if (openIndex <= closeIndex) {\n return content\n }\n\n const partialCloseIndex = content.lastIndexOf('</')\n if (partialCloseIndex > openIndex && closeTag.startsWith(content.slice(partialCloseIndex))) {\n return `${content.slice(0, partialCloseIndex)}${closeTag}`\n }\n\n return `${content}${closeTag}`\n}\n\nfunction completeStreamingToolTag(content: string) {\n const openIndex = content.lastIndexOf('<tool')\n const closeIndex = content.lastIndexOf('</tool>')\n if (openIndex <= closeIndex) {\n return content\n }\n\n const beforeTool = content.slice(0, openIndex)\n const toolText = content.slice(openIndex)\n const closeTag = '</tool>'\n const partialCloseIndex = toolText.lastIndexOf('</')\n const openingText = partialCloseIndex >= 0 ? toolText.slice(0, partialCloseIndex) : toolText\n const openingEnd = openingText.indexOf('>')\n\n if (openingEnd === -1) {\n const attributeMatch = openingText.match(/^<tool\\s+(id|index)=\"([^\"]*)\"$/)\n return attributeMatch ? `${beforeTool}${openingText}>${closeTag}` : beforeTool\n }\n\n const completedOpening = openingText.slice(0, openingEnd + 1)\n const trailingText = openingText.slice(openingEnd + 1)\n return `${beforeTool}${completedOpening}${closeTag}${trailingText}`\n}\n\nfunction findToolCall(kind: string, value: string, toolCalls: MessageToolCall[]) {\n if (kind === 'id') {\n return toolCalls.find((toolCall) => toolCall.id === value)\n }\n\n return toolCalls[Number.parseInt(value, 10)]\n}\n\nfunction findMediaToolCall(media: MessageMedia, toolCalls: MessageToolCall[]) {\n return toolCalls.find((toolCall) => {\n if (getMessageToolCallName(toolCall) !== 'image_generation') {\n return false\n }\n\n const resultUrl = getToolCallResultString(toolCall, 'url')\n const resultExternalUrl = getToolCallResultString(toolCall, 'externalUrl')\n const resultPath = getToolCallResultString(toolCall, 'path')\n return media.url === resultUrl || media.url === resultExternalUrl || media.url === resultPath\n })\n}\n\nfunction getToolCallPrompt(toolCall?: MessageToolCall) {\n return getToolCallResultString(toolCall, 'prompt') ?? getToolCallParamString(toolCall, 'prompt')\n}\n\nfunction getToolCallResultString(toolCall: MessageToolCall | undefined, key: string) {\n const result = toolCall?.result\n if (!result || typeof result !== 'object' || Array.isArray(result)) {\n return undefined\n }\n\n const value = (result as Record<string, unknown>)[key]\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction getToolCallParamString(toolCall: MessageToolCall | undefined, key: string) {\n const params = toolCall ? getMessageToolCallArgs(toolCall) : undefined\n if (!params || typeof params !== 'object' || Array.isArray(params)) {\n return undefined\n }\n\n const value = (params as Record<string, unknown>)[key]\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\ntype SpecialBlock =\n | { type: 'tool'; start: number; end: number; kind: string; value: string }\n | { type: 'mermaid'; start: number; end: number; code: string }\n | { type: 'visualization'; start: number; end: number; path?: string; title: string }\n | { type: 'media'; start: number; end: number; media: MessageMedia }\n\nfunction findSpecialBlocks(content: string, codeBlocks: CodeBlockRange[]) {\n const blocks: SpecialBlock[] = []\n\n for (const block of findMermaidCodeBlocks(content)) {\n blocks.push(block)\n }\n\n for (const match of content.matchAll(visualizationAnnotationRegex)) {\n const start = match.index\n if (isInsideCodeBlock(start, codeBlocks)) continue\n const payload = visualizationPayload(match[1]!)\n blocks.push({\n end: start + match[0].length,\n start,\n title: payload?.title ?? 'Visualization',\n ...(payload?.path ? { path: payload.path } : {}),\n type: 'visualization',\n })\n }\n\n for (const match of content.matchAll(toolTagRegex)) {\n const start = match.index\n if (isInsideCodeBlock(start, codeBlocks)) {\n continue\n }\n\n const kind = match[1]\n const value = match[2]\n if (!kind || !value) {\n continue\n }\n\n blocks.push({\n end: start + match[0].length,\n kind,\n start,\n type: 'tool',\n value\n })\n }\n\n for (const match of content.matchAll(markdownImageRegex)) {\n const start = match.index\n if (isInsideCodeBlock(start, codeBlocks)) {\n continue\n }\n\n const alt = match[1]!.trim()\n const url = match[2]!\n const title = match[3]?.trim()\n blocks.push({\n end: start + match[0].length,\n media: {\n alt: alt || undefined,\n title: title || alt || undefined,\n url\n },\n start,\n type: 'media'\n })\n }\n\n return blocks.sort((first, second) => first.start - second.start)\n}\n\nfunction visualizationPayload(value: string): { path?: string; title: string } | null {\n try {\n const payload = JSON.parse(value) as { path?: unknown; title?: unknown }\n const title = typeof payload.title === 'string' && payload.title.trim()\n ? payload.title.trim()\n : 'Visualization'\n const path = typeof payload.path === 'string' && payload.path.trim()\n ? payload.path.trim()\n : undefined\n return { title, ...(path ? { path } : {}) }\n } catch {\n return null\n }\n}\n\nfunction findMermaidCodeBlocks(content: string): SpecialBlock[] {\n const blocks: SpecialBlock[] = []\n const fenceRegex = /(^|\\n)(```|~~~)[ \\t]*mermaid[^\\n]*\\n/gi\n let match: RegExpExecArray | null\n\n while ((match = fenceRegex.exec(content)) !== null) {\n const fence = match[2]!\n const prefix = match[1]!\n const start = match.index + prefix.length\n const codeStart = start + match[0].length - prefix.length\n const closeRegex = new RegExp(`(^|\\\\n)${escapeRegex(fence)}[ \\\\t]*(?=\\\\n|$)`, 'g')\n closeRegex.lastIndex = codeStart\n const close = closeRegex.exec(content)\n\n if (!close) {\n continue\n }\n\n const codeEnd = close.index\n const end = close.index + close[0].length\n const code = content.slice(codeStart, codeEnd).trim()\n if (code) {\n blocks.push({ code, end, start, type: 'mermaid' })\n }\n fenceRegex.lastIndex = end\n }\n\n return blocks\n}\n\nfunction findCodeBlocks(content: string): CodeBlockRange[] {\n const ranges: CodeBlockRange[] = []\n const fenceRegex = /(^|\\n)(```|~~~)/g\n let match: RegExpExecArray | null\n\n while ((match = fenceRegex.exec(content)) !== null) {\n const fence = match[2]!\n const prefix = match[1]!\n const start = match.index + prefix.length\n const closeRegex = new RegExp(`(^|\\\\n)${escapeRegex(fence)}`, 'g')\n closeRegex.lastIndex = start + fence.length\n const close = closeRegex.exec(content)\n\n if (!close) {\n ranges.push({ start, end: content.length })\n break\n }\n\n const end = close.index + close[1]!.length + fence.length\n ranges.push({ start, end })\n fenceRegex.lastIndex = end\n }\n\n return ranges\n}\n\nfunction isInsideCodeBlock(index: number, ranges: CodeBlockRange[]) {\n return ranges.some((range) => index >= range.start && index <= range.end)\n}\n\nfunction escapeRegex(value: string) {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n","import type { SurfaceMessage, SurfaceMessagePart } from '@codex-app-sdk/core/surface';\nimport type { Message, MessagePart, MessageToolCall, ToolExecutionState } from './types';\n\nexport type ChatMessageInput = Message | SurfaceMessage;\n\nexport function chatMessagesFromInputs(messages: readonly ChatMessageInput[]): Message[] {\n return messages.map(chatMessageFromInput);\n}\n\nexport function chatMessageFromInput(message: ChatMessageInput): Message {\n return settleTerminalMessageToolCalls(\n 'content' in message ? message : surfaceMessageToChatMessage(message),\n );\n}\n\nexport function surfaceMessageToChatMessage(message: SurfaceMessage): Message {\n const contentParts: string[] = [];\n const parts: MessagePart[] = [];\n const toolCalls: MessageToolCall[] = [];\n const turnId = message.turnId ?? stringMetadata(message.metadata, 'turnId');\n\n for (const part of message.parts) {\n if (part.type === 'tool') {\n const toolCall = rendererToolPartToToolCall(message, part, toolCalls.length);\n toolCalls.push(toolCall);\n parts.push({ type: 'tool', toolCall });\n } else if (part.type === 'attachment') {\n parts.push({\n type: 'attachment',\n attachment: { ...part.attachment },\n });\n } else if (part.type === 'media') {\n parts.push({\n type: 'media',\n media: { ...part.media },\n });\n } else if (part.type === 'reasoning') {\n parts.push({\n type: 'reasoning',\n summary: part.summary,\n itemId: part.itemId,\n summaryIndex: part.summaryIndex,\n });\n } else if (part.type === 'question') {\n parts.push({ ...part });\n } else if (part.type === 'text') {\n contentParts.push(part.text);\n parts.push({\n type: 'text',\n content: part.text,\n ...(part.itemId ? { itemId: part.itemId } : {}),\n ...(part.phase ? { phase: part.phase } : {}),\n });\n } else {\n contentParts.push(part.text);\n parts.push({ type: 'text', content: part.text });\n }\n }\n\n return settleTerminalMessageToolCalls({\n content: contentParts.join('\\n\\n'),\n createdAt: message.createdAt,\n id: message.id,\n parts,\n role: message.role === 'user' ? 'user' : 'assistant',\n streaming: message.status === 'streaming',\n toolCalls,\n ...(turnId ? { turnId } : {}),\n ...(message.kind === 'compaction' ? { compactionStatus: message.status === 'streaming' ? 'running' : 'completed' } : {}),\n type: message.kind === 'compaction' ? 'compaction' : message.kind === 'steer' ? 'steer' : 'text',\n });\n}\n\nfunction settleTerminalMessageToolCalls(message: Message): Message {\n if (message.streaming === true) return message;\n\n const settledCalls = new Map<MessageToolCall, MessageToolCall>();\n let changed = false;\n const settle = (toolCall: MessageToolCall): MessageToolCall => {\n const cached = settledCalls.get(toolCall);\n if (cached) return cached;\n if (toolCall.done === true && toolCall.state !== 'running') {\n return toolCall;\n }\n\n changed = true;\n const settled = {\n ...toolCall,\n done: true,\n ...(toolCall.state === 'running' ? {\n state: 'error' as const,\n status: terminalToolStatus(toolCall.status),\n } : {}),\n };\n settledCalls.set(toolCall, settled);\n return settled;\n };\n\n const toolCalls = message.toolCalls?.map(settle);\n const parts = message.parts?.map((part) => (\n part.type === 'tool' ? { ...part, toolCall: settle(part.toolCall) } : part\n ));\n return changed ? { ...message, parts, toolCalls } : message;\n}\n\nfunction terminalToolStatus(status: string | undefined): string {\n if (status?.trim().startsWith('{')) {\n try {\n const descriptor = JSON.parse(status) as Record<string, unknown>;\n return JSON.stringify({ ...descriptor, phase: 'failed' });\n } catch {\n // A stale running label is less useful than a stable terminal fallback.\n }\n }\n return 'failed';\n}\n\nfunction rendererToolPartToToolCall(message: SurfaceMessage, part: Extract<SurfaceMessagePart, { type: 'tool' }>, index: number): MessageToolCall {\n const turnId = message.turnId ?? stringMetadata(message.metadata, 'turnId');\n return {\n args: part.input ?? (part.body ? { output: part.body } : undefined),\n done: part.status !== 'running',\n function: part.title,\n id: part.id || `${message.id}-tool-${index}`,\n ...(part.kind ? { kind: part.kind } : {}),\n itemId: part.id || `${message.id}-tool-${index}`,\n messageId: message.id,\n ...(part.metadata ? { metadata: { ...part.metadata } } : {}),\n result: rendererToolPartResult(part),\n state: rendererToolStatusToState(part.status),\n status: part.statusText ?? part.status,\n ...(turnId ? { turnId } : {}),\n };\n}\n\nfunction stringMetadata(metadata: Record<string, unknown> | undefined, key: string): string | undefined {\n const value = metadata?.[key];\n return typeof value === 'string' && value ? value : undefined;\n}\n\nfunction rendererToolPartResult(part: Extract<SurfaceMessagePart, { type: 'tool' }>): unknown {\n if (isRecord(part.output) && 'structuredContent' in part.output) {\n return part.output.structuredContent;\n }\n\n return part.body ?? part.output;\n}\n\nfunction rendererToolStatusToState(status: Extract<SurfaceMessagePart, { type: 'tool' }>['status']): ToolExecutionState {\n if (status === 'running') {\n return 'running';\n }\n\n return status === 'failed' ? 'error' : 'completed';\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","import {\n onBeforeUnmount,\n onMounted,\n ref,\n watch,\n type Ref,\n} from 'vue';\n\ntype ConversationEscapeInterruptOptions = {\n root: Readonly<Ref<HTMLElement | null>>;\n busy(): boolean;\n enabled(): boolean;\n onInterrupt(): void;\n};\n\nexport function useConversationEscapeInterrupt(options: ConversationEscapeInterruptOptions): {\n armed: Ref<boolean>;\n clear(): void;\n} {\n const armed = ref(false);\n let clearTimer: ReturnType<typeof setTimeout> | null = null;\n let listenerInstalled = false;\n\n watch([options.busy, options.enabled], () => {\n clear();\n syncListener();\n });\n\n onMounted(syncListener);\n onBeforeUnmount(() => {\n clear();\n removeListener();\n });\n\n function syncListener(): void {\n const shouldListen = options.busy() && options.enabled();\n if (shouldListen && !listenerInstalled) {\n document.addEventListener('keydown', handleKeydown);\n listenerInstalled = true;\n } else {\n removeListener();\n }\n }\n\n function removeListener(): void {\n if (!listenerInstalled) return;\n document.removeEventListener('keydown', handleKeydown);\n listenerInstalled = false;\n }\n\n function handleKeydown(event: KeyboardEvent): void {\n if (\n event.key !== 'Escape'\n || event.defaultPrevented\n || event.repeat\n || event.isComposing\n || event.altKey\n || event.ctrlKey\n || event.metaKey\n || event.shiftKey\n || !options.busy()\n || isInsideModalDialog(event)\n ) return;\n\n const root = options.root.value;\n if (!root?.isConnected) return;\n const focusedInside = Boolean(root && document.activeElement && root.contains(document.activeElement));\n const generatingPanes = document.querySelectorAll('[data-codex-generating=\"true\"]');\n if (!focusedInside && generatingPanes.length !== 1) return;\n\n event.preventDefault();\n if (!armed.value) {\n armed.value = true;\n clearTimer = setTimeout(clear, 2_000);\n return;\n }\n\n clear();\n options.onInterrupt();\n }\n\n function isInsideModalDialog(event: KeyboardEvent): boolean {\n const target = event.target instanceof Element ? event.target : document.activeElement;\n return Boolean(target instanceof Element && target.closest('[role=\"dialog\"][aria-modal=\"true\"]'));\n }\n\n function clear(): void {\n armed.value = false;\n if (clearTimer) clearTimeout(clearTimer);\n clearTimer = null;\n }\n\n return { armed, clear };\n}\n","import type { ComputedRef, InjectionKey, Ref } from 'vue'\nimport type { CodexSurfaceTurnStatus } from '@codex-app-sdk/core/surface'\nimport type { ClientRequestResponse } from './contracts'\n\nexport const questionResponsesKey: InjectionKey<Map<string, ClientRequestResponse['payload']>> = Symbol('codex-app-sdk-question-responses')\n\nexport type AssistantWorkTurnContext = {\n active: ComputedRef<boolean>\n completedWithoutFinal: ComputedRef<boolean>\n enabled: ComputedRef<boolean>\n expanded: Ref<boolean>\n finalStarted: ComputedRef<boolean>\n headerMessageIndex: ComputedRef<number | undefined>\n latestStreamingAssistantIndex: ComputedRef<number | undefined>\n phased: ComputedRef<boolean>\n status: ComputedRef<CodexSurfaceTurnStatus | undefined>\n turnId: ComputedRef<string | undefined>\n toggle: () => void\n}\n\nexport const assistantWorkTurnKey: InjectionKey<AssistantWorkTurnContext> = Symbol('codex-app-sdk-assistant-work-turn')\nexport const assistantWorkMessageIndexKey: InjectionKey<ComputedRef<number>> = Symbol('codex-app-sdk-assistant-work-message-index')\n","<template>\n <span\n class=\"codex-chat-theme chat-animated-diff-stat\"\n :class=\"`chat-animated-diff-stat--${kind}`\"\n :aria-label=\"labelText\"\n >\n <span class=\"chat-animated-diff-stat__sign\">{{ sign }}</span>\n <span class=\"chat-animated-diff-stat__digits\">\n <span\n v-for=\"column in digitColumns\"\n :key=\"column.place\"\n class=\"chat-animated-diff-stat__digit-column\"\n >\n <Transition name=\"chat-animated-diff-stat__digit\">\n <span\n :key=\"`${column.place}-${column.digit}`\"\n class=\"chat-animated-diff-stat__digit\"\n >\n {{ column.digit }}\n </span>\n </Transition>\n </span>\n </span>\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n kind: 'added' | 'deleted'\n label: string\n value: number\n}>()\n// Stryker restore all\n\nconst sign = computed(() => (props.kind === 'added' ? '+' : '-'))\n\nconst normalizedValue = computed(() => {\n if (!Number.isFinite(props.value)) {\n return 0\n }\n return Math.max(0, Math.trunc(props.value))\n})\n\nconst digitColumns = computed(() => {\n const digits = String(normalizedValue.value).split('')\n return digits.map((digit, index) => ({\n digit,\n place: digits.length - index - 1,\n }))\n})\n\nconst labelText = computed(() => `${props.label}: ${sign.value}${normalizedValue.value}`)\n</script>\n\n<style scoped>\n.chat-animated-diff-stat {\n display: inline-flex;\n align-items: center;\n color: var(--color-text-muted);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-13);\n line-height: var(--line-height-16);\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n}\n\n.chat-animated-diff-stat--added {\n color: var(--color-success);\n}\n\n.chat-animated-diff-stat--deleted {\n color: var(--color-error);\n}\n\n.chat-animated-diff-stat__sign {\n flex: 0 0 auto;\n}\n\n.chat-animated-diff-stat__digits {\n display: inline-flex;\n align-items: center;\n}\n\n.chat-animated-diff-stat__digit-column {\n position: relative;\n display: inline-block;\n width: 1ch;\n height: 1.25em;\n overflow: hidden;\n vertical-align: top;\n}\n\n.chat-animated-diff-stat__digit {\n position: absolute;\n inset: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.chat-animated-diff-stat__digit-enter-active,\n.chat-animated-diff-stat__digit-leave-active {\n transition:\n transform 180ms ease-out,\n opacity 180ms ease-out;\n}\n\n.chat-animated-diff-stat__digit-enter-from {\n opacity: 0;\n transform: translateY(100%);\n}\n\n.chat-animated-diff-stat__digit-leave-to {\n opacity: 0;\n transform: translateY(-100%);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .chat-animated-diff-stat__digit-enter-active,\n .chat-animated-diff-stat__digit-leave-active {\n transition: none;\n }\n}\n</style>\n","<template>\n <span\n class=\"codex-chat-theme chat-animated-diff-stat\"\n :class=\"`chat-animated-diff-stat--${kind}`\"\n :aria-label=\"labelText\"\n >\n <span class=\"chat-animated-diff-stat__sign\">{{ sign }}</span>\n <span class=\"chat-animated-diff-stat__digits\">\n <span\n v-for=\"column in digitColumns\"\n :key=\"column.place\"\n class=\"chat-animated-diff-stat__digit-column\"\n >\n <Transition name=\"chat-animated-diff-stat__digit\">\n <span\n :key=\"`${column.place}-${column.digit}`\"\n class=\"chat-animated-diff-stat__digit\"\n >\n {{ column.digit }}\n </span>\n </Transition>\n </span>\n </span>\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n kind: 'added' | 'deleted'\n label: string\n value: number\n}>()\n// Stryker restore all\n\nconst sign = computed(() => (props.kind === 'added' ? '+' : '-'))\n\nconst normalizedValue = computed(() => {\n if (!Number.isFinite(props.value)) {\n return 0\n }\n return Math.max(0, Math.trunc(props.value))\n})\n\nconst digitColumns = computed(() => {\n const digits = String(normalizedValue.value).split('')\n return digits.map((digit, index) => ({\n digit,\n place: digits.length - index - 1,\n }))\n})\n\nconst labelText = computed(() => `${props.label}: ${sign.value}${normalizedValue.value}`)\n</script>\n\n<style scoped>\n.chat-animated-diff-stat {\n display: inline-flex;\n align-items: center;\n color: var(--color-text-muted);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-13);\n line-height: var(--line-height-16);\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n}\n\n.chat-animated-diff-stat--added {\n color: var(--color-success);\n}\n\n.chat-animated-diff-stat--deleted {\n color: var(--color-error);\n}\n\n.chat-animated-diff-stat__sign {\n flex: 0 0 auto;\n}\n\n.chat-animated-diff-stat__digits {\n display: inline-flex;\n align-items: center;\n}\n\n.chat-animated-diff-stat__digit-column {\n position: relative;\n display: inline-block;\n width: 1ch;\n height: 1.25em;\n overflow: hidden;\n vertical-align: top;\n}\n\n.chat-animated-diff-stat__digit {\n position: absolute;\n inset: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.chat-animated-diff-stat__digit-enter-active,\n.chat-animated-diff-stat__digit-leave-active {\n transition:\n transform 180ms ease-out,\n opacity 180ms ease-out;\n}\n\n.chat-animated-diff-stat__digit-enter-from {\n opacity: 0;\n transform: translateY(100%);\n}\n\n.chat-animated-diff-stat__digit-leave-to {\n opacity: 0;\n transform: translateY(-100%);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .chat-animated-diff-stat__digit-enter-active,\n .chat-animated-diff-stat__digit-leave-active {\n transition: none;\n }\n}\n</style>\n","<template>\n <component\n v-if=\"resolvedIcon\"\n :is=\"resolvedIcon\"\n class=\"chat-tool-icon\"\n aria-hidden=\"true\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, type Component } from 'vue'\nimport {\n FileTextIcon,\n FolderIcon,\n ListDetailsIcon,\n PencilIcon,\n PhotoIcon,\n SearchIcon,\n Terminal2Icon,\n ToolIcon,\n Trash2Icon,\n WorldSearchIcon,\n} from '../icons/app-icons'\nimport type { CodexToolPresentation } from './tool-presentation'\nimport { parseToolStatusDescriptor } from './tool-status'\nimport { isImageGenerationToolCall, type MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n presentation?: CodexToolPresentation\n toolCall: MessageToolCall\n}>()\n// Stryker restore all\n\nconst resolvedIcon = computed<Component | undefined>(() => {\n if (props.presentation?.icon === null) return undefined\n if (props.presentation?.icon) return props.presentation.icon\n\n if (isImageGenerationToolCall(props.toolCall)) return PhotoIcon\n if (props.toolCall.kind === 'webSearch') return WorldSearchIcon\n\n const descriptor = parseToolStatusDescriptor(props.toolCall.status)\n if (descriptor) {\n switch (descriptor.action) {\n case 'create': return PencilIcon\n case 'delete': return Trash2Icon\n case 'edit': return PencilIcon\n case 'explore':\n case 'list': return FolderIcon\n case 'plan': return ListDetailsIcon\n case 'read': return FileTextIcon\n case 'run': return Terminal2Icon\n case 'search': return SearchIcon\n }\n }\n\n return isCommandLikeToolCall(props.toolCall) ? Terminal2Icon : ToolIcon\n})\n\nfunction isCommandLikeToolCall(toolCall: MessageToolCall): boolean {\n if (toolCall.kind === 'command') return true\n if (isRecord(toolCall.args) && typeof toolCall.args.command === 'string') return true\n\n return [toolCall.function, toolCall.status].some((value) => (\n typeof value === 'string'\n && /(?:^|\\s)(?:\\/bin\\/)?(?:bash|cmd|fish|powershell|pwsh|sh|zsh)(?:\\s|$)/i.test(value)\n ))\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n</script>\n\n<style scoped>\n.chat-tool-icon {\n width: 15px;\n height: 15px;\n}\n</style>\n","<template>\n <component\n v-if=\"resolvedIcon\"\n :is=\"resolvedIcon\"\n class=\"chat-tool-icon\"\n aria-hidden=\"true\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, type Component } from 'vue'\nimport {\n FileTextIcon,\n FolderIcon,\n ListDetailsIcon,\n PencilIcon,\n PhotoIcon,\n SearchIcon,\n Terminal2Icon,\n ToolIcon,\n Trash2Icon,\n WorldSearchIcon,\n} from '../icons/app-icons'\nimport type { CodexToolPresentation } from './tool-presentation'\nimport { parseToolStatusDescriptor } from './tool-status'\nimport { isImageGenerationToolCall, type MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n presentation?: CodexToolPresentation\n toolCall: MessageToolCall\n}>()\n// Stryker restore all\n\nconst resolvedIcon = computed<Component | undefined>(() => {\n if (props.presentation?.icon === null) return undefined\n if (props.presentation?.icon) return props.presentation.icon\n\n if (isImageGenerationToolCall(props.toolCall)) return PhotoIcon\n if (props.toolCall.kind === 'webSearch') return WorldSearchIcon\n\n const descriptor = parseToolStatusDescriptor(props.toolCall.status)\n if (descriptor) {\n switch (descriptor.action) {\n case 'create': return PencilIcon\n case 'delete': return Trash2Icon\n case 'edit': return PencilIcon\n case 'explore':\n case 'list': return FolderIcon\n case 'plan': return ListDetailsIcon\n case 'read': return FileTextIcon\n case 'run': return Terminal2Icon\n case 'search': return SearchIcon\n }\n }\n\n return isCommandLikeToolCall(props.toolCall) ? Terminal2Icon : ToolIcon\n})\n\nfunction isCommandLikeToolCall(toolCall: MessageToolCall): boolean {\n if (toolCall.kind === 'command') return true\n if (isRecord(toolCall.args) && typeof toolCall.args.command === 'string') return true\n\n return [toolCall.function, toolCall.status].some((value) => (\n typeof value === 'string'\n && /(?:^|\\s)(?:\\/bin\\/)?(?:bash|cmd|fish|powershell|pwsh|sh|zsh)(?:\\s|$)/i.test(value)\n ))\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null\n}\n</script>\n\n<style scoped>\n.chat-tool-icon {\n width: 15px;\n height: 15px;\n}\n</style>\n","<template>\n <span\n class=\"codex-chat-theme chat-tool-call__title\"\n :class=\"{ 'chat-tool-call__title--running': running, 'codex-text-shimmer': running }\"\n :data-label=\"title\"\n >\n <component v-if=\"icon\" :is=\"icon\" />\n <ChatToolIcon\n v-else-if=\"toolCall\"\n :presentation=\"toolPresentation\"\n :tool-call=\"toolCall\"\n />\n <span\n v-if=\"titlePrefix && titleTarget\"\n class=\"chat-tool-call__title-content chat-tool-call__title-text\"\n >\n <span>{{ titlePrefix }}</span>{{ ' ' }}<span class=\"chat-tool-call__title-target-list\">\n <template v-if=\"titleTargetParts?.length\">\n <template v-for=\"(part, index) in titleTargetParts\" :key=\"`${part.label}-${index}`\">\n <span v-if=\"part.separator\" class=\"chat-tool-call__title-target-separator\">{{ part.separator }}</span><a\n v-if=\"part.link\"\n class=\"chat-tool-call__title-target chat-tool-call__title-target--link\"\n :href=\"part.link.href\"\n @click.stop.prevent=\"emit('open-link', part.link)\"\n @keydown.enter.stop.prevent=\"emit('open-link', part.link)\"\n @keydown.space.stop.prevent=\"emit('open-link', part.link)\"\n >{{ part.label }}</a><span v-else class=\"chat-tool-call__title-target\">{{ part.label }}</span><span v-if=\"part.suffix\">{{ part.suffix }}</span>\n </template>\n </template>\n <a\n v-else-if=\"titleTargetLink\"\n class=\"chat-tool-call__title-target chat-tool-call__title-target--link\"\n :href=\"titleTargetLink.href\"\n @click.stop.prevent=\"emit('open-link', titleTargetLink)\"\n @keydown.enter.stop.prevent=\"emit('open-link', titleTargetLink)\"\n @keydown.space.stop.prevent=\"emit('open-link', titleTargetLink)\"\n >{{ titleTarget }}</a>\n <span v-else class=\"chat-tool-call__title-target\">{{ titleTarget }}</span>\n </span>\n </span>\n <span v-else class=\"chat-tool-call__title-content\">\n {{ title }}\n </span>\n </span>\n <span v-if=\"lineDiff\" class=\"codex-chat-theme chat-tool-call__diff\" aria-label=\"Line changes\">\n <ChatAnimatedDiffStat\n v-if=\"lineDiff.addedLines\"\n kind=\"added\"\n label=\"Added lines\"\n :value=\"lineDiff.addedLines\"\n />\n <ChatAnimatedDiffStat\n v-if=\"lineDiff.removedLines\"\n kind=\"deleted\"\n label=\"Removed lines\"\n :value=\"lineDiff.removedLines\"\n />\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport ChatAnimatedDiffStat from './ChatAnimatedDiffStat.vue'\nimport ChatToolIcon from './ChatToolIcon.vue'\nimport type { CodexConversationLink } from './contracts'\nimport type { CodexToolDisplayTargetPart, ToolLineDiff } from './tool-status'\nimport type { CodexToolPresentation } from './tool-presentation'\nimport type { MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n lineDiff?: ToolLineDiff\n running?: boolean\n title: string\n titlePrefix?: string\n titleTarget?: string\n titleTargetLink?: CodexConversationLink\n titleTargetParts?: readonly CodexToolDisplayTargetPart[]\n icon?: any\n toolCall?: MessageToolCall\n toolPresentation?: CodexToolPresentation\n}>()\n\nconst emit = defineEmits<{\n 'open-link': [link: CodexConversationLink]\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-tool-call__diff {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-tool-call__title {\n display: inline-flex;\n flex: 0 1 auto;\n align-items: center;\n gap: var(--space-3);\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n font-size: var(--font-size-15);\n line-height: var(--line-height-20);\n font-weight: var(--font-weight-light);\n}\n\n.chat-tool-call__title svg {\n flex-shrink: 0;\n width: 15px;\n height: 15px;\n}\n\n.chat-tool-call__title--running {\n color: var(--color-text-muted);\n}\n\n.chat-tool-call__title-content {\n display: block;\n flex: 1 1 auto;\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-tool-call__title-target-list {\n display: inline;\n min-width: 0;\n}\n\n.chat-tool-call__title-target-separator {\n white-space: pre;\n}\n\n.chat-tool-call__title-target--link {\n color: var(--color-secondary);\n font-weight: var(--font-weight-regular);\n cursor: pointer;\n text-decoration: none;\n}\n</style>\n","<template>\n <span\n class=\"codex-chat-theme chat-tool-call__title\"\n :class=\"{ 'chat-tool-call__title--running': running, 'codex-text-shimmer': running }\"\n :data-label=\"title\"\n >\n <component v-if=\"icon\" :is=\"icon\" />\n <ChatToolIcon\n v-else-if=\"toolCall\"\n :presentation=\"toolPresentation\"\n :tool-call=\"toolCall\"\n />\n <span\n v-if=\"titlePrefix && titleTarget\"\n class=\"chat-tool-call__title-content chat-tool-call__title-text\"\n >\n <span>{{ titlePrefix }}</span>{{ ' ' }}<span class=\"chat-tool-call__title-target-list\">\n <template v-if=\"titleTargetParts?.length\">\n <template v-for=\"(part, index) in titleTargetParts\" :key=\"`${part.label}-${index}`\">\n <span v-if=\"part.separator\" class=\"chat-tool-call__title-target-separator\">{{ part.separator }}</span><a\n v-if=\"part.link\"\n class=\"chat-tool-call__title-target chat-tool-call__title-target--link\"\n :href=\"part.link.href\"\n @click.stop.prevent=\"emit('open-link', part.link)\"\n @keydown.enter.stop.prevent=\"emit('open-link', part.link)\"\n @keydown.space.stop.prevent=\"emit('open-link', part.link)\"\n >{{ part.label }}</a><span v-else class=\"chat-tool-call__title-target\">{{ part.label }}</span><span v-if=\"part.suffix\">{{ part.suffix }}</span>\n </template>\n </template>\n <a\n v-else-if=\"titleTargetLink\"\n class=\"chat-tool-call__title-target chat-tool-call__title-target--link\"\n :href=\"titleTargetLink.href\"\n @click.stop.prevent=\"emit('open-link', titleTargetLink)\"\n @keydown.enter.stop.prevent=\"emit('open-link', titleTargetLink)\"\n @keydown.space.stop.prevent=\"emit('open-link', titleTargetLink)\"\n >{{ titleTarget }}</a>\n <span v-else class=\"chat-tool-call__title-target\">{{ titleTarget }}</span>\n </span>\n </span>\n <span v-else class=\"chat-tool-call__title-content\">\n {{ title }}\n </span>\n </span>\n <span v-if=\"lineDiff\" class=\"codex-chat-theme chat-tool-call__diff\" aria-label=\"Line changes\">\n <ChatAnimatedDiffStat\n v-if=\"lineDiff.addedLines\"\n kind=\"added\"\n label=\"Added lines\"\n :value=\"lineDiff.addedLines\"\n />\n <ChatAnimatedDiffStat\n v-if=\"lineDiff.removedLines\"\n kind=\"deleted\"\n label=\"Removed lines\"\n :value=\"lineDiff.removedLines\"\n />\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport ChatAnimatedDiffStat from './ChatAnimatedDiffStat.vue'\nimport ChatToolIcon from './ChatToolIcon.vue'\nimport type { CodexConversationLink } from './contracts'\nimport type { CodexToolDisplayTargetPart, ToolLineDiff } from './tool-status'\nimport type { CodexToolPresentation } from './tool-presentation'\nimport type { MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n lineDiff?: ToolLineDiff\n running?: boolean\n title: string\n titlePrefix?: string\n titleTarget?: string\n titleTargetLink?: CodexConversationLink\n titleTargetParts?: readonly CodexToolDisplayTargetPart[]\n icon?: any\n toolCall?: MessageToolCall\n toolPresentation?: CodexToolPresentation\n}>()\n\nconst emit = defineEmits<{\n 'open-link': [link: CodexConversationLink]\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-tool-call__diff {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-tool-call__title {\n display: inline-flex;\n flex: 0 1 auto;\n align-items: center;\n gap: var(--space-3);\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n font-size: var(--font-size-15);\n line-height: var(--line-height-20);\n font-weight: var(--font-weight-light);\n}\n\n.chat-tool-call__title svg {\n flex-shrink: 0;\n width: 15px;\n height: 15px;\n}\n\n.chat-tool-call__title--running {\n color: var(--color-text-muted);\n}\n\n.chat-tool-call__title-content {\n display: block;\n flex: 1 1 auto;\n max-width: 100%;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-tool-call__title-target-list {\n display: inline;\n min-width: 0;\n}\n\n.chat-tool-call__title-target-separator {\n white-space: pre;\n}\n\n.chat-tool-call__title-target--link {\n color: var(--color-secondary);\n font-weight: var(--font-weight-regular);\n cursor: pointer;\n text-decoration: none;\n}\n</style>\n","<template>\n <span\n v-if=\"questions.length === 0\"\n class=\"codex-chat-theme chat-message__thinking codex-text-shimmer\"\n data-label=\"Thinking\"\n >\n <SquareDashed :size=\"15\" />\n Preparing question...\n </span>\n\n <section\n v-else\n class=\"codex-chat-theme codex-request-card chat-tool-user-input\"\n :class=\"{\n 'chat-tool-user-input--resolved': cancelled || answered || historical,\n 'chat-tool-user-input--free-text': !cancelled && !answered && !historical && currentQuestion && isFreeTextOnly(currentQuestion),\n }\"\n >\n <div v-if=\"cancelled\" class=\"chat-tool-user-input__summary chat-tool-user-input__summary--muted\">\n <ChatToolCallTitle title=\"Cancelled user question\" :icon=\"SquareX\" />\n </div>\n\n <div v-else-if=\"answered\" class=\"chat-tool-user-input__summary chat-tool-user-input__summary--answered\">\n <ChatToolCallTitle title=\"Answered user question\" :icon=\"SquareCheck\" />\n <div\n v-for=\"question in questions\"\n :key=\"question.id\"\n class=\"chat-tool-user-input__answer\"\n >\n <span class=\"chat-tool-user-input__answer-label\">{{ question.header }}</span>\n <span class=\"chat-tool-user-input__answer-value\">{{ answerSummary[question.id] }}</span>\n </div>\n </div>\n\n <template v-else-if=\"historical\">\n <p v-for=\"question in questions\" :key=\"question.id\" class=\"chat-tool-user-input__historical-question\">\n {{ question.question }}\n </p>\n </template>\n\n <template v-else-if=\"currentQuestion\">\n <header class=\"chat-tool-user-input__header\">\n <div class=\"chat-tool-user-input__heading\">\n <span\n v-if=\"currentQuestion.header.trim() !== currentQuestion.question.trim()\"\n class=\"chat-tool-user-input__tag\"\n >{{ currentQuestion.header }}</span>\n <span class=\"chat-tool-user-input__question\">{{ currentQuestion.question }}</span>\n </div>\n <div class=\"chat-tool-user-input__header-actions\">\n <div\n v-if=\"questions.length > 1\"\n class=\"chat-tool-user-input__progress\"\n aria-label=\"Question progress\"\n >\n <span\n v-for=\"(_, index) in questions\"\n :key=\"index\"\n class=\"chat-tool-user-input__progress-dot\"\n :class=\"{ 'chat-tool-user-input__progress-dot--active': index === currentIndex }\"\n />\n <span class=\"chat-tool-user-input__index\">\n {{ currentIndex + 1 }} / {{ questions.length }}\n </span>\n </div>\n <button\n class=\"chat-tool-user-input__dismiss\"\n type=\"button\"\n aria-label=\"Cancel question\"\n title=\"Cancel question\"\n @click=\"cancel\"\n >\n <X :size=\"17\" />\n </button>\n </div>\n </header>\n\n <div class=\"chat-tool-user-input__options\">\n <textarea\n v-if=\"isFreeTextOnly(currentQuestion)\"\n v-focus\n v-model=\"otherTexts[currentQuestion.id]\"\n autofocus\n class=\"chat-tool-user-input__other-input chat-tool-user-input__other-input--direct\"\n :placeholder=\"currentQuestion.isSecret ? 'Enter private answer' : 'Type your answer...'\"\n rows=\"1\"\n :type=\"currentQuestion.isSecret ? 'password' : 'text'\"\n @keydown=\"onAnswerKeydown\"\n />\n\n <template v-else>\n <button\n v-for=\"option in currentQuestion.options ?? []\"\n :key=\"option.label\"\n :aria-label=\"option.label\"\n :aria-pressed=\"isSelected(currentQuestion.id, option.label)\"\n class=\"chat-tool-user-input__option\"\n :class=\"{ 'chat-tool-user-input__option--selected': isSelected(currentQuestion.id, option.label) }\"\n type=\"button\"\n @click=\"toggleOption(currentQuestion, option.label)\"\n >\n <span class=\"chat-tool-user-input__check\">\n <Check v-if=\"isSelected(currentQuestion.id, option.label)\" class=\"chat-tool-user-input__icon chat-tool-user-input__icon--checked\" :size=\"16\" />\n <Circle v-else class=\"chat-tool-user-input__icon\" :size=\"16\" />\n </span>\n <span class=\"chat-tool-user-input__option-copy\">\n <span class=\"chat-tool-user-input__option-heading\">\n <span class=\"chat-tool-user-input__option-label\">{{ displayOptionLabel(option.label) }}</span>\n <span v-if=\"isRecommendedOption(option.label)\" class=\"chat-tool-user-input__recommended\">Recommended</span>\n </span>\n <span v-if=\"option.description\" class=\"chat-tool-user-input__option-description\">{{ option.description }}</span>\n </span>\n </button>\n\n <div\n v-if=\"currentQuestion.isOther\"\n class=\"chat-tool-user-input__option chat-tool-user-input__option--other\"\n :class=\"{ 'chat-tool-user-input__option--selected': isOtherSelected(currentQuestion.id) }\"\n role=\"button\"\n :aria-pressed=\"isOtherSelected(currentQuestion.id)\"\n tabindex=\"0\"\n @click=\"toggleOther(currentQuestion)\"\n @keydown.enter.prevent=\"toggleOther(currentQuestion)\"\n @keydown.space.prevent=\"toggleOther(currentQuestion)\"\n >\n <span class=\"chat-tool-user-input__check\">\n <Check v-if=\"isOtherSelected(currentQuestion.id)\" class=\"chat-tool-user-input__icon chat-tool-user-input__icon--checked\" :size=\"16\" />\n <Circle v-else class=\"chat-tool-user-input__icon\" :size=\"16\" />\n </span>\n <span class=\"chat-tool-user-input__option-copy\">\n <span class=\"chat-tool-user-input__option-label\">Other</span>\n </span>\n <textarea\n v-model=\"otherTexts[currentQuestion.id]\"\n class=\"chat-tool-user-input__other-input\"\n aria-label=\"Other answer\"\n :placeholder=\"currentQuestion.isSecret ? 'Enter private answer' : 'Type your answer...'\"\n rows=\"1\"\n :type=\"currentQuestion.isSecret ? 'password' : 'text'\"\n @click.stop\n @focus=\"selectOther(currentQuestion)\"\n @input=\"selectOther(currentQuestion)\"\n @keydown=\"onAnswerKeydown\"\n />\n </div>\n </template>\n </div>\n\n <footer class=\"chat-tool-user-input__actions\">\n <button\n v-if=\"currentIndex > 0\"\n class=\"codex-request-button chat-tool-user-input__button\"\n type=\"button\"\n @click=\"back\"\n >\n Back\n </button>\n <button\n class=\"codex-request-button codex-request-button--primary chat-tool-user-input__button chat-tool-user-input__button--primary\"\n :disabled=\"!canProceed\"\n type=\"button\"\n @click=\"proceed\"\n >\n {{ isLastQuestion ? 'Send' : 'Next' }}\n </button>\n </footer>\n </template>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, reactive, ref } from 'vue'\nimport type { AskUserAnswers, AskUserQuestion } from './contracts'\nimport { Check, Circle, SquareCheck, SquareDashed, SquareX, X } from '../icons/app-icons'\nimport ChatToolCallTitle from './ChatToolCallTitle.vue'\nimport { parseToolStatusDescriptor } from './tool-status'\nimport type { MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n answeredClientRequestIds?: ReadonlySet<string>\n historical?: boolean\n toolCall: MessageToolCall\n}>()\n\nconst emit = defineEmits<{\n 'client-response': [response: { id: string; payload: { answers: AskUserAnswers; cancelled?: boolean } }]\n}>()\n// Stryker restore all\n\nconst currentIndex = ref(0)\nconst localAnswered = ref(false)\nconst localCancelled = ref(false)\nconst selections = reactive<Record<string, string[]>>({})\nconst otherSelected = reactive<Record<string, boolean>>({})\nconst otherTexts = reactive<Record<string, string>>({})\n\nconst descriptor = computed(() => parseToolStatusDescriptor(props.toolCall.status))\nconst descriptorParams = computed(() => (\n descriptor.value?.params && typeof descriptor.value.params === 'object'\n ? descriptor.value.params\n : {}\n))\nconst requestId = computed(() => {\n const value = descriptorParams.value.requestId\n return typeof value === 'string' ? value : undefined\n})\nconst questions = computed(() => normalizeQuestions(descriptorParams.value.questions))\nconst currentQuestion = computed(() => questions.value[currentIndex.value])\nconst isLastQuestion = computed(() => currentIndex.value === questions.value.length - 1)\nconst resultAnswers = computed<AskUserAnswers>(() => {\n const result = props.toolCall.result as { answers?: AskUserAnswers } | undefined\n return result?.answers && typeof result.answers === 'object' ? result.answers : {}\n})\nconst externallyResolved = computed(() => (\n requestId.value ? props.answeredClientRequestIds?.has(requestId.value) === true : false\n))\nconst answered = computed(() => localAnswered.value || Object.keys(resultAnswers.value).length > 0 || (externallyResolved.value && !localCancelled.value))\nconst cancelled = computed(() => localCancelled.value || props.toolCall.state === 'canceled')\nconst answerSummary = computed(() => {\n const summary: Record<string, string> = {}\n for (const question of questions.value) {\n summary[question.id] = formatAnswer(resultAnswers.value[question.id] ?? buildAnswer(question))\n }\n return summary\n})\nconst canProceed = computed(() => {\n const question = currentQuestion.value\n if (!question || !hasAnswerFor(question)) {\n return false\n }\n\n return !isLastQuestion.value || questions.value.every((entry) => hasAnswerFor(entry))\n})\n\nconst vFocus = {\n mounted(element: HTMLTextAreaElement) {\n window.setTimeout(() => element.focus(), 0)\n },\n}\n\nfunction isFreeTextOnly(question: AskUserQuestion) {\n return question.options === null\n}\n\nconst recommendedSuffix = /\\s*\\(recommended\\)\\s*$/i\n\nfunction displayOptionLabel(label: string) {\n return label.replace(recommendedSuffix, '').trim() || label\n}\n\nfunction isRecommendedOption(label: string) {\n return recommendedSuffix.test(label)\n}\n\nfunction isSelected(questionId: string, label: string) {\n return selections[questionId]?.includes(label) ?? false\n}\n\nfunction isOtherSelected(questionId: string) {\n return otherSelected[questionId] ?? false\n}\n\nfunction toggleOption(question: AskUserQuestion, label: string) {\n if (answered.value || cancelled.value) {\n return\n }\n\n const questionId = question.id\n selections[questionId] ??= []\n if (question.multiSelect) {\n const index = selections[questionId].indexOf(label)\n if (index >= 0) {\n selections[questionId].splice(index, 1)\n } else {\n selections[questionId].push(label)\n }\n return\n }\n\n selections[questionId] = selections[questionId].includes(label) ? [] : [label]\n otherSelected[questionId] = false\n otherTexts[questionId] = ''\n}\n\nfunction toggleOther(question: AskUserQuestion) {\n if (answered.value || cancelled.value) {\n return\n }\n\n const questionId = question.id\n otherSelected[questionId] = !otherSelected[questionId]\n if (!question.multiSelect) {\n selections[questionId] = []\n }\n\n if (!otherSelected[questionId]) {\n otherTexts[questionId] = ''\n }\n}\n\nfunction selectOther(question: AskUserQuestion) {\n if (answered.value || cancelled.value) {\n return\n }\n\n otherSelected[question.id] = true\n if (!question.multiSelect) {\n selections[question.id] = []\n }\n}\n\nfunction hasAnswerFor(question: AskUserQuestion) {\n return (selections[question.id]?.length ?? 0) > 0 || (\n (isFreeTextOnly(question) || otherSelected[question.id]) && !!otherTexts[question.id]?.trim()\n )\n}\n\nfunction onAnswerKeydown(event: KeyboardEvent) {\n event.stopPropagation()\n if (event.key !== 'Enter' || event.isComposing || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) {\n return\n }\n\n event.preventDefault()\n if (currentQuestion.value && otherTexts[currentQuestion.value.id]?.trim()) {\n proceed()\n }\n}\n\nfunction proceed() {\n if (isLastQuestion.value) {\n submit()\n } else {\n next()\n }\n}\n\nfunction next() {\n if (canProceed.value) {\n currentIndex.value += 1\n }\n}\n\nfunction back() {\n if (currentIndex.value > 0) {\n currentIndex.value -= 1\n }\n}\n\nfunction submit() {\n if (!requestId.value || answered.value || cancelled.value || !canProceed.value) {\n return\n }\n\n const answers = questions.value.reduce<AskUserAnswers>((acc, question) => {\n acc[question.id] = buildAnswer(question)\n return acc\n }, {})\n\n localAnswered.value = true\n emit('client-response', {\n id: requestId.value,\n payload: { answers },\n })\n}\n\nfunction cancel() {\n if (!requestId.value || answered.value || cancelled.value) {\n return\n }\n\n localCancelled.value = true\n emit('client-response', {\n id: requestId.value,\n payload: {\n answers: {},\n cancelled: true,\n },\n })\n}\n\nfunction buildAnswer(question: AskUserQuestion): { answers: string[] } {\n const answers = [...(selections[question.id] ?? [])]\n const otherText = otherTexts[question.id]?.trim()\n if ((isFreeTextOnly(question) || otherSelected[question.id]) && otherText) {\n answers.push(otherText)\n }\n return { answers }\n}\n\nfunction formatAnswer(answer: { answers: string[] }) {\n return answer.answers.filter(Boolean).join(', ') || '-'\n}\n\nfunction normalizeQuestions(value: unknown): AskUserQuestion[] {\n if (!Array.isArray(value)) {\n return []\n }\n\n return value.filter((question): question is AskUserQuestion => {\n return Boolean(\n question &&\n typeof question === 'object' &&\n 'id' in question &&\n typeof question.id === 'string' &&\n 'question' in question &&\n typeof question.question === 'string'\n )\n }).map((question) => ({\n ...question,\n header: question.header || question.question,\n isOther: question.isOther ?? false,\n isSecret: question.isSecret ?? false,\n options: Array.isArray(question.options) ? question.options : null,\n }))\n}\n</script>\n\n<style scoped src=\"./request-controls.css\"></style>\n<style scoped>\n.chat-message__thinking {\n display: inline-flex;\n align-items: center;\n gap: var(--space-4);\n color: var(--color-text-muted);\n}\n\n\n.chat-tool-user-input--resolved {\n container-type: normal;\n width: 100%;\n max-height: none;\n overflow: visible;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n}\n\n.chat-tool-user-input--free-text {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: end;\n column-gap: var(--space-3);\n row-gap: var(--space-4);\n}\n\n.chat-tool-user-input--free-text .chat-tool-user-input__header {\n grid-column: 1 / -1;\n}\n\n.chat-tool-user-input--free-text .chat-tool-user-input__other-input--direct {\n min-height: 38px;\n max-height: 9rem;\n box-sizing: border-box;\n field-sizing: content;\n overflow-y: auto;\n resize: none;\n border: 0;\n padding: 9px 0;\n background: transparent;\n}\n\n.chat-tool-user-input--free-text .chat-tool-user-input__other-input--direct:focus {\n outline: none;\n}\n\n.chat-tool-user-input--free-text .chat-tool-user-input__actions {\n grid-column: 2;\n align-self: end;\n padding: 0;\n background: transparent;\n}\n\n.chat-tool-user-input__historical-question {\n margin: 0;\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n.chat-tool-user-input__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--space-6);\n}\n\n.chat-tool-user-input__heading,\n.chat-tool-user-input__options,\n.chat-tool-user-input__summary {\n display: flex;\n flex-direction: column;\n}\n\n.chat-tool-user-input__heading {\n flex: 1 1 auto;\n gap: var(--space-4);\n min-width: 0;\n}\n\n.chat-tool-user-input__options {\n gap: var(--space-1);\n}\n\n.chat-tool-user-input__summary {\n gap: var(--space-2);\n color: var(--color-text-muted);\n}\n\n.chat-tool-user-input__summary--muted {\n opacity: 0.72;\n}\n\n.chat-tool-user-input__summary--answered {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n}\n\n.chat-tool-user-input__tag {\n width: fit-content;\n flex: 0 0 auto;\n border: 1px solid color-mix(in srgb, var(--color-primary) 24%, transparent);\n border-radius: var(--radius-full);\n padding: var(--space-1) var(--space-3);\n background: color-mix(in srgb, var(--color-primary-container) 74%, var(--color-surface-lowest));\n color: var(--color-primary);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-16);\n}\n\n.chat-tool-user-input__header-actions {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--space-3);\n}\n\n.chat-tool-user-input__dismiss {\n display: inline-grid;\n width: 28px;\n height: 28px;\n flex: 0 0 auto;\n place-items: center;\n border: 0;\n border-radius: var(--radius-full);\n padding: 0;\n background: transparent;\n color: var(--color-text-muted);\n cursor: pointer;\n}\n\n.chat-tool-user-input__dismiss:hover {\n background: var(--color-surface-base);\n color: var(--color-text);\n}\n\n.chat-tool-user-input__question {\n min-width: 0;\n font-size: var(--font-size-16);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-24);\n}\n\n.chat-tool-user-input__progress {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--space-2);\n color: var(--color-text-muted);\n}\n\n.chat-tool-user-input__index {\n flex: 0 0 auto;\n font-size: var(--font-size-12);\n line-height: var(--line-height-16);\n}\n\n.chat-tool-user-input__progress-dot {\n width: 5px;\n height: 5px;\n border-radius: var(--radius-full);\n background: var(--color-border-strong);\n opacity: 0.45;\n}\n\n.chat-tool-user-input__progress-dot--active {\n width: 12px;\n background: var(--color-primary);\n opacity: 1;\n}\n\n.chat-tool-user-input__answer,\n.chat-tool-user-input__option {\n display: flex;\n align-items: flex-start;\n gap: var(--space-4);\n width: 100%;\n box-sizing: border-box;\n border: 0;\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-4);\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n}\n\n.chat-tool-user-input__answer {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--space-2);\n min-width: 0;\n margin-top: var(--space-2);\n border: 0;\n padding: 0 0 0 var(--space-10);\n box-sizing: border-box;\n background: transparent;\n}\n\n.chat-tool-user-input__option {\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.chat-tool-user-input__option:hover {\n background: var(--color-surface-base);\n}\n\n.chat-tool-user-input__option--selected {\n background: color-mix(in srgb, var(--color-primary-container) 50%, var(--color-surface-base));\n}\n\n.chat-tool-user-input__check {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 20px;\n}\n\n.chat-tool-user-input__icon {\n flex: 0 0 auto;\n color: var(--color-text-muted);\n}\n\n.chat-tool-user-input__icon--checked {\n border-radius: var(--radius-full);\n background: var(--color-primary);\n color: var(--color-on-primary);\n padding: var(--space-2);\n stroke-width: var(--space-3);\n}\n\n.chat-tool-user-input__option-copy {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-width: 0;\n}\n\n.chat-tool-user-input__option-heading {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-tool-user-input__option-label {\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-user-input__recommended {\n border-radius: var(--radius-full);\n padding: 0 var(--space-3);\n background: var(--color-surface-base);\n color: var(--color-text-muted);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-regular);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-user-input__option-description,\n.chat-tool-user-input__answer-value {\n min-width: 0;\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n}\n\n.chat-tool-user-input__answer-label {\n color: var(--color-text);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-medium);\n}\n\n.chat-tool-user-input__answer-label,\n.chat-tool-user-input__answer-value {\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n.chat-tool-user-input__option--other {\n display: grid;\n grid-template-columns: 18px auto minmax(0, 1fr);\n align-items: center;\n}\n\n.chat-tool-user-input__option--other .chat-tool-user-input__other-input {\n grid-column: 3;\n margin-top: 0;\n box-sizing: border-box;\n field-sizing: content;\n max-height: 9rem;\n resize: none;\n}\n\n.chat-tool-user-input__other-input {\n grid-column: 2;\n width: 100%;\n min-width: 0;\n margin-top: -2px;\n resize: vertical;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-4);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n font: inherit;\n font-size: var(--font-size-14);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-user-input__other-input:focus {\n outline: 1px solid color-mix(in srgb, var(--color-primary) 28%, transparent);\n}\n\n.chat-tool-user-input__other-input--direct {\n grid-column: auto;\n margin-top: 0;\n}\n\n.chat-tool-user-input__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: var(--space-2);\n}\n\n\n.chat-tool-user-input__option:focus-visible,\n.chat-tool-user-input__dismiss:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: var(--space-1);\n}\n\n@container (max-width: 32rem) {\n .chat-tool-user-input__header {\n gap: var(--space-3);\n }\n\n .chat-tool-user-input__question {\n font-size: var(--font-size-15);\n line-height: var(--line-height-20);\n }\n\n .chat-tool-user-input__option {\n padding: var(--space-3);\n }\n\n .chat-tool-user-input__actions {\n position: sticky;\n bottom: 0;\n padding-top: var(--space-2);\n background: var(--color-surface-lowest);\n }\n\n .chat-tool-user-input--free-text .chat-tool-user-input__actions {\n position: static;\n padding: 0;\n background: transparent;\n }\n}\n</style>\n","<template>\n <span\n v-if=\"questions.length === 0\"\n class=\"codex-chat-theme chat-message__thinking codex-text-shimmer\"\n data-label=\"Thinking\"\n >\n <SquareDashed :size=\"15\" />\n Preparing question...\n </span>\n\n <section\n v-else\n class=\"codex-chat-theme codex-request-card chat-tool-user-input\"\n :class=\"{\n 'chat-tool-user-input--resolved': cancelled || answered || historical,\n 'chat-tool-user-input--free-text': !cancelled && !answered && !historical && currentQuestion && isFreeTextOnly(currentQuestion),\n }\"\n >\n <div v-if=\"cancelled\" class=\"chat-tool-user-input__summary chat-tool-user-input__summary--muted\">\n <ChatToolCallTitle title=\"Cancelled user question\" :icon=\"SquareX\" />\n </div>\n\n <div v-else-if=\"answered\" class=\"chat-tool-user-input__summary chat-tool-user-input__summary--answered\">\n <ChatToolCallTitle title=\"Answered user question\" :icon=\"SquareCheck\" />\n <div\n v-for=\"question in questions\"\n :key=\"question.id\"\n class=\"chat-tool-user-input__answer\"\n >\n <span class=\"chat-tool-user-input__answer-label\">{{ question.header }}</span>\n <span class=\"chat-tool-user-input__answer-value\">{{ answerSummary[question.id] }}</span>\n </div>\n </div>\n\n <template v-else-if=\"historical\">\n <p v-for=\"question in questions\" :key=\"question.id\" class=\"chat-tool-user-input__historical-question\">\n {{ question.question }}\n </p>\n </template>\n\n <template v-else-if=\"currentQuestion\">\n <header class=\"chat-tool-user-input__header\">\n <div class=\"chat-tool-user-input__heading\">\n <span\n v-if=\"currentQuestion.header.trim() !== currentQuestion.question.trim()\"\n class=\"chat-tool-user-input__tag\"\n >{{ currentQuestion.header }}</span>\n <span class=\"chat-tool-user-input__question\">{{ currentQuestion.question }}</span>\n </div>\n <div class=\"chat-tool-user-input__header-actions\">\n <div\n v-if=\"questions.length > 1\"\n class=\"chat-tool-user-input__progress\"\n aria-label=\"Question progress\"\n >\n <span\n v-for=\"(_, index) in questions\"\n :key=\"index\"\n class=\"chat-tool-user-input__progress-dot\"\n :class=\"{ 'chat-tool-user-input__progress-dot--active': index === currentIndex }\"\n />\n <span class=\"chat-tool-user-input__index\">\n {{ currentIndex + 1 }} / {{ questions.length }}\n </span>\n </div>\n <button\n class=\"chat-tool-user-input__dismiss\"\n type=\"button\"\n aria-label=\"Cancel question\"\n title=\"Cancel question\"\n @click=\"cancel\"\n >\n <X :size=\"17\" />\n </button>\n </div>\n </header>\n\n <div class=\"chat-tool-user-input__options\">\n <textarea\n v-if=\"isFreeTextOnly(currentQuestion)\"\n v-focus\n v-model=\"otherTexts[currentQuestion.id]\"\n autofocus\n class=\"chat-tool-user-input__other-input chat-tool-user-input__other-input--direct\"\n :placeholder=\"currentQuestion.isSecret ? 'Enter private answer' : 'Type your answer...'\"\n rows=\"1\"\n :type=\"currentQuestion.isSecret ? 'password' : 'text'\"\n @keydown=\"onAnswerKeydown\"\n />\n\n <template v-else>\n <button\n v-for=\"option in currentQuestion.options ?? []\"\n :key=\"option.label\"\n :aria-label=\"option.label\"\n :aria-pressed=\"isSelected(currentQuestion.id, option.label)\"\n class=\"chat-tool-user-input__option\"\n :class=\"{ 'chat-tool-user-input__option--selected': isSelected(currentQuestion.id, option.label) }\"\n type=\"button\"\n @click=\"toggleOption(currentQuestion, option.label)\"\n >\n <span class=\"chat-tool-user-input__check\">\n <Check v-if=\"isSelected(currentQuestion.id, option.label)\" class=\"chat-tool-user-input__icon chat-tool-user-input__icon--checked\" :size=\"16\" />\n <Circle v-else class=\"chat-tool-user-input__icon\" :size=\"16\" />\n </span>\n <span class=\"chat-tool-user-input__option-copy\">\n <span class=\"chat-tool-user-input__option-heading\">\n <span class=\"chat-tool-user-input__option-label\">{{ displayOptionLabel(option.label) }}</span>\n <span v-if=\"isRecommendedOption(option.label)\" class=\"chat-tool-user-input__recommended\">Recommended</span>\n </span>\n <span v-if=\"option.description\" class=\"chat-tool-user-input__option-description\">{{ option.description }}</span>\n </span>\n </button>\n\n <div\n v-if=\"currentQuestion.isOther\"\n class=\"chat-tool-user-input__option chat-tool-user-input__option--other\"\n :class=\"{ 'chat-tool-user-input__option--selected': isOtherSelected(currentQuestion.id) }\"\n role=\"button\"\n :aria-pressed=\"isOtherSelected(currentQuestion.id)\"\n tabindex=\"0\"\n @click=\"toggleOther(currentQuestion)\"\n @keydown.enter.prevent=\"toggleOther(currentQuestion)\"\n @keydown.space.prevent=\"toggleOther(currentQuestion)\"\n >\n <span class=\"chat-tool-user-input__check\">\n <Check v-if=\"isOtherSelected(currentQuestion.id)\" class=\"chat-tool-user-input__icon chat-tool-user-input__icon--checked\" :size=\"16\" />\n <Circle v-else class=\"chat-tool-user-input__icon\" :size=\"16\" />\n </span>\n <span class=\"chat-tool-user-input__option-copy\">\n <span class=\"chat-tool-user-input__option-label\">Other</span>\n </span>\n <textarea\n v-model=\"otherTexts[currentQuestion.id]\"\n class=\"chat-tool-user-input__other-input\"\n aria-label=\"Other answer\"\n :placeholder=\"currentQuestion.isSecret ? 'Enter private answer' : 'Type your answer...'\"\n rows=\"1\"\n :type=\"currentQuestion.isSecret ? 'password' : 'text'\"\n @click.stop\n @focus=\"selectOther(currentQuestion)\"\n @input=\"selectOther(currentQuestion)\"\n @keydown=\"onAnswerKeydown\"\n />\n </div>\n </template>\n </div>\n\n <footer class=\"chat-tool-user-input__actions\">\n <button\n v-if=\"currentIndex > 0\"\n class=\"codex-request-button chat-tool-user-input__button\"\n type=\"button\"\n @click=\"back\"\n >\n Back\n </button>\n <button\n class=\"codex-request-button codex-request-button--primary chat-tool-user-input__button chat-tool-user-input__button--primary\"\n :disabled=\"!canProceed\"\n type=\"button\"\n @click=\"proceed\"\n >\n {{ isLastQuestion ? 'Send' : 'Next' }}\n </button>\n </footer>\n </template>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, reactive, ref } from 'vue'\nimport type { AskUserAnswers, AskUserQuestion } from './contracts'\nimport { Check, Circle, SquareCheck, SquareDashed, SquareX, X } from '../icons/app-icons'\nimport ChatToolCallTitle from './ChatToolCallTitle.vue'\nimport { parseToolStatusDescriptor } from './tool-status'\nimport type { MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n answeredClientRequestIds?: ReadonlySet<string>\n historical?: boolean\n toolCall: MessageToolCall\n}>()\n\nconst emit = defineEmits<{\n 'client-response': [response: { id: string; payload: { answers: AskUserAnswers; cancelled?: boolean } }]\n}>()\n// Stryker restore all\n\nconst currentIndex = ref(0)\nconst localAnswered = ref(false)\nconst localCancelled = ref(false)\nconst selections = reactive<Record<string, string[]>>({})\nconst otherSelected = reactive<Record<string, boolean>>({})\nconst otherTexts = reactive<Record<string, string>>({})\n\nconst descriptor = computed(() => parseToolStatusDescriptor(props.toolCall.status))\nconst descriptorParams = computed(() => (\n descriptor.value?.params && typeof descriptor.value.params === 'object'\n ? descriptor.value.params\n : {}\n))\nconst requestId = computed(() => {\n const value = descriptorParams.value.requestId\n return typeof value === 'string' ? value : undefined\n})\nconst questions = computed(() => normalizeQuestions(descriptorParams.value.questions))\nconst currentQuestion = computed(() => questions.value[currentIndex.value])\nconst isLastQuestion = computed(() => currentIndex.value === questions.value.length - 1)\nconst resultAnswers = computed<AskUserAnswers>(() => {\n const result = props.toolCall.result as { answers?: AskUserAnswers } | undefined\n return result?.answers && typeof result.answers === 'object' ? result.answers : {}\n})\nconst externallyResolved = computed(() => (\n requestId.value ? props.answeredClientRequestIds?.has(requestId.value) === true : false\n))\nconst answered = computed(() => localAnswered.value || Object.keys(resultAnswers.value).length > 0 || (externallyResolved.value && !localCancelled.value))\nconst cancelled = computed(() => localCancelled.value || props.toolCall.state === 'canceled')\nconst answerSummary = computed(() => {\n const summary: Record<string, string> = {}\n for (const question of questions.value) {\n summary[question.id] = formatAnswer(resultAnswers.value[question.id] ?? buildAnswer(question))\n }\n return summary\n})\nconst canProceed = computed(() => {\n const question = currentQuestion.value\n if (!question || !hasAnswerFor(question)) {\n return false\n }\n\n return !isLastQuestion.value || questions.value.every((entry) => hasAnswerFor(entry))\n})\n\nconst vFocus = {\n mounted(element: HTMLTextAreaElement) {\n window.setTimeout(() => element.focus(), 0)\n },\n}\n\nfunction isFreeTextOnly(question: AskUserQuestion) {\n return question.options === null\n}\n\nconst recommendedSuffix = /\\s*\\(recommended\\)\\s*$/i\n\nfunction displayOptionLabel(label: string) {\n return label.replace(recommendedSuffix, '').trim() || label\n}\n\nfunction isRecommendedOption(label: string) {\n return recommendedSuffix.test(label)\n}\n\nfunction isSelected(questionId: string, label: string) {\n return selections[questionId]?.includes(label) ?? false\n}\n\nfunction isOtherSelected(questionId: string) {\n return otherSelected[questionId] ?? false\n}\n\nfunction toggleOption(question: AskUserQuestion, label: string) {\n if (answered.value || cancelled.value) {\n return\n }\n\n const questionId = question.id\n selections[questionId] ??= []\n if (question.multiSelect) {\n const index = selections[questionId].indexOf(label)\n if (index >= 0) {\n selections[questionId].splice(index, 1)\n } else {\n selections[questionId].push(label)\n }\n return\n }\n\n selections[questionId] = selections[questionId].includes(label) ? [] : [label]\n otherSelected[questionId] = false\n otherTexts[questionId] = ''\n}\n\nfunction toggleOther(question: AskUserQuestion) {\n if (answered.value || cancelled.value) {\n return\n }\n\n const questionId = question.id\n otherSelected[questionId] = !otherSelected[questionId]\n if (!question.multiSelect) {\n selections[questionId] = []\n }\n\n if (!otherSelected[questionId]) {\n otherTexts[questionId] = ''\n }\n}\n\nfunction selectOther(question: AskUserQuestion) {\n if (answered.value || cancelled.value) {\n return\n }\n\n otherSelected[question.id] = true\n if (!question.multiSelect) {\n selections[question.id] = []\n }\n}\n\nfunction hasAnswerFor(question: AskUserQuestion) {\n return (selections[question.id]?.length ?? 0) > 0 || (\n (isFreeTextOnly(question) || otherSelected[question.id]) && !!otherTexts[question.id]?.trim()\n )\n}\n\nfunction onAnswerKeydown(event: KeyboardEvent) {\n event.stopPropagation()\n if (event.key !== 'Enter' || event.isComposing || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) {\n return\n }\n\n event.preventDefault()\n if (currentQuestion.value && otherTexts[currentQuestion.value.id]?.trim()) {\n proceed()\n }\n}\n\nfunction proceed() {\n if (isLastQuestion.value) {\n submit()\n } else {\n next()\n }\n}\n\nfunction next() {\n if (canProceed.value) {\n currentIndex.value += 1\n }\n}\n\nfunction back() {\n if (currentIndex.value > 0) {\n currentIndex.value -= 1\n }\n}\n\nfunction submit() {\n if (!requestId.value || answered.value || cancelled.value || !canProceed.value) {\n return\n }\n\n const answers = questions.value.reduce<AskUserAnswers>((acc, question) => {\n acc[question.id] = buildAnswer(question)\n return acc\n }, {})\n\n localAnswered.value = true\n emit('client-response', {\n id: requestId.value,\n payload: { answers },\n })\n}\n\nfunction cancel() {\n if (!requestId.value || answered.value || cancelled.value) {\n return\n }\n\n localCancelled.value = true\n emit('client-response', {\n id: requestId.value,\n payload: {\n answers: {},\n cancelled: true,\n },\n })\n}\n\nfunction buildAnswer(question: AskUserQuestion): { answers: string[] } {\n const answers = [...(selections[question.id] ?? [])]\n const otherText = otherTexts[question.id]?.trim()\n if ((isFreeTextOnly(question) || otherSelected[question.id]) && otherText) {\n answers.push(otherText)\n }\n return { answers }\n}\n\nfunction formatAnswer(answer: { answers: string[] }) {\n return answer.answers.filter(Boolean).join(', ') || '-'\n}\n\nfunction normalizeQuestions(value: unknown): AskUserQuestion[] {\n if (!Array.isArray(value)) {\n return []\n }\n\n return value.filter((question): question is AskUserQuestion => {\n return Boolean(\n question &&\n typeof question === 'object' &&\n 'id' in question &&\n typeof question.id === 'string' &&\n 'question' in question &&\n typeof question.question === 'string'\n )\n }).map((question) => ({\n ...question,\n header: question.header || question.question,\n isOther: question.isOther ?? false,\n isSecret: question.isSecret ?? false,\n options: Array.isArray(question.options) ? question.options : null,\n }))\n}\n</script>\n\n<style scoped src=\"./request-controls.css\"></style>\n<style scoped>\n.chat-message__thinking {\n display: inline-flex;\n align-items: center;\n gap: var(--space-4);\n color: var(--color-text-muted);\n}\n\n\n.chat-tool-user-input--resolved {\n container-type: normal;\n width: 100%;\n max-height: none;\n overflow: visible;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n}\n\n.chat-tool-user-input--free-text {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: end;\n column-gap: var(--space-3);\n row-gap: var(--space-4);\n}\n\n.chat-tool-user-input--free-text .chat-tool-user-input__header {\n grid-column: 1 / -1;\n}\n\n.chat-tool-user-input--free-text .chat-tool-user-input__other-input--direct {\n min-height: 38px;\n max-height: 9rem;\n box-sizing: border-box;\n field-sizing: content;\n overflow-y: auto;\n resize: none;\n border: 0;\n padding: 9px 0;\n background: transparent;\n}\n\n.chat-tool-user-input--free-text .chat-tool-user-input__other-input--direct:focus {\n outline: none;\n}\n\n.chat-tool-user-input--free-text .chat-tool-user-input__actions {\n grid-column: 2;\n align-self: end;\n padding: 0;\n background: transparent;\n}\n\n.chat-tool-user-input__historical-question {\n margin: 0;\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n.chat-tool-user-input__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--space-6);\n}\n\n.chat-tool-user-input__heading,\n.chat-tool-user-input__options,\n.chat-tool-user-input__summary {\n display: flex;\n flex-direction: column;\n}\n\n.chat-tool-user-input__heading {\n flex: 1 1 auto;\n gap: var(--space-4);\n min-width: 0;\n}\n\n.chat-tool-user-input__options {\n gap: var(--space-1);\n}\n\n.chat-tool-user-input__summary {\n gap: var(--space-2);\n color: var(--color-text-muted);\n}\n\n.chat-tool-user-input__summary--muted {\n opacity: 0.72;\n}\n\n.chat-tool-user-input__summary--answered {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n}\n\n.chat-tool-user-input__tag {\n width: fit-content;\n flex: 0 0 auto;\n border: 1px solid color-mix(in srgb, var(--color-primary) 24%, transparent);\n border-radius: var(--radius-full);\n padding: var(--space-1) var(--space-3);\n background: color-mix(in srgb, var(--color-primary-container) 74%, var(--color-surface-lowest));\n color: var(--color-primary);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-16);\n}\n\n.chat-tool-user-input__header-actions {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--space-3);\n}\n\n.chat-tool-user-input__dismiss {\n display: inline-grid;\n width: 28px;\n height: 28px;\n flex: 0 0 auto;\n place-items: center;\n border: 0;\n border-radius: var(--radius-full);\n padding: 0;\n background: transparent;\n color: var(--color-text-muted);\n cursor: pointer;\n}\n\n.chat-tool-user-input__dismiss:hover {\n background: var(--color-surface-base);\n color: var(--color-text);\n}\n\n.chat-tool-user-input__question {\n min-width: 0;\n font-size: var(--font-size-16);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-24);\n}\n\n.chat-tool-user-input__progress {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--space-2);\n color: var(--color-text-muted);\n}\n\n.chat-tool-user-input__index {\n flex: 0 0 auto;\n font-size: var(--font-size-12);\n line-height: var(--line-height-16);\n}\n\n.chat-tool-user-input__progress-dot {\n width: 5px;\n height: 5px;\n border-radius: var(--radius-full);\n background: var(--color-border-strong);\n opacity: 0.45;\n}\n\n.chat-tool-user-input__progress-dot--active {\n width: 12px;\n background: var(--color-primary);\n opacity: 1;\n}\n\n.chat-tool-user-input__answer,\n.chat-tool-user-input__option {\n display: flex;\n align-items: flex-start;\n gap: var(--space-4);\n width: 100%;\n box-sizing: border-box;\n border: 0;\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-4);\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n}\n\n.chat-tool-user-input__answer {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--space-2);\n min-width: 0;\n margin-top: var(--space-2);\n border: 0;\n padding: 0 0 0 var(--space-10);\n box-sizing: border-box;\n background: transparent;\n}\n\n.chat-tool-user-input__option {\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.chat-tool-user-input__option:hover {\n background: var(--color-surface-base);\n}\n\n.chat-tool-user-input__option--selected {\n background: color-mix(in srgb, var(--color-primary-container) 50%, var(--color-surface-base));\n}\n\n.chat-tool-user-input__check {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 20px;\n}\n\n.chat-tool-user-input__icon {\n flex: 0 0 auto;\n color: var(--color-text-muted);\n}\n\n.chat-tool-user-input__icon--checked {\n border-radius: var(--radius-full);\n background: var(--color-primary);\n color: var(--color-on-primary);\n padding: var(--space-2);\n stroke-width: var(--space-3);\n}\n\n.chat-tool-user-input__option-copy {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-width: 0;\n}\n\n.chat-tool-user-input__option-heading {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-tool-user-input__option-label {\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-user-input__recommended {\n border-radius: var(--radius-full);\n padding: 0 var(--space-3);\n background: var(--color-surface-base);\n color: var(--color-text-muted);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-regular);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-user-input__option-description,\n.chat-tool-user-input__answer-value {\n min-width: 0;\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n}\n\n.chat-tool-user-input__answer-label {\n color: var(--color-text);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-medium);\n}\n\n.chat-tool-user-input__answer-label,\n.chat-tool-user-input__answer-value {\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n\n.chat-tool-user-input__option--other {\n display: grid;\n grid-template-columns: 18px auto minmax(0, 1fr);\n align-items: center;\n}\n\n.chat-tool-user-input__option--other .chat-tool-user-input__other-input {\n grid-column: 3;\n margin-top: 0;\n box-sizing: border-box;\n field-sizing: content;\n max-height: 9rem;\n resize: none;\n}\n\n.chat-tool-user-input__other-input {\n grid-column: 2;\n width: 100%;\n min-width: 0;\n margin-top: -2px;\n resize: vertical;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-4);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n font: inherit;\n font-size: var(--font-size-14);\n line-height: var(--line-height-20);\n}\n\n.chat-tool-user-input__other-input:focus {\n outline: 1px solid color-mix(in srgb, var(--color-primary) 28%, transparent);\n}\n\n.chat-tool-user-input__other-input--direct {\n grid-column: auto;\n margin-top: 0;\n}\n\n.chat-tool-user-input__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: var(--space-2);\n}\n\n\n.chat-tool-user-input__option:focus-visible,\n.chat-tool-user-input__dismiss:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: var(--space-1);\n}\n\n@container (max-width: 32rem) {\n .chat-tool-user-input__header {\n gap: var(--space-3);\n }\n\n .chat-tool-user-input__question {\n font-size: var(--font-size-15);\n line-height: var(--line-height-20);\n }\n\n .chat-tool-user-input__option {\n padding: var(--space-3);\n }\n\n .chat-tool-user-input__actions {\n position: sticky;\n bottom: 0;\n padding-top: var(--space-2);\n background: var(--color-surface-lowest);\n }\n\n .chat-tool-user-input--free-text .chat-tool-user-input__actions {\n position: static;\n padding: 0;\n background: transparent;\n }\n}\n</style>\n","<template>\n <ChatToolUserInputRequest\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :historical=\"historical\"\n :tool-call=\"toolCall\"\n @client-response=\"respond\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject } from 'vue'\nimport { questionResponsesKey } from './message-work-state'\nimport type { CodexSurfaceClientRequest } from '@codex-app-sdk/core/surface'\nimport ChatToolUserInputRequest from './ChatToolUserInputRequest.vue'\nimport type { ClientRequestResponse } from './contracts'\nimport type { MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n answeredClientRequestIds?: ReadonlySet<string>\n historical?: boolean\n request: Extract<CodexSurfaceClientRequest, { kind: 'ask_user' }>\n}>()\n\nconst emit = defineEmits<{\n 'client-response': [response: ClientRequestResponse]\n}>()\n// Stryker restore all\n\nconst responses = inject(questionResponsesKey, undefined)\nfunction respond(response: ClientRequestResponse) {\n responses?.set(response.id, response.payload)\n emit('client-response', response)\n}\n\nconst toolCall = computed<MessageToolCall>(() => ({\n args: props.request.payload.request.questions,\n done: false,\n function: 'ask_user_question',\n id: props.request.itemId,\n itemId: props.request.itemId,\n result: responses?.get(props.request.id) ?? null,\n state: responses?.get(props.request.id)?.cancelled ? 'canceled' : 'running',\n status: JSON.stringify({\n source: 'codex',\n action: 'ask_user_question',\n phase: 'running',\n params: {\n requestId: props.request.id,\n questions: props.request.payload.request.questions,\n },\n }),\n turnId: props.request.turnId,\n}))\n</script>\n","<template>\n <ChatToolUserInputRequest\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :historical=\"historical\"\n :tool-call=\"toolCall\"\n @client-response=\"respond\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject } from 'vue'\nimport { questionResponsesKey } from './message-work-state'\nimport type { CodexSurfaceClientRequest } from '@codex-app-sdk/core/surface'\nimport ChatToolUserInputRequest from './ChatToolUserInputRequest.vue'\nimport type { ClientRequestResponse } from './contracts'\nimport type { MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n answeredClientRequestIds?: ReadonlySet<string>\n historical?: boolean\n request: Extract<CodexSurfaceClientRequest, { kind: 'ask_user' }>\n}>()\n\nconst emit = defineEmits<{\n 'client-response': [response: ClientRequestResponse]\n}>()\n// Stryker restore all\n\nconst responses = inject(questionResponsesKey, undefined)\nfunction respond(response: ClientRequestResponse) {\n responses?.set(response.id, response.payload)\n emit('client-response', response)\n}\n\nconst toolCall = computed<MessageToolCall>(() => ({\n args: props.request.payload.request.questions,\n done: false,\n function: 'ask_user_question',\n id: props.request.itemId,\n itemId: props.request.itemId,\n result: responses?.get(props.request.id) ?? null,\n state: responses?.get(props.request.id)?.cancelled ? 'canceled' : 'running',\n status: JSON.stringify({\n source: 'codex',\n action: 'ask_user_question',\n phase: 'running',\n params: {\n requestId: props.request.id,\n questions: props.request.payload.request.questions,\n },\n }),\n turnId: props.request.turnId,\n}))\n</script>\n","<template>\n <div v-if=\"resolved\" class=\"codex-chat-theme chat-tool-confirmation chat-tool-confirmation--resolved\">\n <ChatToolCallTitle :title=\"resolvedTitle\" />\n </div>\n <ChatApprovalCard\n v-else\n :summary=\"summary\"\n :details=\"argumentsPreview\"\n :actions=\"actions\"\n @decide=\"respond\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport type { ToolConfirmationDecision } from './contracts'\nimport { computed, ref } from 'vue'\nimport ChatToolCallTitle from './ChatToolCallTitle.vue'\nimport ChatApprovalCard from './ChatApprovalCard.vue'\nimport { parseToolStatusDescriptor } from './tool-status'\nimport { getMessageToolCallArgs, getMessageToolCallName, type MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n answeredClientRequestIds?: ReadonlySet<string>\n toolCall: MessageToolCall\n}>()\n\nconst emit = defineEmits<{\n 'client-response': [response: { id: string; payload: { decision: ToolConfirmationDecision } }]\n}>()\n// Stryker restore all\n\nconst localDecision = ref<ToolConfirmationDecision | null>(null)\n\nconst descriptor = computed(() => parseToolStatusDescriptor(props.toolCall.status))\nconst descriptorParams = computed(() => (\n descriptor.value?.params && typeof descriptor.value.params === 'object'\n ? descriptor.value.params\n : {}\n))\nconst requestId = computed(() => {\n const value = descriptorParams.value.requestId\n return typeof value === 'string' ? value : undefined\n})\nconst summary = computed(() => {\n const value = descriptorParams.value.confirmationSummary\n return typeof value === 'string' && value.trim()\n ? value\n : `Allow tool call ${getMessageToolCallName(props.toolCall)}?`\n})\nconst argumentsPreview = computed(() => {\n const preview = descriptorParams.value.argumentsPreview\n if (typeof preview === 'string') {\n return preview\n }\n\n const params = getMessageToolCallArgs(props.toolCall)\n if (!params || typeof params !== 'object') {\n return ''\n }\n return JSON.stringify(params, null, 2)\n})\nconst externallyResolved = computed(() => (\n requestId.value ? props.answeredClientRequestIds?.has(requestId.value) === true : false\n))\nconst resolved = computed(() => Boolean(localDecision.value) || externallyResolved.value || props.toolCall.done)\nconst showConversationAction = computed(() => descriptorParams.value.allowConversation === true)\nconst showAlwaysAction = computed(() => descriptorParams.value.allowAlways === true)\nconst actions = computed(() => [\n { id: 'allow' as const, label: 'Allow', primary: true },\n ...(showConversationAction.value ? [{ id: 'allow_conversation' as const, label: 'Allow for session' }] : []),\n ...(showAlwaysAction.value ? [{ id: 'always_allow' as const, label: 'Always allow' }] : []),\n { id: 'deny' as const, label: 'Deny' },\n])\nconst resolvedTitle = computed(() => {\n const result = props.toolCall.result\n const denied = typeof result === 'object' && result !== null && 'decision' in result && result.decision === 'deny'\n if (localDecision.value === 'deny' || denied || props.toolCall.state === 'canceled') {\n return 'Denied tool call'\n }\n\n return 'Allowed tool call'\n})\n\nfunction respond(decision: ToolConfirmationDecision) {\n if (!requestId.value || resolved.value) {\n return\n }\n\n localDecision.value = decision\n emit('client-response', {\n id: requestId.value,\n payload: { decision },\n })\n}\n</script>\n\n<style scoped>\n.chat-tool-confirmation--resolved {\n width: 100%;\n color: var(--color-text-muted);\n}\n</style>\n","<template>\n <div v-if=\"resolved\" class=\"codex-chat-theme chat-tool-confirmation chat-tool-confirmation--resolved\">\n <ChatToolCallTitle :title=\"resolvedTitle\" />\n </div>\n <ChatApprovalCard\n v-else\n :summary=\"summary\"\n :details=\"argumentsPreview\"\n :actions=\"actions\"\n @decide=\"respond\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport type { ToolConfirmationDecision } from './contracts'\nimport { computed, ref } from 'vue'\nimport ChatToolCallTitle from './ChatToolCallTitle.vue'\nimport ChatApprovalCard from './ChatApprovalCard.vue'\nimport { parseToolStatusDescriptor } from './tool-status'\nimport { getMessageToolCallArgs, getMessageToolCallName, type MessageToolCall } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n answeredClientRequestIds?: ReadonlySet<string>\n toolCall: MessageToolCall\n}>()\n\nconst emit = defineEmits<{\n 'client-response': [response: { id: string; payload: { decision: ToolConfirmationDecision } }]\n}>()\n// Stryker restore all\n\nconst localDecision = ref<ToolConfirmationDecision | null>(null)\n\nconst descriptor = computed(() => parseToolStatusDescriptor(props.toolCall.status))\nconst descriptorParams = computed(() => (\n descriptor.value?.params && typeof descriptor.value.params === 'object'\n ? descriptor.value.params\n : {}\n))\nconst requestId = computed(() => {\n const value = descriptorParams.value.requestId\n return typeof value === 'string' ? value : undefined\n})\nconst summary = computed(() => {\n const value = descriptorParams.value.confirmationSummary\n return typeof value === 'string' && value.trim()\n ? value\n : `Allow tool call ${getMessageToolCallName(props.toolCall)}?`\n})\nconst argumentsPreview = computed(() => {\n const preview = descriptorParams.value.argumentsPreview\n if (typeof preview === 'string') {\n return preview\n }\n\n const params = getMessageToolCallArgs(props.toolCall)\n if (!params || typeof params !== 'object') {\n return ''\n }\n return JSON.stringify(params, null, 2)\n})\nconst externallyResolved = computed(() => (\n requestId.value ? props.answeredClientRequestIds?.has(requestId.value) === true : false\n))\nconst resolved = computed(() => Boolean(localDecision.value) || externallyResolved.value || props.toolCall.done)\nconst showConversationAction = computed(() => descriptorParams.value.allowConversation === true)\nconst showAlwaysAction = computed(() => descriptorParams.value.allowAlways === true)\nconst actions = computed(() => [\n { id: 'allow' as const, label: 'Allow', primary: true },\n ...(showConversationAction.value ? [{ id: 'allow_conversation' as const, label: 'Allow for session' }] : []),\n ...(showAlwaysAction.value ? [{ id: 'always_allow' as const, label: 'Always allow' }] : []),\n { id: 'deny' as const, label: 'Deny' },\n])\nconst resolvedTitle = computed(() => {\n const result = props.toolCall.result\n const denied = typeof result === 'object' && result !== null && 'decision' in result && result.decision === 'deny'\n if (localDecision.value === 'deny' || denied || props.toolCall.state === 'canceled') {\n return 'Denied tool call'\n }\n\n return 'Allowed tool call'\n})\n\nfunction respond(decision: ToolConfirmationDecision) {\n if (!requestId.value || resolved.value) {\n return\n }\n\n localDecision.value = decision\n emit('client-response', {\n id: requestId.value,\n payload: { decision },\n })\n}\n</script>\n\n<style scoped>\n.chat-tool-confirmation--resolved {\n width: 100%;\n color: var(--color-text-muted);\n}\n</style>\n","<template>\n <ChatToolConfirmation\n :tool-call=\"toolCall\"\n @client-response=\"$emit('client-response', $event)\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { CodexSurfaceClientRequest, CodexSurfaceClientRequestResponse } from '@codex-app-sdk/core/surface'\nimport type { MessageToolCall } from './types'\nimport ChatToolConfirmation from './ChatToolConfirmation.vue'\n\nconst props = defineProps<{\n request: Extract<CodexSurfaceClientRequest, { kind: 'confirm_tool' }>\n}>()\ndefineEmits<{ 'client-response': [response: CodexSurfaceClientRequestResponse] }>()\n\nconst toolCall = computed<MessageToolCall>(() => ({\n args: undefined,\n result: undefined,\n id: props.request.itemId,\n itemId: props.request.itemId,\n function: props.request.payload.confirmation.toolName,\n done: false,\n state: 'running',\n status: JSON.stringify({\n source: 'mcp',\n action: 'confirm_tool',\n phase: 'running',\n params: {\n requestId: props.request.id,\n confirmationSummary: props.request.payload.confirmation.summary,\n argumentsPreview: props.request.payload.confirmation.argumentsPreview,\n allowConversation: props.request.payload.confirmation.allowConversation,\n allowAlways: props.request.payload.confirmation.allowAlways,\n },\n }),\n}))\n</script>\n","<template>\n <ChatToolConfirmation\n :tool-call=\"toolCall\"\n @client-response=\"$emit('client-response', $event)\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { CodexSurfaceClientRequest, CodexSurfaceClientRequestResponse } from '@codex-app-sdk/core/surface'\nimport type { MessageToolCall } from './types'\nimport ChatToolConfirmation from './ChatToolConfirmation.vue'\n\nconst props = defineProps<{\n request: Extract<CodexSurfaceClientRequest, { kind: 'confirm_tool' }>\n}>()\ndefineEmits<{ 'client-response': [response: CodexSurfaceClientRequestResponse] }>()\n\nconst toolCall = computed<MessageToolCall>(() => ({\n args: undefined,\n result: undefined,\n id: props.request.itemId,\n itemId: props.request.itemId,\n function: props.request.payload.confirmation.toolName,\n done: false,\n state: 'running',\n status: JSON.stringify({\n source: 'mcp',\n action: 'confirm_tool',\n phase: 'running',\n params: {\n requestId: props.request.id,\n confirmationSummary: props.request.payload.confirmation.summary,\n argumentsPreview: props.request.payload.confirmation.argumentsPreview,\n allowConversation: props.request.payload.confirmation.allowConversation,\n allowAlways: props.request.payload.confirmation.allowAlways,\n },\n }),\n}))\n</script>\n","<template>\n <div v-if=\"goal\" class=\"codex-chat-theme chat-goal\" aria-label=\"Current goal\">\n <TargetArrowIcon class=\"chat-goal__icon\" aria-hidden=\"true\" />\n <div class=\"chat-goal__copy\">\n <span class=\"chat-goal__label\">Goal</span>\n <span class=\"chat-goal__objective\">{{ goal.objective }}</span>\n </div>\n <div class=\"chat-goal__actions\">\n <button\n class=\"chat-goal__action\"\n type=\"button\"\n aria-label=\"Edit goal\"\n title=\"Edit goal\"\n @click=\"emit('edit')\"\n >\n <PencilIcon aria-hidden=\"true\" />\n <span>Edit</span>\n </button>\n <button\n class=\"chat-goal__action\"\n type=\"button\"\n aria-label=\"Clear goal\"\n title=\"Clear goal\"\n @click=\"emit('clear')\"\n >\n <Trash2Icon aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { ThreadGoal } from './contracts';\nimport { PencilIcon, TargetArrowIcon, Trash2Icon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n goal: ThreadGoal | null;\n}>();\n\nconst emit = defineEmits<{\n clear: [];\n edit: [];\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-goal {\n width: 100%;\n display: grid;\n grid-template-columns: max-content minmax(0, 1fr) max-content;\n align-items: center;\n gap: var(--space-4);\n padding: var(--space-3) var(--space-6);\n border: 0.5px solid var(--color-border);\n border-bottom: 0;\n border-top-left-radius: var(--radius-xl);\n border-top-right-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-sm);\n color: var(--color-text-muted);\n}\n\n.chat-goal__icon {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n.chat-goal__copy {\n min-width: 0;\n display: flex;\n align-items: baseline;\n gap: var(--space-3);\n}\n\n.chat-goal__label {\n color: var(--color-text);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-semibold);\n}\n\n.chat-goal__objective {\n min-width: 0;\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-xlight);\n line-height: var(--line-height-18);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-goal__actions {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-goal__action {\n width: auto;\n height: var(--space-12);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: var(--radius-md);\n background: transparent;\n color: var(--color-text-muted);\n font-size: var(--font-size-12);\n gap: var(--space-2);\n cursor: pointer;\n}\n\n.chat-goal__action:hover {\n background: var(--color-surface-low);\n color: var(--color-text);\n}\n\n.chat-goal__action svg {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n</style>\n","<template>\n <div v-if=\"goal\" class=\"codex-chat-theme chat-goal\" aria-label=\"Current goal\">\n <TargetArrowIcon class=\"chat-goal__icon\" aria-hidden=\"true\" />\n <div class=\"chat-goal__copy\">\n <span class=\"chat-goal__label\">Goal</span>\n <span class=\"chat-goal__objective\">{{ goal.objective }}</span>\n </div>\n <div class=\"chat-goal__actions\">\n <button\n class=\"chat-goal__action\"\n type=\"button\"\n aria-label=\"Edit goal\"\n title=\"Edit goal\"\n @click=\"emit('edit')\"\n >\n <PencilIcon aria-hidden=\"true\" />\n <span>Edit</span>\n </button>\n <button\n class=\"chat-goal__action\"\n type=\"button\"\n aria-label=\"Clear goal\"\n title=\"Clear goal\"\n @click=\"emit('clear')\"\n >\n <Trash2Icon aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { ThreadGoal } from './contracts';\nimport { PencilIcon, TargetArrowIcon, Trash2Icon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n goal: ThreadGoal | null;\n}>();\n\nconst emit = defineEmits<{\n clear: [];\n edit: [];\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-goal {\n width: 100%;\n display: grid;\n grid-template-columns: max-content minmax(0, 1fr) max-content;\n align-items: center;\n gap: var(--space-4);\n padding: var(--space-3) var(--space-6);\n border: 0.5px solid var(--color-border);\n border-bottom: 0;\n border-top-left-radius: var(--radius-xl);\n border-top-right-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-sm);\n color: var(--color-text-muted);\n}\n\n.chat-goal__icon {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n.chat-goal__copy {\n min-width: 0;\n display: flex;\n align-items: baseline;\n gap: var(--space-3);\n}\n\n.chat-goal__label {\n color: var(--color-text);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-semibold);\n}\n\n.chat-goal__objective {\n min-width: 0;\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-xlight);\n line-height: var(--line-height-18);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-goal__actions {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-goal__action {\n width: auto;\n height: var(--space-12);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: var(--radius-md);\n background: transparent;\n color: var(--color-text-muted);\n font-size: var(--font-size-12);\n gap: var(--space-2);\n cursor: pointer;\n}\n\n.chat-goal__action:hover {\n background: var(--color-surface-low);\n color: var(--color-text);\n}\n\n.chat-goal__action svg {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-queued-prompt\" aria-label=\"Queued prompt\">\n <TerminalIcon class=\"chat-queued-prompt__icon\" aria-hidden=\"true\" />\n <span class=\"chat-queued-prompt__text\">{{ prompt.text }}</span>\n <div class=\"chat-queued-prompt__actions\">\n <button\n class=\"chat-queued-prompt__action\"\n type=\"button\"\n aria-label=\"Steer queued prompt now\"\n title=\"Steer now\"\n :disabled=\"steerDisabled\"\n @click=\"emit('steer', prompt.id)\"\n >\n <SteeringWheelIcon aria-hidden=\"true\" />\n <span>Steer</span>\n </button>\n <button\n class=\"chat-queued-prompt__action\"\n type=\"button\"\n aria-label=\"Edit queued prompt\"\n title=\"Edit\"\n :disabled=\"editDisabled\"\n @click=\"emit('edit', prompt.id)\"\n >\n <PencilIcon aria-hidden=\"true\" />\n </button>\n <button\n class=\"chat-queued-prompt__action\"\n type=\"button\"\n aria-label=\"Delete queued prompt\"\n title=\"Delete\"\n @click=\"emit('delete', prompt.id)\"\n >\n <Trash2Icon aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { PencilIcon, SteeringWheelIcon, TerminalIcon, Trash2Icon } from '../icons/app-icons';\nimport type { QueuedChatPrompt } from './queued-prompts';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n prompt: QueuedChatPrompt;\n editDisabled?: boolean;\n steerDisabled?: boolean;\n}>();\n\nconst emit = defineEmits<{\n delete: [id: string];\n edit: [id: string];\n steer: [id: string];\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-queued-prompt {\n display: grid;\n grid-template-columns: max-content minmax(0, 1fr) max-content;\n align-items: center;\n gap: var(--space-4);\n padding: var(--space-3) var(--space-6);\n border-bottom: 0.5px solid var(--color-border);\n color: var(--color-text-muted);\n}\n\n.chat-queued-prompt:last-of-type {\n border-bottom: none;\n}\n\n.chat-queued-prompt__icon {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n.chat-queued-prompt__text {\n min-width: 0;\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-xlight);\n line-height: var(--line-height-18);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-queued-prompt__actions {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-queued-prompt__action {\n width: auto;\n height: var(--space-12);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: var(--radius-md);\n background: transparent;\n color: var(--color-text-muted);\n font-size: var(--font-size-12);\n gap: var(--space-2);\n cursor: pointer;\n}\n\n.chat-queued-prompt__action:hover:not(:disabled) {\n background: var(--color-surface-low);\n color: var(--color-text);\n}\n\n.chat-queued-prompt__action:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.chat-queued-prompt__action svg {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-queued-prompt\" aria-label=\"Queued prompt\">\n <TerminalIcon class=\"chat-queued-prompt__icon\" aria-hidden=\"true\" />\n <span class=\"chat-queued-prompt__text\">{{ prompt.text }}</span>\n <div class=\"chat-queued-prompt__actions\">\n <button\n class=\"chat-queued-prompt__action\"\n type=\"button\"\n aria-label=\"Steer queued prompt now\"\n title=\"Steer now\"\n :disabled=\"steerDisabled\"\n @click=\"emit('steer', prompt.id)\"\n >\n <SteeringWheelIcon aria-hidden=\"true\" />\n <span>Steer</span>\n </button>\n <button\n class=\"chat-queued-prompt__action\"\n type=\"button\"\n aria-label=\"Edit queued prompt\"\n title=\"Edit\"\n :disabled=\"editDisabled\"\n @click=\"emit('edit', prompt.id)\"\n >\n <PencilIcon aria-hidden=\"true\" />\n </button>\n <button\n class=\"chat-queued-prompt__action\"\n type=\"button\"\n aria-label=\"Delete queued prompt\"\n title=\"Delete\"\n @click=\"emit('delete', prompt.id)\"\n >\n <Trash2Icon aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { PencilIcon, SteeringWheelIcon, TerminalIcon, Trash2Icon } from '../icons/app-icons';\nimport type { QueuedChatPrompt } from './queued-prompts';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n prompt: QueuedChatPrompt;\n editDisabled?: boolean;\n steerDisabled?: boolean;\n}>();\n\nconst emit = defineEmits<{\n delete: [id: string];\n edit: [id: string];\n steer: [id: string];\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-queued-prompt {\n display: grid;\n grid-template-columns: max-content minmax(0, 1fr) max-content;\n align-items: center;\n gap: var(--space-4);\n padding: var(--space-3) var(--space-6);\n border-bottom: 0.5px solid var(--color-border);\n color: var(--color-text-muted);\n}\n\n.chat-queued-prompt:last-of-type {\n border-bottom: none;\n}\n\n.chat-queued-prompt__icon {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n.chat-queued-prompt__text {\n min-width: 0;\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-xlight);\n line-height: var(--line-height-18);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-queued-prompt__actions {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-queued-prompt__action {\n width: auto;\n height: var(--space-12);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: var(--radius-md);\n background: transparent;\n color: var(--color-text-muted);\n font-size: var(--font-size-12);\n gap: var(--space-2);\n cursor: pointer;\n}\n\n.chat-queued-prompt__action:hover:not(:disabled) {\n background: var(--color-surface-low);\n color: var(--color-text);\n}\n\n.chat-queued-prompt__action:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.chat-queued-prompt__action svg {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n</style>\n","<template>\n <div v-if=\"prompts.length\" class=\"codex-chat-theme chat-queued-prompts\">\n <ChatQueuedPrompt\n v-for=\"prompt in prompts\"\n :key=\"prompt.id\"\n :edit-disabled=\"editDisabled\"\n :steer-disabled=\"steerDisabled\"\n :prompt=\"prompt\"\n @delete=\"$emit('delete', $event)\"\n @edit=\"$emit('edit', $event)\"\n @steer=\"$emit('steer', $event)\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport ChatQueuedPrompt from './ChatQueuedPrompt.vue';\nimport type { QueuedChatPrompt } from './queued-prompts';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n prompts: readonly QueuedChatPrompt[];\n editDisabled?: boolean;\n steerDisabled?: boolean;\n}>();\n\ndefineEmits<{\n delete: [id: string];\n edit: [id: string];\n steer: [id: string];\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-queued-prompts {\n width: 100%;\n display: flex;\n flex-direction: column;\n border: 0.5px solid var(--color-border);\n border-bottom: 0;\n border-top-left-radius: var(--radius-xl);\n border-top-right-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-sm);\n}\n</style>\n","<template>\n <div v-if=\"prompts.length\" class=\"codex-chat-theme chat-queued-prompts\">\n <ChatQueuedPrompt\n v-for=\"prompt in prompts\"\n :key=\"prompt.id\"\n :edit-disabled=\"editDisabled\"\n :steer-disabled=\"steerDisabled\"\n :prompt=\"prompt\"\n @delete=\"$emit('delete', $event)\"\n @edit=\"$emit('edit', $event)\"\n @steer=\"$emit('steer', $event)\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport ChatQueuedPrompt from './ChatQueuedPrompt.vue';\nimport type { QueuedChatPrompt } from './queued-prompts';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n prompts: readonly QueuedChatPrompt[];\n editDisabled?: boolean;\n steerDisabled?: boolean;\n}>();\n\ndefineEmits<{\n delete: [id: string];\n edit: [id: string];\n steer: [id: string];\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-queued-prompts {\n width: 100%;\n display: flex;\n flex-direction: column;\n border: 0.5px solid var(--color-border);\n border-bottom: 0;\n border-top-left-radius: var(--radius-xl);\n border-top-right-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-sm);\n}\n</style>\n","<template>\n <div\n class=\"codex-chat-theme chat-turn-git-info\"\n aria-label=\"Current turn git changes\"\n >\n <span class=\"chat-turn-git-info__label\">Current turn</span>\n <span class=\"chat-turn-git-info__diff\">\n <ChatAnimatedDiffStat\n v-if=\"diff.addedLines\"\n kind=\"added\"\n label=\"Added lines\"\n :value=\"diff.addedLines\"\n />\n <ChatAnimatedDiffStat\n v-if=\"diff.removedLines\"\n kind=\"deleted\"\n label=\"Removed lines\"\n :value=\"diff.removedLines\"\n />\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { TurnGitDiff } from './contracts';\nimport ChatAnimatedDiffStat from './ChatAnimatedDiffStat.vue';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n diff: TurnGitDiff;\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-turn-git-info {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--space-8);\n padding: var(--space-6) var(--space-12);\n border: 1px solid var(--color-border);\n border-bottom: none;\n border-radius: var(--radius-lg) var(--radius-lg) 0 0;\n color: var(--color-text-muted);\n background: var(--color-shell-main);\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n}\n\n.chat-turn-git-info__label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-turn-git-info__diff {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n gap: var(--space-4);\n}\n</style>\n","<template>\n <div\n class=\"codex-chat-theme chat-turn-git-info\"\n aria-label=\"Current turn git changes\"\n >\n <span class=\"chat-turn-git-info__label\">Current turn</span>\n <span class=\"chat-turn-git-info__diff\">\n <ChatAnimatedDiffStat\n v-if=\"diff.addedLines\"\n kind=\"added\"\n label=\"Added lines\"\n :value=\"diff.addedLines\"\n />\n <ChatAnimatedDiffStat\n v-if=\"diff.removedLines\"\n kind=\"deleted\"\n label=\"Removed lines\"\n :value=\"diff.removedLines\"\n />\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { TurnGitDiff } from './contracts';\nimport ChatAnimatedDiffStat from './ChatAnimatedDiffStat.vue';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n diff: TurnGitDiff;\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-turn-git-info {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--space-8);\n padding: var(--space-6) var(--space-12);\n border: 1px solid var(--color-border);\n border-bottom: none;\n border-radius: var(--radius-lg) var(--radius-lg) 0 0;\n color: var(--color-text-muted);\n background: var(--color-shell-main);\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n}\n\n.chat-turn-git-info__label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-turn-git-info__diff {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n gap: var(--space-4);\n}\n</style>\n","<template>\n <div v-if=\"visible\" class=\"codex-chat-theme chat-composer-shelf\">\n <ChatTurnGitInfo\n v-if=\"visibleTurnGitDiff\"\n :diff=\"visibleTurnGitDiff\"\n />\n <ChatQueuedPrompts\n v-if=\"showQueuedPrompts\"\n :edit-disabled=\"queuedPromptEditDisabled\"\n :steer-disabled=\"queuedPromptSteerDisabled\"\n :prompts=\"queuedPrompts\"\n @delete=\"$emit('deleteQueuedPrompt', $event)\"\n @edit=\"$emit('editQueuedPrompt', $event)\"\n @steer=\"$emit('steerQueuedPrompt', $event)\"\n />\n <ChatGoal\n v-if=\"showGoal\"\n :goal=\"goal\"\n @clear=\"$emit('clearGoal')\"\n @edit=\"$emit('editGoal')\"\n />\n <div v-if=\"showActions\" class=\"chat-composer-shelf__actions\">\n <slot name=\"actions\" :disabled=\"effectiveDisabled\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Comment, Fragment, Text, computed, type VNode } from 'vue';\nimport type { CodexComposerShelfPresentation, ThreadGoal, TurnGitDiff } from './contracts';\nimport ChatGoal from './ChatGoal.vue';\nimport ChatQueuedPrompts from './ChatQueuedPrompts.vue';\nimport ChatTurnGitInfo from './ChatTurnGitInfo.vue';\nimport type { QueuedChatPrompt } from './queued-prompts';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n disabled?: boolean;\n goal: ThreadGoal | null;\n presentation?: CodexComposerShelfPresentation;\n queuedPrompts: readonly QueuedChatPrompt[];\n queuedPromptEditDisabled?: boolean;\n queuedPromptSteerDisabled?: boolean;\n turnGitDiff?: TurnGitDiff | null;\n}>();\n\nconst slots = defineSlots<{\n actions(props: { disabled: boolean }): unknown;\n}>();\n\ndefineEmits<{\n clearGoal: [];\n deleteQueuedPrompt: [promptId: string];\n editQueuedPrompt: [promptId: string];\n editGoal: [];\n steerQueuedPrompt: [promptId: string];\n}>();\n// Stryker restore all\n\nconst showGoal = computed(() => (\n props.presentation?.goal !== false\n && Boolean(props.goal)\n && props.goal?.status !== 'complete'\n));\nconst showQueuedPrompts = computed(() => (\n props.presentation?.queuedPrompts !== false && props.queuedPrompts.length > 0\n));\nconst visibleTurnGitDiff = computed(() => (\n props.presentation?.turnGitDiff === false ? null : props.turnGitDiff ?? null\n));\nconst effectiveDisabled = computed(() => props.disabled ?? false);\nconst showActions = computed(() => hasSlotContent(slots.actions?.({ disabled: effectiveDisabled.value })));\nconst visible = computed(() => (\n showGoal.value\n || showQueuedPrompts.value\n || Boolean(visibleTurnGitDiff.value)\n || showActions.value\n));\n\nfunction hasSlotContent(content: unknown): boolean {\n const nodes = Array.isArray(content) ? content : [content];\n return nodes.some((node) => {\n if (node === null || node === undefined || typeof node === 'boolean') return false;\n if (typeof node === 'string' || typeof node === 'number') return String(node).trim().length > 0;\n if (typeof node !== 'object' || !('type' in node)) return true;\n const vnode = node as VNode;\n if (vnode.type === Comment) return false;\n if (vnode.type === Text) return String(vnode.children ?? '').trim().length > 0;\n if (vnode.type === Fragment) return hasSlotContent(vnode.children);\n return true;\n });\n}\n</script>\n\n<style scoped>\n.chat-composer-shelf {\n width: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.chat-composer-shelf:has(.chat-queued-prompts) {\n &:deep() {\n .chat-goal {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n }\n}\n\n.chat-composer-shelf__actions {\n width: 100%;\n min-height: var(--space-16);\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-3) var(--space-6);\n border: 0.5px solid var(--color-border);\n border-bottom: 0;\n background: var(--color-surface-lowest);\n color: var(--color-text-muted);\n}\n\n.chat-composer-shelf__actions:first-child {\n border-top-left-radius: var(--radius-xl);\n border-top-right-radius: var(--radius-xl);\n}\n\n\n</style>\n","<template>\n <div v-if=\"visible\" class=\"codex-chat-theme chat-composer-shelf\">\n <ChatTurnGitInfo\n v-if=\"visibleTurnGitDiff\"\n :diff=\"visibleTurnGitDiff\"\n />\n <ChatQueuedPrompts\n v-if=\"showQueuedPrompts\"\n :edit-disabled=\"queuedPromptEditDisabled\"\n :steer-disabled=\"queuedPromptSteerDisabled\"\n :prompts=\"queuedPrompts\"\n @delete=\"$emit('deleteQueuedPrompt', $event)\"\n @edit=\"$emit('editQueuedPrompt', $event)\"\n @steer=\"$emit('steerQueuedPrompt', $event)\"\n />\n <ChatGoal\n v-if=\"showGoal\"\n :goal=\"goal\"\n @clear=\"$emit('clearGoal')\"\n @edit=\"$emit('editGoal')\"\n />\n <div v-if=\"showActions\" class=\"chat-composer-shelf__actions\">\n <slot name=\"actions\" :disabled=\"effectiveDisabled\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Comment, Fragment, Text, computed, type VNode } from 'vue';\nimport type { CodexComposerShelfPresentation, ThreadGoal, TurnGitDiff } from './contracts';\nimport ChatGoal from './ChatGoal.vue';\nimport ChatQueuedPrompts from './ChatQueuedPrompts.vue';\nimport ChatTurnGitInfo from './ChatTurnGitInfo.vue';\nimport type { QueuedChatPrompt } from './queued-prompts';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n disabled?: boolean;\n goal: ThreadGoal | null;\n presentation?: CodexComposerShelfPresentation;\n queuedPrompts: readonly QueuedChatPrompt[];\n queuedPromptEditDisabled?: boolean;\n queuedPromptSteerDisabled?: boolean;\n turnGitDiff?: TurnGitDiff | null;\n}>();\n\nconst slots = defineSlots<{\n actions(props: { disabled: boolean }): unknown;\n}>();\n\ndefineEmits<{\n clearGoal: [];\n deleteQueuedPrompt: [promptId: string];\n editQueuedPrompt: [promptId: string];\n editGoal: [];\n steerQueuedPrompt: [promptId: string];\n}>();\n// Stryker restore all\n\nconst showGoal = computed(() => (\n props.presentation?.goal !== false\n && Boolean(props.goal)\n && props.goal?.status !== 'complete'\n));\nconst showQueuedPrompts = computed(() => (\n props.presentation?.queuedPrompts !== false && props.queuedPrompts.length > 0\n));\nconst visibleTurnGitDiff = computed(() => (\n props.presentation?.turnGitDiff === false ? null : props.turnGitDiff ?? null\n));\nconst effectiveDisabled = computed(() => props.disabled ?? false);\nconst showActions = computed(() => hasSlotContent(slots.actions?.({ disabled: effectiveDisabled.value })));\nconst visible = computed(() => (\n showGoal.value\n || showQueuedPrompts.value\n || Boolean(visibleTurnGitDiff.value)\n || showActions.value\n));\n\nfunction hasSlotContent(content: unknown): boolean {\n const nodes = Array.isArray(content) ? content : [content];\n return nodes.some((node) => {\n if (node === null || node === undefined || typeof node === 'boolean') return false;\n if (typeof node === 'string' || typeof node === 'number') return String(node).trim().length > 0;\n if (typeof node !== 'object' || !('type' in node)) return true;\n const vnode = node as VNode;\n if (vnode.type === Comment) return false;\n if (vnode.type === Text) return String(vnode.children ?? '').trim().length > 0;\n if (vnode.type === Fragment) return hasSlotContent(vnode.children);\n return true;\n });\n}\n</script>\n\n<style scoped>\n.chat-composer-shelf {\n width: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.chat-composer-shelf:has(.chat-queued-prompts) {\n &:deep() {\n .chat-goal {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n }\n}\n\n.chat-composer-shelf__actions {\n width: 100%;\n min-height: var(--space-16);\n display: flex;\n align-items: center;\n gap: var(--space-2);\n padding: var(--space-3) var(--space-6);\n border: 0.5px solid var(--color-border);\n border-bottom: 0;\n background: var(--color-surface-lowest);\n color: var(--color-text-muted);\n}\n\n.chat-composer-shelf__actions:first-child {\n border-top-left-radius: var(--radius-xl);\n border-top-right-radius: var(--radius-xl);\n}\n\n\n</style>\n","<template>\n <div\n class=\"codex-chat-theme codex-conversation-history-loader\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Loading conversation\"\n >\n <div class=\"codex-conversation-history-loader__inner\">\n <div class=\"codex-conversation-history-loader__block codex-conversation-history-loader__block--user\" />\n <div class=\"codex-conversation-history-loader__group\">\n <div class=\"codex-conversation-history-loader__block codex-conversation-history-loader__block--wide\" />\n <div class=\"codex-conversation-history-loader__block codex-conversation-history-loader__block--medium\" />\n <div class=\"codex-conversation-history-loader__block codex-conversation-history-loader__block--short\" />\n </div>\n <div class=\"codex-conversation-history-loader__group\">\n <div class=\"codex-conversation-history-loader__block codex-conversation-history-loader__block--tool\" />\n <div class=\"codex-conversation-history-loader__block codex-conversation-history-loader__block--wide\" />\n <div class=\"codex-conversation-history-loader__block codex-conversation-history-loader__block--medium\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.codex-conversation-history-loader {\n --conversation-history-loader-shine: var(--color-shine, rgb(255 255 255 / 64%));\n display: grid;\n align-items: center;\n height: 100%;\n padding: var(--space-8) var(--space-32);\n}\n\n.codex-conversation-history-loader__inner {\n display: grid;\n gap: var(--space-8);\n}\n\n.codex-conversation-history-loader__group {\n display: grid;\n gap: var(--space-3);\n max-width: 560px;\n}\n\n.codex-conversation-history-loader__block {\n position: relative;\n overflow: hidden;\n height: 16px;\n border-radius: var(--radius-full);\n background: var(--color-surface-base);\n}\n\n.codex-conversation-history-loader__block::after {\n position: absolute;\n inset: 0;\n content: '';\n background: linear-gradient(\n 90deg,\n transparent 0%,\n var(--conversation-history-loader-shine) 48%,\n transparent 100%\n );\n transform: translateX(-100%);\n animation: codex-conversation-history-loader-shine 1.35s ease-in-out infinite;\n}\n\n.codex-conversation-history-loader__block--user {\n justify-self: end;\n width: min(260px, 55%);\n height: 34px;\n border-radius: var(--radius-xl);\n}\n\n.codex-conversation-history-loader__block--wide {\n width: min(520px, 100%);\n}\n\n.codex-conversation-history-loader__block--medium {\n width: min(420px, 82%);\n}\n\n.codex-conversation-history-loader__block--short {\n width: min(280px, 58%);\n}\n\n.codex-conversation-history-loader__block--tool {\n width: min(340px, 72%);\n height: 28px;\n border-radius: var(--radius-lg);\n}\n\n@keyframes codex-conversation-history-loader-shine {\n to {\n transform: translateX(100%);\n }\n}\n</style>\n","import type { SurfaceMessage } from '@codex-app-sdk/core/surface'\nimport { computeMessageBlocks } from './message-blocks'\nimport { chatMessageFromInput } from './renderer-message-adapter'\nimport type { Message, MessageToolCall } from './types'\n\n/** Return false to hide a tool call from the rendered transcript only. */\nexport type CodexToolVisibility = (toolCall: MessageToolCall) => boolean\n\nexport function filterVisibleMessageTools(\n message: Message | SurfaceMessage,\n visibility: CodexToolVisibility | undefined,\n): Message | SurfaceMessage | null {\n if (!visibility) return message\n\n const adapted = chatMessageFromInput(message)\n const decisions = new Map<string, boolean>()\n const isVisible = (toolCall: MessageToolCall) => {\n if (!decisions.has(toolCall.id)) decisions.set(toolCall.id, visibility(toolCall))\n return decisions.get(toolCall.id)!\n }\n const toolCalls = adapted.toolCalls?.filter(isVisible)\n const parts = adapted.parts?.filter((part) => part.type !== 'tool' || isVisible(part.toolCall))\n if (toolCalls?.length === adapted.toolCalls?.length && parts?.length === adapted.parts?.length) {\n return message\n }\n\n const filtered = { ...adapted, parts, toolCalls }\n return computeMessageBlocks(filtered).length > 0 ? filtered : null\n}\n","<template>\n <component\n :is=\"href ? 'a' : 'button'\"\n class=\"codex-chat-theme chat-icon-button\"\n :class=\"{\n 'chat-icon-button--bordered': bordered,\n 'chat-icon-button--danger': danger,\n 'chat-icon-button--disabled': disabled,\n }\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :disabled=\"href ? undefined : disabled\"\n :download=\"typeof download === 'string' ? download : download ? '' : undefined\"\n :href=\"disabled ? undefined : href\"\n :rel=\"rel\"\n :target=\"target\"\n :type=\"href ? undefined : 'button'\"\n :aria-label=\"label\"\n :title=\"title || label\"\n >\n <slot />\n </component>\n</template>\n\n<script setup lang=\"ts\">\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n bordered?: boolean\n danger?: boolean\n disabled?: boolean\n download?: boolean | string\n href?: string\n label: string\n rel?: string\n target?: string\n title?: string\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--chat-message-action-control-size, var(--space-12));\n height: var(--chat-message-action-control-size, var(--space-12));\n padding: var(--space-2);\n border: 0;\n border-radius: var(--radius-lg);\n appearance: none;\n background: transparent;\n color: var(--color-outline);\n cursor: pointer;\n font: inherit;\n line-height: 1;\n text-decoration: none;\n}\n\n.chat-icon-button--bordered {\n border: 1px solid var(--color-border);\n background: var(--color-surface-lowest);\n}\n\n.chat-icon-button:not(:disabled):not([aria-disabled='true']):hover,\n.chat-icon-button:not(:disabled):not([aria-disabled='true']):focus-visible {\n background-color: var(--color-surface-low);\n color: var(--color-text);\n}\n\n.chat-icon-button--danger:not(:disabled):not([aria-disabled='true']):hover,\n.chat-icon-button--danger:not(:disabled):not([aria-disabled='true']):focus-visible {\n color: var(--color-error);\n}\n\n.chat-icon-button--disabled {\n cursor: default;\n opacity: 0.45;\n}\n\n.chat-icon-button :deep(svg) {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n</style>\n","<template>\n <component\n :is=\"href ? 'a' : 'button'\"\n class=\"codex-chat-theme chat-icon-button\"\n :class=\"{\n 'chat-icon-button--bordered': bordered,\n 'chat-icon-button--danger': danger,\n 'chat-icon-button--disabled': disabled,\n }\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :disabled=\"href ? undefined : disabled\"\n :download=\"typeof download === 'string' ? download : download ? '' : undefined\"\n :href=\"disabled ? undefined : href\"\n :rel=\"rel\"\n :target=\"target\"\n :type=\"href ? undefined : 'button'\"\n :aria-label=\"label\"\n :title=\"title || label\"\n >\n <slot />\n </component>\n</template>\n\n<script setup lang=\"ts\">\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n bordered?: boolean\n danger?: boolean\n disabled?: boolean\n download?: boolean | string\n href?: string\n label: string\n rel?: string\n target?: string\n title?: string\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-icon-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--chat-message-action-control-size, var(--space-12));\n height: var(--chat-message-action-control-size, var(--space-12));\n padding: var(--space-2);\n border: 0;\n border-radius: var(--radius-lg);\n appearance: none;\n background: transparent;\n color: var(--color-outline);\n cursor: pointer;\n font: inherit;\n line-height: 1;\n text-decoration: none;\n}\n\n.chat-icon-button--bordered {\n border: 1px solid var(--color-border);\n background: var(--color-surface-lowest);\n}\n\n.chat-icon-button:not(:disabled):not([aria-disabled='true']):hover,\n.chat-icon-button:not(:disabled):not([aria-disabled='true']):focus-visible {\n background-color: var(--color-surface-low);\n color: var(--color-text);\n}\n\n.chat-icon-button--danger:not(:disabled):not([aria-disabled='true']):hover,\n.chat-icon-button--danger:not(:disabled):not([aria-disabled='true']):focus-visible {\n color: var(--color-error);\n}\n\n.chat-icon-button--disabled {\n cursor: default;\n opacity: 0.45;\n}\n\n.chat-icon-button :deep(svg) {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n</style>\n","const inheritedThemeTokens = [\n '--color-background',\n '--color-text',\n '--color-text-muted',\n '--color-border',\n '--color-border-strong',\n '--color-error',\n '--color-warning',\n '--color-success',\n '--color-primary',\n '--color-primary-container',\n '--color-secondary',\n '--color-secondary-container',\n '--color-on-primary',\n '--color-on-primary-container',\n '--color-on-secondary-container',\n '--color-overlay',\n '--color-surface-lowest',\n '--color-surface',\n '--color-surface-base',\n '--color-surface-low',\n '--color-surface-high',\n '--color-surface-highest',\n '--color-shell-main',\n '--font-family-base',\n '--font-family-mono',\n '--font-size-12',\n '--font-size-13',\n '--line-height-16',\n '--line-height-20',\n '--space-2',\n '--space-4',\n '--space-6',\n '--space-8',\n '--space-12',\n '--space-16',\n '--radius-md',\n '--radius-lg',\n '--shadow-lg',\n] as const;\n\nexport type CodexPortalTheme = {\n mode: 'dark' | 'light';\n style: Record<string, string>;\n};\n\nexport function captureCodexPortalTheme(element: Element | null): CodexPortalTheme {\n if (!element || typeof getComputedStyle !== 'function') {\n return { mode: 'light', style: {} };\n }\n\n const computed = getComputedStyle(element);\n const style: Record<string, string> = {};\n for (const token of inheritedThemeTokens) {\n const value = computed.getPropertyValue(token).trim();\n if (value) style[token] = value;\n }\n\n return {\n mode: computed.colorScheme.includes('dark') ? 'dark' : 'light',\n style,\n };\n}\n","<template>\n <Teleport to=\"body\">\n <div\n v-if=\"open\"\n class=\"codex-chat-theme chat-image-lightbox chat-media-block__fullscreen\"\n :data-codex-theme=\"portalTheme.mode\"\n :style=\"portalTheme.style\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"label\"\n @click.self=\"emit('close')\"\n >\n <ChatIconButton\n bordered\n class=\"chat-image-lightbox__close chat-media-block__fullscreen-close\"\n :label=\"closeLabel\"\n @click=\"emit('close')\"\n >\n <X />\n </ChatIconButton>\n <img\n class=\"chat-image-lightbox__image chat-media-block__fullscreen-image\"\n :alt=\"alt\"\n :src=\"src\"\n >\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, ref, watch } from 'vue'\nimport { X } from '../icons/app-icons'\nimport ChatIconButton from './ChatIconButton.vue'\nimport { captureCodexPortalTheme, type CodexPortalTheme } from './portal-theme'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n alt: string\n closeLabel?: string\n label: string\n open: boolean\n src: string\n themeSource?: HTMLElement | null\n}>(), {\n closeLabel: 'Close fullscreen',\n themeSource: null,\n})\n// Stryker restore all\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n close: []\n}>()\n// Stryker restore all\n\nconst portalTheme = ref<CodexPortalTheme>({ mode: 'light', style: {} })\n\nwatch(() => props.open, (open) => {\n if (open) {\n portalTheme.value = captureCodexPortalTheme(props.themeSource)\n window.addEventListener('keydown', handleKeydown)\n } else {\n window.removeEventListener('keydown', handleKeydown)\n }\n}, { immediate: true })\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', handleKeydown)\n})\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') emit('close')\n}\n</script>\n\n<style scoped>\n.chat-image-lightbox {\n position: fixed;\n inset: 0;\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: calc(var(--space-20) + var(--space-12)) var(--space-12) var(--space-12);\n background: var(--color-overlay);\n}\n\n.chat-image-lightbox__close {\n position: absolute;\n top: var(--space-6);\n right: var(--space-6);\n}\n\n.chat-image-lightbox__image {\n display: block;\n max-width: 100%;\n max-height: 100%;\n border-radius: var(--radius-lg);\n box-shadow: var(--shadow-lg);\n object-fit: contain;\n}\n</style>\n","<template>\n <Teleport to=\"body\">\n <div\n v-if=\"open\"\n class=\"codex-chat-theme chat-image-lightbox chat-media-block__fullscreen\"\n :data-codex-theme=\"portalTheme.mode\"\n :style=\"portalTheme.style\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"label\"\n @click.self=\"emit('close')\"\n >\n <ChatIconButton\n bordered\n class=\"chat-image-lightbox__close chat-media-block__fullscreen-close\"\n :label=\"closeLabel\"\n @click=\"emit('close')\"\n >\n <X />\n </ChatIconButton>\n <img\n class=\"chat-image-lightbox__image chat-media-block__fullscreen-image\"\n :alt=\"alt\"\n :src=\"src\"\n >\n </div>\n </Teleport>\n</template>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, ref, watch } from 'vue'\nimport { X } from '../icons/app-icons'\nimport ChatIconButton from './ChatIconButton.vue'\nimport { captureCodexPortalTheme, type CodexPortalTheme } from './portal-theme'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n alt: string\n closeLabel?: string\n label: string\n open: boolean\n src: string\n themeSource?: HTMLElement | null\n}>(), {\n closeLabel: 'Close fullscreen',\n themeSource: null,\n})\n// Stryker restore all\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n close: []\n}>()\n// Stryker restore all\n\nconst portalTheme = ref<CodexPortalTheme>({ mode: 'light', style: {} })\n\nwatch(() => props.open, (open) => {\n if (open) {\n portalTheme.value = captureCodexPortalTheme(props.themeSource)\n window.addEventListener('keydown', handleKeydown)\n } else {\n window.removeEventListener('keydown', handleKeydown)\n }\n}, { immediate: true })\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', handleKeydown)\n})\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') emit('close')\n}\n</script>\n\n<style scoped>\n.chat-image-lightbox {\n position: fixed;\n inset: 0;\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: calc(var(--space-20) + var(--space-12)) var(--space-12) var(--space-12);\n background: var(--color-overlay);\n}\n\n.chat-image-lightbox__close {\n position: absolute;\n top: var(--space-6);\n right: var(--space-6);\n}\n\n.chat-image-lightbox__image {\n display: block;\n max-width: 100%;\n max-height: 100%;\n border-radius: var(--radius-lg);\n box-shadow: var(--shadow-lg);\n object-fit: contain;\n}\n</style>\n","<template>\n <figure\n v-if=\"previewSource && !previewFailed\"\n ref=\"rootElement\"\n class=\"codex-chat-theme chat-attachment-block chat-attachment-block--image\"\n :title=\"attachment.path || attachment.url || attachment.name\"\n >\n <button\n class=\"chat-attachment-block__preview-button\"\n type=\"button\"\n :aria-label=\"`Open ${attachment.name}`\"\n @click=\"handleImageOpen\"\n >\n <img\n class=\"chat-attachment-block__preview\"\n :alt=\"attachment.name\"\n :src=\"previewSource\"\n @error=\"previewFailed = true\"\n >\n </button>\n <ChatImageLightbox\n :alt=\"attachment.name\"\n :label=\"attachment.name\"\n :open=\"fullscreenOpen\"\n :src=\"previewSource\"\n :theme-source=\"rootElement\"\n @close=\"fullscreenOpen = false\"\n />\n </figure>\n <component\n :is=\"chipHref ? 'a' : 'span'\"\n v-else\n class=\"codex-chat-theme chat-attachment-block chat-attachment-block--chip\"\n :href=\"chipHref\"\n :title=\"attachment.path || attachment.url || attachment.name\"\n >\n <PhotoIcon v-if=\"attachment.kind === 'image'\" aria-hidden=\"true\" />\n <PaperclipIcon v-else aria-hidden=\"true\" />\n <span class=\"chat-attachment-block__name\">{{ attachment.name }}</span>\n </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { useCodexHostCapabilities } from '../native-capabilities'\nimport { PaperclipIcon, PhotoIcon } from '../icons/app-icons'\nimport ChatImageLightbox from './ChatImageLightbox.vue'\nimport type { CodexMessageImageOpenHandler } from './message-image'\nimport type { MessageAttachment } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n attachment: MessageAttachment\n openImage?: CodexMessageImageOpenHandler\n}>()\n// Stryker restore all\n\nconst hostCapabilities = useCodexHostCapabilities()\n\nconst previewFailed = ref(false)\nconst nativePreviewSource = ref<string>()\nconst fullscreenOpen = ref(false)\nconst rootElement = ref<HTMLElement | null>(null)\nconst previewSource = computed(() => (\n props.attachment.kind === 'image' && isSafeImageSource(props.attachment.url)\n ? props.attachment.url\n : nativePreviewSource.value\n))\nconst chipHref = computed(() => (\n safeFileHref(props.attachment.path) || safeLinkHref(props.attachment.url)\n))\n\nwatch(previewSource, () => {\n previewFailed.value = false\n})\n\nlet previewRequest = 0\nwatch(\n () => [props.attachment.kind, props.attachment.path, props.attachment.url] as const,\n async ([kind, path, url]) => {\n const request = ++previewRequest\n nativePreviewSource.value = undefined\n if (kind !== 'image' || !path || isSafeImageSource(url)) return\n const readImagePreview = hostCapabilities?.readImagePreview\n if (!readImagePreview) return\n try {\n const source = await readImagePreview(path)\n if (request === previewRequest && source && isSafeImageSource(source)) {\n nativePreviewSource.value = source\n }\n } catch {\n // Missing, stale, or unreadable historical attachments remain file chips.\n }\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n previewRequest += 1\n})\n\nasync function handleImageOpen() {\n const src = previewSource.value\n if (!src) return\n const image = {\n alt: props.attachment.name,\n kind: 'attachment',\n mimeType: props.attachment.mimeType,\n name: props.attachment.name,\n path: props.attachment.path,\n src,\n title: props.attachment.name,\n } as const\n if (await props.openImage?.(image, { intent: 'open' }) === true) return\n fullscreenOpen.value = true\n}\n\nfunction isSafeImageSource(value: string | undefined): value is string {\n if (!value) return false\n if (/^(?:\\.\\.?\\/|\\/(?!\\/))/.test(value)) return true\n return /^(?:https?:|blob:)/i.test(value)\n || /^data:image\\/(?:avif|bmp|gif|heic|heif|jpe?g|png|webp);base64,/i.test(value)\n}\n\nfunction safeLinkHref(value: string | undefined): string | undefined {\n return value && /^(?:https?:|file:)/i.test(value) ? value : undefined\n}\n\nfunction safeFileHref(value: string | undefined): string | undefined {\n if (!value || /^(?:\\\\\\\\|\\/\\/)/.test(value)) return undefined\n if (/^[a-z]:[\\\\/]/i.test(value)) return value\n return /^[a-z][a-z\\d+.-]*:/i.test(value)\n ? (/^file:/i.test(value) ? value : undefined)\n : value\n}\n</script>\n\n<style scoped>\n.chat-attachment-block {\n box-sizing: border-box;\n max-width: 100%;\n color: inherit;\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n}\n\n.chat-attachment-block--image {\n width: min(160px, 100%);\n margin: 0;\n padding: var(--space-1);\n overflow: hidden;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n background: var(--color-surface-lowest);\n}\n\n.chat-attachment-block__preview {\n display: block;\n width: 100%;\n height: 120px;\n border-radius: calc(var(--radius-lg) - var(--space-1));\n object-fit: cover;\n}\n\n.chat-attachment-block__preview-button {\n display: block;\n width: 100%;\n padding: 0;\n border: 0;\n appearance: none;\n background: transparent;\n cursor: pointer;\n}\n\n.chat-attachment-block--chip {\n display: flex;\n min-width: 0;\n align-items: center;\n gap: var(--space-3);\n}\n\n.chat-attachment-block--chip {\n width: fit-content;\n max-width: 260px;\n margin: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-4);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n text-decoration: none;\n}\n\na.chat-attachment-block--chip:hover {\n border-color: var(--color-border-strong, var(--color-text-muted));\n background: var(--color-surface-low);\n}\n\n.chat-attachment-block svg {\n width: var(--space-8);\n height: var(--space-8);\n flex: 0 0 auto;\n color: var(--color-text-muted);\n}\n\n.chat-attachment-block__name {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n</style>\n","<template>\n <figure\n v-if=\"previewSource && !previewFailed\"\n ref=\"rootElement\"\n class=\"codex-chat-theme chat-attachment-block chat-attachment-block--image\"\n :title=\"attachment.path || attachment.url || attachment.name\"\n >\n <button\n class=\"chat-attachment-block__preview-button\"\n type=\"button\"\n :aria-label=\"`Open ${attachment.name}`\"\n @click=\"handleImageOpen\"\n >\n <img\n class=\"chat-attachment-block__preview\"\n :alt=\"attachment.name\"\n :src=\"previewSource\"\n @error=\"previewFailed = true\"\n >\n </button>\n <ChatImageLightbox\n :alt=\"attachment.name\"\n :label=\"attachment.name\"\n :open=\"fullscreenOpen\"\n :src=\"previewSource\"\n :theme-source=\"rootElement\"\n @close=\"fullscreenOpen = false\"\n />\n </figure>\n <component\n :is=\"chipHref ? 'a' : 'span'\"\n v-else\n class=\"codex-chat-theme chat-attachment-block chat-attachment-block--chip\"\n :href=\"chipHref\"\n :title=\"attachment.path || attachment.url || attachment.name\"\n >\n <PhotoIcon v-if=\"attachment.kind === 'image'\" aria-hidden=\"true\" />\n <PaperclipIcon v-else aria-hidden=\"true\" />\n <span class=\"chat-attachment-block__name\">{{ attachment.name }}</span>\n </component>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { useCodexHostCapabilities } from '../native-capabilities'\nimport { PaperclipIcon, PhotoIcon } from '../icons/app-icons'\nimport ChatImageLightbox from './ChatImageLightbox.vue'\nimport type { CodexMessageImageOpenHandler } from './message-image'\nimport type { MessageAttachment } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n attachment: MessageAttachment\n openImage?: CodexMessageImageOpenHandler\n}>()\n// Stryker restore all\n\nconst hostCapabilities = useCodexHostCapabilities()\n\nconst previewFailed = ref(false)\nconst nativePreviewSource = ref<string>()\nconst fullscreenOpen = ref(false)\nconst rootElement = ref<HTMLElement | null>(null)\nconst previewSource = computed(() => (\n props.attachment.kind === 'image' && isSafeImageSource(props.attachment.url)\n ? props.attachment.url\n : nativePreviewSource.value\n))\nconst chipHref = computed(() => (\n safeFileHref(props.attachment.path) || safeLinkHref(props.attachment.url)\n))\n\nwatch(previewSource, () => {\n previewFailed.value = false\n})\n\nlet previewRequest = 0\nwatch(\n () => [props.attachment.kind, props.attachment.path, props.attachment.url] as const,\n async ([kind, path, url]) => {\n const request = ++previewRequest\n nativePreviewSource.value = undefined\n if (kind !== 'image' || !path || isSafeImageSource(url)) return\n const readImagePreview = hostCapabilities?.readImagePreview\n if (!readImagePreview) return\n try {\n const source = await readImagePreview(path)\n if (request === previewRequest && source && isSafeImageSource(source)) {\n nativePreviewSource.value = source\n }\n } catch {\n // Missing, stale, or unreadable historical attachments remain file chips.\n }\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n previewRequest += 1\n})\n\nasync function handleImageOpen() {\n const src = previewSource.value\n if (!src) return\n const image = {\n alt: props.attachment.name,\n kind: 'attachment',\n mimeType: props.attachment.mimeType,\n name: props.attachment.name,\n path: props.attachment.path,\n src,\n title: props.attachment.name,\n } as const\n if (await props.openImage?.(image, { intent: 'open' }) === true) return\n fullscreenOpen.value = true\n}\n\nfunction isSafeImageSource(value: string | undefined): value is string {\n if (!value) return false\n if (/^(?:\\.\\.?\\/|\\/(?!\\/))/.test(value)) return true\n return /^(?:https?:|blob:)/i.test(value)\n || /^data:image\\/(?:avif|bmp|gif|heic|heif|jpe?g|png|webp);base64,/i.test(value)\n}\n\nfunction safeLinkHref(value: string | undefined): string | undefined {\n return value && /^(?:https?:|file:)/i.test(value) ? value : undefined\n}\n\nfunction safeFileHref(value: string | undefined): string | undefined {\n if (!value || /^(?:\\\\\\\\|\\/\\/)/.test(value)) return undefined\n if (/^[a-z]:[\\\\/]/i.test(value)) return value\n return /^[a-z][a-z\\d+.-]*:/i.test(value)\n ? (/^file:/i.test(value) ? value : undefined)\n : value\n}\n</script>\n\n<style scoped>\n.chat-attachment-block {\n box-sizing: border-box;\n max-width: 100%;\n color: inherit;\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n}\n\n.chat-attachment-block--image {\n width: min(160px, 100%);\n margin: 0;\n padding: var(--space-1);\n overflow: hidden;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n background: var(--color-surface-lowest);\n}\n\n.chat-attachment-block__preview {\n display: block;\n width: 100%;\n height: 120px;\n border-radius: calc(var(--radius-lg) - var(--space-1));\n object-fit: cover;\n}\n\n.chat-attachment-block__preview-button {\n display: block;\n width: 100%;\n padding: 0;\n border: 0;\n appearance: none;\n background: transparent;\n cursor: pointer;\n}\n\n.chat-attachment-block--chip {\n display: flex;\n min-width: 0;\n align-items: center;\n gap: var(--space-3);\n}\n\n.chat-attachment-block--chip {\n width: fit-content;\n max-width: 260px;\n margin: 0;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-4);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n text-decoration: none;\n}\n\na.chat-attachment-block--chip:hover {\n border-color: var(--color-border-strong, var(--color-text-muted));\n background: var(--color-surface-low);\n}\n\n.chat-attachment-block svg {\n width: var(--space-8);\n height: var(--space-8);\n flex: 0 0 auto;\n color: var(--color-text-muted);\n}\n\n.chat-attachment-block__name {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-follow-ups\">\n <button\n v-for=\"prompt in prompts\"\n :key=\"prompt\"\n class=\"chat-follow-ups__chip\"\n :disabled=\"disabled\"\n type=\"button\"\n @click=\"emit('send-follow-up', prompt)\"\n >\n {{ prompt }}\n </button>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n disabled?: boolean\n prompts: string[]\n}>()\n\nconst emit = defineEmits<{\n 'send-follow-up': [prompt: string]\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-follow-ups {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-4);\n margin: var(--space-4) 0;\n}\n\n.chat-follow-ups__chip {\n border: 1px solid var(--color-border-strong);\n border-radius: var(--radius-full);\n padding: var(--space-2) var(--space-6);\n background: var(--color-surface-lowest);\n color: var(--color-text-muted);\n cursor: pointer;\n font-family: var(--font-family-base);\n font-size: var(--font-size-14);\n line-height: var(--line-height-20);\n text-align: left;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-follow-ups__chip:hover:not(:disabled) {\n background: var(--color-text-muted);\n color: var(--color-surface-lowest);\n}\n\n.chat-follow-ups__chip:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-follow-ups\">\n <button\n v-for=\"prompt in prompts\"\n :key=\"prompt\"\n class=\"chat-follow-ups__chip\"\n :disabled=\"disabled\"\n type=\"button\"\n @click=\"emit('send-follow-up', prompt)\"\n >\n {{ prompt }}\n </button>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n disabled?: boolean\n prompts: string[]\n}>()\n\nconst emit = defineEmits<{\n 'send-follow-up': [prompt: string]\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-follow-ups {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-4);\n margin: var(--space-4) 0;\n}\n\n.chat-follow-ups__chip {\n border: 1px solid var(--color-border-strong);\n border-radius: var(--radius-full);\n padding: var(--space-2) var(--space-6);\n background: var(--color-surface-lowest);\n color: var(--color-text-muted);\n cursor: pointer;\n font-family: var(--font-family-base);\n font-size: var(--font-size-14);\n line-height: var(--line-height-20);\n text-align: left;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-follow-ups__chip:hover:not(:disabled) {\n background: var(--color-text-muted);\n color: var(--color-surface-lowest);\n}\n\n.chat-follow-ups__chip:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n</style>\n","<template>\n <ChatIconButton :disabled=\"disabled\" :label=\"copied ? copiedLabel : label\" @click=\"copy\">\n <CheckIcon v-if=\"copied\" />\n <CopyIcon v-else />\n </ChatIconButton>\n</template>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, ref } from 'vue'\nimport { CheckIcon, CopyIcon } from '../icons/app-icons'\nimport ChatIconButton from './ChatIconButton.vue'\n\nconst props = defineProps<{\n action: () => Promise<void> | void\n copiedLabel: string\n disabled?: boolean\n label: string\n}>()\n\nconst copied = ref(false)\nlet resetTimeout: ReturnType<typeof setTimeout> | null = null\n\nasync function copy() {\n await props.action()\n copied.value = true\n\n if (resetTimeout) clearTimeout(resetTimeout)\n resetTimeout = setTimeout(() => {\n copied.value = false\n resetTimeout = null\n }, 1_500)\n}\n\nonBeforeUnmount(() => {\n if (resetTimeout) clearTimeout(resetTimeout)\n})\n</script>\n","<template>\n <ChatIconButton :disabled=\"disabled\" :label=\"copied ? copiedLabel : label\" @click=\"copy\">\n <CheckIcon v-if=\"copied\" />\n <CopyIcon v-else />\n </ChatIconButton>\n</template>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, ref } from 'vue'\nimport { CheckIcon, CopyIcon } from '../icons/app-icons'\nimport ChatIconButton from './ChatIconButton.vue'\n\nconst props = defineProps<{\n action: () => Promise<void> | void\n copiedLabel: string\n disabled?: boolean\n label: string\n}>()\n\nconst copied = ref(false)\nlet resetTimeout: ReturnType<typeof setTimeout> | null = null\n\nasync function copy() {\n await props.action()\n copied.value = true\n\n if (resetTimeout) clearTimeout(resetTimeout)\n resetTimeout = setTimeout(() => {\n copied.value = false\n resetTimeout = null\n }, 1_500)\n}\n\nonBeforeUnmount(() => {\n if (resetTimeout) clearTimeout(resetTimeout)\n})\n</script>\n","<template>\n <div class=\"codex-chat-theme chat-fold\" :class=\"{ 'chat-fold--open': open }\">\n <div class=\"chat-fold__inner\">\n <slot />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n open: boolean\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-fold {\n display: grid;\n grid-template-rows: 0fr;\n opacity: 0;\n transition:\n grid-template-rows 180ms ease,\n opacity 140ms ease;\n}\n\n.chat-fold--open {\n margin-top: var(--space-1);\n display: flex;\n opacity: 1;\n}\n\n.chat-fold__inner {\n min-height: 0;\n overflow: hidden;\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-fold\" :class=\"{ 'chat-fold--open': open }\">\n <div class=\"chat-fold__inner\">\n <slot />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineProps<{\n open: boolean\n}>()\n// Stryker restore all\n</script>\n\n<style scoped>\n.chat-fold {\n display: grid;\n grid-template-rows: 0fr;\n opacity: 0;\n transition:\n grid-template-rows 180ms ease,\n opacity 140ms ease;\n}\n\n.chat-fold--open {\n margin-top: var(--space-1);\n display: flex;\n opacity: 1;\n}\n\n.chat-fold__inner {\n min-height: 0;\n overflow: hidden;\n}\n</style>\n","<template>\n <figure ref=\"rootElement\" class=\"codex-chat-theme chat-media-block\">\n <button\n class=\"chat-media-block__image-button\"\n type=\"button\"\n :aria-label=\"openLabel\"\n @click=\"handleImageAction('open')\"\n >\n <img\n class=\"chat-media-block__image\"\n :alt=\"media.alt || generatedAltLabel\"\n :src=\"media.url\"\n >\n </button>\n <figcaption class=\"chat-media-block__footer\">\n <span class=\"chat-media-block__title\">{{ media.title || generatedLabel }}</span>\n <span class=\"chat-media-block__actions\">\n <ChatIconButton :label=\"fullscreenLabel\" @click=\"handleImageAction('fullscreen')\">\n <Maximize2 />\n </ChatIconButton>\n <ChatCopyButton\n :action=\"copyImage\"\n :copied-label=\"copiedLabel\"\n :label=\"copyLabel\"\n />\n <ChatIconButton\n :download=\"downloadName\"\n :href=\"media.url\"\n :label=\"downloadLabel\"\n @click.stop\n >\n <Download />\n </ChatIconButton>\n <ChatIconButton v-if=\"media.prompt\" :label=\"promptLabel\" @click=\"toggleDetails\">\n <Info />\n </ChatIconButton>\n </span>\n </figcaption>\n <ChatFoldTransition v-if=\"media.prompt\" :open=\"detailsOpen\">\n <div class=\"chat-media-block__details\">\n <div class=\"chat-media-block__details-title\">{{ promptLabel }}</div>\n <p class=\"chat-media-block__prompt\">{{ media.prompt }}</p>\n </div>\n </ChatFoldTransition>\n <ChatImageLightbox\n :alt=\"media.alt || generatedAltLabel\"\n :label=\"media.title || generatedLabel\"\n :open=\"fullscreenOpen\"\n :src=\"media.url\"\n :theme-source=\"rootElement\"\n @close=\"closeFullscreen\"\n />\n </figure>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { Download, Info, Maximize2 } from '../icons/app-icons'\nimport ChatCopyButton from './ChatCopyButton.vue'\nimport ChatFoldTransition from './ChatFoldTransition.vue'\nimport ChatImageLightbox from './ChatImageLightbox.vue'\nimport ChatIconButton from './ChatIconButton.vue'\nimport type { CodexMessageImageOpenHandler, CodexMessageImageOpenIntent } from './message-image'\nimport type { MessageMedia } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n media: MessageMedia\n openImage?: CodexMessageImageOpenHandler\n}>()\n// Stryker restore all\n\nconst downloadLabel = 'Download media'\nconst copyLabel = 'Copy image'\nconst copiedLabel = 'Image copied'\nconst fullscreenLabel = 'Open fullscreen'\nconst generatedAltLabel = 'Generated media'\nconst generatedLabel = 'Generated media'\nconst promptLabel = 'Prompt'\nconst openLabel = computed(() => `Open ${props.media.title || props.media.alt || generatedLabel}`)\nconst detailsOpen = ref(false)\nconst fullscreenOpen = ref(false)\nconst rootElement = ref<HTMLElement | null>(null)\nconst downloadName = computed(() => mediaDownloadName(props.media))\n\nasync function handleImageAction(intent: CodexMessageImageOpenIntent) {\n const image = {\n alt: props.media.alt || generatedAltLabel,\n kind: 'media',\n mimeType: props.media.mimeType,\n name: props.media.title,\n src: props.media.url,\n title: props.media.title || generatedLabel,\n } as const\n if (await props.openImage?.(image, { intent }) === true) return\n fullscreenOpen.value = true\n}\n\nfunction closeFullscreen() {\n fullscreenOpen.value = false\n}\n\nasync function copyImage() {\n const blob = await fetch(props.media.url).then((response) => response.blob())\n const mimeType = blob.type || props.media.mimeType || 'image/png'\n await navigator.clipboard.write([\n new ClipboardItem({ [mimeType]: blob }),\n ])\n}\n\nfunction toggleDetails() {\n detailsOpen.value = !detailsOpen.value\n}\n\nfunction mediaDownloadName(media: MessageMedia): string {\n const baseName = (media.title?.trim() || media.alt?.trim() || 'generated-image')\n .replace(/[\\\\/:*?\"<>|]+/g, '-')\n if (/\\.[a-z\\d]{2,5}$/i.test(baseName)) return baseName\n const extension = {\n 'image/avif': 'avif',\n 'image/gif': 'gif',\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/webp': 'webp',\n }[media.mimeType ?? '']\n return extension ? `${baseName}.${extension}` : baseName\n}\n\n</script>\n\n<style scoped>\n.chat-media-block {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n max-width: 60%;\n margin: var(--space-3) var(--space-6);\n}\n\n.chat-media-block__image-button {\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n border: none;\n border-radius: var(--radius-lg);\n appearance: none;\n background: var(--color-surface-low);\n cursor: pointer;\n}\n\n.chat-media-block__image {\n display: block;\n width: 100%;\n height: auto;\n}\n\n.chat-media-block__footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n}\n\n.chat-media-block__title {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-media-block__actions {\n display: inline-flex;\n align-items: center;\n gap: 0;\n}\n\n.chat-media-block__details {\n color: var(--color-text-muted);\n}\n\n.chat-media-block__details-title {\n margin-bottom: var(--space-2);\n color: var(--color-text);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-semibold);\n line-height: var(--line-height-16);\n}\n\n.chat-media-block__prompt {\n margin: 0;\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n white-space: pre-wrap;\n}\n\n</style>\n","<template>\n <figure ref=\"rootElement\" class=\"codex-chat-theme chat-media-block\">\n <button\n class=\"chat-media-block__image-button\"\n type=\"button\"\n :aria-label=\"openLabel\"\n @click=\"handleImageAction('open')\"\n >\n <img\n class=\"chat-media-block__image\"\n :alt=\"media.alt || generatedAltLabel\"\n :src=\"media.url\"\n >\n </button>\n <figcaption class=\"chat-media-block__footer\">\n <span class=\"chat-media-block__title\">{{ media.title || generatedLabel }}</span>\n <span class=\"chat-media-block__actions\">\n <ChatIconButton :label=\"fullscreenLabel\" @click=\"handleImageAction('fullscreen')\">\n <Maximize2 />\n </ChatIconButton>\n <ChatCopyButton\n :action=\"copyImage\"\n :copied-label=\"copiedLabel\"\n :label=\"copyLabel\"\n />\n <ChatIconButton\n :download=\"downloadName\"\n :href=\"media.url\"\n :label=\"downloadLabel\"\n @click.stop\n >\n <Download />\n </ChatIconButton>\n <ChatIconButton v-if=\"media.prompt\" :label=\"promptLabel\" @click=\"toggleDetails\">\n <Info />\n </ChatIconButton>\n </span>\n </figcaption>\n <ChatFoldTransition v-if=\"media.prompt\" :open=\"detailsOpen\">\n <div class=\"chat-media-block__details\">\n <div class=\"chat-media-block__details-title\">{{ promptLabel }}</div>\n <p class=\"chat-media-block__prompt\">{{ media.prompt }}</p>\n </div>\n </ChatFoldTransition>\n <ChatImageLightbox\n :alt=\"media.alt || generatedAltLabel\"\n :label=\"media.title || generatedLabel\"\n :open=\"fullscreenOpen\"\n :src=\"media.url\"\n :theme-source=\"rootElement\"\n @close=\"closeFullscreen\"\n />\n </figure>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { Download, Info, Maximize2 } from '../icons/app-icons'\nimport ChatCopyButton from './ChatCopyButton.vue'\nimport ChatFoldTransition from './ChatFoldTransition.vue'\nimport ChatImageLightbox from './ChatImageLightbox.vue'\nimport ChatIconButton from './ChatIconButton.vue'\nimport type { CodexMessageImageOpenHandler, CodexMessageImageOpenIntent } from './message-image'\nimport type { MessageMedia } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n media: MessageMedia\n openImage?: CodexMessageImageOpenHandler\n}>()\n// Stryker restore all\n\nconst downloadLabel = 'Download media'\nconst copyLabel = 'Copy image'\nconst copiedLabel = 'Image copied'\nconst fullscreenLabel = 'Open fullscreen'\nconst generatedAltLabel = 'Generated media'\nconst generatedLabel = 'Generated media'\nconst promptLabel = 'Prompt'\nconst openLabel = computed(() => `Open ${props.media.title || props.media.alt || generatedLabel}`)\nconst detailsOpen = ref(false)\nconst fullscreenOpen = ref(false)\nconst rootElement = ref<HTMLElement | null>(null)\nconst downloadName = computed(() => mediaDownloadName(props.media))\n\nasync function handleImageAction(intent: CodexMessageImageOpenIntent) {\n const image = {\n alt: props.media.alt || generatedAltLabel,\n kind: 'media',\n mimeType: props.media.mimeType,\n name: props.media.title,\n src: props.media.url,\n title: props.media.title || generatedLabel,\n } as const\n if (await props.openImage?.(image, { intent }) === true) return\n fullscreenOpen.value = true\n}\n\nfunction closeFullscreen() {\n fullscreenOpen.value = false\n}\n\nasync function copyImage() {\n const blob = await fetch(props.media.url).then((response) => response.blob())\n const mimeType = blob.type || props.media.mimeType || 'image/png'\n await navigator.clipboard.write([\n new ClipboardItem({ [mimeType]: blob }),\n ])\n}\n\nfunction toggleDetails() {\n detailsOpen.value = !detailsOpen.value\n}\n\nfunction mediaDownloadName(media: MessageMedia): string {\n const baseName = (media.title?.trim() || media.alt?.trim() || 'generated-image')\n .replace(/[\\\\/:*?\"<>|]+/g, '-')\n if (/\\.[a-z\\d]{2,5}$/i.test(baseName)) return baseName\n const extension = {\n 'image/avif': 'avif',\n 'image/gif': 'gif',\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/webp': 'webp',\n }[media.mimeType ?? '']\n return extension ? `${baseName}.${extension}` : baseName\n}\n\n</script>\n\n<style scoped>\n.chat-media-block {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n max-width: 60%;\n margin: var(--space-3) var(--space-6);\n}\n\n.chat-media-block__image-button {\n display: block;\n width: 100%;\n padding: 0;\n overflow: hidden;\n border: none;\n border-radius: var(--radius-lg);\n appearance: none;\n background: var(--color-surface-low);\n cursor: pointer;\n}\n\n.chat-media-block__image {\n display: block;\n width: 100%;\n height: auto;\n}\n\n.chat-media-block__footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n}\n\n.chat-media-block__title {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-media-block__actions {\n display: inline-flex;\n align-items: center;\n gap: 0;\n}\n\n.chat-media-block__details {\n color: var(--color-text-muted);\n}\n\n.chat-media-block__details-title {\n margin-bottom: var(--space-2);\n color: var(--color-text);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-semibold);\n line-height: var(--line-height-16);\n}\n\n.chat-media-block__prompt {\n margin: 0;\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n white-space: pre-wrap;\n}\n\n</style>\n","<template>\n <div ref=\"rootElement\" class=\"codex-chat-theme chat-mermaid-block\">\n <div class=\"chat-mermaid-block__actions\">\n <ChatIconButton bordered :label=\"modeToggleLabel\" @click=\"toggleMode\">\n <EyeIcon v-if=\"showingCode\" />\n <CodeIcon v-else />\n </ChatIconButton>\n <ChatIconButton bordered :label=\"fullscreenLabel\" @click=\"openFullscreen\">\n <Maximize2 />\n </ChatIconButton>\n </div>\n <pre v-if=\"showingCode\" class=\"chat-mermaid-block__code\"><code>{{ props.code }}</code></pre>\n <div\n v-else-if=\"rendered.svg\"\n class=\"chat-mermaid-block__diagram\"\n v-html=\"rendered.svg\"\n />\n <pre v-else class=\"chat-mermaid-block__error\"><code>{{ rendered.error }}</code></pre>\n <Teleport to=\"body\">\n <div\n v-if=\"fullscreenOpen\"\n class=\"codex-chat-theme chat-mermaid-block__fullscreen\"\n :data-codex-theme=\"portalTheme.mode\"\n :style=\"portalTheme.style\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"fullscreenLabel\"\n @click.self=\"closeFullscreen\"\n >\n <div class=\"chat-mermaid-block__fullscreen-panel\">\n <div class=\"chat-mermaid-block__actions chat-mermaid-block__actions--fullscreen\">\n <ChatIconButton bordered :label=\"modeToggleLabel\" @click=\"toggleMode\">\n <EyeIcon v-if=\"showingCode\" />\n <CodeIcon v-else />\n </ChatIconButton>\n <ChatIconButton bordered :label=\"closeFullscreenLabel\" @click=\"closeFullscreen\">\n <X />\n </ChatIconButton>\n </div>\n <pre v-if=\"showingCode\" class=\"chat-mermaid-block__code chat-mermaid-block__code--fullscreen\"><code>{{ props.code }}</code></pre>\n <div\n v-else-if=\"rendered.svg\"\n class=\"chat-mermaid-block__diagram chat-mermaid-block__diagram--fullscreen\"\n v-html=\"rendered.svg\"\n />\n <pre v-else class=\"chat-mermaid-block__error\"><code>{{ rendered.error }}</code></pre>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { renderMermaidSVG } from 'beautiful-mermaid'\nimport { CodeIcon, EyeIcon, Maximize2, X } from '../icons/app-icons'\nimport ChatIconButton from './ChatIconButton.vue'\nimport { captureCodexPortalTheme, type CodexPortalTheme } from './portal-theme'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n code: string\n}>()\n// Stryker restore all\n\nconst closeFullscreenLabel = 'Close fullscreen'\nconst fullscreenLabel = 'Open fullscreen'\nconst renderLabel = 'Render diagram'\nconst showCodeLabel = 'Show source'\nconst fullscreenOpen = ref(false)\nconst showingCode = ref(false)\nconst rootElement = ref<HTMLElement | null>(null)\nconst portalTheme = ref<CodexPortalTheme>({ mode: 'light', style: {} })\nconst stylesheetImportPattern = /@import\\s+url\\([^)]*\\);\\s*/g\nconst rawLabelAttributePattern = /\\sdata-label=\"[^\"]*\"/g\n\nconst modeToggleLabel = computed(() => showingCode.value ? renderLabel : showCodeLabel)\nconst rendered = computed(() => {\n try {\n return {\n error: '',\n svg: renderMermaidSVG(props.code, {\n accent: 'var(--color-primary)',\n bg: 'var(--color-surface-lowest)',\n border: 'var(--color-border)',\n fg: 'var(--color-text)',\n line: 'var(--color-border-strong)',\n muted: 'var(--color-text-muted)',\n surface: 'var(--color-surface-low)',\n transparent: true,\n }).replace(stylesheetImportPattern, '').replace(rawLabelAttributePattern, ''),\n }\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error),\n svg: '',\n }\n }\n})\n\nfunction toggleMode() {\n showingCode.value = !showingCode.value\n}\n\nfunction openFullscreen() {\n portalTheme.value = captureCodexPortalTheme(rootElement.value)\n fullscreenOpen.value = true\n}\n\nfunction closeFullscreen() {\n fullscreenOpen.value = false\n}\n\nfunction handleFullscreenKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n closeFullscreen()\n }\n}\n\nwatch(fullscreenOpen, (open) => {\n if (open) {\n window.addEventListener('keydown', handleFullscreenKeydown)\n } else {\n window.removeEventListener('keydown', handleFullscreenKeydown)\n }\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', handleFullscreenKeydown)\n})\n</script>\n\n<style scoped>\n.chat-mermaid-block {\n position: relative;\n max-width: 100%;\n overflow: auto;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: var(--space-16) var(--space-8) var(--space-8);\n background: var(--color-surface-lowest);\n}\n\n.chat-mermaid-block__actions {\n position: absolute;\n top: var(--space-4);\n right: var(--space-4);\n z-index: 1;\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-mermaid-block__actions--fullscreen {\n top: var(--space-6);\n right: var(--space-6);\n}\n\n.chat-mermaid-block__diagram {\n min-width: max-content;\n}\n\n.chat-mermaid-block__diagram :deep(svg) {\n display: block;\n max-width: 100%;\n height: auto;\n}\n\n.chat-mermaid-block__diagram :deep(text) {\n font-family: var(--font-family-base);\n}\n\n.chat-mermaid-block__code {\n margin: 0;\n overflow: auto;\n color: var(--color-text);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n white-space: pre;\n}\n\n.chat-mermaid-block__code--fullscreen {\n flex: 1;\n min-height: 0;\n}\n\n.chat-mermaid-block__error {\n margin: 0;\n color: var(--color-error);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n white-space: pre-wrap;\n}\n\n.chat-mermaid-block__fullscreen {\n position: fixed;\n inset: 0;\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--space-12);\n background: var(--color-overlay);\n}\n\n.chat-mermaid-block__fullscreen-panel {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n overflow: auto;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: var(--space-16) var(--space-12) var(--space-12);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-mermaid-block__diagram--fullscreen {\n flex: 1;\n}\n</style>\n","<template>\n <div ref=\"rootElement\" class=\"codex-chat-theme chat-mermaid-block\">\n <div class=\"chat-mermaid-block__actions\">\n <ChatIconButton bordered :label=\"modeToggleLabel\" @click=\"toggleMode\">\n <EyeIcon v-if=\"showingCode\" />\n <CodeIcon v-else />\n </ChatIconButton>\n <ChatIconButton bordered :label=\"fullscreenLabel\" @click=\"openFullscreen\">\n <Maximize2 />\n </ChatIconButton>\n </div>\n <pre v-if=\"showingCode\" class=\"chat-mermaid-block__code\"><code>{{ props.code }}</code></pre>\n <div\n v-else-if=\"rendered.svg\"\n class=\"chat-mermaid-block__diagram\"\n v-html=\"rendered.svg\"\n />\n <pre v-else class=\"chat-mermaid-block__error\"><code>{{ rendered.error }}</code></pre>\n <Teleport to=\"body\">\n <div\n v-if=\"fullscreenOpen\"\n class=\"codex-chat-theme chat-mermaid-block__fullscreen\"\n :data-codex-theme=\"portalTheme.mode\"\n :style=\"portalTheme.style\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"fullscreenLabel\"\n @click.self=\"closeFullscreen\"\n >\n <div class=\"chat-mermaid-block__fullscreen-panel\">\n <div class=\"chat-mermaid-block__actions chat-mermaid-block__actions--fullscreen\">\n <ChatIconButton bordered :label=\"modeToggleLabel\" @click=\"toggleMode\">\n <EyeIcon v-if=\"showingCode\" />\n <CodeIcon v-else />\n </ChatIconButton>\n <ChatIconButton bordered :label=\"closeFullscreenLabel\" @click=\"closeFullscreen\">\n <X />\n </ChatIconButton>\n </div>\n <pre v-if=\"showingCode\" class=\"chat-mermaid-block__code chat-mermaid-block__code--fullscreen\"><code>{{ props.code }}</code></pre>\n <div\n v-else-if=\"rendered.svg\"\n class=\"chat-mermaid-block__diagram chat-mermaid-block__diagram--fullscreen\"\n v-html=\"rendered.svg\"\n />\n <pre v-else class=\"chat-mermaid-block__error\"><code>{{ rendered.error }}</code></pre>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { renderMermaidSVG } from 'beautiful-mermaid'\nimport { CodeIcon, EyeIcon, Maximize2, X } from '../icons/app-icons'\nimport ChatIconButton from './ChatIconButton.vue'\nimport { captureCodexPortalTheme, type CodexPortalTheme } from './portal-theme'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n code: string\n}>()\n// Stryker restore all\n\nconst closeFullscreenLabel = 'Close fullscreen'\nconst fullscreenLabel = 'Open fullscreen'\nconst renderLabel = 'Render diagram'\nconst showCodeLabel = 'Show source'\nconst fullscreenOpen = ref(false)\nconst showingCode = ref(false)\nconst rootElement = ref<HTMLElement | null>(null)\nconst portalTheme = ref<CodexPortalTheme>({ mode: 'light', style: {} })\nconst stylesheetImportPattern = /@import\\s+url\\([^)]*\\);\\s*/g\nconst rawLabelAttributePattern = /\\sdata-label=\"[^\"]*\"/g\n\nconst modeToggleLabel = computed(() => showingCode.value ? renderLabel : showCodeLabel)\nconst rendered = computed(() => {\n try {\n return {\n error: '',\n svg: renderMermaidSVG(props.code, {\n accent: 'var(--color-primary)',\n bg: 'var(--color-surface-lowest)',\n border: 'var(--color-border)',\n fg: 'var(--color-text)',\n line: 'var(--color-border-strong)',\n muted: 'var(--color-text-muted)',\n surface: 'var(--color-surface-low)',\n transparent: true,\n }).replace(stylesheetImportPattern, '').replace(rawLabelAttributePattern, ''),\n }\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error),\n svg: '',\n }\n }\n})\n\nfunction toggleMode() {\n showingCode.value = !showingCode.value\n}\n\nfunction openFullscreen() {\n portalTheme.value = captureCodexPortalTheme(rootElement.value)\n fullscreenOpen.value = true\n}\n\nfunction closeFullscreen() {\n fullscreenOpen.value = false\n}\n\nfunction handleFullscreenKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n closeFullscreen()\n }\n}\n\nwatch(fullscreenOpen, (open) => {\n if (open) {\n window.addEventListener('keydown', handleFullscreenKeydown)\n } else {\n window.removeEventListener('keydown', handleFullscreenKeydown)\n }\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', handleFullscreenKeydown)\n})\n</script>\n\n<style scoped>\n.chat-mermaid-block {\n position: relative;\n max-width: 100%;\n overflow: auto;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: var(--space-16) var(--space-8) var(--space-8);\n background: var(--color-surface-lowest);\n}\n\n.chat-mermaid-block__actions {\n position: absolute;\n top: var(--space-4);\n right: var(--space-4);\n z-index: 1;\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-mermaid-block__actions--fullscreen {\n top: var(--space-6);\n right: var(--space-6);\n}\n\n.chat-mermaid-block__diagram {\n min-width: max-content;\n}\n\n.chat-mermaid-block__diagram :deep(svg) {\n display: block;\n max-width: 100%;\n height: auto;\n}\n\n.chat-mermaid-block__diagram :deep(text) {\n font-family: var(--font-family-base);\n}\n\n.chat-mermaid-block__code {\n margin: 0;\n overflow: auto;\n color: var(--color-text);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n white-space: pre;\n}\n\n.chat-mermaid-block__code--fullscreen {\n flex: 1;\n min-height: 0;\n}\n\n.chat-mermaid-block__error {\n margin: 0;\n color: var(--color-error);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-13);\n line-height: var(--line-height-20);\n white-space: pre-wrap;\n}\n\n.chat-mermaid-block__fullscreen {\n position: fixed;\n inset: 0;\n z-index: 1000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--space-12);\n background: var(--color-overlay);\n}\n\n.chat-mermaid-block__fullscreen-panel {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n overflow: auto;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: var(--space-16) var(--space-12) var(--space-12);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-mermaid-block__diagram--fullscreen {\n flex: 1;\n}\n</style>\n","import {\n inject,\n provide,\n type Component,\n type InjectionKey,\n} from 'vue';\nimport type { MessageToolCall, ToolStatusDescriptor } from './types';\n\nexport type CodexToolPresentationContext = {\n descriptor?: ToolStatusDescriptor;\n kind?: string;\n metadata?: Readonly<Record<string, unknown>>;\n toolCall: MessageToolCall;\n};\n\nexport type CodexToolPresentation = {\n /** Replaces the SDK icon. Use null to render no icon. */\n icon?: Component | null;\n /** Replaces the SDK title while leaving the rest of the tool row intact. */\n title?: string;\n};\n\nexport type CodexToolPresentationResolver = (\n context: CodexToolPresentationContext,\n) => CodexToolPresentation | undefined;\n\nconst defaultToolPresentationResolver: CodexToolPresentationResolver = () => undefined;\nconst toolPresentationKey: InjectionKey<CodexToolPresentationResolver> = Symbol(\n 'codex-app-sdk-tool-presentation',\n);\n\n/** Configures tool icons and titles for the current Vue component tree. */\nexport function provideCodexToolPresentation(resolver: CodexToolPresentationResolver): void {\n provide(toolPresentationKey, resolver);\n}\n\n/** Reads the nearest tool-presentation resolver, falling back to SDK presentation. */\nexport function useCodexToolPresentation(): CodexToolPresentationResolver {\n return inject(toolPresentationKey, defaultToolPresentationResolver);\n}\n","import {\n computed,\n inject,\n provide,\n toValue,\n type ComputedRef,\n type InjectionKey,\n type MaybeRefOrGetter,\n} from 'vue';\n\nconst toolCallDetailsKey: InjectionKey<MaybeRefOrGetter<boolean>> = Symbol(\n 'codex-app-sdk-tool-call-details',\n);\n\n/** Enables access to raw tool-call input and output for the current Vue subtree. */\nexport function provideCodexToolCallDetails(enabled: MaybeRefOrGetter<boolean>): void {\n provide(toolCallDetailsKey, enabled);\n}\n\n/** Reads the subtree-level raw tool-call detail policy. The secure default is disabled. */\nexport function useCodexToolCallDetails(): ComputedRef<boolean> {\n const enabled = inject(toolCallDetailsKey, false);\n return computed(() => Boolean(toValue(enabled)));\n}\n","<template>\n <ChatToolConfirmation\n v-if=\"isToolConfirmation\"\n class=\"codex-chat-theme\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :tool-call=\"toolCall\"\n @client-response=\"emit('client-response', $event)\"\n />\n <ChatToolUserInputRequest\n v-else-if=\"isUserInputRequest\"\n class=\"codex-chat-theme\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :tool-call=\"toolCall\"\n @client-response=\"emit('client-response', $event)\"\n />\n <section v-else class=\"codex-chat-theme chat-tool-call\" :class=\"{ 'chat-tool-call--open': isOpen, [`chat-tool-call--${toolCall.state}`]: true }\">\n <div v-if=\"summaryOnly\" class=\"chat-tool-call__summary\">\n <ChatToolCallTitle\n :line-diff=\"lineDiff\"\n :running=\"isRunning\"\n :title=\"titleParts.title\"\n :title-prefix=\"titleParts.prefix\"\n :title-target=\"titleParts.target\"\n :title-target-parts=\"titleTargetParts\"\n :tool-call=\"toolCall\"\n :tool-presentation=\"toolPresentation\"\n @open-link=\"emit('open-link', $event)\"\n />\n <component\n :is=\"isOpen ? ChevronUp : ChevronDown\"\n v-if=\"expandable !== false\"\n class=\"chat-tool-group__chevron\"\n :size=\"15\"\n />\n </div>\n\n <div\n v-else-if=\"!detailsAvailable\"\n class=\"chat-tool-call__header chat-tool-call__header--static\"\n >\n <ChatToolCallTitle\n :line-diff=\"lineDiff\"\n :running=\"isRunning\"\n :title=\"titleParts.title\"\n :title-prefix=\"titleParts.prefix\"\n :title-target=\"titleParts.target\"\n :title-target-parts=\"titleTargetParts\"\n :tool-call=\"toolCall\"\n :tool-presentation=\"toolPresentation\"\n @open-link=\"emit('open-link', $event)\"\n />\n </div>\n\n <button v-else-if=\"!headerless\" class=\"chat-tool-call__header\" type=\"button\" @click=\"toggleOpen\">\n <ChatToolCallTitle\n :line-diff=\"lineDiff\"\n :running=\"isRunning\"\n :title=\"titleParts.title\"\n :title-prefix=\"titleParts.prefix\"\n :title-target=\"titleParts.target\"\n :title-target-parts=\"titleTargetParts\"\n :tool-call=\"toolCall\"\n :tool-presentation=\"toolPresentation\"\n @open-link=\"emit('open-link', $event)\"\n />\n <component :is=\"isOpen ? ChevronUp : ChevronDown\" class=\"chat-tool-call__chevron\" :size=\"15\" />\n </button>\n\n <div v-if=\"headerless && toolDetailsEnabled\" class=\"chat-tool-call__body\">\n <div v-if=\"hasParams\" class=\"chat-tool-call__section\">\n <div class=\"chat-tool-call__section-title\">Input</div>\n <pre class=\"chat-tool-call__json\">{{ formatValue(toolCallArgs) }}</pre>\n </div>\n\n <div v-if=\"hasResult\" class=\"chat-tool-call__section\">\n <div class=\"chat-tool-call__section-title\">Result</div>\n <pre class=\"chat-tool-call__json\">{{ formatValue(toolCall.result) }}</pre>\n </div>\n </div>\n\n <ChatFoldTransition v-else-if=\"detailsAvailable\" :open=\"isOpen\">\n <div class=\"chat-tool-call__body\">\n <div v-if=\"hasParams\" class=\"chat-tool-call__section\">\n <div class=\"chat-tool-call__section-title\">Input</div>\n <pre class=\"chat-tool-call__json\">{{ formatValue(toolCallArgs) }}</pre>\n </div>\n\n <div v-if=\"hasResult\" class=\"chat-tool-call__section\">\n <div class=\"chat-tool-call__section-title\">Result</div>\n <pre class=\"chat-tool-call__json\">{{ formatValue(toolCall.result) }}</pre>\n </div>\n </div>\n </ChatFoldTransition>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { useCodexChatTranslate } from './chat-i18n'\nimport { useCodexToolPresentation } from './tool-presentation'\nimport { ChevronDown, ChevronUp } from '../icons/app-icons'\nimport type { ClientRequestResponse, CodexConversationLink } from './contracts'\nimport ChatFoldTransition from './ChatFoldTransition.vue'\nimport ChatToolConfirmation from './ChatToolConfirmation.vue'\nimport ChatToolCallTitle from './ChatToolCallTitle.vue'\nimport ChatToolUserInputRequest from './ChatToolUserInputRequest.vue'\nimport { getToolDisplayTargetParts, getToolDisplayTitleParts, getToolLineDiff, parseToolStatusDescriptor } from './tool-status'\nimport { getMessageToolCallArgs, type MessageToolCall } from './types'\nimport { useCodexToolCallDetails } from './tool-call-details'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n answeredClientRequestIds?: ReadonlySet<string>\n expandable?: boolean\n headerless?: boolean\n showToolDetails?: boolean\n summaryOnly?: boolean\n toolCall: MessageToolCall\n}>(), {\n showToolDetails: undefined,\n})\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'open-link': [link: CodexConversationLink]\n}>()\n// Stryker restore all\n\nconst t = useCodexChatTranslate()\nconst resolveToolPresentation = useCodexToolPresentation()\nconst isOpen = ref(false)\nconst providedToolDetails = useCodexToolCallDetails()\n\nconst toolCallArgs = computed(() => getMessageToolCallArgs(props.toolCall))\nconst isRunning = computed(() => !props.toolCall.done && props.toolCall.state !== 'completed')\nconst statusDescriptor = computed(() => parseToolStatusDescriptor(props.toolCall.status))\nconst toolPresentation = computed(() => resolveToolPresentation({\n descriptor: statusDescriptor.value,\n ...(props.toolCall.kind ? { kind: props.toolCall.kind } : {}),\n ...(props.toolCall.metadata ? { metadata: props.toolCall.metadata } : {}),\n toolCall: props.toolCall,\n}))\nconst confirmationParams = computed(() => (\n statusDescriptor.value?.params && typeof statusDescriptor.value.params === 'object'\n ? statusDescriptor.value.params\n : {}\n))\nconst isToolConfirmation = computed(() => (\n (statusDescriptor.value?.source === 'mcp' || statusDescriptor.value?.source === 'home') &&\n typeof confirmationParams.value.requestId === 'string' &&\n props.toolCall.state === 'running'\n))\nconst isUserInputRequest = computed(() => (\n statusDescriptor.value?.source === 'codex' &&\n statusDescriptor.value.action === 'ask_user_question' &&\n typeof confirmationParams.value.requestId === 'string' &&\n (props.toolCall.state === 'running' || (\n typeof props.toolCall.result === 'object' && props.toolCall.result !== null\n && 'answers' in props.toolCall.result\n ))\n))\nconst titleParts = computed(() => {\n if (toolPresentation.value?.title !== undefined) {\n return { title: toolPresentation.value.title }\n }\n const descriptor = statusDescriptor.value\n if (props.toolCall.status && !['running', 'completed', 'failed'].includes(props.toolCall.status)) {\n return descriptor ? getToolDisplayTitleParts(props.toolCall, descriptor, t) : { title: props.toolCall.status }\n }\n return getToolDisplayTitleParts(props.toolCall, descriptor, t)\n})\nconst titleTargetParts = computed(() => getToolDisplayTargetParts(\n props.toolCall,\n statusDescriptor.value,\n titleParts.value.target,\n))\nconst lineDiff = computed(() => getToolLineDiff(statusDescriptor.value))\nconst hasParams = computed(() => toolCallArgs.value !== undefined)\nconst hasResult = computed(() => props.toolCall.result !== undefined && props.toolCall.result !== null)\nconst toolDetailsEnabled = computed(() => props.showToolDetails ?? providedToolDetails.value)\nconst detailsAvailable = computed(() => toolDetailsEnabled.value && (hasParams.value || hasResult.value))\n\nfunction toggleOpen() {\n isOpen.value = !isOpen.value\n}\n\nfunction formatValue(value: unknown) {\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n}\n</script>\n\n<style scoped>\n.chat-tool-call {\n width: 100%;\n min-width: 0;\n overflow: hidden;\n color: var(--color-text-muted);\n}\n\n.chat-tool-call--canceled,\n.chat-tool-call--error {\n opacity: 0.72;\n}\n\n.chat-tool-call__header,\n.chat-tool-call__summary {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n color: inherit;\n font: inherit;\n text-align: left;\n}\n\n.chat-tool-call__header {\n padding: 0;\n border: 0;\n border-radius: var(--radius-sm);\n background: transparent;\n cursor: pointer;\n}\n\n.chat-tool-call__header--static {\n cursor: default;\n}\n\n.chat-tool-call__header:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: var(--space-1);\n}\n\n.chat-tool-call__chevron,\n.chat-tool-group__chevron {\n flex: 0 0 auto;\n width: 15px;\n height: 15px;\n color: var(--color-text-muted);\n}\n\n.chat-tool-call__body {\n display: flex;\n flex-direction: column;\n gap: var(--space-6);\n padding: var(--space-4) 0 var(--space-4) 0;\n}\n\n.chat-tool-call__section {\n display: flex;\n flex-direction: column;\n gap: var(--space-3);\n}\n\n.chat-tool-call__section-title {\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-semibold);\n color: var(--color-text-muted);\n}\n\n.chat-tool-call__json {\n max-height: 240px;\n overflow: auto;\n margin: 0;\n padding: var(--space-4);\n border-radius: var(--radius-md);\n background: var(--color-surface-low);\n color: var(--color-text);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-12);\n line-height: var(--line-height-20);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n</style>\n","<template>\n <ChatToolConfirmation\n v-if=\"isToolConfirmation\"\n class=\"codex-chat-theme\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :tool-call=\"toolCall\"\n @client-response=\"emit('client-response', $event)\"\n />\n <ChatToolUserInputRequest\n v-else-if=\"isUserInputRequest\"\n class=\"codex-chat-theme\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :tool-call=\"toolCall\"\n @client-response=\"emit('client-response', $event)\"\n />\n <section v-else class=\"codex-chat-theme chat-tool-call\" :class=\"{ 'chat-tool-call--open': isOpen, [`chat-tool-call--${toolCall.state}`]: true }\">\n <div v-if=\"summaryOnly\" class=\"chat-tool-call__summary\">\n <ChatToolCallTitle\n :line-diff=\"lineDiff\"\n :running=\"isRunning\"\n :title=\"titleParts.title\"\n :title-prefix=\"titleParts.prefix\"\n :title-target=\"titleParts.target\"\n :title-target-parts=\"titleTargetParts\"\n :tool-call=\"toolCall\"\n :tool-presentation=\"toolPresentation\"\n @open-link=\"emit('open-link', $event)\"\n />\n <component\n :is=\"isOpen ? ChevronUp : ChevronDown\"\n v-if=\"expandable !== false\"\n class=\"chat-tool-group__chevron\"\n :size=\"15\"\n />\n </div>\n\n <div\n v-else-if=\"!detailsAvailable\"\n class=\"chat-tool-call__header chat-tool-call__header--static\"\n >\n <ChatToolCallTitle\n :line-diff=\"lineDiff\"\n :running=\"isRunning\"\n :title=\"titleParts.title\"\n :title-prefix=\"titleParts.prefix\"\n :title-target=\"titleParts.target\"\n :title-target-parts=\"titleTargetParts\"\n :tool-call=\"toolCall\"\n :tool-presentation=\"toolPresentation\"\n @open-link=\"emit('open-link', $event)\"\n />\n </div>\n\n <button v-else-if=\"!headerless\" class=\"chat-tool-call__header\" type=\"button\" @click=\"toggleOpen\">\n <ChatToolCallTitle\n :line-diff=\"lineDiff\"\n :running=\"isRunning\"\n :title=\"titleParts.title\"\n :title-prefix=\"titleParts.prefix\"\n :title-target=\"titleParts.target\"\n :title-target-parts=\"titleTargetParts\"\n :tool-call=\"toolCall\"\n :tool-presentation=\"toolPresentation\"\n @open-link=\"emit('open-link', $event)\"\n />\n <component :is=\"isOpen ? ChevronUp : ChevronDown\" class=\"chat-tool-call__chevron\" :size=\"15\" />\n </button>\n\n <div v-if=\"headerless && toolDetailsEnabled\" class=\"chat-tool-call__body\">\n <div v-if=\"hasParams\" class=\"chat-tool-call__section\">\n <div class=\"chat-tool-call__section-title\">Input</div>\n <pre class=\"chat-tool-call__json\">{{ formatValue(toolCallArgs) }}</pre>\n </div>\n\n <div v-if=\"hasResult\" class=\"chat-tool-call__section\">\n <div class=\"chat-tool-call__section-title\">Result</div>\n <pre class=\"chat-tool-call__json\">{{ formatValue(toolCall.result) }}</pre>\n </div>\n </div>\n\n <ChatFoldTransition v-else-if=\"detailsAvailable\" :open=\"isOpen\">\n <div class=\"chat-tool-call__body\">\n <div v-if=\"hasParams\" class=\"chat-tool-call__section\">\n <div class=\"chat-tool-call__section-title\">Input</div>\n <pre class=\"chat-tool-call__json\">{{ formatValue(toolCallArgs) }}</pre>\n </div>\n\n <div v-if=\"hasResult\" class=\"chat-tool-call__section\">\n <div class=\"chat-tool-call__section-title\">Result</div>\n <pre class=\"chat-tool-call__json\">{{ formatValue(toolCall.result) }}</pre>\n </div>\n </div>\n </ChatFoldTransition>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { useCodexChatTranslate } from './chat-i18n'\nimport { useCodexToolPresentation } from './tool-presentation'\nimport { ChevronDown, ChevronUp } from '../icons/app-icons'\nimport type { ClientRequestResponse, CodexConversationLink } from './contracts'\nimport ChatFoldTransition from './ChatFoldTransition.vue'\nimport ChatToolConfirmation from './ChatToolConfirmation.vue'\nimport ChatToolCallTitle from './ChatToolCallTitle.vue'\nimport ChatToolUserInputRequest from './ChatToolUserInputRequest.vue'\nimport { getToolDisplayTargetParts, getToolDisplayTitleParts, getToolLineDiff, parseToolStatusDescriptor } from './tool-status'\nimport { getMessageToolCallArgs, type MessageToolCall } from './types'\nimport { useCodexToolCallDetails } from './tool-call-details'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n answeredClientRequestIds?: ReadonlySet<string>\n expandable?: boolean\n headerless?: boolean\n showToolDetails?: boolean\n summaryOnly?: boolean\n toolCall: MessageToolCall\n}>(), {\n showToolDetails: undefined,\n})\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'open-link': [link: CodexConversationLink]\n}>()\n// Stryker restore all\n\nconst t = useCodexChatTranslate()\nconst resolveToolPresentation = useCodexToolPresentation()\nconst isOpen = ref(false)\nconst providedToolDetails = useCodexToolCallDetails()\n\nconst toolCallArgs = computed(() => getMessageToolCallArgs(props.toolCall))\nconst isRunning = computed(() => !props.toolCall.done && props.toolCall.state !== 'completed')\nconst statusDescriptor = computed(() => parseToolStatusDescriptor(props.toolCall.status))\nconst toolPresentation = computed(() => resolveToolPresentation({\n descriptor: statusDescriptor.value,\n ...(props.toolCall.kind ? { kind: props.toolCall.kind } : {}),\n ...(props.toolCall.metadata ? { metadata: props.toolCall.metadata } : {}),\n toolCall: props.toolCall,\n}))\nconst confirmationParams = computed(() => (\n statusDescriptor.value?.params && typeof statusDescriptor.value.params === 'object'\n ? statusDescriptor.value.params\n : {}\n))\nconst isToolConfirmation = computed(() => (\n (statusDescriptor.value?.source === 'mcp' || statusDescriptor.value?.source === 'home') &&\n typeof confirmationParams.value.requestId === 'string' &&\n props.toolCall.state === 'running'\n))\nconst isUserInputRequest = computed(() => (\n statusDescriptor.value?.source === 'codex' &&\n statusDescriptor.value.action === 'ask_user_question' &&\n typeof confirmationParams.value.requestId === 'string' &&\n (props.toolCall.state === 'running' || (\n typeof props.toolCall.result === 'object' && props.toolCall.result !== null\n && 'answers' in props.toolCall.result\n ))\n))\nconst titleParts = computed(() => {\n if (toolPresentation.value?.title !== undefined) {\n return { title: toolPresentation.value.title }\n }\n const descriptor = statusDescriptor.value\n if (props.toolCall.status && !['running', 'completed', 'failed'].includes(props.toolCall.status)) {\n return descriptor ? getToolDisplayTitleParts(props.toolCall, descriptor, t) : { title: props.toolCall.status }\n }\n return getToolDisplayTitleParts(props.toolCall, descriptor, t)\n})\nconst titleTargetParts = computed(() => getToolDisplayTargetParts(\n props.toolCall,\n statusDescriptor.value,\n titleParts.value.target,\n))\nconst lineDiff = computed(() => getToolLineDiff(statusDescriptor.value))\nconst hasParams = computed(() => toolCallArgs.value !== undefined)\nconst hasResult = computed(() => props.toolCall.result !== undefined && props.toolCall.result !== null)\nconst toolDetailsEnabled = computed(() => props.showToolDetails ?? providedToolDetails.value)\nconst detailsAvailable = computed(() => toolDetailsEnabled.value && (hasParams.value || hasResult.value))\n\nfunction toggleOpen() {\n isOpen.value = !isOpen.value\n}\n\nfunction formatValue(value: unknown) {\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n}\n</script>\n\n<style scoped>\n.chat-tool-call {\n width: 100%;\n min-width: 0;\n overflow: hidden;\n color: var(--color-text-muted);\n}\n\n.chat-tool-call--canceled,\n.chat-tool-call--error {\n opacity: 0.72;\n}\n\n.chat-tool-call__header,\n.chat-tool-call__summary {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n color: inherit;\n font: inherit;\n text-align: left;\n}\n\n.chat-tool-call__header {\n padding: 0;\n border: 0;\n border-radius: var(--radius-sm);\n background: transparent;\n cursor: pointer;\n}\n\n.chat-tool-call__header--static {\n cursor: default;\n}\n\n.chat-tool-call__header:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: var(--space-1);\n}\n\n.chat-tool-call__chevron,\n.chat-tool-group__chevron {\n flex: 0 0 auto;\n width: 15px;\n height: 15px;\n color: var(--color-text-muted);\n}\n\n.chat-tool-call__body {\n display: flex;\n flex-direction: column;\n gap: var(--space-6);\n padding: var(--space-4) 0 var(--space-4) 0;\n}\n\n.chat-tool-call__section {\n display: flex;\n flex-direction: column;\n gap: var(--space-3);\n}\n\n.chat-tool-call__section-title {\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-semibold);\n color: var(--color-text-muted);\n}\n\n.chat-tool-call__json {\n max-height: 240px;\n overflow: auto;\n margin: 0;\n padding: var(--space-4);\n border-radius: var(--radius-md);\n background: var(--color-surface-low);\n color: var(--color-text);\n font-family: var(--font-family-mono);\n font-size: var(--font-size-12);\n line-height: var(--line-height-20);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n</style>\n","<template>\n <ChatToolCall\n v-if=\"singleConfirmationToolCall\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :tool-call=\"singleConfirmationToolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n <section v-else class=\"codex-chat-theme chat-tool-group\">\n <component\n v-if=\"props.toolCalls.length === 0 || headerToolCall || completedToolCalls.length > 0\"\n :is=\"canExpand ? 'button' : 'div'\"\n class=\"chat-tool-group__header\"\n :class=\"{ 'chat-tool-group__header--static': !canExpand }\"\n :type=\"canExpand ? 'button' : undefined\"\n @click=\"toggleExpanded\"\n >\n <ChatToolCall\n v-if=\"headerToolCall\"\n class=\"chat-tool-group__active\"\n summary-only\n :expandable=\"canExpand\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :show-tool-details=\"toolDetailsEnabled\"\n :tool-call=\"headerToolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n <template v-else>\n <span\n class=\"chat-tool-group__title\"\n :data-label=\"summary\"\n >\n {{ summary }}\n </span>\n <span v-if=\"lineDiff\" class=\"chat-tool-group__diff\" aria-label=\"Total line changes\">\n <ChatAnimatedDiffStat\n v-if=\"lineDiff.addedLines\"\n kind=\"added\"\n label=\"Total added lines\"\n :value=\"lineDiff.addedLines\"\n />\n <ChatAnimatedDiffStat\n v-if=\"lineDiff.removedLines\"\n kind=\"deleted\"\n label=\"Total removed lines\"\n :value=\"lineDiff.removedLines\"\n />\n </span>\n <component v-if=\"canExpand\" :is=\"expanded ? ChevronUp : ChevronDown\" class=\"chat-tool-group__chevron\" :size=\"15\" />\n </template>\n </component>\n\n <ChatFoldTransition :open=\"expanded\">\n <div class=\"chat-tool-group__body\">\n <ChatToolCall\n v-for=\"toolCall in completedToolCalls\"\n :key=\"toolCall.id\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :headerless=\"isSingleTool\"\n :show-tool-details=\"toolDetailsEnabled\"\n :tool-call=\"toolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n </div>\n </ChatFoldTransition>\n\n <TransitionGroup\n v-if=\"statusContainerVisible\"\n name=\"chat-tool-group-running\"\n tag=\"div\"\n class=\"chat-tool-group__running\"\n :class=\"{ 'chat-tool-group__running--after-completed': expanded }\"\n aria-live=\"polite\"\n @after-leave=\"hideEmptyStatusContainer\"\n >\n <div\n v-for=\"toolCall in statusToolCalls\"\n :key=\"toolCall.id\"\n class=\"chat-tool-group__running-item\"\n >\n <div class=\"chat-tool-group__running-item-content\">\n <ChatToolCall\n class=\"chat-tool-group__active\"\n :summary-only=\"!toolDetailsEnabled\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :show-tool-details=\"toolDetailsEnabled\"\n :tool-call=\"toolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n </div>\n </div>\n </TransitionGroup>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronUp } from '../icons/app-icons'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport type { ClientRequestResponse } from './contracts'\nimport type { CodexConversationLink } from './contracts'\nimport ChatAnimatedDiffStat from './ChatAnimatedDiffStat.vue'\nimport ChatFoldTransition from './ChatFoldTransition.vue'\nimport ChatToolCall from './ChatToolCall.vue'\nimport { getToolGroupLineDiff, parseToolStatusDescriptor } from './tool-status'\nimport type { MessageToolCall } from './types'\nimport { getMessageToolCallArgs } from './types'\nimport { useCodexToolCallDetails } from './tool-call-details'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n activityTitle?: string\n answeredClientRequestIds?: ReadonlySet<string>\n showToolDetails?: boolean\n toolCalls: MessageToolCall[]\n}>(), {\n showToolDetails: undefined,\n})\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'open-link': [link: CodexConversationLink]\n}>()\n// Stryker restore all\n\nconst expanded = ref(false)\nconst recentlyCompletedIds = ref<ReadonlySet<string>>(new Set())\nconst recentCompletionTimers = new Map<string, ReturnType<typeof setTimeout>>()\nconst recentCompletionRetentionMs = 3_000\nlet previousActiveIds = new Set(props.toolCalls.filter(isActiveToolCall).map((toolCall) => toolCall.id))\nconst providedToolDetails = useCodexToolCallDetails()\nconst toolDetailsEnabled = computed(() => props.showToolDetails ?? providedToolDetails.value)\n\nconst isSingleTool = computed(() => props.toolCalls.length === 1)\nconst singleConfirmationToolCall = computed(() => {\n if (!isSingleTool.value || !props.toolCalls[0] || !isConfirmationTool(props.toolCalls[0])) {\n return undefined\n }\n\n return props.toolCalls[0]\n})\nconst completedToolCalls = computed(() => props.toolCalls.filter((toolCall) => !isActiveToolCall(toolCall)))\nconst headerToolCall = computed(() => (\n !props.activityTitle && isSingleTool.value && completedToolCalls.value.length === 1\n ? props.toolCalls[0]\n : undefined\n))\nconst statusToolCalls = computed(() => props.toolCalls.filter((toolCall) => (\n isActiveToolCall(toolCall)\n || (\n !expanded.value\n && recentlyCompletedIds.value.has(toolCall.id)\n && headerToolCall.value?.id !== toolCall.id\n )\n)))\nconst statusContainerVisible = ref(statusToolCalls.value.length > 0)\nconst lineDiff = computed(() => getToolGroupLineDiff(props.toolCalls))\nconst canExpand = computed(() => (\n Boolean(props.activityTitle)\n || props.toolCalls.length > 1\n || (toolDetailsEnabled.value && props.toolCalls.some(hasToolDetails))\n))\nconst summary = computed(() => {\n if (completedToolCalls.value.length > 0) {\n const completed = `${formatActions(completedToolCalls.value.length)} done`\n return props.activityTitle ? `${props.activityTitle} · ${completed}` : completed\n }\n\n return props.activityTitle ?? 'No actions'\n})\n\nwatch(\n () => props.toolCalls.map((toolCall) => ({ id: toolCall.id, active: isActiveToolCall(toolCall) })),\n (toolStates) => {\n const currentIds = new Set(toolStates.map((toolCall) => toolCall.id))\n const currentActiveIds = new Set(\n toolStates.filter((toolCall) => toolCall.active).map((toolCall) => toolCall.id),\n )\n\n for (const id of previousActiveIds) {\n if (!currentActiveIds.has(id) && currentIds.has(id)) retainCompletedTool(id)\n }\n for (const id of currentActiveIds) clearRecentCompletion(id)\n for (const id of recentlyCompletedIds.value) {\n if (!currentIds.has(id)) clearRecentCompletion(id)\n }\n\n previousActiveIds = currentActiveIds\n },\n { flush: 'sync' },\n)\n\nwatch(\n [() => statusToolCalls.value.length, expanded, () => headerToolCall.value?.id],\n ([statusCount, isExpanded, headerId]) => {\n if (statusCount > 0) {\n statusContainerVisible.value = true\n } else if (isExpanded || headerId) {\n statusContainerVisible.value = false\n }\n },\n { flush: 'sync' },\n)\n\nonBeforeUnmount(() => {\n for (const timer of recentCompletionTimers.values()) clearTimeout(timer)\n recentCompletionTimers.clear()\n})\n\nfunction toggleExpanded() {\n if (!canExpand.value) return\n expanded.value = !expanded.value\n}\n\nfunction formatActions(count: number) {\n return `${count} ${count === 1 ? 'action' : 'actions'}`\n}\n\nfunction retainCompletedTool(id: string) {\n recentlyCompletedIds.value = new Set(recentlyCompletedIds.value).add(id)\n recentCompletionTimers.set(id, setTimeout(() => clearRecentCompletion(id), recentCompletionRetentionMs))\n}\n\nfunction clearRecentCompletion(id: string) {\n const timer = recentCompletionTimers.get(id)\n clearTimeout(timer)\n recentCompletionTimers.delete(id)\n if (!recentlyCompletedIds.value.has(id)) return\n const next = new Set(recentlyCompletedIds.value)\n next.delete(id)\n recentlyCompletedIds.value = next\n}\n\nfunction hideEmptyStatusContainer() {\n if (statusToolCalls.value.length === 0) statusContainerVisible.value = false\n}\n\nfunction isActiveToolCall(toolCall: MessageToolCall) {\n return !toolCall.done && toolCall.state !== 'completed'\n}\n\nfunction isConfirmationTool(toolCall: MessageToolCall) {\n const descriptor = parseToolStatusDescriptor(toolCall.status)\n return (\n (descriptor?.source === 'mcp' || descriptor?.source === 'home') &&\n typeof descriptor.params?.requestId === 'string' &&\n toolCall.state === 'running'\n )\n}\n\nfunction hasToolDetails(toolCall: MessageToolCall) {\n return getMessageToolCallArgs(toolCall) !== undefined\n || (toolCall.result !== undefined && toolCall.result !== null)\n}\n</script>\n\n<style scoped>\n.chat-tool-group {\n width: 100%;\n min-width: 0;\n padding: var(--space-1) 0;\n color: var(--color-text-muted);\n}\n\n.chat-tool-group__header {\n display: inline-flex;\n align-items: center;\n gap: var(--space-4);\n max-width: 100%;\n padding: 0;\n border: 0;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--color-text-muted);\n font: inherit;\n cursor: pointer;\n text-align: left;\n}\n\n.chat-tool-group__header--static {\n cursor: default;\n}\n\n.chat-tool-group__header:focus-visible {\n outline: none;\n}\n\n.chat-tool-group__icon,\n.chat-tool-group__chevron {\n flex: 0 0 auto;\n width: 15px;\n height: 15px;\n color: var(--color-text-muted);\n}\n\n.chat-tool-group__icon--running {\n animation: chat-tool-group-square-pulse 1.2s ease-in-out infinite;\n}\n\n.chat-tool-group__active {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.chat-tool-group__running {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n min-width: 0;\n padding-top: var(--space-2);\n}\n\n.chat-tool-group__running-item {\n height: var(--line-height-20);\n overflow: hidden;\n}\n\n.chat-tool-group__running-item-content {\n min-height: var(--line-height-20);\n min-width: 0;\n}\n\n.chat-tool-group-running-leave-active {\n transition:\n height 320ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 320ms ease;\n}\n\n.chat-tool-group-running-leave-active > .chat-tool-group__running-item-content {\n transition: transform 320ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.chat-tool-group-running-leave-to {\n height: 0;\n opacity: 0.3;\n}\n\n.chat-tool-group-running-leave-to > .chat-tool-group__running-item-content {\n transform: translateY(-100%);\n}\n\n.chat-tool-group__running--after-completed {\n padding-top: calc(var(--space-2) + (var(--space-1) * 2));\n}\n\n.chat-tool-group__title {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--font-size-15);\n line-height: var(--line-height-20);\n font-weight: var(--font-weight-light);\n}\n\n.chat-tool-group__diff {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-tool-group__body {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n min-width: 0;\n padding-top: var(--space-2);\n}\n\n.chat-tool-group__body .chat-tool-call:only-of-type:deep() .chat-tool-call__body {\n padding-top: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .chat-tool-group-running-leave-active,\n .chat-tool-group-running-leave-active > .chat-tool-group__running-item-content {\n transition: none;\n }\n}\n\n@keyframes chat-tool-group-square-pulse {\n 0%,\n 100% {\n opacity: 0.55;\n transform: scale(0.88);\n }\n\n 50% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n</style>\n","<template>\n <ChatToolCall\n v-if=\"singleConfirmationToolCall\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :tool-call=\"singleConfirmationToolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n <section v-else class=\"codex-chat-theme chat-tool-group\">\n <component\n v-if=\"props.toolCalls.length === 0 || headerToolCall || completedToolCalls.length > 0\"\n :is=\"canExpand ? 'button' : 'div'\"\n class=\"chat-tool-group__header\"\n :class=\"{ 'chat-tool-group__header--static': !canExpand }\"\n :type=\"canExpand ? 'button' : undefined\"\n @click=\"toggleExpanded\"\n >\n <ChatToolCall\n v-if=\"headerToolCall\"\n class=\"chat-tool-group__active\"\n summary-only\n :expandable=\"canExpand\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :show-tool-details=\"toolDetailsEnabled\"\n :tool-call=\"headerToolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n <template v-else>\n <span\n class=\"chat-tool-group__title\"\n :data-label=\"summary\"\n >\n {{ summary }}\n </span>\n <span v-if=\"lineDiff\" class=\"chat-tool-group__diff\" aria-label=\"Total line changes\">\n <ChatAnimatedDiffStat\n v-if=\"lineDiff.addedLines\"\n kind=\"added\"\n label=\"Total added lines\"\n :value=\"lineDiff.addedLines\"\n />\n <ChatAnimatedDiffStat\n v-if=\"lineDiff.removedLines\"\n kind=\"deleted\"\n label=\"Total removed lines\"\n :value=\"lineDiff.removedLines\"\n />\n </span>\n <component v-if=\"canExpand\" :is=\"expanded ? ChevronUp : ChevronDown\" class=\"chat-tool-group__chevron\" :size=\"15\" />\n </template>\n </component>\n\n <ChatFoldTransition :open=\"expanded\">\n <div class=\"chat-tool-group__body\">\n <ChatToolCall\n v-for=\"toolCall in completedToolCalls\"\n :key=\"toolCall.id\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :headerless=\"isSingleTool\"\n :show-tool-details=\"toolDetailsEnabled\"\n :tool-call=\"toolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n </div>\n </ChatFoldTransition>\n\n <TransitionGroup\n v-if=\"statusContainerVisible\"\n name=\"chat-tool-group-running\"\n tag=\"div\"\n class=\"chat-tool-group__running\"\n :class=\"{ 'chat-tool-group__running--after-completed': expanded }\"\n aria-live=\"polite\"\n @after-leave=\"hideEmptyStatusContainer\"\n >\n <div\n v-for=\"toolCall in statusToolCalls\"\n :key=\"toolCall.id\"\n class=\"chat-tool-group__running-item\"\n >\n <div class=\"chat-tool-group__running-item-content\">\n <ChatToolCall\n class=\"chat-tool-group__active\"\n :summary-only=\"!toolDetailsEnabled\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :show-tool-details=\"toolDetailsEnabled\"\n :tool-call=\"toolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n </div>\n </div>\n </TransitionGroup>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronUp } from '../icons/app-icons'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport type { ClientRequestResponse } from './contracts'\nimport type { CodexConversationLink } from './contracts'\nimport ChatAnimatedDiffStat from './ChatAnimatedDiffStat.vue'\nimport ChatFoldTransition from './ChatFoldTransition.vue'\nimport ChatToolCall from './ChatToolCall.vue'\nimport { getToolGroupLineDiff, parseToolStatusDescriptor } from './tool-status'\nimport type { MessageToolCall } from './types'\nimport { getMessageToolCallArgs } from './types'\nimport { useCodexToolCallDetails } from './tool-call-details'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n activityTitle?: string\n answeredClientRequestIds?: ReadonlySet<string>\n showToolDetails?: boolean\n toolCalls: MessageToolCall[]\n}>(), {\n showToolDetails: undefined,\n})\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'open-link': [link: CodexConversationLink]\n}>()\n// Stryker restore all\n\nconst expanded = ref(false)\nconst recentlyCompletedIds = ref<ReadonlySet<string>>(new Set())\nconst recentCompletionTimers = new Map<string, ReturnType<typeof setTimeout>>()\nconst recentCompletionRetentionMs = 3_000\nlet previousActiveIds = new Set(props.toolCalls.filter(isActiveToolCall).map((toolCall) => toolCall.id))\nconst providedToolDetails = useCodexToolCallDetails()\nconst toolDetailsEnabled = computed(() => props.showToolDetails ?? providedToolDetails.value)\n\nconst isSingleTool = computed(() => props.toolCalls.length === 1)\nconst singleConfirmationToolCall = computed(() => {\n if (!isSingleTool.value || !props.toolCalls[0] || !isConfirmationTool(props.toolCalls[0])) {\n return undefined\n }\n\n return props.toolCalls[0]\n})\nconst completedToolCalls = computed(() => props.toolCalls.filter((toolCall) => !isActiveToolCall(toolCall)))\nconst headerToolCall = computed(() => (\n !props.activityTitle && isSingleTool.value && completedToolCalls.value.length === 1\n ? props.toolCalls[0]\n : undefined\n))\nconst statusToolCalls = computed(() => props.toolCalls.filter((toolCall) => (\n isActiveToolCall(toolCall)\n || (\n !expanded.value\n && recentlyCompletedIds.value.has(toolCall.id)\n && headerToolCall.value?.id !== toolCall.id\n )\n)))\nconst statusContainerVisible = ref(statusToolCalls.value.length > 0)\nconst lineDiff = computed(() => getToolGroupLineDiff(props.toolCalls))\nconst canExpand = computed(() => (\n Boolean(props.activityTitle)\n || props.toolCalls.length > 1\n || (toolDetailsEnabled.value && props.toolCalls.some(hasToolDetails))\n))\nconst summary = computed(() => {\n if (completedToolCalls.value.length > 0) {\n const completed = `${formatActions(completedToolCalls.value.length)} done`\n return props.activityTitle ? `${props.activityTitle} · ${completed}` : completed\n }\n\n return props.activityTitle ?? 'No actions'\n})\n\nwatch(\n () => props.toolCalls.map((toolCall) => ({ id: toolCall.id, active: isActiveToolCall(toolCall) })),\n (toolStates) => {\n const currentIds = new Set(toolStates.map((toolCall) => toolCall.id))\n const currentActiveIds = new Set(\n toolStates.filter((toolCall) => toolCall.active).map((toolCall) => toolCall.id),\n )\n\n for (const id of previousActiveIds) {\n if (!currentActiveIds.has(id) && currentIds.has(id)) retainCompletedTool(id)\n }\n for (const id of currentActiveIds) clearRecentCompletion(id)\n for (const id of recentlyCompletedIds.value) {\n if (!currentIds.has(id)) clearRecentCompletion(id)\n }\n\n previousActiveIds = currentActiveIds\n },\n { flush: 'sync' },\n)\n\nwatch(\n [() => statusToolCalls.value.length, expanded, () => headerToolCall.value?.id],\n ([statusCount, isExpanded, headerId]) => {\n if (statusCount > 0) {\n statusContainerVisible.value = true\n } else if (isExpanded || headerId) {\n statusContainerVisible.value = false\n }\n },\n { flush: 'sync' },\n)\n\nonBeforeUnmount(() => {\n for (const timer of recentCompletionTimers.values()) clearTimeout(timer)\n recentCompletionTimers.clear()\n})\n\nfunction toggleExpanded() {\n if (!canExpand.value) return\n expanded.value = !expanded.value\n}\n\nfunction formatActions(count: number) {\n return `${count} ${count === 1 ? 'action' : 'actions'}`\n}\n\nfunction retainCompletedTool(id: string) {\n recentlyCompletedIds.value = new Set(recentlyCompletedIds.value).add(id)\n recentCompletionTimers.set(id, setTimeout(() => clearRecentCompletion(id), recentCompletionRetentionMs))\n}\n\nfunction clearRecentCompletion(id: string) {\n const timer = recentCompletionTimers.get(id)\n clearTimeout(timer)\n recentCompletionTimers.delete(id)\n if (!recentlyCompletedIds.value.has(id)) return\n const next = new Set(recentlyCompletedIds.value)\n next.delete(id)\n recentlyCompletedIds.value = next\n}\n\nfunction hideEmptyStatusContainer() {\n if (statusToolCalls.value.length === 0) statusContainerVisible.value = false\n}\n\nfunction isActiveToolCall(toolCall: MessageToolCall) {\n return !toolCall.done && toolCall.state !== 'completed'\n}\n\nfunction isConfirmationTool(toolCall: MessageToolCall) {\n const descriptor = parseToolStatusDescriptor(toolCall.status)\n return (\n (descriptor?.source === 'mcp' || descriptor?.source === 'home') &&\n typeof descriptor.params?.requestId === 'string' &&\n toolCall.state === 'running'\n )\n}\n\nfunction hasToolDetails(toolCall: MessageToolCall) {\n return getMessageToolCallArgs(toolCall) !== undefined\n || (toolCall.result !== undefined && toolCall.result !== null)\n}\n</script>\n\n<style scoped>\n.chat-tool-group {\n width: 100%;\n min-width: 0;\n padding: var(--space-1) 0;\n color: var(--color-text-muted);\n}\n\n.chat-tool-group__header {\n display: inline-flex;\n align-items: center;\n gap: var(--space-4);\n max-width: 100%;\n padding: 0;\n border: 0;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--color-text-muted);\n font: inherit;\n cursor: pointer;\n text-align: left;\n}\n\n.chat-tool-group__header--static {\n cursor: default;\n}\n\n.chat-tool-group__header:focus-visible {\n outline: none;\n}\n\n.chat-tool-group__icon,\n.chat-tool-group__chevron {\n flex: 0 0 auto;\n width: 15px;\n height: 15px;\n color: var(--color-text-muted);\n}\n\n.chat-tool-group__icon--running {\n animation: chat-tool-group-square-pulse 1.2s ease-in-out infinite;\n}\n\n.chat-tool-group__active {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.chat-tool-group__running {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n min-width: 0;\n padding-top: var(--space-2);\n}\n\n.chat-tool-group__running-item {\n height: var(--line-height-20);\n overflow: hidden;\n}\n\n.chat-tool-group__running-item-content {\n min-height: var(--line-height-20);\n min-width: 0;\n}\n\n.chat-tool-group-running-leave-active {\n transition:\n height 320ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 320ms ease;\n}\n\n.chat-tool-group-running-leave-active > .chat-tool-group__running-item-content {\n transition: transform 320ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.chat-tool-group-running-leave-to {\n height: 0;\n opacity: 0.3;\n}\n\n.chat-tool-group-running-leave-to > .chat-tool-group__running-item-content {\n transform: translateY(-100%);\n}\n\n.chat-tool-group__running--after-completed {\n padding-top: calc(var(--space-2) + (var(--space-1) * 2));\n}\n\n.chat-tool-group__title {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--font-size-15);\n line-height: var(--line-height-20);\n font-weight: var(--font-weight-light);\n}\n\n.chat-tool-group__diff {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--space-2);\n}\n\n.chat-tool-group__body {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n min-width: 0;\n padding-top: var(--space-2);\n}\n\n.chat-tool-group__body .chat-tool-call:only-of-type:deep() .chat-tool-call__body {\n padding-top: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .chat-tool-group-running-leave-active,\n .chat-tool-group-running-leave-active > .chat-tool-group__running-item-content {\n transition: none;\n }\n}\n\n@keyframes chat-tool-group-square-pulse {\n 0%,\n 100% {\n opacity: 0.55;\n transform: scale(0.88);\n }\n\n 50% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n</style>\n","import type { CodexSurfacePlugin, CodexSurfaceSkill } from '@codex-app-sdk/core/surface';\nimport { skillDisplayName, skillMatchesMention } from './composer-skills';\nimport { pluginMatchesMention } from './composer-plugins';\nimport {\n findComposerMention,\n type CodexComposerMentionGroup,\n type CodexComposerMentionItem,\n} from './composer-mentions-custom';\n\nexport type CodexUserTextToken =\n | { type: 'text'; text: string }\n | { type: 'code'; text: string }\n | { type: 'line-break' }\n | {\n type: 'custom-mention';\n displayName: string;\n group: CodexComposerMentionGroup;\n item: CodexComposerMentionItem;\n label: string;\n }\n | {\n type: 'plugin-mention';\n displayName: string;\n href: string;\n label: string;\n plugin?: CodexSurfacePlugin;\n }\n | {\n type: 'skill-mention';\n displayName: string;\n href: string;\n label: string;\n skill?: CodexSurfaceSkill;\n };\n\nexport function parseCodexUserText(\n content: string,\n plugins: readonly CodexSurfacePlugin[] = [],\n skills: readonly CodexSurfaceSkill[] = [],\n mentionGroups: readonly CodexComposerMentionGroup[] = [],\n): CodexUserTextToken[] {\n const tokens: CodexUserTextToken[] = [];\n let lastIndex = 0;\n\n for (const match of content.matchAll(userTextTokenRegex())) {\n const index = match.index ?? 0;\n if (index > lastIndex) tokens.push({ type: 'text', text: content.slice(lastIndex, index) });\n\n const raw = match[0];\n const code = match[1];\n const label = match[2];\n const href = match[3];\n const bareTrigger = match[4];\n const bareName = match[5];\n if (code !== undefined) {\n tokens.push({ type: 'code', text: code });\n } else if (label !== undefined) {\n tokens.push(mentionToken(label, href!, plugins, skills) ?? { type: 'text', text: raw });\n } else if (bareTrigger !== undefined) {\n tokens.push(bareMentionToken(bareTrigger, bareName!, plugins, skills, mentionGroups) ?? { type: 'text', text: raw });\n } else {\n tokens.push({ type: 'line-break' });\n }\n lastIndex = index + raw.length;\n }\n\n if (lastIndex < content.length) tokens.push({ type: 'text', text: content.slice(lastIndex) });\n return tokens;\n}\n\nfunction bareMentionToken(\n trigger: string,\n name: string,\n plugins: readonly CodexSurfacePlugin[],\n skills: readonly CodexSurfaceSkill[],\n mentionGroups: readonly CodexComposerMentionGroup[],\n): Extract<CodexUserTextToken, { type: 'custom-mention' | 'plugin-mention' | 'skill-mention' }> | null {\n if (trigger === '$') {\n const skill = skills.find((candidate) => skillMatchesMention(candidate, name));\n if (skill) {\n return {\n type: 'skill-mention',\n displayName: skillDisplayName(skill, plugins),\n href: skill.path,\n label: `${trigger}${name}`,\n skill,\n };\n }\n }\n\n if (trigger !== '@') return null;\n const leadingMention = findComposerMention(\n mentionGroups.filter((group) => group.placement !== 'after'),\n name,\n );\n if (leadingMention) {\n return {\n type: 'custom-mention',\n displayName: leadingMention.item.label,\n label: `${trigger}${name}`,\n ...leadingMention,\n };\n }\n const plugin = plugins.find((candidate) => pluginMatchesMention(candidate, name));\n if (plugin) {\n return {\n type: 'plugin-mention',\n displayName: plugin.displayName || plugin.name,\n href: `plugin://${plugin.id}`,\n label: `${trigger}${name}`,\n plugin,\n };\n }\n const trailingMention = findComposerMention(\n mentionGroups,\n name,\n );\n return trailingMention ? {\n type: 'custom-mention',\n displayName: trailingMention.item.label,\n label: `${trigger}${name}`,\n ...trailingMention,\n } : null;\n}\n\nfunction mentionToken(\n rawLabel: string,\n rawHref: string,\n plugins: readonly CodexSurfacePlugin[],\n skills: readonly CodexSurfaceSkill[],\n): Extract<CodexUserTextToken, { type: 'plugin-mention' | 'skill-mention' }> | null {\n const label = rawLabel.trim();\n const href = markdownDestination(rawHref);\n\n if (label.startsWith('@') && href.startsWith('plugin://')) {\n const pluginId = safeDecode(href.slice('plugin://'.length));\n if (!pluginId) return null;\n const plugin = plugins.find((candidate) => candidate.id === pluginId);\n const fallbackName = label.slice(1) || pluginId.split('@')[0]!;\n return {\n type: 'plugin-mention',\n displayName: plugin?.displayName || humanizeMentionName(fallbackName, 'App'),\n href,\n label,\n ...(plugin ? { plugin } : {}),\n };\n }\n\n if (label.startsWith('$')) {\n const skillPath = skillPathFromHref(href);\n if (!skillPath) return null;\n const skill = skills.find((candidate) => candidate.path === skillPath);\n return {\n type: 'skill-mention',\n displayName: skill\n ? skillDisplayName(skill, plugins)\n : humanizeMentionName(label, 'Skill'),\n href,\n label,\n ...(skill ? { skill } : {}),\n };\n }\n\n return null;\n}\n\nfunction markdownDestination(value: string): string {\n const trimmed = value.trim();\n return trimmed.startsWith('<') && trimmed.endsWith('>')\n ? trimmed.slice(1, -1).trim()\n : trimmed;\n}\n\nfunction skillPathFromHref(href: string): string | null {\n const withoutFragment = href.split(/[?#]/, 1)[0]!;\n let path = safeDecode(withoutFragment);\n if (path.startsWith('file://')) {\n try {\n path = decodeURIComponent(new URL(path).pathname);\n } catch {\n return null;\n }\n }\n return /(?:^|[\\\\/])SKILL\\.md$/i.test(path) ? path : null;\n}\n\nfunction safeDecode(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nexport function humanizeMentionName(value: string, fallback: string): string {\n const trimmed = value.trim().replace(/^[@$]/, '');\n if (!trimmed || isOpaqueAppName(trimmed)) return fallback;\n return trimmed\n .split(/[-_:\\s]/)\n .filter(Boolean)\n .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n .join(' ');\n}\n\nfunction userTextTokenRegex(): RegExp {\n return /`([^`\\n]+)`|\\[([^\\]\\n]+)\\]\\(([^)\\n]+)\\)|(?<![\\w.%+-])([$@/])([A-Za-z0-9_.:-]+(?:[ \\t]+\\([A-Za-z0-9_.-]+\\))?)|(\\n)/g;\n}\n\nfunction isOpaqueAppName(value: string): boolean {\n return /^app[-_]?[a-f\\d]{16,}$/i.test(value);\n}\n","<template>\n <div class=\"codex-chat-theme chat-user-text codex-markdown\">\n <p>\n <template v-for=\"(token, index) in tokens\" :key=\"`${token.type}-${index}`\">\n <span v-if=\"token.type === 'text'\">{{ token.text }}</span>\n <code v-else-if=\"token.type === 'code'\">{{ token.text }}</code>\n <br v-else-if=\"token.type === 'line-break'\">\n <slot\n v-else-if=\"token.type === 'custom-mention'\"\n name=\"mention\"\n :group=\"token.group\"\n :item=\"token.item\"\n :token=\"token\"\n surface=\"message\"\n >\n <span class=\"chat-user-text__mention chat-user-text__mention--custom\" :title=\"token.item.description || token.displayName\">\n <SparklesIcon class=\"chat-user-text__mention-icon\" aria-hidden=\"true\" />\n <span class=\"chat-user-text__mention-label\">{{ token.displayName }}</span>\n </span>\n </slot>\n <span\n v-else\n class=\"chat-user-text__mention\"\n :class=\"`chat-user-text__mention--${token.type === 'plugin-mention' ? 'plugin' : 'skill'}`\"\n :style=\"mentionStyle(token)\"\n :title=\"mentionTitle(token)\"\n >\n <span\n class=\"chat-user-text__mention-icon-frame\"\n :class=\"{\n 'chat-user-text__mention-icon-frame--has-light': mentionIcon(token, 'light'),\n 'chat-user-text__mention-icon-frame--has-dark': mentionIcon(token, 'dark'),\n }\"\n >\n <img\n v-if=\"mentionIcon(token, 'light')\"\n class=\"chat-user-text__mention-image chat-user-text__mention-image--light\"\n :src=\"mentionIcon(token, 'light')!\"\n alt=\"\"\n aria-hidden=\"true\"\n decoding=\"async\"\n loading=\"lazy\"\n referrerpolicy=\"no-referrer\"\n @error=\"failedIconUrls.add(mentionIcon(token, 'light')!)\"\n >\n <img\n v-if=\"mentionIcon(token, 'dark')\"\n class=\"chat-user-text__mention-image chat-user-text__mention-image--dark\"\n :src=\"mentionIcon(token, 'dark')!\"\n alt=\"\"\n aria-hidden=\"true\"\n decoding=\"async\"\n loading=\"lazy\"\n referrerpolicy=\"no-referrer\"\n @error=\"failedIconUrls.add(mentionIcon(token, 'dark')!)\"\n >\n <svg\n v-if=\"token.type === 'plugin-mention'\"\n class=\"chat-user-text__mention-icon\"\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M8 3v4\" />\n <path d=\"M16 3v4\" />\n <path d=\"M6 7h12v3a6 6 0 0 1-12 0V7\" />\n <path d=\"M12 16v5\" />\n <path d=\"M9 21h6\" />\n </svg>\n <SparklesIcon v-else class=\"chat-user-text__mention-icon\" aria-hidden=\"true\" />\n </span>\n <span class=\"chat-user-text__mention-label\">{{ token.displayName }}</span>\n </span>\n </template>\n </p>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, reactive } from 'vue';\nimport type { CodexSurfacePlugin, CodexSurfaceSkill } from '@codex-app-sdk/core/surface';\nimport { SparklesIcon } from '../icons/app-icons';\nimport { parseCodexUserText, type CodexUserTextToken } from './user-text';\nimport type { CodexComposerMentionGroup } from './composer-mentions-custom';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n content: string;\n mentionGroups?: readonly CodexComposerMentionGroup[];\n plugins?: readonly CodexSurfacePlugin[];\n skills?: readonly CodexSurfaceSkill[];\n}>(), {\n plugins: () => [],\n mentionGroups: () => [],\n skills: () => [],\n});\n// Stryker restore all\n\nconst failedIconUrls = reactive(new Set<string>());\nconst tokens = computed(() => parseCodexUserText(props.content, props.plugins, props.skills, props.mentionGroups));\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineSlots<{\n mention(props: {\n group: Extract<CodexUserTextToken, { type: 'custom-mention' }>['group'];\n item: Extract<CodexUserTextToken, { type: 'custom-mention' }>['item'];\n surface: 'message';\n token: Extract<CodexUserTextToken, { type: 'custom-mention' }>;\n }): unknown;\n}>();\n// Stryker restore all\n\nfunction mentionIcon(\n token: Extract<CodexUserTextToken, { type: 'plugin-mention' | 'skill-mention' }>,\n theme: 'light' | 'dark',\n): string | null {\n const value = token.type === 'plugin-mention'\n ? (theme === 'dark' && token.plugin?.iconUrlDark !== token.plugin?.iconUrl\n ? token.plugin?.iconUrlDark\n : theme === 'light' ? token.plugin?.iconUrl : undefined)\n : (theme === 'light' ? token.skill?.iconSmall : undefined);\n if (!value) return null;\n if (failedIconUrls.has(value)) return null;\n if (value.startsWith('blob:') || value.startsWith('https://')) return value;\n return /^data:image\\/(?:avif|bmp|gif|jpeg|png|svg\\+xml|webp|x-icon);base64,/i.test(value) ? value : null;\n}\n\nfunction mentionStyle(token: Extract<CodexUserTextToken, { type: 'plugin-mention' | 'skill-mention' }>) {\n const color = token.type === 'plugin-mention'\n ? token.plugin?.brandColor\n : token.skill?.brandColor;\n return isSafeBrandColor(color) ? { '--codex-mention-color': color } : undefined;\n}\n\nfunction mentionTitle(token: Extract<CodexUserTextToken, { type: 'plugin-mention' | 'skill-mention' }>): string {\n if (token.type === 'plugin-mention') {\n return token.plugin?.shortDescription || token.displayName;\n }\n return token.skill?.shortDescription || token.skill?.description || token.displayName;\n}\n\nfunction isSafeBrandColor(value: string | undefined): value is string {\n return Boolean(value && /^#[\\da-f]{3,8}$/i.test(value));\n}\n</script>\n\n<style scoped>\n.chat-user-text {\n white-space: normal;\n overflow-wrap: anywhere;\n}\n\n.chat-user-text__mention {\n --codex-mention-color: var(--color-primary);\n display: inline-flex;\n align-items: center;\n gap: 0.3em;\n max-width: 100%;\n border-radius: var(--radius-md);\n padding: var(--space-2) var(--space-3);\n background: color-mix(in srgb, var(--codex-mention-color) 12%, var(--color-primary-container));\n color: color-mix(in srgb, var(--codex-mention-color) 42%, var(--color-on-primary-container));\n font-weight: var(--font-weight-medium);\n line-height: 1;\n vertical-align: -0.18em;\n}\n\n.chat-user-text__mention-icon-frame,\n.chat-user-text__mention-icon,\n.chat-user-text__mention-image {\n width: 1.12em;\n height: 1.12em;\n flex: 0 0 1.12em;\n}\n\n.chat-user-text__mention-icon-frame {\n position: relative;\n display: inline-flex;\n}\n\n.chat-user-text__mention-icon {\n display: block;\n}\n\n.chat-user-text__mention-icon-frame--has-light .chat-user-text__mention-icon,\n.chat-user-text__mention-image--dark {\n display: none;\n}\n\n:global(.codex-chat-theme--dark) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--light,\n:global([data-codex-theme=\"dark\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--light {\n display: none;\n}\n\n:global(.codex-chat-theme--dark) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--dark,\n:global([data-codex-theme=\"dark\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--dark {\n display: block;\n}\n\n:global(.codex-chat-theme--dark) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-icon,\n:global([data-codex-theme=\"dark\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-icon {\n display: none;\n}\n\n@media (prefers-color-scheme: dark) {\n :global(.codex-chat-theme--system) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--light,\n :global([data-codex-theme=\"system\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--light {\n display: none;\n }\n\n :global(.codex-chat-theme--system) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--dark,\n :global([data-codex-theme=\"system\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--dark {\n display: block;\n }\n\n :global(.codex-chat-theme--system) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-icon,\n :global([data-codex-theme=\"system\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-icon {\n display: none;\n }\n}\n\n.chat-user-text__mention-image {\n border-radius: 0.2em;\n object-fit: contain;\n}\n\n.chat-user-text__mention-label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-user-text codex-markdown\">\n <p>\n <template v-for=\"(token, index) in tokens\" :key=\"`${token.type}-${index}`\">\n <span v-if=\"token.type === 'text'\">{{ token.text }}</span>\n <code v-else-if=\"token.type === 'code'\">{{ token.text }}</code>\n <br v-else-if=\"token.type === 'line-break'\">\n <slot\n v-else-if=\"token.type === 'custom-mention'\"\n name=\"mention\"\n :group=\"token.group\"\n :item=\"token.item\"\n :token=\"token\"\n surface=\"message\"\n >\n <span class=\"chat-user-text__mention chat-user-text__mention--custom\" :title=\"token.item.description || token.displayName\">\n <SparklesIcon class=\"chat-user-text__mention-icon\" aria-hidden=\"true\" />\n <span class=\"chat-user-text__mention-label\">{{ token.displayName }}</span>\n </span>\n </slot>\n <span\n v-else\n class=\"chat-user-text__mention\"\n :class=\"`chat-user-text__mention--${token.type === 'plugin-mention' ? 'plugin' : 'skill'}`\"\n :style=\"mentionStyle(token)\"\n :title=\"mentionTitle(token)\"\n >\n <span\n class=\"chat-user-text__mention-icon-frame\"\n :class=\"{\n 'chat-user-text__mention-icon-frame--has-light': mentionIcon(token, 'light'),\n 'chat-user-text__mention-icon-frame--has-dark': mentionIcon(token, 'dark'),\n }\"\n >\n <img\n v-if=\"mentionIcon(token, 'light')\"\n class=\"chat-user-text__mention-image chat-user-text__mention-image--light\"\n :src=\"mentionIcon(token, 'light')!\"\n alt=\"\"\n aria-hidden=\"true\"\n decoding=\"async\"\n loading=\"lazy\"\n referrerpolicy=\"no-referrer\"\n @error=\"failedIconUrls.add(mentionIcon(token, 'light')!)\"\n >\n <img\n v-if=\"mentionIcon(token, 'dark')\"\n class=\"chat-user-text__mention-image chat-user-text__mention-image--dark\"\n :src=\"mentionIcon(token, 'dark')!\"\n alt=\"\"\n aria-hidden=\"true\"\n decoding=\"async\"\n loading=\"lazy\"\n referrerpolicy=\"no-referrer\"\n @error=\"failedIconUrls.add(mentionIcon(token, 'dark')!)\"\n >\n <svg\n v-if=\"token.type === 'plugin-mention'\"\n class=\"chat-user-text__mention-icon\"\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M8 3v4\" />\n <path d=\"M16 3v4\" />\n <path d=\"M6 7h12v3a6 6 0 0 1-12 0V7\" />\n <path d=\"M12 16v5\" />\n <path d=\"M9 21h6\" />\n </svg>\n <SparklesIcon v-else class=\"chat-user-text__mention-icon\" aria-hidden=\"true\" />\n </span>\n <span class=\"chat-user-text__mention-label\">{{ token.displayName }}</span>\n </span>\n </template>\n </p>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, reactive } from 'vue';\nimport type { CodexSurfacePlugin, CodexSurfaceSkill } from '@codex-app-sdk/core/surface';\nimport { SparklesIcon } from '../icons/app-icons';\nimport { parseCodexUserText, type CodexUserTextToken } from './user-text';\nimport type { CodexComposerMentionGroup } from './composer-mentions-custom';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n content: string;\n mentionGroups?: readonly CodexComposerMentionGroup[];\n plugins?: readonly CodexSurfacePlugin[];\n skills?: readonly CodexSurfaceSkill[];\n}>(), {\n plugins: () => [],\n mentionGroups: () => [],\n skills: () => [],\n});\n// Stryker restore all\n\nconst failedIconUrls = reactive(new Set<string>());\nconst tokens = computed(() => parseCodexUserText(props.content, props.plugins, props.skills, props.mentionGroups));\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineSlots<{\n mention(props: {\n group: Extract<CodexUserTextToken, { type: 'custom-mention' }>['group'];\n item: Extract<CodexUserTextToken, { type: 'custom-mention' }>['item'];\n surface: 'message';\n token: Extract<CodexUserTextToken, { type: 'custom-mention' }>;\n }): unknown;\n}>();\n// Stryker restore all\n\nfunction mentionIcon(\n token: Extract<CodexUserTextToken, { type: 'plugin-mention' | 'skill-mention' }>,\n theme: 'light' | 'dark',\n): string | null {\n const value = token.type === 'plugin-mention'\n ? (theme === 'dark' && token.plugin?.iconUrlDark !== token.plugin?.iconUrl\n ? token.plugin?.iconUrlDark\n : theme === 'light' ? token.plugin?.iconUrl : undefined)\n : (theme === 'light' ? token.skill?.iconSmall : undefined);\n if (!value) return null;\n if (failedIconUrls.has(value)) return null;\n if (value.startsWith('blob:') || value.startsWith('https://')) return value;\n return /^data:image\\/(?:avif|bmp|gif|jpeg|png|svg\\+xml|webp|x-icon);base64,/i.test(value) ? value : null;\n}\n\nfunction mentionStyle(token: Extract<CodexUserTextToken, { type: 'plugin-mention' | 'skill-mention' }>) {\n const color = token.type === 'plugin-mention'\n ? token.plugin?.brandColor\n : token.skill?.brandColor;\n return isSafeBrandColor(color) ? { '--codex-mention-color': color } : undefined;\n}\n\nfunction mentionTitle(token: Extract<CodexUserTextToken, { type: 'plugin-mention' | 'skill-mention' }>): string {\n if (token.type === 'plugin-mention') {\n return token.plugin?.shortDescription || token.displayName;\n }\n return token.skill?.shortDescription || token.skill?.description || token.displayName;\n}\n\nfunction isSafeBrandColor(value: string | undefined): value is string {\n return Boolean(value && /^#[\\da-f]{3,8}$/i.test(value));\n}\n</script>\n\n<style scoped>\n.chat-user-text {\n white-space: normal;\n overflow-wrap: anywhere;\n}\n\n.chat-user-text__mention {\n --codex-mention-color: var(--color-primary);\n display: inline-flex;\n align-items: center;\n gap: 0.3em;\n max-width: 100%;\n border-radius: var(--radius-md);\n padding: var(--space-2) var(--space-3);\n background: color-mix(in srgb, var(--codex-mention-color) 12%, var(--color-primary-container));\n color: color-mix(in srgb, var(--codex-mention-color) 42%, var(--color-on-primary-container));\n font-weight: var(--font-weight-medium);\n line-height: 1;\n vertical-align: -0.18em;\n}\n\n.chat-user-text__mention-icon-frame,\n.chat-user-text__mention-icon,\n.chat-user-text__mention-image {\n width: 1.12em;\n height: 1.12em;\n flex: 0 0 1.12em;\n}\n\n.chat-user-text__mention-icon-frame {\n position: relative;\n display: inline-flex;\n}\n\n.chat-user-text__mention-icon {\n display: block;\n}\n\n.chat-user-text__mention-icon-frame--has-light .chat-user-text__mention-icon,\n.chat-user-text__mention-image--dark {\n display: none;\n}\n\n:global(.codex-chat-theme--dark) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--light,\n:global([data-codex-theme=\"dark\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--light {\n display: none;\n}\n\n:global(.codex-chat-theme--dark) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--dark,\n:global([data-codex-theme=\"dark\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--dark {\n display: block;\n}\n\n:global(.codex-chat-theme--dark) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-icon,\n:global([data-codex-theme=\"dark\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-icon {\n display: none;\n}\n\n@media (prefers-color-scheme: dark) {\n :global(.codex-chat-theme--system) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--light,\n :global([data-codex-theme=\"system\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--light {\n display: none;\n }\n\n :global(.codex-chat-theme--system) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--dark,\n :global([data-codex-theme=\"system\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-image--dark {\n display: block;\n }\n\n :global(.codex-chat-theme--system) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-icon,\n :global([data-codex-theme=\"system\"]) .chat-user-text__mention-icon-frame--has-dark .chat-user-text__mention-icon {\n display: none;\n }\n}\n\n.chat-user-text__mention-image {\n border-radius: 0.2em;\n object-fit: contain;\n}\n\n.chat-user-text__mention-label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n</style>\n","<template>\n <button\n v-if=\"path\"\n class=\"codex-chat-theme chat-visualization-block\"\n type=\"button\"\n @click=\"open\"\n >\n <DashboardIcon class=\"chat-visualization-block__icon\" />\n <span>{{ title }}</span>\n <ExternalLinkIcon class=\"chat-visualization-block__open\" />\n </button>\n <div v-else class=\"codex-chat-theme chat-visualization-block\">\n <DashboardIcon class=\"chat-visualization-block__icon\" />\n <span>{{ title }}</span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { DashboardIcon, ExternalLinkIcon } from '../icons/app-icons'\nimport type { CodexConversationVisualization } from './visualization'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{ path?: string; title: string }>()\nconst emit = defineEmits<{\n 'open-visualization': [visualization: CodexConversationVisualization]\n}>()\n// Stryker restore all\n\nfunction open() {\n if (!props.path) return\n emit('open-visualization', { path: props.path, title: props.title })\n}\n</script>\n\n<style scoped>\n.chat-visualization-block {\n display: flex;\n width: fit-content;\n max-width: 100%;\n align-items: center;\n gap: var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n padding: var(--space-4) var(--space-6);\n background: var(--color-surface-low);\n color: var(--color-text);\n font: inherit;\n overflow-wrap: anywhere;\n text-align: left;\n}\n\nbutton.chat-visualization-block {\n cursor: pointer;\n}\n\nbutton.chat-visualization-block:hover {\n background: var(--color-surface-high);\n}\n\nbutton.chat-visualization-block:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: 2px;\n}\n\n.chat-visualization-block__icon,\n.chat-visualization-block__open {\n width: 18px;\n height: 18px;\n flex: 0 0 auto;\n color: var(--color-text-muted);\n}\n\n.chat-visualization-block__open {\n width: 15px;\n height: 15px;\n}\n</style>\n","<template>\n <button\n v-if=\"path\"\n class=\"codex-chat-theme chat-visualization-block\"\n type=\"button\"\n @click=\"open\"\n >\n <DashboardIcon class=\"chat-visualization-block__icon\" />\n <span>{{ title }}</span>\n <ExternalLinkIcon class=\"chat-visualization-block__open\" />\n </button>\n <div v-else class=\"codex-chat-theme chat-visualization-block\">\n <DashboardIcon class=\"chat-visualization-block__icon\" />\n <span>{{ title }}</span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { DashboardIcon, ExternalLinkIcon } from '../icons/app-icons'\nimport type { CodexConversationVisualization } from './visualization'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{ path?: string; title: string }>()\nconst emit = defineEmits<{\n 'open-visualization': [visualization: CodexConversationVisualization]\n}>()\n// Stryker restore all\n\nfunction open() {\n if (!props.path) return\n emit('open-visualization', { path: props.path, title: props.title })\n}\n</script>\n\n<style scoped>\n.chat-visualization-block {\n display: flex;\n width: fit-content;\n max-width: 100%;\n align-items: center;\n gap: var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n padding: var(--space-4) var(--space-6);\n background: var(--color-surface-low);\n color: var(--color-text);\n font: inherit;\n overflow-wrap: anywhere;\n text-align: left;\n}\n\nbutton.chat-visualization-block {\n cursor: pointer;\n}\n\nbutton.chat-visualization-block:hover {\n background: var(--color-surface-high);\n}\n\nbutton.chat-visualization-block:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: 2px;\n}\n\n.chat-visualization-block__icon,\n.chat-visualization-block__open {\n width: 18px;\n height: 18px;\n flex: 0 0 auto;\n color: var(--color-text-muted);\n}\n\n.chat-visualization-block__open {\n width: 15px;\n height: 15px;\n}\n</style>\n","<template>\n <section\n v-if=\"showHeader || expanded\"\n class=\"codex-chat-theme chat-work-group\"\n :class=\"{ 'chat-work-group--continuation': !showHeader }\"\n >\n <button\n v-if=\"showHeader\"\n type=\"button\"\n class=\"chat-work-group__header\"\n :aria-expanded=\"expanded\"\n :disabled=\"active\"\n @click=\"toggle\"\n >\n <span\n class=\"chat-work-group__title\"\n :class=\"{ 'codex-text-shimmer': active }\"\n :data-label=\"label\"\n >\n {{ label }}\n </span>\n <component v-if=\"!active\" :is=\"expanded ? ChevronDown : ChevronRightIcon\" :size=\"15\" />\n </button>\n\n <ChatFoldTransition v-if=\"showHeader\" :open=\"expanded\">\n <div class=\"chat-work-group__body\">\n <slot />\n </div>\n </ChatFoldTransition>\n <div v-else class=\"chat-work-group__body chat-work-group__body--continuation\">\n <slot />\n </div>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, ref, watch } from 'vue'\nimport { ChevronDown, ChevronRightIcon } from '../icons/app-icons'\nimport { useCodexChatTranslate } from './chat-i18n'\nimport ChatFoldTransition from './ChatFoldTransition.vue'\nimport { assistantWorkMessageIndexKey, assistantWorkTurnKey } from './message-work-state'\n\nconst props = defineProps<{\n active: boolean\n continuation?: boolean\n finalStarted: boolean\n}>()\n\nconst t = useCodexChatTranslate()\nconst assistantWorkTurn = inject(assistantWorkTurnKey, undefined)\nconst messageIndex = inject(assistantWorkMessageIndexKey, undefined)\nconst usesTurn = computed(() => assistantWorkTurn?.enabled.value === true && messageIndex !== undefined)\nconst completedWithoutFinal = computed(() => (\n usesTurn.value\n ? assistantWorkTurn!.completedWithoutFinal.value\n : !props.active && !props.finalStarted\n))\nconst localExpanded = ref(props.active && !props.finalStarted)\nconst userToggled = ref(false)\nconst active = computed(() => (\n usesTurn.value\n ? assistantWorkTurn!.active.value\n : props.active && !props.finalStarted\n))\nconst expanded = computed(() => (\n active.value\n ? true\n : completedWithoutFinal.value\n ? true\n : usesTurn.value ? assistantWorkTurn!.expanded.value : localExpanded.value\n))\nconst showHeader = computed(() => (\n !props.continuation\n && !completedWithoutFinal.value\n && (!usesTurn.value || assistantWorkTurn!.headerMessageIndex.value === messageIndex!.value)\n))\nconst label = computed(() => {\n if (active.value) return t('chat.work.working')\n if (assistantWorkTurn?.status.value === 'interrupted') {\n return t(expanded.value ? 'chat.work.stoppedHideDetails' : 'chat.work.stoppedViewDetails')\n }\n if (assistantWorkTurn?.status.value === 'failed') {\n return t(expanded.value ? 'chat.work.failedHideDetails' : 'chat.work.failedViewDetails')\n }\n return t(expanded.value ? 'chat.work.doneHideDetails' : 'chat.work.doneViewDetails')\n})\n\nwatch(\n () => props.finalStarted,\n (started, previous) => {\n if (!usesTurn.value && started && !previous) localExpanded.value = false\n },\n)\n\nwatch(\n () => props.active,\n (isActive) => {\n if (!usesTurn.value && !userToggled.value) localExpanded.value = isActive && !props.finalStarted\n },\n)\n\nfunction toggle() {\n if (active.value) return\n if (usesTurn.value) {\n assistantWorkTurn!.toggle()\n return\n }\n userToggled.value = true\n localExpanded.value = !localExpanded.value\n}\n</script>\n\n<style scoped>\n.chat-work-group {\n width: 100%;\n min-width: 0;\n color: var(--color-text-muted);\n}\n\n.chat-work-group__header {\n display: inline-flex;\n max-width: 100%;\n align-items: center;\n gap: var(--space-2);\n padding: 0;\n border: 0;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--color-text-muted);\n cursor: pointer;\n font: inherit;\n text-align: left;\n}\n\n.chat-work-group__header:focus-visible {\n outline: none;\n}\n\n.chat-work-group__header:disabled {\n cursor: default;\n}\n\n.chat-work-group__title {\n overflow: hidden;\n font-size: var(--font-size-15);\n font-weight: var(--font-weight-light);\n line-height: var(--line-height-20);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-work-group__body {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--space-4);\n padding-top: var(--space-3);\n}\n\n.chat-work-group__body--continuation {\n padding-top: 0;\n}\n</style>\n","<template>\n <section\n v-if=\"showHeader || expanded\"\n class=\"codex-chat-theme chat-work-group\"\n :class=\"{ 'chat-work-group--continuation': !showHeader }\"\n >\n <button\n v-if=\"showHeader\"\n type=\"button\"\n class=\"chat-work-group__header\"\n :aria-expanded=\"expanded\"\n :disabled=\"active\"\n @click=\"toggle\"\n >\n <span\n class=\"chat-work-group__title\"\n :class=\"{ 'codex-text-shimmer': active }\"\n :data-label=\"label\"\n >\n {{ label }}\n </span>\n <component v-if=\"!active\" :is=\"expanded ? ChevronDown : ChevronRightIcon\" :size=\"15\" />\n </button>\n\n <ChatFoldTransition v-if=\"showHeader\" :open=\"expanded\">\n <div class=\"chat-work-group__body\">\n <slot />\n </div>\n </ChatFoldTransition>\n <div v-else class=\"chat-work-group__body chat-work-group__body--continuation\">\n <slot />\n </div>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, ref, watch } from 'vue'\nimport { ChevronDown, ChevronRightIcon } from '../icons/app-icons'\nimport { useCodexChatTranslate } from './chat-i18n'\nimport ChatFoldTransition from './ChatFoldTransition.vue'\nimport { assistantWorkMessageIndexKey, assistantWorkTurnKey } from './message-work-state'\n\nconst props = defineProps<{\n active: boolean\n continuation?: boolean\n finalStarted: boolean\n}>()\n\nconst t = useCodexChatTranslate()\nconst assistantWorkTurn = inject(assistantWorkTurnKey, undefined)\nconst messageIndex = inject(assistantWorkMessageIndexKey, undefined)\nconst usesTurn = computed(() => assistantWorkTurn?.enabled.value === true && messageIndex !== undefined)\nconst completedWithoutFinal = computed(() => (\n usesTurn.value\n ? assistantWorkTurn!.completedWithoutFinal.value\n : !props.active && !props.finalStarted\n))\nconst localExpanded = ref(props.active && !props.finalStarted)\nconst userToggled = ref(false)\nconst active = computed(() => (\n usesTurn.value\n ? assistantWorkTurn!.active.value\n : props.active && !props.finalStarted\n))\nconst expanded = computed(() => (\n active.value\n ? true\n : completedWithoutFinal.value\n ? true\n : usesTurn.value ? assistantWorkTurn!.expanded.value : localExpanded.value\n))\nconst showHeader = computed(() => (\n !props.continuation\n && !completedWithoutFinal.value\n && (!usesTurn.value || assistantWorkTurn!.headerMessageIndex.value === messageIndex!.value)\n))\nconst label = computed(() => {\n if (active.value) return t('chat.work.working')\n if (assistantWorkTurn?.status.value === 'interrupted') {\n return t(expanded.value ? 'chat.work.stoppedHideDetails' : 'chat.work.stoppedViewDetails')\n }\n if (assistantWorkTurn?.status.value === 'failed') {\n return t(expanded.value ? 'chat.work.failedHideDetails' : 'chat.work.failedViewDetails')\n }\n return t(expanded.value ? 'chat.work.doneHideDetails' : 'chat.work.doneViewDetails')\n})\n\nwatch(\n () => props.finalStarted,\n (started, previous) => {\n if (!usesTurn.value && started && !previous) localExpanded.value = false\n },\n)\n\nwatch(\n () => props.active,\n (isActive) => {\n if (!usesTurn.value && !userToggled.value) localExpanded.value = isActive && !props.finalStarted\n },\n)\n\nfunction toggle() {\n if (active.value) return\n if (usesTurn.value) {\n assistantWorkTurn!.toggle()\n return\n }\n userToggled.value = true\n localExpanded.value = !localExpanded.value\n}\n</script>\n\n<style scoped>\n.chat-work-group {\n width: 100%;\n min-width: 0;\n color: var(--color-text-muted);\n}\n\n.chat-work-group__header {\n display: inline-flex;\n max-width: 100%;\n align-items: center;\n gap: var(--space-2);\n padding: 0;\n border: 0;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--color-text-muted);\n cursor: pointer;\n font: inherit;\n text-align: left;\n}\n\n.chat-work-group__header:focus-visible {\n outline: none;\n}\n\n.chat-work-group__header:disabled {\n cursor: default;\n}\n\n.chat-work-group__title {\n overflow: hidden;\n font-size: var(--font-size-15);\n font-weight: var(--font-weight-light);\n line-height: var(--line-height-20);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-work-group__body {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--space-4);\n padding-top: var(--space-3);\n}\n\n.chat-work-group__body--continuation {\n padding-top: 0;\n}\n</style>\n","export function escapeHtml(content: string) {\n return content\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\nexport function escapeAttribute(content: string) {\n return escapeHtml(content).replace(/`/g, '&#96;')\n}\n","import { createHighlighterCoreSync } from 'shiki/core'\nimport { createJavaScriptRegexEngine } from 'shiki/engine/javascript'\nimport css from '@shikijs/langs/css'\nimport diff from '@shikijs/langs/diff'\nimport docker from '@shikijs/langs/docker'\nimport go from '@shikijs/langs/go'\nimport html from '@shikijs/langs/html'\nimport javascript from '@shikijs/langs/javascript'\nimport json from '@shikijs/langs/json'\nimport jsx from '@shikijs/langs/jsx'\nimport markdown from '@shikijs/langs/markdown'\nimport python from '@shikijs/langs/python'\nimport rust from '@shikijs/langs/rust'\nimport shell from '@shikijs/langs/sh'\nimport sql from '@shikijs/langs/sql'\nimport toml from '@shikijs/langs/toml'\nimport tsx from '@shikijs/langs/tsx'\nimport typescript from '@shikijs/langs/typescript'\nimport vue from '@shikijs/langs/vue'\nimport xml from '@shikijs/langs/xml'\nimport yaml from '@shikijs/langs/yaml'\nimport darkPlus from '@shikijs/themes/dark-plus'\nimport lightPlus from '@shikijs/themes/light-plus'\nimport { escapeAttribute, escapeHtml } from './html-escape'\n\nconst highlighter = createHighlighterCoreSync({\n engine: createJavaScriptRegexEngine(),\n langs: [\n css,\n diff,\n docker,\n go,\n html,\n javascript,\n json,\n jsx,\n markdown,\n python,\n rust,\n shell,\n sql,\n toml,\n tsx,\n typescript,\n vue,\n xml,\n yaml,\n ],\n themes: [lightPlus, darkPlus],\n})\n\nconst loadedLanguages = new Set(highlighter.getLoadedLanguages())\n\nexport function renderCodeBlock(code: string, language: string | undefined) {\n const lang = normalizeLanguage(language)\n if (!lang || !loadedLanguages.has(lang)) {\n return renderPlainCodeBlock(code, language)\n }\n\n try {\n return highlighter.codeToHtml(code, {\n defaultColor: false,\n lang,\n themes: {\n dark: 'dark-plus',\n light: 'light-plus',\n },\n })\n } catch {\n return renderPlainCodeBlock(code, language)\n }\n}\n\nexport function languageForFilePath(filePath: string | undefined): string | undefined {\n const normalizedPath = (filePath ?? '').trim().toLowerCase();\n const extension = normalizedPath.match(/\\.([^.\\\\/]+)$/)?.[1];\n switch (extension) {\n case 'patch':\n return 'diff';\n case 'dockerfile':\n return 'docker';\n case 'htm':\n return 'html';\n case 'js':\n case 'mjs':\n case 'cjs':\n return 'javascript';\n case 'jsonc':\n return 'json';\n case 'md':\n case 'mdown':\n case 'mkdn':\n return 'markdown';\n case 'py':\n return 'python';\n case 'rs':\n return 'rust';\n case 'bash':\n case 'zsh':\n return 'sh';\n case 'ts':\n case 'mts':\n case 'cts':\n return 'typescript';\n case 'svg':\n return 'xml';\n case 'yml':\n return 'yaml';\n default:\n if (normalizedPath.endsWith('/dockerfile') || normalizedPath === 'dockerfile') {\n return 'docker';\n }\n return extension;\n }\n}\n\nfunction normalizeLanguage(language: string | undefined) {\n const [lang] = (language ?? '').trim().toLowerCase().split(/\\s+/)\n return lang || null\n}\n\nfunction renderPlainCodeBlock(code: string, language: string | undefined) {\n const lang = normalizeLanguage(language)\n const className = lang ? ` class=\"language-${escapeAttribute(lang)}\"` : ''\n return `<pre><code${className}>${renderPlainCodeLines(code)}</code></pre>`\n}\n\nfunction renderPlainCodeLines(code: string) {\n return code.split('\\n').map((line) => `<span class=\"line\">${escapeHtml(line)}</span>`).join('\\n')\n}\n","import { Marked, Renderer } from 'marked'\nimport katex from 'katex'\nimport markedKatex from 'marked-katex-extension'\nimport { escapeAttribute, escapeHtml } from './html-escape'\nimport { renderCodeBlock } from './syntax-highlighting'\nimport { parseCodexEditorFileReference } from './conversation-links'\n\nconst renderer = new Renderer()\n\nrenderer.html = ({ text }) => escapeHtml(text)\n\nrenderer.code = ({ text, lang }) => renderCodeBlock(text, lang)\n\nrenderer.link = ({ href, title, tokens }) => {\n const text = renderInlineTokens(tokens)\n const safeHref = safeMarkdownHref(href)\n if (!safeHref) {\n return `<span class=\"chat-message-link chat-message-link--blocked\">${text}</span>`\n }\n const safeTitle = title ? ` title=\"${escapeAttribute(title)}\"` : ''\n const icon = renderLinkIcon(safeHref)\n const target = isAbsoluteHttpUrl(safeHref) ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : ''\n return `<a class=\"chat-message-link\" href=\"${escapeAttribute(safeHref)}\"${safeTitle}${target}>${icon}<span class=\"chat-message-link__label\">${text}</span></a>`\n}\n\nrenderer.image = ({ href, title, text }) => {\n const safeSrc = safeMarkdownImageSrc(href)\n const alt = escapeAttribute(text)\n if (!safeSrc) {\n return `<span class=\"chat-message-image chat-message-image--blocked\">${escapeHtml(text)}</span>`\n }\n const safeTitle = title ? ` title=\"${escapeAttribute(title)}\"` : ''\n return `<img class=\"chat-message-image\" src=\"${escapeAttribute(safeSrc)}\" alt=\"${alt}\"${safeTitle} loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\">`\n}\n\nconst markdown = new Marked({\n async: false,\n breaks: true,\n gfm: true,\n renderer,\n})\n\nmarkdown.use(markedKatex({\n maxExpand: 1_000,\n maxSize: 20,\n nonStandard: false,\n output: 'htmlAndMathml',\n strict: 'ignore',\n throwOnError: false,\n trust: false,\n}))\n\nmarkdown.use({\n extensions: [\n {\n name: 'codexBlockKatex',\n level: 'block',\n tokenizer(src) {\n const match = /^\\\\\\[[ \\t]*(?:\\n([\\s\\S]+?)\\n|([^\\n]*?))[ \\t]*\\\\\\](?:\\n|$)/.exec(src)\n if (!match) return undefined\n return {\n type: 'codexBlockKatex',\n raw: match[0],\n text: (match[1] ?? match[2])!.trim(),\n }\n },\n renderer(token) {\n return `${renderLatex((token as unknown as { text: string }).text, true)}\\n`\n },\n },\n {\n name: 'codexInlineKatex',\n level: 'inline',\n tokenizer(src) {\n const match = /^\\\\\\((.+?)\\\\\\)/.exec(src)\n if (!match) return undefined\n return {\n type: 'codexInlineKatex',\n raw: match[0],\n text: match[1]!.trim(),\n }\n },\n renderer(token) {\n return renderLatex((token as unknown as { text: string }).text, false)\n },\n },\n ],\n})\n\nexport function renderMarkdown(\n content: string,\n options: { codeCopyLabel?: string } = {},\n) {\n const html = markdown.parse(content) as string\n return options.codeCopyLabel ? addCodeCopyControls(html, options.codeCopyLabel) : html\n}\n\nexport function renderUserText(content: string) {\n return `<p>${escapeHtml(content)\n .replace(/`([^`]+)`/g, '<code>$1</code>')\n .replace(/\\n/g, '<br>')}</p>`\n}\n\nfunction addCodeCopyControls(html: string, label: string): string {\n const button = [\n `<button class=\"chat-code-block__copy\" type=\"button\" data-chat-code-copy aria-label=\"${escapeAttribute(label)}\" title=\"${escapeAttribute(label)}\">`,\n '<svg class=\"chat-code-block__copy-icon\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M8 8m-2 0a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2z\"/><path d=\"M16 6V4a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h2\"/></svg>',\n '<svg class=\"chat-code-block__check-icon\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"m5 12 5 5L20 7\"/></svg>',\n '</button>',\n ].join('')\n return html.replace(/(<pre\\b[\\s\\S]*?<\\/pre>)/g, `<div class=\"chat-code-block\">${button}$1</div>`)\n}\n\nfunction isAbsoluteHttpUrl(value: string) {\n try {\n const url = new URL(value)\n return url.protocol === 'http:' || url.protocol === 'https:'\n } catch {\n return false\n }\n}\n\nfunction isMailtoUrl(value: string) {\n try {\n return new URL(value).protocol === 'mailto:'\n } catch {\n return false\n }\n}\n\nfunction renderLatex(source: string, displayMode: boolean): string {\n const rendered = katex.renderToString(source, {\n displayMode,\n maxExpand: 1_000,\n maxSize: 20,\n output: 'htmlAndMathml',\n strict: 'ignore',\n throwOnError: false,\n trust: false,\n })\n return displayMode ? `<span class=\"katex-display\">${rendered}</span>` : rendered\n}\n\nconst allowedAbsoluteProtocols = new Set(['file:', 'http:', 'https:', 'mailto:', 'tel:'])\n\n/**\n * Returns a browser-safe Markdown href or null when the link uses an executable\n * or otherwise unsupported scheme. Relative paths and in-document fragments\n * deliberately remain relative so the host can resolve them against its own\n * workspace policy.\n */\nexport function safeMarkdownHref(value: string): string | null {\n const href = value.trim()\n if (!href || /[\\u0000-\\u001f\\u007f]/.test(href)) {\n return null\n }\n\n if (/^[a-z]:[\\\\/]/i.test(href)) {\n return href\n }\n\n if (parseCodexEditorFileReference(href)) {\n return href\n }\n\n // Network-path references inherit the renderer scheme and are therefore not\n // a stable or safe relative-file contract.\n if (href.startsWith('\\\\') || href.startsWith('//')) {\n return null\n }\n\n const scheme = /^([a-z][a-z\\d+.-]*):/i.exec(href)?.[1]\n if (!scheme) {\n return href\n }\n\n const protocol = `${scheme.toLowerCase()}:`\n if (!allowedAbsoluteProtocols.has(protocol)) {\n return null\n }\n\n try {\n new URL(href)\n return href\n } catch {\n return null\n }\n}\n\nfunction safeMarkdownImageSrc(value: string): string | null {\n const src = safeMarkdownHref(value)\n if (!src || src.startsWith('#') || src.startsWith('?')) return null\n try {\n const protocol = new URL(src).protocol\n return protocol === 'mailto:' || protocol === 'tel:' ? null : src\n } catch {\n return src\n }\n}\n\nfunction renderLinkIcon(href: string) {\n if (isAbsoluteHttpUrl(href)) {\n return '<svg class=\"chat-message-link__icon chat-message-link__icon--external\" aria-hidden=\"true\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 3h6v6\"></path><path d=\"m10 14 11-11\"></path><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"></path></svg>'\n }\n\n if (isMailtoUrl(href)) {\n return '<svg class=\"chat-message-link__icon chat-message-link__icon--mail\" aria-hidden=\"true\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"></rect><path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\"></path></svg>'\n }\n\n return '<svg class=\"chat-message-link__icon chat-message-link__icon--file\" aria-hidden=\"true\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\"></path><path d=\"M14 2v4a2 2 0 0 0 2 2h4\"></path></svg>'\n}\n\nfunction renderInlineTokens(tokens: unknown[]) {\n return tokens.map(renderInlineToken).join('')\n}\n\nexport function renderInlineToken(token: unknown): string {\n if (!token || typeof token !== 'object') {\n return ''\n }\n\n const inlineToken = token as {\n raw?: unknown\n text?: unknown\n tokens?: unknown[]\n type?: unknown\n }\n\n if (Array.isArray(inlineToken.tokens)) {\n const content = renderInlineTokens(inlineToken.tokens)\n if (inlineToken.type === 'strong') {\n return `<strong>${content}</strong>`\n }\n if (inlineToken.type === 'em') {\n return `<em>${content}</em>`\n }\n return content\n }\n\n if (inlineToken.type === 'codespan' && typeof inlineToken.text === 'string') {\n return `<code>${escapeHtml(inlineToken.text)}</code>`\n }\n\n if (typeof inlineToken.text === 'string') {\n return escapeHtml(inlineToken.text)\n }\n\n if (typeof inlineToken.raw === 'string') {\n return escapeHtml(inlineToken.raw)\n }\n\n return ''\n}\n","import { renderMarkdown } from './message-markdown'\nimport { stripMessageContext } from './message-blocks'\nimport type { CodexHostCapabilities } from '@codex-app-sdk/core/native'\nimport { getCodexGlobalHostCapabilities } from '../native-capabilities'\n\nconst toolTagRegex = /<tool\\s+(id|index)=\"[^\"]*\"><\\/tool>/g\nconst followUpTagRegex = /<follow-up>[\\s\\S]*?<\\/follow-up>/g\nconst breakTagRegex = /<br\\s*\\/?>/gi\n\nexport function stripMessageMarkup(content: string) {\n return stripMessageContext(content)\n .replace(toolTagRegex, '')\n .replace(followUpTagRegex, '')\n .trim()\n}\n\nexport function copyableMessageText(content: string) {\n return markdownToText(stripMessageMarkup(content))\n}\n\nexport function copyableMessageHtml(content: string) {\n return renderMarkdown(stripMessageMarkup(content)).trim()\n}\n\nexport async function copyMessageToClipboard(\n content: string,\n hostCapabilities: CodexHostCapabilities | undefined = getCodexGlobalHostCapabilities(),\n) {\n const plainText = copyableMessageText(content)\n const html = copyableMessageHtml(content)\n if (hostCapabilities) {\n await hostCapabilities.copyToClipboard({\n text: plainText,\n ...(html ? { html } : {}),\n })\n return\n }\n const clipboard = navigator.clipboard\n const ClipboardItemConstructor = globalThis.ClipboardItem\n\n if (clipboard.write && ClipboardItemConstructor && html) {\n await clipboard.write([\n new ClipboardItemConstructor({\n 'text/html': new Blob([html], { type: 'text/html' }),\n 'text/plain': new Blob([plainText], { type: 'text/plain' }),\n }),\n ])\n return\n }\n\n await clipboard.writeText(plainText)\n}\n\nexport async function copyTextToClipboard(\n text: string,\n hostCapabilities: CodexHostCapabilities | undefined = getCodexGlobalHostCapabilities(),\n) {\n if (hostCapabilities) {\n await hostCapabilities.copyToClipboard({ text })\n return\n }\n await navigator.clipboard.writeText(text)\n}\n\nfunction markdownToText(content: string) {\n const html = renderMarkdown(content).replace(breakTagRegex, '\\n')\n const template = document.createElement('template')\n template.innerHTML = html\n const blocks: string[] = []\n template.content.childNodes.forEach((node) => collectTextBlocks(node, blocks))\n return blocks.join('\\n')\n}\n\nfunction collectTextBlocks(node: Node, blocks: string[]) {\n if (node.nodeType === Node.TEXT_NODE) {\n const text = node.textContent!.trim()\n if (text) {\n blocks.push(normalizeText(text))\n }\n return\n }\n\n if (!(node instanceof HTMLElement)) {\n return\n }\n\n const tagName = node.tagName.toLowerCase()\n if (node.classList.contains('katex')) {\n const text = readableInlineText(node).trim()\n if (text) {\n blocks.push(normalizeText(text))\n }\n return\n }\n\n if (tagName === 'pre') {\n const highlightedLines = [...node.querySelectorAll(':scope > code > .line')]\n const text = highlightedLines.map((line) => line.textContent ?? '').join('\\n').trim()\n if (text) {\n blocks.push(normalizeText(text))\n }\n return\n }\n\n if (tagName === 'li' || tagName === 'p' || /^h[1-6]$/.test(tagName)) {\n const text = readableInlineText(node).trim()\n if (text) {\n blocks.push(normalizeText(text))\n }\n return\n }\n\n node.childNodes.forEach((child) => collectTextBlocks(child, blocks))\n}\n\nfunction readableInlineText(node: Node): string {\n if (node.nodeType === Node.TEXT_NODE) {\n return node.textContent!\n }\n if (!(node instanceof HTMLElement)) {\n return ''\n }\n if (node.classList.contains('katex')) {\n return node.querySelector('annotation[encoding=\"application/x-tex\"]')?.textContent ?? ''\n }\n return [...node.childNodes].map(readableInlineText).join('')\n}\n\nfunction normalizeText(text: string) {\n return text\n .replace(/[ \\t]+\\n/g, '\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n}\n","<template>\n <slot v-if=\"block.type === 'user-text'\" name=\"text\" :block=\"block\" :content=\"block.content\" user>\n <ChatUserText\n class=\"chat-message-block chat-message-block--text\"\n :content=\"block.content\"\n :mention-groups=\"mentionGroups\"\n :plugins=\"plugins\"\n :skills=\"skills\"\n >\n <template v-if=\"$slots.mention\" #mention=\"scope\"><slot name=\"mention\" v-bind=\"scope\" /></template>\n </ChatUserText>\n </slot>\n <slot v-else-if=\"block.type === 'text'\" name=\"text\" :block=\"block\" :content=\"block.content\" :user=\"false\">\n <div\n class=\"codex-chat-theme chat-message-block chat-message-block--text codex-markdown\"\n v-html=\"renderedMarkdown\"\n @click=\"copyCodeBlock\"\n />\n </slot>\n <div\n v-else-if=\"block.type === 'reasoning'\"\n class=\"codex-chat-theme chat-message-block chat-message-block--reasoning codex-markdown\"\n v-html=\"renderedMarkdown\"\n @click=\"copyCodeBlock\"\n />\n <slot v-else-if=\"block.type === 'mermaid'\" name=\"mermaid\" :block=\"block\" :code=\"block.code\">\n <ChatMermaidBlock :code=\"block.code\" />\n </slot>\n <slot v-else-if=\"block.type === 'visualization'\" name=\"visualization\" :block=\"block\">\n <ChatVisualizationBlock\n :path=\"block.path\"\n :title=\"block.title\"\n @open-visualization=\"emit('open-visualization', $event)\"\n />\n </slot>\n <slot v-else-if=\"block.type === 'media'\" name=\"media\" :block=\"block\" :media=\"block.media\">\n <ChatMediaBlock :media=\"block.media\" :open-image=\"openImage\" />\n </slot>\n <ChatQuestionRequest\n v-else-if=\"block.type === 'question'\"\n :historical=\"block.historical\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :request=\"block.request\"\n @client-response=\"emit('client-response', $event)\"\n />\n <slot\n v-else-if=\"block.type === 'attachment'\"\n name=\"attachment\"\n :attachment=\"block.attachment\"\n :block=\"block\"\n >\n <ChatAttachmentBlock :attachment=\"block.attachment\" :open-image=\"openImage\" />\n </slot>\n <slot v-else-if=\"block.type === 'tool'\" name=\"tool\" :block=\"block\" :tool-call=\"block.toolCall\">\n <ChatToolCall\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :show-tool-details=\"showToolDetails\"\n :tool-call=\"block.toolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n </slot>\n <slot v-else-if=\"block.type === 'tool-group'\" name=\"tool\" :block=\"block\" :tool-calls=\"block.toolCalls\">\n <ChatToolGroup\n :activity-title=\"block.activityTitle\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :show-tool-details=\"showToolDetails\"\n :tool-calls=\"block.toolCalls\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n </slot>\n <ChatWorkGroup\n v-else-if=\"block.type === 'work-group'\"\n :active=\"block.active\"\n :continuation=\"block.continuation\"\n :final-started=\"block.finalStarted\"\n >\n <template v-for=\"(child, index) in block.blocks\" :key=\"child.type === 'tool' ? child.toolCall.id : `${child.type}-${index}`\">\n <slot name=\"block\" :block=\"child\" :block-index=\"index\">\n <ChatMessageBlock\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :block=\"child\"\n :follow-ups-disabled=\"followUpsDisabled\"\n :mention-groups=\"mentionGroups\"\n :open-image=\"openImage\"\n :plugins=\"plugins\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"skills\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n @open-visualization=\"emit('open-visualization', $event)\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n >\n <template v-if=\"$slots.block\" #block=\"scope\"><slot name=\"block\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.text\" #text=\"scope\"><slot name=\"text\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.tool\" #tool=\"scope\"><slot name=\"tool\" v-bind=\"scope\" /></template>\n </ChatMessageBlock>\n </slot>\n </template>\n </ChatWorkGroup>\n <ChatFollowUps\n v-else-if=\"block.type === 'follow-ups'\"\n :disabled=\"followUpsDisabled\"\n :prompts=\"block.prompts\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount } from 'vue'\nimport ChatAttachmentBlock from './ChatAttachmentBlock.vue'\nimport ChatQuestionRequest from './ChatQuestionRequest.vue'\nimport ChatFollowUps from './ChatFollowUps.vue'\nimport ChatMediaBlock from './ChatMediaBlock.vue'\nimport ChatMermaidBlock from './ChatMermaidBlock.vue'\nimport ChatToolGroup from './ChatToolGroup.vue'\nimport ChatToolCall from './ChatToolCall.vue'\nimport ChatUserText from './ChatUserText.vue'\nimport ChatVisualizationBlock from './ChatVisualizationBlock.vue'\nimport ChatWorkGroup from './ChatWorkGroup.vue'\nimport { renderMarkdown } from './message-markdown'\nimport { copyTextToClipboard } from './message-actions'\nimport { useCodexChatTranslate } from './chat-i18n'\nimport type { MessageBlock, RenderedMessageBlock } from './message-blocks'\nimport type { ClientRequestResponse, CodexConversationLink } from './contracts'\nimport type { CodexSurfacePlugin, CodexSurfaceSkill } from '@codex-app-sdk/core/surface'\nimport type { CodexMessageImageOpenHandler } from './message-image'\nimport type { CodexConversationVisualization } from './visualization'\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from './composer-mentions-custom'\nimport { useCodexHostCapabilities } from '../native-capabilities'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineSlots<{\n block(props: { block: MessageBlock; blockIndex: number }): unknown\n attachment(props: {\n attachment: Extract<MessageBlock, { type: 'attachment' }>['attachment']\n block: Extract<MessageBlock, { type: 'attachment' }>\n }): unknown\n media(props: { block: Extract<MessageBlock, { type: 'media' }>; media: Extract<MessageBlock, { type: 'media' }>['media'] }): unknown\n mermaid(props: { block: Extract<MessageBlock, { type: 'mermaid' }>; code: string }): unknown\n mention(props: { group: CodexComposerMentionGroup; item: CodexComposerMentionItem; surface: 'message' }): unknown\n visualization(props: { block: Extract<MessageBlock, { type: 'visualization' }> }): unknown\n text(props: { block: Extract<MessageBlock, { type: 'text' | 'user-text' }>; content: string; user: boolean }): unknown\n tool(props: {\n block: Extract<MessageBlock, { type: 'tool' | 'tool-group' }>\n toolCall?: Extract<MessageBlock, { type: 'tool' }>['toolCall']\n toolCalls?: Extract<MessageBlock, { type: 'tool-group' }>['toolCalls']\n }): unknown\n}>()\n\nconst props = withDefaults(defineProps<{\n block: RenderedMessageBlock\n answeredClientRequestIds?: ReadonlySet<string>\n followUpsDisabled?: boolean\n mentionGroups?: readonly CodexComposerMentionGroup[]\n openImage?: CodexMessageImageOpenHandler\n plugins?: readonly CodexSurfacePlugin[]\n showToolDetails?: boolean\n skills?: readonly CodexSurfaceSkill[]\n}>(), {\n showToolDetails: undefined,\n})\n\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'open-link': [link: CodexConversationLink]\n 'open-visualization': [visualization: CodexConversationVisualization]\n 'send-follow-up': [prompt: string]\n}>()\n// Stryker restore all\n\nconst t = useCodexChatTranslate()\nconst hostCapabilities = useCodexHostCapabilities()\n// Parents re-render their blocks often (every streamed token re-renders the\n// message list), so parse Markdown only when this block's text changes.\nconst renderedMarkdown = computed(() => (\n props.block.type === 'text' || props.block.type === 'reasoning'\n ? renderMarkdown(props.block.content, { codeCopyLabel: t('chat.code.copy') })\n : ''\n))\nconst copyResetTimers = new Map<HTMLButtonElement, ReturnType<typeof setTimeout>>()\n\nasync function copyCodeBlock(event: MouseEvent) {\n const target = event.target instanceof Element ? event.target : null\n const button = target?.closest<HTMLButtonElement>('[data-chat-code-copy]')\n if (!button) return\n const code = button.closest('.chat-code-block')?.querySelector('pre code')?.textContent\n if (code === undefined) return\n\n await copyTextToClipboard(code, hostCapabilities)\n button.dataset.copied = 'true'\n button.setAttribute('aria-label', t('chat.code.copied'))\n button.title = t('chat.code.copied')\n const previousTimer = copyResetTimers.get(button)\n clearTimeout(previousTimer)\n copyResetTimers.set(button, setTimeout(() => {\n button.removeAttribute('data-copied')\n button.setAttribute('aria-label', t('chat.code.copy'))\n button.title = t('chat.code.copy')\n copyResetTimers.delete(button)\n }, 2_000))\n}\n\nonBeforeUnmount(() => {\n for (const timer of copyResetTimers.values()) clearTimeout(timer)\n copyResetTimers.clear()\n})\n</script>\n\n<style scoped>\n\n.chat-message-block--text {\n white-space: normal;\n overflow-wrap: anywhere;\n}\n\n.chat-message-block--reasoning {\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-light);\n line-height: var(--line-height-20);\n}\n\n</style>\n","<template>\n <slot v-if=\"block.type === 'user-text'\" name=\"text\" :block=\"block\" :content=\"block.content\" user>\n <ChatUserText\n class=\"chat-message-block chat-message-block--text\"\n :content=\"block.content\"\n :mention-groups=\"mentionGroups\"\n :plugins=\"plugins\"\n :skills=\"skills\"\n >\n <template v-if=\"$slots.mention\" #mention=\"scope\"><slot name=\"mention\" v-bind=\"scope\" /></template>\n </ChatUserText>\n </slot>\n <slot v-else-if=\"block.type === 'text'\" name=\"text\" :block=\"block\" :content=\"block.content\" :user=\"false\">\n <div\n class=\"codex-chat-theme chat-message-block chat-message-block--text codex-markdown\"\n v-html=\"renderedMarkdown\"\n @click=\"copyCodeBlock\"\n />\n </slot>\n <div\n v-else-if=\"block.type === 'reasoning'\"\n class=\"codex-chat-theme chat-message-block chat-message-block--reasoning codex-markdown\"\n v-html=\"renderedMarkdown\"\n @click=\"copyCodeBlock\"\n />\n <slot v-else-if=\"block.type === 'mermaid'\" name=\"mermaid\" :block=\"block\" :code=\"block.code\">\n <ChatMermaidBlock :code=\"block.code\" />\n </slot>\n <slot v-else-if=\"block.type === 'visualization'\" name=\"visualization\" :block=\"block\">\n <ChatVisualizationBlock\n :path=\"block.path\"\n :title=\"block.title\"\n @open-visualization=\"emit('open-visualization', $event)\"\n />\n </slot>\n <slot v-else-if=\"block.type === 'media'\" name=\"media\" :block=\"block\" :media=\"block.media\">\n <ChatMediaBlock :media=\"block.media\" :open-image=\"openImage\" />\n </slot>\n <ChatQuestionRequest\n v-else-if=\"block.type === 'question'\"\n :historical=\"block.historical\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :request=\"block.request\"\n @client-response=\"emit('client-response', $event)\"\n />\n <slot\n v-else-if=\"block.type === 'attachment'\"\n name=\"attachment\"\n :attachment=\"block.attachment\"\n :block=\"block\"\n >\n <ChatAttachmentBlock :attachment=\"block.attachment\" :open-image=\"openImage\" />\n </slot>\n <slot v-else-if=\"block.type === 'tool'\" name=\"tool\" :block=\"block\" :tool-call=\"block.toolCall\">\n <ChatToolCall\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :show-tool-details=\"showToolDetails\"\n :tool-call=\"block.toolCall\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n </slot>\n <slot v-else-if=\"block.type === 'tool-group'\" name=\"tool\" :block=\"block\" :tool-calls=\"block.toolCalls\">\n <ChatToolGroup\n :activity-title=\"block.activityTitle\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :show-tool-details=\"showToolDetails\"\n :tool-calls=\"block.toolCalls\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n />\n </slot>\n <ChatWorkGroup\n v-else-if=\"block.type === 'work-group'\"\n :active=\"block.active\"\n :continuation=\"block.continuation\"\n :final-started=\"block.finalStarted\"\n >\n <template v-for=\"(child, index) in block.blocks\" :key=\"child.type === 'tool' ? child.toolCall.id : `${child.type}-${index}`\">\n <slot name=\"block\" :block=\"child\" :block-index=\"index\">\n <ChatMessageBlock\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :block=\"child\"\n :follow-ups-disabled=\"followUpsDisabled\"\n :mention-groups=\"mentionGroups\"\n :open-image=\"openImage\"\n :plugins=\"plugins\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"skills\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n @open-visualization=\"emit('open-visualization', $event)\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n >\n <template v-if=\"$slots.block\" #block=\"scope\"><slot name=\"block\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.text\" #text=\"scope\"><slot name=\"text\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.tool\" #tool=\"scope\"><slot name=\"tool\" v-bind=\"scope\" /></template>\n </ChatMessageBlock>\n </slot>\n </template>\n </ChatWorkGroup>\n <ChatFollowUps\n v-else-if=\"block.type === 'follow-ups'\"\n :disabled=\"followUpsDisabled\"\n :prompts=\"block.prompts\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n />\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount } from 'vue'\nimport ChatAttachmentBlock from './ChatAttachmentBlock.vue'\nimport ChatQuestionRequest from './ChatQuestionRequest.vue'\nimport ChatFollowUps from './ChatFollowUps.vue'\nimport ChatMediaBlock from './ChatMediaBlock.vue'\nimport ChatMermaidBlock from './ChatMermaidBlock.vue'\nimport ChatToolGroup from './ChatToolGroup.vue'\nimport ChatToolCall from './ChatToolCall.vue'\nimport ChatUserText from './ChatUserText.vue'\nimport ChatVisualizationBlock from './ChatVisualizationBlock.vue'\nimport ChatWorkGroup from './ChatWorkGroup.vue'\nimport { renderMarkdown } from './message-markdown'\nimport { copyTextToClipboard } from './message-actions'\nimport { useCodexChatTranslate } from './chat-i18n'\nimport type { MessageBlock, RenderedMessageBlock } from './message-blocks'\nimport type { ClientRequestResponse, CodexConversationLink } from './contracts'\nimport type { CodexSurfacePlugin, CodexSurfaceSkill } from '@codex-app-sdk/core/surface'\nimport type { CodexMessageImageOpenHandler } from './message-image'\nimport type { CodexConversationVisualization } from './visualization'\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from './composer-mentions-custom'\nimport { useCodexHostCapabilities } from '../native-capabilities'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineSlots<{\n block(props: { block: MessageBlock; blockIndex: number }): unknown\n attachment(props: {\n attachment: Extract<MessageBlock, { type: 'attachment' }>['attachment']\n block: Extract<MessageBlock, { type: 'attachment' }>\n }): unknown\n media(props: { block: Extract<MessageBlock, { type: 'media' }>; media: Extract<MessageBlock, { type: 'media' }>['media'] }): unknown\n mermaid(props: { block: Extract<MessageBlock, { type: 'mermaid' }>; code: string }): unknown\n mention(props: { group: CodexComposerMentionGroup; item: CodexComposerMentionItem; surface: 'message' }): unknown\n visualization(props: { block: Extract<MessageBlock, { type: 'visualization' }> }): unknown\n text(props: { block: Extract<MessageBlock, { type: 'text' | 'user-text' }>; content: string; user: boolean }): unknown\n tool(props: {\n block: Extract<MessageBlock, { type: 'tool' | 'tool-group' }>\n toolCall?: Extract<MessageBlock, { type: 'tool' }>['toolCall']\n toolCalls?: Extract<MessageBlock, { type: 'tool-group' }>['toolCalls']\n }): unknown\n}>()\n\nconst props = withDefaults(defineProps<{\n block: RenderedMessageBlock\n answeredClientRequestIds?: ReadonlySet<string>\n followUpsDisabled?: boolean\n mentionGroups?: readonly CodexComposerMentionGroup[]\n openImage?: CodexMessageImageOpenHandler\n plugins?: readonly CodexSurfacePlugin[]\n showToolDetails?: boolean\n skills?: readonly CodexSurfaceSkill[]\n}>(), {\n showToolDetails: undefined,\n})\n\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'open-link': [link: CodexConversationLink]\n 'open-visualization': [visualization: CodexConversationVisualization]\n 'send-follow-up': [prompt: string]\n}>()\n// Stryker restore all\n\nconst t = useCodexChatTranslate()\nconst hostCapabilities = useCodexHostCapabilities()\n// Parents re-render their blocks often (every streamed token re-renders the\n// message list), so parse Markdown only when this block's text changes.\nconst renderedMarkdown = computed(() => (\n props.block.type === 'text' || props.block.type === 'reasoning'\n ? renderMarkdown(props.block.content, { codeCopyLabel: t('chat.code.copy') })\n : ''\n))\nconst copyResetTimers = new Map<HTMLButtonElement, ReturnType<typeof setTimeout>>()\n\nasync function copyCodeBlock(event: MouseEvent) {\n const target = event.target instanceof Element ? event.target : null\n const button = target?.closest<HTMLButtonElement>('[data-chat-code-copy]')\n if (!button) return\n const code = button.closest('.chat-code-block')?.querySelector('pre code')?.textContent\n if (code === undefined) return\n\n await copyTextToClipboard(code, hostCapabilities)\n button.dataset.copied = 'true'\n button.setAttribute('aria-label', t('chat.code.copied'))\n button.title = t('chat.code.copied')\n const previousTimer = copyResetTimers.get(button)\n clearTimeout(previousTimer)\n copyResetTimers.set(button, setTimeout(() => {\n button.removeAttribute('data-copied')\n button.setAttribute('aria-label', t('chat.code.copy'))\n button.title = t('chat.code.copy')\n copyResetTimers.delete(button)\n }, 2_000))\n}\n\nonBeforeUnmount(() => {\n for (const timer of copyResetTimers.values()) clearTimeout(timer)\n copyResetTimers.clear()\n})\n</script>\n\n<style scoped>\n\n.chat-message-block--text {\n white-space: normal;\n overflow-wrap: anywhere;\n}\n\n.chat-message-block--reasoning {\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n font-weight: var(--font-weight-light);\n line-height: var(--line-height-20);\n}\n\n</style>\n","const dayMs = 24 * 60 * 60 * 1000\n\nexport function formatMessageSentAt(value: string, now = new Date()) {\n const sentAt = new Date(value)\n if (Number.isNaN(sentAt.getTime())) {\n return ''\n }\n\n const timeOptions = {\n hour: 'numeric',\n minute: '2-digit',\n } satisfies Intl.DateTimeFormatOptions\n\n if (isSameLocalDay(sentAt, now)) {\n return new Intl.DateTimeFormat(undefined, timeOptions).format(sentAt)\n }\n\n if (sentAt.getTime() < now.getTime() && now.getTime() - sentAt.getTime() < 7 * dayMs) {\n return new Intl.DateTimeFormat(undefined, {\n weekday: 'short',\n ...timeOptions,\n }).format(sentAt)\n }\n\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(sentAt)\n}\n\nexport function fullMessageSentAt(value: string) {\n const sentAt = new Date(value)\n if (Number.isNaN(sentAt.getTime())) {\n return ''\n }\n\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: 'full',\n timeStyle: 'short',\n }).format(sentAt)\n}\n\nfunction isSameLocalDay(left: Date, right: Date) {\n return left.getFullYear() === right.getFullYear() &&\n left.getMonth() === right.getMonth() &&\n left.getDate() === right.getDate()\n}\n","<template>\n <div\n class=\"codex-chat-theme chat-message-actions\"\n :class=\"`chat-message-actions--${message.role}`\"\n :aria-busy=\"deleting ? 'true' : undefined\"\n :aria-label=\"t('chat.actions.label')\"\n >\n <span\n v-if=\"sentAtLabel && message.role === 'user'\"\n class=\"chat-message-actions__sent-at\"\n :title=\"sentAtTitle\"\n >\n {{ sentAtLabel }}\n </span>\n <ChatCopyButton\n v-if=\"showCopy\"\n :action=\"copyMessage\"\n :copied-label=\"t('chat.actions.copied')\"\n :disabled=\"deleting\"\n :label=\"t('chat.actions.copy')\"\n />\n <ChatIconButton\n v-if=\"message.role === 'user' && canEdit && showEdit\"\n :disabled=\"deleting\"\n :label=\"t('chat.actions.edit')\"\n @click=\"emit('edit')\"\n >\n <PencilIcon />\n </ChatIconButton>\n <ChatIconButton\n v-if=\"message.role === 'user' && showQuote\"\n :disabled=\"deleting\"\n :label=\"t('chat.actions.quote')\"\n @click=\"emit('quote')\"\n >\n <QuoteIcon />\n </ChatIconButton>\n <ChatIconButton\n v-if=\"message.role === 'assistant' && canRetry && showRetry\"\n :disabled=\"mutationDisabled || deleting\"\n :label=\"t('chat.actions.retry')\"\n @click=\"emit('retry')\"\n >\n <RotateClockwiseIcon />\n </ChatIconButton>\n <ChatIconButton\n v-if=\"canFork && showFork\"\n :disabled=\"mutationDisabled || deleting\"\n :label=\"t('chat.actions.fork')\"\n @click=\"emit('fork')\"\n >\n <ArrowForkIcon class=\"chat-message-actions__fork-icon\" />\n </ChatIconButton>\n <ChatIconButton\n v-if=\"canDelete && showDelete\"\n danger\n :disabled=\"mutationDisabled || deleting\"\n :label=\"deleting ? t('chat.actions.deleting') : t('chat.actions.delete')\"\n @click=\"emit('delete')\"\n >\n <Loader2Icon v-if=\"deleting\" class=\"chat-message-actions__spinner\" />\n <Trash2Icon v-else />\n </ChatIconButton>\n <span\n v-if=\"sentAtLabel && message.role === 'assistant'\"\n class=\"chat-message-actions__sent-at\"\n :title=\"sentAtTitle\"\n >\n {{ sentAtLabel }}\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ArrowForkIcon, Loader2Icon, PencilIcon, QuoteIcon, RotateClockwiseIcon, Trash2Icon } from '../icons/app-icons'\nimport { computed } from 'vue'\nimport { useCodexChatTranslate } from './chat-i18n'\nimport ChatCopyButton from './ChatCopyButton.vue'\nimport ChatIconButton from './ChatIconButton.vue'\nimport { formatMessageSentAt, fullMessageSentAt } from './message-time'\nimport type { CodexMessageActionsPresentation } from './contracts'\nimport type { Message } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n canDelete?: boolean\n canEdit?: boolean\n canFork?: boolean\n canRetry?: boolean\n copyAction?: () => Promise<void> | void\n deleting?: boolean\n message: Message\n mutationDisabled?: boolean\n presentation?: CodexMessageActionsPresentation\n}>(), {\n canDelete: true,\n canEdit: true,\n canFork: false,\n canRetry: true,\n})\n// Stryker restore all\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n copy: []\n delete: []\n edit: []\n fork: []\n quote: []\n retry: []\n}>()\n// Stryker restore all\nconst t = useCodexChatTranslate()\nconst showCopy = computed(() => props.presentation?.copy !== false)\nconst showDelete = computed(() => props.presentation?.delete !== false)\nconst showEdit = computed(() => props.presentation?.edit !== false)\nconst showFork = computed(() => props.presentation?.fork !== false)\nconst showQuote = computed(() => props.presentation?.quote !== false)\nconst showRetry = computed(() => props.presentation?.retry !== false)\nconst sentAtLabel = computed(() => props.message.createdAt ? formatMessageSentAt(props.message.createdAt) : '')\nconst sentAtTitle = computed(() => props.message.createdAt ? fullMessageSentAt(props.message.createdAt) : undefined)\n\nasync function copyMessage() {\n await props.copyAction?.()\n emit('copy')\n}\n</script>\n\n<style scoped>\n.chat-message-actions {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n padding: var(--space-2) 0;\n}\n\n.chat-message-actions--user {\n justify-content: flex-end;\n}\n\n.chat-message-actions--assistant {\n justify-content: flex-start;\n}\n\n.chat-message-actions__sent-at {\n color: var(--color-outline);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-16);\n white-space: nowrap;\n}\n\n.chat-message-actions__fork-icon {\n transform: rotate(90deg);\n}\n\n.chat-message-actions__spinner {\n animation: chat-message-actions-spin 800ms linear infinite;\n}\n\n@keyframes chat-message-actions-spin {\n to {\n transform: rotate(360deg);\n }\n}\n</style>\n","<template>\n <div\n class=\"codex-chat-theme chat-message-actions\"\n :class=\"`chat-message-actions--${message.role}`\"\n :aria-busy=\"deleting ? 'true' : undefined\"\n :aria-label=\"t('chat.actions.label')\"\n >\n <span\n v-if=\"sentAtLabel && message.role === 'user'\"\n class=\"chat-message-actions__sent-at\"\n :title=\"sentAtTitle\"\n >\n {{ sentAtLabel }}\n </span>\n <ChatCopyButton\n v-if=\"showCopy\"\n :action=\"copyMessage\"\n :copied-label=\"t('chat.actions.copied')\"\n :disabled=\"deleting\"\n :label=\"t('chat.actions.copy')\"\n />\n <ChatIconButton\n v-if=\"message.role === 'user' && canEdit && showEdit\"\n :disabled=\"deleting\"\n :label=\"t('chat.actions.edit')\"\n @click=\"emit('edit')\"\n >\n <PencilIcon />\n </ChatIconButton>\n <ChatIconButton\n v-if=\"message.role === 'user' && showQuote\"\n :disabled=\"deleting\"\n :label=\"t('chat.actions.quote')\"\n @click=\"emit('quote')\"\n >\n <QuoteIcon />\n </ChatIconButton>\n <ChatIconButton\n v-if=\"message.role === 'assistant' && canRetry && showRetry\"\n :disabled=\"mutationDisabled || deleting\"\n :label=\"t('chat.actions.retry')\"\n @click=\"emit('retry')\"\n >\n <RotateClockwiseIcon />\n </ChatIconButton>\n <ChatIconButton\n v-if=\"canFork && showFork\"\n :disabled=\"mutationDisabled || deleting\"\n :label=\"t('chat.actions.fork')\"\n @click=\"emit('fork')\"\n >\n <ArrowForkIcon class=\"chat-message-actions__fork-icon\" />\n </ChatIconButton>\n <ChatIconButton\n v-if=\"canDelete && showDelete\"\n danger\n :disabled=\"mutationDisabled || deleting\"\n :label=\"deleting ? t('chat.actions.deleting') : t('chat.actions.delete')\"\n @click=\"emit('delete')\"\n >\n <Loader2Icon v-if=\"deleting\" class=\"chat-message-actions__spinner\" />\n <Trash2Icon v-else />\n </ChatIconButton>\n <span\n v-if=\"sentAtLabel && message.role === 'assistant'\"\n class=\"chat-message-actions__sent-at\"\n :title=\"sentAtTitle\"\n >\n {{ sentAtLabel }}\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ArrowForkIcon, Loader2Icon, PencilIcon, QuoteIcon, RotateClockwiseIcon, Trash2Icon } from '../icons/app-icons'\nimport { computed } from 'vue'\nimport { useCodexChatTranslate } from './chat-i18n'\nimport ChatCopyButton from './ChatCopyButton.vue'\nimport ChatIconButton from './ChatIconButton.vue'\nimport { formatMessageSentAt, fullMessageSentAt } from './message-time'\nimport type { CodexMessageActionsPresentation } from './contracts'\nimport type { Message } from './types'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n canDelete?: boolean\n canEdit?: boolean\n canFork?: boolean\n canRetry?: boolean\n copyAction?: () => Promise<void> | void\n deleting?: boolean\n message: Message\n mutationDisabled?: boolean\n presentation?: CodexMessageActionsPresentation\n}>(), {\n canDelete: true,\n canEdit: true,\n canFork: false,\n canRetry: true,\n})\n// Stryker restore all\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n copy: []\n delete: []\n edit: []\n fork: []\n quote: []\n retry: []\n}>()\n// Stryker restore all\nconst t = useCodexChatTranslate()\nconst showCopy = computed(() => props.presentation?.copy !== false)\nconst showDelete = computed(() => props.presentation?.delete !== false)\nconst showEdit = computed(() => props.presentation?.edit !== false)\nconst showFork = computed(() => props.presentation?.fork !== false)\nconst showQuote = computed(() => props.presentation?.quote !== false)\nconst showRetry = computed(() => props.presentation?.retry !== false)\nconst sentAtLabel = computed(() => props.message.createdAt ? formatMessageSentAt(props.message.createdAt) : '')\nconst sentAtTitle = computed(() => props.message.createdAt ? fullMessageSentAt(props.message.createdAt) : undefined)\n\nasync function copyMessage() {\n await props.copyAction?.()\n emit('copy')\n}\n</script>\n\n<style scoped>\n.chat-message-actions {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n padding: var(--space-2) 0;\n}\n\n.chat-message-actions--user {\n justify-content: flex-end;\n}\n\n.chat-message-actions--assistant {\n justify-content: flex-start;\n}\n\n.chat-message-actions__sent-at {\n color: var(--color-outline);\n font-size: var(--font-size-12);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-16);\n white-space: nowrap;\n}\n\n.chat-message-actions__fork-icon {\n transform: rotate(90deg);\n}\n\n.chat-message-actions__spinner {\n animation: chat-message-actions-spin 800ms linear infinite;\n}\n\n@keyframes chat-message-actions-spin {\n to {\n transform: rotate(360deg);\n }\n}\n</style>\n","<template>\n <div\n class=\"codex-chat-theme chat-message chat-message--compaction\"\n :class=\"{ 'chat-message--compaction-running': running }\"\n >\n <div class=\"chat-message__compaction-line\" />\n <span class=\"chat-message__compaction-title\" :data-label=\"title\">\n <span\n class=\"chat-message__compaction-label\"\n :class=\"{ 'codex-text-shimmer': running }\"\n >\n {{ title }}\n </span>\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n completedTitle: string\n runningTitle: string\n status?: 'completed' | 'running'\n}>()\n// Stryker restore all\n\nconst running = computed(() => props.status === 'running')\nconst title = computed(() => running.value ? props.runningTitle : props.completedTitle)\n</script>\n\n<style scoped>\n.chat-message {\n display: flex;\n}\n\n.chat-message--compaction {\n position: relative;\n align-items: center;\n justify-content: center;\n min-height: 28px;\n}\n\n.chat-message--compaction-running .chat-message__compaction-line {\n opacity: 0.64;\n}\n\n.chat-message__compaction-line {\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n border-top: 1px solid var(--color-border);\n}\n\n.chat-message__compaction-title {\n z-index: 1;\n display: inline-block;\n padding: 0 var(--space-6);\n background: var(--color-surface-lowest);\n}\n\n.chat-message__compaction-label {\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n}\n</style>\n","<template>\n <div\n class=\"codex-chat-theme chat-message chat-message--compaction\"\n :class=\"{ 'chat-message--compaction-running': running }\"\n >\n <div class=\"chat-message__compaction-line\" />\n <span class=\"chat-message__compaction-title\" :data-label=\"title\">\n <span\n class=\"chat-message__compaction-label\"\n :class=\"{ 'codex-text-shimmer': running }\"\n >\n {{ title }}\n </span>\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n completedTitle: string\n runningTitle: string\n status?: 'completed' | 'running'\n}>()\n// Stryker restore all\n\nconst running = computed(() => props.status === 'running')\nconst title = computed(() => running.value ? props.runningTitle : props.completedTitle)\n</script>\n\n<style scoped>\n.chat-message {\n display: flex;\n}\n\n.chat-message--compaction {\n position: relative;\n align-items: center;\n justify-content: center;\n min-height: 28px;\n}\n\n.chat-message--compaction-running .chat-message__compaction-line {\n opacity: 0.64;\n}\n\n.chat-message__compaction-line {\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n border-top: 1px solid var(--color-border);\n}\n\n.chat-message__compaction-title {\n z-index: 1;\n display: inline-block;\n padding: 0 var(--space-6);\n background: var(--color-surface-lowest);\n}\n\n.chat-message__compaction-label {\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-message__edit-card\">\n <textarea\n ref=\"input\"\n v-model=\"draft\"\n class=\"chat-message__edit-input\"\n :aria-label=\"inputLabel\"\n @keydown.escape.prevent=\"cancel\"\n @keydown.meta.enter.prevent=\"save\"\n @keydown.ctrl.enter.prevent=\"save\"\n />\n <div class=\"chat-message__edit-actions\">\n <button type=\"button\" class=\"chat-message__edit-button\" @click=\"cancel\">\n {{ cancelLabel }}\n </button>\n <button\n type=\"button\"\n class=\"chat-message__edit-button chat-message__edit-button--primary\"\n @click=\"save\"\n >\n {{ saveLabel }}\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n cancelLabel: string\n content: string\n inputLabel: string\n saveLabel: string\n}>()\n// Stryker restore all\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n cancel: []\n save: [content: string]\n}>()\n// Stryker restore all\n\nconst draft = ref(props.content)\nconst input = ref<HTMLTextAreaElement | null>(null)\nlet focusFrame: number | null = null\n\nwatch(() => props.content, (content) => {\n draft.value = content\n})\n\nonMounted(() => {\n focusFrame = requestAnimationFrame(() => {\n const element = input.value!\n element.focus()\n element.setSelectionRange(element.value.length, element.value.length)\n focusFrame = null\n })\n})\n\nonBeforeUnmount(() => {\n if (focusFrame !== null) {\n cancelAnimationFrame(focusFrame)\n }\n})\n\nfunction cancel(): void {\n emit('cancel')\n}\n\nfunction save(): void {\n const content = draft.value.trim()\n if (content) {\n emit('save', content)\n }\n}\n</script>\n\n<style scoped>\n.chat-message__edit-card {\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n box-sizing: border-box;\n width: 100%;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: var(--space-8);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n}\n\n.chat-message__edit-input {\n min-height: calc(var(--line-height-24) * 4);\n width: 100%;\n box-sizing: border-box;\n resize: vertical;\n border: 0;\n padding: 0;\n background: transparent;\n color: var(--color-text);\n font: inherit;\n line-height: var(--line-height-24);\n outline: none;\n}\n\n.chat-message__edit-actions {\n display: flex;\n justify-content: flex-end;\n gap: var(--space-2);\n}\n\n.chat-message__edit-button {\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-6);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n font-size: var(--font-size-13);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-18);\n}\n\n.chat-message__edit-button:hover,\n.chat-message__edit-button:focus-visible {\n background: var(--color-surface-low);\n}\n\n.chat-message__edit-button--primary {\n border-color: var(--color-primary);\n background: var(--color-primary);\n color: var(--color-on-primary);\n}\n\n.chat-message__edit-button--primary:hover,\n.chat-message__edit-button--primary:focus-visible {\n border-color: var(--color-on-primary-container);\n background: var(--color-on-primary-container);\n}\n</style>\n","<template>\n <div class=\"codex-chat-theme chat-message__edit-card\">\n <textarea\n ref=\"input\"\n v-model=\"draft\"\n class=\"chat-message__edit-input\"\n :aria-label=\"inputLabel\"\n @keydown.escape.prevent=\"cancel\"\n @keydown.meta.enter.prevent=\"save\"\n @keydown.ctrl.enter.prevent=\"save\"\n />\n <div class=\"chat-message__edit-actions\">\n <button type=\"button\" class=\"chat-message__edit-button\" @click=\"cancel\">\n {{ cancelLabel }}\n </button>\n <button\n type=\"button\"\n class=\"chat-message__edit-button chat-message__edit-button--primary\"\n @click=\"save\"\n >\n {{ saveLabel }}\n </button>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n cancelLabel: string\n content: string\n inputLabel: string\n saveLabel: string\n}>()\n// Stryker restore all\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst emit = defineEmits<{\n cancel: []\n save: [content: string]\n}>()\n// Stryker restore all\n\nconst draft = ref(props.content)\nconst input = ref<HTMLTextAreaElement | null>(null)\nlet focusFrame: number | null = null\n\nwatch(() => props.content, (content) => {\n draft.value = content\n})\n\nonMounted(() => {\n focusFrame = requestAnimationFrame(() => {\n const element = input.value!\n element.focus()\n element.setSelectionRange(element.value.length, element.value.length)\n focusFrame = null\n })\n})\n\nonBeforeUnmount(() => {\n if (focusFrame !== null) {\n cancelAnimationFrame(focusFrame)\n }\n})\n\nfunction cancel(): void {\n emit('cancel')\n}\n\nfunction save(): void {\n const content = draft.value.trim()\n if (content) {\n emit('save', content)\n }\n}\n</script>\n\n<style scoped>\n.chat-message__edit-card {\n display: flex;\n flex-direction: column;\n gap: var(--space-8);\n box-sizing: border-box;\n width: 100%;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n padding: var(--space-8);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n}\n\n.chat-message__edit-input {\n min-height: calc(var(--line-height-24) * 4);\n width: 100%;\n box-sizing: border-box;\n resize: vertical;\n border: 0;\n padding: 0;\n background: transparent;\n color: var(--color-text);\n font: inherit;\n line-height: var(--line-height-24);\n outline: none;\n}\n\n.chat-message__edit-actions {\n display: flex;\n justify-content: flex-end;\n gap: var(--space-2);\n}\n\n.chat-message__edit-button {\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n padding: var(--space-3) var(--space-6);\n background: var(--color-surface-lowest);\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n font-size: var(--font-size-13);\n font-weight: var(--font-weight-medium);\n line-height: var(--line-height-18);\n}\n\n.chat-message__edit-button:hover,\n.chat-message__edit-button:focus-visible {\n background: var(--color-surface-low);\n}\n\n.chat-message__edit-button--primary {\n border-color: var(--color-primary);\n background: var(--color-primary);\n color: var(--color-on-primary);\n}\n\n.chat-message__edit-button--primary:hover,\n.chat-message__edit-button--primary:focus-visible {\n border-color: var(--color-on-primary-container);\n background: var(--color-on-primary-container);\n}\n</style>\n","<template>\n <ChatCompactionMessage\n v-if=\"chatMessage.type === 'compaction'\"\n class=\"codex-chat-theme\"\n :completed-title=\"t('chat.compaction.completed')\"\n :running-title=\"t('chat.compaction.running')\"\n :status=\"chatMessage.compactionStatus\"\n />\n <!-- <div v-else-if=\"message.type === 'steer'\" class=\"chat-message chat-message--steer\">\n <div class=\"chat-message__steer-line\" />\n <div class=\"chat-message__steer-body\">\n <span class=\"chat-message__steer-title\">Steered conversation</span>\n <span class=\"chat-message__steer-text\">{{ message.content }}</span>\n </div>\n </div> -->\n <div\n v-else-if=\"!hideCollapsedTurnDetail\"\n class=\"codex-chat-theme chat-message\"\n :class=\"[`chat-message--${chatMessage.role}`, {\n 'chat-message--actions-visible': actionsAlwaysVisible && !reserveActionSlot,\n 'chat-message--editing': isEditing,\n }]\"\n >\n <div class=\"chat-message__body\">\n <div v-if=\"$slots.header\" class=\"chat-message--steer chat-message--steer-above\">\n <slot name=\"header\" :index=\"index\" :message=\"chatMessage\" />\n </div>\n <div\n v-if=\"userAttachmentBlocks.length > 0\"\n class=\"chat-message__attachments\"\n aria-label=\"Message attachments\"\n >\n <template\n v-for=\"({ block, blockIndex }) in userAttachmentBlocks\"\n :key=\"`attachment-${blockIndex}`\"\n >\n <slot name=\"block\" :block=\"block\" :block-index=\"blockIndex\" :index=\"index\" :message=\"chatMessage\">\n <ChatMessageBlock :block=\"block\" :open-image=\"openImage\">\n <template v-if=\"$slots.attachment\" #attachment=\"scope\">\n <slot name=\"attachment\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n </ChatMessageBlock>\n </slot>\n </template>\n </div>\n <div v-if=\"isEditing || stackBlocks.length > 0 || showEmptyResponse || showThinkingIndicator || showStreamingDot\" class=\"chat-message__stack\">\n <ChatMessageEditor\n v-if=\"isEditing\"\n :cancel-label=\"t('chat.actions.cancel')\"\n :content=\"visibleUserContent\"\n :input-label=\"t('chat.actions.editPrompt')\"\n :save-label=\"t('chat.actions.resubmit')\"\n @cancel=\"cancelEdit\"\n @save=\"saveEdit\"\n />\n <template v-else>\n <template v-for=\"({ block, blockIndex }) in stackBlocks\" :key=\"block.type === 'tool' ? block.toolCall.id : `${block.type}-${blockIndex}`\">\n <ChatMessageBlock\n v-if=\"block.type === 'work-group'\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :block=\"block\"\n :follow-ups-disabled=\"followUpsDisabled\"\n :mention-groups=\"mentionGroups\"\n :plugins=\"plugins\"\n :open-image=\"openImage\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"skills\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n @open-visualization=\"emit('open-visualization', $event)\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n >\n <template v-if=\"$slots.block\" #block=\"scope\">\n <slot name=\"block\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.text\" #text=\"scope\">\n <slot name=\"text\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.tool\" #tool=\"scope\">\n <slot name=\"tool\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n </ChatMessageBlock>\n <slot v-else name=\"block\" :block=\"block\" :block-index=\"blockIndex\" :index=\"index\" :message=\"chatMessage\">\n <ChatMessageBlock\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :block=\"block\"\n :follow-ups-disabled=\"followUpsDisabled\"\n :mention-groups=\"mentionGroups\"\n :plugins=\"plugins\"\n :open-image=\"openImage\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"skills\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n @open-visualization=\"emit('open-visualization', $event)\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n >\n <template v-if=\"$slots.attachment\" #attachment=\"scope\">\n <slot name=\"attachment\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.text\" #text=\"scope\">\n <slot name=\"text\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.mention\" #mention=\"scope\">\n <slot name=\"mention\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.tool\" #tool=\"scope\">\n <slot name=\"tool\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n </ChatMessageBlock>\n </slot>\n </template>\n <span v-if=\"showEmptyResponse\" class=\"chat-message__empty-response\">\n {{ t('chat.message.emptyResponse') }}\n </span>\n <slot v-if=\"showThinkingIndicator\" name=\"thinking\" :index=\"index\" :message=\"chatMessage\">\n <span\n class=\"chat-message__thinking codex-text-shimmer\"\n :data-label=\"activityLabel\"\n >\n {{ activityLabel }}\n </span>\n </slot>\n <slot v-else-if=\"showStreamingDot\" name=\"status\" :index=\"index\" :message=\"chatMessage\" status=\"streaming\">\n <span\n class=\"chat-message__stream-dot\"\n aria-label=\"Streaming\"\n />\n </slot>\n </template>\n </div>\n <slot\n v-if=\"renderActionSlot\"\n name=\"actions\"\n :disabled=\"reserveActionSlot\"\n :index=\"index\"\n :message=\"chatMessage\"\n >\n <ChatMessageActions\n class=\"chat-message__actions\"\n :class=\"{ 'chat-message__actions--reserved': reserveActionSlot }\"\n :aria-hidden=\"reserveActionSlot ? 'true' : undefined\"\n :inert=\"reserveActionSlot ? '' : undefined\"\n :can-delete=\"canDelete\"\n :can-edit=\"canEdit\"\n :can-fork=\"canFork\"\n :can-retry=\"canRetry\"\n :copy-action=\"copyMessage\"\n :deleting=\"deletingTurn\"\n :message=\"chatMessage\"\n :mutation-disabled=\"threadActionsDisabled\"\n :presentation=\"effectivePresentation.messages.actions\"\n @copy=\"emit('copy-message', index)\"\n @delete=\"deleteTurn\"\n @edit=\"startEdit\"\n @fork=\"forkTurn\"\n @quote=\"emit('quote-message', index)\"\n @retry=\"retryTurn\"\n />\n </slot>\n <div v-if=\"chatMessage.type === 'steer'\" class=\"chat-message--steer chat-message--steer-below\">\n Steered conversation\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, provide, ref, shallowReactive } from 'vue'\nimport { questionResponsesKey } from '../chat/message-work-state'\nimport { useCodexChatTranslate } from '../chat/chat-i18n'\nimport type { ClientRequestResponse, CodexConversationLink, CodexConversationPresentation } from '../chat/contracts'\nimport { resolveCodexConversationPresentation } from '../chat/contracts'\nimport type { Message } from '../chat/types'\nimport type { CodexSurfacePlugin, CodexSurfaceSkill, SurfaceMessage } from '@codex-app-sdk/core/surface'\nimport type { MessageBlock, RenderedMessageBlock } from '../chat/message-blocks'\nimport type {\n CodexMessageImage,\n CodexMessageImageContext,\n CodexMessageImageOpenHandler,\n} from '../chat/message-image'\nimport type { CodexConversationVisualization } from '../chat/visualization'\nimport ChatMessageBlock from '../chat/ChatMessageBlock.vue'\nimport ChatMessageActions from '../chat/ChatMessageActions.vue'\nimport ChatCompactionMessage from '../chat/ChatCompactionMessage.vue'\nimport ChatMessageEditor from '../chat/ChatMessageEditor.vue'\nimport { computeMessageBlocks, groupAssistantWorkBlocks, stripMessageContext } from '../chat/message-blocks'\nimport { copyMessageToClipboard } from '../chat/message-actions'\nimport { chatMessageFromInput } from '../chat/renderer-message-adapter'\nimport { assistantWorkMessageIndexKey, assistantWorkTurnKey } from '../chat/message-work-state'\nimport { useCodexHostCapabilities } from '../native-capabilities'\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from '../chat/composer-mentions-custom'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n activityState?: 'working'\n actionsDisabled?: boolean\n actionsAlwaysVisible?: boolean\n answeredClientRequestIds?: ReadonlySet<string>\n canDeleteTurn?: boolean\n canEditTurn?: boolean\n canForkTurn?: boolean\n canRetryTurn?: boolean\n deletingTurn?: boolean\n followUpsDisabled?: boolean\n hiddenClientRequestIds?: ReadonlySet<string>\n index?: number\n message: Message | SurfaceMessage\n mentionGroups?: readonly CodexComposerMentionGroup[]\n openImage?: CodexMessageImageOpenHandler\n plugins?: readonly CodexSurfacePlugin[]\n presentation?: CodexConversationPresentation\n showToolDetails?: boolean\n skills?: readonly CodexSurfaceSkill[]\n threadActionsDisabled?: boolean\n}>(), {\n canDeleteTurn: true,\n canEditTurn: true,\n canForkTurn: false,\n canRetryTurn: true,\n index: 0,\n showToolDetails: undefined,\n})\n\ndefineSlots<{\n actions(props: { disabled: boolean; index: number; message: Message }): unknown\n header(props: { index: number; message: Message }): unknown\n mention(props: { group: CodexComposerMentionGroup; index: number; item: CodexComposerMentionItem; message: Message; surface: 'message' }): unknown\n attachment(props: {\n attachment: Extract<MessageBlock, { type: 'attachment' }>['attachment']\n block: Extract<MessageBlock, { type: 'attachment' }>\n index: number\n message: Message\n }): unknown\n block(props: { block: MessageBlock; blockIndex: number; index: number; message: Message }): unknown\n status(props: { index: number; message: Message; status: 'streaming' }): unknown\n text(props: { block: Extract<MessageBlock, { type: 'text' | 'user-text' }>; content: string; index: number; message: Message; user: boolean }): unknown\n thinking(props: { index: number; message: Message }): unknown\n tool(props: {\n block: Extract<MessageBlock, { type: 'tool' | 'tool-group' }>\n index: number\n message: Message\n toolCall?: Extract<MessageBlock, { type: 'tool' }>['toolCall']\n toolCalls?: Extract<MessageBlock, { type: 'tool-group' }>['toolCalls']\n }): unknown\n}>()\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'open-link': [link: CodexConversationLink]\n 'open-visualization': [visualization: CodexConversationVisualization]\n 'copy-message': [index: number]\n 'delete-turn': [turnId: string]\n 'edit-turn': [payload: { content: string; turnId: string }]\n 'fork-turn': [turnId: string]\n 'quote-message': [index: number]\n 'retry-turn': [turnId: string]\n 'send-follow-up': [prompt: string]\n}>()\n// Stryker restore all\n\nconst hostCapabilities = useCodexHostCapabilities()\n\nconst t = useCodexChatTranslate()\nconst activityLabel = computed(() => props.activityState === 'working' ? t('chat.work.working') : 'Thinking')\nconst chatMessage = computed(() => chatMessageFromInput(props.message))\nconst assistantWorkTurn = inject(assistantWorkTurnKey, undefined)\nprovide(assistantWorkMessageIndexKey, computed(() => props.index))\nconst messageTurnState = computed(() => (\n chatMessage.value.turnId === assistantWorkTurn?.turnId.value\n ? assistantWorkTurn\n : undefined\n))\nconst workTurnState = computed(() => (\n messageTurnState.value?.enabled.value\n ? messageTurnState.value\n : undefined\n))\nconst workActive = computed(() => {\n return workTurnState.value?.active.value\n})\nconst effectivePresentation = computed(() => resolveCodexConversationPresentation(props.presentation))\nprovide(questionResponsesKey, inject(questionResponsesKey, undefined) ?? shallowReactive(new Map()))\nconst allBlocks = computed(() => computeMessageBlocks(chatMessage.value))\nconst visibleBlocks = computed(() => allBlocks.value.filter((block) => (\n (block.type !== 'question' || !props.hiddenClientRequestIds?.has(block.request.id))\n && (effectivePresentation.value.messages.toolBlocks || (block.type !== 'tool' && block.type !== 'tool-group'))\n)))\nconst groupWork = computed(() => {\n const state = workTurnState.value\n if (!state) return undefined\n const onlyStructuredWork = allBlocks.value.length > 0 && allBlocks.value.every((block) => (\n block.type === 'tool' || block.type === 'tool-group'\n ))\n return state.phased.value || (state.active.value && onlyStructuredWork)\n})\nconst blocks = computed(() => groupAssistantWorkBlocks(\n chatMessage.value,\n visibleBlocks.value,\n workActive.value,\n groupWork.value,\n props.answeredClientRequestIds,\n))\nconst assistantWithoutMessageActions = computed(() => (\n chatMessage.value.role === 'assistant'\n && blocks.value.length > 0\n && blocks.value.every((block) => block.type === 'work-group' || block.type === 'media')\n))\nconst hideCollapsedTurnDetail = computed(() => {\n if (\n chatMessage.value.role === 'assistant'\n && chatMessage.value.streaming !== true\n && allBlocks.value.length > 0\n && visibleBlocks.value.length === 0\n ) return true\n const state = messageTurnState.value\n if (!state?.enabled.value || state.active.value) return false\n if (state.completedWithoutFinal.value) return chatMessage.value.type === 'steer'\n if (state.expanded.value) return false\n if (chatMessage.value.type === 'steer') return true\n return chatMessage.value.role === 'assistant'\n && state.headerMessageIndex.value !== props.index\n && blocks.value.every((block) => block.type === 'work-group')\n})\nconst indexedBlocks = computed(() => blocks.value.map((block, blockIndex) => ({ block, blockIndex })))\nconst indexedAllBlocks = computed(() => allBlocks.value.map((block, blockIndex) => ({ block, blockIndex })))\nconst userAttachmentBlocks = computed(() => (\n chatMessage.value.role === 'user'\n ? indexedAllBlocks.value.filter(({ block }) => block.type === 'attachment')\n : []\n))\nconst stackBlocks = computed(() => (\n chatMessage.value.role === 'user'\n ? indexedAllBlocks.value.filter(({ block }) => block.type !== 'attachment')\n : indexedBlocks.value\n))\nconst visibleUserContent = computed(() => stripMessageContext(chatMessage.value.content))\nconst isEditing = ref(false)\n\nconst showActions = computed(() => (\n chatMessage.value.type !== 'compaction' &&\n chatMessage.value.type !== 'steer' &&\n !assistantWithoutMessageActions.value &&\n !isEditing.value\n))\nconst reserveActionSlot = computed(() => (\n props.actionsDisabled ||\n (chatMessage.value.role === 'assistant' && chatMessage.value.streaming === true)\n))\nconst renderActionSlot = computed(() => showActions.value)\nconst canDelete = computed(() => Boolean(chatMessage.value.turnId) && props.canDeleteTurn && effectivePresentation.value.messages.actions.delete)\nconst canEdit = computed(() => Boolean(chatMessage.value.turnId) && props.canEditTurn && effectivePresentation.value.messages.actions.edit)\nconst canFork = computed(() => Boolean(chatMessage.value.turnId) && props.canForkTurn && effectivePresentation.value.messages.actions.fork)\nconst canRetry = computed(() => Boolean(chatMessage.value.turnId) && props.canRetryTurn && effectivePresentation.value.messages.actions.retry)\nconst hasVisibleAssistantActivity = computed(() => blocks.value.some(isVisibleAssistantBlock))\nconst isLatestStreamingAssistantSegment = computed(() => (\n messageTurnState.value?.latestStreamingAssistantIndex.value === undefined\n || messageTurnState.value.latestStreamingAssistantIndex.value === props.index\n))\nconst showEmptyResponse = computed(() => (\n chatMessage.value.role === 'assistant' &&\n chatMessage.value.streaming !== true &&\n allBlocks.value.length === 0\n))\nconst showThinkingIndicator = computed(() => (\n chatMessage.value.role === 'assistant' &&\n chatMessage.value.streaming === true &&\n isLatestStreamingAssistantSegment.value &&\n !hasVisibleAssistantActivity.value\n))\nconst showStreamingDot = computed(() => (\n chatMessage.value.role === 'assistant' &&\n chatMessage.value.streaming === true &&\n isLatestStreamingAssistantSegment.value &&\n hasVisibleAssistantActivity.value\n))\nfunction startEdit() {\n if (chatMessage.value.role !== 'user' || !canEdit.value) {\n return\n }\n\n isEditing.value = true\n}\n\nfunction cancelEdit() {\n isEditing.value = false\n}\n\nfunction saveEdit(content: string) {\n const turnId = chatMessage.value.turnId\n if (!turnId) return\n emit('edit-turn', { content, turnId })\n cancelEdit()\n}\n\nfunction deleteTurn() {\n if (!canDelete.value || props.threadActionsDisabled) {\n return\n }\n\n const turnId = chatMessage.value.turnId\n if (turnId) emit('delete-turn', turnId)\n}\n\nfunction forkTurn() {\n if (!canFork.value || props.threadActionsDisabled) return\n const turnId = chatMessage.value.turnId\n if (turnId) emit('fork-turn', turnId)\n}\n\nfunction retryTurn() {\n if (!canRetry.value || props.threadActionsDisabled) {\n return\n }\n\n const turnId = chatMessage.value.turnId\n if (turnId) emit('retry-turn', turnId)\n}\n\nfunction openImage(image: CodexMessageImage, context?: CodexMessageImageContext) {\n return props.openImage?.(image, {\n index: props.index,\n intent: context?.intent ?? 'open',\n message: chatMessage.value,\n })\n}\n\nasync function copyMessage() {\n await copyMessageToClipboard(chatMessage.value.content, hostCapabilities)\n}\n\nfunction isVisibleAssistantBlock(block: RenderedMessageBlock) {\n if (block.type === 'text') {\n return block.content.trim().length > 0\n }\n\n return block.type === 'attachment'\n || block.type === 'media'\n || block.type === 'mermaid'\n || block.type === 'reasoning'\n || block.type === 'tool'\n || block.type === 'tool-group'\n || block.type === 'visualization'\n || block.type === 'work-group'\n}\n\n</script>\n\n<style scoped>\n.chat-message {\n display: flex;\n}\n\n.chat-message--user {\n justify-content: flex-end;\n}\n\n.chat-message--user :deep(.chat-user-text__mention) {\n padding: var(--space-2);\n background: transparent;\n}\n\n.chat-message--assistant {\n justify-content: flex-start;\n}\n\n.chat-message--steer {\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n}\n\n.chat-message--steer-above {\n margin-bottom: var(--space-1);\n}\n\n.chat-message--steer-below {\n margin-top: var(--space-1);\n}\n\n.chat-message__steer-line {\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n border-top: 1px solid var(--color-border);\n}\n\n.chat-message__steer-body {\n z-index: 1;\n display: inline-flex;\n max-width: min(100%, 640px);\n align-items: baseline;\n gap: var(--space-4);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n padding: var(--space-2) var(--space-6);\n background: var(--color-surface-lowest);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n}\n\n.chat-message__steer-title {\n flex: 0 0 auto;\n color: var(--color-text);\n font-weight: var(--font-weight-medium);\n}\n\n.chat-message__steer-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-message__body {\n flex: 1;\n display: flex;\n flex-direction: column;\n max-width: 100%;\n}\n\n.chat-message--user .chat-message__body {\n align-items: flex-end;\n max-width: 70%;\n}\n\n.chat-message--assistant .chat-message__body {\n align-items: flex-start;\n}\n\n.chat-message--editing .chat-message__body {\n max-width: unset;\n}\n\n.chat-message__stack {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n max-width: 100%;\n}\n\n.chat-message__empty-response {\n color: var(--color-text-muted);\n font-style: italic;\n}\n\n.chat-message__attachments {\n display: flex;\n max-width: 100%;\n align-items: flex-start;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: var(--space-4);\n margin-bottom: var(--space-3);\n}\n\n.chat-message--assistant .chat-message__stack {\n width: 100%;\n}\n\n.chat-message--user .chat-message__stack {\n background: var(--color-shell-sidebar);\n border-radius: var(--radius-xl);\n}\n\n.chat-message--editing .chat-message__stack {\n width: 100%;\n background: transparent;\n border-radius: 0;\n}\n\n.chat-message__actions {\n visibility: hidden;\n}\n\n.chat-message--actions-visible .chat-message__actions {\n visibility: visible;\n}\n\n.chat-message__actions--reserved {\n pointer-events: none;\n}\n\n.chat-message:hover .chat-message__actions,\n.chat-message:focus-within .chat-message__actions {\n visibility: visible;\n}\n\n.chat-message:hover .chat-message__actions--reserved,\n.chat-message:focus-within .chat-message__actions--reserved {\n visibility: hidden;\n}\n\n.chat-message__thinking {\n align-self: flex-start;\n overflow: hidden;\n padding: var(--space-3) 0;\n font-size: var(--chat-message-font-size, var(--font-size-15));\n font-weight: var(--font-weight-light);\n line-height: var(--chat-message-line-height, var(--line-height-20));\n}\n\n.chat-message__stream-dot {\n display: block;\n width: var(--space-4);\n height: var(--space-4);\n align-self: flex-start;\n margin-top: var(--space-1);\n border-radius: 999px;\n background: var(--color-text-muted);\n transform-origin: 50% 50%;\n animation: chat-message-stream-dot 1.15s ease-in-out infinite;\n}\n\n@keyframes chat-message-stream-dot {\n 0%,\n 100% {\n border-radius: 999px;\n opacity: 0.48;\n transform: rotate(0deg) scale(0.72);\n }\n\n 50% {\n border-radius: var(--radius-xs);\n opacity: 1;\n transform: rotate(180deg) scale(1);\n }\n\n 75% {\n border-radius: var(--radius-sm);\n transform: rotate(270deg) scale(0.86);\n }\n}\n</style>\n","<template>\n <ChatCompactionMessage\n v-if=\"chatMessage.type === 'compaction'\"\n class=\"codex-chat-theme\"\n :completed-title=\"t('chat.compaction.completed')\"\n :running-title=\"t('chat.compaction.running')\"\n :status=\"chatMessage.compactionStatus\"\n />\n <!-- <div v-else-if=\"message.type === 'steer'\" class=\"chat-message chat-message--steer\">\n <div class=\"chat-message__steer-line\" />\n <div class=\"chat-message__steer-body\">\n <span class=\"chat-message__steer-title\">Steered conversation</span>\n <span class=\"chat-message__steer-text\">{{ message.content }}</span>\n </div>\n </div> -->\n <div\n v-else-if=\"!hideCollapsedTurnDetail\"\n class=\"codex-chat-theme chat-message\"\n :class=\"[`chat-message--${chatMessage.role}`, {\n 'chat-message--actions-visible': actionsAlwaysVisible && !reserveActionSlot,\n 'chat-message--editing': isEditing,\n }]\"\n >\n <div class=\"chat-message__body\">\n <div v-if=\"$slots.header\" class=\"chat-message--steer chat-message--steer-above\">\n <slot name=\"header\" :index=\"index\" :message=\"chatMessage\" />\n </div>\n <div\n v-if=\"userAttachmentBlocks.length > 0\"\n class=\"chat-message__attachments\"\n aria-label=\"Message attachments\"\n >\n <template\n v-for=\"({ block, blockIndex }) in userAttachmentBlocks\"\n :key=\"`attachment-${blockIndex}`\"\n >\n <slot name=\"block\" :block=\"block\" :block-index=\"blockIndex\" :index=\"index\" :message=\"chatMessage\">\n <ChatMessageBlock :block=\"block\" :open-image=\"openImage\">\n <template v-if=\"$slots.attachment\" #attachment=\"scope\">\n <slot name=\"attachment\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n </ChatMessageBlock>\n </slot>\n </template>\n </div>\n <div v-if=\"isEditing || stackBlocks.length > 0 || showEmptyResponse || showThinkingIndicator || showStreamingDot\" class=\"chat-message__stack\">\n <ChatMessageEditor\n v-if=\"isEditing\"\n :cancel-label=\"t('chat.actions.cancel')\"\n :content=\"visibleUserContent\"\n :input-label=\"t('chat.actions.editPrompt')\"\n :save-label=\"t('chat.actions.resubmit')\"\n @cancel=\"cancelEdit\"\n @save=\"saveEdit\"\n />\n <template v-else>\n <template v-for=\"({ block, blockIndex }) in stackBlocks\" :key=\"block.type === 'tool' ? block.toolCall.id : `${block.type}-${blockIndex}`\">\n <ChatMessageBlock\n v-if=\"block.type === 'work-group'\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :block=\"block\"\n :follow-ups-disabled=\"followUpsDisabled\"\n :mention-groups=\"mentionGroups\"\n :plugins=\"plugins\"\n :open-image=\"openImage\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"skills\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n @open-visualization=\"emit('open-visualization', $event)\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n >\n <template v-if=\"$slots.block\" #block=\"scope\">\n <slot name=\"block\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.text\" #text=\"scope\">\n <slot name=\"text\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.tool\" #tool=\"scope\">\n <slot name=\"tool\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n </ChatMessageBlock>\n <slot v-else name=\"block\" :block=\"block\" :block-index=\"blockIndex\" :index=\"index\" :message=\"chatMessage\">\n <ChatMessageBlock\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :block=\"block\"\n :follow-ups-disabled=\"followUpsDisabled\"\n :mention-groups=\"mentionGroups\"\n :plugins=\"plugins\"\n :open-image=\"openImage\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"skills\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @open-link=\"emit('open-link', $event)\"\n @open-visualization=\"emit('open-visualization', $event)\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n >\n <template v-if=\"$slots.attachment\" #attachment=\"scope\">\n <slot name=\"attachment\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.text\" #text=\"scope\">\n <slot name=\"text\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.mention\" #mention=\"scope\">\n <slot name=\"mention\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n <template v-if=\"$slots.tool\" #tool=\"scope\">\n <slot name=\"tool\" v-bind=\"scope\" :index=\"index\" :message=\"chatMessage\" />\n </template>\n </ChatMessageBlock>\n </slot>\n </template>\n <span v-if=\"showEmptyResponse\" class=\"chat-message__empty-response\">\n {{ t('chat.message.emptyResponse') }}\n </span>\n <slot v-if=\"showThinkingIndicator\" name=\"thinking\" :index=\"index\" :message=\"chatMessage\">\n <span\n class=\"chat-message__thinking codex-text-shimmer\"\n :data-label=\"activityLabel\"\n >\n {{ activityLabel }}\n </span>\n </slot>\n <slot v-else-if=\"showStreamingDot\" name=\"status\" :index=\"index\" :message=\"chatMessage\" status=\"streaming\">\n <span\n class=\"chat-message__stream-dot\"\n aria-label=\"Streaming\"\n />\n </slot>\n </template>\n </div>\n <slot\n v-if=\"renderActionSlot\"\n name=\"actions\"\n :disabled=\"reserveActionSlot\"\n :index=\"index\"\n :message=\"chatMessage\"\n >\n <ChatMessageActions\n class=\"chat-message__actions\"\n :class=\"{ 'chat-message__actions--reserved': reserveActionSlot }\"\n :aria-hidden=\"reserveActionSlot ? 'true' : undefined\"\n :inert=\"reserveActionSlot ? '' : undefined\"\n :can-delete=\"canDelete\"\n :can-edit=\"canEdit\"\n :can-fork=\"canFork\"\n :can-retry=\"canRetry\"\n :copy-action=\"copyMessage\"\n :deleting=\"deletingTurn\"\n :message=\"chatMessage\"\n :mutation-disabled=\"threadActionsDisabled\"\n :presentation=\"effectivePresentation.messages.actions\"\n @copy=\"emit('copy-message', index)\"\n @delete=\"deleteTurn\"\n @edit=\"startEdit\"\n @fork=\"forkTurn\"\n @quote=\"emit('quote-message', index)\"\n @retry=\"retryTurn\"\n />\n </slot>\n <div v-if=\"chatMessage.type === 'steer'\" class=\"chat-message--steer chat-message--steer-below\">\n Steered conversation\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, provide, ref, shallowReactive } from 'vue'\nimport { questionResponsesKey } from '../chat/message-work-state'\nimport { useCodexChatTranslate } from '../chat/chat-i18n'\nimport type { ClientRequestResponse, CodexConversationLink, CodexConversationPresentation } from '../chat/contracts'\nimport { resolveCodexConversationPresentation } from '../chat/contracts'\nimport type { Message } from '../chat/types'\nimport type { CodexSurfacePlugin, CodexSurfaceSkill, SurfaceMessage } from '@codex-app-sdk/core/surface'\nimport type { MessageBlock, RenderedMessageBlock } from '../chat/message-blocks'\nimport type {\n CodexMessageImage,\n CodexMessageImageContext,\n CodexMessageImageOpenHandler,\n} from '../chat/message-image'\nimport type { CodexConversationVisualization } from '../chat/visualization'\nimport ChatMessageBlock from '../chat/ChatMessageBlock.vue'\nimport ChatMessageActions from '../chat/ChatMessageActions.vue'\nimport ChatCompactionMessage from '../chat/ChatCompactionMessage.vue'\nimport ChatMessageEditor from '../chat/ChatMessageEditor.vue'\nimport { computeMessageBlocks, groupAssistantWorkBlocks, stripMessageContext } from '../chat/message-blocks'\nimport { copyMessageToClipboard } from '../chat/message-actions'\nimport { chatMessageFromInput } from '../chat/renderer-message-adapter'\nimport { assistantWorkMessageIndexKey, assistantWorkTurnKey } from '../chat/message-work-state'\nimport { useCodexHostCapabilities } from '../native-capabilities'\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from '../chat/composer-mentions-custom'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n activityState?: 'working'\n actionsDisabled?: boolean\n actionsAlwaysVisible?: boolean\n answeredClientRequestIds?: ReadonlySet<string>\n canDeleteTurn?: boolean\n canEditTurn?: boolean\n canForkTurn?: boolean\n canRetryTurn?: boolean\n deletingTurn?: boolean\n followUpsDisabled?: boolean\n hiddenClientRequestIds?: ReadonlySet<string>\n index?: number\n message: Message | SurfaceMessage\n mentionGroups?: readonly CodexComposerMentionGroup[]\n openImage?: CodexMessageImageOpenHandler\n plugins?: readonly CodexSurfacePlugin[]\n presentation?: CodexConversationPresentation\n showToolDetails?: boolean\n skills?: readonly CodexSurfaceSkill[]\n threadActionsDisabled?: boolean\n}>(), {\n canDeleteTurn: true,\n canEditTurn: true,\n canForkTurn: false,\n canRetryTurn: true,\n index: 0,\n showToolDetails: undefined,\n})\n\ndefineSlots<{\n actions(props: { disabled: boolean; index: number; message: Message }): unknown\n header(props: { index: number; message: Message }): unknown\n mention(props: { group: CodexComposerMentionGroup; index: number; item: CodexComposerMentionItem; message: Message; surface: 'message' }): unknown\n attachment(props: {\n attachment: Extract<MessageBlock, { type: 'attachment' }>['attachment']\n block: Extract<MessageBlock, { type: 'attachment' }>\n index: number\n message: Message\n }): unknown\n block(props: { block: MessageBlock; blockIndex: number; index: number; message: Message }): unknown\n status(props: { index: number; message: Message; status: 'streaming' }): unknown\n text(props: { block: Extract<MessageBlock, { type: 'text' | 'user-text' }>; content: string; index: number; message: Message; user: boolean }): unknown\n thinking(props: { index: number; message: Message }): unknown\n tool(props: {\n block: Extract<MessageBlock, { type: 'tool' | 'tool-group' }>\n index: number\n message: Message\n toolCall?: Extract<MessageBlock, { type: 'tool' }>['toolCall']\n toolCalls?: Extract<MessageBlock, { type: 'tool-group' }>['toolCalls']\n }): unknown\n}>()\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'open-link': [link: CodexConversationLink]\n 'open-visualization': [visualization: CodexConversationVisualization]\n 'copy-message': [index: number]\n 'delete-turn': [turnId: string]\n 'edit-turn': [payload: { content: string; turnId: string }]\n 'fork-turn': [turnId: string]\n 'quote-message': [index: number]\n 'retry-turn': [turnId: string]\n 'send-follow-up': [prompt: string]\n}>()\n// Stryker restore all\n\nconst hostCapabilities = useCodexHostCapabilities()\n\nconst t = useCodexChatTranslate()\nconst activityLabel = computed(() => props.activityState === 'working' ? t('chat.work.working') : 'Thinking')\nconst chatMessage = computed(() => chatMessageFromInput(props.message))\nconst assistantWorkTurn = inject(assistantWorkTurnKey, undefined)\nprovide(assistantWorkMessageIndexKey, computed(() => props.index))\nconst messageTurnState = computed(() => (\n chatMessage.value.turnId === assistantWorkTurn?.turnId.value\n ? assistantWorkTurn\n : undefined\n))\nconst workTurnState = computed(() => (\n messageTurnState.value?.enabled.value\n ? messageTurnState.value\n : undefined\n))\nconst workActive = computed(() => {\n return workTurnState.value?.active.value\n})\nconst effectivePresentation = computed(() => resolveCodexConversationPresentation(props.presentation))\nprovide(questionResponsesKey, inject(questionResponsesKey, undefined) ?? shallowReactive(new Map()))\nconst allBlocks = computed(() => computeMessageBlocks(chatMessage.value))\nconst visibleBlocks = computed(() => allBlocks.value.filter((block) => (\n (block.type !== 'question' || !props.hiddenClientRequestIds?.has(block.request.id))\n && (effectivePresentation.value.messages.toolBlocks || (block.type !== 'tool' && block.type !== 'tool-group'))\n)))\nconst groupWork = computed(() => {\n const state = workTurnState.value\n if (!state) return undefined\n const onlyStructuredWork = allBlocks.value.length > 0 && allBlocks.value.every((block) => (\n block.type === 'tool' || block.type === 'tool-group'\n ))\n return state.phased.value || (state.active.value && onlyStructuredWork)\n})\nconst blocks = computed(() => groupAssistantWorkBlocks(\n chatMessage.value,\n visibleBlocks.value,\n workActive.value,\n groupWork.value,\n props.answeredClientRequestIds,\n))\nconst assistantWithoutMessageActions = computed(() => (\n chatMessage.value.role === 'assistant'\n && blocks.value.length > 0\n && blocks.value.every((block) => block.type === 'work-group' || block.type === 'media')\n))\nconst hideCollapsedTurnDetail = computed(() => {\n if (\n chatMessage.value.role === 'assistant'\n && chatMessage.value.streaming !== true\n && allBlocks.value.length > 0\n && visibleBlocks.value.length === 0\n ) return true\n const state = messageTurnState.value\n if (!state?.enabled.value || state.active.value) return false\n if (state.completedWithoutFinal.value) return chatMessage.value.type === 'steer'\n if (state.expanded.value) return false\n if (chatMessage.value.type === 'steer') return true\n return chatMessage.value.role === 'assistant'\n && state.headerMessageIndex.value !== props.index\n && blocks.value.every((block) => block.type === 'work-group')\n})\nconst indexedBlocks = computed(() => blocks.value.map((block, blockIndex) => ({ block, blockIndex })))\nconst indexedAllBlocks = computed(() => allBlocks.value.map((block, blockIndex) => ({ block, blockIndex })))\nconst userAttachmentBlocks = computed(() => (\n chatMessage.value.role === 'user'\n ? indexedAllBlocks.value.filter(({ block }) => block.type === 'attachment')\n : []\n))\nconst stackBlocks = computed(() => (\n chatMessage.value.role === 'user'\n ? indexedAllBlocks.value.filter(({ block }) => block.type !== 'attachment')\n : indexedBlocks.value\n))\nconst visibleUserContent = computed(() => stripMessageContext(chatMessage.value.content))\nconst isEditing = ref(false)\n\nconst showActions = computed(() => (\n chatMessage.value.type !== 'compaction' &&\n chatMessage.value.type !== 'steer' &&\n !assistantWithoutMessageActions.value &&\n !isEditing.value\n))\nconst reserveActionSlot = computed(() => (\n props.actionsDisabled ||\n (chatMessage.value.role === 'assistant' && chatMessage.value.streaming === true)\n))\nconst renderActionSlot = computed(() => showActions.value)\nconst canDelete = computed(() => Boolean(chatMessage.value.turnId) && props.canDeleteTurn && effectivePresentation.value.messages.actions.delete)\nconst canEdit = computed(() => Boolean(chatMessage.value.turnId) && props.canEditTurn && effectivePresentation.value.messages.actions.edit)\nconst canFork = computed(() => Boolean(chatMessage.value.turnId) && props.canForkTurn && effectivePresentation.value.messages.actions.fork)\nconst canRetry = computed(() => Boolean(chatMessage.value.turnId) && props.canRetryTurn && effectivePresentation.value.messages.actions.retry)\nconst hasVisibleAssistantActivity = computed(() => blocks.value.some(isVisibleAssistantBlock))\nconst isLatestStreamingAssistantSegment = computed(() => (\n messageTurnState.value?.latestStreamingAssistantIndex.value === undefined\n || messageTurnState.value.latestStreamingAssistantIndex.value === props.index\n))\nconst showEmptyResponse = computed(() => (\n chatMessage.value.role === 'assistant' &&\n chatMessage.value.streaming !== true &&\n allBlocks.value.length === 0\n))\nconst showThinkingIndicator = computed(() => (\n chatMessage.value.role === 'assistant' &&\n chatMessage.value.streaming === true &&\n isLatestStreamingAssistantSegment.value &&\n !hasVisibleAssistantActivity.value\n))\nconst showStreamingDot = computed(() => (\n chatMessage.value.role === 'assistant' &&\n chatMessage.value.streaming === true &&\n isLatestStreamingAssistantSegment.value &&\n hasVisibleAssistantActivity.value\n))\nfunction startEdit() {\n if (chatMessage.value.role !== 'user' || !canEdit.value) {\n return\n }\n\n isEditing.value = true\n}\n\nfunction cancelEdit() {\n isEditing.value = false\n}\n\nfunction saveEdit(content: string) {\n const turnId = chatMessage.value.turnId\n if (!turnId) return\n emit('edit-turn', { content, turnId })\n cancelEdit()\n}\n\nfunction deleteTurn() {\n if (!canDelete.value || props.threadActionsDisabled) {\n return\n }\n\n const turnId = chatMessage.value.turnId\n if (turnId) emit('delete-turn', turnId)\n}\n\nfunction forkTurn() {\n if (!canFork.value || props.threadActionsDisabled) return\n const turnId = chatMessage.value.turnId\n if (turnId) emit('fork-turn', turnId)\n}\n\nfunction retryTurn() {\n if (!canRetry.value || props.threadActionsDisabled) {\n return\n }\n\n const turnId = chatMessage.value.turnId\n if (turnId) emit('retry-turn', turnId)\n}\n\nfunction openImage(image: CodexMessageImage, context?: CodexMessageImageContext) {\n return props.openImage?.(image, {\n index: props.index,\n intent: context?.intent ?? 'open',\n message: chatMessage.value,\n })\n}\n\nasync function copyMessage() {\n await copyMessageToClipboard(chatMessage.value.content, hostCapabilities)\n}\n\nfunction isVisibleAssistantBlock(block: RenderedMessageBlock) {\n if (block.type === 'text') {\n return block.content.trim().length > 0\n }\n\n return block.type === 'attachment'\n || block.type === 'media'\n || block.type === 'mermaid'\n || block.type === 'reasoning'\n || block.type === 'tool'\n || block.type === 'tool-group'\n || block.type === 'visualization'\n || block.type === 'work-group'\n}\n\n</script>\n\n<style scoped>\n.chat-message {\n display: flex;\n}\n\n.chat-message--user {\n justify-content: flex-end;\n}\n\n.chat-message--user :deep(.chat-user-text__mention) {\n padding: var(--space-2);\n background: transparent;\n}\n\n.chat-message--assistant {\n justify-content: flex-start;\n}\n\n.chat-message--steer {\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n}\n\n.chat-message--steer-above {\n margin-bottom: var(--space-1);\n}\n\n.chat-message--steer-below {\n margin-top: var(--space-1);\n}\n\n.chat-message__steer-line {\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n border-top: 1px solid var(--color-border);\n}\n\n.chat-message__steer-body {\n z-index: 1;\n display: inline-flex;\n max-width: min(100%, 640px);\n align-items: baseline;\n gap: var(--space-4);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n padding: var(--space-2) var(--space-6);\n background: var(--color-surface-lowest);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n}\n\n.chat-message__steer-title {\n flex: 0 0 auto;\n color: var(--color-text);\n font-weight: var(--font-weight-medium);\n}\n\n.chat-message__steer-text {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-message__body {\n flex: 1;\n display: flex;\n flex-direction: column;\n max-width: 100%;\n}\n\n.chat-message--user .chat-message__body {\n align-items: flex-end;\n max-width: 70%;\n}\n\n.chat-message--assistant .chat-message__body {\n align-items: flex-start;\n}\n\n.chat-message--editing .chat-message__body {\n max-width: unset;\n}\n\n.chat-message__stack {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n max-width: 100%;\n}\n\n.chat-message__empty-response {\n color: var(--color-text-muted);\n font-style: italic;\n}\n\n.chat-message__attachments {\n display: flex;\n max-width: 100%;\n align-items: flex-start;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: var(--space-4);\n margin-bottom: var(--space-3);\n}\n\n.chat-message--assistant .chat-message__stack {\n width: 100%;\n}\n\n.chat-message--user .chat-message__stack {\n background: var(--color-shell-sidebar);\n border-radius: var(--radius-xl);\n}\n\n.chat-message--editing .chat-message__stack {\n width: 100%;\n background: transparent;\n border-radius: 0;\n}\n\n.chat-message__actions {\n visibility: hidden;\n}\n\n.chat-message--actions-visible .chat-message__actions {\n visibility: visible;\n}\n\n.chat-message__actions--reserved {\n pointer-events: none;\n}\n\n.chat-message:hover .chat-message__actions,\n.chat-message:focus-within .chat-message__actions {\n visibility: visible;\n}\n\n.chat-message:hover .chat-message__actions--reserved,\n.chat-message:focus-within .chat-message__actions--reserved {\n visibility: hidden;\n}\n\n.chat-message__thinking {\n align-self: flex-start;\n overflow: hidden;\n padding: var(--space-3) 0;\n font-size: var(--chat-message-font-size, var(--font-size-15));\n font-weight: var(--font-weight-light);\n line-height: var(--chat-message-line-height, var(--line-height-20));\n}\n\n.chat-message__stream-dot {\n display: block;\n width: var(--space-4);\n height: var(--space-4);\n align-self: flex-start;\n margin-top: var(--space-1);\n border-radius: 999px;\n background: var(--color-text-muted);\n transform-origin: 50% 50%;\n animation: chat-message-stream-dot 1.15s ease-in-out infinite;\n}\n\n@keyframes chat-message-stream-dot {\n 0%,\n 100% {\n border-radius: 999px;\n opacity: 0.48;\n transform: rotate(0deg) scale(0.72);\n }\n\n 50% {\n border-radius: var(--radius-xs);\n opacity: 1;\n transform: rotate(180deg) scale(1);\n }\n\n 75% {\n border-radius: var(--radius-sm);\n transform: rotate(270deg) scale(0.86);\n }\n}\n</style>\n","<template>\n <div class=\"codex-message-turn\">\n <slot />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, provide, ref, shallowReactive, watch } from 'vue'\nimport type { CodexSurfaceTurnStatus, SurfaceMessage } from '@codex-app-sdk/core/surface'\nimport {\n computeMessageBlocks,\n hasExplicitAssistantWorkPhases,\n isAssistantWorkBlock,\n} from '../chat/message-blocks'\nimport { chatMessageFromInput } from '../chat/renderer-message-adapter'\nimport type { Message } from '../chat/types'\nimport { assistantWorkTurnKey, questionResponsesKey } from '../chat/message-work-state'\n\nprovide(questionResponsesKey, inject(questionResponsesKey, undefined) ?? shallowReactive(new Map()))\n\ntype TurnEntry = {\n index: number\n message: Message | SurfaceMessage\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n active?: boolean\n answeredClientRequestIds?: ReadonlySet<string>\n entries: readonly TurnEntry[]\n showToolBlocks: boolean\n status?: CodexSurfaceTurnStatus\n turnId?: string\n}>()\n// Stryker restore all\n\nconst messages = computed(() => props.entries.map((entry) => ({\n entry,\n message: chatMessageFromInput(entry.message),\n})))\nconst turnId = computed(() => props.turnId)\nconst phased = computed(() => messages.value.some(({ message }) => (\n message.role === 'assistant' && hasExplicitAssistantWorkPhases(message)\n)))\nconst latestStreamingAssistantIndex = computed(() => [...messages.value]\n .reverse()\n .find(({ message }) => message.role === 'assistant' && message.streaming === true)\n ?.entry.index)\nconst latestStreamingWorkIndex = computed(() => props.active === false\n ? undefined\n : [...messages.value]\n .reverse()\n .find(({ message }) => (\n message.role === 'assistant'\n && message.streaming === true\n && (message.parts?.length ?? 0) > 0\n ))\n ?.entry.index)\nconst finalStarted = computed(() => messages.value.some(({ entry, message }) => (\n message.role === 'assistant'\n && (latestStreamingWorkIndex.value === undefined\n || entry.index >= latestStreamingWorkIndex.value)\n && (message.parts?.some((part) => (\n part.type === 'text'\n && part.phase === 'final_answer'\n && part.content.trim().length > 0\n )) ?? false)\n)))\nconst active = computed(() => !finalStarted.value && (props.active ?? messages.value.some(({ message }) => (\n message.role === 'assistant' && message.streaming === true\n))))\nconst status = computed(() => props.status)\nconst stoppedWithoutFinal = computed(() => (\n !active.value\n && !finalStarted.value\n && (status.value === 'interrupted' || status.value === 'failed')\n))\nconst completedWithoutFinal = computed(() => (\n phased.value\n && !active.value\n && !finalStarted.value\n && (status.value === undefined || status.value === 'completed')\n))\nconst headerMessageIndex = computed(() => messages.value.find(({ message }) => (\n message.role === 'assistant' && shouldGroupMessageWork(message)\n))?.entry.index)\nconst enabled = computed(() => Boolean(turnId.value && headerMessageIndex.value !== undefined))\nconst expanded = ref((active.value && !finalStarted.value) || stoppedWithoutFinal.value)\nconst userToggled = ref(false)\n\nwatch(finalStarted, (started, previous) => {\n if (started && !previous) expanded.value = false\n})\n\nwatch([active, stoppedWithoutFinal], ([isActive, isStoppedWithoutFinal]) => {\n if (!userToggled.value) expanded.value = (isActive && !finalStarted.value) || isStoppedWithoutFinal\n})\n\nprovide(assistantWorkTurnKey, {\n active,\n completedWithoutFinal,\n enabled,\n expanded,\n finalStarted,\n headerMessageIndex,\n latestStreamingAssistantIndex,\n phased,\n status,\n turnId,\n toggle() {\n userToggled.value = true\n expanded.value = !expanded.value\n },\n})\n\nfunction shouldGroupMessageWork(message: Message): boolean {\n const blocks = computeMessageBlocks(message).filter((block) => (\n props.showToolBlocks || (block.type !== 'tool' && block.type !== 'tool-group')\n ))\n if (blocks.length === 0) return false\n if (phased.value) return blocks.some((block) => isAssistantWorkBlock(block, props.answeredClientRequestIds))\n return active.value && blocks.every((block) => block.type === 'tool' || block.type === 'tool-group')\n}\n</script>\n\n<style scoped>\n.codex-message-turn {\n display: contents;\n}\n</style>\n","<template>\n <div class=\"codex-message-turn\">\n <slot />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, provide, ref, shallowReactive, watch } from 'vue'\nimport type { CodexSurfaceTurnStatus, SurfaceMessage } from '@codex-app-sdk/core/surface'\nimport {\n computeMessageBlocks,\n hasExplicitAssistantWorkPhases,\n isAssistantWorkBlock,\n} from '../chat/message-blocks'\nimport { chatMessageFromInput } from '../chat/renderer-message-adapter'\nimport type { Message } from '../chat/types'\nimport { assistantWorkTurnKey, questionResponsesKey } from '../chat/message-work-state'\n\nprovide(questionResponsesKey, inject(questionResponsesKey, undefined) ?? shallowReactive(new Map()))\n\ntype TurnEntry = {\n index: number\n message: Message | SurfaceMessage\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n active?: boolean\n answeredClientRequestIds?: ReadonlySet<string>\n entries: readonly TurnEntry[]\n showToolBlocks: boolean\n status?: CodexSurfaceTurnStatus\n turnId?: string\n}>()\n// Stryker restore all\n\nconst messages = computed(() => props.entries.map((entry) => ({\n entry,\n message: chatMessageFromInput(entry.message),\n})))\nconst turnId = computed(() => props.turnId)\nconst phased = computed(() => messages.value.some(({ message }) => (\n message.role === 'assistant' && hasExplicitAssistantWorkPhases(message)\n)))\nconst latestStreamingAssistantIndex = computed(() => [...messages.value]\n .reverse()\n .find(({ message }) => message.role === 'assistant' && message.streaming === true)\n ?.entry.index)\nconst latestStreamingWorkIndex = computed(() => props.active === false\n ? undefined\n : [...messages.value]\n .reverse()\n .find(({ message }) => (\n message.role === 'assistant'\n && message.streaming === true\n && (message.parts?.length ?? 0) > 0\n ))\n ?.entry.index)\nconst finalStarted = computed(() => messages.value.some(({ entry, message }) => (\n message.role === 'assistant'\n && (latestStreamingWorkIndex.value === undefined\n || entry.index >= latestStreamingWorkIndex.value)\n && (message.parts?.some((part) => (\n part.type === 'text'\n && part.phase === 'final_answer'\n && part.content.trim().length > 0\n )) ?? false)\n)))\nconst active = computed(() => !finalStarted.value && (props.active ?? messages.value.some(({ message }) => (\n message.role === 'assistant' && message.streaming === true\n))))\nconst status = computed(() => props.status)\nconst stoppedWithoutFinal = computed(() => (\n !active.value\n && !finalStarted.value\n && (status.value === 'interrupted' || status.value === 'failed')\n))\nconst completedWithoutFinal = computed(() => (\n phased.value\n && !active.value\n && !finalStarted.value\n && (status.value === undefined || status.value === 'completed')\n))\nconst headerMessageIndex = computed(() => messages.value.find(({ message }) => (\n message.role === 'assistant' && shouldGroupMessageWork(message)\n))?.entry.index)\nconst enabled = computed(() => Boolean(turnId.value && headerMessageIndex.value !== undefined))\nconst expanded = ref((active.value && !finalStarted.value) || stoppedWithoutFinal.value)\nconst userToggled = ref(false)\n\nwatch(finalStarted, (started, previous) => {\n if (started && !previous) expanded.value = false\n})\n\nwatch([active, stoppedWithoutFinal], ([isActive, isStoppedWithoutFinal]) => {\n if (!userToggled.value) expanded.value = (isActive && !finalStarted.value) || isStoppedWithoutFinal\n})\n\nprovide(assistantWorkTurnKey, {\n active,\n completedWithoutFinal,\n enabled,\n expanded,\n finalStarted,\n headerMessageIndex,\n latestStreamingAssistantIndex,\n phased,\n status,\n turnId,\n toggle() {\n userToggled.value = true\n expanded.value = !expanded.value\n },\n})\n\nfunction shouldGroupMessageWork(message: Message): boolean {\n const blocks = computeMessageBlocks(message).filter((block) => (\n props.showToolBlocks || (block.type !== 'tool' && block.type !== 'tool-group')\n ))\n if (blocks.length === 0) return false\n if (phased.value) return blocks.some((block) => isAssistantWorkBlock(block, props.answeredClientRequestIds))\n return active.value && blocks.every((block) => block.type === 'tool' || block.type === 'tool-group')\n}\n</script>\n\n<style scoped>\n.codex-message-turn {\n display: contents;\n}\n</style>\n","<template>\n <button\n class=\"codex-chat-theme codex-scroll-to-bottom\"\n type=\"button\"\n :aria-label=\"label\"\n :title=\"label\"\n @click=\"emit('click')\"\n >\n <ArrowDownIcon aria-hidden=\"true\" :size=\"24\" :stroke-width=\"1.75\" />\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { ArrowDownIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n label?: string;\n}>(), {\n label: 'Scroll to bottom',\n});\n\nconst emit = defineEmits<{\n click: [];\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.codex-scroll-to-bottom {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--codex-scroll-to-bottom-size, 48px);\n height: var(--codex-scroll-to-bottom-size, 48px);\n padding: 0;\n border: 1px solid var(--codex-scroll-to-bottom-border, var(--color-border, #e3e5e8));\n border-radius: 50%;\n appearance: none;\n color: var(--codex-scroll-to-bottom-color, var(--color-text, #202124));\n background: var(--codex-scroll-to-bottom-background, var(--color-surface-lowest, #fff));\n box-shadow: var(--codex-scroll-to-bottom-shadow, 0 1px 3px rgb(0 0 0 / 8%));\n cursor: pointer;\n pointer-events: auto;\n transition: background 120ms ease, box-shadow 120ms ease, transform 120ms ease;\n}\n\n.codex-scroll-to-bottom > svg {\n pointer-events: none;\n}\n\n.codex-scroll-to-bottom:hover,\n.codex-scroll-to-bottom:focus-visible {\n background: var(--codex-scroll-to-bottom-hover-background, var(--color-surface-low, #f5f6f7));\n box-shadow: var(--codex-scroll-to-bottom-hover-shadow, 0 2px 6px rgb(0 0 0 / 12%));\n}\n\n.codex-scroll-to-bottom:active {\n transform: scale(0.96);\n}\n</style>\n","<template>\n <button\n class=\"codex-chat-theme codex-scroll-to-bottom\"\n type=\"button\"\n :aria-label=\"label\"\n :title=\"label\"\n @click=\"emit('click')\"\n >\n <ArrowDownIcon aria-hidden=\"true\" :size=\"24\" :stroke-width=\"1.75\" />\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { ArrowDownIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n label?: string;\n}>(), {\n label: 'Scroll to bottom',\n});\n\nconst emit = defineEmits<{\n click: [];\n}>();\n// Stryker restore all\n</script>\n\n<style scoped>\n.codex-scroll-to-bottom {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--codex-scroll-to-bottom-size, 48px);\n height: var(--codex-scroll-to-bottom-size, 48px);\n padding: 0;\n border: 1px solid var(--codex-scroll-to-bottom-border, var(--color-border, #e3e5e8));\n border-radius: 50%;\n appearance: none;\n color: var(--codex-scroll-to-bottom-color, var(--color-text, #202124));\n background: var(--codex-scroll-to-bottom-background, var(--color-surface-lowest, #fff));\n box-shadow: var(--codex-scroll-to-bottom-shadow, 0 1px 3px rgb(0 0 0 / 8%));\n cursor: pointer;\n pointer-events: auto;\n transition: background 120ms ease, box-shadow 120ms ease, transform 120ms ease;\n}\n\n.codex-scroll-to-bottom > svg {\n pointer-events: none;\n}\n\n.codex-scroll-to-bottom:hover,\n.codex-scroll-to-bottom:focus-visible {\n background: var(--codex-scroll-to-bottom-hover-background, var(--color-surface-low, #f5f6f7));\n box-shadow: var(--codex-scroll-to-bottom-hover-shadow, 0 2px 6px rgb(0 0 0 / 12%));\n}\n\n.codex-scroll-to-bottom:active {\n transform: scale(0.96);\n}\n</style>\n","<template>\n <div\n class=\"codex-chat-theme codex-message-list\"\n :aria-label=\"ariaLabel\"\n >\n <div\n ref=\"scrollElement\"\n class=\"codex-message-list__viewport message-list\"\n @click.capture=\"handleViewportClick\"\n @pointerdown=\"handleSelectionPointerDown\"\n @scroll=\"handleScroll\"\n >\n <div class=\"codex-message-list__content\">\n <slot v-if=\"displayEntries.length === 0\" name=\"empty\">\n <p class=\"codex-message-list__empty\">{{ emptyLabel }}</p>\n </slot>\n <CodexMessageTurn\n v-for=\"group in displayGroups\"\n v-else\n :key=\"group.key\"\n :entries=\"group.entries\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :active=\"activeOverrideForGroup(group)\"\n :show-tool-blocks=\"effectivePresentation.messages.toolBlocks\"\n :status=\"group.turnId ? turnStatusById.get(group.turnId) : undefined\"\n :turn-id=\"group.turnId\"\n >\n <template v-for=\"entry in group.entries\" :key=\"entry.key\">\n <div\n class=\"codex-message-list__entry\"\n :data-codex-message-index=\"entry.index\"\n >\n <slot v-if=\"$slots.message\" name=\"message\" :message=\"chatMessageFromInput(displayMessage(entry.message, group.turnId))\" :index=\"entry.index\" />\n <CodexMessage\n v-else\n :activity-state=\"entry.activityState\"\n :actions-disabled=\"actionsDisabled\"\n :actions-always-visible=\"shouldKeepAssistantActionsVisible(entry.index)\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :can-delete-turn=\"canDeleteTurn && isTerminalTurn(group.turnId)\"\n :can-edit-turn=\"canEditTurn && isTerminalTurn(group.turnId)\"\n :can-fork-turn=\"canForkTurn && isForkableTurn(group.turnId)\"\n :can-retry-turn=\"canRetryTurn && isTerminalTurn(group.turnId)\"\n :deleting-turn=\"group.turnId === deletingTurnId\"\n :follow-ups-disabled=\"followUpsDisabled\"\n :hidden-client-request-ids=\"hiddenClientRequestIds\"\n :index=\"entry.index\"\n :message=\"displayMessage(entry.message, group.turnId)\"\n :mention-groups=\"mentionGroups\"\n :open-image=\"openImage\"\n :plugins=\"plugins\"\n :presentation=\"presentation\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"skills\"\n :thread-actions-disabled=\"busy\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @copy-message=\"emit('copy-message', $event)\"\n @delete-turn=\"emit('delete-turn', $event)\"\n @edit-turn=\"emit('edit-turn', $event)\"\n @fork-turn=\"emit('fork-turn', $event)\"\n @open-link=\"emit('open-link', $event)\"\n @open-visualization=\"emit('open-visualization', $event)\"\n @quote-message=\"emit('quote-message', $event)\"\n @retry-turn=\"emit('retry-turn', $event)\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n >\n <template v-if=\"$slots.actions\" #actions=\"scope\"><slot name=\"actions\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.attachment\" #attachment=\"scope\"><slot name=\"attachment\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.block\" #block=\"scope\"><slot name=\"block\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.header\" #header=\"scope\"><slot name=\"header\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.mention\" #mention=\"scope\"><slot name=\"mention\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.status\" #status=\"scope\"><slot name=\"status\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.text\" #text=\"scope\"><slot name=\"text\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.thinking\" #thinking=\"scope\"><slot name=\"thinking\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.tool\" #tool=\"scope\"><slot name=\"tool\" v-bind=\"scope\" /></template>\n </CodexMessage>\n </div>\n </template>\n </CodexMessageTurn>\n </div>\n </div>\n <CodexScrollToBottom\n v-if=\"overflown\"\n class=\"codex-message-list__scroll-to-bottom\"\n :label=\"scrollToBottomLabel\"\n @click=\"scrollToBottom\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, nextTick, onBeforeUnmount, onMounted, provide, ref, shallowReactive, watch } from 'vue'\nimport { questionResponsesKey } from '../chat/message-work-state'\nimport type {\n CodexConversationRenderStrategy,\n CodexSurfacePlugin,\n CodexSurfaceSkill,\n CodexSurfaceTurn,\n SurfaceMessage,\n} from '@codex-app-sdk/core/surface'\nimport type { ClientRequestResponse, CodexConversationLink, CodexConversationPresentation } from '../chat/contracts'\nimport { resolveCodexConversationPresentation } from '../chat/contracts'\nimport type { Message } from '../chat/types'\nimport type { MessageBlock } from '../chat/message-blocks'\nimport type { CodexMessageImageOpenHandler } from '../chat/message-image'\nimport type { CodexConversationVisualization } from '../chat/visualization'\nimport type { CodexMessageTextSelection } from '../chat/message-text-selection'\nimport { chatMessageFromInput } from '../chat/renderer-message-adapter'\nimport { filterVisibleMessageTools, type CodexToolVisibility } from '../chat/tool-visibility'\nimport CodexMessage from './CodexMessage.vue'\nimport CodexMessageTurn from './CodexMessageTurn.vue'\nimport CodexScrollToBottom from './CodexScrollToBottom.vue'\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from '../chat/composer-mentions-custom'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n actionsDisabled?: boolean\n activeTurnId?: string | null\n ariaLabel?: string\n answeredClientRequestIds?: ReadonlySet<string>\n busy?: boolean\n bottomThreshold?: number\n canDeleteTurn?: boolean\n canEditTurn?: boolean\n canForkTurn?: boolean\n canRetryTurn?: boolean\n deletingTurnId?: string | null\n emptyLabel?: string\n followUpsDisabled?: boolean\n hasOlderMessages?: boolean\n hiddenClientRequestIds?: ReadonlySet<string>\n renderStrategy?: CodexConversationRenderStrategy\n /** @deprecated Use renderStrategy instead. */\n lazyMessages?: boolean\n initialMessageBatchSize?: number\n loadingOlderMessages?: boolean\n messageBatchSize?: number\n messageTextSelection?: boolean\n messages: readonly (Message | SurfaceMessage)[]\n mentionGroups?: readonly CodexComposerMentionGroup[]\n openImage?: CodexMessageImageOpenHandler\n transformMessage?: (message: Message | SurfaceMessage, index: number) => Message | SurfaceMessage\n plugins?: readonly CodexSurfacePlugin[]\n presentation?: CodexConversationPresentation\n resetKey?: string | number | null\n scrollToBottomLabel?: string\n showToolDetails?: boolean\n skills?: readonly CodexSurfaceSkill[]\n toolVisibility?: CodexToolVisibility\n turns?: readonly CodexSurfaceTurn[]\n}>(), {\n ariaLabel: 'Conversation',\n busy: false,\n bottomThreshold: 24,\n canDeleteTurn: true,\n canEditTurn: true,\n canForkTurn: false,\n canRetryTurn: true,\n emptyLabel: 'No messages yet',\n hasOlderMessages: false,\n lazyMessages: undefined,\n loadingOlderMessages: false,\n scrollToBottomLabel: 'Scroll to bottom',\n showToolDetails: undefined,\n})\n\ndefineSlots<{\n actions(props: { disabled: boolean; index: number; message: Message }): unknown\n attachment(props: {\n attachment: Extract<MessageBlock, { type: 'attachment' }>['attachment']\n block: Extract<MessageBlock, { type: 'attachment' }>\n index: number\n message: Message\n }): unknown\n block(props: { block: MessageBlock; blockIndex: number; index: number; message: Message }): unknown\n empty(): unknown\n header(props: { index: number; message: Message }): unknown\n message(props: { index: number; message: Message }): unknown\n mention(props: { group: CodexComposerMentionGroup; index: number; item: CodexComposerMentionItem; message: Message; surface: 'message' }): unknown\n status(props: { index: number; message: Message; status: 'streaming' }): unknown\n text(props: { block: Extract<MessageBlock, { type: 'text' | 'user-text' }>; content: string; index: number; message: Message; user: boolean }): unknown\n thinking(props: { index: number; message: Message }): unknown\n tool(props: {\n block: Extract<MessageBlock, { type: 'tool' | 'tool-group' }>\n index: number\n message: Message\n toolCall?: Extract<MessageBlock, { type: 'tool' }>['toolCall']\n toolCalls?: Extract<MessageBlock, { type: 'tool-group' }>['toolCalls']\n }): unknown\n}>()\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'copy-message': [index: number]\n 'delete-turn': [turnId: string]\n 'edit-turn': [payload: { content: string; turnId: string }]\n 'fork-turn': [turnId: string]\n 'load-older-messages': []\n 'message-text-selection-change': [selection: CodexMessageTextSelection | null]\n 'open-link': [link: CodexConversationLink]\n 'open-visualization': [visualization: CodexConversationVisualization]\n 'quote-message': [index: number]\n 'retry-turn': [turnId: string]\n 'send-follow-up': [prompt: string]\n 'stickiness-change': [stuckToBottom: boolean]\n}>()\n// Stryker restore all\n\nconst thinkingPlaceholder: SurfaceMessage = {\n id: 'codex-thinking-placeholder',\n role: 'assistant',\n status: 'streaming',\n parts: [],\n}\nconst questionResponses = inject(questionResponsesKey, undefined)\n ?? shallowReactive(new Map<string, ClientRequestResponse['payload']>())\nprovide(questionResponsesKey, questionResponses)\nwatch(() => props.messages, (messages) => {\n const answers: Record<string, { answers: string[] }> = {}\n const requestIds = new Set<string>()\n for (const message of messages) {\n if (!('metadata' in message)) continue\n const stored = message.metadata?.asyncQuestionAnswers\n if (!stored || typeof stored !== 'object') continue\n for (const [id, value] of Object.entries(stored)) {\n if (value && typeof value === 'object' && 'answers' in value\n && Array.isArray(value.answers) && value.answers.every((answer: unknown) => typeof answer === 'string')) {\n answers[id] = { answers: value.answers }\n }\n }\n }\n for (const message of messages) {\n for (const part of message.parts ?? []) {\n if (part.type !== 'question') continue\n requestIds.add(part.request.id)\n const restored = Object.fromEntries(part.request.payload.request.questions\n .filter((question) => answers[question.id])\n .map((question) => [question.id, answers[question.id]!]))\n if (Object.keys(restored).length > 0) questionResponses.set(part.request.id, { answers: restored })\n }\n }\n for (const id of questionResponses.keys()) {\n if (!requestIds.has(id)) questionResponses.delete(id)\n }\n}, { immediate: true })\n\nconst effectiveRenderStrategy = computed<CodexConversationRenderStrategy>(() => (\n props.renderStrategy ?? (props.lazyMessages === false ? 'eager' : 'lazy')\n))\nconst effectiveInitialMessageBatchSize = computed(() => (\n props.initialMessageBatchSize ?? props.messageBatchSize ?? 50\n))\nconst effectiveMessageBatchSize = computed(() => props.messageBatchSize ?? 25)\nconst renderStartIndex = ref(initialRenderStart(\n props.messages,\n effectiveInitialMessageBatchSize.value,\n))\ntype MessageIdentity = string | object | null\ntype ConversationScrollState = {\n renderedAnchor: MessageIdentity\n scrollTop: number\n stickToBottom: boolean\n}\nconst conversationScrollStates = new Map<string | number, ConversationScrollState>()\nlet renderedAnchor = messageIdentityAt(props.messages, renderStartIndex.value)\nlet observedMessagesLength = props.messages.length\nlet observedFirstMessage = messageIdentityAt(props.messages, 0)\nlet observedLastMessage = messageIdentityAt(props.messages, props.messages.length - 1)\nconst loadingOlderMessages = ref(false)\nlet olderMessagesRequestPending = false\nconst visibleMessages = computed(() => effectiveRenderStrategy.value === 'lazy'\n ? props.messages.slice(renderStartIndex.value)\n : props.messages)\ntype DisplayEntry = {\n index: number\n message: Message | SurfaceMessage\n key: string | number\n activityState?: 'working'\n}\nconst displayEntries = computed<DisplayEntry[]>(() => {\n let lastUserIndex = -1\n for (let index = props.messages.length - 1; index >= 0; index--) {\n if (props.messages[index]?.role !== 'user') continue\n lastUserIndex = index\n break\n }\n let hiddenCurrentTurnActivity = false\n const entries: DisplayEntry[] = visibleMessages.value.flatMap((message, offset) => {\n const index = effectiveRenderStrategy.value === 'lazy' ? renderStartIndex.value + offset : offset\n const transformed = props.transformMessage?.(message, index) ?? message\n const visible = filterVisibleMessageTools(transformed, props.toolVisibility)\n if (!visible && transformed.role === 'assistant' && (\n props.activeTurnId\n ? chatMessageFromInput(transformed).turnId === props.activeTurnId\n : index > lastUserIndex\n )) hiddenCurrentTurnActivity = true\n return visible ? [{ index, message: visible, key: message.id ?? index }] : []\n })\n const hasStreamingAssistant = entries.some(({ message }) => (\n message.role === 'assistant' && (\n 'content' in message\n ? message.streaming === true\n || (message.type === 'compaction' && message.compactionStatus === 'running')\n : message.status === 'streaming'\n )\n ))\n if (props.busy && !hasStreamingAssistant) {\n const turnId = entries.length > 0\n ? chatMessageFromInput(entries.at(-1)!.message).turnId?.trim() || undefined\n : undefined\n entries.push({\n index: props.messages.length,\n message: turnId ? { ...thinkingPlaceholder, turnId } : thinkingPlaceholder,\n key: thinkingPlaceholder.id,\n ...(hiddenCurrentTurnActivity ? { activityState: 'working' } : {}),\n })\n }\n return entries\n})\nconst effectivePresentation = computed(() => resolveCodexConversationPresentation(props.presentation))\nconst displayGroups = computed(() => {\n const groups: Array<{\n entries: typeof displayEntries.value\n key: string | number\n turnId?: string\n }> = []\n for (const entry of displayEntries.value) {\n const turnId = chatMessageFromInput(entry.message).turnId?.trim() || undefined\n const previous = groups.at(-1)\n if (turnId && previous?.turnId === turnId) {\n previous.entries.push(entry)\n continue\n }\n groups.push({\n entries: [entry],\n key: turnId ? `turn:${turnId}` : entry.key,\n ...(turnId ? { turnId } : {}),\n })\n }\n const assistantTurnIds = new Set(visibleMessages.value\n .filter((message) => message.role === 'assistant')\n .map((message) => chatMessageFromInput(message).turnId?.trim()))\n for (const [index, group] of groups.entries()) {\n if (!group.turnId || group.turnId === inferredActiveTurnId.value\n || turnStatusById.value.get(group.turnId) !== 'completed'\n || assistantTurnIds.has(group.turnId)\n || !group.entries.some((entry) => entry.message.role === 'user')) continue\n // Provider snapshots may omit an empty assistant item. A confirmed\n // completed turn still deserves a visible acknowledgment, unlike idle alone.\n const id = `codex-empty-response:${group.turnId}`\n group.entries.push({\n index: props.messages.length + index + 1,\n key: id,\n message: { id, role: 'assistant', status: 'complete', turnId: group.turnId, parts: [] },\n })\n }\n return groups\n})\n\nfunction activeOverrideForGroup(group: (typeof displayGroups.value)[number]): boolean | undefined {\n if (props.busy && group.entries.some(({ index, message }) => (\n index < props.messages.length\n && message.role === 'assistant'\n && chatMessageFromInput(message).streaming === true\n ))) return true\n if (props.activeTurnId === undefined) return undefined\n return group.turnId !== undefined && group.turnId === props.activeTurnId\n}\nconst inferredActiveTurnId = computed(() => {\n if (props.activeTurnId !== undefined && props.activeTurnId !== null) return props.activeTurnId\n const streamingTurnId = props.busy\n ? [...props.messages]\n .reverse()\n .map(chatMessageFromInput)\n .find((message) => message.role === 'assistant' && message.streaming)\n ?.turnId?.trim()\n : undefined\n return streamingTurnId || null\n})\nconst turnStatusById = computed(() => new Map(\n props.turns?.map((turn) => [turn.id, turn.status] as const) ?? [],\n))\n\nfunction isTerminalTurn(turnId: string | undefined): boolean {\n if (!turnId || turnId === inferredActiveTurnId.value) return false\n return turnStatusById.value.get(turnId) !== 'inProgress'\n}\n\nfunction displayMessage(message: Message | SurfaceMessage, turnId: string | undefined): Message | SurfaceMessage {\n const status = turnId ? turnStatusById.value.get(turnId) : undefined\n if (!status || status === 'inProgress' || turnId === inferredActiveTurnId.value) return message\n if ('content' in message) {\n return message.streaming ? { ...message, streaming: false } : message\n }\n return message.status === 'streaming'\n ? { ...message, status: 'complete' }\n : message\n}\n\nfunction isForkableTurn(turnId: string | undefined): boolean {\n if (!isTerminalTurn(turnId)) return false\n const status = turnStatusById.value.get(turnId!)\n return status === undefined || status === 'completed'\n}\nconst latestAssistantIndex = computed(() => [...displayEntries.value]\n .reverse()\n .find((entry) => entry.message.role === 'assistant')\n ?.index)\n\nfunction shouldKeepAssistantActionsVisible(index: number): boolean {\n return index === latestAssistantIndex.value\n}\n\nconst scrollElement = ref<HTMLElement | null>(null)\nconst tail = ref(true)\nconst overflown = ref(false)\nlet contentResizeObserver: ResizeObserver | null = null\nlet scrollFrame: number | ReturnType<typeof setTimeout> | null = null\nlet lastScrollTop = 0\nlet pointerSelecting = false\nlet lastTextSelection: CodexMessageTextSelection | null = null\n\nonMounted(async () => {\n document.addEventListener('pointerup', handleSelectionPointerUp)\n document.addEventListener('selectionchange', handleDocumentSelectionChange)\n await nextTick()\n scrollToBottom()\n const content = scrollElement.value?.querySelector('.codex-message-list__content')\n if (content && typeof ResizeObserver !== 'undefined') {\n contentResizeObserver = new ResizeObserver(() => {\n if (tail.value) queueScrollToBottom()\n else updateOverflow()\n })\n contentResizeObserver.observe(content)\n }\n queueScrollToBottom()\n})\n\nwatch(() => props.messages.length, async (nextLength) => {\n const previousLength = observedMessagesLength\n const target = scrollElement.value!\n const previousHeight = target.scrollHeight\n const previousTop = target.scrollTop\n observedMessagesLength = nextLength\n const revealedPrependedMessages = effectiveRenderStrategy.value === 'lazy'\n ? reconcileMessageWindow(nextLength, previousLength)\n : false\n observeMessageBounds()\n const shouldScroll = !revealedPrependedMessages && tail.value && isAtBottom()\n await nextTick()\n if (revealedPrependedMessages && target) {\n target.scrollTop = previousTop + target.scrollHeight - previousHeight\n } else if (shouldScroll) {\n scrollToBottom()\n }\n})\n\nwatch(\n [() => props.resetKey, () => props.messages.length, () => props.messages.at(-1)] as const,\n ([conversationKey, length, message], [previousConversationKey, previousLength, previousMessage]) => {\n if (conversationKey !== previousConversationKey || length !== previousLength || !message || !previousMessage) return\n if (message.id && previousMessage.id && message.id !== previousMessage.id) return\n onNewChunk()\n },\n)\n\nwatch(() => props.messageTextSelection, (enabled) => {\n if (!enabled) clearMessageTextSelection()\n})\n\nwatch(() => props.resetKey, async (nextKey, previousKey) => {\n clearMessageTextSelection()\n const target = scrollElement.value\n if (target && previousKey !== null && previousKey !== undefined) {\n conversationScrollStates.set(previousKey, {\n renderedAnchor,\n scrollTop: target.scrollTop,\n stickToBottom: isAtBottom(),\n })\n }\n const restoredState = nextKey === null || nextKey === undefined\n ? undefined\n : conversationScrollStates.get(nextKey)\n const restoredAnchorIndex = restoredState\n ? findMessageIndex(props.messages, restoredState.renderedAnchor)\n : -1\n setRenderStartIndex(restoredAnchorIndex >= 0\n ? restoredAnchorIndex\n : initialRenderStart(props.messages, effectiveInitialMessageBatchSize.value))\n loadingOlderMessages.value = false\n olderMessagesRequestPending = false\n setTail(restoredState?.stickToBottom ?? true)\n observeMessageBounds()\n await nextTick()\n if (restoredState && target) {\n target.scrollTop = restoredState.stickToBottom\n ? target.scrollHeight\n : restoredState.scrollTop\n updateOverflow()\n } else {\n scrollToBottom()\n }\n})\n\nwatch(() => [props.loadingOlderMessages, props.hasOlderMessages] as const, () => {\n olderMessagesRequestPending = false\n})\n\nwatch(() => [effectiveRenderStrategy.value, effectiveInitialMessageBatchSize.value, effectiveMessageBatchSize.value] as const, async () => {\n if (effectiveRenderStrategy.value === 'lazy') {\n setRenderStartIndex(initialRenderStart(props.messages, effectiveInitialMessageBatchSize.value))\n observeMessageBounds()\n await nextTick()\n if (tail.value) scrollToBottom()\n }\n})\n\nfunction handleScroll(): void {\n clearMessageTextSelection()\n const target = scrollElement.value\n const scrolledUp = target !== null && target.scrollTop < lastScrollTop\n if (target) lastScrollTop = target.scrollTop\n updateOverflow()\n if (!overflown.value) setTail(true)\n else if (scrolledUp) setTail(false)\n if (effectiveRenderStrategy.value === 'lazy' && isWithinTopPrefetchRange() && renderStartIndex.value <= 0 && props.hasOlderMessages && !props.loadingOlderMessages) {\n requestOlderMessages()\n } else if (effectiveRenderStrategy.value === 'lazy' && isWithinTopPrefetchRange()) {\n void loadOlderMessages()\n }\n}\n\nfunction onNewChunk(): void {\n if (tail.value) queueScrollToBottom()\n else void nextTick(updateOverflow)\n}\n\nfunction handleViewportClick(event: MouseEvent): void {\n const target = event.target\n if (!(target instanceof Element) || !target.closest('.chat-work-group__header')) return\n setTail(false)\n}\n\nfunction handleSelectionPointerDown(): void {\n if (props.messageTextSelection) pointerSelecting = true\n}\n\nfunction handleSelectionPointerUp(): void {\n if (!pointerSelecting) return\n pointerSelecting = false\n updateMessageTextSelection()\n}\n\nfunction handleDocumentSelectionChange(): void {\n if (!props.messageTextSelection || pointerSelecting) return\n updateMessageTextSelection()\n}\n\nfunction updateMessageTextSelection(): void {\n if (!props.messageTextSelection) {\n clearMessageTextSelection()\n return\n }\n const selection = window.getSelection()\n if (!selection || selection.isCollapsed || selection.rangeCount === 0) {\n clearMessageTextSelection()\n return\n }\n const text = selection.toString().trim()\n const range = selection.getRangeAt(0)\n const startEntry = messageEntryForNode(range.startContainer)\n const endEntry = messageEntryForNode(range.endContainer)\n if (!text || !startEntry || startEntry !== endEntry) {\n clearMessageTextSelection()\n return\n }\n const messageIndex = Number.parseInt(startEntry.dataset.codexMessageIndex ?? '', 10)\n const entry = displayEntries.value.find((candidate) => candidate.index === messageIndex)\n if (!entry) {\n clearMessageTextSelection()\n return\n }\n const rect = range.getBoundingClientRect()\n const message = chatMessageFromInput(entry.message)\n const next: CodexMessageTextSelection = {\n anchor: { x: rect.left, y: rect.top, width: rect.width, height: rect.height },\n messageIndex,\n role: message.role,\n text,\n ...(message.id ? { messageId: message.id } : {}),\n ...(message.turnId ? { turnId: message.turnId } : {}),\n }\n if (sameTextSelection(lastTextSelection, next)) return\n lastTextSelection = next\n emit('message-text-selection-change', next)\n}\n\nfunction messageEntryForNode(node: Node): HTMLElement | null {\n const element = node instanceof Element ? node : node.parentElement\n const entry = element?.closest<HTMLElement>('[data-codex-message-index]') ?? null\n return entry && scrollElement.value?.contains(entry) ? entry : null\n}\n\nfunction clearMessageTextSelection(): void {\n pointerSelecting = false\n if (!lastTextSelection) return\n lastTextSelection = null\n emit('message-text-selection-change', null)\n}\n\nfunction sameTextSelection(\n left: CodexMessageTextSelection | null,\n right: CodexMessageTextSelection,\n): boolean {\n return Boolean(left\n && left.text === right.text\n && left.messageIndex === right.messageIndex\n && left.anchor.x === right.anchor.x\n && left.anchor.y === right.anchor.y\n && left.anchor.width === right.anchor.width\n && left.anchor.height === right.anchor.height)\n}\n\nfunction requestOlderMessages(): void {\n if (!props.hasOlderMessages || props.loadingOlderMessages || olderMessagesRequestPending) return\n olderMessagesRequestPending = true\n emit('load-older-messages')\n}\n\nfunction isWithinTopPrefetchRange(): boolean {\n const target = scrollElement.value\n return target !== null && target.scrollTop <= target.clientHeight\n}\n\nasync function loadOlderMessages(): Promise<void> {\n if (loadingOlderMessages.value || renderStartIndex.value <= 0) return\n const target = scrollElement.value!\n const previousHeight = target.scrollHeight\n const previousTop = target.scrollTop\n loadingOlderMessages.value = true\n setRenderStartIndex(Math.max(0, renderStartIndex.value - normalizedBatchSize(effectiveMessageBatchSize.value)))\n await nextTick()\n target.scrollTop = previousTop + target.scrollHeight - previousHeight\n loadingOlderMessages.value = false\n if (renderStartIndex.value <= 0) requestOlderMessages()\n}\n\nfunction reconcileMessageWindow(nextLength: number, previousLength: number): boolean {\n const batchSize = normalizedBatchSize(effectiveInitialMessageBatchSize.value)\n const previousTailStart = turnAlignedStart(props.messages.slice(0, previousLength), Math.max(0, previousLength - batchSize))\n const wasTailWindow = renderStartIndex.value === previousTailStart\n if (nextLength < previousLength) {\n setRenderStartIndex(initialRenderStart(props.messages, effectiveInitialMessageBatchSize.value))\n return false\n }\n\n const anchorIndex = findMessageIndex(props.messages, renderedAnchor)\n const hasPrependedMessages = anchorIndex >= 0 && !sameMessageIdentity(\n messageIdentityAt(props.messages, 0),\n observedFirstMessage,\n );\n if (hasPrependedMessages) {\n // Once the viewport is pinned at the rendered top, another upward gesture\n // cannot fire a scroll event. Reveal the first server-prepended batch now.\n const revealOlderBatch = renderStartIndex.value <= 0 && isWithinTopPrefetchRange()\n setRenderStartIndex(revealOlderBatch\n ? Math.max(0, anchorIndex - normalizedBatchSize(effectiveMessageBatchSize.value))\n : isAtBottom()\n ? Math.max(0, nextLength - batchSize)\n : anchorIndex)\n return revealOlderBatch\n }\n\n const hasAppendedMessages = sameMessageIdentity(\n messageIdentityAt(props.messages, 0),\n observedFirstMessage,\n ) && !sameMessageIdentity(\n messageIdentityAt(props.messages, nextLength - 1),\n observedLastMessage,\n );\n if (hasAppendedMessages && isAtBottom() && wasTailWindow) {\n setRenderStartIndex(Math.max(0, nextLength - batchSize))\n }\n return false\n}\n\nfunction setRenderStartIndex(nextIndex: number): void {\n const alignedIndex = turnAlignedStart(props.messages, nextIndex)\n renderStartIndex.value = alignedIndex\n renderedAnchor = messageIdentityAt(props.messages, alignedIndex)\n}\n\nfunction observeMessageBounds(): void {\n observedMessagesLength = props.messages.length\n observedFirstMessage = messageIdentityAt(props.messages, 0)\n observedLastMessage = messageIdentityAt(props.messages, props.messages.length - 1)\n}\n\nfunction messageIdentityAt(messages: readonly (Message | SurfaceMessage)[], index: number): MessageIdentity {\n const message = messages[index]\n return message ? message.id ?? message : null\n}\n\nfunction sameMessageIdentity(left: MessageIdentity, right: MessageIdentity): boolean {\n return left === right\n}\n\nfunction findMessageIndex(messages: readonly (Message | SurfaceMessage)[], identity: MessageIdentity): number {\n return messages.findIndex((message) => sameMessageIdentity(message.id ?? message, identity))\n}\n\nfunction normalizedBatchSize(value: number | undefined): number {\n return Math.max(1, Math.floor(value ?? 25))\n}\n\nfunction initialRenderStart(\n messages: readonly (Message | SurfaceMessage)[],\n batchSize: number | undefined,\n): number {\n return tailRenderStart(messages, normalizedBatchSize(batchSize))\n}\n\nfunction tailRenderStart(messages: readonly (Message | SurfaceMessage)[], batchSize: number): number {\n return turnAlignedStart(messages, Math.max(0, messages.length - batchSize))\n}\n\nfunction turnAlignedStart(messages: readonly (Message | SurfaceMessage)[], candidate: number): number {\n let start = Math.max(0, Math.min(messages.length, candidate))\n if (start >= messages.length) return start\n const turnId = chatMessageFromInput(messages[start]!).turnId?.trim()\n if (!turnId) return start\n while (start > 0 && chatMessageFromInput(messages[start - 1]!).turnId?.trim() === turnId) start -= 1\n return start\n}\n\nfunction setTail(next: boolean): void {\n if (tail.value !== next) {\n tail.value = next\n emit('stickiness-change', next)\n }\n}\n\nfunction updateOverflow(): void {\n overflown.value = !isAtBottom()\n}\n\nfunction isAtBottom(): boolean {\n const target = scrollElement.value\n return target\n ? target.scrollHeight - target.scrollTop - target.clientHeight <= props.bottomThreshold\n : tail.value\n}\n\nfunction scrollToBottom(): void {\n if (!scrollElement.value) {\n return\n }\n scrollElement.value.scrollTop = scrollElement.value.scrollHeight\n lastScrollTop = scrollElement.value.scrollTop\n setTail(true)\n updateOverflow()\n}\n\nfunction queueScrollToBottom(): void {\n if (scrollFrame !== null) return\n const callback = () => {\n scrollFrame = null\n if (tail.value) scrollToBottom()\n }\n scrollFrame = typeof requestAnimationFrame === 'function'\n ? requestAnimationFrame(callback)\n : setTimeout(callback, 0)\n}\n\nonBeforeUnmount(() => {\n document.removeEventListener('pointerup', handleSelectionPointerUp)\n document.removeEventListener('selectionchange', handleDocumentSelectionChange)\n contentResizeObserver?.disconnect()\n contentResizeObserver = null\n if (scrollFrame !== null) {\n if (typeof scrollFrame === 'number' && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(scrollFrame)\n } else {\n clearTimeout(scrollFrame)\n }\n }\n})\n\ndefineExpose({ scrollToBottom })\n</script>\n\n<style scoped>\n.codex-message-list {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.codex-message-list__viewport {\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n padding: var(--codex-message-list-padding, 24px 16px);\n overflow-y: auto;\n scrollbar-width: thin;\n box-sizing: border-box;\n}\n\n.codex-message-list__scroll-to-bottom {\n position: absolute;\n right: 50%;\n bottom: var(--codex-scroll-to-bottom-offset, var(--space-8));\n z-index: 1;\n transform: translateX(50%);\n}\n\n.codex-message-list__scroll-to-bottom:active {\n transform: translateX(50%) scale(0.96);\n}\n\n.codex-message-list__content {\n display: flex;\n flex-direction: column;\n gap: var(--codex-message-list-gap, 12px);\n width: min(100%, var(--codex-message-list-content-width, 900px));\n margin: 0 auto;\n padding: var(--codex-message-list-content-padding, 0);\n box-sizing: border-box;\n}\n\n.codex-message-list__entry {\n display: contents;\n}\n\n.codex-message-list__content :deep(.chat-message),\n.codex-message-list__content :deep(.chat-compaction-message) {\n content-visibility: auto;\n contain-intrinsic-size: auto 120px;\n}\n\n.codex-message-list__empty {\n margin: auto;\n color: var(--codex-muted-text-color, var(--color-text-muted, #777b82));\n text-align: center;\n}\n\n.message-list {\n --codex-message-list-padding: var(--space-8) var(--space-16);\n --codex-message-list-gap: var(--space-8);\n --codex-message-list-content-width: var(--message-list-content-width, 100%);\n --codex-message-list-content-padding:\n calc(var(--message-list-content-padding-top, 0) + var(--space-2))\n 0\n calc(var(--message-list-content-padding-bottom, 0) + var(--space-2));\n}\n\n</style>\n","<template>\n <div\n class=\"codex-chat-theme codex-message-list\"\n :aria-label=\"ariaLabel\"\n >\n <div\n ref=\"scrollElement\"\n class=\"codex-message-list__viewport message-list\"\n @click.capture=\"handleViewportClick\"\n @pointerdown=\"handleSelectionPointerDown\"\n @scroll=\"handleScroll\"\n >\n <div class=\"codex-message-list__content\">\n <slot v-if=\"displayEntries.length === 0\" name=\"empty\">\n <p class=\"codex-message-list__empty\">{{ emptyLabel }}</p>\n </slot>\n <CodexMessageTurn\n v-for=\"group in displayGroups\"\n v-else\n :key=\"group.key\"\n :entries=\"group.entries\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :active=\"activeOverrideForGroup(group)\"\n :show-tool-blocks=\"effectivePresentation.messages.toolBlocks\"\n :status=\"group.turnId ? turnStatusById.get(group.turnId) : undefined\"\n :turn-id=\"group.turnId\"\n >\n <template v-for=\"entry in group.entries\" :key=\"entry.key\">\n <div\n class=\"codex-message-list__entry\"\n :data-codex-message-index=\"entry.index\"\n >\n <slot v-if=\"$slots.message\" name=\"message\" :message=\"chatMessageFromInput(displayMessage(entry.message, group.turnId))\" :index=\"entry.index\" />\n <CodexMessage\n v-else\n :activity-state=\"entry.activityState\"\n :actions-disabled=\"actionsDisabled\"\n :actions-always-visible=\"shouldKeepAssistantActionsVisible(entry.index)\"\n :answered-client-request-ids=\"answeredClientRequestIds\"\n :can-delete-turn=\"canDeleteTurn && isTerminalTurn(group.turnId)\"\n :can-edit-turn=\"canEditTurn && isTerminalTurn(group.turnId)\"\n :can-fork-turn=\"canForkTurn && isForkableTurn(group.turnId)\"\n :can-retry-turn=\"canRetryTurn && isTerminalTurn(group.turnId)\"\n :deleting-turn=\"group.turnId === deletingTurnId\"\n :follow-ups-disabled=\"followUpsDisabled\"\n :hidden-client-request-ids=\"hiddenClientRequestIds\"\n :index=\"entry.index\"\n :message=\"displayMessage(entry.message, group.turnId)\"\n :mention-groups=\"mentionGroups\"\n :open-image=\"openImage\"\n :plugins=\"plugins\"\n :presentation=\"presentation\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"skills\"\n :thread-actions-disabled=\"busy\"\n @cancel=\"emit('cancel')\"\n @client-response=\"emit('client-response', $event)\"\n @copy-message=\"emit('copy-message', $event)\"\n @delete-turn=\"emit('delete-turn', $event)\"\n @edit-turn=\"emit('edit-turn', $event)\"\n @fork-turn=\"emit('fork-turn', $event)\"\n @open-link=\"emit('open-link', $event)\"\n @open-visualization=\"emit('open-visualization', $event)\"\n @quote-message=\"emit('quote-message', $event)\"\n @retry-turn=\"emit('retry-turn', $event)\"\n @send-follow-up=\"emit('send-follow-up', $event)\"\n >\n <template v-if=\"$slots.actions\" #actions=\"scope\"><slot name=\"actions\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.attachment\" #attachment=\"scope\"><slot name=\"attachment\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.block\" #block=\"scope\"><slot name=\"block\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.header\" #header=\"scope\"><slot name=\"header\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.mention\" #mention=\"scope\"><slot name=\"mention\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.status\" #status=\"scope\"><slot name=\"status\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.text\" #text=\"scope\"><slot name=\"text\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.thinking\" #thinking=\"scope\"><slot name=\"thinking\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.tool\" #tool=\"scope\"><slot name=\"tool\" v-bind=\"scope\" /></template>\n </CodexMessage>\n </div>\n </template>\n </CodexMessageTurn>\n </div>\n </div>\n <CodexScrollToBottom\n v-if=\"overflown\"\n class=\"codex-message-list__scroll-to-bottom\"\n :label=\"scrollToBottomLabel\"\n @click=\"scrollToBottom\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, inject, nextTick, onBeforeUnmount, onMounted, provide, ref, shallowReactive, watch } from 'vue'\nimport { questionResponsesKey } from '../chat/message-work-state'\nimport type {\n CodexConversationRenderStrategy,\n CodexSurfacePlugin,\n CodexSurfaceSkill,\n CodexSurfaceTurn,\n SurfaceMessage,\n} from '@codex-app-sdk/core/surface'\nimport type { ClientRequestResponse, CodexConversationLink, CodexConversationPresentation } from '../chat/contracts'\nimport { resolveCodexConversationPresentation } from '../chat/contracts'\nimport type { Message } from '../chat/types'\nimport type { MessageBlock } from '../chat/message-blocks'\nimport type { CodexMessageImageOpenHandler } from '../chat/message-image'\nimport type { CodexConversationVisualization } from '../chat/visualization'\nimport type { CodexMessageTextSelection } from '../chat/message-text-selection'\nimport { chatMessageFromInput } from '../chat/renderer-message-adapter'\nimport { filterVisibleMessageTools, type CodexToolVisibility } from '../chat/tool-visibility'\nimport CodexMessage from './CodexMessage.vue'\nimport CodexMessageTurn from './CodexMessageTurn.vue'\nimport CodexScrollToBottom from './CodexScrollToBottom.vue'\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from '../chat/composer-mentions-custom'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n actionsDisabled?: boolean\n activeTurnId?: string | null\n ariaLabel?: string\n answeredClientRequestIds?: ReadonlySet<string>\n busy?: boolean\n bottomThreshold?: number\n canDeleteTurn?: boolean\n canEditTurn?: boolean\n canForkTurn?: boolean\n canRetryTurn?: boolean\n deletingTurnId?: string | null\n emptyLabel?: string\n followUpsDisabled?: boolean\n hasOlderMessages?: boolean\n hiddenClientRequestIds?: ReadonlySet<string>\n renderStrategy?: CodexConversationRenderStrategy\n /** @deprecated Use renderStrategy instead. */\n lazyMessages?: boolean\n initialMessageBatchSize?: number\n loadingOlderMessages?: boolean\n messageBatchSize?: number\n messageTextSelection?: boolean\n messages: readonly (Message | SurfaceMessage)[]\n mentionGroups?: readonly CodexComposerMentionGroup[]\n openImage?: CodexMessageImageOpenHandler\n transformMessage?: (message: Message | SurfaceMessage, index: number) => Message | SurfaceMessage\n plugins?: readonly CodexSurfacePlugin[]\n presentation?: CodexConversationPresentation\n resetKey?: string | number | null\n scrollToBottomLabel?: string\n showToolDetails?: boolean\n skills?: readonly CodexSurfaceSkill[]\n toolVisibility?: CodexToolVisibility\n turns?: readonly CodexSurfaceTurn[]\n}>(), {\n ariaLabel: 'Conversation',\n busy: false,\n bottomThreshold: 24,\n canDeleteTurn: true,\n canEditTurn: true,\n canForkTurn: false,\n canRetryTurn: true,\n emptyLabel: 'No messages yet',\n hasOlderMessages: false,\n lazyMessages: undefined,\n loadingOlderMessages: false,\n scrollToBottomLabel: 'Scroll to bottom',\n showToolDetails: undefined,\n})\n\ndefineSlots<{\n actions(props: { disabled: boolean; index: number; message: Message }): unknown\n attachment(props: {\n attachment: Extract<MessageBlock, { type: 'attachment' }>['attachment']\n block: Extract<MessageBlock, { type: 'attachment' }>\n index: number\n message: Message\n }): unknown\n block(props: { block: MessageBlock; blockIndex: number; index: number; message: Message }): unknown\n empty(): unknown\n header(props: { index: number; message: Message }): unknown\n message(props: { index: number; message: Message }): unknown\n mention(props: { group: CodexComposerMentionGroup; index: number; item: CodexComposerMentionItem; message: Message; surface: 'message' }): unknown\n status(props: { index: number; message: Message; status: 'streaming' }): unknown\n text(props: { block: Extract<MessageBlock, { type: 'text' | 'user-text' }>; content: string; index: number; message: Message; user: boolean }): unknown\n thinking(props: { index: number; message: Message }): unknown\n tool(props: {\n block: Extract<MessageBlock, { type: 'tool' | 'tool-group' }>\n index: number\n message: Message\n toolCall?: Extract<MessageBlock, { type: 'tool' }>['toolCall']\n toolCalls?: Extract<MessageBlock, { type: 'tool-group' }>['toolCalls']\n }): unknown\n}>()\nconst emit = defineEmits<{\n cancel: []\n 'client-response': [response: ClientRequestResponse]\n 'copy-message': [index: number]\n 'delete-turn': [turnId: string]\n 'edit-turn': [payload: { content: string; turnId: string }]\n 'fork-turn': [turnId: string]\n 'load-older-messages': []\n 'message-text-selection-change': [selection: CodexMessageTextSelection | null]\n 'open-link': [link: CodexConversationLink]\n 'open-visualization': [visualization: CodexConversationVisualization]\n 'quote-message': [index: number]\n 'retry-turn': [turnId: string]\n 'send-follow-up': [prompt: string]\n 'stickiness-change': [stuckToBottom: boolean]\n}>()\n// Stryker restore all\n\nconst thinkingPlaceholder: SurfaceMessage = {\n id: 'codex-thinking-placeholder',\n role: 'assistant',\n status: 'streaming',\n parts: [],\n}\nconst questionResponses = inject(questionResponsesKey, undefined)\n ?? shallowReactive(new Map<string, ClientRequestResponse['payload']>())\nprovide(questionResponsesKey, questionResponses)\nwatch(() => props.messages, (messages) => {\n const answers: Record<string, { answers: string[] }> = {}\n const requestIds = new Set<string>()\n for (const message of messages) {\n if (!('metadata' in message)) continue\n const stored = message.metadata?.asyncQuestionAnswers\n if (!stored || typeof stored !== 'object') continue\n for (const [id, value] of Object.entries(stored)) {\n if (value && typeof value === 'object' && 'answers' in value\n && Array.isArray(value.answers) && value.answers.every((answer: unknown) => typeof answer === 'string')) {\n answers[id] = { answers: value.answers }\n }\n }\n }\n for (const message of messages) {\n for (const part of message.parts ?? []) {\n if (part.type !== 'question') continue\n requestIds.add(part.request.id)\n const restored = Object.fromEntries(part.request.payload.request.questions\n .filter((question) => answers[question.id])\n .map((question) => [question.id, answers[question.id]!]))\n if (Object.keys(restored).length > 0) questionResponses.set(part.request.id, { answers: restored })\n }\n }\n for (const id of questionResponses.keys()) {\n if (!requestIds.has(id)) questionResponses.delete(id)\n }\n}, { immediate: true })\n\nconst effectiveRenderStrategy = computed<CodexConversationRenderStrategy>(() => (\n props.renderStrategy ?? (props.lazyMessages === false ? 'eager' : 'lazy')\n))\nconst effectiveInitialMessageBatchSize = computed(() => (\n props.initialMessageBatchSize ?? props.messageBatchSize ?? 50\n))\nconst effectiveMessageBatchSize = computed(() => props.messageBatchSize ?? 25)\nconst renderStartIndex = ref(initialRenderStart(\n props.messages,\n effectiveInitialMessageBatchSize.value,\n))\ntype MessageIdentity = string | object | null\ntype ConversationScrollState = {\n renderedAnchor: MessageIdentity\n scrollTop: number\n stickToBottom: boolean\n}\nconst conversationScrollStates = new Map<string | number, ConversationScrollState>()\nlet renderedAnchor = messageIdentityAt(props.messages, renderStartIndex.value)\nlet observedMessagesLength = props.messages.length\nlet observedFirstMessage = messageIdentityAt(props.messages, 0)\nlet observedLastMessage = messageIdentityAt(props.messages, props.messages.length - 1)\nconst loadingOlderMessages = ref(false)\nlet olderMessagesRequestPending = false\nconst visibleMessages = computed(() => effectiveRenderStrategy.value === 'lazy'\n ? props.messages.slice(renderStartIndex.value)\n : props.messages)\ntype DisplayEntry = {\n index: number\n message: Message | SurfaceMessage\n key: string | number\n activityState?: 'working'\n}\nconst displayEntries = computed<DisplayEntry[]>(() => {\n let lastUserIndex = -1\n for (let index = props.messages.length - 1; index >= 0; index--) {\n if (props.messages[index]?.role !== 'user') continue\n lastUserIndex = index\n break\n }\n let hiddenCurrentTurnActivity = false\n const entries: DisplayEntry[] = visibleMessages.value.flatMap((message, offset) => {\n const index = effectiveRenderStrategy.value === 'lazy' ? renderStartIndex.value + offset : offset\n const transformed = props.transformMessage?.(message, index) ?? message\n const visible = filterVisibleMessageTools(transformed, props.toolVisibility)\n if (!visible && transformed.role === 'assistant' && (\n props.activeTurnId\n ? chatMessageFromInput(transformed).turnId === props.activeTurnId\n : index > lastUserIndex\n )) hiddenCurrentTurnActivity = true\n return visible ? [{ index, message: visible, key: message.id ?? index }] : []\n })\n const hasStreamingAssistant = entries.some(({ message }) => (\n message.role === 'assistant' && (\n 'content' in message\n ? message.streaming === true\n || (message.type === 'compaction' && message.compactionStatus === 'running')\n : message.status === 'streaming'\n )\n ))\n if (props.busy && !hasStreamingAssistant) {\n const turnId = entries.length > 0\n ? chatMessageFromInput(entries.at(-1)!.message).turnId?.trim() || undefined\n : undefined\n entries.push({\n index: props.messages.length,\n message: turnId ? { ...thinkingPlaceholder, turnId } : thinkingPlaceholder,\n key: thinkingPlaceholder.id,\n ...(hiddenCurrentTurnActivity ? { activityState: 'working' } : {}),\n })\n }\n return entries\n})\nconst effectivePresentation = computed(() => resolveCodexConversationPresentation(props.presentation))\nconst displayGroups = computed(() => {\n const groups: Array<{\n entries: typeof displayEntries.value\n key: string | number\n turnId?: string\n }> = []\n for (const entry of displayEntries.value) {\n const turnId = chatMessageFromInput(entry.message).turnId?.trim() || undefined\n const previous = groups.at(-1)\n if (turnId && previous?.turnId === turnId) {\n previous.entries.push(entry)\n continue\n }\n groups.push({\n entries: [entry],\n key: turnId ? `turn:${turnId}` : entry.key,\n ...(turnId ? { turnId } : {}),\n })\n }\n const assistantTurnIds = new Set(visibleMessages.value\n .filter((message) => message.role === 'assistant')\n .map((message) => chatMessageFromInput(message).turnId?.trim()))\n for (const [index, group] of groups.entries()) {\n if (!group.turnId || group.turnId === inferredActiveTurnId.value\n || turnStatusById.value.get(group.turnId) !== 'completed'\n || assistantTurnIds.has(group.turnId)\n || !group.entries.some((entry) => entry.message.role === 'user')) continue\n // Provider snapshots may omit an empty assistant item. A confirmed\n // completed turn still deserves a visible acknowledgment, unlike idle alone.\n const id = `codex-empty-response:${group.turnId}`\n group.entries.push({\n index: props.messages.length + index + 1,\n key: id,\n message: { id, role: 'assistant', status: 'complete', turnId: group.turnId, parts: [] },\n })\n }\n return groups\n})\n\nfunction activeOverrideForGroup(group: (typeof displayGroups.value)[number]): boolean | undefined {\n if (props.busy && group.entries.some(({ index, message }) => (\n index < props.messages.length\n && message.role === 'assistant'\n && chatMessageFromInput(message).streaming === true\n ))) return true\n if (props.activeTurnId === undefined) return undefined\n return group.turnId !== undefined && group.turnId === props.activeTurnId\n}\nconst inferredActiveTurnId = computed(() => {\n if (props.activeTurnId !== undefined && props.activeTurnId !== null) return props.activeTurnId\n const streamingTurnId = props.busy\n ? [...props.messages]\n .reverse()\n .map(chatMessageFromInput)\n .find((message) => message.role === 'assistant' && message.streaming)\n ?.turnId?.trim()\n : undefined\n return streamingTurnId || null\n})\nconst turnStatusById = computed(() => new Map(\n props.turns?.map((turn) => [turn.id, turn.status] as const) ?? [],\n))\n\nfunction isTerminalTurn(turnId: string | undefined): boolean {\n if (!turnId || turnId === inferredActiveTurnId.value) return false\n return turnStatusById.value.get(turnId) !== 'inProgress'\n}\n\nfunction displayMessage(message: Message | SurfaceMessage, turnId: string | undefined): Message | SurfaceMessage {\n const status = turnId ? turnStatusById.value.get(turnId) : undefined\n if (!status || status === 'inProgress' || turnId === inferredActiveTurnId.value) return message\n if ('content' in message) {\n return message.streaming ? { ...message, streaming: false } : message\n }\n return message.status === 'streaming'\n ? { ...message, status: 'complete' }\n : message\n}\n\nfunction isForkableTurn(turnId: string | undefined): boolean {\n if (!isTerminalTurn(turnId)) return false\n const status = turnStatusById.value.get(turnId!)\n return status === undefined || status === 'completed'\n}\nconst latestAssistantIndex = computed(() => [...displayEntries.value]\n .reverse()\n .find((entry) => entry.message.role === 'assistant')\n ?.index)\n\nfunction shouldKeepAssistantActionsVisible(index: number): boolean {\n return index === latestAssistantIndex.value\n}\n\nconst scrollElement = ref<HTMLElement | null>(null)\nconst tail = ref(true)\nconst overflown = ref(false)\nlet contentResizeObserver: ResizeObserver | null = null\nlet scrollFrame: number | ReturnType<typeof setTimeout> | null = null\nlet lastScrollTop = 0\nlet pointerSelecting = false\nlet lastTextSelection: CodexMessageTextSelection | null = null\n\nonMounted(async () => {\n document.addEventListener('pointerup', handleSelectionPointerUp)\n document.addEventListener('selectionchange', handleDocumentSelectionChange)\n await nextTick()\n scrollToBottom()\n const content = scrollElement.value?.querySelector('.codex-message-list__content')\n if (content && typeof ResizeObserver !== 'undefined') {\n contentResizeObserver = new ResizeObserver(() => {\n if (tail.value) queueScrollToBottom()\n else updateOverflow()\n })\n contentResizeObserver.observe(content)\n }\n queueScrollToBottom()\n})\n\nwatch(() => props.messages.length, async (nextLength) => {\n const previousLength = observedMessagesLength\n const target = scrollElement.value!\n const previousHeight = target.scrollHeight\n const previousTop = target.scrollTop\n observedMessagesLength = nextLength\n const revealedPrependedMessages = effectiveRenderStrategy.value === 'lazy'\n ? reconcileMessageWindow(nextLength, previousLength)\n : false\n observeMessageBounds()\n const shouldScroll = !revealedPrependedMessages && tail.value && isAtBottom()\n await nextTick()\n if (revealedPrependedMessages && target) {\n target.scrollTop = previousTop + target.scrollHeight - previousHeight\n } else if (shouldScroll) {\n scrollToBottom()\n }\n})\n\nwatch(\n [() => props.resetKey, () => props.messages.length, () => props.messages.at(-1)] as const,\n ([conversationKey, length, message], [previousConversationKey, previousLength, previousMessage]) => {\n if (conversationKey !== previousConversationKey || length !== previousLength || !message || !previousMessage) return\n if (message.id && previousMessage.id && message.id !== previousMessage.id) return\n onNewChunk()\n },\n)\n\nwatch(() => props.messageTextSelection, (enabled) => {\n if (!enabled) clearMessageTextSelection()\n})\n\nwatch(() => props.resetKey, async (nextKey, previousKey) => {\n clearMessageTextSelection()\n const target = scrollElement.value\n if (target && previousKey !== null && previousKey !== undefined) {\n conversationScrollStates.set(previousKey, {\n renderedAnchor,\n scrollTop: target.scrollTop,\n stickToBottom: isAtBottom(),\n })\n }\n const restoredState = nextKey === null || nextKey === undefined\n ? undefined\n : conversationScrollStates.get(nextKey)\n const restoredAnchorIndex = restoredState\n ? findMessageIndex(props.messages, restoredState.renderedAnchor)\n : -1\n setRenderStartIndex(restoredAnchorIndex >= 0\n ? restoredAnchorIndex\n : initialRenderStart(props.messages, effectiveInitialMessageBatchSize.value))\n loadingOlderMessages.value = false\n olderMessagesRequestPending = false\n setTail(restoredState?.stickToBottom ?? true)\n observeMessageBounds()\n await nextTick()\n if (restoredState && target) {\n target.scrollTop = restoredState.stickToBottom\n ? target.scrollHeight\n : restoredState.scrollTop\n updateOverflow()\n } else {\n scrollToBottom()\n }\n})\n\nwatch(() => [props.loadingOlderMessages, props.hasOlderMessages] as const, () => {\n olderMessagesRequestPending = false\n})\n\nwatch(() => [effectiveRenderStrategy.value, effectiveInitialMessageBatchSize.value, effectiveMessageBatchSize.value] as const, async () => {\n if (effectiveRenderStrategy.value === 'lazy') {\n setRenderStartIndex(initialRenderStart(props.messages, effectiveInitialMessageBatchSize.value))\n observeMessageBounds()\n await nextTick()\n if (tail.value) scrollToBottom()\n }\n})\n\nfunction handleScroll(): void {\n clearMessageTextSelection()\n const target = scrollElement.value\n const scrolledUp = target !== null && target.scrollTop < lastScrollTop\n if (target) lastScrollTop = target.scrollTop\n updateOverflow()\n if (!overflown.value) setTail(true)\n else if (scrolledUp) setTail(false)\n if (effectiveRenderStrategy.value === 'lazy' && isWithinTopPrefetchRange() && renderStartIndex.value <= 0 && props.hasOlderMessages && !props.loadingOlderMessages) {\n requestOlderMessages()\n } else if (effectiveRenderStrategy.value === 'lazy' && isWithinTopPrefetchRange()) {\n void loadOlderMessages()\n }\n}\n\nfunction onNewChunk(): void {\n if (tail.value) queueScrollToBottom()\n else void nextTick(updateOverflow)\n}\n\nfunction handleViewportClick(event: MouseEvent): void {\n const target = event.target\n if (!(target instanceof Element) || !target.closest('.chat-work-group__header')) return\n setTail(false)\n}\n\nfunction handleSelectionPointerDown(): void {\n if (props.messageTextSelection) pointerSelecting = true\n}\n\nfunction handleSelectionPointerUp(): void {\n if (!pointerSelecting) return\n pointerSelecting = false\n updateMessageTextSelection()\n}\n\nfunction handleDocumentSelectionChange(): void {\n if (!props.messageTextSelection || pointerSelecting) return\n updateMessageTextSelection()\n}\n\nfunction updateMessageTextSelection(): void {\n if (!props.messageTextSelection) {\n clearMessageTextSelection()\n return\n }\n const selection = window.getSelection()\n if (!selection || selection.isCollapsed || selection.rangeCount === 0) {\n clearMessageTextSelection()\n return\n }\n const text = selection.toString().trim()\n const range = selection.getRangeAt(0)\n const startEntry = messageEntryForNode(range.startContainer)\n const endEntry = messageEntryForNode(range.endContainer)\n if (!text || !startEntry || startEntry !== endEntry) {\n clearMessageTextSelection()\n return\n }\n const messageIndex = Number.parseInt(startEntry.dataset.codexMessageIndex ?? '', 10)\n const entry = displayEntries.value.find((candidate) => candidate.index === messageIndex)\n if (!entry) {\n clearMessageTextSelection()\n return\n }\n const rect = range.getBoundingClientRect()\n const message = chatMessageFromInput(entry.message)\n const next: CodexMessageTextSelection = {\n anchor: { x: rect.left, y: rect.top, width: rect.width, height: rect.height },\n messageIndex,\n role: message.role,\n text,\n ...(message.id ? { messageId: message.id } : {}),\n ...(message.turnId ? { turnId: message.turnId } : {}),\n }\n if (sameTextSelection(lastTextSelection, next)) return\n lastTextSelection = next\n emit('message-text-selection-change', next)\n}\n\nfunction messageEntryForNode(node: Node): HTMLElement | null {\n const element = node instanceof Element ? node : node.parentElement\n const entry = element?.closest<HTMLElement>('[data-codex-message-index]') ?? null\n return entry && scrollElement.value?.contains(entry) ? entry : null\n}\n\nfunction clearMessageTextSelection(): void {\n pointerSelecting = false\n if (!lastTextSelection) return\n lastTextSelection = null\n emit('message-text-selection-change', null)\n}\n\nfunction sameTextSelection(\n left: CodexMessageTextSelection | null,\n right: CodexMessageTextSelection,\n): boolean {\n return Boolean(left\n && left.text === right.text\n && left.messageIndex === right.messageIndex\n && left.anchor.x === right.anchor.x\n && left.anchor.y === right.anchor.y\n && left.anchor.width === right.anchor.width\n && left.anchor.height === right.anchor.height)\n}\n\nfunction requestOlderMessages(): void {\n if (!props.hasOlderMessages || props.loadingOlderMessages || olderMessagesRequestPending) return\n olderMessagesRequestPending = true\n emit('load-older-messages')\n}\n\nfunction isWithinTopPrefetchRange(): boolean {\n const target = scrollElement.value\n return target !== null && target.scrollTop <= target.clientHeight\n}\n\nasync function loadOlderMessages(): Promise<void> {\n if (loadingOlderMessages.value || renderStartIndex.value <= 0) return\n const target = scrollElement.value!\n const previousHeight = target.scrollHeight\n const previousTop = target.scrollTop\n loadingOlderMessages.value = true\n setRenderStartIndex(Math.max(0, renderStartIndex.value - normalizedBatchSize(effectiveMessageBatchSize.value)))\n await nextTick()\n target.scrollTop = previousTop + target.scrollHeight - previousHeight\n loadingOlderMessages.value = false\n if (renderStartIndex.value <= 0) requestOlderMessages()\n}\n\nfunction reconcileMessageWindow(nextLength: number, previousLength: number): boolean {\n const batchSize = normalizedBatchSize(effectiveInitialMessageBatchSize.value)\n const previousTailStart = turnAlignedStart(props.messages.slice(0, previousLength), Math.max(0, previousLength - batchSize))\n const wasTailWindow = renderStartIndex.value === previousTailStart\n if (nextLength < previousLength) {\n setRenderStartIndex(initialRenderStart(props.messages, effectiveInitialMessageBatchSize.value))\n return false\n }\n\n const anchorIndex = findMessageIndex(props.messages, renderedAnchor)\n const hasPrependedMessages = anchorIndex >= 0 && !sameMessageIdentity(\n messageIdentityAt(props.messages, 0),\n observedFirstMessage,\n );\n if (hasPrependedMessages) {\n // Once the viewport is pinned at the rendered top, another upward gesture\n // cannot fire a scroll event. Reveal the first server-prepended batch now.\n const revealOlderBatch = renderStartIndex.value <= 0 && isWithinTopPrefetchRange()\n setRenderStartIndex(revealOlderBatch\n ? Math.max(0, anchorIndex - normalizedBatchSize(effectiveMessageBatchSize.value))\n : isAtBottom()\n ? Math.max(0, nextLength - batchSize)\n : anchorIndex)\n return revealOlderBatch\n }\n\n const hasAppendedMessages = sameMessageIdentity(\n messageIdentityAt(props.messages, 0),\n observedFirstMessage,\n ) && !sameMessageIdentity(\n messageIdentityAt(props.messages, nextLength - 1),\n observedLastMessage,\n );\n if (hasAppendedMessages && isAtBottom() && wasTailWindow) {\n setRenderStartIndex(Math.max(0, nextLength - batchSize))\n }\n return false\n}\n\nfunction setRenderStartIndex(nextIndex: number): void {\n const alignedIndex = turnAlignedStart(props.messages, nextIndex)\n renderStartIndex.value = alignedIndex\n renderedAnchor = messageIdentityAt(props.messages, alignedIndex)\n}\n\nfunction observeMessageBounds(): void {\n observedMessagesLength = props.messages.length\n observedFirstMessage = messageIdentityAt(props.messages, 0)\n observedLastMessage = messageIdentityAt(props.messages, props.messages.length - 1)\n}\n\nfunction messageIdentityAt(messages: readonly (Message | SurfaceMessage)[], index: number): MessageIdentity {\n const message = messages[index]\n return message ? message.id ?? message : null\n}\n\nfunction sameMessageIdentity(left: MessageIdentity, right: MessageIdentity): boolean {\n return left === right\n}\n\nfunction findMessageIndex(messages: readonly (Message | SurfaceMessage)[], identity: MessageIdentity): number {\n return messages.findIndex((message) => sameMessageIdentity(message.id ?? message, identity))\n}\n\nfunction normalizedBatchSize(value: number | undefined): number {\n return Math.max(1, Math.floor(value ?? 25))\n}\n\nfunction initialRenderStart(\n messages: readonly (Message | SurfaceMessage)[],\n batchSize: number | undefined,\n): number {\n return tailRenderStart(messages, normalizedBatchSize(batchSize))\n}\n\nfunction tailRenderStart(messages: readonly (Message | SurfaceMessage)[], batchSize: number): number {\n return turnAlignedStart(messages, Math.max(0, messages.length - batchSize))\n}\n\nfunction turnAlignedStart(messages: readonly (Message | SurfaceMessage)[], candidate: number): number {\n let start = Math.max(0, Math.min(messages.length, candidate))\n if (start >= messages.length) return start\n const turnId = chatMessageFromInput(messages[start]!).turnId?.trim()\n if (!turnId) return start\n while (start > 0 && chatMessageFromInput(messages[start - 1]!).turnId?.trim() === turnId) start -= 1\n return start\n}\n\nfunction setTail(next: boolean): void {\n if (tail.value !== next) {\n tail.value = next\n emit('stickiness-change', next)\n }\n}\n\nfunction updateOverflow(): void {\n overflown.value = !isAtBottom()\n}\n\nfunction isAtBottom(): boolean {\n const target = scrollElement.value\n return target\n ? target.scrollHeight - target.scrollTop - target.clientHeight <= props.bottomThreshold\n : tail.value\n}\n\nfunction scrollToBottom(): void {\n if (!scrollElement.value) {\n return\n }\n scrollElement.value.scrollTop = scrollElement.value.scrollHeight\n lastScrollTop = scrollElement.value.scrollTop\n setTail(true)\n updateOverflow()\n}\n\nfunction queueScrollToBottom(): void {\n if (scrollFrame !== null) return\n const callback = () => {\n scrollFrame = null\n if (tail.value) scrollToBottom()\n }\n scrollFrame = typeof requestAnimationFrame === 'function'\n ? requestAnimationFrame(callback)\n : setTimeout(callback, 0)\n}\n\nonBeforeUnmount(() => {\n document.removeEventListener('pointerup', handleSelectionPointerUp)\n document.removeEventListener('selectionchange', handleDocumentSelectionChange)\n contentResizeObserver?.disconnect()\n contentResizeObserver = null\n if (scrollFrame !== null) {\n if (typeof scrollFrame === 'number' && typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(scrollFrame)\n } else {\n clearTimeout(scrollFrame)\n }\n }\n})\n\ndefineExpose({ scrollToBottom })\n</script>\n\n<style scoped>\n.codex-message-list {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.codex-message-list__viewport {\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n padding: var(--codex-message-list-padding, 24px 16px);\n overflow-y: auto;\n scrollbar-width: thin;\n box-sizing: border-box;\n}\n\n.codex-message-list__scroll-to-bottom {\n position: absolute;\n right: 50%;\n bottom: var(--codex-scroll-to-bottom-offset, var(--space-8));\n z-index: 1;\n transform: translateX(50%);\n}\n\n.codex-message-list__scroll-to-bottom:active {\n transform: translateX(50%) scale(0.96);\n}\n\n.codex-message-list__content {\n display: flex;\n flex-direction: column;\n gap: var(--codex-message-list-gap, 12px);\n width: min(100%, var(--codex-message-list-content-width, 900px));\n margin: 0 auto;\n padding: var(--codex-message-list-content-padding, 0);\n box-sizing: border-box;\n}\n\n.codex-message-list__entry {\n display: contents;\n}\n\n.codex-message-list__content :deep(.chat-message),\n.codex-message-list__content :deep(.chat-compaction-message) {\n content-visibility: auto;\n contain-intrinsic-size: auto 120px;\n}\n\n.codex-message-list__empty {\n margin: auto;\n color: var(--codex-muted-text-color, var(--color-text-muted, #777b82));\n text-align: center;\n}\n\n.message-list {\n --codex-message-list-padding: var(--space-8) var(--space-16);\n --codex-message-list-gap: var(--space-8);\n --codex-message-list-content-width: var(--message-list-content-width, 100%);\n --codex-message-list-content-padding:\n calc(var(--message-list-content-padding-top, 0) + var(--space-2))\n 0\n calc(var(--message-list-content-padding-bottom, 0) + var(--space-2));\n}\n\n</style>\n","<template>\n <section class=\"codex-chat-theme codex-workbench-layout\" :class=\"`codex-workbench-layout--${scrollMode}`\" :style=\"layoutStyle\">\n <div v-if=\"scrollMode === 'body'\" class=\"codex-workbench-layout__body codex-workbench-layout__body--scroll\">\n <div class=\"codex-workbench-layout__body-content\">\n <slot />\n </div>\n </div>\n\n <div v-else class=\"codex-workbench-layout__body codex-workbench-layout__body--child\">\n <slot />\n </div>\n\n <div\n v-if=\"$slots.header\"\n ref=\"headerEl\"\n class=\"codex-workbench-layout__header\"\n >\n <slot name=\"header\" />\n </div>\n\n <div\n v-if=\"$slots.footer\"\n ref=\"footerEl\"\n class=\"codex-workbench-layout__footer\"\n >\n <slot name=\"footer\" />\n </div>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n scrollMode?: 'body' | 'child'\n}>(), {\n scrollMode: 'body',\n})\n// Stryker restore all\n\nconst headerEl = ref<HTMLElement | null>(null)\nconst footerEl = ref<HTMLElement | null>(null)\nconst headerOffset = ref(0)\nconst footerOffset = ref(0)\n\nconst layoutStyle = computed(() => ({\n '--workbench-layout-header-offset': `${headerOffset.value}px`,\n '--workbench-layout-footer-offset': `${footerOffset.value}px`,\n}))\n\nlet resizeObserver: ResizeObserver | null = null\n\nonMounted(() => {\n measureChrome()\n\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n measureChrome()\n })\n observeChrome()\n }\n})\n\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n})\n\nfunction observeChrome() {\n const observer = resizeObserver!\n observer.disconnect()\n\n if (headerEl.value) {\n observer.observe(headerEl.value)\n }\n\n if (footerEl.value) {\n observer.observe(footerEl.value)\n }\n}\n\nfunction measureChrome() {\n headerOffset.value = headerEl.value?.offsetHeight ?? 0\n footerOffset.value = footerEl.value?.offsetHeight ?? 0\n}\n</script>\n\n<style scoped>\n.codex-workbench-layout {\n height: 100%;\n min-height: 0;\n display: grid;\n}\n\n.codex-workbench-layout__header,\n.codex-workbench-layout__footer,\n.codex-workbench-layout__body {\n grid-area: 1 / 1;\n}\n\n.codex-workbench-layout__body {\n display: flex;\n flex-direction: column;\n min-height: 0;\n height: 100%;\n}\n\n.codex-workbench-layout__header {\n align-self: start;\n z-index: 1;\n margin-right: var(--workbench-layout-scrollbar-gutter, var(--space-8));\n padding: var(--workbench-layout-header-padding, var(--space-12) var(--space-16));\n background: var(--workbench-layout-header-background, var(--color-surface-lowest));\n}\n\n.codex-workbench-layout__footer {\n align-self: end;\n z-index: 1;\n margin-right: var(--workbench-layout-scrollbar-gutter, var(--space-8));\n padding: var(--workbench-layout-footer-padding, var(--space-8));\n background: var(--workbench-layout-footer-background, var(--color-surface-lowest));\n}\n\n.codex-workbench-layout__body--child {\n overflow: hidden;\n}\n\n.codex-workbench-layout__body--scroll {\n overflow: auto;\n scrollbar-width: thin;\n}\n\n.codex-workbench-layout__body-content {\n display: flex;\n flex-direction: column;\n gap: var(--workbench-layout-body-gap, var(--space-8));\n min-height: 100%;\n padding:\n calc(var(--workbench-layout-header-offset) + var(--workbench-layout-body-padding-top, 0px))\n var(--workbench-layout-body-padding-inline, 0px)\n calc(var(--workbench-layout-footer-offset) + var(--workbench-layout-body-padding-bottom, 0px));\n}\n</style>\n","<template>\n <section class=\"codex-chat-theme codex-workbench-layout\" :class=\"`codex-workbench-layout--${scrollMode}`\" :style=\"layoutStyle\">\n <div v-if=\"scrollMode === 'body'\" class=\"codex-workbench-layout__body codex-workbench-layout__body--scroll\">\n <div class=\"codex-workbench-layout__body-content\">\n <slot />\n </div>\n </div>\n\n <div v-else class=\"codex-workbench-layout__body codex-workbench-layout__body--child\">\n <slot />\n </div>\n\n <div\n v-if=\"$slots.header\"\n ref=\"headerEl\"\n class=\"codex-workbench-layout__header\"\n >\n <slot name=\"header\" />\n </div>\n\n <div\n v-if=\"$slots.footer\"\n ref=\"footerEl\"\n class=\"codex-workbench-layout__footer\"\n >\n <slot name=\"footer\" />\n </div>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n scrollMode?: 'body' | 'child'\n}>(), {\n scrollMode: 'body',\n})\n// Stryker restore all\n\nconst headerEl = ref<HTMLElement | null>(null)\nconst footerEl = ref<HTMLElement | null>(null)\nconst headerOffset = ref(0)\nconst footerOffset = ref(0)\n\nconst layoutStyle = computed(() => ({\n '--workbench-layout-header-offset': `${headerOffset.value}px`,\n '--workbench-layout-footer-offset': `${footerOffset.value}px`,\n}))\n\nlet resizeObserver: ResizeObserver | null = null\n\nonMounted(() => {\n measureChrome()\n\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n measureChrome()\n })\n observeChrome()\n }\n})\n\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n})\n\nfunction observeChrome() {\n const observer = resizeObserver!\n observer.disconnect()\n\n if (headerEl.value) {\n observer.observe(headerEl.value)\n }\n\n if (footerEl.value) {\n observer.observe(footerEl.value)\n }\n}\n\nfunction measureChrome() {\n headerOffset.value = headerEl.value?.offsetHeight ?? 0\n footerOffset.value = footerEl.value?.offsetHeight ?? 0\n}\n</script>\n\n<style scoped>\n.codex-workbench-layout {\n height: 100%;\n min-height: 0;\n display: grid;\n}\n\n.codex-workbench-layout__header,\n.codex-workbench-layout__footer,\n.codex-workbench-layout__body {\n grid-area: 1 / 1;\n}\n\n.codex-workbench-layout__body {\n display: flex;\n flex-direction: column;\n min-height: 0;\n height: 100%;\n}\n\n.codex-workbench-layout__header {\n align-self: start;\n z-index: 1;\n margin-right: var(--workbench-layout-scrollbar-gutter, var(--space-8));\n padding: var(--workbench-layout-header-padding, var(--space-12) var(--space-16));\n background: var(--workbench-layout-header-background, var(--color-surface-lowest));\n}\n\n.codex-workbench-layout__footer {\n align-self: end;\n z-index: 1;\n margin-right: var(--workbench-layout-scrollbar-gutter, var(--space-8));\n padding: var(--workbench-layout-footer-padding, var(--space-8));\n background: var(--workbench-layout-footer-background, var(--color-surface-lowest));\n}\n\n.codex-workbench-layout__body--child {\n overflow: hidden;\n}\n\n.codex-workbench-layout__body--scroll {\n overflow: auto;\n scrollbar-width: thin;\n}\n\n.codex-workbench-layout__body-content {\n display: flex;\n flex-direction: column;\n gap: var(--workbench-layout-body-gap, var(--space-8));\n min-height: 100%;\n padding:\n calc(var(--workbench-layout-header-offset) + var(--workbench-layout-body-padding-top, 0px))\n var(--workbench-layout-body-padding-inline, 0px)\n calc(var(--workbench-layout-footer-offset) + var(--workbench-layout-body-padding-bottom, 0px));\n}\n</style>\n","<template>\n <section\n ref=\"paneElement\"\n class=\"codex-chat-theme codex-conversation-pane\"\n :aria-busy=\"effectiveTranscriptBusy || effectiveHistoryLoading\"\n :aria-label=\"ariaLabel\"\n :data-codex-generating=\"effectiveTranscriptBusy ? 'true' : undefined\"\n @click=\"handleConversationClick\"\n @dragover=\"handleDragOver\"\n @drop=\"handleDrop\"\n @paste.capture=\"handlePaste\"\n >\n <CodexConversationHistoryLoader\n v-if=\"showHistoryLoader\"\n class=\"codex-conversation-pane__history-loader\"\n />\n\n <CodexWorkbenchLayout\n v-else\n class=\"codex-conversation-pane__layout\"\n scroll-mode=\"child\"\n >\n <CodexMessageList\n v-if=\"started\"\n ref=\"messageList\"\n class=\"codex-conversation-pane__messages\"\n :actions-disabled=\"effectiveActionsDisabled\"\n :active-turn-id=\"effectiveActiveTurnId\"\n :answered-client-request-ids=\"displayAnsweredClientRequestIds\"\n :aria-label=\"ariaLabel\"\n :busy=\"effectiveTranscriptBusy\"\n :can-delete-turn=\"effectiveCanDeleteTurn\"\n :can-edit-turn=\"effectiveCanEditTurn\"\n :can-fork-turn=\"effectiveCanForkTurn\"\n :can-retry-turn=\"effectiveCanRetryTurn\"\n :deleting-turn-id=\"deletingTurnId\"\n :empty-label=\"emptyTitle\"\n :follow-ups-disabled=\"effectiveFollowUpsDisabled\"\n :has-older-messages=\"effectiveHasOlderHistory\"\n :hidden-client-request-ids=\"hiddenQuestionRequestIds\"\n :render-strategy=\"effectiveRenderStrategy\"\n :loading-older-messages=\"effectiveLoadingOlderHistory\"\n :initial-message-batch-size=\"initialMessageBatchSize\"\n :message-batch-size=\"messageBatchSize\"\n :message-text-selection=\"messageTextSelection\"\n :messages=\"effectiveMessages\"\n :mention-groups=\"effectiveMentionGroups\"\n :open-image=\"openImage\"\n :plugins=\"effectivePlugins\"\n :presentation=\"effectivePresentation\"\n :reset-key=\"effectiveConversationKey\"\n :scroll-to-bottom-label=\"scrollToBottomLabel\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"effectiveSkills\"\n :tool-visibility=\"toolVisibility\"\n :transform-message=\"dismissedQuestionIds.size > 0 || activeComposerRequestItemIds.size > 0 ? transformTranscriptMessage : transformMessage\"\n :turns=\"effectiveTurns\"\n @cancel=\"cancel\"\n @client-response=\"respondToClientRequest\"\n @copy-message=\"copyMessage\"\n @delete-turn=\"deleteTurn\"\n @edit-turn=\"editTurn\"\n @fork-turn=\"forkTurn\"\n @load-older-messages=\"loadOlderHistory\"\n @message-text-selection-change=\"emit('messageTextSelectionChange', $event)\"\n @open-link=\"handleConversationLink\"\n @open-visualization=\"handleVisualization\"\n @quote-message=\"quoteMessage\"\n @retry-turn=\"retryTurn\"\n @send-follow-up=\"sendFollowUp\"\n >\n <template v-if=\"$slots.message\" #message=\"scope\"><slot name=\"message\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-actions']\" #actions=\"scope\"><slot name=\"message-actions\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-attachment']\" #attachment=\"scope\"><slot name=\"message-attachment\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-block']\" #block=\"scope\"><slot name=\"message-block\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-header']\" #header=\"scope\"><slot name=\"message-header\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.mention\" #mention=\"scope\"><slot name=\"mention\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-status']\" #status=\"scope\"><slot name=\"message-status\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-text']\" #text=\"scope\"><slot name=\"message-text\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-thinking']\" #thinking=\"scope\"><slot name=\"message-thinking\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-tool']\" #tool=\"scope\"><slot name=\"message-tool\" v-bind=\"scope\" /></template>\n </CodexMessageList>\n\n <div v-else class=\"codex-conversation-pane__hero\">\n <slot name=\"empty\" :title=\"emptyTitle\" :description=\"emptyDescription\">\n <div class=\"codex-conversation-pane__hero-copy\">\n <h1>{{ emptyTitle }}</h1>\n <p v-if=\"emptyDescription\">{{ emptyDescription }}</p>\n </div>\n </slot>\n </div>\n\n <template #footer>\n <footer ref=\"footerElement\" class=\"codex-conversation-pane__footer\">\n <p v-if=\"effectiveError\" class=\"codex-conversation-pane__error\" role=\"alert\">{{ effectiveError }}</p>\n <div v-if=\"activeApproval\" class=\"codex-conversation-pane__approvals\">\n <slot name=\"approval\" :approval=\"activeApproval\">\n <CodexApprovalPrompt\n :key=\"activeApproval.id\"\n :approval=\"activeApproval\"\n :disabled=\"effectiveDisabled\"\n @resolve=\"(decision, scope) => resolveApproval(activeApproval!.id, decision, scope)\"\n />\n </slot>\n </div>\n <ChatConfirmationRequest\n v-else-if=\"activeConfirmation\"\n :key=\"activeConfirmation.id\"\n class=\"codex-conversation-pane__confirmation-composer\"\n :request=\"activeConfirmation\"\n @client-response=\"respondToClientRequest\"\n />\n <ChatQuestionRequest\n v-else-if=\"expandedQuestionRequest\"\n :key=\"expandedQuestionRequest.id\"\n class=\"codex-conversation-pane__question-composer\"\n :answered-client-request-ids=\"displayAnsweredClientRequestIds\"\n :request=\"expandedQuestionRequest\"\n @client-response=\"respondToClientRequest\"\n />\n <template v-else>\n <slot name=\"before-composer\" />\n <ChatComposerShelf\n class=\"codex-conversation-pane__composer-shelf\"\n :disabled=\"effectiveDisabled\"\n :goal=\"effectiveGoal\"\n :presentation=\"effectivePresentation.shelf\"\n :queued-prompts=\"effectiveQueuedPrompts\"\n :queued-prompt-edit-disabled=\"localDraft.length > 0\"\n :queued-prompt-steer-disabled=\"!effectiveCapabilities.steerPrompt\"\n :turn-git-diff=\"effectiveTurnGitDiff\"\n @clear-goal=\"clearGoal\"\n @delete-queued-prompt=\"deleteQueuedPrompt\"\n @edit-queued-prompt=\"editQueuedPrompt\"\n @edit-goal=\"editGoal\"\n @steer-queued-prompt=\"steerQueuedPrompt\"\n >\n <template v-if=\"$slots['composer-shelf-actions']\" #actions=\"scope\">\n <slot name=\"composer-shelf-actions\" v-bind=\"scope\" />\n </template>\n </ChatComposerShelf>\n <CodexComposer\n :key=\"effectiveConversationKey ?? 'no-conversation'\"\n ref=\"composer\"\n class=\"codex-conversation-pane__composer\"\n :autofocus=\"autofocus\"\n :attach-enabled=\"effectiveAttachEnabled\"\n :capabilities=\"effectiveCapabilities\"\n :can-continue-interrupted-turn=\"canContinueInterruptedTurn\"\n :commands=\"effectiveCommands\"\n :composer-state=\"localComposerState\"\n :context-usage=\"effectiveContextUsage\"\n :disabled=\"effectiveDisabled\"\n :draft=\"localDraft\"\n :empty-send-prompt=\"emptySendPrompt\"\n :files=\"effectiveFiles\"\n :has-attachments=\"selectedAttachments.length > 0\"\n :has-external-content=\"hasComposerContext\"\n :interrupt-armed=\"escapeInterruptArmed\"\n :plugins=\"effectivePlugins\"\n :prompt-history=\"effectivePromptHistory\"\n :prompt-history-loading=\"promptHistoryLoading\"\n :queued-prompt-id=\"effectiveQueuedPrompts[0]?.id ?? null\"\n :is-sending=\"effectiveBusy\"\n :leading-menu-items=\"effectiveLeadingMenuItems\"\n :menu-items=\"effectiveMenuItems\"\n :model-menu-items=\"effectiveModelMenuItems\"\n :mention-groups=\"effectiveMentionGroups\"\n :model-catalog-status=\"effectiveModelCatalogStatus\"\n :models=\"effectiveModels\"\n :placeholder=\"effectivePlaceholder\"\n :approval-preset=\"effectiveApprovalPreset\"\n :plan-mode=\"effectivePlanMode\"\n :presentation=\"effectivePresentation\"\n :selected-model-id=\"effectiveSelectedModelId\"\n :selected-reasoning-effort=\"effectiveSelectedReasoningEffort\"\n :selected-service-tier=\"effectiveSelectedServiceTier\"\n :skill-catalog-status=\"effectiveSkillCatalogStatus\"\n :skills=\"effectiveSkills\"\n :transcribe-audio=\"transcribeAudio\"\n @error=\"handleComposerError\"\n @attach=\"selectAttachments\"\n @continue-interrupted-turn=\"continueInterruptedTurn\"\n @interrupt=\"interrupt\"\n @menu-select=\"menuSelect\"\n @mention-select=\"mentionSelect\"\n @select-approval-preset=\"selectApprovalPreset\"\n @send=\"submit\"\n @steer=\"steer\"\n @steer-queued-prompt=\"steerQueuedPrompt\"\n @update:model-id=\"updateModelId\"\n @update:composer-state=\"updateComposerState\"\n @update:plan-mode=\"updatePlanMode\"\n @update:reasoning-effort=\"updateReasoningEffort\"\n @update:service-tier=\"updateServiceTier\"\n >\n <template #before-meta>\n <span\n v-if=\"pendingQuestionRequests.length > 0\"\n class=\"codex-conversation-pane__pending-question\"\n >\n <button\n class=\"codex-conversation-pane__pending-question-cancel\"\n type=\"button\"\n aria-label=\"Cancel pending question\"\n @click=\"cancelPendingQuestion(pendingQuestionRequests[0]!.id)\"\n >\n <MessageQuestionIcon class=\"codex-conversation-pane__pending-question-icon\" aria-hidden=\"true\" />\n <CircleXIcon class=\"codex-conversation-pane__pending-question-remove\" aria-hidden=\"true\" />\n </button>\n <button\n class=\"codex-conversation-pane__pending-question-open\"\n type=\"button\"\n :aria-label=\"pendingQuestionRequests.length === 1 ? 'Pending question' : `${pendingQuestionRequests.length} pending questions`\"\n @click=\"openedQuestionId = pendingQuestionRequests[0]!.id\"\n >\n {{ pendingQuestionRequests.length === 1 ? 'Pending question' : `${pendingQuestionRequests.length} pending questions` }}\n </button>\n </span>\n </template>\n <template #before>\n <div\n v-if=\"selectedAttachments.length > 0\"\n class=\"codex-conversation-pane__attachments\"\n aria-label=\"Prompt attachments\"\n >\n <div\n v-for=\"(attachment, index) in selectedAttachments\"\n :key=\"attachment.id\"\n class=\"codex-conversation-pane__attachment\"\n >\n <img\n v-if=\"attachment.previewUrl\"\n class=\"codex-conversation-pane__attachment-preview\"\n :src=\"attachment.previewUrl\"\n :alt=\"attachment.name\"\n >\n <span v-else class=\"codex-conversation-pane__attachment-file\" aria-hidden=\"true\">📎</span>\n <span class=\"codex-conversation-pane__attachment-name\" :title=\"attachment.name\">\n {{ attachment.name }}\n </span>\n <span class=\"codex-conversation-pane__attachment-actions\">\n <slot\n name=\"composer-attachment-actions\"\n :attachments=\"selectedAttachments\"\n :index=\"index\"\n :disabled=\"effectiveDisabled\"\n />\n <button\n type=\"button\"\n class=\"codex-conversation-pane__attachment-remove\"\n :aria-label=\"`Remove ${attachment.name}`\"\n :disabled=\"effectiveDisabled\"\n @click=\"removeAttachment(attachment.id)\"\n >\n <XIcon aria-hidden=\"true\" />\n </button>\n </span>\n </div>\n </div>\n <slot name=\"composer-context\" :disabled=\"effectiveDisabled\" />\n </template>\n <template v-if=\"$slots['menu-icon']\" #menu-icon=\"scope\"><slot name=\"menu-icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['menu-item']\" #menu-item=\"scope\"><slot name=\"menu-item\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['suggestion-item']\" #suggestion-item=\"scope\"><slot name=\"suggestion-item\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.mention\" #mention=\"scope\"><slot name=\"mention\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['composer-after-input']\" #after-input><slot name=\"composer-after-input\" /></template>\n <template v-if=\"$slots['composer-after']\" #after><slot name=\"composer-after\" /></template>\n </CodexComposer>\n <slot name=\"after-composer\" />\n </template>\n </footer>\n </template>\n </CodexWorkbenchLayout>\n </section>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed, nextTick, onMounted, provide, ref, shallowReactive, watch } from 'vue';\nimport type {\n CodexConversationRenderStrategy,\n CodexRendererAttachment,\n CodexSurfaceApproval,\n CodexSurfaceApprovalDecision,\n CodexSurfaceApprovalScope,\n CodexSurfacePlugin,\n CodexSurfaceClientRequest,\n CodexSurfaceTurn,\n SurfaceMessage,\n CodexRendererSendMessageOptions,\n} from '@codex-app-sdk/core/surface';\nimport type { CodexHostAttachment } from '@codex-app-sdk/core/native';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport type {\n CodexConversationPaneActions,\n CodexConversationPaneControllerSource,\n CodexConversationPaneState,\n} from '../conversation-pane-controller';\nimport { resolveCodexConversationPaneValue } from '../conversation-pane-controller';\nimport type { Message, MessageToolCall } from '../chat/types';\nimport type { CodexToolVisibility } from '../chat/tool-visibility';\nimport type { MessageBlock } from '../chat/message-blocks';\nimport type {\n CodexMessageImage,\n CodexMessageImageContext,\n CodexMessageImageOpenHandler,\n} from '../chat/message-image';\nimport type {\n CodexConversationVisualization,\n CodexConversationVisualizationOpenHandler,\n} from '../chat/visualization';\nimport type { CodexMessageTextSelection } from '../chat/message-text-selection';\nimport { stripMessageContext } from '../chat/message-blocks';\nimport type { QueuedChatPrompt } from '../chat/queued-prompts';\nimport { chatMessageFromInput } from '../chat/renderer-message-adapter';\nimport type {\n CodexContextUsage,\n CodexFileSearchItem,\n ApprovalPreset,\n CodexCapabilities,\n CodexCommandSummary,\n CodexConversationPresentation,\n CodexModelOption,\n CodexSkillSummary,\n ClientRequestResponse,\n CodexChatTranscription,\n CodexConversationLink,\n ReasoningEffort,\n ThreadGoal,\n TurnGitDiff,\n} from '../chat/contracts';\nimport { resolveCodexConversationPresentation } from '../chat/contracts';\nimport { codexCapabilities } from '../chat/codex-capabilities';\nimport { codexCommands } from '../chat/codex-commands';\nimport { codexConversationLinkFromHref } from '../chat/conversation-links';\nimport {\n ingestCodexAttachments,\n pickCodexAttachments,\n useCodexHostCapabilities,\n type CodexAttachmentIngester,\n type CodexAttachmentPicker,\n} from '../native-capabilities';\nimport type { CodexSurfaceController } from '../use-codex-surface';\nimport type { CodexComposerState } from '../composer-state';\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from '../chat/composer-mentions-custom';\nimport { normalizeCodexComposerState } from '../composer-state';\nimport { useConversationEscapeInterrupt } from '../chat/use-conversation-escape-interrupt';\nimport { CircleXIcon, MessageQuestionIcon, X as XIcon } from '../icons/app-icons';\nimport ChatQuestionRequest from '../chat/ChatQuestionRequest.vue';\nimport ChatConfirmationRequest from '../chat/ChatConfirmationRequest.vue';\nimport ChatComposerShelf from '../chat/ChatComposerShelf.vue';\nimport { questionResponsesKey } from '../chat/message-work-state';\nimport CodexComposer from './CodexComposer.vue';\nimport CodexApprovalPrompt from './CodexApprovalPrompt.vue';\nimport CodexConversationHistoryLoader from './CodexConversationHistoryLoader.vue';\nimport CodexMessageList from './CodexMessageList.vue';\nimport CodexWorkbenchLayout from './CodexWorkbenchLayout.vue';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n ariaLabel?: string;\n actionsDisabled?: boolean;\n activeTurnId?: string | null;\n answeredClientRequestIds?: ReadonlySet<string>;\n approvals?: readonly CodexSurfaceApproval[];\n clientRequests?: readonly CodexSurfaceClientRequest[];\n approvalPresets?: readonly ApprovalPreset[];\n attachEnabled?: boolean;\n attachments?: readonly CodexHostAttachment[];\n autofocus?: boolean;\n capabilities?: CodexCapabilities;\n /** Controlled state/actions adapter. When supplied, it takes precedence over legacy props and surface state. */\n controller?: CodexConversationPaneControllerSource<Payload>;\n busy?: boolean;\n canDeleteTurn?: boolean;\n canEditTurn?: boolean;\n canForkTurn?: boolean;\n canRetryTurn?: boolean;\n commands?: readonly CodexCommandSummary[];\n composerState?: CodexComposerState;\n contextUsage?: CodexContextUsage | null;\n conversationKey?: string | number | null;\n disabled?: boolean;\n emptySendPrompt?: string;\n emptyDescription?: string;\n emptyTitle?: string;\n error?: string | null;\n escapeInterrupt?: boolean;\n files?: readonly CodexFileSearchItem[];\n followUpsDisabled?: boolean;\n goal?: ThreadGoal | null;\n hasComposerContext?: boolean;\n hasOlderHistory?: boolean;\n historyLoading?: boolean;\n renderStrategy?: CodexConversationRenderStrategy;\n /** @deprecated Use renderStrategy instead. */\n lazyMessages?: boolean;\n initialMessageBatchSize?: number;\n loadingOlderHistory?: boolean;\n messageBatchSize?: number;\n messageTextSelection?: boolean;\n leadingMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n menuItems?: readonly CodexComposerMenuItem<Payload>[];\n modelMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n mentionGroups?: readonly CodexComposerMentionGroup<Payload>[];\n messages?: readonly (Message | SurfaceMessage)[];\n turns?: readonly CodexSurfaceTurn[];\n modelCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n models?: readonly CodexModelOption[];\n modelValue?: string;\n openImage?: CodexMessageImageOpenHandler;\n openConversationLink?: (link: CodexConversationLink) => void | Promise<void>;\n openVisualization?: CodexConversationVisualizationOpenHandler;\n pickAttachments?: CodexAttachmentPicker;\n ingestAttachments?: CodexAttachmentIngester;\n placeholder?: string;\n promptHistory?: readonly string[];\n approvalPreset?: ApprovalPreset | null;\n planMode?: boolean;\n plugins?: readonly CodexSurfacePlugin[];\n presentation?: CodexConversationPresentation;\n queuedPrompts?: readonly QueuedChatPrompt[];\n selectedModelId?: string | null;\n selectedReasoningEffort?: ReasoningEffort | null;\n selectedServiceTier?: string | null;\n scrollToBottomLabel?: string;\n showToolDetails?: boolean;\n skillCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n skills?: readonly CodexSkillSummary[];\n surface?: CodexSurfaceController;\n transformMessage?: (message: Message | SurfaceMessage, index: number) => Message | SurfaceMessage;\n transcribeAudio?: CodexChatTranscription;\n toolVisibility?: CodexToolVisibility;\n turnGitDiff?: TurnGitDiff | null;\n}>(), {\n ariaLabel: 'Conversation',\n attachEnabled: true,\n attachments: () => [],\n escapeInterrupt: true,\n autofocus: false,\n busy: undefined,\n canDeleteTurn: true,\n canEditTurn: true,\n canForkTurn: false,\n canRetryTurn: true,\n disabled: undefined,\n emptyDescription: '',\n emptyTitle: 'Start a conversation with Codex',\n historyLoading: undefined,\n lazyMessages: undefined,\n initialMessageBatchSize: 50,\n leadingMenuItems: () => [],\n messageBatchSize: 25,\n menuItems: () => [],\n modelMenuItems: () => [],\n modelValue: '',\n placeholder: 'Ask Codex…',\n planMode: undefined,\n showToolDetails: undefined,\n scrollToBottomLabel: 'Scroll to bottom',\n});\n\ndefineSlots<{\n 'after-composer'(): unknown;\n approval(props: { approval: CodexSurfaceApproval }): unknown;\n 'before-composer'(): unknown;\n 'composer-after'(): unknown;\n 'composer-after-input'(): unknown;\n 'composer-attachment-actions'(props: {\n attachments: readonly CodexHostAttachment[];\n disabled: boolean;\n index: number;\n }): unknown;\n 'composer-context'(props: { disabled: boolean }): unknown;\n 'composer-shelf-actions'(props: { disabled: boolean }): unknown;\n empty(props: { description: string; title: string }): unknown;\n 'menu-icon'(props: { item: CodexComposerMenuItem<Payload> }): unknown;\n 'menu-item'(props: { item: CodexComposerMenuItem<Payload> }): unknown;\n mention(props: {\n group: CodexComposerMentionGroup;\n item: CodexComposerMentionItem;\n surface: 'composer' | 'message';\n }): unknown;\n 'suggestion-item'(props: {\n active: boolean;\n group: CodexComposerMentionGroup;\n item: CodexComposerMentionItem;\n surface: string;\n }): unknown;\n message(props: { index: number; message: Message }): unknown;\n 'message-actions'(props: { disabled: boolean; index: number; message: Message }): unknown;\n 'message-attachment'(props: {\n attachment: Extract<MessageBlock, { type: 'attachment' }>['attachment'];\n block: Extract<MessageBlock, { type: 'attachment' }>;\n index: number;\n message: Message;\n }): unknown;\n 'message-block'(props: { block: MessageBlock; blockIndex: number; index: number; message: Message }): unknown;\n 'message-header'(props: { index: number; message: Message }): unknown;\n 'message-status'(props: { index: number; message: Message; status: 'streaming' }): unknown;\n 'message-text'(props: { block: Extract<MessageBlock, { type: 'text' | 'user-text' }>; content: string; index: number; message: Message; user: boolean }): unknown;\n 'message-thinking'(props: { index: number; message: Message }): unknown;\n 'message-tool'(props: {\n block: Extract<MessageBlock, { type: 'tool' | 'tool-group' }>;\n index: number;\n message: Message;\n toolCall?: Extract<MessageBlock, { type: 'tool' }>['toolCall'];\n toolCalls?: Extract<MessageBlock, { type: 'tool-group' }>['toolCalls'];\n }): unknown;\n}>();\n\nconst emit = defineEmits<{\n attach: [];\n attachmentsChange: [attachments: readonly CodexHostAttachment[]];\n cancel: [];\n clientResponse: [response: ClientRequestResponse];\n copyMessage: [index: number];\n clearGoal: [];\n continueInterruptedTurn: [];\n deleteTurn: [turnId: string];\n deleteQueuedPrompt: [promptId: string];\n updateQueuedPrompt: [promptId: string, prompt: string];\n editGoal: [];\n editTurn: [payload: { content: string; turnId: string }];\n forkTurn: [turnId: string];\n loadOlderHistory: [];\n error: [message: string | null];\n interrupt: [];\n menuSelect: [item: CodexComposerMenuSelectableItem<Payload>];\n messageTextSelectionChange: [selection: CodexMessageTextSelection | null];\n mentionSelect: [item: CodexComposerMentionItem<Payload>, group: CodexComposerMentionGroup<Payload>];\n openLink: [link: CodexConversationLink];\n openVisualization: [visualization: CodexConversationVisualization];\n resolveApproval: [\n approvalId: string,\n decision: CodexSurfaceApprovalDecision,\n scope: CodexSurfaceApprovalScope,\n ];\n quoteMessage: [index: number];\n retryTurn: [turnId: string];\n selectApprovalPreset: [preset: ApprovalPreset];\n sendFollowUp: [prompt: string];\n submit: [prompt: string, options?: CodexRendererSendMessageOptions];\n steer: [prompt: string, options?: CodexRendererSendMessageOptions];\n steerQueuedPrompt: [promptId: string, prompt?: string];\n 'update:modelId': [modelId: string];\n 'update:composerState': [state: CodexComposerState];\n 'update:modelValue': [value: string];\n 'update:planMode': [enabled: boolean];\n 'update:reasoningEffort': [reasoningEffort: ReasoningEffort];\n 'update:serviceTier': [serviceTier: string | null];\n}>();\n// Stryker restore all\n\nconst hostCapabilities = useCodexHostCapabilities();\nconst questionResponses = shallowReactive(new Map<string, ClientRequestResponse['payload']>());\nprovide(questionResponsesKey, questionResponses);\nconst openedQuestionId = ref<string | null>(null);\nconst locallyDismissedQuestionIds = ref<ReadonlySet<string>>(new Set());\n\nconst composer = ref<{ focus(options?: { preserveSelection?: boolean }): void } | null>(null);\nconst footerElement = ref<HTMLElement | null>(null);\nconst messageList = ref<{ scrollToBottom(): void } | null>(null);\nconst paneElement = ref<HTMLElement | null>(null);\nconst effectiveController = computed(() => resolveCodexConversationPaneValue(props.controller));\nconst effectiveControllerState = computed<CodexConversationPaneState | undefined>(() => {\n const controller = effectiveController.value;\n return controller ? resolveCodexConversationPaneValue(controller.state) : undefined;\n});\nconst effectiveControllerActions = computed<CodexConversationPaneActions<Payload> | undefined>(() => {\n const controller = effectiveController.value;\n return controller ? resolveCodexConversationPaneValue(controller.actions) : undefined;\n});\nconst surfaceState = computed(() => props.surface?.state);\nfunction controlledValue<T>(read: (state: CodexConversationPaneState) => T, fallback: () => T): T {\n const state = effectiveControllerState.value;\n return state ? read(state) : fallback();\n}\n\nconst effectiveComposerState = computed(() => controlledValue(\n (state) => state.composer?.state,\n () => props.composerState,\n));\nconst effectiveAttachments = computed(() => controlledValue(\n (state) => state.composer?.attachments ?? [],\n () => props.attachments,\n));\nconst initialComposerState = normalizeCodexComposerState(effectiveComposerState.value ?? (\n effectiveControllerState.value\n ? { text: '', selectionStart: 0, selectionEnd: 0 }\n : {\n text: props.modelValue,\n selectionStart: props.modelValue.length,\n selectionEnd: props.modelValue.length,\n }\n));\nconst localComposerState = ref<CodexComposerState>(initialComposerState);\nconst localDraft = ref(initialComposerState.text);\nconst editingQueuedPromptId = ref<string | null>(null);\nconst deletingTurnId = ref<string | null>(null);\ntype PendingControlledSubmission = {\n adoptedConversationKey: string | number | null;\n hasAdoptedConversationKey: boolean;\n message: SurfaceMessage;\n originConversationKey: string | number | null;\n prompt: string;\n};\nconst pendingControlledSubmission = ref<PendingControlledSubmission | null>(null);\nlet optimisticSubmissionSequence = 0;\nlet deleteOperation = 0;\nconst localError = ref<string | null>(null);\nconst selectedAttachments = ref<CodexHostAttachment[]>([...effectiveAttachments.value]);\nconst promptHistoryByConversation = new Map<string | number, readonly string[]>();\nconst loadedPromptHistory = ref<readonly string[]>([]);\nconst promptHistoryLoading = ref(false);\nlet promptHistoryRequest = 0;\nconst authoritativeMessages = computed(() => controlledValue(\n (state) => state.identity.messages,\n () => props.messages ?? surfaceState.value?.messages ?? [],\n));\nconst effectiveMessages = computed<readonly (Message | SurfaceMessage)[]>(() => {\n const messages = authoritativeMessages.value;\n const pending = pendingControlledSubmission.value;\n if (!pending || messages.some((message) => matchesPendingSubmission(message, pending))) return messages;\n return [...messages, pending.message];\n});\nconst effectiveActiveTurnId = computed(() => controlledValue(\n (state) => state.identity.activeTurnId,\n () => (props.activeTurnId !== undefined ? props.activeTurnId : surfaceState.value?.activeTurnId),\n));\nconst effectiveTurns = computed(() => controlledValue(\n (state) => state.identity.turns,\n () => props.turns ?? surfaceState.value?.turns ?? [],\n));\nconst canContinueInterruptedTurn = computed(() => (\n !effectiveBusy.value\n && effectiveActiveTurnId.value == null\n && (effectiveTurns.value ?? []).at(-1)?.status === 'interrupted'\n));\nconst visiblePromptHistory = computed(() => effectiveMessages.value.flatMap((message) => {\n const chatMessage = chatMessageFromInput(message);\n if (chatMessage.role !== 'user') return [];\n const content = stripMessageContext(chatMessage.content);\n return content && content !== '(no user instructions)' ? [content] : [];\n}));\nconst configuredPromptHistory = computed(() => controlledValue(\n (state) => state.composer?.promptHistory,\n () => props.promptHistory,\n));\nconst effectivePromptHistory = computed(() => mergePromptHistories(\n configuredPromptHistory.value ?? loadedPromptHistory.value,\n visiblePromptHistory.value,\n));\nconst effectiveAnsweredClientRequestIds = computed(() => controlledValue(\n (state) => state.thread?.answeredClientRequestIds,\n () => props.answeredClientRequestIds ?? props.surface?.answeredClientRequestIds,\n));\nconst displayAnsweredClientRequestIds = computed<ReadonlySet<string>>(() => new Set([\n ...(effectiveAnsweredClientRequestIds.value ?? []),\n ...questionResponses.keys(),\n]));\nconst effectiveClientRequests = computed<readonly CodexSurfaceClientRequest[]>(() => controlledValue(\n (state) => state.thread?.clientRequests ?? [],\n () => props.clientRequests ?? surfaceState.value?.clientRequests ?? [],\n));\nconst supersededQuestionIds = computed<ReadonlySet<string>>(() => {\n const ids = new Set<string>();\n const turns = new Map((effectiveTurns.value ?? []).map((turn, index) => [turn.id, index]));\n const messages = authoritativeMessages.value.map(chatMessageFromInput);\n for (const [questionIndex, message] of messages.entries()) {\n for (const part of message.parts ?? []) {\n if (part.type !== 'question' || part.request.payload.request.delivery !== 'async') continue;\n const questionTurnId = part.request.turnId ?? message.turnId;\n const questionTurnIndex = questionTurnId ? turns.get(questionTurnId) : undefined;\n if (messages.some((candidate, userIndex) => {\n if (candidate.role !== 'user') return false;\n const userTurnIndex = candidate.turnId ? turns.get(candidate.turnId) : undefined;\n if (questionTurnIndex !== undefined && userTurnIndex !== undefined\n && userTurnIndex !== questionTurnIndex) return userTurnIndex > questionTurnIndex;\n return userIndex > questionIndex;\n })) ids.add(part.request.id);\n }\n }\n return ids;\n});\nconst dismissedQuestionIds = computed<ReadonlySet<string>>(() => new Set([\n ...locallyDismissedQuestionIds.value,\n ...supersededQuestionIds.value,\n]));\nconst pendingQuestionRequests = computed(() => {\n const requests: Extract<CodexSurfaceClientRequest, { kind: 'ask_user' }>[] = [];\n const seen = new Set<string>();\n for (const request of effectiveClientRequests.value) {\n if (request.kind !== 'ask_user' || request.payload.request.delivery !== 'tool'\n || request.payload.request.questions.length === 0\n || displayAnsweredClientRequestIds.value.has(request.id)) continue;\n seen.add(request.id);\n requests.push(request);\n }\n for (const message of effectiveMessages.value) {\n for (const part of chatMessageFromInput(message).parts ?? []) {\n if (\n part.type !== 'question'\n || part.historical === true\n || part.request.payload.request.questions.length === 0\n || seen.has(part.request.id)\n || displayAnsweredClientRequestIds.value.has(part.request.id)\n || dismissedQuestionIds.value.has(part.request.id)\n ) continue;\n seen.add(part.request.id);\n requests.push(part.request);\n }\n }\n return requests;\n});\nconst expandedQuestionRequest = computed(() => (\n pendingQuestionRequests.value.find((request) => request.payload.request.delivery === 'tool')\n ?? pendingQuestionRequests.value.find((request) => request.id === openedQuestionId.value)\n ?? pendingQuestionRequests.value.find((request) => {\n if (request.payload.request.delivery !== 'async') return true;\n const turn = effectiveTurns.value?.find((candidate) => candidate.id === request.turnId);\n return turn ? turn.status === 'inProgress' : request.turnId === effectiveActiveTurnId.value;\n })\n));\nconst hiddenQuestionRequestIds = computed<ReadonlySet<string>>(() => new Set(\n pendingQuestionRequests.value.map((request) => request.id),\n));\nconst activeConfirmation = computed(() => effectiveClientRequests.value.find(\n (request): request is Extract<CodexSurfaceClientRequest, { kind: 'confirm_tool' }> => (\n request.kind === 'confirm_tool' && !displayAnsweredClientRequestIds.value.has(request.id)\n ),\n));\nconst activeComposerRequestItemIds = computed<ReadonlySet<string>>(() => new Set(\n effectiveClientRequests.value\n .filter((request) => request.kind === 'confirm_tool'\n ? !displayAnsweredClientRequestIds.value.has(request.id)\n : request.payload.request.delivery === 'tool')\n .map((request) => request.itemId),\n));\nfunction transformTranscriptMessage(message: Message | SurfaceMessage, index: number): Message | SurfaceMessage {\n const transformed = props.transformMessage?.(message, index) ?? message;\n const chatMessage = chatMessageFromInput(transformed);\n const isHiddenTool = (toolCall: MessageToolCall) => activeComposerRequestItemIds.value.has(toolCall.itemId ?? toolCall.id);\n if (!chatMessage.parts?.some((part) => (\n (part.type === 'question' && dismissedQuestionIds.value.has(part.request.id))\n || (part.type === 'tool' && isHiddenTool(part.toolCall))\n )) && !chatMessage.toolCalls?.some(isHiddenTool)) return transformed;\n return {\n ...chatMessage,\n parts: chatMessage.parts?.filter((part) => (\n part.type !== 'tool' || !isHiddenTool(part.toolCall)\n )).map((part) => (\n part.type === 'question' && dismissedQuestionIds.value.has(part.request.id)\n ? { ...part, historical: true }\n : part\n )),\n toolCalls: chatMessage.toolCalls?.filter((toolCall) => !isHiddenTool(toolCall)),\n };\n}\nconst effectiveApprovals = computed(() => controlledValue(\n (state) => state.thread?.approvals ?? [],\n () => props.approvals ?? surfaceState.value?.approvals ?? [],\n));\nconst activeApproval = computed(() => effectiveApprovals.value[0]);\nconst effectiveBusy = computed(() => controlledValue(\n (state) => state.identity.busy ?? false,\n () => props.busy ?? surfaceState.value?.busy ?? false,\n));\nconst effectiveTranscriptBusy = computed(() => (\n effectiveBusy.value || pendingControlledSubmission.value !== null\n));\nconst {\n armed: escapeInterruptArmed,\n clear: clearEscapeInterruptArm,\n} = useConversationEscapeInterrupt({\n root: paneElement,\n busy: () => effectiveBusy.value,\n enabled: () => props.escapeInterrupt,\n onInterrupt: interrupt,\n});\nconst effectiveConversationKey = computed(() => controlledValue(\n (state) => state.identity.conversationKey,\n () => (props.conversationKey !== undefined ? props.conversationKey : surfaceState.value?.activeConversationId),\n));\nconst effectiveContextUsage = computed(() => controlledValue(\n (state) => state.thread?.contextUsage,\n () => (props.contextUsage !== undefined ? props.contextUsage : surfaceState.value?.contextUsage),\n));\nconst effectiveDisabled = computed(() => controlledValue(\n (state) => state.identity.disabled ?? false,\n () => props.disabled ?? (surfaceState.value ? surfaceState.value.status !== 'ready' : false),\n));\nconst effectiveError = computed(() => (\n localError.value\n ?? controlledValue(\n (state) => state.identity.error,\n () => props.error ?? surfaceState.value?.error ?? null,\n )\n ?? null\n));\nconst effectiveGoal = computed(() => controlledValue(\n (state) => state.thread?.goal ?? null,\n () => (props.goal !== undefined ? props.goal : surfaceState.value?.goal ?? null),\n));\nconst effectiveHistoryLoading = computed(() => controlledValue(\n (state) => state.history?.loading ?? false,\n () => props.historyLoading ?? surfaceState.value?.historyLoading ?? false,\n));\nconst effectiveRenderStrategy = computed<CodexConversationRenderStrategy>(() => (\n props.renderStrategy ?? (props.lazyMessages === false ? 'eager' : 'lazy')\n));\nconst effectiveHasOlderHistory = computed(() => controlledValue(\n (state) => state.history?.hasOlder ?? false,\n () => props.hasOlderHistory ?? surfaceState.value?.historyState?.hasOlder ?? false,\n));\nconst effectiveLoadingOlderHistory = computed(() => controlledValue(\n (state) => state.history?.loadingOlder ?? false,\n () => props.loadingOlderHistory ?? surfaceState.value?.historyState?.loadingOlder ?? false,\n));\nconst effectiveModelCatalogStatus = computed(() => controlledValue(\n (state) => state.catalogs?.modelCatalogStatus,\n () => props.modelCatalogStatus ?? surfaceState.value?.modelCatalogStatus,\n));\nconst effectiveModels = computed(() => controlledValue(\n (state) => state.catalogs?.models,\n () => props.models ?? surfaceState.value?.models,\n));\nconst effectiveApprovalPreset = computed(() => controlledValue(\n (state) => state.composer?.approvalPreset,\n () => (props.approvalPreset !== undefined ? props.approvalPreset : surfaceState.value?.approvalPreset),\n));\nconst effectivePlanMode = computed(() => controlledValue(\n (state) => state.composer?.planMode,\n () => props.planMode ?? surfaceState.value?.planMode,\n));\nconst effectivePlugins = computed(() => controlledValue(\n (state) => state.catalogs?.plugins,\n () => props.plugins ?? surfaceState.value?.plugins,\n));\nconst effectiveMentionGroups = computed(() => controlledValue(\n (state) => state.catalogs?.mentionGroups,\n () => props.mentionGroups,\n) as readonly CodexComposerMentionGroup<Payload>[] | undefined);\nconst effectivePresentation = computed(() => resolveCodexConversationPresentation(props.presentation));\nconst effectiveQueuedPrompts = computed(() => controlledValue(\n (state) => state.thread?.queuedPrompts ?? [],\n () => props.queuedPrompts ?? surfaceState.value?.queuedPrompts ?? [],\n));\nconst effectiveSelectedModelId = computed(() => controlledValue(\n (state) => state.composer?.selectedModelId,\n () => (props.selectedModelId !== undefined ? props.selectedModelId : surfaceState.value?.selectedModelId),\n));\nconst effectiveSelectedReasoningEffort = computed(() => controlledValue(\n (state) => state.composer?.selectedReasoningEffort,\n () => (props.selectedReasoningEffort !== undefined\n ? props.selectedReasoningEffort\n : surfaceState.value?.selectedReasoningEffort),\n));\nconst effectiveSelectedServiceTier = computed(() => controlledValue(\n (state) => state.composer?.selectedServiceTier,\n () => (props.selectedServiceTier !== undefined\n ? props.selectedServiceTier\n : surfaceState.value?.selectedServiceTier),\n));\nconst effectiveSkillCatalogStatus = computed(() => controlledValue(\n (state) => state.catalogs?.skillCatalogStatus,\n () => props.skillCatalogStatus ?? surfaceState.value?.skillCatalogStatus,\n));\nconst effectiveSkills = computed(() => controlledValue(\n (state) => state.catalogs?.skills,\n () => props.skills ?? surfaceState.value?.skills,\n));\nconst effectiveTurnGitDiff = computed(() => controlledValue(\n (state) => state.thread?.turnGitDiff,\n () => (props.turnGitDiff !== undefined ? props.turnGitDiff : surfaceState.value?.turnGitDiff),\n));\nconst effectiveAttachEnabled = computed(() => controlledValue(\n (state) => state.policy?.attachEnabled ?? true,\n () => props.attachEnabled !== false,\n));\nconst effectiveCapabilities = computed<CodexCapabilities>(() => ({\n ...codexCapabilities,\n ...(effectiveControllerState.value\n ? effectiveControllerState.value.capabilities\n : props.capabilities),\n approvalPresets: effectiveControllerState.value?.capabilities?.approvalPresets\n ?? (effectiveControllerState.value\n ? codexCapabilities.approvalPresets\n : props.approvalPresets ?? surfaceState.value?.approvalPresets ?? props.capabilities?.approvalPresets)\n ?? codexCapabilities.approvalPresets,\n}));\nconst effectiveCommands = computed(() => controlledValue(\n (state) => state.catalogs?.commands ?? [],\n () => props.commands ?? codexCommands,\n));\nconst effectiveFiles = computed(() => controlledValue(\n (state) => state.catalogs?.files ?? [],\n () => props.files,\n));\nconst effectiveLeadingMenuItems = computed(() => controlledValue(\n (state) => state.composer?.leadingMenuItems ?? [],\n () => props.leadingMenuItems,\n));\nconst effectiveMenuItems = computed(() => controlledValue(\n (state) => state.composer?.menuItems ?? [],\n () => props.menuItems,\n));\nconst effectiveModelMenuItems = computed(() => controlledValue(\n (state) => state.composer?.modelMenuItems ?? [],\n () => props.modelMenuItems,\n));\nconst effectivePlaceholder = computed(() => controlledValue(\n (state) => state.composer?.placeholder,\n () => props.placeholder,\n) ?? 'Ask Codex…');\nconst effectiveCanDeleteTurn = computed(() => controlledValue(\n (state) => state.policy?.canDeleteTurn ?? true,\n () => props.canDeleteTurn,\n));\nconst effectiveCanEditTurn = computed(() => controlledValue(\n (state) => state.policy?.canEditTurn ?? true,\n () => props.canEditTurn,\n));\nconst effectiveCanForkTurn = computed(() => controlledValue(\n (state) => state.policy?.canForkTurn ?? false,\n () => props.canForkTurn,\n));\nconst effectiveCanRetryTurn = computed(() => controlledValue(\n (state) => state.policy?.canRetryTurn ?? true,\n () => props.canRetryTurn,\n));\nconst effectiveActionsDisabled = computed(() => (\n controlledValue((state) => state.policy?.actionsDisabled ?? false, () => props.actionsDisabled ?? false)\n));\nconst effectiveFollowUpsDisabled = computed(() => (\n effectiveBusy.value\n || controlledValue((state) => state.policy?.followUpsDisabled ?? false, () => props.followUpsDisabled ?? false)\n));\nconst showHistoryLoader = computed(() => effectiveHistoryLoading.value);\nconst started = computed(() => (\n effectiveMessages.value.length > 0 || effectiveBusy.value || effectiveApprovals.value.length > 0\n));\n\nwatch(() => Boolean(activeApproval.value || activeConfirmation.value || expandedQuestionRequest.value), async (pending, wasPending) => {\n if (pending || !wasPending) return;\n const focused = document.activeElement;\n if (!focused || !footerElement.value?.contains(focused)) return;\n const conversationKey = effectiveConversationKey.value;\n await nextTick();\n // Restore only this request's focus; never steal it from another pane or a\n // control the user selected while the host was resolving the request.\n if (effectiveConversationKey.value === conversationKey\n && (document.activeElement === focused || document.activeElement === document.body)) {\n composer.value?.focus({ preserveSelection: true });\n }\n});\n\nwatch(() => props.modelValue, () => {\n if (effectiveController.value || props.composerState) return;\n if (props.modelValue === localDraft.value) return;\n localDraft.value = props.modelValue;\n localComposerState.value = {\n text: props.modelValue,\n selectionStart: props.modelValue.length,\n selectionEnd: props.modelValue.length,\n };\n});\n\nwatch(effectiveComposerState, (state) => {\n if (!state) return;\n const normalized = normalizeCodexComposerState(state);\n localComposerState.value = normalized;\n localDraft.value = normalized.text;\n}, { deep: true });\n\nwatch(effectiveAttachments, (attachments) => {\n selectedAttachments.value = [...attachments];\n});\n\nwatch(effectiveAttachEnabled, (enabled) => {\n if (!enabled && selectedAttachments.value.length > 0) replaceAttachments([]);\n});\n\nwatch(effectiveConversationKey, (conversationKey, previousConversationKey) => {\n openedQuestionId.value = null;\n locallyDismissedQuestionIds.value = new Set();\n const pending = pendingControlledSubmission.value;\n if (pending) {\n if (\n !pending.hasAdoptedConversationKey\n && (previousConversationKey ?? null) === pending.originConversationKey\n ) {\n pendingControlledSubmission.value = {\n ...pending,\n adoptedConversationKey: conversationKey ?? null,\n hasAdoptedConversationKey: true,\n };\n } else if (\n (conversationKey ?? null) !== pending.originConversationKey\n && (conversationKey ?? null) !== pending.adoptedConversationKey\n ) {\n pendingControlledSubmission.value = null;\n }\n }\n deleteOperation += 1;\n deletingTurnId.value = null;\n clearEscapeInterruptArm();\n editingQueuedPromptId.value = null;\n localError.value = null;\n const incoming = normalizeCodexComposerState(effectiveComposerState.value ?? (\n effectiveController.value\n ? { text: '', selectionStart: 0, selectionEnd: 0 }\n : {\n text: props.modelValue,\n selectionStart: props.modelValue.length,\n selectionEnd: props.modelValue.length,\n }\n ));\n localComposerState.value = incoming;\n localDraft.value = incoming.text;\n});\n\nwatch(authoritativeMessages, (messages) => {\n const pending = pendingControlledSubmission.value;\n if (!pending) return;\n if (messages.some((message) => matchesPendingSubmission(message, pending))) {\n pendingControlledSubmission.value = null;\n return;\n }\n if (pending.hasAdoptedConversationKey && messages.length > 0) {\n pendingControlledSubmission.value = null;\n }\n});\n\nwatch([effectiveMessages, effectiveTurns], () => {\n const turnId = deletingTurnId.value;\n if (!turnId) return;\n const turnStillPresent = effectiveTurns.value?.some((turn) => turn.id === turnId)\n || effectiveMessages.value.some((message) => chatMessageFromInput(message).turnId === turnId);\n if (turnStillPresent) return;\n deleteOperation += 1;\n deletingTurnId.value = null;\n});\n\nwatch(effectiveQueuedPrompts, (prompts) => {\n const editingId = editingQueuedPromptId.value;\n if (editingId && !prompts.some((prompt) => prompt.id === editingId)) {\n editingQueuedPromptId.value = null;\n }\n});\n\nwatch([\n effectiveConversationKey,\n () => surfaceState.value?.activeConversationId,\n () => effectiveControllerActions.value?.readPromptHistory,\n configuredPromptHistory,\n], () => { void loadPromptHistory(); }, { immediate: true });\n\nwatch(() => [surfaceState.value?.status, surfaceState.value?.error] as const, ([status, error]) => {\n if (status === 'ready' && error == null) localError.value = null;\n});\n\nonMounted(() => {\n if (props.surface && props.surface.state.status === 'idle') {\n void runSurfaceAction(() => props.surface!.connect());\n }\n});\n\nasync function loadPromptHistory(): Promise<void> {\n const request = ++promptHistoryRequest;\n const key = effectiveConversationKey.value;\n promptHistoryLoading.value = false;\n loadedPromptHistory.value = [];\n if (key == null || configuredPromptHistory.value !== undefined) return;\n\n const cached = promptHistoryByConversation.get(key);\n if (cached) {\n loadedPromptHistory.value = cached;\n return;\n }\n\n const controlledLoader = effectiveControllerActions.value?.readPromptHistory;\n const surface = props.surface;\n const conversationId = surfaceState.value?.activeConversationId;\n if (!controlledLoader && !conversationId) return;\n\n promptHistoryLoading.value = true;\n try {\n const prompts = controlledLoader\n ? await controlledLoader()\n : (await surface!.readConversationPromptHistory(conversationId!)).prompts;\n if (request !== promptHistoryRequest || effectiveConversationKey.value !== key) return;\n const bounded = [...prompts].slice(-100);\n promptHistoryByConversation.set(key, bounded);\n loadedPromptHistory.value = bounded;\n } catch {\n // Prompt recall is an optional enhancement; visible messages remain usable.\n } finally {\n if (request === promptHistoryRequest) promptHistoryLoading.value = false;\n }\n}\n\nfunction mergePromptHistories(\n older: readonly string[],\n visible: readonly string[],\n): readonly string[] {\n const maximumOverlap = Math.min(older.length, visible.length);\n let overlap = maximumOverlap;\n while (overlap > 0) {\n const olderStart = older.length - overlap;\n if (visible.slice(0, overlap).every((prompt, index) => prompt === older[olderStart + index])) break;\n overlap -= 1;\n }\n return [...older, ...visible.slice(overlap)].slice(-100);\n}\n\nfunction submit(prompt: string, composerOptions?: Pick<CodexRendererSendMessageOptions, 'inputMethod'>): void {\n updateDraft('');\n const queuedPromptId = editingQueuedPromptId.value;\n if (queuedPromptId) {\n editingQueuedPromptId.value = null;\n updateQueuedPrompt(queuedPromptId, prompt);\n replaceAttachments([]);\n return;\n }\n const options = sendOptionsForAttachments(selectedAttachments.value, composerOptions);\n const previousDismissedQuestions = dismissPendingQuestions();\n messageList.value?.scrollToBottom();\n void nextTick(() => messageList.value?.scrollToBottom());\n if (effectiveController.value) {\n const controlledSubmit = effectiveControllerActions.value?.submit;\n if (controlledSubmit) {\n const optimisticMessageId = beginControlledSubmission(prompt, selectedAttachments.value);\n void runSurfaceAction(\n () => Promise.resolve(controlledSubmit(prompt, options)),\n () => {\n clearPendingControlledSubmission(optimisticMessageId);\n locallyDismissedQuestionIds.value = previousDismissedQuestions;\n },\n );\n }\n replaceAttachments([]);\n return;\n }\n if (options) emit('submit', prompt, options);\n else emit('submit', prompt);\n if (props.surface) {\n void runSurfaceAction(\n () => props.surface!.sendMessage(prompt, options),\n () => { locallyDismissedQuestionIds.value = previousDismissedQuestions; },\n );\n }\n replaceAttachments([]);\n}\n\nfunction dismissPendingQuestions(): ReadonlySet<string> {\n const previous = locallyDismissedQuestionIds.value;\n locallyDismissedQuestionIds.value = new Set([\n ...previous,\n ...pendingQuestionRequests.value\n .filter((request) => request.payload.request.delivery === 'async')\n .map((request) => request.id),\n ]);\n openedQuestionId.value = null;\n return previous;\n}\n\nfunction cancelPendingQuestion(id: string): void {\n if (!pendingQuestionRequests.value.some((request) => request.id === id)) return;\n const response: ClientRequestResponse = { id, payload: { answers: {}, cancelled: true } };\n questionResponses.set(id, response.payload);\n locallyDismissedQuestionIds.value = new Set([...locallyDismissedQuestionIds.value, id]);\n openedQuestionId.value = null;\n respondToClientRequest(response);\n}\n\nfunction continueInterruptedTurn(): void {\n if (dispatchControllerAction('continueInterruptedTurn')) return;\n if (effectiveController.value) return;\n emit('continueInterruptedTurn');\n if (props.surface) void runSurfaceAction(() => props.surface!.continueInterruptedTurn());\n}\n\nfunction beginControlledSubmission(\n prompt: string,\n attachments: readonly CodexHostAttachment[],\n): string | null {\n if (effectiveBusy.value || authoritativeMessages.value.length > 0) return null;\n const id = `codex-optimistic-user-${++optimisticSubmissionSequence}`;\n pendingControlledSubmission.value = {\n adoptedConversationKey: null,\n hasAdoptedConversationKey: false,\n originConversationKey: effectiveConversationKey.value ?? null,\n prompt,\n message: {\n id,\n role: 'user',\n status: 'complete',\n createdAt: new Date().toISOString(),\n parts: [\n { type: 'text', text: prompt },\n ...attachments.map((attachment) => ({\n type: 'attachment' as const,\n attachment: {\n kind: attachment.type,\n name: attachment.name,\n mimeType: attachment.mimeType,\n ...(attachment.previewUrl ? { url: attachment.previewUrl } : {}),\n },\n })),\n ],\n },\n };\n return id;\n}\n\nfunction matchesPendingSubmission(\n message: Message | SurfaceMessage,\n pending: PendingControlledSubmission,\n): boolean {\n const candidate = chatMessageFromInput(message);\n return candidate.role === 'user' && stripMessageContext(candidate.content) === pending.prompt;\n}\n\nfunction clearPendingControlledSubmission(messageId: string | null): void {\n if (messageId && pendingControlledSubmission.value?.message.id === messageId) {\n pendingControlledSubmission.value = null;\n }\n}\n\nfunction loadOlderHistory(): void {\n if (dispatchControllerAction('loadOlderHistory')) return;\n if (effectiveController.value) return;\n if (props.surface && effectiveConversationKey.value) {\n void runSurfaceAction(() => props.surface!.loadOlderConversationHistory(String(effectiveConversationKey.value)));\n return;\n }\n emit('loadOlderHistory');\n}\n\nfunction quoteMessage(index: number): void {\n const message = effectiveMessages.value[index];\n if (!message) return;\n const chatMessage = chatMessageFromInput(message);\n const content = stripMessageContext(chatMessage.content);\n if (chatMessage.role !== 'user' || !content) return;\n updateDraft(content);\n if (dispatchControllerAction('quoteMessage', index)) return;\n if (effectiveController.value) return;\n emit('quoteMessage', index);\n}\n\nfunction editGoal(): void {\n if (!effectiveGoal.value?.objective.trim()) return;\n const objective = effectiveGoal.value.objective;\n updateComposerState({\n text: objective,\n selectionStart: objective.length,\n selectionEnd: objective.length,\n activeCommandId: 'codex.goal',\n });\n if (dispatchControllerAction('editGoal')) return;\n if (effectiveController.value) return;\n emit('editGoal');\n}\n\nfunction handleConversationClick(event: MouseEvent): void {\n const target = event.target instanceof Element ? event.target : null;\n const anchor = target?.closest('a[href]');\n if (!anchor) return;\n\n const href = anchor.getAttribute('href')?.trim() ?? '';\n if (!href || href.startsWith('#')) return;\n\n event.preventDefault();\n const link = codexConversationLinkFromHref(href);\n if (!link) return;\n handleConversationLink(link);\n}\n\nfunction handleConversationLink(link: CodexConversationLink): void {\n if (dispatchControllerAction('openLink', link)) return;\n if (effectiveController.value) return;\n emit('openLink', link);\n if (props.openConversationLink) {\n void Promise.resolve(props.openConversationLink(link)).catch(setLocalError);\n return;\n }\n if (link.kind === 'external') {\n if (hostCapabilities) void hostCapabilities.openExternal(link.href).catch(setLocalError);\n else window.open(link.href, '_blank', 'noopener,noreferrer');\n }\n}\n\nfunction handleVisualization(visualization: CodexConversationVisualization): void {\n if (dispatchControllerAction('openVisualization', visualization)) return;\n if (effectiveController.value) return;\n emit('openVisualization', visualization);\n if (props.openVisualization) {\n void Promise.resolve(props.openVisualization(visualization)).catch(setLocalError);\n }\n}\n\nasync function openImage(\n image: CodexMessageImage,\n context?: CodexMessageImageContext,\n): Promise<boolean> {\n const handler = effectiveController.value\n ? effectiveControllerActions.value?.openImage\n : props.openImage;\n if (!handler) return false;\n localError.value = null;\n try {\n return await handler(image, context) !== false;\n } catch (error) {\n setLocalError(error);\n return true;\n }\n}\n\nasync function selectAttachments(): Promise<void> {\n if (dispatchControllerAction('attach')) return;\n if (!effectiveController.value) emit('attach');\n if (!effectiveAttachEnabled.value) return;\n try {\n appendAttachments(await pickCodexAttachments(props.pickAttachments, hostCapabilities));\n } catch (error) {\n setLocalError(error);\n }\n}\n\nfunction handleDragOver(event: DragEvent): void {\n if (effectiveAttachEnabled.value && event.dataTransfer?.types.includes('Files')) event.preventDefault();\n}\n\nfunction handleDrop(event: DragEvent): void {\n if (!effectiveAttachEnabled.value) return;\n const files = [...(event.dataTransfer?.files ?? [])];\n if (files.length === 0) return;\n event.preventDefault();\n void ingestFiles(files);\n}\n\nfunction handlePaste(event: ClipboardEvent): void {\n const images = clipboardFiles(event).filter((file) => file.type.startsWith('image/'));\n if (images.length === 0) return;\n // Never let Chromium insert clipboard image HTML into the contenteditable.\n // The composer inserts accompanying plain text while this pane owns the one\n // attachment-ingestion path.\n event.preventDefault();\n if (!effectiveAttachEnabled.value) return;\n void ingestFiles(images);\n}\n\nfunction clipboardFiles(event: ClipboardEvent): File[] {\n const clipboard = event.clipboardData;\n if (!clipboard) return [];\n const files = [...clipboard.files];\n if (files.length > 0) return files;\n return [...(clipboard.items ?? [])]\n .filter((item) => item.kind === 'file')\n .map((item) => item.getAsFile())\n .filter((file): file is File => file !== null);\n}\n\nasync function ingestFiles(files: readonly File[]): Promise<void> {\n try {\n appendAttachments(await ingestCodexAttachments(files, props.ingestAttachments, hostCapabilities));\n } catch (error) {\n setLocalError(error);\n }\n}\n\nfunction appendAttachments(attachments: readonly CodexHostAttachment[]): void {\n const byReference = new Map(selectedAttachments.value.map((attachment) => [attachment.reference, attachment]));\n for (const attachment of attachments) byReference.set(attachment.reference, attachment);\n replaceAttachments([...byReference.values()].slice(0, 20));\n}\n\nfunction removeAttachment(id: string): void {\n replaceAttachments(selectedAttachments.value.filter((attachment) => attachment.id !== id));\n}\n\nfunction replaceAttachments(attachments: CodexHostAttachment[]): void {\n selectedAttachments.value = attachments;\n if (dispatchControllerAction('updateAttachments', attachments)) return;\n if (effectiveController.value) return;\n emit('attachmentsChange', attachments);\n}\n\nfunction sendOptionsForAttachments(\n attachments: readonly CodexHostAttachment[],\n composerOptions?: Pick<CodexRendererSendMessageOptions, 'inputMethod'>,\n): CodexRendererSendMessageOptions | undefined {\n if (attachments.length === 0) return composerOptions;\n const surfaceAttachments: CodexRendererAttachment[] = attachments.map((attachment) => (\n attachment.type === 'image'\n ? {\n type: 'image',\n reference: attachment.reference,\n }\n : {\n type: 'file', reference: attachment.reference,\n }\n ));\n return { ...composerOptions, attachments: surfaceAttachments };\n}\n\nfunction updateDraft(value: string): void {\n updateComposerState({ text: value, selectionStart: value.length, selectionEnd: value.length });\n}\n\nfunction updateComposerState(state: CodexComposerState): void {\n const normalized = normalizeCodexComposerState(state);\n localComposerState.value = normalized;\n localDraft.value = normalized.text;\n if (dispatchControllerAction('updateComposerState', normalized)) return;\n if (effectiveController.value) return;\n emit('update:modelValue', normalized.text);\n emit('update:composerState', normalized);\n}\n\nfunction cancel(): void {\n if (dispatchControllerAction('cancel')) return;\n if (effectiveController.value) return;\n emit('cancel');\n if (props.surface) void runSurfaceAction(() => props.surface!.interrupt());\n}\n\nfunction respondToClientRequest(response: ClientRequestResponse): void {\n if (dispatchControllerAction('clientResponse', response)) return;\n if (effectiveController.value) return;\n emit('clientResponse', response);\n if (props.surface) void runSurfaceAction(() => props.surface!.respondToClientRequest(response));\n}\n\nfunction copyMessage(index: number): void {\n if (dispatchControllerAction('onMessageCopied', index)) return;\n if (effectiveController.value) return;\n emit('copyMessage', index);\n}\n\nasync function deleteTurn(turnId: string): Promise<void> {\n if (deletingTurnId.value !== null) return;\n const controlledAction = effectiveControllerActions.value?.deleteTurn;\n if (effectiveController.value && !controlledAction) return;\n\n const operation = ++deleteOperation;\n let waitForControlledState = false;\n deletingTurnId.value = turnId;\n try {\n if (controlledAction) {\n localError.value = null;\n let result: void | Promise<void>;\n try {\n result = controlledAction(turnId);\n } catch (error) {\n setLocalError(error);\n return;\n }\n if (result === undefined) {\n waitForControlledState = true;\n return;\n }\n await runSurfaceAction(() => result);\n return;\n }\n emit('deleteTurn', turnId);\n if (props.surface) {\n await runSurfaceAction(() => props.surface!.deleteTurn(turnId));\n }\n } finally {\n if (!waitForControlledState && deleteOperation === operation) deletingTurnId.value = null;\n }\n}\n\nfunction editTurn(payload: { content: string; turnId: string }): void {\n if (dispatchControllerAction('editTurn', payload)) return;\n if (effectiveController.value) return;\n emit('editTurn', payload);\n if (props.surface) void runSurfaceAction(() => props.surface!.editTurn(payload.turnId, payload.content));\n}\n\nfunction forkTurn(turnId: string): void {\n if (dispatchControllerAction('forkTurn', turnId)) return;\n if (effectiveController.value) return;\n emit('forkTurn', turnId);\n if (props.surface) void runSurfaceAction(() => props.surface!.forkTurn(turnId));\n}\n\nfunction retryTurn(turnId: string): void {\n if (dispatchControllerAction('retryTurn', turnId)) return;\n if (effectiveController.value) return;\n emit('retryTurn', turnId);\n if (props.surface) void runSurfaceAction(() => props.surface!.retryTurn(turnId));\n}\n\nfunction sendFollowUp(prompt: string): void {\n if (dispatchControllerAction('sendFollowUp', prompt)) return;\n if (effectiveController.value) return;\n emit('sendFollowUp', prompt);\n if (props.surface) void runSurfaceAction(() => props.surface!.sendMessage(prompt));\n}\n\nfunction clearGoal(): void {\n if (dispatchControllerAction('clearGoal')) return;\n if (effectiveController.value) return;\n emit('clearGoal');\n if (props.surface) void runSurfaceAction(() => props.surface!.clearGoal());\n}\n\nfunction deleteQueuedPrompt(promptId: string): void {\n if (editingQueuedPromptId.value === promptId) editingQueuedPromptId.value = null;\n if (dispatchControllerAction('deleteQueuedPrompt', promptId)) return;\n if (effectiveController.value) return;\n emit('deleteQueuedPrompt', promptId);\n if (props.surface) void runSurfaceAction(() => props.surface!.deleteQueuedPrompt(promptId));\n}\n\nfunction editQueuedPrompt(promptId: string): void {\n if (localDraft.value.length > 0) return;\n const prompt = effectiveQueuedPrompts.value.find((candidate) => candidate.id === promptId);\n if (!prompt) return;\n editingQueuedPromptId.value = promptId;\n updateDraft(prompt.text);\n composer.value?.focus();\n}\n\nfunction updateQueuedPrompt(promptId: string, prompt: string): void {\n if (dispatchControllerAction('updateQueuedPrompt', promptId, prompt)) return;\n if (effectiveController.value) return;\n emit('updateQueuedPrompt', promptId, prompt);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateQueuedPrompt(promptId, prompt));\n}\n\nfunction steerQueuedPrompt(promptId: string, prompt?: string): void {\n if (!effectiveCapabilities.value.steerPrompt) return;\n if (editingQueuedPromptId.value === promptId) editingQueuedPromptId.value = null;\n if (prompt === undefined) dispatchControllerAction('steerQueuedPrompt', promptId);\n else dispatchControllerAction('steerQueuedPrompt', promptId, prompt);\n if (effectiveController.value) return;\n if (prompt === undefined) emit('steerQueuedPrompt', promptId);\n else emit('steerQueuedPrompt', promptId, prompt);\n if (props.surface) {\n void runSurfaceAction(() => prompt === undefined\n ? props.surface!.steerQueuedPrompt(promptId)\n : props.surface!.steerQueuedPrompt(promptId, prompt));\n }\n}\n\nfunction interrupt(): void {\n clearEscapeInterruptArm();\n if (dispatchControllerAction('interrupt')) return;\n if (effectiveController.value) return;\n emit('interrupt');\n if (props.surface) void runSurfaceAction(() => props.surface!.interrupt());\n}\n\nfunction steer(prompt: string, composerOptions?: Pick<CodexRendererSendMessageOptions, 'inputMethod'>): void {\n if (!effectiveCapabilities.value.steerPrompt) {\n submit(prompt, composerOptions);\n return;\n }\n const queuedPromptId = editingQueuedPromptId.value;\n if (queuedPromptId) {\n editingQueuedPromptId.value = null;\n steerQueuedPrompt(queuedPromptId, prompt);\n replaceAttachments([]);\n return;\n }\n const options = sendOptionsForAttachments(selectedAttachments.value, composerOptions);\n if (effectiveController.value) {\n const controlledSteer = effectiveControllerActions.value?.steer;\n if (controlledSteer) {\n const previousDismissedQuestions = dismissPendingQuestions();\n void runSurfaceAction(\n () => Promise.resolve(controlledSteer(prompt, options)),\n () => { locallyDismissedQuestionIds.value = previousDismissedQuestions; },\n );\n }\n replaceAttachments([]);\n return;\n }\n const previousDismissedQuestions = dismissPendingQuestions();\n if (options) emit('steer', prompt, options);\n else emit('steer', prompt);\n if (props.surface) void runSurfaceAction(\n () => props.surface!.steerMessage(prompt, options),\n () => { locallyDismissedQuestionIds.value = previousDismissedQuestions; },\n );\n replaceAttachments([]);\n}\n\nfunction selectApprovalPreset(preset: ApprovalPreset): void {\n if (dispatchControllerAction('selectApprovalPreset', preset)) return;\n if (effectiveController.value) {\n void dispatchControllerAction('updateSettings', { approvalPreset: preset });\n return;\n }\n emit('selectApprovalPreset', preset);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ approvalPreset: preset }));\n}\n\nfunction resolveApproval(\n approvalId: string,\n decision: CodexSurfaceApprovalDecision,\n scope: CodexSurfaceApprovalScope,\n): void {\n if (dispatchControllerAction('resolveApproval', approvalId, decision, scope)) return;\n if (effectiveController.value) return;\n emit('resolveApproval', approvalId, decision, scope);\n if (props.surface) void runSurfaceAction(() => props.surface!.resolveApproval(approvalId, decision, scope));\n}\n\nfunction updateModelId(modelId: string): void {\n if (dispatchControllerAction('updateSettings', { modelId })) return;\n if (effectiveController.value) return;\n emit('update:modelId', modelId);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ modelId }));\n}\n\nfunction updatePlanMode(planMode: boolean): void {\n if (dispatchControllerAction('updateSettings', { planMode })) return;\n if (effectiveController.value) return;\n emit('update:planMode', planMode);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ planMode }));\n}\n\nfunction updateReasoningEffort(reasoningEffort: ReasoningEffort): void {\n if (dispatchControllerAction('updateSettings', { reasoningEffort })) return;\n if (effectiveController.value) return;\n emit('update:reasoningEffort', reasoningEffort);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ reasoningEffort }));\n}\n\nfunction updateServiceTier(serviceTier: string | null): void {\n if (dispatchControllerAction('updateSettings', { serviceTier })) return;\n if (effectiveController.value) return;\n emit('update:serviceTier', serviceTier);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ serviceTier }));\n}\n\nfunction menuSelect(item: CodexComposerMenuSelectableItem<unknown>): void {\n if (dispatchControllerAction('menuSelect', item)) return;\n if (effectiveController.value) return;\n emit('menuSelect', item as CodexComposerMenuSelectableItem<Payload>);\n}\n\nfunction mentionSelect(\n item: CodexComposerMentionItem,\n group: CodexComposerMentionGroup,\n): void {\n if (dispatchControllerAction('mentionSelect', item, group)) return;\n if (effectiveController.value) return;\n emit(\n 'mentionSelect',\n item as CodexComposerMentionItem<Payload>,\n group as CodexComposerMentionGroup<Payload>,\n );\n}\n\nfunction dispatchControllerAction(\n name: keyof CodexConversationPaneActions<Payload>,\n ...args: unknown[]\n): boolean {\n const action = effectiveControllerActions.value?.[name] as\n | ((...actionArgs: never[]) => void | Promise<void>)\n | undefined;\n if (!action) return false;\n void runSurfaceAction(() => Promise.resolve(action(...args as never[])));\n return true;\n}\n\nasync function runSurfaceAction(action: () => Promise<unknown>, onError?: () => void): Promise<void> {\n localError.value = null;\n try {\n await action();\n } catch (error) {\n onError?.();\n setLocalError(error);\n }\n}\n\nfunction setLocalError(error: unknown): void {\n localError.value = error instanceof Error ? error.message : String(error);\n}\n\nfunction handleComposerError(error: string | null): void {\n localError.value = error;\n emit('error', error);\n}\n\nfunction focusComposer(): void {\n composer.value?.focus();\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineExpose({ focusComposer });\n// Stryker restore all\n</script>\n\n<style scoped>\n.codex-conversation-pane {\n --codex-conversation-content-width: 860px;\n display: grid;\n grid-template-rows: minmax(0, 1fr);\n width: 100%;\n min-width: 0;\n min-height: 0;\n height: 100%;\n overflow: hidden;\n color: var(--codex-text-color, var(--color-text, #202124));\n background: var(--codex-surface-color, var(--color-shell-main, #fff));\n}\n\n.codex-conversation-pane__layout {\n height: 100%;\n min-height: 0;\n overflow: hidden;\n --workbench-layout-footer-padding: var(--space-24) 0 var(--space-12);\n --workbench-layout-footer-background: linear-gradient(\n to bottom,\n color-mix(in srgb, var(--color-shell-main) 0%, transparent),\n var(--color-shell-main) 24%\n );\n --workbench-layout-scrollbar-gutter: var(--space-4);\n}\n\n.codex-conversation-pane__messages {\n flex: 1 1 auto;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n background: var(--color-shell-main);\n --codex-scroll-to-bottom-offset: calc(var(--workbench-layout-footer-offset, 0px) - var(--space-12) + 4px);\n --codex-scroll-to-bottom-size: 40px;\n --message-list-content-width: var(--codex-conversation-content-width);\n --message-list-content-padding-top: var(--space-12);\n --message-list-content-padding-bottom: calc(var(--workbench-layout-footer-offset) + var(--space-12));\n --message-list-padding-inline-start: var(--space-8);\n --message-list-padding-inline-end: var(--space-8);\n}\n\n.codex-conversation-pane__hero {\n display: grid;\n flex: 1 1 auto;\n min-height: 0;\n place-items: center;\n padding: var(--space-12) var(--space-16) calc(var(--workbench-layout-footer-offset) + var(--space-12));\n}\n\n.codex-conversation-pane__hero-copy {\n display: grid;\n gap: var(--space-2);\n max-width: var(--codex-conversation-content-width);\n text-align: center;\n}\n\n.codex-conversation-pane__hero h1,\n.codex-conversation-pane__hero p {\n margin: 0;\n}\n\n.codex-conversation-pane__hero h1 {\n color: var(--color-text);\n font-size: var(--font-size-24);\n font-weight: var(--font-weight-semibold);\n line-height: var(--line-height-28);\n}\n\n.codex-conversation-pane__hero p {\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n line-height: var(--line-height-20);\n}\n\n.codex-conversation-pane__footer {\n display: flex;\n flex-direction: column;\n width: min(calc(100% - var(--space-16) * 2), var(--codex-conversation-content-width));\n margin: 0 auto;\n}\n\n.codex-conversation-pane__approvals {\n display: grid;\n gap: var(--space-4);\n margin-bottom: var(--space-4);\n}\n\n.codex-conversation-pane__confirmation-composer {\n width: 100%;\n box-sizing: border-box;\n max-height: min(70vh, 38rem);\n overflow-y: auto;\n margin-bottom: var(--space-4);\n}\n\n.codex-conversation-pane__composer-shelf {\n width: 90%;\n margin: 0 auto;\n}\n\n.codex-conversation-pane__composer {\n width: 100%;\n margin: 0 auto var(--space-4);\n}\n\n.codex-conversation-pane__question-composer {\n margin: 0 auto var(--space-4);\n}\n\n.codex-conversation-pane__pending-question {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n gap: var(--space-1);\n overflow: hidden;\n min-height: 24px;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n padding: 0 var(--space-2);\n background: transparent;\n color: var(--color-text-muted);\n font: inherit;\n font-size: var(--font-size-13);\n white-space: nowrap;\n}\n\n.codex-conversation-pane__pending-question button {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n border: 0;\n padding: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n\n.codex-conversation-pane__pending-question-open {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.codex-conversation-pane__pending-question-cancel svg {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n.codex-conversation-pane__pending-question-remove {\n display: none;\n}\n\n.codex-conversation-pane__pending-question:hover .codex-conversation-pane__pending-question-icon,\n.codex-conversation-pane__pending-question-cancel:focus-visible .codex-conversation-pane__pending-question-icon {\n display: none;\n}\n\n.codex-conversation-pane__pending-question:hover .codex-conversation-pane__pending-question-remove,\n.codex-conversation-pane__pending-question-cancel:focus-visible .codex-conversation-pane__pending-question-remove {\n display: inline;\n}\n\n.codex-conversation-pane__pending-question button:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: 2px;\n}\n\n.codex-conversation-pane__attachments {\n display: flex;\n gap: var(--space-4);\n width: 100%;\n margin-top: var(--space-2);\n padding: 0;\n overflow-x: auto;\n}\n\n.codex-conversation-pane__attachment {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto;\n gap: 0;\n align-items: center;\n min-width: 0;\n max-width: 240px;\n padding: var(--space-2) var(--space-3);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n background: var(--color-surface-lowest);\n}\n\n.codex-conversation-pane__attachment-preview,\n.codex-conversation-pane__attachment-file {\n width: 32px;\n height: 32px;\n margin-inline-end: var(--space-3);\n border-radius: var(--radius-md);\n}\n\n.codex-conversation-pane__attachment-preview {\n object-fit: cover;\n}\n\n.codex-conversation-pane__attachment-file {\n display: grid;\n place-items: center;\n background: var(--color-surface-low);\n}\n\n.codex-conversation-pane__attachment-name {\n overflow: hidden;\n color: var(--color-text);\n font-size: var(--font-size-12);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.codex-conversation-pane__attachment-actions {\n display: flex;\n align-items: center;\n gap: var(--space-1);\n margin-inline-start: var(--space-4);\n}\n\n.codex-conversation-pane__attachment-remove {\n display: grid;\n width: 24px;\n height: 24px;\n margin-inline-start: calc(-1 * var(--space-3));\n padding: 0;\n border: 0;\n border-radius: var(--radius-full);\n place-items: center;\n color: var(--color-text-muted);\n background: transparent;\n cursor: pointer;\n}\n\n.codex-conversation-pane__attachment-remove:hover:not(:disabled) {\n color: var(--color-text);\n background: var(--color-surface-low);\n}\n\n.codex-conversation-pane__attachment-remove svg {\n width: 16px;\n height: 16px;\n}\n\n.codex-conversation-pane__history-loader {\n width: min(100%, var(--codex-conversation-content-width));\n margin: 0 auto;\n}\n\n.codex-conversation-pane__error {\n margin: 0 0 var(--space-4);\n overflow: hidden;\n color: var(--codex-danger-color, var(--color-error, #b3261e));\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n</style>\n","<template>\n <section\n ref=\"paneElement\"\n class=\"codex-chat-theme codex-conversation-pane\"\n :aria-busy=\"effectiveTranscriptBusy || effectiveHistoryLoading\"\n :aria-label=\"ariaLabel\"\n :data-codex-generating=\"effectiveTranscriptBusy ? 'true' : undefined\"\n @click=\"handleConversationClick\"\n @dragover=\"handleDragOver\"\n @drop=\"handleDrop\"\n @paste.capture=\"handlePaste\"\n >\n <CodexConversationHistoryLoader\n v-if=\"showHistoryLoader\"\n class=\"codex-conversation-pane__history-loader\"\n />\n\n <CodexWorkbenchLayout\n v-else\n class=\"codex-conversation-pane__layout\"\n scroll-mode=\"child\"\n >\n <CodexMessageList\n v-if=\"started\"\n ref=\"messageList\"\n class=\"codex-conversation-pane__messages\"\n :actions-disabled=\"effectiveActionsDisabled\"\n :active-turn-id=\"effectiveActiveTurnId\"\n :answered-client-request-ids=\"displayAnsweredClientRequestIds\"\n :aria-label=\"ariaLabel\"\n :busy=\"effectiveTranscriptBusy\"\n :can-delete-turn=\"effectiveCanDeleteTurn\"\n :can-edit-turn=\"effectiveCanEditTurn\"\n :can-fork-turn=\"effectiveCanForkTurn\"\n :can-retry-turn=\"effectiveCanRetryTurn\"\n :deleting-turn-id=\"deletingTurnId\"\n :empty-label=\"emptyTitle\"\n :follow-ups-disabled=\"effectiveFollowUpsDisabled\"\n :has-older-messages=\"effectiveHasOlderHistory\"\n :hidden-client-request-ids=\"hiddenQuestionRequestIds\"\n :render-strategy=\"effectiveRenderStrategy\"\n :loading-older-messages=\"effectiveLoadingOlderHistory\"\n :initial-message-batch-size=\"initialMessageBatchSize\"\n :message-batch-size=\"messageBatchSize\"\n :message-text-selection=\"messageTextSelection\"\n :messages=\"effectiveMessages\"\n :mention-groups=\"effectiveMentionGroups\"\n :open-image=\"openImage\"\n :plugins=\"effectivePlugins\"\n :presentation=\"effectivePresentation\"\n :reset-key=\"effectiveConversationKey\"\n :scroll-to-bottom-label=\"scrollToBottomLabel\"\n :show-tool-details=\"showToolDetails\"\n :skills=\"effectiveSkills\"\n :tool-visibility=\"toolVisibility\"\n :transform-message=\"dismissedQuestionIds.size > 0 || activeComposerRequestItemIds.size > 0 ? transformTranscriptMessage : transformMessage\"\n :turns=\"effectiveTurns\"\n @cancel=\"cancel\"\n @client-response=\"respondToClientRequest\"\n @copy-message=\"copyMessage\"\n @delete-turn=\"deleteTurn\"\n @edit-turn=\"editTurn\"\n @fork-turn=\"forkTurn\"\n @load-older-messages=\"loadOlderHistory\"\n @message-text-selection-change=\"emit('messageTextSelectionChange', $event)\"\n @open-link=\"handleConversationLink\"\n @open-visualization=\"handleVisualization\"\n @quote-message=\"quoteMessage\"\n @retry-turn=\"retryTurn\"\n @send-follow-up=\"sendFollowUp\"\n >\n <template v-if=\"$slots.message\" #message=\"scope\"><slot name=\"message\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-actions']\" #actions=\"scope\"><slot name=\"message-actions\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-attachment']\" #attachment=\"scope\"><slot name=\"message-attachment\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-block']\" #block=\"scope\"><slot name=\"message-block\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-header']\" #header=\"scope\"><slot name=\"message-header\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.mention\" #mention=\"scope\"><slot name=\"mention\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-status']\" #status=\"scope\"><slot name=\"message-status\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-text']\" #text=\"scope\"><slot name=\"message-text\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-thinking']\" #thinking=\"scope\"><slot name=\"message-thinking\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['message-tool']\" #tool=\"scope\"><slot name=\"message-tool\" v-bind=\"scope\" /></template>\n </CodexMessageList>\n\n <div v-else class=\"codex-conversation-pane__hero\">\n <slot name=\"empty\" :title=\"emptyTitle\" :description=\"emptyDescription\">\n <div class=\"codex-conversation-pane__hero-copy\">\n <h1>{{ emptyTitle }}</h1>\n <p v-if=\"emptyDescription\">{{ emptyDescription }}</p>\n </div>\n </slot>\n </div>\n\n <template #footer>\n <footer ref=\"footerElement\" class=\"codex-conversation-pane__footer\">\n <p v-if=\"effectiveError\" class=\"codex-conversation-pane__error\" role=\"alert\">{{ effectiveError }}</p>\n <div v-if=\"activeApproval\" class=\"codex-conversation-pane__approvals\">\n <slot name=\"approval\" :approval=\"activeApproval\">\n <CodexApprovalPrompt\n :key=\"activeApproval.id\"\n :approval=\"activeApproval\"\n :disabled=\"effectiveDisabled\"\n @resolve=\"(decision, scope) => resolveApproval(activeApproval!.id, decision, scope)\"\n />\n </slot>\n </div>\n <ChatConfirmationRequest\n v-else-if=\"activeConfirmation\"\n :key=\"activeConfirmation.id\"\n class=\"codex-conversation-pane__confirmation-composer\"\n :request=\"activeConfirmation\"\n @client-response=\"respondToClientRequest\"\n />\n <ChatQuestionRequest\n v-else-if=\"expandedQuestionRequest\"\n :key=\"expandedQuestionRequest.id\"\n class=\"codex-conversation-pane__question-composer\"\n :answered-client-request-ids=\"displayAnsweredClientRequestIds\"\n :request=\"expandedQuestionRequest\"\n @client-response=\"respondToClientRequest\"\n />\n <template v-else>\n <slot name=\"before-composer\" />\n <ChatComposerShelf\n class=\"codex-conversation-pane__composer-shelf\"\n :disabled=\"effectiveDisabled\"\n :goal=\"effectiveGoal\"\n :presentation=\"effectivePresentation.shelf\"\n :queued-prompts=\"effectiveQueuedPrompts\"\n :queued-prompt-edit-disabled=\"localDraft.length > 0\"\n :queued-prompt-steer-disabled=\"!effectiveCapabilities.steerPrompt\"\n :turn-git-diff=\"effectiveTurnGitDiff\"\n @clear-goal=\"clearGoal\"\n @delete-queued-prompt=\"deleteQueuedPrompt\"\n @edit-queued-prompt=\"editQueuedPrompt\"\n @edit-goal=\"editGoal\"\n @steer-queued-prompt=\"steerQueuedPrompt\"\n >\n <template v-if=\"$slots['composer-shelf-actions']\" #actions=\"scope\">\n <slot name=\"composer-shelf-actions\" v-bind=\"scope\" />\n </template>\n </ChatComposerShelf>\n <CodexComposer\n :key=\"effectiveConversationKey ?? 'no-conversation'\"\n ref=\"composer\"\n class=\"codex-conversation-pane__composer\"\n :autofocus=\"autofocus\"\n :attach-enabled=\"effectiveAttachEnabled\"\n :capabilities=\"effectiveCapabilities\"\n :can-continue-interrupted-turn=\"canContinueInterruptedTurn\"\n :commands=\"effectiveCommands\"\n :composer-state=\"localComposerState\"\n :context-usage=\"effectiveContextUsage\"\n :disabled=\"effectiveDisabled\"\n :draft=\"localDraft\"\n :empty-send-prompt=\"emptySendPrompt\"\n :files=\"effectiveFiles\"\n :has-attachments=\"selectedAttachments.length > 0\"\n :has-external-content=\"hasComposerContext\"\n :interrupt-armed=\"escapeInterruptArmed\"\n :plugins=\"effectivePlugins\"\n :prompt-history=\"effectivePromptHistory\"\n :prompt-history-loading=\"promptHistoryLoading\"\n :queued-prompt-id=\"effectiveQueuedPrompts[0]?.id ?? null\"\n :is-sending=\"effectiveBusy\"\n :leading-menu-items=\"effectiveLeadingMenuItems\"\n :menu-items=\"effectiveMenuItems\"\n :model-menu-items=\"effectiveModelMenuItems\"\n :mention-groups=\"effectiveMentionGroups\"\n :model-catalog-status=\"effectiveModelCatalogStatus\"\n :models=\"effectiveModels\"\n :placeholder=\"effectivePlaceholder\"\n :approval-preset=\"effectiveApprovalPreset\"\n :plan-mode=\"effectivePlanMode\"\n :presentation=\"effectivePresentation\"\n :selected-model-id=\"effectiveSelectedModelId\"\n :selected-reasoning-effort=\"effectiveSelectedReasoningEffort\"\n :selected-service-tier=\"effectiveSelectedServiceTier\"\n :skill-catalog-status=\"effectiveSkillCatalogStatus\"\n :skills=\"effectiveSkills\"\n :transcribe-audio=\"transcribeAudio\"\n @error=\"handleComposerError\"\n @attach=\"selectAttachments\"\n @continue-interrupted-turn=\"continueInterruptedTurn\"\n @interrupt=\"interrupt\"\n @menu-select=\"menuSelect\"\n @mention-select=\"mentionSelect\"\n @select-approval-preset=\"selectApprovalPreset\"\n @send=\"submit\"\n @steer=\"steer\"\n @steer-queued-prompt=\"steerQueuedPrompt\"\n @update:model-id=\"updateModelId\"\n @update:composer-state=\"updateComposerState\"\n @update:plan-mode=\"updatePlanMode\"\n @update:reasoning-effort=\"updateReasoningEffort\"\n @update:service-tier=\"updateServiceTier\"\n >\n <template #before-meta>\n <span\n v-if=\"pendingQuestionRequests.length > 0\"\n class=\"codex-conversation-pane__pending-question\"\n >\n <button\n class=\"codex-conversation-pane__pending-question-cancel\"\n type=\"button\"\n aria-label=\"Cancel pending question\"\n @click=\"cancelPendingQuestion(pendingQuestionRequests[0]!.id)\"\n >\n <MessageQuestionIcon class=\"codex-conversation-pane__pending-question-icon\" aria-hidden=\"true\" />\n <CircleXIcon class=\"codex-conversation-pane__pending-question-remove\" aria-hidden=\"true\" />\n </button>\n <button\n class=\"codex-conversation-pane__pending-question-open\"\n type=\"button\"\n :aria-label=\"pendingQuestionRequests.length === 1 ? 'Pending question' : `${pendingQuestionRequests.length} pending questions`\"\n @click=\"openedQuestionId = pendingQuestionRequests[0]!.id\"\n >\n {{ pendingQuestionRequests.length === 1 ? 'Pending question' : `${pendingQuestionRequests.length} pending questions` }}\n </button>\n </span>\n </template>\n <template #before>\n <div\n v-if=\"selectedAttachments.length > 0\"\n class=\"codex-conversation-pane__attachments\"\n aria-label=\"Prompt attachments\"\n >\n <div\n v-for=\"(attachment, index) in selectedAttachments\"\n :key=\"attachment.id\"\n class=\"codex-conversation-pane__attachment\"\n >\n <img\n v-if=\"attachment.previewUrl\"\n class=\"codex-conversation-pane__attachment-preview\"\n :src=\"attachment.previewUrl\"\n :alt=\"attachment.name\"\n >\n <span v-else class=\"codex-conversation-pane__attachment-file\" aria-hidden=\"true\">📎</span>\n <span class=\"codex-conversation-pane__attachment-name\" :title=\"attachment.name\">\n {{ attachment.name }}\n </span>\n <span class=\"codex-conversation-pane__attachment-actions\">\n <slot\n name=\"composer-attachment-actions\"\n :attachments=\"selectedAttachments\"\n :index=\"index\"\n :disabled=\"effectiveDisabled\"\n />\n <button\n type=\"button\"\n class=\"codex-conversation-pane__attachment-remove\"\n :aria-label=\"`Remove ${attachment.name}`\"\n :disabled=\"effectiveDisabled\"\n @click=\"removeAttachment(attachment.id)\"\n >\n <XIcon aria-hidden=\"true\" />\n </button>\n </span>\n </div>\n </div>\n <slot name=\"composer-context\" :disabled=\"effectiveDisabled\" />\n </template>\n <template v-if=\"$slots['menu-icon']\" #menu-icon=\"scope\"><slot name=\"menu-icon\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['menu-item']\" #menu-item=\"scope\"><slot name=\"menu-item\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['suggestion-item']\" #suggestion-item=\"scope\"><slot name=\"suggestion-item\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots.mention\" #mention=\"scope\"><slot name=\"mention\" v-bind=\"scope\" /></template>\n <template v-if=\"$slots['composer-after-input']\" #after-input><slot name=\"composer-after-input\" /></template>\n <template v-if=\"$slots['composer-after']\" #after><slot name=\"composer-after\" /></template>\n </CodexComposer>\n <slot name=\"after-composer\" />\n </template>\n </footer>\n </template>\n </CodexWorkbenchLayout>\n </section>\n</template>\n\n<script setup lang=\"ts\" generic=\"Payload = unknown\">\nimport { computed, nextTick, onMounted, provide, ref, shallowReactive, watch } from 'vue';\nimport type {\n CodexConversationRenderStrategy,\n CodexRendererAttachment,\n CodexSurfaceApproval,\n CodexSurfaceApprovalDecision,\n CodexSurfaceApprovalScope,\n CodexSurfacePlugin,\n CodexSurfaceClientRequest,\n CodexSurfaceTurn,\n SurfaceMessage,\n CodexRendererSendMessageOptions,\n} from '@codex-app-sdk/core/surface';\nimport type { CodexHostAttachment } from '@codex-app-sdk/core/native';\nimport type { CodexComposerMenuItem, CodexComposerMenuSelectableItem } from '../composer-menu';\nimport type {\n CodexConversationPaneActions,\n CodexConversationPaneControllerSource,\n CodexConversationPaneState,\n} from '../conversation-pane-controller';\nimport { resolveCodexConversationPaneValue } from '../conversation-pane-controller';\nimport type { Message, MessageToolCall } from '../chat/types';\nimport type { CodexToolVisibility } from '../chat/tool-visibility';\nimport type { MessageBlock } from '../chat/message-blocks';\nimport type {\n CodexMessageImage,\n CodexMessageImageContext,\n CodexMessageImageOpenHandler,\n} from '../chat/message-image';\nimport type {\n CodexConversationVisualization,\n CodexConversationVisualizationOpenHandler,\n} from '../chat/visualization';\nimport type { CodexMessageTextSelection } from '../chat/message-text-selection';\nimport { stripMessageContext } from '../chat/message-blocks';\nimport type { QueuedChatPrompt } from '../chat/queued-prompts';\nimport { chatMessageFromInput } from '../chat/renderer-message-adapter';\nimport type {\n CodexContextUsage,\n CodexFileSearchItem,\n ApprovalPreset,\n CodexCapabilities,\n CodexCommandSummary,\n CodexConversationPresentation,\n CodexModelOption,\n CodexSkillSummary,\n ClientRequestResponse,\n CodexChatTranscription,\n CodexConversationLink,\n ReasoningEffort,\n ThreadGoal,\n TurnGitDiff,\n} from '../chat/contracts';\nimport { resolveCodexConversationPresentation } from '../chat/contracts';\nimport { codexCapabilities } from '../chat/codex-capabilities';\nimport { codexCommands } from '../chat/codex-commands';\nimport { codexConversationLinkFromHref } from '../chat/conversation-links';\nimport {\n ingestCodexAttachments,\n pickCodexAttachments,\n useCodexHostCapabilities,\n type CodexAttachmentIngester,\n type CodexAttachmentPicker,\n} from '../native-capabilities';\nimport type { CodexSurfaceController } from '../use-codex-surface';\nimport type { CodexComposerState } from '../composer-state';\nimport type { CodexComposerMentionGroup, CodexComposerMentionItem } from '../chat/composer-mentions-custom';\nimport { normalizeCodexComposerState } from '../composer-state';\nimport { useConversationEscapeInterrupt } from '../chat/use-conversation-escape-interrupt';\nimport { CircleXIcon, MessageQuestionIcon, X as XIcon } from '../icons/app-icons';\nimport ChatQuestionRequest from '../chat/ChatQuestionRequest.vue';\nimport ChatConfirmationRequest from '../chat/ChatConfirmationRequest.vue';\nimport ChatComposerShelf from '../chat/ChatComposerShelf.vue';\nimport { questionResponsesKey } from '../chat/message-work-state';\nimport CodexComposer from './CodexComposer.vue';\nimport CodexApprovalPrompt from './CodexApprovalPrompt.vue';\nimport CodexConversationHistoryLoader from './CodexConversationHistoryLoader.vue';\nimport CodexMessageList from './CodexMessageList.vue';\nimport CodexWorkbenchLayout from './CodexWorkbenchLayout.vue';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = withDefaults(defineProps<{\n ariaLabel?: string;\n actionsDisabled?: boolean;\n activeTurnId?: string | null;\n answeredClientRequestIds?: ReadonlySet<string>;\n approvals?: readonly CodexSurfaceApproval[];\n clientRequests?: readonly CodexSurfaceClientRequest[];\n approvalPresets?: readonly ApprovalPreset[];\n attachEnabled?: boolean;\n attachments?: readonly CodexHostAttachment[];\n autofocus?: boolean;\n capabilities?: CodexCapabilities;\n /** Controlled state/actions adapter. When supplied, it takes precedence over legacy props and surface state. */\n controller?: CodexConversationPaneControllerSource<Payload>;\n busy?: boolean;\n canDeleteTurn?: boolean;\n canEditTurn?: boolean;\n canForkTurn?: boolean;\n canRetryTurn?: boolean;\n commands?: readonly CodexCommandSummary[];\n composerState?: CodexComposerState;\n contextUsage?: CodexContextUsage | null;\n conversationKey?: string | number | null;\n disabled?: boolean;\n emptySendPrompt?: string;\n emptyDescription?: string;\n emptyTitle?: string;\n error?: string | null;\n escapeInterrupt?: boolean;\n files?: readonly CodexFileSearchItem[];\n followUpsDisabled?: boolean;\n goal?: ThreadGoal | null;\n hasComposerContext?: boolean;\n hasOlderHistory?: boolean;\n historyLoading?: boolean;\n renderStrategy?: CodexConversationRenderStrategy;\n /** @deprecated Use renderStrategy instead. */\n lazyMessages?: boolean;\n initialMessageBatchSize?: number;\n loadingOlderHistory?: boolean;\n messageBatchSize?: number;\n messageTextSelection?: boolean;\n leadingMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n menuItems?: readonly CodexComposerMenuItem<Payload>[];\n modelMenuItems?: readonly CodexComposerMenuItem<Payload>[];\n mentionGroups?: readonly CodexComposerMentionGroup<Payload>[];\n messages?: readonly (Message | SurfaceMessage)[];\n turns?: readonly CodexSurfaceTurn[];\n modelCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n models?: readonly CodexModelOption[];\n modelValue?: string;\n openImage?: CodexMessageImageOpenHandler;\n openConversationLink?: (link: CodexConversationLink) => void | Promise<void>;\n openVisualization?: CodexConversationVisualizationOpenHandler;\n pickAttachments?: CodexAttachmentPicker;\n ingestAttachments?: CodexAttachmentIngester;\n placeholder?: string;\n promptHistory?: readonly string[];\n approvalPreset?: ApprovalPreset | null;\n planMode?: boolean;\n plugins?: readonly CodexSurfacePlugin[];\n presentation?: CodexConversationPresentation;\n queuedPrompts?: readonly QueuedChatPrompt[];\n selectedModelId?: string | null;\n selectedReasoningEffort?: ReasoningEffort | null;\n selectedServiceTier?: string | null;\n scrollToBottomLabel?: string;\n showToolDetails?: boolean;\n skillCatalogStatus?: 'notLoaded' | 'loading' | 'loaded' | 'error';\n skills?: readonly CodexSkillSummary[];\n surface?: CodexSurfaceController;\n transformMessage?: (message: Message | SurfaceMessage, index: number) => Message | SurfaceMessage;\n transcribeAudio?: CodexChatTranscription;\n toolVisibility?: CodexToolVisibility;\n turnGitDiff?: TurnGitDiff | null;\n}>(), {\n ariaLabel: 'Conversation',\n attachEnabled: true,\n attachments: () => [],\n escapeInterrupt: true,\n autofocus: false,\n busy: undefined,\n canDeleteTurn: true,\n canEditTurn: true,\n canForkTurn: false,\n canRetryTurn: true,\n disabled: undefined,\n emptyDescription: '',\n emptyTitle: 'Start a conversation with Codex',\n historyLoading: undefined,\n lazyMessages: undefined,\n initialMessageBatchSize: 50,\n leadingMenuItems: () => [],\n messageBatchSize: 25,\n menuItems: () => [],\n modelMenuItems: () => [],\n modelValue: '',\n placeholder: 'Ask Codex…',\n planMode: undefined,\n showToolDetails: undefined,\n scrollToBottomLabel: 'Scroll to bottom',\n});\n\ndefineSlots<{\n 'after-composer'(): unknown;\n approval(props: { approval: CodexSurfaceApproval }): unknown;\n 'before-composer'(): unknown;\n 'composer-after'(): unknown;\n 'composer-after-input'(): unknown;\n 'composer-attachment-actions'(props: {\n attachments: readonly CodexHostAttachment[];\n disabled: boolean;\n index: number;\n }): unknown;\n 'composer-context'(props: { disabled: boolean }): unknown;\n 'composer-shelf-actions'(props: { disabled: boolean }): unknown;\n empty(props: { description: string; title: string }): unknown;\n 'menu-icon'(props: { item: CodexComposerMenuItem<Payload> }): unknown;\n 'menu-item'(props: { item: CodexComposerMenuItem<Payload> }): unknown;\n mention(props: {\n group: CodexComposerMentionGroup;\n item: CodexComposerMentionItem;\n surface: 'composer' | 'message';\n }): unknown;\n 'suggestion-item'(props: {\n active: boolean;\n group: CodexComposerMentionGroup;\n item: CodexComposerMentionItem;\n surface: string;\n }): unknown;\n message(props: { index: number; message: Message }): unknown;\n 'message-actions'(props: { disabled: boolean; index: number; message: Message }): unknown;\n 'message-attachment'(props: {\n attachment: Extract<MessageBlock, { type: 'attachment' }>['attachment'];\n block: Extract<MessageBlock, { type: 'attachment' }>;\n index: number;\n message: Message;\n }): unknown;\n 'message-block'(props: { block: MessageBlock; blockIndex: number; index: number; message: Message }): unknown;\n 'message-header'(props: { index: number; message: Message }): unknown;\n 'message-status'(props: { index: number; message: Message; status: 'streaming' }): unknown;\n 'message-text'(props: { block: Extract<MessageBlock, { type: 'text' | 'user-text' }>; content: string; index: number; message: Message; user: boolean }): unknown;\n 'message-thinking'(props: { index: number; message: Message }): unknown;\n 'message-tool'(props: {\n block: Extract<MessageBlock, { type: 'tool' | 'tool-group' }>;\n index: number;\n message: Message;\n toolCall?: Extract<MessageBlock, { type: 'tool' }>['toolCall'];\n toolCalls?: Extract<MessageBlock, { type: 'tool-group' }>['toolCalls'];\n }): unknown;\n}>();\n\nconst emit = defineEmits<{\n attach: [];\n attachmentsChange: [attachments: readonly CodexHostAttachment[]];\n cancel: [];\n clientResponse: [response: ClientRequestResponse];\n copyMessage: [index: number];\n clearGoal: [];\n continueInterruptedTurn: [];\n deleteTurn: [turnId: string];\n deleteQueuedPrompt: [promptId: string];\n updateQueuedPrompt: [promptId: string, prompt: string];\n editGoal: [];\n editTurn: [payload: { content: string; turnId: string }];\n forkTurn: [turnId: string];\n loadOlderHistory: [];\n error: [message: string | null];\n interrupt: [];\n menuSelect: [item: CodexComposerMenuSelectableItem<Payload>];\n messageTextSelectionChange: [selection: CodexMessageTextSelection | null];\n mentionSelect: [item: CodexComposerMentionItem<Payload>, group: CodexComposerMentionGroup<Payload>];\n openLink: [link: CodexConversationLink];\n openVisualization: [visualization: CodexConversationVisualization];\n resolveApproval: [\n approvalId: string,\n decision: CodexSurfaceApprovalDecision,\n scope: CodexSurfaceApprovalScope,\n ];\n quoteMessage: [index: number];\n retryTurn: [turnId: string];\n selectApprovalPreset: [preset: ApprovalPreset];\n sendFollowUp: [prompt: string];\n submit: [prompt: string, options?: CodexRendererSendMessageOptions];\n steer: [prompt: string, options?: CodexRendererSendMessageOptions];\n steerQueuedPrompt: [promptId: string, prompt?: string];\n 'update:modelId': [modelId: string];\n 'update:composerState': [state: CodexComposerState];\n 'update:modelValue': [value: string];\n 'update:planMode': [enabled: boolean];\n 'update:reasoningEffort': [reasoningEffort: ReasoningEffort];\n 'update:serviceTier': [serviceTier: string | null];\n}>();\n// Stryker restore all\n\nconst hostCapabilities = useCodexHostCapabilities();\nconst questionResponses = shallowReactive(new Map<string, ClientRequestResponse['payload']>());\nprovide(questionResponsesKey, questionResponses);\nconst openedQuestionId = ref<string | null>(null);\nconst locallyDismissedQuestionIds = ref<ReadonlySet<string>>(new Set());\n\nconst composer = ref<{ focus(options?: { preserveSelection?: boolean }): void } | null>(null);\nconst footerElement = ref<HTMLElement | null>(null);\nconst messageList = ref<{ scrollToBottom(): void } | null>(null);\nconst paneElement = ref<HTMLElement | null>(null);\nconst effectiveController = computed(() => resolveCodexConversationPaneValue(props.controller));\nconst effectiveControllerState = computed<CodexConversationPaneState | undefined>(() => {\n const controller = effectiveController.value;\n return controller ? resolveCodexConversationPaneValue(controller.state) : undefined;\n});\nconst effectiveControllerActions = computed<CodexConversationPaneActions<Payload> | undefined>(() => {\n const controller = effectiveController.value;\n return controller ? resolveCodexConversationPaneValue(controller.actions) : undefined;\n});\nconst surfaceState = computed(() => props.surface?.state);\nfunction controlledValue<T>(read: (state: CodexConversationPaneState) => T, fallback: () => T): T {\n const state = effectiveControllerState.value;\n return state ? read(state) : fallback();\n}\n\nconst effectiveComposerState = computed(() => controlledValue(\n (state) => state.composer?.state,\n () => props.composerState,\n));\nconst effectiveAttachments = computed(() => controlledValue(\n (state) => state.composer?.attachments ?? [],\n () => props.attachments,\n));\nconst initialComposerState = normalizeCodexComposerState(effectiveComposerState.value ?? (\n effectiveControllerState.value\n ? { text: '', selectionStart: 0, selectionEnd: 0 }\n : {\n text: props.modelValue,\n selectionStart: props.modelValue.length,\n selectionEnd: props.modelValue.length,\n }\n));\nconst localComposerState = ref<CodexComposerState>(initialComposerState);\nconst localDraft = ref(initialComposerState.text);\nconst editingQueuedPromptId = ref<string | null>(null);\nconst deletingTurnId = ref<string | null>(null);\ntype PendingControlledSubmission = {\n adoptedConversationKey: string | number | null;\n hasAdoptedConversationKey: boolean;\n message: SurfaceMessage;\n originConversationKey: string | number | null;\n prompt: string;\n};\nconst pendingControlledSubmission = ref<PendingControlledSubmission | null>(null);\nlet optimisticSubmissionSequence = 0;\nlet deleteOperation = 0;\nconst localError = ref<string | null>(null);\nconst selectedAttachments = ref<CodexHostAttachment[]>([...effectiveAttachments.value]);\nconst promptHistoryByConversation = new Map<string | number, readonly string[]>();\nconst loadedPromptHistory = ref<readonly string[]>([]);\nconst promptHistoryLoading = ref(false);\nlet promptHistoryRequest = 0;\nconst authoritativeMessages = computed(() => controlledValue(\n (state) => state.identity.messages,\n () => props.messages ?? surfaceState.value?.messages ?? [],\n));\nconst effectiveMessages = computed<readonly (Message | SurfaceMessage)[]>(() => {\n const messages = authoritativeMessages.value;\n const pending = pendingControlledSubmission.value;\n if (!pending || messages.some((message) => matchesPendingSubmission(message, pending))) return messages;\n return [...messages, pending.message];\n});\nconst effectiveActiveTurnId = computed(() => controlledValue(\n (state) => state.identity.activeTurnId,\n () => (props.activeTurnId !== undefined ? props.activeTurnId : surfaceState.value?.activeTurnId),\n));\nconst effectiveTurns = computed(() => controlledValue(\n (state) => state.identity.turns,\n () => props.turns ?? surfaceState.value?.turns ?? [],\n));\nconst canContinueInterruptedTurn = computed(() => (\n !effectiveBusy.value\n && effectiveActiveTurnId.value == null\n && (effectiveTurns.value ?? []).at(-1)?.status === 'interrupted'\n));\nconst visiblePromptHistory = computed(() => effectiveMessages.value.flatMap((message) => {\n const chatMessage = chatMessageFromInput(message);\n if (chatMessage.role !== 'user') return [];\n const content = stripMessageContext(chatMessage.content);\n return content && content !== '(no user instructions)' ? [content] : [];\n}));\nconst configuredPromptHistory = computed(() => controlledValue(\n (state) => state.composer?.promptHistory,\n () => props.promptHistory,\n));\nconst effectivePromptHistory = computed(() => mergePromptHistories(\n configuredPromptHistory.value ?? loadedPromptHistory.value,\n visiblePromptHistory.value,\n));\nconst effectiveAnsweredClientRequestIds = computed(() => controlledValue(\n (state) => state.thread?.answeredClientRequestIds,\n () => props.answeredClientRequestIds ?? props.surface?.answeredClientRequestIds,\n));\nconst displayAnsweredClientRequestIds = computed<ReadonlySet<string>>(() => new Set([\n ...(effectiveAnsweredClientRequestIds.value ?? []),\n ...questionResponses.keys(),\n]));\nconst effectiveClientRequests = computed<readonly CodexSurfaceClientRequest[]>(() => controlledValue(\n (state) => state.thread?.clientRequests ?? [],\n () => props.clientRequests ?? surfaceState.value?.clientRequests ?? [],\n));\nconst supersededQuestionIds = computed<ReadonlySet<string>>(() => {\n const ids = new Set<string>();\n const turns = new Map((effectiveTurns.value ?? []).map((turn, index) => [turn.id, index]));\n const messages = authoritativeMessages.value.map(chatMessageFromInput);\n for (const [questionIndex, message] of messages.entries()) {\n for (const part of message.parts ?? []) {\n if (part.type !== 'question' || part.request.payload.request.delivery !== 'async') continue;\n const questionTurnId = part.request.turnId ?? message.turnId;\n const questionTurnIndex = questionTurnId ? turns.get(questionTurnId) : undefined;\n if (messages.some((candidate, userIndex) => {\n if (candidate.role !== 'user') return false;\n const userTurnIndex = candidate.turnId ? turns.get(candidate.turnId) : undefined;\n if (questionTurnIndex !== undefined && userTurnIndex !== undefined\n && userTurnIndex !== questionTurnIndex) return userTurnIndex > questionTurnIndex;\n return userIndex > questionIndex;\n })) ids.add(part.request.id);\n }\n }\n return ids;\n});\nconst dismissedQuestionIds = computed<ReadonlySet<string>>(() => new Set([\n ...locallyDismissedQuestionIds.value,\n ...supersededQuestionIds.value,\n]));\nconst pendingQuestionRequests = computed(() => {\n const requests: Extract<CodexSurfaceClientRequest, { kind: 'ask_user' }>[] = [];\n const seen = new Set<string>();\n for (const request of effectiveClientRequests.value) {\n if (request.kind !== 'ask_user' || request.payload.request.delivery !== 'tool'\n || request.payload.request.questions.length === 0\n || displayAnsweredClientRequestIds.value.has(request.id)) continue;\n seen.add(request.id);\n requests.push(request);\n }\n for (const message of effectiveMessages.value) {\n for (const part of chatMessageFromInput(message).parts ?? []) {\n if (\n part.type !== 'question'\n || part.historical === true\n || part.request.payload.request.questions.length === 0\n || seen.has(part.request.id)\n || displayAnsweredClientRequestIds.value.has(part.request.id)\n || dismissedQuestionIds.value.has(part.request.id)\n ) continue;\n seen.add(part.request.id);\n requests.push(part.request);\n }\n }\n return requests;\n});\nconst expandedQuestionRequest = computed(() => (\n pendingQuestionRequests.value.find((request) => request.payload.request.delivery === 'tool')\n ?? pendingQuestionRequests.value.find((request) => request.id === openedQuestionId.value)\n ?? pendingQuestionRequests.value.find((request) => {\n if (request.payload.request.delivery !== 'async') return true;\n const turn = effectiveTurns.value?.find((candidate) => candidate.id === request.turnId);\n return turn ? turn.status === 'inProgress' : request.turnId === effectiveActiveTurnId.value;\n })\n));\nconst hiddenQuestionRequestIds = computed<ReadonlySet<string>>(() => new Set(\n pendingQuestionRequests.value.map((request) => request.id),\n));\nconst activeConfirmation = computed(() => effectiveClientRequests.value.find(\n (request): request is Extract<CodexSurfaceClientRequest, { kind: 'confirm_tool' }> => (\n request.kind === 'confirm_tool' && !displayAnsweredClientRequestIds.value.has(request.id)\n ),\n));\nconst activeComposerRequestItemIds = computed<ReadonlySet<string>>(() => new Set(\n effectiveClientRequests.value\n .filter((request) => request.kind === 'confirm_tool'\n ? !displayAnsweredClientRequestIds.value.has(request.id)\n : request.payload.request.delivery === 'tool')\n .map((request) => request.itemId),\n));\nfunction transformTranscriptMessage(message: Message | SurfaceMessage, index: number): Message | SurfaceMessage {\n const transformed = props.transformMessage?.(message, index) ?? message;\n const chatMessage = chatMessageFromInput(transformed);\n const isHiddenTool = (toolCall: MessageToolCall) => activeComposerRequestItemIds.value.has(toolCall.itemId ?? toolCall.id);\n if (!chatMessage.parts?.some((part) => (\n (part.type === 'question' && dismissedQuestionIds.value.has(part.request.id))\n || (part.type === 'tool' && isHiddenTool(part.toolCall))\n )) && !chatMessage.toolCalls?.some(isHiddenTool)) return transformed;\n return {\n ...chatMessage,\n parts: chatMessage.parts?.filter((part) => (\n part.type !== 'tool' || !isHiddenTool(part.toolCall)\n )).map((part) => (\n part.type === 'question' && dismissedQuestionIds.value.has(part.request.id)\n ? { ...part, historical: true }\n : part\n )),\n toolCalls: chatMessage.toolCalls?.filter((toolCall) => !isHiddenTool(toolCall)),\n };\n}\nconst effectiveApprovals = computed(() => controlledValue(\n (state) => state.thread?.approvals ?? [],\n () => props.approvals ?? surfaceState.value?.approvals ?? [],\n));\nconst activeApproval = computed(() => effectiveApprovals.value[0]);\nconst effectiveBusy = computed(() => controlledValue(\n (state) => state.identity.busy ?? false,\n () => props.busy ?? surfaceState.value?.busy ?? false,\n));\nconst effectiveTranscriptBusy = computed(() => (\n effectiveBusy.value || pendingControlledSubmission.value !== null\n));\nconst {\n armed: escapeInterruptArmed,\n clear: clearEscapeInterruptArm,\n} = useConversationEscapeInterrupt({\n root: paneElement,\n busy: () => effectiveBusy.value,\n enabled: () => props.escapeInterrupt,\n onInterrupt: interrupt,\n});\nconst effectiveConversationKey = computed(() => controlledValue(\n (state) => state.identity.conversationKey,\n () => (props.conversationKey !== undefined ? props.conversationKey : surfaceState.value?.activeConversationId),\n));\nconst effectiveContextUsage = computed(() => controlledValue(\n (state) => state.thread?.contextUsage,\n () => (props.contextUsage !== undefined ? props.contextUsage : surfaceState.value?.contextUsage),\n));\nconst effectiveDisabled = computed(() => controlledValue(\n (state) => state.identity.disabled ?? false,\n () => props.disabled ?? (surfaceState.value ? surfaceState.value.status !== 'ready' : false),\n));\nconst effectiveError = computed(() => (\n localError.value\n ?? controlledValue(\n (state) => state.identity.error,\n () => props.error ?? surfaceState.value?.error ?? null,\n )\n ?? null\n));\nconst effectiveGoal = computed(() => controlledValue(\n (state) => state.thread?.goal ?? null,\n () => (props.goal !== undefined ? props.goal : surfaceState.value?.goal ?? null),\n));\nconst effectiveHistoryLoading = computed(() => controlledValue(\n (state) => state.history?.loading ?? false,\n () => props.historyLoading ?? surfaceState.value?.historyLoading ?? false,\n));\nconst effectiveRenderStrategy = computed<CodexConversationRenderStrategy>(() => (\n props.renderStrategy ?? (props.lazyMessages === false ? 'eager' : 'lazy')\n));\nconst effectiveHasOlderHistory = computed(() => controlledValue(\n (state) => state.history?.hasOlder ?? false,\n () => props.hasOlderHistory ?? surfaceState.value?.historyState?.hasOlder ?? false,\n));\nconst effectiveLoadingOlderHistory = computed(() => controlledValue(\n (state) => state.history?.loadingOlder ?? false,\n () => props.loadingOlderHistory ?? surfaceState.value?.historyState?.loadingOlder ?? false,\n));\nconst effectiveModelCatalogStatus = computed(() => controlledValue(\n (state) => state.catalogs?.modelCatalogStatus,\n () => props.modelCatalogStatus ?? surfaceState.value?.modelCatalogStatus,\n));\nconst effectiveModels = computed(() => controlledValue(\n (state) => state.catalogs?.models,\n () => props.models ?? surfaceState.value?.models,\n));\nconst effectiveApprovalPreset = computed(() => controlledValue(\n (state) => state.composer?.approvalPreset,\n () => (props.approvalPreset !== undefined ? props.approvalPreset : surfaceState.value?.approvalPreset),\n));\nconst effectivePlanMode = computed(() => controlledValue(\n (state) => state.composer?.planMode,\n () => props.planMode ?? surfaceState.value?.planMode,\n));\nconst effectivePlugins = computed(() => controlledValue(\n (state) => state.catalogs?.plugins,\n () => props.plugins ?? surfaceState.value?.plugins,\n));\nconst effectiveMentionGroups = computed(() => controlledValue(\n (state) => state.catalogs?.mentionGroups,\n () => props.mentionGroups,\n) as readonly CodexComposerMentionGroup<Payload>[] | undefined);\nconst effectivePresentation = computed(() => resolveCodexConversationPresentation(props.presentation));\nconst effectiveQueuedPrompts = computed(() => controlledValue(\n (state) => state.thread?.queuedPrompts ?? [],\n () => props.queuedPrompts ?? surfaceState.value?.queuedPrompts ?? [],\n));\nconst effectiveSelectedModelId = computed(() => controlledValue(\n (state) => state.composer?.selectedModelId,\n () => (props.selectedModelId !== undefined ? props.selectedModelId : surfaceState.value?.selectedModelId),\n));\nconst effectiveSelectedReasoningEffort = computed(() => controlledValue(\n (state) => state.composer?.selectedReasoningEffort,\n () => (props.selectedReasoningEffort !== undefined\n ? props.selectedReasoningEffort\n : surfaceState.value?.selectedReasoningEffort),\n));\nconst effectiveSelectedServiceTier = computed(() => controlledValue(\n (state) => state.composer?.selectedServiceTier,\n () => (props.selectedServiceTier !== undefined\n ? props.selectedServiceTier\n : surfaceState.value?.selectedServiceTier),\n));\nconst effectiveSkillCatalogStatus = computed(() => controlledValue(\n (state) => state.catalogs?.skillCatalogStatus,\n () => props.skillCatalogStatus ?? surfaceState.value?.skillCatalogStatus,\n));\nconst effectiveSkills = computed(() => controlledValue(\n (state) => state.catalogs?.skills,\n () => props.skills ?? surfaceState.value?.skills,\n));\nconst effectiveTurnGitDiff = computed(() => controlledValue(\n (state) => state.thread?.turnGitDiff,\n () => (props.turnGitDiff !== undefined ? props.turnGitDiff : surfaceState.value?.turnGitDiff),\n));\nconst effectiveAttachEnabled = computed(() => controlledValue(\n (state) => state.policy?.attachEnabled ?? true,\n () => props.attachEnabled !== false,\n));\nconst effectiveCapabilities = computed<CodexCapabilities>(() => ({\n ...codexCapabilities,\n ...(effectiveControllerState.value\n ? effectiveControllerState.value.capabilities\n : props.capabilities),\n approvalPresets: effectiveControllerState.value?.capabilities?.approvalPresets\n ?? (effectiveControllerState.value\n ? codexCapabilities.approvalPresets\n : props.approvalPresets ?? surfaceState.value?.approvalPresets ?? props.capabilities?.approvalPresets)\n ?? codexCapabilities.approvalPresets,\n}));\nconst effectiveCommands = computed(() => controlledValue(\n (state) => state.catalogs?.commands ?? [],\n () => props.commands ?? codexCommands,\n));\nconst effectiveFiles = computed(() => controlledValue(\n (state) => state.catalogs?.files ?? [],\n () => props.files,\n));\nconst effectiveLeadingMenuItems = computed(() => controlledValue(\n (state) => state.composer?.leadingMenuItems ?? [],\n () => props.leadingMenuItems,\n));\nconst effectiveMenuItems = computed(() => controlledValue(\n (state) => state.composer?.menuItems ?? [],\n () => props.menuItems,\n));\nconst effectiveModelMenuItems = computed(() => controlledValue(\n (state) => state.composer?.modelMenuItems ?? [],\n () => props.modelMenuItems,\n));\nconst effectivePlaceholder = computed(() => controlledValue(\n (state) => state.composer?.placeholder,\n () => props.placeholder,\n) ?? 'Ask Codex…');\nconst effectiveCanDeleteTurn = computed(() => controlledValue(\n (state) => state.policy?.canDeleteTurn ?? true,\n () => props.canDeleteTurn,\n));\nconst effectiveCanEditTurn = computed(() => controlledValue(\n (state) => state.policy?.canEditTurn ?? true,\n () => props.canEditTurn,\n));\nconst effectiveCanForkTurn = computed(() => controlledValue(\n (state) => state.policy?.canForkTurn ?? false,\n () => props.canForkTurn,\n));\nconst effectiveCanRetryTurn = computed(() => controlledValue(\n (state) => state.policy?.canRetryTurn ?? true,\n () => props.canRetryTurn,\n));\nconst effectiveActionsDisabled = computed(() => (\n controlledValue((state) => state.policy?.actionsDisabled ?? false, () => props.actionsDisabled ?? false)\n));\nconst effectiveFollowUpsDisabled = computed(() => (\n effectiveBusy.value\n || controlledValue((state) => state.policy?.followUpsDisabled ?? false, () => props.followUpsDisabled ?? false)\n));\nconst showHistoryLoader = computed(() => effectiveHistoryLoading.value);\nconst started = computed(() => (\n effectiveMessages.value.length > 0 || effectiveBusy.value || effectiveApprovals.value.length > 0\n));\n\nwatch(() => Boolean(activeApproval.value || activeConfirmation.value || expandedQuestionRequest.value), async (pending, wasPending) => {\n if (pending || !wasPending) return;\n const focused = document.activeElement;\n if (!focused || !footerElement.value?.contains(focused)) return;\n const conversationKey = effectiveConversationKey.value;\n await nextTick();\n // Restore only this request's focus; never steal it from another pane or a\n // control the user selected while the host was resolving the request.\n if (effectiveConversationKey.value === conversationKey\n && (document.activeElement === focused || document.activeElement === document.body)) {\n composer.value?.focus({ preserveSelection: true });\n }\n});\n\nwatch(() => props.modelValue, () => {\n if (effectiveController.value || props.composerState) return;\n if (props.modelValue === localDraft.value) return;\n localDraft.value = props.modelValue;\n localComposerState.value = {\n text: props.modelValue,\n selectionStart: props.modelValue.length,\n selectionEnd: props.modelValue.length,\n };\n});\n\nwatch(effectiveComposerState, (state) => {\n if (!state) return;\n const normalized = normalizeCodexComposerState(state);\n localComposerState.value = normalized;\n localDraft.value = normalized.text;\n}, { deep: true });\n\nwatch(effectiveAttachments, (attachments) => {\n selectedAttachments.value = [...attachments];\n});\n\nwatch(effectiveAttachEnabled, (enabled) => {\n if (!enabled && selectedAttachments.value.length > 0) replaceAttachments([]);\n});\n\nwatch(effectiveConversationKey, (conversationKey, previousConversationKey) => {\n openedQuestionId.value = null;\n locallyDismissedQuestionIds.value = new Set();\n const pending = pendingControlledSubmission.value;\n if (pending) {\n if (\n !pending.hasAdoptedConversationKey\n && (previousConversationKey ?? null) === pending.originConversationKey\n ) {\n pendingControlledSubmission.value = {\n ...pending,\n adoptedConversationKey: conversationKey ?? null,\n hasAdoptedConversationKey: true,\n };\n } else if (\n (conversationKey ?? null) !== pending.originConversationKey\n && (conversationKey ?? null) !== pending.adoptedConversationKey\n ) {\n pendingControlledSubmission.value = null;\n }\n }\n deleteOperation += 1;\n deletingTurnId.value = null;\n clearEscapeInterruptArm();\n editingQueuedPromptId.value = null;\n localError.value = null;\n const incoming = normalizeCodexComposerState(effectiveComposerState.value ?? (\n effectiveController.value\n ? { text: '', selectionStart: 0, selectionEnd: 0 }\n : {\n text: props.modelValue,\n selectionStart: props.modelValue.length,\n selectionEnd: props.modelValue.length,\n }\n ));\n localComposerState.value = incoming;\n localDraft.value = incoming.text;\n});\n\nwatch(authoritativeMessages, (messages) => {\n const pending = pendingControlledSubmission.value;\n if (!pending) return;\n if (messages.some((message) => matchesPendingSubmission(message, pending))) {\n pendingControlledSubmission.value = null;\n return;\n }\n if (pending.hasAdoptedConversationKey && messages.length > 0) {\n pendingControlledSubmission.value = null;\n }\n});\n\nwatch([effectiveMessages, effectiveTurns], () => {\n const turnId = deletingTurnId.value;\n if (!turnId) return;\n const turnStillPresent = effectiveTurns.value?.some((turn) => turn.id === turnId)\n || effectiveMessages.value.some((message) => chatMessageFromInput(message).turnId === turnId);\n if (turnStillPresent) return;\n deleteOperation += 1;\n deletingTurnId.value = null;\n});\n\nwatch(effectiveQueuedPrompts, (prompts) => {\n const editingId = editingQueuedPromptId.value;\n if (editingId && !prompts.some((prompt) => prompt.id === editingId)) {\n editingQueuedPromptId.value = null;\n }\n});\n\nwatch([\n effectiveConversationKey,\n () => surfaceState.value?.activeConversationId,\n () => effectiveControllerActions.value?.readPromptHistory,\n configuredPromptHistory,\n], () => { void loadPromptHistory(); }, { immediate: true });\n\nwatch(() => [surfaceState.value?.status, surfaceState.value?.error] as const, ([status, error]) => {\n if (status === 'ready' && error == null) localError.value = null;\n});\n\nonMounted(() => {\n if (props.surface && props.surface.state.status === 'idle') {\n void runSurfaceAction(() => props.surface!.connect());\n }\n});\n\nasync function loadPromptHistory(): Promise<void> {\n const request = ++promptHistoryRequest;\n const key = effectiveConversationKey.value;\n promptHistoryLoading.value = false;\n loadedPromptHistory.value = [];\n if (key == null || configuredPromptHistory.value !== undefined) return;\n\n const cached = promptHistoryByConversation.get(key);\n if (cached) {\n loadedPromptHistory.value = cached;\n return;\n }\n\n const controlledLoader = effectiveControllerActions.value?.readPromptHistory;\n const surface = props.surface;\n const conversationId = surfaceState.value?.activeConversationId;\n if (!controlledLoader && !conversationId) return;\n\n promptHistoryLoading.value = true;\n try {\n const prompts = controlledLoader\n ? await controlledLoader()\n : (await surface!.readConversationPromptHistory(conversationId!)).prompts;\n if (request !== promptHistoryRequest || effectiveConversationKey.value !== key) return;\n const bounded = [...prompts].slice(-100);\n promptHistoryByConversation.set(key, bounded);\n loadedPromptHistory.value = bounded;\n } catch {\n // Prompt recall is an optional enhancement; visible messages remain usable.\n } finally {\n if (request === promptHistoryRequest) promptHistoryLoading.value = false;\n }\n}\n\nfunction mergePromptHistories(\n older: readonly string[],\n visible: readonly string[],\n): readonly string[] {\n const maximumOverlap = Math.min(older.length, visible.length);\n let overlap = maximumOverlap;\n while (overlap > 0) {\n const olderStart = older.length - overlap;\n if (visible.slice(0, overlap).every((prompt, index) => prompt === older[olderStart + index])) break;\n overlap -= 1;\n }\n return [...older, ...visible.slice(overlap)].slice(-100);\n}\n\nfunction submit(prompt: string, composerOptions?: Pick<CodexRendererSendMessageOptions, 'inputMethod'>): void {\n updateDraft('');\n const queuedPromptId = editingQueuedPromptId.value;\n if (queuedPromptId) {\n editingQueuedPromptId.value = null;\n updateQueuedPrompt(queuedPromptId, prompt);\n replaceAttachments([]);\n return;\n }\n const options = sendOptionsForAttachments(selectedAttachments.value, composerOptions);\n const previousDismissedQuestions = dismissPendingQuestions();\n messageList.value?.scrollToBottom();\n void nextTick(() => messageList.value?.scrollToBottom());\n if (effectiveController.value) {\n const controlledSubmit = effectiveControllerActions.value?.submit;\n if (controlledSubmit) {\n const optimisticMessageId = beginControlledSubmission(prompt, selectedAttachments.value);\n void runSurfaceAction(\n () => Promise.resolve(controlledSubmit(prompt, options)),\n () => {\n clearPendingControlledSubmission(optimisticMessageId);\n locallyDismissedQuestionIds.value = previousDismissedQuestions;\n },\n );\n }\n replaceAttachments([]);\n return;\n }\n if (options) emit('submit', prompt, options);\n else emit('submit', prompt);\n if (props.surface) {\n void runSurfaceAction(\n () => props.surface!.sendMessage(prompt, options),\n () => { locallyDismissedQuestionIds.value = previousDismissedQuestions; },\n );\n }\n replaceAttachments([]);\n}\n\nfunction dismissPendingQuestions(): ReadonlySet<string> {\n const previous = locallyDismissedQuestionIds.value;\n locallyDismissedQuestionIds.value = new Set([\n ...previous,\n ...pendingQuestionRequests.value\n .filter((request) => request.payload.request.delivery === 'async')\n .map((request) => request.id),\n ]);\n openedQuestionId.value = null;\n return previous;\n}\n\nfunction cancelPendingQuestion(id: string): void {\n if (!pendingQuestionRequests.value.some((request) => request.id === id)) return;\n const response: ClientRequestResponse = { id, payload: { answers: {}, cancelled: true } };\n questionResponses.set(id, response.payload);\n locallyDismissedQuestionIds.value = new Set([...locallyDismissedQuestionIds.value, id]);\n openedQuestionId.value = null;\n respondToClientRequest(response);\n}\n\nfunction continueInterruptedTurn(): void {\n if (dispatchControllerAction('continueInterruptedTurn')) return;\n if (effectiveController.value) return;\n emit('continueInterruptedTurn');\n if (props.surface) void runSurfaceAction(() => props.surface!.continueInterruptedTurn());\n}\n\nfunction beginControlledSubmission(\n prompt: string,\n attachments: readonly CodexHostAttachment[],\n): string | null {\n if (effectiveBusy.value || authoritativeMessages.value.length > 0) return null;\n const id = `codex-optimistic-user-${++optimisticSubmissionSequence}`;\n pendingControlledSubmission.value = {\n adoptedConversationKey: null,\n hasAdoptedConversationKey: false,\n originConversationKey: effectiveConversationKey.value ?? null,\n prompt,\n message: {\n id,\n role: 'user',\n status: 'complete',\n createdAt: new Date().toISOString(),\n parts: [\n { type: 'text', text: prompt },\n ...attachments.map((attachment) => ({\n type: 'attachment' as const,\n attachment: {\n kind: attachment.type,\n name: attachment.name,\n mimeType: attachment.mimeType,\n ...(attachment.previewUrl ? { url: attachment.previewUrl } : {}),\n },\n })),\n ],\n },\n };\n return id;\n}\n\nfunction matchesPendingSubmission(\n message: Message | SurfaceMessage,\n pending: PendingControlledSubmission,\n): boolean {\n const candidate = chatMessageFromInput(message);\n return candidate.role === 'user' && stripMessageContext(candidate.content) === pending.prompt;\n}\n\nfunction clearPendingControlledSubmission(messageId: string | null): void {\n if (messageId && pendingControlledSubmission.value?.message.id === messageId) {\n pendingControlledSubmission.value = null;\n }\n}\n\nfunction loadOlderHistory(): void {\n if (dispatchControllerAction('loadOlderHistory')) return;\n if (effectiveController.value) return;\n if (props.surface && effectiveConversationKey.value) {\n void runSurfaceAction(() => props.surface!.loadOlderConversationHistory(String(effectiveConversationKey.value)));\n return;\n }\n emit('loadOlderHistory');\n}\n\nfunction quoteMessage(index: number): void {\n const message = effectiveMessages.value[index];\n if (!message) return;\n const chatMessage = chatMessageFromInput(message);\n const content = stripMessageContext(chatMessage.content);\n if (chatMessage.role !== 'user' || !content) return;\n updateDraft(content);\n if (dispatchControllerAction('quoteMessage', index)) return;\n if (effectiveController.value) return;\n emit('quoteMessage', index);\n}\n\nfunction editGoal(): void {\n if (!effectiveGoal.value?.objective.trim()) return;\n const objective = effectiveGoal.value.objective;\n updateComposerState({\n text: objective,\n selectionStart: objective.length,\n selectionEnd: objective.length,\n activeCommandId: 'codex.goal',\n });\n if (dispatchControllerAction('editGoal')) return;\n if (effectiveController.value) return;\n emit('editGoal');\n}\n\nfunction handleConversationClick(event: MouseEvent): void {\n const target = event.target instanceof Element ? event.target : null;\n const anchor = target?.closest('a[href]');\n if (!anchor) return;\n\n const href = anchor.getAttribute('href')?.trim() ?? '';\n if (!href || href.startsWith('#')) return;\n\n event.preventDefault();\n const link = codexConversationLinkFromHref(href);\n if (!link) return;\n handleConversationLink(link);\n}\n\nfunction handleConversationLink(link: CodexConversationLink): void {\n if (dispatchControllerAction('openLink', link)) return;\n if (effectiveController.value) return;\n emit('openLink', link);\n if (props.openConversationLink) {\n void Promise.resolve(props.openConversationLink(link)).catch(setLocalError);\n return;\n }\n if (link.kind === 'external') {\n if (hostCapabilities) void hostCapabilities.openExternal(link.href).catch(setLocalError);\n else window.open(link.href, '_blank', 'noopener,noreferrer');\n }\n}\n\nfunction handleVisualization(visualization: CodexConversationVisualization): void {\n if (dispatchControllerAction('openVisualization', visualization)) return;\n if (effectiveController.value) return;\n emit('openVisualization', visualization);\n if (props.openVisualization) {\n void Promise.resolve(props.openVisualization(visualization)).catch(setLocalError);\n }\n}\n\nasync function openImage(\n image: CodexMessageImage,\n context?: CodexMessageImageContext,\n): Promise<boolean> {\n const handler = effectiveController.value\n ? effectiveControllerActions.value?.openImage\n : props.openImage;\n if (!handler) return false;\n localError.value = null;\n try {\n return await handler(image, context) !== false;\n } catch (error) {\n setLocalError(error);\n return true;\n }\n}\n\nasync function selectAttachments(): Promise<void> {\n if (dispatchControllerAction('attach')) return;\n if (!effectiveController.value) emit('attach');\n if (!effectiveAttachEnabled.value) return;\n try {\n appendAttachments(await pickCodexAttachments(props.pickAttachments, hostCapabilities));\n } catch (error) {\n setLocalError(error);\n }\n}\n\nfunction handleDragOver(event: DragEvent): void {\n if (effectiveAttachEnabled.value && event.dataTransfer?.types.includes('Files')) event.preventDefault();\n}\n\nfunction handleDrop(event: DragEvent): void {\n if (!effectiveAttachEnabled.value) return;\n const files = [...(event.dataTransfer?.files ?? [])];\n if (files.length === 0) return;\n event.preventDefault();\n void ingestFiles(files);\n}\n\nfunction handlePaste(event: ClipboardEvent): void {\n const images = clipboardFiles(event).filter((file) => file.type.startsWith('image/'));\n if (images.length === 0) return;\n // Never let Chromium insert clipboard image HTML into the contenteditable.\n // The composer inserts accompanying plain text while this pane owns the one\n // attachment-ingestion path.\n event.preventDefault();\n if (!effectiveAttachEnabled.value) return;\n void ingestFiles(images);\n}\n\nfunction clipboardFiles(event: ClipboardEvent): File[] {\n const clipboard = event.clipboardData;\n if (!clipboard) return [];\n const files = [...clipboard.files];\n if (files.length > 0) return files;\n return [...(clipboard.items ?? [])]\n .filter((item) => item.kind === 'file')\n .map((item) => item.getAsFile())\n .filter((file): file is File => file !== null);\n}\n\nasync function ingestFiles(files: readonly File[]): Promise<void> {\n try {\n appendAttachments(await ingestCodexAttachments(files, props.ingestAttachments, hostCapabilities));\n } catch (error) {\n setLocalError(error);\n }\n}\n\nfunction appendAttachments(attachments: readonly CodexHostAttachment[]): void {\n const byReference = new Map(selectedAttachments.value.map((attachment) => [attachment.reference, attachment]));\n for (const attachment of attachments) byReference.set(attachment.reference, attachment);\n replaceAttachments([...byReference.values()].slice(0, 20));\n}\n\nfunction removeAttachment(id: string): void {\n replaceAttachments(selectedAttachments.value.filter((attachment) => attachment.id !== id));\n}\n\nfunction replaceAttachments(attachments: CodexHostAttachment[]): void {\n selectedAttachments.value = attachments;\n if (dispatchControllerAction('updateAttachments', attachments)) return;\n if (effectiveController.value) return;\n emit('attachmentsChange', attachments);\n}\n\nfunction sendOptionsForAttachments(\n attachments: readonly CodexHostAttachment[],\n composerOptions?: Pick<CodexRendererSendMessageOptions, 'inputMethod'>,\n): CodexRendererSendMessageOptions | undefined {\n if (attachments.length === 0) return composerOptions;\n const surfaceAttachments: CodexRendererAttachment[] = attachments.map((attachment) => (\n attachment.type === 'image'\n ? {\n type: 'image',\n reference: attachment.reference,\n }\n : {\n type: 'file', reference: attachment.reference,\n }\n ));\n return { ...composerOptions, attachments: surfaceAttachments };\n}\n\nfunction updateDraft(value: string): void {\n updateComposerState({ text: value, selectionStart: value.length, selectionEnd: value.length });\n}\n\nfunction updateComposerState(state: CodexComposerState): void {\n const normalized = normalizeCodexComposerState(state);\n localComposerState.value = normalized;\n localDraft.value = normalized.text;\n if (dispatchControllerAction('updateComposerState', normalized)) return;\n if (effectiveController.value) return;\n emit('update:modelValue', normalized.text);\n emit('update:composerState', normalized);\n}\n\nfunction cancel(): void {\n if (dispatchControllerAction('cancel')) return;\n if (effectiveController.value) return;\n emit('cancel');\n if (props.surface) void runSurfaceAction(() => props.surface!.interrupt());\n}\n\nfunction respondToClientRequest(response: ClientRequestResponse): void {\n if (dispatchControllerAction('clientResponse', response)) return;\n if (effectiveController.value) return;\n emit('clientResponse', response);\n if (props.surface) void runSurfaceAction(() => props.surface!.respondToClientRequest(response));\n}\n\nfunction copyMessage(index: number): void {\n if (dispatchControllerAction('onMessageCopied', index)) return;\n if (effectiveController.value) return;\n emit('copyMessage', index);\n}\n\nasync function deleteTurn(turnId: string): Promise<void> {\n if (deletingTurnId.value !== null) return;\n const controlledAction = effectiveControllerActions.value?.deleteTurn;\n if (effectiveController.value && !controlledAction) return;\n\n const operation = ++deleteOperation;\n let waitForControlledState = false;\n deletingTurnId.value = turnId;\n try {\n if (controlledAction) {\n localError.value = null;\n let result: void | Promise<void>;\n try {\n result = controlledAction(turnId);\n } catch (error) {\n setLocalError(error);\n return;\n }\n if (result === undefined) {\n waitForControlledState = true;\n return;\n }\n await runSurfaceAction(() => result);\n return;\n }\n emit('deleteTurn', turnId);\n if (props.surface) {\n await runSurfaceAction(() => props.surface!.deleteTurn(turnId));\n }\n } finally {\n if (!waitForControlledState && deleteOperation === operation) deletingTurnId.value = null;\n }\n}\n\nfunction editTurn(payload: { content: string; turnId: string }): void {\n if (dispatchControllerAction('editTurn', payload)) return;\n if (effectiveController.value) return;\n emit('editTurn', payload);\n if (props.surface) void runSurfaceAction(() => props.surface!.editTurn(payload.turnId, payload.content));\n}\n\nfunction forkTurn(turnId: string): void {\n if (dispatchControllerAction('forkTurn', turnId)) return;\n if (effectiveController.value) return;\n emit('forkTurn', turnId);\n if (props.surface) void runSurfaceAction(() => props.surface!.forkTurn(turnId));\n}\n\nfunction retryTurn(turnId: string): void {\n if (dispatchControllerAction('retryTurn', turnId)) return;\n if (effectiveController.value) return;\n emit('retryTurn', turnId);\n if (props.surface) void runSurfaceAction(() => props.surface!.retryTurn(turnId));\n}\n\nfunction sendFollowUp(prompt: string): void {\n if (dispatchControllerAction('sendFollowUp', prompt)) return;\n if (effectiveController.value) return;\n emit('sendFollowUp', prompt);\n if (props.surface) void runSurfaceAction(() => props.surface!.sendMessage(prompt));\n}\n\nfunction clearGoal(): void {\n if (dispatchControllerAction('clearGoal')) return;\n if (effectiveController.value) return;\n emit('clearGoal');\n if (props.surface) void runSurfaceAction(() => props.surface!.clearGoal());\n}\n\nfunction deleteQueuedPrompt(promptId: string): void {\n if (editingQueuedPromptId.value === promptId) editingQueuedPromptId.value = null;\n if (dispatchControllerAction('deleteQueuedPrompt', promptId)) return;\n if (effectiveController.value) return;\n emit('deleteQueuedPrompt', promptId);\n if (props.surface) void runSurfaceAction(() => props.surface!.deleteQueuedPrompt(promptId));\n}\n\nfunction editQueuedPrompt(promptId: string): void {\n if (localDraft.value.length > 0) return;\n const prompt = effectiveQueuedPrompts.value.find((candidate) => candidate.id === promptId);\n if (!prompt) return;\n editingQueuedPromptId.value = promptId;\n updateDraft(prompt.text);\n composer.value?.focus();\n}\n\nfunction updateQueuedPrompt(promptId: string, prompt: string): void {\n if (dispatchControllerAction('updateQueuedPrompt', promptId, prompt)) return;\n if (effectiveController.value) return;\n emit('updateQueuedPrompt', promptId, prompt);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateQueuedPrompt(promptId, prompt));\n}\n\nfunction steerQueuedPrompt(promptId: string, prompt?: string): void {\n if (!effectiveCapabilities.value.steerPrompt) return;\n if (editingQueuedPromptId.value === promptId) editingQueuedPromptId.value = null;\n if (prompt === undefined) dispatchControllerAction('steerQueuedPrompt', promptId);\n else dispatchControllerAction('steerQueuedPrompt', promptId, prompt);\n if (effectiveController.value) return;\n if (prompt === undefined) emit('steerQueuedPrompt', promptId);\n else emit('steerQueuedPrompt', promptId, prompt);\n if (props.surface) {\n void runSurfaceAction(() => prompt === undefined\n ? props.surface!.steerQueuedPrompt(promptId)\n : props.surface!.steerQueuedPrompt(promptId, prompt));\n }\n}\n\nfunction interrupt(): void {\n clearEscapeInterruptArm();\n if (dispatchControllerAction('interrupt')) return;\n if (effectiveController.value) return;\n emit('interrupt');\n if (props.surface) void runSurfaceAction(() => props.surface!.interrupt());\n}\n\nfunction steer(prompt: string, composerOptions?: Pick<CodexRendererSendMessageOptions, 'inputMethod'>): void {\n if (!effectiveCapabilities.value.steerPrompt) {\n submit(prompt, composerOptions);\n return;\n }\n const queuedPromptId = editingQueuedPromptId.value;\n if (queuedPromptId) {\n editingQueuedPromptId.value = null;\n steerQueuedPrompt(queuedPromptId, prompt);\n replaceAttachments([]);\n return;\n }\n const options = sendOptionsForAttachments(selectedAttachments.value, composerOptions);\n if (effectiveController.value) {\n const controlledSteer = effectiveControllerActions.value?.steer;\n if (controlledSteer) {\n const previousDismissedQuestions = dismissPendingQuestions();\n void runSurfaceAction(\n () => Promise.resolve(controlledSteer(prompt, options)),\n () => { locallyDismissedQuestionIds.value = previousDismissedQuestions; },\n );\n }\n replaceAttachments([]);\n return;\n }\n const previousDismissedQuestions = dismissPendingQuestions();\n if (options) emit('steer', prompt, options);\n else emit('steer', prompt);\n if (props.surface) void runSurfaceAction(\n () => props.surface!.steerMessage(prompt, options),\n () => { locallyDismissedQuestionIds.value = previousDismissedQuestions; },\n );\n replaceAttachments([]);\n}\n\nfunction selectApprovalPreset(preset: ApprovalPreset): void {\n if (dispatchControllerAction('selectApprovalPreset', preset)) return;\n if (effectiveController.value) {\n void dispatchControllerAction('updateSettings', { approvalPreset: preset });\n return;\n }\n emit('selectApprovalPreset', preset);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ approvalPreset: preset }));\n}\n\nfunction resolveApproval(\n approvalId: string,\n decision: CodexSurfaceApprovalDecision,\n scope: CodexSurfaceApprovalScope,\n): void {\n if (dispatchControllerAction('resolveApproval', approvalId, decision, scope)) return;\n if (effectiveController.value) return;\n emit('resolveApproval', approvalId, decision, scope);\n if (props.surface) void runSurfaceAction(() => props.surface!.resolveApproval(approvalId, decision, scope));\n}\n\nfunction updateModelId(modelId: string): void {\n if (dispatchControllerAction('updateSettings', { modelId })) return;\n if (effectiveController.value) return;\n emit('update:modelId', modelId);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ modelId }));\n}\n\nfunction updatePlanMode(planMode: boolean): void {\n if (dispatchControllerAction('updateSettings', { planMode })) return;\n if (effectiveController.value) return;\n emit('update:planMode', planMode);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ planMode }));\n}\n\nfunction updateReasoningEffort(reasoningEffort: ReasoningEffort): void {\n if (dispatchControllerAction('updateSettings', { reasoningEffort })) return;\n if (effectiveController.value) return;\n emit('update:reasoningEffort', reasoningEffort);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ reasoningEffort }));\n}\n\nfunction updateServiceTier(serviceTier: string | null): void {\n if (dispatchControllerAction('updateSettings', { serviceTier })) return;\n if (effectiveController.value) return;\n emit('update:serviceTier', serviceTier);\n if (props.surface) void runSurfaceAction(() => props.surface!.updateConversationSettings({ serviceTier }));\n}\n\nfunction menuSelect(item: CodexComposerMenuSelectableItem<unknown>): void {\n if (dispatchControllerAction('menuSelect', item)) return;\n if (effectiveController.value) return;\n emit('menuSelect', item as CodexComposerMenuSelectableItem<Payload>);\n}\n\nfunction mentionSelect(\n item: CodexComposerMentionItem,\n group: CodexComposerMentionGroup,\n): void {\n if (dispatchControllerAction('mentionSelect', item, group)) return;\n if (effectiveController.value) return;\n emit(\n 'mentionSelect',\n item as CodexComposerMentionItem<Payload>,\n group as CodexComposerMentionGroup<Payload>,\n );\n}\n\nfunction dispatchControllerAction(\n name: keyof CodexConversationPaneActions<Payload>,\n ...args: unknown[]\n): boolean {\n const action = effectiveControllerActions.value?.[name] as\n | ((...actionArgs: never[]) => void | Promise<void>)\n | undefined;\n if (!action) return false;\n void runSurfaceAction(() => Promise.resolve(action(...args as never[])));\n return true;\n}\n\nasync function runSurfaceAction(action: () => Promise<unknown>, onError?: () => void): Promise<void> {\n localError.value = null;\n try {\n await action();\n } catch (error) {\n onError?.();\n setLocalError(error);\n }\n}\n\nfunction setLocalError(error: unknown): void {\n localError.value = error instanceof Error ? error.message : String(error);\n}\n\nfunction handleComposerError(error: string | null): void {\n localError.value = error;\n emit('error', error);\n}\n\nfunction focusComposer(): void {\n composer.value?.focus();\n}\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\ndefineExpose({ focusComposer });\n// Stryker restore all\n</script>\n\n<style scoped>\n.codex-conversation-pane {\n --codex-conversation-content-width: 860px;\n display: grid;\n grid-template-rows: minmax(0, 1fr);\n width: 100%;\n min-width: 0;\n min-height: 0;\n height: 100%;\n overflow: hidden;\n color: var(--codex-text-color, var(--color-text, #202124));\n background: var(--codex-surface-color, var(--color-shell-main, #fff));\n}\n\n.codex-conversation-pane__layout {\n height: 100%;\n min-height: 0;\n overflow: hidden;\n --workbench-layout-footer-padding: var(--space-24) 0 var(--space-12);\n --workbench-layout-footer-background: linear-gradient(\n to bottom,\n color-mix(in srgb, var(--color-shell-main) 0%, transparent),\n var(--color-shell-main) 24%\n );\n --workbench-layout-scrollbar-gutter: var(--space-4);\n}\n\n.codex-conversation-pane__messages {\n flex: 1 1 auto;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n background: var(--color-shell-main);\n --codex-scroll-to-bottom-offset: calc(var(--workbench-layout-footer-offset, 0px) - var(--space-12) + 4px);\n --codex-scroll-to-bottom-size: 40px;\n --message-list-content-width: var(--codex-conversation-content-width);\n --message-list-content-padding-top: var(--space-12);\n --message-list-content-padding-bottom: calc(var(--workbench-layout-footer-offset) + var(--space-12));\n --message-list-padding-inline-start: var(--space-8);\n --message-list-padding-inline-end: var(--space-8);\n}\n\n.codex-conversation-pane__hero {\n display: grid;\n flex: 1 1 auto;\n min-height: 0;\n place-items: center;\n padding: var(--space-12) var(--space-16) calc(var(--workbench-layout-footer-offset) + var(--space-12));\n}\n\n.codex-conversation-pane__hero-copy {\n display: grid;\n gap: var(--space-2);\n max-width: var(--codex-conversation-content-width);\n text-align: center;\n}\n\n.codex-conversation-pane__hero h1,\n.codex-conversation-pane__hero p {\n margin: 0;\n}\n\n.codex-conversation-pane__hero h1 {\n color: var(--color-text);\n font-size: var(--font-size-24);\n font-weight: var(--font-weight-semibold);\n line-height: var(--line-height-28);\n}\n\n.codex-conversation-pane__hero p {\n color: var(--color-text-muted);\n font-size: var(--font-size-14);\n line-height: var(--line-height-20);\n}\n\n.codex-conversation-pane__footer {\n display: flex;\n flex-direction: column;\n width: min(calc(100% - var(--space-16) * 2), var(--codex-conversation-content-width));\n margin: 0 auto;\n}\n\n.codex-conversation-pane__approvals {\n display: grid;\n gap: var(--space-4);\n margin-bottom: var(--space-4);\n}\n\n.codex-conversation-pane__confirmation-composer {\n width: 100%;\n box-sizing: border-box;\n max-height: min(70vh, 38rem);\n overflow-y: auto;\n margin-bottom: var(--space-4);\n}\n\n.codex-conversation-pane__composer-shelf {\n width: 90%;\n margin: 0 auto;\n}\n\n.codex-conversation-pane__composer {\n width: 100%;\n margin: 0 auto var(--space-4);\n}\n\n.codex-conversation-pane__question-composer {\n margin: 0 auto var(--space-4);\n}\n\n.codex-conversation-pane__pending-question {\n display: inline-flex;\n align-items: center;\n min-width: 0;\n gap: var(--space-1);\n overflow: hidden;\n min-height: 24px;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n padding: 0 var(--space-2);\n background: transparent;\n color: var(--color-text-muted);\n font: inherit;\n font-size: var(--font-size-13);\n white-space: nowrap;\n}\n\n.codex-conversation-pane__pending-question button {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n border: 0;\n padding: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n cursor: pointer;\n}\n\n.codex-conversation-pane__pending-question-open {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.codex-conversation-pane__pending-question-cancel svg {\n width: var(--icon-sm);\n height: var(--icon-sm);\n}\n\n.codex-conversation-pane__pending-question-remove {\n display: none;\n}\n\n.codex-conversation-pane__pending-question:hover .codex-conversation-pane__pending-question-icon,\n.codex-conversation-pane__pending-question-cancel:focus-visible .codex-conversation-pane__pending-question-icon {\n display: none;\n}\n\n.codex-conversation-pane__pending-question:hover .codex-conversation-pane__pending-question-remove,\n.codex-conversation-pane__pending-question-cancel:focus-visible .codex-conversation-pane__pending-question-remove {\n display: inline;\n}\n\n.codex-conversation-pane__pending-question button:focus-visible {\n outline: 2px solid var(--color-primary);\n outline-offset: 2px;\n}\n\n.codex-conversation-pane__attachments {\n display: flex;\n gap: var(--space-4);\n width: 100%;\n margin-top: var(--space-2);\n padding: 0;\n overflow-x: auto;\n}\n\n.codex-conversation-pane__attachment {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto;\n gap: 0;\n align-items: center;\n min-width: 0;\n max-width: 240px;\n padding: var(--space-2) var(--space-3);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n background: var(--color-surface-lowest);\n}\n\n.codex-conversation-pane__attachment-preview,\n.codex-conversation-pane__attachment-file {\n width: 32px;\n height: 32px;\n margin-inline-end: var(--space-3);\n border-radius: var(--radius-md);\n}\n\n.codex-conversation-pane__attachment-preview {\n object-fit: cover;\n}\n\n.codex-conversation-pane__attachment-file {\n display: grid;\n place-items: center;\n background: var(--color-surface-low);\n}\n\n.codex-conversation-pane__attachment-name {\n overflow: hidden;\n color: var(--color-text);\n font-size: var(--font-size-12);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.codex-conversation-pane__attachment-actions {\n display: flex;\n align-items: center;\n gap: var(--space-1);\n margin-inline-start: var(--space-4);\n}\n\n.codex-conversation-pane__attachment-remove {\n display: grid;\n width: 24px;\n height: 24px;\n margin-inline-start: calc(-1 * var(--space-3));\n padding: 0;\n border: 0;\n border-radius: var(--radius-full);\n place-items: center;\n color: var(--color-text-muted);\n background: transparent;\n cursor: pointer;\n}\n\n.codex-conversation-pane__attachment-remove:hover:not(:disabled) {\n color: var(--color-text);\n background: var(--color-surface-low);\n}\n\n.codex-conversation-pane__attachment-remove svg {\n width: 16px;\n height: 16px;\n}\n\n.codex-conversation-pane__history-loader {\n width: min(100%, var(--codex-conversation-content-width));\n margin: 0 auto;\n}\n\n.codex-conversation-pane__error {\n margin: 0 0 var(--space-4);\n overflow: hidden;\n color: var(--codex-danger-color, var(--color-error, #b3261e));\n font-size: var(--font-size-13);\n line-height: var(--line-height-18);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n</style>\n","<template>\n <aside class=\"codex-conversation-sidebar\" aria-label=\"Conversations\">\n <div class=\"codex-conversation-sidebar__header\">\n <span class=\"codex-conversation-sidebar__brand\">{{ brand }}</span>\n <button\n class=\"codex-conversation-sidebar__new\"\n type=\"button\"\n :disabled=\"createDisabled\"\n @click=\"emit('create')\"\n >\n <span aria-hidden=\"true\">+</span>\n New thread\n </button>\n </div>\n <p v-if=\"conversations.length === 0\" class=\"codex-conversation-sidebar__empty\">\n {{ loading ? 'Loading threads…' : 'No conversations yet' }}\n </p>\n <nav v-else class=\"codex-conversation-sidebar__list\">\n <div\n v-for=\"conversation in conversations\"\n :key=\"conversation.id\"\n class=\"codex-conversation-sidebar__item\"\n :class=\"{ 'codex-conversation-sidebar__item--active': conversation.id === activeConversationId }\"\n >\n <button\n class=\"codex-conversation-sidebar__select\"\n type=\"button\"\n :aria-current=\"conversation.id === activeConversationId ? 'page' : undefined\"\n @click=\"emit('select', conversation.id)\"\n >\n <span\n class=\"codex-conversation-sidebar__status\"\n :class=\"`codex-conversation-sidebar__status--${conversation.status}`\"\n :aria-label=\"`Status: ${conversation.status}`\"\n :title=\"conversation.status\"\n />\n <span class=\"codex-conversation-sidebar__title\">{{ conversation.title }}</span>\n <span class=\"codex-conversation-sidebar__time\">{{ relativeTime(conversation.updatedAt) }}</span>\n </button>\n <button\n class=\"codex-conversation-sidebar__delete\"\n type=\"button\"\n :aria-label=\"`Delete ${conversation.title}`\"\n title=\"Delete thread\"\n @click=\"confirmDelete(conversation)\"\n >\n <svg aria-hidden=\"true\" fill=\"none\" viewBox=\"0 0 24 24\">\n <path d=\"M4 7h16M10 11v6m4-6v6M9 7l1-2h4l1 2m2 0-1 12H8L7 7\" />\n </svg>\n </button>\n </div>\n </nav>\n </aside>\n</template>\n\n<script setup lang=\"ts\">\nimport type { CodexConversationSummary } from '@codex-app-sdk/core/surface';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n activeConversationId?: string | null;\n brand?: string;\n conversations: readonly CodexConversationSummary[];\n createDisabled?: boolean;\n loading?: boolean;\n}>(), {\n activeConversationId: null,\n brand: 'Codex',\n createDisabled: false,\n loading: false,\n});\n\nconst emit = defineEmits<{\n create: [];\n delete: [conversationId: string];\n select: [conversationId: string];\n}>();\n// Stryker restore all\n\nfunction confirmDelete(conversation: CodexConversationSummary): void {\n const confirmed = window.confirm(\n `Delete \"${conversation.title}\"? This permanently deletes the thread and cannot be undone.`,\n );\n if (confirmed) emit('delete', conversation.id);\n}\n\nfunction relativeTime(value: string): string {\n const elapsedMinutes = Math.max(0, Math.floor((Date.now() - new Date(value).getTime()) / 60_000));\n if (elapsedMinutes < 1) return 'now';\n if (elapsedMinutes < 60) return `${elapsedMinutes}m`;\n const hours = Math.floor(elapsedMinutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\n</script>\n\n<style scoped>\n.codex-conversation-sidebar {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex-direction: column;\n border-right: 1px solid #deded9;\n background: #f1f1ee;\n}\n\n.codex-conversation-sidebar__header {\n display: grid;\n gap: 14px;\n padding: 24px 14px 12px;\n}\n\n.codex-conversation-sidebar__brand {\n padding-left: 8px;\n color: #1f201e;\n font-size: 18px;\n font-weight: 700;\n letter-spacing: -0.02em;\n}\n\n.codex-conversation-sidebar__new,\n.codex-conversation-sidebar__select,\n.codex-conversation-sidebar__delete {\n width: 100%;\n border: 0;\n color: #2a2b29;\n background: transparent;\n font: inherit;\n cursor: pointer;\n}\n\n.codex-conversation-sidebar__new {\n border-radius: 9px;\n padding: 9px 10px;\n font-weight: 600;\n text-align: left;\n}\n\n.codex-conversation-sidebar__new:hover,\n.codex-conversation-sidebar__item:hover,\n.codex-conversation-sidebar__item:focus-within,\n.codex-conversation-sidebar__item--active {\n background: #e2e2dd;\n}\n\n.codex-conversation-sidebar__list {\n display: flex;\n min-height: 0;\n padding: 2px 8px 12px;\n overflow-y: auto;\n flex-direction: column;\n gap: 2px;\n}\n\n.codex-conversation-sidebar__item {\n position: relative;\n border-radius: 9px;\n}\n\n.codex-conversation-sidebar__select {\n display: grid;\n min-width: 0;\n grid-template-columns: 8px minmax(0, 1fr) 34px;\n gap: 8px;\n align-items: center;\n border-radius: 9px;\n padding: 9px 8px 9px 10px;\n text-align: left;\n}\n\n.codex-conversation-sidebar__select:focus-visible,\n.codex-conversation-sidebar__delete:focus-visible {\n outline: 2px solid #3b82f6;\n outline-offset: -2px;\n}\n\n.codex-conversation-sidebar__status {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: #a0a099;\n}\n\n.codex-conversation-sidebar__status--active {\n background: #3b82f6;\n box-shadow: 0 0 0 3px rgb(59 130 246 / 14%);\n}\n\n.codex-conversation-sidebar__status--error {\n background: #c2413b;\n}\n\n.codex-conversation-sidebar__title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n}\n\n.codex-conversation-sidebar__time {\n justify-self: end;\n color: #85857e;\n font-size: 12px;\n pointer-events: none;\n}\n\n.codex-conversation-sidebar__delete {\n position: absolute;\n z-index: 1;\n top: 50%;\n right: 3px;\n display: inline-flex;\n width: 28px;\n height: 28px;\n align-items: center;\n justify-content: center;\n border-radius: 7px;\n color: #85857e;\n opacity: 0;\n pointer-events: none;\n transform: translateY(-50%);\n}\n\n.codex-conversation-sidebar__delete svg {\n width: 16px;\n height: 16px;\n stroke: currentColor;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 1.75;\n}\n\n.codex-conversation-sidebar__item:hover .codex-conversation-sidebar__time,\n.codex-conversation-sidebar__item:focus-within .codex-conversation-sidebar__time {\n opacity: 0;\n}\n\n.codex-conversation-sidebar__item:hover .codex-conversation-sidebar__delete,\n.codex-conversation-sidebar__item:focus-within .codex-conversation-sidebar__delete,\n.codex-conversation-sidebar__delete:focus-visible {\n opacity: 1;\n pointer-events: auto;\n}\n\n.codex-conversation-sidebar__delete:hover,\n.codex-conversation-sidebar__delete:focus-visible {\n color: #b42318;\n background: rgb(180 35 24 / 10%);\n}\n\n.codex-conversation-sidebar__empty {\n padding: 8px 18px;\n color: #85857e;\n font-size: 13px;\n}\n\nbutton:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n</style>\n","<template>\n <aside class=\"codex-conversation-sidebar\" aria-label=\"Conversations\">\n <div class=\"codex-conversation-sidebar__header\">\n <span class=\"codex-conversation-sidebar__brand\">{{ brand }}</span>\n <button\n class=\"codex-conversation-sidebar__new\"\n type=\"button\"\n :disabled=\"createDisabled\"\n @click=\"emit('create')\"\n >\n <span aria-hidden=\"true\">+</span>\n New thread\n </button>\n </div>\n <p v-if=\"conversations.length === 0\" class=\"codex-conversation-sidebar__empty\">\n {{ loading ? 'Loading threads…' : 'No conversations yet' }}\n </p>\n <nav v-else class=\"codex-conversation-sidebar__list\">\n <div\n v-for=\"conversation in conversations\"\n :key=\"conversation.id\"\n class=\"codex-conversation-sidebar__item\"\n :class=\"{ 'codex-conversation-sidebar__item--active': conversation.id === activeConversationId }\"\n >\n <button\n class=\"codex-conversation-sidebar__select\"\n type=\"button\"\n :aria-current=\"conversation.id === activeConversationId ? 'page' : undefined\"\n @click=\"emit('select', conversation.id)\"\n >\n <span\n class=\"codex-conversation-sidebar__status\"\n :class=\"`codex-conversation-sidebar__status--${conversation.status}`\"\n :aria-label=\"`Status: ${conversation.status}`\"\n :title=\"conversation.status\"\n />\n <span class=\"codex-conversation-sidebar__title\">{{ conversation.title }}</span>\n <span class=\"codex-conversation-sidebar__time\">{{ relativeTime(conversation.updatedAt) }}</span>\n </button>\n <button\n class=\"codex-conversation-sidebar__delete\"\n type=\"button\"\n :aria-label=\"`Delete ${conversation.title}`\"\n title=\"Delete thread\"\n @click=\"confirmDelete(conversation)\"\n >\n <svg aria-hidden=\"true\" fill=\"none\" viewBox=\"0 0 24 24\">\n <path d=\"M4 7h16M10 11v6m4-6v6M9 7l1-2h4l1 2m2 0-1 12H8L7 7\" />\n </svg>\n </button>\n </div>\n </nav>\n </aside>\n</template>\n\n<script setup lang=\"ts\">\nimport type { CodexConversationSummary } from '@codex-app-sdk/core/surface';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nwithDefaults(defineProps<{\n activeConversationId?: string | null;\n brand?: string;\n conversations: readonly CodexConversationSummary[];\n createDisabled?: boolean;\n loading?: boolean;\n}>(), {\n activeConversationId: null,\n brand: 'Codex',\n createDisabled: false,\n loading: false,\n});\n\nconst emit = defineEmits<{\n create: [];\n delete: [conversationId: string];\n select: [conversationId: string];\n}>();\n// Stryker restore all\n\nfunction confirmDelete(conversation: CodexConversationSummary): void {\n const confirmed = window.confirm(\n `Delete \"${conversation.title}\"? This permanently deletes the thread and cannot be undone.`,\n );\n if (confirmed) emit('delete', conversation.id);\n}\n\nfunction relativeTime(value: string): string {\n const elapsedMinutes = Math.max(0, Math.floor((Date.now() - new Date(value).getTime()) / 60_000));\n if (elapsedMinutes < 1) return 'now';\n if (elapsedMinutes < 60) return `${elapsedMinutes}m`;\n const hours = Math.floor(elapsedMinutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\n</script>\n\n<style scoped>\n.codex-conversation-sidebar {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex-direction: column;\n border-right: 1px solid #deded9;\n background: #f1f1ee;\n}\n\n.codex-conversation-sidebar__header {\n display: grid;\n gap: 14px;\n padding: 24px 14px 12px;\n}\n\n.codex-conversation-sidebar__brand {\n padding-left: 8px;\n color: #1f201e;\n font-size: 18px;\n font-weight: 700;\n letter-spacing: -0.02em;\n}\n\n.codex-conversation-sidebar__new,\n.codex-conversation-sidebar__select,\n.codex-conversation-sidebar__delete {\n width: 100%;\n border: 0;\n color: #2a2b29;\n background: transparent;\n font: inherit;\n cursor: pointer;\n}\n\n.codex-conversation-sidebar__new {\n border-radius: 9px;\n padding: 9px 10px;\n font-weight: 600;\n text-align: left;\n}\n\n.codex-conversation-sidebar__new:hover,\n.codex-conversation-sidebar__item:hover,\n.codex-conversation-sidebar__item:focus-within,\n.codex-conversation-sidebar__item--active {\n background: #e2e2dd;\n}\n\n.codex-conversation-sidebar__list {\n display: flex;\n min-height: 0;\n padding: 2px 8px 12px;\n overflow-y: auto;\n flex-direction: column;\n gap: 2px;\n}\n\n.codex-conversation-sidebar__item {\n position: relative;\n border-radius: 9px;\n}\n\n.codex-conversation-sidebar__select {\n display: grid;\n min-width: 0;\n grid-template-columns: 8px minmax(0, 1fr) 34px;\n gap: 8px;\n align-items: center;\n border-radius: 9px;\n padding: 9px 8px 9px 10px;\n text-align: left;\n}\n\n.codex-conversation-sidebar__select:focus-visible,\n.codex-conversation-sidebar__delete:focus-visible {\n outline: 2px solid #3b82f6;\n outline-offset: -2px;\n}\n\n.codex-conversation-sidebar__status {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: #a0a099;\n}\n\n.codex-conversation-sidebar__status--active {\n background: #3b82f6;\n box-shadow: 0 0 0 3px rgb(59 130 246 / 14%);\n}\n\n.codex-conversation-sidebar__status--error {\n background: #c2413b;\n}\n\n.codex-conversation-sidebar__title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n}\n\n.codex-conversation-sidebar__time {\n justify-self: end;\n color: #85857e;\n font-size: 12px;\n pointer-events: none;\n}\n\n.codex-conversation-sidebar__delete {\n position: absolute;\n z-index: 1;\n top: 50%;\n right: 3px;\n display: inline-flex;\n width: 28px;\n height: 28px;\n align-items: center;\n justify-content: center;\n border-radius: 7px;\n color: #85857e;\n opacity: 0;\n pointer-events: none;\n transform: translateY(-50%);\n}\n\n.codex-conversation-sidebar__delete svg {\n width: 16px;\n height: 16px;\n stroke: currentColor;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 1.75;\n}\n\n.codex-conversation-sidebar__item:hover .codex-conversation-sidebar__time,\n.codex-conversation-sidebar__item:focus-within .codex-conversation-sidebar__time {\n opacity: 0;\n}\n\n.codex-conversation-sidebar__item:hover .codex-conversation-sidebar__delete,\n.codex-conversation-sidebar__item:focus-within .codex-conversation-sidebar__delete,\n.codex-conversation-sidebar__delete:focus-visible {\n opacity: 1;\n pointer-events: auto;\n}\n\n.codex-conversation-sidebar__delete:hover,\n.codex-conversation-sidebar__delete:focus-visible {\n color: #b42318;\n background: rgb(180 35 24 / 10%);\n}\n\n.codex-conversation-sidebar__empty {\n padding: 8px 18px;\n color: #85857e;\n font-size: 13px;\n}\n\nbutton:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n</style>\n","<template>\n <div\n ref=\"menuEl\"\n class=\"codex-chat-theme chat-composer-file-menu\"\n role=\"listbox\"\n aria-label=\"Files\"\n >\n <div class=\"chat-composer-file-menu__section\">\n {{ t('chat.files.title') }}\n </div>\n <button\n v-for=\"(file, index) in visibleFiles\"\n :key=\"file.path\"\n class=\"chat-composer-file-menu__item\"\n :class=\"{ 'chat-composer-file-menu__item--active': index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select', file)\"\n >\n <FileTextIcon\n class=\"chat-composer-file-menu__icon\"\n aria-hidden=\"true\"\n />\n <span class=\"chat-composer-file-menu__name\">{{ file.name }}</span>\n <span class=\"chat-composer-file-menu__path\">{{ file.path }}</span>\n </button>\n <div\n v-if=\"showHint\"\n class=\"chat-composer-file-menu__hint\"\n >\n {{ t('chat.files.hint') }}\n </div>\n <div\n v-else-if=\"visibleFiles.length === 0\"\n class=\"chat-composer-file-menu__empty\"\n >\n {{ t('chat.files.empty') }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport { useCodexChatTranslate } from './chat-i18n';\nimport type { CodexFileSearchItem } from './contracts';\nimport { FileTextIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n showHint?: boolean;\n visibleFiles: CodexFileSearchItem[];\n}>();\n\ndefineEmits<{\n select: [file: CodexFileSearchItem];\n}>();\n// Stryker restore all\n\nconst t = useCodexChatTranslate();\nconst menuEl = ref<HTMLElement | null>(null);\n\nwatch(\n () => [props.activeIndex, props.visibleFiles],\n async () => {\n await nextTick();\n const activeItem = menuEl.value?.querySelectorAll<HTMLButtonElement>('.chat-composer-file-menu__item')\n .item(props.activeIndex);\n if (typeof activeItem?.scrollIntoView === 'function') {\n activeItem.scrollIntoView({ block: 'nearest' });\n }\n },\n);\n</script>\n\n<style scoped>\n.chat-composer-file-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-composer-file-menu__section {\n padding: var(--space-2) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.chat-composer-file-menu__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n min-height: var(--chat-menu-control-min-height);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n line-height: 1.35;\n text-align: left;\n}\n\n.chat-composer-file-menu__item:hover,\n.chat-composer-file-menu__item--active {\n background: var(--color-surface);\n}\n\n.chat-composer-file-menu__icon {\n width: var(--icon-md);\n height: var(--icon-md);\n flex: 0 0 var(--icon-md);\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.chat-composer-file-menu__name {\n overflow: hidden;\n font-weight: var(--font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.chat-composer-file-menu__path {\n overflow: hidden;\n min-width: 0;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-composer-file-menu__empty,\n.chat-composer-file-menu__hint {\n padding: var(--space-3) var(--space-4) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: normal;\n}\n</style>\n","<template>\n <div\n ref=\"menuEl\"\n class=\"codex-chat-theme chat-composer-file-menu\"\n role=\"listbox\"\n aria-label=\"Files\"\n >\n <div class=\"chat-composer-file-menu__section\">\n {{ t('chat.files.title') }}\n </div>\n <button\n v-for=\"(file, index) in visibleFiles\"\n :key=\"file.path\"\n class=\"chat-composer-file-menu__item\"\n :class=\"{ 'chat-composer-file-menu__item--active': index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select', file)\"\n >\n <FileTextIcon\n class=\"chat-composer-file-menu__icon\"\n aria-hidden=\"true\"\n />\n <span class=\"chat-composer-file-menu__name\">{{ file.name }}</span>\n <span class=\"chat-composer-file-menu__path\">{{ file.path }}</span>\n </button>\n <div\n v-if=\"showHint\"\n class=\"chat-composer-file-menu__hint\"\n >\n {{ t('chat.files.hint') }}\n </div>\n <div\n v-else-if=\"visibleFiles.length === 0\"\n class=\"chat-composer-file-menu__empty\"\n >\n {{ t('chat.files.empty') }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport { useCodexChatTranslate } from './chat-i18n';\nimport type { CodexFileSearchItem } from './contracts';\nimport { FileTextIcon } from '../icons/app-icons';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n showHint?: boolean;\n visibleFiles: CodexFileSearchItem[];\n}>();\n\ndefineEmits<{\n select: [file: CodexFileSearchItem];\n}>();\n// Stryker restore all\n\nconst t = useCodexChatTranslate();\nconst menuEl = ref<HTMLElement | null>(null);\n\nwatch(\n () => [props.activeIndex, props.visibleFiles],\n async () => {\n await nextTick();\n const activeItem = menuEl.value?.querySelectorAll<HTMLButtonElement>('.chat-composer-file-menu__item')\n .item(props.activeIndex);\n if (typeof activeItem?.scrollIntoView === 'function') {\n activeItem.scrollIntoView({ block: 'nearest' });\n }\n },\n);\n</script>\n\n<style scoped>\n.chat-composer-file-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-composer-file-menu__section {\n padding: var(--space-2) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.chat-composer-file-menu__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n min-height: var(--chat-menu-control-min-height);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n line-height: 1.35;\n text-align: left;\n}\n\n.chat-composer-file-menu__item:hover,\n.chat-composer-file-menu__item--active {\n background: var(--color-surface);\n}\n\n.chat-composer-file-menu__icon {\n width: var(--icon-md);\n height: var(--icon-md);\n flex: 0 0 var(--icon-md);\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.chat-composer-file-menu__name {\n overflow: hidden;\n font-weight: var(--font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.chat-composer-file-menu__path {\n overflow: hidden;\n min-width: 0;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chat-composer-file-menu__empty,\n.chat-composer-file-menu__hint {\n padding: var(--space-3) var(--space-4) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n line-height: normal;\n}\n</style>\n","<template>\n <div\n ref=\"menuEl\"\n class=\"codex-chat-theme chat-composer-plugin-menu\"\n role=\"listbox\"\n aria-label=\"Plugins\"\n >\n <div class=\"chat-composer-plugin-menu__section\">Plugins</div>\n <button\n v-for=\"(plugin, index) in visiblePlugins\"\n :key=\"plugin.id\"\n class=\"chat-composer-plugin-menu__item\"\n :class=\"{ 'chat-composer-plugin-menu__item--active': index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select', plugin)\"\n >\n <img\n v-if=\"plugin.iconUrl\"\n class=\"chat-composer-plugin-menu__icon chat-composer-plugin-menu__icon-image\"\n :src=\"plugin.iconUrl\"\n alt=\"\"\n aria-hidden=\"true\"\n referrerpolicy=\"no-referrer\"\n >\n <PlugIcon v-else class=\"chat-composer-plugin-menu__icon\" aria-hidden=\"true\" />\n <span class=\"chat-composer-plugin-menu__main\">\n <span class=\"chat-composer-plugin-menu__name\">{{ pluginDisplayName(plugin) }}</span>\n <span class=\"chat-composer-plugin-menu__description\">{{ pluginDescription(plugin) }}</span>\n </span>\n </button>\n <div v-if=\"visiblePlugins.length === 0\" class=\"chat-composer-plugin-menu__empty\">No matching plugins</div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport { PlugIcon } from '../icons/app-icons';\nimport { pluginDescription, pluginDisplayName } from './composer-plugins';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n visiblePlugins: CodexSurfacePlugin[];\n}>();\n\ndefineEmits<{\n select: [plugin: CodexSurfacePlugin];\n}>();\n// Stryker restore all\n\nconst menuEl = ref<HTMLElement | null>(null);\n\nwatch(\n () => [props.activeIndex, props.visiblePlugins],\n async () => {\n await nextTick();\n const activeItem = menuEl.value?.querySelectorAll<HTMLButtonElement>('.chat-composer-plugin-menu__item')\n .item(props.activeIndex);\n if (typeof activeItem?.scrollIntoView === 'function') {\n activeItem.scrollIntoView({ block: 'nearest' });\n }\n },\n);\n</script>\n\n<style scoped>\n.chat-composer-plugin-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-composer-plugin-menu__section {\n padding: var(--space-2) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.chat-composer-plugin-menu__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n min-height: var(--chat-menu-control-min-height);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n line-height: 1.35;\n text-align: left;\n}\n\n.chat-composer-plugin-menu__item:hover,\n.chat-composer-plugin-menu__item--active {\n background: var(--color-surface);\n}\n\n.chat-composer-plugin-menu__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--icon-md);\n height: var(--icon-md);\n flex: 0 0 var(--icon-md);\n}\n\nsvg.chat-composer-plugin-menu__icon {\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.chat-composer-plugin-menu__icon-image {\n object-fit: contain;\n opacity: 1;\n}\n\n.chat-composer-plugin-menu__main {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: var(--space-4);\n}\n\n.chat-composer-plugin-menu__name {\n overflow: hidden;\n font-weight: var(--font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.chat-composer-plugin-menu__description {\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 1;\n}\n\n.chat-composer-plugin-menu__empty {\n padding: var(--space-3) var(--space-4) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n}\n</style>\n","<template>\n <div\n ref=\"menuEl\"\n class=\"codex-chat-theme chat-composer-plugin-menu\"\n role=\"listbox\"\n aria-label=\"Plugins\"\n >\n <div class=\"chat-composer-plugin-menu__section\">Plugins</div>\n <button\n v-for=\"(plugin, index) in visiblePlugins\"\n :key=\"plugin.id\"\n class=\"chat-composer-plugin-menu__item\"\n :class=\"{ 'chat-composer-plugin-menu__item--active': index === activeIndex }\"\n role=\"option\"\n type=\"button\"\n @mousedown.prevent=\"$emit('select', plugin)\"\n >\n <img\n v-if=\"plugin.iconUrl\"\n class=\"chat-composer-plugin-menu__icon chat-composer-plugin-menu__icon-image\"\n :src=\"plugin.iconUrl\"\n alt=\"\"\n aria-hidden=\"true\"\n referrerpolicy=\"no-referrer\"\n >\n <PlugIcon v-else class=\"chat-composer-plugin-menu__icon\" aria-hidden=\"true\" />\n <span class=\"chat-composer-plugin-menu__main\">\n <span class=\"chat-composer-plugin-menu__name\">{{ pluginDisplayName(plugin) }}</span>\n <span class=\"chat-composer-plugin-menu__description\">{{ pluginDescription(plugin) }}</span>\n </span>\n </button>\n <div v-if=\"visiblePlugins.length === 0\" class=\"chat-composer-plugin-menu__empty\">No matching plugins</div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport type { CodexSurfacePlugin } from '@codex-app-sdk/core/surface';\nimport { PlugIcon } from '../icons/app-icons';\nimport { pluginDescription, pluginDisplayName } from './composer-plugins';\n\n// Stryker disable all: Vue compiler macros cannot be wrapped in mutation activation branches.\nconst props = defineProps<{\n activeIndex: number;\n visiblePlugins: CodexSurfacePlugin[];\n}>();\n\ndefineEmits<{\n select: [plugin: CodexSurfacePlugin];\n}>();\n// Stryker restore all\n\nconst menuEl = ref<HTMLElement | null>(null);\n\nwatch(\n () => [props.activeIndex, props.visiblePlugins],\n async () => {\n await nextTick();\n const activeItem = menuEl.value?.querySelectorAll<HTMLButtonElement>('.chat-composer-plugin-menu__item')\n .item(props.activeIndex);\n if (typeof activeItem?.scrollIntoView === 'function') {\n activeItem.scrollIntoView({ block: 'nearest' });\n }\n },\n);\n</script>\n\n<style scoped>\n.chat-composer-plugin-menu {\n position: absolute;\n right: 0;\n bottom: calc(100% + var(--space-4));\n left: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n max-height: 280px;\n overflow-y: auto;\n padding: var(--space-2);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-xl);\n background: var(--color-surface-lowest);\n box-shadow: var(--shadow-lg);\n}\n\n.chat-composer-plugin-menu__section {\n padding: var(--space-2) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--codex-composer-menu-heading-font-size, 13px);\n font-weight: var(--font-weight-medium);\n line-height: 18px;\n}\n\n.chat-composer-plugin-menu__item {\n display: flex;\n align-items: center;\n gap: var(--space-3);\n width: 100%;\n min-width: 0;\n min-height: var(--chat-menu-control-min-height);\n margin-block: 0.125px;\n padding: var(--space-2) var(--space-4);\n border: 0;\n border-radius: var(--radius-lg);\n background: transparent;\n color: var(--color-text);\n cursor: pointer;\n font: inherit;\n line-height: 1.35;\n text-align: left;\n}\n\n.chat-composer-plugin-menu__item:hover,\n.chat-composer-plugin-menu__item--active {\n background: var(--color-surface);\n}\n\n.chat-composer-plugin-menu__icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--icon-md);\n height: var(--icon-md);\n flex: 0 0 var(--icon-md);\n}\n\nsvg.chat-composer-plugin-menu__icon {\n opacity: 0.5;\n stroke-width: 2px;\n}\n\n.chat-composer-plugin-menu__icon-image {\n object-fit: contain;\n opacity: 1;\n}\n\n.chat-composer-plugin-menu__main {\n display: flex;\n align-items: center;\n min-width: 0;\n gap: var(--space-4);\n}\n\n.chat-composer-plugin-menu__name {\n overflow: hidden;\n font-weight: var(--font-weight-medium);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n.chat-composer-plugin-menu__description {\n overflow: hidden;\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex-shrink: 1;\n}\n\n.chat-composer-plugin-menu__empty {\n padding: var(--space-3) var(--space-4) var(--space-4);\n color: var(--color-text-muted);\n font-size: var(--font-size-13);\n}\n</style>\n","export type QueuedChatPrompt = {\n id: string;\n text: string;\n};\n\nlet nextQueuedPromptId = 0;\n\nexport function createQueuedChatPrompt(text: string): QueuedChatPrompt {\n nextQueuedPromptId += 1;\n return {\n id: `queued-prompt-${nextQueuedPromptId}`,\n text,\n };\n}\n","import { getCurrentScope, onScopeDispose, reactive, readonly, shallowRef } from 'vue';\nimport type {\n CodexConversationHistory,\n CodexConversationPromptHistory,\n CodexSurfaceApprovalDecision,\n CodexSurfaceApprovalScope,\n CodexSurfaceClientRequestResponse,\n CodexSurfaceEvent,\n CodexSurfaceRendererApi,\n CodexSurfaceSnapshot,\n CreateCodexRendererConversationOptions,\n ListCodexConversationsOptions,\n ListCodexModelsOptions,\n CodexRendererSendMessageOptions,\n StartCodexReviewOptions,\n UpdateCodexConversationSettings,\n} from '@codex-app-sdk/core/surface';\nimport { subscribeCodexSurfaceState } from '@codex-app-sdk/core/surface-bridge';\n\nconst initialState: CodexSurfaceSnapshot = {\n status: 'idle',\n authentication: {\n status: 'notLoaded',\n account: null,\n requiresOpenaiAuth: null,\n error: null,\n login: { status: 'idle', loginId: null, authUrl: null, error: null },\n },\n conversations: [],\n activeConversationId: null,\n activeTurnId: null,\n turns: [],\n messages: [],\n clientRequests: [],\n answeredClientRequestIds: [],\n approvals: [],\n models: [],\n modelCatalogStatus: 'notLoaded',\n skills: [],\n skillCatalogStatus: 'notLoaded',\n plugins: [],\n pluginCatalogStatus: 'notLoaded',\n permissionProfiles: [],\n approvalPresets: [],\n approvalPreset: null,\n selectedModelId: null,\n selectedReasoningEffort: null,\n selectedServiceTier: null,\n planMode: false,\n contextUsage: null,\n goal: null,\n turnGitDiff: null,\n threadStatus: null,\n rateLimits: null,\n queuedPrompts: [],\n busy: false,\n historyLoading: false,\n error: null,\n};\n\nexport function useCodexSurface(api: CodexSurfaceRendererApi) {\n const state = reactive<CodexSurfaceSnapshot>(structuredClone(initialState));\n const mutableAnsweredClientRequestIds = reactive(new Set<string>());\n const answeredClientRequestIds: ReadonlySet<string> = readonly(mutableAnsweredClientRequestIds);\n const lastEvent = shallowRef<CodexSurfaceEvent | null>(null);\n const eventListeners = new Set<(event: CodexSurfaceEvent) => void>();\n let pushedSnapshotVersion = 0;\n const apply = (snapshot: CodexSurfaceSnapshot) => {\n Object.assign(state, snapshot);\n mutableAnsweredClientRequestIds.clear();\n for (const requestId of snapshot.answeredClientRequestIds) {\n mutableAnsweredClientRequestIds.add(requestId);\n }\n };\n // Patch-capable APIs keep unchanged messages identical between updates, so\n // only the components whose data changed re-render.\n const unsubscribe = subscribeCodexSurfaceState(api, (snapshot) => {\n pushedSnapshotVersion += 1;\n apply(snapshot);\n });\n const unsubscribeEvents = api.onEvent((event) => {\n lastEvent.value = event;\n for (const listener of eventListeners) listener(event);\n });\n if (getCurrentScope()) onScopeDispose(() => {\n unsubscribeEvents();\n unsubscribe();\n eventListeners.clear();\n });\n\n async function run(action: () => Promise<CodexSurfaceSnapshot>): Promise<CodexSurfaceSnapshot> {\n const versionBeforeAction = pushedSnapshotVersion;\n const snapshot = await action();\n if (pushedSnapshotVersion === versionBeforeAction) apply(snapshot);\n return snapshot;\n }\n\n return {\n state: readonly(state),\n lastEvent: readonly(lastEvent),\n answeredClientRequestIds,\n onEvent: (listener: (event: CodexSurfaceEvent) => void) => {\n eventListeners.add(listener);\n return () => eventListeners.delete(listener);\n },\n archiveConversation: (conversationId: string) => run(() => api.archiveConversation(conversationId)),\n cancelLogin: (loginId?: string) => run(() => api.cancelLogin(loginId)),\n clearGoal: () => run(() => api.clearGoal()),\n compactConversation: () => run(() => api.compactConversation()),\n continueInterruptedTurn: () => run(() => api.continueInterruptedTurn()),\n connect: () => {\n mutableAnsweredClientRequestIds.clear();\n return run(() => api.connect());\n },\n createConversation: (options?: CreateCodexRendererConversationOptions) => run(() => api.createConversation(options)),\n deleteConversation: (conversationId: string) => run(() => api.deleteConversation(conversationId)),\n deleteTurn: (turnId: string) => run(() => api.deleteTurn(turnId)),\n deleteQueuedPrompt: (promptId: string) => run(() => api.deleteQueuedPrompt(promptId)),\n updateQueuedPrompt: (promptId: string, prompt: string) => run(() => api.updateQueuedPrompt(promptId, prompt)),\n editTurn: (turnId: string, content: string) => run(() => api.editTurn(turnId, content)),\n forkTurn: (turnId: string) => run(() => api.forkTurn(turnId)),\n interrupt: () => run(() => api.interrupt()),\n listConversations: (options?: ListCodexConversationsOptions) => api.listConversations(options),\n listModels: (options?: ListCodexModelsOptions) => api.listModels(options),\n logout: () => run(() => api.logout()),\n readConversationHistory: (conversationId?: string): Promise<CodexConversationHistory> => (\n api.readConversationHistory(conversationId)\n ),\n readConversationPromptHistory: (\n conversationId?: string,\n ): Promise<CodexConversationPromptHistory> => api.readConversationPromptHistory(conversationId),\n loadOlderConversationHistory: (conversationId?: string) => (\n api.loadOlderConversationHistory\n ? api.loadOlderConversationHistory(conversationId)\n : Promise.reject(new Error('Conversation history paging is not available.'))\n ),\n refreshAccount: () => run(() => api.refreshAccount()),\n refreshConversations: () => run(() => api.refreshConversations()),\n renameConversation: (title: string) => run(() => api.renameConversation(title)),\n respondToClientRequest: (response: CodexSurfaceClientRequestResponse) => {\n mutableAnsweredClientRequestIds.add(response.id);\n return run(() => api.respondToClientRequest(response));\n },\n resolveApproval: (\n approvalId: string,\n decision: CodexSurfaceApprovalDecision,\n scope?: CodexSurfaceApprovalScope,\n ) => run(() => api.resolveApproval(approvalId, decision, scope)),\n retryTurn: (turnId: string) => run(() => api.retryTurn(turnId)),\n setGoal: (objective: string, tokenBudget?: number | null) => run(() => api.setGoal(objective, tokenBudget)),\n selectConversation: (conversationId: string) => run(() => api.selectConversation(conversationId)),\n sendMessage: (prompt: string, options?: CodexRendererSendMessageOptions) => run(() => api.sendMessage(prompt, options)),\n startReview: (options?: StartCodexReviewOptions) => run(() => api.startReview(options)),\n startChatGptDeviceCodeLogin: () => api.startChatGptDeviceCodeLogin(),\n startChatGptLogin: () => api.startChatGptLogin(),\n steerMessage: (prompt: string, options?: CodexRendererSendMessageOptions) => run(() => api.steerMessage(prompt, options)),\n steerQueuedPrompt: (promptId: string, prompt?: string) => run(() => api.steerQueuedPrompt(promptId, prompt)),\n unarchiveConversation: (conversationId: string) => run(() => api.unarchiveConversation(conversationId)),\n updateConversationSettings: (settings: UpdateCodexConversationSettings) => (\n run(() => api.updateConversationSettings(settings))\n ),\n };\n}\n\nexport type CodexSurfaceController = ReturnType<typeof useCodexSurface>;\n","import { onScopeDispose, readonly, ref } from 'vue';\nimport type { CodexSurfaceEvent, CodexSurfaceRendererApi, StartCodexLiveChatOptions } from '@codex-app-sdk/core/surface';\n\nexport type CodexLiveChatStatus = 'idle' | 'connecting' | 'connected' | 'stopping' | 'error';\nexport type CodexLiveChatTranscript = { id: string; role: string; text: string; complete: boolean };\nexport type CodexLiveChatOptions = {\n surface: Pick<CodexSurfaceRendererApi, 'startLiveChat' | 'stopLiveChat' | 'onEvent'>;\n conversationId: string;\n session?: Omit<StartCodexLiveChatOptions, 'sdp'>;\n};\n\ntype LiveChatAttempt = {\n cancelled: boolean;\n requested: boolean;\n ended: boolean;\n stream?: MediaStream;\n peer?: RTCPeerConnection;\n audio?: HTMLAudioElement;\n unsubscribe?: () => void;\n timer?: ReturnType<typeof setTimeout>;\n done?: Promise<void>;\n stopping?: Promise<void>;\n};\n\n/** Call start from a user gesture. Each instance belongs to one conversation. */\nexport function useCodexLiveChat(options: CodexLiveChatOptions) {\n const status = ref<CodexLiveChatStatus>('idle');\n const error = ref<string | null>(null);\n const muted = ref(false);\n const transcript = ref<CodexLiveChatTranscript[]>([]);\n let attempt: LiveChatAttempt | undefined;\n let disposed = false;\n\n function onEvent(event: CodexSurfaceEvent): void {\n if (!('conversationId' in event) || event.conversationId !== options.conversationId) return;\n if (event.type === 'realtime.error') {\n error.value = event.payload.message;\n void stop().catch(() => undefined);\n } else if (event.type === 'realtime.closed') {\n if (attempt) attempt.ended = true;\n void stop().catch(() => undefined);\n } else if (event.type === 'realtime.itemStarted' || event.type === 'realtime.itemCompleted') {\n const item = event.payload.item;\n if (!item || typeof item !== 'object' || Array.isArray(item) || item.type !== 'transcriptSegment'\n || typeof item.id !== 'string' || typeof item.role !== 'string' || typeof item.text !== 'string') return;\n const row = { id: item.id, role: item.role, text: item.text, complete: event.type === 'realtime.itemCompleted' };\n const index = transcript.value.findIndex((entry) => entry.id === row.id);\n if (index === -1) transcript.value.push(row);\n else transcript.value[index] = row;\n } else if (event.type === 'realtime.itemTranscriptDelta') {\n const row = transcript.value.find((entry) => entry.id === event.payload.itemId);\n if (row && !row.complete) row.text += event.payload.delta;\n } else if (event.type === 'realtime.transcriptDelta' || event.type === 'realtime.transcriptCompleted') {\n // V3 also emits legacy notifications; consuming both duplicates every word.\n if ((options.session?.version ?? 'v3') === 'v3') return;\n let row = transcript.value.at(-1);\n if (!row || row.complete || row.role !== event.payload.role) {\n row = { id: `legacy-${transcript.value.length}`, role: event.payload.role, text: '', complete: false };\n transcript.value.push(row);\n row = transcript.value.at(-1)!;\n }\n if (event.type === 'realtime.transcriptDelta') row.text += event.payload.delta;\n else { row.text = event.payload.text; row.complete = true; }\n }\n }\n\n function release(current: LiveChatAttempt): void {\n clearTimeout(current.timer);\n current.unsubscribe?.();\n current.unsubscribe = undefined;\n if (current.peer) {\n current.peer.onconnectionstatechange = null;\n current.peer.ontrack = null;\n current.peer.close();\n }\n current.stream?.getTracks().forEach((track) => track.stop());\n if (current.audio) {\n current.audio.pause();\n current.audio.srcObject = null;\n }\n }\n\n async function stopBackend(current: LiveChatAttempt): Promise<void> {\n if (current.requested && !current.ended) {\n current.ended = true;\n await options.surface.stopLiveChat!(options.conversationId);\n }\n }\n\n function start(): Promise<void> {\n if (disposed) return Promise.reject(new Error('Live chat has been disposed'));\n if (attempt) return attempt.done ?? Promise.resolve();\n status.value = 'connecting';\n error.value = null;\n muted.value = false;\n transcript.value = [];\n const current: LiveChatAttempt = { cancelled: false, requested: false, ended: false };\n attempt = current;\n current.done = (async () => {\n try {\n if (!options.surface.startLiveChat || !options.surface.stopLiveChat) throw new Error('This surface does not support live chat');\n current.stream = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true, noiseSuppression: true }, video: false });\n if (current.cancelled) return;\n const peer = new RTCPeerConnection();\n current.peer = peer;\n const audio = new Audio();\n audio.autoplay = true;\n current.audio = audio;\n peer.ontrack = (event) => {\n audio.srcObject = event.streams[0] ?? new MediaStream([event.track]);\n void audio.play().catch((cause: unknown) => {\n if (current.cancelled) return;\n error.value = message(cause);\n void stop().catch(() => undefined);\n });\n };\n peer.onconnectionstatechange = () => {\n if (current.cancelled) return;\n if (peer.connectionState === 'connected') {\n clearTimeout(current.timer);\n status.value = 'connected';\n }\n if (peer.connectionState === 'failed' || peer.connectionState === 'closed') {\n error.value = 'Live chat connection ended';\n void stop().catch(() => undefined);\n }\n };\n current.stream.getTracks().forEach((track) => { track.enabled = !muted.value; peer.addTrack(track, current.stream!); });\n peer.createDataChannel('oai-events');\n current.unsubscribe = options.surface.onEvent(onEvent);\n await peer.setLocalDescription(await peer.createOffer());\n if (current.cancelled) return;\n current.requested = true;\n const answer = await options.surface.startLiveChat(options.conversationId, {\n ...options.session, sdp: peer.localDescription!.sdp,\n });\n if (current.cancelled) return;\n await peer.setRemoteDescription({ type: 'answer', sdp: answer.sdp });\n if (!current.cancelled && peer.connectionState !== 'connected') {\n current.timer = setTimeout(() => {\n error.value = 'Timed out connecting live chat';\n void stop().catch(() => undefined);\n }, 30_000);\n }\n } catch (cause) {\n if (!current.cancelled) {\n error.value = message(cause);\n status.value = 'error';\n release(current);\n await stopBackend(current).catch(() => undefined);\n if (attempt === current) attempt = undefined;\n throw cause;\n }\n } finally {\n if (current.cancelled) release(current);\n }\n })();\n return current.done;\n }\n\n function stop(): Promise<void> {\n const current = attempt;\n if (!current) return Promise.resolve();\n if (current.stopping) return current.stopping;\n current.cancelled = true;\n status.value = 'stopping';\n release(current);\n current.stopping = (async () => {\n try {\n if (current.requested) await current.done?.catch(() => undefined);\n await stopBackend(current);\n } catch (cause) {\n error.value = message(cause);\n throw cause;\n } finally {\n if (attempt === current) attempt = undefined;\n status.value = error.value ? 'error' : 'idle';\n }\n })();\n return current.stopping;\n }\n\n function setMuted(value: boolean): void {\n muted.value = value;\n attempt?.stream?.getAudioTracks().forEach((track) => { track.enabled = !value; });\n }\n\n onScopeDispose(() => { disposed = true; void stop().catch(() => undefined); });\n return { status: readonly(status), error: readonly(error), muted: readonly(muted), transcript: readonly(transcript), start, stop, setMuted };\n}\n\nfunction message(cause: unknown): string {\n return cause instanceof Error ? cause.message : String(cause);\n}\n","export type CodexThemeMode = 'dark' | 'light' | 'system';\n\nexport type CodexThemeOptions = {\n mode?: CodexThemeMode;\n /** CSS custom properties. Both `--codex-*` and semantic names are accepted. */\n tokens?: Readonly<Record<string, string | null | undefined>>;\n};\n\n/**\n * Applies the optional SDK theme contract to an application-owned element.\n * The SDK never owns or mutates the surrounding application shell.\n */\nexport function applyCodexTheme(\n element: HTMLElement,\n options: CodexThemeOptions = {},\n): () => void {\n const previousTheme = element.getAttribute('data-codex-theme');\n const previousTokens = new Map<string, string>();\n const mode = options.mode ?? 'system';\n element.setAttribute('data-codex-theme', mode);\n\n for (const [rawName, value] of Object.entries(options.tokens ?? {})) {\n const name = codexThemeTokenName(rawName);\n if (!previousTokens.has(name)) {\n previousTokens.set(name, element.style.getPropertyValue(name));\n }\n if (value === null || value === undefined || !value.trim()) {\n element.style.removeProperty(name);\n } else {\n element.style.setProperty(name, value);\n }\n }\n\n return () => {\n if (previousTheme === null) element.removeAttribute('data-codex-theme');\n else element.setAttribute('data-codex-theme', previousTheme);\n for (const [name, value] of previousTokens) {\n if (value) element.style.setProperty(name, value);\n else element.style.removeProperty(name);\n }\n };\n}\n\nfunction codexThemeTokenName(name: string): string {\n const trimmed = name.trim();\n if (trimmed.startsWith('--codex-')) return trimmed;\n const normalized = trimmed\n .replace(/^--/, '')\n .replace(/([a-z\\d])([A-Z])/g, '$1-$2')\n .replace(/[^a-zA-Z\\d-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .toLowerCase();\n if (!normalized) throw new TypeError('Codex theme token names cannot be empty');\n return `--codex-${normalized}`;\n}\n"],"mappings":"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"}