@burdenoff/microfe-vibecontrols 2026.529.16 → 2026.529.18
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/dist/components/agent-manager/AgentManagerChatPane.js +1 -2
- package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerInputArea.js +114 -116
- package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
- package/dist/components/agents/OpenInBrowserEditorButton.js +109 -97
- package/dist/components/agents/OpenInBrowserEditorButton.js.map +1 -1
- package/dist/components/agents/OpenInEditorMenu.js +38 -43
- package/dist/components/agents/OpenInEditorMenu.js.map +1 -1
- package/dist/components/agents/PluginUIPanel.js +161 -149
- package/dist/components/agents/PluginUIPanel.js.map +1 -1
- package/dist/components/agents/backup/AgentBackupTab.js +124 -132
- package/dist/components/agents/backup/AgentBackupTab.js.map +1 -1
- package/dist/components/ai/AIPlanPanel.js +201 -188
- package/dist/components/ai/AIPlanPanel.js.map +1 -1
- package/dist/components/plugins/AddTabDialog.js +4 -4
- package/dist/components/sessions/TerminalPanel.js +332 -296
- package/dist/components/sessions/TerminalPanel.js.map +1 -1
- package/dist/generated/wspace-operations.js +1499 -1364
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/hooks/useCachedInitialData.js +0 -1
- package/dist/hooks/useCachedInitialData.js.map +1 -1
- package/dist/index.js +10 -10
- package/dist/pages/AgentDetailsPage.js +837 -894
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +89 -109
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +210 -210
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/ai/AIPage.js +1 -2
- package/dist/pages/ai/AIPage.js.map +1 -1
- package/dist/pages/ai/AISessionDetailPage.js +1 -1
- package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
- package/dist/pages/ai/AgentManagerPage.js +1 -1
- package/dist/pages/ai/AgentManagerPage.js.map +1 -1
- package/dist/services/iframeToken.js +4 -4
- package/dist/services/schedulerApi.js +1 -1
- package/dist/services/schedulerApi.js.map +1 -1
- package/package.json +1 -1
|
@@ -166,8 +166,7 @@ var C = ({ sessionId: d, agentId: C }) => {
|
|
|
166
166
|
sessionId: d,
|
|
167
167
|
onSend: (e) => void J(e),
|
|
168
168
|
onCancel: Y,
|
|
169
|
-
agentTunnelUrl: H?.tunnelUrl ?? void 0
|
|
170
|
-
agentApiKey: H?.agentApiKey ?? void 0
|
|
169
|
+
agentTunnelUrl: H?.tunnelUrl ?? void 0
|
|
171
170
|
}),
|
|
172
171
|
/* @__PURE__ */ x(l, {
|
|
173
172
|
open: te,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentManagerChatPane.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerChatPane.tsx"],"sourcesContent":["/**\n * Main chat interface for a single Agent Manager session.\n *\n * Renders message list + input area, manages the send/receive flow,\n * fetches existing conversation logs on mount, and provides\n * auto-scroll, cancel, and in-session search support.\n */\n\nimport { useEffect, useRef, useState, useCallback, useMemo, type FC } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Bookmark, PackagePlus, Search, X } from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useAgentManagerStreaming } from '@/hooks/useAgentManagerStreaming';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { fetchSessionLogs } from '@/services/aiApi';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { useToggleAgentBookmark } from '@/hooks/useToggleAgentBookmark';\nimport { AgentManagerMessageList } from './AgentManagerMessageList';\nimport { AgentManagerInputArea } from './AgentManagerInputArea';\nimport { AgentManagerBookmarksDrawer } from './AgentManagerBookmarksDrawer';\nimport { PluginInstallModal } from './PluginInstallModal';\nimport { AIProviderCredentialsCard } from '@/components/ai/AIProviderCredentialsCard';\nimport type { AgentManagerMessage } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerChatPaneProps {\n sessionId: string;\n agentId: string;\n}\n\nexport const AgentManagerChatPane: FC<AgentManagerChatPaneProps> = ({ sessionId, agentId }) => {\n const [loadingLogs, setLoadingLogs] = useState(false);\n const [searchOpen, setSearchOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n // Provider-install modal triggered from the header. Lets users add a\n // claude/codex/gemini/opencode plugin without leaving the conversation.\n const [installModalOpen, setInstallModalOpen] = useState(false);\n const [bookmarksDrawerOpen, setBookmarksDrawerOpen] = useState(false);\n const [flashMessageId, setFlashMessageId] = useState<string | null>(null);\n const [searchParams, setSearchParams] = useSearchParams();\n const pendingScrollMessageId = searchParams.get('messageId');\n const consumedScrollTargetRef = useRef<string | null>(null);\n const tr = useTr();\n\n const { agents } = useCachedInitialData();\n const activeAgent = useMemo(\n () => agents.find((a) => a.id === agentId) ?? null,\n [agents, agentId]\n );\n\n const sessionState = useAgentManagerStore((s) => s.sessionStates[sessionId]);\n const addMessage = useAgentManagerStore((s) => s.addMessage);\n\n const messages = useMemo(() => sessionState?.messages ?? [], [sessionState?.messages]);\n\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const { sendMessage, cancelStream, isStreaming } = useAgentManagerStreaming({\n agent: agentRef,\n sessionId,\n });\n\n const { bookmarkedIds, toggle: toggleBookmark } = useToggleAgentBookmark(sessionId);\n\n const jumpToMessage = useCallback((messageId: string) => {\n const el = document.querySelector(`[data-message-id=\"${messageId}\"]`);\n if (!el) return;\n el.scrollIntoView({ behavior: 'smooth', block: 'center' });\n setFlashMessageId(messageId);\n window.setTimeout(() => {\n setFlashMessageId((current) => (current === messageId ? null : current));\n }, 1500);\n }, []);\n\n const handleToggleBookmark = useCallback(\n (messageId: string) => {\n void toggleBookmark({ agentId, sessionId, messageId });\n },\n [toggleBookmark, agentId, sessionId]\n );\n\n const toggleSearch = useCallback(() => {\n setSearchOpen((prev) => {\n if (prev) setSearchQuery('');\n return !prev;\n });\n }, []);\n\n // Fetch existing conversation logs on mount\n useEffect(() => {\n let cancelled = false;\n\n const loadExistingLogs = async () => {\n // Only load if session has no messages yet\n if (messages.length > 0) return;\n\n setLoadingLogs(true);\n try {\n const logs = await fetchSessionLogs(agentRef, sessionId, {\n types: ['input', 'output'],\n });\n\n if (cancelled || logs.length === 0) return;\n\n const seenLogKeys = new Set<string>();\n\n // Convert session logs to AgentManagerMessage format. The core AI\n // route owns logging, but older provider builds also wrote the same\n // input/output records; collapse same-second duplicates on restore.\n for (const log of logs) {\n const content = log.message || log.content || '';\n const timestamp = log.timestamp || log.createdAt;\n const timestampSecond = timestamp ? Math.floor(new Date(timestamp).getTime() / 1000) : 0;\n const logKey = [log.type, content, log.model ?? '', timestampSecond].join('\\u0000');\n if (seenLogKeys.has(logKey)) continue;\n seenLogKeys.add(logKey);\n\n const msg: AgentManagerMessage = {\n id: log.id,\n role: log.type === 'input' ? 'user' : 'assistant',\n content,\n timestamp,\n tokens: log.tokenCount ? { input: 0, output: log.tokenCount } : undefined,\n model: log.model,\n };\n addMessage(sessionId, msg);\n }\n } catch {\n // Silent fail -- session may not have logs yet\n } finally {\n if (!cancelled) setLoadingLogs(false);\n }\n };\n\n void loadExistingLogs();\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only run on mount\n }, [agentId, sessionId]);\n\n // Auto-scroll to a message linked via ?messageId=... (from drawer / cross-session page).\n // Waits for logs to finish loading and the target to be in the DOM before scrolling.\n useEffect(() => {\n if (!pendingScrollMessageId || loadingLogs) return;\n if (consumedScrollTargetRef.current === pendingScrollMessageId) return;\n\n const exists = messages.some((m) => m.id === pendingScrollMessageId);\n if (!exists) return;\n\n consumedScrollTargetRef.current = pendingScrollMessageId;\n jumpToMessage(pendingScrollMessageId);\n\n // Strip the query param so a manual refresh doesn't re-trigger the flash.\n const next = new URLSearchParams(searchParams);\n next.delete('messageId');\n setSearchParams(next, { replace: true });\n }, [pendingScrollMessageId, loadingLogs, messages, jumpToMessage, searchParams, setSearchParams]);\n\n return (\n <div className=\"flex flex-col h-full min-h-0\" data-testid=\"agent-manager-chat-pane\">\n {/* In-session search bar.\n Layout: [search controls (flex-1)] ... [Manage AI providers].\n The search input expands inside the LEFT cluster only, so the\n Manage button stays anchored on the right and never shifts. */}\n <div className=\"flex items-center gap-1 px-3 py-1 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <div className=\"flex items-center gap-1.5 min-w-0 flex-1\">\n <button\n type=\"button\"\n onClick={toggleSearch}\n className={`p-1 rounded transition-colors shrink-0 ${\n searchOpen\n ? 'bg-action-primary-bg/10 text-action-primary-text'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated'\n }`}\n title={tr(\n 'vibecontrols.agentManager.chatPane.searchInSession',\n 'Search in session (Ctrl+F)'\n )}\n aria-label={tr(\n 'vibecontrols.agentManager.chatPane.searchInSession',\n 'Search in session'\n )}\n >\n <Search className=\"size-3.5\" />\n </button>\n {searchOpen && (\n <div className=\"flex items-center gap-1.5 flex-1 min-w-0\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.chatPane.searchPlaceholder',\n 'Search in conversation...'\n )}\n className=\"flex-1 min-w-0 bg-transparent text-xs text-text-primary placeholder:text-text-tertiary focus:outline-none\"\n />\n {searchQuery && (\n <button\n type=\"button\"\n onClick={() => setSearchQuery('')}\n className=\"p-0.5 rounded hover:bg-bg-elevated transition-colors\"\n >\n <X className=\"size-3 text-text-tertiary\" />\n </button>\n )}\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => setBookmarksDrawerOpen(true)}\n className=\"shrink-0 p-1 rounded transition-colors text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated\"\n title={tr(\n 'vibecontrols.agentManager.chatPane.bookmarksTooltip',\n 'View bookmarked messages'\n )}\n aria-label={tr('vibecontrols.agentManager.chatPane.bookmarksLabel', 'Bookmarks')}\n data-testid=\"agent-manager-bookmarks-trigger\"\n >\n <Bookmark className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setInstallModalOpen(true)}\n className=\"shrink-0 inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-elevated px-2 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken hover:border-action-primary-bg/40\"\n title={tr(\n 'vibecontrols.agentManager.chatPane.manageProvidersTooltip',\n 'Install or remove AI providers (Claude, Codex, Gemini, OpenCode)'\n )}\n aria-label={tr(\n 'vibecontrols.agentManager.chatPane.manageProviders',\n 'Manage AI providers'\n )}\n data-testid=\"agent-manager-manage-providers\"\n >\n <PackagePlus className=\"size-3.5\" />\n <span className=\"hidden sm:inline\">\n {tr('vibecontrols.agentManager.chatPane.manageProviders', 'Manage AI providers')}\n </span>\n </button>\n </div>\n\n {/* Message list */}\n {loadingLogs ? (\n <div className=\"flex-1 flex items-center justify-center\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.agentManager.chatPane.loadingConversation',\n 'Loading conversation...'\n )}\n </p>\n </div>\n ) : (\n <AgentManagerMessageList\n messages={messages}\n isStreaming={isStreaming}\n onCancelStream={cancelStream}\n searchQuery={searchQuery}\n bookmarkedIds={bookmarkedIds}\n onToggleBookmark={handleToggleBookmark}\n flashMessageId={flashMessageId}\n />\n )}\n\n {/* Rich input area with controls */}\n <AgentManagerInputArea\n agentId={agentId}\n sessionId={sessionId}\n onSend={(text) => void sendMessage(text)}\n onCancel={cancelStream}\n agentTunnelUrl={activeAgent?.tunnelUrl ?? undefined}\n agentApiKey={activeAgent?.agentApiKey ?? undefined}\n />\n\n {/* Per-session bookmarks drawer */}\n <AgentManagerBookmarksDrawer\n open={bookmarksDrawerOpen}\n onClose={() => setBookmarksDrawerOpen(false)}\n sessionId={sessionId}\n messages={messages}\n onJump={jumpToMessage}\n />\n\n {/* Header-triggered provider install/remove. Sits below the chat\n tree so it can render full-screen without disturbing layout. */}\n <PluginInstallModal\n open={installModalOpen}\n agentId={agentId}\n onClose={() => setInstallModalOpen(false)}\n />\n\n {/* SDK auth prompt: opens when the streaming hook detects a missing\n ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, so the user can save the\n credential inline instead of being told to go look elsewhere.\n The session's currently-selected SDK is forwarded so the picker\n can preselect the right provider. */}\n <SdkAuthPromptModal\n agentId={agentId}\n agentRef={agentRef}\n initialProviderId={sessionState?.sdk ?? undefined}\n />\n </div>\n );\n};\n\ninterface SdkAuthPromptModalProps {\n agentId: string;\n agentRef: { id: string; profile: string };\n initialProviderId?: string;\n}\n\nconst SdkAuthPromptModal: FC<SdkAuthPromptModalProps> = ({\n agentId,\n agentRef,\n initialProviderId,\n}) => {\n const sdkAuthPrompt = useAgentManagerStore((s) => s.sdkAuthPrompt);\n const setSdkAuthPrompt = useAgentManagerStore((s) => s.setSdkAuthPrompt);\n // Track whether the inner card has at least one primary credential\n // saved on the agent. The Continue button is gated on this so the user\n // can't dismiss the modal without actually persisting a key — but the\n // moment they save *any* of the either-or options it lights up.\n const [authSatisfied, setAuthSatisfied] = useState(false);\n const tr = useTr();\n\n // Reset the satisfied flag whenever the modal re-opens for a fresh\n // prompt (different agent / different session). Without this, dismissing\n // and re-opening would leave the flag stuck at its previous value.\n useEffect(() => {\n if (sdkAuthPrompt && sdkAuthPrompt.agentId === agentId) {\n setAuthSatisfied(false);\n }\n }, [sdkAuthPrompt, agentId]);\n\n if (!sdkAuthPrompt || sdkAuthPrompt.agentId !== agentId) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div\n className=\"absolute inset-0 bg-bg-overlay\"\n onClick={() => setSdkAuthPrompt(null)}\n aria-hidden\n />\n {/* Constrain height to the viewport and let the inner body scroll so the\n modal never escapes the screen no matter how many providers/fields\n render inside AIProviderCredentialsCard. The header + footer stay\n sticky so the close + Continue buttons are always reachable. */}\n <div className=\"relative w-full max-w-xl max-h-[85vh] flex flex-col rounded-lg border border-border-default bg-bg-surface shadow-xl overflow-hidden\">\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <h3 className=\"text-base font-semibold text-text-primary truncate pr-2\">\n {tr('vibecontrols.ai.sdkAuth.title', 'Configure AI provider credentials')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n aria-label={tr('vibecontrols.common.close', 'Close')}\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto px-4 py-3 space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.ai.sdkAuth.body',\n \"The agent doesn't have a credential configured for this provider. Save any one of the listed keys (you don't need all of them) and click Continue to retry.\"\n )}\n </p>\n <AIProviderCredentialsCard\n agent={agentRef}\n initialProviderId={initialProviderId}\n onProviderAuthSatisfiedChange={setAuthSatisfied}\n />\n </div>\n <div className=\"flex items-center justify-end gap-2 px-4 py-3 border-t border-border-default bg-bg-surface flex-shrink-0\">\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n className=\"px-3 py-1.5 rounded-md text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n {tr('vibecontrols.common.close', 'Close')}\n </button>\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n disabled={!authSatisfied}\n title={\n authSatisfied\n ? undefined\n : tr(\n 'vibecontrols.ai.sdkAuth.saveOneFirst',\n 'Save at least one of the listed credentials to continue'\n )\n }\n className=\"px-3 py-1.5 rounded-md text-sm font-medium bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {tr('vibecontrols.ai.sdkAuth.continue', 'Continue')}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentManagerChatPane.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerChatPane.tsx"],"sourcesContent":["/**\n * Main chat interface for a single Agent Manager session.\n *\n * Renders message list + input area, manages the send/receive flow,\n * fetches existing conversation logs on mount, and provides\n * auto-scroll, cancel, and in-session search support.\n */\n\nimport { useEffect, useRef, useState, useCallback, useMemo, type FC } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Bookmark, PackagePlus, Search, X } from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useAgentManagerStreaming } from '@/hooks/useAgentManagerStreaming';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { fetchSessionLogs } from '@/services/aiApi';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { useToggleAgentBookmark } from '@/hooks/useToggleAgentBookmark';\nimport { AgentManagerMessageList } from './AgentManagerMessageList';\nimport { AgentManagerInputArea } from './AgentManagerInputArea';\nimport { AgentManagerBookmarksDrawer } from './AgentManagerBookmarksDrawer';\nimport { PluginInstallModal } from './PluginInstallModal';\nimport { AIProviderCredentialsCard } from '@/components/ai/AIProviderCredentialsCard';\nimport type { AgentManagerMessage } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerChatPaneProps {\n sessionId: string;\n agentId: string;\n}\n\nexport const AgentManagerChatPane: FC<AgentManagerChatPaneProps> = ({ sessionId, agentId }) => {\n const [loadingLogs, setLoadingLogs] = useState(false);\n const [searchOpen, setSearchOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n // Provider-install modal triggered from the header. Lets users add a\n // claude/codex/gemini/opencode plugin without leaving the conversation.\n const [installModalOpen, setInstallModalOpen] = useState(false);\n const [bookmarksDrawerOpen, setBookmarksDrawerOpen] = useState(false);\n const [flashMessageId, setFlashMessageId] = useState<string | null>(null);\n const [searchParams, setSearchParams] = useSearchParams();\n const pendingScrollMessageId = searchParams.get('messageId');\n const consumedScrollTargetRef = useRef<string | null>(null);\n const tr = useTr();\n\n const { agents } = useCachedInitialData();\n const activeAgent = useMemo(\n () => agents.find((a) => a.id === agentId) ?? null,\n [agents, agentId]\n );\n\n const sessionState = useAgentManagerStore((s) => s.sessionStates[sessionId]);\n const addMessage = useAgentManagerStore((s) => s.addMessage);\n\n const messages = useMemo(() => sessionState?.messages ?? [], [sessionState?.messages]);\n\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const { sendMessage, cancelStream, isStreaming } = useAgentManagerStreaming({\n agent: agentRef,\n sessionId,\n });\n\n const { bookmarkedIds, toggle: toggleBookmark } = useToggleAgentBookmark(sessionId);\n\n const jumpToMessage = useCallback((messageId: string) => {\n const el = document.querySelector(`[data-message-id=\"${messageId}\"]`);\n if (!el) return;\n el.scrollIntoView({ behavior: 'smooth', block: 'center' });\n setFlashMessageId(messageId);\n window.setTimeout(() => {\n setFlashMessageId((current) => (current === messageId ? null : current));\n }, 1500);\n }, []);\n\n const handleToggleBookmark = useCallback(\n (messageId: string) => {\n void toggleBookmark({ agentId, sessionId, messageId });\n },\n [toggleBookmark, agentId, sessionId]\n );\n\n const toggleSearch = useCallback(() => {\n setSearchOpen((prev) => {\n if (prev) setSearchQuery('');\n return !prev;\n });\n }, []);\n\n // Fetch existing conversation logs on mount\n useEffect(() => {\n let cancelled = false;\n\n const loadExistingLogs = async () => {\n // Only load if session has no messages yet\n if (messages.length > 0) return;\n\n setLoadingLogs(true);\n try {\n const logs = await fetchSessionLogs(agentRef, sessionId, {\n types: ['input', 'output'],\n });\n\n if (cancelled || logs.length === 0) return;\n\n const seenLogKeys = new Set<string>();\n\n // Convert session logs to AgentManagerMessage format. The core AI\n // route owns logging, but older provider builds also wrote the same\n // input/output records; collapse same-second duplicates on restore.\n for (const log of logs) {\n const content = log.message || log.content || '';\n const timestamp = log.timestamp || log.createdAt;\n const timestampSecond = timestamp ? Math.floor(new Date(timestamp).getTime() / 1000) : 0;\n const logKey = [log.type, content, log.model ?? '', timestampSecond].join('\\u0000');\n if (seenLogKeys.has(logKey)) continue;\n seenLogKeys.add(logKey);\n\n const msg: AgentManagerMessage = {\n id: log.id,\n role: log.type === 'input' ? 'user' : 'assistant',\n content,\n timestamp,\n tokens: log.tokenCount ? { input: 0, output: log.tokenCount } : undefined,\n model: log.model,\n };\n addMessage(sessionId, msg);\n }\n } catch {\n // Silent fail -- session may not have logs yet\n } finally {\n if (!cancelled) setLoadingLogs(false);\n }\n };\n\n void loadExistingLogs();\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only run on mount\n }, [agentId, sessionId]);\n\n // Auto-scroll to a message linked via ?messageId=... (from drawer / cross-session page).\n // Waits for logs to finish loading and the target to be in the DOM before scrolling.\n useEffect(() => {\n if (!pendingScrollMessageId || loadingLogs) return;\n if (consumedScrollTargetRef.current === pendingScrollMessageId) return;\n\n const exists = messages.some((m) => m.id === pendingScrollMessageId);\n if (!exists) return;\n\n consumedScrollTargetRef.current = pendingScrollMessageId;\n jumpToMessage(pendingScrollMessageId);\n\n // Strip the query param so a manual refresh doesn't re-trigger the flash.\n const next = new URLSearchParams(searchParams);\n next.delete('messageId');\n setSearchParams(next, { replace: true });\n }, [pendingScrollMessageId, loadingLogs, messages, jumpToMessage, searchParams, setSearchParams]);\n\n return (\n <div className=\"flex flex-col h-full min-h-0\" data-testid=\"agent-manager-chat-pane\">\n {/* In-session search bar.\n Layout: [search controls (flex-1)] ... [Manage AI providers].\n The search input expands inside the LEFT cluster only, so the\n Manage button stays anchored on the right and never shifts. */}\n <div className=\"flex items-center gap-1 px-3 py-1 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <div className=\"flex items-center gap-1.5 min-w-0 flex-1\">\n <button\n type=\"button\"\n onClick={toggleSearch}\n className={`p-1 rounded transition-colors shrink-0 ${\n searchOpen\n ? 'bg-action-primary-bg/10 text-action-primary-text'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated'\n }`}\n title={tr(\n 'vibecontrols.agentManager.chatPane.searchInSession',\n 'Search in session (Ctrl+F)'\n )}\n aria-label={tr(\n 'vibecontrols.agentManager.chatPane.searchInSession',\n 'Search in session'\n )}\n >\n <Search className=\"size-3.5\" />\n </button>\n {searchOpen && (\n <div className=\"flex items-center gap-1.5 flex-1 min-w-0\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.chatPane.searchPlaceholder',\n 'Search in conversation...'\n )}\n className=\"flex-1 min-w-0 bg-transparent text-xs text-text-primary placeholder:text-text-tertiary focus:outline-none\"\n />\n {searchQuery && (\n <button\n type=\"button\"\n onClick={() => setSearchQuery('')}\n className=\"p-0.5 rounded hover:bg-bg-elevated transition-colors\"\n >\n <X className=\"size-3 text-text-tertiary\" />\n </button>\n )}\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => setBookmarksDrawerOpen(true)}\n className=\"shrink-0 p-1 rounded transition-colors text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated\"\n title={tr(\n 'vibecontrols.agentManager.chatPane.bookmarksTooltip',\n 'View bookmarked messages'\n )}\n aria-label={tr('vibecontrols.agentManager.chatPane.bookmarksLabel', 'Bookmarks')}\n data-testid=\"agent-manager-bookmarks-trigger\"\n >\n <Bookmark className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setInstallModalOpen(true)}\n className=\"shrink-0 inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-elevated px-2 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken hover:border-action-primary-bg/40\"\n title={tr(\n 'vibecontrols.agentManager.chatPane.manageProvidersTooltip',\n 'Install or remove AI providers (Claude, Codex, Gemini, OpenCode)'\n )}\n aria-label={tr(\n 'vibecontrols.agentManager.chatPane.manageProviders',\n 'Manage AI providers'\n )}\n data-testid=\"agent-manager-manage-providers\"\n >\n <PackagePlus className=\"size-3.5\" />\n <span className=\"hidden sm:inline\">\n {tr('vibecontrols.agentManager.chatPane.manageProviders', 'Manage AI providers')}\n </span>\n </button>\n </div>\n\n {/* Message list */}\n {loadingLogs ? (\n <div className=\"flex-1 flex items-center justify-center\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.agentManager.chatPane.loadingConversation',\n 'Loading conversation...'\n )}\n </p>\n </div>\n ) : (\n <AgentManagerMessageList\n messages={messages}\n isStreaming={isStreaming}\n onCancelStream={cancelStream}\n searchQuery={searchQuery}\n bookmarkedIds={bookmarkedIds}\n onToggleBookmark={handleToggleBookmark}\n flashMessageId={flashMessageId}\n />\n )}\n\n {/* Rich input area with controls */}\n <AgentManagerInputArea\n agentId={agentId}\n sessionId={sessionId}\n onSend={(text) => void sendMessage(text)}\n onCancel={cancelStream}\n agentTunnelUrl={activeAgent?.tunnelUrl ?? undefined}\n />\n\n {/* Per-session bookmarks drawer */}\n <AgentManagerBookmarksDrawer\n open={bookmarksDrawerOpen}\n onClose={() => setBookmarksDrawerOpen(false)}\n sessionId={sessionId}\n messages={messages}\n onJump={jumpToMessage}\n />\n\n {/* Header-triggered provider install/remove. Sits below the chat\n tree so it can render full-screen without disturbing layout. */}\n <PluginInstallModal\n open={installModalOpen}\n agentId={agentId}\n onClose={() => setInstallModalOpen(false)}\n />\n\n {/* SDK auth prompt: opens when the streaming hook detects a missing\n ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, so the user can save the\n credential inline instead of being told to go look elsewhere.\n The session's currently-selected SDK is forwarded so the picker\n can preselect the right provider. */}\n <SdkAuthPromptModal\n agentId={agentId}\n agentRef={agentRef}\n initialProviderId={sessionState?.sdk ?? undefined}\n />\n </div>\n );\n};\n\ninterface SdkAuthPromptModalProps {\n agentId: string;\n agentRef: { id: string; profile: string };\n initialProviderId?: string;\n}\n\nconst SdkAuthPromptModal: FC<SdkAuthPromptModalProps> = ({\n agentId,\n agentRef,\n initialProviderId,\n}) => {\n const sdkAuthPrompt = useAgentManagerStore((s) => s.sdkAuthPrompt);\n const setSdkAuthPrompt = useAgentManagerStore((s) => s.setSdkAuthPrompt);\n // Track whether the inner card has at least one primary credential\n // saved on the agent. The Continue button is gated on this so the user\n // can't dismiss the modal without actually persisting a key — but the\n // moment they save *any* of the either-or options it lights up.\n const [authSatisfied, setAuthSatisfied] = useState(false);\n const tr = useTr();\n\n // Reset the satisfied flag whenever the modal re-opens for a fresh\n // prompt (different agent / different session). Without this, dismissing\n // and re-opening would leave the flag stuck at its previous value.\n useEffect(() => {\n if (sdkAuthPrompt && sdkAuthPrompt.agentId === agentId) {\n setAuthSatisfied(false);\n }\n }, [sdkAuthPrompt, agentId]);\n\n if (!sdkAuthPrompt || sdkAuthPrompt.agentId !== agentId) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div\n className=\"absolute inset-0 bg-bg-overlay\"\n onClick={() => setSdkAuthPrompt(null)}\n aria-hidden\n />\n {/* Constrain height to the viewport and let the inner body scroll so the\n modal never escapes the screen no matter how many providers/fields\n render inside AIProviderCredentialsCard. The header + footer stay\n sticky so the close + Continue buttons are always reachable. */}\n <div className=\"relative w-full max-w-xl max-h-[85vh] flex flex-col rounded-lg border border-border-default bg-bg-surface shadow-xl overflow-hidden\">\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <h3 className=\"text-base font-semibold text-text-primary truncate pr-2\">\n {tr('vibecontrols.ai.sdkAuth.title', 'Configure AI provider credentials')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n aria-label={tr('vibecontrols.common.close', 'Close')}\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto px-4 py-3 space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.ai.sdkAuth.body',\n \"The agent doesn't have a credential configured for this provider. Save any one of the listed keys (you don't need all of them) and click Continue to retry.\"\n )}\n </p>\n <AIProviderCredentialsCard\n agent={agentRef}\n initialProviderId={initialProviderId}\n onProviderAuthSatisfiedChange={setAuthSatisfied}\n />\n </div>\n <div className=\"flex items-center justify-end gap-2 px-4 py-3 border-t border-border-default bg-bg-surface flex-shrink-0\">\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n className=\"px-3 py-1.5 rounded-md text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n {tr('vibecontrols.common.close', 'Close')}\n </button>\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n disabled={!authSatisfied}\n title={\n authSatisfied\n ? undefined\n : tr(\n 'vibecontrols.ai.sdkAuth.saveOneFirst',\n 'Save at least one of the listed credentials to continue'\n )\n }\n className=\"px-3 py-1.5 rounded-md text-sm font-medium bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {tr('vibecontrols.ai.sdkAuth.continue', 'Continue')}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -5,20 +5,20 @@ import { fetchProviders as r } from "../../services/aiApi.js";
|
|
|
5
5
|
import { useAgentManagerStore as i } from "../../store/agentManagerStore.js";
|
|
6
6
|
import { ModelSelector as a } from "./controls/ModelSelector.js";
|
|
7
7
|
import { SdkSelector as o } from "./controls/SdkSelector.js";
|
|
8
|
-
import { resolveProviderDefaultModel as
|
|
9
|
-
import { useVoiceMode as
|
|
10
|
-
import { schedulePrompt as
|
|
11
|
-
import { AutonomySelector as
|
|
12
|
-
import { McpServerSelector as
|
|
13
|
-
import { VoiceToggle as
|
|
14
|
-
import { FileAttachButton as
|
|
15
|
-
import { createDropHandlers as
|
|
16
|
-
import { ContextLevelToggle as
|
|
17
|
-
import { useCallback as
|
|
18
|
-
import { ArrowUp as
|
|
19
|
-
import { jsx as
|
|
8
|
+
import { resolveProviderDefaultModel as ee } from "./modelDefaults.js";
|
|
9
|
+
import { useVoiceMode as te } from "../../hooks/useVoiceMode.js";
|
|
10
|
+
import { schedulePrompt as ne } from "../../services/schedulerApi.js";
|
|
11
|
+
import { AutonomySelector as re } from "./controls/AutonomySelector.js";
|
|
12
|
+
import { McpServerSelector as ie } from "./controls/McpServerSelector.js";
|
|
13
|
+
import { VoiceToggle as ae } from "./controls/VoiceToggle.js";
|
|
14
|
+
import { FileAttachButton as oe } from "./controls/FileAttachButton.js";
|
|
15
|
+
import { createDropHandlers as se } from "./controls/createDropHandlers.js";
|
|
16
|
+
import { ContextLevelToggle as ce } from "./controls/ContextLevelToggle.js";
|
|
17
|
+
import { useCallback as s, useEffect as c, useMemo as l, useRef as le, useState as u } from "react";
|
|
18
|
+
import { ArrowUp as ue, ChevronDown as de, Clock as fe, Square as pe, X as me } from "lucide-react";
|
|
19
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
20
20
|
//#region src/components/agent-manager/AgentManagerInputArea.tsx
|
|
21
|
-
var
|
|
21
|
+
var p = [
|
|
22
22
|
{
|
|
23
23
|
command: "/new",
|
|
24
24
|
description: "Create new session"
|
|
@@ -56,7 +56,7 @@ var pe = [
|
|
|
56
56
|
command: "/help",
|
|
57
57
|
description: "Show available commands"
|
|
58
58
|
}
|
|
59
|
-
],
|
|
59
|
+
], m = [
|
|
60
60
|
"claude",
|
|
61
61
|
"codex",
|
|
62
62
|
"gemini",
|
|
@@ -73,19 +73,19 @@ var pe = [
|
|
|
73
73
|
"pi",
|
|
74
74
|
"aider",
|
|
75
75
|
"plandex"
|
|
76
|
-
],
|
|
77
|
-
function g({ agentId: g, sessionId: _, onSend: v, onCancel: y, mcpServers: he = [], agentTunnelUrl: b
|
|
78
|
-
let [
|
|
79
|
-
|
|
76
|
+
], h = ["sdk", "cli"];
|
|
77
|
+
function g({ agentId: g, sessionId: _, onSend: v, onCancel: y, mcpServers: he = [], agentTunnelUrl: b }) {
|
|
78
|
+
let [x, S] = u(""), [C, w] = u([]), [ge, T] = u(!1), [E, _e] = u(""), [D, O] = u(!1), [k, A] = u(!1), [j, M] = u(""), [ve, N] = u([]), P = e(), F = le(null), I = le(null);
|
|
79
|
+
c(() => {
|
|
80
80
|
F.current?.focus({ preventScroll: !0 });
|
|
81
81
|
}, []);
|
|
82
|
-
let L = i((e) => e.sessionStates[_]), R = i((e) => e.setSessionModel), z = i((e) => e.setSessionSdk), B = i((e) => e.setSessionMode),
|
|
82
|
+
let L = i((e) => e.sessionStates[_]), R = i((e) => e.setSessionModel), z = i((e) => e.setSessionSdk), B = i((e) => e.setSessionMode), ye = i((e) => e.setSessionPermissionMode), be = i((e) => e.toggleVoice), xe = i((e) => e.toggleThinking), Se = i((e) => e.setSessionContextLevel), Ce = i((e) => e.setSessionVibe), we = i((e) => e.setSessionRootPath), V = i((e) => e.openSession), H = i((e) => e.addMessage), { vibes: Te, agents: U } = t(), { active: W } = n(l(() => U.find((e) => e.id === g) ?? null, [U, g])?.id ?? null), G = l(() => ({
|
|
83
83
|
id: g,
|
|
84
84
|
profile: W
|
|
85
|
-
}), [g, W]), { isListening: K, transcript: q, startListening:
|
|
86
|
-
|
|
87
|
-
q && K &&
|
|
88
|
-
}, [q, K]),
|
|
85
|
+
}), [g, W]), { isListening: K, transcript: q, startListening: Ee, stopListening: De } = te(), J = L?.status === "streaming", Y = x.trim().length > 0 && !J;
|
|
86
|
+
c(() => {
|
|
87
|
+
q && K && S((e) => e + (e ? " " : "") + q);
|
|
88
|
+
}, [q, K]), c(() => {
|
|
89
89
|
let e = !1;
|
|
90
90
|
return r(G).then((t) => {
|
|
91
91
|
e || N(t);
|
|
@@ -94,54 +94,52 @@ function g({ agentId: g, sessionId: _, onSend: v, onCancel: y, mcpServers: he =
|
|
|
94
94
|
}), () => {
|
|
95
95
|
e = !0;
|
|
96
96
|
};
|
|
97
|
-
}, [G]),
|
|
98
|
-
|
|
99
|
-
}, [
|
|
100
|
-
let
|
|
101
|
-
|
|
97
|
+
}, [G]), c(() => {
|
|
98
|
+
x.startsWith("/") && !x.includes(" ") ? (T(!0), _e(x.slice(1))) : T(!1);
|
|
99
|
+
}, [x]);
|
|
100
|
+
let Oe = l(() => p.filter((e) => e.command.toLowerCase().includes(`/${E.toLowerCase()}`)), [E]);
|
|
101
|
+
c(() => {
|
|
102
102
|
let e = F.current;
|
|
103
103
|
e && (e.style.height = "auto", e.style.height = `${Math.min(e.scrollHeight, 200)}px`);
|
|
104
|
-
}, [
|
|
104
|
+
}, [x]), c(() => {
|
|
105
105
|
if (!D && !k) return;
|
|
106
106
|
let e = (e) => {
|
|
107
107
|
I.current && !I.current.contains(e.target) && (O(!1), A(!1));
|
|
108
108
|
};
|
|
109
109
|
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
|
|
110
110
|
}, [D, k]);
|
|
111
|
-
let X =
|
|
111
|
+
let X = s((e) => {
|
|
112
112
|
H(_, {
|
|
113
113
|
id: `sys-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
114
114
|
role: "system",
|
|
115
115
|
content: e,
|
|
116
116
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
117
117
|
});
|
|
118
|
-
}, [H, _]),
|
|
119
|
-
if (!(!
|
|
120
|
-
let e = await
|
|
118
|
+
}, [H, _]), ke = s(async () => {
|
|
119
|
+
if (!(!x.trim() || !j || !b || !g)) try {
|
|
120
|
+
let e = await ne({
|
|
121
121
|
sessionId: _,
|
|
122
122
|
agentTunnelUrl: b,
|
|
123
|
-
|
|
124
|
-
agentRef: W ? {
|
|
123
|
+
agentRef: {
|
|
125
124
|
agentId: g,
|
|
126
|
-
profile: W
|
|
127
|
-
}
|
|
128
|
-
prompt:
|
|
125
|
+
profile: W ?? "default"
|
|
126
|
+
},
|
|
127
|
+
prompt: x.trim(),
|
|
129
128
|
scheduledAt: new Date(j).toISOString()
|
|
130
129
|
});
|
|
131
|
-
X(`Prompt scheduled for ${new Date(e.scheduledAt).toLocaleString()} (Job: ${e.jobId.slice(0, 8)})`),
|
|
130
|
+
X(`Prompt scheduled for ${new Date(e.scheduledAt).toLocaleString()} (Job: ${e.jobId.slice(0, 8)})`), S(""), M(""), A(!1), O(!1);
|
|
132
131
|
} catch (e) {
|
|
133
132
|
X(`Failed to schedule: ${e instanceof Error ? e.message : "Unknown error"}`);
|
|
134
133
|
}
|
|
135
134
|
}, [
|
|
136
|
-
|
|
135
|
+
x,
|
|
137
136
|
j,
|
|
138
137
|
b,
|
|
139
|
-
x,
|
|
140
138
|
_,
|
|
141
139
|
g,
|
|
142
140
|
W,
|
|
143
141
|
X
|
|
144
|
-
]), Z =
|
|
142
|
+
]), Z = s((e) => {
|
|
145
143
|
let t = e.trim().split(/\s+/), n = t[0].toLowerCase(), r = t.slice(1).join(" ");
|
|
146
144
|
switch (n) {
|
|
147
145
|
case "/new":
|
|
@@ -154,13 +152,13 @@ function g({ agentId: g, sessionId: _, onSend: v, onCancel: y, mcpServers: he =
|
|
|
154
152
|
r ? (R(_, r), X(`Model switched to "${r}".`)) : X("Usage: /model <model-name>");
|
|
155
153
|
break;
|
|
156
154
|
case "/sdk":
|
|
157
|
-
if (r &&
|
|
155
|
+
if (r && m.includes(r)) {
|
|
158
156
|
let e = r;
|
|
159
|
-
z(_, e),
|
|
160
|
-
} else X(`Usage: /sdk <${
|
|
157
|
+
z(_, e), ee(G, e, L?.model ?? "default").then((e) => R(_, e)).catch(() => R(_, L?.model ?? "default")), X(`SDK switched to "${r}".`);
|
|
158
|
+
} else X(`Usage: /sdk <${m.join("|")}>`);
|
|
161
159
|
break;
|
|
162
160
|
case "/mode":
|
|
163
|
-
r &&
|
|
161
|
+
r && h.includes(r) ? (B(_, r), X(`Mode switched to "${r}".`)) : X(`Usage: /mode <${h.join("|")}>`);
|
|
164
162
|
break;
|
|
165
163
|
case "/export": {
|
|
166
164
|
let e = r === "md" ? "md" : "json", t = L?.messages ?? [], n = e === "json" ? JSON.stringify(t, null, 2) : t.map((e) => `**${e.role}** (${e.timestamp ?? ""}):\n${e.content ?? ""}`).join("\n\n---\n\n"), i = new Blob([n], { type: e === "json" ? "application/json" : "text/markdown" }), a = URL.createObjectURL(i), o = document.createElement("a");
|
|
@@ -171,7 +169,7 @@ function g({ agentId: g, sessionId: _, onSend: v, onCancel: y, mcpServers: he =
|
|
|
171
169
|
X("Conversation cleared.");
|
|
172
170
|
break;
|
|
173
171
|
case "/help":
|
|
174
|
-
X(`Available commands:\n${
|
|
172
|
+
X(`Available commands:\n${p.map((e) => ` ${e.command}${e.args ? " " + e.args : ""} - ${e.description}`).join("\n")}`);
|
|
175
173
|
break;
|
|
176
174
|
default: X(`Unknown command: ${n}. Type /help for available commands.`);
|
|
177
175
|
}
|
|
@@ -185,123 +183,123 @@ function g({ agentId: g, sessionId: _, onSend: v, onCancel: y, mcpServers: he =
|
|
|
185
183
|
B,
|
|
186
184
|
X,
|
|
187
185
|
G
|
|
188
|
-
]),
|
|
189
|
-
e.args ?
|
|
190
|
-
}, [Z]), Q =
|
|
186
|
+
]), Ae = s((e) => {
|
|
187
|
+
e.args ? S(`${e.command} `) : (Z(e.command), S("")), T(!1), F.current?.focus();
|
|
188
|
+
}, [Z]), Q = s(() => {
|
|
191
189
|
if (!Y) return;
|
|
192
|
-
let e =
|
|
190
|
+
let e = x.trim();
|
|
193
191
|
if (e.startsWith("/")) {
|
|
194
|
-
Z(e),
|
|
192
|
+
Z(e), S(""), w([]);
|
|
195
193
|
return;
|
|
196
194
|
}
|
|
197
|
-
v(e,
|
|
195
|
+
v(e, C.length > 0 ? C : void 0), S(""), w([]);
|
|
198
196
|
}, [
|
|
199
197
|
Y,
|
|
200
|
-
|
|
201
|
-
|
|
198
|
+
x,
|
|
199
|
+
C,
|
|
202
200
|
v,
|
|
203
201
|
Z
|
|
204
|
-
]),
|
|
202
|
+
]), je = s((e) => {
|
|
205
203
|
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), Q());
|
|
206
|
-
}, [Q]),
|
|
204
|
+
}, [Q]), Me = s(() => {
|
|
207
205
|
y?.();
|
|
208
|
-
}, [y]), $ =
|
|
209
|
-
|
|
210
|
-
}, []),
|
|
211
|
-
|
|
212
|
-
}, []),
|
|
213
|
-
return L ? /* @__PURE__ */
|
|
206
|
+
}, [y]), $ = s((e) => {
|
|
207
|
+
w((t) => [...t, ...e]);
|
|
208
|
+
}, []), Ne = s((e) => {
|
|
209
|
+
w((t) => t.filter((t, n) => n !== e));
|
|
210
|
+
}, []), Pe = se($);
|
|
211
|
+
return L ? /* @__PURE__ */ f("div", {
|
|
214
212
|
className: "relative z-30 border-t border-border-default bg-bg-surface",
|
|
215
|
-
...
|
|
213
|
+
...Pe,
|
|
216
214
|
children: [
|
|
217
|
-
ge &&
|
|
215
|
+
ge && Oe.length > 0 && /* @__PURE__ */ d("div", {
|
|
218
216
|
className: "absolute bottom-full left-0 right-0 mb-1 mx-3 bg-bg-elevated border border-border-default rounded-lg shadow-lg max-h-48 overflow-y-auto z-50",
|
|
219
|
-
children:
|
|
217
|
+
children: Oe.map((e) => /* @__PURE__ */ f("button", {
|
|
220
218
|
type: "button",
|
|
221
|
-
onClick: () =>
|
|
219
|
+
onClick: () => Ae(e),
|
|
222
220
|
className: "flex items-center gap-2 w-full px-3 py-2 text-left hover:bg-bg-sunken transition-colors",
|
|
223
221
|
children: [
|
|
224
|
-
/* @__PURE__ */
|
|
222
|
+
/* @__PURE__ */ d("span", {
|
|
225
223
|
className: "font-mono text-xs text-text-primary",
|
|
226
224
|
children: e.command
|
|
227
225
|
}),
|
|
228
|
-
e.args && /* @__PURE__ */
|
|
226
|
+
e.args && /* @__PURE__ */ d("span", {
|
|
229
227
|
className: "text-text-tertiary text-xs",
|
|
230
228
|
children: e.args
|
|
231
229
|
}),
|
|
232
|
-
/* @__PURE__ */
|
|
230
|
+
/* @__PURE__ */ d("span", {
|
|
233
231
|
className: "text-text-secondary text-xs ml-auto",
|
|
234
232
|
children: e.description
|
|
235
233
|
})
|
|
236
234
|
]
|
|
237
235
|
}, e.command))
|
|
238
236
|
}),
|
|
239
|
-
|
|
237
|
+
C.length > 0 && /* @__PURE__ */ d("div", {
|
|
240
238
|
className: "flex items-center gap-2 px-3 pt-2 overflow-x-auto",
|
|
241
|
-
children:
|
|
239
|
+
children: C.map((e, t) => /* @__PURE__ */ f("div", {
|
|
242
240
|
className: "flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary",
|
|
243
|
-
children: [/* @__PURE__ */
|
|
241
|
+
children: [/* @__PURE__ */ d("span", {
|
|
244
242
|
className: "truncate max-w-[120px]",
|
|
245
243
|
children: e.name
|
|
246
|
-
}), /* @__PURE__ */
|
|
244
|
+
}), /* @__PURE__ */ d("button", {
|
|
247
245
|
type: "button",
|
|
248
|
-
onClick: () =>
|
|
246
|
+
onClick: () => Ne(t),
|
|
249
247
|
className: "p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0",
|
|
250
|
-
children: /* @__PURE__ */
|
|
248
|
+
children: /* @__PURE__ */ d(me, { className: "size-3" })
|
|
251
249
|
})]
|
|
252
250
|
}, `${e.name}-${t}`))
|
|
253
251
|
}),
|
|
254
|
-
/* @__PURE__ */
|
|
252
|
+
/* @__PURE__ */ f("div", {
|
|
255
253
|
className: "flex flex-wrap items-center gap-1 px-3 pt-2 pb-1 overflow-x-auto",
|
|
256
254
|
children: [
|
|
257
|
-
/* @__PURE__ */
|
|
255
|
+
/* @__PURE__ */ d(o, {
|
|
258
256
|
sdk: L.sdk,
|
|
259
257
|
mode: L.mode,
|
|
260
|
-
providers:
|
|
258
|
+
providers: ve,
|
|
261
259
|
onSdkChange: (e) => {
|
|
262
|
-
z(_, e),
|
|
260
|
+
z(_, e), ee(G, e, L.model ?? "default").then((e) => R(_, e)).catch(() => R(_, L.model ?? "default"));
|
|
263
261
|
},
|
|
264
262
|
onModeChange: (e) => B(_, e)
|
|
265
263
|
}),
|
|
266
|
-
/* @__PURE__ */
|
|
264
|
+
/* @__PURE__ */ d(a, {
|
|
267
265
|
value: L.model,
|
|
268
266
|
onChange: (e) => R(_, e),
|
|
269
267
|
provider: L.sdk,
|
|
270
268
|
agentId: g
|
|
271
269
|
}),
|
|
272
|
-
/* @__PURE__ */
|
|
270
|
+
/* @__PURE__ */ d(re, {
|
|
273
271
|
value: L.permissionMode,
|
|
274
272
|
mode: L.mode,
|
|
275
|
-
onChange: (e) =>
|
|
273
|
+
onChange: (e) => ye(_, e)
|
|
276
274
|
}),
|
|
277
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ d(ie, {
|
|
278
276
|
selected: L.mcpServers,
|
|
279
277
|
available: he,
|
|
280
278
|
onChange: () => {}
|
|
281
279
|
}),
|
|
282
|
-
/* @__PURE__ */
|
|
280
|
+
/* @__PURE__ */ d(ce, {
|
|
283
281
|
agentId: "",
|
|
284
282
|
sessionId: _,
|
|
285
283
|
contextLevel: L.contextLevel,
|
|
286
284
|
rootPath: L.rootPath,
|
|
287
285
|
onChange: (e, t, n) => {
|
|
288
|
-
|
|
286
|
+
Se(_, e), we(_, t ?? null), Ce(_, n ?? null, t ?? null);
|
|
289
287
|
},
|
|
290
|
-
vibes:
|
|
288
|
+
vibes: Te.map((e) => ({
|
|
291
289
|
id: e.id,
|
|
292
290
|
name: e.name,
|
|
293
291
|
path: e.path
|
|
294
292
|
}))
|
|
295
293
|
}),
|
|
296
|
-
/* @__PURE__ */
|
|
297
|
-
/* @__PURE__ */
|
|
294
|
+
/* @__PURE__ */ d("div", { className: "flex-1" }),
|
|
295
|
+
/* @__PURE__ */ d("button", {
|
|
298
296
|
type: "button",
|
|
299
|
-
onClick: () =>
|
|
297
|
+
onClick: () => xe(_),
|
|
300
298
|
className: `p-1.5 rounded text-xs font-medium transition-colors ${L.showThinking ? "bg-action-primary-bg/10 text-action-primary-text" : "text-text-tertiary hover:text-text-secondary"}`,
|
|
301
299
|
title: L.showThinking ? P("vibecontrols.agentManager.inputArea.hideThinking", "Hide thinking") : P("vibecontrols.agentManager.inputArea.showThinking", "Show thinking"),
|
|
302
300
|
children: "Think"
|
|
303
301
|
}),
|
|
304
|
-
/* @__PURE__ */
|
|
302
|
+
/* @__PURE__ */ f("button", {
|
|
305
303
|
type: "button",
|
|
306
304
|
onClick: () => {
|
|
307
305
|
let e = window.prompt("Context history limit (messages sent with each prompt):", String(L.contextHistoryLimit));
|
|
@@ -323,83 +321,83 @@ function g({ agentId: g, sessionId: _, onSend: v, onCancel: y, mcpServers: he =
|
|
|
323
321
|
title: `Context history: last ${L.contextHistoryLimit} messages sent with each prompt`,
|
|
324
322
|
children: ["H:", L.contextHistoryLimit]
|
|
325
323
|
}),
|
|
326
|
-
/* @__PURE__ */
|
|
324
|
+
/* @__PURE__ */ d(ae, {
|
|
327
325
|
enabled: L.voiceEnabled,
|
|
328
326
|
onToggle: () => {
|
|
329
|
-
|
|
327
|
+
be(_), L.voiceEnabled ? De() : Ee();
|
|
330
328
|
},
|
|
331
329
|
isListening: K
|
|
332
330
|
}),
|
|
333
|
-
/* @__PURE__ */
|
|
331
|
+
/* @__PURE__ */ d(oe, { onFileSelect: $ })
|
|
334
332
|
]
|
|
335
333
|
}),
|
|
336
|
-
/* @__PURE__ */
|
|
334
|
+
/* @__PURE__ */ f("div", {
|
|
337
335
|
className: "flex items-end gap-2 px-3 pb-3 pt-1",
|
|
338
|
-
children: [/* @__PURE__ */
|
|
336
|
+
children: [/* @__PURE__ */ d("textarea", {
|
|
339
337
|
"aria-label": "control",
|
|
340
338
|
ref: F,
|
|
341
|
-
value:
|
|
342
|
-
onChange: (e) =>
|
|
343
|
-
onKeyDown:
|
|
339
|
+
value: x,
|
|
340
|
+
onChange: (e) => S(e.target.value),
|
|
341
|
+
onKeyDown: je,
|
|
344
342
|
placeholder: P("vibecontrols.agentManager.inputArea.placeholder", "Type a message or / for commands... (Enter to send)"),
|
|
345
343
|
rows: 1,
|
|
346
344
|
className: "flex-1 resize-none rounded-lg border border-border-default bg-bg-primary px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors",
|
|
347
345
|
disabled: J
|
|
348
|
-
}), J ? /* @__PURE__ */
|
|
346
|
+
}), J ? /* @__PURE__ */ d("button", {
|
|
349
347
|
type: "button",
|
|
350
|
-
onClick:
|
|
348
|
+
onClick: Me,
|
|
351
349
|
className: "flex-shrink-0 p-2 rounded-lg bg-status-error-bg text-status-error-text hover:opacity-90 transition-opacity",
|
|
352
350
|
title: P("vibecontrols.agentManager.inputArea.cancel", "Cancel"),
|
|
353
|
-
children: /* @__PURE__ */
|
|
354
|
-
}) : /* @__PURE__ */
|
|
351
|
+
children: /* @__PURE__ */ d(pe, { className: "size-4" })
|
|
352
|
+
}) : /* @__PURE__ */ f("div", {
|
|
355
353
|
className: "flex items-end flex-shrink-0 relative",
|
|
356
354
|
ref: I,
|
|
357
355
|
children: [
|
|
358
|
-
/* @__PURE__ */
|
|
356
|
+
/* @__PURE__ */ d("button", {
|
|
359
357
|
type: "button",
|
|
360
358
|
onClick: Q,
|
|
361
359
|
disabled: !Y,
|
|
362
360
|
className: "p-2 rounded-l-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
|
|
363
361
|
title: P("vibecontrols.agentManager.inputArea.send", "Send (Enter)"),
|
|
364
|
-
children: /* @__PURE__ */
|
|
362
|
+
children: /* @__PURE__ */ d(ue, { className: "size-4" })
|
|
365
363
|
}),
|
|
366
|
-
/* @__PURE__ */
|
|
364
|
+
/* @__PURE__ */ d("button", {
|
|
367
365
|
type: "button",
|
|
368
366
|
onClick: () => O(!D),
|
|
369
367
|
disabled: !Y,
|
|
370
368
|
className: "ml-1 p-2 rounded-r-lg border-l border-action-primary-text/20 bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
|
|
371
369
|
title: P("vibecontrols.agentManager.inputArea.scheduleSend", "Schedule send"),
|
|
372
|
-
children: /* @__PURE__ */
|
|
370
|
+
children: /* @__PURE__ */ d(de, { className: "size-3" })
|
|
373
371
|
}),
|
|
374
|
-
D && /* @__PURE__ */
|
|
372
|
+
D && /* @__PURE__ */ d("div", {
|
|
375
373
|
className: "absolute bottom-full right-0 mb-1 w-56 bg-bg-surface border border-border-default rounded-md shadow-lg py-1 z-50",
|
|
376
|
-
children: k ? /* @__PURE__ */
|
|
374
|
+
children: k ? /* @__PURE__ */ f("div", {
|
|
377
375
|
className: "px-3 py-2 space-y-2",
|
|
378
376
|
children: [
|
|
379
|
-
/* @__PURE__ */
|
|
377
|
+
/* @__PURE__ */ d("label", {
|
|
380
378
|
className: "block text-[11px] font-medium text-text-secondary",
|
|
381
379
|
children: P("vibecontrols.agentManager.inputArea.sendAt", "Send at:")
|
|
382
380
|
}),
|
|
383
|
-
/* @__PURE__ */
|
|
381
|
+
/* @__PURE__ */ d("input", {
|
|
384
382
|
"aria-label": "control",
|
|
385
383
|
type: "datetime-local",
|
|
386
384
|
value: j,
|
|
387
385
|
onChange: (e) => M(e.target.value),
|
|
388
386
|
className: "w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-primary text-text-primary focus:outline-none focus:border-border-strong"
|
|
389
387
|
}),
|
|
390
|
-
/* @__PURE__ */
|
|
388
|
+
/* @__PURE__ */ d("button", {
|
|
391
389
|
type: "button",
|
|
392
|
-
onClick: () => void
|
|
393
|
-
disabled: !j || !b || !
|
|
390
|
+
onClick: () => void ke(),
|
|
391
|
+
disabled: !j || !b || !g,
|
|
394
392
|
className: "w-full px-2 py-1.5 text-xs font-medium rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
|
|
395
393
|
children: P("vibecontrols.agentManager.inputArea.schedule", "Schedule")
|
|
396
394
|
})
|
|
397
395
|
]
|
|
398
|
-
}) : /* @__PURE__ */
|
|
396
|
+
}) : /* @__PURE__ */ f("button", {
|
|
399
397
|
type: "button",
|
|
400
398
|
onClick: () => A(!0),
|
|
401
399
|
className: "flex items-center gap-2 w-full px-3 py-2 text-left text-xs text-text-primary hover:bg-bg-sunken transition-colors",
|
|
402
|
-
children: [/* @__PURE__ */
|
|
400
|
+
children: [/* @__PURE__ */ d(fe, { className: "size-3.5 text-text-secondary" }), P("vibecontrols.agentManager.inputArea.scheduleSendEllipsis", "Schedule Send...")]
|
|
403
401
|
})
|
|
404
402
|
})
|
|
405
403
|
]
|