servherd 0.0.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.
Files changed (95) hide show
  1. package/CONTRIBUTING.md +250 -0
  2. package/LICENSE +21 -0
  3. package/README.md +653 -29
  4. package/dist/cli/commands/config.d.ts +35 -0
  5. package/dist/cli/commands/config.js +336 -0
  6. package/dist/cli/commands/info.d.ts +37 -0
  7. package/dist/cli/commands/info.js +98 -0
  8. package/dist/cli/commands/list.d.ts +26 -0
  9. package/dist/cli/commands/list.js +86 -0
  10. package/dist/cli/commands/logs.d.ts +46 -0
  11. package/dist/cli/commands/logs.js +292 -0
  12. package/dist/cli/commands/mcp.d.ts +5 -0
  13. package/dist/cli/commands/mcp.js +17 -0
  14. package/dist/cli/commands/refresh.d.ts +20 -0
  15. package/dist/cli/commands/refresh.js +139 -0
  16. package/dist/cli/commands/remove.d.ts +20 -0
  17. package/dist/cli/commands/remove.js +144 -0
  18. package/dist/cli/commands/restart.d.ts +25 -0
  19. package/dist/cli/commands/restart.js +177 -0
  20. package/dist/cli/commands/start.d.ts +37 -0
  21. package/dist/cli/commands/start.js +293 -0
  22. package/dist/cli/commands/stop.d.ts +20 -0
  23. package/dist/cli/commands/stop.js +108 -0
  24. package/dist/cli/index.d.ts +9 -0
  25. package/dist/cli/index.js +160 -0
  26. package/dist/cli/output/formatters.d.ts +117 -0
  27. package/dist/cli/output/formatters.js +454 -0
  28. package/dist/cli/output/json-formatter.d.ts +22 -0
  29. package/dist/cli/output/json-formatter.js +40 -0
  30. package/dist/index.d.ts +15 -0
  31. package/dist/index.js +25 -0
  32. package/dist/mcp/index.d.ts +14 -0
  33. package/dist/mcp/index.js +352 -0
  34. package/dist/mcp/resources/servers.d.ts +14 -0
  35. package/dist/mcp/resources/servers.js +128 -0
  36. package/dist/mcp/tools/config.d.ts +33 -0
  37. package/dist/mcp/tools/config.js +88 -0
  38. package/dist/mcp/tools/info.d.ts +36 -0
  39. package/dist/mcp/tools/info.js +65 -0
  40. package/dist/mcp/tools/list.d.ts +36 -0
  41. package/dist/mcp/tools/list.js +49 -0
  42. package/dist/mcp/tools/logs.d.ts +44 -0
  43. package/dist/mcp/tools/logs.js +55 -0
  44. package/dist/mcp/tools/refresh.d.ts +33 -0
  45. package/dist/mcp/tools/refresh.js +54 -0
  46. package/dist/mcp/tools/remove.d.ts +23 -0
  47. package/dist/mcp/tools/remove.js +43 -0
  48. package/dist/mcp/tools/restart.d.ts +23 -0
  49. package/dist/mcp/tools/restart.js +42 -0
  50. package/dist/mcp/tools/start.d.ts +38 -0
  51. package/dist/mcp/tools/start.js +73 -0
  52. package/dist/mcp/tools/stop.d.ts +23 -0
  53. package/dist/mcp/tools/stop.js +40 -0
  54. package/dist/services/config.service.d.ts +80 -0
  55. package/dist/services/config.service.js +227 -0
  56. package/dist/services/port.service.d.ts +82 -0
  57. package/dist/services/port.service.js +151 -0
  58. package/dist/services/process.service.d.ts +61 -0
  59. package/dist/services/process.service.js +220 -0
  60. package/dist/services/registry.service.d.ts +50 -0
  61. package/dist/services/registry.service.js +157 -0
  62. package/dist/types/config.d.ts +107 -0
  63. package/dist/types/config.js +44 -0
  64. package/dist/types/errors.d.ts +102 -0
  65. package/dist/types/errors.js +197 -0
  66. package/dist/types/pm2.d.ts +50 -0
  67. package/dist/types/pm2.js +4 -0
  68. package/dist/types/registry.d.ts +230 -0
  69. package/dist/types/registry.js +33 -0
  70. package/dist/utils/ci-detector.d.ts +31 -0
  71. package/dist/utils/ci-detector.js +68 -0
  72. package/dist/utils/config-drift.d.ts +71 -0
  73. package/dist/utils/config-drift.js +128 -0
  74. package/dist/utils/error-handler.d.ts +21 -0
  75. package/dist/utils/error-handler.js +38 -0
  76. package/dist/utils/log-follower.d.ts +10 -0
  77. package/dist/utils/log-follower.js +98 -0
  78. package/dist/utils/logger.d.ts +11 -0
  79. package/dist/utils/logger.js +24 -0
  80. package/dist/utils/names.d.ts +7 -0
  81. package/dist/utils/names.js +20 -0
  82. package/dist/utils/template.d.ts +88 -0
  83. package/dist/utils/template.js +180 -0
  84. package/dist/utils/time-parser.d.ts +19 -0
  85. package/dist/utils/time-parser.js +54 -0
  86. package/docs/ci-cd.md +408 -0
  87. package/docs/configuration.md +325 -0
  88. package/docs/mcp-integration.md +411 -0
  89. package/examples/basic-usage/README.md +187 -0
  90. package/examples/ci-github-actions/workflow.yml +195 -0
  91. package/examples/mcp-claude-code/README.md +213 -0
  92. package/examples/multi-server/README.md +270 -0
  93. package/examples/storybook/README.md +187 -0
  94. package/examples/vite-project/README.md +251 -0
  95. package/package.json +123 -6
