@agent-native/toolkit 0.228.0-nightly-20261111212500 → 0.228.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.
- package/agent-native.eject.json +2 -0
- package/dist/app/agentkit/react/approval-card.d.ts.map +1 -1
- package/dist/app/agentkit/react/approval-card.js +5 -3
- package/dist/app/agentkit/react/approval-card.js.map +1 -1
- package/dist/app/agentkit/react/code-block.d.ts +32 -0
- package/dist/app/agentkit/react/code-block.d.ts.map +1 -0
- package/dist/app/agentkit/react/code-block.js +125 -0
- package/dist/app/agentkit/react/code-block.js.map +1 -0
- package/dist/app/agentkit/react/components.d.ts +33 -14
- package/dist/app/agentkit/react/components.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.js +843 -168
- package/dist/app/agentkit/react/components.js.map +1 -1
- package/dist/app/agentkit/react/context-usage.d.ts +45 -0
- package/dist/app/agentkit/react/context-usage.d.ts.map +1 -0
- package/dist/app/agentkit/react/context-usage.js +93 -0
- package/dist/app/agentkit/react/context-usage.js.map +1 -0
- package/dist/app/agentkit/react/context.d.ts +42 -3
- package/dist/app/agentkit/react/context.d.ts.map +1 -1
- package/dist/app/agentkit/react/context.js +46 -1
- package/dist/app/agentkit/react/context.js.map +1 -1
- package/dist/app/agentkit/react/disclosure-content.d.ts +12 -0
- package/dist/app/agentkit/react/disclosure-content.d.ts.map +1 -0
- package/dist/app/agentkit/react/disclosure-content.js +33 -0
- package/dist/app/agentkit/react/disclosure-content.js.map +1 -0
- package/dist/app/agentkit/react/duration.d.ts +6 -0
- package/dist/app/agentkit/react/duration.d.ts.map +1 -0
- package/dist/app/agentkit/react/duration.js +21 -0
- package/dist/app/agentkit/react/duration.js.map +1 -0
- package/dist/app/agentkit/react/file-change.d.ts +33 -0
- package/dist/app/agentkit/react/file-change.d.ts.map +1 -0
- package/dist/app/agentkit/react/file-change.js +83 -0
- package/dist/app/agentkit/react/file-change.js.map +1 -0
- package/dist/app/agentkit/react/file-diff.d.ts +17 -0
- package/dist/app/agentkit/react/file-diff.d.ts.map +1 -0
- package/dist/app/agentkit/react/file-diff.js +94 -0
- package/dist/app/agentkit/react/file-diff.js.map +1 -0
- package/dist/app/agentkit/react/index.d.ts +7 -0
- package/dist/app/agentkit/react/index.d.ts.map +1 -1
- package/dist/app/agentkit/react/index.js +7 -0
- package/dist/app/agentkit/react/index.js.map +1 -1
- package/dist/app/agentkit/react/question-card.d.ts +67 -0
- package/dist/app/agentkit/react/question-card.d.ts.map +1 -0
- package/dist/app/agentkit/react/question-card.js +198 -0
- package/dist/app/agentkit/react/question-card.js.map +1 -0
- package/dist/app/agentkit/react/root.d.ts +3 -2
- package/dist/app/agentkit/react/root.d.ts.map +1 -1
- package/dist/app/agentkit/react/root.js +2 -2
- package/dist/app/agentkit/react/root.js.map +1 -1
- package/dist/app/agentkit/react/roving-focus.d.ts +4 -0
- package/dist/app/agentkit/react/roving-focus.d.ts.map +1 -0
- package/dist/app/agentkit/react/roving-focus.js +75 -0
- package/dist/app/agentkit/react/roving-focus.js.map +1 -0
- package/dist/app/agentkit/react/stack-trace.d.ts +34 -0
- package/dist/app/agentkit/react/stack-trace.d.ts.map +1 -0
- package/dist/app/agentkit/react/stack-trace.js +121 -0
- package/dist/app/agentkit/react/stack-trace.js.map +1 -0
- package/dist/app/agentkit/react/stop-button.d.ts.map +1 -1
- package/dist/app/agentkit/react/stop-button.js +22 -6
- package/dist/app/agentkit/react/stop-button.js.map +1 -1
- package/dist/app/agentkit/react/styles.css +1306 -395
- package/dist/app/agentkit/react/terminal.d.ts +28 -0
- package/dist/app/agentkit/react/terminal.d.ts.map +1 -0
- package/dist/app/agentkit/react/terminal.js +84 -0
- package/dist/app/agentkit/react/terminal.js.map +1 -0
- package/dist/app/agentkit/react/trace.d.ts +31 -0
- package/dist/app/agentkit/react/trace.d.ts.map +1 -0
- package/dist/app/agentkit/react/trace.js +73 -0
- package/dist/app/agentkit/react/trace.js.map +1 -0
- package/dist/app/blocks/library/HighlightedCode.d.ts +2 -1
- package/dist/app/blocks/library/HighlightedCode.d.ts.map +1 -1
- package/dist/app/blocks/library/HighlightedCode.js +8 -111
- package/dist/app/blocks/library/HighlightedCode.js.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +23 -245
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/agentkit-chat/guided-questions.d.ts +15 -1
- package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/guided-questions.js +142 -2
- package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
- package/dist/app/chat/agentkit-chat/history.js +1 -1
- package/dist/app/chat/agentkit-chat/history.js.map +1 -1
- package/dist/app/chat/agentkit-chat/index.d.ts +1 -1
- package/dist/app/chat/agentkit-chat/index.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/index.js +1 -1
- package/dist/app/chat/agentkit-chat/index.js.map +1 -1
- package/dist/app/chat/agentkit-chat/labels.d.ts +5 -0
- package/dist/app/chat/agentkit-chat/labels.d.ts.map +1 -0
- package/dist/app/chat/agentkit-chat/labels.js +245 -0
- package/dist/app/chat/agentkit-chat/labels.js.map +1 -0
- package/dist/app/chat/agentkit-chat/questions.d.ts +1 -1
- package/dist/app/chat/agentkit-chat/questions.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/questions.js +1 -1
- package/dist/app/chat/agentkit-chat/questions.js.map +1 -1
- package/dist/app/chat/agentkit-chat/root.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/root.js +5 -64
- package/dist/app/chat/agentkit-chat/root.js.map +1 -1
- package/dist/app/chat/agentkit-chat/work-step-labels.d.ts +2 -0
- package/dist/app/chat/agentkit-chat/work-step-labels.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/work-step-labels.js +31 -0
- package/dist/app/chat/agentkit-chat/work-step-labels.js.map +1 -1
- package/dist/app/chat/chat/markdown-renderer.d.ts +2 -12
- package/dist/app/chat/chat/markdown-renderer.d.ts.map +1 -1
- package/dist/app/chat/chat/markdown-renderer.js +2 -41
- package/dist/app/chat/chat/markdown-renderer.js.map +1 -1
- package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-call-display.js +2 -2
- package/dist/app/chat/chat/tool-call-display.js.map +1 -1
- package/dist/app/chat/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/app/chat/conversation/AgentConversation.js +2 -37
- package/dist/app/chat/conversation/AgentConversation.js.map +1 -1
- package/dist/app/chat/tool-cells/BashCell.d.ts +3 -1
- package/dist/app/chat/tool-cells/BashCell.d.ts.map +1 -1
- package/dist/app/chat/tool-cells/BashCell.js +4 -40
- package/dist/app/chat/tool-cells/BashCell.js.map +1 -1
- package/dist/app/chat/tool-cells/EditCell.d.ts.map +1 -1
- package/dist/app/chat/tool-cells/EditCell.js +5 -108
- package/dist/app/chat/tool-cells/EditCell.js.map +1 -1
- package/dist/app/chat/tool-cells/FilesChangedSummary.d.ts.map +1 -1
- package/dist/app/chat/tool-cells/FilesChangedSummary.js +23 -81
- package/dist/app/chat/tool-cells/FilesChangedSummary.js.map +1 -1
- package/dist/app/chat/tool-cells/WriteCell.d.ts.map +1 -1
- package/dist/app/chat/tool-cells/WriteCell.js +5 -24
- package/dist/app/chat/tool-cells/WriteCell.js.map +1 -1
- package/dist/app/code-highlighter.d.ts +11 -0
- package/dist/app/code-highlighter.d.ts.map +1 -0
- package/dist/app/code-highlighter.js +122 -0
- package/dist/app/code-highlighter.js.map +1 -0
- package/dist/app/context-xray/ThreadContextRing.js +3 -3
- package/dist/app/context-xray/ThreadContextRing.js.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +22 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +22 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +22 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +22 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +22 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +22 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +22 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +22 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +22 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +22 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +22 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +22 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/onboarding/first-run-first-paint.d.ts +10 -0
- package/dist/app/onboarding/first-run-first-paint.d.ts.map +1 -0
- package/dist/app/onboarding/first-run-first-paint.js +22 -0
- package/dist/app/onboarding/first-run-first-paint.js.map +1 -0
- package/dist/app/onboarding/first-run-startup-gate.d.ts +3 -1
- package/dist/app/onboarding/first-run-startup-gate.d.ts.map +1 -1
- package/dist/app/onboarding/first-run-startup-gate.js +30 -6
- package/dist/app/onboarding/first-run-startup-gate.js.map +1 -1
- package/dist/app/providers/AppProviders.d.ts.map +1 -1
- package/dist/app/providers/AppProviders.js +9 -2
- package/dist/app/providers/AppProviders.js.map +1 -1
- package/dist/app/providers/BuilderSignupActivation.d.ts +2 -1
- package/dist/app/providers/BuilderSignupActivation.d.ts.map +1 -1
- package/dist/app/providers/BuilderSignupActivation.js +6 -3
- package/dist/app/providers/BuilderSignupActivation.js.map +1 -1
- package/dist/app/shared/AppShellSkeleton.d.ts.map +1 -1
- package/dist/app/shared/AppShellSkeleton.js +11 -1
- package/dist/app/shared/AppShellSkeleton.js.map +1 -1
- package/dist/app/styles/agent-native.css +2 -2
- package/dist/app/styles/tokens/agent-kit.css +20 -3
- package/dist/composer/AgentSuggestionBar.d.ts.map +1 -1
- package/dist/composer/AgentSuggestionBar.js +2 -2
- package/dist/composer/AgentSuggestionBar.js.map +1 -1
- package/dist/composer/ComposerContextMenu.js +4 -4
- package/dist/composer/ComposerContextMenu.js.map +1 -1
- package/dist/composer/ComposerContextPicker.d.ts.map +1 -1
- package/dist/composer/ComposerContextPicker.js +2 -2
- package/dist/composer/ComposerContextPicker.js.map +1 -1
- package/dist/composer/ComposerContextPickerDialog.d.ts.map +1 -1
- package/dist/composer/ComposerContextPickerDialog.js +2 -2
- package/dist/composer/ComposerContextPickerDialog.js.map +1 -1
- package/dist/composer/ComposerModePicker.d.ts.map +1 -1
- package/dist/composer/ComposerModePicker.js +2 -1
- package/dist/composer/ComposerModePicker.js.map +1 -1
- package/dist/composer/ComposerPlusMenu.js +1 -1
- package/dist/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/composer/MentionChip.js +1 -1
- package/dist/composer/MentionChip.js.map +1 -1
- package/dist/composer/MentionPopover.d.ts +3 -0
- package/dist/composer/MentionPopover.d.ts.map +1 -1
- package/dist/composer/MentionPopover.js +34 -15
- package/dist/composer/MentionPopover.js.map +1 -1
- package/dist/composer/MessageQueueDrawer.d.ts.map +1 -1
- package/dist/composer/MessageQueueDrawer.js +14 -9
- package/dist/composer/MessageQueueDrawer.js.map +1 -1
- package/dist/composer/PastedTextChip.d.ts.map +1 -1
- package/dist/composer/PastedTextChip.js +14 -18
- package/dist/composer/PastedTextChip.js.map +1 -1
- package/dist/composer/PromptBar.js +1 -1
- package/dist/composer/PromptBar.js.map +1 -1
- package/dist/composer/PromptComposer.d.ts.map +1 -1
- package/dist/composer/PromptComposer.js +11 -9
- package/dist/composer/PromptComposer.js.map +1 -1
- package/dist/composer/RealtimeVoiceMode.js +2 -2
- package/dist/composer/RealtimeVoiceMode.js.map +1 -1
- package/dist/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/composer/TiptapComposer.js +52 -89
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/dist/composer/VoiceButton.d.ts +3 -1
- package/dist/composer/VoiceButton.d.ts.map +1 -1
- package/dist/composer/VoiceButton.js +10 -8
- package/dist/composer/VoiceButton.js.map +1 -1
- package/dist/composer/composer-notice.js +3 -3
- package/dist/composer/composer-notice.js.map +1 -1
- package/dist/composer/extensions/FileReference.js +1 -1
- package/dist/composer/extensions/FileReference.js.map +1 -1
- package/dist/composer/extensions/SkillReference.js +1 -1
- package/dist/composer/extensions/SkillReference.js.map +1 -1
- package/dist/composer/popover-surface.d.ts +1 -1
- package/dist/composer/popover-surface.d.ts.map +1 -1
- package/dist/composer/popover-surface.js +1 -1
- package/dist/composer/popover-surface.js.map +1 -1
- package/dist/context-ui/ContextUsageRing.d.ts +1 -45
- package/dist/context-ui/ContextUsageRing.d.ts.map +1 -1
- package/dist/context-ui/ContextUsageRing.js +2 -87
- package/dist/context-ui/ContextUsageRing.js.map +1 -1
- package/dist/context-ui/index.d.ts +2 -2
- package/dist/context-ui/index.d.ts.map +1 -1
- package/dist/context-ui/index.js +2 -2
- package/dist/context-ui/index.js.map +1 -1
- package/package.json +4 -4
- package/src/app/agentkit/react/approval-card.tsx +14 -2
- package/src/app/agentkit/react/code-block.spec.tsx +154 -0
- package/src/app/agentkit/react/code-block.tsx +317 -0
- package/src/app/agentkit/react/components.interaction.spec.tsx +7 -0
- package/src/app/agentkit/react/components.papercuts.spec.tsx +143 -2
- package/src/app/agentkit/react/components.spec.tsx +40 -47
- package/src/app/agentkit/react/components.tsx +1533 -413
- package/src/app/agentkit/react/composer-context.spec.tsx +35 -0
- package/src/app/agentkit/react/context-usage.tsx +353 -0
- package/src/app/agentkit/react/context.tsx +93 -1
- package/src/app/agentkit/react/disclosure-content.ts +42 -0
- package/src/app/agentkit/react/disclosures.spec.tsx +62 -4
- package/src/app/agentkit/react/duration.ts +22 -0
- package/src/app/agentkit/react/file-change.spec.tsx +124 -0
- package/src/app/agentkit/react/file-change.tsx +228 -0
- package/src/app/agentkit/react/file-diff.ts +110 -0
- package/src/app/agentkit/react/index.ts +7 -0
- package/src/app/agentkit/react/lifecycle.spec.tsx +565 -20
- package/src/app/agentkit/react/markdown.spec.tsx +18 -8
- package/src/app/agentkit/react/message-actions.spec.tsx +55 -1
- package/src/app/agentkit/react/notices.spec.tsx +4 -4
- package/src/app/agentkit/react/optimistic-send.spec.tsx +43 -0
- package/src/app/agentkit/react/question-card.spec.tsx +276 -0
- package/src/app/agentkit/react/question-card.tsx +533 -0
- package/src/app/agentkit/react/root.tsx +4 -0
- package/src/app/agentkit/react/roving-focus.spec.tsx +114 -0
- package/src/app/agentkit/react/roving-focus.ts +82 -0
- package/src/app/agentkit/react/stack-trace.spec.tsx +177 -0
- package/src/app/agentkit/react/stack-trace.tsx +281 -0
- package/src/app/agentkit/react/stop-button.spec.tsx +40 -0
- package/src/app/agentkit/react/stop-button.tsx +22 -5
- package/src/app/agentkit/react/styles.css +1306 -395
- package/src/app/agentkit/react/subagent-step.spec.tsx +554 -0
- package/src/app/agentkit/react/terminal.spec.tsx +228 -0
- package/src/app/agentkit/react/terminal.tsx +228 -0
- package/src/app/agentkit/react/trace.spec.tsx +120 -0
- package/src/app/agentkit/react/trace.tsx +239 -0
- package/src/app/blocks/library/HighlightedCode.tsx +14 -126
- package/src/app/chat/AgentKitAssistantChat.spec.tsx +28 -12
- package/src/app/chat/AgentKitAssistantChat.tsx +27 -253
- package/src/app/chat/agentkit-chat/approval-card.spec.tsx +1 -0
- package/src/app/chat/agentkit-chat/guided-questions.flow.spec.tsx +381 -0
- package/src/app/chat/agentkit-chat/guided-questions.tsx +236 -3
- package/src/app/chat/agentkit-chat/history.tsx +1 -1
- package/src/app/chat/agentkit-chat/index.ts +2 -0
- package/src/app/chat/agentkit-chat/labels.ts +259 -0
- package/src/app/chat/agentkit-chat/questions.ts +2 -0
- package/src/app/chat/agentkit-chat/root.spec.tsx +18 -0
- package/src/app/chat/agentkit-chat/root.tsx +5 -64
- package/src/app/chat/agentkit-chat/work-step-labels.ts +42 -0
- package/src/app/chat/chat/markdown-renderer.tsx +2 -59
- package/src/app/chat/chat/tool-call-display.spec.tsx +26 -14
- package/src/app/chat/chat/tool-call-display.tsx +2 -1
- package/src/app/chat/conversation/AgentConversation.tsx +2 -50
- package/src/app/chat/tool-cells/BashCell.tsx +14 -136
- package/src/app/chat/tool-cells/EditCell.tsx +11 -248
- package/src/app/chat/tool-cells/FilesChangedSummary.spec.tsx +62 -5
- package/src/app/chat/tool-cells/FilesChangedSummary.tsx +31 -162
- package/src/app/chat/tool-cells/WriteCell.tsx +11 -121
- package/src/app/code-highlighter.ts +131 -0
- package/src/app/context-xray/ThreadContextRing.tsx +7 -7
- package/src/app/i18n/catalogs/ar-SA.ts +22 -0
- package/src/app/i18n/catalogs/de-DE.ts +22 -0
- package/src/app/i18n/catalogs/en-US.ts +22 -0
- package/src/app/i18n/catalogs/es-ES.ts +22 -0
- package/src/app/i18n/catalogs/fr-FR.ts +22 -0
- package/src/app/i18n/catalogs/hi-IN.ts +22 -0
- package/src/app/i18n/catalogs/ja-JP.ts +22 -0
- package/src/app/i18n/catalogs/ko-KR.ts +22 -0
- package/src/app/i18n/catalogs/pt-BR.ts +22 -0
- package/src/app/i18n/catalogs/zh-CN.ts +22 -0
- package/src/app/i18n/catalogs/zh-TW.ts +22 -0
- package/src/app/onboarding/first-run-first-paint.spec.ts +39 -0
- package/src/app/onboarding/first-run-first-paint.ts +24 -0
- package/src/app/onboarding/first-run-startup-gate.spec.tsx +125 -13
- package/src/app/onboarding/first-run-startup-gate.tsx +48 -5
- package/src/app/providers/AppProviders.tsx +18 -0
- package/src/app/providers/BuilderSignupActivation.tsx +8 -2
- package/src/app/shared/AppShellSkeleton.spec.tsx +60 -1
- package/src/app/shared/AppShellSkeleton.tsx +31 -1
- package/src/app/styles/agent-native.css +2 -2
- package/src/app/styles/agent-native.spec.ts +2 -2
- package/src/app/styles/tokens/agent-kit.css +20 -3
- package/src/composer/AgentSuggestionBar.spec.tsx +3 -1
- package/src/composer/AgentSuggestionBar.tsx +5 -2
- package/src/composer/ComposerContextMenu.tsx +4 -4
- package/src/composer/ComposerContextPicker.tsx +8 -2
- package/src/composer/ComposerContextPickerDialog.tsx +5 -2
- package/src/composer/ComposerModePicker.tsx +2 -1
- package/src/composer/ComposerPlusMenu.tsx +1 -1
- package/src/composer/MentionChip.tsx +1 -1
- package/src/composer/MentionPopover.spec.tsx +108 -2
- package/src/composer/MentionPopover.tsx +93 -17
- package/src/composer/MessageQueueDrawer.spec.tsx +5 -5
- package/src/composer/MessageQueueDrawer.tsx +19 -12
- package/src/composer/PastedTextChip.spec.tsx +36 -0
- package/src/composer/PastedTextChip.tsx +52 -58
- package/src/composer/PromptBar.tsx +1 -1
- package/src/composer/PromptComposer.context.spec.tsx +2 -2
- package/src/composer/PromptComposer.submission.spec.tsx +27 -0
- package/src/composer/PromptComposer.tsx +17 -9
- package/src/composer/RealtimeVoiceMode.tsx +2 -2
- package/src/composer/TiptapComposer.model-picker.spec.tsx +23 -82
- package/src/composer/TiptapComposer.tsx +68 -145
- package/src/composer/VoiceButton.tsx +12 -7
- package/src/composer/composer-notice.tsx +3 -3
- package/src/composer/extensions/FileReference.tsx +1 -1
- package/src/composer/extensions/SkillReference.tsx +1 -1
- package/src/composer/popover-surface.ts +1 -1
- package/src/context-ui/ContextUsageRing.spec.tsx +33 -8
- package/src/context-ui/ContextUsageRing.tsx +13 -348
- package/src/context-ui/index.ts +7 -1
- package/dist/composer/ModelPickerParts.d.ts +0 -20
- package/dist/composer/ModelPickerParts.d.ts.map +0 -1
- package/dist/composer/ModelPickerParts.js +0 -77
- package/dist/composer/ModelPickerParts.js.map +0 -1
- package/src/composer/ModelPickerParts.tsx +0 -188
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
|
|
3
|
+
import { act, type ReactNode } from "react";
|
|
4
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { Terminal, TerminalOutput } from "./terminal.js";
|
|
8
|
+
|
|
9
|
+
let root: Root;
|
|
10
|
+
let container: HTMLDivElement;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
14
|
+
container = document.createElement("div");
|
|
15
|
+
document.body.append(container);
|
|
16
|
+
root = createRoot(container);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
act(() => root.unmount());
|
|
21
|
+
container.remove();
|
|
22
|
+
vi.unstubAllGlobals();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
async function render(node: ReactNode) {
|
|
26
|
+
await act(async () => root.render(node));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const trigger = () =>
|
|
30
|
+
container.querySelector<HTMLButtonElement>(
|
|
31
|
+
"button.agentkit-disclosure-summary",
|
|
32
|
+
);
|
|
33
|
+
const status = () =>
|
|
34
|
+
container
|
|
35
|
+
.querySelector('[data-slot="trace-line"]')
|
|
36
|
+
?.getAttribute("data-trace-status");
|
|
37
|
+
|
|
38
|
+
describe("Terminal", () => {
|
|
39
|
+
it("shows a command with no output yet as a static running step", async () => {
|
|
40
|
+
await render(<Terminal command="pnpm build" running />);
|
|
41
|
+
expect(trigger()).toBeNull();
|
|
42
|
+
expect(container.querySelector(".agentkit-trace-title")?.textContent).toBe(
|
|
43
|
+
"pnpm build",
|
|
44
|
+
);
|
|
45
|
+
expect(status()).toBe("running");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("masks closed output in fresh nodes, so replay never keeps it", async () => {
|
|
49
|
+
await render(
|
|
50
|
+
<Terminal command="pnpm build" output={"token=abc\n"} exitCode={0} />,
|
|
51
|
+
);
|
|
52
|
+
const output = () =>
|
|
53
|
+
document.querySelector(".agentkit-terminal-body [data-an-mask]");
|
|
54
|
+
expect(
|
|
55
|
+
document.querySelector(".agentkit-terminal-body")?.textContent,
|
|
56
|
+
).toContain("token=abc");
|
|
57
|
+
expect(output()).not.toBeNull();
|
|
58
|
+
|
|
59
|
+
await act(async () =>
|
|
60
|
+
document
|
|
61
|
+
.querySelector<HTMLButtonElement>(".agentkit-disclosure-summary")
|
|
62
|
+
?.click(),
|
|
63
|
+
);
|
|
64
|
+
const opened = document.querySelector(".agentkit-terminal-body");
|
|
65
|
+
expect(output()).toBeNull();
|
|
66
|
+
|
|
67
|
+
await act(async () =>
|
|
68
|
+
document
|
|
69
|
+
.querySelector<HTMLButtonElement>(".agentkit-disclosure-summary")
|
|
70
|
+
?.click(),
|
|
71
|
+
);
|
|
72
|
+
// Closing replaces the node instead of masking the one replay recorded.
|
|
73
|
+
expect(opened?.isConnected).toBe(false);
|
|
74
|
+
expect(output()).not.toBeNull();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("opens when output starts streaming and marks a nonzero exit failed", async () => {
|
|
78
|
+
await render(<Terminal command="pnpm test" running output="" />);
|
|
79
|
+
await render(
|
|
80
|
+
<Terminal command="pnpm test" running output={"1 passed\n"} />,
|
|
81
|
+
);
|
|
82
|
+
expect(trigger()?.getAttribute("aria-expanded")).toBe("true");
|
|
83
|
+
expect(container.querySelector("pre")?.textContent).toBe("1 passed");
|
|
84
|
+
|
|
85
|
+
await render(
|
|
86
|
+
<Terminal
|
|
87
|
+
command="pnpm test"
|
|
88
|
+
output={"1 passed\n1 failed\n"}
|
|
89
|
+
exitCode={1}
|
|
90
|
+
durationMs={4_200}
|
|
91
|
+
/>,
|
|
92
|
+
);
|
|
93
|
+
expect(status()).toBe("error");
|
|
94
|
+
expect(
|
|
95
|
+
container.querySelector(".agentkit-trace-description")?.textContent,
|
|
96
|
+
).toBe("4s · Exit code 1");
|
|
97
|
+
// Finishing never closes what streaming opened.
|
|
98
|
+
expect(trigger()?.getAttribute("aria-expanded")).toBe("true");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("stays closed once the user closes it, while output keeps streaming", async () => {
|
|
102
|
+
await render(<Terminal command="pnpm dev" running output={"ready\n"} />);
|
|
103
|
+
await act(async () => trigger()?.click());
|
|
104
|
+
expect(trigger()?.getAttribute("aria-expanded")).toBe("false");
|
|
105
|
+
await render(
|
|
106
|
+
<Terminal command="pnpm dev" running output={"ready\nrebuilt\n"} />,
|
|
107
|
+
);
|
|
108
|
+
expect(trigger()?.getAttribute("aria-expanded")).toBe("false");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("shows the newest lines first and reveals the earlier ones", async () => {
|
|
112
|
+
const output = Array.from(
|
|
113
|
+
{ length: 8 },
|
|
114
|
+
(_, index) => `line ${index + 1}`,
|
|
115
|
+
).join("\n");
|
|
116
|
+
await render(
|
|
117
|
+
<Terminal command="seq 8" output={output} maxLines={3} defaultOpen />,
|
|
118
|
+
);
|
|
119
|
+
expect(trigger()?.getAttribute("aria-expanded")).toBe("true");
|
|
120
|
+
const pre = () => container.querySelector("pre")?.textContent;
|
|
121
|
+
expect(pre()).toBe("line 6\nline 7\nline 8");
|
|
122
|
+
const earlier = container.querySelector<HTMLButtonElement>(
|
|
123
|
+
".agentkit-terminal-earlier",
|
|
124
|
+
);
|
|
125
|
+
expect(earlier?.textContent).toBe("Show 5 earlier lines");
|
|
126
|
+
await act(async () => earlier?.click());
|
|
127
|
+
expect(pre()).toBe(output);
|
|
128
|
+
|
|
129
|
+
// The body remounts on each toggle; the revealed lines stay revealed.
|
|
130
|
+
await act(async () => trigger()?.click());
|
|
131
|
+
await act(async () => trigger()?.click());
|
|
132
|
+
expect(pre()).toBe(output);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("reveals earlier lines when given showAll without onShowAll", async () => {
|
|
136
|
+
const output = ["one", "two", "three"].join("\n");
|
|
137
|
+
await render(
|
|
138
|
+
<TerminalOutput output={output} maxLines={1} showAll={false} />,
|
|
139
|
+
);
|
|
140
|
+
await act(async () =>
|
|
141
|
+
container
|
|
142
|
+
.querySelector<HTMLButtonElement>(".agentkit-terminal-earlier")
|
|
143
|
+
?.click(),
|
|
144
|
+
);
|
|
145
|
+
expect(container.querySelector("pre")?.textContent).toBe(output);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("shows every line for showAll and reports a reveal to onShowAll", async () => {
|
|
149
|
+
const output = ["one", "two", "three"].join("\n");
|
|
150
|
+
const pre = () => container.querySelector("pre")?.textContent;
|
|
151
|
+
await render(<TerminalOutput output={output} maxLines={1} showAll />);
|
|
152
|
+
expect(pre()).toBe(output);
|
|
153
|
+
|
|
154
|
+
const onShowAll = vi.fn();
|
|
155
|
+
await render(
|
|
156
|
+
<TerminalOutput
|
|
157
|
+
key="callback-only"
|
|
158
|
+
output={output}
|
|
159
|
+
maxLines={1}
|
|
160
|
+
onShowAll={onShowAll}
|
|
161
|
+
/>,
|
|
162
|
+
);
|
|
163
|
+
expect(pre()).toBe("three");
|
|
164
|
+
await act(async () =>
|
|
165
|
+
container
|
|
166
|
+
.querySelector<HTMLButtonElement>(".agentkit-terminal-earlier")
|
|
167
|
+
?.click(),
|
|
168
|
+
);
|
|
169
|
+
expect(pre()).toBe(output);
|
|
170
|
+
expect(onShowAll).toHaveBeenCalledTimes(1);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("leaves showAll to the host when it also passes onShowAll", async () => {
|
|
174
|
+
const output = ["one", "two", "three"].join("\n");
|
|
175
|
+
const pre = () => container.querySelector("pre")?.textContent;
|
|
176
|
+
const onShowAll = vi.fn();
|
|
177
|
+
const renderWith = (showAll: boolean) =>
|
|
178
|
+
render(
|
|
179
|
+
<TerminalOutput
|
|
180
|
+
output={output}
|
|
181
|
+
maxLines={1}
|
|
182
|
+
showAll={showAll}
|
|
183
|
+
onShowAll={onShowAll}
|
|
184
|
+
/>,
|
|
185
|
+
);
|
|
186
|
+
await renderWith(false);
|
|
187
|
+
await act(async () =>
|
|
188
|
+
container
|
|
189
|
+
.querySelector<HTMLButtonElement>(".agentkit-terminal-earlier")
|
|
190
|
+
?.click(),
|
|
191
|
+
);
|
|
192
|
+
expect(onShowAll).toHaveBeenCalledTimes(1);
|
|
193
|
+
expect(pre()).toBe("three");
|
|
194
|
+
await renderWith(true);
|
|
195
|
+
expect(pre()).toBe(output);
|
|
196
|
+
await renderWith(false);
|
|
197
|
+
expect(pre()).toBe("three");
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("copies the whole output without color codes", async () => {
|
|
201
|
+
const writeText = vi.fn(async () => undefined);
|
|
202
|
+
vi.stubGlobal("navigator", { ...navigator, clipboard: { writeText } });
|
|
203
|
+
await render(
|
|
204
|
+
<Terminal
|
|
205
|
+
command="pnpm lint"
|
|
206
|
+
output={"\u001b[31merror\u001b[0m in a.ts"}
|
|
207
|
+
exitCode={1}
|
|
208
|
+
/>,
|
|
209
|
+
);
|
|
210
|
+
const copy = container.querySelector<HTMLButtonElement>(
|
|
211
|
+
".agentkit-terminal-actions button",
|
|
212
|
+
);
|
|
213
|
+
expect(copy?.getAttribute("aria-label")).toBe("Copy output");
|
|
214
|
+
await act(async () => {
|
|
215
|
+
copy?.click();
|
|
216
|
+
await Promise.resolve();
|
|
217
|
+
await Promise.resolve();
|
|
218
|
+
});
|
|
219
|
+
expect(writeText).toHaveBeenCalledWith("error in a.ts");
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("marks a call that failed apart from its exit code", async () => {
|
|
223
|
+
await render(
|
|
224
|
+
<Terminal command="rm -rf /" output="Error: command blocked" failed />,
|
|
225
|
+
);
|
|
226
|
+
expect(status()).toBe("error");
|
|
227
|
+
});
|
|
228
|
+
});
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { IconAlertTriangle, IconTerminal2 } from "@tabler/icons-react";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
CodeBlock,
|
|
6
|
+
CodeBlockContent,
|
|
7
|
+
CodeBlockCopyButton,
|
|
8
|
+
CodeBlockHeader,
|
|
9
|
+
} from "./code-block.js";
|
|
10
|
+
import { useAgentKitDurationFormat, useAgentKitLabels } from "./context.js";
|
|
11
|
+
import {
|
|
12
|
+
Trace,
|
|
13
|
+
TraceCollapsible,
|
|
14
|
+
TraceCollapsibleContent,
|
|
15
|
+
TraceCollapsibleTrigger,
|
|
16
|
+
TraceDescription,
|
|
17
|
+
TraceIcon,
|
|
18
|
+
TraceLine,
|
|
19
|
+
TraceTitle,
|
|
20
|
+
type TraceCollapsibleOpenProps,
|
|
21
|
+
} from "./trace.js";
|
|
22
|
+
|
|
23
|
+
// A global regex's `test` keeps state between calls, so `HAS_ANSI` is separate.
|
|
24
|
+
const ANSI_SEQUENCE = /\u001b\[[0-9;]*m/g;
|
|
25
|
+
const HAS_ANSI = /\u001b\[[0-9;]*m/;
|
|
26
|
+
|
|
27
|
+
const DEFAULT_MAX_LINES = 500;
|
|
28
|
+
const SESSION_REPLAY_MASK_PROPS = { "data-an-mask": "" } as const;
|
|
29
|
+
const FOLLOW_SLACK_PX = 24;
|
|
30
|
+
|
|
31
|
+
/** Copy sits beside the trigger: a button cannot nest in the trigger. */
|
|
32
|
+
export function Terminal({
|
|
33
|
+
command,
|
|
34
|
+
output,
|
|
35
|
+
running = false,
|
|
36
|
+
exitCode,
|
|
37
|
+
durationMs,
|
|
38
|
+
timedOut = false,
|
|
39
|
+
failed: failedOverride,
|
|
40
|
+
defaultOpen = false,
|
|
41
|
+
maxLines = DEFAULT_MAX_LINES,
|
|
42
|
+
className,
|
|
43
|
+
...openProps
|
|
44
|
+
}: TraceCollapsibleOpenProps & {
|
|
45
|
+
command: string;
|
|
46
|
+
/** May hold ANSI color codes. */
|
|
47
|
+
output?: string | undefined;
|
|
48
|
+
running?: boolean;
|
|
49
|
+
exitCode?: number | null | undefined;
|
|
50
|
+
durationMs?: number | undefined;
|
|
51
|
+
timedOut?: boolean | undefined;
|
|
52
|
+
/** A failure the exit code does not show, such as a rejected command. */
|
|
53
|
+
failed?: boolean | undefined;
|
|
54
|
+
defaultOpen?: boolean;
|
|
55
|
+
/** How many of the newest lines show before "Show earlier lines". */
|
|
56
|
+
maxLines?: number;
|
|
57
|
+
className?: string;
|
|
58
|
+
}) {
|
|
59
|
+
const labels = useAgentKitLabels();
|
|
60
|
+
const formatDuration = useAgentKitDurationFormat();
|
|
61
|
+
const failed =
|
|
62
|
+
!running &&
|
|
63
|
+
(failedOverride === true ||
|
|
64
|
+
timedOut ||
|
|
65
|
+
(exitCode !== undefined && exitCode !== null && exitCode !== 0));
|
|
66
|
+
const hasOutput = Boolean(output?.trim());
|
|
67
|
+
// Opens once when running output starts; never closes on its own.
|
|
68
|
+
const [autoOpen, setAutoOpen] = useState(false);
|
|
69
|
+
// Outlives the body, which remounts on each toggle.
|
|
70
|
+
const [showAllOutput, setShowAllOutput] = useState(false);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (running && hasOutput) setAutoOpen(true);
|
|
73
|
+
}, [running, hasOutput]);
|
|
74
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
75
|
+
const open = openProps.open ?? (uncontrolledOpen || autoOpen);
|
|
76
|
+
const setOpen = (next: boolean) => {
|
|
77
|
+
if (openProps.open === undefined) {
|
|
78
|
+
setUncontrolledOpen(next);
|
|
79
|
+
setAutoOpen(false);
|
|
80
|
+
}
|
|
81
|
+
openProps.onOpenChange?.(next);
|
|
82
|
+
};
|
|
83
|
+
const meta = [
|
|
84
|
+
!running && durationMs !== undefined && durationMs >= 1_000
|
|
85
|
+
? formatDuration(durationMs)
|
|
86
|
+
: undefined,
|
|
87
|
+
failed && exitCode !== undefined && exitCode !== null && exitCode !== 0
|
|
88
|
+
? labels.workStepTerminalExitCode.replace("{{code}}", () => `${exitCode}`)
|
|
89
|
+
: undefined,
|
|
90
|
+
timedOut ? labels.workStepTerminalTimedOut : undefined,
|
|
91
|
+
].filter((part): part is string => Boolean(part));
|
|
92
|
+
const line = (
|
|
93
|
+
<TraceLine status={running ? "running" : failed ? "error" : undefined}>
|
|
94
|
+
<TraceIcon>
|
|
95
|
+
{/* Without an exit code, the triangle marks a failure besides color. */}
|
|
96
|
+
{failed ? (
|
|
97
|
+
<IconAlertTriangle aria-hidden="true" className="agentkit-icon" />
|
|
98
|
+
) : (
|
|
99
|
+
<IconTerminal2 aria-hidden="true" className="agentkit-icon" />
|
|
100
|
+
)}
|
|
101
|
+
</TraceIcon>
|
|
102
|
+
<TraceTitle className="agentkit-terminal-command">{command}</TraceTitle>
|
|
103
|
+
{running || failed ? (
|
|
104
|
+
// Status shows as motion and color; the accessible name says it.
|
|
105
|
+
<span className="agentkit-visually-hidden">
|
|
106
|
+
{running ? labels.taskStatusRunning : labels.taskStatusFailed}
|
|
107
|
+
</span>
|
|
108
|
+
) : null}
|
|
109
|
+
{meta.length ? (
|
|
110
|
+
<TraceDescription>{meta.join(" · ")}</TraceDescription>
|
|
111
|
+
) : null}
|
|
112
|
+
</TraceLine>
|
|
113
|
+
);
|
|
114
|
+
return (
|
|
115
|
+
<Trace
|
|
116
|
+
data-slot="terminal"
|
|
117
|
+
data-status={running ? "running" : failed ? "failed" : "completed"}
|
|
118
|
+
className={
|
|
119
|
+
className ? `agentkit-terminal ${className}` : "agentkit-terminal"
|
|
120
|
+
}
|
|
121
|
+
>
|
|
122
|
+
{hasOutput ? (
|
|
123
|
+
<TraceCollapsible open={open} onOpenChange={setOpen}>
|
|
124
|
+
<div className="agentkit-terminal-row">
|
|
125
|
+
<TraceCollapsibleTrigger>{line}</TraceCollapsibleTrigger>
|
|
126
|
+
<span className="agentkit-terminal-actions">
|
|
127
|
+
<CodeBlockCopyButton
|
|
128
|
+
value={(output ?? "").replace(ANSI_SEQUENCE, "")}
|
|
129
|
+
label={labels.workStepCopyOutput}
|
|
130
|
+
/>
|
|
131
|
+
</span>
|
|
132
|
+
</div>
|
|
133
|
+
<TraceCollapsibleContent
|
|
134
|
+
// A fresh node on each toggle: masking a node replay already
|
|
135
|
+
// recorded would not hide its text.
|
|
136
|
+
key={open ? "open" : "closed"}
|
|
137
|
+
keepMounted
|
|
138
|
+
className="agentkit-terminal-body"
|
|
139
|
+
>
|
|
140
|
+
<TerminalOutput
|
|
141
|
+
output={output ?? ""}
|
|
142
|
+
maxLines={maxLines}
|
|
143
|
+
masked={failed || !open}
|
|
144
|
+
showAll={showAllOutput}
|
|
145
|
+
onShowAll={() => setShowAllOutput(true)}
|
|
146
|
+
/>
|
|
147
|
+
</TraceCollapsibleContent>
|
|
148
|
+
</TraceCollapsible>
|
|
149
|
+
) : (
|
|
150
|
+
<span className="agentkit-disclosure-summary" data-expandable="false">
|
|
151
|
+
{line}
|
|
152
|
+
</span>
|
|
153
|
+
)}
|
|
154
|
+
</Trace>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function TerminalOutput({
|
|
159
|
+
output,
|
|
160
|
+
maxLines = DEFAULT_MAX_LINES,
|
|
161
|
+
masked = false,
|
|
162
|
+
showAll: controlledShowAll,
|
|
163
|
+
onShowAll,
|
|
164
|
+
}: {
|
|
165
|
+
output: string;
|
|
166
|
+
maxLines?: number;
|
|
167
|
+
/** Hides the output from session replays. */
|
|
168
|
+
masked?: boolean;
|
|
169
|
+
/** Shows every line. Pass with `onShowAll` to control it. */
|
|
170
|
+
showAll?: boolean;
|
|
171
|
+
/** Called when the user reveals the earlier lines. */
|
|
172
|
+
onShowAll?: () => void;
|
|
173
|
+
}) {
|
|
174
|
+
const labels = useAgentKitLabels();
|
|
175
|
+
const [revealed, setRevealed] = useState(false);
|
|
176
|
+
// With both props the host owns it; with one, a press still reveals.
|
|
177
|
+
const showAll =
|
|
178
|
+
onShowAll && controlledShowAll !== undefined
|
|
179
|
+
? controlledShowAll
|
|
180
|
+
: controlledShowAll === true || revealed;
|
|
181
|
+
const setShowAll = () => {
|
|
182
|
+
setRevealed(true);
|
|
183
|
+
onShowAll?.();
|
|
184
|
+
};
|
|
185
|
+
const content = useRef<HTMLPreElement>(null);
|
|
186
|
+
const lines = output.replace(/\n$/, "").split("\n");
|
|
187
|
+
const hidden = showAll ? 0 : Math.max(0, lines.length - maxLines);
|
|
188
|
+
const visible = hidden ? lines.slice(hidden).join("\n") : output;
|
|
189
|
+
// Follow only if the reader was at the bottom before the output grew;
|
|
190
|
+
// measured here, not tracked from scroll events.
|
|
191
|
+
const lastHeight = useRef(0);
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
const element = content.current;
|
|
194
|
+
if (!element) return;
|
|
195
|
+
const wasAtBottom =
|
|
196
|
+
lastHeight.current - element.scrollTop - element.clientHeight <=
|
|
197
|
+
FOLLOW_SLACK_PX;
|
|
198
|
+
if (wasAtBottom) element.scrollTop = element.scrollHeight;
|
|
199
|
+
lastHeight.current = element.scrollHeight;
|
|
200
|
+
}, [visible]);
|
|
201
|
+
return (
|
|
202
|
+
<CodeBlock size="sm">
|
|
203
|
+
{hidden ? (
|
|
204
|
+
<CodeBlockHeader>
|
|
205
|
+
<button
|
|
206
|
+
type="button"
|
|
207
|
+
className="agentkit-terminal-earlier"
|
|
208
|
+
onClick={setShowAll}
|
|
209
|
+
>
|
|
210
|
+
{labels.workStepTerminalEarlierLines.replace(
|
|
211
|
+
"{{count}}",
|
|
212
|
+
() => `${hidden}`,
|
|
213
|
+
)}
|
|
214
|
+
</button>
|
|
215
|
+
</CodeBlockHeader>
|
|
216
|
+
) : null}
|
|
217
|
+
<CodeBlockContent
|
|
218
|
+
ref={content}
|
|
219
|
+
wrap
|
|
220
|
+
language={HAS_ANSI.test(visible) ? "ansi" : undefined}
|
|
221
|
+
className="agentkit-terminal-output"
|
|
222
|
+
{...(masked ? SESSION_REPLAY_MASK_PROPS : {})}
|
|
223
|
+
>
|
|
224
|
+
{visible}
|
|
225
|
+
</CodeBlockContent>
|
|
226
|
+
</CodeBlock>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
|
|
3
|
+
import { act, useState, type ReactNode } from "react";
|
|
4
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
5
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
TraceCollapsible,
|
|
9
|
+
TraceCollapsibleContent,
|
|
10
|
+
TraceCollapsibleTrigger,
|
|
11
|
+
TraceLine,
|
|
12
|
+
TraceTitle,
|
|
13
|
+
} from "./trace.js";
|
|
14
|
+
|
|
15
|
+
(
|
|
16
|
+
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }
|
|
17
|
+
).IS_REACT_ACT_ENVIRONMENT = true;
|
|
18
|
+
|
|
19
|
+
let root: Root | undefined;
|
|
20
|
+
let container: HTMLDivElement | undefined;
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
act(() => root?.unmount());
|
|
24
|
+
container?.remove();
|
|
25
|
+
root = undefined;
|
|
26
|
+
container = undefined;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
function render(node: ReactNode): HTMLDivElement {
|
|
30
|
+
container = document.createElement("div");
|
|
31
|
+
document.body.append(container);
|
|
32
|
+
root = createRoot(container);
|
|
33
|
+
act(() => root!.render(node));
|
|
34
|
+
return container;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function step(keepMounted?: boolean) {
|
|
38
|
+
return (
|
|
39
|
+
<TraceCollapsible>
|
|
40
|
+
<TraceCollapsibleTrigger>
|
|
41
|
+
<TraceLine status="running">
|
|
42
|
+
<TraceTitle>Reading file</TraceTitle>
|
|
43
|
+
</TraceLine>
|
|
44
|
+
</TraceCollapsibleTrigger>
|
|
45
|
+
<TraceCollapsibleContent keepMounted={keepMounted}>
|
|
46
|
+
File contents
|
|
47
|
+
</TraceCollapsibleContent>
|
|
48
|
+
</TraceCollapsible>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
describe("Trace", () => {
|
|
53
|
+
it("mounts closed content only while open by default", () => {
|
|
54
|
+
const view = render(step());
|
|
55
|
+
const trigger = view.querySelector("button")!;
|
|
56
|
+
expect(trigger.getAttribute("aria-expanded")).toBe("false");
|
|
57
|
+
expect(trigger.hasAttribute("aria-controls")).toBe(false);
|
|
58
|
+
expect(view.textContent).not.toContain("File contents");
|
|
59
|
+
|
|
60
|
+
act(() => trigger.click());
|
|
61
|
+
const content = view.querySelector<HTMLElement>(
|
|
62
|
+
'[data-slot="trace-collapsible-content"]',
|
|
63
|
+
)!;
|
|
64
|
+
expect(trigger.getAttribute("aria-expanded")).toBe("true");
|
|
65
|
+
expect(trigger.getAttribute("aria-controls")).toBe(content.id);
|
|
66
|
+
expect(content.textContent).toBe("File contents");
|
|
67
|
+
|
|
68
|
+
act(() => trigger.click());
|
|
69
|
+
expect(view.textContent).not.toContain("File contents");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("keeps closed content findable and opens on a find-in-page match", () => {
|
|
73
|
+
const view = render(step(true));
|
|
74
|
+
const trigger = view.querySelector("button")!;
|
|
75
|
+
const content = view.querySelector<HTMLElement>(
|
|
76
|
+
'[data-slot="trace-collapsible-content"]',
|
|
77
|
+
)!;
|
|
78
|
+
expect(content.getAttribute("hidden")).toBe("until-found");
|
|
79
|
+
expect(content.textContent).toBe("File contents");
|
|
80
|
+
expect(trigger.getAttribute("aria-controls")).toBe(content.id);
|
|
81
|
+
|
|
82
|
+
act(() => content.dispatchEvent(new Event("beforematch")));
|
|
83
|
+
expect(trigger.getAttribute("aria-expanded")).toBe("true");
|
|
84
|
+
expect(content.hidden).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("follows a controlled open state", () => {
|
|
88
|
+
let setOpen: (open: boolean) => void = () => undefined;
|
|
89
|
+
const changes: boolean[] = [];
|
|
90
|
+
function Controlled() {
|
|
91
|
+
const [open, update] = useState(false);
|
|
92
|
+
setOpen = update;
|
|
93
|
+
return (
|
|
94
|
+
<TraceCollapsible
|
|
95
|
+
open={open}
|
|
96
|
+
onOpenChange={(next) => {
|
|
97
|
+
changes.push(next);
|
|
98
|
+
update(next);
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
<TraceCollapsibleTrigger>Step</TraceCollapsibleTrigger>
|
|
102
|
+
<TraceCollapsibleContent>Detail</TraceCollapsibleContent>
|
|
103
|
+
</TraceCollapsible>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
const view = render(<Controlled />);
|
|
107
|
+
act(() => setOpen(true));
|
|
108
|
+
expect(view.textContent).toContain("Detail");
|
|
109
|
+
act(() => view.querySelector("button")!.click());
|
|
110
|
+
expect(changes).toEqual([false]);
|
|
111
|
+
expect(view.textContent).not.toContain("Detail");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("keeps the trace status apart from a row's protocol status", () => {
|
|
115
|
+
const view = render(step());
|
|
116
|
+
const line = view.querySelector('[data-slot="trace-line"]')!;
|
|
117
|
+
expect(line.getAttribute("data-trace-status")).toBe("running");
|
|
118
|
+
expect(line.hasAttribute("data-status")).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
});
|