tmuxes 0.1.9 → 0.1.10

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 (140) hide show
  1. package/dist/agentHooks.js +91 -0
  2. package/dist/agentHooks.js.map +1 -0
  3. package/dist/agentOutput.js +30 -0
  4. package/dist/agentOutput.js.map +1 -0
  5. package/dist/agentState.js +45 -0
  6. package/dist/agentState.js.map +1 -0
  7. package/dist/config.js +32 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/exe.js +37 -0
  10. package/dist/exe.js.map +1 -0
  11. package/dist/exec.js +43 -0
  12. package/dist/exec.js.map +1 -0
  13. package/dist/files.js +308 -0
  14. package/dist/files.js.map +1 -0
  15. package/dist/foldersStore.js +103 -0
  16. package/dist/foldersStore.js.map +1 -0
  17. package/dist/index.js +117 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/logger.js +16 -0
  20. package/dist/logger.js.map +1 -0
  21. package/{server/src/monitor.ts → dist/monitor.js} +9 -10
  22. package/dist/monitor.js.map +1 -0
  23. package/dist/openBrowser.js +31 -0
  24. package/dist/openBrowser.js.map +1 -0
  25. package/{server/src/platform.ts → dist/platform.js} +5 -4
  26. package/dist/platform.js.map +1 -0
  27. package/dist/rest/router.js +198 -0
  28. package/dist/rest/router.js.map +1 -0
  29. package/dist/targetCommand.js +60 -0
  30. package/dist/targetCommand.js.map +1 -0
  31. package/dist/targets.js +131 -0
  32. package/dist/targets.js.map +1 -0
  33. package/dist/tmux/builder.js +174 -0
  34. package/dist/tmux/builder.js.map +1 -0
  35. package/dist/tmux/formats.js +61 -0
  36. package/dist/tmux/formats.js.map +1 -0
  37. package/dist/tmux/sessions.js +157 -0
  38. package/dist/tmux/sessions.js.map +1 -0
  39. package/dist/validate.js +65 -0
  40. package/dist/validate.js.map +1 -0
  41. package/dist/windowsSsh.js +209 -0
  42. package/dist/windowsSsh.js.map +1 -0
  43. package/dist/winshell/manager.js +267 -0
  44. package/dist/winshell/manager.js.map +1 -0
  45. package/dist/ws/protocol.js +4 -0
  46. package/dist/ws/protocol.js.map +1 -0
  47. package/dist/ws/sshState.js +35 -0
  48. package/dist/ws/sshState.js.map +1 -0
  49. package/dist/ws/terminalSession.js +204 -0
  50. package/dist/ws/terminalSession.js.map +1 -0
  51. package/dist/ws/wsServer.js +151 -0
  52. package/dist/ws/wsServer.js.map +1 -0
  53. package/dist/wsl.js +35 -0
  54. package/dist/wsl.js.map +1 -0
  55. package/package.json +49 -16
  56. package/public/assets/index-D_X5SnGx.css +1 -0
  57. package/public/assets/index-Dl69CPyt.js +44 -0
  58. package/{client → public}/index.html +3 -2
  59. package/.node-version +0 -1
  60. package/.nvmrc +0 -1
  61. package/.tmp-npm-cache/_cacache/content-v2/sha512/43/27/5e000b8b9c56a6ccc66f709485499f4304e2cb1982582ba571321c07b3ef56fcabd2c671898cc8003365a0485b6fd8e73e7b17b073cec0f7d1628c1a99df +0 -0
  62. package/.tmp-npm-cache/_cacache/content-v2/sha512/51/cf/4301295d74559ed494bae160d54d8741077f89faebb311882ac065019246951e7b53f3dcb913793c42b331e14c7070c4810c3cdc27a427d103a7db4614e0 +0 -0
  63. package/.tmp-npm-cache/_cacache/content-v2/sha512/c3/4d/d68a454a916e74c2617f586fbf770981b33811d667c2547eb0e9fc21938f4ee7e98f1ceee4bde8ad8815b5f6efe21b60eee798837d68f51a3340d7e5bb7a +0 -0
  64. package/.tmp-npm-cache/_cacache/content-v2/sha512/fe/40/2abfbefc96299e8bf714aa91d62607190ae299e102cf5933db2e2904640d65d25d67dbbb6fa2ddc92a17f00b9dbfdf2e37487f67d96ec36c64a285b59a7d +0 -0
  65. package/.tmp-npm-cache/_cacache/index-v5/27/fe/81a3de6ce7ae3d1e41a3421de20c5629998c4ee5d0ffe2037630f03b03b2 +0 -4
  66. package/.tmp-npm-cache/_cacache/index-v5/65/22/dd66711f62681fce09aabb2357a2907b4a0c778ac5227c4baf9603fd86e8 +0 -4
  67. package/.tmp-npm-cache/_update-notifier-last-checked +0 -0
  68. package/AGENTS.md +0 -15
  69. package/CLAUDE.md +0 -3
  70. package/README.en.md +0 -304
  71. package/SECURITY.md +0 -31
  72. package/client/package.json +0 -29
  73. package/client/src/App.tsx +0 -123
  74. package/client/src/activity.ts +0 -5
  75. package/client/src/api.ts +0 -130
  76. package/client/src/attention.tsx +0 -157
  77. package/client/src/components/FileExplorer.tsx +0 -156
  78. package/client/src/components/FileViewer.tsx +0 -194
  79. package/client/src/components/SessionRow.tsx +0 -108
  80. package/client/src/components/SessionTree.tsx +0 -197
  81. package/client/src/components/SettingsButton.tsx +0 -122
  82. package/client/src/components/Sidebar.tsx +0 -96
  83. package/client/src/components/StatusBanner.tsx +0 -31
  84. package/client/src/components/TargetGroup.tsx +0 -275
  85. package/client/src/components/TerminalPanel.tsx +0 -192
  86. package/client/src/folders.ts +0 -245
  87. package/client/src/hooks/useTerminal.ts +0 -67
  88. package/client/src/hooks/useTmuxSocket.ts +0 -65
  89. package/client/src/i18n.ts +0 -213
  90. package/client/src/main.tsx +0 -17
  91. package/client/src/settings.tsx +0 -87
  92. package/client/src/styles.css +0 -723
  93. package/client/src/types.ts +0 -93
  94. package/client/src/util.ts +0 -65
  95. package/client/tsconfig.json +0 -13
  96. package/client/vite.config.ts +0 -15
  97. package/fig/fig1.png +0 -0
  98. package/scripts/prepack.mjs +0 -35
  99. package/server/package.json +0 -61
  100. package/server/src/agentHooks.ts +0 -120
  101. package/server/src/agentOutput.ts +0 -36
  102. package/server/src/agentState.ts +0 -70
  103. package/server/src/config.ts +0 -31
  104. package/server/src/exe.ts +0 -34
  105. package/server/src/exec.ts +0 -61
  106. package/server/src/files.ts +0 -330
  107. package/server/src/foldersStore.ts +0 -114
  108. package/server/src/index.ts +0 -114
  109. package/server/src/logger.ts +0 -16
  110. package/server/src/openBrowser.ts +0 -28
  111. package/server/src/rest/router.ts +0 -290
  112. package/server/src/targetCommand.ts +0 -79
  113. package/server/src/targets.ts +0 -152
  114. package/server/src/tmux/builder.ts +0 -198
  115. package/server/src/tmux/formats.ts +0 -95
  116. package/server/src/tmux/sessions.ts +0 -204
  117. package/server/src/validate.ts +0 -79
  118. package/server/src/windowsSsh.ts +0 -239
  119. package/server/src/winshell/manager.ts +0 -296
  120. package/server/src/ws/protocol.ts +0 -15
  121. package/server/src/ws/sshState.ts +0 -36
  122. package/server/src/ws/terminalSession.ts +0 -207
  123. package/server/src/ws/wsServer.ts +0 -153
  124. package/server/src/wsl.ts +0 -38
  125. package/server/test/agentHooks.test.ts +0 -66
  126. package/server/test/agentOutput.test.ts +0 -26
  127. package/server/test/agentState.test.ts +0 -24
  128. package/server/test/builder.test.ts +0 -162
  129. package/server/test/files.test.ts +0 -81
  130. package/server/test/formats.test.ts +0 -123
  131. package/server/test/monitor.test.ts +0 -25
  132. package/server/test/validate.test.ts +0 -71
  133. package/server/test/wsl.test.ts +0 -18
  134. package/server/tsconfig.json +0 -9
  135. package/server/vitest.config.ts +0 -12
  136. package/start.cmd +0 -30
  137. package/start.command +0 -20
  138. package/start.sh +0 -20
  139. package/tsconfig.base.json +0 -19
  140. /package/{server/bin → bin}/tmuxes.js +0 -0
