@swarmclawai/swarmclaw 0.6.4 → 0.6.7

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 (143) hide show
  1. package/README.md +62 -30
  2. package/package.json +10 -1
  3. package/src/app/api/agents/[id]/clone/route.ts +40 -0
  4. package/src/app/api/agents/route.ts +39 -14
  5. package/src/app/api/chatrooms/[id]/chat/route.ts +58 -3
  6. package/src/app/api/chatrooms/[id]/moderate/route.ts +150 -0
  7. package/src/app/api/chatrooms/[id]/route.ts +34 -2
  8. package/src/app/api/chatrooms/route.ts +26 -3
  9. package/src/app/api/connectors/[id]/health/route.ts +64 -0
  10. package/src/app/api/connectors/route.ts +17 -2
  11. package/src/app/api/knowledge/route.ts +6 -1
  12. package/src/app/api/openclaw/doctor/route.ts +17 -0
  13. package/src/app/api/schedules/[id]/run/route.ts +3 -0
  14. package/src/app/api/sessions/[id]/chat/route.ts +5 -1
  15. package/src/app/api/sessions/route.ts +11 -2
  16. package/src/app/api/tasks/[id]/route.ts +18 -13
  17. package/src/app/api/tasks/route.ts +44 -1
  18. package/src/app/api/usage/route.ts +16 -7
  19. package/src/app/api/wallets/[id]/approve/route.ts +62 -0
  20. package/src/app/api/wallets/[id]/balance-history/route.ts +18 -0
  21. package/src/app/api/wallets/[id]/route.ts +118 -0
  22. package/src/app/api/wallets/[id]/send/route.ts +118 -0
  23. package/src/app/api/wallets/[id]/transactions/route.ts +18 -0
  24. package/src/app/api/wallets/route.ts +74 -0
  25. package/src/app/globals.css +8 -0
  26. package/src/cli/index.js +20 -0
  27. package/src/cli/index.ts +223 -39
  28. package/src/cli/spec.js +14 -0
  29. package/src/components/agents/agent-avatar.tsx +15 -1
  30. package/src/components/agents/agent-card.tsx +38 -6
  31. package/src/components/agents/agent-chat-list.tsx +79 -3
  32. package/src/components/agents/agent-sheet.tsx +191 -26
  33. package/src/components/auth/setup-wizard.tsx +268 -353
  34. package/src/components/chat/chat-area.tsx +24 -9
  35. package/src/components/chat/chat-header.tsx +48 -19
  36. package/src/components/chat/chat-tool-toggles.tsx +1 -1
  37. package/src/components/chat/delegation-banner.test.ts +27 -0
  38. package/src/components/chat/delegation-banner.tsx +109 -23
  39. package/src/components/chat/message-bubble.tsx +17 -16
  40. package/src/components/chat/message-list.tsx +6 -5
  41. package/src/components/chat/streaming-bubble.tsx +3 -2
  42. package/src/components/chat/thinking-indicator.tsx +3 -2
  43. package/src/components/chat/transfer-agent-picker.tsx +1 -1
  44. package/src/components/chatrooms/agent-hover-card.tsx +1 -1
  45. package/src/components/chatrooms/chatroom-input.tsx +1 -1
  46. package/src/components/chatrooms/chatroom-message.tsx +165 -23
  47. package/src/components/chatrooms/chatroom-sheet.tsx +289 -4
  48. package/src/components/chatrooms/chatroom-typing-bar.tsx +1 -1
  49. package/src/components/chatrooms/chatroom-view.tsx +62 -17
  50. package/src/components/connectors/connector-health.tsx +120 -0
  51. package/src/components/connectors/connector-list.tsx +1 -1
  52. package/src/components/connectors/connector-sheet.tsx +9 -0
  53. package/src/components/home/home-view.tsx +25 -3
  54. package/src/components/input/chat-input.tsx +8 -1
  55. package/src/components/knowledge/knowledge-list.tsx +1 -1
  56. package/src/components/knowledge/knowledge-sheet.tsx +1 -1
  57. package/src/components/layout/app-layout.tsx +35 -4
  58. package/src/components/memory/memory-agent-list.tsx +1 -1
  59. package/src/components/memory/memory-browser.tsx +1 -0
  60. package/src/components/memory/memory-card.tsx +3 -2
  61. package/src/components/memory/memory-detail.tsx +3 -3
  62. package/src/components/memory/memory-sheet.tsx +2 -2
  63. package/src/components/projects/project-detail.tsx +4 -4
  64. package/src/components/schedules/schedule-list.tsx +55 -9
  65. package/src/components/schedules/schedule-sheet.tsx +134 -23
  66. package/src/components/secrets/secret-sheet.tsx +1 -1
  67. package/src/components/secrets/secrets-list.tsx +1 -1
  68. package/src/components/sessions/session-card.tsx +1 -1
  69. package/src/components/shared/agent-picker-list.tsx +1 -1
  70. package/src/components/shared/agent-switch-dialog.tsx +1 -1
  71. package/src/components/shared/command-palette.tsx +237 -0
  72. package/src/components/shared/connector-platform-icon.tsx +1 -0
  73. package/src/components/shared/settings/section-user-preferences.tsx +4 -4
  74. package/src/components/skills/skill-list.tsx +1 -1
  75. package/src/components/skills/skill-sheet.tsx +1 -1
  76. package/src/components/tasks/task-board.tsx +3 -3
  77. package/src/components/tasks/task-card.tsx +22 -2
  78. package/src/components/tasks/task-sheet.tsx +112 -17
  79. package/src/components/usage/metrics-dashboard.tsx +13 -25
  80. package/src/components/wallets/wallet-approval-dialog.tsx +99 -0
  81. package/src/components/wallets/wallet-panel.tsx +616 -0
  82. package/src/components/wallets/wallet-section.tsx +100 -0
  83. package/src/hooks/use-swipe.ts +49 -0
  84. package/src/lib/providers/anthropic.ts +16 -2
  85. package/src/lib/providers/claude-cli.ts +7 -1
  86. package/src/lib/providers/index.ts +7 -0
  87. package/src/lib/providers/ollama.ts +16 -2
  88. package/src/lib/providers/openai.ts +7 -2
  89. package/src/lib/providers/openclaw.ts +6 -1
  90. package/src/lib/providers/provider-defaults.ts +7 -0
  91. package/src/lib/schedule-templates.ts +115 -0
  92. package/src/lib/server/agent-registry.ts +2 -2
  93. package/src/lib/server/alert-dispatch.ts +64 -0
  94. package/src/lib/server/chat-execution.ts +76 -4
  95. package/src/lib/server/chatroom-health.ts +60 -0
  96. package/src/lib/server/chatroom-helpers.test.ts +94 -0
  97. package/src/lib/server/chatroom-helpers.ts +86 -12
  98. package/src/lib/server/chatroom-routing.ts +65 -0
  99. package/src/lib/server/connectors/discord.ts +3 -0
  100. package/src/lib/server/connectors/email.ts +267 -0
  101. package/src/lib/server/connectors/inbound-audio-transcription.test.ts +191 -0
  102. package/src/lib/server/connectors/inbound-audio-transcription.ts +261 -0
  103. package/src/lib/server/connectors/manager.ts +239 -5
  104. package/src/lib/server/connectors/openclaw.ts +3 -0
  105. package/src/lib/server/connectors/slack.ts +6 -0
  106. package/src/lib/server/connectors/telegram.ts +18 -0
  107. package/src/lib/server/connectors/types.ts +2 -0
  108. package/src/lib/server/connectors/whatsapp-text.test.ts +29 -0
  109. package/src/lib/server/connectors/whatsapp-text.ts +26 -0
  110. package/src/lib/server/connectors/whatsapp.ts +17 -5
  111. package/src/lib/server/cost.ts +70 -0
  112. package/src/lib/server/create-notification.ts +2 -0
  113. package/src/lib/server/daemon-state.ts +124 -0
  114. package/src/lib/server/dag-validation.ts +115 -0
  115. package/src/lib/server/memory-db.ts +12 -7
  116. package/src/lib/server/openclaw-doctor.ts +48 -0
  117. package/src/lib/server/orchestrator-lg.ts +12 -2
  118. package/src/lib/server/orchestrator.ts +6 -1
  119. package/src/lib/server/queue-followups.test.ts +224 -0
  120. package/src/lib/server/queue.ts +238 -24
  121. package/src/lib/server/scheduler.ts +3 -0
  122. package/src/lib/server/session-run-manager.ts +22 -1
  123. package/src/lib/server/session-tools/chatroom.ts +11 -2
  124. package/src/lib/server/session-tools/context-mgmt.ts +2 -2
  125. package/src/lib/server/session-tools/index.ts +8 -2
  126. package/src/lib/server/session-tools/memory.ts +23 -4
  127. package/src/lib/server/session-tools/openclaw-workspace.ts +132 -0
  128. package/src/lib/server/session-tools/shell.ts +1 -1
  129. package/src/lib/server/session-tools/wallet.ts +124 -0
  130. package/src/lib/server/session-tools/web.ts +2 -2
  131. package/src/lib/server/solana.ts +122 -0
  132. package/src/lib/server/storage.ts +158 -6
  133. package/src/lib/server/stream-agent-chat.ts +126 -63
  134. package/src/lib/server/task-mention.test.ts +41 -0
  135. package/src/lib/server/task-mention.ts +3 -2
  136. package/src/lib/setup-defaults.ts +277 -0
  137. package/src/lib/tool-definitions.ts +1 -0
  138. package/src/lib/validation/schemas.ts +69 -0
  139. package/src/lib/view-routes.ts +1 -0
  140. package/src/stores/use-app-store.ts +15 -3
  141. package/src/stores/use-chatroom-store.ts +52 -2
  142. package/src/types/index.ts +98 -2
  143. package/tsconfig.json +2 -1
