apteva 0.4.41 → 0.4.44

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.
Files changed (102) hide show
  1. package/dist/ActivityPage.c48n83h2.js +3 -0
  2. package/dist/ApiDocsPage.yzcxx5ax.js +4 -0
  3. package/dist/App.09yb8t0b.js +1 -0
  4. package/dist/App.152mbs1r.js +4 -0
  5. package/dist/App.3a67nx9w.js +4 -0
  6. package/dist/App.9epx6785.js +4 -0
  7. package/dist/App.d8955awp.js +4 -0
  8. package/dist/App.drwb57jq.js +4 -0
  9. package/dist/App.gssbmajb.js +4 -0
  10. package/dist/App.qw70pc29.js +53 -0
  11. package/dist/{App.7fb3e7mp.js → App.qzbx5wtj.js} +1 -1
  12. package/dist/App.r5serxkt.js +8 -0
  13. package/dist/App.tpmp9020.js +20 -0
  14. package/dist/App.v2wb4d7d.js +61 -0
  15. package/dist/App.vxmaaj0m.js +13 -0
  16. package/dist/App.w4p2tda9.js +4 -0
  17. package/dist/App.wv2ng55q.js +221 -0
  18. package/dist/App.yncnrn0f.js +4 -0
  19. package/dist/ConnectionsPage.k6cspyqq.js +3 -0
  20. package/dist/McpPage.cdxm48xj.js +3 -0
  21. package/dist/SettingsPage.evpv7c2y.js +3 -0
  22. package/dist/SkillsPage.pvzp6c1a.js +3 -0
  23. package/dist/TasksPage.6jnvbpsy.js +3 -0
  24. package/dist/TelemetryPage.t7vk24zc.js +3 -0
  25. package/dist/TestsPage.5x6658aa.js +3 -0
  26. package/dist/ThreadsPage.3fvhtevh.js +3 -0
  27. package/dist/apteva-kit.css +1 -1
  28. package/dist/index.html +1 -1
  29. package/dist/styles.css +1 -1
  30. package/package.json +8 -8
  31. package/src/db.ts +19 -9
  32. package/src/integrations/agentdojo.ts +1 -0
  33. package/src/mcp-platform.ts +418 -63
  34. package/src/openapi.ts +96 -0
  35. package/src/providers.ts +50 -24
  36. package/src/routes/api/agent-utils.ts +0 -1
  37. package/src/routes/api/agents.ts +19 -1
  38. package/src/routes/api/meta-agent.ts +2 -0
  39. package/src/routes/api/system.ts +90 -1
  40. package/src/routes/api/telemetry.ts +19 -1
  41. package/src/routes/share.ts +85 -0
  42. package/src/server.ts +12 -0
  43. package/src/web/App.tsx +89 -11
  44. package/src/web/components/activity/ActivityPage.tsx +14 -14
  45. package/src/web/components/agents/AgentCard.tsx +14 -14
  46. package/src/web/components/agents/AgentPanel.tsx +358 -198
  47. package/src/web/components/agents/AgentsView.tsx +4 -4
  48. package/src/web/components/agents/CreateAgentModal.tsx +21 -79
  49. package/src/web/components/api/ApiDocsPage.tsx +66 -66
  50. package/src/web/components/auth/CreateAccountStep.tsx +16 -16
  51. package/src/web/components/auth/LoginPage.tsx +10 -10
  52. package/src/web/components/common/LoadingSpinner.tsx +2 -2
  53. package/src/web/components/common/Modal.tsx +8 -8
  54. package/src/web/components/common/Select.tsx +9 -9
  55. package/src/web/components/connections/ConnectionsPage.tsx +4 -4
  56. package/src/web/components/connections/IntegrationsTab.tsx +18 -18
  57. package/src/web/components/connections/OverviewTab.tsx +13 -13
  58. package/src/web/components/connections/TriggersTab.tsx +99 -99
  59. package/src/web/components/dashboard/Dashboard.tsx +32 -32
  60. package/src/web/components/layout/Header.tsx +50 -34
  61. package/src/web/components/layout/Sidebar.tsx +34 -15
  62. package/src/web/components/mcp/IntegrationsPanel.tsx +40 -40
  63. package/src/web/components/mcp/McpPage.tsx +208 -208
  64. package/src/web/components/meta-agent/MetaAgent.tsx +12 -10
  65. package/src/web/components/onboarding/OnboardingWizard.tsx +25 -25
  66. package/src/web/components/settings/SettingsPage.tsx +258 -175
  67. package/src/web/components/skills/SkillsPage.tsx +88 -88
  68. package/src/web/components/tasks/TasksPage.tsx +339 -54
  69. package/src/web/components/telemetry/TelemetryPage.tsx +135 -64
  70. package/src/web/components/tests/TestsPage.tsx +50 -50
  71. package/src/web/components/threads/ThreadsPage.tsx +23 -21
  72. package/src/web/context/ProjectContext.tsx +6 -1
  73. package/src/web/context/ThemeContext.tsx +69 -0
  74. package/src/web/context/index.ts +2 -0
  75. package/src/web/styles.css +5 -3
  76. package/src/web/themes.ts +99 -0
  77. package/src/web/types.ts +0 -4
  78. package/dist/ActivityPage.7907h64p.js +0 -3
  79. package/dist/ApiDocsPage.k3jjenpq.js +0 -4
  80. package/dist/App.01nq20st.js +0 -4
  81. package/dist/App.1maqvamf.js +0 -4
  82. package/dist/App.2yjrh32f.js +0 -4
  83. package/dist/App.3qw8nben.js +0 -20
  84. package/dist/App.7sy3wq8c.js +0 -4
  85. package/dist/App.apjrmctz.js +0 -57
  86. package/dist/App.av6t2yhe.js +0 -4
  87. package/dist/App.jqj5a094.js +0 -46
  88. package/dist/App.mc7xf85h.js +0 -4
  89. package/dist/App.myxqcj9x.js +0 -4
  90. package/dist/App.nm91r1mp.js +0 -13
  91. package/dist/App.p02f4ret.js +0 -1
  92. package/dist/App.qcknavjz.js +0 -221
  93. package/dist/App.vc7vfhg4.js +0 -4
  94. package/dist/App.z4s9zkw5.js +0 -4
  95. package/dist/ConnectionsPage.z1pw5xe2.js +0 -3
  96. package/dist/McpPage.8vc97z0b.js +0 -3
  97. package/dist/SettingsPage.p61bz8kd.js +0 -3
  98. package/dist/SkillsPage.r9x43g3g.js +0 -3
  99. package/dist/TasksPage.1e0zkye4.js +0 -3
  100. package/dist/TelemetryPage.p9vbe4gf.js +0 -3
  101. package/dist/TestsPage.d4xy504e.js +0 -3
  102. package/dist/ThreadsPage.m016am3x.js +0 -3
@@ -4,9 +4,9 @@ import { CloseIcon, MemoryIcon, TasksIcon, VisionIcon, OperatorIcon, McpIcon, Re
4
4
  import { formatCron, formatRelativeTime, TrajectoryView } from "../tasks/TasksPage";
5
5
  import { Select } from "../common/Select";
6
6
  import { useConfirm } from "../common/Modal";
7
- import { useTelemetry } from "../../context";
7
+ import { useTelemetry, useTheme } from "../../context";
8
8
  import { useAuth } from "../../context";
9
- import type { Agent, Provider, AgentFeatures, McpServer, SkillSummary, AgentMode, MultiAgentConfig, OperatorConfig, Task } from "../../types";
9
+ import type { Agent, Provider, AgentFeatures, McpServer, SkillSummary, MultiAgentConfig, OperatorConfig, Task } from "../../types";
10
10
  import { getMultiAgentConfig, getOperatorConfig } from "../../types";
11
11
 
12
12
  type Tab = "chat" | "threads" | "tasks" | "memory" | "files" | "settings";
@@ -35,9 +35,9 @@ export function AgentPanel({ agent, providers, onClose, onStartAgent, onUpdateAg
35
35
  const [activeTab, setActiveTab] = useState<Tab>("chat");
36
36
 
37
37
  return (
38
- <div className="w-full h-full flex flex-col overflow-hidden bg-[#0a0a0a] border-l border-[#1a1a1a]">
38
+ <div className="w-full h-full flex flex-col overflow-hidden bg-[var(--color-bg)] border-l border-[var(--color-border)]">
39
39
  {/* Header with tabs */}
40
- <div className="border-b border-[#1a1a1a] flex items-center">
40
+ <div className="border-b border-[var(--color-border)] flex items-center">
41
41
  {/* Scrollable tabs */}
42
42
  <div className="flex-1 overflow-x-auto scrollbar-hide px-2 md:px-4">
43
43
  <div className="flex gap-1">
@@ -65,7 +65,7 @@ export function AgentPanel({ agent, providers, onClose, onStartAgent, onUpdateAg
65
65
  {/* Close button - fixed on right */}
66
66
  <button
67
67
  onClick={onClose}
68
- className="text-[#666] hover:text-[#e0e0e0] transition p-2 flex-shrink-0 mr-2"
68
+ className="text-[var(--color-text-muted)] hover:text-[var(--color-text)] transition p-2 flex-shrink-0 mr-2"
69
69
  >
70
70
  <CloseIcon />
71
71
  </button>
@@ -102,8 +102,8 @@ function TabButton({ active, onClick, children }: { active: boolean; onClick: ()
102
102
  onClick={onClick}
103
103
  className={`px-4 py-3 text-sm font-medium border-b-2 transition ${
104
104
  active
105
- ? "border-[#f97316] text-[#e0e0e0]"
106
- : "border-transparent text-[#666] hover:text-[#888]"
105
+ ? "border-[var(--color-accent)] text-[var(--color-text)]"
106
+ : "border-transparent text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"
107
107
  }`}
108
108
  >
109
109
  {children}
@@ -112,6 +112,7 @@ function TabButton({ active, onClick, children }: { active: boolean; onClick: ()
112
112
  }
113
113
 
114
114
  function ChatTab({ agent, onStartAgent }: { agent: Agent; onStartAgent: (e?: React.MouseEvent) => void }) {
115
+ const { theme } = useTheme();
115
116
  if (agent.status === "running" && agent.port) {
116
117
  return (
117
118
  <Chat
@@ -120,13 +121,14 @@ function ChatTab({ agent, onStartAgent }: { agent: Agent; onStartAgent: (e?: Rea
120
121
  placeholder="Message this agent..."
121
122
  context={agent.systemPrompt}
122
123
  variant="terminal"
124
+ theme={theme.id as "light" | "dark"}
123
125
  headerTitle={agent.name}
124
126
  />
125
127
  );
126
128
  }
127
129
 
128
130
  return (
129
- <div className="flex-1 flex items-center justify-center text-[#666]">
131
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
130
132
  <div className="text-center">
131
133
  <p className="text-lg mb-2">Agent is not running</p>
132
134
  <button
@@ -149,6 +151,7 @@ interface Thread {
149
151
  }
150
152
 
151
153
  function ThreadsTab({ agent }: { agent: Agent }) {
154
+ const { theme: themeObj } = useTheme();
152
155
  const [threads, setThreads] = useState<Thread[]>([]);
153
156
  const [loading, setLoading] = useState(true);
154
157
  const [error, setError] = useState<string | null>(null);
@@ -223,7 +226,7 @@ function ThreadsTab({ agent }: { agent: Agent }) {
223
226
 
224
227
  if (agent.status !== "running") {
225
228
  return (
226
- <div className="flex-1 flex items-center justify-center text-[#666]">
229
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
227
230
  <p>Start the agent to view threads</p>
228
231
  </div>
229
232
  );
@@ -231,7 +234,7 @@ function ThreadsTab({ agent }: { agent: Agent }) {
231
234
 
232
235
  if (loading) {
233
236
  return (
234
- <div className="flex-1 flex items-center justify-center text-[#666]">
237
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
235
238
  <p>Loading threads...</p>
236
239
  </div>
237
240
  );
@@ -252,7 +255,7 @@ function ThreadsTab({ agent }: { agent: Agent }) {
252
255
  {ConfirmDialog}
253
256
  <div className="flex-1 flex flex-col overflow-hidden">
254
257
  {loadingMessages ? (
255
- <div className="flex-1 flex items-center justify-center text-[#666]">Loading messages...</div>
258
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">Loading messages...</div>
256
259
  ) : (
257
260
  <Chat
258
261
  key={selectedThread}
@@ -263,6 +266,7 @@ function ThreadsTab({ agent }: { agent: Agent }) {
263
266
  placeholder="Continue this conversation..."
264
267
  context={agent.systemPrompt}
265
268
  variant="terminal"
269
+ theme={themeObj.id as "light" | "dark"}
266
270
  showHeader={true}
267
271
  onHeaderBack={() => { setSelectedThread(null); setInitialMessages([]); }}
268
272
  />
@@ -278,29 +282,29 @@ function ThreadsTab({ agent }: { agent: Agent }) {
278
282
  {ConfirmDialog}
279
283
  <div className="flex-1 overflow-auto">
280
284
  {threads.length === 0 ? (
281
- <div className="flex items-center justify-center h-full text-[#666]">
285
+ <div className="flex items-center justify-center h-full text-[var(--color-text-muted)]">
282
286
  <p>No conversation threads yet</p>
283
287
  </div>
284
288
  ) : (
285
- <div className="divide-y divide-[#1a1a1a]">
289
+ <div className="divide-y divide-[var(--color-border)]">
286
290
  {threads.map(thread => (
287
291
  <div
288
292
  key={thread.id}
289
293
  onClick={() => openThread(thread.id)}
290
- className="p-4 cursor-pointer hover:bg-[#111] transition flex items-center justify-between"
294
+ className="p-4 cursor-pointer hover:bg-[var(--color-surface)] transition flex items-center justify-between"
291
295
  >
292
296
  <div className="flex-1 min-w-0">
293
297
  <p className="text-sm font-medium truncate">
294
298
  {thread.title || `Thread ${thread.id.slice(0, 8)}`}
295
299
  </p>
296
- <p className="text-xs text-[#666] mt-1">
300
+ <p className="text-xs text-[var(--color-text-muted)] mt-1">
297
301
  {new Date(thread.updated_at || thread.created_at).toLocaleString()}
298
302
  {thread.message_count !== undefined && ` • ${thread.message_count} messages`}
299
303
  </p>
300
304
  </div>
301
305
  <button
302
306
  onClick={(e) => deleteThread(thread.id, e)}
303
- className="text-[#666] hover:text-red-400 text-lg ml-4"
307
+ className="text-[var(--color-text-muted)] hover:text-red-400 text-lg ml-4"
304
308
  >
305
309
  ×
306
310
  </button>
@@ -321,6 +325,10 @@ function TasksTab({ agent }: { agent: Agent }) {
321
325
  const [filter, setFilter] = useState<string>("all");
322
326
  const [selectedTask, setSelectedTask] = useState<Task | null>(null);
323
327
  const [loadingTask, setLoadingTask] = useState(false);
328
+ const [showCreateForm, setShowCreateForm] = useState(false);
329
+ const [executing, setExecuting] = useState(false);
330
+ const [deleting, setDeleting] = useState(false);
331
+ const { confirm, ConfirmDialog } = useConfirm();
324
332
  const { events } = useTelemetry({ agent_id: agent.id, category: "task" });
325
333
 
326
334
  // Reset state when agent changes
@@ -368,6 +376,58 @@ function TasksTab({ agent }: { agent: Agent }) {
368
376
  }
369
377
  };
370
378
 
379
+ const handleExecuteTask = async () => {
380
+ if (!selectedTask || executing) return;
381
+ setExecuting(true);
382
+ try {
383
+ await authFetch(`/api/tasks/${agent.id}/${selectedTask.id}/execute`, { method: "POST" });
384
+ setSelectedTask(null);
385
+ fetchTasks();
386
+ } catch (e) {
387
+ console.error("Failed to execute task:", e);
388
+ } finally {
389
+ setExecuting(false);
390
+ }
391
+ };
392
+
393
+ const handleDeleteTask = async () => {
394
+ if (!selectedTask || deleting) return;
395
+ const ok = await confirm(`Are you sure you want to delete "${selectedTask.title}"?`, {
396
+ title: "Delete Task",
397
+ confirmText: "Delete",
398
+ confirmVariant: "danger",
399
+ });
400
+ if (!ok) return;
401
+ setDeleting(true);
402
+ try {
403
+ await authFetch(`/api/tasks/${agent.id}/${selectedTask.id}`, { method: "DELETE" });
404
+ setSelectedTask(null);
405
+ fetchTasks();
406
+ } catch (e) {
407
+ console.error("Failed to delete task:", e);
408
+ } finally {
409
+ setDeleting(false);
410
+ }
411
+ };
412
+
413
+ const handleCreateTask = async (data: { title: string; description: string; type: string; priority: number; execute_at?: string; recurrence?: string }) => {
414
+ try {
415
+ const body: Record<string, unknown> = { ...data };
416
+ if (data.execute_at) body.execute_at = new Date(data.execute_at).toISOString();
417
+ const res = await authFetch(`/api/tasks/${agent.id}`, {
418
+ method: "POST",
419
+ headers: { "Content-Type": "application/json" },
420
+ body: JSON.stringify(body),
421
+ });
422
+ if (res.ok) {
423
+ setShowCreateForm(false);
424
+ fetchTasks();
425
+ }
426
+ } catch (e) {
427
+ console.error("Failed to create task:", e);
428
+ }
429
+ };
430
+
371
431
  // Refetch when agent changes, filter changes, or task telemetry arrives
372
432
  useEffect(() => {
373
433
  setLoading(true);
@@ -384,7 +444,7 @@ function TasksTab({ agent }: { agent: Agent }) {
384
444
 
385
445
  if (agent.status !== "running") {
386
446
  return (
387
- <div className="flex-1 flex items-center justify-center text-[#666]">
447
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
388
448
  <p>Start the agent to view tasks</p>
389
449
  </div>
390
450
  );
@@ -392,7 +452,7 @@ function TasksTab({ agent }: { agent: Agent }) {
392
452
 
393
453
  if (!agent.features?.tasks) {
394
454
  return (
395
- <div className="flex-1 flex items-center justify-center text-[#666]">
455
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
396
456
  <div className="text-center">
397
457
  <p className="mb-2">Tasks feature is not enabled</p>
398
458
  <p className="text-sm">Enable it in Settings to schedule tasks</p>
@@ -403,7 +463,7 @@ function TasksTab({ agent }: { agent: Agent }) {
403
463
 
404
464
  if (loading) {
405
465
  return (
406
- <div className="flex-1 flex items-center justify-center text-[#666]">
466
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
407
467
  <p>Loading tasks...</p>
408
468
  </div>
409
469
  );
@@ -429,14 +489,35 @@ function TasksTab({ agent }: { agent: Agent }) {
429
489
  if (selectedTask) {
430
490
  return (
431
491
  <div className="flex-1 flex flex-col overflow-hidden">
432
- {/* Back button */}
433
- <div className="px-4 pt-3 pb-2 border-b border-[#1a1a1a] shrink-0">
492
+ {ConfirmDialog}
493
+ {/* Back button + actions */}
494
+ <div className="px-4 pt-3 pb-2 border-b border-[var(--color-border)] shrink-0 flex items-center justify-between">
434
495
  <button
435
496
  onClick={() => setSelectedTask(null)}
436
- className="text-sm text-[#666] hover:text-[#e0e0e0] transition flex items-center gap-1"
497
+ className="text-sm text-[var(--color-text-muted)] hover:text-[var(--color-text)] transition flex items-center gap-1"
437
498
  >
438
499
  <span>←</span> Back to tasks
439
500
  </button>
501
+ <div className="flex items-center gap-2">
502
+ {(selectedTask.status === "pending" || selectedTask.status === "completed") && (
503
+ <button
504
+ onClick={handleExecuteTask}
505
+ disabled={executing}
506
+ title="Execute now"
507
+ className="text-[var(--color-accent)] hover:opacity-80 transition disabled:opacity-50"
508
+ >
509
+ <svg className="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" /><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
510
+ </button>
511
+ )}
512
+ <button
513
+ onClick={handleDeleteTask}
514
+ disabled={deleting}
515
+ title="Delete task"
516
+ className="text-red-400 hover:text-red-300 transition disabled:opacity-50"
517
+ >
518
+ <svg className="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
519
+ </button>
520
+ </div>
440
521
  </div>
441
522
 
442
523
  {/* Task detail content */}
@@ -454,26 +535,26 @@ function TasksTab({ agent }: { agent: Agent }) {
454
535
  {/* Description */}
455
536
  {selectedTask.description && (
456
537
  <div>
457
- <h4 className="text-xs text-[#666] uppercase tracking-wider mb-1">Description</h4>
458
- <p className="text-sm text-[#888] whitespace-pre-wrap">{selectedTask.description}</p>
538
+ <h4 className="text-xs text-[var(--color-text-muted)] uppercase tracking-wider mb-1">Description</h4>
539
+ <p className="text-sm text-[var(--color-text-secondary)] whitespace-pre-wrap">{selectedTask.description}</p>
459
540
  </div>
460
541
  )}
461
542
 
462
543
  {/* Metadata */}
463
544
  <div className="grid grid-cols-2 gap-3 text-sm">
464
545
  <div>
465
- <span className="text-[#666]">Type</span>
546
+ <span className="text-[var(--color-text-muted)]">Type</span>
466
547
  <p className="capitalize">{selectedTask.type}</p>
467
548
  </div>
468
549
  <div>
469
- <span className="text-[#666]">Priority</span>
550
+ <span className="text-[var(--color-text-muted)]">Priority</span>
470
551
  <p>{selectedTask.priority}</p>
471
552
  </div>
472
553
  {selectedTask.recurrence && (
473
554
  <div>
474
- <span className="text-[#666]">Recurrence</span>
555
+ <span className="text-[var(--color-text-muted)]">Recurrence</span>
475
556
  <p>{formatCron(selectedTask.recurrence)}</p>
476
- <p className="text-xs text-[#444] mt-0.5 font-mono">{selectedTask.recurrence}</p>
557
+ <p className="text-xs text-[var(--color-text-faint)] mt-0.5 font-mono">{selectedTask.recurrence}</p>
477
558
  </div>
478
559
  )}
479
560
  </div>
@@ -481,31 +562,31 @@ function TasksTab({ agent }: { agent: Agent }) {
481
562
  {/* Timestamps */}
482
563
  <div className="space-y-2 text-sm">
483
564
  <div className="flex justify-between">
484
- <span className="text-[#666]">Created</span>
565
+ <span className="text-[var(--color-text-muted)]">Created</span>
485
566
  <span>{new Date(selectedTask.created_at).toLocaleString()}</span>
486
567
  </div>
487
568
  {selectedTask.execute_at && (
488
569
  <div className="flex justify-between">
489
- <span className="text-[#666]">Scheduled</span>
490
- <span className="text-[#f97316]">{formatRelativeTime(selectedTask.execute_at)}</span>
570
+ <span className="text-[var(--color-text-muted)]">Scheduled</span>
571
+ <span className="text-[var(--color-accent)]">{formatRelativeTime(selectedTask.execute_at)}</span>
491
572
  </div>
492
573
  )}
493
574
  {selectedTask.executed_at && (
494
575
  <div className="flex justify-between">
495
- <span className="text-[#666]">Started</span>
576
+ <span className="text-[var(--color-text-muted)]">Started</span>
496
577
  <span>{new Date(selectedTask.executed_at).toLocaleString()}</span>
497
578
  </div>
498
579
  )}
499
580
  {selectedTask.completed_at && (
500
581
  <div className="flex justify-between">
501
- <span className="text-[#666]">Completed</span>
582
+ <span className="text-[var(--color-text-muted)]">Completed</span>
502
583
  <span>{new Date(selectedTask.completed_at).toLocaleString()}</span>
503
584
  </div>
504
585
  )}
505
586
  {selectedTask.next_run && (
506
587
  <div className="flex justify-between">
507
- <span className="text-[#666]">Next Run</span>
508
- <span className="text-[#f97316]">{formatRelativeTime(selectedTask.next_run)}</span>
588
+ <span className="text-[var(--color-text-muted)]">Next Run</span>
589
+ <span className="text-[var(--color-accent)]">{formatRelativeTime(selectedTask.next_run)}</span>
509
590
  </div>
510
591
  )}
511
592
  </div>
@@ -535,13 +616,13 @@ function TasksTab({ agent }: { agent: Agent }) {
535
616
  {/* Trajectory */}
536
617
  {loadingTask && !selectedTask.trajectory && (
537
618
  <div>
538
- <h4 className="text-xs text-[#666] uppercase tracking-wider mb-2">Trajectory</h4>
539
- <div className="text-sm text-[#555]">Loading trajectory...</div>
619
+ <h4 className="text-xs text-[var(--color-text-muted)] uppercase tracking-wider mb-2">Trajectory</h4>
620
+ <div className="text-sm text-[var(--color-text-faint)]">Loading trajectory...</div>
540
621
  </div>
541
622
  )}
542
623
  {selectedTask.trajectory && selectedTask.trajectory.length > 0 && (
543
624
  <div>
544
- <h4 className="text-xs text-[#666] uppercase tracking-wider mb-2">
625
+ <h4 className="text-xs text-[var(--color-text-muted)] uppercase tracking-wider mb-2">
545
626
  Trajectory ({selectedTask.trajectory.length} steps)
546
627
  </h4>
547
628
  <TrajectoryView trajectory={selectedTask.trajectory} />
@@ -554,28 +635,45 @@ function TasksTab({ agent }: { agent: Agent }) {
554
635
 
555
636
  return (
556
637
  <div className="flex-1 overflow-auto p-4">
557
- {/* Filter tabs */}
558
- <div className="flex gap-2 mb-4">
559
- {filterOptions.map(opt => (
560
- <button
561
- key={opt.value}
562
- onClick={() => setFilter(opt.value)}
638
+ {/* Create Task Button + Filter tabs */}
639
+ <div className="flex items-center justify-between mb-4">
640
+ <div className="flex gap-2">
641
+ {filterOptions.map(opt => (
642
+ <button
643
+ key={opt.value}
644
+ onClick={() => setFilter(opt.value)}
563
645
  className={`px-3 py-1.5 rounded text-sm transition ${
564
646
  filter === opt.value
565
- ? "bg-[#f97316] text-black"
566
- : "bg-[#1a1a1a] hover:bg-[#222]"
647
+ ? "bg-[var(--color-accent)] text-black"
648
+ : "bg-[var(--color-surface-raised)] hover:bg-[var(--color-surface-raised)]"
567
649
  }`}
568
650
  >
569
651
  {opt.label}
570
652
  </button>
571
653
  ))}
654
+ </div>
655
+ <button
656
+ onClick={() => setShowCreateForm(!showCreateForm)}
657
+ className="px-3 py-1.5 rounded text-sm bg-[var(--color-accent)] text-black hover:opacity-90 transition flex items-center gap-1 flex-shrink-0"
658
+ >
659
+ <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" /></svg>
660
+ New
661
+ </button>
572
662
  </div>
573
663
 
664
+ {/* Inline Create Form */}
665
+ {showCreateForm && (
666
+ <AgentCreateTaskForm
667
+ onSubmit={handleCreateTask}
668
+ onCancel={() => setShowCreateForm(false)}
669
+ />
670
+ )}
671
+
574
672
  {tasks.length === 0 ? (
575
673
  <div className="text-center py-10">
576
- <TasksIcon className="w-10 h-10 mx-auto mb-3 text-[#333]" />
577
- <p className="text-[#666]">No {filter === "all" ? "" : filter + " "}tasks</p>
578
- <p className="text-sm text-[#444] mt-1">Tasks will appear here when created</p>
674
+ <TasksIcon className="w-10 h-10 mx-auto mb-3 text-[var(--color-border-light)]" />
675
+ <p className="text-[var(--color-text-muted)]">No {filter === "all" ? "" : filter + " "}tasks</p>
676
+ <p className="text-sm text-[var(--color-text-faint)] mt-1">Tasks will appear here when created</p>
579
677
  </div>
580
678
  ) : (
581
679
  <div className="space-y-3">
@@ -583,7 +681,7 @@ function TasksTab({ agent }: { agent: Agent }) {
583
681
  <div
584
682
  key={task.id}
585
683
  onClick={() => selectTask(task)}
586
- className="bg-[#111] border border-[#1a1a1a] rounded-lg p-4 cursor-pointer hover:border-[#333] transition"
684
+ className="bg-[var(--color-surface)] border border-[var(--color-border)] rounded-lg p-4 cursor-pointer hover:border-[var(--color-border-light)] transition"
587
685
  >
588
686
  <div className="flex items-start justify-between mb-2">
589
687
  <div className="flex-1 min-w-0">
@@ -595,10 +693,10 @@ function TasksTab({ agent }: { agent: Agent }) {
595
693
  </div>
596
694
 
597
695
  {task.description && (
598
- <p className="text-sm text-[#888] mb-2 line-clamp-2">{task.description}</p>
696
+ <p className="text-sm text-[var(--color-text-secondary)] mb-2 line-clamp-2">{task.description}</p>
599
697
  )}
600
698
 
601
- <div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-[#555]">
699
+ <div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-[var(--color-text-faint)]">
602
700
  <span className="flex items-center gap-1">
603
701
  {task.type === "recurring"
604
702
  ? <RecurringIcon className="w-3.5 h-3.5" />
@@ -612,10 +710,10 @@ function TasksTab({ agent }: { agent: Agent }) {
612
710
  <span>Priority: {task.priority}</span>
613
711
  )}
614
712
  {task.next_run && (
615
- <span className="text-[#f97316]">{formatRelativeTime(task.next_run)}</span>
713
+ <span className="text-[var(--color-accent)]">{formatRelativeTime(task.next_run)}</span>
616
714
  )}
617
715
  {!task.next_run && task.execute_at && (
618
- <span className="text-[#f97316]">{formatRelativeTime(task.execute_at)}</span>
716
+ <span className="text-[var(--color-accent)]">{formatRelativeTime(task.execute_at)}</span>
619
717
  )}
620
718
  <span>Created: {new Date(task.created_at).toLocaleDateString()}</span>
621
719
  </div>
@@ -643,6 +741,82 @@ function TasksTab({ agent }: { agent: Agent }) {
643
741
  );
644
742
  }
645
743
 
744
+ function AgentCreateTaskForm({ onSubmit, onCancel }: {
745
+ onSubmit: (data: { title: string; description: string; type: string; priority: number; execute_at?: string; recurrence?: string }) => void;
746
+ onCancel: () => void;
747
+ }) {
748
+ const [title, setTitle] = useState("");
749
+ const [description, setDescription] = useState("");
750
+ const [type, setType] = useState("once");
751
+ const [priority, setPriority] = useState(5);
752
+ const [executeAt, setExecuteAt] = useState("");
753
+ const [recurrence, setRecurrence] = useState("");
754
+
755
+ return (
756
+ <div className="bg-[var(--color-surface)] border border-[var(--color-accent)]/30 rounded-lg p-3 mb-4 space-y-3">
757
+ <input
758
+ type="text"
759
+ value={title}
760
+ onChange={e => setTitle(e.target.value)}
761
+ className="w-full bg-[var(--color-bg)] border border-[var(--color-border)] rounded px-3 py-1.5 text-sm"
762
+ placeholder="Task title..."
763
+ autoFocus
764
+ />
765
+ <textarea
766
+ value={description}
767
+ onChange={e => setDescription(e.target.value)}
768
+ className="w-full bg-[var(--color-bg)] border border-[var(--color-border)] rounded px-3 py-1.5 text-sm resize-none"
769
+ rows={2}
770
+ placeholder="Description (optional)..."
771
+ />
772
+ <div className="grid grid-cols-2 gap-2">
773
+ <select
774
+ value={type}
775
+ onChange={e => setType(e.target.value)}
776
+ className="bg-[var(--color-bg)] border border-[var(--color-border)] rounded px-2 py-1.5 text-sm"
777
+ >
778
+ <option value="once">One-time</option>
779
+ <option value="recurring">Recurring</option>
780
+ </select>
781
+ <input
782
+ type="number"
783
+ min={1}
784
+ max={10}
785
+ value={priority}
786
+ onChange={e => setPriority(Number(e.target.value))}
787
+ className="bg-[var(--color-bg)] border border-[var(--color-border)] rounded px-2 py-1.5 text-sm"
788
+ placeholder="Priority"
789
+ />
790
+ </div>
791
+ {type === "once" && (
792
+ <input
793
+ type="datetime-local"
794
+ value={executeAt}
795
+ onChange={e => setExecuteAt(e.target.value)}
796
+ className="w-full bg-[var(--color-bg)] border border-[var(--color-border)] rounded px-3 py-1.5 text-sm"
797
+ />
798
+ )}
799
+ {type === "recurring" && (
800
+ <input
801
+ type="text"
802
+ value={recurrence}
803
+ onChange={e => setRecurrence(e.target.value)}
804
+ className="w-full bg-[var(--color-bg)] border border-[var(--color-border)] rounded px-3 py-1.5 text-sm font-mono"
805
+ placeholder="*/30 * * * * (cron)"
806
+ />
807
+ )}
808
+ <div className="flex justify-end gap-2">
809
+ <button onClick={onCancel} className="px-3 py-1.5 rounded text-sm bg-[var(--color-surface-raised)] hover:bg-[var(--color-border)] transition">Cancel</button>
810
+ <button
811
+ onClick={() => title.trim() && onSubmit({ title: title.trim(), description: description.trim(), type, priority, execute_at: executeAt || undefined, recurrence: recurrence || undefined })}
812
+ disabled={!title.trim()}
813
+ className="px-3 py-1.5 rounded text-sm bg-[var(--color-accent)] text-black hover:opacity-90 transition disabled:opacity-50"
814
+ >Create</button>
815
+ </div>
816
+ </div>
817
+ );
818
+ }
819
+
646
820
  interface Memory {
647
821
  id: string;
648
822
  content: string;
@@ -712,7 +886,7 @@ function MemoryTab({ agent }: { agent: Agent }) {
712
886
 
713
887
  if (!agent.features?.memory) {
714
888
  return (
715
- <div className="flex-1 flex items-center justify-center text-[#666]">
889
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
716
890
  <div className="text-center">
717
891
  <p className="mb-2">Memory feature is not enabled</p>
718
892
  <p className="text-sm">Enable it in Settings to persist knowledge</p>
@@ -723,7 +897,7 @@ function MemoryTab({ agent }: { agent: Agent }) {
723
897
 
724
898
  if (agent.status !== "running") {
725
899
  return (
726
- <div className="flex-1 flex items-center justify-center text-[#666]">
900
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
727
901
  <p>Start the agent to view memories</p>
728
902
  </div>
729
903
  );
@@ -731,7 +905,7 @@ function MemoryTab({ agent }: { agent: Agent }) {
731
905
 
732
906
  if (loading) {
733
907
  return (
734
- <div className="flex-1 flex items-center justify-center text-[#666]">
908
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
735
909
  <p>Loading memories...</p>
736
910
  </div>
737
911
  );
@@ -747,7 +921,7 @@ function MemoryTab({ agent }: { agent: Agent }) {
747
921
 
748
922
  if (!enabled) {
749
923
  return (
750
- <div className="flex-1 flex items-center justify-center text-[#666]">
924
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
751
925
  <div className="text-center">
752
926
  <p className="mb-2">Memory system not initialized</p>
753
927
  <p className="text-sm">Check OPENAI_API_KEY for embeddings</p>
@@ -761,7 +935,7 @@ function MemoryTab({ agent }: { agent: Agent }) {
761
935
  {ConfirmDialog}
762
936
  <div className="flex-1 overflow-auto p-4">
763
937
  <div className="flex items-center justify-between mb-4">
764
- <h3 className="text-sm font-medium text-[#888]">Stored Memories ({memories.length})</h3>
938
+ <h3 className="text-sm font-medium text-[var(--color-text-secondary)]">Stored Memories ({memories.length})</h3>
765
939
  {memories.length > 0 && (
766
940
  <button
767
941
  onClick={clearAllMemories}
@@ -773,19 +947,19 @@ function MemoryTab({ agent }: { agent: Agent }) {
773
947
  </div>
774
948
 
775
949
  {memories.length === 0 ? (
776
- <div className="text-center py-10 text-[#666]">
950
+ <div className="text-center py-10 text-[var(--color-text-muted)]">
777
951
  <p>No memories stored yet</p>
778
952
  <p className="text-sm mt-1">The agent will remember important information from conversations</p>
779
953
  </div>
780
954
  ) : (
781
955
  <div className="space-y-3">
782
956
  {memories.map(memory => (
783
- <div key={memory.id} className="bg-[#111] border border-[#1a1a1a] rounded p-3">
957
+ <div key={memory.id} className="bg-[var(--color-surface)] border border-[var(--color-border)] rounded p-3">
784
958
  <div className="flex items-start justify-between gap-2">
785
- <p className="text-sm text-[#e0e0e0] flex-1">{memory.content}</p>
959
+ <p className="text-sm text-[var(--color-text)] flex-1">{memory.content}</p>
786
960
  <button
787
961
  onClick={() => deleteMemory(memory.id)}
788
- className="text-[#666] hover:text-red-400 text-sm flex-shrink-0"
962
+ className="text-[var(--color-text-muted)] hover:text-red-400 text-sm flex-shrink-0"
789
963
  >
790
964
  ×
791
965
  </button>
@@ -800,11 +974,11 @@ function MemoryTab({ agent }: { agent: Agent }) {
800
974
  }`}>
801
975
  {memory.type}
802
976
  </span>
803
- <span className="text-xs text-[#666]">
977
+ <span className="text-xs text-[var(--color-text-muted)]">
804
978
  {new Date(memory.created_at).toLocaleString()}
805
979
  </span>
806
980
  {memory.importance && (
807
- <span className="text-xs text-[#555]">
981
+ <span className="text-xs text-[var(--color-text-faint)]">
808
982
  importance: {memory.importance.toFixed(1)}
809
983
  </span>
810
984
  )}
@@ -961,7 +1135,7 @@ function FilesTab({ agent }: { agent: Agent }) {
961
1135
 
962
1136
  if (!agent.features?.files) {
963
1137
  return (
964
- <div className="flex-1 flex items-center justify-center text-[#666]">
1138
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
965
1139
  <div className="text-center">
966
1140
  <p className="mb-2">Files feature is not enabled</p>
967
1141
  <p className="text-sm">Enable it in Settings to manage files</p>
@@ -972,7 +1146,7 @@ function FilesTab({ agent }: { agent: Agent }) {
972
1146
 
973
1147
  if (agent.status !== "running") {
974
1148
  return (
975
- <div className="flex-1 flex items-center justify-center text-[#666]">
1149
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
976
1150
  <p>Start the agent to view files</p>
977
1151
  </div>
978
1152
  );
@@ -980,7 +1154,7 @@ function FilesTab({ agent }: { agent: Agent }) {
980
1154
 
981
1155
  if (loading) {
982
1156
  return (
983
- <div className="flex-1 flex items-center justify-center text-[#666]">
1157
+ <div className="flex-1 flex items-center justify-center text-[var(--color-text-muted)]">
984
1158
  <p>Loading files...</p>
985
1159
  </div>
986
1160
  );
@@ -998,7 +1172,7 @@ function FilesTab({ agent }: { agent: Agent }) {
998
1172
  <>
999
1173
  {ConfirmDialog}
1000
1174
  <div
1001
- className={`flex-1 overflow-auto p-4 transition ${dragOver ? "bg-[#f97316]/5" : ""}`}
1175
+ className={`flex-1 overflow-auto p-4 transition ${dragOver ? "bg-[var(--color-accent-5)]" : ""}`}
1002
1176
  onDrop={handleDrop}
1003
1177
  onDragOver={handleDragOver}
1004
1178
  onDragLeave={handleDragLeave}
@@ -1012,18 +1186,18 @@ function FilesTab({ agent }: { agent: Agent }) {
1012
1186
  />
1013
1187
 
1014
1188
  <div className="flex items-center justify-between mb-4">
1015
- <h3 className="text-sm font-medium text-[#888]">Agent Files ({files.length})</h3>
1189
+ <h3 className="text-sm font-medium text-[var(--color-text-secondary)]">Agent Files ({files.length})</h3>
1016
1190
  <div className="flex items-center gap-2">
1017
1191
  <button
1018
1192
  onClick={() => fileInputRef.current?.click()}
1019
1193
  disabled={uploading}
1020
- className="text-xs bg-[#f97316] hover:bg-[#fb923c] disabled:opacity-50 text-black px-3 py-1 rounded font-medium transition"
1194
+ className="text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] disabled:opacity-50 text-black px-3 py-1 rounded font-medium transition"
1021
1195
  >
1022
1196
  {uploading ? "Uploading..." : "Upload"}
1023
1197
  </button>
1024
1198
  <button
1025
1199
  onClick={fetchFiles}
1026
- className="text-xs text-[#666] hover:text-[#888]"
1200
+ className="text-xs text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"
1027
1201
  >
1028
1202
  Refresh
1029
1203
  </button>
@@ -1037,17 +1211,17 @@ function FilesTab({ agent }: { agent: Agent }) {
1037
1211
  )}
1038
1212
 
1039
1213
  {dragOver && (
1040
- <div className="mb-4 border-2 border-dashed border-[#f97316] rounded-lg p-8 text-center">
1041
- <p className="text-[#f97316]">Drop file to upload</p>
1214
+ <div className="mb-4 border-2 border-dashed border-[var(--color-accent)] rounded-lg p-8 text-center">
1215
+ <p className="text-[var(--color-accent)]">Drop file to upload</p>
1042
1216
  </div>
1043
1217
  )}
1044
1218
 
1045
1219
  {files.length === 0 && !dragOver && (
1046
- <div className="text-center py-10 text-[#666]">
1220
+ <div className="text-center py-10 text-[var(--color-text-muted)]">
1047
1221
  <p>No files stored yet</p>
1048
1222
  <p className="text-sm mt-1">Drop files here, click Upload, or attach files in Chat</p>
1049
1223
  {agent.features?.memory && (
1050
- <p className="text-xs mt-2 text-[#555]">Files will be auto-ingested into memory</p>
1224
+ <p className="text-xs mt-2 text-[var(--color-text-faint)]">Files will be auto-ingested into memory</p>
1051
1225
  )}
1052
1226
  </div>
1053
1227
  )}
@@ -1055,13 +1229,13 @@ function FilesTab({ agent }: { agent: Agent }) {
1055
1229
  {files.length > 0 && (
1056
1230
  <div className="space-y-2">
1057
1231
  {files.map(file => (
1058
- <div key={file.id} className="bg-[#111] border border-[#1a1a1a] rounded p-3 flex items-center gap-3">
1059
- <div className="w-10 h-10 bg-[#1a1a1a] rounded flex items-center justify-center text-[#666]">
1232
+ <div key={file.id} className="bg-[var(--color-surface)] border border-[var(--color-border)] rounded p-3 flex items-center gap-3">
1233
+ <div className="w-10 h-10 bg-[var(--color-surface-raised)] rounded flex items-center justify-center text-[var(--color-text-muted)]">
1060
1234
  {getFileIcon(file.mime_type)}
1061
1235
  </div>
1062
1236
  <div className="flex-1 min-w-0">
1063
- <p className="text-sm text-[#e0e0e0] truncate">{file.filename}</p>
1064
- <p className="text-xs text-[#666]">
1237
+ <p className="text-sm text-[var(--color-text)] truncate">{file.filename}</p>
1238
+ <p className="text-xs text-[var(--color-text-muted)]">
1065
1239
  {formatSize(file.size_bytes)} • {new Date(file.created_at).toLocaleString()}
1066
1240
  {file.source && file.source !== "upload" && ` • ${file.source}`}
1067
1241
  </p>
@@ -1069,13 +1243,13 @@ function FilesTab({ agent }: { agent: Agent }) {
1069
1243
  <div className="flex items-center gap-2">
1070
1244
  <button
1071
1245
  onClick={() => downloadFile(file.id, file.filename)}
1072
- className="text-xs text-[#666] hover:text-[#f97316] px-2 py-1"
1246
+ className="text-xs text-[var(--color-text-muted)] hover:text-[var(--color-accent)] px-2 py-1"
1073
1247
  >
1074
1248
 
1075
1249
  </button>
1076
1250
  <button
1077
1251
  onClick={() => deleteFile(file.id)}
1078
- className="text-[#666] hover:text-red-400 text-sm"
1252
+ className="text-[var(--color-text-muted)] hover:text-red-400 text-sm"
1079
1253
  >
1080
1254
  ×
1081
1255
  </button>
@@ -1126,6 +1300,8 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1126
1300
  const [apiKeyFull, setApiKeyFull] = useState<string | null>(null);
1127
1301
  const [showApiKey, setShowApiKey] = useState(false);
1128
1302
  const [subscriptions, setSubscriptions] = useState<{ id: string; trigger_slug: string; enabled: boolean }[]>([]);
1303
+ const [shareToken, setShareToken] = useState<string | null>(null);
1304
+ const [shareCopied, setShareCopied] = useState(false);
1129
1305
 
1130
1306
  // Fetch subscriptions for this agent
1131
1307
  useEffect(() => {
@@ -1166,6 +1342,20 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1166
1342
  fetchApiKey();
1167
1343
  }, [agent.id, authFetch]);
1168
1344
 
1345
+ // Fetch share token
1346
+ useEffect(() => {
1347
+ const fetchShareToken = async () => {
1348
+ try {
1349
+ const res = await authFetch(`/api/agents/${agent.id}/share-token`);
1350
+ if (res.ok) {
1351
+ const data = await res.json();
1352
+ setShareToken(data.token || null);
1353
+ }
1354
+ } catch {}
1355
+ };
1356
+ fetchShareToken();
1357
+ }, [agent.id, authFetch]);
1358
+
1169
1359
  // Fetch available skills
1170
1360
  useEffect(() => {
1171
1361
  const fetchSkills = async () => {
@@ -1229,7 +1419,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1229
1419
  ...prev,
1230
1420
  features: {
1231
1421
  ...prev.features,
1232
- agents: { enabled: true, mode: "worker" as AgentMode, group: agent.projectId || undefined },
1422
+ agents: { enabled: true, group: agent.projectId || undefined },
1233
1423
  },
1234
1424
  };
1235
1425
  }
@@ -1258,20 +1448,6 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1258
1448
  }
1259
1449
  };
1260
1450
 
1261
- // Set multi-agent mode
1262
- const setAgentMode = (mode: AgentMode) => {
1263
- setForm(prev => {
1264
- const currentConfig = getMultiAgentConfig(prev.features, agent.projectId);
1265
- return {
1266
- ...prev,
1267
- features: {
1268
- ...prev.features,
1269
- agents: { ...currentConfig, enabled: true, mode },
1270
- },
1271
- };
1272
- });
1273
- };
1274
-
1275
1451
  // Helper to check if agents feature is enabled
1276
1452
  const isAgentsEnabled = () => {
1277
1453
  const agentsVal = form.features.agents;
@@ -1279,12 +1455,6 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1279
1455
  return (agentsVal as MultiAgentConfig)?.enabled ?? false;
1280
1456
  };
1281
1457
 
1282
- // Get current agent mode
1283
- const getAgentMode = (): AgentMode => {
1284
- const config = getMultiAgentConfig(form.features, agent.projectId);
1285
- return config.mode || "worker";
1286
- };
1287
-
1288
1458
  // Helper to check if operator feature is enabled
1289
1459
  const isOperatorEnabled = () => {
1290
1460
  return getOperatorConfig(form.features).enabled;
@@ -1360,7 +1530,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1360
1530
  type="text"
1361
1531
  value={form.name}
1362
1532
  onChange={(e) => setForm(prev => ({ ...prev, name: e.target.value }))}
1363
- className="w-full bg-[#0a0a0a] border border-[#222] rounded px-3 py-2 focus:outline-none focus:border-[#f97316] text-[#e0e0e0]"
1533
+ className="w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 focus:outline-none focus:border-[var(--color-accent)] text-[var(--color-text)]"
1364
1534
  />
1365
1535
  </FormField>
1366
1536
 
@@ -1384,7 +1554,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1384
1554
  <textarea
1385
1555
  value={form.systemPrompt}
1386
1556
  onChange={(e) => setForm(prev => ({ ...prev, systemPrompt: e.target.value }))}
1387
- className="w-full bg-[#0a0a0a] border border-[#222] rounded px-3 py-2 h-24 resize-none focus:outline-none focus:border-[#f97316] text-[#e0e0e0]"
1557
+ className="w-full bg-[var(--color-bg)] border border-[var(--color-border-light)] rounded px-3 py-2 h-24 resize-none focus:outline-none focus:border-[var(--color-accent)] text-[var(--color-text)]"
1388
1558
  />
1389
1559
  </FormField>
1390
1560
 
@@ -1402,16 +1572,16 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1402
1572
  onClick={() => toggleFeature(key)}
1403
1573
  className={`flex items-center gap-3 p-3 rounded border text-left transition ${
1404
1574
  isEnabled
1405
- ? "border-[#f97316] bg-[#f97316]/10"
1406
- : "border-[#222] hover:border-[#333]"
1575
+ ? "border-[var(--color-accent)] bg-[var(--color-accent-10)]"
1576
+ : "border-[var(--color-border-light)] hover:border-[var(--color-border-light)]"
1407
1577
  }`}
1408
1578
  >
1409
- <Icon className={`w-5 h-5 flex-shrink-0 ${isEnabled ? "text-[#f97316]" : "text-[#666]"}`} />
1579
+ <Icon className={`w-5 h-5 flex-shrink-0 ${isEnabled ? "text-[var(--color-accent)]" : "text-[var(--color-text-muted)]"}`} />
1410
1580
  <div className="flex-1 min-w-0">
1411
- <div className={`text-sm font-medium ${isEnabled ? "text-[#f97316]" : ""}`}>
1581
+ <div className={`text-sm font-medium ${isEnabled ? "text-[var(--color-accent)]" : ""}`}>
1412
1582
  {label}
1413
1583
  </div>
1414
- <div className="text-xs text-[#666]">{description}</div>
1584
+ <div className="text-xs text-[var(--color-text-muted)]">{description}</div>
1415
1585
  </div>
1416
1586
  </button>
1417
1587
  );
@@ -1419,47 +1589,6 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1419
1589
  </div>
1420
1590
  </FormField>
1421
1591
 
1422
- {/* Multi-Agent Mode Selection - shown when agents is enabled */}
1423
- {isAgentsEnabled() && (
1424
- <FormField label="Multi-Agent Mode">
1425
- <div className="flex gap-2">
1426
- <button
1427
- type="button"
1428
- onClick={() => setAgentMode("coordinator")}
1429
- className={`flex-1 p-3 rounded border text-left transition ${
1430
- getAgentMode() === "coordinator"
1431
- ? "border-[#f97316] bg-[#f97316]/10"
1432
- : "border-[#222] hover:border-[#333]"
1433
- }`}
1434
- >
1435
- <div className={`text-sm font-medium ${getAgentMode() === "coordinator" ? "text-[#f97316]" : ""}`}>
1436
- Coordinator
1437
- </div>
1438
- <div className="text-xs text-[#666]">Orchestrates and delegates to other agents</div>
1439
- </button>
1440
- <button
1441
- type="button"
1442
- onClick={() => setAgentMode("worker")}
1443
- className={`flex-1 p-3 rounded border text-left transition ${
1444
- getAgentMode() === "worker"
1445
- ? "border-[#f97316] bg-[#f97316]/10"
1446
- : "border-[#222] hover:border-[#333]"
1447
- }`}
1448
- >
1449
- <div className={`text-sm font-medium ${getAgentMode() === "worker" ? "text-[#f97316]" : ""}`}>
1450
- Worker
1451
- </div>
1452
- <div className="text-xs text-[#666]">Receives tasks from coordinators</div>
1453
- </button>
1454
- </div>
1455
- {agent.projectId && (
1456
- <p className="text-xs text-[#555] mt-2">
1457
- Group: Using project as agent group
1458
- </p>
1459
- )}
1460
- </FormField>
1461
- )}
1462
-
1463
1592
  {/* Operator Browser Provider - shown when operator is enabled */}
1464
1593
  {isOperatorEnabled() && (
1465
1594
  <FormField label="Browser Provider">
@@ -1476,7 +1605,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1476
1605
  onChange={(value) => setOperatorBrowserProvider(value)}
1477
1606
  />
1478
1607
  ) : (
1479
- <p className="text-sm text-[#666] p-3 border border-[#222] rounded bg-[#0a0a0a]">
1608
+ <p className="text-sm text-[var(--color-text-muted)] p-3 border border-[var(--color-border-light)] rounded bg-[var(--color-bg)]">
1480
1609
  No browser providers configured. Go to Settings &rarr; Providers to add one.
1481
1610
  </p>
1482
1611
  )}
@@ -1501,8 +1630,8 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1501
1630
  }))}
1502
1631
  className={`flex items-center gap-2 px-3 py-2 rounded border transition ${
1503
1632
  form.features.builtinTools?.webSearch
1504
- ? "border-[#f97316] bg-[#f97316]/10 text-[#f97316]"
1505
- : "border-[#222] hover:border-[#333] text-[#888]"
1633
+ ? "border-[var(--color-accent)] bg-[var(--color-accent-10)] text-[var(--color-accent)]"
1634
+ : "border-[var(--color-border-light)] hover:border-[var(--color-border-light)] text-[var(--color-text-secondary)]"
1506
1635
  }`}
1507
1636
  >
1508
1637
  <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -1524,8 +1653,8 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1524
1653
  }))}
1525
1654
  className={`flex items-center gap-2 px-3 py-2 rounded border transition ${
1526
1655
  form.features.builtinTools?.webFetch
1527
- ? "border-[#f97316] bg-[#f97316]/10 text-[#f97316]"
1528
- : "border-[#222] hover:border-[#333] text-[#888]"
1656
+ ? "border-[var(--color-accent)] bg-[var(--color-accent-10)] text-[var(--color-accent)]"
1657
+ : "border-[var(--color-border-light)] hover:border-[var(--color-border-light)] text-[var(--color-text-secondary)]"
1529
1658
  }`}
1530
1659
  >
1531
1660
  <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -1534,7 +1663,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1534
1663
  <span className="text-sm">Web Fetch</span>
1535
1664
  </button>
1536
1665
  </div>
1537
- <p className="text-xs text-[#555] mt-2">
1666
+ <p className="text-xs text-[var(--color-text-faint)] mt-2">
1538
1667
  Provider-native tools for real-time web access
1539
1668
  </p>
1540
1669
  </FormField>
@@ -1544,7 +1673,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1544
1673
  {form.features.mcp && (
1545
1674
  <FormField label="MCP Servers">
1546
1675
  {availableMcpServers.length === 0 ? (
1547
- <p className="text-sm text-[#666]">
1676
+ <p className="text-sm text-[var(--color-text-muted)]">
1548
1677
  No MCP servers configured. Add servers in the MCP page first.
1549
1678
  </p>
1550
1679
  ) : (
@@ -1564,35 +1693,35 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1564
1693
  onClick={() => toggleMcpServer(server.id)}
1565
1694
  className={`w-full flex items-center gap-3 p-3 rounded border text-left transition ${
1566
1695
  form.mcpServers.includes(server.id)
1567
- ? "border-[#f97316] bg-[#f97316]/10"
1568
- : "border-[#222] hover:border-[#333]"
1696
+ ? "border-[var(--color-accent)] bg-[var(--color-accent-10)]"
1697
+ : "border-[var(--color-border-light)] hover:border-[var(--color-border-light)]"
1569
1698
  }`}
1570
1699
  >
1571
1700
  <div className={`w-2 h-2 rounded-full flex-shrink-0 ${
1572
- isAvailable ? "bg-green-400" : "bg-[#444]"
1701
+ isAvailable ? "bg-green-400" : "bg-[var(--color-scrollbar)]"
1573
1702
  }`} />
1574
1703
  <div className="flex-1 min-w-0">
1575
1704
  <div className="flex items-center gap-2">
1576
- <span className={`text-sm font-medium ${form.mcpServers.includes(server.id) ? "text-[#f97316]" : ""}`}>
1705
+ <span className={`text-sm font-medium ${form.mcpServers.includes(server.id) ? "text-[var(--color-accent)]" : ""}`}>
1577
1706
  {server.name}
1578
1707
  </span>
1579
1708
  {server.project_id === null && (
1580
- <span className="text-[10px] text-[#666] bg-[#1a1a1a] px-1.5 py-0.5 rounded">Global</span>
1709
+ <span className="text-[10px] text-[var(--color-text-muted)] bg-[var(--color-surface-raised)] px-1.5 py-0.5 rounded">Global</span>
1581
1710
  )}
1582
1711
  </div>
1583
- <div className="text-xs text-[#666]">{serverInfo}</div>
1712
+ <div className="text-xs text-[var(--color-text-muted)]">{serverInfo}</div>
1584
1713
  </div>
1585
1714
  <div className={`text-xs px-2 py-0.5 rounded ${
1586
1715
  isAvailable
1587
1716
  ? "bg-green-500/20 text-green-400"
1588
- : "bg-[#222] text-[#666]"
1717
+ : "bg-[var(--color-surface-raised)] text-[var(--color-text-muted)]"
1589
1718
  }`}>
1590
1719
  {isRemote ? "remote" : server.status}
1591
1720
  </div>
1592
1721
  </button>
1593
1722
  );
1594
1723
  })}
1595
- <p className="text-xs text-[#666] mt-2">
1724
+ <p className="text-xs text-[var(--color-text-muted)] mt-2">
1596
1725
  Remote servers are always available. Local servers must be running.
1597
1726
  </p>
1598
1727
  </div>
@@ -1603,7 +1732,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1603
1732
  {/* Skills Selection */}
1604
1733
  <FormField label="Skills">
1605
1734
  {availableSkills.length === 0 ? (
1606
- <p className="text-sm text-[#666]">
1735
+ <p className="text-sm text-[var(--color-text-muted)]">
1607
1736
  No skills configured. Add skills in the Skills page first.
1608
1737
  </p>
1609
1738
  ) : (
@@ -1617,27 +1746,27 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1617
1746
  onClick={() => toggleSkill(skill.id)}
1618
1747
  className={`w-full flex items-center gap-3 p-3 rounded border text-left transition ${
1619
1748
  form.skills.includes(skill.id)
1620
- ? "border-[#f97316] bg-[#f97316]/10"
1621
- : "border-[#222] hover:border-[#333]"
1749
+ ? "border-[var(--color-accent)] bg-[var(--color-accent-10)]"
1750
+ : "border-[var(--color-border-light)] hover:border-[var(--color-border-light)]"
1622
1751
  }`}
1623
1752
  >
1624
1753
  <div className="flex-1 min-w-0">
1625
1754
  <div className="flex items-center gap-2">
1626
- <span className={`text-sm font-medium ${form.skills.includes(skill.id) ? "text-[#f97316]" : ""}`}>
1755
+ <span className={`text-sm font-medium ${form.skills.includes(skill.id) ? "text-[var(--color-accent)]" : ""}`}>
1627
1756
  {skill.name}
1628
1757
  </span>
1629
1758
  {skill.project_id === null && (
1630
- <span className="text-[10px] text-[#666] bg-[#1a1a1a] px-1.5 py-0.5 rounded">Global</span>
1759
+ <span className="text-[10px] text-[var(--color-text-muted)] bg-[var(--color-surface-raised)] px-1.5 py-0.5 rounded">Global</span>
1631
1760
  )}
1632
1761
  </div>
1633
- <div className="text-xs text-[#666]">{skill.description}</div>
1762
+ <div className="text-xs text-[var(--color-text-muted)]">{skill.description}</div>
1634
1763
  </div>
1635
- <div className="text-xs px-2 py-0.5 rounded bg-[#222] text-[#666]">
1764
+ <div className="text-xs px-2 py-0.5 rounded bg-[var(--color-surface-raised)] text-[var(--color-text-muted)]">
1636
1765
  v{skill.version}
1637
1766
  </div>
1638
1767
  </button>
1639
1768
  ))}
1640
- <p className="text-xs text-[#666] mt-2">
1769
+ <p className="text-xs text-[var(--color-text-muted)] mt-2">
1641
1770
  Skills provide reusable instructions for the agent.
1642
1771
  </p>
1643
1772
  </div>
@@ -1657,31 +1786,31 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1657
1786
  <button
1658
1787
  onClick={handleSave}
1659
1788
  disabled={!hasChanges || saving || !form.name}
1660
- className="w-full bg-[#f97316] hover:bg-[#fb923c] disabled:opacity-50 disabled:cursor-not-allowed text-black px-4 py-2 rounded font-medium transition"
1789
+ className="w-full bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] disabled:opacity-50 disabled:cursor-not-allowed text-black px-4 py-2 rounded font-medium transition"
1661
1790
  >
1662
1791
  {saving ? "Saving..." : "Save Changes"}
1663
1792
  </button>
1664
1793
 
1665
1794
  {agent.status === "running" && hasChanges && (
1666
- <p className="text-xs text-[#666] text-center">
1795
+ <p className="text-xs text-[var(--color-text-muted)] text-center">
1667
1796
  Changes will be applied to the running agent
1668
1797
  </p>
1669
1798
  )}
1670
1799
 
1671
1800
  {/* Subscriptions */}
1672
- <div className="mt-8 pt-6 border-t border-[#222]">
1673
- <p className="text-sm text-[#666] mb-3">Subscriptions</p>
1801
+ <div className="mt-8 pt-6 border-t border-[var(--color-border-light)]">
1802
+ <p className="text-sm text-[var(--color-text-muted)] mb-3">Subscriptions</p>
1674
1803
  {subscriptions.length === 0 ? (
1675
- <p className="text-xs text-[#555]">No subscriptions. Set up triggers in Connections to have this agent listen to external events.</p>
1804
+ <p className="text-xs text-[var(--color-text-faint)]">No subscriptions. Set up triggers in Connections to have this agent listen to external events.</p>
1676
1805
  ) : (
1677
1806
  <div className="space-y-2">
1678
1807
  {subscriptions.map(sub => (
1679
- <div key={sub.id} className="flex items-center gap-2 px-3 py-2 bg-[#111] rounded border border-[#1a1a1a]">
1680
- <span className={`w-2 h-2 rounded-full shrink-0 ${sub.enabled ? "bg-cyan-400" : "bg-[#444]"}`} />
1681
- <span className={`text-sm flex-1 ${sub.enabled ? "text-cyan-400" : "text-[#666]"}`}>
1808
+ <div key={sub.id} className="flex items-center gap-2 px-3 py-2 bg-[var(--color-surface)] rounded border border-[var(--color-border)]">
1809
+ <span className={`w-2 h-2 rounded-full shrink-0 ${sub.enabled ? "bg-cyan-400" : "bg-[var(--color-scrollbar)]"}`} />
1810
+ <span className={`text-sm flex-1 ${sub.enabled ? "text-cyan-400" : "text-[var(--color-text-muted)]"}`}>
1682
1811
  {sub.trigger_slug.replace(/_/g, " ")}
1683
1812
  </span>
1684
- <span className={`text-[10px] px-1.5 py-0.5 rounded ${sub.enabled ? "bg-cyan-500/10 text-cyan-400" : "bg-[#222] text-[#555]"}`}>
1813
+ <span className={`text-[10px] px-1.5 py-0.5 rounded ${sub.enabled ? "bg-cyan-500/10 text-cyan-400" : "bg-[var(--color-surface-raised)] text-[var(--color-text-faint)]"}`}>
1685
1814
  {sub.enabled ? "active" : "disabled"}
1686
1815
  </span>
1687
1816
  </div>
@@ -1692,35 +1821,35 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1692
1821
 
1693
1822
  {/* Developer Info (dev mode only) */}
1694
1823
  {apiKey && (
1695
- <div className="mt-8 pt-6 border-t border-[#222]">
1696
- <p className="text-sm text-[#666] mb-3">Developer Info</p>
1824
+ <div className="mt-8 pt-6 border-t border-[var(--color-border-light)]">
1825
+ <p className="text-sm text-[var(--color-text-muted)] mb-3">Developer Info</p>
1697
1826
  <div className="space-y-2">
1698
1827
  <div className="flex items-center justify-between">
1699
- <span className="text-xs text-[#666]">Agent ID</span>
1700
- <code className="text-xs bg-[#1a1a1a] px-2 py-1 rounded text-[#888]">{agent.id}</code>
1828
+ <span className="text-xs text-[var(--color-text-muted)]">Agent ID</span>
1829
+ <code className="text-xs bg-[var(--color-surface-raised)] px-2 py-1 rounded text-[var(--color-text-secondary)]">{agent.id}</code>
1701
1830
  </div>
1702
1831
  <div className="flex items-center justify-between">
1703
- <span className="text-xs text-[#666]">Port</span>
1704
- <code className="text-xs bg-[#1a1a1a] px-2 py-1 rounded text-[#888]">{agent.port || "N/A"}</code>
1832
+ <span className="text-xs text-[var(--color-text-muted)]">Port</span>
1833
+ <code className="text-xs bg-[var(--color-surface-raised)] px-2 py-1 rounded text-[var(--color-text-secondary)]">{agent.port || "N/A"}</code>
1705
1834
  </div>
1706
1835
  <div className="flex flex-col gap-1">
1707
1836
  <div className="flex items-center justify-between">
1708
- <span className="text-xs text-[#666]">API Key</span>
1837
+ <span className="text-xs text-[var(--color-text-muted)]">API Key</span>
1709
1838
  <button
1710
1839
  onClick={() => setShowApiKey(!showApiKey)}
1711
- className="text-xs text-[#f97316] hover:text-[#fb923c]"
1840
+ className="text-xs text-[var(--color-accent)] hover:text-[var(--color-accent-hover)]"
1712
1841
  >
1713
1842
  {showApiKey ? "Hide" : "Show"}
1714
1843
  </button>
1715
1844
  </div>
1716
- <code className="text-xs bg-[#1a1a1a] px-2 py-1 rounded text-[#888] break-all">
1845
+ <code className="text-xs bg-[var(--color-surface-raised)] px-2 py-1 rounded text-[var(--color-text-secondary)] break-all">
1717
1846
  {showApiKey ? (apiKeyFull || apiKey) : apiKey}
1718
1847
  </code>
1719
1848
  </div>
1720
1849
  {agent.status === "running" && agent.port && (
1721
1850
  <div className="flex flex-col gap-1 mt-2">
1722
- <span className="text-xs text-[#666]">Test with curl</span>
1723
- <code className="text-xs bg-[#1a1a1a] px-2 py-1.5 rounded text-[#666] break-all">
1851
+ <span className="text-xs text-[var(--color-text-muted)]">Test with curl</span>
1852
+ <code className="text-xs bg-[var(--color-surface-raised)] px-2 py-1.5 rounded text-[var(--color-text-muted)] break-all">
1724
1853
  curl -H "X-API-Key: {showApiKey ? (apiKeyFull || apiKey) : "***"}" http://localhost:{agent.port}/config
1725
1854
  </code>
1726
1855
  </div>
@@ -1729,14 +1858,45 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1729
1858
  </div>
1730
1859
  )}
1731
1860
 
1861
+ {/* Share Link */}
1862
+ {shareToken && (
1863
+ <div className="mt-8 pt-6 border-t border-[var(--color-border-light)]">
1864
+ <p className="text-sm text-[var(--color-text-muted)] mb-3">Share Link</p>
1865
+ <p className="text-xs text-[var(--color-text-faint)] mb-3">
1866
+ Anyone with this link can chat with this agent. No login required. Regenerate the API key to invalidate.
1867
+ </p>
1868
+ <div className="flex gap-2">
1869
+ <code className="flex-1 text-xs bg-[var(--color-surface-raised)] px-3 py-2 rounded text-[var(--color-text-secondary)] break-all border border-[var(--color-border-light)]">
1870
+ {`${window.location.origin}/share/${shareToken}`}
1871
+ </code>
1872
+ <button
1873
+ onClick={() => {
1874
+ navigator.clipboard.writeText(`${window.location.origin}/share/${shareToken}`);
1875
+ setShareCopied(true);
1876
+ setTimeout(() => setShareCopied(false), 2000);
1877
+ }}
1878
+ className="px-3 py-2 text-xs bg-[var(--color-surface-raised)] hover:bg-[var(--color-surface-raised)] border border-[var(--color-border-light)] rounded text-[var(--color-text-secondary)] hover:text-[var(--color-text)] transition flex-shrink-0"
1879
+ >
1880
+ {shareCopied ? "Copied!" : "Copy"}
1881
+ </button>
1882
+ </div>
1883
+ <div className="mt-3">
1884
+ <p className="text-xs text-[var(--color-text-faint)] mb-1">Embed</p>
1885
+ <code className="block text-xs bg-[var(--color-surface-raised)] px-3 py-2 rounded text-[var(--color-text-muted)] break-all border border-[var(--color-border-light)]">
1886
+ {`<iframe src="${window.location.origin}/share/${shareToken}" width="400" height="600" style="border:none; border-radius:12px;" />`}
1887
+ </code>
1888
+ </div>
1889
+ </div>
1890
+ )}
1891
+
1732
1892
  {/* Danger Zone */}
1733
- <div className="mt-8 pt-6 border-t border-[#222]">
1734
- <p className="text-sm text-[#666] mb-3">Danger Zone</p>
1893
+ <div className="mt-8 pt-6 border-t border-[var(--color-border-light)]">
1894
+ <p className="text-sm text-[var(--color-text-muted)] mb-3">Danger Zone</p>
1735
1895
  {confirmDelete ? (
1736
1896
  <div className="flex gap-2">
1737
1897
  <button
1738
1898
  onClick={() => setConfirmDelete(false)}
1739
- className="flex-1 border border-[#333] hover:border-[#444] px-4 py-2 rounded font-medium transition"
1899
+ className="flex-1 border border-[var(--color-border-light)] hover:border-[var(--color-scrollbar)] px-4 py-2 rounded font-medium transition"
1740
1900
  >
1741
1901
  Cancel
1742
1902
  </button>
@@ -1764,7 +1924,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
1764
1924
  function FormField({ label, children }: { label: string; children: React.ReactNode }) {
1765
1925
  return (
1766
1926
  <div>
1767
- <label className="block text-sm text-[#666] mb-1">{label}</label>
1927
+ <label className="block text-sm text-[var(--color-text-muted)] mb-1">{label}</label>
1768
1928
  {children}
1769
1929
  </div>
1770
1930
  );