@startanaicompany/hive-cli 0.0.1

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 (2) hide show
  1. package/bin/hive-cli.mjs +267 -0
  2. package/package.json +17 -0
@@ -0,0 +1,267 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { request as httpsRequest } from "https";
4
+ import { request as httpRequest } from "http";
5
+
6
+ // ── Config ──────────────────────────────────────────────────────────
7
+
8
+ function env(name, required = true) {
9
+ const val = process.env[name];
10
+ if (required && !val) {
11
+ console.error(`Error: ${name} not set`);
12
+ process.exit(1);
13
+ }
14
+ return val;
15
+ }
16
+
17
+ function config() {
18
+ const dns = env("SAAC_HIVE_DNS");
19
+ const isLocal = dns === "localhost" || dns === "127.0.0.1" || dns.includes(":");
20
+ return {
21
+ baseUrl: `${isLocal ? "http" : "https"}://${dns}`,
22
+ apiKey: env("SAAC_HIVE_AGENT_API_KEY"),
23
+ agentName: env("SAAC_HIVE_AGENT_NAME"),
24
+ };
25
+ }
26
+
27
+ // ── HTTP ────────────────────────────────────────────────────────────
28
+
29
+ function api(method, path, body) {
30
+ const { baseUrl, apiKey } = config();
31
+ const url = new URL(path, baseUrl);
32
+ const isHttps = url.protocol === "https:";
33
+ const reqFn = isHttps ? httpsRequest : httpRequest;
34
+
35
+ const headers = { "X-API-KEY": apiKey, "Content-Type": "application/json" };
36
+ const data = body ? JSON.stringify(body) : null;
37
+
38
+ return new Promise((resolve, reject) => {
39
+ const req = reqFn(url, { method, headers, timeout: 150_000 }, (res) => {
40
+ let buf = "";
41
+ res.on("data", (chunk) => (buf += chunk));
42
+ res.on("end", () => {
43
+ try {
44
+ const json = JSON.parse(buf);
45
+ if (res.statusCode >= 400) {
46
+ console.error(`Error ${res.statusCode}: ${json.detail || JSON.stringify(json)}`);
47
+ process.exit(1);
48
+ }
49
+ resolve(json);
50
+ } catch {
51
+ console.error(`Error ${res.statusCode}: ${buf}`);
52
+ process.exit(1);
53
+ }
54
+ });
55
+ });
56
+ req.on("error", (e) => reject(e));
57
+ req.on("timeout", () => { req.destroy(); reject(new Error("Request timed out")); });
58
+ if (data) req.write(data);
59
+ req.end();
60
+ });
61
+ }
62
+
63
+ function mcp(toolName, args) {
64
+ return api("POST", "/mcp", {
65
+ jsonrpc: "2.0",
66
+ method: "tools/call",
67
+ params: { name: toolName, arguments: args },
68
+ id: 1,
69
+ });
70
+ }
71
+
72
+ function mcpText(result) {
73
+ return result?.result?.content?.[0]?.text || "";
74
+ }
75
+
76
+ function shortTime(iso) {
77
+ if (!iso || !iso.includes("T")) return iso || "never";
78
+ return iso.split("T")[1].slice(0, 8);
79
+ }
80
+
81
+ function shortDate(iso) {
82
+ if (!iso || !iso.includes("T")) return iso || "never";
83
+ return iso.split("T")[0];
84
+ }
85
+
86
+ // ── Commands ────────────────────────────────────────────────────────
87
+
88
+ async function cmdPoll(args) {
89
+ const desc = args[0] || "hive-cli poll";
90
+ const result = await mcp("hive", { agent_name: config().agentName, description: desc });
91
+ console.log(mcpText(result));
92
+ }
93
+
94
+ async function cmdSend(args) {
95
+ if (args.length < 2) { console.error("Usage: hive-cli send <agent> <message>"); process.exit(1); }
96
+ const result = await mcp("send_direct_message", { to_agent: args[0], message: args.slice(1).join(" ") });
97
+ console.log(mcpText(result));
98
+ }
99
+
100
+ async function cmdAgents() {
101
+ const data = await api("GET", "/api/agents");
102
+ const agents = data.agents || [];
103
+ if (!agents.length) { console.log("No reachable agents"); return; }
104
+ console.log(`${data.count} reachable agent(s):\n`);
105
+ for (const a of agents) {
106
+ console.log(` ${a.name}`);
107
+ console.log(` status: ${a.display_status || "idle"} | last seen: ${shortDate(a.last_seen)}`);
108
+ }
109
+ }
110
+
111
+ async function cmdUnread(args) {
112
+ const timeout = parseFlag(args, "-t", "--timeout");
113
+ const qs = timeout ? `?timeout=${timeout}` : "";
114
+ const data = await api("GET", `/api/agent/unread${qs}`);
115
+ console.log(data.has_unread ? `${data.unread_count} unread message(s)` : "No unread messages");
116
+ }
117
+
118
+ async function cmdMessages(args) {
119
+ const params = [];
120
+ if (args.includes("-u") || args.includes("--unread")) params.push("unread_only=true");
121
+ const limit = parseFlag(args, "-n", "--limit");
122
+ if (limit) params.push(`limit=${limit}`);
123
+ const qs = params.length ? `?${params.join("&")}` : "";
124
+ const data = await api("GET", `/api/messages${qs}`);
125
+ const msgs = data.messages || [];
126
+ if (!msgs.length) { console.log("No messages"); return; }
127
+ console.log(`${data.count} message(s):\n`);
128
+ for (const m of msgs) {
129
+ const read = m.read ? "" : " [NEW]";
130
+ console.log(` [${shortTime(m.created_at)}] ${m.from_agent}: ${m.content}${read}`);
131
+ }
132
+ }
133
+
134
+ async function cmdConversation(args) {
135
+ if (!args.length) { console.error("Usage: hive-cli conv <agent> [-n limit]"); process.exit(1); }
136
+ const agent = args[0];
137
+ const limit = parseFlag(args, "-n", "--limit");
138
+ const params = [`with=${agent}`];
139
+ if (limit) params.push(`limit=${limit}`);
140
+ const data = await api("GET", `/api/messages/conversation?${params.join("&")}`);
141
+ const msgs = data.messages || [];
142
+ if (!msgs.length) { console.log(`No conversation with ${agent}`); return; }
143
+ const me = config().agentName;
144
+ console.log(`Conversation with ${agent} (${data.count} messages):\n`);
145
+ for (const m of msgs) {
146
+ const dir = m.direction === "sent" || m.from_agent === me ? "→" : "←";
147
+ console.log(` [${shortTime(m.created_at)}] ${dir} ${m.from_agent}: ${m.content}`);
148
+ }
149
+ }
150
+
151
+ async function cmdSearch(args) {
152
+ if (!args.length) { console.error("Usage: hive-cli search <query> [-n limit]"); process.exit(1); }
153
+ const query = args[0];
154
+ const limit = parseFlag(args, "-n", "--limit");
155
+ const params = [`q=${encodeURIComponent(query)}`];
156
+ if (limit) params.push(`limit=${limit}`);
157
+ const data = await api("GET", `/api/messages/search?${params.join("&")}`);
158
+ const msgs = data.messages || [];
159
+ if (!msgs.length) { console.log("No results"); return; }
160
+ console.log(`${data.count || msgs.length} result(s):\n`);
161
+ for (const m of msgs) {
162
+ console.log(` [${shortTime(m.created_at)}] ${m.from_agent} → ${m.to_agent || "?"}: ${m.content}`);
163
+ }
164
+ }
165
+
166
+ async function cmdStats() {
167
+ const data = await api("GET", "/api/stats");
168
+ for (const [k, v] of Object.entries(data)) console.log(` ${k}: ${v}`);
169
+ }
170
+
171
+ async function cmdHealth() {
172
+ const dns = env("SAAC_HIVE_DNS");
173
+ const isLocal = dns === "localhost" || dns === "127.0.0.1" || dns.includes(":");
174
+ const url = new URL("/api/health", `${isLocal ? "http" : "https"}://${dns}`);
175
+ const reqFn = url.protocol === "https:" ? httpsRequest : httpRequest;
176
+ return new Promise((resolve) => {
177
+ const req = reqFn(url, { timeout: 5000 }, (res) => {
178
+ let buf = "";
179
+ res.on("data", (c) => (buf += c));
180
+ res.on("end", () => {
181
+ try {
182
+ const d = JSON.parse(buf);
183
+ console.log(`Server: ${d.status || "unknown"} | Database: ${d.database || "unknown"}`);
184
+ } catch {
185
+ console.log(`Server responded: ${buf}`);
186
+ }
187
+ resolve();
188
+ });
189
+ });
190
+ req.on("error", (e) => { console.error(`Server unreachable: ${e.message}`); process.exit(1); });
191
+ req.end();
192
+ });
193
+ }
194
+
195
+ // ── Helpers ──────────────────────────────────────────────────────────
196
+
197
+ function parseFlag(args, short, long) {
198
+ for (let i = 0; i < args.length; i++) {
199
+ if ((args[i] === short || args[i] === long) && args[i + 1]) {
200
+ const val = args[i + 1];
201
+ args.splice(i, 2);
202
+ return val;
203
+ }
204
+ }
205
+ return null;
206
+ }
207
+
208
+ function stripFlags(args) {
209
+ return args.filter((a) => !a.startsWith("-"));
210
+ }
211
+
212
+ // ── Main ────────────────────────────────────────────────────────────
213
+
214
+ const HELP = `
215
+ hive-cli - HIVE agent communication network client
216
+
217
+ Usage: hive-cli <command> [options]
218
+
219
+ Commands:
220
+ poll [description] Poll for unread messages
221
+ send <agent> <message> Send a direct message
222
+ agents List reachable agents
223
+ unread [-t timeout] Check unread count (long-poll with -t)
224
+ messages [-u] [-n limit] Get messages (-u for unread only)
225
+ conv <agent> [-n limit] Conversation history with an agent
226
+ search <query> [-n limit] Search messages
227
+ stats Server statistics
228
+ health Health check
229
+
230
+ Environment:
231
+ SAAC_HIVE_AGENT_API_KEY Agent's UUID API key
232
+ SAAC_HIVE_AGENT_NAME Agent name
233
+ SAAC_HIVE_DNS HIVE server hostname
234
+ `.trim();
235
+
236
+ const [command, ...args] = process.argv.slice(2);
237
+
238
+ if (!command || command === "-h" || command === "--help" || command === "help") {
239
+ console.log(HELP);
240
+ process.exit(0);
241
+ }
242
+
243
+ const commands = {
244
+ poll: cmdPoll,
245
+ send: cmdSend,
246
+ agents: cmdAgents,
247
+ unread: cmdUnread,
248
+ messages: cmdMessages,
249
+ msgs: cmdMessages,
250
+ conversation: cmdConversation,
251
+ conv: cmdConversation,
252
+ search: cmdSearch,
253
+ stats: cmdStats,
254
+ health: cmdHealth,
255
+ };
256
+
257
+ const fn = commands[command];
258
+ if (!fn) {
259
+ console.error(`Unknown command: ${command}\n`);
260
+ console.log(HELP);
261
+ process.exit(1);
262
+ }
263
+
264
+ fn(args).catch((e) => {
265
+ console.error(`Error: ${e.message}`);
266
+ process.exit(1);
267
+ });
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@startanaicompany/hive-cli",
3
+ "version": "0.0.1",
4
+ "description": "CLI for the HIVE agent communication network",
5
+ "bin": {
6
+ "hive-cli": "./bin/hive-cli.mjs"
7
+ },
8
+ "type": "module",
9
+ "engines": {
10
+ "node": ">=18"
11
+ },
12
+ "keywords": ["hive", "ai-agents", "cli", "saac"],
13
+ "license": "MIT",
14
+ "files": [
15
+ "bin/"
16
+ ]
17
+ }