@swarmroom/server 0.1.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.
Files changed (61) hide show
  1. package/dist/__tests__/setup.d.ts +6 -0
  2. package/dist/__tests__/setup.js +88 -0
  3. package/dist/app.d.ts +3 -0
  4. package/dist/app.js +41 -0
  5. package/dist/db/index.d.ts +6 -0
  6. package/dist/db/index.js +62 -0
  7. package/dist/db/schema.d.ts +655 -0
  8. package/dist/db/schema.js +61 -0
  9. package/dist/db/seed.d.ts +1 -0
  10. package/dist/db/seed.js +15 -0
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +30 -0
  13. package/dist/lib/names.d.ts +1 -0
  14. package/dist/lib/names.js +32 -0
  15. package/dist/mcp/server.d.ts +2 -0
  16. package/dist/mcp/server.js +154 -0
  17. package/dist/mcp/transport.d.ts +2 -0
  18. package/dist/mcp/transport.js +27 -0
  19. package/dist/middleware/cors.d.ts +1 -0
  20. package/dist/middleware/cors.js +8 -0
  21. package/dist/middleware/error-handler.d.ts +2 -0
  22. package/dist/middleware/error-handler.js +10 -0
  23. package/dist/routes/__tests__/agents.test.d.ts +1 -0
  24. package/dist/routes/__tests__/agents.test.js +80 -0
  25. package/dist/routes/agents.d.ts +3 -0
  26. package/dist/routes/agents.js +100 -0
  27. package/dist/routes/health.d.ts +3 -0
  28. package/dist/routes/health.js +14 -0
  29. package/dist/routes/messages.d.ts +3 -0
  30. package/dist/routes/messages.js +65 -0
  31. package/dist/routes/projects.d.ts +3 -0
  32. package/dist/routes/projects.js +94 -0
  33. package/dist/routes/teams.d.ts +3 -0
  34. package/dist/routes/teams.js +94 -0
  35. package/dist/routes/well-known.d.ts +3 -0
  36. package/dist/routes/well-known.js +78 -0
  37. package/dist/routes/ws.d.ts +5 -0
  38. package/dist/routes/ws.js +19 -0
  39. package/dist/services/__tests__/agent-service.test.d.ts +1 -0
  40. package/dist/services/__tests__/agent-service.test.js +67 -0
  41. package/dist/services/__tests__/heartbeat-service.test.d.ts +1 -0
  42. package/dist/services/__tests__/heartbeat-service.test.js +76 -0
  43. package/dist/services/__tests__/message-service.test.d.ts +1 -0
  44. package/dist/services/__tests__/message-service.test.js +85 -0
  45. package/dist/services/agent-service.d.ts +74 -0
  46. package/dist/services/agent-service.js +131 -0
  47. package/dist/services/heartbeat-service.d.ts +2 -0
  48. package/dist/services/heartbeat-service.js +35 -0
  49. package/dist/services/mdns-browser.d.ts +2 -0
  50. package/dist/services/mdns-browser.js +53 -0
  51. package/dist/services/mdns-service.d.ts +2 -0
  52. package/dist/services/mdns-service.js +66 -0
  53. package/dist/services/message-service.d.ts +82 -0
  54. package/dist/services/message-service.js +172 -0
  55. package/dist/services/project-service.d.ts +130 -0
  56. package/dist/services/project-service.js +104 -0
  57. package/dist/services/team-service.d.ts +130 -0
  58. package/dist/services/team-service.js +104 -0
  59. package/dist/services/ws-manager.d.ts +19 -0
  60. package/dist/services/ws-manager.js +165 -0
  61. package/package.json +47 -0