@@ -0,0 +1,118 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { loadWallets, upsertWallet, deleteWallet as deleteWalletFromStore, loadAgents, saveAgents } from '@/lib/server/storage'
3
+ import { getBalance, lamportsToSol } from '@/lib/server/solana'
4
+ import { notify } from '@/lib/server/ws-hub'
5
+ import type { AgentWallet } from '@/types'
6
+ export const dynamic = 'force-dynamic'
7
+
8
+ function stripPrivateKey(wallet: Record<string, unknown>): Record<string, unknown> {
9
+ return Object.fromEntries(Object.entries(wallet).filter(([k]) => k !== 'encryptedPrivateKey'))
10
+ }
11
+
12
+ export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
13
+ const { id } = await params
14
+ const wallets = loadWallets() as Record<string, AgentWallet>
15
+ const wallet = wallets[id]
16
+ if (!wallet) return NextResponse.json({ error: 'Wallet not found' }, { status: 404 })
17
+
18
+ // Fetch live on-chain balance
19
+ let balanceLamports = 0
20
+ let balanceSol = 0
21
+ try {
22
+ balanceLamports = await getBalance(wallet.publicKey)
23
+ balanceSol = lamportsToSol(balanceLamports)
24
+ } catch {
25
+ // RPC failure — return 0
26
+ }
27
+
28
+ return NextResponse.json({
29
+ ...stripPrivateKey(wallet as unknown as Record<string, unknown>),
30
+ balanceLamports,
31
+ balanceSol,
32
+ })
33
+ }
34
+
35
+ export async function PATCH(req: Request, { params }: { params: Promise<{ id: string }> }) {
36
+ const { id } = await params
37
+ const wallets = loadWallets() as Record<string, AgentWallet>
38
+ const wallet = wallets[id]
39
+ if (!wallet) return NextResponse.json({ error: 'Wallet not found' }, { status: 404 })
40
+
41
+ const body = await req.json()
42
+
43
+ // Reassign wallet to a different agent
44
+ if (typeof body.agentId === 'string' && body.agentId !== wallet.agentId) {
45
+ const agents = loadAgents()
46
+ const newAgent = agents[body.agentId]
47
+ if (!newAgent) return NextResponse.json({ error: 'Agent not found' }, { status: 404 })
48
+
49
+ // Check new agent doesn't already have a wallet
50
+ const allWallets = loadWallets() as Record<string, AgentWallet>
51
+ const conflict = Object.values(allWallets).find((w) => w.agentId === body.agentId && w.id !== id)
52
+ if (conflict) return NextResponse.json({ error: 'Target agent already has a wallet' }, { status: 409 })
53
+
54
+ // Unlink old agent
55
+ const oldAgent = agents[wallet.agentId]
56
+ if (oldAgent) {
57
+ oldAgent.walletId = null
58
+ oldAgent.updatedAt = Date.now()
59
+ agents[wallet.agentId] = oldAgent
60
+ }
61
+
62
+ // Link new agent
63
+ newAgent.walletId = id
64
+ newAgent.updatedAt = Date.now()
65
+ agents[body.agentId] = newAgent
66
+ saveAgents(agents)
67
+ notify('agents')
68
+
69
+ wallet.agentId = body.agentId
70
+ }
71
+
72
+ if (body.label !== undefined) wallet.label = body.label
73
+ if (typeof body.spendingLimitLamports === 'number') wallet.spendingLimitLamports = body.spendingLimitLamports
74
+ if (typeof body.dailyLimitLamports === 'number') wallet.dailyLimitLamports = body.dailyLimitLamports
75
+ if (typeof body.requireApproval === 'boolean') wallet.requireApproval = body.requireApproval
76
+ wallet.updatedAt = Date.now()
77
+
78
+ upsertWallet(id, wallet)
79
+ notify('wallets')
80
+
81
+ return NextResponse.json(stripPrivateKey(wallet as unknown as Record<string, unknown>))
82
+ }
83
+
84
+ export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
85
+ const { id } = await params
86
+ const wallets = loadWallets() as Record<string, AgentWallet>
87
+ const wallet = wallets[id]
88
+ if (!wallet) return NextResponse.json({ error: 'Wallet not found' }, { status: 404 })
89
+
90
+ // Check if balance > 0 and warn
91
+ let balanceLamports = 0
92
+ try {
93
+ balanceLamports = await getBalance(wallet.publicKey)
94
+ } catch { /* ignore */ }
95
+
96
+ if (balanceLamports > 0) {
97
+ // Still delete, but include warning
98
+ }
99
+
100
+ // Unlink from agent
101
+ const agents = loadAgents()
102
+ const agent = agents[wallet.agentId]
103
+ if (agent) {
104
+ agent.walletId = null
105
+ agent.updatedAt = Date.now()
106
+ agents[wallet.agentId] = agent
107
+ saveAgents(agents)
108
+ notify('agents')
109
+ }
110
+
111
+ deleteWalletFromStore(id)
112
+ notify('wallets')
113
+
114
+ return NextResponse.json({
115
+ ok: true,
116
+ warning: balanceLamports > 0 ? `Wallet had ${lamportsToSol(balanceLamports)} SOL remaining` : undefined,
117
+ })
118
+ }
@@ -0,0 +1,118 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { genId } from '@/lib/id'
3
+ import { loadWallets, loadWalletTransactions, upsertWalletTransaction } from '@/lib/server/storage'
4
+ import { sendSol, isValidSolanaAddress, lamportsToSol } from '@/lib/server/solana'
5
+ import { notify } from '@/lib/server/ws-hub'
6
+ import type { AgentWallet, WalletTransaction } from '@/types'
7
+ export const dynamic = 'force-dynamic'
8
+
9
+ export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
10
+ const { id } = await params
11
+ const wallets = loadWallets() as Record<string, AgentWallet>
12
+ const wallet = wallets[id]
13
+ if (!wallet) return NextResponse.json({ error: 'Wallet not found' }, { status: 404 })
14
+
15
+ const body = await req.json()
16
+ const toAddress = typeof body.toAddress === 'string' ? body.toAddress.trim() : ''
17
+ const amountLamports = typeof body.amountLamports === 'number' ? Math.floor(body.amountLamports) : 0
18
+ const memo = typeof body.memo === 'string' ? body.memo.slice(0, 500) : undefined
19
+
20
+ if (!toAddress || !isValidSolanaAddress(toAddress)) {
21
+ return NextResponse.json({ error: 'Invalid recipient address' }, { status: 400 })
22
+ }
23
+ if (amountLamports <= 0) {
24
+ return NextResponse.json({ error: 'Amount must be positive' }, { status: 400 })
25
+ }
26
+
27
+ // Per-tx spending limit
28
+ const perTxLimit = wallet.spendingLimitLamports ?? 100_000_000
29
+ if (amountLamports > perTxLimit) {
30
+ return NextResponse.json({
31
+ error: `Amount ${lamportsToSol(amountLamports)} SOL exceeds per-transaction limit of ${lamportsToSol(perTxLimit)} SOL`,
32
+ }, { status: 403 })
33
+ }
34
+
35
+ // 24h rolling daily limit
36
+ const dailyLimit = wallet.dailyLimitLamports ?? 1_000_000_000
37
+ const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000
38
+ const allTxs = loadWalletTransactions() as Record<string, WalletTransaction>
39
+ const recentSends = Object.values(allTxs).filter(
40
+ (tx) => tx.walletId === id && tx.type === 'send' && tx.status === 'confirmed' && tx.timestamp > oneDayAgo,
41
+ )
42
+ const dailySpent = recentSends.reduce((sum, tx) => sum + tx.amountLamports, 0)
43
+ if (dailySpent + amountLamports > dailyLimit) {
44
+ return NextResponse.json({
45
+ error: `Daily limit exceeded. Spent ${lamportsToSol(dailySpent)} SOL in last 24h, limit is ${lamportsToSol(dailyLimit)} SOL`,
46
+ }, { status: 403 })
47
+ }
48
+
49
+ const txId = genId(8)
50
+ const now = Date.now()
51
+
52
+ // If requireApproval, create pending tx and return it
53
+ if (wallet.requireApproval) {
54
+ const pendingTx: WalletTransaction = {
55
+ id: txId,
56
+ walletId: id,
57
+ agentId: wallet.agentId,
58
+ chain: wallet.chain,
59
+ type: 'send',
60
+ signature: '',
61
+ fromAddress: wallet.publicKey,
62
+ toAddress,
63
+ amountLamports,
64
+ status: 'pending_approval',
65
+ memo,
66
+ timestamp: now,
67
+ }
68
+ upsertWalletTransaction(txId, pendingTx)
69
+ notify('wallets')
70
+ return NextResponse.json({ status: 'pending_approval', transactionId: txId, message: 'Transaction requires user approval' })
71
+ }
72
+
73
+ // Auto-approved — sign and submit
74
+ try {
75
+ const { signature, fee } = await sendSol(wallet.encryptedPrivateKey, toAddress, amountLamports)
76
+ const confirmedTx: WalletTransaction = {
77
+ id: txId,
78
+ walletId: id,
79
+ agentId: wallet.agentId,
80
+ chain: wallet.chain,
81
+ type: 'send',
82
+ signature,
83
+ fromAddress: wallet.publicKey,
84
+ toAddress,
85
+ amountLamports,
86
+ feeLamports: fee,
87
+ status: 'confirmed',
88
+ memo,
89
+ approvedBy: 'auto',
90
+ timestamp: now,
91
+ }
92
+ upsertWalletTransaction(txId, confirmedTx)
93
+ notify('wallets')
94
+ return NextResponse.json({ status: 'confirmed', transactionId: txId, signature })
95
+ } catch (err: unknown) {
96
+ const failedTx: WalletTransaction = {
97
+ id: txId,
98
+ walletId: id,
99
+ agentId: wallet.agentId,
100
+ chain: wallet.chain,
101
+ type: 'send',
102
+ signature: '',
103
+ fromAddress: wallet.publicKey,
104
+ toAddress,
105
+ amountLamports,
106
+ status: 'failed',
107
+ memo,
108
+ timestamp: now,
109
+ }
110
+ upsertWalletTransaction(txId, failedTx)
111
+ notify('wallets')
112
+ return NextResponse.json({
113
+ error: err instanceof Error ? err.message : String(err),
114
+ transactionId: txId,
115
+ status: 'failed',
116
+ }, { status: 500 })
117
+ }
118
+ }
@@ -0,0 +1,18 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { loadWallets, loadWalletTransactions } from '@/lib/server/storage'
3
+ import type { AgentWallet, WalletTransaction } from '@/types'
4
+ export const dynamic = 'force-dynamic'
5
+
6
+ export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
7
+ const { id } = await params
8
+ const wallets = loadWallets() as Record<string, AgentWallet>
9
+ const wallet = wallets[id]
10
+ if (!wallet) return NextResponse.json({ error: 'Wallet not found' }, { status: 404 })
11
+
12
+ const allTxs = loadWalletTransactions() as Record<string, WalletTransaction>
13
+ const walletTxs = Object.values(allTxs)
14
+ .filter((tx) => tx.walletId === id)
15
+ .sort((a, b) => b.timestamp - a.timestamp)
16
+
17
+ return NextResponse.json(walletTxs)
18
+ }
@@ -0,0 +1,74 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { genId } from '@/lib/id'
3
+ import { loadWallets, upsertWallet, loadAgents, saveAgents } from '@/lib/server/storage'
4
+ import { generateSolanaKeypair } from '@/lib/server/solana'
5
+ import { notify } from '@/lib/server/ws-hub'
6
+ import type { AgentWallet, WalletChain } from '@/types'
7
+ export const dynamic = 'force-dynamic'
8
+
9
+ /** Strip encryptedPrivateKey from wallet for safe API responses */
10
+ function stripPrivateKey(wallet: Record<string, unknown>): Record<string, unknown> {
11
+ return Object.fromEntries(Object.entries(wallet).filter(([k]) => k !== 'encryptedPrivateKey'))
12
+ }
13
+
14
+ export async function GET() {
15
+ const wallets = loadWallets() as Record<string, AgentWallet>
16
+ const safe = Object.fromEntries(
17
+ Object.entries(wallets).map(([id, w]) => [id, stripPrivateKey(w as unknown as Record<string, unknown>)]),
18
+ )
19
+ return NextResponse.json(safe)
20
+ }
21
+
22
+ export async function POST(req: Request) {
23
+ const body = await req.json()
24
+ const agentId = typeof body.agentId === 'string' ? body.agentId.trim() : ''
25
+ if (!agentId) {
26
+ return NextResponse.json({ error: 'agentId is required' }, { status: 400 })
27
+ }
28
+
29
+ const agents = loadAgents()
30
+ if (!agents[agentId]) {
31
+ return NextResponse.json({ error: 'Agent not found' }, { status: 404 })
32
+ }
33
+
34
+ // Check agent doesn't already have a wallet
35
+ const existing = loadWallets() as Record<string, AgentWallet>
36
+ const hasWallet = Object.values(existing).some((w) => w.agentId === agentId)
37
+ if (hasWallet) {
38
+ return NextResponse.json({ error: 'Agent already has a wallet' }, { status: 409 })
39
+ }
40
+
41
+ const chain: WalletChain = body.chain === 'solana' ? 'solana' : 'solana' // extensible later
42
+ const { publicKey, encryptedPrivateKey } = generateSolanaKeypair()
43
+
44
+ const id = genId()
45
+ const now = Date.now()
46
+
47
+ const wallet: AgentWallet = {
48
+ id,
49
+ agentId,
50
+ chain,
51
+ publicKey,
52
+ encryptedPrivateKey,
53
+ label: typeof body.label === 'string' ? body.label : undefined,
54
+ spendingLimitLamports: typeof body.spendingLimitLamports === 'number' ? body.spendingLimitLamports : 100_000_000,
55
+ dailyLimitLamports: typeof body.dailyLimitLamports === 'number' ? body.dailyLimitLamports : 1_000_000_000,
56
+ requireApproval: body.requireApproval !== false,
57
+ createdAt: now,
58
+ updatedAt: now,
59
+ }
60
+
61
+ upsertWallet(id, wallet)
62
+
63
+ // Link wallet to agent
64
+ const agent = agents[agentId]
65
+ agent.walletId = id
66
+ agent.updatedAt = now
67
+ agents[agentId] = agent
68
+ saveAgents(agents)
69
+
70
+ notify('wallets')
71
+ notify('agents')
72
+
73
+ return NextResponse.json(stripPrivateKey(wallet as unknown as Record<string, unknown>))
74
+ }
@@ -215,6 +215,14 @@ textarea:hover::-webkit-scrollbar { width: 6px; }
215
215
  to { opacity: 1; transform: translateY(0); }
