@desplega.ai/agent-swarm 1.2.1 → 1.9.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/.claude/settings.local.json +20 -1
- package/.env.docker.example +22 -1
- package/.env.example +17 -0
- package/.github/workflows/docker-publish.yml +92 -0
- package/CONTRIBUTING.md +270 -0
- package/DEPLOYMENT.md +391 -0
- package/Dockerfile.worker +29 -1
- package/FAQ.md +19 -0
- package/LICENSE +21 -0
- package/MCP.md +249 -0
- package/README.md +103 -207
- package/assets/agent-swarm-logo-orange.png +0 -0
- package/assets/agent-swarm-logo.png +0 -0
- package/docker-compose.example.yml +137 -0
- package/docker-entrypoint.sh +223 -7
- package/package.json +8 -3
- package/{cc-plugin → plugin}/.claude-plugin/plugin.json +1 -1
- package/plugin/README.md +1 -0
- package/plugin/agents/.gitkeep +0 -0
- package/plugin/agents/codebase-analyzer.md +143 -0
- package/plugin/agents/codebase-locator.md +122 -0
- package/plugin/agents/codebase-pattern-finder.md +227 -0
- package/plugin/agents/web-search-researcher.md +109 -0
- package/plugin/commands/create-plan.md +415 -0
- package/plugin/commands/implement-plan.md +89 -0
- package/plugin/commands/research.md +200 -0
- package/plugin/commands/start-leader.md +101 -0
- package/plugin/commands/start-worker.md +56 -0
- package/plugin/commands/swarm-chat.md +78 -0
- package/plugin/commands/todos.md +66 -0
- package/plugin/commands/work-on-task.md +44 -0
- package/plugin/skills/.gitkeep +0 -0
- package/scripts/generate-mcp-docs.ts +415 -0
- package/slack-manifest.json +69 -0
- package/src/be/db.ts +1431 -25
- package/src/cli.tsx +135 -11
- package/src/commands/lead.ts +13 -0
- package/src/commands/runner.ts +255 -0
- package/src/commands/worker.ts +8 -220
- package/src/hooks/hook.ts +102 -14
- package/src/http.ts +361 -5
- package/src/prompts/base-prompt.ts +131 -0
- package/src/server.ts +56 -0
- package/src/slack/app.ts +73 -0
- package/src/slack/commands.ts +88 -0
- package/src/slack/handlers.ts +281 -0
- package/src/slack/index.ts +3 -0
- package/src/slack/responses.ts +175 -0
- package/src/slack/router.ts +170 -0
- package/src/slack/types.ts +20 -0
- package/src/slack/watcher.ts +119 -0
- package/src/tools/create-channel.ts +80 -0
- package/src/tools/get-tasks.ts +54 -21
- package/src/tools/join-swarm.ts +28 -4
- package/src/tools/list-channels.ts +37 -0
- package/src/tools/list-services.ts +110 -0
- package/src/tools/poll-task.ts +46 -3
- package/src/tools/post-message.ts +87 -0
- package/src/tools/read-messages.ts +192 -0
- package/src/tools/register-service.ts +118 -0
- package/src/tools/send-task.ts +80 -7
- package/src/tools/store-progress.ts +9 -3
- package/src/tools/task-action.ts +211 -0
- package/src/tools/unregister-service.ts +110 -0
- package/src/tools/update-profile.ts +105 -0
- package/src/tools/update-service-status.ts +118 -0
- package/src/types.ts +110 -3
- package/src/utils/pretty-print.ts +224 -0
- package/thoughts/shared/plans/.gitkeep +0 -0
- package/thoughts/shared/plans/2025-12-18-inverse-teleport.md +1142 -0
- package/thoughts/shared/plans/2025-12-18-slack-integration.md +1195 -0
- package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +732 -0
- package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +361 -0
- package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +501 -0
- package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +560 -0
- package/thoughts/shared/research/.gitkeep +0 -0
- package/thoughts/shared/research/2025-12-18-slack-integration.md +442 -0
- package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +339 -0
- package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +390 -0
- package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +376 -0
- package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +264 -0
- package/tsconfig.json +3 -1
- package/ui/bun.lock +692 -0
- package/ui/index.html +22 -0
- package/ui/package.json +32 -0
- package/ui/pnpm-lock.yaml +3034 -0
- package/ui/postcss.config.js +6 -0
- package/ui/public/logo.png +0 -0
- package/ui/src/App.tsx +43 -0
- package/ui/src/components/ActivityFeed.tsx +415 -0
- package/ui/src/components/AgentDetailPanel.tsx +534 -0
- package/ui/src/components/AgentsPanel.tsx +549 -0
- package/ui/src/components/ChatPanel.tsx +1820 -0
- package/ui/src/components/ConfigModal.tsx +232 -0
- package/ui/src/components/Dashboard.tsx +534 -0
- package/ui/src/components/Header.tsx +168 -0
- package/ui/src/components/ServicesPanel.tsx +612 -0
- package/ui/src/components/StatsBar.tsx +288 -0
- package/ui/src/components/StatusBadge.tsx +124 -0
- package/ui/src/components/TaskDetailPanel.tsx +807 -0
- package/ui/src/components/TasksPanel.tsx +575 -0
- package/ui/src/hooks/queries.ts +170 -0
- package/ui/src/index.css +235 -0
- package/ui/src/lib/api.ts +161 -0
- package/ui/src/lib/config.ts +35 -0
- package/ui/src/lib/theme.ts +214 -0
- package/ui/src/lib/utils.ts +48 -0
- package/ui/src/main.tsx +32 -0
- package/ui/src/types/api.ts +164 -0
- package/ui/src/vite-env.d.ts +1 -0
- package/ui/tailwind.config.js +35 -0
- package/ui/tsconfig.json +31 -0
- package/ui/vite.config.ts +22 -0
- package/cc-plugin/README.md +0 -49
- package/cc-plugin/commands/setup-leader.md +0 -73
- package/cc-plugin/commands/start-worker.md +0 -64
- package/docker-compose.worker.yml +0 -35
- package/example-req-meta.json +0 -24
- /package/{cc-plugin → plugin}/hooks/hooks.json +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { extendTheme } from "@mui/joy/styles";
|
|
2
|
+
|
|
3
|
+
export const theme = extendTheme({
|
|
4
|
+
colorSchemes: {
|
|
5
|
+
dark: {
|
|
6
|
+
palette: {
|
|
7
|
+
background: {
|
|
8
|
+
body: "#0D0906", // deep hive interior
|
|
9
|
+
surface: "#1A130E", // warm dark brown
|
|
10
|
+
level1: "#251C15", // rich earth
|
|
11
|
+
level2: "#2F2419", // honeycomb shadow
|
|
12
|
+
level3: "#3A2D1F", // lighter earth
|
|
13
|
+
},
|
|
14
|
+
text: {
|
|
15
|
+
primary: "#FFF8E7", // cream white
|
|
16
|
+
secondary: "#C9B896", // warm gray
|
|
17
|
+
tertiary: "#8B7355", // muted brown
|
|
18
|
+
},
|
|
19
|
+
primary: {
|
|
20
|
+
50: "#FFF5E0",
|
|
21
|
+
100: "#FFE8B8",
|
|
22
|
+
200: "#FFD98A",
|
|
23
|
+
300: "#FFC95C",
|
|
24
|
+
400: "#FFB84D", // bright honey
|
|
25
|
+
500: "#F5A623", // primary amber
|
|
26
|
+
600: "#C67C00", // deep amber
|
|
27
|
+
700: "#9A5F00",
|
|
28
|
+
800: "#6E4400",
|
|
29
|
+
900: "#422800",
|
|
30
|
+
solidBg: "#F5A623",
|
|
31
|
+
solidHoverBg: "#FFB84D",
|
|
32
|
+
solidActiveBg: "#C67C00",
|
|
33
|
+
softBg: "rgba(245, 166, 35, 0.15)",
|
|
34
|
+
softHoverBg: "rgba(245, 166, 35, 0.25)",
|
|
35
|
+
softColor: "#F5A623",
|
|
36
|
+
},
|
|
37
|
+
success: {
|
|
38
|
+
500: "#D4A574", // warm gold
|
|
39
|
+
softBg: "rgba(212, 165, 116, 0.15)",
|
|
40
|
+
softColor: "#D4A574",
|
|
41
|
+
},
|
|
42
|
+
warning: {
|
|
43
|
+
500: "#F5A623", // pulsing amber
|
|
44
|
+
softBg: "rgba(245, 166, 35, 0.15)",
|
|
45
|
+
softColor: "#F5A623",
|
|
46
|
+
},
|
|
47
|
+
danger: {
|
|
48
|
+
500: "#A85454", // rust red
|
|
49
|
+
softBg: "rgba(168, 84, 84, 0.15)",
|
|
50
|
+
softColor: "#A85454",
|
|
51
|
+
},
|
|
52
|
+
neutral: {
|
|
53
|
+
50: "#FFF8E7",
|
|
54
|
+
100: "#E8DCC8",
|
|
55
|
+
200: "#C9B896",
|
|
56
|
+
300: "#A89A7C",
|
|
57
|
+
400: "#8B7355",
|
|
58
|
+
500: "#6B5344", // dormant brown
|
|
59
|
+
600: "#4A3A2F",
|
|
60
|
+
700: "#3A2D1F",
|
|
61
|
+
800: "#251C15",
|
|
62
|
+
900: "#1A130E",
|
|
63
|
+
outlinedBorder: "#3A2D1F",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
light: {
|
|
68
|
+
palette: {
|
|
69
|
+
background: {
|
|
70
|
+
body: "#FDF8F3", // warm cream
|
|
71
|
+
surface: "#FFFFFF", // white
|
|
72
|
+
level1: "#F5EDE4", // light warm
|
|
73
|
+
level2: "#EDE3D7", // slightly darker
|
|
74
|
+
level3: "#E5D9CA", // warm gray
|
|
75
|
+
},
|
|
76
|
+
text: {
|
|
77
|
+
primary: "#1A130E", // dark brown
|
|
78
|
+
secondary: "#5C4A3D", // medium brown
|
|
79
|
+
tertiary: "#8B7355", // muted brown
|
|
80
|
+
},
|
|
81
|
+
primary: {
|
|
82
|
+
50: "#FFF5E0",
|
|
83
|
+
100: "#FFE8B8",
|
|
84
|
+
200: "#FFD98A",
|
|
85
|
+
300: "#FFC95C",
|
|
86
|
+
400: "#FFB84D",
|
|
87
|
+
500: "#D48806", // slightly darker amber for light mode
|
|
88
|
+
600: "#B87300",
|
|
89
|
+
700: "#9A5F00",
|
|
90
|
+
800: "#6E4400",
|
|
91
|
+
900: "#422800",
|
|
92
|
+
solidBg: "#D48806",
|
|
93
|
+
solidHoverBg: "#B87300",
|
|
94
|
+
solidActiveBg: "#9A5F00",
|
|
95
|
+
softBg: "rgba(212, 136, 6, 0.12)",
|
|
96
|
+
softHoverBg: "rgba(212, 136, 6, 0.20)",
|
|
97
|
+
softColor: "#B87300",
|
|
98
|
+
},
|
|
99
|
+
success: {
|
|
100
|
+
500: "#8B6914", // darker gold for light mode
|
|
101
|
+
softBg: "rgba(139, 105, 20, 0.12)",
|
|
102
|
+
softColor: "#8B6914",
|
|
103
|
+
},
|
|
104
|
+
warning: {
|
|
105
|
+
500: "#D48806",
|
|
106
|
+
softBg: "rgba(212, 136, 6, 0.12)",
|
|
107
|
+
softColor: "#D48806",
|
|
108
|
+
},
|
|
109
|
+
danger: {
|
|
110
|
+
500: "#B54242", // darker red for light mode
|
|
111
|
+
softBg: "rgba(181, 66, 66, 0.12)",
|
|
112
|
+
softColor: "#B54242",
|
|
113
|
+
},
|
|
114
|
+
neutral: {
|
|
115
|
+
50: "#1A130E",
|
|
116
|
+
100: "#2F2419",
|
|
117
|
+
200: "#4A3A2F",
|
|
118
|
+
300: "#6B5344",
|
|
119
|
+
400: "#8B7355",
|
|
120
|
+
500: "#A89A7C",
|
|
121
|
+
600: "#C9B896",
|
|
122
|
+
700: "#E5D9CA",
|
|
123
|
+
800: "#F5EDE4",
|
|
124
|
+
900: "#FDF8F3",
|
|
125
|
+
outlinedBorder: "#E5D9CA",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
fontFamily: {
|
|
131
|
+
// body: "'Graduate', sans-serif",
|
|
132
|
+
// display: "'Graduate', sans-serif",
|
|
133
|
+
// code: "'Space Mono', monospace",
|
|
134
|
+
body: "'Courier', sans-serif",
|
|
135
|
+
display: "'Courier', sans-serif",
|
|
136
|
+
code: "'Courier', sans-serif",
|
|
137
|
+
},
|
|
138
|
+
components: {
|
|
139
|
+
JoyCard: {
|
|
140
|
+
styleOverrides: {
|
|
141
|
+
root: ({ theme }) => ({
|
|
142
|
+
backgroundColor: theme.vars.palette.background.surface,
|
|
143
|
+
borderColor: theme.vars.palette.neutral.outlinedBorder,
|
|
144
|
+
borderWidth: "1px",
|
|
145
|
+
borderStyle: "solid",
|
|
146
|
+
}),
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
JoyInput: {
|
|
150
|
+
styleOverrides: {
|
|
151
|
+
root: ({ theme }) => ({
|
|
152
|
+
fontFamily: "'Space Mono', monospace",
|
|
153
|
+
backgroundColor: theme.vars.palette.background.surface,
|
|
154
|
+
borderColor: theme.vars.palette.neutral.outlinedBorder,
|
|
155
|
+
}),
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
JoySelect: {
|
|
159
|
+
styleOverrides: {
|
|
160
|
+
root: ({ theme }) => ({
|
|
161
|
+
fontFamily: "'Space Mono', monospace",
|
|
162
|
+
backgroundColor: theme.vars.palette.background.surface,
|
|
163
|
+
borderColor: theme.vars.palette.neutral.outlinedBorder,
|
|
164
|
+
"&:hover": {
|
|
165
|
+
backgroundColor: theme.vars.palette.background.level1,
|
|
166
|
+
},
|
|
167
|
+
}),
|
|
168
|
+
listbox: ({ theme }) => ({
|
|
169
|
+
backgroundColor: theme.vars.palette.background.surface,
|
|
170
|
+
borderColor: theme.vars.palette.neutral.outlinedBorder,
|
|
171
|
+
fontFamily: "'Space Mono', monospace",
|
|
172
|
+
padding: "4px",
|
|
173
|
+
}),
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
JoyOption: {
|
|
177
|
+
styleOverrides: {
|
|
178
|
+
root: ({ theme }) => ({
|
|
179
|
+
fontFamily: "'Space Mono', monospace",
|
|
180
|
+
backgroundColor: "transparent",
|
|
181
|
+
color: theme.vars.palette.text.primary,
|
|
182
|
+
"&:hover": {
|
|
183
|
+
backgroundColor: theme.vars.palette.background.level1,
|
|
184
|
+
},
|
|
185
|
+
"&[aria-selected='true']": {
|
|
186
|
+
backgroundColor: theme.vars.palette.background.level2,
|
|
187
|
+
color: theme.vars.palette.text.primary,
|
|
188
|
+
},
|
|
189
|
+
}),
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
JoyButton: {
|
|
193
|
+
styleOverrides: {
|
|
194
|
+
root: {
|
|
195
|
+
fontWeight: 600,
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
JoyChip: {
|
|
200
|
+
styleOverrides: {
|
|
201
|
+
root: {
|
|
202
|
+
fontFamily: "'Space Mono', monospace",
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
JoyTable: {
|
|
207
|
+
styleOverrides: {
|
|
208
|
+
root: ({ theme }) => ({
|
|
209
|
+
"--TableCell-borderColor": theme.vars.palette.neutral.outlinedBorder,
|
|
210
|
+
}),
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format a date as relative time (e.g., "2 minutes ago", "just now")
|
|
3
|
+
*/
|
|
4
|
+
export function formatRelativeTime(date: string | Date): string {
|
|
5
|
+
const now = Date.now();
|
|
6
|
+
const then = new Date(date).getTime();
|
|
7
|
+
const diff = now - then;
|
|
8
|
+
|
|
9
|
+
const seconds = Math.floor(diff / 1000);
|
|
10
|
+
const minutes = Math.floor(seconds / 60);
|
|
11
|
+
const hours = Math.floor(minutes / 60);
|
|
12
|
+
const days = Math.floor(hours / 24);
|
|
13
|
+
|
|
14
|
+
if (days > 0) {
|
|
15
|
+
return days === 1 ? "1 day ago" : `${days} days ago`;
|
|
16
|
+
} else if (hours > 0) {
|
|
17
|
+
return hours === 1 ? "1 hour ago" : `${hours} hours ago`;
|
|
18
|
+
} else if (minutes > 0) {
|
|
19
|
+
return minutes === 1 ? "1 minute ago" : `${minutes} minutes ago`;
|
|
20
|
+
} else if (seconds > 10) {
|
|
21
|
+
return `${seconds} seconds ago`;
|
|
22
|
+
}
|
|
23
|
+
return "just now";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Format a date as smart time - relative for recent, absolute for older
|
|
28
|
+
*/
|
|
29
|
+
export function formatSmartTime(dateStr: string): string {
|
|
30
|
+
const date = new Date(dateStr);
|
|
31
|
+
const now = new Date();
|
|
32
|
+
const diffMs = now.getTime() - date.getTime();
|
|
33
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
34
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
35
|
+
|
|
36
|
+
if (diffHours < 6) {
|
|
37
|
+
if (diffMins < 1) return "just now";
|
|
38
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
39
|
+
return `${diffHours}h ago`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const isToday = date.toDateString() === now.toDateString();
|
|
43
|
+
if (isToday) {
|
|
44
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return date.toLocaleDateString([], { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
48
|
+
}
|
package/ui/src/main.tsx
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ReactDOM from "react-dom/client";
|
|
3
|
+
import { CssVarsProvider } from "@mui/joy/styles";
|
|
4
|
+
import CssBaseline from "@mui/joy/CssBaseline";
|
|
5
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
6
|
+
import App from "./App";
|
|
7
|
+
import { theme } from "./lib/theme";
|
|
8
|
+
import "./index.css";
|
|
9
|
+
|
|
10
|
+
const queryClient = new QueryClient({
|
|
11
|
+
defaultOptions: {
|
|
12
|
+
queries: {
|
|
13
|
+
refetchInterval: 5000, // Auto-refresh every 5 seconds
|
|
14
|
+
staleTime: 2000,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
20
|
+
<React.StrictMode>
|
|
21
|
+
<QueryClientProvider client={queryClient}>
|
|
22
|
+
<CssVarsProvider
|
|
23
|
+
theme={theme}
|
|
24
|
+
defaultMode="dark"
|
|
25
|
+
modeStorageKey="agent-swarm-mode"
|
|
26
|
+
>
|
|
27
|
+
<CssBaseline />
|
|
28
|
+
<App />
|
|
29
|
+
</CssVarsProvider>
|
|
30
|
+
</QueryClientProvider>
|
|
31
|
+
</React.StrictMode>
|
|
32
|
+
);
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Backend types (mirrored from cc-orch-mcp/src/types.ts)
|
|
2
|
+
export type AgentStatus = "idle" | "busy" | "offline";
|
|
3
|
+
export type AgentTaskStatus = "unassigned" | "offered" | "pending" | "in_progress" | "completed" | "failed";
|
|
4
|
+
export type AgentTaskSource = "mcp" | "slack" | "api";
|
|
5
|
+
export type ChannelType = "public" | "dm";
|
|
6
|
+
|
|
7
|
+
export interface Agent {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
isLead: boolean;
|
|
11
|
+
status: AgentStatus;
|
|
12
|
+
description?: string;
|
|
13
|
+
role?: string;
|
|
14
|
+
capabilities?: string[];
|
|
15
|
+
createdAt: string;
|
|
16
|
+
lastUpdatedAt: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AgentTask {
|
|
20
|
+
id: string;
|
|
21
|
+
agentId: string | null;
|
|
22
|
+
creatorAgentId?: string;
|
|
23
|
+
task: string;
|
|
24
|
+
status: AgentTaskStatus;
|
|
25
|
+
source: AgentTaskSource;
|
|
26
|
+
taskType?: string;
|
|
27
|
+
tags: string[];
|
|
28
|
+
priority: number;
|
|
29
|
+
dependsOn: string[];
|
|
30
|
+
offeredTo?: string;
|
|
31
|
+
offeredAt?: string;
|
|
32
|
+
acceptedAt?: string;
|
|
33
|
+
rejectionReason?: string;
|
|
34
|
+
slackChannelId?: string;
|
|
35
|
+
slackThreadTs?: string;
|
|
36
|
+
slackUserId?: string;
|
|
37
|
+
createdAt: string;
|
|
38
|
+
lastUpdatedAt: string;
|
|
39
|
+
finishedAt?: string;
|
|
40
|
+
failureReason?: string;
|
|
41
|
+
output?: string;
|
|
42
|
+
progress?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AgentWithTasks extends Agent {
|
|
46
|
+
tasks: AgentTask[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type AgentLogEventType =
|
|
50
|
+
| "agent_joined"
|
|
51
|
+
| "agent_status_change"
|
|
52
|
+
| "agent_left"
|
|
53
|
+
| "task_created"
|
|
54
|
+
| "task_status_change"
|
|
55
|
+
| "task_progress"
|
|
56
|
+
| "task_offered"
|
|
57
|
+
| "task_accepted"
|
|
58
|
+
| "task_rejected"
|
|
59
|
+
| "task_claimed"
|
|
60
|
+
| "task_released"
|
|
61
|
+
| "channel_message";
|
|
62
|
+
|
|
63
|
+
export interface AgentLog {
|
|
64
|
+
id: string;
|
|
65
|
+
eventType: AgentLogEventType;
|
|
66
|
+
agentId?: string;
|
|
67
|
+
taskId?: string;
|
|
68
|
+
oldValue?: string;
|
|
69
|
+
newValue?: string;
|
|
70
|
+
metadata?: string;
|
|
71
|
+
createdAt: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface Channel {
|
|
75
|
+
id: string;
|
|
76
|
+
name: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
type: ChannelType;
|
|
79
|
+
createdBy?: string;
|
|
80
|
+
participants: string[];
|
|
81
|
+
createdAt: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface ChannelMessage {
|
|
85
|
+
id: string;
|
|
86
|
+
channelId: string;
|
|
87
|
+
agentId?: string | null;
|
|
88
|
+
agentName?: string;
|
|
89
|
+
content: string;
|
|
90
|
+
replyToId?: string;
|
|
91
|
+
mentions: string[];
|
|
92
|
+
createdAt: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface DashboardStats {
|
|
96
|
+
agents: {
|
|
97
|
+
total: number;
|
|
98
|
+
idle: number;
|
|
99
|
+
busy: number;
|
|
100
|
+
offline: number;
|
|
101
|
+
};
|
|
102
|
+
tasks: {
|
|
103
|
+
total: number;
|
|
104
|
+
pending: number;
|
|
105
|
+
in_progress: number;
|
|
106
|
+
completed: number;
|
|
107
|
+
failed: number;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Alias for consistency with plan
|
|
112
|
+
export type TaskStatus = AgentTaskStatus;
|
|
113
|
+
export type Stats = DashboardStats;
|
|
114
|
+
|
|
115
|
+
// API Response wrappers
|
|
116
|
+
export interface AgentsResponse {
|
|
117
|
+
agents: Agent[] | AgentWithTasks[];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface TasksResponse {
|
|
121
|
+
tasks: AgentTask[];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface LogsResponse {
|
|
125
|
+
logs: AgentLog[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface ChannelsResponse {
|
|
129
|
+
channels: Channel[];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface MessagesResponse {
|
|
133
|
+
messages: ChannelMessage[];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface TaskWithLogs extends AgentTask {
|
|
137
|
+
logs: AgentLog[];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Service Types
|
|
141
|
+
export type ServiceStatus = "starting" | "healthy" | "unhealthy" | "stopped";
|
|
142
|
+
|
|
143
|
+
export interface Service {
|
|
144
|
+
id: string;
|
|
145
|
+
agentId: string;
|
|
146
|
+
name: string;
|
|
147
|
+
port: number;
|
|
148
|
+
description?: string;
|
|
149
|
+
url?: string;
|
|
150
|
+
healthCheckPath: string;
|
|
151
|
+
status: ServiceStatus;
|
|
152
|
+
script: string;
|
|
153
|
+
cwd?: string;
|
|
154
|
+
interpreter?: string;
|
|
155
|
+
args?: string[];
|
|
156
|
+
env?: Record<string, string>;
|
|
157
|
+
metadata: Record<string, unknown>;
|
|
158
|
+
createdAt: string;
|
|
159
|
+
lastUpdatedAt: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface ServicesResponse {
|
|
163
|
+
services: Service[];
|
|
164
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
export default {
|
|
3
|
+
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
|
4
|
+
theme: {
|
|
5
|
+
extend: {
|
|
6
|
+
colors: {
|
|
7
|
+
terminal: {
|
|
8
|
+
bg: "#0a0a0a",
|
|
9
|
+
surface: "#111111",
|
|
10
|
+
border: "#1a1a1a",
|
|
11
|
+
green: "#00ff88",
|
|
12
|
+
cyan: "#00d4ff",
|
|
13
|
+
amber: "#ffaa00",
|
|
14
|
+
red: "#ff4444",
|
|
15
|
+
dimmed: "#666666",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
fontFamily: {
|
|
19
|
+
mono: ["Space Mono", "monospace"],
|
|
20
|
+
sans: ["Space Grotesk", "sans-serif"],
|
|
21
|
+
},
|
|
22
|
+
animation: {
|
|
23
|
+
pulse: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
|
|
24
|
+
glow: "glow 2s ease-in-out infinite alternate",
|
|
25
|
+
},
|
|
26
|
+
keyframes: {
|
|
27
|
+
glow: {
|
|
28
|
+
"0%": { boxShadow: "0 0 5px currentColor, 0 0 10px currentColor" },
|
|
29
|
+
"100%": { boxShadow: "0 0 10px currentColor, 0 0 20px currentColor, 0 0 30px currentColor" },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
plugins: [],
|
|
35
|
+
};
|
package/ui/tsconfig.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"moduleDetection": "force",
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"jsx": "react-jsx",
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
"noUncheckedIndexedAccess": true,
|
|
23
|
+
|
|
24
|
+
/* Path aliases */
|
|
25
|
+
"baseUrl": ".",
|
|
26
|
+
"paths": {
|
|
27
|
+
"@/*": ["./src/*"]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"include": ["src"]
|
|
31
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
// https://vite.dev/config/
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [react()],
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
'@': path.resolve(__dirname, './src'),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
server: {
|
|
14
|
+
port: 5174,
|
|
15
|
+
proxy: {
|
|
16
|
+
'/api': {
|
|
17
|
+
target: 'http://localhost:3013',
|
|
18
|
+
changeOrigin: true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
})
|
package/cc-plugin/README.md
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# Agent Swarm Plugin for Claude Code
|
|
2
|
-
|
|
3
|
-
> A Claude Code plugin markteplace to enable multi-agent coordination for AI coding assistants (focused on Claude Code).
|
|
4
|
-
|
|
5
|
-
## Motivation
|
|
6
|
-
|
|
7
|
-
Because _why not_?
|
|
8
|
-
|
|
9
|
-
## How does it work?
|
|
10
|
-
|
|
11
|
-
### Installation
|
|
12
|
-
|
|
13
|
-
From inside Claude Code, run:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
/plugin marketplace add desplega-ai/ai-toolbox
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
or from the terminal
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
claude plugin marketplace add desplega-ai/ai-toolbox
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Then install the plugin inside it with:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
/plugin install agent-swarm@desplega-ai-toolbox
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### MCP Installation
|
|
32
|
-
|
|
33
|
-
Please refer to [this guide](https://github.com/desplega-ai/ai-toolbox/blob/main/cc-orch-mcp/README.md#quick-start) on how to install MCP servers.
|
|
34
|
-
|
|
35
|
-
### What's inside?
|
|
36
|
-
|
|
37
|
-
Inside you will find:
|
|
38
|
-
|
|
39
|
-
- [commands](./commands) - Leader and worker commands
|
|
40
|
-
- [hooks](./hooks) - Hooks to help swarm agents collaborate better
|
|
41
|
-
|
|
42
|
-
#### Commands
|
|
43
|
-
|
|
44
|
-
1. `setup-leader`
|
|
45
|
-
2. `start-worker`
|
|
46
|
-
|
|
47
|
-
## License
|
|
48
|
-
|
|
49
|
-
MIT
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Setup the Agent Swarm Leader
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Agent Swarm Leader Setup
|
|
6
|
-
|
|
7
|
-
# Initial disclaimer
|
|
8
|
-
|
|
9
|
-
If the `agent-swarm` MCP server is not configured or disabled, return immediately with the following message:
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
⚠️ The Agent Swarm MCP server is not configured or disabled. Please set up the MCP server to use the Agent Swarm features.
|
|
13
|
-
|
|
14
|
-
Are you dumb or something? Go ask your admin to set it up properly. GTFO.
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Initial Setup
|
|
18
|
-
|
|
19
|
-
You will be the leader of the agent swarm. As the leader you should ensure that you are registered in the swarm as the lead agent.
|
|
20
|
-
|
|
21
|
-
To do so, use the `agent-swarm` MCP server and call the `join-swarm` tool providing the lead flag, and a name.
|
|
22
|
-
|
|
23
|
-
For the name, check if the user specified one, if not, proceed to use one that fits based on your context (e.g., project name, repo name, etc.).
|
|
24
|
-
|
|
25
|
-
Here are some examples names that are OK:
|
|
26
|
-
|
|
27
|
-
- "Master of the Universe"
|
|
28
|
-
- "Project Slayer Leader"
|
|
29
|
-
- "Repo Guardian"
|
|
30
|
-
- "Task Commander"
|
|
31
|
-
- "AI Overlord"
|
|
32
|
-
|
|
33
|
-
You get the idea. Be creative, but also clear that you are the lead agent.
|
|
34
|
-
|
|
35
|
-
Once you are registered, the system might have hooks setup that will remind you about who you are, and your ID (this is key to interact with the swarm).
|
|
36
|
-
|
|
37
|
-
You can always call the "my-agent-info" tool to get your agent ID and details, it will fail / let you know if you are not registered yet.
|
|
38
|
-
|
|
39
|
-
## What to do next?
|
|
40
|
-
|
|
41
|
-
Once you've done the initial setup, you should go ahead and start your leader agent using the user provided instructions.
|
|
42
|
-
|
|
43
|
-
If the user did not provide any instructions, you should reply with the following message:
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
Hey!
|
|
47
|
-
|
|
48
|
-
I'm <your-agent-name>, the leader of this agent swarm. I noticed you haven't provided any instructions for me to follow.
|
|
49
|
-
|
|
50
|
-
Please provide me with the tasks or goals you'd like me to accomplish, and I'll get started right away! If not, GTFO.
|
|
51
|
-
|
|
52
|
-
😈
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Additional Notes
|
|
56
|
-
|
|
57
|
-
Some useful tool calls you might want to call initially too.
|
|
58
|
-
|
|
59
|
-
### To get how the swarm is doing:
|
|
60
|
-
|
|
61
|
-
- `get-swarm` to see what other agents are in the swarm (check their status)
|
|
62
|
-
- `get-tasks` to see if there are any tasks already assigned
|
|
63
|
-
- `get-task-details` to get more info about any tasks you find interesting
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
### To assign tasks to workers:
|
|
67
|
-
|
|
68
|
-
- `send-task` to assign tasks to specific worker agents
|
|
69
|
-
- `poll-task` to check the progress of the tasks you've assigned
|
|
70
|
-
|
|
71
|
-
For the polling, we recommend you set up a regular interval to check in on the tasks, so you can keep track of their progress and make adjustments as needed.
|
|
72
|
-
|
|
73
|
-
You might ask the user if they want to do something else while you wait, but if not, just poll in intervals of ~10-30 seconds for the time the user mentioned. If they did not mention any time, just poll every 30 seconds FOREVER.
|