@studiomopoke/crosschat 1.8.2 → 2.0.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/README.md +48 -118
- package/bin/cli.cjs +37 -57
- package/crosschat.md +73 -104
- package/dashboard/dist/assets/index-BY-IQhma.js +49 -0
- package/dashboard/dist/assets/index-CI8v9PKQ.css +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/hub/_hub-section-1-infra.d.ts +8 -0
- package/dist/hub/_hub-section-1-infra.d.ts.map +1 -0
- package/dist/hub/_hub-section-1-infra.js +152 -0
- package/dist/hub/_hub-section-1-infra.js.map +1 -0
- package/dist/hub/_hub-section-2-handlers.d.ts +2 -0
- package/dist/hub/_hub-section-2-handlers.d.ts.map +1 -0
- package/dist/hub/_hub-section-2-handlers.js +514 -0
- package/dist/hub/_hub-section-2-handlers.js.map +1 -0
- package/dist/hub/_hub-section-3-rest.d.ts +2 -0
- package/dist/hub/_hub-section-3-rest.d.ts.map +1 -0
- package/dist/hub/_hub-section-3-rest.js +418 -0
- package/dist/hub/_hub-section-3-rest.js.map +1 -0
- package/dist/hub/_hub-section-4-ws.d.ts +2 -0
- package/dist/hub/_hub-section-4-ws.d.ts.map +1 -0
- package/dist/hub/_hub-section-4-ws.js +367 -0
- package/dist/hub/_hub-section-4-ws.js.map +1 -0
- package/dist/hub/agent-connection.d.ts +38 -62
- package/dist/hub/agent-connection.d.ts.map +1 -1
- package/dist/hub/agent-connection.js +146 -229
- package/dist/hub/agent-connection.js.map +1 -1
- package/dist/hub/hub-server.d.ts +1 -1
- package/dist/hub/hub-server.d.ts.map +1 -1
- package/dist/hub/hub-server.js +389 -685
- package/dist/hub/hub-server.js.map +1 -1
- package/dist/hub/message-manager.d.ts +158 -0
- package/dist/hub/message-manager.d.ts.map +1 -0
- package/dist/hub/message-manager.js +443 -0
- package/dist/hub/message-manager.js.map +1 -0
- package/dist/hub/protocol.d.ts +73 -131
- package/dist/hub/protocol.d.ts.map +1 -1
- package/dist/hub/protocol.js +3 -0
- package/dist/hub/protocol.js.map +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +15 -89
- package/dist/lifecycle.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +22 -33
- package/dist/server.js.map +1 -1
- package/dist/tools/add-badge.d.ts +4 -0
- package/dist/tools/add-badge.d.ts.map +1 -0
- package/dist/tools/add-badge.js +29 -0
- package/dist/tools/add-badge.js.map +1 -0
- package/dist/tools/claim-task.js +5 -5
- package/dist/tools/claim-task.js.map +1 -1
- package/dist/tools/clear-session.d.ts +1 -2
- package/dist/tools/clear-session.d.ts.map +1 -1
- package/dist/tools/clear-session.js +7 -22
- package/dist/tools/clear-session.js.map +1 -1
- package/dist/tools/flag-as-task.d.ts +4 -0
- package/dist/tools/flag-as-task.d.ts.map +1 -0
- package/dist/tools/flag-as-task.js +31 -0
- package/dist/tools/flag-as-task.js.map +1 -0
- package/dist/tools/get-messages.d.ts +2 -1
- package/dist/tools/get-messages.d.ts.map +1 -1
- package/dist/tools/get-messages.js +19 -6
- package/dist/tools/get-messages.js.map +1 -1
- package/dist/tools/list-peers.d.ts.map +1 -1
- package/dist/tools/list-peers.js +1 -4
- package/dist/tools/list-peers.js.map +1 -1
- package/dist/tools/resolve-task.d.ts +4 -0
- package/dist/tools/resolve-task.d.ts.map +1 -0
- package/dist/tools/resolve-task.js +29 -0
- package/dist/tools/resolve-task.js.map +1 -0
- package/dist/tools/send-message.d.ts.map +1 -1
- package/dist/tools/send-message.js +6 -5
- package/dist/tools/send-message.js.map +1 -1
- package/dist/tools/set-status.js +3 -3
- package/dist/tools/set-status.js.map +1 -1
- package/dist/tools/wait-for-messages.js +1 -1
- package/dist/tools/wait-for-messages.js.map +1 -1
- package/dist/types.d.ts +4 -3
- package/dist/types.d.ts.map +1 -1
- package/hooks/permission-hook.sh +19 -18
- package/package.json +1 -1
- package/dashboard/dist/assets/index-BR-2rRm6.css +0 -1
- package/dashboard/dist/assets/index-Ci2ihChN.js +0 -49
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CrossChat
|
|
2
2
|
|
|
3
|
-
CrossChat is an MCP server that lets multiple Claude Code instances discover each other, communicate, and collaborate — all on a single machine. It uses a central hub with
|
|
3
|
+
CrossChat is an MCP server that lets multiple Claude Code instances discover each other, communicate, and collaborate — all on a single machine. It uses a central hub with persistent messaging, threads, badges, and a real-time web dashboard.
|
|
4
4
|
|
|
5
5
|
## How it works
|
|
6
6
|
|
|
@@ -23,15 +23,15 @@ Each Claude Code instance runs CrossChat as an MCP server (via stdio). On startu
|
|
|
23
23
|
└─────────────┘ └──────────────┘
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
**Hub server** — a single Node.js process that manages
|
|
26
|
+
**Hub server** — a single Node.js process that manages messaging, routes messages, tracks peers, and serves the dashboard. Spawned automatically by the first CrossChat instance.
|
|
27
27
|
|
|
28
|
-
**Peer discovery** — agents register with the hub on connect. `list_peers` returns all connected agents with their name, status, working directory
|
|
28
|
+
**Peer discovery** — agents register with the hub on connect. `list_peers` returns all connected agents with their name, status, and working directory.
|
|
29
29
|
|
|
30
|
-
**
|
|
30
|
+
**Unified messaging** — messages are the atomic unit. Any message can have thread replies (persistent) and badges (extensible metadata like task status, importance, questions).
|
|
31
31
|
|
|
32
|
-
**
|
|
32
|
+
**Tasks as badges** — any message can be flagged as a task. Tasks are a workflow layer on messages, not a separate system. Lifecycle: flag → claim → resolve.
|
|
33
33
|
|
|
34
|
-
**Dashboard** — a real-time web UI for monitoring agent activity, sending messages,
|
|
34
|
+
**Dashboard** — a real-time web UI for monitoring agent activity, sending messages, viewing badges, and approving permission requests.
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
@@ -65,40 +65,6 @@ npm install
|
|
|
65
65
|
npm run build
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
### Configure Claude Code
|
|
69
|
-
|
|
70
|
-
Add CrossChat to your MCP configuration (`~/.claude/settings.json`):
|
|
71
|
-
|
|
72
|
-
```json
|
|
73
|
-
{
|
|
74
|
-
"mcpServers": {
|
|
75
|
-
"crosschat": {
|
|
76
|
-
"command": "node",
|
|
77
|
-
"args": ["/path/to/crosschat/dist/index.js"]
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Optionally set a custom name or working directory:
|
|
84
|
-
|
|
85
|
-
```json
|
|
86
|
-
{
|
|
87
|
-
"mcpServers": {
|
|
88
|
-
"crosschat": {
|
|
89
|
-
"command": "node",
|
|
90
|
-
"args": ["/path/to/crosschat/dist/index.js"],
|
|
91
|
-
"env": {
|
|
92
|
-
"CROSSCHAT_NAME": "frontend-worker",
|
|
93
|
-
"CROSSCHAT_CWD": "/path/to/project"
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
If `CROSSCHAT_NAME` is omitted, a name is auto-generated from the working directory (e.g., `myproject-a1b2`).
|
|
101
|
-
|
|
102
68
|
---
|
|
103
69
|
|
|
104
70
|
## Using CrossChat
|
|
@@ -107,10 +73,10 @@ Once configured, CrossChat starts automatically with each Claude Code session. T
|
|
|
107
73
|
|
|
108
74
|
1. Discovers connected peers
|
|
109
75
|
2. Sets up a background message listener
|
|
110
|
-
3. Announces the instance to the
|
|
76
|
+
3. Announces the instance to the channel
|
|
111
77
|
4. Shows the dashboard URL
|
|
112
78
|
|
|
113
|
-
From there, you can ask Claude to message peers,
|
|
79
|
+
From there, you can ask Claude to message peers, flag tasks, add badges, or check status — all through natural language.
|
|
114
80
|
|
|
115
81
|
### Example
|
|
116
82
|
|
|
@@ -118,142 +84,106 @@ From there, you can ask Claude to message peers, delegate tasks, switch rooms, o
|
|
|
118
84
|
```
|
|
119
85
|
You: /crosschat
|
|
120
86
|
|
|
121
|
-
Claude: CrossChat is live. You are frontend-a1b2
|
|
87
|
+
Claude: CrossChat is live. You are frontend-a1b2.
|
|
122
88
|
Peers: api-worker-c3d4 (available), backend-e5f6 (available)
|
|
123
89
|
Dashboard: http://localhost:49322
|
|
124
90
|
|
|
125
91
|
You: Ask the other instances to run their test suites
|
|
126
92
|
|
|
127
|
-
Claude:
|
|
93
|
+
Claude: Sent messages and flagged as tasks. Listening for results...
|
|
128
94
|
|
|
129
|
-
Claude: api-worker completed: 18 tests passed, 0 failed.
|
|
95
|
+
Claude: api-worker claimed the task and completed: 18 tests passed, 0 failed.
|
|
130
96
|
Claude: backend completed: 42 tests passed, 2 failed (auth_middleware, rate_limiter).
|
|
131
97
|
```
|
|
132
98
|
|
|
133
|
-
**Terminal 2:**
|
|
134
|
-
```
|
|
135
|
-
You: /crosschat
|
|
136
|
-
|
|
137
|
-
Claude: Connected as api-worker-c3d4. Listening for messages.
|
|
138
|
-
|
|
139
|
-
Claude: Received task from frontend-a1b2: "Run the test suite and report results"
|
|
140
|
-
Working on it now...
|
|
141
|
-
All 18 tests passed. Sent results back.
|
|
142
|
-
```
|
|
143
|
-
|
|
144
99
|
### @mentions
|
|
145
100
|
|
|
146
101
|
- **`@agent-name`** — delivers only to that agent
|
|
147
|
-
- **`@here`** — delivers to everyone
|
|
102
|
+
- **`@here`** — delivers to everyone
|
|
148
103
|
- **No mention** — broadcast to all (default)
|
|
149
104
|
|
|
150
|
-
The hub parses @mentions automatically. The dashboard always shows all messages regardless of mentions.
|
|
151
|
-
|
|
152
105
|
---
|
|
153
106
|
|
|
154
107
|
## Dashboard
|
|
155
108
|
|
|
156
|
-
The hub serves a real-time web dashboard
|
|
109
|
+
The hub serves a real-time web dashboard at `http://localhost:{port}`.
|
|
157
110
|
|
|
158
111
|
The dashboard provides:
|
|
159
112
|
|
|
160
|
-
- **Chat view** — real-time message stream
|
|
161
|
-
- **Agent sidebar** — all connected agents with status
|
|
162
|
-
- **
|
|
163
|
-
- **
|
|
113
|
+
- **Chat view** — real-time message stream with badge rendering and thread indicators
|
|
114
|
+
- **Agent sidebar** — all connected agents with status and working directory
|
|
115
|
+
- **Badge system** — visual metadata on messages (task status, importance, questions, git commits)
|
|
116
|
+
- **Instances panel** — registered projects with one-click agent launching
|
|
164
117
|
- **Permission popups** — approve or deny tool-use requests from agents in real time
|
|
165
118
|
|
|
166
119
|
---
|
|
167
120
|
|
|
168
121
|
## Tools
|
|
169
122
|
|
|
170
|
-
CrossChat provides
|
|
123
|
+
CrossChat provides 10 MCP tools:
|
|
171
124
|
|
|
172
125
|
### Messaging
|
|
173
126
|
| Tool | Purpose |
|
|
174
127
|
|------|---------|
|
|
175
|
-
| `send_message` |
|
|
176
|
-
| `get_messages` | Read messages
|
|
177
|
-
| `wait_for_messages` | Block until a message arrives
|
|
178
|
-
| `join_room` | Switch to a different room |
|
|
179
|
-
| `create_room` | Create a new room and join it |
|
|
180
|
-
| `get_room_digest` | Get an AI-generated summary of room history |
|
|
128
|
+
| `send_message` | Send to channel or thread (use `threadId` to reply) |
|
|
129
|
+
| `get_messages` | Read messages with badge data for at-a-glance context |
|
|
130
|
+
| `wait_for_messages` | Block until a message arrives — used for background listeners |
|
|
181
131
|
|
|
182
132
|
### Peers
|
|
183
133
|
| Tool | Purpose |
|
|
184
134
|
|------|---------|
|
|
185
|
-
| `list_peers` | Discover connected agents — names, status, working directories
|
|
186
|
-
| `set_status` | Set your availability (`available` or `busy`)
|
|
135
|
+
| `list_peers` | Discover connected agents — names, status, working directories |
|
|
136
|
+
| `set_status` | Set your availability (`available` or `busy`) |
|
|
187
137
|
|
|
188
|
-
### Tasks
|
|
138
|
+
### Tasks & Badges
|
|
189
139
|
| Tool | Purpose |
|
|
190
140
|
|------|---------|
|
|
191
|
-
| `
|
|
192
|
-
| `claim_task` |
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `complete_task` | Mark a task done or failed with a markdown result |
|
|
196
|
-
| `list_tasks` | List tasks with optional filters (status, room, assignee) |
|
|
197
|
-
| `get_task_status` | Get full task details including notes history |
|
|
141
|
+
| `flag_as_task` | Promote any message to a tracked task |
|
|
142
|
+
| `claim_task` | Claim a flagged task (first-come-first-served) |
|
|
143
|
+
| `resolve_task` | Complete or fail a task with a markdown result |
|
|
144
|
+
| `add_badge` | Add metadata badge to any message |
|
|
198
145
|
|
|
199
146
|
### Session
|
|
200
147
|
| Tool | Purpose |
|
|
201
148
|
|------|---------|
|
|
202
|
-
| `clear_session` |
|
|
149
|
+
| `clear_session` | Clear channel messages |
|
|
203
150
|
|
|
204
151
|
---
|
|
205
152
|
|
|
206
153
|
## Architecture
|
|
207
154
|
|
|
208
|
-
###
|
|
155
|
+
### Unified messaging
|
|
209
156
|
|
|
210
|
-
|
|
157
|
+
Messages are persistent (JSONL storage) and support:
|
|
158
|
+
- **Threads** — reply to any message to start a persistent thread
|
|
159
|
+
- **Badges** — extensible metadata: task status, importance, questions, git commits, projects
|
|
160
|
+
- **Task workflow** — flag any message as a task, claim it, resolve it
|
|
211
161
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
162
|
+
### Task lifecycle
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
send message → flag_as_task → claim_task → resolve_task (completed/failed)
|
|
166
|
+
```
|
|
216
167
|
|
|
217
|
-
|
|
168
|
+
Tasks are badges on messages, not a separate system. Thread replies on the flagged message serve as progress discussion.
|
|
218
169
|
|
|
219
170
|
### Data directory (`~/.crosschat/`)
|
|
220
171
|
|
|
221
172
|
```
|
|
222
173
|
~/.crosschat/
|
|
223
174
|
dashboard.lock # Hub PID, port, and start time
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
```
|
|
233
|
-
delegate → open → claimed → in_progress → completed
|
|
234
|
-
→ failed
|
|
175
|
+
instances.json # Registered instances (persisted)
|
|
176
|
+
hooks/ # Permission hook (stable location)
|
|
177
|
+
messages/ # Persistent message storage
|
|
178
|
+
general.jsonl # Channel messages
|
|
179
|
+
threads/ # Thread messages (one file per thread)
|
|
180
|
+
badges/ # Badge sidecar files
|
|
181
|
+
tasks/ # Task metadata for flagged messages
|
|
235
182
|
```
|
|
236
183
|
|
|
237
|
-
1. **Delegator** creates a task with `delegate_task`
|
|
238
|
-
2. **Worker** bids on it with `claim_task`
|
|
239
|
-
3. **Delegator** accepts the bid with `accept_claim`
|
|
240
|
-
4. **Worker** sends progress updates with `update_task`
|
|
241
|
-
5. **Worker** finishes with `complete_task` (status: `completed` or `failed`)
|
|
242
|
-
|
|
243
|
-
Tasks persist across hub restarts. Messages are ephemeral.
|
|
244
|
-
|
|
245
184
|
### Permission elevation
|
|
246
185
|
|
|
247
|
-
When the permission hook is installed (`crosschat install`), tool-use requests
|
|
248
|
-
|
|
249
|
-
The hook works by:
|
|
250
|
-
1. Detecting CrossChat-connected instances via session markers (`~/.crosschat/sessions/`)
|
|
251
|
-
2. POSTing the permission request to the hub API
|
|
252
|
-
3. Polling until the dashboard user approves or denies (up to 5 minutes)
|
|
253
|
-
|
|
254
|
-
### Project registry
|
|
255
|
-
|
|
256
|
-
Projects are auto-registered when agents connect — the hub records each agent's working directory. Projects can also be manually added via the dashboard. From the dashboard, you can launch new Claude Code agents into any registered project directory.
|
|
186
|
+
When the permission hook is installed (`crosschat install`), tool-use requests are elevated to the dashboard. The hook queries the hub to detect CrossChat agents via parent PID, then polls for dashboard user approval.
|
|
257
187
|
|
|
258
188
|
---
|
|
259
189
|
|
package/bin/cli.cjs
CHANGED
|
@@ -12,26 +12,20 @@ const COMMANDS_DIR = path.join(os.homedir(), ".claude", "commands");
|
|
|
12
12
|
const COMMAND_SOURCE = path.join(__dirname, "..", "crosschat.md");
|
|
13
13
|
const COMMAND_TARGET = path.join(COMMANDS_DIR, "crosschat.md");
|
|
14
14
|
const HOOK_SOURCE = path.join(__dirname, "..", "hooks", "permission-hook.sh");
|
|
15
|
+
const STABLE_HOOK = path.join(os.homedir(), ".crosschat", "hooks", "permission-hook.sh");
|
|
15
16
|
const MCP_KEY = "crosschat";
|
|
16
17
|
|
|
17
18
|
const CROSSCHAT_PERMISSIONS = [
|
|
18
|
-
"
|
|
19
|
+
"mcp__crosschat__send_message",
|
|
19
20
|
"mcp__crosschat__get_messages",
|
|
21
|
+
"mcp__crosschat__wait_for_messages",
|
|
20
22
|
"mcp__crosschat__list_peers",
|
|
21
|
-
"mcp__crosschat__send_message",
|
|
22
23
|
"mcp__crosschat__set_status",
|
|
23
|
-
"
|
|
24
|
-
"mcp__crosschat__delegate_task",
|
|
25
|
-
"mcp__crosschat__get_task_status",
|
|
26
|
-
"mcp__crosschat__join_room",
|
|
27
|
-
"mcp__crosschat__create_room",
|
|
24
|
+
"mcp__crosschat__flag_as_task",
|
|
28
25
|
"mcp__crosschat__claim_task",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"mcp__crosschat__list_tasks",
|
|
26
|
+
"mcp__crosschat__resolve_task",
|
|
27
|
+
"mcp__crosschat__add_badge",
|
|
32
28
|
"mcp__crosschat__clear_session",
|
|
33
|
-
"mcp__crosschat__get_room_digest",
|
|
34
|
-
"mcp__crosschat__request_digest",
|
|
35
29
|
];
|
|
36
30
|
|
|
37
31
|
const { spawn } = require("child_process");
|
|
@@ -141,12 +135,18 @@ function install() {
|
|
|
141
135
|
addedPerms++;
|
|
142
136
|
}
|
|
143
137
|
}
|
|
144
|
-
// 2b.
|
|
138
|
+
// 2b. Copy hook to stable location and register in settings (PreToolUse)
|
|
145
139
|
if (fs.existsSync(HOOK_SOURCE)) {
|
|
140
|
+
// Copy to ~/.crosschat/hooks/ so the path survives package updates
|
|
141
|
+
const stableDir = path.dirname(STABLE_HOOK);
|
|
142
|
+
fs.mkdirSync(stableDir, { recursive: true });
|
|
143
|
+
fs.copyFileSync(HOOK_SOURCE, STABLE_HOOK);
|
|
144
|
+
fs.chmodSync(STABLE_HOOK, 0o755);
|
|
145
|
+
|
|
146
146
|
if (!settings.hooks) settings.hooks = {};
|
|
147
147
|
if (!settings.hooks.PreToolUse) settings.hooks.PreToolUse = [];
|
|
148
148
|
|
|
149
|
-
const hookCommand =
|
|
149
|
+
const hookCommand = STABLE_HOOK;
|
|
150
150
|
const existingIdx = settings.hooks.PreToolUse.findIndex((entry) =>
|
|
151
151
|
entry.hooks &&
|
|
152
152
|
entry.hooks.some((h) => h.command && h.command.includes("permission-hook.sh"))
|
|
@@ -303,15 +303,13 @@ async function status() {
|
|
|
303
303
|
console.log("Dashboard: http://localhost:" + hubPort);
|
|
304
304
|
|
|
305
305
|
try {
|
|
306
|
-
const [peerList,
|
|
306
|
+
const [peerList, channelList] = await Promise.all([
|
|
307
307
|
hubGet(hubPort, "/api/peers"),
|
|
308
|
-
hubGet(hubPort, "/api/
|
|
309
|
-
hubGet(hubPort, "/api/rooms"),
|
|
308
|
+
hubGet(hubPort, "/api/channels"),
|
|
310
309
|
]);
|
|
311
310
|
|
|
312
311
|
const peers = Array.isArray(peerList) ? peerList : [];
|
|
313
|
-
const
|
|
314
|
-
const roomArr = Array.isArray(roomList) ? roomList : [];
|
|
312
|
+
const channels = Array.isArray(channelList) ? channelList : [];
|
|
315
313
|
|
|
316
314
|
console.log("");
|
|
317
315
|
console.log("Agents: " + peers.length + " connected");
|
|
@@ -320,16 +318,7 @@ async function status() {
|
|
|
320
318
|
console.log(" " + badge + " " + p.name + " — " + (p.cwd || "?"));
|
|
321
319
|
}
|
|
322
320
|
|
|
323
|
-
|
|
324
|
-
const byStatus = {};
|
|
325
|
-
for (const t of tasks) {
|
|
326
|
-
byStatus[t.status] = (byStatus[t.status] || 0) + 1;
|
|
327
|
-
}
|
|
328
|
-
const summary = Object.entries(byStatus).map(([k, v]) => v + " " + k).join(", ");
|
|
329
|
-
console.log("Tasks: " + tasks.length + " (" + summary + ")");
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
console.log("Rooms: " + roomArr.length);
|
|
321
|
+
console.log("Channels: " + channels.length);
|
|
333
322
|
} catch {
|
|
334
323
|
console.log("");
|
|
335
324
|
console.log("Hub not responding (port " + hubPort + ").");
|
|
@@ -456,7 +445,7 @@ async function peers() {
|
|
|
456
445
|
const detail = p.statusDetail ? " " + p.statusDetail : "";
|
|
457
446
|
console.log(" " + p.name + " " + badge + detail);
|
|
458
447
|
console.log(" ID: " + p.peerId);
|
|
459
|
-
console.log("
|
|
448
|
+
console.log(" Channel: " + (p.currentChannel || "general"));
|
|
460
449
|
console.log(" Directory: " + (p.cwd || "—"));
|
|
461
450
|
console.log(" Connected: " + (p.connectedAt ? timeAgo(p.connectedAt) : "—"));
|
|
462
451
|
console.log("");
|
|
@@ -485,7 +474,7 @@ async function tasks() {
|
|
|
485
474
|
}[t.status] || t.status.toUpperCase();
|
|
486
475
|
console.log(" [" + statusTag + "] " + t.description);
|
|
487
476
|
console.log(" ID: " + t.taskId);
|
|
488
|
-
console.log("
|
|
477
|
+
console.log(" Channel: " + (t.channelId || "—"));
|
|
489
478
|
console.log(" Creator: " + (t.creatorName || "—"));
|
|
490
479
|
if (t.claimantName) {
|
|
491
480
|
console.log(" Assignee: " + t.claimantName);
|
|
@@ -498,37 +487,27 @@ async function tasks() {
|
|
|
498
487
|
}
|
|
499
488
|
}
|
|
500
489
|
|
|
501
|
-
async function
|
|
490
|
+
async function channels() {
|
|
502
491
|
const port = requireHub();
|
|
503
|
-
const [
|
|
504
|
-
hubGet(port, "/api/
|
|
492
|
+
const [channelData, peerData] = await Promise.all([
|
|
493
|
+
hubGet(port, "/api/channels"),
|
|
505
494
|
hubGet(port, "/api/peers"),
|
|
506
495
|
]);
|
|
507
|
-
const
|
|
496
|
+
const channelList = Array.isArray(channelData) ? channelData : [];
|
|
508
497
|
const peerList = Array.isArray(peerData) ? peerData : [];
|
|
509
498
|
|
|
510
|
-
if (
|
|
511
|
-
console.log("No active
|
|
499
|
+
if (channelList.length === 0) {
|
|
500
|
+
console.log("No active channels.");
|
|
512
501
|
return;
|
|
513
502
|
}
|
|
514
503
|
|
|
515
|
-
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
console.log("Rooms (" + roomList.length + "):\n");
|
|
524
|
-
for (const r of roomList) {
|
|
525
|
-
const name = r.name || r.id;
|
|
526
|
-
const msgCount = r.messageCount != null ? r.messageCount : "?";
|
|
527
|
-
const roomPeers = peersPerRoom[name] || peersPerRoom[r.id] || [];
|
|
528
|
-
console.log(" " + name);
|
|
529
|
-
console.log(" Messages: " + msgCount + " Agents: " + roomPeers.length);
|
|
530
|
-
if (roomPeers.length > 0) {
|
|
531
|
-
console.log(" " + roomPeers.join(", "));
|
|
504
|
+
console.log("Channels (" + channelList.length + "):\n");
|
|
505
|
+
for (const ch of channelList) {
|
|
506
|
+
const agentsInChannel = peerList.filter((p) => (p.currentChannel || "general") === ch);
|
|
507
|
+
console.log(" # " + ch);
|
|
508
|
+
console.log(" Agents: " + agentsInChannel.length);
|
|
509
|
+
if (agentsInChannel.length > 0) {
|
|
510
|
+
console.log(" " + agentsInChannel.map((a) => a.name).join(", "));
|
|
532
511
|
}
|
|
533
512
|
console.log("");
|
|
534
513
|
}
|
|
@@ -589,10 +568,10 @@ function showHelp() {
|
|
|
589
568
|
console.log(" crosschat restart Restart the hub server");
|
|
590
569
|
console.log("");
|
|
591
570
|
console.log("Info:");
|
|
592
|
-
console.log(" crosschat status Overview of hub, agents,
|
|
571
|
+
console.log(" crosschat status Overview of hub, agents, and channels");
|
|
593
572
|
console.log(" crosschat peers List connected agents with details");
|
|
594
573
|
console.log(" crosschat tasks [status] List tasks (optional: open, claimed, completed, failed)");
|
|
595
|
-
console.log(" crosschat
|
|
574
|
+
console.log(" crosschat channels List active channels");
|
|
596
575
|
console.log("");
|
|
597
576
|
console.log(" crosschat --version Show version");
|
|
598
577
|
console.log(" crosschat --help Show this help");
|
|
@@ -633,8 +612,9 @@ switch (command) {
|
|
|
633
612
|
case "tasks":
|
|
634
613
|
tasks();
|
|
635
614
|
break;
|
|
615
|
+
case "channels":
|
|
636
616
|
case "rooms":
|
|
637
|
-
|
|
617
|
+
channels();
|
|
638
618
|
break;
|
|
639
619
|
case "--version":
|
|
640
620
|
case "-v":
|