216
216
  }
217
217
  @keyframes spin { to { transform: rotate(360deg); } }
218
+ @keyframes pulse-glow {
219
+ 0%, 100% { transform: scale(1); opacity: 0.45; }
220
+ 50% { transform: scale(1.2); opacity: 0.85; }
221
+ }
222
+ @keyframes avatar-pulse {
223
+ 0%, 100% { transform: scale(1); }
224
+ 50% { transform: scale(1.1); }
225
+ }
218
226
  @keyframes slide-in-left {
219
227
  from { transform: translateX(-100%); }
220
228
  to { transform: translateX(0); }
package/src/cli/index.js CHANGED
@@ -21,6 +21,7 @@ const COMMAND_GROUPS = [
21
21
  cmd('restore', 'POST', '/agents/trash', 'Restore a trashed agent', { expectsJsonBody: true }),
22
22
  cmd('purge', 'DELETE', '/agents/trash', 'Permanently delete a trashed agent', { expectsJsonBody: true }),
23
23
  cmd('thread', 'POST', '/agents/:id/thread', 'Get or create agent thread session'),
24
+ cmd('clone', 'POST', '/agents/:id/clone', 'Clone an agent'),
24
25
  ],
25
26
  },
26
27
  {
@@ -77,6 +78,7 @@ const COMMAND_GROUPS = [
77
78
  cmd('pin', 'POST', '/chatrooms/:id/pins', 'Toggle pin on a chatroom message', {
78
79
  expectsJsonBody: true,
79
80
  }),
81
+ cmd('moderate', 'POST', '/chatrooms/:id/moderate', 'Run moderation action on a chatroom', { expectsJsonBody: true }),
80
82
  ],
81
83
  },
