@ebowwa/terminal 0.3.7 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Activity tracking for terminal operations
3
+ */
4
+ export interface Activity {
5
+ type: string;
6
+ message: string;
7
+ nodeId?: string;
8
+ sessionName?: string;
9
+ timestamp?: Date;
10
+ }
11
+ export declare function addActivity(activity: Activity): void;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Hetzner client stub for type checking
3
+ */
4
+ export interface HetznerClient {
5
+ }
6
+ export declare function createHetznerClient(): HetznerClient;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Hetzner types stub for type checking
3
+ */
4
+ export interface HetznerServer {
5
+ id: number;
6
+ name: string;
7
+ status: string;
8
+ }
9
+ export interface HetznerSSHKey {
10
+ id: number;
11
+ name: string;
12
+ fingerprint: string;
13
+ }
package/dist/manager.d.ts CHANGED
@@ -14,7 +14,27 @@
14
14
  * ENVIRONMENT VARIABLES:
15
15
  * - HETZNER_SSH_KEYS_DIR: Override default SSH keys directory
16
16
  */
17
- import type { HetznerClient } from "../lib/hetzner/client";
17
+ interface HetznerSSHKeysAPI {
18
+ getAll(): Promise<{
19
+ ssh_keys: HetznerSSHKey[];
20
+ }>;
21
+ list(): Promise<{
22
+ ssh_keys: HetznerSSHKey[];
23
+ }>;
24
+ create(params: {
25
+ name: string;
26
+ public_key: string;
27
+ }): Promise<HetznerSSHKey>;
28
+ findByName(name: string): Promise<HetznerSSHKey | undefined>;
29
+ }
30
+ interface HetznerClient {
31
+ ssh_keys: HetznerSSHKeysAPI;
32
+ }
33
+ interface HetznerSSHKey {
34
+ id: number;
35
+ name: string;
36
+ fingerprint: string;
37
+ }
18
38
  declare module "bun" {
19
39
  interface Env {
20
40
  HETZNER_SSH_KEYS_DIR?: string;
@@ -100,3 +120,4 @@ export declare class SSHKeyManager {
100
120
  * @returns SSH key information
101
121
  */
102
122
  export declare function ensureSSHKey(hetznerClient: HetznerClient, config?: SSHKeyManagerConfig): Promise<SSHKeyInfo>;
123
+ export {};
package/dist/mcp/index.js CHANGED
@@ -16,7 +16,6 @@ var __toESM = (mod, isNodeMode, target) => {
16
16
  });
17
17
  return to;
18
18
  };
19
- var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
20
19
  var __export = (target, all) => {
21
20
  for (var name in all)
22
21
  __defProp(target, name, {
@@ -446,34 +445,33 @@ var init_error = __esm(() => {
446
445
  });
447
446
 
448
447
  // node_modules/@ebowwa/codespaces-types/runtime/ssh.js
449
- var require_ssh = __commonJS((exports) => {
450
- Object.defineProperty(exports, "__esModule", { value: true });
451
- exports.FilePreviewOptionsSchema = exports.FilesListOptionsSchema = exports.SCPOptionsSchema = exports.SSHCommandSchema = exports.SSHOptionsSchema = undefined;
452
- var zod_1 = __require("zod");
453
- exports.SSHOptionsSchema = zod_1.z.object({
454
- host: zod_1.z.string().min(1, "Host is required"),
455
- user: zod_1.z.string().default("root"),
456
- timeout: zod_1.z.number().int().positive().default(5),
457
- port: zod_1.z.number().int().positive().max(65535).default(22),
458
- keyPath: zod_1.z.string().optional(),
459
- password: zod_1.z.string().optional()
448
+ import { z } from "zod";
449
+ var SSHOptionsSchema, SSHCommandSchema, SCPOptionsSchema, FilesListOptionsSchema, FilePreviewOptionsSchema;
450
+ var init_ssh = __esm(() => {
451
+ SSHOptionsSchema = z.object({
452
+ host: z.string().min(1, "Host is required"),
453
+ user: z.string().default("root"),
454
+ timeout: z.number().int().positive().default(5),
455
+ port: z.number().int().positive().max(65535).default(22),
456
+ keyPath: z.string().optional(),
457
+ password: z.string().optional()
460
458
  });
461
- exports.SSHCommandSchema = zod_1.z.string().min(1, "Command cannot be empty");
462
- exports.SCPOptionsSchema = exports.SSHOptionsSchema.extend({
463
- source: zod_1.z.string().min(1, "Source is required"),
464
- destination: zod_1.z.string().min(1, "Destination is required"),
465
- recursive: zod_1.z.boolean().default(false),
466
- preserve: zod_1.z.boolean().default(false)
459
+ SSHCommandSchema = z.string().min(1, "Command cannot be empty");
460
+ SCPOptionsSchema = SSHOptionsSchema.extend({
461
+ source: z.string().min(1, "Source is required"),
462
+ destination: z.string().min(1, "Destination is required"),
463
+ recursive: z.boolean().default(false),
464
+ preserve: z.boolean().default(false)
467
465
  });
468
- exports.FilesListOptionsSchema = zod_1.z.object({
469
- host: zod_1.z.string().min(1, "Host is required"),
470
- user: zod_1.z.string().default("root"),
471
- path: zod_1.z.string().default(".")
466
+ FilesListOptionsSchema = z.object({
467
+ host: z.string().min(1, "Host is required"),
468
+ user: z.string().default("root"),
469
+ path: z.string().default(".")
472
470
  });
473
- exports.FilePreviewOptionsSchema = zod_1.z.object({
474
- host: zod_1.z.string().min(1, "Host is required"),
475
- user: zod_1.z.string().default("root"),
476
- path: zod_1.z.string().min(1, "Path is required")
471
+ FilePreviewOptionsSchema = z.object({
472
+ host: z.string().min(1, "Host is required"),
473
+ user: z.string().default("root"),
474
+ path: z.string().min(1, "Path is required")
477
475
  });
478
476
  });
479
477
 
@@ -483,11 +481,11 @@ __export(exports_client, {
483
481
  execSSH: () => execSSH
484
482
  });
485
483
  async function execSSH(command, options) {
486
- const validatedCommand = import_ssh.SSHCommandSchema.safeParse(command);
484
+ const validatedCommand = SSHCommandSchema.safeParse(command);
487
485
  if (!validatedCommand.success) {
488
486
  throw new Error(`Invalid SSH command: ${validatedCommand.error.issues.map((i) => i.message).join(", ")}`);
489
487
  }
490
- const validatedOptions = import_ssh.SSHOptionsSchema.safeParse(options);
488
+ const validatedOptions = SSHOptionsSchema.safeParse(options);
491
489
  if (!validatedOptions.success) {
492
490
  throw new Error(`Invalid SSH options: ${validatedOptions.error.issues.map((i) => i.message).join(", ")}`);
493
491
  }
@@ -507,120 +505,10 @@ async function execSSH(command, options) {
507
505
  throw new SSHError(`SSH command failed: ${validatedCommand.data}`, error);
508
506
  }
509
507
  }
510
- var import_ssh;
511
508
  var init_client = __esm(() => {
512
509
  init_error();
510
+ init_ssh();
513
511
  init_pool();
514
- import_ssh = __toESM(require_ssh(), 1);
515
- });
516
-
517
- // node_modules/@ebowwa/codespaces-types/compile/terminal-websocket.js
518
- var require_terminal_websocket = __commonJS((exports) => {
519
- Object.defineProperty(exports, "__esModule", { value: true });
520
- exports.WebSocketCloseCode = undefined;
521
- exports.WebSocketCloseCode = {
522
- NORMAL_CLOSURE: 1000,
523
- ENDPOINT_GOING_AWAY: 1001,
524
- PROTOCOL_ERROR: 1002,
525
- UNSUPPORTED_DATA: 1003,
526
- NO_STATUS_RECEIVED: 1005,
527
- ABNORMAL_CLOSURE: 1006,
528
- INVALID_FRAME_PAYLOAD_DATA: 1007,
529
- POLICY_VIOLATION: 1008,
530
- MESSAGE_TOO_BIG: 1009,
531
- MISSING_MANDATORY_EXTENSION: 1010,
532
- INTERNAL_ERROR: 1011,
533
- SERVICE_RESTART: 1012,
534
- TRY_AGAIN_LATER: 1013,
535
- SESSION_NOT_FOUND: 4001,
536
- SESSION_ALREADY_CLOSED: 4002,
537
- INVALID_MESSAGE_FORMAT: 4003,
538
- AUTHENTICATION_FAILED: 4004,
539
- CONNECTION_TIMEOUT: 4005,
540
- SESSION_LIMIT_REACHED: 4006,
541
- INVALID_HOST: 4007,
542
- SSH_CONNECTION_FAILED: 4008,
543
- NETWORK_BLOCKED: 4009
544
- };
545
- });
546
-
547
- // node_modules/@ebowwa/codespaces-types/compile/index.js
548
- var require_compile = __commonJS((exports) => {
549
- var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
550
- if (k2 === undefined)
551
- k2 = k;
552
- var desc = Object.getOwnPropertyDescriptor(m, k);
553
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
554
- desc = { enumerable: true, get: function() {
555
- return m[k];
556
- } };
557
- }
558
- Object.defineProperty(o, k2, desc);
559
- } : function(o, m, k, k2) {
560
- if (k2 === undefined)
561
- k2 = k;
562
- o[k2] = m[k];
563
- });
564
- var __exportStar = exports && exports.__exportStar || function(m, exports2) {
565
- for (var p in m)
566
- if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p))
567
- __createBinding(exports2, m, p);
568
- };
569
- Object.defineProperty(exports, "__esModule", { value: true });
570
- exports.LoopStatus = exports.VolumeStatus = exports.ActionStatus = exports.EnvironmentStatus = undefined;
571
- exports.getEnvLocation = getEnvLocation;
572
- exports.getEnvRegionName = getEnvRegionName;
573
- exports.getEnvLocationLabel = getEnvLocationLabel;
574
- __exportStar(require_terminal_websocket(), exports);
575
- var EnvironmentStatus;
576
- (function(EnvironmentStatus2) {
577
- EnvironmentStatus2["Running"] = "running";
578
- EnvironmentStatus2["Stopped"] = "stopped";
579
- EnvironmentStatus2["Creating"] = "creating";
580
- EnvironmentStatus2["Deleting"] = "deleting";
581
- EnvironmentStatus2["Starting"] = "starting";
582
- EnvironmentStatus2["Stopping"] = "stopping";
583
- EnvironmentStatus2["Initializing"] = "initializing";
584
- })(EnvironmentStatus || (exports.EnvironmentStatus = EnvironmentStatus = {}));
585
- var ActionStatus;
586
- (function(ActionStatus2) {
587
- ActionStatus2["Running"] = "running";
588
- ActionStatus2["Success"] = "success";
589
- ActionStatus2["Error"] = "error";
590
- })(ActionStatus || (exports.ActionStatus = ActionStatus = {}));
591
- var VolumeStatus;
592
- (function(VolumeStatus2) {
593
- VolumeStatus2["Creating"] = "creating";
594
- VolumeStatus2["Available"] = "available";
595
- VolumeStatus2["Deleting"] = "deleting";
596
- })(VolumeStatus || (exports.VolumeStatus = VolumeStatus = {}));
597
- var LoopStatus;
598
- (function(LoopStatus2) {
599
- LoopStatus2["Running"] = "running";
600
- LoopStatus2["Stopped"] = "stopped";
601
- LoopStatus2["Error"] = "error";
602
- LoopStatus2["Completed"] = "completed";
603
- })(LoopStatus || (exports.LoopStatus = LoopStatus = {}));
604
- function getEnvLocation(env) {
605
- if (!env)
606
- return null;
607
- return env.location || null;
608
- }
609
- function getEnvRegionName(env) {
610
- var _a;
611
- if (!env)
612
- return "Unknown";
613
- return ((_a = env.location) === null || _a === undefined ? undefined : _a.name) || "Unknown";
614
- }
615
- function getEnvLocationLabel(env) {
616
- var _a, _b, _c;
617
- if (!env)
618
- return "Unknown";
619
- if (((_a = env.location) === null || _a === undefined ? undefined : _a.city) && ((_b = env.location) === null || _b === undefined ? undefined : _b.country)) {
620
- return "".concat(env.location.city, ", ").concat(env.location.country);
621
- }
622
- return ((_c = env.location) === null || _c === undefined ? undefined : _c.name) || "Unknown";
623
- }
624
512
  });
625
513
 
626
514
  // src/tmux.ts
@@ -1265,7 +1153,7 @@ class TmuxSessionManager {
1265
1153
  return { success: false, error: `Node ${nodeId} is not running` };
1266
1154
  }
1267
1155
  try {
1268
- const result = await createOrAttachTmuxSession(node.ip, node.user, node.keyPath, { sessionName });
1156
+ const result = await createOrAttachTmuxSession(node.ip, node.user, node.keyPath, {});
1269
1157
  return {
1270
1158
  success: true,
1271
1159
  sshArgs: result.sshArgs,
@@ -1697,10 +1585,10 @@ async function testSSHConnection(options) {
1697
1585
  init_pool();
1698
1586
  // src/scp.ts
1699
1587
  init_error();
1588
+ init_ssh();
1700
1589
  init_pool();
1701
- var import_ssh2 = __toESM(require_ssh(), 1);
1702
1590
  async function scpUpload(options) {
1703
- const validated = import_ssh2.SCPOptionsSchema.safeParse(options);
1591
+ const validated = SCPOptionsSchema.safeParse(options);
1704
1592
  if (!validated.success) {
1705
1593
  throw new Error(`Invalid SCP options: ${validated.error.issues.map((i) => i.message).join(", ")}`);
1706
1594
  }
@@ -1727,7 +1615,7 @@ async function scpUpload(options) {
1727
1615
  }
1728
1616
  }
1729
1617
  async function scpDownload(options) {
1730
- const validated = import_ssh2.SCPOptionsSchema.safeParse(options);
1618
+ const validated = SCPOptionsSchema.safeParse(options);
1731
1619
  if (!validated.success) {
1732
1620
  throw new Error(`Invalid SCP options: ${validated.error.issues.map((i) => i.message).join(", ")}`);
1733
1621
  }
@@ -1983,13 +1871,70 @@ import { promisify } from "util";
1983
1871
  var execAsync = promisify(__require("child_process").exec);
1984
1872
  // src/pty.ts
1985
1873
  var activeSessions = new Map;
1874
+ var activeReplSessions = new Map;
1986
1875
 
1987
1876
  // src/index.ts
1988
1877
  init_pool();
1989
1878
 
1990
1879
  // src/sessions.ts
1991
1880
  import path2 from "path";
1992
- var import_compile = __toESM(require_compile(), 1);
1881
+
1882
+ // node_modules/@ebowwa/codespaces-types/compile/index.js
1883
+ var WebSocketCloseCode = {
1884
+ NORMAL_CLOSURE: 1000,
1885
+ ENDPOINT_GOING_AWAY: 1001,
1886
+ PROTOCOL_ERROR: 1002,
1887
+ UNSUPPORTED_DATA: 1003,
1888
+ NO_STATUS_RECEIVED: 1005,
1889
+ ABNORMAL_CLOSURE: 1006,
1890
+ INVALID_FRAME_PAYLOAD_DATA: 1007,
1891
+ POLICY_VIOLATION: 1008,
1892
+ MESSAGE_TOO_BIG: 1009,
1893
+ MISSING_MANDATORY_EXTENSION: 1010,
1894
+ INTERNAL_ERROR: 1011,
1895
+ SERVICE_RESTART: 1012,
1896
+ TRY_AGAIN_LATER: 1013,
1897
+ SESSION_NOT_FOUND: 4001,
1898
+ SESSION_ALREADY_CLOSED: 4002,
1899
+ INVALID_MESSAGE_FORMAT: 4003,
1900
+ AUTHENTICATION_FAILED: 4004,
1901
+ CONNECTION_TIMEOUT: 4005,
1902
+ SESSION_LIMIT_REACHED: 4006,
1903
+ INVALID_HOST: 4007,
1904
+ SSH_CONNECTION_FAILED: 4008,
1905
+ NETWORK_BLOCKED: 4009
1906
+ };
1907
+ var EnvironmentStatus;
1908
+ ((EnvironmentStatus2) => {
1909
+ EnvironmentStatus2["Running"] = "running";
1910
+ EnvironmentStatus2["Stopped"] = "stopped";
1911
+ EnvironmentStatus2["Creating"] = "creating";
1912
+ EnvironmentStatus2["Deleting"] = "deleting";
1913
+ EnvironmentStatus2["Starting"] = "starting";
1914
+ EnvironmentStatus2["Stopping"] = "stopping";
1915
+ EnvironmentStatus2["Initializing"] = "initializing";
1916
+ })(EnvironmentStatus ||= {});
1917
+ var ActionStatus;
1918
+ ((ActionStatus2) => {
1919
+ ActionStatus2["Running"] = "running";
1920
+ ActionStatus2["Success"] = "success";
1921
+ ActionStatus2["Error"] = "error";
1922
+ })(ActionStatus ||= {});
1923
+ var VolumeStatus;
1924
+ ((VolumeStatus2) => {
1925
+ VolumeStatus2["Creating"] = "creating";
1926
+ VolumeStatus2["Available"] = "available";
1927
+ VolumeStatus2["Deleting"] = "deleting";
1928
+ })(VolumeStatus ||= {});
1929
+ var LoopStatus;
1930
+ ((LoopStatus2) => {
1931
+ LoopStatus2["Running"] = "running";
1932
+ LoopStatus2["Stopped"] = "stopped";
1933
+ LoopStatus2["Error"] = "error";
1934
+ LoopStatus2["Completed"] = "completed";
1935
+ })(LoopStatus ||= {});
1936
+
1937
+ // src/sessions.ts
1993
1938
  var metadataModule = null;
1994
1939
  function loadMetadata() {
1995
1940
  if (metadataModule === null) {
@@ -2030,7 +1975,7 @@ async function closeSession(sessionId) {
2030
1975
  } catch {}
2031
1976
  }
2032
1977
  try {
2033
- session.ws?.close(import_compile.WebSocketCloseCode.NORMAL_CLOSURE, "Session closed");
1978
+ session.ws?.close(WebSocketCloseCode.NORMAL_CLOSURE, "Session closed");
2034
1979
  } catch {}
2035
1980
  if (session.bootstrapLogStreamer) {
2036
1981
  try {
@@ -2350,14 +2295,14 @@ async function getOrCreateSession(host, user = "root", sessionId = null, keyPath
2350
2295
  console.log(`[Terminal] Process for ${newSessionId} exited with code ${exitCode}`);
2351
2296
  session.closed = true;
2352
2297
  try {
2353
- session.ws?.close(import_compile.WebSocketCloseCode.NORMAL_CLOSURE, `SSH process exited (code: ${exitCode})`);
2298
+ session.ws?.close(WebSocketCloseCode.NORMAL_CLOSURE, `SSH process exited (code: ${exitCode})`);
2354
2299
  } catch {}
2355
2300
  terminalSessions.delete(newSessionId);
2356
2301
  }).catch((err) => {
2357
2302
  console.log(`[Terminal] Process exit error for ${newSessionId}:`, err);
2358
2303
  session.closed = true;
2359
2304
  try {
2360
- session.ws?.close(import_compile.WebSocketCloseCode.INTERNAL_ERROR, "SSH process error");
2305
+ session.ws?.close(WebSocketCloseCode.INTERNAL_ERROR, "SSH process error");
2361
2306
  } catch {}
2362
2307
  });
2363
2308
  return session;
@@ -2439,6 +2384,12 @@ var DEFAULT_CONFIG3 = {
2439
2384
  historyLimit: 1e4,
2440
2385
  sessionAgeLimit: 30 * 24 * 60 * 60 * 1000
2441
2386
  };
2387
+ // src/config.ts
2388
+ import { join, dirname, isAbsolute, resolve } from "path";
2389
+ import { exec as exec2 } from "child_process";
2390
+ import { promisify as promisify3 } from "util";
2391
+ var execAsync3 = promisify3(exec2);
2392
+ var SSH_CONFIG_PATH = join(process.env.HOME || "~", ".ssh", "config");
2442
2393
  // src/mcp/index.ts
2443
2394
  async function listSessionsTool() {
2444
2395
  const sessions = getAllSessionInfo();
@@ -20,7 +20,9 @@ export interface TerminalSession {
20
20
  createdAt: number;
21
21
  lastUsed: number;
22
22
  reader: ReadableStreamDefaultReader<Uint8Array> | null;
23
- stderrReader: ReadableStreamDefaultReader<Uint8Array> | null;
23
+ stderrReader: (ReadableStreamDefaultReader<Uint8Array> & {
24
+ readMany?: () => Promise<any>;
25
+ }) | null;
24
26
  writer: WritableStreamDefaultWriter<Uint8Array> | null;
25
27
  closed: boolean;
26
28
  tmuxSessionName?: string;
Binary file
@@ -46,7 +46,7 @@ export interface TmuxSession {
46
46
  /**
47
47
  * Detailed session information with windows and panes
48
48
  */
49
- export interface DetailedTmuxSession extends TmuxSession {
49
+ export interface DetailedTmuxSession extends Omit<TmuxSession, 'windows'> {
50
50
  windows: Array<{
51
51
  index: string;
52
52
  name: string;
@@ -95,8 +95,8 @@ export interface CreateSessionOptions {
95
95
  * Options for batch command execution
96
96
  */
97
97
  export interface BatchCommandOptions {
98
- /** Command to execute */
99
- command: string;
98
+ /** Command to execute (optional - passed separately to sendCommandToNodes) */
99
+ command?: string;
100
100
  /** Target pane index (default: "0") */
101
101
  paneIndex?: string;
102
102
  /** Execute in parallel (default: true) */
@@ -293,6 +293,7 @@ export declare class TmuxSessionManager {
293
293
  success: boolean;
294
294
  cleaned?: number;
295
295
  errors?: string[];
296
+ error?: string;
296
297
  }>;
297
298
  /**
298
299
  * Get resource usage for sessions on a node
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ebowwa/terminal",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Terminal session management with tmux integration, SSH client, WebSocket support, and MCP interface",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,10 +17,15 @@
17
17
  "./types": {
18
18
  "types": "./dist/types.d.ts",
19
19
  "default": "./dist/types.d.ts"
20
+ },
21
+ "./client": {
22
+ "types": "./dist/client.d.ts",
23
+ "default": "./dist/client.js"
20
24
  }
21
25
  },
22
26
  "scripts": {
23
- "build": "bun build src/index.ts --outdir dist --target bun --external 'node-ssh' --external 'hono' --external 'zod' --external 'node:*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external 'node-ssh' --external 'hono' --external 'zod' --external 'node:*' --external '@modelcontextprotocol/*'"
27
+ "build": "bun build src/index.ts --outdir dist --target bun --external 'node-ssh' --external 'hono' --external 'zod' --external 'node:*' && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external 'node-ssh' --external 'hono' --external 'zod' --external 'node:*' --external '@modelcontextprotocol/*'",
28
+ "prepublishOnly": "bun run build"
24
29
  },
25
30
  "files": [
26
31
  "dist"
@@ -61,5 +66,13 @@
61
66
  "@types/bun": "latest",
62
67
  "@types/node-ssh": "^11.0.0",
63
68
  "typescript": "^5.9.3"
69
+ },
70
+ "ownership": {
71
+ "domain": "terminal",
72
+ "responsibilities": [
73
+ "ssh",
74
+ "tmux",
75
+ "session-management"
76
+ ]
64
77
  }
65
78
  }
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Terminal MCP Server
4
- *
5
- * Exposes terminal session management via Model Context Protocol
6
- * Integrates with tmux, SSH, PTY, and file operations
7
- */
8
- export {};
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Terminal MCP Server (stdio protocol)
4
- *
5
- * Model Context Protocol server for terminal session management
6
- * Uses stdio transport for Claude Code integration
7
- */
8
- export {};