@swarmclawai/swarmclaw 0.7.7 → 0.8.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 (281) hide show
  1. package/README.md +12 -14
  2. package/next.config.ts +13 -2
  3. package/package.json +4 -2
  4. package/src/app/api/agents/[id]/thread/route.ts +9 -0
  5. package/src/app/api/agents/route.ts +4 -0
  6. package/src/app/api/agents/thread-route.test.ts +133 -0
  7. package/src/app/api/approvals/route.test.ts +148 -0
  8. package/src/app/api/canvas/[sessionId]/route.ts +3 -1
  9. package/src/app/api/chatrooms/[id]/chat/route.ts +4 -2
  10. package/src/app/api/chats/[id]/devserver/route.ts +48 -7
  11. package/src/app/api/chats/[id]/messages/route.ts +42 -18
  12. package/src/app/api/chats/[id]/route.ts +1 -1
  13. package/src/app/api/chats/[id]/stop/route.ts +5 -4
  14. package/src/app/api/chats/route.ts +23 -2
  15. package/src/app/api/clawhub/install/route.ts +28 -8
  16. package/src/app/api/connectors/[id]/route.ts +46 -3
  17. package/src/app/api/connectors/route.ts +12 -8
  18. package/src/app/api/external-agents/route.test.ts +165 -0
  19. package/src/app/api/gateways/[id]/health/route.ts +27 -12
  20. package/src/app/api/gateways/[id]/route.ts +2 -0
  21. package/src/app/api/gateways/health-route.test.ts +135 -0
  22. package/src/app/api/gateways/route.ts +2 -0
  23. package/src/app/api/mcp-servers/route.test.ts +130 -0
  24. package/src/app/api/openclaw/deploy/route.ts +38 -5
  25. package/src/app/api/plugins/install/route.ts +46 -6
  26. package/src/app/api/plugins/marketplace/route.ts +48 -15
  27. package/src/app/api/preview-server/route.ts +26 -11
  28. package/src/app/api/projects/[id]/route.ts +6 -2
  29. package/src/app/api/projects/route.ts +4 -3
  30. package/src/app/api/schedules/[id]/run/route.ts +4 -0
  31. package/src/app/api/schedules/route.test.ts +86 -0
  32. package/src/app/api/schedules/route.ts +6 -1
  33. package/src/app/api/secrets/[id]/route.ts +1 -0
  34. package/src/app/api/secrets/route.ts +2 -1
  35. package/src/app/api/settings/route.ts +2 -0
  36. package/src/app/api/setup/check-provider/route.test.ts +19 -0
  37. package/src/app/api/setup/check-provider/route.ts +40 -10
  38. package/src/app/api/skills/[id]/route.ts +12 -0
  39. package/src/app/api/skills/import/route.ts +14 -12
  40. package/src/app/api/skills/route.ts +13 -1
  41. package/src/app/api/tasks/[id]/route.ts +10 -1
  42. package/src/app/api/tasks/import/github/route.test.ts +65 -0
  43. package/src/app/api/tasks/import/github/route.ts +337 -0
  44. package/src/app/api/wallets/[id]/approve/route.ts +17 -3
  45. package/src/app/api/wallets/[id]/route.ts +79 -33
  46. package/src/app/api/wallets/[id]/send/route.ts +19 -33
  47. package/src/app/api/wallets/route.ts +78 -61
  48. package/src/app/api/webhooks/[id]/route.ts +33 -6
  49. package/src/app/api/webhooks/route.test.ts +272 -0
  50. package/src/cli/index.js +1 -0
  51. package/src/cli/spec.js +1 -0
  52. package/src/components/agents/agent-card.tsx +9 -2
  53. package/src/components/agents/agent-chat-list.tsx +18 -2
  54. package/src/components/agents/agent-list.tsx +1 -0
  55. package/src/components/agents/agent-sheet.tsx +257 -38
  56. package/src/components/agents/inspector-panel.tsx +41 -0
  57. package/src/components/canvas/canvas-panel.tsx +236 -65
  58. package/src/components/chat/chat-area.tsx +36 -19
  59. package/src/components/chat/chat-card.tsx +36 -13
  60. package/src/components/chat/chat-header.tsx +48 -16
  61. package/src/components/chat/chat-list.tsx +28 -4
  62. package/src/components/chat/checkpoint-timeline.tsx +50 -34
  63. package/src/components/chat/delegation-banner.test.ts +14 -1
  64. package/src/components/chat/delegation-banner.tsx +1 -1
  65. package/src/components/chat/message-bubble.tsx +208 -145
  66. package/src/components/chat/message-list.tsx +48 -19
  67. package/src/components/chatrooms/chatroom-message.tsx +2 -2
  68. package/src/components/chatrooms/chatroom-sheet.tsx +16 -2
  69. package/src/components/connectors/connector-health.tsx +1 -1
  70. package/src/components/connectors/connector-list.tsx +7 -2
  71. package/src/components/connectors/connector-sheet.tsx +337 -148
  72. package/src/components/gateways/gateway-sheet.tsx +2 -2
  73. package/src/components/layout/app-layout.tsx +40 -23
  74. package/src/components/mcp-servers/mcp-server-list.tsx +26 -5
  75. package/src/components/mcp-servers/mcp-server-sheet.tsx +19 -2
  76. package/src/components/openclaw/openclaw-deploy-panel.tsx +269 -21
  77. package/src/components/plugins/plugin-list.tsx +45 -9
  78. package/src/components/plugins/plugin-sheet.tsx +55 -7
  79. package/src/components/projects/project-detail.tsx +217 -0
  80. package/src/components/projects/project-sheet.tsx +176 -4
  81. package/src/components/providers/provider-list.tsx +2 -1
  82. package/src/components/providers/provider-sheet.tsx +21 -2
  83. package/src/components/schedules/schedule-card.tsx +25 -1
  84. package/src/components/schedules/schedule-sheet.tsx +44 -2
  85. package/src/components/secrets/secret-sheet.tsx +21 -2
  86. package/src/components/shared/agent-switch-dialog.tsx +12 -1
  87. package/src/components/shared/bottom-sheet.tsx +13 -3
  88. package/src/components/shared/command-palette.tsx +8 -1
  89. package/src/components/shared/confirm-dialog.tsx +19 -4
  90. package/src/components/shared/connector-platform-icon.test.ts +28 -0
  91. package/src/components/shared/connector-platform-icon.tsx +39 -6
  92. package/src/components/shared/settings/plugin-manager.tsx +29 -6
  93. package/src/components/shared/settings/section-capability-policy.tsx +45 -3
  94. package/src/components/shared/settings/section-voice.tsx +11 -3
  95. package/src/components/skills/skill-list.tsx +25 -0
  96. package/src/components/skills/skill-sheet.tsx +84 -12
  97. package/src/components/tasks/approvals-panel.tsx +289 -34
  98. package/src/components/tasks/task-board.tsx +410 -25
  99. package/src/components/tasks/task-card.tsx +66 -8
  100. package/src/components/tasks/task-sheet.tsx +16 -4
  101. package/src/components/ui/dialog.tsx +2 -2
  102. package/src/components/wallets/wallet-approval-dialog.tsx +4 -2
  103. package/src/components/wallets/wallet-panel.tsx +435 -90
  104. package/src/components/wallets/wallet-section.tsx +198 -48
  105. package/src/components/webhooks/webhook-sheet.tsx +22 -2
  106. package/src/lib/approval-display.ts +20 -0
  107. package/src/lib/canvas-content.ts +198 -0
  108. package/src/lib/chat-artifact-summary.ts +165 -0
  109. package/src/lib/chat-display.test.ts +91 -0
  110. package/src/lib/chat-display.ts +58 -0
  111. package/src/lib/chat-streaming-state.test.ts +47 -1
  112. package/src/lib/chat-streaming-state.ts +42 -0
  113. package/src/lib/ollama-model.ts +10 -0
  114. package/src/lib/openclaw-endpoint.test.ts +8 -0
  115. package/src/lib/openclaw-endpoint.ts +6 -1
  116. package/src/lib/plugin-install-cors.ts +46 -0
  117. package/src/lib/plugin-sources.test.ts +43 -0
  118. package/src/lib/plugin-sources.ts +77 -0
  119. package/src/lib/providers/ollama.ts +16 -6
  120. package/src/lib/providers/openclaw.test.ts +54 -0
  121. package/src/lib/providers/openclaw.ts +127 -11
  122. package/src/lib/schedule-dedupe-advanced.test.ts +1335 -0
  123. package/src/lib/schedule-dedupe.test.ts +66 -1
  124. package/src/lib/schedule-dedupe.ts +169 -12
  125. package/src/lib/schedule-origin.test.ts +20 -0
  126. package/src/lib/schedule-origin.ts +15 -0
  127. package/src/lib/server/__fixtures__/fake-mcp-stdio-server.mjs +27 -0
  128. package/src/lib/server/agent-availability.ts +16 -0
  129. package/src/lib/server/agent-runtime-config.ts +12 -4
  130. package/src/lib/server/agent-thread-session.test.ts +51 -0
  131. package/src/lib/server/agent-thread-session.ts +7 -0
  132. package/src/lib/server/approval-match.ts +205 -0
  133. package/src/lib/server/approvals-auto-approve.test.ts +538 -1
  134. package/src/lib/server/approvals.ts +214 -1
  135. package/src/lib/server/assistant-control.test.ts +29 -0
  136. package/src/lib/server/assistant-control.ts +23 -0
  137. package/src/lib/server/build-llm.test.ts +79 -0
  138. package/src/lib/server/build-llm.ts +14 -4
  139. package/src/lib/server/canvas-content.test.ts +32 -0
  140. package/src/lib/server/canvas-content.ts +6 -0
  141. package/src/lib/server/capability-router.test.ts +33 -0
  142. package/src/lib/server/capability-router.ts +80 -19
  143. package/src/lib/server/chat-execution-advanced.test.ts +651 -0
  144. package/src/lib/server/chat-execution-disabled.test.ts +94 -0
  145. package/src/lib/server/chat-execution-tool-events.test.ts +157 -0
  146. package/src/lib/server/chat-execution.ts +378 -73
  147. package/src/lib/server/clawhub-client.test.ts +14 -8
  148. package/src/lib/server/connectors/manager-reconnect.test.ts +47 -0
  149. package/src/lib/server/connectors/manager.test.ts +1147 -0
  150. package/src/lib/server/connectors/manager.ts +461 -137
  151. package/src/lib/server/connectors/pairing.ts +26 -5
  152. package/src/lib/server/connectors/types.ts +2 -0
  153. package/src/lib/server/connectors/whatsapp.test.ts +134 -0
  154. package/src/lib/server/connectors/whatsapp.ts +271 -47
  155. package/src/lib/server/context-manager.ts +6 -1
  156. package/src/lib/server/daemon-state.ts +84 -47
  157. package/src/lib/server/data-dir.test.ts +37 -0
  158. package/src/lib/server/data-dir.ts +20 -1
  159. package/src/lib/server/delegation-jobs-advanced.test.ts +513 -0
  160. package/src/lib/server/devserver-launch.test.ts +60 -0
  161. package/src/lib/server/devserver-launch.ts +85 -0
  162. package/src/lib/server/elevenlabs.test.ts +247 -1
  163. package/src/lib/server/elevenlabs.ts +147 -43
  164. package/src/lib/server/ethereum.ts +590 -0
  165. package/src/lib/server/eval/agent-regression-advanced.test.ts +302 -0
  166. package/src/lib/server/eval/agent-regression.test.ts +18 -1
  167. package/src/lib/server/eval/agent-regression.ts +383 -11
  168. package/src/lib/server/evm-swap.ts +475 -0
  169. package/src/lib/server/execution-log.ts +1 -0
  170. package/src/lib/server/heartbeat-service-timer.test.ts +173 -0
  171. package/src/lib/server/heartbeat-service.ts +20 -11
  172. package/src/lib/server/heartbeat-wake.test.ts +112 -0
  173. package/src/lib/server/heartbeat-wake.ts +338 -57
  174. package/src/lib/server/main-agent-loop-advanced.test.ts +538 -0
  175. package/src/lib/server/main-agent-loop.test.ts +260 -0
  176. package/src/lib/server/main-agent-loop.ts +559 -14
  177. package/src/lib/server/mcp-client.test.ts +16 -0
  178. package/src/lib/server/mcp-client.ts +25 -0
  179. package/src/lib/server/memory-integration.test.ts +719 -0
  180. package/src/lib/server/memory-policy.test.ts +43 -0
  181. package/src/lib/server/memory-policy.ts +132 -0
  182. package/src/lib/server/memory-tiers.test.ts +60 -0
  183. package/src/lib/server/memory-tiers.ts +16 -0
  184. package/src/lib/server/ollama-runtime.ts +58 -0
  185. package/src/lib/server/openclaw-deploy.test.ts +109 -1
  186. package/src/lib/server/openclaw-deploy.ts +557 -81
  187. package/src/lib/server/openclaw-gateway.test.ts +131 -0
  188. package/src/lib/server/openclaw-gateway.ts +10 -4
  189. package/src/lib/server/openclaw-health.test.ts +35 -0
  190. package/src/lib/server/openclaw-health.ts +215 -47
  191. package/src/lib/server/orchestrator-lg.ts +3 -2
  192. package/src/lib/server/orchestrator.ts +2 -0
  193. package/src/lib/server/plugins-advanced.test.ts +351 -0
  194. package/src/lib/server/plugins.ts +211 -6
  195. package/src/lib/server/project-context.ts +162 -0
  196. package/src/lib/server/project-utils.ts +150 -0
  197. package/src/lib/server/queue-advanced.test.ts +528 -0
  198. package/src/lib/server/queue-followups.test.ts +409 -2
  199. package/src/lib/server/queue-reconcile.test.ts +128 -0
  200. package/src/lib/server/queue.ts +527 -68
  201. package/src/lib/server/scheduler.ts +29 -1
  202. package/src/lib/server/session-note.test.ts +36 -0
  203. package/src/lib/server/session-note.ts +42 -0
  204. package/src/lib/server/session-run-manager.ts +83 -4
  205. package/src/lib/server/session-tools/canvas.ts +14 -12
  206. package/src/lib/server/session-tools/connector-inputs.test.ts +37 -0
  207. package/src/lib/server/session-tools/connector.test.ts +138 -0
  208. package/src/lib/server/session-tools/connector.ts +366 -54
  209. package/src/lib/server/session-tools/context.ts +17 -3
  210. package/src/lib/server/session-tools/crud.ts +484 -84
  211. package/src/lib/server/session-tools/delegate-fallback.test.ts +103 -0
  212. package/src/lib/server/session-tools/delegate-resume.test.ts +50 -0
  213. package/src/lib/server/session-tools/delegate.ts +102 -10
  214. package/src/lib/server/session-tools/discovery-approvals.test.ts +142 -0
  215. package/src/lib/server/session-tools/discovery.ts +80 -12
  216. package/src/lib/server/session-tools/file-normalize.test.ts +36 -0
  217. package/src/lib/server/session-tools/file.ts +43 -4
  218. package/src/lib/server/session-tools/human-loop.ts +35 -5
  219. package/src/lib/server/session-tools/index.ts +44 -9
  220. package/src/lib/server/session-tools/manage-connectors.test.ts +139 -0
  221. package/src/lib/server/session-tools/manage-schedules-advanced.test.ts +564 -0
  222. package/src/lib/server/session-tools/manage-schedules.test.ts +283 -0
  223. package/src/lib/server/session-tools/manage-tasks-advanced.test.ts +852 -0
  224. package/src/lib/server/session-tools/manage-tasks.test.ts +114 -0
  225. package/src/lib/server/session-tools/memory.test.ts +93 -0
  226. package/src/lib/server/session-tools/memory.ts +554 -75
  227. package/src/lib/server/session-tools/normalize-tool-args.ts +1 -1
  228. package/src/lib/server/session-tools/platform-access.test.ts +58 -0
  229. package/src/lib/server/session-tools/platform.ts +60 -19
  230. package/src/lib/server/session-tools/plugin-creator.ts +57 -1
  231. package/src/lib/server/session-tools/primitive-tools.test.ts +6 -0
  232. package/src/lib/server/session-tools/schedule.ts +6 -1
  233. package/src/lib/server/session-tools/shell-normalize.test.ts +25 -1
  234. package/src/lib/server/session-tools/shell.ts +22 -3
  235. package/src/lib/server/session-tools/wallet-tool.test.ts +254 -0
  236. package/src/lib/server/session-tools/wallet.ts +1374 -139
  237. package/src/lib/server/session-tools/web-inputs.test.ts +178 -0
  238. package/src/lib/server/session-tools/web.ts +621 -70
  239. package/src/lib/server/skill-discovery.ts +128 -0
  240. package/src/lib/server/skill-eligibility.test.ts +84 -0
  241. package/src/lib/server/skill-eligibility.ts +95 -0
  242. package/src/lib/server/skill-prompt-budget.test.ts +102 -0
  243. package/src/lib/server/skill-prompt-budget.ts +125 -0
  244. package/src/lib/server/skills-normalize.test.ts +54 -0
  245. package/src/lib/server/skills-normalize.ts +372 -26
  246. package/src/lib/server/solana.ts +214 -29
  247. package/src/lib/server/storage.ts +65 -36
  248. package/src/lib/server/stream-agent-chat.test.ts +437 -2
  249. package/src/lib/server/stream-agent-chat.ts +957 -79
  250. package/src/lib/server/system-events.ts +1 -1
  251. package/src/lib/server/tool-aliases.ts +2 -0
  252. package/src/lib/server/tool-capability-policy-advanced.test.ts +502 -0
  253. package/src/lib/server/tool-capability-policy.test.ts +24 -0
  254. package/src/lib/server/tool-capability-policy.ts +29 -1
  255. package/src/lib/server/tool-loop-detection.test.ts +105 -0
  256. package/src/lib/server/tool-loop-detection.ts +260 -0
  257. package/src/lib/server/tool-planning.test.ts +44 -0
  258. package/src/lib/server/tool-planning.ts +271 -0
  259. package/src/lib/server/wallet-execution.test.ts +198 -0
  260. package/src/lib/server/wallet-portfolio.test.ts +98 -0
  261. package/src/lib/server/wallet-portfolio.ts +724 -0
  262. package/src/lib/server/wallet-service.test.ts +57 -0
  263. package/src/lib/server/wallet-service.ts +213 -0
  264. package/src/lib/server/watch-jobs-advanced.test.ts +594 -0
  265. package/src/lib/server/watch-jobs.ts +17 -2
  266. package/src/lib/server/workspace-context.ts +111 -0
  267. package/src/lib/skill-save-payload.test.ts +39 -0
  268. package/src/lib/skill-save-payload.ts +37 -0
  269. package/src/lib/tasks.ts +28 -0
  270. package/src/lib/tool-definitions.ts +2 -1
  271. package/src/lib/tool-event-summary.test.ts +30 -0
  272. package/src/lib/tool-event-summary.ts +37 -0
  273. package/src/lib/validation/schemas.ts +1 -0
  274. package/src/lib/wallet-transactions.test.ts +75 -0
  275. package/src/lib/wallet-transactions.ts +43 -0
  276. package/src/lib/wallet.test.ts +17 -0
  277. package/src/lib/wallet.ts +183 -0
  278. package/src/proxy.test.ts +31 -0
  279. package/src/proxy.ts +34 -2
  280. package/src/stores/use-chat-store.ts +15 -1
  281. package/src/types/index.ts +249 -14
