agent-dir 0.4.1 β 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.
- package/README.md +40 -374
- package/SECURITY.md +39 -0
- package/assets/agent-dir-banner.svg +38 -0
- package/dist/bin/agent-dir.js +105 -51
- package/dist/src/auth.js +3 -1
- package/dist/src/config.js +31 -3
- package/dist/src/logging.d.ts +1 -1
- package/dist/src/logging.js +13 -70
- package/dist/src/mcp.js +304 -665
- package/dist/src/server.d.ts +1 -1
- package/dist/src/server.js +41 -146
- package/dist/src/setup.js +67 -6
- package/dist/src/telemetry/privacy.js +48 -0
- package/dist/src/telemetry/recorder.js +8 -17
- package/dist/src/telemetry/storage.d.ts +9 -0
- package/dist/src/telemetry/storage.js +133 -0
- package/dist/src/telemetry/types.d.ts +24 -0
- package/dist/src/tools/code.d.ts +0 -12
- package/dist/src/tools/code.js +9 -29
- package/dist/src/tools/commands.d.ts +7 -0
- package/dist/src/tools/commands.js +63 -5
- package/dist/src/tools/diagnostics.js +3 -1
- package/dist/src/tools/files.d.ts +2 -21
- package/dist/src/tools/files.js +85 -70
- package/dist/src/tools/git.d.ts +0 -7
- package/dist/src/tools/git.js +10 -68
- package/dist/src/tools/metadata.d.ts +0 -1
- package/dist/src/tools/metadata.js +0 -22
- package/dist/src/tools/npm.js +7 -5
- package/dist/src/tools/skills.d.ts +1 -0
- package/dist/src/tools/skills.js +65 -0
- package/dist/src/tunnel.js +35 -18
- package/dist/src/types.d.ts +16 -4
- package/docs/CONFIGURATION.md +154 -0
- package/docs/MCP.md +106 -0
- package/docs/RELEASING.md +213 -0
- package/docs/telemetry.md +109 -0
- package/package.json +4 -1
package/dist/bin/agent-dir.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
3
|
-
import {
|
|
2
|
+
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
3
|
+
import { watch } from "node:fs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
6
|
import { createInterface } from "node:readline/promises";
|
|
@@ -12,6 +12,7 @@ import { hasConfigFile, runFirstTimeSetup, shouldOfferSetup } from "../src/setup
|
|
|
12
12
|
import { summarizeTelemetry } from "../src/telemetry/aggregate.js";
|
|
13
13
|
import { isTelemetryLevel } from "../src/telemetry/config.js";
|
|
14
14
|
import { formatTelemetrySummary } from "../src/telemetry/format.js";
|
|
15
|
+
import { ensureTelemetryDirectory, migrateLegacyTelemetry, readAllTelemetryEvents, resetTelemetry, TELEMETRY_DIRECTORY, } from "../src/telemetry/storage.js";
|
|
15
16
|
import { startTunnel } from "../src/tunnel.js";
|
|
16
17
|
const require = createRequire(import.meta.url);
|
|
17
18
|
const packageVersion = require("../../package.json").version;
|
|
@@ -41,12 +42,15 @@ const { values, positionals } = parseArgs({
|
|
|
41
42
|
directory: { type: "string", short: "d" },
|
|
42
43
|
port: { type: "string", short: "p" },
|
|
43
44
|
tunnel: { type: "string", short: "t" },
|
|
45
|
+
wormhole: { type: "boolean", short: "w" },
|
|
46
|
+
cloudflared: { type: "boolean", short: "c" },
|
|
44
47
|
subdomain: { type: "string", short: "s" },
|
|
48
|
+
hostname: { type: "string" },
|
|
49
|
+
"cloudflared-token": { type: "string" },
|
|
45
50
|
npm: { type: "string" },
|
|
46
51
|
command: { type: "string" },
|
|
47
52
|
blacklist: { type: "string" },
|
|
48
53
|
token: { type: "string" },
|
|
49
|
-
git: { type: "boolean" },
|
|
50
54
|
rotate: { type: "boolean" },
|
|
51
55
|
"no-tunnel": { type: "boolean" },
|
|
52
56
|
random: { type: "boolean" },
|
|
@@ -75,7 +79,8 @@ if (command === "setup") {
|
|
|
75
79
|
if (shouldOfferSetup(await hasConfigFile(), {
|
|
76
80
|
random: values.random,
|
|
77
81
|
noTunnel: values["no-tunnel"],
|
|
78
|
-
tunnel: values.tunnel
|
|
82
|
+
tunnel: values.tunnel ??
|
|
83
|
+
(values.wormhole ? "wormhole" : values.cloudflared ? "cloudflared" : undefined),
|
|
79
84
|
}) &&
|
|
80
85
|
command !== "config" &&
|
|
81
86
|
command !== "telemetry") {
|
|
@@ -90,7 +95,8 @@ if (shouldOfferSetup(await hasConfigFile(), {
|
|
|
90
95
|
if (command === "telemetry") {
|
|
91
96
|
const action = positionals[1];
|
|
92
97
|
const currentLevel = config.telemetry?.level ?? "none";
|
|
93
|
-
const
|
|
98
|
+
const telemetryProfile = positionals[2];
|
|
99
|
+
const telemetrySession = positionals[3];
|
|
94
100
|
if (action === "status") {
|
|
95
101
|
console.log(`Telemetry: ${currentLevel === "none" ? "disabled" : "enabled"}`);
|
|
96
102
|
console.log(`Level: ${currentLevel}`);
|
|
@@ -138,12 +144,13 @@ if (command === "telemetry") {
|
|
|
138
144
|
process.exit(0);
|
|
139
145
|
}
|
|
140
146
|
if (action === "summary") {
|
|
141
|
-
console.log(formatTelemetrySummary(summarizeTelemetry(
|
|
147
|
+
console.log(formatTelemetrySummary(summarizeTelemetry(readAllTelemetryEvents().filter((event) => !telemetryProfile || event.configId === telemetryProfile)), currentLevel));
|
|
142
148
|
process.exit(0);
|
|
143
149
|
}
|
|
144
150
|
if (action === "show") {
|
|
145
151
|
const printEvents = () => {
|
|
146
|
-
const events =
|
|
152
|
+
const events = readAllTelemetryEvents().filter((event) => (!telemetryProfile || event.configId === telemetryProfile) &&
|
|
153
|
+
(!telemetrySession || event.sessionId === telemetrySession));
|
|
147
154
|
const grouped = new Map();
|
|
148
155
|
for (const event of events) {
|
|
149
156
|
const configId = isRecord(event) && typeof event.configId === "string" ? event.configId : "unknown";
|
|
@@ -170,17 +177,8 @@ if (command === "telemetry") {
|
|
|
170
177
|
};
|
|
171
178
|
printEvents();
|
|
172
179
|
if (values.follow) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
mode: 0o700,
|
|
176
|
-
});
|
|
177
|
-
try {
|
|
178
|
-
readFileSync(telemetryFile);
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
writeFileSync(telemetryFile, "", { encoding: "utf8", mode: 0o600 });
|
|
182
|
-
}
|
|
183
|
-
const watcher = watch(telemetryFile, () => {
|
|
180
|
+
ensureTelemetryDirectory();
|
|
181
|
+
const watcher = watch(TELEMETRY_DIRECTORY, { recursive: true }, () => {
|
|
184
182
|
process.stdout.write("\x1b[2J\x1b[H");
|
|
185
183
|
printEvents();
|
|
186
184
|
});
|
|
@@ -195,16 +193,21 @@ if (command === "telemetry") {
|
|
|
195
193
|
process.exit(0);
|
|
196
194
|
}
|
|
197
195
|
if (action === "reset") {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
if (values.all && telemetryProfile)
|
|
197
|
+
fail("Use either a profile name or --all, not both.");
|
|
198
|
+
if (!values.all && !telemetryProfile)
|
|
199
|
+
fail("Usage: agent-dir telemetry reset <profile> | --all");
|
|
200
|
+
if (values.all) {
|
|
201
|
+
delete config.telemetry;
|
|
202
|
+
await saveConfig(config);
|
|
203
|
+
resetTelemetry(undefined, true);
|
|
204
|
+
console.log("β Telemetry settings reset and all recorded data was cleared.");
|
|
202
205
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
else {
|
|
207
|
+
migrateLegacyTelemetry();
|
|
208
|
+
resetTelemetry(telemetryProfile);
|
|
209
|
+
console.log(`β Telemetry data cleared for profile: ${telemetryProfile}`);
|
|
206
210
|
}
|
|
207
|
-
console.log("β Telemetry reset to defaults and all recorded data was cleared.");
|
|
208
211
|
process.exit(0);
|
|
209
212
|
}
|
|
210
213
|
fail("Usage: agent-dir telemetry {status|enable|disable|schema|show|summary|reset}");
|
|
@@ -223,6 +226,8 @@ if (command === "config") {
|
|
|
223
226
|
const profile = structuredClone(config.profiles[name]);
|
|
224
227
|
if (profile.token)
|
|
225
228
|
profile.token = "<configured>";
|
|
229
|
+
if (profile.tunnels?.cloudflared?.token)
|
|
230
|
+
profile.tunnels.cloudflared.token = "<configured>";
|
|
226
231
|
console.log(JSON.stringify(profile, null, 2));
|
|
227
232
|
process.exit(0);
|
|
228
233
|
}
|
|
@@ -283,8 +288,21 @@ if (command === "config") {
|
|
|
283
288
|
fail("Usage: agent-dir config add <name> [options]");
|
|
284
289
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name))
|
|
285
290
|
fail("Profile names may contain letters, numbers, dots, underscores, and hyphens.");
|
|
286
|
-
|
|
287
|
-
|
|
291
|
+
if (values.wormhole && values.cloudflared)
|
|
292
|
+
fail("Choose only one of -w or -c.");
|
|
293
|
+
if ((values.wormhole || values.cloudflared) && values.tunnel)
|
|
294
|
+
fail("Use either -w/-c or --tunnel, not both.");
|
|
295
|
+
const tunnel = values.wormhole
|
|
296
|
+
? "wormhole"
|
|
297
|
+
: values.cloudflared
|
|
298
|
+
? "cloudflared"
|
|
299
|
+
: (values.tunnel ??
|
|
300
|
+
(values.hostname
|
|
301
|
+
? "cloudflared"
|
|
302
|
+
: values.subdomain || values.random
|
|
303
|
+
? "wormhole"
|
|
304
|
+
: "none"));
|
|
305
|
+
if (tunnel !== "none" && tunnel !== "wormhole" && tunnel !== "cloudflared")
|
|
288
306
|
fail(`Unsupported tunnel provider: ${tunnel}`);
|
|
289
307
|
const profile = {
|
|
290
308
|
directory: resolve(values.directory ?? "."),
|
|
@@ -294,6 +312,28 @@ if (command === "config") {
|
|
|
294
312
|
};
|
|
295
313
|
if (values.subdomain)
|
|
296
314
|
profile.subdomain = values.subdomain;
|
|
315
|
+
if (values.hostname)
|
|
316
|
+
profile.hostname = values.hostname;
|
|
317
|
+
if (values.subdomain || values.hostname || values.random) {
|
|
318
|
+
profile.tunnels = {
|
|
319
|
+
...(values.subdomain || values.random
|
|
320
|
+
? {
|
|
321
|
+
wormhole: {
|
|
322
|
+
...(values.subdomain ? { subdomain: values.subdomain } : { random: true }),
|
|
323
|
+
},
|
|
324
|
+
}
|
|
325
|
+
: {}),
|
|
326
|
+
...(values.hostname
|
|
327
|
+
? {
|
|
328
|
+
cloudflared: {
|
|
329
|
+
hostname: values.hostname,
|
|
330
|
+
...(values["cloudflared-token"] ? { token: values["cloudflared-token"] } : {}),
|
|
331
|
+
},
|
|
332
|
+
}
|
|
333
|
+
: {}),
|
|
334
|
+
};
|
|
335
|
+
profile.defaultTunnel = tunnel;
|
|
336
|
+
}
|
|
297
337
|
const npm = parseList(values.npm);
|
|
298
338
|
if (npm !== undefined)
|
|
299
339
|
profile.npm = { allowedScripts: npm };
|
|
@@ -303,11 +343,12 @@ if (command === "config") {
|
|
|
303
343
|
const blacklist = parseList(values.blacklist);
|
|
304
344
|
if (blacklist !== undefined)
|
|
305
345
|
profile.blacklistedCommands = blacklist;
|
|
306
|
-
if (values.git !== undefined)
|
|
307
|
-
profile.git = values.git;
|
|
308
346
|
if (profile.tunnel === "wormhole" && !profile.subdomain && !values.random) {
|
|
309
347
|
fail("Wormhole profiles require --subdomain <name>, or use --random.");
|
|
310
348
|
}
|
|
349
|
+
if (profile.tunnel === "cloudflared" && !profile.hostname) {
|
|
350
|
+
fail("Cloudflared profiles require --hostname <host> (a hostname already routed to your named Cloudflare Tunnel).");
|
|
351
|
+
}
|
|
311
352
|
config.profiles[name] = profile;
|
|
312
353
|
await saveConfig(config);
|
|
313
354
|
console.log(`β Saved profile '${name}'.`);
|
|
@@ -323,17 +364,37 @@ if (command && command !== "config" && !profile && command.startsWith("-")) {
|
|
|
323
364
|
const positionalDirectory = profile ? positionals[1] : positionals[0];
|
|
324
365
|
const directory = resolve(values.directory ?? profile?.directory ?? positionalDirectory ?? ".");
|
|
325
366
|
const port = parsePort(values.port, profile?.port ?? 3002);
|
|
326
|
-
|
|
327
|
-
|
|
367
|
+
if (values.wormhole && values.cloudflared)
|
|
368
|
+
fail("Choose only one of -w or -c.");
|
|
369
|
+
if ((values.wormhole || values.cloudflared) && values.tunnel)
|
|
370
|
+
fail("Use either -w/-c or --tunnel, not both.");
|
|
371
|
+
const configuredDefault = profile?.defaultTunnel ??
|
|
372
|
+
(profile?.tunnels?.cloudflared ? "cloudflared" : (profile?.tunnel ?? "none"));
|
|
373
|
+
const tunnelValue = values["no-tunnel"]
|
|
374
|
+
? "none"
|
|
375
|
+
: values.wormhole
|
|
376
|
+
? "wormhole"
|
|
377
|
+
: values.cloudflared
|
|
378
|
+
? "cloudflared"
|
|
379
|
+
: (values.tunnel ?? configuredDefault);
|
|
380
|
+
if (tunnelValue !== "none" && tunnelValue !== "wormhole" && tunnelValue !== "cloudflared") {
|
|
328
381
|
fail(`Unsupported tunnel provider: ${tunnelValue}`);
|
|
329
382
|
}
|
|
330
383
|
const tunnel = tunnelValue;
|
|
331
|
-
const randomTunnel = values.random === true
|
|
332
|
-
|
|
384
|
+
const randomTunnel = values.random === true ||
|
|
385
|
+
(values.subdomain === undefined && profile?.tunnels?.wormhole?.random === true);
|
|
386
|
+
const subdomain = randomTunnel
|
|
387
|
+
? undefined
|
|
388
|
+
: (values.subdomain ?? profile?.tunnels?.wormhole?.subdomain ?? profile?.subdomain);
|
|
389
|
+
const hostname = values.hostname ?? profile?.tunnels?.cloudflared?.hostname ?? profile?.hostname;
|
|
390
|
+
const cloudflaredToken = values["cloudflared-token"] ?? profile?.tunnels?.cloudflared?.token;
|
|
333
391
|
if (tunnel === "wormhole" && !subdomain && !randomTunnel) {
|
|
334
392
|
fail("Wormhole requires --subdomain <name>, or use --random.");
|
|
335
393
|
}
|
|
336
|
-
if (
|
|
394
|
+
if (tunnel === "cloudflared" && !hostname) {
|
|
395
|
+
fail("Cloudflared requires --hostname <host> (a hostname already routed to your named Cloudflare Tunnel).");
|
|
396
|
+
}
|
|
397
|
+
if (randomTunnel && tunnel !== "wormhole") {
|
|
337
398
|
fail("--random requires --tunnel wormhole.");
|
|
338
399
|
}
|
|
339
400
|
const token = values.token ?? profile?.token ?? randomBytes(24).toString("hex");
|
|
@@ -347,8 +408,6 @@ if (commands !== undefined)
|
|
|
347
408
|
overrides.commands = commands;
|
|
348
409
|
if (blacklist !== undefined)
|
|
349
410
|
overrides.blacklistedCommands = blacklist;
|
|
350
|
-
if (values.git !== undefined)
|
|
351
|
-
overrides.git = values.git;
|
|
352
411
|
const commandConfig = mergeProfile(profile ?? { directory, port, tunnel }, overrides);
|
|
353
412
|
const telemetryConfigId = profile
|
|
354
413
|
? command
|
|
@@ -358,11 +417,11 @@ const telemetryConfigId = profile
|
|
|
358
417
|
port,
|
|
359
418
|
tunnel,
|
|
360
419
|
subdomain,
|
|
420
|
+
hostname,
|
|
361
421
|
randomTunnel,
|
|
362
422
|
npm: commandConfig.npm?.allowedScripts ?? [],
|
|
363
423
|
commands: commandConfig.commands ?? [],
|
|
364
424
|
blacklistedCommands: commandConfig.blacklistedCommands ?? [],
|
|
365
|
-
git: commandConfig.git ?? commandConfig.commands?.includes("git") ?? false,
|
|
366
425
|
}))
|
|
367
426
|
.digest("hex")
|
|
368
427
|
.slice(0, 12);
|
|
@@ -377,6 +436,8 @@ if (profile && command)
|
|
|
377
436
|
bannerOptions.profileName = command;
|
|
378
437
|
if (subdomain)
|
|
379
438
|
bannerOptions.subdomain = subdomain;
|
|
439
|
+
if (hostname)
|
|
440
|
+
bannerOptions.hostname = hostname;
|
|
380
441
|
if (npmScripts)
|
|
381
442
|
bannerOptions.npmScripts = npmScripts;
|
|
382
443
|
if (allowedCommands)
|
|
@@ -384,8 +445,8 @@ if (allowedCommands)
|
|
|
384
445
|
if (commandConfig.blacklistedCommands?.length) {
|
|
385
446
|
bannerOptions.blacklistedCommands = commandConfig.blacklistedCommands;
|
|
386
447
|
}
|
|
387
|
-
bannerOptions.gitEnabled = commandConfig.git ?? commandConfig.commands?.includes("git") ?? false;
|
|
388
448
|
printBanner(bannerOptions);
|
|
449
|
+
const telemetrySessionId = randomUUID();
|
|
389
450
|
const server = await startServer({
|
|
390
451
|
root: directory,
|
|
391
452
|
port,
|
|
@@ -394,6 +455,7 @@ const server = await startServer({
|
|
|
394
455
|
telemetry: {
|
|
395
456
|
...(config.telemetry ?? { level: "none" }),
|
|
396
457
|
...(telemetryConfigId ? { configId: telemetryConfigId } : {}),
|
|
458
|
+
sessionId: telemetrySessionId,
|
|
397
459
|
persist: true,
|
|
398
460
|
},
|
|
399
461
|
});
|
|
@@ -405,12 +467,15 @@ console.log(" Token : <configured>");
|
|
|
405
467
|
if (tunnel !== "none") {
|
|
406
468
|
try {
|
|
407
469
|
tunnelResult = await startTunnel({
|
|
408
|
-
provider:
|
|
470
|
+
provider: tunnel,
|
|
409
471
|
port,
|
|
472
|
+
...(hostname ? { hostname } : {}),
|
|
473
|
+
...(cloudflaredToken ? { cloudflaredToken } : {}),
|
|
410
474
|
token,
|
|
411
475
|
telemetry: {
|
|
412
476
|
...(config.telemetry ?? { level: "none" }),
|
|
413
477
|
...(telemetryConfigId ? { configId: telemetryConfigId } : {}),
|
|
478
|
+
sessionId: telemetrySessionId,
|
|
414
479
|
persist: true,
|
|
415
480
|
},
|
|
416
481
|
random: randomTunnel,
|
|
@@ -453,14 +518,3 @@ async function confirmConfigDelete(message, skipPrompt) {
|
|
|
453
518
|
function isRecord(value) {
|
|
454
519
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
455
520
|
}
|
|
456
|
-
function readTelemetryEvents(path) {
|
|
457
|
-
try {
|
|
458
|
-
return readFileSync(path, "utf8")
|
|
459
|
-
.split("\n")
|
|
460
|
-
.filter(Boolean)
|
|
461
|
-
.map((line) => JSON.parse(line));
|
|
462
|
-
}
|
|
463
|
-
catch {
|
|
464
|
-
return [];
|
|
465
|
-
}
|
|
466
|
-
}
|
package/dist/src/auth.js
CHANGED
|
@@ -14,7 +14,9 @@ function secureCompare(left, right) {
|
|
|
14
14
|
return timingSafeEqual(leftHash, rightHash);
|
|
15
15
|
}
|
|
16
16
|
export function unauthorized() {
|
|
17
|
-
return new Response(JSON.stringify({
|
|
17
|
+
return new Response(JSON.stringify({
|
|
18
|
+
error: "Unauthorized: provide a valid Authorization: Bearer <token> header.",
|
|
19
|
+
}), {
|
|
18
20
|
status: 401,
|
|
19
21
|
headers: {
|
|
20
22
|
"content-type": "application/json; charset=utf-8",
|
package/dist/src/config.js
CHANGED
|
@@ -63,12 +63,42 @@ function isProfile(value) {
|
|
|
63
63
|
return false;
|
|
64
64
|
if (port < 1 || port > 65_535)
|
|
65
65
|
return false;
|
|
66
|
-
if (profile.tunnel !== "none" &&
|
|
66
|
+
if (profile.tunnel !== "none" &&
|
|
67
|
+
profile.tunnel !== "wormhole" &&
|
|
68
|
+
profile.tunnel !== "cloudflared")
|
|
67
69
|
return false;
|
|
68
70
|
if (profile.subdomain !== undefined && typeof profile.subdomain !== "string")
|
|
69
71
|
return false;
|
|
72
|
+
if (profile.hostname !== undefined && typeof profile.hostname !== "string")
|
|
73
|
+
return false;
|
|
70
74
|
if (profile.token !== undefined && typeof profile.token !== "string")
|
|
71
75
|
return false;
|
|
76
|
+
if (profile.defaultTunnel !== undefined &&
|
|
77
|
+
!["none", "wormhole", "cloudflared"].includes(String(profile.defaultTunnel)))
|
|
78
|
+
return false;
|
|
79
|
+
if (profile.tunnels !== undefined) {
|
|
80
|
+
if (!profile.tunnels || typeof profile.tunnels !== "object")
|
|
81
|
+
return false;
|
|
82
|
+
const tunnels = profile.tunnels;
|
|
83
|
+
if (tunnels.wormhole !== undefined) {
|
|
84
|
+
if (!tunnels.wormhole || typeof tunnels.wormhole !== "object")
|
|
85
|
+
return false;
|
|
86
|
+
const wormhole = tunnels.wormhole;
|
|
87
|
+
if (wormhole.subdomain !== undefined && typeof wormhole.subdomain !== "string")
|
|
88
|
+
return false;
|
|
89
|
+
if (wormhole.random !== undefined && typeof wormhole.random !== "boolean")
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (tunnels.cloudflared !== undefined) {
|
|
93
|
+
if (!tunnels.cloudflared || typeof tunnels.cloudflared !== "object")
|
|
94
|
+
return false;
|
|
95
|
+
const cloudflared = tunnels.cloudflared;
|
|
96
|
+
if (typeof cloudflared.hostname !== "string" || !cloudflared.hostname)
|
|
97
|
+
return false;
|
|
98
|
+
if (cloudflared.token !== undefined && typeof cloudflared.token !== "string")
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
72
102
|
if (profile.npm !== undefined) {
|
|
73
103
|
if (!profile.npm || typeof profile.npm !== "object")
|
|
74
104
|
return false;
|
|
@@ -87,7 +117,5 @@ function isProfile(value) {
|
|
|
87
117
|
profile.blacklistedCommands.some((item) => typeof item !== "string"))
|
|
88
118
|
return false;
|
|
89
119
|
}
|
|
90
|
-
if (profile.git !== undefined && typeof profile.git !== "boolean")
|
|
91
|
-
return false;
|
|
92
120
|
return true;
|
|
93
121
|
}
|
package/dist/src/logging.d.ts
CHANGED
|
@@ -6,11 +6,11 @@ export declare function printBanner(options: {
|
|
|
6
6
|
tunnel: string;
|
|
7
7
|
profileName?: string;
|
|
8
8
|
subdomain?: string;
|
|
9
|
+
hostname?: string;
|
|
9
10
|
token?: string;
|
|
10
11
|
npmScripts?: string[];
|
|
11
12
|
commands?: string[];
|
|
12
13
|
blacklistedCommands?: string[];
|
|
13
|
-
gitEnabled?: boolean;
|
|
14
14
|
}): void;
|
|
15
15
|
export declare function printRequestLog(entry: RequestLog): void;
|
|
16
16
|
export declare function logRequest(entry: RequestLog): void;
|
package/dist/src/logging.js
CHANGED
|
@@ -9,53 +9,24 @@ const BRIGHT_BLUE = "\x1b[94m";
|
|
|
9
9
|
const BRIGHT_CYAN = "\x1b[96m";
|
|
10
10
|
const BRIGHT_MAGENTA = "\x1b[95m";
|
|
11
11
|
const BRIGHT_YELLOW = "\x1b[93m";
|
|
12
|
-
const BRIGHT_RED = "\x1b[91m";
|
|
13
|
-
const BRIGHT_GREEN = "\x1b[92m";
|
|
14
12
|
const writeLine = (line = "") => {
|
|
15
13
|
process.stdout.write(`${line}\r\n`);
|
|
16
14
|
};
|
|
17
15
|
const color = (value, code) => `${code}${value}${RESET}`;
|
|
18
16
|
const TOOL_ICONS = {
|
|
19
|
-
list_files: "π",
|
|
20
|
-
list_dirs: "ποΈ",
|
|
21
17
|
read_range: "π",
|
|
22
|
-
read_files: "π",
|
|
23
|
-
write_files: "π",
|
|
24
|
-
patch_files: "π§©",
|
|
25
|
-
delete_files: "ποΈ",
|
|
26
18
|
run_npm_batch: "π§",
|
|
27
19
|
run_command_batch: "π οΈ",
|
|
28
|
-
search_files: "π",
|
|
29
20
|
find_files: "π§",
|
|
30
21
|
search_code: "π§ ",
|
|
31
22
|
find_symbol: "πΉ",
|
|
32
|
-
find_definition: "π―",
|
|
33
23
|
find_references: "π",
|
|
34
|
-
find_imports: "βͺ",
|
|
35
|
-
find_exports: "β",
|
|
36
|
-
git_status: "πΏ",
|
|
37
|
-
git_stage: "β",
|
|
38
|
-
git_unstage: "β",
|
|
39
|
-
git_commit: "β",
|
|
40
|
-
git_restore: "β©",
|
|
41
|
-
git_push: "β¬",
|
|
42
|
-
git_diff: "π",
|
|
43
|
-
git_log: "π",
|
|
44
|
-
project_overview: "πΊοΈ",
|
|
45
|
-
package_info: "π¦",
|
|
46
|
-
allowed_commands: "π",
|
|
47
24
|
file_info: "βΉοΈ",
|
|
48
|
-
diagnostics: "π©Ί",
|
|
49
25
|
project_context: "π§",
|
|
50
|
-
inspect: "π",
|
|
51
|
-
locate: "π―",
|
|
52
|
-
read_relevant: "π―",
|
|
53
|
-
git_changes: "π",
|
|
54
26
|
apply_changes: "βοΈ",
|
|
55
27
|
validate: "β",
|
|
56
28
|
};
|
|
57
29
|
const MCP_METHOD_ICONS = {
|
|
58
|
-
initialize: "π",
|
|
59
30
|
"notifications/initialized": "β",
|
|
60
31
|
"notifications/cancelled": "β",
|
|
61
32
|
"notifications/progress": "β³",
|
|
@@ -80,19 +51,8 @@ const MCP_METHOD_ICONS = {
|
|
|
80
51
|
const TOOL_NAME_WIDTH = Math.max(...Object.keys(TOOL_ICONS).map((name) => name.length));
|
|
81
52
|
const MCP_METHOD_NAME_WIDTH = Math.max(...Object.keys(MCP_METHOD_ICONS).map((name) => name.length));
|
|
82
53
|
const TOOL_COLORS = {
|
|
83
|
-
list_files: CYAN,
|
|
84
|
-
list_dirs: BRIGHT_CYAN,
|
|
85
|
-
read_files: BRIGHT_GREEN,
|
|
86
|
-
write_files: BRIGHT_YELLOW,
|
|
87
|
-
patch_files: BRIGHT_MAGENTA,
|
|
88
|
-
delete_files: BRIGHT_RED,
|
|
89
54
|
run_npm_batch: BRIGHT_BLUE,
|
|
90
55
|
run_command_batch: BRIGHT_CYAN,
|
|
91
|
-
git_stage: YELLOW,
|
|
92
|
-
git_unstage: MAGENTA,
|
|
93
|
-
git_commit: BRIGHT_GREEN,
|
|
94
|
-
git_restore: RED,
|
|
95
|
-
git_push: BRIGHT_BLUE,
|
|
96
56
|
};
|
|
97
57
|
const NARROW_TOOL_ICONS = new Set(["β", "β", "β", "β", "βͺ", "β"]);
|
|
98
58
|
const TOOL_ICON_SLOT_WIDTH = 3;
|
|
@@ -116,14 +76,16 @@ export function printHelp() {
|
|
|
116
76
|
writeLine("");
|
|
117
77
|
writeLine("Options:");
|
|
118
78
|
writeLine(" -p, --port <port> Local server port");
|
|
119
|
-
writeLine(" -t, --tunnel <provider>
|
|
79
|
+
writeLine(" -t, --tunnel <provider> Explicit tunnel provider (none, wormhole, cloudflared)");
|
|
80
|
+
writeLine(" -w, --wormhole Use Wormhole for this run");
|
|
81
|
+
writeLine(" -c, --cloudflared Use Cloudflare Tunnel for this run");
|
|
120
82
|
writeLine(" -s, --subdomain <name> Wormhole subdomain");
|
|
83
|
+
writeLine(" --hostname <host> Hostname routed to a Cloudflare Tunnel");
|
|
84
|
+
writeLine(" --cloudflared-token <token> Cloudflare Tunnel connector token (stored in config)");
|
|
121
85
|
writeLine(" --directory <path> Directory to expose");
|
|
122
86
|
writeLine(" --npm <scripts> Comma-separated allowed npm scripts");
|
|
123
87
|
writeLine(" --command <commands> Comma-separated allowed commands");
|
|
124
88
|
writeLine(" --blacklist <commands> Comma-separated blocked command prefixes");
|
|
125
|
-
writeLine(" --git Enable dedicated Git MCP tools");
|
|
126
|
-
writeLine(" --no-git Disable dedicated Git MCP tools");
|
|
127
89
|
writeLine(" --token <token> Explicit Bearer token");
|
|
128
90
|
writeLine(" --no-tunnel Disable tunneling");
|
|
129
91
|
writeLine(" --random Use a random Wormhole URL (no subdomain)");
|
|
@@ -169,43 +131,24 @@ export function printBanner(options) {
|
|
|
169
131
|
}
|
|
170
132
|
if (options.subdomain)
|
|
171
133
|
writeLine(` Domain https://${options.subdomain}.wormhole.bar`);
|
|
134
|
+
if (options.hostname)
|
|
135
|
+
writeLine(` Domain https://${options.hostname}`);
|
|
172
136
|
writeLine("");
|
|
173
137
|
writeLine(" MCP");
|
|
174
138
|
writeLine(` ${color("β‘ /mcp", CYAN)}`);
|
|
175
139
|
writeLine("");
|
|
176
140
|
writeLine(" TOOLS");
|
|
177
|
-
writeLine(` ${color(toolLabel("
|
|
178
|
-
writeLine(` ${color(toolLabel("list_dirs"), BRIGHT_CYAN)}`);
|
|
179
|
-
writeLine(` ${color(toolLabel("read_range"), GREEN)}`);
|
|
180
|
-
writeLine(` ${color(toolLabel("read_files"), BRIGHT_GREEN)}`);
|
|
181
|
-
writeLine(` ${color(toolLabel("write_files"), BRIGHT_YELLOW)}`);
|
|
182
|
-
writeLine(` ${color(toolLabel("patch_files"), BRIGHT_MAGENTA)}`);
|
|
183
|
-
writeLine(` ${color(toolLabel("delete_files"), BRIGHT_RED)}`);
|
|
184
|
-
writeLine(` ${color(toolLabel("run_npm_batch"), BRIGHT_BLUE)}`);
|
|
185
|
-
writeLine(` ${color(toolLabel("run_command_batch"), BRIGHT_CYAN)}`);
|
|
186
|
-
writeLine(` ${color(toolLabel("search_files"), CYAN)}`);
|
|
141
|
+
writeLine(` ${color(toolLabel("project_context"), BRIGHT_CYAN)}`);
|
|
187
142
|
writeLine(` ${color(toolLabel("find_files"), CYAN)}`);
|
|
188
143
|
writeLine(` ${color(toolLabel("search_code"), BRIGHT_CYAN)}`);
|
|
189
144
|
writeLine(` ${color(toolLabel("find_symbol"), GREEN)}`);
|
|
190
|
-
writeLine(` ${color(toolLabel("find_definition"), GREEN)}`);
|
|
191
145
|
writeLine(` ${color(toolLabel("find_references"), GREEN)}`);
|
|
192
|
-
writeLine(` ${color(toolLabel("
|
|
193
|
-
writeLine(` ${color(toolLabel("
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
writeLine(` ${color(toolLabel("git_unstage"), MAGENTA)}`);
|
|
198
|
-
writeLine(` ${color(toolLabel("git_commit"), BRIGHT_GREEN)}`);
|
|
199
|
-
writeLine(` ${color(toolLabel("git_restore"), RED)}`);
|
|
200
|
-
writeLine(` ${color(toolLabel("git_push"), BRIGHT_BLUE)}`);
|
|
201
|
-
writeLine(` ${color(toolLabel("git_diff"), CYAN)}`);
|
|
202
|
-
writeLine(` ${color(toolLabel("git_log"), CYAN)}`);
|
|
203
|
-
}
|
|
204
|
-
writeLine(` ${color(toolLabel("project_overview"), BRIGHT_CYAN)}`);
|
|
205
|
-
writeLine(` ${color(toolLabel("package_info"), YELLOW)}`);
|
|
206
|
-
writeLine(` ${color(toolLabel("allowed_commands"), YELLOW)}`);
|
|
146
|
+
writeLine(` ${color(toolLabel("read_range"), GREEN)}`);
|
|
147
|
+
writeLine(` ${color(toolLabel("apply_changes"), BRIGHT_MAGENTA)}`);
|
|
148
|
+
writeLine(` ${color(toolLabel("validate"), BRIGHT_YELLOW)}`);
|
|
149
|
+
writeLine(` ${color(toolLabel("run_npm_batch"), BRIGHT_BLUE)}`);
|
|
150
|
+
writeLine(` ${color(toolLabel("run_command_batch"), BRIGHT_CYAN)}`);
|
|
207
151
|
writeLine(` ${color(toolLabel("file_info"), YELLOW)}`);
|
|
208
|
-
writeLine(` ${color(toolLabel("diagnostics"), BRIGHT_YELLOW)}`);
|
|
209
152
|
writeLine("");
|
|
210
153
|
if (options.npmScripts?.length) {
|
|
211
154
|
writeLine(" NPM COMMANDS");
|