@swarmclawai/swarmclaw 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -4
- package/bin/server-cmd.js +28 -19
- package/next.config.ts +13 -0
- package/package.json +3 -1
- package/src/app/api/agents/[id]/route.ts +39 -22
- package/src/app/api/agents/[id]/thread/route.ts +2 -2
- package/src/app/api/agents/route.ts +3 -2
- package/src/app/api/agents/trash/route.ts +44 -0
- package/src/app/api/clawhub/install/route.ts +2 -2
- package/src/app/api/connectors/[id]/route.ts +17 -7
- package/src/app/api/connectors/[id]/webhook/route.ts +103 -0
- package/src/app/api/connectors/route.ts +6 -3
- package/src/app/api/credentials/[id]/route.ts +2 -1
- package/src/app/api/credentials/route.ts +2 -2
- package/src/app/api/documents/route.ts +2 -2
- package/src/app/api/files/serve/route.ts +8 -0
- package/src/app/api/knowledge/[id]/route.ts +5 -4
- package/src/app/api/knowledge/upload/route.ts +2 -2
- package/src/app/api/mcp-servers/[id]/route.ts +11 -14
- package/src/app/api/mcp-servers/[id]/test/route.ts +2 -1
- package/src/app/api/mcp-servers/[id]/tools/route.ts +2 -1
- package/src/app/api/mcp-servers/route.ts +2 -2
- package/src/app/api/memory/[id]/route.ts +9 -8
- package/src/app/api/memory/route.ts +2 -2
- package/src/app/api/memory-images/[filename]/route.ts +2 -1
- package/src/app/api/openclaw/agent-files/route.ts +57 -0
- package/src/app/api/openclaw/approvals/route.ts +46 -0
- package/src/app/api/openclaw/config-sync/route.ts +33 -0
- package/src/app/api/openclaw/cron/route.ts +52 -0
- package/src/app/api/openclaw/directory/route.ts +27 -0
- package/src/app/api/openclaw/discover/route.ts +62 -0
- package/src/app/api/openclaw/dotenv-keys/route.ts +18 -0
- package/src/app/api/openclaw/exec-config/route.ts +41 -0
- package/src/app/api/openclaw/gateway/route.ts +72 -0
- package/src/app/api/openclaw/history/route.ts +109 -0
- package/src/app/api/openclaw/media/route.ts +53 -0
- package/src/app/api/openclaw/models/route.ts +12 -0
- package/src/app/api/openclaw/permissions/route.ts +39 -0
- package/src/app/api/openclaw/sandbox-env/route.ts +69 -0
- package/src/app/api/openclaw/skills/install/route.ts +32 -0
- package/src/app/api/openclaw/skills/remove/route.ts +24 -0
- package/src/app/api/openclaw/skills/route.ts +82 -0
- package/src/app/api/openclaw/sync/route.ts +31 -0
- package/src/app/api/orchestrator/run/route.ts +2 -2
- package/src/app/api/projects/[id]/route.ts +55 -0
- package/src/app/api/projects/route.ts +27 -0
- package/src/app/api/providers/[id]/models/route.ts +2 -1
- package/src/app/api/providers/[id]/route.ts +13 -15
- package/src/app/api/providers/route.ts +2 -2
- package/src/app/api/schedules/[id]/route.ts +16 -18
- package/src/app/api/schedules/[id]/run/route.ts +4 -3
- package/src/app/api/schedules/route.ts +2 -2
- package/src/app/api/secrets/[id]/route.ts +16 -17
- package/src/app/api/secrets/route.ts +2 -2
- package/src/app/api/sessions/[id]/clear/route.ts +2 -1
- package/src/app/api/sessions/[id]/deploy/route.ts +2 -1
- package/src/app/api/sessions/[id]/devserver/route.ts +2 -1
- package/src/app/api/sessions/[id]/edit-resend/route.ts +22 -0
- package/src/app/api/sessions/[id]/fork/route.ts +44 -0
- package/src/app/api/sessions/[id]/messages/route.ts +20 -2
- package/src/app/api/sessions/[id]/retry/route.ts +2 -1
- package/src/app/api/sessions/[id]/route.ts +14 -4
- package/src/app/api/sessions/route.ts +8 -4
- package/src/app/api/skills/[id]/route.ts +23 -21
- package/src/app/api/skills/import/route.ts +2 -2
- package/src/app/api/skills/route.ts +2 -2
- package/src/app/api/tasks/[id]/approve/route.ts +2 -1
- package/src/app/api/tasks/[id]/route.ts +6 -5
- package/src/app/api/tasks/route.ts +2 -2
- package/src/app/api/tts/stream/route.ts +48 -0
- package/src/app/api/upload/route.ts +2 -2
- package/src/app/api/uploads/[filename]/route.ts +4 -1
- package/src/app/api/webhooks/[id]/route.ts +29 -31
- package/src/app/api/webhooks/route.ts +2 -2
- package/src/app/globals.css +14 -0
- package/src/app/layout.tsx +5 -20
- package/src/app/page.tsx +3 -24
- package/src/cli/index.js +60 -0
- package/src/cli/index.ts +1 -1
- package/src/cli/spec.js +42 -0
- package/src/components/agents/agent-avatar.tsx +45 -0
- package/src/components/agents/agent-card.tsx +19 -5
- package/src/components/agents/agent-chat-list.tsx +31 -24
- package/src/components/agents/agent-files-editor.tsx +185 -0
- package/src/components/agents/agent-list.tsx +84 -3
- package/src/components/agents/agent-sheet.tsx +147 -14
- package/src/components/agents/cron-job-form.tsx +137 -0
- package/src/components/agents/exec-config-panel.tsx +147 -0
- package/src/components/agents/inspector-panel.tsx +310 -0
- package/src/components/agents/openclaw-skills-panel.tsx +230 -0
- package/src/components/agents/permission-preset-selector.tsx +79 -0
- package/src/components/agents/personality-builder.tsx +111 -0
- package/src/components/agents/sandbox-env-panel.tsx +72 -0
- package/src/components/agents/skill-install-dialog.tsx +102 -0
- package/src/components/agents/trash-list.tsx +109 -0
- package/src/components/chat/chat-area.tsx +41 -6
- package/src/components/chat/chat-header.tsx +305 -29
- package/src/components/chat/chat-preview-panel.tsx +113 -0
- package/src/components/chat/exec-approval-card.tsx +89 -0
- package/src/components/chat/message-bubble.tsx +218 -36
- package/src/components/chat/message-list.tsx +135 -31
- package/src/components/chat/streaming-bubble.tsx +59 -10
- package/src/components/chat/suggestions-bar.tsx +74 -0
- package/src/components/chat/thinking-indicator.tsx +20 -6
- package/src/components/chat/tool-call-bubble.tsx +98 -19
- package/src/components/chat/tool-request-banner.tsx +20 -2
- package/src/components/chat/trace-block.tsx +103 -0
- package/src/components/chat/voice-overlay.tsx +80 -0
- package/src/components/connectors/connector-list.tsx +6 -2
- package/src/components/connectors/connector-sheet.tsx +31 -7
- package/src/components/layout/app-layout.tsx +47 -25
- package/src/components/projects/project-list.tsx +123 -0
- package/src/components/projects/project-sheet.tsx +135 -0
- package/src/components/schedules/schedule-list.tsx +3 -1
- package/src/components/sessions/new-session-sheet.tsx +6 -6
- package/src/components/sessions/session-card.tsx +1 -1
- package/src/components/sessions/session-list.tsx +7 -7
- package/src/components/settings/gateway-connection-panel.tsx +278 -0
- package/src/components/shared/avatar.tsx +13 -2
- package/src/components/shared/connector-platform-icon.tsx +4 -0
- package/src/components/shared/settings/section-heartbeat.tsx +1 -1
- package/src/components/shared/settings/section-orchestrator.tsx +1 -2
- package/src/components/shared/settings/section-web-search.tsx +56 -0
- package/src/components/shared/settings/settings-page.tsx +74 -0
- package/src/components/skills/skill-list.tsx +2 -1
- package/src/components/tasks/task-board.tsx +1 -1
- package/src/components/tasks/task-list.tsx +5 -2
- package/src/components/tasks/task-sheet.tsx +12 -12
- package/src/hooks/use-continuous-speech.ts +181 -0
- package/src/hooks/use-openclaw-gateway.ts +63 -0
- package/src/hooks/use-view-router.ts +52 -0
- package/src/hooks/use-voice-conversation.ts +80 -0
- package/src/lib/id.ts +6 -0
- package/src/lib/notification-sounds.ts +58 -0
- package/src/lib/personality-parser.ts +97 -0
- package/src/lib/projects.ts +13 -0
- package/src/lib/provider-sets.ts +5 -0
- package/src/lib/providers/anthropic.ts +14 -1
- package/src/lib/providers/index.ts +6 -0
- package/src/lib/providers/ollama.ts +9 -1
- package/src/lib/providers/openai.ts +9 -1
- package/src/lib/providers/openclaw.ts +28 -2
- package/src/lib/runtime-loop.ts +2 -2
- package/src/lib/server/api-routes.test.ts +5 -6
- package/src/lib/server/build-llm.ts +17 -4
- package/src/lib/server/chat-execution.ts +82 -6
- package/src/lib/server/collection-helpers.ts +54 -0
- package/src/lib/server/connectors/bluebubbles.test.ts +217 -0
- package/src/lib/server/connectors/bluebubbles.ts +360 -0
- package/src/lib/server/connectors/connector-routing.test.ts +1 -1
- package/src/lib/server/connectors/googlechat.ts +51 -8
- package/src/lib/server/connectors/manager.ts +424 -13
- package/src/lib/server/connectors/media.ts +2 -2
- package/src/lib/server/connectors/openclaw.ts +65 -0
- package/src/lib/server/connectors/pairing.test.ts +99 -0
- package/src/lib/server/connectors/pairing.ts +256 -0
- package/src/lib/server/connectors/signal.ts +1 -0
- package/src/lib/server/connectors/teams.ts +5 -5
- package/src/lib/server/connectors/types.ts +10 -0
- package/src/lib/server/daemon-state.ts +11 -0
- package/src/lib/server/execution-log.ts +3 -3
- package/src/lib/server/heartbeat-service.ts +1 -1
- package/src/lib/server/knowledge-db.test.ts +2 -33
- package/src/lib/server/main-agent-loop.ts +8 -9
- package/src/lib/server/main-session.ts +21 -0
- package/src/lib/server/memory-db.ts +6 -6
- package/src/lib/server/openclaw-approvals.ts +105 -0
- package/src/lib/server/openclaw-config-sync.ts +107 -0
- package/src/lib/server/openclaw-exec-config.ts +52 -0
- package/src/lib/server/openclaw-gateway.ts +291 -0
- package/src/lib/server/openclaw-history-merge.ts +36 -0
- package/src/lib/server/openclaw-models.ts +56 -0
- package/src/lib/server/openclaw-permission-presets.ts +64 -0
- package/src/lib/server/openclaw-sync.ts +497 -0
- package/src/lib/server/orchestrator-lg.ts +30 -9
- package/src/lib/server/orchestrator.ts +4 -4
- package/src/lib/server/process-manager.ts +2 -2
- package/src/lib/server/queue.ts +24 -11
- package/src/lib/server/scheduler.ts +2 -2
- package/src/lib/server/session-mailbox.ts +2 -2
- package/src/lib/server/session-run-manager.ts +2 -2
- package/src/lib/server/session-tools/connector.ts +53 -6
- package/src/lib/server/session-tools/crud.ts +3 -3
- package/src/lib/server/session-tools/delegate.ts +22 -6
- package/src/lib/server/session-tools/file.ts +192 -19
- package/src/lib/server/session-tools/index.ts +4 -2
- package/src/lib/server/session-tools/memory.ts +2 -2
- package/src/lib/server/session-tools/openclaw-nodes.ts +112 -0
- package/src/lib/server/session-tools/sandbox.ts +33 -0
- package/src/lib/server/session-tools/search-providers.ts +277 -0
- package/src/lib/server/session-tools/session-info.ts +2 -2
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +2 -2
- package/src/lib/server/session-tools/shell.ts +1 -1
- package/src/lib/server/session-tools/web.ts +53 -72
- package/src/lib/server/storage.ts +74 -11
- package/src/lib/server/stream-agent-chat.ts +53 -4
- package/src/lib/server/suggestions.ts +20 -0
- package/src/lib/server/task-result.test.ts +44 -0
- package/src/lib/server/task-result.ts +14 -0
- package/src/lib/server/ws-hub.ts +14 -0
- package/src/lib/tool-definitions.ts +5 -3
- package/src/lib/tts-stream.ts +130 -0
- package/src/lib/view-routes.ts +28 -0
- package/src/proxy.ts +3 -0
- package/src/stores/use-app-store.ts +80 -1
- package/src/stores/use-approval-store.ts +78 -0
- package/src/stores/use-chat-store.ts +162 -6
- package/src/types/index.ts +154 -3
- package/tsconfig.json +13 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
+
import { notFound } from '@/lib/server/collection-helpers'
|
|
2
3
|
import { getMemoryDb } from '@/lib/server/memory-db'
|
|
3
4
|
|
|
4
5
|
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
@@ -6,7 +7,7 @@ export async function GET(_req: Request, { params }: { params: Promise<{ id: str
|
|
|
6
7
|
const db = getMemoryDb()
|
|
7
8
|
const entry = db.get(id)
|
|
8
9
|
if (!entry || entry.category !== 'knowledge') {
|
|
9
|
-
return
|
|
10
|
+
return notFound()
|
|
10
11
|
}
|
|
11
12
|
return NextResponse.json(entry)
|
|
12
13
|
}
|
|
@@ -16,7 +17,7 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
16
17
|
const db = getMemoryDb()
|
|
17
18
|
const existing = db.get(id)
|
|
18
19
|
if (!existing || existing.category !== 'knowledge') {
|
|
19
|
-
return
|
|
20
|
+
return notFound()
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
const body = await req.json().catch(() => null)
|
|
@@ -44,7 +45,7 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
44
45
|
|
|
45
46
|
const updated = db.update(id, updates)
|
|
46
47
|
if (!updated) {
|
|
47
|
-
return
|
|
48
|
+
return notFound()
|
|
48
49
|
}
|
|
49
50
|
return NextResponse.json(updated)
|
|
50
51
|
}
|
|
@@ -54,7 +55,7 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
|
|
54
55
|
const db = getMemoryDb()
|
|
55
56
|
const existing = db.get(id)
|
|
56
57
|
if (!existing || existing.category !== 'knowledge') {
|
|
57
|
-
return
|
|
58
|
+
return notFound()
|
|
58
59
|
}
|
|
59
60
|
db.delete(id)
|
|
60
61
|
return NextResponse.json({ deleted: id })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import fs from 'fs'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import
|
|
4
|
+
import { genId } from '@/lib/id'
|
|
5
5
|
import { UPLOAD_DIR } from '@/lib/server/storage'
|
|
6
6
|
|
|
7
7
|
const TEXT_EXTS = new Set([
|
|
@@ -40,7 +40,7 @@ export async function POST(req: Request) {
|
|
|
40
40
|
|
|
41
41
|
// Save file to uploads
|
|
42
42
|
if (!fs.existsSync(UPLOAD_DIR)) fs.mkdirSync(UPLOAD_DIR, { recursive: true })
|
|
43
|
-
const safeName =
|
|
43
|
+
const safeName = genId() + '-' + filename.replace(/[^a-zA-Z0-9._-]/g, '_')
|
|
44
44
|
const filePath = path.join(UPLOAD_DIR, safeName)
|
|
45
45
|
fs.writeFileSync(filePath, buf)
|
|
46
46
|
|
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { loadMcpServers, saveMcpServers, deleteMcpServer } from '@/lib/server/storage'
|
|
3
|
+
import { mutateItem, deleteItem, notFound, type CollectionOps } from '@/lib/server/collection-helpers'
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
const ops: CollectionOps<any> = { load: loadMcpServers, save: saveMcpServers, deleteFn: deleteMcpServer }
|
|
3
7
|
|
|
4
8
|
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
5
9
|
const { id } = await params
|
|
6
10
|
const servers = loadMcpServers()
|
|
7
|
-
if (!servers[id]) return
|
|
11
|
+
if (!servers[id]) return notFound()
|
|
8
12
|
return NextResponse.json(servers[id])
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
12
16
|
const { id } = await params
|
|
13
17
|
const body = await req.json()
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
id,
|
|
20
|
-
updatedAt: Date.now(),
|
|
21
|
-
}
|
|
22
|
-
saveMcpServers(servers)
|
|
23
|
-
return NextResponse.json(servers[id])
|
|
18
|
+
const result = mutateItem(ops, id, (server) => ({
|
|
19
|
+
...server, ...body, id, updatedAt: Date.now(),
|
|
20
|
+
}))
|
|
21
|
+
if (!result) return notFound()
|
|
22
|
+
return NextResponse.json(result)
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
27
26
|
const { id } = await params
|
|
28
|
-
|
|
29
|
-
if (!servers[id]) return new NextResponse(null, { status: 404 })
|
|
30
|
-
deleteMcpServer(id)
|
|
27
|
+
if (!deleteItem(ops, id)) return notFound()
|
|
31
28
|
return NextResponse.json({ deleted: id })
|
|
32
29
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { loadMcpServers } from '@/lib/server/storage'
|
|
3
|
+
import { notFound } from '@/lib/server/collection-helpers'
|
|
3
4
|
import { connectMcpServer, mcpToolsToLangChain, disconnectMcpServer } from '@/lib/server/mcp-client'
|
|
4
5
|
|
|
5
6
|
export async function POST(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
7
|
const { id } = await params
|
|
7
8
|
const servers = loadMcpServers()
|
|
8
9
|
const server = servers[id]
|
|
9
|
-
if (!server) return
|
|
10
|
+
if (!server) return notFound()
|
|
10
11
|
|
|
11
12
|
try {
|
|
12
13
|
const { client, transport } = await connectMcpServer(server)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { loadMcpServers } from '@/lib/server/storage'
|
|
3
|
+
import { notFound } from '@/lib/server/collection-helpers'
|
|
3
4
|
import { connectMcpServer, disconnectMcpServer } from '@/lib/server/mcp-client'
|
|
4
5
|
|
|
5
6
|
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
7
|
const { id } = await params
|
|
7
8
|
const servers = loadMcpServers()
|
|
8
9
|
const config = servers[id]
|
|
9
|
-
if (!config) return
|
|
10
|
+
if (!config) return notFound()
|
|
10
11
|
|
|
11
12
|
let client: any
|
|
12
13
|
let transport: any
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import
|
|
2
|
+
import { genId } from '@/lib/id'
|
|
3
3
|
import { loadMcpServers, saveMcpServers } from '@/lib/server/storage'
|
|
4
4
|
export const dynamic = 'force-dynamic'
|
|
5
5
|
|
|
@@ -11,7 +11,7 @@ export async function GET(_req: Request) {
|
|
|
11
11
|
export async function POST(req: Request) {
|
|
12
12
|
const body = await req.json()
|
|
13
13
|
const servers = loadMcpServers()
|
|
14
|
-
const id =
|
|
14
|
+
const id = genId()
|
|
15
15
|
servers[id] = {
|
|
16
16
|
id,
|
|
17
17
|
name: body.name,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { genId } from '@/lib/id'
|
|
2
2
|
import fs from 'fs'
|
|
3
3
|
import { NextResponse } from 'next/server'
|
|
4
|
+
import { notFound } from '@/lib/server/collection-helpers'
|
|
4
5
|
import { getMemoryDb, getMemoryLookupLimits, storeMemoryImageAsset, storeMemoryImageFromDataUrl } from '@/lib/server/memory-db'
|
|
5
6
|
import { resolveLookupRequest } from '@/lib/server/memory-graph'
|
|
6
7
|
import type { MemoryImage } from '@/types'
|
|
@@ -42,7 +43,7 @@ export async function GET(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
42
43
|
|
|
43
44
|
if (limits.maxDepth <= 0) {
|
|
44
45
|
const entry = db.get(id)
|
|
45
|
-
if (!entry) return
|
|
46
|
+
if (!entry) return notFound()
|
|
46
47
|
if (envelope) {
|
|
47
48
|
return NextResponse.json({
|
|
48
49
|
entries: [entry],
|
|
@@ -55,7 +56,7 @@ export async function GET(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
const result = db.getWithLinked(id, limits.maxDepth, limits.maxPerLookup, limits.maxLinkedExpansion)
|
|
58
|
-
if (!result) return
|
|
59
|
+
if (!result) return notFound()
|
|
59
60
|
if (envelope) return NextResponse.json(result)
|
|
60
61
|
return NextResponse.json(result.entries)
|
|
61
62
|
}
|
|
@@ -78,7 +79,7 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
78
79
|
const updated = linkAction === 'link'
|
|
79
80
|
? db.link(id, targetIds, true)
|
|
80
81
|
: db.unlink(id, targetIds, true)
|
|
81
|
-
if (!updated) return
|
|
82
|
+
if (!updated) return notFound()
|
|
82
83
|
return NextResponse.json(updated)
|
|
83
84
|
}
|
|
84
85
|
|
|
@@ -90,7 +91,7 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
90
91
|
image = null
|
|
91
92
|
} else if (inputImageDataUrl) {
|
|
92
93
|
try {
|
|
93
|
-
image = await storeMemoryImageFromDataUrl(inputImageDataUrl, `${id}-${
|
|
94
|
+
image = await storeMemoryImageFromDataUrl(inputImageDataUrl, `${id}-${genId(2)}`)
|
|
94
95
|
} catch (err) {
|
|
95
96
|
return NextResponse.json({ error: err instanceof Error ? err.message : 'Invalid image data URL' }, { status: 400 })
|
|
96
97
|
}
|
|
@@ -99,7 +100,7 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
99
100
|
return NextResponse.json({ error: `Image file not found: ${inputImagePath}` }, { status: 400 })
|
|
100
101
|
}
|
|
101
102
|
try {
|
|
102
|
-
image = await storeMemoryImageAsset(inputImagePath, `${id}-${
|
|
103
|
+
image = await storeMemoryImageAsset(inputImagePath, `${id}-${genId(2)}`)
|
|
103
104
|
} catch (err) {
|
|
104
105
|
return NextResponse.json({ error: err instanceof Error ? err.message : 'Failed to store memory image' }, { status: 400 })
|
|
105
106
|
}
|
|
@@ -114,7 +115,7 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
114
115
|
? String((image as { path: string }).path)
|
|
115
116
|
: (typeof body.imagePath === 'string' ? body.imagePath : undefined),
|
|
116
117
|
})
|
|
117
|
-
if (!entry) return
|
|
118
|
+
if (!entry) return notFound()
|
|
118
119
|
return NextResponse.json(entry)
|
|
119
120
|
}
|
|
120
121
|
|
|
@@ -122,5 +123,5 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
|
|
122
123
|
const { id } = await params
|
|
123
124
|
const db = getMemoryDb()
|
|
124
125
|
db.delete(id)
|
|
125
|
-
return NextResponse.json(
|
|
126
|
+
return NextResponse.json({ ok: true })
|
|
126
127
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { genId } from '@/lib/id'
|
|
2
2
|
import fs from 'fs'
|
|
3
3
|
import { NextResponse } from 'next/server'
|
|
4
4
|
import { getMemoryDb, getMemoryLookupLimits, storeMemoryImageAsset, storeMemoryImageFromDataUrl } from '@/lib/server/memory-db'
|
|
@@ -72,7 +72,7 @@ export async function POST(req: Request) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
const db = getMemoryDb()
|
|
75
|
-
const draftId =
|
|
75
|
+
const draftId = genId(6)
|
|
76
76
|
|
|
77
77
|
let image = body.image
|
|
78
78
|
const inputImagePath = typeof body.imagePath === 'string' ? body.imagePath.trim() : ''
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
+
import { notFound } from '@/lib/server/collection-helpers'
|
|
2
3
|
import fs from 'fs'
|
|
3
4
|
import path from 'path'
|
|
4
5
|
|
|
@@ -20,7 +21,7 @@ export async function GET(_req: Request, { params }: { params: Promise<{ filenam
|
|
|
20
21
|
const filePath = path.join(IMAGES_DIR, safeName)
|
|
21
22
|
|
|
22
23
|
if (!fs.existsSync(filePath)) {
|
|
23
|
-
return
|
|
24
|
+
return notFound()
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
const ext = path.extname(safeName).toLowerCase()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { ensureGatewayConnected } from '@/lib/server/openclaw-gateway'
|
|
3
|
+
|
|
4
|
+
const AGENT_FILES = ['SOUL.md', 'IDENTITY.md', 'USER.md', 'TOOLS.md', 'HEARTBEAT.md', 'MEMORY.md', 'AGENTS.md'] as const
|
|
5
|
+
|
|
6
|
+
/** GET ?agentId=X — fetch all agent files from gateway */
|
|
7
|
+
export async function GET(req: Request) {
|
|
8
|
+
const { searchParams } = new URL(req.url)
|
|
9
|
+
const agentId = searchParams.get('agentId')
|
|
10
|
+
if (!agentId) {
|
|
11
|
+
return NextResponse.json({ error: 'Missing agentId' }, { status: 400 })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const gw = await ensureGatewayConnected()
|
|
15
|
+
if (!gw) {
|
|
16
|
+
return NextResponse.json({ error: 'OpenClaw gateway not connected' }, { status: 503 })
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const files: Record<string, { content: string; error?: string }> = {}
|
|
20
|
+
await Promise.all(
|
|
21
|
+
AGENT_FILES.map(async (filename) => {
|
|
22
|
+
try {
|
|
23
|
+
const result = await gw.rpc('agents.files.get', { agentId, filename }) as { content?: string } | undefined
|
|
24
|
+
files[filename] = { content: result?.content ?? '' }
|
|
25
|
+
} catch (err: unknown) {
|
|
26
|
+
files[filename] = { content: '', error: err instanceof Error ? err.message : String(err) }
|
|
27
|
+
}
|
|
28
|
+
}),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
return NextResponse.json(files)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** PUT { agentId, filename, content } — save an agent file */
|
|
35
|
+
export async function PUT(req: Request) {
|
|
36
|
+
const body = await req.json()
|
|
37
|
+
const { agentId, filename, content } = body as { agentId?: string; filename?: string; content?: string }
|
|
38
|
+
if (!agentId || !filename) {
|
|
39
|
+
return NextResponse.json({ error: 'Missing agentId or filename' }, { status: 400 })
|
|
40
|
+
}
|
|
41
|
+
if (!AGENT_FILES.includes(filename as typeof AGENT_FILES[number])) {
|
|
42
|
+
return NextResponse.json({ error: `Invalid filename: ${filename}` }, { status: 400 })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const gw = await ensureGatewayConnected()
|
|
46
|
+
if (!gw) {
|
|
47
|
+
return NextResponse.json({ error: 'OpenClaw gateway not connected' }, { status: 503 })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
await gw.rpc('agents.files.set', { agentId, filename, content: content ?? '' })
|
|
52
|
+
return NextResponse.json({ ok: true })
|
|
53
|
+
} catch (err: unknown) {
|
|
54
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
55
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { ensureGatewayConnected } from '@/lib/server/openclaw-gateway'
|
|
3
|
+
import type { PendingExecApproval, ExecApprovalDecision } from '@/types'
|
|
4
|
+
|
|
5
|
+
/** GET — fetch pending execution approvals from gateway */
|
|
6
|
+
export async function GET() {
|
|
7
|
+
const gw = await ensureGatewayConnected()
|
|
8
|
+
if (!gw) {
|
|
9
|
+
return NextResponse.json([], { status: 200 })
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const result = await gw.rpc('exec.approvals.get') as PendingExecApproval[] | undefined
|
|
14
|
+
return NextResponse.json(result ?? [])
|
|
15
|
+
} catch {
|
|
16
|
+
return NextResponse.json([])
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** POST { id, decision } — resolve an execution approval */
|
|
21
|
+
export async function POST(req: Request) {
|
|
22
|
+
const body = await req.json()
|
|
23
|
+
const { id, decision } = body as { id?: string; decision?: ExecApprovalDecision }
|
|
24
|
+
|
|
25
|
+
if (!id || !decision) {
|
|
26
|
+
return NextResponse.json({ error: 'Missing id or decision' }, { status: 400 })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const validDecisions: ExecApprovalDecision[] = ['allow-once', 'allow-always', 'deny']
|
|
30
|
+
if (!validDecisions.includes(decision)) {
|
|
31
|
+
return NextResponse.json({ error: 'Invalid decision' }, { status: 400 })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const gw = await ensureGatewayConnected()
|
|
35
|
+
if (!gw) {
|
|
36
|
+
return NextResponse.json({ error: 'OpenClaw gateway not connected' }, { status: 503 })
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
await gw.rpc('exec.approvals.resolve', { id, decision })
|
|
41
|
+
return NextResponse.json({ ok: true })
|
|
42
|
+
} catch (err: unknown) {
|
|
43
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
44
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { detectConfigIssues, repairConfigIssue } from '@/lib/server/openclaw-config-sync'
|
|
3
|
+
|
|
4
|
+
/** GET — detect configuration issues */
|
|
5
|
+
export async function GET() {
|
|
6
|
+
try {
|
|
7
|
+
const issues = await detectConfigIssues()
|
|
8
|
+
return NextResponse.json({ issues })
|
|
9
|
+
} catch (err: unknown) {
|
|
10
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
11
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** POST { issueId } — repair a specific issue */
|
|
16
|
+
export async function POST(req: Request) {
|
|
17
|
+
const body = await req.json()
|
|
18
|
+
const { issueId } = body as { issueId?: string }
|
|
19
|
+
if (!issueId) {
|
|
20
|
+
return NextResponse.json({ error: 'Missing issueId' }, { status: 400 })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const result = await repairConfigIssue(issueId)
|
|
25
|
+
if (!result.ok) {
|
|
26
|
+
return NextResponse.json({ error: result.error }, { status: 502 })
|
|
27
|
+
}
|
|
28
|
+
return NextResponse.json({ ok: true })
|
|
29
|
+
} catch (err: unknown) {
|
|
30
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
31
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { ensureGatewayConnected } from '@/lib/server/openclaw-gateway'
|
|
3
|
+
import type { GatewayCronJob } from '@/types'
|
|
4
|
+
|
|
5
|
+
/** GET — list all cron jobs from gateway */
|
|
6
|
+
export async function GET() {
|
|
7
|
+
const gw = await ensureGatewayConnected()
|
|
8
|
+
if (!gw) {
|
|
9
|
+
return NextResponse.json({ error: 'Gateway not connected' }, { status: 503 })
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const result = await gw.rpc('cron.list', { includeDisabled: true }) as GatewayCronJob[] | undefined
|
|
14
|
+
return NextResponse.json(result ?? [])
|
|
15
|
+
} catch (err: unknown) {
|
|
16
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
17
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** POST { action, ...params } — add/run/remove cron jobs */
|
|
22
|
+
export async function POST(req: Request) {
|
|
23
|
+
const body = await req.json()
|
|
24
|
+
const { action, ...params } = body as { action: string; [key: string]: unknown }
|
|
25
|
+
|
|
26
|
+
const gw = await ensureGatewayConnected()
|
|
27
|
+
if (!gw) {
|
|
28
|
+
return NextResponse.json({ error: 'Gateway not connected' }, { status: 503 })
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
switch (action) {
|
|
33
|
+
case 'add': {
|
|
34
|
+
const result = await gw.rpc('cron.add', params.job)
|
|
35
|
+
return NextResponse.json({ ok: true, result })
|
|
36
|
+
}
|
|
37
|
+
case 'run': {
|
|
38
|
+
const result = await gw.rpc('cron.run', { id: params.id, mode: 'force' })
|
|
39
|
+
return NextResponse.json({ ok: true, result })
|
|
40
|
+
}
|
|
41
|
+
case 'remove': {
|
|
42
|
+
await gw.rpc('cron.remove', { id: params.id })
|
|
43
|
+
return NextResponse.json({ ok: true })
|
|
44
|
+
}
|
|
45
|
+
default:
|
|
46
|
+
return NextResponse.json({ error: `Unknown action: ${action}` }, { status: 400 })
|
|
47
|
+
}
|
|
48
|
+
} catch (err: unknown) {
|
|
49
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
50
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
export const dynamic = 'force-dynamic'
|
|
3
|
+
|
|
4
|
+
export async function GET() {
|
|
5
|
+
try {
|
|
6
|
+
const { listRunningConnectors } = await import('@/lib/server/connectors/manager')
|
|
7
|
+
const openclawConnectors = listRunningConnectors('openclaw')
|
|
8
|
+
|
|
9
|
+
if (!openclawConnectors.length) {
|
|
10
|
+
return NextResponse.json({ devices: [], note: 'No running OpenClaw connector.' })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// The directory.list RPC requires gateway support — degrade gracefully
|
|
14
|
+
return NextResponse.json({
|
|
15
|
+
devices: [],
|
|
16
|
+
connectors: openclawConnectors.map((c) => ({
|
|
17
|
+
id: c.id,
|
|
18
|
+
name: c.name,
|
|
19
|
+
platform: c.platform,
|
|
20
|
+
})),
|
|
21
|
+
note: 'Directory listing requires OpenClaw gateway directory.list RPC support.',
|
|
22
|
+
})
|
|
23
|
+
} catch (err: unknown) {
|
|
24
|
+
const message = err instanceof Error ? err.message : 'Directory listing failed'
|
|
25
|
+
return NextResponse.json({ error: message }, { status: 500 })
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import { probeOpenClawHealth } from '@/lib/server/openclaw-health'
|
|
4
|
+
export const dynamic = 'force-dynamic'
|
|
5
|
+
|
|
6
|
+
const DEFAULT_PORTS = [18789, 18790]
|
|
7
|
+
const PROBE_TIMEOUT_MS = 4000
|
|
8
|
+
|
|
9
|
+
function getLanIps(): string[] {
|
|
10
|
+
const interfaces = os.networkInterfaces()
|
|
11
|
+
const ips: string[] = []
|
|
12
|
+
for (const iface of Object.values(interfaces)) {
|
|
13
|
+
if (!iface) continue
|
|
14
|
+
for (const info of iface) {
|
|
15
|
+
if (info.family === 'IPv4' && !info.internal) {
|
|
16
|
+
ips.push(info.address)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return ips
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function GET() {
|
|
24
|
+
try {
|
|
25
|
+
const hosts = ['127.0.0.1', ...getLanIps()]
|
|
26
|
+
const probes: Array<Promise<{
|
|
27
|
+
host: string
|
|
28
|
+
port: number
|
|
29
|
+
healthy: boolean
|
|
30
|
+
models?: string[]
|
|
31
|
+
error?: string
|
|
32
|
+
}>> = []
|
|
33
|
+
|
|
34
|
+
for (const host of hosts) {
|
|
35
|
+
for (const port of DEFAULT_PORTS) {
|
|
36
|
+
probes.push(
|
|
37
|
+
probeOpenClawHealth({
|
|
38
|
+
endpoint: `http://${host}:${port}`,
|
|
39
|
+
timeoutMs: PROBE_TIMEOUT_MS,
|
|
40
|
+
}).then((result) => ({
|
|
41
|
+
host,
|
|
42
|
+
port,
|
|
43
|
+
healthy: result.ok,
|
|
44
|
+
models: result.models.length > 0 ? result.models : undefined,
|
|
45
|
+
error: result.error || undefined,
|
|
46
|
+
})).catch(() => ({
|
|
47
|
+
host,
|
|
48
|
+
port,
|
|
49
|
+
healthy: false,
|
|
50
|
+
error: 'unreachable',
|
|
51
|
+
})),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const results = await Promise.all(probes)
|
|
57
|
+
return NextResponse.json({ gateways: results })
|
|
58
|
+
} catch (err: unknown) {
|
|
59
|
+
const message = err instanceof Error ? err.message : 'Discovery failed'
|
|
60
|
+
return NextResponse.json({ error: message }, { status: 500 })
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { ensureGatewayConnected } from '@/lib/server/openclaw-gateway'
|
|
3
|
+
|
|
4
|
+
/** GET — list env var keys from gateway .env */
|
|
5
|
+
export async function GET() {
|
|
6
|
+
const gw = await ensureGatewayConnected()
|
|
7
|
+
if (!gw) {
|
|
8
|
+
return NextResponse.json({ error: 'OpenClaw gateway not connected' }, { status: 503 })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const result = await gw.rpc('env.keys') as string[] | undefined
|
|
13
|
+
return NextResponse.json(result ?? [])
|
|
14
|
+
} catch (err: unknown) {
|
|
15
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
16
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getExecConfig, setExecConfig } from '@/lib/server/openclaw-exec-config'
|
|
3
|
+
import type { ExecApprovalConfig } from '@/types'
|
|
4
|
+
|
|
5
|
+
/** GET ?agentId=X — fetch exec approval config */
|
|
6
|
+
export async function GET(req: Request) {
|
|
7
|
+
const { searchParams } = new URL(req.url)
|
|
8
|
+
const agentId = searchParams.get('agentId')
|
|
9
|
+
if (!agentId) {
|
|
10
|
+
return NextResponse.json({ error: 'Missing agentId' }, { status: 400 })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const snapshot = await getExecConfig(agentId)
|
|
15
|
+
return NextResponse.json(snapshot)
|
|
16
|
+
} catch (err: unknown) {
|
|
17
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
18
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** PUT { agentId, config, baseHash } — save exec approval config */
|
|
23
|
+
export async function PUT(req: Request) {
|
|
24
|
+
const body = await req.json()
|
|
25
|
+
const { agentId, config, baseHash } = body as {
|
|
26
|
+
agentId?: string
|
|
27
|
+
config?: ExecApprovalConfig
|
|
28
|
+
baseHash?: string
|
|
29
|
+
}
|
|
30
|
+
if (!agentId || !config) {
|
|
31
|
+
return NextResponse.json({ error: 'Missing agentId or config' }, { status: 400 })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const result = await setExecConfig(agentId, config, baseHash ?? '')
|
|
36
|
+
return NextResponse.json(result)
|
|
37
|
+
} catch (err: unknown) {
|
|
38
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
39
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { ensureGatewayConnected, getGateway, disconnectGateway, manualConnect } from '@/lib/server/openclaw-gateway'
|
|
3
|
+
|
|
4
|
+
/** POST — proxy an RPC call or perform gateway actions */
|
|
5
|
+
export async function POST(req: Request) {
|
|
6
|
+
const body = await req.json()
|
|
7
|
+
const { method, params } = body as { method?: string; params?: Record<string, unknown> }
|
|
8
|
+
if (!method || typeof method !== 'string') {
|
|
9
|
+
return NextResponse.json({ error: 'Missing RPC method' }, { status: 400 })
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Gateway control actions
|
|
13
|
+
if (method === 'gateway.connect') {
|
|
14
|
+
try {
|
|
15
|
+
const url = (params?.url as string) || undefined
|
|
16
|
+
const token = (params?.token as string) || undefined
|
|
17
|
+
const ok = await manualConnect(url, token)
|
|
18
|
+
return NextResponse.json({ ok })
|
|
19
|
+
} catch (err: unknown) {
|
|
20
|
+
return NextResponse.json({ ok: false, error: err instanceof Error ? err.message : String(err) }, { status: 502 })
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (method === 'gateway.disconnect') {
|
|
25
|
+
disconnectGateway()
|
|
26
|
+
return NextResponse.json({ ok: true })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Reload mode get/set
|
|
30
|
+
if (method === 'gateway.reload-mode.get') {
|
|
31
|
+
const gw = await ensureGatewayConnected()
|
|
32
|
+
if (!gw) return NextResponse.json({ error: 'Not connected' }, { status: 503 })
|
|
33
|
+
try {
|
|
34
|
+
const config = await gw.rpc('config.get') as Record<string, unknown> | undefined
|
|
35
|
+
const mode = (config as Record<string, unknown>)?.reloadMode ?? 'hot'
|
|
36
|
+
return NextResponse.json({ ok: true, result: mode })
|
|
37
|
+
} catch (err: unknown) {
|
|
38
|
+
return NextResponse.json({ error: err instanceof Error ? err.message : String(err) }, { status: 502 })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (method === 'gateway.reload-mode.set') {
|
|
43
|
+
const gw = await ensureGatewayConnected()
|
|
44
|
+
if (!gw) return NextResponse.json({ error: 'Not connected' }, { status: 503 })
|
|
45
|
+
try {
|
|
46
|
+
await gw.rpc('config.set', { reloadMode: params?.mode })
|
|
47
|
+
return NextResponse.json({ ok: true })
|
|
48
|
+
} catch (err: unknown) {
|
|
49
|
+
return NextResponse.json({ error: err instanceof Error ? err.message : String(err) }, { status: 502 })
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// General RPC proxy
|
|
54
|
+
const gw = await ensureGatewayConnected()
|
|
55
|
+
if (!gw) {
|
|
56
|
+
return NextResponse.json({ error: 'OpenClaw gateway not connected' }, { status: 503 })
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const result = await gw.rpc(method, params)
|
|
61
|
+
return NextResponse.json({ ok: true, result })
|
|
62
|
+
} catch (err: unknown) {
|
|
63
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
64
|
+
return NextResponse.json({ error: message }, { status: 502 })
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** GET — check gateway connection status */
|
|
69
|
+
export async function GET() {
|
|
70
|
+
const gw = getGateway()
|
|
71
|
+
return NextResponse.json({ connected: !!gw?.connected })
|
|
72
|
+
}
|