@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.
- package/README.md +54 -23
- package/next.config.ts +1 -0
- package/package.json +4 -3
- package/scripts/easy-setup.mjs +1 -1
- package/scripts/postinstall.mjs +1 -1
- package/skills/swarmclaw.md +115 -0
- package/skills/tools/browser.md +131 -0
- package/skills/tools/execute.md +98 -0
- package/skills/tools/files.md +98 -0
- package/skills/tools/memory.md +104 -0
- package/skills/tools/platform.md +144 -0
- package/skills/tools/skills.md +83 -0
- package/src/app/agents/[id]/page.tsx +1 -18
- package/src/app/api/agents/thread-route.test.ts +0 -1
- package/src/app/api/approvals/route.test.ts +6 -22
- package/src/app/api/chats/[id]/messages/route.ts +23 -19
- package/src/app/api/chats/messages-route.test.ts +105 -51
- package/src/app/api/connectors/route.ts +2 -2
- package/src/app/api/mcp-servers/[id]/test/route.ts +3 -2
- package/src/app/api/openclaw/deploy/route.ts +2 -0
- package/src/app/api/portability/export/route.ts +8 -0
- package/src/app/api/portability/import/route.test.ts +80 -0
- package/src/app/api/portability/import/route.ts +28 -0
- package/src/app/api/settings/route.ts +0 -2
- package/src/app/api/setup/doctor/route.ts +4 -4
- package/src/app/api/wallets/[id]/route.ts +15 -157
- package/src/app/api/wallets/generate/route.ts +22 -0
- package/src/app/api/wallets/route.test.ts +147 -0
- package/src/app/api/wallets/route.ts +13 -95
- package/src/app/autonomy/page.tsx +2 -57
- package/src/app/protocols/page.tsx +2 -21
- package/src/app/settings/page.tsx +0 -9
- package/src/app/wallets/page.tsx +105 -5
- package/src/cli/index.js +21 -33
- package/src/cli/spec.js +19 -30
- package/src/components/agents/agent-chat-list.tsx +23 -1
- package/src/components/agents/agent-sheet.tsx +2 -40
- package/src/components/agents/inspector-panel.tsx +165 -131
- package/src/components/chat/chat-area.tsx +38 -9
- package/src/components/chat/chat-card.tsx +0 -31
- package/src/components/chat/message-bubble.tsx +1 -108
- package/src/components/chat/message-list.tsx +33 -19
- package/src/components/connectors/connector-sheet.tsx +25 -1
- package/src/components/gateways/gateway-sheet.tsx +5 -2
- package/src/components/layout/sidebar-rail.tsx +6 -10
- package/src/components/projects/project-detail.tsx +3 -35
- package/src/components/projects/tabs/overview-tab.tsx +3 -59
- package/src/components/projects/tabs/work-tab.tsx +7 -77
- package/src/components/protocols/structured-session-launcher.tsx +1 -22
- package/src/components/shared/connector-platform-icon.tsx +1 -0
- package/src/components/tasks/task-card.tsx +4 -34
- package/src/components/tasks/task-sheet.tsx +6 -36
- package/src/components/wallets/wallet-list.tsx +150 -0
- package/src/lib/agent-execute-defaults.test.ts +24 -0
- package/src/lib/agent-execute-defaults.ts +62 -0
- package/src/lib/app/navigation.test.ts +0 -13
- package/src/lib/app/navigation.ts +2 -7
- package/src/lib/app/view-constants.ts +14 -19
- package/src/lib/chat/queued-message-queue.test.ts +134 -1
- package/src/lib/chat/queued-message-queue.ts +77 -2
- package/src/lib/server/agents/agent-service.ts +5 -0
- package/src/lib/server/agents/agent-thread-session.ts +0 -1
- package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
- package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
- package/src/lib/server/agents/delegation-jobs.ts +0 -25
- package/src/lib/server/agents/main-agent-loop.ts +1 -49
- package/src/lib/server/agents/subagent-runtime.ts +0 -1
- package/src/lib/server/approval-match.ts +0 -85
- package/src/lib/server/approvals.test.ts +6 -6
- package/src/lib/server/approvals.ts +0 -6
- package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
- package/src/lib/server/builtin-extensions.ts +1 -2
- package/src/lib/server/capability-router.test.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-advanced.test.ts +1 -1
- package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +15 -14
- package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-utils.ts +2 -4
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +81 -64
- package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -0
- package/src/lib/server/chat-execution/continuation-evaluator.ts +8 -0
- package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
- package/src/lib/server/chat-execution/memory-mutation-tools.ts +1 -1
- package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
- package/src/lib/server/chat-execution/message-classifier.ts +11 -16
- package/src/lib/server/chat-execution/prompt-builder.test.ts +27 -0
- package/src/lib/server/chat-execution/prompt-builder.ts +14 -31
- package/src/lib/server/chat-execution/prompt-mode.test.ts +24 -0
- package/src/lib/server/chat-execution/prompt-mode.ts +5 -1
- package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
- package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
- package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
- package/src/lib/server/chat-execution/stream-agent-chat.test.ts +13 -126
- package/src/lib/server/chat-execution/stream-agent-chat.ts +46 -21
- package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
- package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
- package/src/lib/server/chatrooms/chatroom-routing.test.ts +4 -0
- package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
- package/src/lib/server/chats/chat-session-service.ts +3 -5
- package/src/lib/server/connectors/connector-inbound.ts +0 -1
- package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
- package/src/lib/server/connectors/connector-service.ts +39 -9
- package/src/lib/server/connectors/discord.ts +2 -2
- package/src/lib/server/connectors/matrix.ts +3 -2
- package/src/lib/server/connectors/signal.ts +5 -4
- package/src/lib/server/connectors/slack.ts +10 -9
- package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
- package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
- package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
- package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
- package/src/lib/server/connectors/swarmdock-tasks.ts +119 -0
- package/src/lib/server/connectors/swarmdock.ts +255 -0
- package/src/lib/server/connectors/teams.ts +3 -2
- package/src/lib/server/connectors/telegram.ts +4 -4
- package/src/lib/server/connectors/whatsapp.ts +2 -2
- package/src/lib/server/daemon/controller.ts +7 -0
- package/src/lib/server/execution-brief.test.ts +2 -25
- package/src/lib/server/execution-brief.ts +12 -35
- package/src/lib/server/execution-engine/task-attempt.ts +0 -1
- package/src/lib/server/gateways/gateway-profile-service.ts +19 -1
- package/src/lib/server/messages/message-repository.test.ts +70 -0
- package/src/lib/server/messages/message-repository.ts +11 -6
- package/src/lib/server/openclaw/deploy.ts +32 -2
- package/src/lib/server/persistence/storage-context.ts +0 -5
- package/src/lib/server/plugins-advanced.test.ts +1 -2
- package/src/lib/server/portability/export.ts +109 -0
- package/src/lib/server/portability/import.ts +159 -0
- package/src/lib/server/protocols/protocol-normalization.ts +0 -4
- package/src/lib/server/protocols/protocol-queries.ts +0 -6
- package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
- package/src/lib/server/protocols/protocol-service.ts +0 -1
- package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
- package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
- package/src/lib/server/protocols/protocol-swarm.ts +0 -2
- package/src/lib/server/protocols/protocol-types.ts +0 -2
- package/src/lib/server/provider-health.ts +1 -10
- package/src/lib/server/runtime/daemon-state/core.ts +0 -9
- package/src/lib/server/runtime/daemon-state.test.ts +0 -35
- package/src/lib/server/runtime/heartbeat-service.ts +3 -23
- package/src/lib/server/runtime/process-manager.ts +13 -9
- package/src/lib/server/runtime/queue/core.ts +11 -33
- package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
- package/src/lib/server/runtime/scheduler.ts +0 -13
- package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
- package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
- package/src/lib/server/runtime/session-run-manager/queries.ts +15 -1
- package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
- package/src/lib/server/runtime/session-run-manager.test.ts +58 -28
- package/src/lib/server/sandbox/session-runtime.test.ts +18 -1
- package/src/lib/server/sandbox/session-runtime.ts +40 -28
- package/src/lib/server/session-tools/autonomy-tools.test.ts +7 -9
- package/src/lib/server/session-tools/context.ts +1 -1
- package/src/lib/server/session-tools/credential-env.ts +109 -0
- package/src/lib/server/session-tools/crud.ts +3 -17
- package/src/lib/server/session-tools/delegate.ts +0 -4
- package/src/lib/server/session-tools/edit_file.ts +3 -2
- package/src/lib/server/session-tools/execute.test.ts +58 -0
- package/src/lib/server/session-tools/execute.ts +334 -0
- package/src/lib/server/session-tools/files-tool.ts +635 -0
- package/src/lib/server/session-tools/index.ts +14 -8
- package/src/lib/server/session-tools/memory-tool.ts +242 -0
- package/src/lib/server/session-tools/memory.ts +1 -1
- package/src/lib/server/session-tools/openclaw-nodes.ts +3 -2
- package/src/lib/server/session-tools/openclaw-workspace.ts +3 -2
- package/src/lib/server/session-tools/platform-tool.ts +617 -0
- package/src/lib/server/session-tools/session-info.ts +3 -2
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +3 -4
- package/src/lib/server/session-tools/shell.ts +7 -122
- package/src/lib/server/session-tools/skills-tool.ts +396 -0
- package/src/lib/server/session-tools/team-context.ts +0 -3
- package/src/lib/server/session-tools/web.ts +2 -2
- package/src/lib/server/storage-normalization.ts +10 -0
- package/src/lib/server/storage.ts +18 -45
- package/src/lib/server/tasks/task-checkout.ts +59 -0
- package/src/lib/server/tasks/task-lifecycle.ts +2 -0
- package/src/lib/server/tasks/task-route-service.ts +4 -26
- package/src/lib/server/tasks/task-service.ts +0 -7
- package/src/lib/server/tool-aliases.ts +2 -2
- package/src/lib/server/tool-capability-policy-advanced.test.ts +13 -6
- package/src/lib/server/tool-capability-policy.test.ts +2 -1
- package/src/lib/server/tool-capability-policy.ts +60 -35
- package/src/lib/server/tool-planning.ts +11 -12
- package/src/lib/server/universal-tool-access.ts +0 -1
- package/src/lib/server/wallets/wallet-crypto.ts +33 -0
- package/src/lib/server/wallets/wallet-repository.ts +24 -0
- package/src/lib/server/wallets/wallet-service.ts +119 -0
- package/src/lib/server/working-state/extraction.ts +8 -42
- package/src/lib/server/working-state/normalization.ts +10 -103
- package/src/lib/server/working-state/service.ts +12 -21
- package/src/lib/setup-defaults.ts +5 -0
- package/src/lib/strip-internal-metadata.test.ts +1 -1
- package/src/lib/strip-internal-metadata.ts +1 -1
- package/src/lib/tool-definitions.ts +1 -1
- package/src/lib/validation/schemas.test.ts +16 -0
- package/src/lib/validation/schemas.ts +49 -2
- package/src/stores/slices/data-slice.ts +5 -1
- package/src/stores/slices/ui-slice.ts +0 -4
- package/src/stores/use-chat-store.test.ts +231 -0
- package/src/stores/use-chat-store.ts +62 -13
- package/src/types/agent.ts +264 -0
- package/src/types/app-settings.ts +173 -0
- package/src/types/approval.ts +25 -0
- package/src/types/connector.ts +188 -0
- package/src/types/extension.ts +386 -0
- package/src/types/index.ts +16 -3555
- package/src/types/message.ts +56 -0
- package/src/types/misc.ts +737 -0
- package/src/types/protocol.ts +420 -0
- package/src/types/provider.ts +52 -0
- package/src/types/run.ts +180 -0
- package/src/types/schedule.ts +59 -0
- package/src/types/session.ts +215 -0
- package/src/types/skill.ts +157 -0
- package/src/types/swarmdock.ts +29 -0
- package/src/types/task.ts +144 -0
- package/src/types/working-state.ts +204 -0
- package/src/views/settings/section-heartbeat.tsx +2 -2
- package/src/views/settings/section-runtime-loop.tsx +0 -14
- package/src/app/api/canvas/[sessionId]/route.ts +0 -35
- package/src/app/api/missions/[id]/actions/route.ts +0 -31
- package/src/app/api/missions/[id]/events/route.ts +0 -14
- package/src/app/api/missions/[id]/route.ts +0 -10
- package/src/app/api/missions/route.test.ts +0 -244
- package/src/app/api/missions/route.ts +0 -57
- package/src/app/api/wallets/[id]/approve/route.ts +0 -79
- package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
- package/src/app/api/wallets/[id]/send/route.ts +0 -113
- package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
- package/src/app/missions/[id]/page.tsx +0 -3
- package/src/app/missions/page.tsx +0 -685
- package/src/components/canvas/canvas-panel.tsx +0 -267
- package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
- package/src/components/wallets/wallet-panel.tsx +0 -1010
- package/src/components/wallets/wallet-section.tsx +0 -260
- package/src/features/missions/queries.ts +0 -23
- package/src/lib/canvas-content.test.ts +0 -360
- package/src/lib/canvas-content.ts +0 -198
- package/src/lib/server/canvas-content.test.ts +0 -32
- package/src/lib/server/canvas-content.ts +0 -6
- package/src/lib/server/ethereum.ts +0 -591
- package/src/lib/server/evm-swap.ts +0 -476
- package/src/lib/server/missions/mission-intent.test.ts +0 -63
- package/src/lib/server/missions/mission-intent.ts +0 -569
- package/src/lib/server/missions/mission-repository.ts +0 -74
- package/src/lib/server/missions/mission-service/actions.ts +0 -6
- package/src/lib/server/missions/mission-service/bindings.ts +0 -9
- package/src/lib/server/missions/mission-service/context.ts +0 -4
- package/src/lib/server/missions/mission-service/core.ts +0 -2271
- package/src/lib/server/missions/mission-service/queries.ts +0 -12
- package/src/lib/server/missions/mission-service/recovery.ts +0 -5
- package/src/lib/server/missions/mission-service/ticks.ts +0 -9
- package/src/lib/server/missions/mission-service.test.ts +0 -888
- package/src/lib/server/missions/mission-service.ts +0 -6
- package/src/lib/server/session-tools/canvas.ts +0 -105
- package/src/lib/server/session-tools/sandbox.ts +0 -281
- package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
- package/src/lib/server/session-tools/wallet.ts +0 -1287
- package/src/lib/server/solana.ts +0 -327
- package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
- package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
- package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
- package/src/lib/server/wallet/wallet-service.test.ts +0 -81
- package/src/lib/server/wallet/wallet-service.ts +0 -225
- package/src/lib/wallet/wallet-transactions.test.ts +0 -75
- package/src/lib/wallet/wallet-transactions.ts +0 -43
- package/src/lib/wallet/wallet.test.ts +0 -333
- package/src/lib/wallet/wallet.ts +0 -183
- 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
|
-
{
|
|
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">"{walletRequest.memo}"</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 (
|
|
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[
|
|
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:
|
|
254
|
+
await api('PUT', `/chats/${sid}/messages`, { messageIndex: absoluteIndex, bookmarked: next })
|
|
249
255
|
const updated = [...msgs]
|
|
250
|
-
updated[
|
|
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 =
|
|
303
|
-
const candidate =
|
|
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
|
-
}, [
|
|
320
|
+
}, [displayedMessages])
|
|
310
321
|
|
|
311
322
|
const currentRunHasCompletedAssistant = useMemo(
|
|
312
323
|
() => (
|
|
313
324
|
streaming
|
|
314
325
|
&& thinkingStartTime > 0
|
|
315
|
-
&&
|
|
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
|
-
[
|
|
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(
|
|
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,
|
|
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 (
|
|
386
|
+
const handleDeleteMessage = useCallback(async (absoluteIndex: number) => {
|
|
376
387
|
const sid = sessionIdRef.current
|
|
377
388
|
const msgs = messagesCallbackRef.current
|
|
378
|
-
|
|
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(
|
|
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
|
-
|
|
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() ||
|
|
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
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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
|
|
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}
|
|
78
|
+
<OverviewTab project={project} />
|
|
111
79
|
)}
|
|
112
80
|
{activeTab === 'work' && (
|
|
113
|
-
<WorkTab
|
|
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 {
|
|
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
|
|
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:
|
|
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">
|