ttyd-mux 0.2.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 (106) hide show
  1. package/README.md +222 -0
  2. package/dist/caddy/client.d.ts +84 -0
  3. package/dist/caddy/client.d.ts.map +1 -0
  4. package/dist/caddy/client.js +144 -0
  5. package/dist/caddy/client.js.map +1 -0
  6. package/dist/client/index.d.ts +11 -0
  7. package/dist/client/index.d.ts.map +1 -0
  8. package/dist/client/index.js +124 -0
  9. package/dist/client/index.js.map +1 -0
  10. package/dist/commands/attach.d.ts +5 -0
  11. package/dist/commands/attach.d.ts.map +1 -0
  12. package/dist/commands/attach.js +100 -0
  13. package/dist/commands/attach.js.map +1 -0
  14. package/dist/commands/caddy.d.ts +10 -0
  15. package/dist/commands/caddy.d.ts.map +1 -0
  16. package/dist/commands/caddy.js +151 -0
  17. package/dist/commands/caddy.js.map +1 -0
  18. package/dist/commands/daemon.d.ts +6 -0
  19. package/dist/commands/daemon.d.ts.map +1 -0
  20. package/dist/commands/daemon.js +24 -0
  21. package/dist/commands/daemon.js.map +1 -0
  22. package/dist/commands/down.d.ts +5 -0
  23. package/dist/commands/down.d.ts.map +1 -0
  24. package/dist/commands/down.js +25 -0
  25. package/dist/commands/down.js.map +1 -0
  26. package/dist/commands/shutdown.d.ts +5 -0
  27. package/dist/commands/shutdown.d.ts.map +1 -0
  28. package/dist/commands/shutdown.js +10 -0
  29. package/dist/commands/shutdown.js.map +1 -0
  30. package/dist/commands/start.d.ts +6 -0
  31. package/dist/commands/start.d.ts.map +1 -0
  32. package/dist/commands/start.js +59 -0
  33. package/dist/commands/start.js.map +1 -0
  34. package/dist/commands/status.d.ts +5 -0
  35. package/dist/commands/status.d.ts.map +1 -0
  36. package/dist/commands/status.js +38 -0
  37. package/dist/commands/status.js.map +1 -0
  38. package/dist/commands/stop.d.ts +6 -0
  39. package/dist/commands/stop.d.ts.map +1 -0
  40. package/dist/commands/stop.js +39 -0
  41. package/dist/commands/stop.js.map +1 -0
  42. package/dist/commands/up.d.ts +8 -0
  43. package/dist/commands/up.d.ts.map +1 -0
  44. package/dist/commands/up.js +48 -0
  45. package/dist/commands/up.js.map +1 -0
  46. package/dist/config/config.d.ts +13 -0
  47. package/dist/config/config.d.ts.map +1 -0
  48. package/dist/config/config.js +53 -0
  49. package/dist/config/config.js.map +1 -0
  50. package/dist/config/index.d.ts +4 -0
  51. package/dist/config/index.d.ts.map +1 -0
  52. package/dist/config/index.js +4 -0
  53. package/dist/config/index.js.map +1 -0
  54. package/dist/config/state.d.ts +20 -0
  55. package/dist/config/state.d.ts.map +1 -0
  56. package/dist/config/state.js +119 -0
  57. package/dist/config/state.js.map +1 -0
  58. package/dist/config/types.d.ts +70 -0
  59. package/dist/config/types.d.ts.map +1 -0
  60. package/dist/config/types.js +17 -0
  61. package/dist/config/types.js.map +1 -0
  62. package/dist/daemon/index.d.ts +6 -0
  63. package/dist/daemon/index.d.ts.map +1 -0
  64. package/dist/daemon/index.js +103 -0
  65. package/dist/daemon/index.js.map +1 -0
  66. package/dist/daemon/portal.d.ts +4 -0
  67. package/dist/daemon/portal.d.ts.map +1 -0
  68. package/dist/daemon/portal.js +127 -0
  69. package/dist/daemon/portal.js.map +1 -0
  70. package/dist/daemon/proxy.d.ts +7 -0
  71. package/dist/daemon/proxy.d.ts.map +1 -0
  72. package/dist/daemon/proxy.js +17 -0
  73. package/dist/daemon/proxy.js.map +1 -0
  74. package/dist/daemon/server.d.ts +5 -0
  75. package/dist/daemon/server.d.ts.map +1 -0
  76. package/dist/daemon/server.js +172 -0
  77. package/dist/daemon/server.js.map +1 -0
  78. package/dist/daemon/session-manager.d.ts +37 -0
  79. package/dist/daemon/session-manager.d.ts.map +1 -0
  80. package/dist/daemon/session-manager.js +131 -0
  81. package/dist/daemon/session-manager.js.map +1 -0
  82. package/dist/daemon/session-resolver.d.ts +41 -0
  83. package/dist/daemon/session-resolver.d.ts.map +1 -0
  84. package/dist/daemon/session-resolver.js +68 -0
  85. package/dist/daemon/session-resolver.js.map +1 -0
  86. package/dist/index.d.ts +3 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.js +95 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/tmux.d.ts +8 -0
  91. package/dist/tmux.d.ts.map +1 -0
  92. package/dist/tmux.js +65 -0
  93. package/dist/tmux.js.map +1 -0
  94. package/dist/types.d.ts +7 -0
  95. package/dist/types.d.ts.map +1 -0
  96. package/dist/types.js +2 -0
  97. package/dist/types.js.map +1 -0
  98. package/dist/ui.d.ts +25 -0
  99. package/dist/ui.d.ts.map +1 -0
  100. package/dist/ui.js +118 -0
  101. package/dist/ui.js.map +1 -0
  102. package/dist/utils/errors.d.ts +25 -0
  103. package/dist/utils/errors.d.ts.map +1 -0
  104. package/dist/utils/errors.js +52 -0
  105. package/dist/utils/errors.js.map +1 -0
  106. package/package.json +69 -0
