@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 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 { Bonjour } from 'bonjour-service';
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 SERVICE_TYPE = "claude-collab";
673
- var MdnsAdvertiser = class {
674
- bonjour = null;
675
- start(port) {
676
- this.bonjour = new Bonjour();
677
- this.bonjour.publish({ name: "claude-collab-hub", type: SERVICE_TYPE, port });
678
- console.error(`[mdns] advertising hub on port ${port}`);
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 (!this.bonjour) return;
682
- this.bonjour.unpublishAll(() => {
683
- this.bonjour?.destroy();
684
- });
685
- this.bonjour = null;
686
- console.error("[mdns] stopped advertising");
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
- advertiser = null;
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 advertiser = new MdnsAdvertiser();
708
- advertiser.start(port);
709
- this.advertiser = advertiser;
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.advertiser) {
722
- this.advertiser.stop();
723
- this.advertiser = null;
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();