@swarmclawai/swarmclaw 0.4.0 → 0.5.0

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 (209) hide show
  1. package/README.md +21 -4
  2. package/bin/server-cmd.js +28 -19
  3. package/next.config.ts +13 -0
  4. package/package.json +3 -1
  5. package/src/app/api/agents/[id]/route.ts +39 -22
  6. package/src/app/api/agents/[id]/thread/route.ts +2 -2
  7. package/src/app/api/agents/route.ts +3 -2
  8. package/src/app/api/agents/trash/route.ts +44 -0
  9. package/src/app/api/clawhub/install/route.ts +2 -2
  10. package/src/app/api/connectors/[id]/route.ts +17 -7
  11. package/src/app/api/connectors/[id]/webhook/route.ts +103 -0
  12. package/src/app/api/connectors/route.ts +6 -3
  13. package/src/app/api/credentials/[id]/route.ts +2 -1
  14. package/src/app/api/credentials/route.ts +2 -2
  15. package/src/app/api/documents/route.ts +2 -2
  16. package/src/app/api/files/serve/route.ts +8 -0
  17. package/src/app/api/knowledge/[id]/route.ts +5 -4
  18. package/src/app/api/knowledge/upload/route.ts +2 -2
  19. package/src/app/api/mcp-servers/[id]/route.ts +11 -14
  20. package/src/app/api/mcp-servers/[id]/test/route.ts +2 -1
  21. package/src/app/api/mcp-servers/[id]/tools/route.ts +2 -1
  22. package/src/app/api/mcp-servers/route.ts +2 -2
  23. package/src/app/api/memory/[id]/route.ts +9 -8
  24. package/src/app/api/memory/route.ts +2 -2
  25. package/src/app/api/memory-images/[filename]/route.ts +2 -1
  26. package/src/app/api/openclaw/agent-files/route.ts +57 -0
  27. package/src/app/api/openclaw/approvals/route.ts +46 -0
  28. package/src/app/api/openclaw/config-sync/route.ts +33 -0
  29. package/src/app/api/openclaw/cron/route.ts +52 -0
  30. package/src/app/api/openclaw/directory/route.ts +27 -0
  31. package/src/app/api/openclaw/discover/route.ts +62 -0
  32. package/src/app/api/openclaw/dotenv-keys/route.ts +18 -0
  33. package/src/app/api/openclaw/exec-config/route.ts +41 -0
  34. package/src/app/api/openclaw/gateway/route.ts +72 -0
  35. package/src/app/api/openclaw/history/route.ts +109 -0
  36. package/src/app/api/openclaw/media/route.ts +53 -0
  37. package/src/app/api/openclaw/models/route.ts +12 -0
  38. package/src/app/api/openclaw/permissions/route.ts +39 -0
  39. package/src/app/api/openclaw/sandbox-env/route.ts +69 -0
  40. package/src/app/api/openclaw/skills/install/route.ts +32 -0
  41. package/src/app/api/openclaw/skills/remove/route.ts +24 -0
  42. package/src/app/api/openclaw/skills/route.ts +82 -0
  43. package/src/app/api/openclaw/sync/route.ts +31 -0
  44. package/src/app/api/orchestrator/run/route.ts +2 -2
  45. package/src/app/api/projects/[id]/route.ts +55 -0
  46. package/src/app/api/projects/route.ts +27 -0
  47. package/src/app/api/providers/[id]/models/route.ts +2 -1
  48. package/src/app/api/providers/[id]/route.ts +13 -15
  49. package/src/app/api/providers/route.ts +2 -2
  50. package/src/app/api/schedules/[id]/route.ts +16 -18
  51. package/src/app/api/schedules/[id]/run/route.ts +4 -3
  52. package/src/app/api/schedules/route.ts +2 -2
  53. package/src/app/api/secrets/[id]/route.ts +16 -17
  54. package/src/app/api/secrets/route.ts +2 -2
  55. package/src/app/api/sessions/[id]/clear/route.ts +2 -1
  56. package/src/app/api/sessions/[id]/deploy/route.ts +2 -1
  57. package/src/app/api/sessions/[id]/devserver/route.ts +2 -1
  58. package/src/app/api/sessions/[id]/edit-resend/route.ts +22 -0
  59. package/src/app/api/sessions/[id]/fork/route.ts +44 -0
  60. package/src/app/api/sessions/[id]/messages/route.ts +20 -2
  61. package/src/app/api/sessions/[id]/retry/route.ts +2 -1
  62. package/src/app/api/sessions/[id]/route.ts +14 -4
  63. package/src/app/api/sessions/route.ts +8 -4
  64. package/src/app/api/skills/[id]/route.ts +23 -21
  65. package/src/app/api/skills/import/route.ts +2 -2
  66. package/src/app/api/skills/route.ts +2 -2
  67. package/src/app/api/tasks/[id]/approve/route.ts +2 -1
  68. package/src/app/api/tasks/[id]/route.ts +6 -5
  69. package/src/app/api/tasks/route.ts +2 -2
  70. package/src/app/api/tts/stream/route.ts +48 -0
  71. package/src/app/api/upload/route.ts +2 -2
  72. package/src/app/api/uploads/[filename]/route.ts +4 -1
  73. package/src/app/api/webhooks/[id]/route.ts +29 -31
  74. package/src/app/api/webhooks/route.ts +2 -2
  75. package/src/app/globals.css +14 -0
  76. package/src/app/layout.tsx +5 -20
  77. package/src/app/page.tsx +3 -24
  78. package/src/cli/index.js +60 -0
  79. package/src/cli/index.ts +1 -1
  80. package/src/cli/spec.js +42 -0
  81. package/src/components/agents/agent-avatar.tsx +45 -0
  82. package/src/components/agents/agent-card.tsx +19 -5
  83. package/src/components/agents/agent-chat-list.tsx +31 -24
  84. package/src/components/agents/agent-files-editor.tsx +185 -0
  85. package/src/components/agents/agent-list.tsx +84 -3
  86. package/src/components/agents/agent-sheet.tsx +147 -14
  87. package/src/components/agents/cron-job-form.tsx +137 -0
  88. package/src/components/agents/exec-config-panel.tsx +147 -0
  89. package/src/components/agents/inspector-panel.tsx +310 -0
  90. package/src/components/agents/openclaw-skills-panel.tsx +230 -0
  91. package/src/components/agents/permission-preset-selector.tsx +79 -0
  92. package/src/components/agents/personality-builder.tsx +111 -0
  93. package/src/components/agents/sandbox-env-panel.tsx +72 -0
  94. package/src/components/agents/skill-install-dialog.tsx +102 -0
  95. package/src/components/agents/trash-list.tsx +109 -0
  96. package/src/components/chat/chat-area.tsx +41 -6
  97. package/src/components/chat/chat-header.tsx +305 -29
  98. package/src/components/chat/chat-preview-panel.tsx +113 -0
  99. package/src/components/chat/exec-approval-card.tsx +89 -0
  100. package/src/components/chat/message-bubble.tsx +218 -36
  101. package/src/components/chat/message-list.tsx +135 -31
  102. package/src/components/chat/streaming-bubble.tsx +59 -10
  103. package/src/components/chat/suggestions-bar.tsx +74 -0
  104. package/src/components/chat/thinking-indicator.tsx +20 -6
  105. package/src/components/chat/tool-call-bubble.tsx +98 -19
  106. package/src/components/chat/tool-request-banner.tsx +20 -2
  107. package/src/components/chat/trace-block.tsx +103 -0
  108. package/src/components/chat/voice-overlay.tsx +80 -0
  109. package/src/components/connectors/connector-list.tsx +6 -2
  110. package/src/components/connectors/connector-sheet.tsx +31 -7
  111. package/src/components/layout/app-layout.tsx +47 -25
  112. package/src/components/projects/project-list.tsx +123 -0
  113. package/src/components/projects/project-sheet.tsx +135 -0
  114. package/src/components/schedules/schedule-list.tsx +3 -1
  115. package/src/components/sessions/new-session-sheet.tsx +6 -6
  116. package/src/components/sessions/session-card.tsx +1 -1
  117. package/src/components/sessions/session-list.tsx +7 -7
  118. package/src/components/settings/gateway-connection-panel.tsx +278 -0
  119. package/src/components/shared/avatar.tsx +13 -2
  120. package/src/components/shared/connector-platform-icon.tsx +4 -0
  121. package/src/components/shared/settings/section-heartbeat.tsx +1 -1
  122. package/src/components/shared/settings/section-orchestrator.tsx +1 -2
  123. package/src/components/shared/settings/section-web-search.tsx +56 -0
  124. package/src/components/shared/settings/settings-page.tsx +74 -0
  125. package/src/components/skills/skill-list.tsx +2 -1
  126. package/src/components/tasks/task-board.tsx +1 -1
  127. package/src/components/tasks/task-list.tsx +5 -2
  128. package/src/components/tasks/task-sheet.tsx +12 -12
  129. package/src/hooks/use-continuous-speech.ts +181 -0
  130. package/src/hooks/use-openclaw-gateway.ts +63 -0
  131. package/src/hooks/use-view-router.ts +52 -0
  132. package/src/hooks/use-voice-conversation.ts +80 -0
  133. package/src/lib/id.ts +6 -0
  134. package/src/lib/notification-sounds.ts +58 -0
  135. package/src/lib/personality-parser.ts +97 -0
  136. package/src/lib/projects.ts +13 -0
  137. package/src/lib/provider-sets.ts +5 -0
  138. package/src/lib/providers/anthropic.ts +14 -1
  139. package/src/lib/providers/index.ts +6 -0
  140. package/src/lib/providers/ollama.ts +9 -1
  141. package/src/lib/providers/openai.ts +9 -1
  142. package/src/lib/providers/openclaw.ts +28 -2
  143. package/src/lib/runtime-loop.ts +2 -2
  144. package/src/lib/server/api-routes.test.ts +5 -6
  145. package/src/lib/server/build-llm.ts +17 -4
  146. package/src/lib/server/chat-execution.ts +82 -6
  147. package/src/lib/server/collection-helpers.ts +54 -0
  148. package/src/lib/server/connectors/bluebubbles.test.ts +217 -0
  149. package/src/lib/server/connectors/bluebubbles.ts +360 -0
  150. package/src/lib/server/connectors/connector-routing.test.ts +1 -1
  151. package/src/lib/server/connectors/googlechat.ts +51 -8
  152. package/src/lib/server/connectors/manager.ts +424 -13
  153. package/src/lib/server/connectors/media.ts +2 -2
  154. package/src/lib/server/connectors/openclaw.ts +65 -0
  155. package/src/lib/server/connectors/pairing.test.ts +99 -0
  156. package/src/lib/server/connectors/pairing.ts +256 -0
  157. package/src/lib/server/connectors/signal.ts +1 -0
  158. package/src/lib/server/connectors/teams.ts +5 -5
  159. package/src/lib/server/connectors/types.ts +10 -0
  160. package/src/lib/server/daemon-state.ts +11 -0
  161. package/src/lib/server/execution-log.ts +3 -3
  162. package/src/lib/server/heartbeat-service.ts +1 -1
  163. package/src/lib/server/knowledge-db.test.ts +2 -33
  164. package/src/lib/server/main-agent-loop.ts +8 -9
  165. package/src/lib/server/main-session.ts +21 -0
  166. package/src/lib/server/memory-db.ts +6 -6
  167. package/src/lib/server/openclaw-approvals.ts +105 -0
  168. package/src/lib/server/openclaw-config-sync.ts +107 -0
  169. package/src/lib/server/openclaw-exec-config.ts +52 -0
  170. package/src/lib/server/openclaw-gateway.ts +291 -0
  171. package/src/lib/server/openclaw-history-merge.ts +36 -0
  172. package/src/lib/server/openclaw-models.ts +56 -0
  173. package/src/lib/server/openclaw-permission-presets.ts +64 -0
  174. package/src/lib/server/openclaw-sync.ts +497 -0
  175. package/src/lib/server/orchestrator-lg.ts +30 -9
  176. package/src/lib/server/orchestrator.ts +4 -4
  177. package/src/lib/server/process-manager.ts +2 -2
  178. package/src/lib/server/queue.ts +24 -11
  179. package/src/lib/server/scheduler.ts +2 -2
  180. package/src/lib/server/session-mailbox.ts +2 -2
  181. package/src/lib/server/session-run-manager.ts +2 -2
  182. package/src/lib/server/session-tools/connector.ts +53 -6
  183. package/src/lib/server/session-tools/crud.ts +3 -3
  184. package/src/lib/server/session-tools/delegate.ts +22 -6
  185. package/src/lib/server/session-tools/file.ts +192 -19
  186. package/src/lib/server/session-tools/index.ts +4 -2
  187. package/src/lib/server/session-tools/memory.ts +2 -2
  188. package/src/lib/server/session-tools/openclaw-nodes.ts +112 -0
  189. package/src/lib/server/session-tools/sandbox.ts +33 -0
  190. package/src/lib/server/session-tools/search-providers.ts +277 -0
  191. package/src/lib/server/session-tools/session-info.ts +2 -2
  192. package/src/lib/server/session-tools/session-tools-wiring.test.ts +2 -2
  193. package/src/lib/server/session-tools/shell.ts +1 -1
  194. package/src/lib/server/session-tools/web.ts +53 -72
  195. package/src/lib/server/storage.ts +74 -11
  196. package/src/lib/server/stream-agent-chat.ts +53 -4
  197. package/src/lib/server/suggestions.ts +20 -0
  198. package/src/lib/server/task-result.test.ts +44 -0
  199. package/src/lib/server/task-result.ts +14 -0
  200. package/src/lib/server/ws-hub.ts +14 -0
  201. package/src/lib/tool-definitions.ts +5 -3
  202. package/src/lib/tts-stream.ts +130 -0
  203. package/src/lib/view-routes.ts +28 -0
  204. package/src/proxy.ts +3 -0
  205. package/src/stores/use-app-store.ts +80 -1
  206. package/src/stores/use-approval-store.ts +78 -0
  207. package/src/stores/use-chat-store.ts +162 -6
  208. package/src/types/index.ts +154 -3
  209. package/tsconfig.json +13 -4
