@swarmclawai/swarmclaw 0.2.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 +577 -0
- package/bin/server-cmd.js +359 -0
- package/bin/swarmclaw.js +29 -0
- package/bin/swarmclaw.mjs +1504 -0
- package/next.config.ts +33 -0
- package/package.json +112 -0
- package/postcss.config.mjs +7 -0
- package/public/branding/swarmclaw-org-avatar.png +0 -0
- package/public/branding/swarmclaw-org-avatar.svg +58 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/screenshots/agents.png +0 -0
- package/public/screenshots/connectors.png +0 -0
- package/public/screenshots/dashboard.png +0 -0
- package/public/screenshots/new-session-openclaw.png +0 -0
- package/public/screenshots/providers.png +0 -0
- package/public/screenshots/schedules.png +0 -0
- package/public/screenshots/tasks.png +0 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/src/app/api/agents/[id]/route.ts +30 -0
- package/src/app/api/agents/[id]/thread/route.ts +66 -0
- package/src/app/api/agents/generate/route.ts +42 -0
- package/src/app/api/agents/route.ts +33 -0
- package/src/app/api/auth/route.ts +25 -0
- package/src/app/api/claude-skills/route.ts +42 -0
- package/src/app/api/clawhub/install/route.ts +39 -0
- package/src/app/api/clawhub/search/route.ts +11 -0
- package/src/app/api/connectors/[id]/route.ts +79 -0
- package/src/app/api/connectors/route.ts +60 -0
- package/src/app/api/credentials/[id]/route.ts +14 -0
- package/src/app/api/credentials/route.ts +31 -0
- package/src/app/api/daemon/health-check/route.ts +11 -0
- package/src/app/api/daemon/route.ts +22 -0
- package/src/app/api/dirs/pick/route.ts +60 -0
- package/src/app/api/dirs/route.ts +29 -0
- package/src/app/api/documents/[id]/route.ts +47 -0
- package/src/app/api/documents/route.ts +93 -0
- package/src/app/api/files/serve/route.ts +69 -0
- package/src/app/api/generate/info/route.ts +12 -0
- package/src/app/api/generate/route.ts +106 -0
- package/src/app/api/ip/route.ts +6 -0
- package/src/app/api/knowledge/[id]/route.ts +61 -0
- package/src/app/api/knowledge/route.ts +48 -0
- package/src/app/api/knowledge/upload/route.ts +86 -0
- package/src/app/api/logs/route.ts +65 -0
- package/src/app/api/mcp-servers/[id]/route.ts +32 -0
- package/src/app/api/mcp-servers/[id]/test/route.ts +23 -0
- package/src/app/api/mcp-servers/[id]/tools/route.ts +32 -0
- package/src/app/api/mcp-servers/route.ts +27 -0
- package/src/app/api/memory/[id]/route.ts +126 -0
- package/src/app/api/memory/maintenance/route.ts +63 -0
- package/src/app/api/memory/route.ts +111 -0
- package/src/app/api/memory-images/[filename]/route.ts +36 -0
- package/src/app/api/orchestrator/run/route.ts +43 -0
- package/src/app/api/plugins/install/route.ts +58 -0
- package/src/app/api/plugins/marketplace/route.ts +33 -0
- package/src/app/api/plugins/route.ts +21 -0
- package/src/app/api/preview-server/route.ts +339 -0
- package/src/app/api/providers/[id]/models/route.ts +29 -0
- package/src/app/api/providers/[id]/route.ts +34 -0
- package/src/app/api/providers/configs/route.ts +7 -0
- package/src/app/api/providers/ollama/route.ts +30 -0
- package/src/app/api/providers/openclaw/health/route.ts +23 -0
- package/src/app/api/providers/route.ts +28 -0
- package/src/app/api/runs/[id]/route.ts +9 -0
- package/src/app/api/runs/route.ts +13 -0
- package/src/app/api/schedules/[id]/route.ts +28 -0
- package/src/app/api/schedules/[id]/run/route.ts +104 -0
- package/src/app/api/schedules/route.ts +78 -0
- package/src/app/api/secrets/[id]/route.ts +29 -0
- package/src/app/api/secrets/route.ts +42 -0
- package/src/app/api/sessions/[id]/browser/route.ts +13 -0
- package/src/app/api/sessions/[id]/chat/route.ts +96 -0
- package/src/app/api/sessions/[id]/clear/route.ts +19 -0
- package/src/app/api/sessions/[id]/deploy/route.ts +34 -0
- package/src/app/api/sessions/[id]/devserver/route.ts +69 -0
- package/src/app/api/sessions/[id]/mailbox/route.ts +70 -0
- package/src/app/api/sessions/[id]/main-loop/route.ts +94 -0
- package/src/app/api/sessions/[id]/messages/route.ts +9 -0
- package/src/app/api/sessions/[id]/retry/route.ts +28 -0
- package/src/app/api/sessions/[id]/route.ts +103 -0
- package/src/app/api/sessions/[id]/stop/route.ts +13 -0
- package/src/app/api/sessions/heartbeat/route.ts +26 -0
- package/src/app/api/sessions/route.ts +85 -0
- package/src/app/api/settings/route.ts +58 -0
- package/src/app/api/setup/check-provider/route.ts +326 -0
- package/src/app/api/setup/doctor/route.ts +250 -0
- package/src/app/api/skills/[id]/route.ts +40 -0
- package/src/app/api/skills/import/route.ts +69 -0
- package/src/app/api/skills/route.ts +28 -0
- package/src/app/api/tasks/[id]/route.ts +102 -0
- package/src/app/api/tasks/route.ts +115 -0
- package/src/app/api/tts/route.ts +40 -0
- package/src/app/api/upload/route.ts +18 -0
- package/src/app/api/uploads/[filename]/route.ts +59 -0
- package/src/app/api/usage/route.ts +35 -0
- package/src/app/api/version/route.ts +81 -0
- package/src/app/api/version/update/route.ts +95 -0
- package/src/app/api/webhooks/[id]/history/route.ts +13 -0
- package/src/app/api/webhooks/[id]/route.ts +204 -0
- package/src/app/api/webhooks/route.ts +37 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +370 -0
- package/src/app/layout.tsx +52 -0
- package/src/app/page.tsx +172 -0
- package/src/cli/index.js +1232 -0
- package/src/cli/index.test.js +281 -0
- package/src/cli/index.ts +1158 -0
- package/src/cli/spec.js +284 -0
- package/src/components/agents/agent-card.tsx +219 -0
- package/src/components/agents/agent-chat-list.tsx +165 -0
- package/src/components/agents/agent-list.tsx +110 -0
- package/src/components/agents/agent-sheet.tsx +1220 -0
- package/src/components/auth/access-key-gate.tsx +248 -0
- package/src/components/auth/setup-wizard.tsx +940 -0
- package/src/components/auth/user-picker.tsx +88 -0
- package/src/components/chat/chat-area.tsx +406 -0
- package/src/components/chat/chat-header.tsx +491 -0
- package/src/components/chat/chat-tool-toggles.tsx +161 -0
- package/src/components/chat/code-block.tsx +146 -0
- package/src/components/chat/dev-server-bar.tsx +39 -0
- package/src/components/chat/message-bubble.tsx +486 -0
- package/src/components/chat/message-list.tsx +299 -0
- package/src/components/chat/session-debug-panel.tsx +196 -0
- package/src/components/chat/streaming-bubble.tsx +85 -0
- package/src/components/chat/thinking-indicator.tsx +26 -0
- package/src/components/chat/tool-call-bubble.tsx +438 -0
- package/src/components/chat/tool-request-banner.tsx +103 -0
- package/src/components/connectors/connector-list.tsx +196 -0
- package/src/components/connectors/connector-sheet.tsx +804 -0
- package/src/components/input/chat-input.tsx +235 -0
- package/src/components/knowledge/knowledge-list.tsx +206 -0
- package/src/components/knowledge/knowledge-sheet.tsx +316 -0
- package/src/components/layout/app-layout.tsx +1016 -0
- package/src/components/layout/daemon-indicator.tsx +56 -0
- package/src/components/layout/mobile-header.tsx +31 -0
- package/src/components/layout/network-banner.tsx +17 -0
- package/src/components/layout/update-banner.tsx +130 -0
- package/src/components/logs/log-list.tsx +358 -0
- package/src/components/mcp-servers/mcp-server-list.tsx +122 -0
- package/src/components/mcp-servers/mcp-server-sheet.tsx +243 -0
- package/src/components/memory/memory-card.tsx +63 -0
- package/src/components/memory/memory-detail.tsx +339 -0
- package/src/components/memory/memory-list.tsx +198 -0
- package/src/components/memory/memory-sheet.tsx +70 -0
- package/src/components/plugins/plugin-list.tsx +60 -0
- package/src/components/plugins/plugin-sheet.tsx +311 -0
- package/src/components/providers/provider-list.tsx +96 -0
- package/src/components/providers/provider-sheet.tsx +542 -0
- package/src/components/runs/run-list.tsx +231 -0
- package/src/components/schedules/schedule-card.tsx +63 -0
- package/src/components/schedules/schedule-list.tsx +76 -0
- package/src/components/schedules/schedule-sheet.tsx +336 -0
- package/src/components/secrets/secret-sheet.tsx +180 -0
- package/src/components/secrets/secrets-list.tsx +91 -0
- package/src/components/sessions/new-session-sheet.tsx +478 -0
- package/src/components/sessions/session-card.tsx +144 -0
- package/src/components/sessions/session-list.tsx +202 -0
- package/src/components/shared/ai-gen-block.tsx +77 -0
- package/src/components/shared/avatar.tsx +48 -0
- package/src/components/shared/bottom-sheet.tsx +30 -0
- package/src/components/shared/confirm-dialog.tsx +47 -0
- package/src/components/shared/connector-platform-icon.tsx +113 -0
- package/src/components/shared/dir-browser.tsx +285 -0
- package/src/components/shared/dropdown.tsx +55 -0
- package/src/components/shared/icon-button.tsx +25 -0
- package/src/components/shared/settings/plugin-manager.tsx +207 -0
- package/src/components/shared/settings/section-capability-policy.tsx +93 -0
- package/src/components/shared/settings/section-embedding.tsx +99 -0
- package/src/components/shared/settings/section-heartbeat.tsx +168 -0
- package/src/components/shared/settings/section-memory.tsx +77 -0
- package/src/components/shared/settings/section-orchestrator.tsx +108 -0
- package/src/components/shared/settings/section-providers.tsx +181 -0
- package/src/components/shared/settings/section-runtime-loop.tsx +183 -0
- package/src/components/shared/settings/section-secrets.tsx +132 -0
- package/src/components/shared/settings/section-user-preferences.tsx +24 -0
- package/src/components/shared/settings/section-voice.tsx +53 -0
- package/src/components/shared/settings/settings-sheet.tsx +88 -0
- package/src/components/shared/settings/types.ts +7 -0
- package/src/components/shared/settings/utils.ts +13 -0
- package/src/components/shared/settings-sheet.tsx +1 -0
- package/src/components/shared/skeleton.tsx +19 -0
- package/src/components/shared/usage-badge.tsx +28 -0
- package/src/components/skills/clawhub-browser.tsx +225 -0
- package/src/components/skills/skill-list.tsx +70 -0
- package/src/components/skills/skill-sheet.tsx +254 -0
- package/src/components/tasks/task-board.tsx +96 -0
- package/src/components/tasks/task-card.tsx +179 -0
- package/src/components/tasks/task-column.tsx +73 -0
- package/src/components/tasks/task-list.tsx +118 -0
- package/src/components/tasks/task-sheet.tsx +415 -0
- package/src/components/ui/avatar.tsx +109 -0
- package/src/components/ui/badge.tsx +48 -0
- package/src/components/ui/button.tsx +64 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/dialog.tsx +158 -0
- package/src/components/ui/dropdown-menu.tsx +257 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/scroll-area.tsx +58 -0
- package/src/components/ui/select.tsx +190 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +143 -0
- package/src/components/ui/sonner.tsx +22 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +56 -0
- package/src/components/usage/usage-list.tsx +105 -0
- package/src/components/webhooks/webhook-list.tsx +166 -0
- package/src/components/webhooks/webhook-sheet.tsx +402 -0
- package/src/hooks/use-auto-resize.ts +20 -0
- package/src/hooks/use-media-query.ts +21 -0
- package/src/hooks/use-speech-recognition.ts +83 -0
- package/src/instrumentation.ts +8 -0
- package/src/lib/agents.ts +13 -0
- package/src/lib/api-client.ts +100 -0
- package/src/lib/chat.ts +60 -0
- package/src/lib/memory.ts +42 -0
- package/src/lib/openclaw-endpoint.test.ts +48 -0
- package/src/lib/openclaw-endpoint.ts +67 -0
- package/src/lib/provider-config.ts +13 -0
- package/src/lib/providers/anthropic.ts +135 -0
- package/src/lib/providers/claude-cli.ts +202 -0
- package/src/lib/providers/codex-cli.ts +260 -0
- package/src/lib/providers/index.ts +351 -0
- package/src/lib/providers/ollama.ts +131 -0
- package/src/lib/providers/openai.ts +164 -0
- package/src/lib/providers/openclaw.ts +330 -0
- package/src/lib/providers/opencode-cli.ts +164 -0
- package/src/lib/runtime-loop.ts +15 -0
- package/src/lib/schedule-dedupe.test.ts +84 -0
- package/src/lib/schedule-dedupe.ts +174 -0
- package/src/lib/schedule-name.ts +62 -0
- package/src/lib/schedules.ts +16 -0
- package/src/lib/server/agent-registry.ts +70 -0
- package/src/lib/server/api-routes.test.ts +362 -0
- package/src/lib/server/autonomy-contract.ts +200 -0
- package/src/lib/server/build-llm.ts +155 -0
- package/src/lib/server/capability-router.test.ts +21 -0
- package/src/lib/server/capability-router.ts +172 -0
- package/src/lib/server/chat-execution.ts +894 -0
- package/src/lib/server/clawhub-client.test.ts +161 -0
- package/src/lib/server/clawhub-client.ts +26 -0
- package/src/lib/server/connectors/connector-routing.test.ts +243 -0
- package/src/lib/server/connectors/discord.ts +116 -0
- package/src/lib/server/connectors/googlechat.ts +66 -0
- package/src/lib/server/connectors/manager.ts +559 -0
- package/src/lib/server/connectors/matrix.ts +78 -0
- package/src/lib/server/connectors/media.ts +149 -0
- package/src/lib/server/connectors/openclaw.test.ts +375 -0
- package/src/lib/server/connectors/openclaw.ts +1132 -0
- package/src/lib/server/connectors/signal.ts +183 -0
- package/src/lib/server/connectors/slack.ts +258 -0
- package/src/lib/server/connectors/teams.ts +94 -0
- package/src/lib/server/connectors/telegram.ts +221 -0
- package/src/lib/server/connectors/types.ts +62 -0
- package/src/lib/server/connectors/whatsapp.ts +349 -0
- package/src/lib/server/context-manager.ts +232 -0
- package/src/lib/server/cost.ts +31 -0
- package/src/lib/server/daemon-state.ts +354 -0
- package/src/lib/server/data-dir.ts +3 -0
- package/src/lib/server/embeddings.ts +111 -0
- package/src/lib/server/execution-log.ts +257 -0
- package/src/lib/server/gateway/protocol.test.ts +54 -0
- package/src/lib/server/gateway/protocol.ts +114 -0
- package/src/lib/server/heartbeat-service.ts +366 -0
- package/src/lib/server/knowledge-db.test.ts +441 -0
- package/src/lib/server/logger.ts +47 -0
- package/src/lib/server/main-agent-loop.ts +1017 -0
- package/src/lib/server/mcp-client.test.ts +342 -0
- package/src/lib/server/mcp-client.ts +130 -0
- package/src/lib/server/memory-db.ts +1078 -0
- package/src/lib/server/memory-graph.test.ts +153 -0
- package/src/lib/server/memory-graph.ts +138 -0
- package/src/lib/server/openclaw-health.ts +245 -0
- package/src/lib/server/orchestrator-lg.ts +431 -0
- package/src/lib/server/orchestrator.ts +364 -0
- package/src/lib/server/playwright-proxy.mjs +70 -0
- package/src/lib/server/plugins.ts +229 -0
- package/src/lib/server/process-manager.ts +327 -0
- package/src/lib/server/provider-health.ts +113 -0
- package/src/lib/server/queue.ts +859 -0
- package/src/lib/server/runtime-settings.ts +119 -0
- package/src/lib/server/scheduler.ts +196 -0
- package/src/lib/server/session-mailbox.ts +129 -0
- package/src/lib/server/session-run-manager.ts +512 -0
- package/src/lib/server/session-tools/connector.ts +124 -0
- package/src/lib/server/session-tools/context-mgmt.ts +103 -0
- package/src/lib/server/session-tools/context.ts +114 -0
- package/src/lib/server/session-tools/crud.ts +673 -0
- package/src/lib/server/session-tools/delegate.ts +708 -0
- package/src/lib/server/session-tools/file.ts +264 -0
- package/src/lib/server/session-tools/index.ts +164 -0
- package/src/lib/server/session-tools/memory.ts +230 -0
- package/src/lib/server/session-tools/session-info.ts +422 -0
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +166 -0
- package/src/lib/server/session-tools/shell.ts +171 -0
- package/src/lib/server/session-tools/web.ts +408 -0
- package/src/lib/server/session-tools.ts +9 -0
- package/src/lib/server/skills-normalize.ts +130 -0
- package/src/lib/server/storage-mcp.test.ts +161 -0
- package/src/lib/server/storage.ts +670 -0
- package/src/lib/server/stream-agent-chat.ts +571 -0
- package/src/lib/server/task-reports.ts +122 -0
- package/src/lib/server/task-result.ts +161 -0
- package/src/lib/server/task-validation.test.ts +27 -0
- package/src/lib/server/task-validation.ts +90 -0
- package/src/lib/server/tool-capability-policy.test.ts +58 -0
- package/src/lib/server/tool-capability-policy.ts +262 -0
- package/src/lib/sessions.ts +68 -0
- package/src/lib/tasks.ts +20 -0
- package/src/lib/tts.ts +42 -0
- package/src/lib/upload.ts +10 -0
- package/src/lib/utils.ts +6 -0
- package/src/proxy.ts +43 -0
- package/src/stores/use-app-store.ts +468 -0
- package/src/stores/use-chat-store.ts +323 -0
- package/src/types/index.ts +621 -0
- package/tsconfig.json +34 -0
package/next.config.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
|
|
4
|
+
function getGitSha(): string {
|
|
5
|
+
try {
|
|
6
|
+
return execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim()
|
|
7
|
+
} catch {
|
|
8
|
+
return 'unknown'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const nextConfig: NextConfig = {
|
|
13
|
+
output: 'standalone',
|
|
14
|
+
env: {
|
|
15
|
+
NEXT_PUBLIC_GIT_SHA: getGitSha(),
|
|
16
|
+
},
|
|
17
|
+
// Allow external network access
|
|
18
|
+
serverExternalPackages: [
|
|
19
|
+
'highlight.js', 'better-sqlite3',
|
|
20
|
+
'discord.js', '@discordjs/ws', '@discordjs/rest',
|
|
21
|
+
'grammy',
|
|
22
|
+
'@slack/bolt', '@slack/web-api', '@slack/socket-mode',
|
|
23
|
+
'@whiskeysockets/baileys',
|
|
24
|
+
'qrcode',
|
|
25
|
+
],
|
|
26
|
+
allowedDevOrigins: [
|
|
27
|
+
'localhost',
|
|
28
|
+
'127.0.0.1',
|
|
29
|
+
'0.0.0.0',
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default nextConfig;
|
package/package.json
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@swarmclawai/swarmclaw",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Self-hosted AI agent orchestration dashboard — manage LLM providers, orchestrate agent swarms, schedule tasks, and bridge agents to chat platforms.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/swarmclawai/swarmclaw.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"ai",
|
|
12
|
+
"agents",
|
|
13
|
+
"llm",
|
|
14
|
+
"orchestration",
|
|
15
|
+
"swarm",
|
|
16
|
+
"dashboard",
|
|
17
|
+
"self-hosted",
|
|
18
|
+
"chatbot"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=22.6.0"
|
|
22
|
+
},
|
|
23
|
+
"bin": {
|
|
24
|
+
"swarmclaw": "./bin/swarmclaw.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"bin/",
|
|
28
|
+
"src/",
|
|
29
|
+
"public/",
|
|
30
|
+
"next.config.ts",
|
|
31
|
+
"tsconfig.json",
|
|
32
|
+
"postcss.config.mjs",
|
|
33
|
+
"package.json"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"setup:easy": "node ./scripts/easy-setup.mjs",
|
|
37
|
+
"quickstart": "node ./scripts/easy-setup.mjs --start",
|
|
38
|
+
"quickstart:prod": "node ./scripts/easy-setup.mjs --prod",
|
|
39
|
+
"update:easy": "node ./scripts/easy-update.mjs",
|
|
40
|
+
"dev": "next dev --hostname 0.0.0.0 -p 3456",
|
|
41
|
+
"dev:webpack": "next dev --webpack --hostname 0.0.0.0 -p 3456",
|
|
42
|
+
"dev:clean": "rm -rf .next && next dev --hostname 0.0.0.0 -p 3456",
|
|
43
|
+
"build": "next build",
|
|
44
|
+
"build:ci": "NEXT_DISABLE_ESLINT=1 next build",
|
|
45
|
+
"start": "next start",
|
|
46
|
+
"start:standalone": "node .next/standalone/server.js",
|
|
47
|
+
"lint": "eslint",
|
|
48
|
+
"lint:fix": "eslint --fix",
|
|
49
|
+
"lint:baseline": "node ./scripts/lint-baseline.mjs check",
|
|
50
|
+
"lint:baseline:update": "node ./scripts/lint-baseline.mjs update",
|
|
51
|
+
"cli": "node ./bin/swarmclaw.js",
|
|
52
|
+
"test:cli": "node --test src/cli/index.test.js",
|
|
53
|
+
"test:openclaw": "tsx --test src/lib/server/connectors/openclaw.test.ts src/lib/openclaw-endpoint.test.ts src/lib/server/gateway/protocol.test.ts src/lib/server/tool-capability-policy.test.ts"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@huggingface/transformers": "^3.8.1",
|
|
57
|
+
"@langchain/anthropic": "^1.3.18",
|
|
58
|
+
"@langchain/core": "^1.1.26",
|
|
59
|
+
"@langchain/langgraph": "^1.1.5",
|
|
60
|
+
"@langchain/openai": "^1.2.8",
|
|
61
|
+
"@playwright/mcp": "^0.0.68",
|
|
62
|
+
"@slack/bolt": "^4.6.0",
|
|
63
|
+
"@whiskeysockets/baileys": "^7.0.0-rc.9",
|
|
64
|
+
"better-sqlite3": "^12.6.2",
|
|
65
|
+
"cheerio": "^1.2.0",
|
|
66
|
+
"class-variance-authority": "^0.7.1",
|
|
67
|
+
"clsx": "^2.1.1",
|
|
68
|
+
"commander": "^13.1.0",
|
|
69
|
+
"cron-parser": "^5.5.0",
|
|
70
|
+
"cronstrue": "^3.12.0",
|
|
71
|
+
"discord.js": "^14.25.1",
|
|
72
|
+
"grammy": "^1.40.0",
|
|
73
|
+
"highlight.js": "^11.11.1",
|
|
74
|
+
"lucide-react": "^0.574.0",
|
|
75
|
+
"next": "16.1.6",
|
|
76
|
+
"next-themes": "^0.4.6",
|
|
77
|
+
"openclaw": "^2026.2.26",
|
|
78
|
+
"qrcode": "^1.5.4",
|
|
79
|
+
"radix-ui": "^1.4.3",
|
|
80
|
+
"react": "19.2.3",
|
|
81
|
+
"react-dom": "19.2.3",
|
|
82
|
+
"react-markdown": "^10.1.0",
|
|
83
|
+
"rehype-highlight": "^7.0.2",
|
|
84
|
+
"remark-gfm": "^4.0.1",
|
|
85
|
+
"sonner": "^2.0.7",
|
|
86
|
+
"tailwind-merge": "^3.4.1",
|
|
87
|
+
"ws": "^8.19.0",
|
|
88
|
+
"zod": "^4.3.6",
|
|
89
|
+
"zustand": "^5.0.11"
|
|
90
|
+
},
|
|
91
|
+
"devDependencies": {
|
|
92
|
+
"@tailwindcss/postcss": "^4",
|
|
93
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
94
|
+
"@types/node": "^20",
|
|
95
|
+
"@types/qrcode": "^1.5.6",
|
|
96
|
+
"@types/react": "^19",
|
|
97
|
+
"@types/react-dom": "^19",
|
|
98
|
+
"@types/ws": "^8.18.1",
|
|
99
|
+
"eslint": "^9",
|
|
100
|
+
"eslint-config-next": "16.1.6",
|
|
101
|
+
"shadcn": "^3.8.5",
|
|
102
|
+
"tailwindcss": "^4",
|
|
103
|
+
"tsx": "^4.20.6",
|
|
104
|
+
"tw-animate-css": "^1.4.0",
|
|
105
|
+
"typescript": "^5"
|
|
106
|
+
},
|
|
107
|
+
"optionalDependencies": {
|
|
108
|
+
"botbuilder": "^4.23.3",
|
|
109
|
+
"googleapis": "^171.4.0",
|
|
110
|
+
"matrix-bot-sdk": "^0.8.0"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">SwarmClaw Lobster Avatar</title>
|
|
3
|
+
<desc id="desc">SwarmClaw org avatar using an OpenClaw-inspired lobster mark with swarm accents.</desc>
|
|
4
|
+
|
|
5
|
+
<defs>
|
|
6
|
+
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
7
|
+
<stop offset="0%" stop-color="#050B18"/>
|
|
8
|
+
<stop offset="100%" stop-color="#111827"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
<radialGradient id="glow" cx="50%" cy="38%" r="62%">
|
|
11
|
+
<stop offset="0%" stop-color="#22d3ee" stop-opacity="0.22"/>
|
|
12
|
+
<stop offset="100%" stop-color="#22d3ee" stop-opacity="0"/>
|
|
13
|
+
</radialGradient>
|
|
14
|
+
<linearGradient id="lobster-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
15
|
+
<stop offset="0%" stop-color="#ff6a5f"/>
|
|
16
|
+
<stop offset="100%" stop-color="#a41318"/>
|
|
17
|
+
</linearGradient>
|
|
18
|
+
<filter id="soft-shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
19
|
+
<feDropShadow dx="0" dy="16" stdDeviation="18" flood-color="#020617" flood-opacity="0.55"/>
|
|
20
|
+
</filter>
|
|
21
|
+
</defs>
|
|
22
|
+
|
|
23
|
+
<rect x="40" y="40" width="944" height="944" rx="216" fill="url(#bg)"/>
|
|
24
|
+
<rect x="40" y="40" width="944" height="944" rx="216" fill="url(#glow)"/>
|
|
25
|
+
<rect x="56" y="56" width="912" height="912" rx="200" fill="none" stroke="#334155" stroke-width="6"/>
|
|
26
|
+
|
|
27
|
+
<!-- swarm accents -->
|
|
28
|
+
<g stroke="#22d3ee" stroke-opacity="0.8" stroke-width="10" fill="none" stroke-linecap="round">
|
|
29
|
+
<path d="M182 286 C232 236, 314 224, 378 252"/>
|
|
30
|
+
<path d="M842 286 C792 236, 710 224, 646 252"/>
|
|
31
|
+
<path d="M202 760 C270 814, 350 826, 420 806"/>
|
|
32
|
+
<path d="M822 760 C754 814, 674 826, 604 806"/>
|
|
33
|
+
</g>
|
|
34
|
+
<g fill="#67e8f9">
|
|
35
|
+
<circle cx="172" cy="282" r="14"/>
|
|
36
|
+
<circle cx="852" cy="282" r="14"/>
|
|
37
|
+
<circle cx="198" cy="760" r="12"/>
|
|
38
|
+
<circle cx="826" cy="760" r="12"/>
|
|
39
|
+
</g>
|
|
40
|
+
|
|
41
|
+
<!-- OpenClaw-inspired lobster mark -->
|
|
42
|
+
<g transform="translate(152 156) scale(6)" filter="url(#soft-shadow)">
|
|
43
|
+
<!-- Body -->
|
|
44
|
+
<path d="M60 10 C30 10 15 35 15 55 C15 75 30 95 45 100 L45 110 L55 110 L55 100 C55 100 60 102 65 100 L65 110 L75 110 L75 100 C90 95 105 75 105 55 C105 35 90 10 60 10Z" fill="url(#lobster-gradient)"/>
|
|
45
|
+
<!-- Left Claw -->
|
|
46
|
+
<path d="M20 45 C5 40 0 50 5 60 C10 70 20 65 25 55 C28 48 25 45 20 45Z" fill="url(#lobster-gradient)"/>
|
|
47
|
+
<!-- Right Claw -->
|
|
48
|
+
<path d="M100 45 C115 40 120 50 115 60 C110 70 100 65 95 55 C92 48 95 45 100 45Z" fill="url(#lobster-gradient)"/>
|
|
49
|
+
<!-- Antenna -->
|
|
50
|
+
<path d="M45 15 Q35 5 30 8" stroke="#ff8b84" stroke-width="3" stroke-linecap="round"/>
|
|
51
|
+
<path d="M75 15 Q85 5 90 8" stroke="#ff8b84" stroke-width="3" stroke-linecap="round"/>
|
|
52
|
+
<!-- Eyes -->
|
|
53
|
+
<circle cx="45" cy="35" r="6" fill="#030712"/>
|
|
54
|
+
<circle cx="75" cy="35" r="6" fill="#030712"/>
|
|
55
|
+
<circle cx="46" cy="34" r="2.5" fill="#22d3ee"/>
|
|
56
|
+
<circle cx="76" cy="34" r="2.5" fill="#22d3ee"/>
|
|
57
|
+
</g>
|
|
58
|
+
</svg>
|
package/public/file.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
package/public/globe.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
package/public/next.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { loadAgents, saveAgents, deleteAgent } from '@/lib/server/storage'
|
|
3
|
+
import { normalizeProviderEndpoint } from '@/lib/openclaw-endpoint'
|
|
4
|
+
|
|
5
|
+
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
|
+
const { id } = await params
|
|
7
|
+
const body = await req.json()
|
|
8
|
+
const agents = loadAgents()
|
|
9
|
+
if (!agents[id]) return new NextResponse(null, { status: 404 })
|
|
10
|
+
|
|
11
|
+
Object.assign(agents[id], body, { updatedAt: Date.now() })
|
|
12
|
+
if (body.apiEndpoint !== undefined) {
|
|
13
|
+
agents[id].apiEndpoint = normalizeProviderEndpoint(
|
|
14
|
+
body.provider || agents[id].provider,
|
|
15
|
+
body.apiEndpoint,
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
delete (agents[id] as Record<string, unknown>).id // prevent id overwrite
|
|
19
|
+
agents[id].id = id
|
|
20
|
+
saveAgents(agents)
|
|
21
|
+
return NextResponse.json(agents[id])
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
25
|
+
const { id } = await params
|
|
26
|
+
const agents = loadAgents()
|
|
27
|
+
if (!agents[id]) return new NextResponse(null, { status: 404 })
|
|
28
|
+
deleteAgent(id)
|
|
29
|
+
return NextResponse.json('ok')
|
|
30
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import crypto from 'crypto'
|
|
3
|
+
import { loadAgents, saveAgents, loadSessions, saveSessions } from '@/lib/server/storage'
|
|
4
|
+
|
|
5
|
+
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
|
+
const { id: agentId } = await params
|
|
7
|
+
const agents = loadAgents()
|
|
8
|
+
const agent = agents[agentId]
|
|
9
|
+
if (!agent) {
|
|
10
|
+
return NextResponse.json({ error: 'Agent not found' }, { status: 404 })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const body = await req.json().catch(() => ({}))
|
|
14
|
+
const user = body.user || 'default'
|
|
15
|
+
const sessions = loadSessions()
|
|
16
|
+
|
|
17
|
+
// If agent already has a thread session that exists, return it
|
|
18
|
+
if (agent.threadSessionId && sessions[agent.threadSessionId]) {
|
|
19
|
+
return NextResponse.json(sessions[agent.threadSessionId])
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Check if an existing session is already linked to this agent as a thread
|
|
23
|
+
const existing = Object.values(sessions).find(
|
|
24
|
+
(s: Record<string, unknown>) => s.name === `agent-thread:${agentId}` && s.user === user
|
|
25
|
+
)
|
|
26
|
+
if (existing) {
|
|
27
|
+
agent.threadSessionId = (existing as Record<string, unknown>).id as string
|
|
28
|
+
agent.updatedAt = Date.now()
|
|
29
|
+
saveAgents(agents)
|
|
30
|
+
return NextResponse.json(existing)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Create a new thread session
|
|
34
|
+
const sessionId = `agent-thread-${agentId}-${crypto.randomBytes(4).toString('hex')}`
|
|
35
|
+
const now = Date.now()
|
|
36
|
+
const session = {
|
|
37
|
+
id: sessionId,
|
|
38
|
+
name: `agent-thread:${agentId}`,
|
|
39
|
+
cwd: process.cwd(),
|
|
40
|
+
user: user,
|
|
41
|
+
provider: agent.provider,
|
|
42
|
+
model: agent.model,
|
|
43
|
+
credentialId: agent.credentialId || null,
|
|
44
|
+
fallbackCredentialIds: agent.fallbackCredentialIds || [],
|
|
45
|
+
apiEndpoint: agent.apiEndpoint || null,
|
|
46
|
+
claudeSessionId: null,
|
|
47
|
+
messages: [],
|
|
48
|
+
createdAt: now,
|
|
49
|
+
lastActiveAt: now,
|
|
50
|
+
active: false,
|
|
51
|
+
sessionType: 'human' as const,
|
|
52
|
+
agentId,
|
|
53
|
+
tools: agent.tools || [],
|
|
54
|
+
heartbeatEnabled: agent.heartbeatEnabled || false,
|
|
55
|
+
heartbeatIntervalSec: agent.heartbeatIntervalSec || null,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
sessions[sessionId] = session as Record<string, unknown>
|
|
59
|
+
saveSessions(sessions)
|
|
60
|
+
|
|
61
|
+
agent.threadSessionId = sessionId
|
|
62
|
+
agent.updatedAt = Date.now()
|
|
63
|
+
saveAgents(agents)
|
|
64
|
+
|
|
65
|
+
return NextResponse.json(session)
|
|
66
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import { buildLLM } from '@/lib/server/build-llm'
|
|
4
|
+
|
|
5
|
+
const agentSchema = z.object({
|
|
6
|
+
name: z.string().describe('Short name for the agent'),
|
|
7
|
+
description: z.string().describe('One sentence describing what it does'),
|
|
8
|
+
systemPrompt: z.string().describe('Full system prompt — thorough and specific, at least 3-4 paragraphs'),
|
|
9
|
+
isOrchestrator: z.boolean().describe('True only if it needs to coordinate multiple sub-agents'),
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const GENERATE_PROMPT = `You are a agent generator. The user will describe an AI agent they want to create. Generate a complete agent definition.
|
|
13
|
+
|
|
14
|
+
Set isOrchestrator to true ONLY if the user describes something that needs to coordinate multiple sub-agents.
|
|
15
|
+
Make the systemPrompt detailed and actionable — at least 3-4 paragraphs. Include specific instructions about how the agent should behave, what it should focus on, and how it should format its responses.`
|
|
16
|
+
|
|
17
|
+
export async function POST(req: Request) {
|
|
18
|
+
const { prompt } = await req.json()
|
|
19
|
+
if (!prompt?.trim()) {
|
|
20
|
+
return NextResponse.json({ error: 'prompt is required' }, { status: 400 })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const { llm, provider } = await buildLLM()
|
|
25
|
+
const structured = provider === 'anthropic'
|
|
26
|
+
? llm.withStructuredOutput(agentSchema)
|
|
27
|
+
: (llm as any).withStructuredOutput(agentSchema, {
|
|
28
|
+
name: 'agent_definition',
|
|
29
|
+
method: 'functionCalling',
|
|
30
|
+
})
|
|
31
|
+
const result = await structured.invoke([
|
|
32
|
+
{ role: 'system' as const, content: GENERATE_PROMPT },
|
|
33
|
+
{ role: 'user' as const, content: prompt },
|
|
34
|
+
], { signal: AbortSignal.timeout(60_000) })
|
|
35
|
+
|
|
36
|
+
return NextResponse.json(result)
|
|
37
|
+
} catch (err: unknown) {
|
|
38
|
+
const message = err instanceof Error ? err.message : 'Generation failed'
|
|
39
|
+
console.error('[agent-generate] Error:', message)
|
|
40
|
+
return NextResponse.json({ error: message }, { status: 500 })
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import crypto from 'crypto'
|
|
3
|
+
import { loadAgents, saveAgents } from '@/lib/server/storage'
|
|
4
|
+
import { normalizeProviderEndpoint } from '@/lib/openclaw-endpoint'
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
return NextResponse.json(loadAgents())
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function POST(req: Request) {
|
|
11
|
+
const body = await req.json()
|
|
12
|
+
const id = crypto.randomBytes(4).toString('hex')
|
|
13
|
+
const now = Date.now()
|
|
14
|
+
const agents = loadAgents()
|
|
15
|
+
agents[id] = {
|
|
16
|
+
id,
|
|
17
|
+
name: body.name || 'Unnamed Agent',
|
|
18
|
+
description: body.description || '',
|
|
19
|
+
systemPrompt: body.systemPrompt || '',
|
|
20
|
+
provider: body.provider || 'claude-cli',
|
|
21
|
+
model: body.model || '',
|
|
22
|
+
credentialId: body.credentialId || null,
|
|
23
|
+
apiEndpoint: normalizeProviderEndpoint(body.provider || 'claude-cli', body.apiEndpoint || null),
|
|
24
|
+
isOrchestrator: body.isOrchestrator || false,
|
|
25
|
+
subAgentIds: body.subAgentIds || [],
|
|
26
|
+
tools: body.tools || [],
|
|
27
|
+
capabilities: body.capabilities || [],
|
|
28
|
+
createdAt: now,
|
|
29
|
+
updatedAt: now,
|
|
30
|
+
}
|
|
31
|
+
saveAgents(agents)
|
|
32
|
+
return NextResponse.json(agents[id])
|
|
33
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { validateAccessKey, getAccessKey, isFirstTimeSetup, markSetupComplete } from '@/lib/server/storage'
|
|
3
|
+
import { ensureDaemonStarted } from '@/lib/server/daemon-state'
|
|
4
|
+
|
|
5
|
+
/** GET /api/auth — check if this is a first-time setup (returns key for initial display) */
|
|
6
|
+
export async function GET() {
|
|
7
|
+
if (isFirstTimeSetup()) {
|
|
8
|
+
return NextResponse.json({ firstTime: true, key: getAccessKey() })
|
|
9
|
+
}
|
|
10
|
+
return NextResponse.json({ firstTime: false })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** POST /api/auth — validate an access key */
|
|
14
|
+
export async function POST(req: Request) {
|
|
15
|
+
const { key } = await req.json()
|
|
16
|
+
if (!key || !validateAccessKey(key)) {
|
|
17
|
+
return NextResponse.json({ error: 'Invalid access key' }, { status: 401 })
|
|
18
|
+
}
|
|
19
|
+
// If this was first-time setup, mark it as claimed
|
|
20
|
+
if (isFirstTimeSetup()) {
|
|
21
|
+
markSetupComplete()
|
|
22
|
+
}
|
|
23
|
+
ensureDaemonStarted('api/auth:post')
|
|
24
|
+
return NextResponse.json({ ok: true })
|
|
25
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import os from 'os'
|
|
5
|
+
|
|
6
|
+
/** GET /api/claude-skills — discover skills from ~/.claude/skills/ */
|
|
7
|
+
export async function GET() {
|
|
8
|
+
const skillsDir = path.join(os.homedir(), '.claude', 'skills')
|
|
9
|
+
const skills: { id: string; name: string; description: string }[] = []
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(skillsDir)) {
|
|
12
|
+
return NextResponse.json(skills)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
if (!entry.isDirectory()) continue
|
|
18
|
+
const skillMd = path.join(skillsDir, entry.name, 'SKILL.md')
|
|
19
|
+
if (!fs.existsSync(skillMd)) continue
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const content = fs.readFileSync(skillMd, 'utf8')
|
|
23
|
+
// Parse YAML frontmatter between --- markers
|
|
24
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/)
|
|
25
|
+
if (!match) continue
|
|
26
|
+
|
|
27
|
+
const frontmatter = match[1]
|
|
28
|
+
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m)
|
|
29
|
+
const descMatch = frontmatter.match(/^description:\s*(.+)$/m)
|
|
30
|
+
|
|
31
|
+
skills.push({
|
|
32
|
+
id: entry.name,
|
|
33
|
+
name: nameMatch?.[1]?.trim() || entry.name,
|
|
34
|
+
description: descMatch?.[1]?.trim() || '',
|
|
35
|
+
})
|
|
36
|
+
} catch {
|
|
37
|
+
// Skip malformed skill files
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return NextResponse.json(skills)
|
|
42
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import crypto from 'crypto'
|
|
3
|
+
import { loadSkills, saveSkills } from '@/lib/server/storage'
|
|
4
|
+
import { fetchSkillContent } from '@/lib/server/clawhub-client'
|
|
5
|
+
|
|
6
|
+
export async function POST(req: Request) {
|
|
7
|
+
const body = await req.json()
|
|
8
|
+
const { name, description, url, author, tags } = body
|
|
9
|
+
let { content } = body
|
|
10
|
+
|
|
11
|
+
if (!content) {
|
|
12
|
+
try {
|
|
13
|
+
content = await fetchSkillContent(url)
|
|
14
|
+
} catch (err: any) {
|
|
15
|
+
return NextResponse.json(
|
|
16
|
+
{ error: err.message || 'Failed to fetch skill content' },
|
|
17
|
+
{ status: 502 }
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const skills = loadSkills()
|
|
23
|
+
const id = crypto.randomBytes(4).toString('hex')
|
|
24
|
+
skills[id] = {
|
|
25
|
+
id,
|
|
26
|
+
name,
|
|
27
|
+
filename: `skill-${id}.md`,
|
|
28
|
+
content,
|
|
29
|
+
description: description || '',
|
|
30
|
+
sourceFormat: 'openclaw',
|
|
31
|
+
sourceUrl: url,
|
|
32
|
+
author: author || '',
|
|
33
|
+
tags: tags || [],
|
|
34
|
+
createdAt: Date.now(),
|
|
35
|
+
updatedAt: Date.now(),
|
|
36
|
+
}
|
|
37
|
+
saveSkills(skills)
|
|
38
|
+
return NextResponse.json(skills[id])
|
|
39
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { searchClawHub } from '@/lib/server/clawhub-client'
|
|
3
|
+
|
|
4
|
+
export async function GET(req: Request) {
|
|
5
|
+
const { searchParams } = new URL(req.url)
|
|
6
|
+
const q = searchParams.get('q') || ''
|
|
7
|
+
const page = parseInt(searchParams.get('page') || '1', 10)
|
|
8
|
+
const limit = parseInt(searchParams.get('limit') || '20', 10)
|
|
9
|
+
const results = await searchClawHub(q, page, limit)
|
|
10
|
+
return NextResponse.json(results)
|
|
11
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { loadConnectors, saveConnectors } from '@/lib/server/storage'
|
|
3
|
+
|
|
4
|
+
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
5
|
+
const { id } = await params
|
|
6
|
+
const connectors = loadConnectors()
|
|
7
|
+
const connector = connectors[id]
|
|
8
|
+
if (!connector) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
9
|
+
|
|
10
|
+
// Merge runtime status and QR code
|
|
11
|
+
try {
|
|
12
|
+
const { getConnectorStatus, getConnectorQR, isConnectorAuthenticated, hasConnectorCredentials } = await import('@/lib/server/connectors/manager')
|
|
13
|
+
connector.status = getConnectorStatus(id)
|
|
14
|
+
const qr = getConnectorQR(id)
|
|
15
|
+
if (qr) connector.qrDataUrl = qr
|
|
16
|
+
connector.authenticated = isConnectorAuthenticated(id)
|
|
17
|
+
connector.hasCredentials = hasConnectorCredentials(id)
|
|
18
|
+
} catch { /* ignore */ }
|
|
19
|
+
|
|
20
|
+
return NextResponse.json(connector)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
24
|
+
const { id } = await params
|
|
25
|
+
const body = await req.json()
|
|
26
|
+
const connectors = loadConnectors()
|
|
27
|
+
const connector = connectors[id]
|
|
28
|
+
if (!connector) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
29
|
+
|
|
30
|
+
// Handle start/stop/repair actions — these modify connector state internally,
|
|
31
|
+
// so re-read from storage after to avoid overwriting with stale data
|
|
32
|
+
if (body.action === 'start' || body.action === 'stop' || body.action === 'repair') {
|
|
33
|
+
try {
|
|
34
|
+
const manager = await import('@/lib/server/connectors/manager')
|
|
35
|
+
if (body.action === 'start') {
|
|
36
|
+
await manager.startConnector(id)
|
|
37
|
+
} else if (body.action === 'stop') {
|
|
38
|
+
await manager.stopConnector(id)
|
|
39
|
+
} else {
|
|
40
|
+
await manager.repairConnector(id)
|
|
41
|
+
}
|
|
42
|
+
} catch (err: any) {
|
|
43
|
+
// Re-read to get the error state saved by startConnector
|
|
44
|
+
const fresh = loadConnectors()
|
|
45
|
+
return NextResponse.json(fresh[id] || { error: err.message }, { status: 500 })
|
|
46
|
+
}
|
|
47
|
+
// Re-read the connector after manager modified it
|
|
48
|
+
const fresh = loadConnectors()
|
|
49
|
+
return NextResponse.json(fresh[id])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Regular update
|
|
53
|
+
if (body.name !== undefined) connector.name = body.name
|
|
54
|
+
if (body.agentId !== undefined) connector.agentId = body.agentId
|
|
55
|
+
if (body.credentialId !== undefined) connector.credentialId = body.credentialId
|
|
56
|
+
if (body.config !== undefined) connector.config = body.config
|
|
57
|
+
if (body.isEnabled !== undefined) connector.isEnabled = body.isEnabled
|
|
58
|
+
connector.updatedAt = Date.now()
|
|
59
|
+
|
|
60
|
+
connectors[id] = connector
|
|
61
|
+
saveConnectors(connectors)
|
|
62
|
+
return NextResponse.json(connector)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
66
|
+
const { id } = await params
|
|
67
|
+
const connectors = loadConnectors()
|
|
68
|
+
if (!connectors[id]) return NextResponse.json({ error: 'Not found' }, { status: 404 })
|
|
69
|
+
|
|
70
|
+
// Stop if running
|
|
71
|
+
try {
|
|
72
|
+
const { stopConnector } = await import('@/lib/server/connectors/manager')
|
|
73
|
+
await stopConnector(id)
|
|
74
|
+
} catch { /* ignore */ }
|
|
75
|
+
|
|
76
|
+
delete connectors[id]
|
|
77
|
+
saveConnectors(connectors)
|
|
78
|
+
return NextResponse.json({ ok: true })
|
|
79
|
+
}
|