@johpaz/hive-cli 1.0.8 → 1.0.10
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/package.json +5 -5
- package/src/commands/agent-run.ts +180 -0
- package/src/commands/gateway.ts +1 -1
- package/src/commands/message.ts +90 -0
- package/src/commands/onboard.ts +2 -2
- package/src/index.ts +15 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johpaz/hive-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Hive CLI — Command line interface for the Hive AI Gateway",
|
|
5
5
|
"bin": {
|
|
6
6
|
"hive": "src/index.ts"
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
"test": "bun test"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@clack/prompts": "^
|
|
18
|
-
"@johpaz/hive-core": "^1.0.
|
|
19
|
-
"@johpaz/hive-orchestrator": "
|
|
17
|
+
"@clack/prompts": "^",
|
|
18
|
+
"@johpaz/hive-core": "^1.0.10",
|
|
19
|
+
"@johpaz/hive-orchestrator": "^1.0.10",
|
|
20
20
|
"js-yaml": "latest"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"typescript": "latest",
|
|
24
24
|
"@types/bun": "latest"
|
|
25
25
|
}
|
|
26
|
-
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as yaml from "js-yaml";
|
|
5
|
+
|
|
6
|
+
const HIVE_DIR = path.join(process.env.HOME || "", ".hive");
|
|
7
|
+
const CONFIG_PATH = path.join(HIVE_DIR, "hive.yaml");
|
|
8
|
+
|
|
9
|
+
function loadConfig(): Record<string, unknown> | null {
|
|
10
|
+
if (!fs.existsSync(CONFIG_PATH)) return null;
|
|
11
|
+
|
|
12
|
+
const content = fs.readFileSync(CONFIG_PATH, "utf-8");
|
|
13
|
+
return yaml.load(content) as Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getGatewayUrl(config: Record<string, unknown> | null): string {
|
|
17
|
+
const gateway = config?.gateway as Record<string, unknown> | undefined;
|
|
18
|
+
const host = (gateway?.host as string) ?? "localhost";
|
|
19
|
+
const port = (gateway?.port as number) ?? 3000;
|
|
20
|
+
return `http://${host}:${port}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function agent(subcommand: string | undefined, args: string[]): Promise<void> {
|
|
24
|
+
switch (subcommand) {
|
|
25
|
+
case "run":
|
|
26
|
+
await agentRun(args);
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
console.log(`
|
|
30
|
+
Usage: hive agent <command>
|
|
31
|
+
|
|
32
|
+
Commands:
|
|
33
|
+
run --message <text> Ejecutar agente con mensaje
|
|
34
|
+
run --thinking <level> Nivel de razonamiento (low/medium/high)
|
|
35
|
+
run --wait Esperar respuesta completa
|
|
36
|
+
`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function agentRun(args: string[]): Promise<void> {
|
|
41
|
+
const messageIndex = args.indexOf("--message");
|
|
42
|
+
const thinkingIndex = args.indexOf("--thinking");
|
|
43
|
+
const toolsIndex = args.indexOf("--tools");
|
|
44
|
+
const agentIndex = args.indexOf("--agent");
|
|
45
|
+
const waitIndex = args.indexOf("--wait");
|
|
46
|
+
|
|
47
|
+
if (messageIndex === -1) {
|
|
48
|
+
const msg = await p.text({
|
|
49
|
+
message: "Mensaje para el agente:",
|
|
50
|
+
placeholder: "Analiza el archivo README.md",
|
|
51
|
+
validate: (v) => (!v ? "El mensaje es requerido" : undefined),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (p.isCancel(msg)) {
|
|
55
|
+
p.cancel("Cancelado");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
args.push("--message", msg as string);
|
|
60
|
+
return agentRun(args);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const message = args[messageIndex + 1];
|
|
64
|
+
const thinking = thinkingIndex !== -1 ? args[thinkingIndex + 1] : "medium";
|
|
65
|
+
const tools = toolsIndex !== -1 ? args[toolsIndex + 1] : "all";
|
|
66
|
+
const agentId = agentIndex !== -1 ? args[agentIndex + 1] : "main";
|
|
67
|
+
const wait = waitIndex !== -1;
|
|
68
|
+
|
|
69
|
+
if (!message) {
|
|
70
|
+
console.log("❌ Mensaje requerido");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const config = loadConfig();
|
|
75
|
+
const gatewayUrl = getGatewayUrl(config);
|
|
76
|
+
|
|
77
|
+
const spinner = p.spinner();
|
|
78
|
+
spinner.start("Conectando con el agente...");
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
if (wait) {
|
|
82
|
+
await executeWithStream(gatewayUrl, { message, thinking, tools, agentId }, spinner);
|
|
83
|
+
} else {
|
|
84
|
+
await executeAsync(gatewayUrl, { message, thinking, tools, agentId }, spinner);
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
spinner.stop("Error");
|
|
88
|
+
console.log(`❌ ${(error as Error).message}`);
|
|
89
|
+
console.log(" ¿Está corriendo el Gateway? Ejecuta: hive start");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function executeWithStream(
|
|
94
|
+
gatewayUrl: string,
|
|
95
|
+
payload: { message: string; thinking: string; tools: string; agentId: string },
|
|
96
|
+
spinner: ReturnType<typeof p.spinner>
|
|
97
|
+
): Promise<void> {
|
|
98
|
+
const response = await fetch(`${gatewayUrl}/api/agent/execute`, {
|
|
99
|
+
method: "POST",
|
|
100
|
+
headers: { "Content-Type": "application/json" },
|
|
101
|
+
body: JSON.stringify({ ...payload, stream: true }),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new Error(`Error: ${response.statusText}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
spinner.stop("Conectado");
|
|
109
|
+
|
|
110
|
+
const reader = response.body?.getReader();
|
|
111
|
+
if (!reader) {
|
|
112
|
+
throw new Error("No se pudo obtener el stream");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const decoder = new TextDecoder();
|
|
116
|
+
let buffer = "";
|
|
117
|
+
let thinking = true;
|
|
118
|
+
|
|
119
|
+
process.stdout.write("\n");
|
|
120
|
+
|
|
121
|
+
while (true) {
|
|
122
|
+
const { done, value } = await reader.read();
|
|
123
|
+
if (done) break;
|
|
124
|
+
|
|
125
|
+
buffer += decoder.decode(value, { stream: true });
|
|
126
|
+
const lines = buffer.split("\n");
|
|
127
|
+
buffer = lines.pop() ?? "";
|
|
128
|
+
|
|
129
|
+
for (const line of lines) {
|
|
130
|
+
if (!line.trim() || !line.startsWith("data: ")) continue;
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const data = JSON.parse(line.slice(6));
|
|
134
|
+
|
|
135
|
+
if (data.type === "thinking" && thinking) {
|
|
136
|
+
process.stdout.write(".");
|
|
137
|
+
} else if (data.type === "response") {
|
|
138
|
+
if (thinking) {
|
|
139
|
+
process.stdout.write("\n\n");
|
|
140
|
+
thinking = false;
|
|
141
|
+
}
|
|
142
|
+
process.stdout.write(data.content ?? "");
|
|
143
|
+
} else if (data.type === "tool_call") {
|
|
144
|
+
process.stdout.write(`\n[Tool: ${data.toolName}]`);
|
|
145
|
+
} else if (data.type === "complete") {
|
|
146
|
+
process.stdout.write("\n\n");
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
// Ignore parse errors
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function executeAsync(
|
|
156
|
+
gatewayUrl: string,
|
|
157
|
+
payload: { message: string; thinking: string; tools: string; agentId: string },
|
|
158
|
+
spinner: ReturnType<typeof p.spinner>
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
const response = await fetch(`${gatewayUrl}/api/agent/execute`, {
|
|
161
|
+
method: "POST",
|
|
162
|
+
headers: { "Content-Type": "application/json" },
|
|
163
|
+
body: JSON.stringify({ ...payload, stream: false }),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (!response.ok) {
|
|
167
|
+
throw new Error(`Error: ${response.statusText}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const result = await response.json() as { taskId?: string; success: boolean };
|
|
171
|
+
|
|
172
|
+
spinner.stop("Enviado");
|
|
173
|
+
|
|
174
|
+
if (result.taskId) {
|
|
175
|
+
console.log(`✓ Tarea enviada: ${result.taskId}`);
|
|
176
|
+
console.log(" Usa `hive tasks list` para ver el estado");
|
|
177
|
+
} else {
|
|
178
|
+
console.log("✓ Tarea enviada");
|
|
179
|
+
}
|
|
180
|
+
}
|
package/src/commands/gateway.ts
CHANGED
|
@@ -64,7 +64,7 @@ export async function start(flags: string[]): Promise<void> {
|
|
|
64
64
|
║ ██║ ██║██║ ╚████╔╝ ███████╗ ║
|
|
65
65
|
║ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚══════╝ ║
|
|
66
66
|
║ ║
|
|
67
|
-
║ Personal AI Gateway — v1.0.
|
|
67
|
+
║ Personal AI Gateway — v1.0.10 ║
|
|
68
68
|
╚════════════════════════════════════════════╝
|
|
69
69
|
`);
|
|
70
70
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as yaml from "js-yaml";
|
|
5
|
+
|
|
6
|
+
const HIVE_DIR = path.join(process.env.HOME || "", ".hive");
|
|
7
|
+
const CONFIG_PATH = path.join(HIVE_DIR, "hive.yaml");
|
|
8
|
+
|
|
9
|
+
interface MessageResult {
|
|
10
|
+
success: boolean;
|
|
11
|
+
messageId?: string;
|
|
12
|
+
error?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function loadConfig(): Record<string, unknown> | null {
|
|
16
|
+
if (!fs.existsSync(CONFIG_PATH)) return null;
|
|
17
|
+
|
|
18
|
+
const content = fs.readFileSync(CONFIG_PATH, "utf-8");
|
|
19
|
+
return yaml.load(content) as Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getGatewayUrl(config: Record<string, unknown> | null): string {
|
|
23
|
+
const gateway = config?.gateway as Record<string, unknown> | undefined;
|
|
24
|
+
const host = (gateway?.host as string) ?? "localhost";
|
|
25
|
+
const port = (gateway?.port as number) ?? 3000;
|
|
26
|
+
return `http://${host}:${port}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function message(subcommand: string | undefined, args: string[]): Promise<void> {
|
|
30
|
+
switch (subcommand) {
|
|
31
|
+
case "send":
|
|
32
|
+
await messageSend(args);
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
console.log(`
|
|
36
|
+
Usage: hive message <command>
|
|
37
|
+
|
|
38
|
+
Commands:
|
|
39
|
+
send --to <id> --content <text> Enviar mensaje
|
|
40
|
+
`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function messageSend(args: string[]): Promise<void> {
|
|
45
|
+
const toIndex = args.indexOf("--to");
|
|
46
|
+
const contentIndex = args.indexOf("--content");
|
|
47
|
+
const channelIndex = args.indexOf("--channel");
|
|
48
|
+
|
|
49
|
+
if (toIndex === -1 || contentIndex === -1) {
|
|
50
|
+
console.log("❌ Faltan parámetros requeridos");
|
|
51
|
+
console.log(" hive message send --to <id> --content <texto>");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const to = args[toIndex + 1];
|
|
56
|
+
const content = args[contentIndex + 1];
|
|
57
|
+
const channel = channelIndex !== -1 ? args[channelIndex + 1] : "default";
|
|
58
|
+
|
|
59
|
+
if (!to || !content) {
|
|
60
|
+
console.log("❌ Parámetros inválidos");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const config = loadConfig();
|
|
65
|
+
const gatewayUrl = getGatewayUrl(config);
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const response = await fetch(`${gatewayUrl}/api/messages/send`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: { "Content-Type": "application/json" },
|
|
71
|
+
body: JSON.stringify({ to, content, channel }),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
console.log(`❌ Error: ${response.statusText}`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const result = (await response.json()) as MessageResult;
|
|
80
|
+
|
|
81
|
+
if (result.success) {
|
|
82
|
+
console.log(`✓ Mensaje enviado: ${result.messageId}`);
|
|
83
|
+
} else {
|
|
84
|
+
console.log(`❌ Error: ${result.error}`);
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.log(`❌ No se pudo conectar al Gateway: ${(error as Error).message}`);
|
|
88
|
+
console.log(" ¿Está corriendo? Ejecuta: hive start");
|
|
89
|
+
}
|
|
90
|
+
}
|
package/src/commands/onboard.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as fs from "fs";
|
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import * as yaml from "js-yaml";
|
|
5
5
|
|
|
6
|
-
const VERSION = "
|
|
6
|
+
const VERSION = "";
|
|
7
7
|
|
|
8
8
|
const DEFAULT_MODELS: Record<string, string> = {
|
|
9
9
|
anthropic: "claude-sonnet-4-6",
|
|
@@ -649,7 +649,7 @@ async function runUpdateWizard(configPath: string, existing: ExistingConfig): Pr
|
|
|
649
649
|
const keyResult = await p.text({
|
|
650
650
|
message: `API key de ${provider}:`,
|
|
651
651
|
placeholder: API_KEY_PLACEHOLDERS[provider] || "sk-...",
|
|
652
|
-
validate: (v
|
|
652
|
+
validate: (v) => (!v || v.length < 10 ? "La key parece muy corta" : undefined),
|
|
653
653
|
});
|
|
654
654
|
|
|
655
655
|
if (p.isCancel(keyResult)) {
|
package/src/index.ts
CHANGED
|
@@ -13,8 +13,10 @@ import { doctor } from "./commands/doctor";
|
|
|
13
13
|
import { securityAudit } from "./commands/security";
|
|
14
14
|
import { installService } from "./commands/service";
|
|
15
15
|
import { update } from "./commands/update";
|
|
16
|
+
import { message } from "./commands/message";
|
|
17
|
+
import { agent } from "./commands/agent-run";
|
|
16
18
|
|
|
17
|
-
const VERSION = "1.0.
|
|
19
|
+
const VERSION = "1.0.10";
|
|
18
20
|
|
|
19
21
|
const HELP = `
|
|
20
22
|
🐝 Hive — Personal AI Gateway v${VERSION}
|
|
@@ -30,6 +32,10 @@ Commands:
|
|
|
30
32
|
chat [--agent <id>] Chat directo en terminal
|
|
31
33
|
logs [--follow] [--level] Ver logs del Gateway
|
|
32
34
|
|
|
35
|
+
message send --to <id> --content <text>
|
|
36
|
+
Enviar mensaje por canal
|
|
37
|
+
agent run --message <text> Ejecutar agente con mensaje
|
|
38
|
+
|
|
33
39
|
agents add <id> Crear nuevo agente
|
|
34
40
|
agents list [--bindings] Listar agentes
|
|
35
41
|
agents remove <id> Eliminar agente
|
|
@@ -73,6 +79,8 @@ Examples:
|
|
|
73
79
|
hive onboard Configurar Hive por primera vez
|
|
74
80
|
hive start Arrancar el Gateway
|
|
75
81
|
hive chat Chatear con el agente en terminal
|
|
82
|
+
hive message send --to 123 --content "Hola"
|
|
83
|
+
hive agent run --message "Analiza README.md" --wait
|
|
76
84
|
hive agents add work Crear agente "work"
|
|
77
85
|
hive mcp add Añadir servidor MCP
|
|
78
86
|
hive doctor Diagnosticar problemas
|
|
@@ -110,6 +118,12 @@ async function main(): Promise<void> {
|
|
|
110
118
|
case "logs":
|
|
111
119
|
await logs(flags);
|
|
112
120
|
break;
|
|
121
|
+
case "message":
|
|
122
|
+
await message(subcommand, args.slice(2));
|
|
123
|
+
break;
|
|
124
|
+
case "agent":
|
|
125
|
+
await agent(subcommand, args.slice(2));
|
|
126
|
+
break;
|
|
113
127
|
case "agents":
|
|
114
128
|
await agents(subcommand, args.slice(2));
|
|
115
129
|
break;
|