@@ -6,7 +6,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/u
6
6
  import { useAppStore } from '@/stores/use-app-store'
7
7
  import { useMediaQuery } from '@/hooks/use-media-query'
8
8
  import { Avatar } from '@/components/shared/avatar'
9
- import { SettingsSheet } from '@/components/shared/settings-sheet'
9
+ import { SettingsPage } from '@/components/shared/settings/settings-page'
10
10
  import { AgentList } from '@/components/agents/agent-list'
11
11
  import { AgentChatList } from '@/components/agents/agent-chat-list'
12
12
  import { AgentSheet } from '@/components/agents/agent-sheet'
@@ -37,6 +37,8 @@ import { PluginList } from '@/components/plugins/plugin-list'
37
37
  import { PluginSheet } from '@/components/plugins/plugin-sheet'
38
38
  import { UsageList } from '@/components/usage/usage-list'
39
39
  import { RunList } from '@/components/runs/run-list'
40
+ import { ProjectList } from '@/components/projects/project-list'
41
+ import { ProjectSheet } from '@/components/projects/project-sheet'
40
42
  import { NetworkBanner } from './network-banner'
41
43
  import { UpdateBanner } from './update-banner'
42
44
  import { MobileHeader } from './mobile-header'
@@ -53,7 +55,6 @@ export function AppLayout() {
53
55
  const currentSessionId = useAppStore((s) => s.currentSessionId)
54
56
  const sidebarOpen = useAppStore((s) => s.sidebarOpen)
55
57
  const setSidebarOpen = useAppStore((s) => s.setSidebarOpen)
56
- const setSettingsOpen = useAppStore((s) => s.setSettingsOpen)
57
58
  const setUser = useAppStore((s) => s.setUser)
58
59
  const setCurrentSession = useAppStore((s) => s.setCurrentSession)
59
60
  const activeView = useAppStore((s) => s.activeView)
@@ -69,6 +70,7 @@ export function AppLayout() {
69
70
  const setMcpServerSheetOpen = useAppStore((s) => s.setMcpServerSheetOpen)
70
71
  const setKnowledgeSheetOpen = useAppStore((s) => s.setKnowledgeSheetOpen)
71
72
  const setPluginSheetOpen = useAppStore((s) => s.setPluginSheetOpen)
73
+ const setProjectSheetOpen = useAppStore((s) => s.setProjectSheetOpen)
72
74
  const tasks = useAppStore((s) => s.tasks)
73
75
  const isDesktop = useMediaQuery('(min-width: 768px)')
74
76
  const hasSelectedSession = !!(currentSessionId && sessions[currentSessionId])
@@ -128,6 +130,7 @@ export function AppLayout() {
128
130
  else if (activeView === 'mcp_servers') setMcpServerSheetOpen(true)
129
131
  else if (activeView === 'knowledge') setKnowledgeSheetOpen(true)
130
132
  else if (activeView === 'plugins') setPluginSheetOpen(true)
133
+ else if (activeView === 'projects') setProjectSheetOpen(true)
131
134
  }
132
135
 
133
136
  const handleNavClick = (view: AppView) => {
@@ -145,15 +148,11 @@ export function AppLayout() {
145
148
  const agents = useAppStore((s) => s.agents)
146
149
  const currentAgentId = useAppStore((s) => s.currentAgentId)
147
150
  const setCurrentAgent = useAppStore((s) => s.setCurrentAgent)
148
- const mainSession = Object.values(sessions).find((s) => s.name === '__main__' && s.user === currentUser)
149
-
150
151
  const goToMainChat = async () => {
151
152
  // Navigate to default agent's chat thread
152
153
  const defaultAgent = agents['default'] || Object.values(agents)[0]
153
154
  if (defaultAgent) {
154
155
  await setCurrentAgent(defaultAgent.id)
155
- } else if (mainSession) {
156
- setCurrentSession(mainSession.id)
157
156
  }
158
157
  setActiveView('agents')
159
158
  setSidebarOpen(false)
@@ -245,6 +244,11 @@ export function AppLayout() {
245
244
  <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" />
246
245
  </svg>
247
246
  </NavItem>
247
+ <NavItem view="projects" label="Projects" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('projects')}>
248
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
249
+ <path d="M2 20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-7-7H4a2 2 0 0 0-2 2v17Z" /><path d="M14 2v7h7" />
250
+ </svg>
251
+ </NavItem>
248
252
  <NavItem view="schedules" label="Schedules" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('schedules')}>
249
253
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
250
254
  <circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 14" />
@@ -355,7 +359,7 @@ export function AppLayout() {
355
359
  {railExpanded && <DaemonIndicator />}
356
360
  {railExpanded ? (
357
361
  <button
358
- onClick={() => setSettingsOpen(true)}
362
+ onClick={() => handleNavClick('settings')}
359
363
  className="w-full flex items-center gap-2.5 px-3 py-2 rounded-[10px] text-[13px] font-500 cursor-pointer transition-all
360
364
  bg-transparent text-text-3 hover:text-text hover:bg-white/[0.04] border-none"
361
365
  style={{ fontFamily: 'inherit' }}
@@ -368,7 +372,7 @@ export function AppLayout() {
368
372
  </button>
369
373
  ) : (
370
374
  <RailTooltip label="Settings" description="API keys, providers & app config">
371
- <button onClick={() => setSettingsOpen(true)} className="rail-btn">
375
+ <button onClick={() => handleNavClick('settings')} className="rail-btn">
372
376
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
373
377
  <circle cx="12" cy="12" r="3" />
374
378
  <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
@@ -486,7 +490,7 @@ export function AppLayout() {
486
490
  <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" /><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" />
487
491
  </svg>
488
492
  </a>
489
- <button onClick={() => setSettingsOpen(true)} className="rail-btn">
493
+ <button onClick={() => handleNavClick('settings')} className="rail-btn">
490
494
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
491
495
  <circle cx="12" cy="12" r="3" />
492
496
  <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
@@ -512,7 +516,7 @@ export function AppLayout() {
512
516
  </button>
513
517
  ))}
514
518
  </div>
515
- {activeView !== 'logs' && activeView !== 'usage' && activeView !== 'runs' && (
519
+ {activeView !== 'logs' && activeView !== 'usage' && activeView !== 'runs' && activeView !== 'settings' && (
516
520
  <div className="px-4 py-2.5 shrink-0">
517
521
  <button
518
522
  onClick={() => {
@@ -524,7 +528,7 @@ export function AppLayout() {
524
528
  shadow-[0_2px_12px_rgba(99,102,241,0.15)]"
525
529
  style={{ fontFamily: 'inherit' }}
526
530
  >
527
- + New {activeView === 'agents' ? 'Agent' : activeView === 'schedules' ? 'Schedule' : activeView === 'tasks' ? 'Task' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : activeView === 'plugins' ? 'Plugin' : 'Entry'}
531
+ + New {activeView === 'agents' ? 'Agent' : activeView === 'schedules' ? 'Schedule' : activeView === 'tasks' ? 'Task' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : activeView === 'plugins' ? 'Plugin' : activeView === 'projects' ? 'Project' : 'Entry'}
528
532
  </button>
529
533
  </div>
530
534
  )}
@@ -557,6 +561,7 @@ export function AppLayout() {
557
561
  {activeView === 'mcp_servers' && <McpServerList />}
558
562
  {activeView === 'knowledge' && <KnowledgeList />}
559
563
  {activeView === 'plugins' && <PluginList inSidebar />}
564
+ {activeView === 'projects' && <ProjectList />}
560
565
  {activeView === 'usage' && <UsageList />}
561
566
  {activeView === 'runs' && <RunList />}
562
567
  {activeView === 'logs' && <LogList />}
@@ -591,6 +596,8 @@ export function AppLayout() {
591
596
  <TaskBoard />
592
597
  ) : activeView === 'memory' ? (
593
598
  <MemoryDetail />
599
+ ) : activeView === 'settings' ? (
600
+ <SettingsPage />
594
601
  ) : !sidebarOpen && FULL_WIDTH_VIEWS.has(activeView) ? (
595
602
  <div className="flex-1 flex flex-col h-full">
596
603
  <div className="flex items-center px-6 pt-5 pb-3 shrink-0">
@@ -606,7 +613,7 @@ export function AppLayout() {
606
613
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
607
614
  <line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" />
608
615
  </svg>
609
- {activeView === 'schedules' ? 'Schedule' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : activeView === 'plugins' ? 'Plugin' : 'New'}
616
+ {activeView === 'schedules' ? 'Schedule' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : activeView === 'plugins' ? 'Plugin' : activeView === 'projects' ? 'Project' : 'New'}
610
617
  </button>
611
618
  )}
612
619
  </div>
@@ -619,6 +626,7 @@ export function AppLayout() {
619
626
  {activeView === 'mcp_servers' && <McpServerList />}
620
627
  {activeView === 'knowledge' && <KnowledgeList />}
621
628
  {activeView === 'plugins' && <PluginList />}
629
+ {activeView === 'projects' && <ProjectList />}
622
630
  {activeView === 'usage' && <UsageList />}
623
631
  {activeView === 'runs' && <RunList />}
624
632
  {activeView === 'logs' && <LogList />}
@@ -629,7 +637,6 @@ export function AppLayout() {
629
637
  </div>
630
638
  </ErrorBoundary>
631
639
 
632
- <SettingsSheet />
633
640
  <AgentSheet />
634
641
  <ScheduleSheet />
635
642
  <MemorySheet />
@@ -642,6 +649,7 @@ export function AppLayout() {
642
649
  <McpServerSheet />
643
650
  <KnowledgeSheet />
644
651
  <PluginSheet />
652
+ <ProjectSheet />
645
653
 
646
654
  <Dialog open={shortcutsOpen} onOpenChange={setShortcutsOpen}>
647
655
  <DialogContent className="sm:max-w-[380px] bg-raised border-white/[0.08]">
@@ -735,13 +743,15 @@ const VIEW_DESCRIPTIONS: Record<AppView, string> = {
735
743
  logs: 'Application logs & error tracking',
736
744
  plugins: 'Extend agent capabilities with custom plugins',
737
745
  usage: 'Token usage analytics & cost tracking',
738
- runs: 'Live session run monitoring & history',
746
+ runs: 'Live run monitoring & history',
747
+ settings: 'Manage providers, API keys & orchestrator engine',
748
+ projects: 'Group agents, tasks & schedules into projects',
739
749
  }
740
750
 
741
751
  const FULL_WIDTH_VIEWS = new Set<AppView>([
742
752
  'schedules', 'secrets', 'providers', 'skills',
743
753
  'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'plugins',
744
- 'usage', 'runs', 'logs',
754
+ 'usage', 'runs', 'logs', 'settings', 'projects',
745
755
  ])
746
756
 
747
757
  const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents'>, { icon: string; title: string; description: string; features: string[] }> = {
@@ -754,14 +764,14 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents'>, { icon: string; titl
754
764
  memory: {
755
765
  icon: 'database',
756
766
  title: 'Memory',
757
- description: 'Long-term memory store for AI agents. Orchestrators can store and retrieve knowledge across sessions.',
758
- features: ['Agents store findings and learnings automatically', 'Full-text search across all stored memories', 'Organized by categories and agents', 'Persists across sessions for continuity'],
767
+ description: 'Long-term memory store for AI agents. Orchestrators can store and retrieve knowledge across conversations.',
768
+ features: ['Agents store findings and learnings automatically', 'Full-text search across all stored memories', 'Organized by categories and agents', 'Persists across conversations for continuity'],
759
769
  },
760
770
  tasks: {
761
771
  icon: 'clipboard',
762
772
  title: 'Task Board',
763
773
  description: 'A Trello-style board for managing orchestrator jobs. Create tasks, assign them to orchestrators, and track progress.',
764
- features: ['Kanban columns: Backlog, Queued, Running, Completed, Failed', 'Assign tasks to specific orchestrator agents', 'Sequential queue ensures orchestrators don\'t conflict', 'View results and session logs for completed tasks'],
774
+ features: ['Kanban columns: Backlog, Queued, Running, Completed, Failed', 'Assign tasks to specific orchestrator agents', 'Sequential queue ensures orchestrators don\'t conflict', 'View results and logs for completed tasks'],
765
775
  },
766
776
  secrets: {
767
777
  icon: 'lock',
@@ -785,7 +795,7 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents'>, { icon: string; titl
785
795
  icon: 'link',
786
796
  title: 'Connectors',
787
797
  description: 'Bridge chat platforms to your AI agents. Receive messages from Discord, Telegram, Slack, or WhatsApp and route them to agents.',
788
- features: ['Connect Discord, Telegram, Slack, or WhatsApp bots', 'Route incoming messages to any agent', 'Each platform channel gets its own session', 'Start and stop connectors from the UI'],
798
+ features: ['Connect Discord, Telegram, Slack, or WhatsApp bots', 'Route incoming messages to any agent', 'Each platform channel gets its own chat thread', 'Start and stop connectors from the UI'],
789
799
  },
790
800
  webhooks: {
791
801
  icon: 'webhook',
@@ -796,7 +806,7 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents'>, { icon: string; titl
796
806
  mcp_servers: {
797
807
  icon: 'server',
798
808
  title: 'MCP Servers',
799
- description: 'Connect agents to external MCP (Model Context Protocol) servers, injecting their tools into chat sessions.',
809
+ description: 'Connect agents to external MCP (Model Context Protocol) servers, injecting their tools into agent chats.',
800
810
  features: ['Configure stdio, SSE, or streamable HTTP transports', 'Test connections and discover available tools', 'Assign MCP servers to specific agents', 'Tools appear alongside built-in tools in chat'],
801
811
  },
802
812
  knowledge: {
@@ -820,15 +830,27 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents'>, { icon: string; titl
820
830
  usage: {
821
831
  icon: 'bar-chart',
822
832
  title: 'Usage',
823
- description: 'Track token usage and costs across all providers and sessions.',
824
- features: ['Per-provider cost breakdown', 'Token usage over time', 'Session-level cost tracking', 'Export usage data'],
833
+ description: 'Track token usage and costs across all providers and agents.',
834
+ features: ['Per-provider cost breakdown', 'Token usage over time', 'Per-agent cost tracking', 'Export usage data'],
825
835
  },
826
836
  runs: {
827
837
  icon: 'activity',
828
838
  title: 'Runs',
829
- description: 'View the session run queue and execution history.',
839
+ description: 'View the run queue and execution history.',
830
840
  features: ['Monitor queued and running tasks', 'View run results and errors', 'Cancel pending runs', 'Automatic retry tracking'],
831
841
  },
842
+ settings: {
843
+ icon: 'settings',
844
+ title: 'Settings',
845
+ description: 'Manage providers, API keys & orchestrator engine.',
846
+ features: ['Configure LLM providers', 'Manage API credentials', 'Tune orchestrator settings', 'Set up voice & embedding'],
847
+ },
848
+ projects: {
849
+ icon: 'folder',
850
+ title: 'Projects',
851
+ description: 'Organize your work into projects. Group agents, tasks, and schedules under a common scope.',
852
+ features: ['Create named projects with color badges', 'Assign agents and tasks to projects', 'Filter sidebar views by project', 'Global view when no filter is active'],
853
+ },
832
854
  }
833
855
 
834
856
  function ViewEmptyState({ view }: { view: AppView }) {
@@ -1016,7 +1038,7 @@ function DesktopEmptyState({ userName }: { userName: string | null }) {
1016
1038
  <span className="text-text-2">What would you like to do?</span>
1017
1039
  </h1>
1018
1040
  <p className="text-[15px] text-text-3 mb-12">
1019
- Create a new session to start chatting
1041
+ Create a new chat to start chatting
1020
1042
  </p>
1021
1043
  <button
1022
1044
  onClick={() => setNewSessionOpen(true)}
@@ -1029,7 +1051,7 @@ function DesktopEmptyState({ userName }: { userName: string | null }) {
1029
1051
  <line x1="12" y1="5" x2="12" y2="19" />
1030
1052
  <line x1="5" y1="12" x2="19" y2="12" />
1031
1053
  </svg>
1032
- New Session
1054
+ New Chat
1033
1055
  </button>
1034
1056
  </div>
1035
1057
  </div>
@@ -0,0 +1,123 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useMemo, useState } from 'react'
4
+ import { useAppStore } from '@/stores/use-app-store'
5
+
6
+ export function ProjectList() {
7
+ const projects = useAppStore((s) => s.projects)
8
+ const loadProjects = useAppStore((s) => s.loadProjects)
9
+ const agents = useAppStore((s) => s.agents)
10
+ const tasks = useAppStore((s) => s.tasks)
11
+ const setProjectSheetOpen = useAppStore((s) => s.setProjectSheetOpen)
12
+ const setEditingProjectId = useAppStore((s) => s.setEditingProjectId)
13
+ const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
14
+ const setActiveProjectFilter = useAppStore((s) => s.setActiveProjectFilter)
15
+ const [search, setSearch] = useState('')
16
+
17
+ // eslint-disable-next-line react-hooks/exhaustive-deps
18
+ useEffect(() => { loadProjects() }, [])
19
+
20
+ const filtered = useMemo(() => {
21
+ return Object.values(projects)
22
+ .filter((p) => {
23
+ if (search && !p.name.toLowerCase().includes(search.toLowerCase())) return false
24
+ return true
25
+ })
26
+ .sort((a, b) => b.updatedAt - a.updatedAt)
27
+ }, [projects, search])
28
+
29
+ const entityCounts = useMemo(() => {
30
+ const counts: Record<string, { agents: number; tasks: number }> = {}
31
+ for (const p of Object.values(projects)) {
32
+ counts[p.id] = { agents: 0, tasks: 0 }
33
+ }
34
+ for (const a of Object.values(agents)) {
35
+ if (a.projectId && counts[a.projectId]) counts[a.projectId].agents++
36
+ }
37
+ for (const t of Object.values(tasks)) {
38
+ if (t.projectId && counts[t.projectId]) counts[t.projectId].tasks++
39
+ }
40
+ return counts
41
+ }, [projects, agents, tasks])
42
+
43
+ if (!filtered.length && !search) {
44
+ return (
45
+ <div className="flex-1 flex flex-col items-center justify-center gap-4 text-text-3 p-8 text-center">
46
+ <div className="w-12 h-12 rounded-[14px] bg-accent-soft flex items-center justify-center mb-1">
47
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-accent-bright">
48
+ <path d="M2 20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-7-7H4a2 2 0 0 0-2 2v17Z" />
49
+ <path d="M14 2v7h7" />
50
+ </svg>
51
+ </div>
52
+ <p className="font-display text-[15px] font-600 text-text-2">No projects yet</p>
53
+ <p className="text-[13px] text-text-3/50">Group agents, tasks, and schedules into projects</p>
54
+ <button
55
+ onClick={() => { setEditingProjectId(null); setProjectSheetOpen(true) }}
56
+ className="inline-flex items-center gap-1.5 px-4 py-2 text-[13px] font-500 text-white bg-accent rounded-lg hover:bg-accent-bright transition-colors"
57
+ >
58
+ <span className="text-lg leading-none">+</span> New Project
59
+ </button>
60
+ </div>
61
+ )
62
+ }
63
+
64
+ return (
65
+ <div className="flex-1 flex flex-col h-full overflow-y-auto">
66
+ <div className="p-4 pb-0">
67
+ <div className="flex items-center gap-2 mb-4">
68
+ <input
69
+ type="text"
70
+ value={search}
71
+ onChange={(e) => setSearch(e.target.value)}
72
+ placeholder="Search projects..."
73
+ className="flex-1 px-3 py-2 rounded-lg bg-white/[0.06] border border-white/[0.06] text-[13px] text-text-1 placeholder:text-text-3/40 focus:outline-none focus:border-accent/40"
74
+ style={{ fontFamily: 'inherit' }}
75
+ />
76
+ </div>
77
+ </div>
78
+ <div className="flex-1 overflow-y-auto px-4 pb-4 space-y-2">
79
+ {filtered.map((project) => {
80
+ const counts = entityCounts[project.id] || { agents: 0, tasks: 0 }
81
+ const isActive = activeProjectFilter === project.id
82
+ return (
83
+ <div
84
+ key={project.id}
85
+ className={`group relative p-4 rounded-xl border transition-colors cursor-pointer ${
86
+ isActive
87
+ ? 'bg-accent/10 border-accent/30'
88
+ : 'bg-white/[0.03] border-white/[0.06] hover:bg-white/[0.06]'
89
+ }`}
90
+ onClick={() => setActiveProjectFilter(isActive ? null : project.id)}
91
+ >
92
+ <div className="flex items-start justify-between gap-3">
93
+ <div className="flex items-center gap-2.5 min-w-0">
94
+ {project.color && (
95
+ <div className="w-3 h-3 rounded-full shrink-0" style={{ backgroundColor: project.color }} />
96
+ )}
97
+ <div className="min-w-0">
98
+ <div className="font-display text-[14px] font-600 text-text-1 truncate">{project.name}</div>
99
+ {project.description && (
100
+ <p className="text-[12px] text-text-3/60 mt-0.5 line-clamp-2">{project.description}</p>
101
+ )}
102
+ </div>
103
+ </div>
104
+ <button
105
+ onClick={(e) => { e.stopPropagation(); setEditingProjectId(project.id); setProjectSheetOpen(true) }}
106
+ className="opacity-0 group-hover:opacity-100 p-1.5 rounded-md hover:bg-white/[0.08] transition-all text-text-3/50 hover:text-text-2"
107
+ >
108
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
109
+ <path d="M17 3a2.83 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" />
110
+ </svg>
111
+ </button>
112
+ </div>
113
+ <div className="flex items-center gap-3 mt-2.5 text-[11px] text-text-3/50">
114
+ <span>{counts.agents} agent{counts.agents !== 1 ? 's' : ''}</span>
115
+ <span>{counts.tasks} task{counts.tasks !== 1 ? 's' : ''}</span>
116
+ </div>
117
+ </div>
118
+ )
119
+ })}
120
+ </div>
121
+ </div>
122
+ )
123
+ }
@@ -0,0 +1,135 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useState } from 'react'
4
+ import { useAppStore } from '@/stores/use-app-store'
5
+ import { createProject, updateProject, deleteProject } from '@/lib/projects'
6
+ import { BottomSheet } from '@/components/shared/bottom-sheet'
7
+ import { toast } from 'sonner'
8
+
9
+ const PROJECT_COLORS = [
10
+ '#EF4444', '#F97316', '#EAB308', '#22C55E', '#06B6D4',
11
+ '#3B82F6', '#8B5CF6', '#EC4899', '#6B7280',
12
+ ]
13
+
14
+ const inputClass = 'w-full px-3 py-2.5 rounded-lg bg-white/[0.06] border border-white/[0.06] text-[13px] text-text-1 placeholder:text-text-3/40 focus:outline-none focus:border-accent/40 transition-colors'
15
+
16
+ export function ProjectSheet() {
17
+ const open = useAppStore((s) => s.projectSheetOpen)
18
+ const setOpen = useAppStore((s) => s.setProjectSheetOpen)
19
+ const editingId = useAppStore((s) => s.editingProjectId)
20
+ const setEditingId = useAppStore((s) => s.setEditingProjectId)
21
+ const projects = useAppStore((s) => s.projects)
22
+ const loadProjects = useAppStore((s) => s.loadProjects)
23
+
24
+ const [name, setName] = useState('')
25
+ const [description, setDescription] = useState('')
26
+ const [color, setColor] = useState<string | undefined>(undefined)
27
+
28
+ const editing = editingId ? projects[editingId] : null
29
+
30
+ useEffect(() => {
31
+ if (open) {
32
+ if (editing) {
33
+ setName(editing.name)
34
+ setDescription(editing.description)
35
+ setColor(editing.color)
36
+ } else {
37
+ setName('')
38
+ setDescription('')
39
+ setColor(PROJECT_COLORS[0])
40
+ }
41
+ }
42
+ // eslint-disable-next-line react-hooks/exhaustive-deps
43
+ }, [open, editingId])
44
+
45
+ const onClose = () => {
46
+ setOpen(false)
47
+ setEditingId(null)
48
+ }
49
+
50
+ const handleSave = async () => {
51
+ const data = {
52
+ name: name.trim() || 'Unnamed Project',
53
+ description,
54
+ color,
55
+ }
56
+ if (editing) {
57
+ await updateProject(editing.id, data)
58
+ } else {
59
+ await createProject(data)
60
+ }
61
+ await loadProjects()
62
+ onClose()
63
+ }
64
+
65
+ const handleDelete = async () => {
66
+ if (editing) {
67
+ await deleteProject(editing.id)
68
+ await loadProjects()
69
+ onClose()
70
+ toast.success('Project deleted')
71
+ }
72
+ }
73
+
74
+ return (
75
+ <BottomSheet open={open} onClose={onClose}>
76
+ <h2 className="font-display text-[18px] font-700 text-text mb-6">{editing ? 'Edit Project' : 'New Project'}</h2>
77
+ <div className="mb-6">
78
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">Name</label>
79
+ <input
80
+ type="text"
81
+ value={name}
82
+ onChange={(e) => setName(e.target.value)}
83
+ placeholder="e.g. Marketing Site"
84
+ className={inputClass}
85
+ style={{ fontFamily: 'inherit' }}
86
+ autoFocus
87
+ />
88
+ </div>
89
+
90
+ <div className="mb-6">
91
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">Description</label>
92
+ <textarea
93
+ value={description}
94
+ onChange={(e) => setDescription(e.target.value)}
95
+ placeholder="What is this project about?"
96
+ className={inputClass + ' min-h-[80px] resize-y'}
97
+ style={{ fontFamily: 'inherit' }}
98
+ rows={3}
99
+ />
100
+ </div>
101
+
102
+ <div className="mb-8">
103
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">Color</label>
104
+ <div className="flex items-center gap-2">
105
+ {PROJECT_COLORS.map((c) => (
106
+ <button
107
+ key={c}
108
+ type="button"
109
+ onClick={() => setColor(c)}
110
+ className={`w-7 h-7 rounded-full transition-all ${color === c ? 'ring-2 ring-offset-2 ring-offset-surface ring-accent scale-110' : 'hover:scale-105'}`}
111
+ style={{ backgroundColor: c }}
112
+ />
113
+ ))}
114
+ </div>
115
+ </div>
116
+
117
+ <div className="flex items-center gap-3">
118
+ <button
119
+ onClick={handleSave}
120
+ className="flex-1 py-2.5 rounded-lg bg-accent text-white text-[13px] font-600 hover:bg-accent-bright transition-colors"
121
+ >
122
+ {editing ? 'Update' : 'Create'} Project
123
+ </button>
124
+ {editing && (
125
+ <button
126
+ onClick={handleDelete}
127
+ className="px-4 py-2.5 rounded-lg bg-red-500/10 text-red-400 text-[13px] font-600 hover:bg-red-500/20 transition-colors"
128
+ >
129
+ Delete
130
+ </button>
131
+ )}
132
+ </div>
133
+ </BottomSheet>
134
+ )
135
+ }
@@ -12,6 +12,7 @@ export function ScheduleList({ inSidebar }: Props) {
12
12
  const schedules = useAppStore((s) => s.schedules)
13
13
  const loadSchedules = useAppStore((s) => s.loadSchedules)
14
14
  const setScheduleSheetOpen = useAppStore((s) => s.setScheduleSheetOpen)
15
+ const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
15
16
  const [search, setSearch] = useState('')
16
17
 
17
18
  useEffect(() => { loadSchedules() }, [])
@@ -20,10 +21,11 @@ export function ScheduleList({ inSidebar }: Props) {
20
21
  return Object.values(schedules)
21
22
  .filter((s) => {
22
23
  if (search && !s.name.toLowerCase().includes(search.toLowerCase())) return false
24
+ if (activeProjectFilter && s.projectId !== activeProjectFilter) return false
23
25
  return true
24
26
  })
25
27
  .sort((a, b) => b.createdAt - a.createdAt)
26
- }, [schedules, search])
28
+ }, [schedules, search, activeProjectFilter])
27
29
 
28
30
  if (!filtered.length && !search) {
29
31
  return (
@@ -129,7 +129,7 @@ export function NewSessionSheet() {
129
129
  }
130
130
 
131
131
  const handleCreate = async () => {
132
- const sessionName = name.trim() || 'New Session'
132
+ const sessionName = name.trim() || 'New Chat'
133
133
  const cwd = selectedDir || ''
134
134
  const resolvedCredentialId = currentProvider?.requiresApiKey
135
135
  ? credentialId
@@ -174,14 +174,14 @@ export function NewSessionSheet() {
174
174
  <BottomSheet open={open} onClose={onClose} wide>
175
175
  {/* Header */}
176
176
  <div className="mb-10">
177
- <h2 className="font-display text-[28px] font-700 tracking-[-0.03em] mb-2">New Session</h2>
178
- <p className="text-[14px] text-text-3">Configure your AI session</p>
177
+ <h2 className="font-display text-[28px] font-700 tracking-[-0.03em] mb-2">New Chat</h2>
178
+ <p className="text-[14px] text-text-3">Configure your AI chat</p>
179
179
  </div>
180
180
 
181
181
  {/* Name */}
182
182
  <div className="mb-8">
183
183
  <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">
184
- Session Name
184
+ Chat Name
185
185
  </label>
186
186
  <input
187
187
  type="text"
@@ -373,7 +373,7 @@ export function NewSessionSheet() {
373
373
  <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
374
374
  Tools <span className="normal-case tracking-normal font-normal text-text-3">(optional)</span>
375
375
  </label>
376
- <p className="text-[12px] text-text-3/60 mb-3">Allow this model to execute commands and access files in the session directory.</p>
376
+ <p className="text-[12px] text-text-3/60 mb-3">Allow this model to execute commands and access files in the working directory.</p>
377
377
  <div className="flex flex-wrap gap-2.5">
378
378
  {([
379
379
  { id: 'shell' as SessionTool, label: 'Shell' },
@@ -469,7 +469,7 @@ export function NewSessionSheet() {
469
469
  shadow-[0_4px_20px_rgba(99,102,241,0.25)] hover:brightness-110"
470
470
  style={{ fontFamily: 'inherit' }}
471
471
  >
472
- Create Session
472
+ Create Chat
473
473
  </button>
474
474
  </div>
475
475
  </BottomSheet>
@@ -117,7 +117,7 @@ export function SessionCard({ session, active, onClick }: Props) {
117
117
  onClick={handleDelete}
118
118
  className="shrink-0 opacity-0 group-hover/card:opacity-100 transition-opacity duration-150
119
119
  text-text-3 hover:text-red-400 p-0.5 -mr-1 cursor-pointer bg-transparent border-none"
120
- title="Delete session"
120
+ title="Delete chat"
121
121
  >
122
122
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
123
123
  <line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />