1- import { useQuery } from "@tanstack/react-query" ;
2- import { settingsAtom } from "@yaakapp-internal/models" ;
1+ import { useQuery , useQueryClient } from "@tanstack/react-query" ;
32import { platform } from "@yaakapp-internal/platform" ;
4- import { Heading , Icon , InlineCode , VStack } from "@yaakapp-internal/ui " ;
5- import type { AppMetaData } from "@yaakapp-internal/rpc-schema " ;
6- import { useAtomValue } from "jotai " ;
3+ import type { AgentSetupStatus , AppMetaData } from "@yaakapp-internal/rpc-schema " ;
4+ import { Banner , Heading , Icon , InlineCode , VStack } from "@yaakapp-internal/ui " ;
5+ import { useEffect } from "react " ;
76import { useKeyValue } from "../../hooks/useKeyValue" ;
8- import { appInfo } from "../../lib/appInfo " ;
7+ import { usePluginInfos } from "../../hooks/usePluginInfo " ;
98import {
109 AGENT_CLIENTS ,
1110 type AgentClient ,
12- type AgentSetup ,
13- appSetup ,
1411 cliSetup ,
12+ skillInstallCommand ,
1513} from "../../lib/agentSetup" ;
14+ import { appInfo } from "../../lib/appInfo" ;
1615import { rpc } from "../../lib/rpc" ;
17- import { CopyIconButton } from "../CopyIconButton" ;
18- import { Button } from "../core/Button" ;
19- import { Editor } from "../core/Editor/LazyEditor" ;
20- import { IconButton } from "../core/IconButton" ;
16+ import { Link } from "../core/Link" ;
2117import { SegmentedControl } from "../core/SegmentedControl" ;
2218import {
23- ModelSettingRowBoolean ,
24- SettingRow ,
25- SettingValue ,
19+ SettingCommand ,
20+ SettingSnippet ,
2621 SettingsList ,
2722 SettingsSection ,
2823} from "../core/SettingRow" ;
24+ import { DeprecatedPluginBanner } from "./SettingsPlugins" ;
2925
30- const MCP_URL = "http://127.0.0.1:64343/mcp" ;
3126const CLI_INSTALL_COMMAND = "npm install -g @yaakapp/cli" ;
32- const SKILL_INSTALL_COMMAND = "yaak agent install " ;
27+ const MCP_SERVER_PLUGIN = "@ yaak/mcp-server " ;
3328
3429export function SettingsAgents ( ) {
35- const settings = useAtomValue ( settingsAtom ) ;
36- const { value : token } = useKeyValue < string | null > ( {
37- namespace : "no_sync" ,
38- key : "mcp_server_token" ,
39- fallback : null ,
40- } ) ;
30+ const queryClient = useQueryClient ( ) ;
4131 const { value : storedClient , set : setClient } = useKeyValue < AgentClient > ( {
4232 key : "agents_setup_client" ,
4333 fallback : "claude_code" ,
4434 } ) ;
4535 const client = AGENT_CLIENTS . find ( ( c ) => c . value === storedClient ) ?. value ?? "claude_code" ;
36+ const clientLabel = AGENT_CLIENTS . find ( ( c ) => c . value === client ) ?. label ?? "your agent" ;
4637 const cliVersion = useQuery ( {
4738 queryKey : [ "cli_version" ] ,
4839 queryFn : async ( ) => ( await rpc < AppMetaData > ( "cmd_metadata" ) ) . cliVersion ,
4940 initialData : appInfo . cliVersion ,
5041 } ) ;
42+ const setupStatus = useQuery ( {
43+ queryKey : [ "agent_setup_status" , client ] ,
44+ queryFn : ( ) => rpc < AgentSetupStatus > ( "cmd_agent_setup_status" , { agent : client } ) ,
45+ } ) ;
46+ const mcpServerPlugin = usePluginInfos ( ) . find ( ( { info } ) => info . name === MCP_SERVER_PLUGIN ) ;
47+
48+ useEffect ( ( ) => {
49+ return platform . window . onFocusChanged ( ( focused ) => {
50+ if ( ! focused ) return ;
51+ void queryClient . invalidateQueries ( { queryKey : [ "cli_version" ] } ) ;
52+ void queryClient . invalidateQueries ( { queryKey : [ "agent_setup_status" ] } ) ;
53+ } ) ;
54+ } , [ queryClient ] ) ;
55+
56+ const cliInstalled = cliVersion . data != null ;
57+ const cli = cliSetup ( client ) ;
5158
5259 return (
5360 < VStack space = { 1.5 } className = "mb-4" >
5461 < div className = "mb-3" >
5562 < Heading > Agents</ Heading >
5663 < p className = "text-text-subtle" >
57- Connect AI coding agents like Claude Code and Cursor to Yaak, so they can read, edit, and
58- send your requests.
64+ Connect AI coding agents like Claude Code and Cursor to Yaak.
5965 </ p >
6066 </ div >
61- < SettingsList className = "space-y-8" >
62- < SettingsSection
63- title = "Yaak CLI"
64- description = "Lets agents use Yaak from the command line, even with the app closed."
65- >
66- < SettingRow
67- title = "Status"
68- description = {
69- cliVersion . data == null
70- ? "The Yaak CLI is not installed."
71- : `Yaak CLI ${ cliVersion . data } is installed.`
72- }
73- controlClassName = "gap-2"
74- >
75- < IconButton
76- size = "sm"
77- icon = "refresh"
78- title = "Check again"
79- spin = { cliVersion . isFetching }
80- onClick = { ( ) => cliVersion . refetch ( ) }
81- />
82- { cliVersion . data == null && (
83- < Button
84- variant = "border"
85- color = "secondary"
86- size = "sm"
87- onClick = { ( ) => platform . openUrl ( "https://yaak.app/docs/cli" ) }
88- rightSlot = { < Icon icon = "external_link" /> }
89- >
90- Install CLI
91- </ Button >
92- ) }
93- </ SettingRow >
94- { cliVersion . data == null ? (
95- < SettingRow title = "Install" description = "Install it with npm." >
96- < SettingValue value = { CLI_INSTALL_COMMAND } />
97- </ SettingRow >
98- ) : (
99- < SettingRow
100- title = "Agent skill"
101- description = {
102- < >
103- Teach Claude Code, Cursor, Codex, and opencode to drive the{ " " }
104- < InlineCode > yaak</ InlineCode > command, wherever they're installed.
105- </ >
106- }
107- >
108- < SettingValue value = { SKILL_INSTALL_COMMAND } />
109- </ SettingRow >
110- ) }
111- </ SettingsSection >
112-
113- < SettingsSection
114- title = "MCP server in the app"
115- description = "For agents that connect over HTTP, or to act on the workspaces open in Yaak."
116- >
117- < ModelSettingRowBoolean
118- model = { settings }
119- modelKey = "mcpServerEnabled"
120- title = "Enable MCP server"
121- description = {
122- < >
123- Serve Yaak's tools at < InlineCode > { MCP_URL } </ InlineCode > while Yaak is open.
124- </ >
125- }
126- />
127- { settings . mcpServerEnabled && token != null && (
128- < SettingRow
129- title = "Token"
130- description = "Agents send this as a bearer token."
131- controlClassName = "min-w-0 max-w-[min(24rem,40vw)] gap-2"
132- >
133- < SettingValue value = { token } />
134- </ SettingRow >
135- ) }
136- </ SettingsSection >
137-
138- < SettingsSection
139- title = "Connect an agent"
140- description = "Pick your agent or editor to see how to add Yaak's MCP tools to it."
141- >
142- < div className = "py-4 border-b border-border-subtle" >
67+ < SettingsList >
68+ < SettingsSection title = { null } >
69+ < div className = "pb-4 border-b border-border-subtle" >
14370 < SegmentedControl
14471 name = "agents_setup_client"
14572 label = "Agent"
@@ -149,59 +76,65 @@ export function SettingsAgents() {
14976 options = { AGENT_CLIENTS }
15077 />
15178 </ div >
152- < SetupRow
153- title = "Through the Yaak CLI"
79+ { cliInstalled ? (
80+ < div className = "flex items-center gap-2 py-3 text-sm text-text-subtle border-b border-border-subtle" >
81+ < Icon icon = "check" size = "sm" color = "success" />
82+ < span >
83+ Yaak CLI < span className = "text-text" > { cliVersion . data } </ span > is installed.
84+ </ span >
85+ </ div >
86+ ) : (
87+ < div className = "py-4 border-b border-border-subtle" >
88+ < Banner color = "info" >
89+ < div className = "flex items-center gap-2 text text-text" >
90+ < Icon icon = "square_terminal" color = "info" />
91+ Install the Yaak CLI first
92+ </ div >
93+ < p className = "mt-1 text-sm text-text-subtle" >
94+ Agents launch it to reach Yaak, even with the app closed.
95+ </ p >
96+ < SettingSnippet className = "mt-3" language = "shell" snippet = { CLI_INSTALL_COMMAND } />
97+ < div className = "mt-3 mb-1 flex items-center gap-4 text-sm" >
98+ < Link href = "https://yaak.app/docs/cli" > Docs</ Link >
99+ < span className = "text-text-subtlest" >
100+ Checks again when you come back to Yaak.
101+ </ span >
102+ </ div >
103+ </ Banner >
104+ </ div >
105+ ) }
106+ { mcpServerPlugin != null && (
107+ < div className = "py-4 border-b border-border-subtle" >
108+ < DeprecatedPluginBanner
109+ plugin = { mcpServerPlugin . plugin }
110+ name = { mcpServerPlugin . info . displayName }
111+ >
112+ The two steps below replace it. Uninstall it once your agent is connected.
113+ </ DeprecatedPluginBanner >
114+ </ div >
115+ ) }
116+ < SettingCommand
117+ title = "Add the MCP server"
118+ description = { cli . where }
119+ snippet = { cli . snippet }
120+ language = { cli . language }
121+ disabled = { ! cliInstalled }
122+ done = { setupStatus . data ?. mcpServer ? "Added" : null }
123+ />
124+ < SettingCommand
125+ title = "Install the skill"
154126 description = {
155- cliVersion . data == null
156- ? "Recommended. Install the Yaak CLI above first."
157- : `Recommended. ${ cliSetup ( client ) . where } `
127+ < >
128+ Lets { clientLabel } run the < InlineCode > yaak </ InlineCode > command directly.
129+ </ >
158130 }
159- setup = { cliSetup ( client ) }
131+ snippet = { skillInstallCommand ( client ) }
132+ language = "shell"
133+ disabled = { ! cliInstalled }
134+ done = { setupStatus . data ?. skill ? "Installed" : null }
160135 />
161- { settings . mcpServerEnabled && token != null ? (
162- < SetupRow
163- title = "Through the app"
164- description = { appSetup ( client , MCP_URL , token ) . where }
165- setup = { appSetup ( client , MCP_URL , token ) }
166- />
167- ) : (
168- < SettingRow
169- title = "Through the app"
170- description = "Turn on the MCP server above to connect this way."
171- >
172- < span />
173- </ SettingRow >
174- ) }
175136 </ SettingsSection >
176137 </ SettingsList >
177138 </ VStack >
178139 ) ;
179140}
180-
181- function SetupRow ( {
182- title,
183- description,
184- setup,
185- } : {
186- title : string ;
187- description : string ;
188- setup : AgentSetup ;
189- } ) {
190- return (
191- < div className = "py-4 border-b border-border-subtle" >
192- < div className = "text text-text" > { title } </ div >
193- < div className = "mt-1 text-sm text-text-subtle" > { description } </ div >
194- < Editor
195- readOnly
196- hideGutter
197- wrapLines
198- heightMode = "auto"
199- stateKey = { null }
200- language = { setup . language }
201- defaultValue = { setup . snippet }
202- className = "mt-3 border border-border-subtle rounded-md px-2"
203- actions = { < CopyIconButton size = "sm" variant = "border" text = { setup . snippet } title = "Copy setup" /> }
204- />
205- </ div >
206- ) ;
207- }
0 commit comments