tabminal 2.0.9 → 2.0.11

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 CHANGED
@@ -40,7 +40,7 @@ As a long-time terminal user who frequently needs to step away from my computer
40
40
 
41
41
  ### 🧠 AI-Native Intelligence
42
42
  Powered by **modern AI models** (via OpenRouter or OpenAI), `t> Tabminal` understands your context.
43
- *(Defaults to **Gemini 3 Flash** for OpenRouter or **GPT-5.2** for OpenAI if not configured)*
43
+ *(Defaults to **Gemini 3 Flash** for OpenRouter or **GPT-5.4** for OpenAI if not configured)*
44
44
  * **Context-Aware Chat**: Type `# how do I...` to ask questions. The AI knows your **CWD**, **Environment**, and **Recent History**.
45
45
  * **Auto-Fix**: Command failed? `t> Tabminal` automatically analyzes the exit code and error output to suggest fixes. No copy-pasting required.
46
46
  * **Web Search**: Enable Google Search integration to let the AI fetch real-time answers from the web.
@@ -129,7 +129,7 @@ You can configure `t> Tabminal` via command-line arguments, environment variable
129
129
  | `-k`, `--openrouter-key` | `TABMINAL_OPENROUTER_KEY` | OpenRouter API Key (Mutually exclusive with OpenAI) | `null` |
130
130
  | `-o`, `--openai-key` | `TABMINAL_OPENAI_KEY` | OpenAI API Key (Mutually exclusive with OpenRouter) | `null` |
131
131
  | `-u`, `--openai-api` | `TABMINAL_OPENAI_API` | OpenAI Base API URL (Optional) | `null` |
132
- | `-m`, `--model` | `TABMINAL_MODEL` | AI Model ID | `gpt-5.2` (OpenAI) / `gemini-3-flash-preview` (OpenRouter) |
132
+ | `-m`, `--model` | `TABMINAL_MODEL` | AI Model ID | `gpt-5.4` (OpenAI) / `gemini-3-flash-preview` (OpenRouter) |
133
133
  | `-f`, `--cloudflare-key` | `TABMINAL_CLOUDFLARE_KEY` | Cloudflare Tunnel Token | `null` |
134
134
  | `-g`, `--google-key` | `TABMINAL_GOOGLE_KEY` | Google Search API Key | `null` |
135
135
  | `-c`, `--google-cx` | `TABMINAL_GOOGLE_CX` | Google Search Engine ID (CX) | `null` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tabminal",
3
- "version": "2.0.9",
3
+ "version": "2.0.11",
4
4
  "description": "A modern, persistent web terminal with multi-tab support and real-time system monitoring.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/server.mjs CHANGED
@@ -275,6 +275,14 @@ app.use(router.allowedMethods());
275
275
 
276
276
  const httpServer = createServer(app.callback());
277
277
  const wss = new WebSocketServer({ noServer: true, verifyClient });
278
+ const httpConnections = new Set();
279
+
280
+ httpServer.on('connection', (socket) => {
281
+ httpConnections.add(socket);
282
+ socket.on('close', () => {
283
+ httpConnections.delete(socket);
284
+ });
285
+ });
278
286
 
279
287
  httpServer.on('upgrade', (request, socket, head) => {
280
288
  const url = new URL(request.url, `http://${request.headers.host}`);
@@ -370,6 +378,9 @@ function shutdown(signal) {
370
378
  isShuttingDown = true;
371
379
  console.log(`Shutting down (${signal})...`);
372
380
  clearInterval(heartbeatInterval);
381
+ for (const socket of wss.clients) {
382
+ socket.terminate();
383
+ }
373
384
  wss.close();
374
385
  terminalManager.dispose();
375
386
 
@@ -382,6 +393,11 @@ function shutdown(signal) {
382
393
  clearTimeout(forceExitTimer);
383
394
  process.exit(0);
384
395
  });
396
+ httpServer.closeIdleConnections?.();
397
+ httpServer.closeAllConnections?.();
398
+ for (const socket of httpConnections) {
399
+ socket.destroy();
400
+ }
385
401
  }
386
402
 
387
403
  process.on('SIGINT', () => shutdown('SIGINT'));
@@ -9,13 +9,12 @@ import * as persistence from './persistence.mjs';
9
9
  import { config } from './config.mjs';
10
10
 
11
11
  function resolveShell() {
12
- if (process.platform === 'win32') {
13
- return process.env.COMSPEC || 'cmd.exe';
14
- }
15
- // config.shell has already handled process.env.SHELL and TABMINAL_SHELL via config.mjs
16
12
  if (config.shell) {
17
13
  return config.shell;
18
14
  }
15
+ if (process.platform === 'win32') {
16
+ return process.env.COMSPEC || 'cmd.exe';
17
+ }
19
18
  // Try to use Homebrew installed bash if available (newer version)
20
19
  if (fs.existsSync('/opt/homebrew/bin/bash')) {
21
20
  return '/opt/homebrew/bin/bash';
@@ -60,7 +59,12 @@ export class TerminalManager {
60
59
 
61
60
  // Inject shell tools
62
61
  const shellToolsPath = path.join(process.cwd(), 'shell');
63
- env.PATH = `${shellToolsPath}:${env.PATH}`;
62
+ const pathDelimiter = path.delimiter;
63
+ const pathKey = Object.keys(env).find((key) => key.toLowerCase() === 'path') || 'PATH';
64
+ const existingPath = env[pathKey];
65
+ env[pathKey] = existingPath
66
+ ? `${shellToolsPath}${pathDelimiter}${existingPath}`
67
+ : shellToolsPath;
64
68
 
65
69
  let args = [];
66
70
  let initFilePath = null;
@@ -151,14 +155,17 @@ precmd_functions+=(_tabminal_zsh_apply_prompt_marker)
151
155
 
152
156
  let ptyProcess;
153
157
  try {
154
- ptyProcess = pty.spawn(shell, args, {
158
+ const ptyOptions = {
155
159
  name: 'xterm-256color',
156
160
  cols: cols,
157
161
  rows: rows,
158
162
  cwd: initialCwd,
159
- env: env,
160
- encoding: 'utf8'
161
- });
163
+ env: env
164
+ };
165
+ if (process.platform !== 'win32') {
166
+ ptyOptions.encoding = 'utf8';
167
+ }
168
+ ptyProcess = pty.spawn(shell, args, ptyOptions);
162
169
  } catch (err) {
163
170
  const spawnInfo = {
164
171
  shell,
@@ -295,7 +302,11 @@ precmd_functions+=(_tabminal_zsh_apply_prompt_marker)
295
302
  this.disposing = true;
296
303
  for (const session of this.sessions.values()) {
297
304
  try {
298
- session.pty.kill('SIGHUP');
305
+ if (process.platform === 'win32') {
306
+ session.pty.kill();
307
+ } else {
308
+ session.pty.kill('SIGHUP');
309
+ }
299
310
  } catch {
300
311
  // ignore
301
312
  }