tabminal 1.1.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.
- package/LICENSE +21 -0
- package/README.md +95 -0
- package/build.mjs +156 -0
- package/config.sample.json +11 -0
- package/icon-gen.html +46 -0
- package/package.json +54 -0
- package/public/app.js +2245 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon.svg +23 -0
- package/public/fonts/MonaspaceNeon-Bold.woff2 +0 -0
- package/public/fonts/MonaspaceNeon-Regular.woff2 +0 -0
- package/public/icons/c.svg +1 -0
- package/public/icons/certificate.svg +1 -0
- package/public/icons/console.svg +1 -0
- package/public/icons/cpp.svg +1 -0
- package/public/icons/css.svg +1 -0
- package/public/icons/docker.svg +1 -0
- package/public/icons/document.svg +1 -0
- package/public/icons/folder-src-open.svg +1 -0
- package/public/icons/folder-src.svg +1 -0
- package/public/icons/git.svg +1 -0
- package/public/icons/go.svg +1 -0
- package/public/icons/html.svg +1 -0
- package/public/icons/image.svg +1 -0
- package/public/icons/java.svg +1 -0
- package/public/icons/javascript.svg +1 -0
- package/public/icons/json.svg +1 -0
- package/public/icons/lock.svg +1 -0
- package/public/icons/map.json +52 -0
- package/public/icons/markdown.svg +1 -0
- package/public/icons/nodejs.svg +1 -0
- package/public/icons/php.svg +1 -0
- package/public/icons/python.svg +1 -0
- package/public/icons/react.svg +1 -0
- package/public/icons/react_ts.svg +1 -0
- package/public/icons/readme.svg +1 -0
- package/public/icons/ruby.svg +1 -0
- package/public/icons/rust.svg +1 -0
- package/public/icons/svg.svg +1 -0
- package/public/icons/tsconfig.svg +1 -0
- package/public/icons/tune.svg +1 -0
- package/public/icons/typescript.svg +1 -0
- package/public/icons/xml.svg +1 -0
- package/public/icons/yaml.svg +1 -0
- package/public/index.html +227 -0
- package/public/manifest.json +15 -0
- package/public/styles.css +1267 -0
- package/shell/terminal_ver +12 -0
- package/src/auth.mjs +86 -0
- package/src/config.mjs +199 -0
- package/src/fs-routes.mjs +125 -0
- package/src/persistence.mjs +174 -0
- package/src/server.mjs +306 -0
- package/src/system-monitor.mjs +108 -0
- package/src/terminal-manager.mjs +283 -0
- package/src/terminal-session.mjs +984 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tabminal Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Tabminal
|
|
2
|
+
|
|
3
|
+
> **A modern, AI-native web terminal built for the cloud age.**
|
|
4
|
+
> Seamlessly accessible from Desktop, iPad, and iPhone with a native-like experience.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## ⨠Key Features
|
|
9
|
+
|
|
10
|
+
### š§ AI-Native Integration
|
|
11
|
+
Tabminal isn't just a terminal; it's an intelligent workspace paired with **Gemini 2.5 Flash**.
|
|
12
|
+
* **Context-Aware**: The AI knows your **Current Working Directory**, **Environment Variables**, and **Recent Command History**. No need to copy-paste context.
|
|
13
|
+
* **Command Hijack (`#`)**: Simply type `#` followed by your question (e.g., `# how to tar a folder`) to chat with the AI. The output streams in real-time with syntax highlighting.
|
|
14
|
+
* **Auto-Fix**: If a shell command fails (non-zero exit code), Tabminal automatically analyzes the error log and suggests a fix.
|
|
15
|
+
* **Audit Logging**: All AI interactions are logged and persisted for future context.
|
|
16
|
+
|
|
17
|
+
### š± Ultimate Mobile Experience
|
|
18
|
+
Optimized specifically for **iPadOS** and **iOS**, solving the pain points of coding on touch devices.
|
|
19
|
+
* **PWA Support**: Installable as a full-screen app. Solves the infamous iOS viewport height issues.
|
|
20
|
+
* **HHKB-Style Soft Keyboard**: A custom 12-column virtual keyboard bringing the HHKB layout to iPhone.
|
|
21
|
+
* **Drag-to-Ctrl**: Touch and drag the `CTRL` key to perform combinations (e.g., drag to 'C' for `Ctrl+C`).
|
|
22
|
+
* **Smart Modifiers**: `SHIFT` allows continuous entry; `SYM` toggles the full keyboard overlay.
|
|
23
|
+
* **Responsive Layout**: Keyboard height adapts to landscape/portrait modes automatically.
|
|
24
|
+
* **Optimized UI**: Hamburger menu for sessions on small screens, resource-saving mode (no preview rendering) on iPhone.
|
|
25
|
+
|
|
26
|
+
### š» Powerful Desktop Features
|
|
27
|
+
* **Persistent Sessions**: Close your browser, come back later, and your terminal state (and running processes) are exactly where you left them.
|
|
28
|
+
* **Built-in Editor**: Integrated **Monaco Editor** (VS Code core) with split-pane view. Edit files on the server directly.
|
|
29
|
+
* **Visual File Manager**: Sidebar file tree for easy navigation and opening of files.
|
|
30
|
+
* **Network Heartbeat**: Real-time latency visualization (capsule style on desktop, bottom-fill on mobile).
|
|
31
|
+
|
|
32
|
+
## š Getting Started
|
|
33
|
+
|
|
34
|
+
### Prerequisites
|
|
35
|
+
* Node.js >= 16
|
|
36
|
+
* An AI API Key (e.g., Google AI Studio / OpenRouter)
|
|
37
|
+
|
|
38
|
+
### Quick Start (No Install)
|
|
39
|
+
Run directly with npx:
|
|
40
|
+
```bash
|
|
41
|
+
npx tabminal --openrouter-key "YOUR_API_KEY" --accept-terms
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Clone the repository
|
|
48
|
+
git clone https://github.com/yourusername/tabminal.git
|
|
49
|
+
cd tabminal
|
|
50
|
+
|
|
51
|
+
# Install dependencies
|
|
52
|
+
npm install
|
|
53
|
+
|
|
54
|
+
# Start the server
|
|
55
|
+
npm start -- --openrouter-key "YOUR_API_KEY" --accept-terms
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Configuration
|
|
59
|
+
|
|
60
|
+
You can configure Tabminal via command-line arguments or environment variables.
|
|
61
|
+
|
|
62
|
+
| Argument | Env Variable | Description | Default |
|
|
63
|
+
| :--- | :--- | :--- | :--- |
|
|
64
|
+
| `-p`, `--port` | `PORT` | Server port | `9846` |
|
|
65
|
+
| `-h`, `--host` | `HOST` | Bind address | `127.0.0.1` |
|
|
66
|
+
| `-a`, `--password` | `TABMINAL_PASSWORD` | Access password | (Randomly Generated) |
|
|
67
|
+
| `-k`, `--openrouter-key` | `TABMINAL_OPENROUTER_KEY` | OpenRouter API Key | `null` |
|
|
68
|
+
| `-m`, `--model` | `TABMINAL_MODEL` | AI Model ID | `gemini-2.5-flash-preview-09-2025` |
|
|
69
|
+
| `-g`, `--google-key` | `TABMINAL_GOOGLE_KEY` | Google Search API Key | `null` |
|
|
70
|
+
| `-c`, `--google-cx` | `TABMINAL_GOOGLE_CX` | Google Search Engine ID (CX) | `null` |
|
|
71
|
+
| `-d`, `--debug` | `TABMINAL_DEBUG` | Enable debug logs | `false` |
|
|
72
|
+
| `-y`, `--accept-terms` | `TABMINAL_ACCEPT` | Accept security terms | `false` |
|
|
73
|
+
|
|
74
|
+
## āØļø Shortcuts
|
|
75
|
+
|
|
76
|
+
### Physical Keyboard (Desktop/iPad)
|
|
77
|
+
* **`Ctrl + Shift + T`**: New Tab (Inherits current CWD)
|
|
78
|
+
* **`Ctrl + Shift + W`**: Close Current Tab
|
|
79
|
+
* **`Ctrl + Shift + [` / `]`**: Switch Previous/Next Tab
|
|
80
|
+
* **`Ctrl + Alt + [` / `]`**: Switch Previous/Next Open File in Editor
|
|
81
|
+
* **`Ctrl + Shift + E`**: Toggle Editor Pane
|
|
82
|
+
* **`Ctrl + Shift + ?`**: Show Shortcuts Help
|
|
83
|
+
|
|
84
|
+
### Touch Gestures (Mobile)
|
|
85
|
+
* **Virtual `^C`**: Send SIGINT (Ctrl+C).
|
|
86
|
+
* **Virtual `CTRL` (Hold & Drag)**: Visualize a QWERTY overlay to quickly trigger Control combinations without lifting your finger.
|
|
87
|
+
* **Virtual `SYM`**: Toggle the full HHKB-style soft keyboard.
|
|
88
|
+
|
|
89
|
+
## š Tech Stack
|
|
90
|
+
* **Backend**: Node.js, Koa, node-pty, WebSocket (ws).
|
|
91
|
+
* **Frontend**: Vanilla JS (ES Modules), xterm.js, Monaco Editor.
|
|
92
|
+
* **AI**: Integration via `utilitas`.
|
|
93
|
+
|
|
94
|
+
## š License
|
|
95
|
+
MIT
|
package/build.mjs
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import fsPromises from 'node:fs/promises';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import https from 'node:https';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
const PUBLIC_ICONS_DIR = path.join(__dirname, 'public', 'icons');
|
|
10
|
+
|
|
11
|
+
// Fallback to PKief's repo which is often stable for raw access, or use material-extensions
|
|
12
|
+
const BASE_URL = 'https://raw.githubusercontent.com/PKief/vscode-material-icon-theme/main/icons';
|
|
13
|
+
|
|
14
|
+
// Ensure icons directory exists
|
|
15
|
+
await fsPromises.mkdir(PUBLIC_ICONS_DIR, { recursive: true });
|
|
16
|
+
|
|
17
|
+
const downloadFile = (url, dest) => {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const stream = fs.createWriteStream(dest);
|
|
20
|
+
https.get(url, (res) => {
|
|
21
|
+
if (res.statusCode !== 200) {
|
|
22
|
+
stream.close();
|
|
23
|
+
fsPromises.unlink(dest).catch(() => {});
|
|
24
|
+
console.warn(`Failed to download: ${url} (${res.statusCode})`);
|
|
25
|
+
resolve(false);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
res.pipe(stream);
|
|
29
|
+
stream.on('finish', () => {
|
|
30
|
+
stream.close();
|
|
31
|
+
resolve(true);
|
|
32
|
+
});
|
|
33
|
+
}).on('error', (err) => {
|
|
34
|
+
fsPromises.unlink(dest).catch(() => {});
|
|
35
|
+
reject(err);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
async function main() {
|
|
41
|
+
console.log('šļø Starting build process (Fallback Mode)...');
|
|
42
|
+
|
|
43
|
+
// Hardcoded map for stability
|
|
44
|
+
const fileMap = {
|
|
45
|
+
extensions: {
|
|
46
|
+
'html': 'html',
|
|
47
|
+
'htm': 'html',
|
|
48
|
+
'css': 'css',
|
|
49
|
+
'js': 'javascript',
|
|
50
|
+
'mjs': 'javascript',
|
|
51
|
+
'cjs': 'javascript',
|
|
52
|
+
'ts': 'typescript',
|
|
53
|
+
'tsx': 'react_ts',
|
|
54
|
+
'jsx': 'react',
|
|
55
|
+
'json': 'json',
|
|
56
|
+
'md': 'markdown',
|
|
57
|
+
'py': 'python',
|
|
58
|
+
'rb': 'ruby',
|
|
59
|
+
'go': 'go',
|
|
60
|
+
'rs': 'rust',
|
|
61
|
+
'php': 'php',
|
|
62
|
+
'java': 'java',
|
|
63
|
+
'c': 'c',
|
|
64
|
+
'cpp': 'cpp',
|
|
65
|
+
'h': 'cpp',
|
|
66
|
+
'png': 'image',
|
|
67
|
+
'jpg': 'image',
|
|
68
|
+
'jpeg': 'image',
|
|
69
|
+
'gif': 'image',
|
|
70
|
+
'svg': 'svg',
|
|
71
|
+
'xml': 'xml',
|
|
72
|
+
'yaml': 'yaml',
|
|
73
|
+
'yml': 'yaml',
|
|
74
|
+
'sh': 'console',
|
|
75
|
+
'bash': 'console',
|
|
76
|
+
'zsh': 'console',
|
|
77
|
+
'txt': 'document',
|
|
78
|
+
'lock': 'lock'
|
|
79
|
+
},
|
|
80
|
+
filenames: {
|
|
81
|
+
'package.json': 'nodejs',
|
|
82
|
+
'package-lock.json': 'nodejs',
|
|
83
|
+
'tsconfig.json': 'tsconfig',
|
|
84
|
+
'.gitignore': 'git',
|
|
85
|
+
'.gitattributes': 'git',
|
|
86
|
+
'.env': 'tune',
|
|
87
|
+
'readme.md': 'readme',
|
|
88
|
+
'license': 'certificate',
|
|
89
|
+
'dockerfile': 'docker',
|
|
90
|
+
'docker-compose.yml': 'docker'
|
|
91
|
+
},
|
|
92
|
+
default: 'document',
|
|
93
|
+
folder: 'folder-src',
|
|
94
|
+
folderOpen: 'folder-src-open'
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const iconsToDownload = new Set([
|
|
98
|
+
'folder-src', 'folder-src-open',
|
|
99
|
+
...Object.values(fileMap.extensions),
|
|
100
|
+
...Object.values(fileMap.filenames)
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
console.log(`š Need ${iconsToDownload.size} icons.`);
|
|
104
|
+
console.log('ā¬ļø Downloading SVGs...');
|
|
105
|
+
|
|
106
|
+
const downloadQueue = Array.from(iconsToDownload);
|
|
107
|
+
const batchSize = 10;
|
|
108
|
+
|
|
109
|
+
for (let i = 0; i < downloadQueue.length; i += batchSize) {
|
|
110
|
+
const batch = downloadQueue.slice(i, i + batchSize);
|
|
111
|
+
await Promise.all(batch.map(async (iconName) => {
|
|
112
|
+
const fileName = `${iconName}.svg`;
|
|
113
|
+
const dest = path.join(PUBLIC_ICONS_DIR, fileName);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
await fsPromises.access(dest);
|
|
117
|
+
return;
|
|
118
|
+
} catch {}
|
|
119
|
+
|
|
120
|
+
const url = `${BASE_URL}/${fileName}`;
|
|
121
|
+
await downloadFile(url, dest);
|
|
122
|
+
}));
|
|
123
|
+
process.stdout.write(`\rProgress: ${Math.min(i + batchSize, downloadQueue.length)}/${downloadQueue.length}`);
|
|
124
|
+
}
|
|
125
|
+
console.log('\nā
Icons downloaded.');
|
|
126
|
+
|
|
127
|
+
await fsPromises.writeFile(path.join(PUBLIC_ICONS_DIR, 'map.json'), JSON.stringify(fileMap, null, 2));
|
|
128
|
+
console.log('ā
Map generated at public/icons/map.json');
|
|
129
|
+
|
|
130
|
+
// Copy Fonts
|
|
131
|
+
console.log('ā¬ļø Copying Fonts...');
|
|
132
|
+
const fontsDir = path.join(__dirname, 'public', 'fonts');
|
|
133
|
+
const fontSourceDir = path.join(__dirname, 'node_modules', '@fontsource', 'monaspace-neon', 'files');
|
|
134
|
+
|
|
135
|
+
await fsPromises.mkdir(fontsDir, { recursive: true });
|
|
136
|
+
|
|
137
|
+
const fontsToCopy = [
|
|
138
|
+
{ src: 'monaspace-neon-latin-400-normal.woff2', dest: 'MonaspaceNeon-Regular.woff2' },
|
|
139
|
+
{ src: 'monaspace-neon-latin-700-normal.woff2', dest: 'MonaspaceNeon-Bold.woff2' }
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
for (const font of fontsToCopy) {
|
|
143
|
+
const srcPath = path.join(fontSourceDir, font.src);
|
|
144
|
+
const destPath = path.join(fontsDir, font.dest);
|
|
145
|
+
try {
|
|
146
|
+
await fsPromises.copyFile(srcPath, destPath);
|
|
147
|
+
console.log(` Copied ${font.dest}`);
|
|
148
|
+
} catch (e) {
|
|
149
|
+
console.warn(` Failed to copy ${font.dest}:`, e.message);
|
|
150
|
+
console.warn(' Make sure you have run "npm install" and @fontsource/monaspace-neon is installed.');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
console.log('ā
Fonts copied.');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"host": "0.0.0.0",
|
|
3
|
+
"port": 9846,
|
|
4
|
+
"password": "YOUR_SECURE_PASSWORD",
|
|
5
|
+
"openrouter-key": "YOUR_OPENROUTER_API_KEY",
|
|
6
|
+
"model": "gemini-2.5-flash-preview-09-2025",
|
|
7
|
+
"google-key": "YOUR_GOOGLE_SEARCH_API_KEY",
|
|
8
|
+
"google-cx": "YOUR_GOOGLE_SEARCH_ENGINE_ID",
|
|
9
|
+
"accept-terms": true,
|
|
10
|
+
"debug": false
|
|
11
|
+
}
|
package/icon-gen.html
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Icon Generator</title>
|
|
5
|
+
<style>body { background: #eee; font-family: sans-serif; padding: 20px; }</style>
|
|
6
|
+
</head>
|
|
7
|
+
<body>
|
|
8
|
+
<h2>Tabminal Icon Generator</h2>
|
|
9
|
+
<p>1. Allow the page to load the SVG.</p>
|
|
10
|
+
<p>2. Click the link below to download the PNG.</p>
|
|
11
|
+
<p>3. Save it as <code>public/apple-touch-icon.png</code>.</p>
|
|
12
|
+
|
|
13
|
+
<canvas id="c180" width="180" height="180" style="border:1px solid #ccc"></canvas>
|
|
14
|
+
<div id="links" style="margin-top: 20px;"></div>
|
|
15
|
+
|
|
16
|
+
<script>
|
|
17
|
+
const img = new Image();
|
|
18
|
+
img.onload = () => {
|
|
19
|
+
const canvas = document.getElementById('c180');
|
|
20
|
+
const ctx = canvas.getContext('2d');
|
|
21
|
+
|
|
22
|
+
// Draw Background (Solarized Base03)
|
|
23
|
+
ctx.fillStyle = '#002b36';
|
|
24
|
+
ctx.fillRect(0, 0, 180, 180);
|
|
25
|
+
|
|
26
|
+
// Draw SVG centered and scaled
|
|
27
|
+
// Assume SVG is square. Padding 20px.
|
|
28
|
+
ctx.drawImage(img, 20, 20, 140, 140);
|
|
29
|
+
|
|
30
|
+
const link = document.createElement('a');
|
|
31
|
+
link.href = canvas.toDataURL('image/png');
|
|
32
|
+
link.download = 'apple-touch-icon.png';
|
|
33
|
+
link.style.display = 'inline-block';
|
|
34
|
+
link.style.padding = '10px 20px';
|
|
35
|
+
link.style.background = '#268bd2';
|
|
36
|
+
link.style.color = 'white';
|
|
37
|
+
link.style.textDecoration = 'none';
|
|
38
|
+
link.style.borderRadius = '5px';
|
|
39
|
+
link.innerText = 'Download apple-touch-icon.png';
|
|
40
|
+
|
|
41
|
+
document.getElementById('links').appendChild(link);
|
|
42
|
+
};
|
|
43
|
+
img.src = 'favicon.svg';
|
|
44
|
+
</script>
|
|
45
|
+
</body>
|
|
46
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tabminal",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "A modern, persistent web terminal with multi-tab support and real-time system monitoring.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"tabminal": "./src/server.mjs"
|
|
8
|
+
},
|
|
9
|
+
"main": "src/server.mjs",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node src/server.mjs",
|
|
12
|
+
"dev": "node --watch src/server.mjs",
|
|
13
|
+
"build": "node build.mjs",
|
|
14
|
+
"test": "node --test",
|
|
15
|
+
"test:watch": "node --test --watch",
|
|
16
|
+
"lint": "eslint ."
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"terminal",
|
|
20
|
+
"web-terminal",
|
|
21
|
+
"xterm.js",
|
|
22
|
+
"node-pty",
|
|
23
|
+
"websocket",
|
|
24
|
+
"monitoring",
|
|
25
|
+
"dashboard",
|
|
26
|
+
"cli"
|
|
27
|
+
],
|
|
28
|
+
"author": "Leask Wong",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@fontsource/monaspace-neon": "^5.2.5",
|
|
35
|
+
"@koa/router": "^14.0.0",
|
|
36
|
+
"js-tiktoken": "^1.0.21",
|
|
37
|
+
"koa": "^3.1.1",
|
|
38
|
+
"koa-bodyparser": "^4.4.1",
|
|
39
|
+
"koa-static": "^5.0.0",
|
|
40
|
+
"node-ansiparser": "^2.2.1",
|
|
41
|
+
"node-pty": "^1.0.0",
|
|
42
|
+
"openai": "^6.9.1",
|
|
43
|
+
"utilitas": "^2000.3.3",
|
|
44
|
+
"ws": "^8.18.3"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/leask/tabminal.git"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/leask/tabminal/issues"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://github.com/leask/tabminal#readme"
|
|
54
|
+
}
|