@johpaz/hive 1.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.
- package/CONTRIBUTING.md +44 -0
- package/README.md +310 -0
- package/package.json +96 -0
- package/packages/cli/package.json +28 -0
- package/packages/cli/src/commands/agent-run.ts +168 -0
- package/packages/cli/src/commands/agents.ts +398 -0
- package/packages/cli/src/commands/chat.ts +142 -0
- package/packages/cli/src/commands/config.ts +50 -0
- package/packages/cli/src/commands/cron.ts +161 -0
- package/packages/cli/src/commands/dev.ts +95 -0
- package/packages/cli/src/commands/doctor.ts +133 -0
- package/packages/cli/src/commands/gateway.ts +443 -0
- package/packages/cli/src/commands/logs.ts +57 -0
- package/packages/cli/src/commands/mcp.ts +175 -0
- package/packages/cli/src/commands/message.ts +77 -0
- package/packages/cli/src/commands/onboard.ts +1868 -0
- package/packages/cli/src/commands/security.ts +144 -0
- package/packages/cli/src/commands/service.ts +50 -0
- package/packages/cli/src/commands/sessions.ts +116 -0
- package/packages/cli/src/commands/skills.ts +187 -0
- package/packages/cli/src/commands/update.ts +25 -0
- package/packages/cli/src/index.ts +185 -0
- package/packages/cli/src/utils/token.ts +6 -0
- package/packages/code-bridge/README.md +78 -0
- package/packages/code-bridge/package.json +18 -0
- package/packages/code-bridge/src/index.ts +95 -0
- package/packages/code-bridge/src/process-manager.ts +212 -0
- package/packages/code-bridge/src/schemas.ts +133 -0
- package/packages/core/package.json +46 -0
- package/packages/core/src/agent/agent-loop.ts +369 -0
- package/packages/core/src/agent/compaction.ts +140 -0
- package/packages/core/src/agent/context-compiler.ts +378 -0
- package/packages/core/src/agent/context-guard.ts +91 -0
- package/packages/core/src/agent/context.ts +138 -0
- package/packages/core/src/agent/conversation-store.ts +198 -0
- package/packages/core/src/agent/curator.ts +158 -0
- package/packages/core/src/agent/hooks.ts +166 -0
- package/packages/core/src/agent/index.ts +116 -0
- package/packages/core/src/agent/llm-client.ts +503 -0
- package/packages/core/src/agent/native-tools.ts +505 -0
- package/packages/core/src/agent/prompt-builder.ts +532 -0
- package/packages/core/src/agent/providers/index.ts +167 -0
- package/packages/core/src/agent/providers.ts +1 -0
- package/packages/core/src/agent/reflector.ts +170 -0
- package/packages/core/src/agent/service.ts +64 -0
- package/packages/core/src/agent/stuck-loop.ts +133 -0
- package/packages/core/src/agent/supervisor.ts +39 -0
- package/packages/core/src/agent/tracer.ts +102 -0
- package/packages/core/src/agent/workspace.ts +110 -0
- package/packages/core/src/canvas/canvas-manager.test.ts +161 -0
- package/packages/core/src/canvas/canvas-manager.ts +319 -0
- package/packages/core/src/canvas/canvas-tools.ts +420 -0
- package/packages/core/src/canvas/emitter.ts +115 -0
- package/packages/core/src/canvas/index.ts +2 -0
- package/packages/core/src/channels/base.ts +138 -0
- package/packages/core/src/channels/discord.ts +260 -0
- package/packages/core/src/channels/index.ts +7 -0
- package/packages/core/src/channels/manager.ts +383 -0
- package/packages/core/src/channels/slack.ts +287 -0
- package/packages/core/src/channels/telegram.ts +502 -0
- package/packages/core/src/channels/webchat.ts +128 -0
- package/packages/core/src/channels/whatsapp.ts +375 -0
- package/packages/core/src/config/index.ts +12 -0
- package/packages/core/src/config/loader.ts +529 -0
- package/packages/core/src/events/event-bus.ts +169 -0
- package/packages/core/src/gateway/index.ts +5 -0
- package/packages/core/src/gateway/initializer.ts +290 -0
- package/packages/core/src/gateway/lane-queue.ts +169 -0
- package/packages/core/src/gateway/resolver.ts +108 -0
- package/packages/core/src/gateway/router.ts +124 -0
- package/packages/core/src/gateway/server.ts +3317 -0
- package/packages/core/src/gateway/session.ts +95 -0
- package/packages/core/src/gateway/slash-commands.ts +192 -0
- package/packages/core/src/heartbeat/index.ts +157 -0
- package/packages/core/src/index.ts +19 -0
- package/packages/core/src/integrations/catalog.ts +286 -0
- package/packages/core/src/integrations/env.ts +64 -0
- package/packages/core/src/integrations/index.ts +2 -0
- package/packages/core/src/memory/index.ts +1 -0
- package/packages/core/src/memory/notes.ts +68 -0
- package/packages/core/src/plugins/api.ts +128 -0
- package/packages/core/src/plugins/index.ts +2 -0
- package/packages/core/src/plugins/loader.ts +365 -0
- package/packages/core/src/resilience/circuit-breaker.ts +225 -0
- package/packages/core/src/security/google-chat.ts +269 -0
- package/packages/core/src/security/index.ts +192 -0
- package/packages/core/src/security/pairing.ts +250 -0
- package/packages/core/src/security/rate-limit.ts +270 -0
- package/packages/core/src/security/signal.ts +321 -0
- package/packages/core/src/state/store.ts +312 -0
- package/packages/core/src/storage/bun-sqlite-store.ts +188 -0
- package/packages/core/src/storage/crypto.ts +101 -0
- package/packages/core/src/storage/db-context.ts +333 -0
- package/packages/core/src/storage/onboarding.ts +1087 -0
- package/packages/core/src/storage/schema.ts +541 -0
- package/packages/core/src/storage/seed.ts +571 -0
- package/packages/core/src/storage/sqlite.ts +387 -0
- package/packages/core/src/storage/usage.ts +212 -0
- package/packages/core/src/tools/bridge-events.ts +74 -0
- package/packages/core/src/tools/browser.ts +275 -0
- package/packages/core/src/tools/codebridge.ts +421 -0
- package/packages/core/src/tools/coordinator-tools.ts +179 -0
- package/packages/core/src/tools/cron.ts +611 -0
- package/packages/core/src/tools/exec.ts +140 -0
- package/packages/core/src/tools/fs.ts +364 -0
- package/packages/core/src/tools/index.ts +12 -0
- package/packages/core/src/tools/memory.ts +176 -0
- package/packages/core/src/tools/notify.ts +113 -0
- package/packages/core/src/tools/project-management.ts +376 -0
- package/packages/core/src/tools/project.ts +375 -0
- package/packages/core/src/tools/read.ts +158 -0
- package/packages/core/src/tools/web.ts +436 -0
- package/packages/core/src/tools/workspace.ts +171 -0
- package/packages/core/src/utils/benchmark.ts +80 -0
- package/packages/core/src/utils/crypto.ts +73 -0
- package/packages/core/src/utils/date.ts +42 -0
- package/packages/core/src/utils/index.ts +4 -0
- package/packages/core/src/utils/logger.ts +388 -0
- package/packages/core/src/utils/retry.ts +70 -0
- package/packages/core/src/voice/index.ts +583 -0
- package/packages/core/tsconfig.json +9 -0
- package/packages/mcp/package.json +26 -0
- package/packages/mcp/src/config.ts +13 -0
- package/packages/mcp/src/index.ts +1 -0
- package/packages/mcp/src/logger.ts +42 -0
- package/packages/mcp/src/manager.ts +434 -0
- package/packages/mcp/src/transports/index.ts +67 -0
- package/packages/mcp/src/transports/sse.ts +241 -0
- package/packages/mcp/src/transports/websocket.ts +159 -0
- package/packages/skills/package.json +21 -0
- package/packages/skills/src/bundled/agent_management/SKILL.md +24 -0
- package/packages/skills/src/bundled/browser_automation/SKILL.md +30 -0
- package/packages/skills/src/bundled/context_compact/SKILL.md +35 -0
- package/packages/skills/src/bundled/cron_manager/SKILL.md +52 -0
- package/packages/skills/src/bundled/file_manager/SKILL.md +76 -0
- package/packages/skills/src/bundled/http_client/SKILL.md +24 -0
- package/packages/skills/src/bundled/memory/SKILL.md +42 -0
- package/packages/skills/src/bundled/project_management/SKILL.md +26 -0
- package/packages/skills/src/bundled/shell/SKILL.md +43 -0
- package/packages/skills/src/bundled/system_notify/SKILL.md +52 -0
- package/packages/skills/src/bundled/voice/SKILL.md +25 -0
- package/packages/skills/src/bundled/web_search/SKILL.md +29 -0
- package/packages/skills/src/index.ts +1 -0
- package/packages/skills/src/loader.ts +282 -0
- package/packages/tools/package.json +43 -0
- package/packages/tools/src/browser/browser.test.ts +111 -0
- package/packages/tools/src/browser/index.ts +272 -0
- package/packages/tools/src/canvas/index.ts +220 -0
- package/packages/tools/src/cron/cron.test.ts +164 -0
- package/packages/tools/src/cron/index.ts +304 -0
- package/packages/tools/src/filesystem/filesystem.test.ts +240 -0
- package/packages/tools/src/filesystem/index.ts +379 -0
- package/packages/tools/src/git/index.ts +239 -0
- package/packages/tools/src/index.ts +4 -0
- package/packages/tools/src/shell/detect-env.ts +70 -0
- package/packages/tools/tsconfig.json +9 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
2
|
+
import { logger } from "../logger";
|
|
3
|
+
|
|
4
|
+
export interface SSETransportConfig {
|
|
5
|
+
url: string; // URL base
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class SSETransport implements Transport {
|
|
10
|
+
private baseUrl: string;
|
|
11
|
+
private messagesUrl: string | null = null; // Endpoint recibido del servidor
|
|
12
|
+
|
|
13
|
+
private headers: Record<string, string>;
|
|
14
|
+
private abortController: AbortController | null = null;
|
|
15
|
+
private cookies: string[] = [];
|
|
16
|
+
private startResolve: (() => void) | null = null;
|
|
17
|
+
private startReject: ((err: Error) => void) | null = null;
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
|
|
20
|
+
onmessage: ((message: unknown) => void) | undefined;
|
|
21
|
+
onerror: ((error: Error) => void) | undefined;
|
|
22
|
+
onclose: (() => void) | undefined;
|
|
23
|
+
|
|
24
|
+
constructor(config: SSETransportConfig) {
|
|
25
|
+
this.baseUrl = config.url;
|
|
26
|
+
this.headers = config.headers ?? {};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async start(): Promise<void> {
|
|
30
|
+
this.abortController = new AbortController();
|
|
31
|
+
|
|
32
|
+
return new Promise(async (resolve, reject) => {
|
|
33
|
+
// Timeout fallback: if no endpoint received in 5s, continue anyway
|
|
34
|
+
const timeout = setTimeout(() => {
|
|
35
|
+
this.startResolve = null;
|
|
36
|
+
this.startReject = null;
|
|
37
|
+
resolve();
|
|
38
|
+
}, 5000);
|
|
39
|
+
|
|
40
|
+
this.startResolve = () => {
|
|
41
|
+
clearTimeout(timeout);
|
|
42
|
+
this.startResolve = null;
|
|
43
|
+
this.startReject = null;
|
|
44
|
+
resolve();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
this.startReject = (err) => {
|
|
48
|
+
clearTimeout(timeout);
|
|
49
|
+
this.startResolve = null;
|
|
50
|
+
this.startReject = null;
|
|
51
|
+
reject(err);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
logger.debug(`[SSE] Connecting to: ${this.baseUrl}`);
|
|
56
|
+
const response = await fetch(this.baseUrl, {
|
|
57
|
+
method: "GET",
|
|
58
|
+
headers: {
|
|
59
|
+
"Accept": "application/json, text/event-stream",
|
|
60
|
+
"Cache-Control": "no-cache",
|
|
61
|
+
...this.headers,
|
|
62
|
+
},
|
|
63
|
+
signal: this.abortController!.signal,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (response.status === 405) {
|
|
67
|
+
logger.debug(`[SSE] GET not allowed (405), falling back to Streamable HTTP pattern for ${this.baseUrl}`);
|
|
68
|
+
this.startResolve();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
this.startReject(new Error(`MCP SSE connection failed: ${response.status} ${response.statusText}`));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.readSessionId(response);
|
|
78
|
+
|
|
79
|
+
if (response.body) {
|
|
80
|
+
this.startReading(response.body);
|
|
81
|
+
} else {
|
|
82
|
+
this.startResolve();
|
|
83
|
+
}
|
|
84
|
+
} catch (error: any) {
|
|
85
|
+
if (error.name !== "AbortError") {
|
|
86
|
+
this.startReject(error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private readSessionId(response: Response) {
|
|
93
|
+
const sessionId = response.headers.get("x-session-id") ??
|
|
94
|
+
response.headers.get("mcp-session-id");
|
|
95
|
+
if (sessionId) {
|
|
96
|
+
this.sessionId = sessionId;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Track cookies for session affinity (important for n8n/proxies)
|
|
100
|
+
const setCookie = response.headers.get("set-cookie");
|
|
101
|
+
if (setCookie) {
|
|
102
|
+
// Simple cookie extraction: just keep the keys and values
|
|
103
|
+
const newCookies = setCookie.split(',').map(c => c.split(';')[0].trim());
|
|
104
|
+
this.cookies = [...new Set([...this.cookies, ...newCookies])];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private startReading(stream: ReadableStream<Uint8Array>) {
|
|
109
|
+
const reader = stream.getReader();
|
|
110
|
+
const decoder = new TextDecoder();
|
|
111
|
+
let buffer = "";
|
|
112
|
+
|
|
113
|
+
this.processStream(reader, decoder, buffer).catch((error) => {
|
|
114
|
+
if (this.onerror && error.name !== "AbortError") {
|
|
115
|
+
this.onerror(error instanceof Error ? error : new Error(String(error)));
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private async processStream(
|
|
121
|
+
reader: ReadableStreamDefaultReader<Uint8Array>,
|
|
122
|
+
decoder: TextDecoder,
|
|
123
|
+
buffer: string
|
|
124
|
+
): Promise<void> {
|
|
125
|
+
try {
|
|
126
|
+
let eventType = "message";
|
|
127
|
+
let eventData = "";
|
|
128
|
+
|
|
129
|
+
while (true) {
|
|
130
|
+
const { done, value } = await reader.read();
|
|
131
|
+
|
|
132
|
+
if (done) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
buffer += decoder.decode(value, { stream: true });
|
|
137
|
+
|
|
138
|
+
const lines = buffer.split("\n");
|
|
139
|
+
buffer = lines.pop() ?? "";
|
|
140
|
+
|
|
141
|
+
for (const line of lines) {
|
|
142
|
+
if (line.startsWith("event: ")) {
|
|
143
|
+
eventType = line.slice(7).trim();
|
|
144
|
+
} else if (line.startsWith("data: ")) {
|
|
145
|
+
const data = line.slice(6);
|
|
146
|
+
if (data.trim() === "[DONE]") {
|
|
147
|
+
this.onclose?.();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
eventData += data + "\n";
|
|
151
|
+
} else if (line === "") {
|
|
152
|
+
if (eventData) {
|
|
153
|
+
eventData = eventData.trim();
|
|
154
|
+
if (eventType === "endpoint") {
|
|
155
|
+
try {
|
|
156
|
+
this.messagesUrl = new URL(eventData, this.baseUrl).href;
|
|
157
|
+
logger.debug(`[SSE] Messages endpoint received: ${this.messagesUrl}`);
|
|
158
|
+
this.startResolve?.();
|
|
159
|
+
} catch (e) {
|
|
160
|
+
logger.warn(`[SSE] Failed to parse endpoint: ${eventData}`);
|
|
161
|
+
}
|
|
162
|
+
} else if (eventType === "message" || eventType === "") {
|
|
163
|
+
try {
|
|
164
|
+
const parsed = JSON.parse(eventData);
|
|
165
|
+
this.onmessage?.(parsed);
|
|
166
|
+
} catch {
|
|
167
|
+
// Ignorar heartbeats o no-JSON
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
eventData = "";
|
|
171
|
+
}
|
|
172
|
+
eventType = "message";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
} catch (error: any) {
|
|
177
|
+
if (error.name !== "AbortError") {
|
|
178
|
+
this.onerror?.(error instanceof Error ? error : new Error(String(error)));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async close(): Promise<void> {
|
|
184
|
+
this.abortController?.abort();
|
|
185
|
+
this.abortController = null;
|
|
186
|
+
this.sessionId = undefined;
|
|
187
|
+
this.onclose?.();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async send(message: unknown): Promise<void> {
|
|
191
|
+
if (!this.abortController) {
|
|
192
|
+
throw new Error("SSE transport not started — llama start() primero");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const targetUrl = this.messagesUrl || this.baseUrl;
|
|
196
|
+
let url = targetUrl;
|
|
197
|
+
|
|
198
|
+
if (this.sessionId && !url.includes(`sessionId=${this.sessionId}`)) {
|
|
199
|
+
url = `${targetUrl}${targetUrl.includes('?') ? '&' : '?'}sessionId=${this.sessionId}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const response = await fetch(url, {
|
|
203
|
+
method: "POST",
|
|
204
|
+
headers: {
|
|
205
|
+
"Content-Type": "application/json",
|
|
206
|
+
"Accept": "application/json, text/event-stream",
|
|
207
|
+
...this.headers,
|
|
208
|
+
...(this.cookies.length > 0 ? { "Cookie": this.cookies.join('; ') } : {}),
|
|
209
|
+
},
|
|
210
|
+
body: JSON.stringify(message),
|
|
211
|
+
signal: this.abortController.signal,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
this.readSessionId(response);
|
|
215
|
+
|
|
216
|
+
if (!response.ok) {
|
|
217
|
+
const body = await response.text().catch(() => "");
|
|
218
|
+
throw new Error(`MCP message failed (${response.status}): ${body || response.statusText}`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
222
|
+
|
|
223
|
+
if (contentType.includes("text/event-stream") && response.body) {
|
|
224
|
+
this.startReading(response.body);
|
|
225
|
+
}
|
|
226
|
+
else if (contentType.includes("application/json")) {
|
|
227
|
+
const text = await response.text();
|
|
228
|
+
if (text.trim()) {
|
|
229
|
+
try {
|
|
230
|
+
this.onmessage?.(JSON.parse(text));
|
|
231
|
+
} catch {
|
|
232
|
+
// ignored
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export function createSSETransport(config: SSETransportConfig): Transport {
|
|
240
|
+
return new SSETransport(config) as unknown as Transport;
|
|
241
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
2
|
+
|
|
3
|
+
export interface WebSocketTransportConfig {
|
|
4
|
+
url: string;
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
reconnect?: boolean; // reconectar automáticamente si se cae (default: true)
|
|
7
|
+
reconnectDelay?: number; // ms entre intentos de reconexión (default: 3000)
|
|
8
|
+
reconnectMaxAttempts?: number; // máximo de intentos (default: 10)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class WebSocketTransport implements Transport {
|
|
12
|
+
private url: string;
|
|
13
|
+
private ws: WebSocket | null = null;
|
|
14
|
+
private headers?: Record<string, string>;
|
|
15
|
+
private intentionallyClosed = false; // distingue close() manual de caída
|
|
16
|
+
private reconnectAttempts = 0;
|
|
17
|
+
private reconnectDelay: number;
|
|
18
|
+
private reconnectMaxAttempts: number;
|
|
19
|
+
private shouldReconnect: boolean;
|
|
20
|
+
|
|
21
|
+
onmessage: ((message: unknown) => void) | undefined;
|
|
22
|
+
onerror: ((error: Error) => void) | undefined;
|
|
23
|
+
onclose: (() => void) | undefined;
|
|
24
|
+
|
|
25
|
+
constructor(config: WebSocketTransportConfig) {
|
|
26
|
+
this.url = config.url;
|
|
27
|
+
this.headers = config.headers;
|
|
28
|
+
this.shouldReconnect = config.reconnect ?? true;
|
|
29
|
+
this.reconnectDelay = config.reconnectDelay ?? 3000;
|
|
30
|
+
this.reconnectMaxAttempts = config.reconnectMaxAttempts ?? 10;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async start(): Promise<void> {
|
|
34
|
+
this.intentionallyClosed = false;
|
|
35
|
+
this.reconnectAttempts = 0;
|
|
36
|
+
return this.connect();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private connect(): Promise<void> {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
|
|
42
|
+
// CORRECCIÓN 1 — headers en Bun WebSocket
|
|
43
|
+
// Bun acepta las opciones como segundo argumento cuando no hay subprotocols,
|
|
44
|
+
// o como objeto con `headers` dentro de un array de subprotocols vacío.
|
|
45
|
+
// La forma más segura y compatible:
|
|
46
|
+
const ws = this.headers && Object.keys(this.headers).length > 0
|
|
47
|
+
? new WebSocket(this.url, {
|
|
48
|
+
// @ts-expect-error — Bun extiende la API estándar de WebSocket
|
|
49
|
+
headers: this.headers,
|
|
50
|
+
})
|
|
51
|
+
: new WebSocket(this.url);
|
|
52
|
+
|
|
53
|
+
this.ws = ws;
|
|
54
|
+
let resolved = false;
|
|
55
|
+
|
|
56
|
+
ws.onopen = () => {
|
|
57
|
+
resolved = true;
|
|
58
|
+
this.reconnectAttempts = 0; // reset contador al conectar exitosamente
|
|
59
|
+
resolve();
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
ws.onmessage = (event: MessageEvent) => {
|
|
63
|
+
try {
|
|
64
|
+
const data = JSON.parse(event.data as string);
|
|
65
|
+
this.onmessage?.(data);
|
|
66
|
+
} catch {
|
|
67
|
+
// Ignorar mensajes no-JSON (ping/pong, heartbeats)
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// CORRECCIÓN 2 — separar el error de conexión del error post-conexión
|
|
72
|
+
ws.onerror = (event: Event) => {
|
|
73
|
+
const error =
|
|
74
|
+
(event as ErrorEvent).error ??
|
|
75
|
+
new Error(`WebSocket error en ${this.url}`);
|
|
76
|
+
|
|
77
|
+
if (!resolved) {
|
|
78
|
+
// Error durante la conexión inicial → rechazar la promesa
|
|
79
|
+
reject(error);
|
|
80
|
+
} else {
|
|
81
|
+
// Error después de conectar → notificar sin rechazar
|
|
82
|
+
this.onerror?.(error instanceof Error ? error : new Error(String(error)));
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// CORRECCIÓN 3 — reconexión automática en cierre inesperado
|
|
87
|
+
ws.onclose = (event: CloseEvent) => {
|
|
88
|
+
this.ws = null;
|
|
89
|
+
|
|
90
|
+
if (this.intentionallyClosed) {
|
|
91
|
+
// Cierre manual con close() — notificar y no reconectar
|
|
92
|
+
this.onclose?.();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!resolved) {
|
|
97
|
+
// Cierre antes de que se abriera → rechazar la promesa
|
|
98
|
+
reject(new Error(
|
|
99
|
+
`WebSocket cerrado antes de conectar — code: ${event.code}, reason: ${event.reason}`
|
|
100
|
+
));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Cierre inesperado después de conectar
|
|
105
|
+
if (
|
|
106
|
+
this.shouldReconnect &&
|
|
107
|
+
this.reconnectAttempts < this.reconnectMaxAttempts
|
|
108
|
+
) {
|
|
109
|
+
this.reconnectAttempts++;
|
|
110
|
+
const delay = this.reconnectDelay * this.reconnectAttempts; // backoff lineal
|
|
111
|
+
|
|
112
|
+
setTimeout(async () => {
|
|
113
|
+
try {
|
|
114
|
+
await this.connect();
|
|
115
|
+
} catch (err) {
|
|
116
|
+
this.onerror?.(err instanceof Error ? err : new Error(String(err)));
|
|
117
|
+
this.onclose?.();
|
|
118
|
+
}
|
|
119
|
+
}, delay);
|
|
120
|
+
} else {
|
|
121
|
+
// Sin más intentos → notificar cierre definitivo
|
|
122
|
+
this.onerror?.(new Error(
|
|
123
|
+
`WebSocket desconectado después de ${this.reconnectAttempts} intentos — ${this.url}`
|
|
124
|
+
));
|
|
125
|
+
this.onclose?.();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async close(): Promise<void> {
|
|
132
|
+
this.intentionallyClosed = true; // marcar como cierre intencional
|
|
133
|
+
if (this.ws) {
|
|
134
|
+
// Código 1000 = cierre normal
|
|
135
|
+
this.ws.close(1000, "Client closed connection");
|
|
136
|
+
this.ws = null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async send(message: unknown): Promise<void> {
|
|
141
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
`WebSocket no está conectado — readyState: ${this.ws?.readyState ?? "null"}`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
this.ws.send(JSON.stringify(message));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Útil para health checks desde el MCP client
|
|
150
|
+
get isConnected(): boolean {
|
|
151
|
+
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function createWebSocketTransport(
|
|
156
|
+
config: WebSocketTransportConfig
|
|
157
|
+
): Transport {
|
|
158
|
+
return new WebSocketTransport(config) as unknown as Transport;
|
|
159
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@johpaz/hive-skills",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Hive Skills — Official bundled skills for Hive",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"files": [
|
|
9
|
+
"src/"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "bun test"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"js-yaml": "latest"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "latest",
|
|
19
|
+
"@types/bun": "latest"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent_management
|
|
3
|
+
description: "Create and manage specialized agents within the swarm"
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Hive Team
|
|
6
|
+
icon: "🤖"
|
|
7
|
+
category: agents
|
|
8
|
+
permissions:
|
|
9
|
+
- conversation_manage
|
|
10
|
+
dependencies: []
|
|
11
|
+
tools: [create_agent]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Agent Management Skill
|
|
15
|
+
|
|
16
|
+
Esta skill permite expandir las capacidades del enjambre creando nuevos agentes especializados para tareas específicas.
|
|
17
|
+
|
|
18
|
+
## Herramientas Disponibles
|
|
19
|
+
|
|
20
|
+
- `create_agent`: Crea un nuevo agente especializado con un propósito y capacidades definidas.
|
|
21
|
+
|
|
22
|
+
## Mejores Prácticas
|
|
23
|
+
- **Propósito Claro**: Define un propósito específico y conciso al crear un nuevo agente.
|
|
24
|
+
- **Delegación**: Usa nuevos agentes cuando una tarea sea lo suficientemente compleja para requerir un enfoque dedicado.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser_automation
|
|
3
|
+
description: "Full control of a web browser for automation and scraping"
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Hive Team
|
|
6
|
+
icon: "🌐"
|
|
7
|
+
category: system
|
|
8
|
+
permissions:
|
|
9
|
+
- browser_control
|
|
10
|
+
- conversation_manage
|
|
11
|
+
dependencies: []
|
|
12
|
+
tools: [browser_automation, browser_navigate, browser_fetch, browser_screenshot, browser_click, browser_type]
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Browser Automation Skill
|
|
16
|
+
|
|
17
|
+
Esta skill permite controlar un navegador real para realizar tareas complejas de automatización, captura de pantalla e interacción con aplicaciones web.
|
|
18
|
+
|
|
19
|
+
## Herramientas Disponibles
|
|
20
|
+
|
|
21
|
+
- `browser_navigate`: Navega a una URL específica.
|
|
22
|
+
- `browser_fetch`: Obtiene el contenido HTML o Markdown de la página actual.
|
|
23
|
+
- `browser_screenshot`: Toma una captura de pantalla de la página o de un elemento.
|
|
24
|
+
- `browser_click`: Haz clic en un elemento identificado por un selector CSS.
|
|
25
|
+
- `browser_type`: Escribe texto en un campo de entrada.
|
|
26
|
+
|
|
27
|
+
## Mejores Prácticas
|
|
28
|
+
- **Esperas**: Asegúrate de que la página haya cargado completamente antes de interactuar.
|
|
29
|
+
- **Selectores**: Usa selectores de CSS robustos e identificables.
|
|
30
|
+
- **Capturas**: Usa capturas de pantalla para verificar el estado visual de una página si hay errores.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context_compact
|
|
3
|
+
description: "Conversation history management and content summarization"
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Hive Team
|
|
6
|
+
icon: "📦"
|
|
7
|
+
category: system
|
|
8
|
+
permissions:
|
|
9
|
+
- conversation_manage
|
|
10
|
+
dependencies: []
|
|
11
|
+
tools: [context_compact]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Context Compact Skill
|
|
15
|
+
|
|
16
|
+
Esta skill gestiona la memoria a corto plazo del agente, resumiendo conversaciones largas para mantener el rendimiento y la relevancia sin perder el hilo de la charla.
|
|
17
|
+
|
|
18
|
+
## Funcionamiento Automático
|
|
19
|
+
|
|
20
|
+
A diferencia de otras skills, `context_compact` no proporciona herramientas (tools) manuales para el agente. Es una **capacidad intrínseca del sistema** que se activa automáticamente cuando el historial de mensajes alcanza un umbral crítico de tokens.
|
|
21
|
+
|
|
22
|
+
El motor de compactación:
|
|
23
|
+
1. Analiza el historial de mensajes cuando excede el límite configurado.
|
|
24
|
+
2. Genera un resumen interactivo de los temas claves.
|
|
25
|
+
3. Preserva las respuestas más recientes y las llamadas a herramientas que aún esperan resultado.
|
|
26
|
+
4. Sustituye los mensajes antiguos por el resumen para liberar espacio en el contexto.
|
|
27
|
+
|
|
28
|
+
## Interacción del Agente
|
|
29
|
+
|
|
30
|
+
El agente no necesita invocar ninguna tool para "compactar". Si el sistema detecta saturación, realizará el proceso de forma transparente antes de la siguiente respuesta del modelo.
|
|
31
|
+
|
|
32
|
+
## Beneficios
|
|
33
|
+
- **Velocidad**: Reduce la latencia de respuesta en conversaciones largas.
|
|
34
|
+
- **Rendimiento**: Menor consumo de tokens de entrada.
|
|
35
|
+
- **Limpieza**: Enfoca la atención del modelo en la tarea actual actual.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cron_manager
|
|
3
|
+
description: "Schedule and manage automated tasks using cron expressions"
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Hive Team
|
|
6
|
+
icon: "⏰"
|
|
7
|
+
category: system
|
|
8
|
+
permissions:
|
|
9
|
+
- cron_manage
|
|
10
|
+
dependencies: []
|
|
11
|
+
tools: [cron_manager, cron_add, cron_list, cron_edit, cron_remove]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Cron Manager Skill
|
|
15
|
+
|
|
16
|
+
Esta skill permite al agente programar y gestionar tareas automatizadas que se ejecutan periódicamente.
|
|
17
|
+
|
|
18
|
+
## Herramientas Disponibles
|
|
19
|
+
|
|
20
|
+
- `cron_add`: Añade una nueva tarea programada.
|
|
21
|
+
- `cron_list`: Lista todas las tareas programadas actualmente.
|
|
22
|
+
- `cron_edit`: Edita una tarea existente (cambia la expresión cron o la tarea).
|
|
23
|
+
- `cron_remove`: Elimina una tarea programada por su ID.
|
|
24
|
+
|
|
25
|
+
## Formato de Expresión Cron
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
┌───────────── minuto (0 - 59)
|
|
29
|
+
│ ┌───────────── hora (0 - 23)
|
|
30
|
+
│ │ ┌───────────── día del mes (1 - 31)
|
|
31
|
+
│ │ │ ┌───────────── mes (1 - 12)
|
|
32
|
+
│ │ │ │ ┌───────────── día de la semana (0 - 6) (Domingo = 0)
|
|
33
|
+
│ │ │ │ │
|
|
34
|
+
* * * * *
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Ejemplos de Uso
|
|
38
|
+
|
|
39
|
+
### Programar un informe diario
|
|
40
|
+
```javascript
|
|
41
|
+
cron_add({ expression: "0 9 * * *", task: "Enviar resumen diario de actividades" })
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Listar tareas para obtener el ID
|
|
45
|
+
```javascript
|
|
46
|
+
cron_list({})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Mejores Prácticas
|
|
50
|
+
- Usa expresiones cron descriptivas.
|
|
51
|
+
- Verifica siempre que la tarea programada sea clara para evitar ejecuciones inesperadas.
|
|
52
|
+
- Limpia las tareas viejas que ya no sean necesarias.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: file_manager
|
|
3
|
+
description: "Read, write, and manage files in the workspace"
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Hive Team
|
|
6
|
+
icon: "📁"
|
|
7
|
+
category: tools
|
|
8
|
+
permissions:
|
|
9
|
+
- filesystem_read
|
|
10
|
+
- filesystem_write
|
|
11
|
+
dependencies: []
|
|
12
|
+
tools: [file_manager, read, write, edit, fs_read, fs_write, fs_list, fs_mkdir, fs_delete, fs_copy, fs_move, project_read, project_write, project_list, workspace_read, workspace_write, workspace_patch, workspace_append]
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# File Manager Skill
|
|
16
|
+
|
|
17
|
+
Esta skill permite al agente gestionar archivos y directorios en el espacio de trabajo, incluyendo herramientas específicas para proyectos y configuración del sistema.
|
|
18
|
+
|
|
19
|
+
## Herramientas Disponibles
|
|
20
|
+
|
|
21
|
+
### Gestión de Archivos (Básico)
|
|
22
|
+
- `read`: Lee el contenido de un archivo (con soporte para `offset` y `limit`).
|
|
23
|
+
- `write`: Crea o sobrescribe un archivo.
|
|
24
|
+
- `edit`: Realiza ediciones específicas reemplazando cadenas de texto.
|
|
25
|
+
|
|
26
|
+
### Sistema de Archivos Avanzado (`fs_*`)
|
|
27
|
+
- `fs_read`: Lee un archivo del sistema de archivos.
|
|
28
|
+
- `fs_write`: Escribe contenido en un archivo.
|
|
29
|
+
- `fs_list`: Lista el contenido de un directorio (soporta recursividad).
|
|
30
|
+
- `fs_mkdir`: Crea directorios.
|
|
31
|
+
- `fs_delete`: Elimina archivos o directorios.
|
|
32
|
+
- `fs_copy`: Copia archivos.
|
|
33
|
+
- `fs_move`: Mueve o renombra archivos.
|
|
34
|
+
|
|
35
|
+
### Gestión de Proyecto (`project_*`)
|
|
36
|
+
- `project_read`: Lee archivos relativos a la ruta del proyecto.
|
|
37
|
+
- `project_write`: Escribe archivos en el proyecto.
|
|
38
|
+
- `project_edit`: Edita secciones de archivos del proyecto.
|
|
39
|
+
- `project_list`: Explora la estructura del proyecto.
|
|
40
|
+
- `project_glob`: Busca archivos usando patrones glob (ej: `**/*.ts`).
|
|
41
|
+
- `project_exists`: Verifica la existencia de archivos/directorios.
|
|
42
|
+
|
|
43
|
+
### Espacio de Trabajo (`workspace_*`)
|
|
44
|
+
- `workspace_read`: Consulta archivos de identidad (`soul`), usuario (`user`) o ética (`ethics`).
|
|
45
|
+
- `workspace_write`: Reescribe archivos de configuración.
|
|
46
|
+
- `workspace_patch`: Modifica secciones específicas de archivos Markdown.
|
|
47
|
+
- `workspace_append`: Añade información a secciones existentes.
|
|
48
|
+
|
|
49
|
+
## Ejemplo de Uso
|
|
50
|
+
|
|
51
|
+
### Lectura de Archivo con Líneas
|
|
52
|
+
```javascript
|
|
53
|
+
read({ path: "src/main.ts", offset: 1, limit: 100 })
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Búsqueda de Archivos
|
|
57
|
+
```javascript
|
|
58
|
+
project_glob({ pattern: "packages/**/*.json" })
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Actualización de Perfil de Usuario
|
|
62
|
+
```javascript
|
|
63
|
+
workspace_patch({
|
|
64
|
+
file: "user",
|
|
65
|
+
section: "Preferencias",
|
|
66
|
+
newContent: "Tema: oscuro",
|
|
67
|
+
reason: "Usuario cambió preferencia"
|
|
68
|
+
})
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Mejores Prácticas
|
|
72
|
+
|
|
73
|
+
- **Lectura Previa**: Siempre lee un archivo antes de editarlo para entender su estructura.
|
|
74
|
+
- **Paginación**: Usa `offset` y `limit` en archivos grandes para evitar saturar el contexto.
|
|
75
|
+
- **Rutas Relativas**: Prefiere herramientas de `project` para manipular archivos del código fuente.
|
|
76
|
+
- **Workspace**: Usa `workspace_patch` en lugar de `workspace_write` para cambios pequeños.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: http_client
|
|
3
|
+
description: "Fetch web content and interact with external APIs"
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: Hive Team
|
|
6
|
+
icon: "🌐"
|
|
7
|
+
category: tools
|
|
8
|
+
permissions:
|
|
9
|
+
- internet_access
|
|
10
|
+
dependencies: []
|
|
11
|
+
tools: [http_client, web_fetch]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# HTTP Client Skill
|
|
15
|
+
|
|
16
|
+
Esta skill permite al agente descargar contenido de la web o interactuar con APIs externas.
|
|
17
|
+
|
|
18
|
+
## Herramientas Disponibles
|
|
19
|
+
|
|
20
|
+
- `web_fetch`: Descarga el contenido de una URL (HTML convertido a Markdown para fácil lectura por el agente).
|
|
21
|
+
|
|
22
|
+
## Mejores Prácticas
|
|
23
|
+
- **Validación**: Verifica siempre que la URL sea correcta y segura.
|
|
24
|
+
- **Sintetización**: Extrae solo la información relevante del contenido descargado para no exceder el límite de contexto.
|