@geminilight/mindos 0.5.69 → 0.5.70

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.
@@ -214,34 +214,36 @@ export default function AgentDetailContent({ agentKey }: { agentKey: string }) {
214
214
  </Link>
215
215
 
216
216
  {/* ═══════════ AGENT PROFILE (consolidated header) ═══════════ */}
217
- <section className="rounded-lg border border-border bg-card p-4 space-y-3">
218
- <div className="flex items-center gap-3">
217
+ <section className="rounded-xl border border-border bg-gradient-to-b from-card to-card/80 overflow-hidden">
218
+ <div className="flex items-center gap-4 p-5">
219
219
  <AgentAvatar name={agent.name} status={status} size="md" />
220
- <div className="min-w-0">
220
+ <div className="min-w-0 flex-1">
221
221
  <h1 className="text-xl font-semibold tracking-tight font-display text-foreground">{agent.name}</h1>
222
- <div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 mt-0.5">
223
- <span className={`text-2xs font-medium px-1.5 py-0.5 rounded ${
222
+ <div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 mt-1">
223
+ <span className={`text-2xs font-medium px-2 py-0.5 rounded-full ${
224
224
  status === 'connected' ? 'bg-success/10 text-success'
225
225
  : status === 'detected' ? 'bg-[var(--amber-subtle)] text-[var(--amber)]'
226
226
  : 'bg-muted text-muted-foreground'
227
227
  }`}>{status}</span>
228
- <span className="text-2xs text-muted-foreground font-mono">{agent.transport ?? agent.preferredTransport}</span>
229
- <span className="text-2xs text-muted-foreground">·</span>
230
- <span className="text-2xs text-muted-foreground">{agent.skillMode ?? a.na}</span>
228
+ <span className="text-2xs text-muted-foreground/60 font-mono">{agent.transport ?? agent.preferredTransport}</span>
229
+ <span className="text-2xs text-muted-foreground/30" aria-hidden="true">·</span>
230
+ <span className="text-2xs text-muted-foreground/60">{agent.skillMode ?? a.na}</span>
231
231
  </div>
232
232
  </div>
233
233
  </div>
234
- <div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted-foreground pt-2 border-t border-border">
235
- <span>{a.detail.format}: <span className="text-foreground">{agent.format}</span></span>
236
- <span>{a.detail.lastActivityAt}: <span className="text-foreground tabular-nums">{agent.runtimeLastActivityAt ?? a.na}</span></span>
237
- <span>{configuredMcpServers.length} MCP · {nativeInstalledSkills.length} skills</span>
234
+ <div className="flex flex-wrap items-center gap-x-5 gap-y-1 text-xs text-muted-foreground/70 px-5 py-3 border-t border-border/50 bg-muted/[0.03]">
235
+ <span>{a.detail.format}: <span className="text-foreground/80 font-medium">{agent.format}</span></span>
236
+ <span>{a.detail.lastActivityAt}: <span className="text-foreground/80 tabular-nums font-medium">{agent.runtimeLastActivityAt ?? a.na}</span></span>
237
+ <span className="font-medium text-foreground/80 tabular-nums">{configuredMcpServers.length} MCP · {nativeInstalledSkills.length} skills</span>
238
238
  </div>
239
239
  </section>
240
240
 
241
241
  {/* ═══════════ MCP MANAGEMENT ═══════════ */}
242
- <section className="rounded-lg border border-border bg-card p-4 space-y-3">
243
- <h2 className="text-sm font-medium text-foreground flex items-center gap-1.5">
244
- <Server size={14} className="text-muted-foreground" />
242
+ <section className="rounded-xl border border-border bg-card p-5 space-y-4">
243
+ <h2 className="text-sm font-semibold text-foreground flex items-center gap-2">
244
+ <div className="w-6 h-6 rounded-md bg-muted/50 flex items-center justify-center">
245
+ <Server size={13} className="text-muted-foreground/70" />
246
+ </div>
245
247
  {a.detail.mcpManagement}
246
248
  </h2>
247
249
 
@@ -253,10 +255,10 @@ export default function AgentDetailContent({ agentKey }: { agentKey: string }) {
253
255
  </div>
254
256
 
255
257
  {/* Configured MCP servers with management */}
256
- <div className="rounded-lg border border-border bg-background p-4 space-y-2">
258
+ <div className="rounded-xl border border-border/60 bg-background/50 p-4 space-y-2.5">
257
259
  <div className="flex items-center justify-between">
258
260
  <p className="text-xs font-semibold text-foreground">{a.detail.configuredMcpServers}</p>
259
- <span className="text-2xs text-muted-foreground tabular-nums">{a.detail.configuredMcpServersCount(configuredMcpServers.length)}</span>
261
+ <span className="text-2xs text-muted-foreground/60 tabular-nums">{a.detail.configuredMcpServersCount(configuredMcpServers.length)}</span>
260
262
  </div>
261
263
 
262
264
  {mcpHint && (
@@ -272,8 +274,10 @@ export default function AgentDetailContent({ agentKey }: { agentKey: string }) {
272
274
  {configuredMcpServers.map((name) => {
273
275
  const sharedWith = (crossAgentMcpMap.get(name) ?? []).filter((n) => n !== agent.name);
274
276
  return (
275
- <div key={name} className="flex items-center gap-2 rounded-md border border-border/60 px-2.5 py-2 group/mcp hover:border-border hover:bg-muted/20 transition-all duration-100">
276
- <Server size={11} className="text-[var(--amber)] shrink-0" />
277
+ <div key={name} className="flex items-center gap-2.5 rounded-lg border border-border/40 bg-muted/[0.02] px-3 py-2.5 group/mcp hover:border-border/60 hover:bg-muted/[0.06] hover:shadow-[0_1px_3px_rgba(0,0,0,0.02)] transition-all duration-150">
278
+ <div className="w-5 h-5 rounded-md bg-[var(--amber)]/[0.08] flex items-center justify-center shrink-0">
279
+ <Server size={10} className="text-[var(--amber)]" />
280
+ </div>
277
281
  <span className="text-xs font-medium text-foreground flex-1 min-w-0 truncate">{name}</span>
278
282
  {sharedWith.length > 0 && (
279
283
  <div className="flex items-center gap-1">
@@ -325,13 +329,18 @@ export default function AgentDetailContent({ agentKey }: { agentKey: string }) {
325
329
  </section>
326
330
 
327
331
  {/* ═══════════ SKILL ASSIGNMENTS ═══════════ */}
328
- <section className="rounded-lg border border-border bg-card p-4 space-y-3">
332
+ <section className="rounded-xl border border-border bg-card p-5 space-y-4">
329
333
  <div className="flex items-center justify-between">
330
- <h2 className="text-sm font-medium text-foreground">{a.detail.skillAssignments}</h2>
331
- <div className="flex items-center gap-3 text-2xs text-muted-foreground tabular-nums">
332
- <span>MindOS {skillSummary.total}</span>
333
- <span>{a.detail.skillsEnabled.split(' ')[0]} {skillSummary.enabled}</span>
334
- <span>{a.detail.nativeInstalledSkills} {nativeInstalledSkills.length}</span>
334
+ <h2 className="text-sm font-semibold text-foreground flex items-center gap-2">
335
+ <div className="w-6 h-6 rounded-md bg-muted/50 flex items-center justify-center">
336
+ <Zap size={13} className="text-muted-foreground/70" />
337
+ </div>
338
+ {a.detail.skillAssignments}
339
+ </h2>
340
+ <div className="flex items-center gap-2 text-2xs text-muted-foreground/60 tabular-nums">
341
+ <span className="px-1.5 py-0.5 rounded bg-muted/40">MindOS {skillSummary.total}</span>
342
+ <span className="px-1.5 py-0.5 rounded bg-emerald-500/[0.06] text-emerald-600 dark:text-emerald-400">{a.detail.skillsEnabled.split(' ')[0]} {skillSummary.enabled}</span>
343
+ <span className="px-1.5 py-0.5 rounded bg-muted/40">{a.detail.nativeInstalledSkills} {nativeInstalledSkills.length}</span>
335
344
  </div>
336
345
  </div>
337
346
 
@@ -504,9 +513,9 @@ export default function AgentDetailContent({ agentKey }: { agentKey: string }) {
504
513
 
505
514
  function DetailLine({ label, value }: { label: string; value: string }) {
506
515
  return (
507
- <div className="rounded-md border border-border px-3 py-2">
508
- <p className="text-2xs text-muted-foreground mb-1">{label}</p>
509
- <p className="text-sm text-foreground truncate">{value}</p>
516
+ <div className="rounded-lg border border-border/60 bg-muted/[0.02] px-3.5 py-2.5 hover:bg-muted/[0.06] transition-colors duration-100">
517
+ <p className="text-2xs text-muted-foreground/60 mb-1 uppercase tracking-wider">{label}</p>
518
+ <p className="text-sm text-foreground font-medium truncate">{value}</p>
510
519
  </div>
511
520
  );
512
521
  }
@@ -142,8 +142,10 @@ export default function AgentsMcpSection({
142
142
  {/* Header */}
143
143
  <div className="flex items-center justify-between gap-2">
144
144
  <div className="flex items-center gap-2.5">
145
- <h2 className="text-sm font-medium text-foreground flex items-center gap-2">
146
- <Server size={15} className="text-muted-foreground" aria-hidden="true" />
145
+ <h2 className="text-sm font-semibold text-foreground flex items-center gap-2">
146
+ <div className="w-6 h-6 rounded-md bg-muted/50 flex items-center justify-center">
147
+ <Server size={13} className="text-muted-foreground/70" aria-hidden="true" />
148
+ </div>
147
149
  {copy.title}
148
150
  </h2>
149
151
  <button
@@ -164,8 +166,8 @@ export default function AgentsMcpSection({
164
166
  </div>
165
167
 
166
168
  {/* Compact status strip + risk alerts */}
167
- <div className="rounded-lg border border-border bg-card p-3">
168
- <div className="flex flex-wrap items-center gap-x-4 gap-y-2 text-xs">
169
+ <div className="rounded-xl border border-border/60 bg-gradient-to-r from-card to-card/80 p-3.5">
170
+ <div className="flex flex-wrap items-center gap-x-5 gap-y-2 text-xs">
169
171
  <StatusDot tone="ok" label={copy.filters.connected} count={buckets.connected.length} />
170
172
  <StatusDot tone="warn" label={copy.filters.detected} count={buckets.detected.length} />
171
173
  {buckets.notFound.length > 0 && (
@@ -294,7 +296,7 @@ function ByAgentView({
294
296
  const mcpServers = agent.configuredMcpServers ?? [];
295
297
  const nativeSkillCount = (agent.installedSkillNames ?? []).length;
296
298
  return (
297
- <div key={agent.key} className="rounded-lg border border-border bg-card group hover:border-border/60 hover:shadow-sm transition-all duration-150">
299
+ <div key={agent.key} className={`rounded-xl border bg-card group hover:shadow-[0_2px_8px_rgba(0,0,0,0.04)] transition-all duration-150 ${status === 'connected' ? 'border-l-2 border-l-[var(--success)] border-border' : status === 'detected' ? 'border-l-2 border-l-[var(--amber)] border-border' : 'border-border'}`}>
298
300
  {/* Card header with avatar */}
299
301
  <div className="flex items-center gap-3 p-3">
300
302
  <AgentAvatar name={agent.name} status={status} />
@@ -344,8 +346,8 @@ function ByAgentView({
344
346
  {mcpServers.length > 0 && (
345
347
  <div className="flex flex-wrap gap-1 px-3 pb-3 ml-12">
346
348
  {mcpServers.map((name) => (
347
- <span key={name} className="inline-flex items-center gap-1 rounded-full bg-muted/60 px-2 py-0.5 text-2xs text-muted-foreground">
348
- <Server size={9} className="text-[var(--amber)] shrink-0" aria-hidden="true" />
349
+ <span key={name} className="inline-flex items-center gap-1.5 rounded-full bg-muted/40 border border-border/30 px-2.5 py-0.5 text-2xs text-muted-foreground hover:bg-muted/60 transition-colors duration-100">
350
+ <span className="w-1 h-1 rounded-full bg-[var(--amber)]" aria-hidden="true" />
349
351
  {name}
350
352
  </span>
351
353
  ))}
@@ -450,12 +452,14 @@ function ByServerView({
450
452
  const notFoundCount = agentDetails.length - connectedCount - detectedCount + orphanNames.length;
451
453
 
452
454
  return (
453
- <div key={srv.serverName} className="rounded-lg border border-border bg-card p-4 hover:border-border/60 hover:shadow-sm transition-all duration-150">
455
+ <div key={srv.serverName} className="rounded-xl border border-border bg-card p-4 hover:shadow-[0_2px_8px_rgba(0,0,0,0.04)] transition-all duration-200">
454
456
  {/* Server header */}
455
- <div className="flex items-center justify-between gap-2 mb-2">
456
- <div className="flex items-center gap-2 min-w-0">
457
- <Server size={14} className="text-[var(--amber)] shrink-0" aria-hidden="true" />
458
- <span className="text-sm font-medium text-foreground truncate">{srv.serverName}</span>
457
+ <div className="flex items-center justify-between gap-2 mb-3">
458
+ <div className="flex items-center gap-2.5 min-w-0">
459
+ <div className="w-7 h-7 rounded-lg bg-[var(--amber)]/[0.08] flex items-center justify-center shrink-0">
460
+ <Server size={13} className="text-[var(--amber)]" aria-hidden="true" />
461
+ </div>
462
+ <span className="text-sm font-semibold text-foreground truncate">{srv.serverName}</span>
459
463
  </div>
460
464
  <div className="flex items-center gap-1.5 shrink-0">
461
465
  {canManage && agentDetails.length > 0 && (
@@ -91,10 +91,10 @@ export default function AgentsOverviewSection({
91
91
  <div className="space-y-5">
92
92
  {/* ═══════════ HERO STATS BAR ═══════════ */}
93
93
  <section
94
- className="rounded-xl border border-border bg-card overflow-hidden"
94
+ className="rounded-xl border border-border bg-gradient-to-b from-card to-card/80 overflow-hidden"
95
95
  aria-label={pulseCopy.connected}
96
96
  >
97
- <div className="flex divide-x divide-border [&>*]:flex-1">
97
+ <div className="flex divide-x divide-border/50 [&>*]:flex-1">
98
98
  <StatCell
99
99
  icon={<Zap size={14} aria-hidden="true" />}
100
100
  label={pulseCopy.connected}
@@ -231,13 +231,13 @@ export default function AgentsOverviewSection({
231
231
  </section>
232
232
  ) : (
233
233
  <section
234
- className="rounded-xl border border-dashed border-border bg-card/50 p-10 text-center"
234
+ className="rounded-xl border border-dashed border-border/60 bg-gradient-to-b from-card/80 to-card/40 p-12 text-center"
235
235
  aria-label={copy.usagePulse}
236
236
  >
237
- <div className="w-12 h-12 rounded-full bg-muted/60 flex items-center justify-center mx-auto mb-3">
238
- <Cable size={20} className="text-muted-foreground" aria-hidden="true" />
237
+ <div className="w-14 h-14 rounded-2xl bg-muted/40 flex items-center justify-center mx-auto mb-4">
238
+ <Cable size={22} className="text-muted-foreground/50" aria-hidden="true" />
239
239
  </div>
240
- <p className="text-sm text-muted-foreground leading-relaxed max-w-xs mx-auto">
240
+ <p className="text-sm text-muted-foreground/70 leading-relaxed max-w-xs mx-auto">
241
241
  {copy.nextActionHint as string}
242
242
  </p>
243
243
  </section>
@@ -269,27 +269,33 @@ function StatCell({
269
269
  : 'text-muted-foreground';
270
270
  const iconColor =
271
271
  tone === 'ok'
272
- ? 'text-muted-foreground'
272
+ ? 'text-emerald-500/70'
273
273
  : tone === 'warn'
274
274
  ? 'text-amber-500/70'
275
- : 'text-muted-foreground/50';
275
+ : 'text-muted-foreground/40';
276
+ const hoverBg =
277
+ tone === 'ok'
278
+ ? 'hover:bg-emerald-500/[0.04]'
279
+ : tone === 'warn'
280
+ ? 'hover:bg-amber-500/[0.04]'
281
+ : 'hover:bg-muted/20';
276
282
 
277
283
  return (
278
284
  <div
279
- className="px-3 py-3.5 text-center hover:bg-muted/20 transition-colors duration-100 group/stat"
285
+ className={`px-3 py-4 text-center ${hoverBg} transition-colors duration-150 group/stat`}
280
286
  role="group"
281
287
  aria-label={`${label}: ${value}${total !== undefined ? `/${total}` : ''}`}
282
288
  >
283
- <div className={`flex items-center justify-center gap-1.5 mb-1.5 ${iconColor} group-hover/stat:text-foreground transition-colors duration-100`}>
289
+ <div className={`flex items-center justify-center gap-1.5 mb-2 ${iconColor} group-hover/stat:opacity-100 transition-all duration-150`}>
284
290
  {icon}
285
- <span className="text-2xs text-muted-foreground truncate">{label}</span>
286
291
  </div>
287
- <p className={`text-lg font-semibold tabular-nums leading-none ${textColor}`}>
292
+ <p className={`text-xl font-semibold tabular-nums leading-none mb-1.5 ${textColor}`}>
288
293
  {value}
289
294
  {total !== undefined && (
290
295
  <span className="text-xs font-normal text-muted-foreground ml-0.5">/{total}</span>
291
296
  )}
292
297
  </p>
298
+ <span className="text-2xs text-muted-foreground/70 truncate block">{label}</span>
293
299
  </div>
294
300
  );
295
301
  }
@@ -315,19 +321,19 @@ function QuickNavCard({
315
321
  <Link
316
322
  href={href}
317
323
  className="group rounded-xl border border-border bg-card p-4 flex items-start gap-3.5
318
- hover:border-[var(--amber)]/30 hover:bg-muted/20 hover:shadow-sm
324
+ hover:border-[var(--amber)]/30 hover:shadow-[0_2px_12px_rgba(0,0,0,0.04)]
319
325
  active:scale-[0.99]
320
- transition-all duration-150
326
+ transition-all duration-200
321
327
  focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
322
328
  >
323
- <div className="shrink-0 w-10 h-10 rounded-lg bg-muted/60 flex items-center justify-center text-muted-foreground group-hover:text-[var(--amber)] group-hover:bg-[var(--amber-dim)] transition-colors duration-150">
329
+ <div className="shrink-0 w-10 h-10 rounded-xl bg-muted/50 flex items-center justify-center text-muted-foreground/70 group-hover:text-[var(--amber)] group-hover:bg-[var(--amber)]/[0.08] transition-all duration-200">
324
330
  {icon}
325
331
  </div>
326
332
  <div className="flex-1 min-w-0">
327
333
  <div className="flex items-center gap-2 mb-1">
328
334
  <span className="text-sm font-semibold text-foreground">{title}</span>
329
335
  <span
330
- className={`text-2xs px-1.5 py-0.5 rounded font-medium select-none ${
336
+ className={`text-2xs px-2 py-0.5 rounded-full font-medium select-none ${
331
337
  statTone === 'ok'
332
338
  ? 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400'
333
339
  : 'bg-amber-500/10 text-amber-600 dark:text-amber-400'
@@ -336,11 +342,11 @@ function QuickNavCard({
336
342
  {stat}
337
343
  </span>
338
344
  </div>
339
- <p className="text-xs text-muted-foreground leading-relaxed line-clamp-2">{description}</p>
345
+ <p className="text-xs text-muted-foreground/70 leading-relaxed line-clamp-2">{description}</p>
340
346
  </div>
341
347
  <ArrowRight
342
348
  size={14}
343
- className="shrink-0 mt-1.5 text-muted-foreground/30 group-hover:text-[var(--amber)] group-hover:translate-x-0.5 transition-all duration-150"
349
+ className="shrink-0 mt-1.5 text-muted-foreground/20 group-hover:text-[var(--amber)] group-hover:translate-x-0.5 transition-all duration-200"
344
350
  aria-hidden="true"
345
351
  />
346
352
  </Link>
@@ -372,14 +378,22 @@ function AgentCard({
372
378
  ? 'bg-amber-500/10 text-amber-600 dark:text-amber-400'
373
379
  : 'bg-zinc-500/10 text-zinc-500';
374
380
 
381
+ const accentBorder =
382
+ status === 'connected'
383
+ ? 'border-l-[var(--success)]'
384
+ : status === 'detected'
385
+ ? 'border-l-[var(--amber)]'
386
+ : '';
387
+
375
388
  return (
376
389
  <Link
377
390
  href={`/agents/${encodeURIComponent(agent.key)}`}
378
- className="group rounded-xl border border-border bg-card p-3.5
379
- hover:border-[var(--amber)]/30 hover:shadow-sm
391
+ className={`group rounded-xl border bg-card p-3.5
392
+ ${accentBorder ? `border-l-2 ${accentBorder} border-border` : 'border-border'}
393
+ hover:border-[var(--amber)]/30 hover:shadow-[0_2px_8px_rgba(0,0,0,0.04)]
380
394
  active:scale-[0.98]
381
395
  transition-all duration-150 animate-in
382
- focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
396
+ focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring`}
383
397
  style={{ animationDelay: `${Math.min(index * 30, 300)}ms` }}
384
398
  >
385
399
  {/* Top row: avatar + name + status */}
@@ -390,26 +404,22 @@ function AgentCard({
390
404
  {agent.name}
391
405
  </span>
392
406
  {agent.transport && status === 'connected' && (
393
- <span className="text-2xs text-muted-foreground font-mono">{agent.transport}</span>
407
+ <span className="text-2xs text-muted-foreground/60 font-mono">{agent.transport}</span>
394
408
  )}
395
409
  </div>
396
- <span className={`text-2xs px-1.5 py-0.5 rounded font-medium shrink-0 select-none ${statusColor}`}>
410
+ <span className={`text-2xs px-2 py-0.5 rounded-full font-medium shrink-0 select-none ${statusColor}`}>
397
411
  {statusLabel}
398
412
  </span>
399
413
  </div>
400
414
 
401
415
  {/* Metrics row */}
402
- <div className="flex items-center gap-0 pt-2.5 border-t border-border/50">
416
+ <div className="flex items-center gap-1 pt-2.5 border-t border-border/40">
403
417
  <MetricChip icon={<Server size={11} aria-hidden="true" />} value={mcpCount} label={copy.colMcp as string} />
404
- <span className="text-border mx-2 select-none" aria-hidden="true">·</span>
405
418
  <MetricChip icon={<Zap size={11} aria-hidden="true" />} value={skillCount} label={copy.colSkills as string} />
406
419
  {agent.skillMode && (
407
- <>
408
- <span className="text-border mx-2 select-none" aria-hidden="true">·</span>
409
- <span className="text-2xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground truncate select-none">
410
- {agent.skillMode}
411
- </span>
412
- </>
420
+ <span className="text-2xs px-1.5 py-0.5 rounded-md bg-muted/50 text-muted-foreground/70 truncate select-none">
421
+ {agent.skillMode}
422
+ </span>
413
423
  )}
414
424
  <span className="flex-1 min-w-[4px]" />
415
425
  {hasRuntime && (
@@ -438,9 +448,13 @@ function MetricChip({
438
448
  label: string;
439
449
  }) {
440
450
  return (
441
- <span className="inline-flex items-center gap-1" title={label} aria-label={`${label}: ${value}`}>
442
- <span className="text-muted-foreground/60">{icon}</span>
443
- <span className={`tabular-nums text-xs ${value > 0 ? 'text-foreground font-medium' : 'text-muted-foreground/50'}`}>
451
+ <span
452
+ className={`inline-flex items-center gap-1 px-1.5 py-0.5 rounded-md ${value > 0 ? 'bg-muted/40' : ''}`}
453
+ title={label}
454
+ aria-label={`${label}: ${value}`}
455
+ >
456
+ <span className={value > 0 ? 'text-muted-foreground' : 'text-muted-foreground/30'}>{icon}</span>
457
+ <span className={`tabular-nums text-xs ${value > 0 ? 'text-foreground font-medium' : 'text-muted-foreground/40'}`}>
444
458
  {value}
445
459
  </span>
446
460
  </span>
@@ -11,8 +11,10 @@ export function PillButton({ active, label, onClick }: { active: boolean; label:
11
11
  type="button"
12
12
  onClick={onClick}
13
13
  aria-pressed={active}
14
- className={`px-2.5 min-h-[28px] rounded text-xs cursor-pointer transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${
15
- active ? 'bg-[var(--amber-dim)] text-[var(--amber)] font-medium' : 'text-muted-foreground hover:text-foreground hover:bg-muted'
14
+ className={`relative px-2.5 min-h-[28px] rounded text-xs cursor-pointer transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${
15
+ active
16
+ ? 'bg-[var(--amber-dim)] text-[var(--amber)] font-medium shadow-[0_1px_2px_rgba(200,135,58,0.08)]'
17
+ : 'text-muted-foreground hover:text-foreground hover:bg-muted/60'
16
18
  }`}
17
19
  >
18
20
  {label}
@@ -21,11 +23,13 @@ export function PillButton({ active, label, onClick }: { active: boolean; label:
21
23
  }
22
24
 
23
25
  export function StatusDot({ tone, label, count }: { tone: 'ok' | 'warn' | 'neutral'; label: string; count: number }) {
24
- const dotCls = tone === 'ok' ? 'bg-[var(--success)]' : tone === 'warn' ? 'bg-[var(--amber)]' : 'bg-muted-foreground';
26
+ const dotCls = tone === 'ok' ? 'bg-[var(--success)]' : tone === 'warn' ? 'bg-[var(--amber)]' : 'bg-muted-foreground/60';
27
+ const countCls = tone === 'ok' ? 'text-foreground' : tone === 'warn' ? 'text-[var(--amber)]' : 'text-muted-foreground';
25
28
  return (
26
29
  <span className="inline-flex items-center gap-1.5 text-muted-foreground">
27
- <span className={`w-1.5 h-1.5 rounded-full ${dotCls}`} aria-hidden="true" />
28
- {label} <span className="tabular-nums text-foreground">{count}</span>
30
+ <span className={`w-2 h-2 rounded-full ${dotCls} ${tone === 'ok' ? 'ring-2 ring-[var(--success)]/20' : ''}`} aria-hidden="true" />
31
+ <span className="text-xs">{label}</span>
32
+ <span className={`tabular-nums font-medium ${countCls}`}>{count}</span>
29
33
  </span>
30
34
  );
31
35
  }
@@ -44,23 +48,23 @@ export function SearchInput({
44
48
  icon: React.ComponentType<{ size?: number; className?: string }>;
45
49
  }) {
46
50
  return (
47
- <label className="relative block">
48
- <Icon size={14} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none" />
51
+ <label className="relative block group/search">
52
+ <Icon size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground/60 group-focus-within/search:text-[var(--amber)] pointer-events-none transition-colors duration-150" />
49
53
  <input
50
54
  value={value}
51
55
  onChange={(e) => onChange(e.target.value)}
52
56
  placeholder={placeholder}
53
57
  aria-label={ariaLabel}
54
- className="w-full h-9 rounded-md border border-border bg-background pl-8 pr-8 text-sm text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors duration-150"
58
+ className="w-full h-9 rounded-lg border border-border bg-background pl-9 pr-8 text-sm text-foreground placeholder:text-muted-foreground/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--amber)]/30 focus-visible:border-[var(--amber)]/40 transition-all duration-150"
55
59
  />
56
60
  {value.length > 0 && (
57
61
  <button
58
62
  type="button"
59
63
  onClick={() => onChange('')}
60
64
  aria-label="Clear search"
61
- className="absolute right-2 top-1/2 -translate-y-1/2 p-0.5 rounded-sm text-muted-foreground hover:text-foreground cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors duration-150"
65
+ className="absolute right-2.5 top-1/2 -translate-y-1/2 p-0.5 rounded-full text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors duration-150"
62
66
  >
63
- <X size={14} />
67
+ <X size={13} />
64
68
  </button>
65
69
  )}
66
70
  </label>
@@ -112,20 +116,35 @@ export function BulkMessage({ message }: { message: string | null }) {
112
116
  );
113
117
  }
114
118
 
115
- export function EmptyState({ message, className }: { message: string; className?: string }) {
119
+ export function EmptyState({ message, icon, className }: { message: string; icon?: React.ReactNode; className?: string }) {
116
120
  return (
117
- <div className={`rounded-lg border border-dashed border-border bg-card/50 p-8 text-center ${className ?? ''}`}>
118
- <p className="text-sm text-muted-foreground">{message}</p>
121
+ <div className={`rounded-xl border border-dashed border-border/60 bg-gradient-to-b from-card/80 to-card/40 p-10 text-center ${className ?? ''}`}>
122
+ {icon && (
123
+ <div className="w-10 h-10 rounded-full bg-muted/50 flex items-center justify-center mx-auto mb-3 text-muted-foreground/40">
124
+ {icon}
125
+ </div>
126
+ )}
127
+ <p className="text-sm text-muted-foreground/70 leading-relaxed max-w-xs mx-auto">{message}</p>
119
128
  </div>
120
129
  );
121
130
  }
122
131
 
123
132
  /* ────────── Agent Avatar ────────── */
124
133
 
125
- const AVATAR_COLORS = [
126
- 'bg-blue-500', 'bg-emerald-500', 'bg-violet-500', 'bg-rose-500',
127
- 'bg-amber-600', 'bg-cyan-600', 'bg-indigo-500', 'bg-pink-500',
128
- 'bg-teal-500', 'bg-orange-500', 'bg-sky-500', 'bg-fuchsia-500',
134
+ /** Soft pastel palette: [bg, border, text] — watercolor aesthetic */
135
+ const AVATAR_PALETTES: [string, string, string][] = [
136
+ ['bg-rose-100/70', 'border-rose-300/50', 'text-rose-600/80'],
137
+ ['bg-violet-100/70', 'border-violet-300/50', 'text-violet-600/80'],
138
+ ['bg-emerald-100/70', 'border-emerald-300/50', 'text-emerald-600/80'],
139
+ ['bg-sky-100/70', 'border-sky-300/50', 'text-sky-600/80'],
140
+ ['bg-amber-100/70', 'border-amber-300/50', 'text-amber-700/80'],
141
+ ['bg-teal-100/70', 'border-teal-300/50', 'text-teal-600/80'],
142
+ ['bg-pink-100/70', 'border-pink-300/50', 'text-pink-600/80'],
143
+ ['bg-indigo-100/70', 'border-indigo-300/50', 'text-indigo-600/80'],
144
+ ['bg-lime-100/70', 'border-lime-300/50', 'text-lime-700/80'],
145
+ ['bg-fuchsia-100/70', 'border-fuchsia-300/50', 'text-fuchsia-600/80'],
146
+ ['bg-cyan-100/70', 'border-cyan-300/50', 'text-cyan-600/80'],
147
+ ['bg-orange-100/70', 'border-orange-300/50', 'text-orange-600/80'],
129
148
  ];
130
149
 
131
150
  function hashName(str: string): number {
@@ -153,13 +172,13 @@ export function AgentAvatar({
153
172
  onRemove?: () => void;
154
173
  href?: string;
155
174
  }) {
156
- const color = AVATAR_COLORS[hashName(name) % AVATAR_COLORS.length];
175
+ const [bg, border, text] = AVATAR_PALETTES[hashName(name) % AVATAR_PALETTES.length];
157
176
  const sizeClasses = size === 'sm' ? 'w-7 h-7 text-[10px]' : 'w-9 h-9 text-xs';
158
177
  const dotColor = status === 'connected' ? 'bg-[var(--success)]' : status === 'detected' ? 'bg-[var(--amber)]' : 'bg-muted-foreground';
159
178
 
160
179
  return (
161
180
  <div className="relative group/avatar" title={name}>
162
- <div className={`${sizeClasses} ${color} rounded-full flex items-center justify-center text-white font-medium select-none shadow-sm`}>
181
+ <div className={`${sizeClasses} ${bg} ${border} ${text} border rounded-full flex items-center justify-center font-semibold select-none`}>
163
182
  {initials(name)}
164
183
  </div>
165
184
  {status && (
@@ -322,9 +341,11 @@ export function AgentPickerPopover({
322
341
  onClick={() => onSelect(agent.key)}
323
342
  className="w-full text-left px-3 py-2 text-xs text-foreground hover:bg-muted cursor-pointer flex items-center gap-2 transition-colors duration-100"
324
343
  >
325
- <div className={`w-6 h-6 rounded-full ${AVATAR_COLORS[hashName(agent.name) % AVATAR_COLORS.length]} flex items-center justify-center text-white text-[9px] font-medium shrink-0`}>
344
+ {(() => { const [bg, bdr, txt] = AVATAR_PALETTES[hashName(agent.name) % AVATAR_PALETTES.length]; return (
345
+ <div className={`w-6 h-6 rounded-full border ${bg} ${bdr} ${txt} flex items-center justify-center text-[9px] font-semibold shrink-0`}>
326
346
  {initials(agent.name)}
327
347
  </div>
348
+ ); })()}
328
349
  {agent.name}
329
350
  </button>
330
351
  ))}
@@ -207,7 +207,12 @@ export default function AgentsSkillsSection({
207
207
  <section className="space-y-4 overflow-hidden" aria-label={copy.title}>
208
208
  {/* Header */}
209
209
  <div className="flex items-center justify-between gap-3">
210
- <h2 className="text-sm font-medium text-foreground">{copy.title}</h2>
210
+ <h2 className="text-sm font-semibold text-foreground flex items-center gap-2">
211
+ <div className="w-6 h-6 rounded-md bg-muted/50 flex items-center justify-center">
212
+ <Zap size={13} className="text-muted-foreground/70" aria-hidden="true" />
213
+ </div>
214
+ {copy.title}
215
+ </h2>
211
216
  <div className="flex items-center gap-1 rounded-md border border-border p-0.5 bg-background" role="tablist" aria-label={copy.title}>
212
217
  <PillButton active={view === 'bySkill'} label={copy.tabs.bySkill} onClick={() => setView('bySkill')} />
213
218
  <PillButton active={view === 'byAgent'} label={copy.tabs.byAgent} onClick={() => setView('byAgent')} />
@@ -215,8 +220,8 @@ export default function AgentsSkillsSection({
215
220
  </div>
216
221
 
217
222
  {/* Compact status strip */}
218
- <div className="rounded-lg border border-border bg-card p-3">
219
- <div className="flex flex-wrap items-center gap-x-4 gap-y-2 text-xs">
223
+ <div className="rounded-xl border border-border/60 bg-gradient-to-r from-card to-card/80 p-3.5">
224
+ <div className="flex flex-wrap items-center gap-x-5 gap-y-2 text-xs">
220
225
  <span className="inline-flex items-center gap-1.5 text-muted-foreground">
221
226
  <span className="w-1.5 h-1.5 rounded-full bg-[var(--success)]" aria-hidden="true" />
222
227
  {copy.summaryEnabled(enabledCount)}
@@ -446,8 +451,12 @@ function BySkillView({
446
451
  <div className="space-y-3">
447
452
  {sortedGrouped.map(([groupKey, sortedSkills]) => (
448
453
  <div key={groupKey}>
449
- <div className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2">
450
- {copy.groupLabels[groupKey as keyof typeof copy.groupLabels]} <span className="tabular-nums">({sortedSkills.length})</span>
454
+ <div className="flex items-center gap-2 mb-2.5">
455
+ <span className="w-1 h-4 rounded-full bg-[var(--amber)]/40" aria-hidden="true" />
456
+ <span className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">
457
+ {copy.groupLabels[groupKey as keyof typeof copy.groupLabels]}
458
+ </span>
459
+ <span className="text-2xs tabular-nums text-muted-foreground/50 font-medium">({sortedSkills.length})</span>
451
460
  </div>
452
461
  <div className="space-y-3">
453
462
  {sortedSkills.map((skill) => {
@@ -457,7 +466,7 @@ function BySkillView({
457
466
  const isUserSkill = skill.kind === 'mindos' && skill.source === 'user';
458
467
 
459
468
  return (
460
- <div key={skill.name} className="rounded-lg border border-border bg-card p-4 hover:border-border/60 hover:shadow-sm transition-all duration-150">
469
+ <div key={skill.name} className="rounded-xl border border-border bg-card p-4 hover:shadow-[0_2px_8px_rgba(0,0,0,0.04)] transition-all duration-200">
461
470
  {/* Skill header */}
462
471
  <div className="flex items-center justify-between gap-2 mb-2">
463
472
  <div className="flex items-center gap-2 min-w-0">
@@ -676,7 +685,7 @@ function AgentCard({
676
685
  const visibleNative = nativeExpanded ? nativeSkills : nativeSkills.slice(0, NATIVE_COLLAPSE_THRESHOLD);
677
686
 
678
687
  return (
679
- <div className="rounded-lg border border-border bg-card hover:border-border/60 hover:shadow-sm transition-all duration-150 overflow-hidden">
688
+ <div className="rounded-xl border border-border bg-card hover:shadow-[0_2px_8px_rgba(0,0,0,0.04)] transition-all duration-200 overflow-hidden">
680
689
  {/* Card header with avatar */}
681
690
  <div className="flex items-center gap-3 p-4 pb-0">
682
691
  <AgentAvatar name={name} status={status} />
@@ -217,14 +217,14 @@ export default function SkillDetailPopover({
217
217
  className="fixed right-0 top-0 z-50 h-full w-full max-w-md border-l border-border bg-card shadow-2xl flex flex-col animate-in slide-in-from-right duration-200"
218
218
  >
219
219
  {/* ─── Header ─── */}
220
- <div className="flex items-center gap-3 px-5 py-4 border-b border-border shrink-0">
221
- <div className="w-9 h-9 rounded-lg bg-muted/60 flex items-center justify-center text-muted-foreground shrink-0">
220
+ <div className="flex items-center gap-3 px-5 py-4 border-b border-border/60 bg-gradient-to-r from-card to-card/80 shrink-0">
221
+ <div className="w-9 h-9 rounded-xl bg-[var(--amber)]/[0.08] flex items-center justify-center text-[var(--amber)] shrink-0">
222
222
  <CapIcon size={18} />
223
223
  </div>
224
224
  <div className="flex-1 min-w-0">
225
225
  <h2 className="text-sm font-semibold text-foreground truncate">{skillName}</h2>
226
- <div className="flex items-center gap-2 mt-0.5">
227
- <span className={`text-2xs px-1.5 py-0.5 rounded font-medium select-none ${
226
+ <div className="flex items-center gap-2 mt-1">
227
+ <span className={`text-2xs px-2 py-0.5 rounded-full font-medium select-none ${
228
228
  isNative
229
229
  ? 'bg-muted text-muted-foreground'
230
230
  : skill?.source === 'builtin'
@@ -233,7 +233,7 @@ export default function SkillDetailPopover({
233
233
  }`}>
234
234
  {sourceLabel}
235
235
  </span>
236
- <span className="text-2xs text-muted-foreground capitalize">{capability}</span>
236
+ <span className="text-2xs text-muted-foreground/60 capitalize">{capability}</span>
237
237
  </div>
238
238
  </div>
239
239
  <button
@@ -267,9 +267,9 @@ export default function SkillDetailPopover({
267
267
 
268
268
  {/* Path */}
269
269
  {skillPath && (
270
- <div className="rounded-lg border border-border bg-background p-3">
271
- <span className="text-2xs text-muted-foreground block mb-1">{copy.path}</span>
272
- <code className="text-xs text-foreground font-mono break-all leading-relaxed">{skillPath}</code>
270
+ <div className="rounded-xl border border-border/50 bg-muted/[0.03] p-3.5">
271
+ <span className="text-2xs text-muted-foreground/60 block mb-1.5 uppercase tracking-wider">{copy.path}</span>
272
+ <code className="text-xs text-foreground/80 font-mono break-all leading-relaxed">{skillPath}</code>
273
273
  </div>
274
274
  )}
275
275
 
@@ -410,9 +410,9 @@ function MetaCard({
410
410
  : tone === 'muted' ? 'text-muted-foreground'
411
411
  : 'text-foreground';
412
412
  return (
413
- <div className="rounded-lg border border-border bg-background px-3 py-2.5">
414
- <span className="text-2xs text-muted-foreground block mb-0.5">{label}</span>
415
- <span className={`text-sm font-medium capitalize ${valueColor}`}>{value}</span>
413
+ <div className="rounded-xl border border-border/50 bg-muted/[0.03] px-3.5 py-3 hover:bg-muted/[0.06] transition-colors duration-100">
414
+ <span className="text-2xs text-muted-foreground/60 block mb-1 uppercase tracking-wider">{label}</span>
415
+ <span className={`text-sm font-semibold capitalize ${valueColor}`}>{value}</span>
416
416
  </div>
417
417
  );
418
418
  }