package/dist/tmux.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { TmuxSession } from './types.js';
2
+ export declare function isInsideTmux(): boolean;
3
+ export declare function isTmuxInstalled(): boolean;
4
+ export declare function listSessions(): TmuxSession[];
5
+ export declare function attachSession(sessionName: string): Promise<number>;
6
+ export declare function getCwdSessionName(): string;
7
+ export declare function createSessionFromCwd(): Promise<number>;
8
+ //# sourceMappingURL=tmux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux.d.ts","sourceRoot":"","sources":["../src/tmux.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED,wBAAgB,eAAe,IAAI,OAAO,CAQzC;AAcD,wBAAgB,YAAY,IAAI,WAAW,EAAE,CAY5C;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYlE;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAYtD"}
package/dist/tmux.js ADDED
@@ -0,0 +1,65 @@
1
+ import { execSync, spawn } from 'node:child_process';
2
+ import { basename } from 'node:path';
3
+ export function isInsideTmux() {
4
+ return !!process.env['TMUX'];
5
+ }
6
+ export function isTmuxInstalled() {
7
+ try {
8
+ execSync('which tmux', { stdio: 'ignore' });
9
+ return true;
10
+ }
11
+ catch {
12
+ // Expected: tmux is not installed
13
+ return false;
14
+ }
15
+ }
16
+ const SESSION_FORMAT = '#{session_name}|#{session_windows}|#{session_created}|#{session_attached}';
17
+ function parseSessionLine(line) {
18
+ const [name = '', windows = '0', created = '0', attached] = line.split('|');
19
+ return {
20
+ name,
21
+ windows: Number.parseInt(windows, 10),
22
+ created: new Date(Number.parseInt(created, 10) * 1000),
23
+ attached: attached === '1'
24
+ };
25
+ }
26
+ export function listSessions() {
27
+ try {
28
+ const output = execSync(`tmux list-sessions -F "${SESSION_FORMAT}"`, { encoding: 'utf-8' });
29
+ return output
30
+ .trim()
31
+ .split('\n')
32
+ .filter((line) => line.length > 0)
33
+ .map(parseSessionLine);
34
+ }
35
+ catch {
36
+ // Expected: no tmux server running or no sessions
37
+ return [];
38
+ }
39
+ }
40
+ export function attachSession(sessionName) {
41
+ return new Promise((resolve) => {
42
+ const command = isInsideTmux() ? 'switch-client' : 'attach-session';
43
+ const tmux = spawn('tmux', [command, '-t', sessionName], {
44
+ stdio: 'inherit'
45
+ });
46
+ tmux.on('close', (code) => {
47
+ resolve(code ?? 0);
48
+ });
49
+ });
50
+ }
51
+ export function getCwdSessionName() {
52
+ return basename(process.cwd());
53
+ }
54
+ export function createSessionFromCwd() {
55
+ return new Promise((resolve) => {
56
+ const sessionName = getCwdSessionName();
57
+ const tmux = spawn('tmux', ['new', '-A', '-s', sessionName], {
58
+ stdio: 'inherit'
59
+ });
60
+ tmux.on('close', (code) => {
61
+ resolve(code ?? 0);
62
+ });
63
+ });
64
+ }
65
+ //# sourceMappingURL=tmux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux.js","sourceRoot":"","sources":["../src/tmux.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface TmuxSession {
2
+ name: string;
3
+ windows: number;
4
+ created: Date;
5
+ attached: boolean;
6
+ }
7
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/dist/ui.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import type { TmuxSession } from './types.js';
2
+ export declare function formatDate(date: Date): string;
3
+ export interface SelectResult {
4
+ action: 'attach' | 'quit';
5
+ session?: TmuxSession;
6
+ }
7
+ export type KeyAction = {
8
+ type: 'quit';
9
+ } | {
10
+ type: 'select';
11
+ index: number;
12
+ } | {
13
+ type: 'move';
14
+ direction: 'up' | 'down';
15
+ } | {
16
+ type: 'none';
17
+ };
18
+ export declare function handleKeypress(key: {
19
+ name?: string;
20
+ ctrl?: boolean;
21
+ } | undefined, sessionsCount: number): KeyAction;
22
+ export declare function findInitialIndex(sessions: TmuxSession[]): number;
23
+ export declare function calculateNewIndex(currentIndex: number, direction: 'up' | 'down', maxIndex: number): number;
24
+ export declare function selectSession(sessions: TmuxSession[]): Promise<SelectResult>;
25
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAiB9C,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAM7C;AA2BD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAWrB,wBAAgB,cAAc,CAC5B,GAAG,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,EAClD,aAAa,EAAE,MAAM,GACpB,SAAS,CAgBX;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,CAGhE;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,IAAI,GAAG,MAAM,EACxB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAoD5E"}
package/dist/ui.js ADDED
@@ -0,0 +1,118 @@
1
+ import * as readline from 'node:readline';
2
+ // ANSI escape codes
3
+ const ansi = {
4
+ clearScreen: '\x1b[2J\x1b[H',
5
+ hideCursor: '\x1b[?25l',
6
+ showCursor: '\x1b[?25h',
7
+ bold: '\x1b[1m',
8
+ dim: '\x1b[2m',
9
+ reset: '\x1b[0m',
10
+ cyan: '\x1b[36m',
11
+ yellow: '\x1b[33m',
12
+ green: '\x1b[32m'
13
+ };
14
+ const pad2 = (n) => String(n).padStart(2, '0');
15
+ export function formatDate(date) {
16
+ const month = pad2(date.getMonth() + 1);
17
+ const day = pad2(date.getDate());
18
+ const hours = pad2(date.getHours());
19
+ const minutes = pad2(date.getMinutes());
20
+ return `${month}/${day} ${hours}:${minutes}`;
21
+ }
22
+ function formatSessionLine(session, index, isSelected) {
23
+ const prefix = isSelected ? `${ansi.cyan}>${ansi.reset}` : ' ';
24
+ const num = `${ansi.yellow}[${index + 1}]${ansi.reset}`;
25
+ const name = isSelected
26
+ ? `${ansi.cyan}${ansi.bold}${session.name}${ansi.reset}`
27
+ : `${ansi.bold}${session.name}${ansi.reset}`;
28
+ const windowLabel = session.windows === 1 ? 'window' : 'windows';
29
+ const windows = `${ansi.dim}${session.windows} ${windowLabel}${ansi.reset}`;
30
+ const created = `${ansi.dim}(${formatDate(session.created)})${ansi.reset}`;
31
+ const attached = session.attached ? ` ${ansi.green}*attached*${ansi.reset}` : '';
32
+ return `${prefix} ${num} ${name.padEnd(20)} ${windows} ${created}${attached}`;
33
+ }
34
+ function renderSessions(sessions, selectedIndex) {
35
+ process.stdout.write(ansi.clearScreen);
36
+ console.log(`${ansi.bold}tmux sessions:${ansi.reset}\n`);
37
+ for (const [index, session] of sessions.entries()) {
38
+ console.log(formatSessionLine(session, index, index === selectedIndex));
39
+ }
40
+ console.log(`\n${ansi.dim}↑↓/jk: move 1-9: quick select Enter: attach q: quit${ansi.reset}`);
41
+ }
42
+ const keyBindings = {
43
+ q: { type: 'quit' },
44
+ up: { type: 'move', direction: 'up' },
45
+ k: { type: 'move', direction: 'up' },
46
+ down: { type: 'move', direction: 'down' },
47
+ j: { type: 'move', direction: 'down' },
48
+ return: { type: 'select', index: -1 }
49
+ };
50
+ export function handleKeypress(key, sessionsCount) {
51
+ if (!key?.name)
52
+ return { type: 'none' };
53
+ if (key.ctrl && key.name === 'c') {
54
+ return { type: 'quit' };
55
+ }
56
+ const binding = keyBindings[key.name];
57
+ if (binding)
58
+ return binding;
59
+ const num = Number.parseInt(key.name, 10);
60
+ if (num >= 1 && num <= 9 && num <= sessionsCount) {
61
+ return { type: 'select', index: num - 1 };
62
+ }
63
+ return { type: 'none' };
64
+ }
65
+ export function findInitialIndex(sessions) {
66
+ const attachedIndex = sessions.findIndex((s) => s.attached);
67
+ return attachedIndex !== -1 ? attachedIndex : 0;
68
+ }
69
+ export function calculateNewIndex(currentIndex, direction, maxIndex) {
70
+ return direction === 'up' ? Math.max(0, currentIndex - 1) : Math.min(maxIndex, currentIndex + 1);
71
+ }
72
+ export function selectSession(sessions) {
73
+ return new Promise((resolve) => {
74
+ if (sessions.length === 0) {
75
+ console.log('No tmux sessions found.');
76
+ resolve({ action: 'quit' });
77
+ return;
78
+ }
79
+ let selectedIndex = findInitialIndex(sessions);
80
+ process.stdout.write(ansi.hideCursor);
81
+ renderSessions(sessions, selectedIndex);
82
+ readline.emitKeypressEvents(process.stdin);
83
+ if (process.stdin.isTTY) {
84
+ process.stdin.setRawMode(true);
85
+ }
86
+ const cleanupAndResolve = (result) => {
87
+ process.stdout.write(ansi.showCursor);
88
+ if (process.stdin.isTTY) {
89
+ process.stdin.setRawMode(false);
90
+ }
91
+ process.stdin.removeListener('keypress', onKeypress);
92
+ process.stdout.write(ansi.clearScreen);
93
+ resolve(result);
94
+ };
95
+ const onKeypress = (_str, key) => {
96
+ const action = handleKeypress(key, sessions.length);
97
+ switch (action.type) {
98
+ case 'quit':
99
+ cleanupAndResolve({ action: 'quit' });
100
+ break;
101
+ case 'move':
102
+ selectedIndex = calculateNewIndex(selectedIndex, action.direction, sessions.length - 1);
103
+ renderSessions(sessions, selectedIndex);
104
+ break;
105
+ case 'select':
106
+ cleanupAndResolve({
107
+ action: 'attach',
108
+ session: sessions[action.index === -1 ? selectedIndex : action.index]
109
+ });
110
+ break;
111
+ case 'none':
112
+ break;
113
+ }
114
+ };
115
+ process.stdin.on('keypress', onKeypress);
116
+ });
117
+ }
118
+ //# sourceMappingURL=ui.js.map
package/dist/ui.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Application-specific error class with structured error information
3
+ */
4
+ export declare class AppError extends Error {
5
+ readonly code?: string;
6
+ constructor(message: string, code?: string, cause?: unknown);
7
+ static wrap(error: unknown, message: string, code?: string): AppError;
8
+ }
9
+ /**
10
+ * Extract error message from unknown error type
11
+ */
12
+ export declare function getErrorMessage(error: unknown): string;
13
+ /**
14
+ * Format error for CLI output
15
+ */
16
+ export declare function formatCliError(prefix: string, error: unknown): string;
17
+ /**
18
+ * Handle CLI command errors consistently
19
+ */
20
+ export declare function handleCliError(prefix: string, error: unknown): void;
21
+ /**
22
+ * Wrap a function with error handling
23
+ */
24
+ export declare function withErrorHandling<T>(fn: () => Promise<T>, errorPrefix: string): Promise<T | null>;
25
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;IAM3D,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;CAGtE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQtD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAErE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGnE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAOnB"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Application-specific error class with structured error information
3
+ */
4
+ export class AppError extends Error {
5
+ code;
6
+ constructor(message, code, cause) {
7
+ super(message, { cause });
8
+ this.name = 'AppError';
9
+ this.code = code;
10
+ }
11
+ static wrap(error, message, code) {
12
+ return new AppError(message, code, error);
13
+ }
14
+ }
15
+ /**
16
+ * Extract error message from unknown error type
17
+ */
18
+ export function getErrorMessage(error) {
19
+ if (error instanceof Error) {
20
+ return error.message;
21
+ }
22
+ if (typeof error === 'string') {
23
+ return error;
24
+ }
25
+ return 'Unknown error';
26
+ }
27
+ /**
28
+ * Format error for CLI output
29
+ */
30
+ export function formatCliError(prefix, error) {
31
+ return `${prefix}: ${getErrorMessage(error)}`;
32
+ }
33
+ /**
34
+ * Handle CLI command errors consistently
35
+ */
36
+ export function handleCliError(prefix, error) {
37
+ // biome-ignore lint/suspicious/noConsole: CLI error output is intentional
38
+ console.error(formatCliError(prefix, error));
39
+ }
40
+ /**
41
+ * Wrap a function with error handling
42
+ */
43
+ export async function withErrorHandling(fn, errorPrefix) {
44
+ try {
45
+ return await fn();
46
+ }
47
+ catch (error) {
48
+ handleCliError(errorPrefix, error);
49
+ return null;
50
+ }
51
+ }
52
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjB,IAAI,CAAU;IAE9B,YAAY,OAAe,EAAE,IAAa,EAAE,KAAe;QACzD,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,KAAc,EAAE,OAAe,EAAE,IAAa;QACxD,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,KAAc;IAC3D,OAAO,GAAG,MAAM,KAAK,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,KAAc;IAC3D,0EAA0E;IAC1E,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,EAAoB,EACpB,WAAmB;IAEnB,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "ttyd-mux",
3
+ "version": "0.2.0",
4
+ "description": "ttyd session multiplexer - manage multiple ttyd+tmux sessions",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "ttyd-mux": "./dist/index.js"
10
+ },
11
+ "scripts": {
12
+ "dev": "bun run src/index.ts",
13
+ "typecheck": "tsc --noEmit",
14
+ "check": "biome check ./src",
15
+ "check:fix": "biome check ./src --write",
16
+ "format": "biome format ./src --write",
17
+ "test": "bun test src/",
18
+ "test:watch": "bun test src/ --watch",
19
+ "test:e2e": "bunx playwright test",
20
+ "test:e2e:headed": "bunx playwright test --headed",
21
+ "test:e2e:debug": "bunx playwright test --debug",
22
+ "validate": "bun run typecheck && bun run check && bun run test",
23
+ "build": "tsc",
24
+ "build:binary": "bun build src/index.ts --compile --outfile ttyd-mux",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "devDependencies": {
28
+ "@biomejs/biome": "^1.9.0",
29
+ "@playwright/test": "^1.58.2",
30
+ "@types/bun": "latest",
31
+ "@types/http-proxy": "^1.17.14",
32
+ "@types/node": "^22.0.0",
33
+ "@types/proper-lockfile": "^4.1.4",
34
+ "playwright": "^1.58.2",
35
+ "typescript": "^5.6.0"
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "keywords": [
44
+ "ttyd",
45
+ "tmux",
46
+ "terminal",
47
+ "multiplexer",
48
+ "cli",
49
+ "web-terminal",
50
+ "session-manager"
51
+ ],
52
+ "license": "MIT",
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/cuzic/ttyd-mux.git"
56
+ },
57
+ "homepage": "https://github.com/cuzic/ttyd-mux#readme",
58
+ "bugs": {
59
+ "url": "https://github.com/cuzic/ttyd-mux/issues"
60
+ },
61
+ "author": "cuzic",
62
+ "dependencies": {
63
+ "commander": "^14.0.2",
64
+ "http-proxy": "^1.18.1",
65
+ "proper-lockfile": "^4.1.2",
66
+ "yaml": "^2.6.0",
67
+ "zod": "^4.3.6"
68
+ }
69
+ }