lockin-mcp 1.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.
Files changed (175) hide show
  1. package/README.md +349 -0
  2. package/assets/icon-256.png +0 -0
  3. package/assets/icon-32.png +0 -0
  4. package/assets/icon.svg +4 -0
  5. package/dist/blocker.d.ts +23 -0
  6. package/dist/blocker.d.ts.map +1 -0
  7. package/dist/blocker.js +184 -0
  8. package/dist/blocker.js.map +1 -0
  9. package/dist/brand.d.ts +12 -0
  10. package/dist/brand.d.ts.map +1 -0
  11. package/dist/brand.js +12 -0
  12. package/dist/brand.js.map +1 -0
  13. package/dist/hosts-manager.d.ts +14 -0
  14. package/dist/hosts-manager.d.ts.map +1 -0
  15. package/dist/hosts-manager.js +233 -0
  16. package/dist/hosts-manager.js.map +1 -0
  17. package/dist/hosts-manager.test.d.ts +2 -0
  18. package/dist/hosts-manager.test.d.ts.map +1 -0
  19. package/dist/hosts-manager.test.js +19 -0
  20. package/dist/hosts-manager.test.js.map +1 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +296 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/install.d.ts +3 -0
  26. package/dist/install.d.ts.map +1 -0
  27. package/dist/install.js +15 -0
  28. package/dist/install.js.map +1 -0
  29. package/dist/installer/agent-instructions.d.ts +25 -0
  30. package/dist/installer/agent-instructions.d.ts.map +1 -0
  31. package/dist/installer/agent-instructions.js +36 -0
  32. package/dist/installer/agent-instructions.js.map +1 -0
  33. package/dist/installer/agents.d.ts +9 -0
  34. package/dist/installer/agents.d.ts.map +1 -0
  35. package/dist/installer/agents.js +223 -0
  36. package/dist/installer/agents.js.map +1 -0
  37. package/dist/installer/background-service.d.ts +11 -0
  38. package/dist/installer/background-service.d.ts.map +1 -0
  39. package/dist/installer/background-service.js +47 -0
  40. package/dist/installer/background-service.js.map +1 -0
  41. package/dist/installer/clipboard.d.ts +2 -0
  42. package/dist/installer/clipboard.d.ts.map +1 -0
  43. package/dist/installer/clipboard.js +28 -0
  44. package/dist/installer/clipboard.js.map +1 -0
  45. package/dist/installer/daemon-linux.d.ts +10 -0
  46. package/dist/installer/daemon-linux.d.ts.map +1 -0
  47. package/dist/installer/daemon-linux.js +66 -0
  48. package/dist/installer/daemon-linux.js.map +1 -0
  49. package/dist/installer/daemon-windows.d.ts +10 -0
  50. package/dist/installer/daemon-windows.d.ts.map +1 -0
  51. package/dist/installer/daemon-windows.js +88 -0
  52. package/dist/installer/daemon-windows.js.map +1 -0
  53. package/dist/installer/daemon.d.ts +10 -0
  54. package/dist/installer/daemon.d.ts.map +1 -0
  55. package/dist/installer/daemon.js +96 -0
  56. package/dist/installer/daemon.js.map +1 -0
  57. package/dist/installer/hosts-sudo.d.ts +6 -0
  58. package/dist/installer/hosts-sudo.d.ts.map +1 -0
  59. package/dist/installer/hosts-sudo.js +111 -0
  60. package/dist/installer/hosts-sudo.js.map +1 -0
  61. package/dist/installer/legacy-tunnels.d.ts +2 -0
  62. package/dist/installer/legacy-tunnels.d.ts.map +1 -0
  63. package/dist/installer/legacy-tunnels.js +27 -0
  64. package/dist/installer/legacy-tunnels.js.map +1 -0
  65. package/dist/installer/license.d.ts +9 -0
  66. package/dist/installer/license.d.ts.map +1 -0
  67. package/dist/installer/license.js +193 -0
  68. package/dist/installer/license.js.map +1 -0
  69. package/dist/installer/mcp-cleanup.d.ts +3 -0
  70. package/dist/installer/mcp-cleanup.d.ts.map +1 -0
  71. package/dist/installer/mcp-cleanup.js +28 -0
  72. package/dist/installer/mcp-cleanup.js.map +1 -0
  73. package/dist/installer/platform.d.ts +7 -0
  74. package/dist/installer/platform.d.ts.map +1 -0
  75. package/dist/installer/platform.js +76 -0
  76. package/dist/installer/platform.js.map +1 -0
  77. package/dist/installer/poke-daemon.d.ts +14 -0
  78. package/dist/installer/poke-daemon.d.ts.map +1 -0
  79. package/dist/installer/poke-daemon.js +161 -0
  80. package/dist/installer/poke-daemon.js.map +1 -0
  81. package/dist/installer/poke.d.ts +43 -0
  82. package/dist/installer/poke.d.ts.map +1 -0
  83. package/dist/installer/poke.js +154 -0
  84. package/dist/installer/poke.js.map +1 -0
  85. package/dist/installer/port.d.ts +6 -0
  86. package/dist/installer/port.d.ts.map +1 -0
  87. package/dist/installer/port.js +76 -0
  88. package/dist/installer/port.js.map +1 -0
  89. package/dist/installer/presets.d.ts +5 -0
  90. package/dist/installer/presets.d.ts.map +1 -0
  91. package/dist/installer/presets.js +22 -0
  92. package/dist/installer/presets.js.map +1 -0
  93. package/dist/installer/prompts.d.ts +8 -0
  94. package/dist/installer/prompts.d.ts.map +1 -0
  95. package/dist/installer/prompts.js +128 -0
  96. package/dist/installer/prompts.js.map +1 -0
  97. package/dist/installer/relay-credentials.d.ts +26 -0
  98. package/dist/installer/relay-credentials.d.ts.map +1 -0
  99. package/dist/installer/relay-credentials.js +75 -0
  100. package/dist/installer/relay-credentials.js.map +1 -0
  101. package/dist/installer/relay-provision.d.ts +26 -0
  102. package/dist/installer/relay-provision.d.ts.map +1 -0
  103. package/dist/installer/relay-provision.js +57 -0
  104. package/dist/installer/relay-provision.js.map +1 -0
  105. package/dist/installer/run.d.ts +2 -0
  106. package/dist/installer/run.d.ts.map +1 -0
  107. package/dist/installer/run.js +365 -0
  108. package/dist/installer/run.js.map +1 -0
  109. package/dist/installer/tty.d.ts +7 -0
  110. package/dist/installer/tty.d.ts.map +1 -0
  111. package/dist/installer/tty.js +37 -0
  112. package/dist/installer/tty.js.map +1 -0
  113. package/dist/installer/tui.d.ts +14 -0
  114. package/dist/installer/tui.d.ts.map +1 -0
  115. package/dist/installer/tui.js +150 -0
  116. package/dist/installer/tui.js.map +1 -0
  117. package/dist/installer/tunnel-daemon.d.ts +13 -0
  118. package/dist/installer/tunnel-daemon.d.ts.map +1 -0
  119. package/dist/installer/tunnel-daemon.js +129 -0
  120. package/dist/installer/tunnel-daemon.js.map +1 -0
  121. package/dist/installer/tunnel-provision.d.ts +14 -0
  122. package/dist/installer/tunnel-provision.d.ts.map +1 -0
  123. package/dist/installer/tunnel-provision.js +31 -0
  124. package/dist/installer/tunnel-provision.js.map +1 -0
  125. package/dist/installer/tunnel.d.ts +12 -0
  126. package/dist/installer/tunnel.d.ts.map +1 -0
  127. package/dist/installer/tunnel.js +91 -0
  128. package/dist/installer/tunnel.js.map +1 -0
  129. package/dist/installer/types.d.ts +59 -0
  130. package/dist/installer/types.d.ts.map +1 -0
  131. package/dist/installer/types.js +2 -0
  132. package/dist/installer/types.js.map +1 -0
  133. package/dist/license-check.d.ts +12 -0
  134. package/dist/license-check.d.ts.map +1 -0
  135. package/dist/license-check.js +59 -0
  136. package/dist/license-check.js.map +1 -0
  137. package/dist/license-guard.d.ts +14 -0
  138. package/dist/license-guard.d.ts.map +1 -0
  139. package/dist/license-guard.js +56 -0
  140. package/dist/license-guard.js.map +1 -0
  141. package/dist/license-guard.test.d.ts +2 -0
  142. package/dist/license-guard.test.d.ts.map +1 -0
  143. package/dist/license-guard.test.js +34 -0
  144. package/dist/license-guard.test.js.map +1 -0
  145. package/dist/relay-client.d.ts +32 -0
  146. package/dist/relay-client.d.ts.map +1 -0
  147. package/dist/relay-client.js +249 -0
  148. package/dist/relay-client.js.map +1 -0
  149. package/dist/relay-types.d.ts +30 -0
  150. package/dist/relay-types.d.ts.map +1 -0
  151. package/dist/relay-types.js +2 -0
  152. package/dist/relay-types.js.map +1 -0
  153. package/dist/relay-urls.d.ts +22 -0
  154. package/dist/relay-urls.d.ts.map +1 -0
  155. package/dist/relay-urls.js +57 -0
  156. package/dist/relay-urls.js.map +1 -0
  157. package/dist/server.d.ts +6 -0
  158. package/dist/server.d.ts.map +1 -0
  159. package/dist/server.js +164 -0
  160. package/dist/server.js.map +1 -0
  161. package/dist/state.d.ts +12 -0
  162. package/dist/state.d.ts.map +1 -0
  163. package/dist/state.js +91 -0
  164. package/dist/state.js.map +1 -0
  165. package/dist/types.d.ts +40 -0
  166. package/dist/types.d.ts.map +1 -0
  167. package/dist/types.js +41 -0
  168. package/dist/types.js.map +1 -0
  169. package/dist/types.test.d.ts +2 -0
  170. package/dist/types.test.d.ts.map +1 -0
  171. package/dist/types.test.js +13 -0
  172. package/dist/types.test.js.map +1 -0
  173. package/install.ps1 +41 -0
  174. package/install.sh +39 -0
  175. package/package.json +64 -0