@@ -0,0 +1,454 @@
1
+ import chalk from "chalk";
2
+ import Table from "cli-table3";
3
+ import boxen from "boxen";
4
+ /**
5
+ * Format server status with color
6
+ */
7
+ export function formatStatus(status) {
8
+ switch (status) {
9
+ case "online":
10
+ return chalk.green("● online");
11
+ case "stopped":
12
+ return chalk.gray("○ stopped");
13
+ case "errored":
14
+ return chalk.red("✖ errored");
15
+ default:
16
+ return chalk.yellow("? unknown");
17
+ }
18
+ }
19
+ /**
20
+ * Format URL for display
21
+ */
22
+ export function formatUrl(protocol, hostname, port) {
23
+ return chalk.cyan(`${protocol}://${hostname}:${port}`);
24
+ }
25
+ /**
26
+ * Format server name for display
27
+ */
28
+ export function formatName(name) {
29
+ return chalk.bold(name);
30
+ }
31
+ export function formatServerListTable(servers) {
32
+ if (servers.length === 0) {
33
+ return chalk.yellow("No servers registered");
34
+ }
35
+ const table = new Table({
36
+ head: [
37
+ chalk.bold("Name"),
38
+ chalk.bold("Status"),
39
+ chalk.bold("Port"),
40
+ chalk.bold("Command"),
41
+ chalk.bold("Working Directory"),
42
+ ],
43
+ style: {
44
+ head: [],
45
+ border: [],
46
+ },
47
+ });
48
+ for (const { server, status, hasDrift } of servers) {
49
+ // Add drift indicator to name if config has drifted
50
+ const nameDisplay = hasDrift
51
+ ? formatName(server.name) + chalk.yellow(" ⚡")
52
+ : formatName(server.name);
53
+ table.push([
54
+ nameDisplay,
55
+ formatStatus(status),
56
+ String(server.port),
57
+ truncateString(server.command, 30),
58
+ truncatePath(server.cwd, 30),
59
+ ]);
60
+ }
61
+ // Add legend if any server has drift
62
+ const anyDrift = servers.some(s => s.hasDrift);
63
+ let result = table.toString();
64
+ if (anyDrift) {
65
+ result += "\n\n" + chalk.yellow("⚡ = Config has changed since server started. Run `servherd refresh` to update.");
66
+ }
67
+ return result;
68
+ }
69
+ export function formatStartResult(result) {
70
+ const { action, server, status } = result;
71
+ const url = `${server.protocol}://${server.hostname}:${server.port}`;
72
+ const lines = [];
73
+ switch (action) {
74
+ case "started":
75
+ lines.push(chalk.green(`✓ Server "${server.name}" started`));
76
+ break;
77
+ case "existing":
78
+ lines.push(chalk.blue(`ℹ Server "${server.name}" already exists`));
79
+ break;
80
+ case "restarted":
81
+ lines.push(chalk.green(`✓ Server "${server.name}" restarted`));
82
+ break;
83
+ case "renamed":
84
+ lines.push(chalk.green(`✓ Server renamed from "${result.previousName}" to "${server.name}"`));
85
+ break;
86
+ }
87
+ lines.push(` ${chalk.bold("Name:")} ${server.name}`);
88
+ lines.push(` ${chalk.bold("Port:")} ${server.port}`);
89
+ lines.push(` ${chalk.bold("URL:")} ${chalk.cyan(url)}`);
90
+ lines.push(` ${chalk.bold("Status:")} ${formatStatus(status)}`);
91
+ lines.push(` ${chalk.bold("CWD:")} ${server.cwd}`);
92
+ return lines.join("\n");
93
+ }
94
+ export function formatStopResult(results) {
95
+ if (results.length === 0) {
96
+ return chalk.yellow("No servers to stop");
97
+ }
98
+ const lines = [];
99
+ for (const result of results) {
100
+ if (result.success) {
101
+ lines.push(chalk.green(`✓ Server "${result.name}" stopped`));
102
+ }
103
+ else {
104
+ lines.push(chalk.red(`✖ Failed to stop "${result.name}": ${result.message}`));
105
+ }
106
+ }
107
+ return lines.join("\n");
108
+ }
109
+ /**
110
+ * Format error message
111
+ */
112
+ export function formatError(message) {
113
+ return chalk.red(`✖ Error: ${message}`);
114
+ }
115
+ /**
116
+ * Format success message
117
+ */
118
+ export function formatSuccess(message) {
119
+ return chalk.green(`✓ ${message}`);
120
+ }
121
+ /**
122
+ * Format info message
123
+ */
124
+ export function formatInfo(message) {
125
+ return chalk.blue(`ℹ ${message}`);
126
+ }
127
+ /**
128
+ * Format warning message
129
+ */
130
+ export function formatWarning(message) {
131
+ return chalk.yellow(`⚠ ${message}`);
132
+ }
133
+ /**
134
+ * Truncate a string for display
135
+ */
136
+ function truncateString(str, maxLength) {
137
+ if (str.length <= maxLength) {
138
+ return str;
139
+ }
140
+ return str.slice(0, maxLength - 3) + "...";
141
+ }
142
+ /**
143
+ * Truncate a path for display
144
+ */
145
+ function truncatePath(path, maxLength) {
146
+ if (path.length <= maxLength) {
147
+ return path;
148
+ }
149
+ const parts = path.split("/");
150
+ let result = "";
151
+ // Start from the end and work backward
152
+ for (let i = parts.length - 1; i >= 0; i--) {
153
+ const candidate = parts.slice(i).join("/");
154
+ if (candidate.length <= maxLength - 3) {
155
+ result = "..." + (i > 0 ? "/" : "") + candidate;
156
+ break;
157
+ }
158
+ }
159
+ if (!result) {
160
+ // If even the last part is too long, just truncate
161
+ result = "..." + path.slice(-(maxLength - 3));
162
+ }
163
+ return result;
164
+ }
165
+ /**
166
+ * Format bytes to human readable string
167
+ */
168
+ function formatBytes(bytes) {
169
+ if (bytes < 1024) {
170
+ return `${bytes} B`;
171
+ }
172
+ else if (bytes < 1024 * 1024) {
173
+ return `${(bytes / 1024).toFixed(1)} KB`;
174
+ }
175
+ else if (bytes < 1024 * 1024 * 1024) {
176
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
177
+ }
178
+ else {
179
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
180
+ }
181
+ }
182
+ /**
183
+ * Format uptime to human readable string
184
+ */
185
+ function formatUptime(uptimeMs) {
186
+ const now = Date.now();
187
+ const durationMs = now - uptimeMs;
188
+ const seconds = Math.floor(durationMs / 1000);
189
+ const minutes = Math.floor(seconds / 60);
190
+ const hours = Math.floor(minutes / 60);
191
+ const days = Math.floor(hours / 24);
192
+ if (days > 0) {
193
+ return `${days}d ${hours % 24}h`;
194
+ }
195
+ else if (hours > 0) {
196
+ return `${hours}h ${minutes % 60}m`;
197
+ }
198
+ else if (minutes > 0) {
199
+ return `${minutes}m ${seconds % 60}s`;
200
+ }
201
+ else {
202
+ return `${seconds}s`;
203
+ }
204
+ }
205
+ /**
206
+ * Format server info as a boxed display
207
+ */
208
+ export function formatServerInfo(info) {
209
+ const lines = [];
210
+ // Header
211
+ lines.push(chalk.bold.cyan(`Server: ${info.name}`));
212
+ lines.push("");
213
+ // Status and basic info
214
+ lines.push(`${chalk.bold("Status:")} ${formatStatus(info.status)}`);
215
+ lines.push(`${chalk.bold("URL:")} ${chalk.cyan(info.url)}`);
216
+ lines.push(`${chalk.bold("Port:")} ${info.port}`);
217
+ lines.push(`${chalk.bold("Hostname:")} ${info.hostname}`);
218
+ lines.push(`${chalk.bold("Protocol:")} ${info.protocol}`);
219
+ lines.push("");
220
+ // Process info
221
+ if (info.pid) {
222
+ lines.push(`${chalk.bold("PID:")} ${info.pid}`);
223
+ }
224
+ if (info.uptime) {
225
+ lines.push(`${chalk.bold("Uptime:")} ${formatUptime(info.uptime)}`);
226
+ }
227
+ if (info.restarts !== undefined) {
228
+ lines.push(`${chalk.bold("Restarts:")} ${info.restarts}`);
229
+ }
230
+ if (info.memory !== undefined) {
231
+ lines.push(`${chalk.bold("Memory:")} ${formatBytes(info.memory)}`);
232
+ }
233
+ if (info.cpu !== undefined) {
234
+ lines.push(`${chalk.bold("CPU:")} ${info.cpu.toFixed(1)}%`);
235
+ }
236
+ lines.push("");
237
+ // Command info
238
+ lines.push(`${chalk.bold("Command:")} ${info.command}`);
239
+ lines.push(`${chalk.bold("Resolved:")} ${info.resolvedCommand}`);
240
+ lines.push(`${chalk.bold("CWD:")} ${info.cwd}`);
241
+ lines.push(`${chalk.bold("PM2 Name:")} ${info.pm2Name}`);
242
+ lines.push("");
243
+ // Optional fields
244
+ if (info.description) {
245
+ lines.push(`${chalk.bold("Description:")} ${info.description}`);
246
+ }
247
+ if (info.tags && info.tags.length > 0) {
248
+ lines.push(`${chalk.bold("Tags:")} ${info.tags.join(", ")}`);
249
+ }
250
+ // Log paths
251
+ if (info.outLogPath) {
252
+ lines.push(`${chalk.bold("Out Log:")} ${info.outLogPath}`);
253
+ }
254
+ if (info.errLogPath) {
255
+ lines.push(`${chalk.bold("Err Log:")} ${info.errLogPath}`);
256
+ }
257
+ // Environment variables
258
+ if (info.env && Object.keys(info.env).length > 0) {
259
+ lines.push("");
260
+ lines.push(chalk.bold("Environment:"));
261
+ for (const [key, value] of Object.entries(info.env)) {
262
+ lines.push(` ${key}=${value}`);
263
+ }
264
+ }
265
+ // Created at
266
+ lines.push("");
267
+ lines.push(`${chalk.bold("Created:")} ${new Date(info.createdAt).toLocaleString()}`);
268
+ return boxen(lines.join("\n"), {
269
+ padding: 1,
270
+ margin: 0,
271
+ borderStyle: "round",
272
+ borderColor: "cyan",
273
+ });
274
+ }
275
+ /**
276
+ * Format logs output
277
+ */
278
+ export function formatLogs(result) {
279
+ const lines = [];
280
+ lines.push(chalk.bold.cyan(`Logs for: ${result.name}`));
281
+ lines.push(`${chalk.bold("Status:")} ${formatStatus(result.status)}`);
282
+ if (result.outLogPath) {
283
+ lines.push(`${chalk.bold("Log file:")} ${result.outLogPath}`);
284
+ }
285
+ lines.push(`${chalk.bold("Lines:")} ${result.lines}`);
286
+ lines.push("");
287
+ lines.push(chalk.gray("─".repeat(60)));
288
+ lines.push("");
289
+ if (result.logs) {
290
+ lines.push(result.logs);
291
+ }
292
+ else {
293
+ lines.push(chalk.gray("(no logs available)"));
294
+ }
295
+ return lines.join("\n");
296
+ }
297
+ export function formatRestartResult(results) {
298
+ if (results.length === 0) {
299
+ return chalk.yellow("No servers to restart");
300
+ }
301
+ const lines = [];
302
+ for (const result of results) {
303
+ if (result.success) {
304
+ if (result.configRefreshed) {
305
+ lines.push(chalk.green(`✓ Server "${result.name}" restarted with updated config`));
306
+ }
307
+ else {
308
+ lines.push(chalk.green(`✓ Server "${result.name}" restarted`));
309
+ }
310
+ if (result.status) {
311
+ lines.push(` Status: ${formatStatus(result.status)}`);
312
+ }
313
+ }
314
+ else {
315
+ lines.push(chalk.red(`✖ Failed to restart "${result.name}": ${result.message}`));
316
+ }
317
+ }
318
+ return lines.join("\n");
319
+ }
320
+ function formatRefreshResult(results, dryRun) {
321
+ // Check if this is a "no drift" result
322
+ if (results.length === 1 && results[0].skipped && results[0].name === "") {
323
+ return chalk.blue(`ℹ ${results[0].message}`);
324
+ }
325
+ const lines = [];
326
+ if (dryRun) {
327
+ lines.push(chalk.yellow("Dry run mode - no changes made"));
328
+ lines.push("");
329
+ }
330
+ for (const result of results) {
331
+ if (result.skipped && dryRun) {
332
+ lines.push(chalk.yellow(`⚠ Server "${result.name}" would be refreshed`));
333
+ if (result.driftDetails) {
334
+ lines.push(chalk.gray(` ${result.driftDetails.split("\n").join("\n ")}`));
335
+ }
336
+ }
337
+ else if (result.success) {
338
+ lines.push(chalk.green(`✓ Server "${result.name}" refreshed with updated config`));
339
+ if (result.status) {
340
+ lines.push(` Status: ${formatStatus(result.status)}`);
341
+ }
342
+ }
343
+ else {
344
+ lines.push(chalk.red(`✖ Failed to refresh "${result.name}": ${result.message}`));
345
+ }
346
+ }
347
+ return lines.join("\n");
348
+ }
349
+ export function formatRemoveResult(results) {
350
+ if (results.length === 0) {
351
+ return chalk.yellow("No servers to remove");
352
+ }
353
+ const lines = [];
354
+ for (const result of results) {
355
+ if (result.success) {
356
+ lines.push(chalk.green(`✓ Server "${result.name}" removed`));
357
+ }
358
+ else if (result.cancelled) {
359
+ lines.push(chalk.yellow(`⚠ Removal of "${result.name}" cancelled`));
360
+ }
361
+ else {
362
+ lines.push(chalk.red(`✖ Failed to remove "${result.name}": ${result.message}`));
363
+ }
364
+ }
365
+ return lines.join("\n");
366
+ }
367
+ export function formatConfigResult(result) {
368
+ const lines = [];
369
+ // Handle error
370
+ if (result.error) {
371
+ return formatError(result.error);
372
+ }
373
+ // Handle --refresh / --refresh-all
374
+ if (result.refreshResults) {
375
+ return formatRefreshResult(result.refreshResults, result.dryRun);
376
+ }
377
+ // Handle --get
378
+ if (result.key !== undefined && result.value !== undefined && result.updated === undefined && result.reset === undefined) {
379
+ return `${chalk.bold(result.key)}: ${formatValue(result.value)}`;
380
+ }
381
+ // Handle --set
382
+ if (result.updated !== undefined) {
383
+ if (result.updated) {
384
+ let message = formatSuccess(`Configuration "${result.key}" set to ${formatValue(result.value)}`);
385
+ if (result.refreshMessage) {
386
+ message += "\n" + chalk.blue(`ℹ ${result.refreshMessage}`);
387
+ }
388
+ return message;
389
+ }
390
+ return formatError(result.error || "Failed to update configuration");
391
+ }
392
+ // Handle --reset
393
+ if (result.reset !== undefined) {
394
+ if (result.reset) {
395
+ return formatSuccess("Configuration reset to defaults");
396
+ }
397
+ if (result.cancelled) {
398
+ return formatWarning("Reset cancelled");
399
+ }
400
+ return formatError("Failed to reset configuration");
401
+ }
402
+ // Handle --show (default)
403
+ if (result.config) {
404
+ lines.push(chalk.bold.cyan("Current Configuration"));
405
+ lines.push("");
406
+ if (result.configPath) {
407
+ lines.push(`${chalk.bold("Loaded from:")} ${result.configPath}`);
408
+ }
409
+ else if (result.globalConfigPath) {
410
+ lines.push(`${chalk.bold("Global config:")} ${result.globalConfigPath}`);
411
+ }
412
+ lines.push("");
413
+ const table = new Table({
414
+ head: [chalk.bold("Setting"), chalk.bold("Value")],
415
+ style: { head: [], border: [] },
416
+ });
417
+ // Flatten config for display
418
+ const flatConfig = flattenConfig(result.config);
419
+ for (const [key, value] of Object.entries(flatConfig)) {
420
+ table.push([key, formatValue(value)]);
421
+ }
422
+ lines.push(table.toString());
423
+ return lines.join("\n");
424
+ }
425
+ return "";
426
+ }
427
+ /**
428
+ * Format a value for display
429
+ */
430
+ function formatValue(value) {
431
+ if (value === null || value === undefined) {
432
+ return chalk.gray("(not set)");
433
+ }
434
+ if (typeof value === "object") {
435
+ return JSON.stringify(value);
436
+ }
437
+ return String(value);
438
+ }
439
+ /**
440
+ * Flatten a nested config object for display
441
+ */
442
+ function flattenConfig(obj, prefix = "") {
443
+ const result = {};
444
+ for (const [key, value] of Object.entries(obj)) {
445
+ const fullKey = prefix ? `${prefix}.${key}` : key;
446
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
447
+ Object.assign(result, flattenConfig(value, fullKey));
448
+ }
449
+ else {
450
+ result[fullKey] = value;
451
+ }
452
+ }
453
+ return result;
454
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * JSON output formatting utilities for CLI commands.
3
+ */
4
+ /**
5
+ * Standard JSON output wrapper for successful operations.
6
+ */
7
+ export interface JsonOutput<T> {
8
+ success: boolean;
9
+ data: T;
10
+ error?: {
11
+ code: string;
12
+ message: string;
13
+ };
14
+ }
15
+ /**
16
+ * Format data as a successful JSON response.
17
+ */
18
+ export declare function formatAsJson<T>(data: T): string;
19
+ /**
20
+ * Format an error as a JSON response.
21
+ */
22
+ export declare function formatErrorAsJson(error: unknown): string;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * JSON output formatting utilities for CLI commands.
3
+ */
4
+ import { isServherdError } from "../../types/errors.js";
5
+ /**
6
+ * Format data as a successful JSON response.
7
+ */
8
+ export function formatAsJson(data) {
9
+ const output = {
10
+ success: true,
11
+ data,
12
+ };
13
+ return JSON.stringify(output, null, 2);
14
+ }
15
+ /**
16
+ * Format an error as a JSON response.
17
+ */
18
+ export function formatErrorAsJson(error) {
19
+ if (isServherdError(error)) {
20
+ const output = {
21
+ success: false,
22
+ data: null,
23
+ error: {
24
+ code: error.getCodeName(),
25
+ message: error.message,
26
+ },
27
+ };
28
+ return JSON.stringify(output, null, 2);
29
+ }
30
+ const message = error instanceof Error ? error.message : String(error);
31
+ const output = {
32
+ success: false,
33
+ data: null,
34
+ error: {
35
+ code: "UNKNOWN_ERROR",
36
+ message,
37
+ },
38
+ };
39
+ return JSON.stringify(output, null, 2);
40
+ }
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * servherd - CLI tool and MCP server for managing development servers across projects
4
+ */
5
+ export * from "./types/config.js";
6
+ export * from "./types/registry.js";
7
+ export * from "./types/pm2.js";
8
+ export * from "./utils/ci-detector.js";
9
+ export * from "./utils/logger.js";
10
+ export * from "./utils/template.js";
11
+ export { ConfigService } from "./services/config.service.js";
12
+ export { RegistryService } from "./services/registry.service.js";
13
+ export { PortService } from "./services/port.service.js";
14
+ export { ProcessService } from "./services/process.service.js";
15
+ export { runCLI, createProgram } from "./cli/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * servherd - CLI tool and MCP server for managing development servers across projects
4
+ */
5
+ import { runCLI } from "./cli/index.js";
6
+ // Export types
7
+ export * from "./types/config.js";
8
+ export * from "./types/registry.js";
9
+ export * from "./types/pm2.js";
10
+ // Export utilities
11
+ export * from "./utils/ci-detector.js";
12
+ export * from "./utils/logger.js";
13
+ export * from "./utils/template.js";
14
+ // Export services
15
+ export { ConfigService } from "./services/config.service.js";
16
+ export { RegistryService } from "./services/registry.service.js";
17
+ export { PortService } from "./services/port.service.js";
18
+ export { ProcessService } from "./services/process.service.js";
19
+ // Export CLI
20
+ export { runCLI, createProgram } from "./cli/index.js";
21
+ // Run CLI when executed directly
22
+ runCLI().catch((error) => {
23
+ console.error("Fatal error:", error);
24
+ process.exit(1);
25
+ });
@@ -0,0 +1,14 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface MCPServerOptions {
3
+ name?: string;
4
+ version?: string;
5
+ }
6
+ /**
7
+ * Create and configure an MCP server for servherd
8
+ */
9
+ export declare function createMCPServer(options?: MCPServerOptions): McpServer;
10
+ /**
11
+ * Start the MCP server in stdio mode
12
+ */
13
+ export declare function startStdioServer(): Promise<void>;
14
+ export { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";