@bamptee/aia-code 2.0.11 → 2.0.13
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 +408 -34
- package/package.json +11 -2
- package/src/constants.js +24 -0
- package/src/providers/anthropic.js +2 -21
- package/src/providers/cli-runner.js +5 -3
- package/src/services/agent-sessions.js +110 -0
- package/src/services/apps.js +132 -0
- package/src/services/config.js +41 -0
- package/src/services/feature.js +28 -7
- package/src/services/model-call.js +2 -2
- package/src/services/runner.js +23 -1
- package/src/services/status.js +69 -1
- package/src/services/test-quick.js +229 -0
- package/src/services/worktrunk.js +135 -21
- package/src/types/test-quick.js +88 -0
- package/src/ui/api/config.js +28 -1
- package/src/ui/api/features.js +160 -50
- package/src/ui/api/index.js +2 -0
- package/src/ui/api/test-quick.js +207 -0
- package/src/ui/api/worktrunk.js +63 -25
- package/src/ui/public/components/config-view.js +95 -0
- package/src/ui/public/components/dashboard.js +823 -163
- package/src/ui/public/components/feature-detail.js +517 -124
- package/src/ui/public/components/test-quick.js +276 -0
- package/src/ui/public/components/worktrunk-panel.js +187 -25
- package/src/ui/public/index.html +13 -0
- package/src/ui/public/main.js +5 -1
- package/src/ui/server.js +97 -67
package/src/ui/server.js
CHANGED
|
@@ -99,81 +99,111 @@ export async function startServer(preferredPort, root = process.cwd()) {
|
|
|
99
99
|
// Setup WebSocket server for terminal
|
|
100
100
|
const wss = new WebSocketServer({ noServer: true });
|
|
101
101
|
|
|
102
|
+
// Helper function to setup PTY terminal with WebSocket
|
|
103
|
+
const setupPtyTerminal = (ws, command, args, options) => {
|
|
104
|
+
import('node-pty').then(({ spawn: ptySpawn }) => {
|
|
105
|
+
const ptyProcess = ptySpawn(command, args, {
|
|
106
|
+
name: 'xterm-256color',
|
|
107
|
+
cols: 80,
|
|
108
|
+
rows: 24,
|
|
109
|
+
env: process.env,
|
|
110
|
+
...options,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Idle timeout - close terminal after 30 minutes of inactivity
|
|
114
|
+
const IDLE_TIMEOUT = 30 * 60 * 1000;
|
|
115
|
+
let idleTimer = setTimeout(() => {
|
|
116
|
+
ws.send('\r\n\x1b[33m[Session closed due to inactivity]\x1b[0m\r\n');
|
|
117
|
+
ws.close();
|
|
118
|
+
}, IDLE_TIMEOUT);
|
|
119
|
+
|
|
120
|
+
const resetIdleTimer = () => {
|
|
121
|
+
clearTimeout(idleTimer);
|
|
122
|
+
idleTimer = setTimeout(() => {
|
|
123
|
+
ws.send('\r\n\x1b[33m[Session closed due to inactivity]\x1b[0m\r\n');
|
|
124
|
+
ws.close();
|
|
125
|
+
}, IDLE_TIMEOUT);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
ws.on('message', (data) => {
|
|
129
|
+
resetIdleTimer();
|
|
130
|
+
const msg = data.toString();
|
|
131
|
+
// Limit message size to 64KB
|
|
132
|
+
if (msg.length > 65536) return;
|
|
133
|
+
// Handle resize messages
|
|
134
|
+
if (msg.startsWith('\x1b[8;')) {
|
|
135
|
+
const match = msg.match(/\x1b\[8;(\d+);(\d+)t/);
|
|
136
|
+
if (match) {
|
|
137
|
+
ptyProcess.resize(parseInt(match[2], 10), parseInt(match[1], 10));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
ptyProcess.write(msg);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
ptyProcess.onData((data) => {
|
|
145
|
+
resetIdleTimer();
|
|
146
|
+
try {
|
|
147
|
+
ws.send(data);
|
|
148
|
+
} catch {}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
ws.on('close', () => {
|
|
152
|
+
clearTimeout(idleTimer);
|
|
153
|
+
ptyProcess.kill();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
ws.on('error', () => {
|
|
157
|
+
clearTimeout(idleTimer);
|
|
158
|
+
ptyProcess.kill();
|
|
159
|
+
});
|
|
160
|
+
}).catch((err) => {
|
|
161
|
+
ws.send(`\r\n\x1b[31mError: ${err.message}\x1b[0m\r\n`);
|
|
162
|
+
if (err.code === 'ERR_MODULE_NOT_FOUND') {
|
|
163
|
+
ws.send(`\x1b[33mRun: npm install node-pty\x1b[0m\r\n`);
|
|
164
|
+
}
|
|
165
|
+
ws.close();
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
|
|
102
169
|
server.on('upgrade', (req, socket, head) => {
|
|
103
170
|
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
104
171
|
|
|
105
172
|
if (url.pathname === '/api/terminal') {
|
|
106
173
|
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
107
174
|
const cwd = url.searchParams.get('cwd') || root;
|
|
175
|
+
const shell = process.platform === 'win32'
|
|
176
|
+
? 'powershell.exe'
|
|
177
|
+
: process.env.SHELL || '/bin/bash';
|
|
178
|
+
setupPtyTerminal(ws, shell, [], { cwd });
|
|
179
|
+
});
|
|
180
|
+
} else if (url.pathname === '/api/terminal/compose') {
|
|
181
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
182
|
+
const service = url.searchParams.get('service');
|
|
183
|
+
const cwd = url.searchParams.get('cwd');
|
|
108
184
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
name: 'xterm-256color',
|
|
117
|
-
cols: 80,
|
|
118
|
-
rows: 24,
|
|
119
|
-
cwd,
|
|
120
|
-
env: process.env,
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// F7: Idle timeout - close terminal after 30 minutes of inactivity
|
|
124
|
-
const IDLE_TIMEOUT = 30 * 60 * 1000;
|
|
125
|
-
let idleTimer = setTimeout(() => {
|
|
126
|
-
ws.send('\r\n\x1b[33m[Session closed due to inactivity]\x1b[0m\r\n');
|
|
127
|
-
ws.close();
|
|
128
|
-
}, IDLE_TIMEOUT);
|
|
129
|
-
|
|
130
|
-
const resetIdleTimer = () => {
|
|
131
|
-
clearTimeout(idleTimer);
|
|
132
|
-
idleTimer = setTimeout(() => {
|
|
133
|
-
ws.send('\r\n\x1b[33m[Session closed due to inactivity]\x1b[0m\r\n');
|
|
134
|
-
ws.close();
|
|
135
|
-
}, IDLE_TIMEOUT);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
ws.on('message', (data) => {
|
|
139
|
-
resetIdleTimer();
|
|
140
|
-
const msg = data.toString();
|
|
141
|
-
// F5: Limit message size to 64KB
|
|
142
|
-
if (msg.length > 65536) return;
|
|
143
|
-
// Handle resize messages
|
|
144
|
-
if (msg.startsWith('\x1b[8;')) {
|
|
145
|
-
const match = msg.match(/\x1b\[8;(\d+);(\d+)t/);
|
|
146
|
-
if (match) {
|
|
147
|
-
ptyProcess.resize(parseInt(match[2], 10), parseInt(match[1], 10));
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
ptyProcess.write(msg);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
ptyProcess.onData((data) => {
|
|
155
|
-
resetIdleTimer();
|
|
156
|
-
try {
|
|
157
|
-
ws.send(data);
|
|
158
|
-
} catch {}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
ws.on('close', () => {
|
|
162
|
-
clearTimeout(idleTimer);
|
|
163
|
-
ptyProcess.kill();
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
ws.on('error', () => {
|
|
167
|
-
clearTimeout(idleTimer);
|
|
168
|
-
ptyProcess.kill();
|
|
169
|
-
});
|
|
170
|
-
}).catch((err) => {
|
|
171
|
-
ws.send(`\r\n\x1b[31mError: ${err.message}\x1b[0m\r\n`);
|
|
172
|
-
if (err.code === 'ERR_MODULE_NOT_FOUND') {
|
|
173
|
-
ws.send(`\x1b[33mRun: npm install node-pty\x1b[0m\r\n`);
|
|
174
|
-
}
|
|
185
|
+
if (!service) {
|
|
186
|
+
ws.send('\r\n\x1b[31mError: service parameter required\x1b[0m\r\n');
|
|
187
|
+
ws.close();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (!cwd) {
|
|
191
|
+
ws.send('\r\n\x1b[31mError: cwd parameter required\x1b[0m\r\n');
|
|
175
192
|
ws.close();
|
|
176
|
-
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
// Validate service name (alphanumeric, dash, underscore)
|
|
196
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(service)) {
|
|
197
|
+
ws.send('\r\n\x1b[31mError: invalid service name\x1b[0m\r\n');
|
|
198
|
+
ws.close();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// Get shell from query param or default to sh (most compatible)
|
|
202
|
+
const shell = url.searchParams.get('shell') || 'sh';
|
|
203
|
+
const validShells = ['sh', 'bash', 'ash', 'zsh'];
|
|
204
|
+
const safeShell = validShells.includes(shell) ? shell : 'sh';
|
|
205
|
+
// Spawn docker-compose exec <service> <shell>
|
|
206
|
+
setupPtyTerminal(ws, 'docker-compose', ['-f', 'docker-compose.wt.yml', 'exec', service, safeShell], { cwd });
|
|
177
207
|
});
|
|
178
208
|
} else {
|
|
179
209
|
socket.destroy();
|