82
84
  {
@@ -109,6 +111,7 @@ const COMMAND_GROUPS = [
109
111
  expectsJsonBody: true,
110
112
  defaultBody: { action: 'repair' },
111
113
  }),
114
+ cmd('health', 'GET', '/connectors/:id/health', 'Get connector health status'),
112
115
  ],
113
116
  },
114
117
  {
@@ -289,6 +292,8 @@ const COMMAND_GROUPS = [
289
292
  cmd('skills-install', 'POST', '/openclaw/skills/install', 'Install OpenClaw skill dependencies', { expectsJsonBody: true }),
290
293
  cmd('skills-remove', 'POST', '/openclaw/skills/remove', 'Remove OpenClaw skill', { expectsJsonBody: true }),
291
294
  cmd('sync', 'POST', '/openclaw/sync', 'Run OpenClaw sync action', { expectsJsonBody: true }),
295
+ cmd('doctor', 'GET', '/openclaw/doctor', 'Run OpenClaw doctor check (read-only)'),
296
+ cmd('doctor-fix', 'POST', '/openclaw/doctor', 'Run OpenClaw doctor with auto-fix', { expectsJsonBody: true }),
292
297
  ],
293
298
  },
294
299
  {
@@ -485,6 +490,21 @@ const COMMAND_GROUPS = [
485
490
  }),