@@ -5,10 +5,11 @@ import { useAppStore } from '@/stores/use-app-store'
5
5
  import { api } from '@/lib/api-client'
6
6
  import { updateTask, archiveTask } from '@/lib/tasks'
7
7
  import { ConfirmDialog } from '@/components/shared/confirm-dialog'
8
+ import { AgentAvatar } from '@/components/agents/agent-avatar'
8
9
  import type { BoardTask } from '@/types'
9
10
 
10
- function timeAgo(ts: number) {
11
- const diff = Date.now() - ts
11
+ function timeAgo(ts: number, now: number) {
12
+ const diff = now - ts
12
13
  if (diff < 60_000) return 'just now'
13
14
  if (diff < 3600_000) return `${Math.floor(diff / 60_000)}m ago`
14
15
  if (diff < 86400_000) return `${Math.floor(diff / 3600_000)}h ago`
@@ -34,18 +35,29 @@ export function TaskCard({ task, selectionMode, selected, onToggleSelect, index
34
35
  const [dragging, setDragging] = useState(false)
35
36
  const [confirmArchive, setConfirmArchive] = useState(false)
36
37
  const [allowDrag, setAllowDrag] = useState(false)
38
+ const [now, setNow] = useState(() => Date.now())
37
39
 
38
40
  useEffect(() => {
39
41
  if (typeof window === 'undefined') return
40
- const isCoarsePointer = typeof window.matchMedia === 'function'
41
- ? window.matchMedia('(pointer: coarse)').matches
42
- : 'ontouchstart' in window
43
- setAllowDrag(!isCoarsePointer)
42
+ const frame = window.requestAnimationFrame(() => {
43
+ const isCoarsePointer = typeof window.matchMedia === 'function'
44
+ ? window.matchMedia('(pointer: coarse)').matches
45
+ : 'ontouchstart' in window
46
+ setAllowDrag(!isCoarsePointer)
47
+ })
48
+ const timer = window.setInterval(() => setNow(Date.now()), 60_000)
49
+ return () => {
50
+ window.cancelAnimationFrame(frame)
51
+ window.clearInterval(timer)
52
+ }
44
53
  }, [])
45
54
 
46
55
  const tasks = useAppStore((s) => s.tasks)
47
56
  const agent = agents[task.agentId]
48
57
  const project = task.projectId ? projects[task.projectId] : null
58
+ const creatorAgent = task.createdByAgentId ? agents[task.createdByAgentId] : null
59
+ const delegatorAgent = task.delegatedByAgentId ? agents[task.delegatedByAgentId] : null
60
+ const githubSource = task.externalSource?.source === 'github' ? task.externalSource : null
49
61
 
50
62
  const priorityConfig = {
51
63
  critical: { label: 'Critical', cls: 'bg-red-500/10 text-red-400' },
@@ -56,7 +68,7 @@ export function TaskCard({ task, selectionMode, selected, onToggleSelect, index
56
68
  const prio = task.priority && priorityConfig[task.priority]
57
69
 
58
70
  const isBlocked = Array.isArray(task.blockedBy) && task.blockedBy.length > 0
59
- const isOverdue = task.dueAt && task.dueAt < Date.now() && task.status !== 'completed' && task.status !== 'archived'
71
+ const isOverdue = task.dueAt && task.dueAt < now && task.status !== 'completed' && task.status !== 'archived'
60
72
  const borderColor = isBlocked ? 'border-l-rose-500'
61
73
  : task.pendingApproval ? 'border-l-amber-500'
62
74
  : task.status === 'running' ? 'border-l-emerald-500'
@@ -207,6 +219,52 @@ export function TaskCard({ task, selectionMode, selected, onToggleSelect, index
207
219
  </div>
208
220
  )}
209
221
 
222
+ {(creatorAgent || delegatorAgent || task.sourceType === 'schedule' || githubSource) && (
223
+ <div className="flex flex-wrap gap-1.5 mb-3">
224
+ {delegatorAgent && (
225
+ <span className="inline-flex items-center gap-1.5 rounded-[7px] bg-amber-500/10 px-2 py-1 text-[10px] font-600 text-amber-300">
226
+ <AgentAvatar seed={delegatorAgent.avatarSeed} avatarUrl={delegatorAgent.avatarUrl} name={delegatorAgent.name} size={14} />
227
+ Delegated by {delegatorAgent.name}
228
+ </span>
229
+ )}
230
+ {creatorAgent && creatorAgent.id !== delegatorAgent?.id && (
231
+ <span className="inline-flex items-center gap-1.5 rounded-[7px] bg-white/[0.05] px-2 py-1 text-[10px] font-600 text-text-2">
232
+ <AgentAvatar seed={creatorAgent.avatarSeed} avatarUrl={creatorAgent.avatarUrl} name={creatorAgent.name} size={14} />
233
+ Created by {creatorAgent.name}
234
+ </span>
235
+ )}
236
+ {task.sourceType === 'schedule' && (
237
+ <span className="inline-flex items-center gap-1.5 rounded-[7px] bg-purple-500/10 px-2 py-1 text-[10px] font-600 text-purple-300">
238
+ <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
239
+ <circle cx="12" cy="12" r="8" />
240
+ <path d="M12 8v4l3 2" />
241
+ </svg>
242
+ {task.sourceScheduleName ? `Scheduled via ${task.sourceScheduleName}` : 'Scheduled task'}
243
+ </span>
244
+ )}
245
+ {githubSource && (
246
+ githubSource.url ? (
247
+ <a
248
+ href={githubSource.url}
249
+ target="_blank"
250
+ rel="noreferrer"
251
+ onClick={(e) => e.stopPropagation()}
252
+ className="inline-flex items-center gap-1.5 rounded-[7px] bg-sky-500/10 px-2 py-1 text-[10px] font-600 text-sky-300 hover:bg-sky-500/15"
253
+ >
254
+ <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor" className="shrink-0">
255
+ <path d="M12 .5C5.65.5.5 5.65.5 12A11.5 11.5 0 0 0 8.36 22.9c.57.1.78-.25.78-.55 0-.27-.01-1.17-.02-2.13-3.2.69-3.88-1.36-3.88-1.36-.52-1.33-1.28-1.68-1.28-1.68-1.05-.72.08-.71.08-.71 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.55-.29-5.24-1.28-5.24-5.68 0-1.25.45-2.27 1.18-3.07-.12-.29-.51-1.45.11-3.02 0 0 .96-.31 3.15 1.17a10.9 10.9 0 0 1 5.73 0c2.18-1.48 3.14-1.17 3.14-1.17.63 1.57.24 2.73.12 3.02.74.8 1.18 1.82 1.18 3.07 0 4.41-2.7 5.38-5.27 5.66.42.36.78 1.06.78 2.14 0 1.55-.01 2.79-.01 3.17 0 .31.2.66.79.55A11.5 11.5 0 0 0 23.5 12C23.5 5.65 18.35.5 12 .5Z" />
256
+ </svg>
257
+ {githubSource.repo ? `${githubSource.repo}#${githubSource.number}` : `GitHub #${githubSource.number ?? githubSource.id}`}
258
+ </a>
259
+ ) : (
260
+ <span className="inline-flex items-center gap-1.5 rounded-[7px] bg-sky-500/10 px-2 py-1 text-[10px] font-600 text-sky-300">
261
+ GitHub {githubSource.repo ? `${githubSource.repo}#${githubSource.number}` : `#${githubSource.number ?? githubSource.id}`}
262
+ </span>
263
+ )
264
+ )}
265
+ </div>
266
+ )}
267
+
210
268
  <div className="flex items-center gap-2 flex-wrap">
211
269
  {agent && (
212
270
  <span className="px-2 py-1 rounded-[6px] bg-accent-soft text-accent-bright text-[11px] font-600">
@@ -219,7 +277,7 @@ export function TaskCard({ task, selectionMode, selected, onToggleSelect, index
219
277
  {project.name}
220
278
  </span>
221
279
  )}
222
- <span className="text-[11px] text-text-3">{timeAgo(task.updatedAt)}</span>
280
+ <span className="text-[11px] text-text-3">{timeAgo(task.updatedAt, now)}</span>
223
281
  {task.comments && task.comments.length > 0 && (
224
282
  <span className="flex items-center gap-1 text-[11px] text-text-3">
225
283
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-text-3/60">
@@ -467,7 +467,7 @@ export function TaskSheet() {
467
467
  )}
468
468
 
469
469
  {/* CLI Sessions */}
470
- {(editing.claudeResumeId || editing.codexResumeId || editing.opencodeResumeId || editing.cliResumeId) && (
470
+ {(editing.claudeResumeId || editing.codexResumeId || editing.opencodeResumeId || editing.geminiResumeId || editing.cliResumeId) && (
471
471
  <div className="mb-8">
472
472
  <SectionLabel>CLI Sessions</SectionLabel>
473
473
  <div className="flex flex-wrap gap-2">
@@ -489,7 +489,13 @@ export function TaskSheet() {
489
489
  <code className="text-[11px] text-text-3 font-mono">{editing.opencodeResumeId}</code>
490
490
  </div>
491
491
  )}
492
- {!(editing.claudeResumeId || editing.codexResumeId || editing.opencodeResumeId) && editing.cliResumeId && (
492
+ {editing.geminiResumeId && (
493
+ <div className="flex items-center gap-2 px-3 py-2 rounded-[10px] border border-white/[0.06] bg-surface">
494
+ <span className="text-[11px] font-600 text-fuchsia-400">Gemini</span>
495
+ <code className="text-[11px] text-text-3 font-mono">{editing.geminiResumeId}</code>
496
+ </div>
497
+ )}
498
+ {!(editing.claudeResumeId || editing.codexResumeId || editing.opencodeResumeId || editing.geminiResumeId) && editing.cliResumeId && (
493
499
  <div className="flex items-center gap-2 px-3 py-2 rounded-[10px] border border-white/[0.06] bg-surface">
494
500
  <span className="text-[11px] font-600 text-text-2">{editing.cliProvider || 'CLI'}</span>
495
501
  <code className="text-[11px] text-text-3 font-mono">{editing.cliResumeId}</code>
@@ -971,7 +977,7 @@ export function TaskSheet() {
971
977
  </div>
972
978
  )}
973
979
 
974
- {editing && (editing.claudeResumeId || editing.codexResumeId || editing.opencodeResumeId || editing.cliResumeId) && (
980
+ {editing && (editing.claudeResumeId || editing.codexResumeId || editing.opencodeResumeId || editing.geminiResumeId || editing.cliResumeId) && (
975
981
  <div className="mb-8">
976
982
  <SectionLabel>CLI Sessions</SectionLabel>
977
983
  <div className="flex flex-wrap gap-2">
@@ -993,7 +999,13 @@ export function TaskSheet() {
993
999
  <code className="text-[11px] text-text-3 font-mono">{editing.opencodeResumeId}</code>
994
1000
  </div>
995
1001
  )}
996
- {!(editing.claudeResumeId || editing.codexResumeId || editing.opencodeResumeId) && editing.cliResumeId && (
1002
+ {editing.geminiResumeId && (
1003
+ <div className="flex items-center gap-2 px-3 py-2 rounded-[10px] border border-white/[0.06] bg-surface">
1004
+ <span className="text-[11px] font-600 text-fuchsia-400">Gemini</span>
1005
+ <code className="text-[11px] text-text-3 font-mono">{editing.geminiResumeId}</code>
1006
+ </div>
1007
+ )}
1008
+ {!(editing.claudeResumeId || editing.codexResumeId || editing.opencodeResumeId || editing.geminiResumeId) && editing.cliResumeId && (
997
1009
  <div className="flex items-center gap-2 px-3 py-2 rounded-[10px] border border-white/[0.06] bg-surface">
998
1010
  <span className="text-[11px] font-600 text-text-2">{editing.cliProvider || 'CLI'}</span>
999
1011
  <code className="text-[11px] text-text-3 font-mono">{editing.cliResumeId}</code>
@@ -39,7 +39,7 @@ function DialogOverlay({
39
39
  <DialogPrimitive.Overlay
40
40
  data-slot="dialog-overlay"
41
41
  className={cn(
42
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/72 backdrop-blur-md",
42
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-[1400] bg-black/72 backdrop-blur-md",
43
43
  className
44
44
  )}
45
45
  {...props}
@@ -61,7 +61,7 @@ function DialogContent({
61
61
  <DialogPrimitive.Content
62
62
  data-slot="dialog-content"
63
63
  className={cn(
64
- "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
64
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-[1400] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
65
65
  className
66
66
  )}
67
67
  style={{ animation: 'spring-in 0.4s var(--ease-spring)' }}
@@ -4,6 +4,7 @@ import { useState, useCallback } from 'react'
4
4
  import { api } from '@/lib/api-client'
5
5
  import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
6
6
  import type { WalletTransaction } from '@/types'
7
+ import { formatWalletAmount, getWalletAssetSymbol, getWalletAtomicAmount } from '@/lib/wallet'
7
8
 
8
9
  interface WalletApprovalDialogProps {
9
10
  transaction: WalletTransaction
@@ -33,7 +34,8 @@ export function WalletApprovalDialog({ transaction, walletAddress, onClose, onRe
33
34
  }
34
35
  }, [transaction, onResolved, onClose])
35
36
 
36
- const amountSol = transaction.amountLamports / 1e9
37
+ const amountFormatted = formatWalletAmount(transaction.chain, getWalletAtomicAmount(transaction), { minFractionDigits: 4, maxFractionDigits: 6 })
38
+ const symbol = getWalletAssetSymbol(transaction.chain)
37
39
 
38
40
  return (
39
41
  <Dialog open onOpenChange={(nextOpen) => { if (!nextOpen) onClose() }}>
@@ -57,7 +59,7 @@ export function WalletApprovalDialog({ transaction, walletAddress, onClose, onRe
57
59
  <div className="rounded-[14px] border border-white/[0.06] bg-black/20 p-4 space-y-3">
58
60
  <div className="flex items-center justify-between">
59
61
  <span className="text-[11px] uppercase tracking-wide text-text-3/70">Amount</span>
60
- <span className="text-[16px] font-600 text-text-1">{amountSol.toFixed(4)} SOL</span>
62
+ <span className="text-[16px] font-600 text-text-1">{amountFormatted} {symbol}</span>
61
63
  </div>
62
64
  <div>
63
65
  <span className="mb-1 block text-[11px] uppercase tracking-wide text-text-3/70">From</span>