clawborrator-mcp 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.
@@ -0,0 +1,148 @@
1
+ import type { ChannelConfig } from './config.js';
2
+ type Outbound = {
3
+ type: 'register';
4
+ host: string;
5
+ cwd: string;
6
+ osUser: string | null;
7
+ pid: number;
8
+ channelVersion: string;
9
+ sessionId: string | null;
10
+ } | {
11
+ type: 'chat_event';
12
+ eventType: 'prompt' | 'reply';
13
+ payload: Record<string, unknown>;
14
+ ts: string;
15
+ } | {
16
+ type: 'tail_event';
17
+ eventType: 'PreToolUse' | 'PostToolUse' | 'Stop' | 'Notification' | 'UserPromptSubmit';
18
+ payload: Record<string, unknown>;
19
+ ts: string;
20
+ } | {
21
+ type: 'permission_request';
22
+ requestId: string;
23
+ tool: string;
24
+ inputPreview: string;
25
+ ts: string;
26
+ } | {
27
+ type: 'route_request';
28
+ correlationId: string;
29
+ peer: string;
30
+ prompt: string;
31
+ mode: 'ask' | 'tell';
32
+ } | {
33
+ type: 'probe_request';
34
+ correlationId: string;
35
+ peers: string[] | null;
36
+ prompt: string;
37
+ } | {
38
+ type: 'list_peers_request';
39
+ correlationId: string;
40
+ } | {
41
+ type: 'pong';
42
+ ts: string;
43
+ };
44
+ type Inbound = {
45
+ type: 'welcome';
46
+ sessionId: string;
47
+ routingName: string;
48
+ channelTokenName: string;
49
+ } | {
50
+ type: 'prompt';
51
+ chatId: string;
52
+ text: string;
53
+ } | {
54
+ type: 'permission_response';
55
+ requestId: string;
56
+ decision: 'allow' | 'deny' | 'expired';
57
+ message: string | null;
58
+ } | {
59
+ type: 'route_response';
60
+ correlationId: string;
61
+ peerLogin: string;
62
+ reply: string;
63
+ } | {
64
+ type: 'probe_response';
65
+ correlationId: string;
66
+ peerLogin: string | null;
67
+ answer: string | null;
68
+ done?: boolean;
69
+ } | {
70
+ type: 'list_peers_response';
71
+ correlationId: string;
72
+ peers: {
73
+ login: string;
74
+ name: string;
75
+ online: boolean;
76
+ }[];
77
+ } | {
78
+ type: 'peers_update';
79
+ peers: {
80
+ login: string;
81
+ name: string;
82
+ online: boolean;
83
+ }[];
84
+ } | {
85
+ type: 'bye';
86
+ reason: string;
87
+ retry: boolean;
88
+ } | {
89
+ type: 'ping';
90
+ ts: string;
91
+ } | {
92
+ type: 'error';
93
+ code: string;
94
+ message: string;
95
+ };
96
+ export interface ChannelClientHandlers {
97
+ onWelcome?: (msg: Extract<Inbound, {
98
+ type: 'welcome';
99
+ }>) => void;
100
+ onPrompt?: (msg: Extract<Inbound, {
101
+ type: 'prompt';
102
+ }>) => void;
103
+ onPermissionResponse?: (msg: Extract<Inbound, {
104
+ type: 'permission_response';
105
+ }>) => void;
106
+ onPeersUpdate?: (msg: Extract<Inbound, {
107
+ type: 'peers_update';
108
+ }>) => void;
109
+ onError?: (msg: Extract<Inbound, {
110
+ type: 'error';
111
+ }>) => void;
112
+ }
113
+ export declare class ChannelClient {
114
+ private readonly config;
115
+ private readonly handlers;
116
+ private ws;
117
+ private attempt;
118
+ private stopped;
119
+ private reconnectTimer;
120
+ private currentSessionId;
121
+ private pending;
122
+ constructor(config: ChannelConfig, handlers?: ChannelClientHandlers);
123
+ connect(): void;
124
+ /** Stop the client; do not reconnect. */
125
+ stop(): void;
126
+ /** Send a message to hub. Drops the message if the WS isn't open. */
127
+ send(msg: Outbound): void;
128
+ /** Send a request and await its single matching response. Used by
129
+ * list_peers and route_to_peer (ask mode). */
130
+ requestSingle<T>(msg: Outbound & {
131
+ correlationId: string;
132
+ }, timeoutMs: number): Promise<T>;
133
+ /** Send a probe_request and accumulate per-peer probe_response
134
+ * events until {done: true} or timeout. Resolves with whatever
135
+ * was collected. */
136
+ requestProbe(msg: Outbound & {
137
+ type: 'probe_request';
138
+ }, timeoutMs: number): Promise<{
139
+ peerLogin: string;
140
+ answer: string | null;
141
+ }[]>;
142
+ private onOpen;
143
+ private onMessage;
144
+ private onClose;
145
+ private onError;
146
+ private scheduleReconnect;
147
+ }
148
+ export {};
@@ -0,0 +1,196 @@
1
+ // WebSocket client to hub_v1's /channel endpoint. Owns the connect /
2
+ // register / heartbeat / reconnect-with-backoff loop. Exposes a small
3
+ // surface so the MCP entrypoint and hook handlers can post events
4
+ // without caring about reconnect state.
5
+ //
6
+ // Design (per IMPL-PLAN-1-CHANNEL-V1-FRESH-START §4.3):
7
+ // - First connect: register with sessionId=null
8
+ // - Reconnect: register with sessionId=<reuseSessionId env var if set,
9
+ // else null> — fresh session by default
10
+ // - Backoff: 1s, 2s, 5s, 15s, 30s, 60s capped at 60s
11
+ // - Heartbeat: server pings every ~25s; we pong; if 2 pings missed,
12
+ // drop and reconnect
13
+ import WebSocket from 'ws';
14
+ import { hostname, userInfo } from 'node:os';
15
+ import { log } from './log.js';
16
+ const BACKOFF_SCHEDULE = [1_000, 2_000, 5_000, 15_000, 30_000, 60_000];
17
+ const PACKAGE_VERSION = '0.0.1';
18
+ export class ChannelClient {
19
+ config;
20
+ handlers;
21
+ ws = null;
22
+ attempt = 0;
23
+ stopped = false;
24
+ reconnectTimer = null;
25
+ currentSessionId;
26
+ pending = new Map();
27
+ constructor(config, handlers = {}) {
28
+ this.config = config;
29
+ this.handlers = handlers;
30
+ this.currentSessionId = config.reuseSessionId;
31
+ }
32
+ connect() {
33
+ if (this.stopped)
34
+ return;
35
+ const url = `${this.config.hubUrl}/channel`;
36
+ log.info('connecting', { url, attempt: this.attempt });
37
+ this.ws = new WebSocket(url, {
38
+ headers: { Authorization: `Bearer ${this.config.token}` },
39
+ });
40
+ this.ws.on('open', () => this.onOpen());
41
+ this.ws.on('message', (data) => this.onMessage(data.toString('utf8')));
42
+ this.ws.on('close', (code, reason) => this.onClose(code, reason.toString()));
43
+ this.ws.on('error', (err) => this.onError(err));
44
+ }
45
+ /** Stop the client; do not reconnect. */
46
+ stop() {
47
+ this.stopped = true;
48
+ if (this.reconnectTimer)
49
+ clearTimeout(this.reconnectTimer);
50
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
51
+ this.ws.close(1000, 'stop');
52
+ }
53
+ }
54
+ /** Send a message to hub. Drops the message if the WS isn't open. */
55
+ send(msg) {
56
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
57
+ log.warn('drop send (ws not open)', { type: msg.type });
58
+ return;
59
+ }
60
+ this.ws.send(JSON.stringify(msg));
61
+ }
62
+ /** Send a request and await its single matching response. Used by
63
+ * list_peers and route_to_peer (ask mode). */
64
+ requestSingle(msg, timeoutMs) {
65
+ return new Promise((resolve, reject) => {
66
+ const timer = setTimeout(() => {
67
+ this.pending.delete(msg.correlationId);
68
+ reject(new Error(`request timed out (correlationId=${msg.correlationId})`));
69
+ }, timeoutMs);
70
+ this.pending.set(msg.correlationId, { kind: 'single', resolve, reject, timer });
71
+ this.send(msg);
72
+ });
73
+ }
74
+ /** Send a probe_request and accumulate per-peer probe_response
75
+ * events until {done: true} or timeout. Resolves with whatever
76
+ * was collected. */
77
+ requestProbe(msg, timeoutMs) {
78
+ return new Promise((resolve) => {
79
+ const results = [];
80
+ const timer = setTimeout(() => {
81
+ this.pending.delete(msg.correlationId);
82
+ resolve(results);
83
+ }, timeoutMs);
84
+ this.pending.set(msg.correlationId, { kind: 'probe', results, resolve, timer });
85
+ this.send(msg);
86
+ });
87
+ }
88
+ onOpen() {
89
+ log.info('ws open');
90
+ this.attempt = 0;
91
+ const reg = {
92
+ type: 'register',
93
+ host: hostname(),
94
+ cwd: process.cwd(),
95
+ osUser: userInfo().username || null,
96
+ pid: process.pid,
97
+ channelVersion: PACKAGE_VERSION,
98
+ sessionId: this.currentSessionId, // null on fresh, populated on rebind
99
+ };
100
+ this.send(reg);
101
+ }
102
+ onMessage(text) {
103
+ let msg;
104
+ try {
105
+ msg = JSON.parse(text);
106
+ }
107
+ catch (e) {
108
+ log.warn('bad message', { text, err: String(e) });
109
+ return;
110
+ }
111
+ log.debug('recv', { type: msg.type });
112
+ switch (msg.type) {
113
+ case 'welcome':
114
+ this.currentSessionId = msg.sessionId;
115
+ log.info('welcomed', { sessionId: msg.sessionId, routingName: msg.routingName });
116
+ this.handlers.onWelcome?.(msg);
117
+ break;
118
+ case 'ping':
119
+ this.send({ type: 'pong', ts: new Date().toISOString() });
120
+ break;
121
+ case 'prompt':
122
+ this.handlers.onPrompt?.(msg);
123
+ break;
124
+ case 'permission_response':
125
+ this.handlers.onPermissionResponse?.(msg);
126
+ break;
127
+ case 'peers_update':
128
+ this.handlers.onPeersUpdate?.(msg);
129
+ break;
130
+ case 'list_peers_response': {
131
+ const p = this.pending.get(msg.correlationId);
132
+ if (p && p.kind === 'single') {
133
+ clearTimeout(p.timer);
134
+ this.pending.delete(msg.correlationId);
135
+ p.resolve(msg.peers);
136
+ }
137
+ break;
138
+ }
139
+ case 'route_response': {
140
+ const p = this.pending.get(msg.correlationId);
141
+ if (p && p.kind === 'single') {
142
+ clearTimeout(p.timer);
143
+ this.pending.delete(msg.correlationId);
144
+ p.resolve({ peerLogin: msg.peerLogin, reply: msg.reply });
145
+ }
146
+ break;
147
+ }
148
+ case 'probe_response': {
149
+ const p = this.pending.get(msg.correlationId);
150
+ if (!p || p.kind !== 'probe')
151
+ break;
152
+ if (msg.done) {
153
+ clearTimeout(p.timer);
154
+ this.pending.delete(msg.correlationId);
155
+ p.resolve(p.results);
156
+ }
157
+ else if (msg.peerLogin) {
158
+ p.results.push({ peerLogin: msg.peerLogin, answer: msg.answer });
159
+ }
160
+ break;
161
+ }
162
+ case 'bye':
163
+ log.info('bye from hub', { reason: msg.reason, retry: msg.retry });
164
+ if (!msg.retry)
165
+ this.stopped = true;
166
+ break;
167
+ case 'error':
168
+ log.error('hub error', { code: msg.code, message: msg.message });
169
+ this.handlers.onError?.(msg);
170
+ // Auth failures are fatal — don't loop on a revoked token.
171
+ if (msg.code === 'auth_failed' || msg.code === 'token_revoked') {
172
+ this.stopped = true;
173
+ this.ws?.close(1008, msg.code);
174
+ process.exit(2);
175
+ }
176
+ break;
177
+ }
178
+ }
179
+ onClose(code, reason) {
180
+ log.info('ws close', { code, reason });
181
+ this.ws = null;
182
+ if (!this.stopped)
183
+ this.scheduleReconnect();
184
+ }
185
+ onError(err) {
186
+ log.warn('ws error', { message: err.message });
187
+ // The 'close' handler runs after; let it own reconnect scheduling.
188
+ }
189
+ scheduleReconnect() {
190
+ const delay = BACKOFF_SCHEDULE[Math.min(this.attempt, BACKOFF_SCHEDULE.length - 1)];
191
+ this.attempt += 1;
192
+ log.info('reconnecting', { delayMs: delay, attempt: this.attempt });
193
+ this.reconnectTimer = setTimeout(() => this.connect(), delay);
194
+ }
195
+ }
196
+ //# sourceMappingURL=ws-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "clawborrator-mcp",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "description": "clawborrator channel for hub_v1 — MCP server that connects Claude Code to a hub over WebSocket, with hooks for activity capture and tools for cross-session routing.",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/clawborrator/channel_v1",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/clawborrator/channel_v1.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/clawborrator/channel_v1/issues"
14
+ },
15
+ "keywords": [
16
+ "claude-code",
17
+ "mcp",
18
+ "clawborrator",
19
+ "websocket",
20
+ "remote",
21
+ "ai",
22
+ "agent",
23
+ "hub-v1"
24
+ ],
25
+ "main": "dist/index.js",
26
+ "bin": {
27
+ "clawborrator-mcp": "bin/clawborrator-mcp"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "bin",
32
+ "README.md"
33
+ ],
34
+ "engines": {
35
+ "node": ">=20"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -p tsconfig.json",
39
+ "dev": "tsx watch src/index.ts",
40
+ "typecheck": "tsc -p tsconfig.json --noEmit",
41
+ "start": "node dist/index.js",
42
+ "prepublishOnly": "npm run build"
43
+ },
44
+ "dependencies": {
45
+ "@modelcontextprotocol/sdk": "^1.0.4",
46
+ "ws": "^8.18.0"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^22.7.5",
50
+ "@types/ws": "^8.5.13",
51
+ "tsx": "^4.19.1",
52
+ "typescript": "^5.6.2"
53
+ }
54
+ }