486
491
  ],
487
492
  },
493
+ {
494
+ name: 'wallets',
495
+ description: 'Manage agent wallets and wallet transactions',
496
+ commands: [
497
+ cmd('list', 'GET', '/wallets', 'List wallets'),
498
+ cmd('get', 'GET', '/wallets/:id', 'Get wallet by id'),
499
+ cmd('create', 'POST', '/wallets', 'Create wallet', { expectsJsonBody: true }),
500
+ cmd('update', 'PATCH', '/wallets/:id', 'Update wallet settings', { expectsJsonBody: true }),
501
+ cmd('delete', 'DELETE', '/wallets/:id', 'Delete wallet'),
502
+ cmd('send', 'POST', '/wallets/:id/send', 'Send funds from wallet', { expectsJsonBody: true }),
503
+ cmd('approve', 'POST', '/wallets/:id/approve', 'Approve or deny a pending wallet transaction', { expectsJsonBody: true }),
504
+ cmd('transactions', 'GET', '/wallets/:id/transactions', 'List wallet transactions'),
505
+ cmd('balance-history', 'GET', '/wallets/:id/balance-history', 'Get wallet balance history'),
506
+ ],
507
+ },
488
508
  {
489
509
  name: 'upload',
490
510
  description: 'Upload raw file/blob',