@dolusoft/claude-collab 1.8.4 → 1.8.6
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/dist/cli.js +133 -56
- package/dist/cli.js.map +1 -1
- package/dist/mcp-main.js +133 -56
- package/dist/mcp-main.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { execFile, spawn } from 'child_process';
|
|
|
7
7
|
import { unlinkSync } from 'fs';
|
|
8
8
|
import { tmpdir } from 'os';
|
|
9
9
|
import { join } from 'path';
|
|
10
|
-
import {
|
|
10
|
+
import { createSocket } from 'dgram';
|
|
11
11
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
12
12
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
13
|
import { z } from 'zod';
|
|
@@ -669,28 +669,48 @@ var HubClient = class {
|
|
|
669
669
|
});
|
|
670
670
|
}
|
|
671
671
|
};
|
|
672
|
-
var
|
|
673
|
-
var
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
672
|
+
var DISCOVERY_PORT = 9998;
|
|
673
|
+
var BROADCAST_INTERVAL_MS = 3e3;
|
|
674
|
+
var BROADCAST_ADDRESS = "255.255.255.255";
|
|
675
|
+
var HubBroadcaster = class {
|
|
676
|
+
socket = null;
|
|
677
|
+
timer = null;
|
|
678
|
+
start(hubPort) {
|
|
679
|
+
if (this.socket) return;
|
|
680
|
+
const socket = createSocket("udp4");
|
|
681
|
+
this.socket = socket;
|
|
682
|
+
socket.on("error", (err) => {
|
|
683
|
+
console.error("[hub-broadcaster] error:", err.message);
|
|
684
|
+
});
|
|
685
|
+
socket.bind(0, () => {
|
|
686
|
+
socket.setBroadcast(true);
|
|
687
|
+
const send = () => {
|
|
688
|
+
if (!this.socket) return;
|
|
689
|
+
const msg = Buffer.from(JSON.stringify({ type: "claude-collab-hub", port: hubPort }));
|
|
690
|
+
socket.send(msg, 0, msg.length, DISCOVERY_PORT, BROADCAST_ADDRESS, (err) => {
|
|
691
|
+
if (err) console.error("[hub-broadcaster] send error:", err.message);
|
|
692
|
+
});
|
|
693
|
+
};
|
|
694
|
+
send();
|
|
695
|
+
this.timer = setInterval(send, BROADCAST_INTERVAL_MS);
|
|
696
|
+
});
|
|
679
697
|
}
|
|
680
698
|
stop() {
|
|
681
|
-
if (
|
|
682
|
-
|
|
683
|
-
this.
|
|
684
|
-
}
|
|
685
|
-
this.
|
|
686
|
-
|
|
699
|
+
if (this.timer) {
|
|
700
|
+
clearInterval(this.timer);
|
|
701
|
+
this.timer = null;
|
|
702
|
+
}
|
|
703
|
+
if (this.socket) {
|
|
704
|
+
this.socket.close();
|
|
705
|
+
this.socket = null;
|
|
706
|
+
}
|
|
687
707
|
}
|
|
688
708
|
};
|
|
689
709
|
|
|
690
710
|
// src/infrastructure/hub/hub-manager.ts
|
|
691
711
|
var HubManager = class {
|
|
692
712
|
hubServer = null;
|
|
693
|
-
|
|
713
|
+
broadcaster = null;
|
|
694
714
|
currentPort = null;
|
|
695
715
|
get isRunning() {
|
|
696
716
|
return this.hubServer !== null;
|
|
@@ -704,9 +724,9 @@ var HubManager = class {
|
|
|
704
724
|
server.start(port);
|
|
705
725
|
this.hubServer = server;
|
|
706
726
|
this.currentPort = port;
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
this.
|
|
727
|
+
const broadcaster = new HubBroadcaster();
|
|
728
|
+
broadcaster.start(port);
|
|
729
|
+
this.broadcaster = broadcaster;
|
|
710
730
|
let firewallAdded = false;
|
|
711
731
|
try {
|
|
712
732
|
await addFirewallRule(port);
|
|
@@ -718,9 +738,9 @@ var HubManager = class {
|
|
|
718
738
|
}
|
|
719
739
|
async stop() {
|
|
720
740
|
if (!this.isRunning) throw new Error("Hub is not running");
|
|
721
|
-
if (this.
|
|
722
|
-
this.
|
|
723
|
-
this.
|
|
741
|
+
if (this.broadcaster) {
|
|
742
|
+
this.broadcaster.stop();
|
|
743
|
+
this.broadcaster = null;
|
|
724
744
|
}
|
|
725
745
|
const port = this.currentPort;
|
|
726
746
|
this.hubServer.stop();
|
|
@@ -1015,6 +1035,97 @@ function registerStopHubTool(server, hubManager) {
|
|
|
1015
1035
|
}
|
|
1016
1036
|
);
|
|
1017
1037
|
}
|
|
1038
|
+
function discoverHub(timeoutMs = 1e4) {
|
|
1039
|
+
return new Promise((resolve) => {
|
|
1040
|
+
const socket = createSocket("udp4");
|
|
1041
|
+
let settled = false;
|
|
1042
|
+
const finish = (result) => {
|
|
1043
|
+
if (settled) return;
|
|
1044
|
+
settled = true;
|
|
1045
|
+
clearTimeout(timer);
|
|
1046
|
+
try {
|
|
1047
|
+
socket.close();
|
|
1048
|
+
} catch {
|
|
1049
|
+
}
|
|
1050
|
+
resolve(result);
|
|
1051
|
+
};
|
|
1052
|
+
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
1053
|
+
socket.on("error", () => finish(null));
|
|
1054
|
+
socket.on("message", (msg, rinfo) => {
|
|
1055
|
+
try {
|
|
1056
|
+
const data = JSON.parse(msg.toString());
|
|
1057
|
+
if (data.type === "claude-collab-hub" && typeof data.port === "number") {
|
|
1058
|
+
finish({ host: rinfo.address, port: data.port });
|
|
1059
|
+
}
|
|
1060
|
+
} catch {
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
socket.bind(DISCOVERY_PORT, "0.0.0.0");
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
function watchForHub(onFound) {
|
|
1067
|
+
const socket = createSocket("udp4");
|
|
1068
|
+
socket.on("error", (err) => {
|
|
1069
|
+
console.error("[hub-listener] error:", err.message);
|
|
1070
|
+
});
|
|
1071
|
+
socket.on("message", (msg, rinfo) => {
|
|
1072
|
+
try {
|
|
1073
|
+
const data = JSON.parse(msg.toString());
|
|
1074
|
+
if (data.type === "claude-collab-hub" && typeof data.port === "number") {
|
|
1075
|
+
onFound({ host: rinfo.address, port: data.port });
|
|
1076
|
+
}
|
|
1077
|
+
} catch {
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
socket.bind(DISCOVERY_PORT, "0.0.0.0");
|
|
1081
|
+
return () => {
|
|
1082
|
+
try {
|
|
1083
|
+
socket.close();
|
|
1084
|
+
} catch {
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// src/presentation/mcp/tools/connect.tool.ts
|
|
1090
|
+
function registerConnectTool(server, client) {
|
|
1091
|
+
server.tool(
|
|
1092
|
+
"connect",
|
|
1093
|
+
"Find and connect to the hub on the LAN automatically. No IP or port needed.",
|
|
1094
|
+
{},
|
|
1095
|
+
async () => {
|
|
1096
|
+
if (client.isConnected) {
|
|
1097
|
+
const info = client.getInfo();
|
|
1098
|
+
return {
|
|
1099
|
+
content: [{ type: "text", text: `Already connected to hub as "${info.teamName}".` }]
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
const hub = await discoverHub(1e4);
|
|
1103
|
+
if (!hub) {
|
|
1104
|
+
return {
|
|
1105
|
+
content: [{
|
|
1106
|
+
type: "text",
|
|
1107
|
+
text: "No hub found on the LAN. Make sure someone has called start_hub on the host machine."
|
|
1108
|
+
}]
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
try {
|
|
1112
|
+
await client.connectToHub(`ws://${hub.host}:${hub.port}`);
|
|
1113
|
+
const info = client.getInfo();
|
|
1114
|
+
return {
|
|
1115
|
+
content: [{
|
|
1116
|
+
type: "text",
|
|
1117
|
+
text: `Connected to hub at ${hub.host}:${hub.port} as "${info.teamName}".`
|
|
1118
|
+
}]
|
|
1119
|
+
};
|
|
1120
|
+
} catch (err) {
|
|
1121
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1122
|
+
return {
|
|
1123
|
+
content: [{ type: "text", text: `Hub found at ${hub.host}:${hub.port} but connection failed: ${msg}` }]
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1018
1129
|
|
|
1019
1130
|
// src/presentation/mcp/server.ts
|
|
1020
1131
|
function createMcpServer(options) {
|
|
@@ -1029,6 +1140,7 @@ function createMcpServer(options) {
|
|
|
1029
1140
|
registerHistoryTool(server, client);
|
|
1030
1141
|
registerStartHubTool(server, client, hubManager);
|
|
1031
1142
|
registerStopHubTool(server, hubManager);
|
|
1143
|
+
registerConnectTool(server, client);
|
|
1032
1144
|
return server;
|
|
1033
1145
|
}
|
|
1034
1146
|
async function startMcpServer(options) {
|
|
@@ -1036,41 +1148,6 @@ async function startMcpServer(options) {
|
|
|
1036
1148
|
const transport = new StdioServerTransport();
|
|
1037
1149
|
await server.connect(transport);
|
|
1038
1150
|
}
|
|
1039
|
-
var SERVICE_TYPE2 = "claude-collab";
|
|
1040
|
-
function resolveHost(svc) {
|
|
1041
|
-
const ipv4 = svc.addresses?.find((a) => /^\d+\.\d+\.\d+\.\d+$/.test(a));
|
|
1042
|
-
return ipv4 ?? svc.host;
|
|
1043
|
-
}
|
|
1044
|
-
function discoverHub(timeoutMs = 5e3) {
|
|
1045
|
-
return new Promise((resolve) => {
|
|
1046
|
-
const bonjour = new Bonjour();
|
|
1047
|
-
const browser = bonjour.find({ type: SERVICE_TYPE2 });
|
|
1048
|
-
let settled = false;
|
|
1049
|
-
const finish = (result) => {
|
|
1050
|
-
if (settled) return;
|
|
1051
|
-
settled = true;
|
|
1052
|
-
clearTimeout(timer);
|
|
1053
|
-
browser.stop();
|
|
1054
|
-
bonjour.destroy();
|
|
1055
|
-
resolve(result);
|
|
1056
|
-
};
|
|
1057
|
-
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
1058
|
-
browser.on("up", (svc) => {
|
|
1059
|
-
finish({ host: resolveHost(svc), port: svc.port });
|
|
1060
|
-
});
|
|
1061
|
-
});
|
|
1062
|
-
}
|
|
1063
|
-
function watchForHub(onFound) {
|
|
1064
|
-
const bonjour = new Bonjour();
|
|
1065
|
-
const browser = bonjour.find({ type: SERVICE_TYPE2 });
|
|
1066
|
-
browser.on("up", (svc) => {
|
|
1067
|
-
onFound({ host: resolveHost(svc), port: svc.port });
|
|
1068
|
-
});
|
|
1069
|
-
return () => {
|
|
1070
|
-
browser.stop();
|
|
1071
|
-
bonjour.destroy();
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
1074
1151
|
|
|
1075
1152
|
// src/cli.ts
|
|
1076
1153
|
var program = new Command();
|