@swarmclawai/swarmclaw 0.7.4 → 0.7.6
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 +32 -9
- package/package.json +2 -2
- package/src/app/api/agents/[id]/thread/route.ts +4 -89
- package/src/app/api/openclaw/deploy/route.ts +101 -0
- package/src/cli/index.js +13 -0
- package/src/cli/index.test.js +34 -0
- package/src/cli/spec.js +19 -0
- package/src/components/auth/setup-wizard.tsx +36 -52
- package/src/components/gateways/gateway-sheet.tsx +63 -3
- package/src/components/openclaw/openclaw-deploy-panel.tsx +626 -0
- package/src/components/providers/provider-list.tsx +103 -8
- package/src/lib/server/agent-thread-session.test.ts +85 -0
- package/src/lib/server/agent-thread-session.ts +123 -0
- package/src/lib/server/data-dir.test.ts +56 -0
- package/src/lib/server/data-dir.ts +15 -9
- package/src/lib/server/heartbeat-service.ts +18 -5
- package/src/lib/server/heartbeat-wake.ts +6 -2
- package/src/lib/server/openclaw-deploy.test.ts +67 -0
- package/src/lib/server/openclaw-deploy.ts +724 -0
|
@@ -2,10 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState } from 'react'
|
|
4
4
|
import { BottomSheet } from '@/components/shared/bottom-sheet'
|
|
5
|
+
import { OpenClawDeployPanel } from '@/components/openclaw/openclaw-deploy-panel'
|
|
5
6
|
import { useAppStore } from '@/stores/use-app-store'
|
|
6
7
|
import { api } from '@/lib/api-client'
|
|
7
8
|
import { toast } from 'sonner'
|
|
8
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
Credential,
|
|
11
|
+
OpenClawDevicePairRequest,
|
|
12
|
+
OpenClawNode,
|
|
13
|
+
OpenClawNodePairRequest,
|
|
14
|
+
OpenClawPairedDevice,
|
|
15
|
+
} from '@/types'
|
|
9
16
|
|
|
10
17
|
interface DiscoveryResult {
|
|
11
18
|
host: string
|
|
@@ -46,6 +53,7 @@ export function GatewaySheet() {
|
|
|
46
53
|
const [name, setName] = useState('')
|
|
47
54
|
const [endpoint, setEndpoint] = useState('http://localhost:18789')
|
|
48
55
|
const [credentialId, setCredentialId] = useState<string | null>(null)
|
|
56
|
+
const [tokenDraft, setTokenDraft] = useState('')
|
|
49
57
|
const [notes, setNotes] = useState('')
|
|
50
58
|
const [tags, setTags] = useState('')
|
|
51
59
|
const [isDefault, setIsDefault] = useState(false)
|
|
@@ -81,6 +89,7 @@ export function GatewaySheet() {
|
|
|
81
89
|
setName(editing.name)
|
|
82
90
|
setEndpoint(editing.endpoint)
|
|
83
91
|
setCredentialId(editing.credentialId || null)
|
|
92
|
+
setTokenDraft('')
|
|
84
93
|
setNotes(editing.notes || '')
|
|
85
94
|
setTags((editing.tags || []).join(', '))
|
|
86
95
|
setIsDefault(editing.isDefault === true)
|
|
@@ -89,6 +98,7 @@ export function GatewaySheet() {
|
|
|
89
98
|
setName('')
|
|
90
99
|
setEndpoint('http://localhost:18789')
|
|
91
100
|
setCredentialId(null)
|
|
101
|
+
setTokenDraft('')
|
|
92
102
|
setNotes('')
|
|
93
103
|
setTags('')
|
|
94
104
|
setIsDefault(gatewayProfiles.length === 0)
|
|
@@ -157,10 +167,19 @@ export function GatewaySheet() {
|
|
|
157
167
|
const handleSave = async () => {
|
|
158
168
|
setSaving(true)
|
|
159
169
|
try {
|
|
170
|
+
let nextCredentialId = credentialId
|
|
171
|
+
if (tokenDraft.trim()) {
|
|
172
|
+
const created = await api<Credential>('POST', '/credentials', {
|
|
173
|
+
provider: 'openclaw',
|
|
174
|
+
name: `${name.trim() || 'OpenClaw Gateway'} token`,
|
|
175
|
+
apiKey: tokenDraft.trim(),
|
|
176
|
+
})
|
|
177
|
+
nextCredentialId = created.id
|
|
178
|
+
}
|
|
160
179
|
const payload = {
|
|
161
180
|
name: name.trim() || 'OpenClaw Gateway',
|
|
162
181
|
endpoint: endpoint.trim() || 'http://localhost:18789',
|
|
163
|
-
credentialId:
|
|
182
|
+
credentialId: nextCredentialId || null,
|
|
164
183
|
notes: notes.trim() || null,
|
|
165
184
|
tags: tags.split(',').map((item) => item.trim()).filter(Boolean),
|
|
166
185
|
isDefault,
|
|
@@ -172,7 +191,7 @@ export function GatewaySheet() {
|
|
|
172
191
|
await api('POST', '/gateways', payload)
|
|
173
192
|
toast.success('Gateway added')
|
|
174
193
|
}
|
|
175
|
-
await loadGatewayProfiles()
|
|
194
|
+
await Promise.all([loadGatewayProfiles(), loadCredentials()])
|
|
176
195
|
onClose()
|
|
177
196
|
} catch (err: unknown) {
|
|
178
197
|
toast.error(err instanceof Error ? err.message : 'Failed to save gateway')
|
|
@@ -188,6 +207,7 @@ export function GatewaySheet() {
|
|
|
188
207
|
const params = new URLSearchParams()
|
|
189
208
|
params.set('endpoint', endpoint.trim() || 'http://localhost:18789')
|
|
190
209
|
if (credentialId) params.set('credentialId', credentialId)
|
|
210
|
+
if (tokenDraft.trim()) params.set('token', tokenDraft.trim())
|
|
191
211
|
const result = await api<{ ok: boolean; models: string[]; error?: string; hint?: string }>('GET', `/providers/openclaw/health?${params.toString()}`)
|
|
192
212
|
if (result.ok) {
|
|
193
213
|
setCheckMessage(`Connected. ${result.models?.length ? `${result.models.length} model${result.models.length === 1 ? '' : 's'} visible.` : 'Gateway responded normally.'}`)
|
|
@@ -278,6 +298,23 @@ export function GatewaySheet() {
|
|
|
278
298
|
|
|
279
299
|
const inputClass = 'w-full px-4 py-3.5 rounded-[14px] border border-white/[0.08] bg-surface text-text text-[15px] outline-none transition-all duration-200 placeholder:text-text-3/50 focus-glow'
|
|
280
300
|
|
|
301
|
+
const applyDeployPatch = (patch: { endpoint?: string; token?: string; name?: string; notes?: string }) => {
|
|
302
|
+
if (patch.endpoint) {
|
|
303
|
+
setEndpoint(patch.endpoint)
|
|
304
|
+
setCheckMessage('')
|
|
305
|
+
}
|
|
306
|
+
if (patch.token) {
|
|
307
|
+
setTokenDraft(patch.token)
|
|
308
|
+
setCredentialId(null)
|
|
309
|
+
}
|
|
310
|
+
if (patch.name && !name.trim()) {
|
|
311
|
+
setName(patch.name)
|
|
312
|
+
}
|
|
313
|
+
if (patch.notes && !notes.trim()) {
|
|
314
|
+
setNotes(patch.notes)
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
281
318
|
return (
|
|
282
319
|
<BottomSheet open={open} onClose={onClose} wide>
|
|
283
320
|
<div className="mb-10">
|
|
@@ -309,6 +346,17 @@ export function GatewaySheet() {
|
|
|
309
346
|
<p className="text-[11px] text-text-3/60 mt-2">Remote HTTPS URLs and local loopback endpoints are both supported.</p>
|
|
310
347
|
</div>
|
|
311
348
|
|
|
349
|
+
<div className="mb-6">
|
|
350
|
+
<OpenClawDeployPanel
|
|
351
|
+
endpoint={endpoint}
|
|
352
|
+
token={tokenDraft}
|
|
353
|
+
suggestedName={name || null}
|
|
354
|
+
title="Deploy OpenClaw From SwarmClaw"
|
|
355
|
+
description="Use official OpenClaw sources only. Start it on this host, or generate a pre-configured remote bundle for VPS and hosted deployments."
|
|
356
|
+
onApply={applyDeployPatch}
|
|
357
|
+
/>
|
|
358
|
+
</div>
|
|
359
|
+
|
|
312
360
|
{discoveries.length > 0 && (
|
|
313
361
|
<div className="mb-6">
|
|
314
362
|
<div className="text-[12px] text-text-3/70 mb-2">Detected healthy gateways</div>
|
|
@@ -342,6 +390,18 @@ export function GatewaySheet() {
|
|
|
342
390
|
<option key={item.id} value={item.id}>{item.name}</option>
|
|
343
391
|
))}
|
|
344
392
|
</select>
|
|
393
|
+
<input
|
|
394
|
+
value={tokenDraft}
|
|
395
|
+
onChange={(e) => {
|
|
396
|
+
setTokenDraft(e.target.value)
|
|
397
|
+
if (e.target.value) setCredentialId(null)
|
|
398
|
+
}}
|
|
399
|
+
placeholder="Or paste/generate a new gateway token"
|
|
400
|
+
className={`${inputClass} mt-3 font-mono text-[13px]`}
|
|
401
|
+
/>
|
|
402
|
+
<p className="mt-2 text-[11px] text-text-3/60">
|
|
403
|
+
A pasted token is stored as a new encrypted OpenClaw credential when you save this gateway.
|
|
404
|
+
</p>
|
|
345
405
|
</div>
|
|
346
406
|
|
|
347
407
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|