@@ -70,16 +70,17 @@ function AgentConnectPrompt() {
7070 const isMobileDevice = typeof window !== 'undefined' && window . innerWidth <= 768
7171 const [ url , setUrl ] = useState ( isMobileDevice ? '' : 'ws://localhost:18789' )
7272 const [ password , setPassword ] = useState ( '' )
73+ const [ accessToken , setAccessToken ] = useState ( '' )
7374
7475 const isConnecting = status === 'connecting' || status === 'authenticating'
7576
7677 const handleConnect = ( ) => {
7778 if ( ! url . trim ( ) ) return
78- connect ( url . trim ( ) , password )
79+ connect ( url . trim ( ) , accessToken . trim ( ) || password )
7980 }
8081
8182 return (
82- < div className = "flex flex-1 flex-col items-center justify-center text-center px-6" >
83+ < div className = "flex flex-1 flex-col items-center justify-center px-6 text-center " >
8384 { /* Animated connection icon */ }
8485 < div className = "relative mb-6" >
8586 < div
@@ -102,21 +103,44 @@ function AgentConnectPrompt() {
102103
103104 { isConnecting ? (
104105 < >
105- < h3 className = "text-[17px] font-semibold text-[var(--text-primary)] mb-1" > Connecting…</ h3 >
106- < p className = "text-[13px] text-[var(--text-tertiary)]" > Looking for your gateway</ p >
106+ < h3 className = "mb-1 text-[19px] font-semibold tracking-[-0.02em] text-[var(--text-primary)]" >
107+ Connecting…
108+ </ h3 >
109+ < p className = "text-[14px] leading-[1.65] text-[var(--text-tertiary)]" >
110+ Looking for your gateway
111+ </ p >
107112 </ >
108113 ) : (
109114 < >
110- < h3 className = "text-[17px ] font-semibold text-[var(--text-primary)] mb-1 " >
115+ < h3 className = "mb-1 text-[20px ] font-semibold tracking-[-0.025em] text-[var(--text-primary)]" >
111116 Connect to Gateway
112117 </ h3 >
113- < p className = "text-[13px] text-[var(--text-tertiary)] leading-relaxed mb-6 max-w-[280px ]" >
118+ < p className = "mb-4 max-w-[360px] text-[14px] leading-[1.7] text-[var(--text-tertiary)]" >
114119 { isMobileDevice
115- ? 'Enter your gateway address to start chatting .'
116- : 'Make sure OpenClaw is running on this machine .' }
120+ ? 'Enter your gateway address, then use a token or password if your gateway requires auth .'
121+ : 'Paste your gateway URL here. If auth is enabled, the token/password fields live directly below .' }
117122 </ p >
118123
119- < div className = "w-full max-w-[340px] space-y-3" >
124+ < div className = "mb-4 w-full max-w-[360px] rounded-2xl border border-[color-mix(in_srgb,var(--brand)_18%,var(--border))] bg-[color-mix(in_srgb,var(--brand)_4%,transparent)] px-4 py-3.5 text-left shadow-[0_18px_40px_-28px_color-mix(in_srgb,var(--brand)_26%,transparent)]" >
125+ < div className = "flex items-start gap-2" >
126+ < div className = "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-[color-mix(in_srgb,var(--brand)_12%,transparent)] text-[var(--brand)]" >
127+ < Icon icon = "lucide:key-round" width = { 14 } height = { 14 } />
128+ </ div >
129+ < div className = "min-w-0" >
130+ < p className = "text-[13px] font-semibold tracking-[-0.01em] text-[var(--text-primary)]" >
131+ Gateway credentials
132+ </ p >
133+ < p className = "mt-1 text-[12px] leading-[1.65] text-[var(--text-secondary)]" >
134+ Use < span className = "font-medium text-[var(--text-primary)]" > Access token</ span > { ' ' }
135+ first when you have one. The fallback{ ' ' }
136+ < span className = "font-medium text-[var(--text-primary)]" > Password</ span > field is
137+ also masked.
138+ </ p >
139+ </ div >
140+ </ div >
141+ </ div >
142+
143+ < div className = "w-full max-w-[360px] space-y-3" >
120144 { /* URL input */ }
121145 < div className = "relative" >
122146 < Icon
@@ -133,10 +157,35 @@ function AgentConnectPrompt() {
133157 if ( e . key === 'Enter' ) handleConnect ( )
134158 } }
135159 placeholder = { isMobileDevice ? 'wss://your-gateway.ts.net' : 'ws://localhost:18789' }
136- className = "w-full pl-10 pr-3 py-3.5 rounded-xl bg-[var(--bg)] border border-[var(--border)] text-[14px] font-mono text-[var(--text-primary)] placeholder:text-[var(--text-disabled)] outline-none focus:border-[var(--brand)] focus:ring-1 focus:ring-[color-mix(in_srgb,var(--brand)_30%,transparent)] transition-all"
160+ className = "w-full pl-10 pr-3 py-3.5 rounded-xl bg-[var(--bg)] border border-[var(--border)] text-[14px] font-mono text-[var(--text-primary)] placeholder:text-[var(--text-disabled)] outline-none transition-all gateway-connect-url-input"
161+ autoCapitalize = "off"
162+ autoCorrect = "off"
163+ spellCheck = { false }
164+ />
165+ </ div >
166+
167+ { /* Access token input */ }
168+ < div className = "relative" >
169+ < Icon
170+ icon = "lucide:key-round"
171+ width = { 15 }
172+ height = { 15 }
173+ className = "absolute left-3.5 top-1/2 -translate-y-1/2 text-[var(--text-disabled)]"
174+ />
175+ < input
176+ type = "password"
177+ value = { accessToken }
178+ onChange = { ( e ) => setAccessToken ( e . target . value ) }
179+ onKeyDown = { ( e ) => {
180+ if ( e . key === 'Enter' ) handleConnect ( )
181+ } }
182+ placeholder = "Access token (recommended)"
183+ className = "gateway-credential-input w-full pl-10 pr-3 py-3.5 rounded-xl bg-[var(--bg)] border border-[var(--border)] text-[14px] font-mono text-[var(--text-primary)] placeholder:text-[var(--text-disabled)] outline-none transition-all"
137184 autoCapitalize = "off"
138185 autoCorrect = "off"
139186 spellCheck = { false }
187+ autoComplete = "current-password"
188+ data-1p-ignore
140189 />
141190 </ div >
142191
@@ -155,16 +204,28 @@ function AgentConnectPrompt() {
155204 onKeyDown = { ( e ) => {
156205 if ( e . key === 'Enter' ) handleConnect ( )
157206 } }
158- placeholder = "Password (optional)"
159- className = "w-full pl-10 pr-3 py-3.5 rounded-xl bg-[var(--bg)] border border-[var(--border)] text-[14px] font-mono text-[var(--text-primary)] placeholder:text-[var(--text-disabled)] outline-none focus:border-[var(--brand)] focus:ring-1 focus:ring-[color-mix(in_srgb,var(--brand)_30%,transparent)] transition-all"
207+ placeholder = "Password (fallback)"
208+ className = "gateway-credential-input w-full pl-10 pr-3 py-3.5 rounded-xl bg-[var(--bg)] border border-[var(--border)] text-[14px] font-mono text-[var(--text-primary)] placeholder:text-[var(--text-disabled)] outline-none transition-all"
209+ autoComplete = "current-password"
210+ data-1p-ignore
160211 />
161212 </ div >
162213
214+ < div className = "rounded-xl border border-[var(--border)] bg-[color-mix(in_srgb,var(--bg-elevated)_82%,transparent)] px-3.5 py-2.5" >
215+ < p className = "text-[12px] font-medium tracking-[-0.01em] text-[var(--text-secondary)]" >
216+ Where do I put the gateway secret?
217+ </ p >
218+ < p className = "mt-1 text-[11.5px] leading-[1.65] text-[var(--text-disabled)]" >
219+ Right here: paste a gateway access token into the token field, or use the password
220+ field if your setup still uses password auth. Both stay masked in the UI.
221+ </ p >
222+ </ div >
223+
163224 { /* Connect button */ }
164225 < button
165226 onClick = { handleConnect }
166227 disabled = { ! url . trim ( ) }
167- className = "w-full py-3.5 rounded-xl text-[14px ] font-semibold transition-all cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"
228+ className = "w-full rounded-xl py-3.5 text-[14.5px ] font-semibold tracking-[-0.01em] transition-all cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"
168229 style = { {
169230 backgroundColor : url . trim ( ) ? 'var(--brand)' : 'var(--bg-subtle)' ,
170231 color : url . trim ( ) ? 'var(--brand-contrast, #fff)' : 'var(--text-disabled)' ,
@@ -904,6 +965,7 @@ export function AgentPanel({ onClose }: { onClose?: () => void } = {}) {
904965 return labels
905966 } , [ contextAttachments , imageAttachments ] )
906967
968+ // Follow-up seam: fallback local agent routing (Cursor Agent / Claude Code CLI) should plug in above sendStructuredGatewayMessage, while keeping local repo/docs as the default context source before any remote fetch.
907969 const buildSilentContext = useCallback ( ( ) => {
908970 const context = buildContext ( )
909971 const attachCtx = buildAttachmentContext ( )
@@ -2485,7 +2547,7 @@ export function AgentPanel({ onClose }: { onClose?: () => void } = {}) {
24852547 onClose = { onClose }
24862548 />
24872549 { messages . length > 0 && (
2488- < div className = "flex items-center justify-between border-b border-[var(--border)] bg-[var(--bg-elevated)] px-2.5 py-0 .5 shrink-0 " >
2550+ < div className = "flex shrink-0 items-center justify-between border-b border-[var(--border)] bg-[color-mix(in_srgb, var(--bg-elevated)_92%,transparent) ] px-3 py-1 .5 backdrop-blur-sm " >
24892551 < div className = "flex min-w-0 items-center gap-1.5" >
24902552 { /* Font size controls */ }
24912553 < div className = "inline-flex items-center gap-0.5" >
@@ -2496,7 +2558,7 @@ export function AgentPanel({ onClose }: { onClose?: () => void } = {}) {
24962558 >
24972559 < Icon icon = "lucide:minus" width = { 12 } height = { 12 } />
24982560 </ button >
2499- < span className = "w-7 select-none text-center text-[10px ] font-mono tabular-nums text-[var(--text-disabled)]" >
2561+ < span className = "w-7 select-none text-center text-[11px ] font-mono tabular-nums text-[var(--text-disabled)]" >
25002562 { chatFontSize }
25012563 </ span >
25022564 < button
@@ -2516,7 +2578,7 @@ export function AgentPanel({ onClose }: { onClose?: () => void } = {}) {
25162578 < button
25172579 key = { f . id }
25182580 onClick = { ( ) => setChatFontFamily ( f . id ) }
2519- className = { `whitespace-nowrap rounded px-2 py-0.5 text-[10px ] font-medium transition-colors cursor-pointer ${
2581+ className = { `whitespace-nowrap rounded-md px-2.5 py-1 text-[11px ] font-medium transition-colors cursor-pointer ${
25202582 chatFontFamily === f . id
25212583 ? 'text-[var(--brand)] bg-[color-mix(in_srgb,var(--brand)_10%,transparent)]'
25222584 : 'text-[var(--text-disabled)] hover:text-[var(--text-tertiary)]'
0 commit comments