@@ -0,0 +1,249 @@
1
+ import WebSocket from "ws";
2
+ export class RelayClient {
3
+ config;
4
+ ws = null;
5
+ reconnectDelayMs = 1000;
6
+ maxReconnectDelayMs = 30_000;
7
+ stopped = false;
8
+ heartbeatTimer = null;
9
+ constructor(config) {
10
+ this.config = config;
11
+ }
12
+ start() {
13
+ this.stopped = false;
14
+ void this.connect();
15
+ }
16
+ stop() {
17
+ this.stopped = true;
18
+ if (this.heartbeatTimer) {
19
+ clearInterval(this.heartbeatTimer);
20
+ this.heartbeatTimer = null;
21
+ }
22
+ this.ws?.close(1000, "shutdown");
23
+ this.ws = null;
24
+ }
25
+ log(message) {
26
+ this.config.onLog?.(message);
27
+ }
28
+ connectUrl() {
29
+ const base = this.config.relayUrl.replace(/\/$/, "");
30
+ const wsBase = base.replace(/^http/, "ws");
31
+ const connectBase = wsBase.endsWith("/connect")
32
+ ? wsBase
33
+ : `${wsBase}/connect`;
34
+ return `${connectBase}?deviceId=${encodeURIComponent(this.config.deviceId)}`;
35
+ }
36
+ async connect() {
37
+ if (this.stopped) {
38
+ return;
39
+ }
40
+ const url = this.connectUrl();
41
+ this.log(`Connecting to relay at ${url}`);
42
+ const ws = new WebSocket(url, {
43
+ headers: {
44
+ Authorization: `Bearer ${this.config.deviceToken}`,
45
+ },
46
+ });
47
+ this.ws = ws;
48
+ ws.on("open", () => {
49
+ this.log("Relay connected");
50
+ this.reconnectDelayMs = 1000;
51
+ this.startHeartbeat();
52
+ });
53
+ ws.on("message", (data) => {
54
+ void this.handleMessage(data.toString());
55
+ });
56
+ ws.on("close", () => {
57
+ this.log("Relay disconnected");
58
+ this.stopHeartbeat();
59
+ this.ws = null;
60
+ this.scheduleReconnect();
61
+ });
62
+ ws.on("error", (error) => {
63
+ this.log(`Relay socket error: ${error instanceof Error ? error.message : String(error)}`);
64
+ });
65
+ }
66
+ scheduleReconnect() {
67
+ if (this.stopped) {
68
+ return;
69
+ }
70
+ const delay = this.reconnectDelayMs;
71
+ this.reconnectDelayMs = Math.min(this.reconnectDelayMs * 2, this.maxReconnectDelayMs);
72
+ this.log(`Reconnecting in ${delay}ms`);
73
+ setTimeout(() => {
74
+ void this.connect();
75
+ }, delay);
76
+ }
77
+ startHeartbeat() {
78
+ this.stopHeartbeat();
79
+ this.heartbeatTimer = setInterval(() => {
80
+ this.send({ type: "ping" });
81
+ }, 30_000);
82
+ }
83
+ stopHeartbeat() {
84
+ if (this.heartbeatTimer) {
85
+ clearInterval(this.heartbeatTimer);
86
+ this.heartbeatTimer = null;
87
+ }
88
+ }
89
+ send(message) {
90
+ if (this.ws?.readyState === WebSocket.OPEN) {
91
+ this.ws.send(JSON.stringify(message));
92
+ }
93
+ }
94
+ async handleMessage(raw) {
95
+ let message;
96
+ try {
97
+ message = JSON.parse(raw);
98
+ }
99
+ catch {
100
+ return;
101
+ }
102
+ if (message.type === "ping") {
103
+ this.send({ type: "pong" });
104
+ return;
105
+ }
106
+ if (message.type === "http") {
107
+ await this.handleHttpBridge(message);
108
+ }
109
+ }
110
+ localOrigin() {
111
+ return `http://127.0.0.1:${this.config.localPort}`;
112
+ }
113
+ async handleHttpBridge(request) {
114
+ const url = `${this.localOrigin()}${request.path}`;
115
+ const isSse = request.method === "GET" &&
116
+ (request.path === "/sse" || request.path.startsWith("/sse?"));
117
+ if (isSse) {
118
+ await this.handleSseBridge(request);
119
+ return;
120
+ }
121
+ try {
122
+ const headers = new Headers(request.headers);
123
+ let body;
124
+ if (request.body !== undefined) {
125
+ body =
126
+ typeof request.body === "string"
127
+ ? request.body
128
+ : JSON.stringify(request.body);
129
+ if (!headers.has("content-type")) {
130
+ headers.set("content-type", "application/json");
131
+ }
132
+ }
133
+ const response = await fetch(url, {
134
+ method: request.method,
135
+ headers,
136
+ body: body ?? (request.method === "GET" ? undefined : ""),
137
+ });
138
+ const contentType = response.headers.get("content-type") ?? "";
139
+ let responseBody;
140
+ if (contentType.includes("application/json")) {
141
+ responseBody = await response.json();
142
+ }
143
+ else {
144
+ const text = await response.text();
145
+ responseBody = text.length > 0 ? text : undefined;
146
+ }
147
+ const responseHeaders = {};
148
+ response.headers.forEach((value, key) => {
149
+ responseHeaders[key] = value;
150
+ });
151
+ this.send({
152
+ type: "http_response",
153
+ requestId: request.requestId,
154
+ status: response.status,
155
+ headers: responseHeaders,
156
+ body: responseBody,
157
+ });
158
+ }
159
+ catch (error) {
160
+ this.send({
161
+ type: "http_response",
162
+ requestId: request.requestId,
163
+ status: 502,
164
+ headers: { "content-type": "application/json" },
165
+ body: {
166
+ error: error instanceof Error ? error.message : "Local proxy failed",
167
+ },
168
+ });
169
+ }
170
+ }
171
+ async handleSseBridge(request) {
172
+ const url = `${this.localOrigin()}${request.path}`;
173
+ try {
174
+ const response = await fetch(url, {
175
+ method: "GET",
176
+ headers: request.headers,
177
+ });
178
+ if (!response.ok || !response.body) {
179
+ this.send({
180
+ type: "http_response",
181
+ requestId: request.requestId,
182
+ status: response.status,
183
+ headers: { "content-type": "text/plain" },
184
+ body: await response.text(),
185
+ });
186
+ return;
187
+ }
188
+ const reader = response.body.getReader();
189
+ const decoder = new TextDecoder();
190
+ while (true) {
191
+ const { done, value } = await reader.read();
192
+ if (done) {
193
+ this.send({
194
+ type: "sse_chunk",
195
+ requestId: request.requestId,
196
+ data: "",
197
+ done: true,
198
+ });
199
+ break;
200
+ }
201
+ this.send({
202
+ type: "sse_chunk",
203
+ requestId: request.requestId,
204
+ data: decoder.decode(value, { stream: true }),
205
+ });
206
+ }
207
+ }
208
+ catch (error) {
209
+ this.send({
210
+ type: "http_response",
211
+ requestId: request.requestId,
212
+ status: 502,
213
+ headers: { "content-type": "application/json" },
214
+ body: {
215
+ error: error instanceof Error ? error.message : "SSE proxy failed",
216
+ },
217
+ });
218
+ }
219
+ }
220
+ }
221
+ export function loadRelayConfigFromEnv() {
222
+ const relayUrl = process.env.MDB_RELAY_URL;
223
+ const deviceId = process.env.MDB_DEVICE_ID;
224
+ const deviceToken = process.env.MDB_RELAY_DEVICE_TOKEN;
225
+ const portValue = process.env.MDB_HTTP_PORT ?? process.env.MDB_MCP_PORT;
226
+ const localPort = portValue ? Number(portValue) : 3847;
227
+ if (!relayUrl || !deviceId || !deviceToken) {
228
+ return null;
229
+ }
230
+ if (!Number.isFinite(localPort) || localPort < 1) {
231
+ return null;
232
+ }
233
+ return {
234
+ relayUrl,
235
+ deviceId,
236
+ deviceToken,
237
+ localPort,
238
+ };
239
+ }
240
+ export function startRelayClientFromEnv(onLog) {
241
+ const config = loadRelayConfigFromEnv();
242
+ if (!config) {
243
+ return null;
244
+ }
245
+ const client = new RelayClient({ ...config, onLog });
246
+ client.start();
247
+ return client;
248
+ }
249
+ //# sourceMappingURL=relay-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-client.js","sourceRoot":"","sources":["../src/relay-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export interface HttpBridgeRequest {
2
+ type: "http";
3
+ requestId: string;
4
+ method: string;
5
+ path: string;
6
+ headers: Record<string, string>;
7
+ body?: unknown;
8
+ }
9
+ export interface HttpBridgeResponse {
10
+ type: "http_response";
11
+ requestId: string;
12
+ status: number;
13
+ headers: Record<string, string>;
14
+ body?: unknown;
15
+ }
16
+ export interface SseChunkMessage {
17
+ type: "sse_chunk";
18
+ requestId: string;
19
+ data: string;
20
+ done?: boolean;
21
+ }
22
+ export interface PingMessage {
23
+ type: "ping";
24
+ }
25
+ export interface PongMessage {
26
+ type: "pong";
27
+ }
28
+ export type DeviceToRelayMessage = HttpBridgeResponse | SseChunkMessage | PongMessage;
29
+ export type RelayToDeviceMessage = HttpBridgeRequest | PingMessage;
30
+ //# sourceMappingURL=relay-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-types.d.ts","sourceRoot":"","sources":["../src/relay-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,eAAe,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,oBAAoB,GAC5B,kBAAkB,GAClB,eAAe,GACf,WAAW,CAAC;AAEhB,MAAM,MAAM,oBAAoB,GAAG,iBAAiB,GAAG,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=relay-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-types.js","sourceRoot":"","sources":["../src/relay-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ /** Public HTTPS origin for agent-facing relay URLs (no trailing slash). */
2
+ export declare const RELAY_PUBLIC_ORIGIN: string;
3
+ /** Worker origin for daemon WebSocket /connect (no trailing slash). */
4
+ export declare function relayConnectOrigin(): string;
5
+ /** Rewrite *.workers.dev relay hosts to the branded custom domain. */
6
+ export declare function canonicalizeRelayUrl(url: string): string;
7
+ export declare function deviceRelayUrls(deviceId: string): {
8
+ relayUrl: string;
9
+ relayConnectUrl: string;
10
+ deviceBase: string;
11
+ mcpUrl: string;
12
+ sseUrl: string;
13
+ healthUrl: string;
14
+ };
15
+ export declare function canonicalizeRelayFields<T extends {
16
+ relayUrl?: string;
17
+ relayConnectUrl?: string;
18
+ mcpUrl?: string;
19
+ sseUrl?: string;
20
+ healthUrl?: string;
21
+ }>(fields: T): T;
22
+ //# sourceMappingURL=relay-urls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-urls.d.ts","sourceRoot":"","sources":["../src/relay-urls.ts"],"names":[],"mappings":"AAEA,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,QAEZ,CAAC;AAErB,uEAAuE;AACvE,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAMD,sEAAsE;AACtE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAcxD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAWA;AAED,wBAAgB,uBAAuB,CAAC,CAAC,SAAS;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAkBf"}
@@ -0,0 +1,57 @@
1
+ import { RELAY_PUBLIC_ORIGIN as BRAND_RELAY_ORIGIN } from "./brand.js";
2
+ /** Public HTTPS origin for agent-facing relay URLs (no trailing slash). */
3
+ export const RELAY_PUBLIC_ORIGIN = (process.env.MDB_RELAY_PUBLIC_URL ?? BRAND_RELAY_ORIGIN).replace(/\/$/, "");
4
+ /** Worker origin for daemon WebSocket /connect (no trailing slash). */
5
+ export function relayConnectOrigin() {
6
+ return (process.env.MDB_RELAY_URL ?? RELAY_PUBLIC_ORIGIN).replace(/\/$/, "");
7
+ }
8
+ function relayPublicHostname() {
9
+ return new URL(RELAY_PUBLIC_ORIGIN).hostname;
10
+ }
11
+ /** Rewrite *.workers.dev relay hosts to the branded custom domain. */
12
+ export function canonicalizeRelayUrl(url) {
13
+ try {
14
+ const parsed = new URL(url);
15
+ if (parsed.hostname.endsWith(".workers.dev") ||
16
+ parsed.hostname.includes("workers.dev")) {
17
+ parsed.hostname = relayPublicHostname();
18
+ parsed.protocol = "https:";
19
+ }
20
+ return parsed.toString().replace(/\/$/, "");
21
+ }
22
+ catch {
23
+ return url;
24
+ }
25
+ }
26
+ export function deviceRelayUrls(deviceId) {
27
+ const deviceBase = `${RELAY_PUBLIC_ORIGIN}/device/${deviceId}`;
28
+ const connect = relayConnectOrigin();
29
+ return {
30
+ relayUrl: RELAY_PUBLIC_ORIGIN,
31
+ relayConnectUrl: connect,
32
+ deviceBase,
33
+ mcpUrl: `${deviceBase}/mcp`,
34
+ sseUrl: `${deviceBase}/sse`,
35
+ healthUrl: `${deviceBase}/health`,
36
+ };
37
+ }
38
+ export function canonicalizeRelayFields(fields) {
39
+ const next = { ...fields };
40
+ if (next.relayUrl) {
41
+ next.relayUrl = canonicalizeRelayUrl(next.relayUrl);
42
+ }
43
+ if (next.relayConnectUrl) {
44
+ next.relayConnectUrl = canonicalizeRelayUrl(next.relayConnectUrl);
45
+ }
46
+ if (next.mcpUrl) {
47
+ next.mcpUrl = canonicalizeRelayUrl(next.mcpUrl);
48
+ }
49
+ if (next.sseUrl) {
50
+ next.sseUrl = canonicalizeRelayUrl(next.sseUrl);
51
+ }
52
+ if (next.healthUrl) {
53
+ next.healthUrl = canonicalizeRelayUrl(next.healthUrl);
54
+ }
55
+ return next;
56
+ }
57
+ //# sourceMappingURL=relay-urls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-urls.js","sourceRoot":"","sources":["../src/relay-urls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,IAAI,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEvE,2EAA2E;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,kBAAkB,CACvD,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAErB,uEAAuE;AACvE,MAAM,UAAU,kBAAkB;IAChC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,mBAAmB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC;AAC/C,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IACE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC;YACxC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EACvC,CAAC;YACD,MAAM,CAAC,QAAQ,GAAG,mBAAmB,EAAE,CAAC;YACxC,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC7B,CAAC;QACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB;IAQ9C,MAAM,UAAU,GAAG,GAAG,mBAAmB,WAAW,QAAQ,EAAE,CAAC;IAC/D,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IACrC,OAAO;QACL,QAAQ,EAAE,mBAAmB;QAC7B,eAAe,EAAE,OAAO;QACxB,UAAU;QACV,MAAM,EAAE,GAAG,UAAU,MAAM;QAC3B,MAAM,EAAE,GAAG,UAAU,MAAM;QAC3B,SAAS,EAAE,GAAG,UAAU,SAAS;KAClC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CAMpC,MAAS;IACV,MAAM,IAAI,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;IAC3B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,oBAAoB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,GAAG,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,GAAG,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface McpServerOptions {
3
+ skipLicenseCheck?: boolean;
4
+ }
5
+ export declare function createMcpServer(options?: McpServerOptions): McpServer;
6
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4CpE,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,SAAS,CA8KzE"}
package/dist/server.js ADDED
@@ -0,0 +1,164 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { APP_SLUG } from "./brand.js";
4
+ import { blockDomains, getBlockStatus, temporarilyUnblockDomains, unblockDomains, } from "./blocker.js";
5
+ import { requireProLicense } from "./license-guard.js";
6
+ const FOCUS_MODE_DOMAINS = [
7
+ "youtube.com",
8
+ "x.com",
9
+ "tiktok.com",
10
+ "instagram.com",
11
+ "reddit.com",
12
+ "facebook.com",
13
+ "netflix.com",
14
+ "twitch.tv",
15
+ ];
16
+ function toolResult(data) {
17
+ const text = JSON.stringify(data, null, 2);
18
+ return {
19
+ content: [{ type: "text", text }],
20
+ structuredContent: typeof data === "object" && data !== null
21
+ ? data
22
+ : { result: data },
23
+ };
24
+ }
25
+ function toolError(message) {
26
+ throw new Error(message);
27
+ }
28
+ const domainsSchema = z
29
+ .array(z.string().min(1))
30
+ .min(1, "At least one domain is required");
31
+ export function createMcpServer(options = {}) {
32
+ const server = new McpServer({
33
+ name: APP_SLUG,
34
+ version: "1.0.0",
35
+ });
36
+ const guardOptions = { skipCheck: options.skipLicenseCheck };
37
+ server.registerTool("block_domains", {
38
+ title: "Block Domains",
39
+ description: "Block distracting domains at the system level by redirecting them to localhost in /etc/hosts. Automatically includes www subdomains.",
40
+ inputSchema: {
41
+ domains: domainsSchema.describe("Domains to block, e.g. ['youtube.com', 'x.com', 'tiktok.com']"),
42
+ },
43
+ annotations: {
44
+ readOnlyHint: false,
45
+ destructiveHint: true,
46
+ idempotentHint: true,
47
+ openWorldHint: false,
48
+ },
49
+ }, async ({ domains }) => {
50
+ try {
51
+ await requireProLicense(guardOptions);
52
+ const result = await blockDomains(domains);
53
+ return toolResult({ success: true, ...result });
54
+ }
55
+ catch (error) {
56
+ return toolError(error instanceof Error ? error.message : "Failed to block domains");
57
+ }
58
+ });
59
+ server.registerTool("unblock_domains", {
60
+ title: "Unblock Domains",
61
+ description: "Permanently remove domains from the distraction blocker and restore normal DNS resolution.",
62
+ inputSchema: {
63
+ domains: domainsSchema.describe("Domains to unblock"),
64
+ },
65
+ annotations: {
66
+ readOnlyHint: false,
67
+ destructiveHint: false,
68
+ idempotentHint: true,
69
+ openWorldHint: false,
70
+ },
71
+ }, async ({ domains }) => {
72
+ try {
73
+ await requireProLicense(guardOptions);
74
+ const result = await unblockDomains(domains);
75
+ return toolResult({ success: true, ...result });
76
+ }
77
+ catch (error) {
78
+ return toolError(error instanceof Error ? error.message : "Failed to unblock domains");
79
+ }
80
+ });
81
+ server.registerTool("temporarily_unblock_domains", {
82
+ title: "Temporarily Unblock Domains",
83
+ description: "Temporarily allow access to blocked domains for a specified duration. Domains are automatically re-blocked when the timer expires (requires the server process to stay running).",
84
+ inputSchema: {
85
+ domains: domainsSchema.describe("Blocked domains to temporarily allow"),
86
+ duration_seconds: z
87
+ .number()
88
+ .int()
89
+ .positive()
90
+ .max(86_400)
91
+ .describe("How long to allow access, in seconds (max 24 hours)"),
92
+ },
93
+ annotations: {
94
+ readOnlyHint: false,
95
+ destructiveHint: false,
96
+ idempotentHint: false,
97
+ openWorldHint: false,
98
+ },
99
+ }, async ({ domains, duration_seconds }) => {
100
+ try {
101
+ await requireProLicense(guardOptions);
102
+ const result = await temporarilyUnblockDomains(domains, duration_seconds);
103
+ return toolResult({ success: true, ...result });
104
+ }
105
+ catch (error) {
106
+ return toolError(error instanceof Error
107
+ ? error.message
108
+ : "Failed to temporarily unblock domains");
109
+ }
110
+ });
111
+ server.registerTool("enter_focus_mode", {
112
+ title: "Enter Focus Mode",
113
+ description: "Block common distracting sites in one action (YouTube, X, TikTok, Instagram, Reddit, Facebook, Netflix, Twitch). Use when the user says they want to focus, lock in, or enter focus mode.",
114
+ inputSchema: {
115
+ extra_domains: z
116
+ .array(z.string().min(1))
117
+ .optional()
118
+ .describe("Additional domains to block alongside the default focus set"),
119
+ },
120
+ annotations: {
121
+ readOnlyHint: false,
122
+ destructiveHint: true,
123
+ idempotentHint: true,
124
+ openWorldHint: false,
125
+ },
126
+ }, async ({ extra_domains }) => {
127
+ try {
128
+ await requireProLicense(guardOptions);
129
+ const domains = [
130
+ ...new Set([...FOCUS_MODE_DOMAINS, ...(extra_domains ?? [])]),
131
+ ];
132
+ const result = await blockDomains(domains);
133
+ return toolResult({
134
+ success: true,
135
+ mode: "focus",
136
+ ...result,
137
+ });
138
+ }
139
+ catch (error) {
140
+ return toolError(error instanceof Error ? error.message : "Failed to enter focus mode");
141
+ }
142
+ });
143
+ server.registerTool("get_block_status", {
144
+ title: "Get Block Status",
145
+ description: "Check which domains are currently blocked, temporarily unblocked, and whether /etc/hosts is writable.",
146
+ inputSchema: {},
147
+ annotations: {
148
+ readOnlyHint: true,
149
+ destructiveHint: false,
150
+ idempotentHint: true,
151
+ openWorldHint: false,
152
+ },
153
+ }, async () => {
154
+ try {
155
+ const status = await getBlockStatus();
156
+ return toolResult({ success: true, ...status });
157
+ }
158
+ catch (error) {
159
+ return toolError(error instanceof Error ? error.message : "Failed to get block status");
160
+ }
161
+ });
162
+ return server;
163
+ }
164
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type BlockerState, type TemporaryUnblock } from "./types.js";
2
+ export declare function getStateDir(): string;
3
+ export declare function getStatePath(): string;
4
+ export declare function loadState(): Promise<BlockerState>;
5
+ export declare function saveState(state: BlockerState): Promise<void>;
6
+ export declare function dedupeDomains(domains: string[]): string[];
7
+ export declare function pruneExpiredUnblocks(temporaryUnblocks: TemporaryUnblock[], now?: number): TemporaryUnblock[];
8
+ export declare function getActiveTemporaryUnblock(domain: string, temporaryUnblocks: TemporaryUnblock[], now?: number): TemporaryUnblock | undefined;
9
+ export declare function isDomainBlocked(domain: string, state: BlockerState, now?: number): boolean;
10
+ export declare function appendAuditEntry(state: BlockerState, action: string, domains: string[]): BlockerState;
11
+ export declare function getDomainsToBlockInHosts(state: BlockerState, now?: number): string[];
12
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,YAAY,EAGjB,KAAK,gBAAgB,EAItB,MAAM,YAAY,CAAC;AAQpB,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC,CAwBvD;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAWlE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAczD;AAED,wBAAgB,oBAAoB,CAClC,iBAAiB,EAAE,gBAAgB,EAAE,EACrC,GAAG,SAAa,GACf,gBAAgB,EAAE,CAEpB;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,gBAAgB,EAAE,EACrC,GAAG,SAAa,GACf,gBAAgB,GAAG,SAAS,CAK9B;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,EACnB,GAAG,SAAa,GACf,OAAO,CAOT;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EAAE,GAChB,YAAY,CAQd;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,YAAY,EACnB,GAAG,SAAa,GACf,MAAM,EAAE,CAQV"}