@swarmclawai/swarmclaw 1.2.3 → 1.2.5
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 +20 -0
- package/bin/daemon-cmd.js +169 -0
- package/bin/server-cmd.js +3 -0
- package/bin/swarmclaw.js +11 -0
- package/package.json +17 -16
- package/src/app/api/agents/[id]/clone/route.ts +3 -32
- package/src/app/api/agents/[id]/route.ts +6 -158
- package/src/app/api/agents/[id]/status/route.ts +2 -3
- package/src/app/api/agents/[id]/thread/route.ts +4 -17
- package/src/app/api/agents/bulk/route.ts +5 -47
- package/src/app/api/agents/route.ts +5 -119
- package/src/app/api/agents/trash/route.ts +13 -24
- package/src/app/api/auth/route.ts +3 -9
- package/src/app/api/autonomy/estop/route.ts +5 -5
- package/src/app/api/chatrooms/[id]/chat/route.ts +11 -5
- package/src/app/api/chatrooms/[id]/route.ts +23 -2
- package/src/app/api/chatrooms/route.ts +13 -2
- package/src/app/api/chats/[id]/clear/route.ts +2 -13
- package/src/app/api/chats/[id]/deploy/route.ts +2 -3
- package/src/app/api/chats/[id]/edit-resend/route.ts +7 -13
- package/src/app/api/chats/[id]/mailbox/route.ts +6 -8
- package/src/app/api/chats/[id]/queue/route.ts +17 -64
- package/src/app/api/chats/[id]/retry/route.ts +4 -22
- package/src/app/api/chats/[id]/route.ts +10 -138
- package/src/app/api/chats/heartbeat/route.ts +2 -1
- package/src/app/api/chats/migrate-messages/route.ts +7 -0
- package/src/app/api/chats/route.ts +13 -134
- package/src/app/api/connectors/[id]/access/route.ts +12 -229
- package/src/app/api/connectors/[id]/doctor/route.ts +1 -1
- package/src/app/api/connectors/[id]/health/route.ts +12 -39
- package/src/app/api/connectors/[id]/route.ts +14 -122
- package/src/app/api/connectors/[id]/webhook/route.ts +1 -1
- package/src/app/api/connectors/doctor/route.ts +1 -1
- package/src/app/api/connectors/route.ts +12 -70
- package/src/app/api/credentials/[id]/route.ts +2 -4
- package/src/app/api/credentials/route.ts +10 -19
- package/src/app/api/daemon/health-check/route.ts +3 -4
- package/src/app/api/daemon/route.ts +10 -8
- package/src/app/api/documents/route.ts +11 -10
- package/src/app/api/external-agents/route.ts +3 -3
- package/src/app/api/gateways/[id]/health/route.ts +2 -3
- package/src/app/api/gateways/[id]/route.ts +7 -122
- package/src/app/api/gateways/route.ts +3 -103
- package/src/app/api/mcp-servers/[id]/tools/route.ts +5 -5
- package/src/app/api/openclaw/dashboard-url/route.ts +8 -16
- package/src/app/api/openclaw/directory/route.ts +2 -2
- package/src/app/api/openclaw/history/route.ts +3 -5
- package/src/app/api/providers/[id]/models/route.test.ts +60 -0
- package/src/app/api/providers/[id]/models/route.ts +33 -1
- package/src/app/api/providers/[id]/route.test.ts +49 -0
- package/src/app/api/providers/[id]/route.ts +30 -1
- package/src/app/api/providers/ollama/route.ts +6 -5
- package/src/app/api/schedules/[id]/route.ts +14 -108
- package/src/app/api/schedules/[id]/run/route.ts +6 -67
- package/src/app/api/schedules/route.ts +9 -51
- package/src/app/api/settings/route.ts +4 -3
- package/src/app/api/setup/check-provider/route.ts +15 -1
- package/src/app/api/setup/openclaw-device/route.ts +2 -2
- package/src/app/api/system/status/route.ts +2 -2
- package/src/app/api/tasks/[id]/route.ts +16 -202
- package/src/app/api/tasks/bulk/route.ts +5 -86
- package/src/app/api/tasks/metrics/route.ts +2 -1
- package/src/app/api/tasks/route.ts +11 -171
- package/src/app/api/upload/route.ts +1 -1
- package/src/app/api/uploads/[filename]/route.ts +1 -1
- package/src/app/api/uploads/route.ts +1 -1
- package/src/app/api/webhooks/[id]/history/route.ts +2 -2
- package/src/app/layout.tsx +9 -6
- package/src/app/protocols/page.tsx +71 -89
- package/src/app/tasks/page.tsx +32 -32
- package/src/cli/index.js +1 -0
- package/src/cli/spec.js +1 -0
- package/src/components/agents/agent-sheet.tsx +51 -25
- package/src/components/agents/inspector-panel.tsx +15 -4
- package/src/components/auth/setup-wizard/index.tsx +27 -18
- package/src/components/auth/setup-wizard/shared.tsx +2 -2
- package/src/components/auth/setup-wizard/step-agents.tsx +51 -38
- package/src/components/auth/setup-wizard/step-connect.tsx +48 -17
- package/src/components/auth/setup-wizard/types.ts +6 -4
- package/src/components/auth/setup-wizard/utils.test.ts +38 -8
- package/src/components/auth/setup-wizard/utils.ts +14 -8
- package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
- package/src/components/connectors/connector-list.tsx +26 -40
- package/src/components/connectors/connector-sheet.tsx +95 -149
- package/src/components/gateways/gateway-sheet.tsx +61 -110
- package/src/components/layout/live-query-sync.tsx +121 -0
- package/src/components/protocols/structured-session-launcher.tsx +24 -45
- package/src/components/providers/app-query-provider.tsx +17 -0
- package/src/components/providers/provider-list.tsx +150 -77
- package/src/components/providers/provider-sheet.tsx +102 -77
- package/src/components/shared/model-combobox.tsx +5 -4
- package/src/components/skills/skill-list.tsx +5 -18
- package/src/components/skills/skill-sheet.tsx +21 -20
- package/src/components/skills/skills-workspace.tsx +48 -87
- package/src/components/tasks/task-card.tsx +20 -13
- package/src/components/tasks/task-column.tsx +22 -7
- package/src/components/tasks/task-list.tsx +8 -11
- package/src/components/tasks/task-sheet.tsx +111 -103
- package/src/features/agents/queries.ts +20 -0
- package/src/features/chatrooms/queries.ts +20 -0
- package/src/features/chats/queries.ts +27 -0
- package/src/features/connectors/queries.ts +145 -0
- package/src/features/credentials/queries.ts +37 -0
- package/src/features/extensions/queries.ts +26 -0
- package/src/features/external-agents/queries.ts +36 -0
- package/src/features/gateways/queries.ts +274 -0
- package/src/features/missions/queries.ts +23 -0
- package/src/features/projects/queries.ts +20 -0
- package/src/features/protocols/queries.ts +149 -0
- package/src/features/providers/queries.ts +142 -0
- package/src/features/settings/queries.ts +20 -0
- package/src/features/skills/queries.ts +182 -0
- package/src/features/tasks/queries.ts +189 -0
- package/src/hooks/use-ws.ts +3 -2
- package/src/lib/agent-provider-options.test.ts +152 -0
- package/src/lib/agent-provider-options.ts +84 -0
- package/src/lib/app/api-client.ts +2 -2
- package/src/lib/providers/index.test.ts +78 -0
- package/src/lib/providers/index.ts +13 -10
- package/src/lib/query/client.ts +17 -0
- package/src/lib/server/agents/agent-runtime-config.ts +6 -6
- package/src/lib/server/agents/agent-service.ts +429 -0
- package/src/lib/server/agents/agent-thread-session.ts +6 -5
- package/src/lib/server/agents/autonomy-contract.ts +1 -4
- package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
- package/src/lib/server/agents/delegation-advisory.ts +251 -0
- package/src/lib/server/agents/main-agent-loop.ts +98 -40
- package/src/lib/server/agents/subagent-runtime.ts +12 -0
- package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
- package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
- package/src/lib/server/build-llm.ts +7 -15
- package/src/lib/server/capability-router.test.ts +70 -1
- package/src/lib/server/capability-router.ts +24 -99
- package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
- package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
- package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
- package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
- package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
- package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
- package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
- package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
- package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
- package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
- package/src/lib/server/chat-execution/message-classifier.ts +74 -32
- package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
- package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
- package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
- package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
- package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
- package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
- package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
- package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
- package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
- package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
- package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
- package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
- package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
- package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
- package/src/lib/server/chats/chat-session-service.ts +410 -0
- package/src/lib/server/connectors/access.ts +1 -1
- package/src/lib/server/connectors/commands.ts +7 -6
- package/src/lib/server/connectors/connector-inbound.ts +14 -7
- package/src/lib/server/connectors/connector-outbound.ts +16 -11
- package/src/lib/server/connectors/connector-service.ts +453 -0
- package/src/lib/server/connectors/delivery.ts +17 -12
- package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
- package/src/lib/server/connectors/media.ts +1 -1
- package/src/lib/server/connectors/response-media.ts +1 -1
- package/src/lib/server/connectors/session-consolidation.ts +11 -7
- package/src/lib/server/connectors/session.ts +9 -7
- package/src/lib/server/connectors/voice-note.ts +2 -1
- package/src/lib/server/context-manager.ts +20 -1
- package/src/lib/server/cost.ts +2 -3
- package/src/lib/server/credentials/credential-repository.ts +43 -4
- package/src/lib/server/credentials/credential-service.ts +112 -0
- package/src/lib/server/daemon/admin-metadata.ts +64 -0
- package/src/lib/server/daemon/controller.ts +577 -0
- package/src/lib/server/daemon/daemon-runtime.ts +352 -0
- package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
- package/src/lib/server/daemon/types.ts +101 -0
- package/src/lib/server/embeddings.ts +3 -9
- package/src/lib/server/eval/agent-regression.ts +3 -2
- package/src/lib/server/eval/runner.ts +2 -2
- package/src/lib/server/execution-brief.test.ts +167 -0
- package/src/lib/server/execution-brief.ts +295 -0
- package/src/lib/server/execution-engine/chat-turn.ts +9 -0
- package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
- package/src/lib/server/execution-engine/index.ts +35 -0
- package/src/lib/server/execution-engine/task-attempt.ts +303 -0
- package/src/lib/server/execution-engine/types.ts +33 -0
- package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
- package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
- package/src/lib/server/memory/session-archive-memory.ts +12 -10
- package/src/lib/server/messages/message-repository.ts +330 -0
- package/src/lib/server/missions/mission-service/core.ts +8 -6
- package/src/lib/server/openclaw/agent-resolver.ts +2 -3
- package/src/lib/server/openclaw/doctor.ts +1 -1
- package/src/lib/server/openclaw/gateway.test.ts +10 -1
- package/src/lib/server/openclaw/gateway.ts +5 -14
- package/src/lib/server/openclaw/health.ts +3 -11
- package/src/lib/server/openclaw/sync.ts +8 -6
- package/src/lib/server/persistence/storage-context.ts +3 -0
- package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
- package/src/lib/server/protocols/protocol-normalization.ts +1 -1
- package/src/lib/server/protocols/protocol-queries.ts +13 -7
- package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
- package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
- package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
- package/src/lib/server/protocols/protocol-swarm.ts +8 -8
- package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
- package/src/lib/server/protocols/protocol-templates.ts +4 -2
- package/src/lib/server/protocols/protocol-types.ts +10 -7
- package/src/lib/server/provider-endpoint.ts +7 -12
- package/src/lib/server/provider-model-discovery.ts +2 -11
- package/src/lib/server/query-expansion.ts +5 -6
- package/src/lib/server/run-context.test.ts +365 -0
- package/src/lib/server/run-context.ts +367 -0
- package/src/lib/server/runtime/heartbeat-service.ts +7 -5
- package/src/lib/server/runtime/queue/core.ts +61 -190
- package/src/lib/server/runtime/run-ledger.ts +8 -0
- package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
- package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
- package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
- package/src/lib/server/schedules/schedule-route-service.ts +230 -0
- package/src/lib/server/service-result.ts +16 -0
- package/src/lib/server/session-note.ts +2 -3
- package/src/lib/server/session-reset-policy.ts +4 -3
- package/src/lib/server/session-tools/connector.ts +9 -6
- package/src/lib/server/session-tools/context-mgmt.ts +58 -9
- package/src/lib/server/session-tools/crud.ts +162 -10
- package/src/lib/server/session-tools/delegate.ts +1 -1
- package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
- package/src/lib/server/session-tools/memory.ts +6 -4
- package/src/lib/server/session-tools/session-info.test.ts +56 -0
- package/src/lib/server/session-tools/session-info.ts +119 -12
- package/src/lib/server/session-tools/skill-runtime.ts +3 -1
- package/src/lib/server/session-tools/skills.ts +15 -15
- package/src/lib/server/session-tools/subagent.test.ts +115 -1
- package/src/lib/server/session-tools/subagent.ts +125 -7
- package/src/lib/server/session-tools/team-context.ts +4 -3
- package/src/lib/server/session-tools/wallet.ts +0 -58
- package/src/lib/server/sessions/session-lineage.ts +55 -0
- package/src/lib/server/sessions/session-repository.ts +2 -2
- package/src/lib/server/skills/learned-skills.ts +24 -23
- package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
- package/src/lib/server/skills/skill-repository.ts +136 -13
- package/src/lib/server/skills/skill-suggestions.ts +25 -28
- package/src/lib/server/storage-normalization.test.ts +42 -215
- package/src/lib/server/storage-normalization.ts +98 -0
- package/src/lib/server/storage.ts +19 -0
- package/src/lib/server/structured-extract.ts +3 -14
- package/src/lib/server/tasks/task-followups.ts +16 -11
- package/src/lib/server/tasks/task-result.test.ts +25 -29
- package/src/lib/server/tasks/task-result.ts +5 -9
- package/src/lib/server/tasks/task-route-service.ts +449 -0
- package/src/lib/server/text-normalization.ts +41 -0
- package/src/lib/server/tool-planning.ts +6 -42
- package/src/lib/server/upload-path.ts +5 -0
- package/src/lib/server/working-state/extraction.ts +614 -0
- package/src/lib/server/working-state/normalization.ts +866 -0
- package/src/lib/server/working-state/prompt.ts +60 -0
- package/src/lib/server/working-state/repository.ts +38 -0
- package/src/lib/server/working-state/service.test.ts +253 -0
- package/src/lib/server/working-state/service.ts +293 -0
- package/src/lib/validation/schemas.ts +1 -0
- package/src/lib/ws-client.ts +3 -3
- package/src/stores/slices/task-slice.ts +1 -4
- package/src/stores/use-chatroom-store.ts +2 -2
- package/src/types/index.ts +288 -22
- package/src/views/settings/section-providers.tsx +2 -2
|
@@ -1,64 +1,37 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import { loadConnectors, loadConnectorHealth } from '@/lib/server/storage'
|
|
3
2
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
3
|
+
import { getConnectorHealthForApi } from '@/lib/server/connectors/connector-service'
|
|
4
4
|
import type { ConnectorHealthEvent } from '@/types'
|
|
5
5
|
|
|
6
6
|
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
7
|
const { id } = await params
|
|
8
|
-
const
|
|
9
|
-
if (!
|
|
10
|
-
|
|
8
|
+
const result = getConnectorHealthForApi(id)
|
|
9
|
+
if (!result) return notFound()
|
|
11
10
|
const url = new URL(req.url)
|
|
12
11
|
const since = url.searchParams.get('since')
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const events: ConnectorHealthEvent[] = []
|
|
16
|
-
|
|
17
|
-
for (const raw of Object.values(allHealth)) {
|
|
18
|
-
const entry = raw as ConnectorHealthEvent
|
|
19
|
-
if (entry.connectorId !== id) continue
|
|
20
|
-
if (since && entry.timestamp < since) continue
|
|
21
|
-
events.push(entry)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Sort by timestamp ascending
|
|
25
|
-
events.sort((a, b) => a.timestamp.localeCompare(b.timestamp))
|
|
26
|
-
|
|
27
|
-
// Compute uptime percentage
|
|
28
|
-
const uptimePercent = computeUptime(events)
|
|
29
|
-
|
|
30
|
-
return NextResponse.json({ events, uptimePercent })
|
|
12
|
+
const events = since ? result.events.filter((entry) => entry.timestamp >= since) : result.events
|
|
13
|
+
return NextResponse.json({ events, uptimePercent: computeUptime(events) })
|
|
31
14
|
}
|
|
32
15
|
|
|
33
16
|
function computeUptime(events: ConnectorHealthEvent[]): number {
|
|
34
17
|
if (events.length === 0) return 0
|
|
35
|
-
|
|
36
18
|
const firstTime = new Date(events[0].timestamp).getTime()
|
|
37
19
|
const now = Date.now()
|
|
38
20
|
const totalMs = now - firstTime
|
|
39
21
|
if (totalMs <= 0) return 100
|
|
40
|
-
|
|
41
22
|
let uptimeMs = 0
|
|
42
23
|
let lastUpAt: number | null = null
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
lastUpAt = t
|
|
49
|
-
}
|
|
50
|
-
} else if (ev.event === 'stopped' || ev.event === 'error' || ev.event === 'disconnected') {
|
|
24
|
+
for (const event of events) {
|
|
25
|
+
const time = new Date(event.timestamp).getTime()
|
|
26
|
+
if (event.event === 'started' || event.event === 'reconnected') {
|
|
27
|
+
if (lastUpAt === null) lastUpAt = time
|
|
28
|
+
} else if (event.event === 'stopped' || event.event === 'error' || event.event === 'disconnected') {
|
|
51
29
|
if (lastUpAt !== null) {
|
|
52
|
-
uptimeMs +=
|
|
30
|
+
uptimeMs += time - lastUpAt
|
|
53
31
|
lastUpAt = null
|
|
54
32
|
}
|
|
55
33
|
}
|
|
56
34
|
}
|
|
57
|
-
|
|
58
|
-
// If still up, count time until now
|
|
59
|
-
if (lastUpAt !== null) {
|
|
60
|
-
uptimeMs += now - lastUpAt
|
|
61
|
-
}
|
|
62
|
-
|
|
35
|
+
if (lastUpAt !== null) uptimeMs += now - lastUpAt
|
|
63
36
|
return Math.round((uptimeMs / totalMs) * 10000) / 100
|
|
64
37
|
}
|
|
@@ -1,141 +1,33 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { safeParseBody } from '@/lib/server/safe-parse-body'
|
|
3
|
-
import { loadConnectors, logActivity, upsertStoredItem, deleteStoredItem } from '@/lib/server/storage'
|
|
4
|
-
import { notify } from '@/lib/server/ws-hub'
|
|
5
3
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
6
|
-
import {
|
|
7
|
-
|
|
4
|
+
import {
|
|
5
|
+
deleteConnectorFromRoute,
|
|
6
|
+
getConnectorWithRuntime,
|
|
7
|
+
updateConnectorFromRoute,
|
|
8
|
+
} from '@/lib/server/connectors/connector-service'
|
|
8
9
|
|
|
9
10
|
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
10
|
-
ensureDaemonStarted('api/connectors/[id]:get')
|
|
11
11
|
const { id } = await params
|
|
12
|
-
const
|
|
13
|
-
const connector = connectors[id]
|
|
12
|
+
const connector = await getConnectorWithRuntime(id)
|
|
14
13
|
if (!connector) return notFound()
|
|
15
|
-
|
|
16
|
-
// Merge runtime status, QR code, and presence
|
|
17
|
-
try {
|
|
18
|
-
const { getConnectorStatus, getConnectorQR, isConnectorAuthenticated, hasConnectorCredentials, getConnectorPresence, getReconnectState } = await import('@/lib/server/connectors/manager')
|
|
19
|
-
const runtimeStatus = getConnectorStatus(id)
|
|
20
|
-
connector.status = runtimeStatus === 'running'
|
|
21
|
-
? 'running'
|
|
22
|
-
: connector.lastError
|
|
23
|
-
? 'error'
|
|
24
|
-
: 'stopped'
|
|
25
|
-
const rState = getReconnectState(id)
|
|
26
|
-
if (rState) {
|
|
27
|
-
const ext = connector as unknown as Record<string, unknown>
|
|
28
|
-
ext.reconnectAttempts = rState.attempts
|
|
29
|
-
ext.nextRetryAt = rState.nextRetryAt
|
|
30
|
-
ext.reconnectError = rState.error
|
|
31
|
-
ext.reconnectExhausted = rState.exhausted
|
|
32
|
-
}
|
|
33
|
-
const qr = getConnectorQR(id)
|
|
34
|
-
if (qr) connector.qrDataUrl = qr
|
|
35
|
-
connector.authenticated = isConnectorAuthenticated(id)
|
|
36
|
-
connector.hasCredentials = hasConnectorCredentials(id)
|
|
37
|
-
if (connector.status === 'running') {
|
|
38
|
-
connector.presence = getConnectorPresence(id)
|
|
39
|
-
}
|
|
40
|
-
} catch { /* ignore */ }
|
|
41
|
-
|
|
42
14
|
return NextResponse.json(connector)
|
|
43
15
|
}
|
|
44
16
|
|
|
45
17
|
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
46
|
-
ensureDaemonStarted('api/connectors/[id]:put')
|
|
47
18
|
const { id } = await params
|
|
48
19
|
const { data: body, error } = await safeParseBody<Record<string, unknown>>(req)
|
|
49
20
|
if (error) return error
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// so re-read from storage after to avoid overwriting with stale data
|
|
56
|
-
if (body.action === 'start' || body.action === 'stop' || body.action === 'repair') {
|
|
57
|
-
try {
|
|
58
|
-
const manager = await import('@/lib/server/connectors/manager')
|
|
59
|
-
if (body.action === 'start') {
|
|
60
|
-
manager.clearReconnectState(id)
|
|
61
|
-
await manager.startConnector(id)
|
|
62
|
-
logActivity({ entityType: 'connector', entityId: id, action: 'started', actor: 'user', summary: `Connector started: "${connector.name}"` })
|
|
63
|
-
} else if (body.action === 'stop') {
|
|
64
|
-
await manager.stopConnector(id)
|
|
65
|
-
logActivity({ entityType: 'connector', entityId: id, action: 'stopped', actor: 'user', summary: `Connector stopped: "${connector.name}"` })
|
|
66
|
-
} else {
|
|
67
|
-
manager.clearReconnectState(id)
|
|
68
|
-
await manager.repairConnector(id)
|
|
69
|
-
logActivity({ entityType: 'connector', entityId: id, action: 'started', actor: 'user', summary: `Connector repaired: "${connector.name}"` })
|
|
70
|
-
}
|
|
71
|
-
} catch (err: unknown) {
|
|
72
|
-
// Re-read to get the error state saved by startConnector
|
|
73
|
-
const fresh = loadConnectors()
|
|
74
|
-
return NextResponse.json(fresh[id] || { error: errorMessage(err) }, { status: 500 })
|
|
75
|
-
}
|
|
76
|
-
// Re-read the connector after manager modified it
|
|
77
|
-
const fresh = loadConnectors()
|
|
78
|
-
notify('connectors')
|
|
79
|
-
return NextResponse.json(fresh[id])
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Regular update — guard types at the boundary
|
|
83
|
-
if (body.name !== undefined) connector.name = typeof body.name === 'string' ? body.name : connector.name
|
|
84
|
-
if (body.agentId !== undefined) connector.agentId = typeof body.agentId === 'string' || body.agentId === null ? body.agentId : connector.agentId
|
|
85
|
-
if (body.chatroomId !== undefined) connector.chatroomId = typeof body.chatroomId === 'string' || body.chatroomId === null ? body.chatroomId : connector.chatroomId
|
|
86
|
-
if (body.credentialId !== undefined) connector.credentialId = typeof body.credentialId === 'string' || body.credentialId === null ? body.credentialId : connector.credentialId
|
|
87
|
-
if (body.config !== undefined) connector.config = body.config && typeof body.config === 'object' && !Array.isArray(body.config) ? body.config as Record<string, string> : connector.config
|
|
88
|
-
if (body.isEnabled !== undefined) connector.isEnabled = typeof body.isEnabled === 'boolean' ? body.isEnabled : connector.isEnabled
|
|
89
|
-
connector.updatedAt = Date.now()
|
|
90
|
-
|
|
91
|
-
upsertStoredItem('connectors', id, connector)
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
const manager = await import('@/lib/server/connectors/manager')
|
|
95
|
-
const wasRunning = manager.getConnectorStatus(id) === 'running'
|
|
96
|
-
const shouldStop = body.isEnabled === false
|
|
97
|
-
const shouldReload = wasRunning && (
|
|
98
|
-
body.name !== undefined
|
|
99
|
-
|| body.agentId !== undefined
|
|
100
|
-
|| body.chatroomId !== undefined
|
|
101
|
-
|| body.credentialId !== undefined
|
|
102
|
-
|| body.config !== undefined
|
|
103
|
-
|| body.isEnabled !== undefined
|
|
104
|
-
)
|
|
105
|
-
const shouldStart = body.isEnabled === true && !wasRunning
|
|
106
|
-
|
|
107
|
-
if (shouldStop) {
|
|
108
|
-
await manager.stopConnector(id)
|
|
109
|
-
} else if (shouldReload || shouldStart) {
|
|
110
|
-
manager.clearReconnectState(id)
|
|
111
|
-
await manager.startConnector(id)
|
|
112
|
-
}
|
|
113
|
-
} catch {
|
|
114
|
-
// Keep the saved connector update even if the runtime reload fails.
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
notify('connectors')
|
|
118
|
-
return NextResponse.json(loadConnectors()[id] || connector)
|
|
21
|
+
const result = await updateConnectorFromRoute(id, body)
|
|
22
|
+
if (!result.ok && result.status === 404) return notFound()
|
|
23
|
+
return result.ok
|
|
24
|
+
? NextResponse.json(result.payload)
|
|
25
|
+
: NextResponse.json(result.payload, { status: result.status })
|
|
119
26
|
}
|
|
120
27
|
|
|
121
28
|
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
122
29
|
const { id } = await params
|
|
123
|
-
const
|
|
124
|
-
if (!
|
|
125
|
-
|
|
126
|
-
// Stop if running
|
|
127
|
-
try {
|
|
128
|
-
const { stopConnector } = await import('@/lib/server/connectors/manager')
|
|
129
|
-
await stopConnector(id)
|
|
130
|
-
} catch { /* ignore */ }
|
|
131
|
-
|
|
132
|
-
// Clear persisted pairing state when connector is deleted.
|
|
133
|
-
try {
|
|
134
|
-
const { clearConnectorPairingState } = await import('@/lib/server/connectors/pairing')
|
|
135
|
-
clearConnectorPairingState(id)
|
|
136
|
-
} catch { /* ignore */ }
|
|
137
|
-
|
|
138
|
-
deleteStoredItem('connectors', id)
|
|
139
|
-
notify('connectors')
|
|
140
|
-
return NextResponse.json({ ok: true })
|
|
30
|
+
const result = await deleteConnectorFromRoute(id)
|
|
31
|
+
if (!result.ok) return notFound()
|
|
32
|
+
return NextResponse.json(result.payload)
|
|
141
33
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { buildConnectorDoctorPreview, buildConnectorDoctorReport, type ConnectorDoctorPreviewInput } from '@/lib/server/connectors/doctor'
|
|
3
|
-
import { loadConnectors } from '@/lib/server/
|
|
3
|
+
import { loadConnectors } from '@/lib/server/connectors/connector-repository'
|
|
4
4
|
|
|
5
5
|
export const dynamic = 'force-dynamic'
|
|
6
6
|
|
|
@@ -1,91 +1,33 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { safeParseBody } from '@/lib/server/safe-parse-body'
|
|
3
|
-
import { genId } from '@/lib/id'
|
|
4
3
|
import { perf } from '@/lib/server/runtime/perf'
|
|
5
|
-
import { loadConnectors, upsertStoredItem } from '@/lib/server/storage'
|
|
6
|
-
import { notify } from '@/lib/server/ws-hub'
|
|
7
|
-
import { ensureDaemonStarted } from '@/lib/server/runtime/daemon-state'
|
|
8
4
|
import { ConnectorCreateSchema, formatZodError } from '@/lib/validation/schemas'
|
|
9
5
|
import { z } from 'zod'
|
|
10
|
-
import
|
|
6
|
+
import {
|
|
7
|
+
autoStartConnectorIfNeeded,
|
|
8
|
+
createConnector,
|
|
9
|
+
listConnectorsWithRuntime,
|
|
10
|
+
} from '@/lib/server/connectors/connector-service'
|
|
11
|
+
import { ensureDaemonProcessRunning } from '@/lib/server/daemon/controller'
|
|
12
|
+
import { loadConnector } from '@/lib/server/connectors/connector-repository'
|
|
11
13
|
export const dynamic = 'force-dynamic'
|
|
12
14
|
|
|
13
|
-
|
|
14
15
|
export async function GET() {
|
|
15
16
|
const endPerf = perf.start('api', 'GET /api/connectors')
|
|
16
|
-
|
|
17
|
-
const connectors = loadConnectors()
|
|
18
|
-
// Merge runtime status from manager
|
|
19
|
-
try {
|
|
20
|
-
const { getConnectorStatus, isConnectorAuthenticated, hasConnectorCredentials, getConnectorQR, getReconnectState } = await import('@/lib/server/connectors/manager')
|
|
21
|
-
for (const c of Object.values(connectors) as Connector[]) {
|
|
22
|
-
const runtimeStatus = getConnectorStatus(c.id)
|
|
23
|
-
c.status = runtimeStatus === 'running'
|
|
24
|
-
? 'running'
|
|
25
|
-
: c.lastError
|
|
26
|
-
? 'error'
|
|
27
|
-
: 'stopped'
|
|
28
|
-
if (c.platform === 'whatsapp') {
|
|
29
|
-
c.authenticated = isConnectorAuthenticated(c.id)
|
|
30
|
-
c.hasCredentials = hasConnectorCredentials(c.id)
|
|
31
|
-
const qr = getConnectorQR(c.id)
|
|
32
|
-
if (qr) c.qrDataUrl = qr
|
|
33
|
-
}
|
|
34
|
-
// Surface reconnect state if connector is in a recovery cycle
|
|
35
|
-
const rState = getReconnectState(c.id)
|
|
36
|
-
if (rState) {
|
|
37
|
-
const ext = c as unknown as Record<string, unknown>
|
|
38
|
-
ext.reconnectAttempts = rState.attempts
|
|
39
|
-
ext.nextRetryAt = rState.nextRetryAt
|
|
40
|
-
ext.reconnectError = rState.error
|
|
41
|
-
ext.reconnectExhausted = rState.exhausted
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
} catch { /* manager not loaded yet */ }
|
|
17
|
+
const connectors = await listConnectorsWithRuntime()
|
|
45
18
|
endPerf({ count: Object.keys(connectors).length })
|
|
46
19
|
return NextResponse.json(connectors)
|
|
47
20
|
}
|
|
48
21
|
|
|
49
22
|
export async function POST(req: Request) {
|
|
50
|
-
|
|
23
|
+
await ensureDaemonProcessRunning('api/connectors:post')
|
|
51
24
|
const { data: raw, error } = await safeParseBody<Record<string, unknown>>(req)
|
|
52
25
|
if (error) return error
|
|
53
26
|
const parsed = ConnectorCreateSchema.safeParse(raw)
|
|
54
27
|
if (!parsed.success) {
|
|
55
28
|
return NextResponse.json(formatZodError(parsed.error as z.ZodError), { status: 400 })
|
|
56
29
|
}
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const connector: Connector = {
|
|
61
|
-
id,
|
|
62
|
-
name: body.name || `${body.platform} Connector`,
|
|
63
|
-
platform: body.platform,
|
|
64
|
-
agentId: body.agentId || null,
|
|
65
|
-
chatroomId: body.chatroomId || null,
|
|
66
|
-
credentialId: body.credentialId || null,
|
|
67
|
-
config: body.config || {},
|
|
68
|
-
isEnabled: false,
|
|
69
|
-
status: 'stopped',
|
|
70
|
-
lastError: null,
|
|
71
|
-
createdAt: Date.now(),
|
|
72
|
-
updatedAt: Date.now(),
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
upsertStoredItem('connectors', id, connector)
|
|
76
|
-
notify('connectors')
|
|
77
|
-
|
|
78
|
-
// Auto-start if connector has credentials (or is WhatsApp which uses QR)
|
|
79
|
-
const hasCredentials = connector.platform === 'whatsapp'
|
|
80
|
-
|| connector.platform === 'openclaw'
|
|
81
|
-
|| (connector.platform === 'bluebubbles' && (!!connector.credentialId || !!connector.config.password))
|
|
82
|
-
|| !!connector.credentialId
|
|
83
|
-
if (hasCredentials && body.autoStart !== false) {
|
|
84
|
-
try {
|
|
85
|
-
const { startConnector } = await import('@/lib/server/connectors/manager')
|
|
86
|
-
await startConnector(id)
|
|
87
|
-
} catch { /* auto-start is best-effort */ }
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return NextResponse.json(loadConnectors()[id] || connector)
|
|
30
|
+
const connector = createConnector(parsed.data as unknown as Record<string, unknown>)
|
|
31
|
+
await autoStartConnectorIfNeeded(connector, parsed.data as unknown as Record<string, unknown>)
|
|
32
|
+
return NextResponse.json(loadConnector(connector.id) || connector)
|
|
91
33
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import {
|
|
2
|
+
import { deleteCredentialRecord } from '@/lib/server/credentials/credential-service'
|
|
3
3
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
4
4
|
import { log } from '@/lib/server/logger'
|
|
5
5
|
|
|
@@ -7,11 +7,9 @@ const TAG = 'api-credentials'
|
|
|
7
7
|
|
|
8
8
|
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
9
9
|
const { id: credId } = await params
|
|
10
|
-
|
|
11
|
-
if (!creds[credId]) {
|
|
10
|
+
if (!deleteCredentialRecord(credId)) {
|
|
12
11
|
return notFound()
|
|
13
12
|
}
|
|
14
|
-
deleteCredential(credId)
|
|
15
13
|
log.info(TAG, `deleted ${credId}`)
|
|
16
14
|
return new NextResponse('OK')
|
|
17
15
|
}
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import {
|
|
3
|
-
import { loadCredentials, saveCredentials, encryptKey } from '@/lib/server/storage'
|
|
2
|
+
import { createCredentialRecord, listCredentialSummaries } from '@/lib/server/credentials/credential-service'
|
|
4
3
|
import { safeParseBody } from '@/lib/server/safe-parse-body'
|
|
5
4
|
export const dynamic = 'force-dynamic'
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
export async function GET(
|
|
9
|
-
|
|
10
|
-
const safe: Record<string, Record<string, unknown>> = {}
|
|
11
|
-
for (const [id, c] of Object.entries(creds) as [string, Record<string, unknown>][]) {
|
|
12
|
-
safe[id] = { id: c.id, provider: c.provider, name: c.name, createdAt: c.createdAt }
|
|
13
|
-
}
|
|
14
|
-
return NextResponse.json(safe)
|
|
7
|
+
export async function GET() {
|
|
8
|
+
return NextResponse.json(listCredentialSummaries())
|
|
15
9
|
}
|
|
16
10
|
|
|
17
11
|
export async function POST(req: Request) {
|
|
@@ -21,15 +15,12 @@ export async function POST(req: Request) {
|
|
|
21
15
|
if (!provider || !apiKey) {
|
|
22
16
|
return NextResponse.json({ error: 'provider and apiKey are required' }, { status: 400 })
|
|
23
17
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
createdAt: Date.now(),
|
|
18
|
+
try {
|
|
19
|
+
return NextResponse.json(createCredentialRecord({ provider, name, apiKey }))
|
|
20
|
+
} catch (err: unknown) {
|
|
21
|
+
return NextResponse.json(
|
|
22
|
+
{ error: err instanceof Error ? err.message : 'Failed to create credential' },
|
|
23
|
+
{ status: 500 },
|
|
24
|
+
)
|
|
32
25
|
}
|
|
33
|
-
saveCredentials(creds)
|
|
34
|
-
return NextResponse.json({ id, provider, name: creds[id].name, createdAt: creds[id].createdAt })
|
|
35
26
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import {
|
|
2
|
+
import { runDaemonHealthCheckViaAdmin } from '@/lib/server/daemon/controller'
|
|
3
3
|
|
|
4
4
|
export async function POST() {
|
|
5
|
-
|
|
6
|
-
await runDaemonHealthCheckNow()
|
|
5
|
+
const snapshot = await runDaemonHealthCheckViaAdmin('api/daemon/health-check:post')
|
|
7
6
|
return NextResponse.json({
|
|
8
7
|
ok: true,
|
|
9
|
-
status:
|
|
8
|
+
status: snapshot.status,
|
|
10
9
|
})
|
|
11
10
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
+
import {
|
|
3
|
+
ensureDaemonProcessRunning,
|
|
4
|
+
getDaemonStatusSnapshot,
|
|
5
|
+
stopDaemonProcess,
|
|
6
|
+
} from '@/lib/server/daemon/controller'
|
|
2
7
|
import { notify } from '@/lib/server/ws-hub'
|
|
3
8
|
export const dynamic = 'force-dynamic'
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
export async function GET() {
|
|
7
|
-
|
|
8
|
-
return NextResponse.json(getDaemonStatus())
|
|
12
|
+
return NextResponse.json(await getDaemonStatusSnapshot())
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
export async function POST(req: Request) {
|
|
@@ -13,15 +17,13 @@ export async function POST(req: Request) {
|
|
|
13
17
|
const action = body.action
|
|
14
18
|
|
|
15
19
|
if (action === 'start') {
|
|
16
|
-
|
|
17
|
-
startDaemon({ source: 'api/daemon:post:start', manualStart: true })
|
|
20
|
+
await ensureDaemonProcessRunning('api/daemon:post:start', { manualStart: true })
|
|
18
21
|
notify('daemon')
|
|
19
|
-
return NextResponse.json(
|
|
22
|
+
return NextResponse.json(await getDaemonStatusSnapshot())
|
|
20
23
|
} else if (action === 'stop') {
|
|
21
|
-
|
|
22
|
-
await stopDaemon({ source: 'api/daemon:post:stop', manualStop: true })
|
|
24
|
+
await stopDaemonProcess({ source: 'api/daemon:post:stop', manualStop: true })
|
|
23
25
|
notify('daemon')
|
|
24
|
-
return NextResponse.json(
|
|
26
|
+
return NextResponse.json(await getDaemonStatusSnapshot())
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
return NextResponse.json({ error: 'Invalid action. Use "start" or "stop".' }, { status: 400 })
|
|
@@ -26,9 +26,10 @@ export async function GET(req: Request) {
|
|
|
26
26
|
const terms = q.split(/\s+/).filter(Boolean)
|
|
27
27
|
const limit = normalizeLimit(searchParams.get('limit'), 10, 100)
|
|
28
28
|
const rows = Object.values(docs)
|
|
29
|
-
.map((doc
|
|
30
|
-
const
|
|
31
|
-
const
|
|
29
|
+
.map((doc) => {
|
|
30
|
+
const d = doc as Record<string, unknown>
|
|
31
|
+
const title = String(d.title || '')
|
|
32
|
+
const content = String(d.content || '')
|
|
32
33
|
const hay = `${title}\n${content}`.toLowerCase()
|
|
33
34
|
if (!terms.every((term) => hay.includes(term))) return null
|
|
34
35
|
|
|
@@ -48,18 +49,18 @@ export async function GET(req: Request) {
|
|
|
48
49
|
const snippet = content.slice(snippetStart, snippetEnd).replace(/\s+/g, ' ').trim()
|
|
49
50
|
|
|
50
51
|
return {
|
|
51
|
-
id:
|
|
52
|
-
title:
|
|
53
|
-
fileName:
|
|
54
|
-
sourcePath:
|
|
55
|
-
textLength:
|
|
56
|
-
updatedAt:
|
|
52
|
+
id: d.id,
|
|
53
|
+
title: d.title,
|
|
54
|
+
fileName: d.fileName,
|
|
55
|
+
sourcePath: d.sourcePath,
|
|
56
|
+
textLength: (d.textLength as number) || content.length,
|
|
57
|
+
updatedAt: d.updatedAt,
|
|
57
58
|
score,
|
|
58
59
|
snippet,
|
|
59
60
|
}
|
|
60
61
|
})
|
|
61
62
|
.filter(Boolean)
|
|
62
|
-
.sort((a
|
|
63
|
+
.sort((a, b) => (b as { score: number }).score - (a as { score: number }).score)
|
|
63
64
|
.slice(0, limit)
|
|
64
65
|
|
|
65
66
|
return NextResponse.json(rows)
|
|
@@ -3,7 +3,7 @@ import { genId } from '@/lib/id'
|
|
|
3
3
|
import { formatZodError, ExternalAgentRegisterSchema } from '@/lib/validation/schemas'
|
|
4
4
|
import { loadExternalAgents, loadGatewayProfiles, saveExternalAgents } from '@/lib/server/storage'
|
|
5
5
|
import { notify } from '@/lib/server/ws-hub'
|
|
6
|
-
import type { ExternalAgentRuntime } from '@/types'
|
|
6
|
+
import type { ExternalAgentRuntime, GatewayProfile } from '@/types'
|
|
7
7
|
import { z } from 'zod'
|
|
8
8
|
export const dynamic = 'force-dynamic'
|
|
9
9
|
|
|
@@ -14,9 +14,9 @@ function withDerivedStatus(record: ExternalAgentRuntime): ExternalAgentRuntime {
|
|
|
14
14
|
if (!lastSeenAt) return { ...record, status: record.status || 'offline' }
|
|
15
15
|
if (record.status === 'offline') return record
|
|
16
16
|
const gateways = loadGatewayProfiles()
|
|
17
|
-
const gateway = record.gatewayProfileId ? gateways[record.gatewayProfileId] as
|
|
17
|
+
const gateway = record.gatewayProfileId ? gateways[record.gatewayProfileId] as GatewayProfile | undefined : undefined
|
|
18
18
|
const gatewayTags = Array.isArray(gateway?.tags)
|
|
19
|
-
?
|
|
19
|
+
? gateway.tags.filter((tag): tag is string => typeof tag === 'string' && tag.trim().length > 0)
|
|
20
20
|
: []
|
|
21
21
|
const gatewayUseCase = gateway?.deployment && typeof gateway.deployment === 'object' && typeof (gateway.deployment as Record<string, unknown>).useCase === 'string'
|
|
22
22
|
? (gateway.deployment as Record<string, unknown>).useCase as string
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { probeOpenClawHealth, persistGatewayHealthResult } from '@/lib/server/openclaw/health'
|
|
3
|
-
import {
|
|
3
|
+
import { loadGatewayProfile } from '@/lib/server/gateways/gateway-profile-repository'
|
|
4
4
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
5
5
|
export const dynamic = 'force-dynamic'
|
|
6
6
|
|
|
7
7
|
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
8
8
|
const { id } = await params
|
|
9
|
-
const
|
|
10
|
-
const gateway = gateways[id]
|
|
9
|
+
const gateway = loadGatewayProfile(id)
|
|
11
10
|
if (!gateway) return notFound()
|
|
12
11
|
|
|
13
12
|
const result = await probeOpenClawHealth({
|