@swarmclawai/swarmclaw 1.2.6 → 1.2.9

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 (269) hide show
  1. package/README.md +54 -23
  2. package/next.config.ts +1 -0
  3. package/package.json +4 -3
  4. package/scripts/easy-setup.mjs +1 -1
  5. package/scripts/postinstall.mjs +1 -1
  6. package/skills/swarmclaw.md +115 -0
  7. package/skills/tools/browser.md +131 -0
  8. package/skills/tools/execute.md +98 -0
  9. package/skills/tools/files.md +98 -0
  10. package/skills/tools/memory.md +104 -0
  11. package/skills/tools/platform.md +144 -0
  12. package/skills/tools/skills.md +83 -0
  13. package/src/app/agents/[id]/page.tsx +1 -18
  14. package/src/app/api/agents/thread-route.test.ts +0 -1
  15. package/src/app/api/approvals/route.test.ts +6 -22
  16. package/src/app/api/chats/[id]/messages/route.ts +23 -19
  17. package/src/app/api/chats/messages-route.test.ts +105 -51
  18. package/src/app/api/connectors/route.ts +2 -2
  19. package/src/app/api/mcp-servers/[id]/test/route.ts +3 -2
  20. package/src/app/api/openclaw/deploy/route.ts +2 -0
  21. package/src/app/api/portability/export/route.ts +8 -0
  22. package/src/app/api/portability/import/route.test.ts +80 -0
  23. package/src/app/api/portability/import/route.ts +28 -0
  24. package/src/app/api/settings/route.ts +0 -2
  25. package/src/app/api/setup/doctor/route.ts +4 -4
  26. package/src/app/api/wallets/[id]/route.ts +15 -157
  27. package/src/app/api/wallets/generate/route.ts +22 -0
  28. package/src/app/api/wallets/route.test.ts +147 -0
  29. package/src/app/api/wallets/route.ts +13 -95
  30. package/src/app/autonomy/page.tsx +2 -57
  31. package/src/app/protocols/page.tsx +2 -21
  32. package/src/app/settings/page.tsx +0 -9
  33. package/src/app/wallets/page.tsx +105 -5
  34. package/src/cli/index.js +21 -33
  35. package/src/cli/spec.js +19 -30
  36. package/src/components/agents/agent-chat-list.tsx +23 -1
  37. package/src/components/agents/agent-sheet.tsx +2 -40
  38. package/src/components/agents/inspector-panel.tsx +165 -131
  39. package/src/components/chat/chat-area.tsx +38 -9
  40. package/src/components/chat/chat-card.tsx +0 -31
  41. package/src/components/chat/message-bubble.tsx +1 -108
  42. package/src/components/chat/message-list.tsx +33 -19
  43. package/src/components/connectors/connector-sheet.tsx +25 -1
  44. package/src/components/gateways/gateway-sheet.tsx +5 -2
  45. package/src/components/layout/sidebar-rail.tsx +6 -10
  46. package/src/components/projects/project-detail.tsx +3 -35
  47. package/src/components/projects/tabs/overview-tab.tsx +3 -59
  48. package/src/components/projects/tabs/work-tab.tsx +7 -77
  49. package/src/components/protocols/structured-session-launcher.tsx +1 -22
  50. package/src/components/shared/connector-platform-icon.tsx +1 -0
  51. package/src/components/tasks/task-card.tsx +4 -34
  52. package/src/components/tasks/task-sheet.tsx +6 -36
  53. package/src/components/wallets/wallet-list.tsx +150 -0
  54. package/src/lib/agent-execute-defaults.test.ts +24 -0
  55. package/src/lib/agent-execute-defaults.ts +62 -0
  56. package/src/lib/app/navigation.test.ts +0 -13
  57. package/src/lib/app/navigation.ts +2 -7
  58. package/src/lib/app/view-constants.ts +14 -19
  59. package/src/lib/chat/queued-message-queue.test.ts +134 -1
  60. package/src/lib/chat/queued-message-queue.ts +77 -2
  61. package/src/lib/server/agents/agent-service.ts +5 -0
  62. package/src/lib/server/agents/agent-thread-session.ts +0 -1
  63. package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
  64. package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
  65. package/src/lib/server/agents/delegation-jobs.ts +0 -25
  66. package/src/lib/server/agents/main-agent-loop.ts +1 -49
  67. package/src/lib/server/agents/subagent-runtime.ts +0 -1
  68. package/src/lib/server/approval-match.ts +0 -85
  69. package/src/lib/server/approvals.test.ts +6 -6
  70. package/src/lib/server/approvals.ts +0 -6
  71. package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
  72. package/src/lib/server/builtin-extensions.ts +1 -2
  73. package/src/lib/server/capability-router.test.ts +0 -2
  74. package/src/lib/server/chat-execution/chat-execution-advanced.test.ts +1 -1
  75. package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +15 -14
  76. package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
  77. package/src/lib/server/chat-execution/chat-execution-utils.ts +2 -4
  78. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
  79. package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
  80. package/src/lib/server/chat-execution/chat-turn-preparation.ts +81 -64
  81. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -0
  82. package/src/lib/server/chat-execution/continuation-evaluator.ts +8 -0
  83. package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
  84. package/src/lib/server/chat-execution/memory-mutation-tools.ts +1 -1
  85. package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
  86. package/src/lib/server/chat-execution/message-classifier.ts +11 -16
  87. package/src/lib/server/chat-execution/prompt-builder.test.ts +27 -0
  88. package/src/lib/server/chat-execution/prompt-builder.ts +14 -31
  89. package/src/lib/server/chat-execution/prompt-mode.test.ts +24 -0
  90. package/src/lib/server/chat-execution/prompt-mode.ts +5 -1
  91. package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
  92. package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
  93. package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
  94. package/src/lib/server/chat-execution/stream-agent-chat.test.ts +13 -126
  95. package/src/lib/server/chat-execution/stream-agent-chat.ts +46 -21
  96. package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
  97. package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
  98. package/src/lib/server/chatrooms/chatroom-routing.test.ts +4 -0
  99. package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
  100. package/src/lib/server/chats/chat-session-service.ts +3 -5
  101. package/src/lib/server/connectors/connector-inbound.ts +0 -1
  102. package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
  103. package/src/lib/server/connectors/connector-service.ts +39 -9
  104. package/src/lib/server/connectors/discord.ts +2 -2
  105. package/src/lib/server/connectors/matrix.ts +3 -2
  106. package/src/lib/server/connectors/signal.ts +5 -4
  107. package/src/lib/server/connectors/slack.ts +10 -9
  108. package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
  109. package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
  110. package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
  111. package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
  112. package/src/lib/server/connectors/swarmdock-tasks.ts +119 -0
  113. package/src/lib/server/connectors/swarmdock.ts +255 -0
  114. package/src/lib/server/connectors/teams.ts +3 -2
  115. package/src/lib/server/connectors/telegram.ts +4 -4
  116. package/src/lib/server/connectors/whatsapp.ts +2 -2
  117. package/src/lib/server/daemon/controller.ts +7 -0
  118. package/src/lib/server/execution-brief.test.ts +2 -25
  119. package/src/lib/server/execution-brief.ts +12 -35
  120. package/src/lib/server/execution-engine/task-attempt.ts +0 -1
  121. package/src/lib/server/gateways/gateway-profile-service.ts +19 -1
  122. package/src/lib/server/messages/message-repository.test.ts +70 -0
  123. package/src/lib/server/messages/message-repository.ts +11 -6
  124. package/src/lib/server/openclaw/deploy.ts +32 -2
  125. package/src/lib/server/persistence/storage-context.ts +0 -5
  126. package/src/lib/server/plugins-advanced.test.ts +1 -2
  127. package/src/lib/server/portability/export.ts +109 -0
  128. package/src/lib/server/portability/import.ts +159 -0
  129. package/src/lib/server/protocols/protocol-normalization.ts +0 -4
  130. package/src/lib/server/protocols/protocol-queries.ts +0 -6
  131. package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
  132. package/src/lib/server/protocols/protocol-service.ts +0 -1
  133. package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
  134. package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
  135. package/src/lib/server/protocols/protocol-swarm.ts +0 -2
  136. package/src/lib/server/protocols/protocol-types.ts +0 -2
  137. package/src/lib/server/provider-health.ts +1 -10
  138. package/src/lib/server/runtime/daemon-state/core.ts +0 -9
  139. package/src/lib/server/runtime/daemon-state.test.ts +0 -35
  140. package/src/lib/server/runtime/heartbeat-service.ts +3 -23
  141. package/src/lib/server/runtime/process-manager.ts +13 -9
  142. package/src/lib/server/runtime/queue/core.ts +11 -33
  143. package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
  144. package/src/lib/server/runtime/scheduler.ts +0 -13
  145. package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
  146. package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
  147. package/src/lib/server/runtime/session-run-manager/queries.ts +15 -1
  148. package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
  149. package/src/lib/server/runtime/session-run-manager.test.ts +58 -28
  150. package/src/lib/server/sandbox/session-runtime.test.ts +18 -1
  151. package/src/lib/server/sandbox/session-runtime.ts +40 -28
  152. package/src/lib/server/session-tools/autonomy-tools.test.ts +7 -9
  153. package/src/lib/server/session-tools/context.ts +1 -1
  154. package/src/lib/server/session-tools/credential-env.ts +109 -0
  155. package/src/lib/server/session-tools/crud.ts +3 -17
  156. package/src/lib/server/session-tools/delegate.ts +0 -4
  157. package/src/lib/server/session-tools/edit_file.ts +3 -2
  158. package/src/lib/server/session-tools/execute.test.ts +58 -0
  159. package/src/lib/server/session-tools/execute.ts +334 -0
  160. package/src/lib/server/session-tools/files-tool.ts +635 -0
  161. package/src/lib/server/session-tools/index.ts +14 -8
  162. package/src/lib/server/session-tools/memory-tool.ts +242 -0
  163. package/src/lib/server/session-tools/memory.ts +1 -1
  164. package/src/lib/server/session-tools/openclaw-nodes.ts +3 -2
  165. package/src/lib/server/session-tools/openclaw-workspace.ts +3 -2
  166. package/src/lib/server/session-tools/platform-tool.ts +617 -0
  167. package/src/lib/server/session-tools/session-info.ts +3 -2
  168. package/src/lib/server/session-tools/session-tools-wiring.test.ts +3 -4
  169. package/src/lib/server/session-tools/shell.ts +7 -122
  170. package/src/lib/server/session-tools/skills-tool.ts +396 -0
  171. package/src/lib/server/session-tools/team-context.ts +0 -3
  172. package/src/lib/server/session-tools/web.ts +2 -2
  173. package/src/lib/server/storage-normalization.ts +10 -0
  174. package/src/lib/server/storage.ts +18 -45
  175. package/src/lib/server/tasks/task-checkout.ts +59 -0
  176. package/src/lib/server/tasks/task-lifecycle.ts +2 -0
  177. package/src/lib/server/tasks/task-route-service.ts +4 -26
  178. package/src/lib/server/tasks/task-service.ts +0 -7
  179. package/src/lib/server/tool-aliases.ts +2 -2
  180. package/src/lib/server/tool-capability-policy-advanced.test.ts +13 -6
  181. package/src/lib/server/tool-capability-policy.test.ts +2 -1
  182. package/src/lib/server/tool-capability-policy.ts +60 -35
  183. package/src/lib/server/tool-planning.ts +11 -12
  184. package/src/lib/server/universal-tool-access.ts +0 -1
  185. package/src/lib/server/wallets/wallet-crypto.ts +33 -0
  186. package/src/lib/server/wallets/wallet-repository.ts +24 -0
  187. package/src/lib/server/wallets/wallet-service.ts +119 -0
  188. package/src/lib/server/working-state/extraction.ts +8 -42
  189. package/src/lib/server/working-state/normalization.ts +10 -103
  190. package/src/lib/server/working-state/service.ts +12 -21
  191. package/src/lib/setup-defaults.ts +5 -0
  192. package/src/lib/strip-internal-metadata.test.ts +1 -1
  193. package/src/lib/strip-internal-metadata.ts +1 -1
  194. package/src/lib/tool-definitions.ts +1 -1
  195. package/src/lib/validation/schemas.test.ts +16 -0
  196. package/src/lib/validation/schemas.ts +49 -2
  197. package/src/stores/slices/data-slice.ts +5 -1
  198. package/src/stores/slices/ui-slice.ts +0 -4
  199. package/src/stores/use-chat-store.test.ts +231 -0
  200. package/src/stores/use-chat-store.ts +62 -13
  201. package/src/types/agent.ts +264 -0
  202. package/src/types/app-settings.ts +173 -0
  203. package/src/types/approval.ts +25 -0
  204. package/src/types/connector.ts +188 -0
  205. package/src/types/extension.ts +386 -0
  206. package/src/types/index.ts +16 -3555
  207. package/src/types/message.ts +56 -0
  208. package/src/types/misc.ts +737 -0
  209. package/src/types/protocol.ts +420 -0
  210. package/src/types/provider.ts +52 -0
  211. package/src/types/run.ts +180 -0
  212. package/src/types/schedule.ts +59 -0
  213. package/src/types/session.ts +215 -0
  214. package/src/types/skill.ts +157 -0
  215. package/src/types/swarmdock.ts +29 -0
  216. package/src/types/task.ts +144 -0
  217. package/src/types/working-state.ts +204 -0
  218. package/src/views/settings/section-heartbeat.tsx +2 -2
  219. package/src/views/settings/section-runtime-loop.tsx +0 -14
  220. package/src/app/api/canvas/[sessionId]/route.ts +0 -35
  221. package/src/app/api/missions/[id]/actions/route.ts +0 -31
  222. package/src/app/api/missions/[id]/events/route.ts +0 -14
  223. package/src/app/api/missions/[id]/route.ts +0 -10
  224. package/src/app/api/missions/route.test.ts +0 -244
  225. package/src/app/api/missions/route.ts +0 -57
  226. package/src/app/api/wallets/[id]/approve/route.ts +0 -79
  227. package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
  228. package/src/app/api/wallets/[id]/send/route.ts +0 -113
  229. package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
  230. package/src/app/missions/[id]/page.tsx +0 -3
  231. package/src/app/missions/page.tsx +0 -685
  232. package/src/components/canvas/canvas-panel.tsx +0 -267
  233. package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
  234. package/src/components/wallets/wallet-panel.tsx +0 -1010
  235. package/src/components/wallets/wallet-section.tsx +0 -260
  236. package/src/features/missions/queries.ts +0 -23
  237. package/src/lib/canvas-content.test.ts +0 -360
  238. package/src/lib/canvas-content.ts +0 -198
  239. package/src/lib/server/canvas-content.test.ts +0 -32
  240. package/src/lib/server/canvas-content.ts +0 -6
  241. package/src/lib/server/ethereum.ts +0 -591
  242. package/src/lib/server/evm-swap.ts +0 -476
  243. package/src/lib/server/missions/mission-intent.test.ts +0 -63
  244. package/src/lib/server/missions/mission-intent.ts +0 -569
  245. package/src/lib/server/missions/mission-repository.ts +0 -74
  246. package/src/lib/server/missions/mission-service/actions.ts +0 -6
  247. package/src/lib/server/missions/mission-service/bindings.ts +0 -9
  248. package/src/lib/server/missions/mission-service/context.ts +0 -4
  249. package/src/lib/server/missions/mission-service/core.ts +0 -2271
  250. package/src/lib/server/missions/mission-service/queries.ts +0 -12
  251. package/src/lib/server/missions/mission-service/recovery.ts +0 -5
  252. package/src/lib/server/missions/mission-service/ticks.ts +0 -9
  253. package/src/lib/server/missions/mission-service.test.ts +0 -888
  254. package/src/lib/server/missions/mission-service.ts +0 -6
  255. package/src/lib/server/session-tools/canvas.ts +0 -105
  256. package/src/lib/server/session-tools/sandbox.ts +0 -281
  257. package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
  258. package/src/lib/server/session-tools/wallet.ts +0 -1287
  259. package/src/lib/server/solana.ts +0 -327
  260. package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
  261. package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
  262. package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
  263. package/src/lib/server/wallet/wallet-service.test.ts +0 -81
  264. package/src/lib/server/wallet/wallet-service.ts +0 -225
  265. package/src/lib/wallet/wallet-transactions.test.ts +0 -75
  266. package/src/lib/wallet/wallet-transactions.ts +0 -43
  267. package/src/lib/wallet/wallet.test.ts +0 -333
  268. package/src/lib/wallet/wallet.ts +0 -183
  269. package/src/views/settings/section-wallets.tsx +0 -35