@@ -0,0 +1,209 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { config } from './config.js';
4
+ import { sshDestination } from './targets.js';
5
+ import { sshClientArgs } from './tmux/builder.js';
6
+ const SENSITIVE_SSH_OPTIONS = new Set([
7
+ '-B',
8
+ '-b',
9
+ '-c',
10
+ '-D',
11
+ '-E',
12
+ '-e',
13
+ '-F',
14
+ '-I',
15
+ '-i',
16
+ '-J',
17
+ '-L',
18
+ '-l',
19
+ '-m',
20
+ '-O',
21
+ '-o',
22
+ '-p',
23
+ '-Q',
24
+ '-R',
25
+ '-S',
26
+ '-W',
27
+ '-w',
28
+ ]);
29
+ const sessions = new Map();
30
+ function targetKey(target) {
31
+ return `${sshDestination(target)}:${target.port ?? 22}:${target.id}`;
32
+ }
33
+ function splitSshArgs(args) {
34
+ for (let i = 0; i < args.length; i++) {
35
+ const arg = args[i];
36
+ if (SENSITIVE_SSH_OPTIONS.has(arg)) {
37
+ i++;
38
+ continue;
39
+ }
40
+ if (arg.startsWith('-'))
41
+ continue;
42
+ return { connectArgs: args.slice(0, i + 1), remoteArgs: args.slice(i + 1) };
43
+ }
44
+ return { connectArgs: args, remoteArgs: [] };
45
+ }
46
+ function commandFromSshArgv(file, args, input) {
47
+ if (file !== 'ssh')
48
+ return { command: '', input };
49
+ const { remoteArgs } = splitSshArgs(args);
50
+ return { command: remoteArgs.join(' '), input };
51
+ }
52
+ function connectArgsFor(target) {
53
+ const argv = sshClientArgs(target, {
54
+ batchMode: true,
55
+ connectTimeout: config.ssh.connectTimeoutMgmt,
56
+ multiplex: false,
57
+ });
58
+ const { connectArgs } = splitSshArgs(argv.slice(1));
59
+ return ['-T', ...connectArgs, 'sh'];
60
+ }
61
+ function encodeInput(input) {
62
+ return Buffer.from(input, 'utf8').toString('base64').replace(/(.{76})/g, '$1\n');
63
+ }
64
+ function decodePayload(payload) {
65
+ return Buffer.from(payload.replace(/\s+/g, ''), 'base64').toString('utf8');
66
+ }
67
+ function scriptFor(id, command, input) {
68
+ const inputMarker = `__TMUXES_INPUT_${id}__`;
69
+ const begin = `__TMUXES_BEGIN_${id}__`;
70
+ const stderr = `__TMUXES_STDERR_${id}__`;
71
+ const end = `__TMUXES_END_${id}__`;
72
+ const run = input === undefined
73
+ ? `( ${command} )`
74
+ : `base64 -d <<'${inputMarker}' | ( ${command} )\n${encodeInput(input)}\n${inputMarker}`;
75
+ return [
76
+ `__tmuxes_out=$(mktemp "\${TMPDIR:-/tmp}/tmuxes-out.XXXXXX") || exit 125`,
77
+ `__tmuxes_err=$(mktemp "\${TMPDIR:-/tmp}/tmuxes-err.XXXXXX") || { rm -f "$__tmuxes_out"; exit 125; }`,
78
+ `{ ${run}\n} > "$__tmuxes_out" 2> "$__tmuxes_err"`,
79
+ `__tmuxes_code=$?`,
80
+ `printf '\\n${begin}\\n'`,
81
+ `printf '%s\\n' "$__tmuxes_code"`,
82
+ `base64 < "$__tmuxes_out"`,
83
+ `printf '\\n${stderr}\\n'`,
84
+ `base64 < "$__tmuxes_err"`,
85
+ `printf '\\n${end}\\n'`,
86
+ `rm -f "$__tmuxes_out" "$__tmuxes_err"`,
87
+ ].join('\n') + '\n';
88
+ }
89
+ class WindowsSshSession {
90
+ key;
91
+ child;
92
+ queue = Promise.resolve();
93
+ stdout = '';
94
+ sshStderr = '';
95
+ closed = false;
96
+ pending;
97
+ constructor(key, target) {
98
+ this.key = key;
99
+ this.child = spawn('ssh', connectArgsFor(target), { shell: false });
100
+ this.child.stdout.on('data', (chunk) => this.onStdout(chunk.toString('utf8')));
101
+ this.child.stderr.on('data', (chunk) => {
102
+ this.sshStderr += chunk.toString('utf8');
103
+ });
104
+ this.child.on('error', (err) => this.finishPending(null, null, err.message));
105
+ this.child.on('close', (code, signal) => {
106
+ this.closed = true;
107
+ if (sessions.get(this.key) === this)
108
+ sessions.delete(this.key);
109
+ this.finishPending(code, signal, this.sshStderr || 'ssh connection closed');
110
+ });
111
+ }
112
+ dispose() {
113
+ this.closed = true;
114
+ if (sessions.get(this.key) === this)
115
+ sessions.delete(this.key);
116
+ try {
117
+ this.child.kill('SIGKILL');
118
+ }
119
+ catch {
120
+ /* already gone */
121
+ }
122
+ }
123
+ run(command, input, opts) {
124
+ const next = this.queue
125
+ .catch(() => {
126
+ /* keep later commands moving */
127
+ })
128
+ .then(() => this.runNow(command, input, opts));
129
+ this.queue = next.then(() => undefined, () => undefined);
130
+ return next;
131
+ }
132
+ runNow(command, input, opts) {
133
+ if (this.closed)
134
+ return Promise.resolve({ code: 255, signal: null, stdout: '', stderr: 'ssh connection closed' });
135
+ if (!command)
136
+ return Promise.resolve({ code: 255, signal: null, stdout: '', stderr: 'missing remote command' });
137
+ const id = randomUUID().replace(/-/g, '');
138
+ return new Promise((resolve) => {
139
+ const pending = { id, resolve };
140
+ this.pending = pending;
141
+ if (opts.timeoutMs) {
142
+ pending.timer = setTimeout(() => {
143
+ this.resolvePending({ code: null, signal: 'SIGKILL', stdout: '', stderr: 'ssh command timed out' });
144
+ this.dispose();
145
+ }, opts.timeoutMs);
146
+ }
147
+ this.child.stdin.write(scriptFor(id, command, input), (err) => {
148
+ if (err)
149
+ this.finishPending(null, null, err.message);
150
+ });
151
+ });
152
+ }
153
+ onStdout(chunk) {
154
+ this.stdout += chunk;
155
+ const pending = this.pending;
156
+ if (!pending)
157
+ return;
158
+ const begin = `__TMUXES_BEGIN_${pending.id}__\n`;
159
+ const stderr = `\n__TMUXES_STDERR_${pending.id}__\n`;
160
+ const end = `\n__TMUXES_END_${pending.id}__`;
161
+ const beginIndex = this.stdout.indexOf(begin);
162
+ if (beginIndex < 0)
163
+ return;
164
+ const stderrIndex = this.stdout.indexOf(stderr, beginIndex + begin.length);
165
+ if (stderrIndex < 0)
166
+ return;
167
+ const endIndex = this.stdout.indexOf(end, stderrIndex + stderr.length);
168
+ if (endIndex < 0)
169
+ return;
170
+ const stdoutStart = beginIndex + begin.length;
171
+ const codeLineEnd = this.stdout.indexOf('\n', stdoutStart);
172
+ if (codeLineEnd < 0 || codeLineEnd > stderrIndex)
173
+ return;
174
+ const code = Number(this.stdout.slice(stdoutStart, codeLineEnd)) || 0;
175
+ const out = decodePayload(this.stdout.slice(codeLineEnd + 1, stderrIndex));
176
+ const err = decodePayload(this.stdout.slice(stderrIndex + stderr.length, endIndex));
177
+ this.stdout = this.stdout.slice(endIndex + end.length);
178
+ this.resolvePending({ code, signal: null, stdout: out, stderr: err });
179
+ }
180
+ resolvePending(result) {
181
+ const pending = this.pending;
182
+ if (!pending)
183
+ return;
184
+ this.pending = undefined;
185
+ if (pending.timer)
186
+ clearTimeout(pending.timer);
187
+ pending.resolve(result);
188
+ }
189
+ finishPending(code, signal, stderr) {
190
+ this.resolvePending({ code, signal, stdout: '', stderr });
191
+ }
192
+ }
193
+ function sessionFor(target) {
194
+ const key = targetKey(target);
195
+ const existing = sessions.get(key);
196
+ if (existing)
197
+ return existing;
198
+ const session = new WindowsSshSession(key, target);
199
+ sessions.set(key, session);
200
+ return session;
201
+ }
202
+ export async function runWindowsSshCommand(target, file, args, opts) {
203
+ const { command, input } = commandFromSshArgv(file, args, opts.input);
204
+ return sessionFor(target).run(command, input, opts);
205
+ }
206
+ export function dropWindowsSshSession(target) {
207
+ sessions.get(targetKey(target))?.dispose();
208
+ }
209
+ //# sourceMappingURL=windowsSsh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowsSsh.js","sourceRoot":"","sources":["../src/windowsSsh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,267 @@
1
+ import * as pty from 'node-pty';
2
+ import { existsSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { isWindows } from '../platform.js';
6
+ import { log } from '../logger.js';
7
+ const SCROLLBACK_CAP = 256 * 1024; // bytes of history replayed to a new client
8
+ function nowEpoch() {
9
+ return Math.floor(Date.now() / 1000);
10
+ }
11
+ /** One persistent native shell (its own pty), shared by 0..N attached clients.
12
+ * Survives client disconnects (the pty lives until killed or it exits), which
13
+ * is what gives "refresh / reconnect / multi-tab" persistence. */
14
+ export class WinShellSession {
15
+ name;
16
+ shell;
17
+ ptyProc;
18
+ onClosed;
19
+ created = nowEpoch();
20
+ clients = new Set();
21
+ scroll = [];
22
+ scrollBytes = 0;
23
+ disposed = false;
24
+ /** epoch seconds of last pty output — drives idle/attention detection */
25
+ lastActivity = nowEpoch();
26
+ constructor(name, shell, ptyProc, onClosed) {
27
+ this.name = name;
28
+ this.shell = shell;
29
+ this.ptyProc = ptyProc;
30
+ this.onClosed = onClosed;
31
+ this.ptyProc.onData((d) => this.onData(d));
32
+ this.ptyProc.onExit(({ exitCode }) => this.onExit(exitCode));
33
+ }
34
+ get attached() {
35
+ return this.clients.size > 0;
36
+ }
37
+ onData(data) {
38
+ this.lastActivity = nowEpoch();
39
+ const buf = Buffer.from(data, 'utf8');
40
+ this.scroll.push(buf);
41
+ this.scrollBytes += buf.length;
42
+ while (this.scrollBytes > SCROLLBACK_CAP && this.scroll.length > 1) {
43
+ this.scrollBytes -= this.scroll.shift().length;
44
+ }
45
+ for (const c of this.clients)
46
+ if (c.isOpen())
47
+ c.sendBinary(buf);
48
+ }
49
+ onExit(code) {
50
+ if (this.disposed)
51
+ return;
52
+ this.disposed = true;
53
+ for (const c of this.clients) {
54
+ c.sendControl({ type: 'exit', code });
55
+ c.close(1000, 'shell exited');
56
+ }
57
+ this.clients.clear();
58
+ this.onClosed(this.name);
59
+ }
60
+ /** Add a client: replay history, then it's live. Caller sends `ready` after. */
61
+ attach(client) {
62
+ if (this.scroll.length)
63
+ client.sendBinary(Buffer.concat(this.scroll));
64
+ this.clients.add(client);
65
+ }
66
+ detach(client) {
67
+ this.clients.delete(client); // pty stays alive — persistence across reconnects
68
+ }
69
+ write(data) {
70
+ if (!this.disposed)
71
+ this.ptyProc.write(data);
72
+ }
73
+ resize(cols, rows) {
74
+ try {
75
+ this.ptyProc.resize(cols, rows);
76
+ }
77
+ catch {
78
+ /* pty may have exited */
79
+ }
80
+ }
81
+ info() {
82
+ return {
83
+ name: this.name,
84
+ windows: 1,
85
+ attached: this.attached,
86
+ created: this.created,
87
+ lastActivity: this.lastActivity,
88
+ };
89
+ }
90
+ dispose() {
91
+ if (this.disposed) {
92
+ this.onClosed(this.name);
93
+ return;
94
+ }
95
+ this.disposed = true;
96
+ try {
97
+ this.ptyProc.kill();
98
+ }
99
+ catch {
100
+ /* already gone */
101
+ }
102
+ for (const c of this.clients)
103
+ c.close(1000, 'killed');
104
+ this.clients.clear();
105
+ this.onClosed(this.name);
106
+ }
107
+ }
108
+ const NAME_RE = /^[A-Za-z0-9_-]{1,64}$/;
109
+ /** Owns all native shell sessions for the local Windows machine. */
110
+ export class WinShellManager {
111
+ sessions = new Map();
112
+ shells;
113
+ constructor(shells) {
114
+ this.shells = shells ?? detectShells();
115
+ }
116
+ listShells() {
117
+ return this.shells.map((s) => ({ id: s.id, label: s.label }));
118
+ }
119
+ resolveShell(shellId) {
120
+ if (shellId) {
121
+ const found = this.shells.find((s) => s.id === shellId);
122
+ if (found)
123
+ return found;
124
+ }
125
+ if (this.shells.length === 0)
126
+ throw new Error('no shell available');
127
+ return this.shells[0];
128
+ }
129
+ list() {
130
+ return [...this.sessions.values()]
131
+ .map((s) => s.info())
132
+ .sort((a, b) => a.created - b.created);
133
+ }
134
+ windows(name) {
135
+ const s = this.sessions.get(name);
136
+ if (!s)
137
+ return [];
138
+ return [{ index: 0, name: s.shell.label, panes: 1, active: true }];
139
+ }
140
+ has(name) {
141
+ return this.sessions.has(name);
142
+ }
143
+ autoName(shell) {
144
+ for (let i = 1; i < 10000; i++) {
145
+ const candidate = `${shell.id}-${i}`;
146
+ if (!this.sessions.has(candidate))
147
+ return candidate;
148
+ }
149
+ return `${shell.id}-${nowEpoch()}`;
150
+ }
151
+ /** Create a new shell session. Returns the (possibly auto-assigned) name. */
152
+ create(opts) {
153
+ const shell = this.resolveShell(opts.shellId);
154
+ const name = opts.name ?? this.autoName(shell);
155
+ if (!NAME_RE.test(name))
156
+ throw new ManagerError(400, 'invalid session name');
157
+ if (this.sessions.has(name))
158
+ throw new ManagerError(409, `session "${name}" already exists`);
159
+ const cols = opts.cols ?? 80;
160
+ const rows = opts.rows ?? 24;
161
+ let proc;
162
+ try {
163
+ proc = pty.spawn(shell.file, shell.args, {
164
+ name: 'xterm-256color',
165
+ cols,
166
+ rows,
167
+ cwd: homedir(),
168
+ env: { ...process.env, TERM: 'xterm-256color' },
169
+ });
170
+ }
171
+ catch (e) {
172
+ throw new ManagerError(502, `failed to start ${shell.label}: ${e.message}`);
173
+ }
174
+ const session = new WinShellSession(name, shell, proc, (n) => this.sessions.delete(n));
175
+ this.sessions.set(name, session);
176
+ if (opts.command && opts.command.length > 0)
177
+ session.write(`${opts.command}\r`);
178
+ log.info(`winshell created ${name} (${shell.label})`);
179
+ return { name };
180
+ }
181
+ rename(oldName, newName) {
182
+ if (!NAME_RE.test(newName))
183
+ throw new ManagerError(400, 'invalid new session name');
184
+ const s = this.sessions.get(oldName);
185
+ if (!s)
186
+ throw new ManagerError(404, `session "${oldName}" not found`);
187
+ if (this.sessions.has(newName))
188
+ throw new ManagerError(409, `session "${newName}" already exists`);
189
+ // Re-key the same live instance (its pty handlers read `this.name`).
190
+ this.sessions.delete(oldName);
191
+ s.name = newName;
192
+ this.sessions.set(newName, s);
193
+ }
194
+ kill(name) {
195
+ const s = this.sessions.get(name);
196
+ if (!s)
197
+ throw new ManagerError(404, `session "${name}" not found`);
198
+ s.dispose();
199
+ }
200
+ /** Attach a client to an existing session, creating it (default shell) if missing. */
201
+ attachOrCreate(name, cols, rows, client) {
202
+ let s = this.sessions.get(name);
203
+ if (!s) {
204
+ this.create({ name, cols, rows });
205
+ s = this.sessions.get(name);
206
+ }
207
+ else {
208
+ s.resize(cols, rows);
209
+ }
210
+ s.attach(client);
211
+ return s;
212
+ }
213
+ disposeAll() {
214
+ for (const s of [...this.sessions.values()])
215
+ s.dispose();
216
+ }
217
+ }
218
+ /** Manager error carrying an HTTP status for the router. */
219
+ export class ManagerError extends Error {
220
+ status;
221
+ constructor(status, message) {
222
+ super(message);
223
+ this.status = status;
224
+ this.name = 'ManagerError';
225
+ }
226
+ }
227
+ /** Detect launchable shells for this machine. Windows: PowerShell 7 (if on
228
+ * PATH) → Windows PowerShell → cmd → Git Bash. Otherwise (test/fake): the
229
+ * user's shell, so the whole path can be exercised on Linux. */
230
+ export function detectShells() {
231
+ if (!isWindows) {
232
+ const file = process.env.SHELL || '/bin/bash';
233
+ return [{ id: 'shell', label: file.split('/').pop() || 'shell', file, args: ['-i'] }];
234
+ }
235
+ const shells = [];
236
+ const sysRoot = process.env.SystemRoot || process.env.windir || 'C:\\Windows';
237
+ const pwsh = findOnPath('pwsh.exe');
238
+ if (pwsh)
239
+ shells.push({ id: 'pwsh', label: 'PowerShell 7', file: pwsh, args: ['-NoLogo'] });
240
+ const winPs = join(sysRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
241
+ if (existsSync(winPs))
242
+ shells.push({ id: 'powershell', label: 'Windows PowerShell', file: winPs, args: ['-NoLogo'] });
243
+ const cmd = join(sysRoot, 'System32', 'cmd.exe');
244
+ if (existsSync(cmd))
245
+ shells.push({ id: 'cmd', label: 'Command Prompt', file: cmd, args: [] });
246
+ const gitBash = 'C:\\Program Files\\Git\\bin\\bash.exe';
247
+ if (existsSync(gitBash))
248
+ shells.push({ id: 'gitbash', label: 'Git Bash', file: gitBash, args: ['-i', '-l'] });
249
+ // Last-resort fallback so the target is never shell-less.
250
+ if (shells.length === 0)
251
+ shells.push({ id: 'cmd', label: 'Command Prompt', file: 'cmd.exe', args: [] });
252
+ return shells;
253
+ }
254
+ function findOnPath(exe) {
255
+ const dirs = (process.env.PATH || '').split(isWindows ? ';' : ':');
256
+ for (const dir of dirs) {
257
+ if (!dir)
258
+ continue;
259
+ const candidate = join(dir, exe);
260
+ if (existsSync(candidate))
261
+ return candidate;
262
+ }
263
+ return null;
264
+ }
265
+ /** Singleton used by the REST and WS layers. */
266
+ export const winShell = new WinShellManager();
267
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/winshell/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** Shared WebSocket control-message types. Terminal bytes travel as BINARY
2
+ * frames; everything below travels as TEXT (JSON) frames. */
3
+ export {};
4
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/ws/protocol.ts"],"names":[],"mappings":"AAAA;8DAC8D"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Classify ssh failure/prompt states from PTY output so the UI can show
3
+ * something better than a black screen. Best-effort string matching on the
4
+ * raw ssh client output.
5
+ */
6
+ const MATCHERS = [
7
+ {
8
+ state: 'hostkey',
9
+ re: /authenticity of host|fingerprint|known_hosts|REMOTE HOST IDENTIFICATION HAS CHANGED/i,
10
+ message: 'Unknown or changed host key — verify the host in a regular terminal first.',
11
+ },
12
+ {
13
+ state: 'authfail',
14
+ re: /permission denied|too many authentication failures|no such identity|authentication failed/i,
15
+ message: 'SSH authentication failed — check your keys / ssh-agent.',
16
+ },
17
+ {
18
+ state: 'refused',
19
+ re: /connection refused|could not resolve hostname|name or service not known|no route to host/i,
20
+ message: 'Could not connect to the host (refused / unresolved).',
21
+ },
22
+ {
23
+ state: 'timeout',
24
+ re: /connection timed out|operation timed out|timed out waiting/i,
25
+ message: 'Connection timed out.',
26
+ },
27
+ ];
28
+ export function classifySsh(text) {
29
+ for (const m of MATCHERS) {
30
+ if (m.re.test(text))
31
+ return { state: m.state, message: m.message };
32
+ }
33
+ return null;
34
+ }
35
+ //# sourceMappingURL=sshState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sshState.js","sourceRoot":"","sources":["../../src/ws/sshState.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,QAAQ,GAAuD;IACnE;QACE,KAAK,EAAE,SAAS;QAChB,EAAE,EAAE,sFAAsF;QAC1F,OAAO,EAAE,4EAA4E;KACtF;IACD;QACE,KAAK,EAAE,UAAU;QACjB,EAAE,EAAE,4FAA4F;QAChG,OAAO,EAAE,0DAA0D;KACpE;IACD;QACE,KAAK,EAAE,SAAS;QAChB,EAAE,EAAE,2FAA2F;QAC/F,OAAO,EAAE,uDAAuD;KACjE;IACD;QACE,KAAK,EAAE,SAAS;QAChB,EAAE,EAAE,6DAA6D;QACjE,OAAO,EAAE,uBAAuB;KACjC;CACF,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}