@@ -0,0 +1,131 @@
1
+ import { eq, and, count, asc, desc, inArray } from 'drizzle-orm';
2
+ import { db, agents, agentTeams, agentProjects } from '../db/index.js';
3
+ import { generateDisplayName } from '../lib/names.js';
4
+ function resolveUniqueDisplayName(existingNames, candidate) {
5
+ if (!existingNames.includes(candidate)) {
6
+ return candidate;
7
+ }
8
+ let suffix = 1;
9
+ while (existingNames.includes(`${candidate}-${suffix}`)) {
10
+ suffix++;
11
+ }
12
+ return `${candidate}-${suffix}`;
13
+ }
14
+ export function createAgent(input) {
15
+ const id = crypto.randomUUID();
16
+ const now = Date.now();
17
+ const allAgents = db.select({ displayName: agents.displayName }).from(agents).all();
18
+ const existingNames = allAgents
19
+ .map((a) => a.displayName)
20
+ .filter((n) => n !== null);
21
+ const rawDisplayName = generateDisplayName();
22
+ const displayName = resolveUniqueDisplayName(existingNames, rawDisplayName);
23
+ db.insert(agents)
24
+ .values({
25
+ id,
26
+ name: input.name,
27
+ displayName,
28
+ url: input.url,
29
+ status: 'online',
30
+ agentCard: input.agentCard ? JSON.stringify(input.agentCard) : null,
31
+ lastHeartbeat: now,
32
+ createdAt: now,
33
+ updatedAt: now,
34
+ })
35
+ .run();
36
+ if (input.teamIds && input.teamIds.length > 0) {
37
+ for (const teamId of input.teamIds) {
38
+ db.insert(agentTeams).values({ agentId: id, teamId }).run();
39
+ }
40
+ }
41
+ return getAgentById(id);
42
+ }
43
+ export function listAgents(filters) {
44
+ const conditions = [];
45
+ if (filters?.status) {
46
+ conditions.push(eq(agents.status, filters.status));
47
+ }
48
+ if (filters?.teamId) {
49
+ const agentIdsInTeam = db
50
+ .select({ agentId: agentTeams.agentId })
51
+ .from(agentTeams)
52
+ .where(eq(agentTeams.teamId, filters.teamId))
53
+ .all()
54
+ .map((r) => r.agentId);
55
+ if (agentIdsInTeam.length === 0) {
56
+ return [];
57
+ }
58
+ conditions.push(inArray(agents.id, agentIdsInTeam));
59
+ }
60
+ if (filters?.projectId) {
61
+ const agentIdsInProject = db
62
+ .select({ agentId: agentProjects.agentId })
63
+ .from(agentProjects)
64
+ .where(eq(agentProjects.projectId, filters.projectId))
65
+ .all()
66
+ .map((r) => r.agentId);
67
+ if (agentIdsInProject.length === 0) {
68
+ return [];
69
+ }
70
+ conditions.push(inArray(agents.id, agentIdsInProject));
71
+ }
72
+ const query = db
73
+ .select()
74
+ .from(agents)
75
+ .orderBy(desc(agents.status), asc(agents.name));
76
+ if (conditions.length > 0) {
77
+ return query.where(and(...conditions)).all();
78
+ }
79
+ return query.all();
80
+ }
81
+ export function getAgentById(id) {
82
+ const agent = db.select().from(agents).where(eq(agents.id, id)).get();
83
+ if (!agent)
84
+ return null;
85
+ const teamRows = db
86
+ .select({ teamId: agentTeams.teamId })
87
+ .from(agentTeams)
88
+ .where(eq(agentTeams.agentId, id))
89
+ .all();
90
+ const projectRows = db
91
+ .select({ projectId: agentProjects.projectId })
92
+ .from(agentProjects)
93
+ .where(eq(agentProjects.agentId, id))
94
+ .all();
95
+ return {
96
+ ...agent,
97
+ agentCard: agent.agentCard ? JSON.parse(agent.agentCard) : null,
98
+ teamIds: teamRows.map((r) => r.teamId),
99
+ projectIds: projectRows.map((r) => r.projectId),
100
+ };
101
+ }
102
+ export function updateAgent(id, updates) {
103
+ const existing = db.select().from(agents).where(eq(agents.id, id)).get();
104
+ if (!existing)
105
+ return null;
106
+ const values = { updatedAt: Date.now() };
107
+ if (updates.name !== undefined)
108
+ values.name = updates.name;
109
+ if (updates.url !== undefined)
110
+ values.url = updates.url;
111
+ if (updates.status !== undefined)
112
+ values.status = updates.status;
113
+ if (updates.agentCard !== undefined)
114
+ values.agentCard = updates.agentCard;
115
+ db.update(agents).set(values).where(eq(agents.id, id)).run();
116
+ return getAgentById(id);
117
+ }
118
+ export function deregisterAgent(id) {
119
+ const existing = db.select().from(agents).where(eq(agents.id, id)).get();
120
+ if (!existing)
121
+ return null;
122
+ db.update(agents)
123
+ .set({ status: 'offline', updatedAt: Date.now() })
124
+ .where(eq(agents.id, id))
125
+ .run();
126
+ return getAgentById(id);
127
+ }
128
+ export function getAgentCount() {
129
+ const result = db.select({ value: count() }).from(agents).get();
130
+ return result?.value ?? 0;
131
+ }
@@ -0,0 +1,2 @@
1
+ export declare function startHeartbeatChecker(): void;
2
+ export declare function stopHeartbeatChecker(): void;
@@ -0,0 +1,35 @@
1
+ import { eq, lt, and, ne } from 'drizzle-orm';
2
+ import { db, agents } from '../db/index.js';
3
+ import { HEARTBEAT_INTERVAL_MS, STALE_TIMEOUT_MS } from '@swarmroom/shared';
4
+ import { broadcastAgentOffline } from './ws-manager.js';
5
+ let intervalId = null;
6
+ function markStaleAgentsOffline() {
7
+ const cutoff = Date.now() - STALE_TIMEOUT_MS;
8
+ const staleAgents = db
9
+ .select({ id: agents.id, name: agents.name, status: agents.status })
10
+ .from(agents)
11
+ .where(and(lt(agents.lastHeartbeat, cutoff), ne(agents.status, 'offline')))
12
+ .all();
13
+ for (const agent of staleAgents) {
14
+ console.log(`[heartbeat] Agent "${agent.name}" (${agent.id}) transitioned from "${agent.status}" to "offline" (stale heartbeat)`);
15
+ db.update(agents)
16
+ .set({ status: 'offline', updatedAt: Date.now() })
17
+ .where(eq(agents.id, agent.id))
18
+ .run();
19
+ broadcastAgentOffline({ id: agent.id, name: agent.name });
20
+ }
21
+ }
22
+ export function startHeartbeatChecker() {
23
+ if (intervalId !== null) {
24
+ return;
25
+ }
26
+ console.log(`[heartbeat] Starting stale agent checker (interval: ${HEARTBEAT_INTERVAL_MS}ms, timeout: ${STALE_TIMEOUT_MS}ms)`);
27
+ intervalId = setInterval(markStaleAgentsOffline, HEARTBEAT_INTERVAL_MS);
28
+ }
29
+ export function stopHeartbeatChecker() {
30
+ if (intervalId !== null) {
31
+ clearInterval(intervalId);
32
+ intervalId = null;
33
+ console.log('[heartbeat] Stopped stale agent checker');
34
+ }
35
+ }
@@ -0,0 +1,2 @@
1
+ export declare function startBrowsing(): void;
2
+ export declare function stopBrowsing(): void;
@@ -0,0 +1,53 @@
1
+ import { createSocket } from 'dgram';
2
+ import { MDNS_SERVICE_TYPE } from '@swarmroom/shared';
3
+ const MDNS_ADDRESS = '224.0.0.251';
4
+ const MDNS_PORT = 5353;
5
+ let socket = null;
6
+ let running = false;
7
+ export function startBrowsing() {
8
+ if (process.env.SWARMROOM_DISABLE_MDNS === 'true') {
9
+ return;
10
+ }
11
+ try {
12
+ socket = createSocket({ type: 'udp4', reuseAddr: true });
13
+ socket.on('message', (msg) => {
14
+ const content = msg.toString('utf8');
15
+ if (content.includes(MDNS_SERVICE_TYPE.replace(/^_/, '').replace(/\._tcp$/, ''))) {
16
+ console.log(`[mdns-browser] Detected ${MDNS_SERVICE_TYPE} service activity on the network`);
17
+ }
18
+ });
19
+ socket.on('error', (err) => {
20
+ console.warn('[mdns-browser] Socket error:', err.message);
21
+ stopBrowsing();
22
+ });
23
+ socket.bind(MDNS_PORT, () => {
24
+ try {
25
+ socket?.addMembership(MDNS_ADDRESS);
26
+ running = true;
27
+ console.log(`[mdns-browser] Browsing for ${MDNS_SERVICE_TYPE} services on the network`);
28
+ }
29
+ catch (error) {
30
+ console.warn('[mdns-browser] Failed to join multicast group:', error);
31
+ stopBrowsing();
32
+ }
33
+ });
34
+ }
35
+ catch (error) {
36
+ console.warn('[mdns-browser] Failed to start browsing — continuing without mDNS browsing:', error);
37
+ socket = null;
38
+ }
39
+ }
40
+ export function stopBrowsing() {
41
+ if (socket) {
42
+ try {
43
+ socket.close();
44
+ }
45
+ catch {
46
+ }
47
+ socket = null;
48
+ }
49
+ if (running) {
50
+ running = false;
51
+ console.log('[mdns-browser] Stopped browsing');
52
+ }
53
+ }
@@ -0,0 +1,2 @@
1
+ export declare function startMdns(port: number): Promise<void>;
2
+ export declare function stopMdns(): Promise<void>;
@@ -0,0 +1,66 @@
1
+ import { getResponder } from '@homebridge/ciao';
2
+ import { MDNS_SERVICE_TYPE } from '@swarmroom/shared';
3
+ import { networkInterfaces } from 'os';
4
+ let responder = null;
5
+ let service = null;
6
+ function getLocalIpAddress() {
7
+ const nets = networkInterfaces();
8
+ for (const name of Object.keys(nets)) {
9
+ const netInfos = nets[name];
10
+ if (!netInfos)
11
+ continue;
12
+ for (const net of netInfos) {
13
+ if (!net.internal && net.family === 'IPv4') {
14
+ return net.address;
15
+ }
16
+ }
17
+ }
18
+ return '127.0.0.1';
19
+ }
20
+ export async function startMdns(port) {
21
+ if (process.env.SWARMROOM_DISABLE_MDNS === 'true') {
22
+ console.log('[mdns] mDNS disabled via SWARMROOM_DISABLE_MDNS');
23
+ return;
24
+ }
25
+ try {
26
+ responder = getResponder();
27
+ const ip = getLocalIpAddress();
28
+ const serviceType = MDNS_SERVICE_TYPE.replace(/^_/, '').replace(/\._tcp$/, '');
29
+ service = responder.createService({
30
+ name: 'SwarmRoom Hub',
31
+ type: serviceType,
32
+ port,
33
+ txt: {
34
+ version: '0.1.0',
35
+ hub: 'true',
36
+ url: `http://${ip}:${port}`,
37
+ },
38
+ });
39
+ service.on('name-change', (newName) => {
40
+ console.log(`[mdns] Service name changed to "${newName}" (conflict resolution)`);
41
+ });
42
+ await service.advertise();
43
+ console.log(`[mdns] Advertising ${MDNS_SERVICE_TYPE} on port ${port} (url: http://${ip}:${port})`);
44
+ }
45
+ catch (error) {
46
+ console.warn('[mdns] Failed to start mDNS advertisement — continuing without mDNS:', error);
47
+ responder = null;
48
+ service = null;
49
+ }
50
+ }
51
+ export async function stopMdns() {
52
+ try {
53
+ if (service) {
54
+ await service.end();
55
+ service = null;
56
+ }
57
+ if (responder) {
58
+ await responder.shutdown();
59
+ responder = null;
60
+ }
61
+ console.log('[mdns] Stopped mDNS advertisement');
62
+ }
63
+ catch (error) {
64
+ console.warn('[mdns] Error stopping mDNS:', error);
65
+ }
66
+ }
@@ -0,0 +1,82 @@
1
+ import type { SendMessageRequest } from '@swarmroom/shared';
2
+ export declare function createMessage(input: SendMessageRequest): {
3
+ id: string;
4
+ from: string;
5
+ to: string;
6
+ senderType: string | null;
7
+ content: string;
8
+ type: string | null;
9
+ replyTo: string | undefined;
10
+ metadata: any;
11
+ read: boolean;
12
+ createdAt: number | null;
13
+ } | {
14
+ id: string;
15
+ from: string;
16
+ to: string;
17
+ senderType: string | null;
18
+ content: string;
19
+ type: string | null;
20
+ replyTo: string | undefined;
21
+ metadata: any;
22
+ read: boolean;
23
+ createdAt: number | null;
24
+ }[];
25
+ export declare function getMessagesForAgent(agentId: string, options?: {
26
+ since?: string;
27
+ limit?: number;
28
+ type?: string;
29
+ }): {
30
+ id: string;
31
+ from: string;
32
+ to: string;
33
+ senderType: string | null;
34
+ content: string;
35
+ type: string | null;
36
+ replyTo: string | undefined;
37
+ metadata: any;
38
+ read: boolean;
39
+ createdAt: number | null;
40
+ }[];
41
+ export declare function getMessageById(id: string): {
42
+ id: string;
43
+ from: string;
44
+ to: string;
45
+ senderType: string | null;
46
+ content: string;
47
+ type: string | null;
48
+ replyTo: string | undefined;
49
+ metadata: any;
50
+ read: boolean;
51
+ createdAt: number | null;
52
+ } | null;
53
+ export declare function markMessageAsRead(id: string): {
54
+ id: string;
55
+ from: string;
56
+ to: string;
57
+ senderType: string | null;
58
+ content: string;
59
+ type: string | null;
60
+ replyTo: string | undefined;
61
+ metadata: any;
62
+ read: boolean;
63
+ createdAt: number | null;
64
+ } | null;
65
+ export declare function getConversation(agentA: string, agentB: string, limit?: number): {
66
+ id: string;
67
+ from: string;
68
+ to: string;
69
+ senderType: string | null;
70
+ content: string;
71
+ type: string | null;
72
+ replyTo: string | undefined;
73
+ metadata: any;
74
+ read: boolean;
75
+ createdAt: number | null;
76
+ }[];
77
+ export declare class MessageSizeError extends Error {
78
+ constructor(message: string);
79
+ }
80
+ export declare class InvalidReplyError extends Error {
81
+ constructor(message: string);
82
+ }
@@ -0,0 +1,172 @@
1
+ import { eq, and, or, desc, asc, gt } from 'drizzle-orm';
2
+ import { db, messages, agents } from '../db/index.js';
3
+ import { MAX_MESSAGE_SIZE_BYTES } from '@swarmroom/shared';
4
+ import { pushMessageToRecipient, hasActiveConnections, sendToDaemons } from './ws-manager.js';
5
+ export function createMessage(input) {
6
+ const contentBytes = new TextEncoder().encode(input.content).length;
7
+ if (contentBytes > MAX_MESSAGE_SIZE_BYTES) {
8
+ throw new MessageSizeError(`Message content exceeds maximum size of ${MAX_MESSAGE_SIZE_BYTES} bytes (got ${contentBytes})`);
9
+ }
10
+ if (input.replyTo) {
11
+ const parent = db
12
+ .select({ id: messages.id })
13
+ .from(messages)
14
+ .where(eq(messages.id, input.replyTo))
15
+ .get();
16
+ if (!parent) {
17
+ throw new InvalidReplyError(`Parent message "${input.replyTo}" not found`);
18
+ }
19
+ }
20
+ const now = Date.now();
21
+ if (input.to === 'broadcast') {
22
+ const onlineAgents = db
23
+ .select({ id: agents.id })
24
+ .from(agents)
25
+ .where(eq(agents.status, 'online'))
26
+ .all();
27
+ const createdMessages = [];
28
+ for (const agent of onlineAgents) {
29
+ if (agent.id === input.from)
30
+ continue;
31
+ const id = crypto.randomUUID();
32
+ db.insert(messages)
33
+ .values({
34
+ id,
35
+ fromAgentId: input.from,
36
+ toAgentId: agent.id,
37
+ senderType: input.senderType ?? 'agent',
38
+ content: input.content,
39
+ type: input.type ?? 'notification',
40
+ replyTo: input.replyTo ?? null,
41
+ metadata: input.metadata ? JSON.stringify(input.metadata) : null,
42
+ read: 0,
43
+ createdAt: now,
44
+ })
45
+ .run();
46
+ createdMessages.push(getMessageById(id));
47
+ }
48
+ for (const msg of createdMessages) {
49
+ pushMessageToRecipient(msg.to, msg);
50
+ // Notify daemons if recipient has no active WebSocket connections
51
+ if (!hasActiveConnections(msg.to)) {
52
+ const recipient = db
53
+ .select({ name: agents.name })
54
+ .from(agents)
55
+ .where(eq(agents.id, msg.to))
56
+ .get();
57
+ if (recipient) {
58
+ sendToDaemons('message_undelivered', {
59
+ recipientAgentId: msg.to,
60
+ recipientAgentName: recipient.name,
61
+ message: msg,
62
+ });
63
+ }
64
+ }
65
+ }
66
+ return createdMessages;
67
+ }
68
+ const id = crypto.randomUUID();
69
+ db.insert(messages)
70
+ .values({
71
+ id,
72
+ fromAgentId: input.from,
73
+ toAgentId: input.to,
74
+ senderType: input.senderType ?? 'agent',
75
+ content: input.content,
76
+ type: input.type ?? 'notification',
77
+ replyTo: input.replyTo ?? null,
78
+ metadata: input.metadata ? JSON.stringify(input.metadata) : null,
79
+ read: 0,
80
+ createdAt: now,
81
+ })
82
+ .run();
83
+ const created = getMessageById(id);
84
+ pushMessageToRecipient(created.to, created);
85
+ if (!hasActiveConnections(created.to)) {
86
+ const recipient = db
87
+ .select({ name: agents.name })
88
+ .from(agents)
89
+ .where(eq(agents.id, created.to))
90
+ .get();
91
+ if (recipient) {
92
+ sendToDaemons('message_undelivered', {
93
+ recipientAgentId: created.to,
94
+ recipientAgentName: recipient.name,
95
+ message: created,
96
+ });
97
+ }
98
+ }
99
+ return created;
100
+ }
101
+ export function getMessagesForAgent(agentId, options) {
102
+ const conditions = [eq(messages.toAgentId, agentId)];
103
+ if (options?.since) {
104
+ const sinceTs = Number(options.since);
105
+ if (!Number.isNaN(sinceTs)) {
106
+ conditions.push(gt(messages.createdAt, sinceTs));
107
+ }
108
+ }
109
+ if (options?.type) {
110
+ conditions.push(eq(messages.type, options.type));
111
+ }
112
+ const limit = options?.limit ?? 50;
113
+ const rows = db
114
+ .select()
115
+ .from(messages)
116
+ .where(and(...conditions))
117
+ .orderBy(desc(messages.createdAt))
118
+ .limit(limit)
119
+ .all();
120
+ return rows.map(formatMessage);
121
+ }
122
+ export function getMessageById(id) {
123
+ const row = db.select().from(messages).where(eq(messages.id, id)).get();
124
+ if (!row)
125
+ return null;
126
+ return formatMessage(row);
127
+ }
128
+ export function markMessageAsRead(id) {
129
+ const existing = db.select().from(messages).where(eq(messages.id, id)).get();
130
+ if (!existing)
131
+ return null;
132
+ db.update(messages).set({ read: 1 }).where(eq(messages.id, id)).run();
133
+ return getMessageById(id);
134
+ }
135
+ export function getConversation(agentA, agentB, limit = 100) {
136
+ const rows = db
137
+ .select()
138
+ .from(messages)
139
+ .where(or(and(eq(messages.fromAgentId, agentA), eq(messages.toAgentId, agentB)), and(eq(messages.fromAgentId, agentB), eq(messages.toAgentId, agentA))))
140
+ .orderBy(asc(messages.createdAt))
141
+ .limit(limit)
142
+ .all();
143
+ return rows.map(formatMessage);
144
+ }
145
+ // ─── Helpers ────────────────────────────────────────────────────────────────
146
+ function formatMessage(row) {
147
+ return {
148
+ id: row.id,
149
+ from: row.fromAgentId,
150
+ to: row.toAgentId,
151
+ senderType: row.senderType,
152
+ content: row.content,
153
+ type: row.type,
154
+ replyTo: row.replyTo ?? undefined,
155
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
156
+ read: row.read === 1,
157
+ createdAt: row.createdAt,
158
+ };
159
+ }
160
+ // ─── Custom Errors ──────────────────────────────────────────────────────────
161
+ export class MessageSizeError extends Error {
162
+ constructor(message) {
163
+ super(message);
164
+ this.name = 'MessageSizeError';
165
+ }
166
+ }
167
+ export class InvalidReplyError extends Error {
168
+ constructor(message) {
169
+ super(message);
170
+ this.name = 'InvalidReplyError';
171
+ }
172
+ }
@@ -0,0 +1,130 @@
1
+ import type { CreateProjectRequest } from '@swarmroom/shared';
2
+ export declare function createProject(input: CreateProjectRequest & {
3
+ repository?: string;
4
+ }): {
5
+ agents: {
6
+ agentCard: any;
7
+ id: string;
8
+ name: string;
9
+ displayName: string | null;
10
+ url: string;
11
+ status: string | null;
12
+ lastHeartbeat: number | null;
13
+ createdAt: number | null;
14
+ updatedAt: number | null;
15
+ }[];
16
+ id: string;
17
+ name: string;
18
+ description: string | null;
19
+ repository: string | null;
20
+ createdAt: number | null;
21
+ } | null;
22
+ export declare function listProjects(): {
23
+ agentCount: number;
24
+ id: string;
25
+ name: string;
26
+ description: string | null;
27
+ repository: string | null;
28
+ createdAt: number | null;
29
+ }[];
30
+ export declare function getProjectById(id: string): {
31
+ agents: {
32
+ agentCard: any;
33
+ id: string;
34
+ name: string;
35
+ displayName: string | null;
36
+ url: string;
37
+ status: string | null;
38
+ lastHeartbeat: number | null;
39
+ createdAt: number | null;
40
+ updatedAt: number | null;
41
+ }[];
42
+ id: string;
43
+ name: string;
44
+ description: string | null;
45
+ repository: string | null;
46
+ createdAt: number | null;
47
+ } | null;
48
+ export declare function updateProject(id: string, updates: Partial<{
49
+ name: string;
50
+ description: string;
51
+ repository: string;
52
+ }>): {
53
+ agents: {
54
+ agentCard: any;
55
+ id: string;
56
+ name: string;
57
+ displayName: string | null;
58
+ url: string;
59
+ status: string | null;
60
+ lastHeartbeat: number | null;
61
+ createdAt: number | null;
62
+ updatedAt: number | null;
63
+ }[];
64
+ id: string;
65
+ name: string;
66
+ description: string | null;
67
+ repository: string | null;
68
+ createdAt: number | null;
69
+ } | null;
70
+ export declare function deleteProject(id: string): {
71
+ id: string;
72
+ name: string;
73
+ description: string | null;
74
+ repository: string | null;
75
+ createdAt: number | null;
76
+ } | null;
77
+ export declare function addAgentToProject(projectId: string, agentId: string): {
78
+ error: "project_not_found";
79
+ data?: undefined;
80
+ } | {
81
+ error: "agent_not_found";
82
+ data?: undefined;
83
+ } | {
84
+ data: {
85
+ agents: {
86
+ agentCard: any;
87
+ id: string;
88
+ name: string;
89
+ displayName: string | null;
90
+ url: string;
91
+ status: string | null;
92
+ lastHeartbeat: number | null;
93
+ createdAt: number | null;
94
+ updatedAt: number | null;
95
+ }[];
96
+ id: string;
97
+ name: string;
98
+ description: string | null;
99
+ repository: string | null;
100
+ createdAt: number | null;
101
+ } | null;
102
+ error?: undefined;
103
+ };
104
+ export declare function removeAgentFromProject(projectId: string, agentId: string): {
105
+ error: "project_not_found";
106
+ data?: undefined;
107
+ } | {
108
+ error: "not_a_member";
109
+ data?: undefined;
110
+ } | {
111
+ data: {
112
+ agents: {
113
+ agentCard: any;
114
+ id: string;
115
+ name: string;
116
+ displayName: string | null;
117
+ url: string;
118
+ status: string | null;
119
+ lastHeartbeat: number | null;
120
+ createdAt: number | null;
121
+ updatedAt: number | null;
122
+ }[];
123
+ id: string;
124
+ name: string;
125
+ description: string | null;
126
+ repository: string | null;
127
+ createdAt: number | null;
128
+ } | null;
129
+ error?: undefined;
130
+ };