@@ -337,23 +337,6 @@ export const MessageBubble = memo(function MessageBubble({ message, assistantNam
337
337
  return null
338
338
  }, [message.text, isUser])
339
339
 
340
- const walletRequest = useMemo(() => {
341
- if (isUser) return null
342
- try {
343
- const data = JSON.parse(message.text)
344
- if (data.type === 'extension_wallet_transfer_request') return data
345
- } catch { /* ignore */ }
346
- return null
347
- }, [message.text, isUser])
348
-
349
- const walletActionRequest = useMemo(() => {
350
- if (isUser) return null
351
- try {
352
- const data = JSON.parse(message.text)
353
- if (data.type === 'extension_wallet_action_request') return data
354
- } catch { /* ignore */ }
355
- return null
356
- }, [message.text, isUser])
357
340
  const currentUser = useAppStore((s) => s.currentUser)
358
341
  const isDesktop = useMediaQuery('(min-width: 768px)')
359
342
  const setPreviewContent = useChatStore((s) => s.setPreviewContent)
@@ -560,8 +543,6 @@ export const MessageBubble = memo(function MessageBubble({ message, assistantNam
560
543
  const hasPrimaryAttachments = Boolean(message.imagePath || message.imageUrl || message.attachedFiles?.length)
561
544
  const shouldRenderBubbleShell = hasPrimaryAttachments
562
545
  || Boolean(allToolMedia)
563
- || Boolean(walletRequest)
564
- || Boolean(walletActionRequest)
565
546
  || Boolean(installRequest)
566
547
  || Boolean(scaffoldRequest)
567
548
  || isExtensionUI
@@ -703,95 +684,7 @@ export const MessageBubble = memo(function MessageBubble({ message, assistantNam
703
684
  ) : shouldRenderBubbleShell ? (
704
685
  /* Message bubble */
705
686
  <div className={`${isStructured ? 'max-w-[92%] md:max-w-[85%]' : 'max-w-[85%] md:max-w-[72%]'} ${isUser ? 'bubble-user px-5 py-3.5' : isHeartbeat ? 'bubble-ai px-4 py-3' : 'bubble-ai px-5 py-3.5'}`}>
706
- {walletRequest ? (
707
- <div className="flex flex-col gap-3 p-4 rounded-[18px] bg-sky-500/[0.03] border border-sky-500/20 shadow-[0_0_20px_rgba(14,165,233,0.05)]">
708
- <div className="flex items-center gap-2 mb-1">
709
- <div className="w-5 h-5 rounded-full bg-sky-500/20 flex items-center justify-center text-sky-400">
710
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
711
- <path d="M12 1v22M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
712
- </svg>
713
- </div>
714
- <span className="text-[11px] font-700 uppercase tracking-wider text-sky-400/80">Wallet Transfer Request</span>
715
- </div>
716
- <p className="text-[13px] text-text-2/90 leading-relaxed">{walletRequest.message}</p>
717
- <div className="p-3 rounded-[12px] bg-black/40 border border-white/5 flex flex-col gap-2">
718
- <div className="flex justify-between items-center">
719
- <span className="text-[11px] text-text-3/60 font-600 uppercase">Amount</span>
720
- <span className="text-[13px] font-700 text-sky-400">{walletRequest.amountDisplay || `${walletRequest.amountSol} SOL`}</span>
721
- </div>
722
- <div className="flex flex-col gap-1">
723
- <span className="text-[11px] text-text-3/60 font-600 uppercase">To Address</span>
724
- <span className="text-[11px] font-mono text-text-2/70 break-all">{walletRequest.toAddress}</span>
725
- </div>
726
- {walletRequest.memo && (
727
- <div className="flex flex-col gap-1 border-t border-white/5 pt-2">
728
- <span className="text-[11px] text-text-3/60 font-600 uppercase">Memo</span>
729
- <span className="text-[12px] text-text-3/80 italic">&quot;{walletRequest.memo}&quot;</span>
730
- </div>
731
- )}
732
- </div>
733
- <div className="flex gap-2 mt-1">
734
- <button
735
- onClick={() => useChatStore.getState().sendMessage(`I approve this transfer of ${walletRequest.amountDisplay || `${walletRequest.amountSol} SOL`} to ${walletRequest.toAddress}. Proceed with wallet_tool and set approved=true.`)}
736
- className="px-4 py-2 rounded-[12px] bg-sky-500 text-black text-[13px] font-700 hover:bg-sky-400 transition-all active:scale-[0.98]"
737
- >
738
- Approve & Send
739
- </button>
740
- <button
741
- onClick={() => useChatStore.getState().sendMessage(`I do not approve this transaction. Cancel it.`)}
742
- className="px-4 py-2 rounded-[12px] bg-white/[0.05] hover:bg-white/[0.1] text-text-2 text-[13px] font-600 transition-all border border-white/10"
743
- >
744
- Reject
745
- </button>
746
- </div>
747
- </div>
748
- ) : walletActionRequest ? (
749
- <div className="flex flex-col gap-3 p-4 rounded-[18px] bg-violet-500/[0.03] border border-violet-500/20 shadow-[0_0_20px_rgba(139,92,246,0.05)]">
750
- <div className="flex items-center gap-2 mb-1">
751
- <div className="w-5 h-5 rounded-full bg-violet-500/20 flex items-center justify-center text-violet-400">
752
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
753
- <path d="M12 2v8" />
754
- <path d="M8 6h8" />
755
- <path d="m5 19 4-4 3 3 7-7" />
756
- </svg>
757
- </div>
758
- <span className="text-[11px] font-700 uppercase tracking-wider text-violet-400/80">Wallet Action Request</span>
759
- </div>
760
- <p className="text-[13px] text-text-2/90 leading-relaxed">{walletActionRequest.message}</p>
761
- <div className="p-3 rounded-[12px] bg-black/40 border border-white/5 flex flex-col gap-2">
762
- <div className="flex justify-between items-center gap-3">
763
- <span className="text-[11px] text-text-3/60 font-600 uppercase">Action</span>
764
- <span className="text-[13px] font-700 text-violet-400">{walletActionRequest.action || 'wallet_action'}</span>
765
- </div>
766
- {(walletActionRequest.chain || walletActionRequest.network) && (
767
- <div className="flex justify-between items-center gap-3">
768
- <span className="text-[11px] text-text-3/60 font-600 uppercase">Chain</span>
769
- <span className="text-[12px] text-text-2/80">{[walletActionRequest.chain, walletActionRequest.network].filter(Boolean).join(' / ')}</span>
770
- </div>
771
- )}
772
- {walletActionRequest.summary && (
773
- <div className="flex flex-col gap-1 border-t border-white/5 pt-2">
774
- <span className="text-[11px] text-text-3/60 font-600 uppercase">Summary</span>
775
- <span className="text-[12px] text-text-2/80 whitespace-pre-wrap break-words">{walletActionRequest.summary}</span>
776
- </div>
777
- )}
778
- </div>
779
- <div className="flex gap-2 mt-1">
780
- <button
781
- onClick={() => useChatStore.getState().sendMessage(`I approve this wallet action (${walletActionRequest.action || 'wallet_action'}). Proceed with wallet_tool and set approved=true.`)}
782
- className="px-4 py-2 rounded-[12px] bg-violet-500 text-black text-[13px] font-700 hover:bg-violet-400 transition-all active:scale-[0.98]"
783
- >
784
- Approve Action
785
- </button>
786
- <button
787
- onClick={() => useChatStore.getState().sendMessage('I do not approve this wallet action. Cancel it.')}
788
- className="px-4 py-2 rounded-[12px] bg-white/[0.05] hover:bg-white/[0.1] text-text-2 text-[13px] font-600 transition-all border border-white/10"
789
- >
790
- Reject
791
- </button>
792
- </div>
793
- </div>
794
- ) : installRequest ? (
687
+ {installRequest ? (
795
688
  <div className="flex flex-col gap-3 p-4 rounded-[18px] bg-emerald-500/[0.03] border border-emerald-500/20 shadow-[0_0_20px_rgba(16,185,129,0.05)]">
796
689
  <div className="flex items-center gap-2 mb-1">
797
690
  <div className="w-5 h-5 rounded-full bg-emerald-500/20 flex items-center justify-center text-emerald-400">
@@ -10,6 +10,7 @@ import { selectActiveSessionId } from '@/stores/slices/session-slice'
10
10
  import { api } from '@/lib/app/api-client'
11
11
  import { buildStreamingAwareMessageList } from '@/lib/chat/chat-streaming-state'
12
12
  import { dedupeMessagesForDisplay } from '@/lib/chat/chat-display'
13
+ import { mergeQueuedTranscriptMessages } from '@/lib/chat/queued-message-queue'
13
14
  import { shouldShowDateSeparator } from '@/lib/chat/message-list-utils'
14
15
  import { errorMessage } from '@/lib/shared-utils'
15
16
  import { AgentAvatar } from '@/components/agents/agent-avatar'
@@ -190,7 +191,9 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
190
191
  const assistantRenderId = useChatStore((s) => s.assistantRenderId)
191
192
  const thinkingStartTime = useChatStore((s) => s.thinkingStartTime)
192
193
  const hasLiveArtifacts = useChatStore(selectHasLiveArtifacts)
194
+ const messageStartIndex = useChatStore((s) => s.messageStartIndex)
193
195
  const setMessages = useChatStore((s) => s.setMessages)
196
+ const queuedMessages = useChatStore((s) => s.queuedMessages)
194
197
  const retryLastMessage = useChatStore((s) => s.retryLastMessage)
195
198
  const editAndResend = useChatStore((s) => s.editAndResend)
196
199
  const sendMessage = useChatStore((s) => s.sendMessage)
@@ -234,20 +237,23 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
234
237
  // Use refs for callbacks so transcriptNodes memo doesn't bust on every messages change
235
238
  const messagesCallbackRef = useRef(messages)
236
239
  messagesCallbackRef.current = messages
240
+ const messageStartIndexRef = useRef(messageStartIndex)
241
+ messageStartIndexRef.current = messageStartIndex
237
242
  const sessionIdRef = useRef(sessionId)
238
243
  sessionIdRef.current = sessionId
239
244
 
240
- const toggleBookmark = useCallback(async (index: number) => {
245
+ const toggleBookmark = useCallback(async (absoluteIndex: number) => {
241
246
  const sid = sessionIdRef.current
242
247
  const msgs = messagesCallbackRef.current
248
+ const localIndex = absoluteIndex - messageStartIndexRef.current
243
249
  if (!sid) return
244
- const msg = msgs[index]
250
+ const msg = msgs[localIndex]
245
251
  if (!msg) return
246
252
  const next = !msg.bookmarked
247
253
  try {
248
- await api('PUT', `/chats/${sid}/messages`, { messageIndex: index, bookmarked: next })
254
+ await api('PUT', `/chats/${sid}/messages`, { messageIndex: absoluteIndex, bookmarked: next })
249
255
  const updated = [...msgs]
250
- updated[index] = { ...updated[index], bookmarked: next }
256
+ updated[localIndex] = { ...updated[localIndex], bookmarked: next }
251
257
  setMessages(updated)
252
258
  } catch (err: unknown) {
253
259
  console.error('Failed to toggle bookmark:', errorMessage(err))
@@ -298,21 +304,26 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
298
304
  return dedupeMessagesForDisplay(displayedMessages)
299
305
  }, [messages, showAlerts, showOk])
300
306
 
307
+ const displayedMessages = useMemo(
308
+ () => mergeQueuedTranscriptMessages(baseDisplayedMessages, queuedMessages, sessionId),
309
+ [baseDisplayedMessages, queuedMessages, sessionId],
310
+ )
311
+
301
312
  const latestPersistedStreamingMessage = useMemo(() => {
302
- for (let i = baseDisplayedMessages.length - 1; i >= 0; i -= 1) {
303
- const candidate = baseDisplayedMessages[i]
313
+ for (let i = displayedMessages.length - 1; i >= 0; i -= 1) {
314
+ const candidate = displayedMessages[i]
304
315
  if (candidate.role === 'assistant' && candidate.streaming === true) {
305
316
  return candidate
306
317
  }
307
318
  }
308
319
  return null
309
- }, [baseDisplayedMessages])
320
+ }, [displayedMessages])
310
321
 
311
322
  const currentRunHasCompletedAssistant = useMemo(
312
323
  () => (
313
324
  streaming
314
325
  && thinkingStartTime > 0
315
- && baseDisplayedMessages.some((message) => (
326
+ && displayedMessages.some((message) => (
316
327
  message.role === 'assistant'
317
328
  && message.streaming !== true
318
329
  && message.kind !== 'system'
@@ -321,7 +332,7 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
321
332
  && message.time >= thinkingStartTime
322
333
  ))
323
334
  ),
324
- [baseDisplayedMessages, streaming, thinkingStartTime],
335
+ [displayedMessages, streaming, thinkingStartTime],
325
336
  )
326
337
 
327
338
  const showLiveStreamRow = streaming
@@ -330,14 +341,14 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
330
341
  && (hasLiveArtifacts || !!latestPersistedStreamingMessage)
331
342
 
332
343
  const streamingAwareMessages = useMemo(() => (
333
- buildStreamingAwareMessageList(baseDisplayedMessages, {
344
+ buildStreamingAwareMessageList(displayedMessages, {
334
345
  localStreaming: streaming,
335
346
  hasLiveArtifacts,
336
347
  assistantRenderId,
337
348
  showLiveRow: showLiveStreamRow,
338
349
  syntheticAssistant: latestPersistedStreamingMessage,
339
350
  })
340
- ), [assistantRenderId, baseDisplayedMessages, hasLiveArtifacts, latestPersistedStreamingMessage, showLiveStreamRow, streaming])
351
+ ), [assistantRenderId, displayedMessages, hasLiveArtifacts, latestPersistedStreamingMessage, showLiveStreamRow, streaming])
341
352
 
342
353
  const filteredMessages = useMemo(() => {
343
354
  let nextMessages = bookmarkFilter
@@ -367,23 +378,26 @@ export function MessageList({ messages, streaming, connectorFilter = null, loadi
367
378
  const originalIndexMap = useMemo(() => {
368
379
  const indexMap = new Map<Message, number>()
369
380
  messages.forEach((msg, index) => {
370
- indexMap.set(msg, index)
381
+ indexMap.set(msg, messageStartIndex + index)
371
382
  })
372
383
  return indexMap
373
- }, [messages])
384
+ }, [messageStartIndex, messages])
374
385
 
375
- const handleDeleteMessage = useCallback(async (messageIndex: number) => {
386
+ const handleDeleteMessage = useCallback(async (absoluteIndex: number) => {
376
387
  const sid = sessionIdRef.current
377
388
  const msgs = messagesCallbackRef.current
378
- if (!sid || messageIndex < 0) return
389
+ const localIndex = absoluteIndex - messageStartIndexRef.current
390
+ if (!sid || absoluteIndex < 0 || localIndex < 0) return
379
391
  try {
380
- await api('DELETE', `/chats/${sid}/messages`, { messageIndex })
381
- setMessages(msgs.filter((_: Message, idx: number) => idx !== messageIndex))
392
+ await api('DELETE', `/chats/${sid}/messages`, { messageIndex: absoluteIndex })
393
+ setMessages(
394
+ msgs.filter((_: Message, idx: number) => idx !== localIndex),
395
+ { totalMessages: Math.max(0, totalMessages - 1) },
396
+ )
382
397
  } catch {
383
398
  // best-effort
384
399
  }
385
- // eslint-disable-next-line react-hooks/exhaustive-deps
386
- }, [])
400
+ }, [setMessages, totalMessages])
387
401
 
388
402
  // Snapshot the settled count at memo time so it's captured in the closure.
389
403
  // Messages up to this count appear instantly; only new ones get entrance animations.
@@ -96,6 +96,8 @@ const FIELD_HINTS: Record<string, string> = {
96
96
  dmAddressingMode: 'Control whether DMs need to address the agent by name before it replies',
97
97
  ownerSenderId: 'Optional sender ID that should route to the main owner thread for direct agent connectors',
98
98
  scopes: 'Press Enter after each scope to add it',
99
+ walletAddress: 'Base L2 Ethereum address for receiving USDC payments from completed tasks',
100
+ maxBudget: 'USDC with 6 decimal places. $1.00 = 1000000, $5.00 = 5000000',
99
101
  }
100
102
 
101
103
  const BOOLEAN_SELECT_OPTIONS: ConnectorConfigOption[] = [
@@ -344,6 +346,26 @@ const PLATFORMS: {
344
346
  { key: 'signalCliHttpUrl', label: 'HTTP API URL', placeholder: 'http://localhost:8080', help: 'Only needed for http mode', section: 'advanced' },
345
347
  ],
346
348
  },
349
+ {
350
+ id: 'swarmdock',
351
+ label: 'SwarmDock',
352
+ color: '#F59E0B',
353
+ setupSteps: [
354
+ 'Generate an Ed25519 keypair for agent identity',
355
+ 'Set your Base L2 wallet address for receiving USDC payments',
356
+ 'Configure skills and auto-discovery preferences',
357
+ ],
358
+ tokenLabel: 'SwarmDock Identity Key',
359
+ tokenHelp: 'Encrypted Ed25519 private key used to authenticate this agent on SwarmDock.',
360
+ configFields: [
361
+ { key: 'apiUrl', label: 'API URL', placeholder: 'https://api.swarmdock.ai', help: 'SwarmDock marketplace API endpoint' },
362
+ { key: 'walletAddress', label: 'Base L2 Wallet Address', placeholder: '0x...', help: 'USDC wallet on Base L2 for payments' },
363
+ { key: 'agentDescription', label: 'Marketplace Description', placeholder: 'Specialized in...', help: 'Description on your SwarmDock profile' },
364
+ { key: 'skills', label: 'Skills (comma-separated)', placeholder: 'data-analysis,web-design', help: 'Skill IDs for task matching' },
365
+ { key: 'autoDiscover', label: 'Auto-Discover Tasks', placeholder: 'false', help: 'Automatically bid on matching tasks' },
366
+ { key: 'maxBudget', label: 'Max Budget (USDC micro-units)', placeholder: '5000000', help: '$1 = 1000000, $5 = 5000000' },
367
+ ],
368
+ },
347
369
  ]
348
370
 
349
371
  const COMMON_CONFIG_FIELDS: ConnectorConfigField[] = [
@@ -1181,7 +1203,9 @@ export function ConnectorSheet() {
1181
1203
  try {
1182
1204
  const cred = await createCredentialMutation.mutateAsync({
1183
1205
  provider: platform,
1184
- name: newCredName.trim() || `${platformConfig.label} Bot Token`,
1206
+ name: newCredName.trim() || (platform === 'swarmdock'
1207
+ ? `${platformConfig.label} Identity Key`
1208
+ : `${platformConfig.label} Bot Token`),
1185
1209
  apiKey: newCredValue.trim(),
1186
1210
  })
1187
1211
  await credentialsQuery.refetch()
@@ -118,11 +118,14 @@ export function GatewaySheet() {
118
118
  setInvokeParamsText('{}')
119
119
  }, [open, editing, gatewayProfiles.length])
120
120
 
121
+ const refreshRef = useRef(refreshGatewayTopologyMutation)
122
+ refreshRef.current = refreshGatewayTopologyMutation
123
+
121
124
  const loadNodesAndDevices = useCallback(async (profileId: string) => {
122
125
  setNodesLoading(true)
123
126
  setNodesError('')
124
127
  try {
125
- const result = await refreshGatewayTopologyMutation.mutateAsync(profileId)
128
+ const result = await refreshRef.current.mutateAsync(profileId)
126
129
  setNodes(result.nodes)
127
130
  setNodePairings(result.nodePairings)
128
131
  setDevicePairings(result.devicePairings)
@@ -136,7 +139,7 @@ export function GatewaySheet() {
136
139
  } finally {
137
140
  setNodesLoading(false)
138
141
  }
139
- }, [refreshGatewayTopologyMutation])
142
+ }, [])
140
143
 
141
144
  useEffect(() => {
142
145
  if (!open || !editing?.id) return
@@ -270,11 +270,7 @@ export function SidebarRail({
270
270
  <path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2" /><rect x="9" y="3" width="6" height="4" rx="1" /><path d="M9 14l2 2 4-4" />
271
271
  </svg>
272
272
  </NavItem>
273
- <NavItem view="missions" label="Missions" expanded={railExpanded} isActive={isNavActive('missions')} onClick={() => handleNavClick('missions')}>
274
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
275
- <path d="M12 3 4 7v5c0 5 3.4 8.8 8 10 4.6-1.2 8-5 8-10V7l-8-4Z" /><path d="m9.5 12 1.8 1.8L15 10" />
276
- </svg>
277
- </NavItem>
273
+
278
274
  <NavItem view="schedules" label="Schedules" expanded={railExpanded} isActive={isNavActive('schedules')} onClick={() => handleNavClick('schedules')}>
279
275
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
280
276
  <circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 14" />
@@ -343,6 +339,11 @@ export function SidebarRail({
343
339
  <rect x="3" y="11" width="18" height="11" rx="2" ry="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" />
344
340
  </svg>
345
341
  </NavItem>
342
+ <NavItem view="wallets" label="Wallets" expanded={railExpanded} isActive={isNavActive('wallets')} onClick={() => handleNavClick('wallets')}>
343
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
344
+ <rect x="2" y="6" width="20" height="14" rx="2" /><path d="M22 10H18a2 2 0 0 0 0 4h4" /><path d="M6 6V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v2" />
345
+ </svg>
346
+ </NavItem>
346
347
  <NavItem view="providers" label="Providers" expanded={railExpanded} isActive={isNavActive('providers')} onClick={() => handleNavClick('providers')}>
347
348
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
348
349
  <path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z" />
@@ -365,11 +366,6 @@ export function SidebarRail({
365
366
  <path d="M12 16h.01" />
366
367
  </svg>
367
368
  </NavItem>
368
- <NavItem view="wallets" label="Wallets" expanded={railExpanded} isActive={isNavActive('wallets')} onClick={() => handleNavClick('wallets')}>
369
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
370
- <rect x="2" y="6" width="20" height="14" rx="2" /><path d="M22 10H18a2 2 0 0 0 0 4h4" /><path d="M6 6V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v2" />
371
- </svg>
372
- </NavItem>
373
369
  <NavItem view="logs" label="Logs" expanded={railExpanded} isActive={isNavActive('logs')} onClick={() => handleNavClick('logs')}>
374
370
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
375
371
  <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><polyline points="14 2 14 8 20 8" /><line x1="16" y1="13" x2="8" y2="13" /><line x1="16" y1="17" x2="8" y2="17" /><polyline points="10 9 9 9 8 9" />
@@ -8,7 +8,7 @@ import { OverviewTab } from './tabs/overview-tab'
8
8
  import { WorkTab } from './tabs/work-tab'
9
9
  import { OperationsTab } from './tabs/operations-tab'
10
10
  import { ActivityTab } from './tabs/activity-tab'
11
- import type { BoardTask, Mission } from '@/types'
11
+ import type { BoardTask } from '@/types'
12
12
 
13
13
  export function ProjectDetail() {
14
14
  const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
@@ -17,43 +17,11 @@ export function ProjectDetail() {
17
17
  const activeTab = useAppStore((s) => s.projectDetailTab)
18
18
  const loadSecrets = useAppStore((s) => s.loadSecrets)
19
19
 
20
- const [projectMissionSnapshot, setProjectMissionSnapshot] = useState<{ projectId: string | null; missions: Mission[] }>({
21
- projectId: null,
22
- missions: [],
23
- })
24
-
25
20
  useEffect(() => {
26
21
  if (!activeProjectFilter) return
27
22
  void loadSecrets()
28
23
  }, [activeProjectFilter, loadSecrets])
29
24
 
30
- useEffect(() => {
31
- let cancelled = false
32
- if (!activeProjectFilter) return
33
- void api<Mission[]>('GET', `/missions?projectId=${encodeURIComponent(activeProjectFilter)}&status=non_terminal&limit=8`)
34
- .then((missions) => {
35
- if (!cancelled) {
36
- setProjectMissionSnapshot({
37
- projectId: activeProjectFilter,
38
- missions: Array.isArray(missions) ? missions : [],
39
- })
40
- }
41
- })
42
- .catch(() => {
43
- if (!cancelled) {
44
- setProjectMissionSnapshot({
45
- projectId: activeProjectFilter,
46
- missions: [],
47
- })
48
- }
49
- })
50
- return () => { cancelled = true }
51
- }, [activeProjectFilter])
52
-
53
- const projectMissions = projectMissionSnapshot.projectId === activeProjectFilter
54
- ? projectMissionSnapshot.missions
55
- : []
56
-
57
25
  const project = activeProjectFilter ? projects[activeProjectFilter] : null
58
26
 
59
27
  const projectTasks = useMemo(
@@ -107,10 +75,10 @@ export function ProjectDetail() {
107
75
  />
108
76
  <div className="flex-1 overflow-y-auto">
109
77
  {activeTab === 'overview' && (
110
- <OverviewTab project={project} missions={projectMissions} />
78
+ <OverviewTab project={project} />
111
79
  )}
112
80
  {activeTab === 'work' && (
113
- <WorkTab missions={projectMissions} />
81
+ <WorkTab />
114
82
  )}
115
83
  {activeTab === 'operations' && (
116
84
  <OperationsTab project={project} />
@@ -1,19 +1,15 @@
1
1
  'use client'
2
2
 
3
3
  import { useEffect, useMemo, useState } from 'react'
4
- import { useRouter } from 'next/navigation'
5
4
  import { useAppStore } from '@/stores/use-app-store'
6
5
  import { relativeDate } from '../project-utils'
7
- import { getMissionPath } from '@/lib/app/navigation'
8
- import type { BoardTask, Mission, Project, Schedule } from '@/types'
6
+ import type { BoardTask, Project, Schedule } from '@/types'
9
7
 
10
8
  interface OverviewTabProps {
11
9
  project: Project
12
- missions: Mission[]
13
10
  }
14
11
 
15
- export function OverviewTab({ project, missions }: OverviewTabProps) {
16
- const router = useRouter()
12
+ export function OverviewTab({ project }: OverviewTabProps) {
17
13
  const tasks = useAppStore((s) => s.tasks) as Record<string, BoardTask>
18
14
  const schedules = useAppStore((s) => s.schedules) as Record<string, Schedule>
19
15
  const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
@@ -66,8 +62,6 @@ export function OverviewTab({ project, missions }: OverviewTabProps) {
66
62
  { label: 'Stale', value: staleCount, tone: 'text-sky-400', hint: 'No meaningful progress in 3+ days' },
67
63
  ]
68
64
 
69
- const displayedMissions = missions.slice(0, 5)
70
-
71
65
  return (
72
66
  <div className="max-w-3xl mx-auto px-8 py-6 space-y-6">
73
67
  {/* Section 1: Project Identity */}
@@ -110,57 +104,7 @@ export function OverviewTab({ project, missions }: OverviewTabProps) {
110
104
  </div>
111
105
  </div>
112
106
 
113
- {/* Section 3: Active Missions */}
114
- <div>
115
- <h3 className="text-[12px] font-700 uppercase tracking-[0.08em] text-text-3/60 mb-3">Active Missions</h3>
116
- {displayedMissions.length === 0 ? (
117
- <p className="text-[12px] text-text-3/45">No active missions.</p>
118
- ) : (
119
- <div className="flex flex-col gap-2">
120
- {displayedMissions.map((mission) => (
121
- <button
122
- key={mission.id}
123
- onClick={() => router.push(getMissionPath(mission.id))}
124
- className="w-full flex items-center justify-between gap-3 px-4 py-3 rounded-[12px] border border-white/[0.06] bg-white/[0.02] hover:bg-white/[0.04] transition-all cursor-pointer text-left"
125
- style={{ fontFamily: 'inherit' }}
126
- >
127
- <div className="min-w-0 flex-1">
128
- <div className="text-[13px] font-600 text-text truncate">{mission.objective}</div>
129
- <div className="flex items-center gap-2 mt-1 flex-wrap">
130
- <span className={`text-[9px] font-600 uppercase tracking-wider px-1.5 py-0.5 rounded-[4px] ${
131
- mission.status === 'active' ? 'bg-sky-500/15 text-sky-400'
132
- : mission.status === 'waiting' ? 'bg-amber-500/15 text-amber-400'
133
- : 'bg-white/[0.06] text-text-3'
134
- }`}>
135
- {mission.status}
136
- </span>
137
- {mission.status === 'waiting' && (
138
- <span className="text-[9px] font-600 px-1.5 py-0.5 rounded-[4px] bg-amber-500/10 text-amber-400/70">waiting</span>
139
- )}
140
- {mission.status === 'failed' && (
141
- <span className="text-[9px] font-600 px-1.5 py-0.5 rounded-[4px] bg-red-500/10 text-red-400/70">blocked</span>
142
- )}
143
- {(mission.childMissionIds?.length || 0) > 0 && (
144
- <span className="text-[9px] font-600 px-1.5 py-0.5 rounded-[4px] bg-sky-500/10 text-sky-400/70">{mission.childMissionIds?.length} children</span>
145
- )}
146
- {(mission.taskIds?.length || 0) > 0 && (
147
- <span className="text-[9px] font-600 px-1.5 py-0.5 rounded-[4px] bg-white/[0.06] text-text-3/60">{mission.taskIds?.length} task{mission.taskIds?.length === 1 ? '' : 's'}</span>
148
- )}
149
- </div>
150
- </div>
151
- <span className="text-[10px] text-text-3/35 shrink-0">{relativeDate(mission.updatedAt)}</span>
152
- </button>
153
- ))}
154
- {missions.length > 5 && (
155
- <p className="text-[11px] text-accent-bright/70 text-center py-1">
156
- {missions.length - 5} more mission{missions.length - 5 === 1 ? '' : 's'}
157
- </p>
158
- )}
159
- </div>
160
- )}
161
- </div>
162
-
163
- {/* Section 4: Progress */}
107
+ {/* Section 3: Progress */}
164
108
  {totalTasks > 0 && (
165
109
  <div className="rounded-[12px] border border-white/[0.06] bg-white/[0.02] px-5 py-4">
166
110
  <div className="flex items-center justify-between mb-2.5">