@wonderwhy-er/desktop-commander 0.2.17 → 0.2.18-alpha.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.
- package/README.md +1 -4
- package/dist/http-server-auto-tunnel.d.ts +1 -0
- package/dist/http-server-auto-tunnel.js +667 -0
- package/dist/http-server-named-tunnel.d.ts +2 -0
- package/dist/http-server-named-tunnel.js +167 -0
- package/dist/http-server-tunnel.d.ts +2 -0
- package/dist/http-server-tunnel.js +111 -0
- package/dist/http-server.d.ts +2 -0
- package/dist/http-server.js +270 -0
- package/dist/index.js +4 -0
- package/dist/oauth/auth-middleware.d.ts +20 -0
- package/dist/oauth/auth-middleware.js +62 -0
- package/dist/oauth/index.d.ts +3 -0
- package/dist/oauth/index.js +3 -0
- package/dist/oauth/oauth-manager.d.ts +80 -0
- package/dist/oauth/oauth-manager.js +179 -0
- package/dist/oauth/oauth-routes.d.ts +3 -0
- package/dist/oauth/oauth-routes.js +377 -0
- package/dist/server.js +32 -7
- package/dist/setup-claude-server.js +43 -5
- package/dist/terminal-manager.d.ts +1 -1
- package/dist/terminal-manager.js +56 -1
- package/dist/tools/config.js +2 -0
- package/dist/tools/feedback.js +2 -2
- package/dist/tools/improved-process-tools.js +179 -58
- package/dist/tools/schemas.d.ts +9 -0
- package/dist/tools/schemas.js +3 -0
- package/dist/types.d.ts +19 -0
- package/dist/utils/feature-flags.d.ts +43 -0
- package/dist/utils/feature-flags.js +147 -0
- package/dist/utils/toolHistory.js +3 -8
- package/dist/utils/usageTracker.d.ts +4 -0
- package/dist/utils/usageTracker.js +63 -37
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -10,10 +10,7 @@
|
|
|
10
10
|
[](https://discord.gg/kQ27sNnZr7)
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
Work with code and text, run processes, and automate tasks, going far beyond other AI editors -
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-

|
|
13
|
+
Work with code and text, run processes, and automate tasks, going far beyond other AI editors - while using host client subscriptions instead of API token costs.
|
|
17
14
|
|
|
18
15
|
<a href="https://glama.ai/mcp/servers/zempur9oh4">
|
|
19
16
|
<img width="380" height="200" src="https://glama.ai/mcp/servers/zempur9oh4/badge" alt="Desktop Commander MCP" />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
#;
|
|
54
|
+
Tunnel;
|
|
55
|
+
Options;
|
|
56
|
+
for (Desktop; Commander; #)
|
|
57
|
+
#;
|
|
58
|
+
The;
|
|
59
|
+
Problem;
|
|
60
|
+
Currently;
|
|
61
|
+
Desktop;
|
|
62
|
+
Commander;
|
|
63
|
+
requires: -;
|
|
64
|
+
Named;
|
|
65
|
+
tunnel(stable, URL) - `https://mcp.desktopcommander.app`
|
|
66
|
+
- ;
|
|
67
|
+
Requires;
|
|
68
|
+
own;
|
|
69
|
+
domain + Cloudflare;
|
|
70
|
+
account
|
|
71
|
+
- ;
|
|
72
|
+
Not;
|
|
73
|
+
accessible;
|
|
74
|
+
for (all; users
|
|
75
|
+
** Goal; )
|
|
76
|
+
: ** Make;
|
|
77
|
+
Desktop;
|
|
78
|
+
Commander;
|
|
79
|
+
work;
|
|
80
|
+
for (users; without; their)
|
|
81
|
+
own;
|
|
82
|
+
infrastructure.
|
|
83
|
+
;
|
|
84
|
+
-- - ;
|
|
85
|
+
#;
|
|
86
|
+
Solution;
|
|
87
|
+
Options;
|
|
88
|
+
#;
|
|
89
|
+
#;
|
|
90
|
+
#;
|
|
91
|
+
Option;
|
|
92
|
+
1;
|
|
93
|
+
Random;
|
|
94
|
+
Cloudflare;
|
|
95
|
+
Tunnels(Quick, Start)
|
|
96
|
+
** Best;
|
|
97
|
+
for (; ; )
|
|
98
|
+
: ** Testing, development, personal;
|
|
99
|
+
use
|
|
100
|
+
** How;
|
|
101
|
+
it;
|
|
102
|
+
works: **
|
|
103
|
+
-Run `cloudflared tunnel --url http://localhost:3000`
|
|
104
|
+
- Get;
|
|
105
|
+
random;
|
|
106
|
+
URL: `https://random-words-1234.trycloudflare.com`
|
|
107
|
+
- ** Changes;
|
|
108
|
+
every;
|
|
109
|
+
restart **
|
|
110
|
+
** Pros;
|
|
111
|
+
**
|
|
112
|
+
-;
|
|
113
|
+
No;
|
|
114
|
+
domain;
|
|
115
|
+
needed
|
|
116
|
+
- ;
|
|
117
|
+
No;
|
|
118
|
+
Cloudflare;
|
|
119
|
+
account;
|
|
120
|
+
needed
|
|
121
|
+
- ;
|
|
122
|
+
Free
|
|
123
|
+
- ;
|
|
124
|
+
Works;
|
|
125
|
+
immediately
|
|
126
|
+
** Cons;
|
|
127
|
+
**
|
|
128
|
+
-;
|
|
129
|
+
URL;
|
|
130
|
+
changes;
|
|
131
|
+
on;
|
|
132
|
+
restart
|
|
133
|
+
- ;
|
|
134
|
+
Must;
|
|
135
|
+
reconfigure;
|
|
136
|
+
clients;
|
|
137
|
+
after;
|
|
138
|
+
restart
|
|
139
|
+
- ;
|
|
140
|
+
OAuth;
|
|
141
|
+
redirect;
|
|
142
|
+
URIs;
|
|
143
|
+
break ;
|
|
144
|
+
(need);
|
|
145
|
+
new URL;
|
|
146
|
+
each;
|
|
147
|
+
time;
|
|
148
|
+
** Implementation;
|
|
149
|
+
**
|
|
150
|
+
`` `bash
|
|
151
|
+
# Already supported!
|
|
152
|
+
npm run start:tunnel
|
|
153
|
+
|
|
154
|
+
# Or manually:
|
|
155
|
+
cloudflared tunnel --url http://localhost:3000 &
|
|
156
|
+
node dist/http-server.js
|
|
157
|
+
` ``
|
|
158
|
+
** For;
|
|
159
|
+
OAuth: **
|
|
160
|
+
-;
|
|
161
|
+
Not;
|
|
162
|
+
viable(redirect, URIs, must, be, stable)
|
|
163
|
+
- ;
|
|
164
|
+
Works;
|
|
165
|
+
without;
|
|
166
|
+
auth;
|
|
167
|
+
-- - ;
|
|
168
|
+
#;
|
|
169
|
+
#;
|
|
170
|
+
Option;
|
|
171
|
+
2;
|
|
172
|
+
Desktop;
|
|
173
|
+
Commander;
|
|
174
|
+
Cloud;
|
|
175
|
+
Service(Recommended)
|
|
176
|
+
** Best;
|
|
177
|
+
for (; ; )
|
|
178
|
+
: ** Production;
|
|
179
|
+
use, end;
|
|
180
|
+
users
|
|
181
|
+
** How;
|
|
182
|
+
it;
|
|
183
|
+
works: **
|
|
184
|
+
1.;
|
|
185
|
+
Desktop;
|
|
186
|
+
Commander;
|
|
187
|
+
hosts;
|
|
188
|
+
a;
|
|
189
|
+
proxy;
|
|
190
|
+
service;
|
|
191
|
+
2.;
|
|
192
|
+
Users;
|
|
193
|
+
run;
|
|
194
|
+
local;
|
|
195
|
+
server;
|
|
196
|
+
3.;
|
|
197
|
+
Proxy;
|
|
198
|
+
connects;
|
|
199
|
+
local;
|
|
200
|
+
cloud;
|
|
201
|
+
4.;
|
|
202
|
+
Users;
|
|
203
|
+
get;
|
|
204
|
+
stable;
|
|
205
|
+
subdomain: `https://username.dc.run/mcp`
|
|
206
|
+
** Pros;
|
|
207
|
+
**
|
|
208
|
+
-;
|
|
209
|
+
No;
|
|
210
|
+
domain;
|
|
211
|
+
needed
|
|
212
|
+
- ;
|
|
213
|
+
Stable;
|
|
214
|
+
URLs(survives, restarts)
|
|
215
|
+
- ;
|
|
216
|
+
OAuth;
|
|
217
|
+
works(stable, redirect, URIs)
|
|
218
|
+
- ;
|
|
219
|
+
Easy;
|
|
220
|
+
user;
|
|
221
|
+
experience
|
|
222
|
+
- ;
|
|
223
|
+
Can;
|
|
224
|
+
manage;
|
|
225
|
+
auth / quotas;
|
|
226
|
+
centrally
|
|
227
|
+
** Cons;
|
|
228
|
+
**
|
|
229
|
+
-;
|
|
230
|
+
Requires;
|
|
231
|
+
building;
|
|
232
|
+
proxy;
|
|
233
|
+
service
|
|
234
|
+
- ;
|
|
235
|
+
Hosting;
|
|
236
|
+
costs
|
|
237
|
+
- ;
|
|
238
|
+
Privacy;
|
|
239
|
+
concerns(traffic, goes, through, proxy)
|
|
240
|
+
** Architecture;
|
|
241
|
+
**
|
|
242
|
+
`` `
|
|
243
|
+
User's Computer Desktop Commander Cloud AI Client
|
|
244
|
+
┌──────────────┐ ┌─────────────────────┐ ┌──────────┐
|
|
245
|
+
│ │ │ │ │ │
|
|
246
|
+
│ DC Server │─────────────▶│ Proxy Service │◀────────│ Claude/ │
|
|
247
|
+
│ (local:3000) │ WebSocket │ username.dc.run │ HTTPS │ ChatGPT │
|
|
248
|
+
│ │ │ │ │ │
|
|
249
|
+
└──────────────┘ └─────────────────────┘ └──────────┘
|
|
250
|
+
` ``
|
|
251
|
+
** Implementation;
|
|
252
|
+
Plan: **
|
|
253
|
+
-Build;
|
|
254
|
+
proxy;
|
|
255
|
+
service(Node.js + WebSocket)
|
|
256
|
+
- Deploy;
|
|
257
|
+
to;
|
|
258
|
+
cloud(Vercel / Railway / Fly.io)
|
|
259
|
+
- Users;
|
|
260
|
+
register;
|
|
261
|
+
for (subdomain
|
|
262
|
+
- Local; client; connects)
|
|
263
|
+
to;
|
|
264
|
+
proxy;
|
|
265
|
+
-- - ;
|
|
266
|
+
#;
|
|
267
|
+
#;
|
|
268
|
+
Option;
|
|
269
|
+
3;
|
|
270
|
+
ngrok;
|
|
271
|
+
Integration
|
|
272
|
+
** Best;
|
|
273
|
+
for (; ; )
|
|
274
|
+
: ** Users;
|
|
275
|
+
already;
|
|
276
|
+
/**
|
|
277
|
+
* Start Desktop Commander with auto-detected tunnel
|
|
278
|
+
*
|
|
279
|
+
* Usage:
|
|
280
|
+
* node http-server-auto-tunnel.js
|
|
281
|
+
*
|
|
282
|
+
* This script:
|
|
283
|
+
* 1. Checks for TUNNEL_URL env var (named tunnel)
|
|
284
|
+
* 2. If not set, starts random Cloudflare tunnel
|
|
285
|
+
* 3. Extracts tunnel URL from cloudflared output
|
|
286
|
+
* 4. Starts HTTP server with detected URL
|
|
287
|
+
*/
|
|
288
|
+
import { spawn } from 'child_process';
|
|
289
|
+
import { fileURLToPath } from 'url';
|
|
290
|
+
import { dirname } from 'path';
|
|
291
|
+
function startRandomTunnel() {
|
|
292
|
+
console.log('🌐 Starting random Cloudflare Tunnel...');
|
|
293
|
+
console.log('⏳ Waiting for tunnel URL...\n');
|
|
294
|
+
const tunnel = spawn('cloudflared', ['tunnel', '--url', 'http://localhost:3000']);
|
|
295
|
+
let tunnelURL = null;
|
|
296
|
+
let server = null;
|
|
297
|
+
tunnel.stdout.on('data', (data) => {
|
|
298
|
+
const output = data.toString();
|
|
299
|
+
process.stdout.write(data);
|
|
300
|
+
// Look for the tunnel URL
|
|
301
|
+
const urlMatch = output.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/i);
|
|
302
|
+
if (urlMatch && !tunnelURL) {
|
|
303
|
+
tunnelURL = urlMatch[0];
|
|
304
|
+
console.log('\n✅ Random Tunnel URL detected:', tunnelURL);
|
|
305
|
+
if (process.env.REQUIRE_AUTH === 'true') {
|
|
306
|
+
console.log('\n⚠️ WARNING: OAuth with random tunnels is not recommended!');
|
|
307
|
+
console.log(' The URL will change on restart, breaking OAuth redirects.');
|
|
308
|
+
console.log(' Consider using REQUIRE_AUTH=false or setting up a named tunnel.\n');
|
|
309
|
+
}
|
|
310
|
+
console.log('📝 To use this URL:');
|
|
311
|
+
console.log(` Add to Claude/ChatGPT: ${tunnelURL}/mcp`);
|
|
312
|
+
console.log(` This URL expires when the tunnel stops!\n`);
|
|
313
|
+
server = startServer(tunnelURL);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
tunnel.stderr.on('data', (data) => {
|
|
317
|
+
const output = data.toString();
|
|
318
|
+
process.stderr.write(data);
|
|
319
|
+
// Also check stderr
|
|
320
|
+
const urlMatch = output.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/i);
|
|
321
|
+
if (urlMatch && !tunnelURL) {
|
|
322
|
+
tunnelURL = urlMatch[0];
|
|
323
|
+
console.log('\n✅ Random Tunnel URL detected:', tunnelURL);
|
|
324
|
+
server = startServer(tunnelURL);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
tunnel.on('error', (err) => {
|
|
328
|
+
console.error('❌ Tunnel failed to start:', err);
|
|
329
|
+
console.error('\nMake sure cloudflared is installed:');
|
|
330
|
+
console.error(' brew install cloudflare/cloudflare/cloudflared');
|
|
331
|
+
process.exit(1);
|
|
332
|
+
});
|
|
333
|
+
tunnel.on('close', (code) => {
|
|
334
|
+
console.log('\n🛑 Tunnel closed with code:', code);
|
|
335
|
+
if (server)
|
|
336
|
+
server.kill();
|
|
337
|
+
process.exit(code);
|
|
338
|
+
});
|
|
339
|
+
// Cleanup
|
|
340
|
+
process.on('SIGINT', () => {
|
|
341
|
+
console.log('\n🛑 Shutting down...');
|
|
342
|
+
tunnel.kill();
|
|
343
|
+
if (server)
|
|
344
|
+
server.kill();
|
|
345
|
+
process.exit(0);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
function startServer(baseUrl) {
|
|
349
|
+
console.log('\n📡 Starting Desktop Commander HTTP server...');
|
|
350
|
+
const env = {
|
|
351
|
+
...process.env,
|
|
352
|
+
BASE_URL: baseUrl,
|
|
353
|
+
PORT: '3000'
|
|
354
|
+
};
|
|
355
|
+
const server = spawn('node', ['dist/http-server.js'], {
|
|
356
|
+
cwd: __dirname,
|
|
357
|
+
env,
|
|
358
|
+
stdio: 'inherit'
|
|
359
|
+
});
|
|
360
|
+
server.on('error', (err) => {
|
|
361
|
+
console.error('❌ Server failed to start:', err);
|
|
362
|
+
process.exit(1);
|
|
363
|
+
});
|
|
364
|
+
server.on('close', (code) => {
|
|
365
|
+
console.log('🔴 Server closed with code:', code);
|
|
366
|
+
process.exit(code);
|
|
367
|
+
});
|
|
368
|
+
return server;
|
|
369
|
+
}
|
|
370
|
+
var ngrok, __filename, __dirname;
|
|
371
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
372
|
+
try {
|
|
373
|
+
ngrok = __addDisposableResource(env_1, void 0, false);
|
|
374
|
+
** How;
|
|
375
|
+
it;
|
|
376
|
+
works: **
|
|
377
|
+
-Use;
|
|
378
|
+
ngrok;
|
|
379
|
+
instead;
|
|
380
|
+
of;
|
|
381
|
+
Cloudflare;
|
|
382
|
+
tunnels
|
|
383
|
+
- Get;
|
|
384
|
+
stable;
|
|
385
|
+
URLs;
|
|
386
|
+
with (ngrok)
|
|
387
|
+
paid;
|
|
388
|
+
plan
|
|
389
|
+
- Free;
|
|
390
|
+
tier;
|
|
391
|
+
has;
|
|
392
|
+
random;
|
|
393
|
+
URLs;
|
|
394
|
+
like;
|
|
395
|
+
Cloudflare
|
|
396
|
+
** Pros;
|
|
397
|
+
**
|
|
398
|
+
-;
|
|
399
|
+
Well - known;
|
|
400
|
+
tool
|
|
401
|
+
- ;
|
|
402
|
+
Good;
|
|
403
|
+
documentation
|
|
404
|
+
- ;
|
|
405
|
+
Paid;
|
|
406
|
+
plan = stable;
|
|
407
|
+
URLs
|
|
408
|
+
** Cons;
|
|
409
|
+
**
|
|
410
|
+
-;
|
|
411
|
+
Free;
|
|
412
|
+
tier = random;
|
|
413
|
+
URLs(same, problem)
|
|
414
|
+
- ;
|
|
415
|
+
Paid;
|
|
416
|
+
plan = $8 - 10 / month;
|
|
417
|
+
per;
|
|
418
|
+
user
|
|
419
|
+
- ;
|
|
420
|
+
Not
|
|
421
|
+
** Implementation;
|
|
422
|
+
**
|
|
423
|
+
`` `typescript
|
|
424
|
+
// Add to package.json
|
|
425
|
+
"scripts": {
|
|
426
|
+
"start:ngrok": "node dist/http-server-ngrok.js"
|
|
427
|
+
}
|
|
428
|
+
` `` `` `typescript
|
|
429
|
+
// src/http-server-ngrok.ts
|
|
430
|
+
import ngrok from 'ngrok';
|
|
431
|
+
|
|
432
|
+
async function startWithNgrok() {
|
|
433
|
+
const url = await ngrok.connect({
|
|
434
|
+
addr: 3000,
|
|
435
|
+
authtoken: process.env.NGROK_AUTH_TOKEN
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
console.log(`;
|
|
439
|
+
ngrok;
|
|
440
|
+
tunnel: $;
|
|
441
|
+
{
|
|
442
|
+
url;
|
|
443
|
+
}
|
|
444
|
+
`);
|
|
445
|
+
process.env.BASE_URL = url;
|
|
446
|
+
|
|
447
|
+
// Start server...
|
|
448
|
+
}
|
|
449
|
+
` ``;
|
|
450
|
+
-- - ;
|
|
451
|
+
#;
|
|
452
|
+
#;
|
|
453
|
+
Option;
|
|
454
|
+
4;
|
|
455
|
+
Hybrid;
|
|
456
|
+
Approach(Best, Balance)
|
|
457
|
+
** Best;
|
|
458
|
+
for (; ; )
|
|
459
|
+
: ** Supporting;
|
|
460
|
+
all;
|
|
461
|
+
user;
|
|
462
|
+
types
|
|
463
|
+
** How;
|
|
464
|
+
it;
|
|
465
|
+
works: **
|
|
466
|
+
-Offer;
|
|
467
|
+
multiple;
|
|
468
|
+
tunnel;
|
|
469
|
+
options
|
|
470
|
+
- Users;
|
|
471
|
+
choose;
|
|
472
|
+
based;
|
|
473
|
+
on;
|
|
474
|
+
their;
|
|
475
|
+
needs `` `bash
|
|
476
|
+
# Option A: Random tunnel (no setup)
|
|
477
|
+
npm run start:tunnel
|
|
478
|
+
|
|
479
|
+
# Option B: Named tunnel (own domain)
|
|
480
|
+
TUNNEL_URL=https://mcp.yourname.com npm run start:named-tunnel
|
|
481
|
+
|
|
482
|
+
# Option C: Cloud service (future)
|
|
483
|
+
npm run start:cloud -- --username yourname
|
|
484
|
+
|
|
485
|
+
# Option D: Local only (no tunnel)
|
|
486
|
+
npm run start:local
|
|
487
|
+
` ``
|
|
488
|
+
** Configuration;
|
|
489
|
+
**
|
|
490
|
+
`` `typescript
|
|
491
|
+
// Auto-detect best option
|
|
492
|
+
export async function startServer(options) {
|
|
493
|
+
if (options.cloudUsername) {
|
|
494
|
+
// Use DC cloud proxy
|
|
495
|
+
return startWithCloudProxy(options.cloudUsername);
|
|
496
|
+
} else if (options.namedTunnel) {
|
|
497
|
+
// Use named Cloudflare tunnel
|
|
498
|
+
return startWithNamedTunnel(options.namedTunnel);
|
|
499
|
+
} else if (options.ngrokToken) {
|
|
500
|
+
// Use ngrok
|
|
501
|
+
return startWithNgrok(options.ngrokToken);
|
|
502
|
+
} else {
|
|
503
|
+
// Random Cloudflare tunnel
|
|
504
|
+
return startWithRandomTunnel();
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
` ``;
|
|
508
|
+
-- - ;
|
|
509
|
+
#;
|
|
510
|
+
#;
|
|
511
|
+
Option;
|
|
512
|
+
5;
|
|
513
|
+
Local;
|
|
514
|
+
Network;
|
|
515
|
+
Only(No, Tunnel)
|
|
516
|
+
** Best;
|
|
517
|
+
for (; ; )
|
|
518
|
+
: ** Privacy - conscious;
|
|
519
|
+
users, local;
|
|
520
|
+
testing
|
|
521
|
+
** How;
|
|
522
|
+
it;
|
|
523
|
+
works: **
|
|
524
|
+
-Server;
|
|
525
|
+
runs;
|
|
526
|
+
on;
|
|
527
|
+
local;
|
|
528
|
+
network;
|
|
529
|
+
only
|
|
530
|
+
- Access;
|
|
531
|
+
via `http://192.168.x.x:3000`
|
|
532
|
+
- No;
|
|
533
|
+
internet;
|
|
534
|
+
exposure
|
|
535
|
+
** Pros;
|
|
536
|
+
**
|
|
537
|
+
-;
|
|
538
|
+
Maximum;
|
|
539
|
+
privacy
|
|
540
|
+
- ;
|
|
541
|
+
No;
|
|
542
|
+
external;
|
|
543
|
+
dependencies
|
|
544
|
+
- ;
|
|
545
|
+
Free
|
|
546
|
+
** Cons;
|
|
547
|
+
**
|
|
548
|
+
-;
|
|
549
|
+
Only;
|
|
550
|
+
works;
|
|
551
|
+
on;
|
|
552
|
+
same;
|
|
553
|
+
network
|
|
554
|
+
- ;
|
|
555
|
+
Can;
|
|
556
|
+
't use with cloud AI services
|
|
557
|
+
- ;
|
|
558
|
+
Must;
|
|
559
|
+
use;
|
|
560
|
+
Claude;
|
|
561
|
+
Desktop(not, claude.ai)
|
|
562
|
+
** Implementation;
|
|
563
|
+
**
|
|
564
|
+
`` `bash
|
|
565
|
+
# Already works!
|
|
566
|
+
npm run start
|
|
567
|
+
|
|
568
|
+
# Claude Desktop config:
|
|
569
|
+
{
|
|
570
|
+
"mcpServers": {
|
|
571
|
+
"desktop-commander": {
|
|
572
|
+
"command": "node",
|
|
573
|
+
"args": ["/path/to/dist/index.js"]
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
` ``;
|
|
578
|
+
-- - ;
|
|
579
|
+
#;
|
|
580
|
+
Recommended;
|
|
581
|
+
Architecture;
|
|
582
|
+
#;
|
|
583
|
+
#;
|
|
584
|
+
#;
|
|
585
|
+
Phase;
|
|
586
|
+
1;
|
|
587
|
+
Current(Multiple, Options);
|
|
588
|
+
Offer;
|
|
589
|
+
all;
|
|
590
|
+
tunnel;
|
|
591
|
+
methods, let;
|
|
592
|
+
users;
|
|
593
|
+
choose: `` `markdown
|
|
594
|
+
# Installation Methods
|
|
595
|
+
|
|
596
|
+
## Quick Start (No Setup)
|
|
597
|
+
npm run start:tunnel
|
|
598
|
+
→ Random URL, changes on restart
|
|
599
|
+
|
|
600
|
+
## Production (Own Domain)
|
|
601
|
+
TUNNEL_URL=https://mcp.yourname.com npm run start:named-tunnel
|
|
602
|
+
→ Stable URL, requires Cloudflare
|
|
603
|
+
|
|
604
|
+
## Local Only (Claude Desktop)
|
|
605
|
+
npm run start
|
|
606
|
+
→ No tunnel, configure in Claude Desktop
|
|
607
|
+
` ``;
|
|
608
|
+
#;
|
|
609
|
+
#;
|
|
610
|
+
#;
|
|
611
|
+
Phase;
|
|
612
|
+
2;
|
|
613
|
+
Cloud;
|
|
614
|
+
Service(Future);
|
|
615
|
+
Build;
|
|
616
|
+
Desktop;
|
|
617
|
+
Commander;
|
|
618
|
+
Cloud: `` `bash
|
|
619
|
+
# User experience
|
|
620
|
+
npm install -g desktop-commander
|
|
621
|
+
dc login
|
|
622
|
+
dc start
|
|
623
|
+
|
|
624
|
+
# Behind the scenes:
|
|
625
|
+
# - Authenticates with DC Cloud
|
|
626
|
+
# - Gets stable subdomain: https://yourname.dc.run
|
|
627
|
+
# - Starts local server
|
|
628
|
+
# - Connects to cloud proxy
|
|
629
|
+
# - OAuth redirect: https://yourname.dc.run/oauth/callback
|
|
630
|
+
` ``;
|
|
631
|
+
-- - ;
|
|
632
|
+
#;
|
|
633
|
+
Quick;
|
|
634
|
+
Implementation: Support;
|
|
635
|
+
Random;
|
|
636
|
+
Tunnels;
|
|
637
|
+
Let;
|
|
638
|
+
's make random tunnels work better:
|
|
639
|
+
< function_calls >
|
|
640
|
+
name;
|
|
641
|
+
"desktop-commander-host:write_file" >
|
|
642
|
+
name;
|
|
643
|
+
"content" > ;
|
|
644
|
+
!/usr/bin / env;
|
|
645
|
+
node;
|
|
646
|
+
__filename = fileURLToPath(import.meta.url);
|
|
647
|
+
__dirname = dirname(__filename);
|
|
648
|
+
console.log('🚀 Starting Desktop Commander with Auto Tunnel Detection\n');
|
|
649
|
+
// Check if named tunnel is configured
|
|
650
|
+
if (process.env.TUNNEL_URL) {
|
|
651
|
+
console.log('✅ Using named tunnel from TUNNEL_URL');
|
|
652
|
+
console.log(` URL: ${process.env.TUNNEL_URL}\n`);
|
|
653
|
+
startServer(process.env.TUNNEL_URL);
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
console.log('⚠️ No TUNNEL_URL configured, using random Cloudflare tunnel');
|
|
657
|
+
console.log(' Note: URL will change on restart!\n');
|
|
658
|
+
startRandomTunnel();
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
catch (e_1) {
|
|
662
|
+
env_1.error = e_1;
|
|
663
|
+
env_1.hasError = true;
|
|
664
|
+
}
|
|
665
|
+
finally {
|
|
666
|
+
__disposeResources(env_1);
|
|
667
|
+
}
|