Skip to content

Commit 0765f74

Browse files
spranabclaude
andcommitted
Add swarmcode status CLI command
Shows all registered workspaces, active/idle status, pending messages, descriptions, and message log count. Closes #1. Usage: swarmcode status [--redis redis://host:6379] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e6118c7 commit 0765f74

4 files changed

Lines changed: 100 additions & 4 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "swarmcode-mcp",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"description": "SwarmCode — real-time networking between Claude Code instances. Your AI agents talk to each other across machines, workspaces, and conversations.",
55
"type": "module",
66
"main": "src/channel.js",

src/server.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ if (cmd === "init") {
2020
await import("./listener.js");
2121
} else if (cmd === "check") {
2222
await import("./check-inbox-http.js");
23+
} else if (cmd === "status") {
24+
await import("./status.js");
2325
} else {
2426
console.log("SwarmCode — real-time networking between Claude Code instances\n");
2527
console.log("Usage:");
2628
console.log(" swarmcode init <workspace-id> --redis <redis-url>");
2729
console.log(" swarmcode channel (MCP server — spawned by Claude Code)");
2830
console.log(" swarmcode listen (background Redis listener)");
29-
console.log(" swarmcode check (quick inbox check for hooks)\n");
31+
console.log(" swarmcode check (quick inbox check for hooks)");
32+
console.log(" swarmcode status (show all workspaces and pending messages)\n");
3033
console.log("Quick start:");
3134
console.log(" npm install -g swarmcode");
3235
console.log(" swarmcode init my-workspace --redis redis://your-redis:6379");

src/status.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* SwarmCode status — show all workspaces and pending messages.
5+
*
6+
* Usage: swarmcode status [--redis <redis-url>]
7+
*/
8+
9+
import Redis from "ioredis";
10+
import { readFileSync } from "fs";
11+
import { resolve } from "path";
12+
13+
let REDIS_URL = process.env.SWARMCODE_REDIS_URL || process.env.AGENT_BRIDGE_REDIS_URL;
14+
15+
// Read from .mcp.json if not set
16+
if (!REDIS_URL) {
17+
try {
18+
const mcpPath = resolve(process.cwd(), ".mcp.json");
19+
const mcpConfig = JSON.parse(readFileSync(mcpPath, "utf-8"));
20+
const sc = mcpConfig?.mcpServers?.["swarmcode"];
21+
if (sc?.env) REDIS_URL = sc.env.SWARMCODE_REDIS_URL;
22+
} catch {}
23+
}
24+
25+
// Check --redis flag
26+
const redisIdx = process.argv.indexOf("--redis");
27+
if (redisIdx !== -1) REDIS_URL = process.argv[redisIdx + 1];
28+
29+
if (!REDIS_URL) {
30+
REDIS_URL = "redis://localhost:6379";
31+
}
32+
33+
const c = {
34+
reset: "\x1b[0m",
35+
bold: "\x1b[1m",
36+
dim: "\x1b[2m",
37+
green: "\x1b[38;5;114m",
38+
red: "\x1b[38;5;210m",
39+
yellow: "\x1b[38;5;221m",
40+
blue: "\x1b[38;5;75m",
41+
gray: "\x1b[38;5;244m",
42+
purple: "\x1b[38;5;141m",
43+
};
44+
45+
function timeAgo(ts) {
46+
const s = Math.floor((Date.now() - new Date(ts)) / 1000);
47+
if (s < 60) return `${s}s ago`;
48+
if (s < 3600) return `${Math.floor(s / 60)}m ago`;
49+
if (s < 86400) return `${Math.floor(s / 3600)}h ago`;
50+
return `${Math.floor(s / 86400)}d ago`;
51+
}
52+
53+
try {
54+
const redis = new Redis(REDIS_URL, { keyPrefix: "swarmcode:" });
55+
56+
const raw = await redis.hgetall("workspaces");
57+
const workspaces = Object.values(raw).map((v) => JSON.parse(v));
58+
59+
for (const ws of workspaces) {
60+
ws.pending_messages = await redis.llen(`inbox:${ws.id}`);
61+
}
62+
63+
workspaces.sort((a, b) => new Date(b.last_active) - new Date(a.last_active));
64+
65+
console.log();
66+
console.log(`${c.bold}${c.purple} SwarmCode Status${c.reset} ${c.dim}(${REDIS_URL})${c.reset}`);
67+
console.log(`${c.gray} ${"─".repeat(50)}${c.reset}`);
68+
69+
if (workspaces.length === 0) {
70+
console.log(` ${c.dim}No workspaces registered.${c.reset}`);
71+
} else {
72+
for (const ws of workspaces) {
73+
const active = (Date.now() - new Date(ws.last_active)) < 600000;
74+
const status = active ? `${c.green}active${c.reset}` : `${c.red}idle${c.reset}`;
75+
const pending = ws.pending_messages > 0 ? ` ${c.yellow}${ws.pending_messages} pending${c.reset}` : "";
76+
77+
console.log(` ${c.bold}${c.blue}${ws.id}${c.reset} ${status}${pending}`);
78+
if (ws.description) console.log(` ${c.dim}${ws.description}${c.reset}`);
79+
console.log(` ${c.gray}${ws.machine || "unknown"} · ${timeAgo(ws.last_active)}${c.reset}`);
80+
}
81+
}
82+
83+
// Message log count
84+
const logLen = await redis.llen("messages:log");
85+
console.log(`${c.gray} ${"─".repeat(50)}${c.reset}`);
86+
console.log(` ${c.dim}${workspaces.length} workspace(s) · ${logLen} messages in log${c.reset}`);
87+
console.log();
88+
89+
await redis.quit();
90+
} catch (err) {
91+
console.error(`Could not connect to Redis at ${REDIS_URL}: ${err.message}`);
92+
process.exit(1);
93+
}

0 commit comments

Comments
 (0)